1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains the routines for embedded scsi disks 31 */ 32 #include "global.h" 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/ioctl.h> 37 #include <sys/uio.h> 38 #include <sys/fcntl.h> 39 #include <errno.h> 40 #include <memory.h> 41 #include <malloc.h> 42 #include <unistd.h> 43 #include <stdlib.h> 44 #include <values.h> 45 #include <sys/byteorder.h> 46 47 48 49 #include "startup.h" 50 #include "scsi_com.h" 51 #include "misc.h" 52 #include "ctlr_scsi.h" 53 #include "analyze.h" 54 #include "param.h" 55 #include "io.h" 56 57 58 #ifndef DAD_MODE_CACHE_CCS 59 #define DAD_MODE_CACHE_CCS 0x38 60 #endif /* DAD_MODE_CACHE_CCS */ 61 62 /* format defect header bits */ 63 #define FDH_FOV 0x80 64 #define FDH_IMMED 0x02 65 66 #define SENSE_LEN 20 67 68 #define RETRY_DELAY 5 69 70 #define PROGRESS_INDICATION_BASE 65536 71 72 #ifdef __STDC__ 73 /* 74 * Local prototypes for ANSI C compilers 75 */ 76 static int scsi_format(uint64_t, uint64_t, struct defect_list *); 77 static int scsi_raw_format(void); 78 static int scsi_ms_page8(int); 79 static int scsi_ms_page38(int); 80 static void scsi_convert_list_to_new(struct defect_list *, 81 struct scsi_defect_list *, int); 82 static char *scsi_find_command_name(uint_t); 83 static int chg_list_affects_page(struct chg_list *, int); 84 static void scsi_printerr(struct uscsi_cmd *, 85 struct scsi_extended_sense *, int); 86 static diskaddr_t 87 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen); 88 89 static void scsi_print_extended_sense(struct scsi_extended_sense *, int); 90 static void scsi_print_descr_sense(struct scsi_descr_sense_hdr *, int); 91 92 static int test_until_ready(int fd); 93 static int uscsi_reserve_release(int, int); 94 static int check_support_for_defects(void); 95 static int scsi_format_without_defects(void); 96 static int scsi_ms_page1(int); 97 static int scsi_ms_page2(int); 98 static int scsi_ms_page3(int); 99 static int scsi_ms_page4(int); 100 static int scsi_repair(uint64_t, int); 101 static int scsi_read_defect_data(struct defect_list *, int); 102 static int scsi_ck_format(void); 103 104 #ifdef i386 105 static int scsi_rdwr(int, int, diskaddr_t, int, caddr_t, int, int *); 106 #endif /* i386 */ 107 108 #else /* __STDC__ */ 109 110 static int scsi_format(); 111 static int scsi_raw_format(); 112 static int scsi_ms_page8(); 113 static int scsi_ms_page38(); 114 static void scsi_convert_list_to_new(); 115 static char *scsi_find_command_name(); 116 static int chg_list_affects_page(); 117 static void scsi_printerr(); 118 static diskaddr_t scsi_extract_sense_info_descr(); 119 static void scsi_print_extended_sense(); 120 static void scsi_print_descr_sense(); 121 122 static int test_until_ready(); 123 124 static int uscsi_reserve_release(); 125 static int check_support_for_defects(); 126 static int scsi_format_without_defects(); 127 static int scsi_ms_page1(); 128 static int scsi_ms_page2(); 129 static int scsi_ms_page3(); 130 static int scsi_ms_page4(); 131 static int scsi_repair(); 132 static int scsi_read_defect_data(); 133 static int scsi_ck_format(); 134 135 #ifdef i386 136 static int scsi_rdwr(int, int, diskaddr_t, int, caddr_t, int, int *); 137 #endif /* i386 */ 138 139 #endif /* __STDC__ */ 140 141 142 143 struct ctlr_ops scsiops = { 144 scsi_rdwr, 145 scsi_ck_format, 146 scsi_format, 147 scsi_ex_man, 148 scsi_ex_cur, 149 scsi_repair, 150 0, 151 }; 152 153 #define SCMD_UNKNOWN 0xff 154 155 /* 156 * Names of commands. Must have SCMD_UNKNOWN at end of list. 157 */ 158 static struct scsi_command_name { 159 uchar_t command; 160 char *name; 161 } scsi_command_names[] = { 162 SCMD_FORMAT, "format", 163 SCMD_READ, "read", 164 SCMD_WRITE, "write", 165 SCMD_READ|SCMD_GROUP1, "read", 166 SCMD_WRITE|SCMD_GROUP1, "write", 167 SCMD_INQUIRY, "inquiry", 168 SCMD_MODE_SELECT, "mode select", 169 SCMD_MODE_SENSE, "mode sense", 170 SCMD_REASSIGN_BLOCK, "reassign block", 171 SCMD_READ_DEFECT_LIST, "read defect list", 172 SCMD_UNKNOWN, "unknown" 173 }; 174 175 176 /* 177 * Strings for printing mode sense page control values 178 */ 179 static slist_t page_control_strings[] = { 180 { "current", "", MODE_SENSE_PC_CURRENT }, 181 { "changeable", "", MODE_SENSE_PC_CHANGEABLE }, 182 { "default", "", MODE_SENSE_PC_DEFAULT }, 183 { "saved", "", MODE_SENSE_PC_SAVED } 184 }; 185 186 /* 187 * Strings for printing the mode select options 188 */ 189 static slist_t mode_select_strings[] = { 190 { "", "", 0 }, 191 { " (pf)", "", MODE_SELECT_PF }, 192 { " (sp)", "", MODE_SELECT_SP }, 193 { " (pf,sp)", "", MODE_SELECT_PF|MODE_SELECT_SP } 194 }; 195 196 static int scsi_format_revolutions = 5; 197 static int scsi_format_timeout = 2*60*60; /* two hours */ 198 199 /* 200 * READ DEFECT DATA commands is optional as per SCSI-2 spec. 201 * Hence check if the read_defect_data command fails with 202 * Invalid Opcode so that we can give a more meaningful message 203 * to the user. 204 */ 205 #define INVALID_OPCODE 0x20 206 207 /* 208 * Read or write the disk. 209 */ 210 int 211 scsi_rdwr(dir, fd, blkno, secnt, bufaddr, flags, xfercntp) 212 int dir; 213 int fd; 214 diskaddr_t blkno; 215 int secnt; 216 caddr_t bufaddr; 217 int flags; 218 int *xfercntp; 219 { 220 struct uscsi_cmd ucmd; 221 union scsi_cdb cdb; 222 int max_sectors; 223 int rc = 0; 224 225 /* 226 * If the max xfercnt hasn't been determined start with BUF_SECTS 227 * (currently 126 == 63K), otherwise use the xfercnt value 228 * my caller saved from the previous invocation. 229 */ 230 if (xfercntp == NULL) { 231 max_sectors = BUF_SECTS; 232 } else if (*xfercntp == 0) { 233 max_sectors = BUF_SECTS; 234 *xfercntp = max_sectors; 235 } else { 236 max_sectors = *xfercntp; 237 } 238 239 /* 240 * Build and execute the uscsi ioctl. We build a group0 241 * or group1 command as necessary, since some targets 242 * do not support group1 commands. 243 */ 244 while (secnt) { 245 int nsectors; 246 247 nsectors = (max_sectors < secnt) ? max_sectors : secnt; 248 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 249 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 250 cdb.scc_cmd = (dir == DIR_READ) ? SCMD_READ : SCMD_WRITE; 251 if (blkno < (2<<20) && nsectors <= 0xff) { 252 FORMG0ADDR(&cdb, blkno); 253 FORMG0COUNT(&cdb, nsectors); 254 ucmd.uscsi_cdblen = CDB_GROUP0; 255 } else { 256 if (blkno > 0xffffffff) { 257 FORMG4LONGADDR(&cdb, blkno); 258 FORMG4COUNT(&cdb, nsectors); 259 ucmd.uscsi_cdblen = CDB_GROUP4; 260 cdb.scc_cmd |= SCMD_GROUP4; 261 } else { 262 FORMG1ADDR(&cdb, blkno); 263 FORMG1COUNT(&cdb, nsectors); 264 ucmd.uscsi_cdblen = CDB_GROUP1; 265 cdb.scc_cmd |= SCMD_GROUP1; 266 } 267 } 268 ucmd.uscsi_cdb = (caddr_t)&cdb; 269 ucmd.uscsi_bufaddr = bufaddr; 270 ucmd.uscsi_buflen = nsectors * SECSIZE; 271 rc = uscsi_cmd(fd, &ucmd, flags); 272 273 if (rc != 0) 274 break; 275 276 /* 277 * check if partial DMA breakup required 278 * if so, reduce the request size by half and retry 279 * the last request 280 */ 281 if (ucmd.uscsi_resid == ucmd.uscsi_buflen) { 282 max_sectors >>= 1; 283 if (max_sectors <= 0) { 284 rc = -1; 285 break; 286 } 287 continue; 288 } 289 if (ucmd.uscsi_resid != 0) { 290 rc = -1; 291 break; 292 } 293 294 blkno += nsectors; 295 secnt -= nsectors; 296 bufaddr += nsectors * SECSIZE; 297 } 298 299 /* 300 * If the xfercnt wasn't previously saved or if the 301 * new value is smaller than the old value, save the 302 * current value in my caller's save area. 303 */ 304 if (xfercntp != NULL && max_sectors < *xfercntp) { 305 if (diag_msg) 306 err_print("reducing xfercnt %d %d\n", 307 *xfercntp, max_sectors); 308 *xfercntp = max_sectors; 309 } 310 return (rc); 311 } 312 313 314 /* 315 * Check to see if the disk has been formatted. 316 * If we are able to read the first track, we conclude that 317 * the disk has been formatted. 318 */ 319 #ifdef i386 320 static int 321 #else /* i386 */ 322 static int 323 #endif /* i386 */ 324 scsi_ck_format(void) 325 { 326 int status; 327 328 /* 329 * Try to read the first four blocks. 330 */ 331 status = scsi_rdwr(DIR_READ, cur_file, 0, 4, (caddr_t)cur_buf, 332 F_SILENT, NULL); 333 return (!status); 334 } 335 336 337 /* 338 * Format the disk, the whole disk, and nothing but the disk. 339 */ 340 /*ARGSUSED*/ 341 static int 342 scsi_format(start, end, list) 343 uint64_t start; /* irrelevant for us */ 344 uint64_t end; 345 struct defect_list *list; 346 { 347 struct uscsi_cmd ucmd; 348 union scsi_cdb cdb; 349 struct scsi_defect_hdr defect_hdr; 350 int status; 351 int flag; 352 struct scsi_inquiry *inq; 353 char rawbuf[MAX_MODE_SENSE_SIZE]; 354 355 /* 356 * Determine if the target appears to be SCSI-2 357 * compliant. We handle mode sense/mode selects 358 * a little differently, depending upon CCS/SCSI-2 359 */ 360 if (uscsi_inquiry(cur_file, rawbuf, sizeof (rawbuf))) { 361 err_print("Inquiry failed\n"); 362 return (-1); 363 } 364 inq = (struct scsi_inquiry *)rawbuf; 365 flag = (inq->inq_rdf == RDF_SCSI2); 366 367 /* 368 * Reserve the scsi disk before performing mode select and 369 * format operations. This will keep other hosts, if any, from 370 * touching the disk while we are here. 371 */ 372 if (uscsi_reserve_release(cur_file, SCMD_RESERVE)) { 373 err_print("Reserve failed\n"); 374 return (-1); 375 } 376 377 /* 378 * Set up the various SCSI parameters specified before 379 * formatting the disk. Each routine handles the 380 * parameters relevant to a particular page. 381 * If no parameters are specified for a page, there's 382 * no need to do anything. Otherwise, issue a mode 383 * sense for that page. If a specified parameter 384 * differs from the drive's default value, and that 385 * parameter is not fixed, then issue a mode select to 386 * set the default value for the disk as specified 387 * in format.dat. 388 */ 389 if (scsi_ms_page1(flag) || scsi_ms_page2(flag) || 390 scsi_ms_page4(flag) || scsi_ms_page38(flag) || 391 scsi_ms_page8(flag) || scsi_ms_page3(flag)) { 392 (void) uscsi_reserve_release(cur_file, SCMD_RELEASE); 393 return (-1); 394 } 395 396 /* 397 * If we're debugging the drive, dump every page 398 * the device supports, for thorough analysis. 399 */ 400 if (option_msg && diag_msg) { 401 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_DEFAULT); 402 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CURRENT); 403 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_SAVED); 404 (void) scsi_dump_mode_sense_pages(MODE_SENSE_PC_CHANGEABLE); 405 err_print("\n"); 406 } 407 408 /* 409 * Construct the uscsi format ioctl. The form depends 410 * upon the defect list the user extracted. If s/he 411 * extracted the "original" list, we format with only 412 * the P (manufacturer's defect) list. Otherwise, we 413 * format with both the P and the G (grown) list. 414 * To format with the P and G list, we set the fmtData 415 * bit, and send an empty list. To format with the 416 * P list only, we also set the cmpLst bit, meaning 417 * that the (empty) list we send down is the complete 418 * G list, thereby discarding the old G list.. 419 */ 420 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 421 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 422 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 423 424 cdb.scc_cmd = SCMD_FORMAT; 425 ucmd.uscsi_cdb = (caddr_t)&cdb; 426 ucmd.uscsi_cdblen = CDB_GROUP0; 427 ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr; 428 ucmd.uscsi_buflen = sizeof (defect_hdr); 429 cdb.cdb_opaque[1] = FPB_DATA; 430 defect_hdr.descriptor = FDH_FOV | FDH_IMMED; 431 432 if ((list->list != NULL) && ((list->flags & LIST_PGLIST) == 0)) { 433 /* 434 * No G list. The empty list we send down 435 * is the complete list. 436 */ 437 cdb.cdb_opaque[1] |= FPB_CMPLT; 438 } 439 440 /* 441 * Issue the format ioctl 442 */ 443 fmt_print("Formatting...\n"); 444 (void) fflush(stdout); 445 status = uscsi_cmd(cur_file, &ucmd, 446 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 447 448 /* check if format with immed was successfully accepted */ 449 if (status == 0) { 450 /* immed accepted pool to completion */ 451 status = test_until_ready(cur_file); 452 } else { 453 /* clear defect header and try basecase format */ 454 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 455 status = uscsi_cmd(cur_file, &ucmd, 456 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 457 } 458 459 /* format failure check */ 460 if (status != 0) { 461 /* 462 * formatting failed with fmtdata = 1. 463 * Check if defects list command is supported, if it 464 * is not supported then use fmtdata = 0. 465 * From SCSI Spec 466 * A FmtData bit of zero indicates, the 467 * source of defect information is not specified. 468 * else 469 * proceed to format using with mode selects. 470 */ 471 if (!(check_support_for_defects())) { 472 status = scsi_format_without_defects(); 473 } 474 475 if (status != 0) { 476 fmt_print("Format failed\n"); 477 status = scsi_raw_format(); 478 } 479 } 480 (void) uscsi_reserve_release(cur_file, SCMD_RELEASE); 481 return (status); 482 } 483 484 /* 485 * Format without any of the standard mode selects ignoring Grown defects list. 486 */ 487 static int 488 scsi_raw_format(void) 489 { 490 struct uscsi_cmd ucmd; 491 union scsi_cdb cdb; 492 struct scsi_defect_hdr defect_hdr; 493 int status; 494 495 fmt_print("\n" 496 "Retry of formatting operation without any of the standard\n" 497 "mode selects and ignoring disk's Grown Defects list. The\n" 498 "disk may be able to be reformatted this way if an earlier\n" 499 "formatting operation was interrupted by a power failure or\n" 500 "SCSI bus reset. The Grown Defects list will be recreated\n" 501 "by format verification and surface analysis.\n\n"); 502 503 if (check("Retry format without mode selects and Grown Defects list") 504 != 0) { 505 return (-1); 506 } 507 508 /* 509 * Construct the uscsi format ioctl. 510 * To format with the P and G list, we set the fmtData 511 * and cmpLst bits to zero. To format with just the 512 * P list, we set the fmtData bit (meaning that we will 513 * send down a defect list in the data phase) and the 514 * cmpLst bit (meaning that the list we send is the 515 * complete G list), and a defect list header with 516 * a defect list length of zero. 517 */ 518 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 519 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 520 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 521 522 cdb.scc_cmd = SCMD_FORMAT; 523 ucmd.uscsi_cdb = (caddr_t)&cdb; 524 ucmd.uscsi_cdblen = CDB_GROUP0; 525 /* No G list. Send empty defect list to replace it */ 526 cdb.cdb_opaque[1] = FPB_DATA | FPB_CMPLT | FPB_BFI; 527 ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr; 528 ucmd.uscsi_buflen = sizeof (defect_hdr); 529 defect_hdr.descriptor = FDH_FOV | FDH_IMMED; 530 531 /* 532 * Issue the format ioctl 533 */ 534 fmt_print("Formatting...\n"); 535 (void) fflush(stdout); 536 status = uscsi_cmd(cur_file, &ucmd, F_NORMAL); 537 538 /* check if format with immed was successfully accepted */ 539 if (status == 0) { 540 /* immed accepted pool to completion */ 541 status = test_until_ready(cur_file); 542 } else { 543 /* clear defect header and try basecase format */ 544 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 545 status = uscsi_cmd(cur_file, &ucmd, F_NORMAL); 546 } 547 548 /* fmt_print(status ? "Format failed\n\n" : "Format ok\n\n"); */ 549 return (status); 550 } 551 552 /* 553 * Estimate the time required for format operation (See 1163770). 554 * format time = (5_revs * p4_heads * p4_cylinders) / p4_rpm 555 * 5 revolutions (correspond to format_time keyword in format.dat file) are: 556 * 1 rev. for positioning 557 * 2 rev. for writing the track 558 * 1 rev. for positioning 559 * 1 rev. for cerifying the data integrity of the track 560 * The return value is a good estimate on the formatting time in minutes. 561 * Caller should add 50% margin to cover defect management overhead. 562 */ 563 int 564 scsi_format_time() 565 { 566 struct mode_geometry *page4; 567 struct scsi_ms_header header; 568 int status; 569 int p4_cylinders, p4_heads, p4_rpm; 570 int length; 571 int format_time; 572 union { 573 struct mode_geometry page4; 574 char rawbuf[MAX_MODE_SENSE_SIZE]; 575 } u_page4; 576 577 578 page4 = &u_page4.page4; 579 (void) memset(&u_page4, 0, sizeof (u_page4)); 580 581 /* 582 * Issue a mode sense to determine the default parameters 583 * If it fail, try to use the saved or current instead. 584 */ 585 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 586 MODE_SENSE_PC_DEFAULT, (caddr_t)page4, 587 MAX_MODE_SENSE_SIZE, &header); 588 589 if (status) { 590 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 591 MODE_SENSE_PC_SAVED, (caddr_t)page4, 592 MAX_MODE_SENSE_SIZE, &header); 593 } 594 if (status) { 595 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 596 MODE_SENSE_PC_CURRENT, (caddr_t)page4, 597 MAX_MODE_SENSE_SIZE, &header); 598 } 599 if (status) { 600 return (0); 601 } 602 603 /* 604 * We only need the common subset between the CCS 605 * and SCSI-2 structures, so we can treat both 606 * cases identically. 607 */ 608 length = MODESENSE_PAGE_LEN(page4); 609 if (length < MIN_PAGE4_LEN) { 610 return (0); 611 } 612 613 page4->rpm = BE_16(page4->rpm); 614 p4_cylinders = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + 615 page4->cyl_lb; 616 p4_heads = page4->heads; 617 p4_rpm = page4->rpm; 618 619 /* 620 * Some drives report 0 for page4->rpm, adjust it to AVG_RPM, 3600. 621 */ 622 if (p4_rpm < MIN_RPM || p4_rpm > MAX_RPM) { 623 err_print("Mode sense page(4) reports rpm value as %d," 624 " adjusting it to %d\n", p4_rpm, AVG_RPM); 625 p4_rpm = AVG_RPM; 626 } 627 628 if (p4_cylinders <= 0 || p4_heads <= 0) 629 return (0); 630 631 format_time = ((scsi_format_revolutions * p4_heads * 632 p4_cylinders) + p4_rpm) / p4_rpm; 633 634 if (option_msg && diag_msg) { 635 err_print(" pcyl: %d\n", p4_cylinders); 636 err_print(" heads: %d\n", p4_heads); 637 err_print(" rpm: %d\n", p4_rpm); 638 err_print("format_time: %d minutes\n", format_time); 639 } 640 return (format_time); 641 } 642 643 /* 644 * Check disk error recovery parameters via mode sense. 645 * Issue a mode select if we need to change something. 646 */ 647 /*ARGSUSED*/ 648 static int 649 scsi_ms_page1(scsi2_flag) 650 int scsi2_flag; 651 { 652 struct mode_err_recov *page1; 653 struct mode_err_recov *fixed; 654 struct scsi_ms_header header; 655 struct scsi_ms_header fixed_hdr; 656 int status; 657 int tmp1, tmp2; 658 int flag; 659 int length; 660 int sp_flags; 661 union { 662 struct mode_err_recov page1; 663 char rawbuf[MAX_MODE_SENSE_SIZE]; 664 } u_page1, u_fixed; 665 666 667 page1 = &u_page1.page1; 668 fixed = &u_fixed.page1; 669 670 /* 671 * If debugging, issue mode senses on the default and 672 * current values. 673 */ 674 if (option_msg && diag_msg) { 675 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 676 MODE_SENSE_PC_DEFAULT, (caddr_t)page1, 677 MAX_MODE_SENSE_SIZE, &header); 678 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 679 MODE_SENSE_PC_CURRENT, (caddr_t)page1, 680 MAX_MODE_SENSE_SIZE, &header); 681 } 682 683 /* 684 * Issue a mode sense to determine the saved parameters 685 * If the saved values fail, use the current instead. 686 */ 687 status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 688 MODE_SENSE_PC_SAVED, (caddr_t)page1, 689 MAX_MODE_SENSE_SIZE, &header); 690 if (status) { 691 status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 692 MODE_SENSE_PC_CURRENT, (caddr_t)page1, 693 MAX_MODE_SENSE_SIZE, &header); 694 if (status) { 695 return (0); 696 } 697 } 698 699 /* 700 * We only need the common subset between the CCS 701 * and SCSI-2 structures, so we can treat both 702 * cases identically. Whatever the drive gives 703 * us, we return to the drive in the mode select, 704 * delta'ed by whatever we want to change. 705 */ 706 length = MODESENSE_PAGE_LEN(page1); 707 if (length < MIN_PAGE1_LEN) { 708 return (0); 709 } 710 711 /* 712 * Ask for changeable parameters. 713 */ 714 status = uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 715 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 716 MAX_MODE_SENSE_SIZE, &fixed_hdr); 717 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE1_LEN) { 718 return (0); 719 } 720 721 /* 722 * We need to issue a mode select only if one or more 723 * parameters need to be changed, and those parameters 724 * are flagged by the drive as changeable. 725 */ 726 flag = 0; 727 tmp1 = page1->read_retry_count; 728 tmp2 = page1->write_retry_count; 729 if (cur_dtype->dtype_options & SUP_READ_RETRIES && 730 fixed->read_retry_count != 0) { 731 flag |= (page1->read_retry_count != 732 cur_dtype->dtype_read_retries); 733 page1->read_retry_count = cur_dtype->dtype_read_retries; 734 } 735 if (length > 8) { 736 if (cur_dtype->dtype_options & SUP_WRITE_RETRIES && 737 fixed->write_retry_count != 0) { 738 flag |= (page1->write_retry_count != 739 cur_dtype->dtype_write_retries); 740 page1->write_retry_count = 741 cur_dtype->dtype_write_retries; 742 } 743 } 744 /* 745 * Report any changes so far... 746 */ 747 if (flag && option_msg) { 748 fmt_print( 749 "PAGE 1: read retries= %d (%d) write retries= %d (%d)\n", 750 page1->read_retry_count, tmp1, 751 page1->write_retry_count, tmp2); 752 } 753 /* 754 * Apply any changes requested via the change list method 755 */ 756 flag |= apply_chg_list(DAD_MODE_ERR_RECOV, length, 757 (uchar_t *)page1, (uchar_t *)fixed, 758 cur_dtype->dtype_chglist); 759 /* 760 * If no changes required, do not issue a mode select 761 */ 762 if (flag == 0) { 763 return (0); 764 } 765 /* 766 * We always want to set the Page Format bit for mode 767 * selects. Set the Save Page bit if the drive indicates 768 * that it can save this page via the mode sense. 769 */ 770 sp_flags = MODE_SELECT_PF; 771 if (page1->mode_page.ps) { 772 sp_flags |= MODE_SELECT_SP; 773 } 774 page1->mode_page.ps = 0; 775 header.mode_header.length = 0; 776 header.mode_header.device_specific = 0; 777 status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV, 778 sp_flags, (caddr_t)page1, length, &header); 779 if (status && (sp_flags & MODE_SELECT_SP)) { 780 /* If failed, try not saving mode select params. */ 781 sp_flags &= ~MODE_SELECT_SP; 782 status = uscsi_mode_select(cur_file, DAD_MODE_ERR_RECOV, 783 sp_flags, (caddr_t)page1, length, &header); 784 } 785 if (status && option_msg) { 786 err_print("\ 787 Warning: Using default error recovery parameters.\n\n"); 788 } 789 790 /* 791 * If debugging, issue mode senses on the current and 792 * saved values, so we can see the result of the mode 793 * selects. 794 */ 795 if (option_msg && diag_msg) { 796 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 797 MODE_SENSE_PC_CURRENT, (caddr_t)page1, 798 MAX_MODE_SENSE_SIZE, &header); 799 (void) uscsi_mode_sense(cur_file, DAD_MODE_ERR_RECOV, 800 MODE_SENSE_PC_SAVED, (caddr_t)page1, 801 MAX_MODE_SENSE_SIZE, &header); 802 } 803 804 return (0); 805 } 806 807 /* 808 * Check disk disconnect/reconnect parameters via mode sense. 809 * Issue a mode select if we need to change something. 810 */ 811 /*ARGSUSED*/ 812 static int 813 scsi_ms_page2(scsi2_flag) 814 int scsi2_flag; 815 { 816 struct mode_disco_reco *page2; 817 struct mode_disco_reco *fixed; 818 struct scsi_ms_header header; 819 struct scsi_ms_header fixed_hdr; 820 int status; 821 int flag; 822 int length; 823 int sp_flags; 824 union { 825 struct mode_disco_reco page2; 826 char rawbuf[MAX_MODE_SENSE_SIZE]; 827 } u_page2, u_fixed; 828 829 page2 = &u_page2.page2; 830 fixed = &u_fixed.page2; 831 832 /* 833 * If debugging, issue mode senses on the default and 834 * current values. 835 */ 836 if (option_msg && diag_msg) { 837 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 838 MODE_SENSE_PC_DEFAULT, (caddr_t)page2, 839 MAX_MODE_SENSE_SIZE, &header); 840 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 841 MODE_SENSE_PC_CURRENT, (caddr_t)page2, 842 MAX_MODE_SENSE_SIZE, &header); 843 } 844 845 /* 846 * Issue a mode sense to determine the saved parameters 847 * If the saved values fail, use the current instead. 848 */ 849 status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 850 MODE_SENSE_PC_SAVED, (caddr_t)page2, 851 MAX_MODE_SENSE_SIZE, &header); 852 if (status) { 853 status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 854 MODE_SENSE_PC_CURRENT, (caddr_t)page2, 855 MAX_MODE_SENSE_SIZE, &header); 856 if (status) { 857 return (0); 858 } 859 } 860 861 /* 862 * We only need the common subset between the CCS 863 * and SCSI-2 structures, so we can treat both 864 * cases identically. Whatever the drive gives 865 * us, we return to the drive in the mode select, 866 * delta'ed by whatever we want to change. 867 */ 868 length = MODESENSE_PAGE_LEN(page2); 869 if (length < MIN_PAGE2_LEN) { 870 return (0); 871 } 872 873 /* 874 * Ask for changeable parameters. 875 */ 876 status = uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 877 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 878 MAX_MODE_SENSE_SIZE, &fixed_hdr); 879 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE2_LEN) { 880 return (0); 881 } 882 883 /* 884 * We need to issue a mode select only if one or more 885 * parameters need to be changed, and those parameters 886 * are flagged by the drive as changeable. 887 */ 888 flag = 0; 889 /* 890 * Apply any changes requested via the change list method 891 */ 892 flag |= apply_chg_list(MODEPAGE_DISCO_RECO, length, 893 (uchar_t *)page2, (uchar_t *)fixed, 894 cur_dtype->dtype_chglist); 895 /* 896 * If no changes required, do not issue a mode select 897 */ 898 if (flag == 0) { 899 return (0); 900 } 901 /* 902 * We always want to set the Page Format bit for mode 903 * selects. Set the Save Page bit if the drive indicates 904 * that it can save this page via the mode sense. 905 */ 906 sp_flags = MODE_SELECT_PF; 907 if (page2->mode_page.ps) { 908 sp_flags |= MODE_SELECT_SP; 909 } 910 page2->mode_page.ps = 0; 911 header.mode_header.length = 0; 912 header.mode_header.device_specific = 0; 913 status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO, 914 MODE_SELECT_SP, (caddr_t)page2, length, &header); 915 if (status && (sp_flags & MODE_SELECT_SP)) { 916 /* If failed, try not saving mode select params. */ 917 sp_flags &= ~MODE_SELECT_SP; 918 status = uscsi_mode_select(cur_file, MODEPAGE_DISCO_RECO, 919 sp_flags, (caddr_t)page2, length, &header); 920 } 921 if (status && option_msg) { 922 err_print("Warning: Using default .\n\n"); 923 } 924 925 /* 926 * If debugging, issue mode senses on the current and 927 * saved values, so we can see the result of the mode 928 * selects. 929 */ 930 if (option_msg && diag_msg) { 931 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 932 MODE_SENSE_PC_CURRENT, (caddr_t)page2, 933 MAX_MODE_SENSE_SIZE, &header); 934 (void) uscsi_mode_sense(cur_file, MODEPAGE_DISCO_RECO, 935 MODE_SENSE_PC_SAVED, (caddr_t)page2, 936 MAX_MODE_SENSE_SIZE, &header); 937 } 938 939 return (0); 940 } 941 942 /* 943 * Check disk format parameters via mode sense. 944 * Issue a mode select if we need to change something. 945 */ 946 /*ARGSUSED*/ 947 static int 948 scsi_ms_page3(scsi2_flag) 949 int scsi2_flag; 950 { 951 struct mode_format *page3; 952 struct mode_format *fixed; 953 struct scsi_ms_header header; 954 struct scsi_ms_header fixed_hdr; 955 int status; 956 int tmp1, tmp2, tmp3; 957 int tmp4, tmp5, tmp6; 958 int flag; 959 int length; 960 int sp_flags; 961 union { 962 struct mode_format page3; 963 char rawbuf[MAX_MODE_SENSE_SIZE]; 964 } u_page3, u_fixed; 965 966 967 page3 = &u_page3.page3; 968 fixed = &u_fixed.page3; 969 970 /* 971 * If debugging, issue mode senses on the default and 972 * current values. 973 */ 974 if (option_msg && diag_msg) { 975 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 976 MODE_SENSE_PC_DEFAULT, (caddr_t)page3, 977 MAX_MODE_SENSE_SIZE, &header); 978 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 979 MODE_SENSE_PC_CURRENT, (caddr_t)page3, 980 MAX_MODE_SENSE_SIZE, &header); 981 } 982 983 /* 984 * Issue a mode sense to determine the saved parameters 985 * If the saved values fail, use the current instead. 986 */ 987 status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 988 MODE_SENSE_PC_SAVED, (caddr_t)page3, 989 MAX_MODE_SENSE_SIZE, &header); 990 if (status) { 991 status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 992 MODE_SENSE_PC_CURRENT, (caddr_t)page3, 993 MAX_MODE_SENSE_SIZE, &header); 994 if (status) { 995 return (0); 996 } 997 } 998 999 /* 1000 * We only need the common subset between the CCS 1001 * and SCSI-2 structures, so we can treat both 1002 * cases identically. Whatever the drive gives 1003 * us, we return to the drive in the mode select, 1004 * delta'ed by whatever we want to change. 1005 */ 1006 length = MODESENSE_PAGE_LEN(page3); 1007 if (length < MIN_PAGE3_LEN) { 1008 return (0); 1009 } 1010 1011 /* 1012 * Ask for changeable parameters. 1013 */ 1014 status = uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 1015 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 1016 MAX_MODE_SENSE_SIZE, &fixed_hdr); 1017 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE3_LEN) { 1018 return (0); 1019 } 1020 1021 /* 1022 * We need to issue a mode select only if one or more 1023 * parameters need to be changed, and those parameters 1024 * are flagged by the drive as changeable. 1025 */ 1026 tmp1 = page3->track_skew; 1027 tmp2 = page3->cylinder_skew; 1028 tmp3 = page3->sect_track; 1029 tmp4 = page3->tracks_per_zone; 1030 tmp5 = page3->alt_tracks_vol; 1031 tmp6 = page3->alt_sect_zone; 1032 1033 flag = (page3->data_bytes_sect != SECSIZE); 1034 page3->data_bytes_sect = SECSIZE; 1035 1036 flag |= (page3->interleave != 1); 1037 page3->interleave = 1; 1038 1039 if (cur_dtype->dtype_options & SUP_CYLSKEW && 1040 fixed->cylinder_skew != 0) { 1041 flag |= (page3->cylinder_skew != cur_dtype->dtype_cyl_skew); 1042 page3->cylinder_skew = cur_dtype->dtype_cyl_skew; 1043 } 1044 if (cur_dtype->dtype_options & SUP_TRKSKEW && 1045 fixed->track_skew != 0) { 1046 flag |= (page3->track_skew != cur_dtype->dtype_trk_skew); 1047 page3->track_skew = cur_dtype->dtype_trk_skew; 1048 } 1049 if (cur_dtype->dtype_options & SUP_PSECT && 1050 fixed->sect_track != 0) { 1051 flag |= (page3->sect_track != psect); 1052 page3->sect_track = (ushort_t)psect; 1053 } 1054 if (cur_dtype->dtype_options & SUP_TRKS_ZONE && 1055 fixed->tracks_per_zone != 0) { 1056 flag |= (page3->tracks_per_zone != cur_dtype->dtype_trks_zone); 1057 page3->tracks_per_zone = cur_dtype->dtype_trks_zone; 1058 } 1059 if (cur_dtype->dtype_options & SUP_ASECT && 1060 fixed->alt_sect_zone != 0) { 1061 flag |= (page3->alt_sect_zone != cur_dtype->dtype_asect); 1062 page3->alt_sect_zone = cur_dtype->dtype_asect; 1063 } 1064 if (cur_dtype->dtype_options & SUP_ATRKS && 1065 fixed->alt_tracks_vol != 0) { 1066 flag |= (page3->alt_tracks_vol != cur_dtype->dtype_atrks); 1067 page3->alt_tracks_vol = cur_dtype->dtype_atrks; 1068 } 1069 /* 1070 * Notify user of any changes so far 1071 */ 1072 if (flag && option_msg) { 1073 fmt_print("PAGE 3: trk skew= %d (%d) cyl skew= %d (%d) ", 1074 page3->track_skew, tmp1, page3->cylinder_skew, tmp2); 1075 fmt_print("sects/trk= %d (%d)\n", page3->sect_track, tmp3); 1076 fmt_print(" trks/zone= %d (%d) alt trks= %d (%d) ", 1077 page3->tracks_per_zone, tmp4, 1078 page3->alt_tracks_vol, tmp5); 1079 fmt_print("alt sects/zone= %d (%d)\n", 1080 page3->alt_sect_zone, tmp6); 1081 } 1082 /* 1083 * Apply any changes requested via the change list method 1084 */ 1085 flag |= apply_chg_list(DAD_MODE_FORMAT, length, 1086 (uchar_t *)page3, (uchar_t *)fixed, 1087 cur_dtype->dtype_chglist); 1088 /* 1089 * If no changes required, do not issue a mode select 1090 */ 1091 if (flag == 0) { 1092 return (0); 1093 } 1094 /* 1095 * Issue a mode select 1096 */ 1097 /* 1098 * We always want to set the Page Format bit for mode 1099 * selects. Set the Save Page bit if the drive indicates 1100 * that it can save this page via the mode sense. 1101 */ 1102 sp_flags = MODE_SELECT_PF; 1103 if (page3->mode_page.ps) { 1104 sp_flags |= MODE_SELECT_SP; 1105 } 1106 page3->mode_page.ps = 0; 1107 header.mode_header.length = 0; 1108 header.mode_header.device_specific = 0; 1109 status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT, 1110 MODE_SELECT_SP, (caddr_t)page3, length, &header); 1111 if (status && (sp_flags & MODE_SELECT_SP)) { 1112 /* If failed, try not saving mode select params. */ 1113 sp_flags &= ~MODE_SELECT_SP; 1114 status = uscsi_mode_select(cur_file, DAD_MODE_FORMAT, 1115 sp_flags, (caddr_t)page3, length, &header); 1116 } 1117 if (status && option_msg) { 1118 err_print("Warning: Using default drive format parameters.\n"); 1119 err_print("Warning: Drive format may not be correct.\n\n"); 1120 } 1121 1122 /* 1123 * If debugging, issue mode senses on the current and 1124 * saved values, so we can see the result of the mode 1125 * selects. 1126 */ 1127 if (option_msg && diag_msg) { 1128 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 1129 MODE_SENSE_PC_CURRENT, (caddr_t)page3, 1130 MAX_MODE_SENSE_SIZE, &header); 1131 (void) uscsi_mode_sense(cur_file, DAD_MODE_FORMAT, 1132 MODE_SENSE_PC_SAVED, (caddr_t)page3, 1133 MAX_MODE_SENSE_SIZE, &header); 1134 } 1135 1136 return (0); 1137 } 1138 1139 /* 1140 * Check disk geometry parameters via mode sense. 1141 * Issue a mode select if we need to change something. 1142 */ 1143 /*ARGSUSED*/ 1144 static int 1145 scsi_ms_page4(scsi2_flag) 1146 int scsi2_flag; 1147 { 1148 struct mode_geometry *page4; 1149 struct mode_geometry *fixed; 1150 struct scsi_ms_header header; 1151 struct scsi_ms_header fixed_hdr; 1152 int status; 1153 int tmp1, tmp2; 1154 int flag; 1155 int length; 1156 int sp_flags; 1157 union { 1158 struct mode_geometry page4; 1159 char rawbuf[MAX_MODE_SENSE_SIZE]; 1160 } u_page4, u_fixed; 1161 1162 page4 = &u_page4.page4; 1163 fixed = &u_fixed.page4; 1164 1165 /* 1166 * If debugging, issue mode senses on the default and 1167 * current values. 1168 */ 1169 if (option_msg && diag_msg) { 1170 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1171 MODE_SENSE_PC_DEFAULT, (caddr_t)page4, 1172 MAX_MODE_SENSE_SIZE, &header); 1173 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1174 MODE_SENSE_PC_CURRENT, (caddr_t)page4, 1175 MAX_MODE_SENSE_SIZE, &header); 1176 } 1177 1178 /* 1179 * Issue a mode sense to determine the saved parameters 1180 * If the saved values fail, use the current instead. 1181 */ 1182 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1183 MODE_SENSE_PC_SAVED, (caddr_t)page4, 1184 MAX_MODE_SENSE_SIZE, &header); 1185 if (status) { 1186 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1187 MODE_SENSE_PC_CURRENT, (caddr_t)page4, 1188 MAX_MODE_SENSE_SIZE, &header); 1189 if (status) { 1190 return (0); 1191 } 1192 } 1193 1194 /* 1195 * We only need the common subset between the CCS 1196 * and SCSI-2 structures, so we can treat both 1197 * cases identically. Whatever the drive gives 1198 * us, we return to the drive in the mode select, 1199 * delta'ed by whatever we want to change. 1200 */ 1201 length = MODESENSE_PAGE_LEN(page4); 1202 if (length < MIN_PAGE4_LEN) { 1203 return (0); 1204 } 1205 1206 /* 1207 * Ask for changeable parameters. 1208 */ 1209 status = uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1210 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 1211 MAX_MODE_SENSE_SIZE, &fixed_hdr); 1212 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE4_LEN) { 1213 return (0); 1214 } 1215 1216 /* 1217 * We need to issue a mode select only if one or more 1218 * parameters need to be changed, and those parameters 1219 * are flagged by the drive as changeable. 1220 */ 1221 tmp1 = (page4->cyl_ub << 16) + (page4->cyl_mb << 8) + page4->cyl_lb; 1222 tmp2 = page4->heads; 1223 1224 flag = 0; 1225 if ((cur_dtype->dtype_options & SUP_PHEAD) && fixed->heads != 0) { 1226 flag |= (page4->heads != phead); 1227 page4->heads = phead; 1228 } 1229 /* 1230 * Notify user of changes so far 1231 */ 1232 if (flag && option_msg) { 1233 fmt_print("PAGE 4: cylinders= %d heads= %d (%d)\n", 1234 tmp1, page4->heads, tmp2); 1235 } 1236 /* 1237 * Apply any changes requested via the change list method 1238 */ 1239 flag |= apply_chg_list(DAD_MODE_GEOMETRY, length, 1240 (uchar_t *)page4, (uchar_t *)fixed, 1241 cur_dtype->dtype_chglist); 1242 /* 1243 * If no changes required, do not issue a mode select 1244 */ 1245 if (flag == 0) { 1246 return (0); 1247 } 1248 /* 1249 * Issue a mode select 1250 */ 1251 /* 1252 * We always want to set the Page Format bit for mode 1253 * selects. Set the Save Page bit if the drive indicates 1254 * that it can save this page via the mode sense. 1255 */ 1256 sp_flags = MODE_SELECT_PF; 1257 if (page4->mode_page.ps) { 1258 sp_flags |= MODE_SELECT_SP; 1259 } 1260 page4->mode_page.ps = 0; 1261 header.mode_header.length = 0; 1262 header.mode_header.device_specific = 0; 1263 status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY, 1264 MODE_SELECT_SP, (caddr_t)page4, length, &header); 1265 if (status && (sp_flags & MODE_SELECT_SP)) { 1266 /* If failed, try not saving mode select params. */ 1267 sp_flags &= ~MODE_SELECT_SP; 1268 status = uscsi_mode_select(cur_file, DAD_MODE_GEOMETRY, 1269 sp_flags, (caddr_t)page4, length, &header); 1270 } 1271 if (status && option_msg) { 1272 err_print("Warning: Using default drive geometry.\n\n"); 1273 } 1274 1275 /* 1276 * If debugging, issue mode senses on the current and 1277 * saved values, so we can see the result of the mode 1278 * selects. 1279 */ 1280 if (option_msg && diag_msg) { 1281 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1282 MODE_SENSE_PC_CURRENT, (caddr_t)page4, 1283 MAX_MODE_SENSE_SIZE, &header); 1284 (void) uscsi_mode_sense(cur_file, DAD_MODE_GEOMETRY, 1285 MODE_SENSE_PC_SAVED, (caddr_t)page4, 1286 MAX_MODE_SENSE_SIZE, &header); 1287 } 1288 1289 return (0); 1290 } 1291 1292 /* 1293 * Check SCSI-2 disk cache parameters via mode sense. 1294 * Issue a mode select if we need to change something. 1295 */ 1296 /*ARGSUSED*/ 1297 static int 1298 scsi_ms_page8(scsi2_flag) 1299 int scsi2_flag; 1300 { 1301 struct mode_cache *page8; 1302 struct mode_cache *fixed; 1303 struct scsi_ms_header header; 1304 struct scsi_ms_header fixed_hdr; 1305 int status; 1306 int flag; 1307 int length; 1308 int sp_flags; 1309 union { 1310 struct mode_cache page8; 1311 char rawbuf[MAX_MODE_SENSE_SIZE]; 1312 } u_page8, u_fixed; 1313 1314 page8 = &u_page8.page8; 1315 fixed = &u_fixed.page8; 1316 1317 /* 1318 * Only SCSI-2 devices support this page 1319 */ 1320 if (!scsi2_flag) { 1321 return (0); 1322 } 1323 1324 /* 1325 * If debugging, issue mode senses on the default and 1326 * current values. 1327 */ 1328 if (option_msg && diag_msg) { 1329 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1330 MODE_SENSE_PC_DEFAULT, (caddr_t)page8, 1331 MAX_MODE_SENSE_SIZE, &header); 1332 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1333 MODE_SENSE_PC_CURRENT, (caddr_t)page8, 1334 MAX_MODE_SENSE_SIZE, &header); 1335 } 1336 1337 /* 1338 * Issue a mode sense to determine the saved parameters 1339 * If the saved values fail, use the current instead. 1340 */ 1341 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1342 MODE_SENSE_PC_SAVED, (caddr_t)page8, 1343 MAX_MODE_SENSE_SIZE, &header); 1344 if (status) { 1345 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1346 MODE_SENSE_PC_CURRENT, (caddr_t)page8, 1347 MAX_MODE_SENSE_SIZE, &header); 1348 if (status) { 1349 return (0); 1350 } 1351 } 1352 1353 /* 1354 * We only need the common subset between the CCS 1355 * and SCSI-2 structures, so we can treat both 1356 * cases identically. Whatever the drive gives 1357 * us, we return to the drive in the mode select, 1358 * delta'ed by whatever we want to change. 1359 */ 1360 length = MODESENSE_PAGE_LEN(page8); 1361 if (length < MIN_PAGE8_LEN) { 1362 return (0); 1363 } 1364 1365 /* 1366 * Ask for changeable parameters. 1367 */ 1368 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1369 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 1370 MAX_MODE_SENSE_SIZE, &fixed_hdr); 1371 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE8_LEN) { 1372 return (0); 1373 } 1374 1375 /* 1376 * We need to issue a mode select only if one or more 1377 * parameters need to be changed, and those parameters 1378 * are flagged by the drive as changeable. 1379 */ 1380 flag = 0; 1381 /* 1382 * Apply any changes requested via the change list method 1383 */ 1384 flag |= apply_chg_list(DAD_MODE_CACHE, length, 1385 (uchar_t *)page8, (uchar_t *)fixed, 1386 cur_dtype->dtype_chglist); 1387 /* 1388 * If no changes required, do not issue a mode select 1389 */ 1390 if (flag == 0) { 1391 return (0); 1392 } 1393 /* 1394 * Issue a mode select 1395 */ 1396 /* 1397 * We always want to set the Page Format bit for mode 1398 * selects. Set the Save Page bit if the drive indicates 1399 * that it can save this page via the mode sense. 1400 */ 1401 sp_flags = MODE_SELECT_PF; 1402 if (page8->mode_page.ps) { 1403 sp_flags |= MODE_SELECT_SP; 1404 } 1405 page8->mode_page.ps = 0; 1406 header.mode_header.length = 0; 1407 header.mode_header.device_specific = 0; 1408 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE, 1409 sp_flags, (caddr_t)page8, length, &header); 1410 if (status && (sp_flags & MODE_SELECT_SP)) { 1411 /* If failed, try not saving mode select params. */ 1412 sp_flags &= ~MODE_SELECT_SP; 1413 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE, 1414 sp_flags, (caddr_t)page8, length, &header); 1415 } 1416 if (status && option_msg) { 1417 err_print("\ 1418 Warning: Using default SCSI-2 cache parameters.\n\n"); 1419 } 1420 1421 /* 1422 * If debugging, issue mode senses on the current and 1423 * saved values, so we can see the result of the mode 1424 * selects. 1425 */ 1426 if (option_msg && diag_msg) { 1427 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1428 MODE_SENSE_PC_CURRENT, (caddr_t)page8, 1429 MAX_MODE_SENSE_SIZE, &header); 1430 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE, 1431 MODE_SENSE_PC_SAVED, (caddr_t)page8, 1432 MAX_MODE_SENSE_SIZE, &header); 1433 } 1434 1435 return (0); 1436 } 1437 1438 /* 1439 * Check CCS disk cache parameters via mode sense. 1440 * Issue a mode select if we need to change something. 1441 */ 1442 /*ARGSUSED*/ 1443 static int 1444 scsi_ms_page38(scsi2_flag) 1445 int scsi2_flag; 1446 { 1447 struct mode_cache_ccs *page38; 1448 struct mode_cache_ccs *fixed; 1449 struct scsi_ms_header header; 1450 struct scsi_ms_header fixed_hdr; 1451 int status; 1452 int tmp1, tmp2, tmp3, tmp4; 1453 int flag; 1454 int length; 1455 int sp_flags; 1456 union { 1457 struct mode_cache_ccs page38; 1458 char rawbuf[MAX_MODE_SENSE_SIZE]; 1459 } u_page38, u_fixed; 1460 1461 /* 1462 * First, determine if we need to look at page 38 at all. 1463 * Not all devices support it. 1464 */ 1465 if (((cur_dtype->dtype_options & (SUP_CACHE | SUP_PREFETCH | 1466 SUP_CACHE_MIN | SUP_CACHE_MAX)) == 0) && 1467 (!chg_list_affects_page(cur_dtype->dtype_chglist, 1468 0x38))) { 1469 return (0); 1470 } 1471 1472 page38 = &u_page38.page38; 1473 fixed = &u_fixed.page38; 1474 1475 /* 1476 * If debugging, issue mode senses on the default and 1477 * current values. 1478 */ 1479 if (option_msg && diag_msg) { 1480 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1481 MODE_SENSE_PC_DEFAULT, (caddr_t)page38, 1482 MAX_MODE_SENSE_SIZE, &header); 1483 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1484 MODE_SENSE_PC_CURRENT, (caddr_t)page38, 1485 MAX_MODE_SENSE_SIZE, &header); 1486 } 1487 1488 /* 1489 * Issue a mode sense to determine the saved parameters 1490 * If the saved values fail, use the current instead. 1491 */ 1492 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1493 MODE_SENSE_PC_SAVED, (caddr_t)page38, 1494 MAX_MODE_SENSE_SIZE, &header); 1495 if (status) { 1496 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1497 MODE_SENSE_PC_CURRENT, (caddr_t)page38, 1498 MAX_MODE_SENSE_SIZE, &header); 1499 if (status) { 1500 return (0); 1501 } 1502 } 1503 1504 /* 1505 * We only need the common subset between the CCS 1506 * and SCSI-2 structures, so we can treat both 1507 * cases identically. Whatever the drive gives 1508 * us, we return to the drive in the mode select, 1509 * delta'ed by whatever we want to change. 1510 */ 1511 length = MODESENSE_PAGE_LEN(page38); 1512 if (length < MIN_PAGE38_LEN) { 1513 return (0); 1514 } 1515 1516 /* 1517 * Ask for changeable parameters. 1518 */ 1519 status = uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1520 MODE_SENSE_PC_CHANGEABLE, (caddr_t)fixed, 1521 MAX_MODE_SENSE_SIZE, &fixed_hdr); 1522 if (status || MODESENSE_PAGE_LEN(fixed) < MIN_PAGE38_LEN) { 1523 return (0); 1524 } 1525 1526 /* 1527 * We need to issue a mode select only if one or more 1528 * parameters need to be changed, and those parameters 1529 * are flagged by the drive as changeable. 1530 */ 1531 tmp1 = page38->mode; 1532 tmp2 = page38->threshold; 1533 tmp3 = page38->min_prefetch; 1534 tmp4 = page38->max_prefetch; 1535 1536 flag = 0; 1537 if ((cur_dtype->dtype_options & SUP_CACHE) && 1538 (fixed->mode & cur_dtype->dtype_cache) == 1539 cur_dtype->dtype_cache) { 1540 flag |= (page38->mode != cur_dtype->dtype_cache); 1541 page38->mode = cur_dtype->dtype_cache; 1542 } 1543 if ((cur_dtype->dtype_options & SUP_PREFETCH) && 1544 (fixed->threshold & cur_dtype->dtype_threshold) == 1545 cur_dtype->dtype_threshold) { 1546 flag |= (page38->threshold != cur_dtype->dtype_threshold); 1547 page38->threshold = cur_dtype->dtype_threshold; 1548 } 1549 if ((cur_dtype->dtype_options & SUP_CACHE_MIN) && 1550 (fixed->min_prefetch & cur_dtype->dtype_prefetch_min) == 1551 cur_dtype->dtype_prefetch_min) { 1552 flag |= (page38->min_prefetch != cur_dtype->dtype_prefetch_min); 1553 page38->min_prefetch = cur_dtype->dtype_prefetch_min; 1554 } 1555 if ((cur_dtype->dtype_options & SUP_CACHE_MAX) && 1556 (fixed->max_prefetch & cur_dtype->dtype_prefetch_max) == 1557 cur_dtype->dtype_prefetch_max) { 1558 flag |= (page38->max_prefetch != cur_dtype->dtype_prefetch_max); 1559 page38->max_prefetch = cur_dtype->dtype_prefetch_max; 1560 } 1561 /* 1562 * Notify the user of changes up to this point 1563 */ 1564 if (flag && option_msg) { 1565 fmt_print("PAGE 38: cache mode= 0x%x (0x%x)\n", 1566 page38->mode, tmp1); 1567 fmt_print(" min. prefetch multiplier= %d ", 1568 page38->min_multiplier); 1569 fmt_print("max. prefetch multiplier= %d\n", 1570 page38->max_multiplier); 1571 fmt_print(" threshold= %d (%d) ", 1572 page38->threshold, tmp2); 1573 fmt_print("min. prefetch= %d (%d) ", 1574 page38->min_prefetch, tmp3); 1575 fmt_print("max. prefetch= %d (%d)\n", 1576 page38->max_prefetch, tmp4); 1577 } 1578 /* 1579 * Apply any changes requested via the change list method 1580 */ 1581 flag |= apply_chg_list(DAD_MODE_CACHE_CCS, length, 1582 (uchar_t *)page38, (uchar_t *)fixed, 1583 cur_dtype->dtype_chglist); 1584 /* 1585 * If no changes required, do not issue a mode select 1586 */ 1587 if (flag == 0) { 1588 return (0); 1589 } 1590 /* 1591 * Issue a mode select 1592 * 1593 * We always want to set the Page Format bit for mode 1594 * selects. Set the Save Page bit if the drive indicates 1595 * that it can save this page via the mode sense. 1596 */ 1597 sp_flags = MODE_SELECT_PF; 1598 if (page38->mode_page.ps) { 1599 sp_flags |= MODE_SELECT_SP; 1600 } 1601 page38->mode_page.ps = 0; 1602 header.mode_header.length = 0; 1603 header.mode_header.device_specific = 0; 1604 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS, 1605 sp_flags, (caddr_t)page38, length, &header); 1606 if (status && (sp_flags & MODE_SELECT_SP)) { 1607 /* If failed, try not saving mode select params. */ 1608 sp_flags &= ~MODE_SELECT_SP; 1609 status = uscsi_mode_select(cur_file, DAD_MODE_CACHE_CCS, 1610 sp_flags, (caddr_t)page38, length, &header); 1611 } 1612 if (status && option_msg) { 1613 err_print("Warning: Using default CCS cache parameters.\n\n"); 1614 } 1615 1616 /* 1617 * If debugging, issue mode senses on the current and 1618 * saved values, so we can see the result of the mode 1619 * selects. 1620 */ 1621 if (option_msg && diag_msg) { 1622 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1623 MODE_SENSE_PC_CURRENT, (caddr_t)page38, 1624 MAX_MODE_SENSE_SIZE, &header); 1625 (void) uscsi_mode_sense(cur_file, DAD_MODE_CACHE_CCS, 1626 MODE_SENSE_PC_SAVED, (caddr_t)page38, 1627 MAX_MODE_SENSE_SIZE, &header); 1628 } 1629 1630 return (0); 1631 } 1632 1633 1634 /* 1635 * Extract the manufacturer's defect list. 1636 */ 1637 int 1638 scsi_ex_man(list) 1639 struct defect_list *list; 1640 { 1641 int i; 1642 1643 i = scsi_read_defect_data(list, DLD_MAN_DEF_LIST); 1644 if (i != 0) 1645 return (i); 1646 list->flags &= ~LIST_PGLIST; 1647 return (0); 1648 } 1649 1650 /* 1651 * Extract the current defect list. 1652 * For embedded scsi drives, this means both the manufacturer's (P) 1653 * and the grown (G) lists. 1654 */ 1655 int 1656 scsi_ex_cur(list) 1657 struct defect_list *list; 1658 { 1659 int i; 1660 1661 i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST|DLD_MAN_DEF_LIST); 1662 if (i != 0) 1663 return (i); 1664 list->flags |= LIST_PGLIST; 1665 return (0); 1666 } 1667 1668 1669 /* 1670 * Extract the grown list only 1671 */ 1672 int 1673 scsi_ex_grown(list) 1674 struct defect_list *list; 1675 { 1676 int i; 1677 1678 i = scsi_read_defect_data(list, DLD_GROWN_DEF_LIST); 1679 if (i != 0) 1680 return (i); 1681 list->flags |= LIST_PGLIST; 1682 return (0); 1683 } 1684 1685 1686 static int 1687 scsi_read_defect_data(list, pglist_flags) 1688 struct defect_list *list; 1689 int pglist_flags; 1690 { 1691 struct uscsi_cmd ucmd; 1692 char rqbuf[255]; 1693 union scsi_cdb cdb; 1694 struct scsi_defect_list *defects; 1695 struct scsi_defect_list def_list; 1696 struct scsi_defect_hdr *hdr; 1697 int status; 1698 int nbytes; 1699 int len; /* returned defect list length */ 1700 struct scsi_extended_sense *rq; 1701 1702 hdr = (struct scsi_defect_hdr *)&def_list; 1703 1704 /* 1705 * First get length of list by asking for the header only. 1706 */ 1707 (void) memset((char *)&def_list, 0, sizeof (def_list)); 1708 1709 /* 1710 * Build and execute the uscsi ioctl 1711 */ 1712 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 1713 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 1714 (void) memset((char *)rqbuf, 0, 255); 1715 cdb.scc_cmd = SCMD_READ_DEFECT_LIST; 1716 FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr)); 1717 cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT; 1718 ucmd.uscsi_cdb = (caddr_t)&cdb; 1719 ucmd.uscsi_cdblen = CDB_GROUP1; 1720 ucmd.uscsi_bufaddr = (caddr_t)hdr; 1721 ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr); 1722 ucmd.uscsi_rqbuf = rqbuf; 1723 ucmd.uscsi_rqlen = sizeof (rqbuf); 1724 ucmd.uscsi_rqresid = sizeof (rqbuf); 1725 rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf; 1726 1727 status = uscsi_cmd(cur_file, &ucmd, 1728 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 1729 1730 if (status != 0) { 1731 /* 1732 * check if read_defect_list_is_supported. 1733 */ 1734 if (ucmd.uscsi_rqstatus == STATUS_GOOD && 1735 rq->es_key == KEY_ILLEGAL_REQUEST && 1736 rq->es_add_code == INVALID_OPCODE) { 1737 err_print("\nWARNING: Current Disk does not support" 1738 " defect lists. \n"); 1739 } else 1740 if (option_msg) { 1741 err_print("No %s defect list.\n", 1742 pglist_flags & DLD_GROWN_DEF_LIST ? 1743 "grown" : "manufacturer's"); 1744 } 1745 return (-1); 1746 } 1747 1748 /* 1749 * Read the full list the second time 1750 */ 1751 hdr->length = BE_16(hdr->length); 1752 len = hdr->length; 1753 nbytes = len + sizeof (struct scsi_defect_hdr); 1754 1755 defects = zalloc(nbytes); 1756 *(struct scsi_defect_hdr *)defects = *(struct scsi_defect_hdr *)hdr; 1757 1758 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 1759 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 1760 cdb.scc_cmd = SCMD_READ_DEFECT_LIST; 1761 FORMG1COUNT(&cdb, nbytes); 1762 cdb.cdb_opaque[2] = pglist_flags | DLD_BFI_FORMAT; 1763 ucmd.uscsi_cdb = (caddr_t)&cdb; 1764 ucmd.uscsi_cdblen = CDB_GROUP1; 1765 ucmd.uscsi_bufaddr = (caddr_t)defects; 1766 ucmd.uscsi_buflen = nbytes; 1767 status = uscsi_cmd(cur_file, &ucmd, 1768 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 1769 1770 if (status) { 1771 err_print("can't read defect list 2nd time"); 1772 destroy_data((char *)defects); 1773 return (-1); 1774 } 1775 1776 defects->length = BE_16(defects->length); 1777 1778 if (len != hdr->length) { 1779 err_print("not enough defects"); 1780 destroy_data((char *)defects); 1781 return (-1); 1782 } 1783 scsi_convert_list_to_new(list, (struct scsi_defect_list *)defects, 1784 DLD_BFI_FORMAT); 1785 destroy_data((char *)defects); 1786 return (0); 1787 } 1788 1789 1790 /* 1791 * Map a block. 1792 */ 1793 /*ARGSUSED*/ 1794 static int 1795 scsi_repair(bn, flag) 1796 uint64_t bn; 1797 int flag; 1798 { 1799 struct uscsi_cmd ucmd; 1800 union scsi_cdb cdb; 1801 struct scsi_reassign_blk defect_list; 1802 1803 /* 1804 * Build and execute the uscsi ioctl 1805 */ 1806 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 1807 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 1808 (void) memset((char *)&defect_list, 0, 1809 sizeof (struct scsi_reassign_blk)); 1810 cdb.scc_cmd = SCMD_REASSIGN_BLOCK; 1811 ucmd.uscsi_cdb = (caddr_t)&cdb; 1812 ucmd.uscsi_cdblen = CDB_GROUP0; 1813 ucmd.uscsi_bufaddr = (caddr_t)&defect_list; 1814 ucmd.uscsi_buflen = sizeof (struct scsi_reassign_blk); 1815 defect_list.length = sizeof (defect_list.defect); 1816 defect_list.length = BE_16(defect_list.length); 1817 defect_list.defect = bn; 1818 defect_list.defect = BE_32(defect_list.defect); 1819 return (uscsi_cmd(cur_file, &ucmd, 1820 (option_msg && diag_msg) ? F_NORMAL : F_SILENT)); 1821 } 1822 1823 /* 1824 * Convert a SCSI-style defect list to our generic format. 1825 * We can handle different format lists. 1826 */ 1827 static void 1828 scsi_convert_list_to_new(list, def_list, list_format) 1829 struct defect_list *list; 1830 struct scsi_defect_list *def_list; 1831 int list_format; 1832 { 1833 register struct scsi_bfi_defect *old_defect, *old_defect1; 1834 register struct defect_entry *new_defect; 1835 register int len, new_len, obfi, nbfi; 1836 register int i; 1837 int old_cyl, new_cyl; 1838 unsigned char *cp; 1839 1840 1841 switch (list_format) { 1842 1843 case DLD_BFI_FORMAT: 1844 /* 1845 * Allocate space for the rest of the list. 1846 */ 1847 len = def_list->length / sizeof (struct scsi_bfi_defect); 1848 old_defect = def_list->list; 1849 new_defect = (struct defect_entry *) 1850 zalloc(LISTSIZE(len) * SECSIZE); 1851 1852 list->header.magicno = (uint_t)DEFECT_MAGIC; 1853 list->list = new_defect; 1854 1855 for (i = 0, new_len = 0; i < len; new_defect++, new_len++) { 1856 cp = (unsigned char *)old_defect; 1857 new_defect->cyl = (cp[0] << 16 | cp[1] << 8) | cp[2]; 1858 new_defect->head = old_defect->head; 1859 new_defect->bfi = (int)old_defect->bytes_from_index; 1860 new_defect->bfi = BE_32(new_defect->bfi); 1861 new_defect->nbits = 0; /* size of defect */ 1862 old_defect1 = old_defect++; 1863 i++; 1864 /* 1865 * Since we reached the end of the list, old_defect 1866 * now points to an invalid reference, since it got 1867 * incremented in the above operation. So we don't 1868 * need to proceed further. new_len needs to be 1869 * incremented to account for the last element. 1870 */ 1871 if (i == len) { 1872 new_len++; 1873 break; 1874 } 1875 obfi = new_defect->bfi; 1876 nbfi = (int)old_defect->bytes_from_index; 1877 nbfi = BE_32(nbfi); 1878 1879 old_cyl = new_defect->cyl; 1880 cp = (unsigned char *)old_defect; 1881 new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2]; 1882 1883 1884 /* 1885 * Merge adjacent contiguous defect entries into one 1886 * and update the length of the defect 1887 */ 1888 while ((i < len) && 1889 (old_cyl == new_cyl) && 1890 (old_defect->head == old_defect1->head) && 1891 (nbfi == (obfi + BITSPERBYTE))) { 1892 old_defect1 = old_defect++; 1893 cp = (unsigned char *)old_defect; 1894 new_cyl = (cp[0] << 16 | cp[1] << 8) | cp[2]; 1895 obfi = (int)old_defect1->bytes_from_index; 1896 obfi = BE_32(obfi); 1897 nbfi = (int)old_defect->bytes_from_index; 1898 nbfi = BE_32(nbfi); 1899 new_defect->nbits += (8*BITSPERBYTE); 1900 i++; 1901 } 1902 } 1903 1904 list->header.count = new_len; 1905 break; 1906 1907 default: 1908 err_print("scsi_convert_list_to_new: can't deal with it\n"); 1909 exit(0); 1910 /*NOTREACHED*/ 1911 } 1912 1913 (void) checkdefsum(list, CK_MAKESUM); 1914 } 1915 1916 1917 1918 /* 1919 * Execute a command and determine the result. 1920 * Uses the "uscsi" ioctl interface, which is 1921 * fully supported. 1922 * 1923 * If the user wants request sense data to be returned 1924 * in case of error then , the "uscsi_cmd" structure 1925 * should have the request sense buffer allocated in 1926 * uscsi_rqbuf. 1927 * 1928 */ 1929 int 1930 uscsi_cmd(fd, ucmd, flags) 1931 int fd; 1932 struct uscsi_cmd *ucmd; 1933 int flags; 1934 { 1935 struct scsi_extended_sense *rq; 1936 char rqbuf[255]; 1937 int status; 1938 int rqlen; 1939 int timeout = 0; 1940 1941 /* 1942 * Set function flags for driver. 1943 */ 1944 ucmd->uscsi_flags = USCSI_ISOLATE; 1945 if (flags & F_SILENT) { 1946 ucmd->uscsi_flags |= USCSI_SILENT; 1947 } 1948 if (flags & F_RQENABLE) { 1949 ucmd->uscsi_flags |= USCSI_RQENABLE; 1950 } 1951 1952 /* 1953 * If this command will perform a read, set the USCSI_READ flag 1954 */ 1955 if (ucmd->uscsi_buflen > 0) { 1956 /* 1957 * uscsi_cdb is declared as a caddr_t, so any CDB 1958 * command byte with the MSB set will result in a 1959 * compiler error unless we cast to an unsigned value. 1960 */ 1961 switch ((uint8_t)ucmd->uscsi_cdb[0]) { 1962 case SCMD_READ: 1963 case SCMD_READ|SCMD_GROUP1: 1964 case SCMD_READ|SCMD_GROUP4: 1965 case SCMD_MODE_SENSE: 1966 case SCMD_INQUIRY: 1967 case SCMD_READ_DEFECT_LIST: 1968 case SCMD_READ_CAPACITY: 1969 case SCMD_SVC_ACTION_IN_G4: 1970 ucmd->uscsi_flags |= USCSI_READ; 1971 break; 1972 } 1973 } 1974 1975 /* 1976 * Set timeout: 30 seconds for all commands except format 1977 */ 1978 switch (ucmd->uscsi_cdb[0]) { 1979 case SCMD_FORMAT: 1980 if (ucmd->uscsi_timeout == 0) { 1981 ucmd->uscsi_timeout = scsi_format_timeout; 1982 /* 1983 * Get the timeout value computed using page4 geometry. 1984 * add 50% margin to cover defect management overhead. 1985 * add another 50% margin to have a safe timeout. 1986 * If it exceeds 2 hours then use this value. 1987 */ 1988 if ((timeout = scsi_format_time()) > 0) { 1989 timeout *= 60; /* convert to seconds */ 1990 timeout += timeout; 1991 /* 1992 * formatting drives with huge capacity 1993 * will cause these heuristics to come 1994 * up with times that overflow ~9 hours 1995 */ 1996 if (timeout > SHRT_MAX) 1997 timeout = SHRT_MAX; 1998 if (timeout > scsi_format_timeout) 1999 ucmd->uscsi_timeout = timeout; 2000 } 2001 } 2002 if (option_msg && diag_msg) { 2003 err_print("format_timeout set to %d seconds, %d" 2004 " required\n", ucmd->uscsi_timeout, timeout); 2005 } 2006 break; 2007 2008 default: 2009 ucmd->uscsi_timeout = 30; /* 30 seconds */ 2010 break; 2011 } 2012 2013 /* 2014 * Set up Request Sense buffer 2015 */ 2016 ucmd->uscsi_flags |= USCSI_RQENABLE; 2017 2018 if (ucmd->uscsi_rqbuf == NULL) { 2019 ucmd->uscsi_rqbuf = rqbuf; 2020 ucmd->uscsi_rqlen = sizeof (rqbuf); 2021 ucmd->uscsi_rqresid = sizeof (rqbuf); 2022 } 2023 ucmd->uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS; 2024 2025 /* 2026 * Clear global error state 2027 */ 2028 media_error = 0; 2029 2030 /* 2031 * Execute the ioctl 2032 */ 2033 status = ioctl(fd, USCSICMD, ucmd); 2034 if (status == 0 && ucmd->uscsi_status == 0) { 2035 return (status); 2036 } 2037 2038 #ifdef sparc 2039 /* 2040 * Check the status and return appropriate errors if the disk is 2041 * unavailable (could be formatting) or reserved (by other host). 2042 * In either case we can not talk to the disk now. 2043 */ 2044 if (status == -1 && errno == EAGAIN) { 2045 disk_error = DISK_STAT_UNAVAILABLE; 2046 return (DSK_UNAVAILABLE); 2047 } 2048 if ((ucmd->uscsi_status & STATUS_MASK) == STATUS_RESERVATION_CONFLICT) { 2049 disk_error = DISK_STAT_RESERVED; 2050 return (DSK_RESERVED); 2051 } 2052 /* 2053 * Check for physically removed or completely unresponsive drive 2054 */ 2055 if (status == -1 && !ucmd->uscsi_status && errno == EIO) { 2056 disk_error = DISK_STAT_UNAVAILABLE; 2057 return (DSK_UNAVAILABLE); 2058 } 2059 #endif /* sparc */ 2060 2061 /* 2062 * If an automatic Request Sense gave us valid 2063 * info about the error, we may be able to use 2064 * that to print a reasonable error msg. 2065 */ 2066 if (ucmd->uscsi_rqstatus == IMPOSSIBLE_SCSI_STATUS) { 2067 if (option_msg && diag_msg) { 2068 err_print("No request sense for command %s\n", 2069 scsi_find_command_name(ucmd->uscsi_cdb[0])); 2070 } 2071 return (-1); 2072 } 2073 if (ucmd->uscsi_rqstatus != STATUS_GOOD) { 2074 if (option_msg && diag_msg) { 2075 err_print("Request sense status for command %s: 0x%x\n", 2076 scsi_find_command_name(ucmd->uscsi_cdb[0]), 2077 ucmd->uscsi_rqstatus); 2078 } 2079 return (-1); 2080 } 2081 rq = (struct scsi_extended_sense *)ucmd->uscsi_rqbuf; 2082 rqlen = ucmd->uscsi_rqlen - ucmd->uscsi_rqresid; 2083 if ((((int)rq->es_add_len) + 8) < MIN_REQUEST_SENSE_LEN || 2084 rq->es_class != CLASS_EXTENDED_SENSE || 2085 rqlen < MIN_REQUEST_SENSE_LEN) { 2086 if (option_msg) { 2087 err_print("Request sense for command %s failed\n", 2088 scsi_find_command_name(ucmd->uscsi_cdb[0])); 2089 } 2090 if (option_msg && diag_msg) { 2091 err_print("Sense data:\n"); 2092 dump("", (caddr_t)rqbuf, rqlen, HEX_ONLY); 2093 } 2094 return (-1); 2095 } 2096 2097 /* 2098 * If the failed command is a Mode Select, and the 2099 * target is indicating that it has rounded one of 2100 * the mode select parameters, as defined in the SCSI-2 2101 * specification, then we should accept the command 2102 * as successful. 2103 */ 2104 if (ucmd->uscsi_cdb[0] == SCMD_MODE_SELECT) { 2105 if (rq->es_key == KEY_RECOVERABLE_ERROR && 2106 rq->es_add_code == ROUNDED_PARAMETER && 2107 rq->es_qual_code == 0) { 2108 return (0); 2109 } 2110 } 2111 2112 switch (rq->es_key) { 2113 case KEY_NOT_READY: 2114 disk_error = DISK_STAT_NOTREADY; 2115 break; 2116 case KEY_DATA_PROTECT: 2117 disk_error = DISK_STAT_DATA_PROTECT; 2118 break; 2119 } 2120 2121 if (flags & F_ALLERRS) { 2122 media_error = (rq->es_key == KEY_MEDIUM_ERROR); 2123 } 2124 if (!(flags & F_SILENT) || option_msg) { 2125 scsi_printerr(ucmd, rq, rqlen); 2126 } 2127 if ((rq->es_key != KEY_RECOVERABLE_ERROR) || (flags & F_ALLERRS)) { 2128 return (-1); 2129 } 2130 return (0); 2131 } 2132 2133 2134 /* 2135 * Execute a uscsi mode sense command. 2136 * This can only be used to return one page at a time. 2137 * Return the mode header/block descriptor and the actual 2138 * page data separately - this allows us to support 2139 * devices which return either 0 or 1 block descriptors. 2140 * Whatever a device gives us in the mode header/block descriptor 2141 * will be returned to it upon subsequent mode selects. 2142 */ 2143 int 2144 uscsi_mode_sense(fd, page_code, page_control, page_data, page_size, header) 2145 int fd; /* file descriptor */ 2146 int page_code; /* requested page number */ 2147 int page_control; /* current, changeable, etc. */ 2148 caddr_t page_data; /* place received data here */ 2149 int page_size; /* size of page_data */ 2150 struct scsi_ms_header *header; /* mode header/block descriptor */ 2151 { 2152 caddr_t mode_sense_buf; 2153 struct mode_header *hdr; 2154 struct mode_page *pg; 2155 int nbytes; 2156 struct uscsi_cmd ucmd; 2157 union scsi_cdb cdb; 2158 int status; 2159 int maximum; 2160 2161 assert(page_size >= 0 && page_size < 256); 2162 assert(page_control == MODE_SENSE_PC_CURRENT || 2163 page_control == MODE_SENSE_PC_CHANGEABLE || 2164 page_control == MODE_SENSE_PC_DEFAULT || 2165 page_control == MODE_SENSE_PC_SAVED); 2166 /* 2167 * Allocate a buffer for the mode sense headers 2168 * and mode sense data itself. 2169 */ 2170 nbytes = sizeof (struct block_descriptor) + 2171 sizeof (struct mode_header) + page_size; 2172 nbytes = page_size; 2173 if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) { 2174 err_print("cannot malloc %d bytes\n", nbytes); 2175 return (-1); 2176 } 2177 2178 /* 2179 * Build and execute the uscsi ioctl 2180 */ 2181 (void) memset(mode_sense_buf, 0, nbytes); 2182 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2183 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2184 cdb.scc_cmd = SCMD_MODE_SENSE; 2185 FORMG0COUNT(&cdb, (uchar_t)nbytes); 2186 cdb.cdb_opaque[2] = page_control | page_code; 2187 ucmd.uscsi_cdb = (caddr_t)&cdb; 2188 ucmd.uscsi_cdblen = CDB_GROUP0; 2189 ucmd.uscsi_bufaddr = mode_sense_buf; 2190 ucmd.uscsi_buflen = nbytes; 2191 status = uscsi_cmd(fd, &ucmd, 2192 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2193 if (status) { 2194 if (option_msg) { 2195 err_print("Mode sense page 0x%x failed\n", 2196 page_code); 2197 } 2198 free(mode_sense_buf); 2199 return (-1); 2200 } 2201 2202 /* 2203 * Verify that the returned data looks reasonabled, 2204 * find the actual page data, and copy it into the 2205 * user's buffer. Copy the mode_header and block_descriptor 2206 * into the header structure, which can then be used to 2207 * return the same data to the drive when issuing a mode select. 2208 */ 2209 hdr = (struct mode_header *)mode_sense_buf; 2210 (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header)); 2211 if (hdr->bdesc_length != sizeof (struct block_descriptor) && 2212 hdr->bdesc_length != 0) { 2213 if (option_msg) { 2214 err_print("\ 2215 \nMode sense page 0x%x: block descriptor length %d incorrect\n", 2216 page_code, hdr->bdesc_length); 2217 if (diag_msg) 2218 dump("Mode sense: ", mode_sense_buf, 2219 nbytes, HEX_ONLY); 2220 } 2221 free(mode_sense_buf); 2222 return (-1); 2223 } 2224 (void) memcpy((caddr_t)header, mode_sense_buf, 2225 (int) (sizeof (struct mode_header) + hdr->bdesc_length)); 2226 pg = (struct mode_page *)((ulong_t)mode_sense_buf + 2227 sizeof (struct mode_header) + hdr->bdesc_length); 2228 if (pg->code != page_code) { 2229 if (option_msg) { 2230 err_print("\ 2231 \nMode sense page 0x%x: incorrect page code 0x%x\n", 2232 page_code, pg->code); 2233 if (diag_msg) 2234 dump("Mode sense: ", mode_sense_buf, 2235 nbytes, HEX_ONLY); 2236 } 2237 free(mode_sense_buf); 2238 return (-1); 2239 } 2240 /* 2241 * Accept up to "page_size" bytes of mode sense data. 2242 * This allows us to accept both CCS and SCSI-2 2243 * structures, as long as we request the greater 2244 * of the two. 2245 */ 2246 maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length; 2247 if (((int)pg->length) > maximum) { 2248 if (option_msg) { 2249 err_print("\ 2250 Mode sense page 0x%x: incorrect page length %d - expected max %d\n", 2251 page_code, pg->length, maximum); 2252 if (diag_msg) 2253 dump("Mode sense: ", mode_sense_buf, 2254 nbytes, HEX_ONLY); 2255 } 2256 free(mode_sense_buf); 2257 return (-1); 2258 } 2259 2260 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg)); 2261 2262 if (option_msg && diag_msg) { 2263 char *pc = find_string(page_control_strings, page_control); 2264 err_print("\nMode sense page 0x%x (%s):\n", page_code, 2265 pc != NULL ? pc : ""); 2266 dump("header: ", (caddr_t)header, 2267 sizeof (struct scsi_ms_header), HEX_ONLY); 2268 dump("data: ", page_data, 2269 MODESENSE_PAGE_LEN(pg), HEX_ONLY); 2270 } 2271 2272 free(mode_sense_buf); 2273 return (0); 2274 } 2275 2276 2277 /* 2278 * Execute a uscsi mode select command. 2279 */ 2280 int 2281 uscsi_mode_select(fd, page_code, options, page_data, page_size, header) 2282 int fd; /* file descriptor */ 2283 int page_code; /* mode select page */ 2284 int options; /* save page/page format */ 2285 caddr_t page_data; /* place received data here */ 2286 int page_size; /* size of page_data */ 2287 struct scsi_ms_header *header; /* mode header/block descriptor */ 2288 { 2289 caddr_t mode_select_buf; 2290 int nbytes; 2291 struct uscsi_cmd ucmd; 2292 union scsi_cdb cdb; 2293 int status; 2294 2295 assert(((struct mode_page *)page_data)->ps == 0); 2296 assert(header->mode_header.length == 0); 2297 assert(header->mode_header.device_specific == 0); 2298 assert((options & ~(MODE_SELECT_SP|MODE_SELECT_PF)) == 0); 2299 2300 /* 2301 * Allocate a buffer for the mode select header and data 2302 */ 2303 nbytes = sizeof (struct block_descriptor) + 2304 sizeof (struct mode_header) + page_size; 2305 if ((mode_select_buf = malloc((uint_t)nbytes)) == NULL) { 2306 err_print("cannot malloc %d bytes\n", nbytes); 2307 return (-1); 2308 } 2309 2310 /* 2311 * Build the mode select data out of the header and page data 2312 * This allows us to support devices which return either 2313 * 0 or 1 block descriptors. 2314 */ 2315 (void) memset(mode_select_buf, 0, nbytes); 2316 nbytes = sizeof (struct mode_header); 2317 if (header->mode_header.bdesc_length == 2318 sizeof (struct block_descriptor)) { 2319 nbytes += sizeof (struct block_descriptor); 2320 } 2321 2322 /* 2323 * Dump the structures if anyone's interested 2324 */ 2325 if (option_msg && diag_msg) { 2326 char *s; 2327 s = find_string(mode_select_strings, 2328 options & (MODE_SELECT_SP|MODE_SELECT_PF)); 2329 err_print("\nMode select page 0x%x%s:\n", page_code, 2330 s != NULL ? s : ""); 2331 dump("header: ", (caddr_t)header, 2332 nbytes, HEX_ONLY); 2333 dump("data: ", (caddr_t)page_data, 2334 page_size, HEX_ONLY); 2335 } 2336 2337 /* 2338 * Fix the code for byte ordering 2339 */ 2340 2341 switch (page_code) { 2342 case DAD_MODE_ERR_RECOV: 2343 { 2344 struct mode_err_recov *pd; 2345 pd = (struct mode_err_recov *)(void *)page_data; 2346 pd->recovery_time_limit = BE_16(pd->recovery_time_limit); 2347 break; 2348 } 2349 case MODEPAGE_DISCO_RECO: 2350 { 2351 struct mode_disco_reco *pd; 2352 pd = (struct mode_disco_reco *)(void *)page_data; 2353 pd->bus_inactivity_limit = BE_16(pd->bus_inactivity_limit); 2354 pd->disconect_time_limit = BE_16(pd->disconect_time_limit); 2355 pd->connect_time_limit = BE_16(pd->connect_time_limit); 2356 pd->max_burst_size = BE_16(pd->max_burst_size); 2357 break; 2358 } 2359 case DAD_MODE_FORMAT: 2360 { 2361 struct mode_format *pd; 2362 pd = (struct mode_format *)(void *)page_data; 2363 pd->tracks_per_zone = BE_16(pd->tracks_per_zone); 2364 pd->alt_sect_zone = BE_16(pd->alt_sect_zone); 2365 pd->alt_tracks_zone = BE_16(pd->alt_tracks_zone); 2366 pd->alt_tracks_vol = BE_16(pd->alt_tracks_vol); 2367 pd->sect_track = BE_16(pd->sect_track); 2368 pd->data_bytes_sect = BE_16(pd->data_bytes_sect); 2369 pd->interleave = BE_16(pd->interleave); 2370 pd->track_skew = BE_16(pd->track_skew); 2371 pd->cylinder_skew = BE_16(pd->cylinder_skew); 2372 break; 2373 } 2374 case DAD_MODE_GEOMETRY: 2375 { 2376 struct mode_geometry *pd; 2377 pd = (struct mode_geometry *)(void *)page_data; 2378 pd->step_rate = BE_16(pd->step_rate); 2379 pd->rpm = BE_16(pd->rpm); 2380 break; 2381 } 2382 case DAD_MODE_CACHE: 2383 { 2384 struct mode_cache *pd; 2385 pd = (struct mode_cache *)(void *)page_data; 2386 pd->dis_prefetch_len = BE_16(pd->dis_prefetch_len); 2387 pd->min_prefetch = BE_16(pd->min_prefetch); 2388 pd->max_prefetch = BE_16(pd->max_prefetch); 2389 pd->prefetch_ceiling = BE_16(pd->prefetch_ceiling); 2390 break; 2391 } 2392 case MODEPAGE_PDEVICE: 2393 { 2394 struct mode_pdevice *pd; 2395 pd = (struct mode_pdevice *)(void *)page_data; 2396 pd->if_ident = BE_16(pd->if_ident); 2397 break; 2398 } 2399 case MODEPAGE_CTRL_MODE: 2400 { 2401 struct mode_control *pd; 2402 pd = (struct mode_control *)(void *)page_data; 2403 pd->ready_aen_holdoff = BE_16(pd->ready_aen_holdoff); 2404 break; 2405 } 2406 } 2407 2408 /* 2409 * Put the header and data together 2410 */ 2411 (void) memcpy(mode_select_buf, (caddr_t)header, nbytes); 2412 (void) memcpy(mode_select_buf + nbytes, page_data, page_size); 2413 nbytes += page_size; 2414 2415 /* 2416 * Build and execute the uscsi ioctl 2417 */ 2418 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2419 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2420 cdb.scc_cmd = SCMD_MODE_SELECT; 2421 FORMG0COUNT(&cdb, (uchar_t)nbytes); 2422 cdb.cdb_opaque[1] = (uchar_t)options; 2423 ucmd.uscsi_cdb = (caddr_t)&cdb; 2424 ucmd.uscsi_cdblen = CDB_GROUP0; 2425 ucmd.uscsi_bufaddr = mode_select_buf; 2426 ucmd.uscsi_buflen = nbytes; 2427 status = uscsi_cmd(fd, &ucmd, 2428 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2429 2430 if (status && option_msg) { 2431 err_print("Mode select page 0x%x failed\n", page_code); 2432 } 2433 2434 free(mode_select_buf); 2435 return (status); 2436 } 2437 2438 2439 /* 2440 * Execute a uscsi inquiry command and return the 2441 * resulting data. 2442 */ 2443 int 2444 uscsi_inquiry(fd, inqbuf, inqbufsiz) 2445 int fd; 2446 caddr_t inqbuf; 2447 int inqbufsiz; 2448 { 2449 struct uscsi_cmd ucmd; 2450 union scsi_cdb cdb; 2451 struct scsi_inquiry *inq; 2452 int n; 2453 int status; 2454 2455 assert(inqbufsiz >= sizeof (struct scsi_inquiry) && 2456 inqbufsiz < 256); 2457 2458 /* 2459 * Build and execute the uscsi ioctl 2460 */ 2461 (void) memset((char *)inqbuf, 0, inqbufsiz); 2462 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2463 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2464 cdb.scc_cmd = SCMD_INQUIRY; 2465 FORMG0COUNT(&cdb, (uchar_t)inqbufsiz); 2466 ucmd.uscsi_cdb = (caddr_t)&cdb; 2467 ucmd.uscsi_cdblen = CDB_GROUP0; 2468 ucmd.uscsi_bufaddr = (caddr_t)inqbuf; 2469 ucmd.uscsi_buflen = inqbufsiz; 2470 status = uscsi_cmd(fd, &ucmd, 2471 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2472 if (status) { 2473 if (option_msg) { 2474 err_print("Inquiry failed\n"); 2475 } 2476 } else if (option_msg && diag_msg) { 2477 /* 2478 * Dump the inquiry data if anyone's interested 2479 */ 2480 inq = (struct scsi_inquiry *)inqbuf; 2481 n = (int)inq->inq_len + 4; 2482 n = min(n, inqbufsiz); 2483 err_print("Inquiry:\n"); 2484 dump("", (caddr_t)inqbuf, n, HEX_ASCII); 2485 } 2486 return (status); 2487 } 2488 2489 2490 /* 2491 * Return the Read Capacity information 2492 */ 2493 int 2494 uscsi_read_capacity(fd, capacity) 2495 int fd; 2496 struct scsi_capacity_16 *capacity; 2497 { 2498 struct uscsi_cmd ucmd; 2499 union scsi_cdb cdb; 2500 int status; 2501 struct scsi_capacity cap_old; 2502 2503 /* 2504 * Build and execute the uscsi ioctl 2505 */ 2506 (void) memset((char *)capacity, 0, sizeof (struct scsi_capacity_16)); 2507 (void) memset((char *)&cap_old, 0, sizeof (struct scsi_capacity)); 2508 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2509 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2510 cdb.scc_cmd = SCMD_READ_CAPACITY; 2511 ucmd.uscsi_cdb = (caddr_t)&cdb; 2512 ucmd.uscsi_cdblen = CDB_GROUP1; 2513 ucmd.uscsi_bufaddr = (caddr_t)&cap_old; 2514 ucmd.uscsi_buflen = sizeof (struct scsi_capacity); 2515 status = uscsi_cmd(fd, &ucmd, 2516 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2517 2518 if (cap_old.capacity == UINT_MAX32) { 2519 /* 2520 * A capacity of 0xffffffff in response to a 2521 * READ CAPACITY 10 indicates that the lun 2522 * is too large to report the size in a 32 bit 2523 * value, and a READ CAPACITY 16 is required 2524 * to get the correct size. 2525 */ 2526 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2527 (void) memset((char *)&cdb, 0, 2528 sizeof (union scsi_cdb)); 2529 2530 ucmd.uscsi_cdb = (caddr_t)&cdb; 2531 ucmd.uscsi_cdblen = CDB_GROUP4; 2532 ucmd.uscsi_bufaddr = (caddr_t)capacity; 2533 ucmd.uscsi_buflen = sizeof (struct scsi_capacity_16); 2534 2535 /* 2536 * Read Capacity (16) is a Service Action In command. One 2537 * command byte (0x9E) is overloaded for multiple operations, 2538 * with the second CDB byte specifying the desired operation 2539 */ 2540 cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4; 2541 cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4; 2542 2543 /* 2544 * Fill in allocation length field 2545 */ 2546 cdb.cdb_opaque[10] = 2547 (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24); 2548 cdb.cdb_opaque[11] = 2549 (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16); 2550 cdb.cdb_opaque[12] = 2551 (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8); 2552 cdb.cdb_opaque[13] = 2553 (uchar_t)(ucmd.uscsi_buflen & 0x000000ff); 2554 2555 status = uscsi_cmd(fd, &ucmd, 2556 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2557 } 2558 2559 if (status) { 2560 if (option_msg) { 2561 /* 2562 * Indicate which of the commands failed 2563 */ 2564 if (cdb.scc_cmd == SCMD_READ_CAPACITY) { 2565 err_print("Read capacity failed\n"); 2566 } else { 2567 err_print("Read capacity 16 failed\n"); 2568 } 2569 } 2570 } else if (option_msg && diag_msg) { 2571 /* 2572 * Dump the capacity data if anyone's interested 2573 */ 2574 if (cap_old.capacity == UINT_MAX32) { 2575 dump("Capacity: ", (caddr_t)capacity, 2576 sizeof (struct scsi_capacity_16), HEX_ONLY); 2577 } else { 2578 dump("Capacity: ", (caddr_t)&cap_old, 2579 sizeof (struct scsi_capacity), HEX_ONLY); 2580 } 2581 } 2582 2583 if (cap_old.capacity == UINT_MAX32) { 2584 capacity->sc_capacity = BE_64(capacity->sc_capacity); 2585 capacity->sc_lbasize = BE_32(capacity->sc_lbasize); 2586 } else { 2587 capacity->sc_capacity = (uint64_t)BE_32(cap_old.capacity); 2588 capacity->sc_lbasize = BE_32(cap_old.lbasize); 2589 } 2590 2591 return (status); 2592 } 2593 2594 2595 /* 2596 * Reserve the current disk 2597 */ 2598 static int 2599 uscsi_reserve_release(int fd, int cmd) 2600 { 2601 int status = 0; 2602 #ifdef sparc 2603 struct uscsi_cmd ucmd; 2604 union scsi_cdb cdb; 2605 2606 /* 2607 * Build and execute the uscsi ioctl 2608 */ 2609 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2610 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2611 cdb.scc_cmd = (cmd == SCMD_RESERVE) ? SCMD_RESERVE : SCMD_RELEASE; 2612 ucmd.uscsi_cdb = (caddr_t)&cdb; 2613 ucmd.uscsi_cdblen = CDB_GROUP0; 2614 status = uscsi_cmd(fd, &ucmd, 2615 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2616 2617 if (status) { 2618 /* 2619 * Reserve/Release(6) failed. 2620 * Try Reserve/Release(10) , if it succeeds then 2621 * return success. 2622 */ 2623 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2624 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2625 ucmd.uscsi_cdb = (caddr_t)&cdb; 2626 cdb.scc_cmd = (cmd == SCMD_RESERVE) ? 2627 SCMD_RESERVE_G1 : SCMD_RELEASE_G1; 2628 ucmd.uscsi_cdblen = CDB_GROUP1; 2629 status = uscsi_cmd(fd, &ucmd, 2630 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2631 if (status) { 2632 if (option_msg) { 2633 err_print("%s failed\n", (cmd == SCMD_RESERVE) ? 2634 "Reserve" : "Release"); 2635 } 2636 } 2637 } 2638 #else /* not sparc */ 2639 2640 #ifdef lint 2641 fd = fd; 2642 cmd = cmd; 2643 #endif /* lint */ 2644 2645 #endif /* not sparc */ 2646 2647 return (status); 2648 } 2649 2650 int 2651 scsi_dump_mode_sense_pages(page_control) 2652 int page_control; 2653 { 2654 struct uscsi_cmd ucmd; 2655 union scsi_cdb cdb; 2656 char *msbuf; 2657 int nbytes; 2658 char *pc_str; 2659 int status; 2660 struct mode_header *mh; 2661 char *p; 2662 struct mode_page *mp; 2663 int n; 2664 char s[16]; 2665 int result = 0; 2666 2667 pc_str = find_string(page_control_strings, page_control); 2668 2669 /* 2670 * Allocate memory for the mode sense buffer. 2671 */ 2672 nbytes = 255; 2673 msbuf = (char *)zalloc(nbytes); 2674 2675 /* 2676 * Build and execute the uscsi ioctl 2677 */ 2678 (void) memset(msbuf, 0, nbytes); 2679 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 2680 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 2681 cdb.scc_cmd = SCMD_MODE_SENSE; 2682 FORMG0COUNT(&cdb, (uchar_t)nbytes); 2683 cdb.cdb_opaque[2] = page_control | 0x3f; 2684 ucmd.uscsi_cdb = (caddr_t)&cdb; 2685 ucmd.uscsi_cdblen = CDB_GROUP0; 2686 ucmd.uscsi_bufaddr = msbuf; 2687 ucmd.uscsi_buflen = nbytes; 2688 status = uscsi_cmd(cur_file, &ucmd, 2689 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 2690 if (status) { 2691 err_print("\nMode sense page 0x3f (%s) failed\n", 2692 pc_str); 2693 result = 1; 2694 } else { 2695 err_print("\nMode sense pages (%s):\n", pc_str); 2696 mh = (struct mode_header *)msbuf; 2697 nbytes = mh->length - sizeof (struct mode_header) - 2698 mh->bdesc_length + 1; 2699 p = msbuf + sizeof (struct mode_header) + 2700 mh->bdesc_length; 2701 dump(" ", msbuf, sizeof (struct mode_header) + 2702 (int)mh->bdesc_length, HEX_ONLY); 2703 while (nbytes > 0) { 2704 mp = (struct mode_page *)p; 2705 n = mp->length + sizeof (struct mode_page); 2706 nbytes -= n; 2707 if (nbytes < 0) 2708 break; 2709 (void) sprintf(s, " %3x: ", mp->code); 2710 dump(s, p, n, HEX_ONLY); 2711 p += n; 2712 } 2713 if (nbytes < 0) { 2714 err_print(" Sense data formatted incorrectly:\n"); 2715 dump(" ", msbuf, (int)mh->length+1, HEX_ONLY); 2716 result = 1; 2717 } 2718 err_print("\n"); 2719 } 2720 2721 free(msbuf); 2722 return (result); 2723 } 2724 2725 2726 static void 2727 scsi_printerr(ucmd, rq, rqlen) 2728 struct uscsi_cmd *ucmd; 2729 struct scsi_extended_sense *rq; 2730 int rqlen; 2731 { 2732 diskaddr_t blkno; 2733 struct scsi_descr_sense_hdr *sdsp = 2734 (struct scsi_descr_sense_hdr *)rq; 2735 2736 switch (rq->es_key) { 2737 case KEY_NO_SENSE: 2738 err_print("No sense error"); 2739 break; 2740 case KEY_RECOVERABLE_ERROR: 2741 err_print("Recoverable error"); 2742 break; 2743 case KEY_NOT_READY: 2744 err_print("Not ready error"); 2745 break; 2746 case KEY_MEDIUM_ERROR: 2747 err_print("Medium error"); 2748 break; 2749 case KEY_HARDWARE_ERROR: 2750 err_print("Hardware error"); 2751 break; 2752 case KEY_ILLEGAL_REQUEST: 2753 err_print("Illegal request"); 2754 break; 2755 case KEY_UNIT_ATTENTION: 2756 err_print("Unit attention error"); 2757 break; 2758 case KEY_WRITE_PROTECT: 2759 err_print("Write protect error"); 2760 break; 2761 case KEY_BLANK_CHECK: 2762 err_print("Blank check error"); 2763 break; 2764 case KEY_VENDOR_UNIQUE: 2765 err_print("Vendor unique error"); 2766 break; 2767 case KEY_COPY_ABORTED: 2768 err_print("Copy aborted error"); 2769 break; 2770 case KEY_ABORTED_COMMAND: 2771 err_print("Aborted command"); 2772 break; 2773 case KEY_EQUAL: 2774 err_print("Equal error"); 2775 break; 2776 case KEY_VOLUME_OVERFLOW: 2777 err_print("Volume overflow"); 2778 break; 2779 case KEY_MISCOMPARE: 2780 err_print("Miscompare error"); 2781 break; 2782 case KEY_RESERVED: 2783 err_print("Reserved error"); 2784 break; 2785 default: 2786 err_print("Unknown error"); 2787 break; 2788 } 2789 2790 err_print(" during %s", scsi_find_command_name(ucmd->uscsi_cdb[0])); 2791 2792 /* 2793 * Get asc, ascq and info field from sense data. There are two 2794 * possible formats (fixed sense data and descriptor sense data) 2795 * depending on the value of es_code. 2796 */ 2797 switch (rq->es_code) { 2798 case CODE_FMT_DESCR_CURRENT: 2799 case CODE_FMT_DESCR_DEFERRED: 2800 blkno = 2801 (diskaddr_t)scsi_extract_sense_info_descr(sdsp, rqlen); 2802 if (blkno != (diskaddr_t)-1) { 2803 err_print(": block %lld (0x%llx) (", blkno, blkno); 2804 pr_dblock(err_print, blkno); 2805 err_print(")"); 2806 } 2807 2808 err_print("\n"); 2809 2810 err_print("ASC: 0x%x ASCQ: 0x%x\n", 2811 sdsp->ds_add_code, sdsp->ds_qual_code); 2812 break; 2813 case CODE_FMT_FIXED_CURRENT: 2814 case CODE_FMT_FIXED_DEFERRED: 2815 default: 2816 if (rq->es_valid) { 2817 blkno = (rq->es_info_1 << 24) | 2818 (rq->es_info_2 << 16) | 2819 (rq->es_info_3 << 8) | rq->es_info_4; 2820 err_print(": block %lld (0x%llx) (", blkno, blkno); 2821 pr_dblock(err_print, blkno); 2822 err_print(")"); 2823 } 2824 2825 err_print("\n"); 2826 2827 if (rq->es_add_len >= 6) { 2828 err_print("ASC: 0x%x ASCQ: 0x%x\n", 2829 rq->es_add_code, rq->es_qual_code); 2830 } 2831 break; 2832 } 2833 2834 if (option_msg && diag_msg) { 2835 if (rq->es_key == KEY_ILLEGAL_REQUEST) { 2836 dump("cmd: ", (caddr_t)ucmd, 2837 sizeof (struct uscsi_cmd), HEX_ONLY); 2838 dump("cdb: ", (caddr_t)ucmd->uscsi_cdb, 2839 ucmd->uscsi_cdblen, HEX_ONLY); 2840 } 2841 dump("sense: ", (caddr_t)rq, rqlen, HEX_ONLY); 2842 } 2843 2844 if (option_msg) { 2845 switch (rq->es_code) { 2846 case CODE_FMT_DESCR_CURRENT: 2847 case CODE_FMT_DESCR_DEFERRED: 2848 scsi_print_descr_sense(sdsp, rqlen); 2849 break; 2850 case CODE_FMT_FIXED_CURRENT: 2851 case CODE_FMT_FIXED_DEFERRED: 2852 default: 2853 scsi_print_extended_sense(rq, rqlen); 2854 break; 2855 } 2856 } 2857 } 2858 2859 /* 2860 * Retrieve "information" field from descriptor format 2861 * sense data. Iterates through each sense descriptor 2862 * looking for the information descriptor and returns 2863 * the information field from that descriptor. 2864 */ 2865 static diskaddr_t 2866 scsi_extract_sense_info_descr(struct scsi_descr_sense_hdr *sdsp, int rqlen) 2867 { 2868 diskaddr_t result; 2869 uint8_t *descr_offset; 2870 int valid_sense_length; 2871 struct scsi_information_sense_descr *isd; 2872 2873 /* 2874 * Initialize result to -1 indicating there is no information 2875 * descriptor 2876 */ 2877 result = (diskaddr_t)-1; 2878 2879 /* 2880 * The first descriptor will immediately follow the header 2881 */ 2882 descr_offset = (uint8_t *)(sdsp+1); /* Pointer arithmetic */ 2883 2884 /* 2885 * Calculate the amount of valid sense data 2886 */ 2887 valid_sense_length = 2888 min((sizeof (struct scsi_descr_sense_hdr) + 2889 sdsp->ds_addl_sense_length), 2890 rqlen); 2891 2892 /* 2893 * Iterate through the list of descriptors, stopping when we 2894 * run out of sense data 2895 */ 2896 while ((descr_offset + sizeof (struct scsi_information_sense_descr)) <= 2897 (uint8_t *)sdsp + valid_sense_length) { 2898 /* 2899 * Check if this is an information descriptor. We can 2900 * use the scsi_information_sense_descr structure as a 2901 * template sense the first two fields are always the 2902 * same 2903 */ 2904 isd = (struct scsi_information_sense_descr *)descr_offset; 2905 if (isd->isd_descr_type == DESCR_INFORMATION) { 2906 /* 2907 * Found an information descriptor. Copy the 2908 * information field. There will only be one 2909 * information descriptor so we can stop looking. 2910 */ 2911 result = 2912 (((diskaddr_t)isd->isd_information[0] << 56) | 2913 ((diskaddr_t)isd->isd_information[1] << 48) | 2914 ((diskaddr_t)isd->isd_information[2] << 40) | 2915 ((diskaddr_t)isd->isd_information[3] << 32) | 2916 ((diskaddr_t)isd->isd_information[4] << 24) | 2917 ((diskaddr_t)isd->isd_information[5] << 16) | 2918 ((diskaddr_t)isd->isd_information[6] << 8) | 2919 ((diskaddr_t)isd->isd_information[7])); 2920 break; 2921 } 2922 2923 /* 2924 * Get pointer to the next descriptor. The "additional 2925 * length" field holds the length of the descriptor except 2926 * for the "type" and "additional length" fields, so 2927 * we need to add 2 to get the total length. 2928 */ 2929 descr_offset += (isd->isd_addl_length + 2); 2930 } 2931 2932 return (result); 2933 } 2934 2935 /* 2936 * Return a pointer to a string telling us the name of the command. 2937 */ 2938 static char * 2939 scsi_find_command_name(uint_t cmd) 2940 { 2941 struct scsi_command_name *c; 2942 2943 for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++) 2944 if (c->command == cmd) 2945 break; 2946 return (c->name); 2947 } 2948 2949 2950 /* 2951 * Return true if we support a particular mode page 2952 */ 2953 int 2954 scsi_supported_page(int page) { 2955 return (page == 1 || page == 2 || page == 3 || page == 4 || 2956 page == 8 || page == 0x38); 2957 } 2958 2959 2960 int 2961 apply_chg_list(int pageno, int pagsiz, uchar_t *curbits, 2962 uchar_t *chgbits, struct chg_list *chglist) 2963 { 2964 uchar_t c; 2965 int i; 2966 int m; 2967 int delta; 2968 int changed = 0; 2969 2970 while (chglist != NULL) { 2971 if (chglist->pageno == pageno && 2972 chglist->byteno < pagsiz) { 2973 i = chglist->byteno; 2974 c = curbits[i]; 2975 switch (chglist->mode) { 2976 case CHG_MODE_SET: 2977 c |= (uchar_t)chglist->value; 2978 break; 2979 case CHG_MODE_CLR: 2980 c &= (uchar_t)chglist->value; 2981 break; 2982 case CHG_MODE_ABS: 2983 c = (uchar_t)chglist->value; 2984 break; 2985 } 2986 /* 2987 * Figure out which bits changed, and 2988 * are marked as changeable. If this 2989 * result actually differs from the 2990 * current value, update the current 2991 * value, and note that a mode select 2992 * should be done. 2993 */ 2994 delta = c ^ curbits[i]; 2995 for (m = 0x01; m < 0x100; m <<= 1) { 2996 if ((delta & m) && (chgbits[i] & m)) { 2997 curbits[i] ^= m; 2998 changed = 1; 2999 } 3000 } 3001 } 3002 chglist = chglist->next; 3003 } 3004 3005 return (changed); 3006 } 3007 3008 3009 /* 3010 * Return whether a given page is affected by an item on 3011 * the change list. 3012 */ 3013 static int 3014 chg_list_affects_page(chglist, pageno) 3015 struct chg_list *chglist; 3016 int pageno; 3017 { 3018 while (chglist != NULL) { 3019 if (chglist->pageno == pageno) { 3020 return (1); 3021 } 3022 chglist = chglist->next; 3023 } 3024 3025 return (0); 3026 } 3027 3028 3029 /* 3030 * Labels for the various fields of the scsi_extended_sense structure 3031 */ 3032 static char *scsi_extended_sense_labels[] = { 3033 "Request sense valid: ", 3034 "Error class and code: ", 3035 "Segment number: ", 3036 "Filemark: ", 3037 "End-of-medium: ", 3038 "Incorrect length indicator: ", 3039 "Sense key: ", 3040 "Information field: ", 3041 "Additional sense length: ", 3042 "Command-specific information: ", 3043 "Additional sense code: ", 3044 "Additional sense code qualifier: ", 3045 "Field replaceable unit code: ", 3046 "Sense-key specific: ", 3047 "Additional sense bytes: " 3048 }; 3049 3050 3051 /* 3052 * Display the full scsi_extended_sense as returned by the device 3053 */ 3054 static void 3055 scsi_print_extended_sense(rq, rqlen) 3056 struct scsi_extended_sense *rq; 3057 int rqlen; 3058 { 3059 char **p; 3060 3061 p = scsi_extended_sense_labels; 3062 if (rqlen < (sizeof (*rq) - 2) || !rq->es_valid) { 3063 /* 3064 * target should be capable of returning at least 18 3065 * bytes of data, i.e upto rq->es_skey_specific field. 3066 * The additional sense bytes (2 or more ...) are optional. 3067 */ 3068 return; 3069 } 3070 3071 fmt_print("\n%s%s\n", *p++, rq->es_valid ? "yes" : "no"); 3072 fmt_print("%s0x%02x\n", *p++, (rq->es_class << 4) + rq->es_code); 3073 fmt_print("%s%d\n", *p++, rq->es_segnum); 3074 fmt_print("%s%s\n", *p++, rq->es_filmk ? "yes" : "no"); 3075 fmt_print("%s%s\n", *p++, rq->es_eom ? "yes" : "no"); 3076 fmt_print("%s%s\n", *p++, rq->es_ili ? "yes" : "no"); 3077 fmt_print("%s%d\n", *p++, rq->es_key); 3078 3079 fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_info_1, 3080 rq->es_info_2, rq->es_info_3, rq->es_info_4); 3081 fmt_print("%s%d\n", *p++, rq->es_add_len); 3082 fmt_print("%s0x%02x 0x%02x 0x%02x 0x%02x\n", *p++, rq->es_cmd_info[0], 3083 rq->es_cmd_info[1], rq->es_cmd_info[2], rq->es_cmd_info[3]); 3084 fmt_print("%s0x%02x = %d\n", *p++, rq->es_add_code, rq->es_add_code); 3085 fmt_print("%s0x%02x = %d\n", *p++, rq->es_qual_code, rq->es_qual_code); 3086 fmt_print("%s%d\n", *p++, rq->es_fru_code); 3087 fmt_print("%s0x%02x 0x%02x 0x%02x\n", *p++, rq->es_skey_specific[0], 3088 rq->es_skey_specific[1], rq->es_skey_specific[2]); 3089 if (rqlen >= sizeof (*rq)) { 3090 fmt_print("%s0x%02x 0x%02x%s\n", *p, rq->es_add_info[0], 3091 rq->es_add_info[1], (rqlen > sizeof (*rq)) ? " ..." : ""); 3092 } 3093 3094 fmt_print("\n"); 3095 } 3096 3097 /* 3098 * Labels for the various fields of the scsi_descr_sense_hdr structure 3099 */ 3100 static char *scsi_descr_sense_labels[] = { 3101 "Error class and code: ", 3102 "Sense key: ", 3103 "Additional sense length: ", 3104 "Additional sense code: ", 3105 "Additional sense code qualifier: ", 3106 "Additional sense bytes: " 3107 }; 3108 3109 3110 /* 3111 * Display the full descriptor sense data as returned by the device 3112 */ 3113 3114 static void 3115 scsi_print_descr_sense(rq, rqlen) 3116 struct scsi_descr_sense_hdr *rq; 3117 int rqlen; 3118 { 3119 char **p; 3120 uint8_t *descr_offset; 3121 int valid_sense_length; 3122 struct scsi_information_sense_descr *isd; 3123 3124 p = scsi_descr_sense_labels; 3125 if (rqlen < sizeof (struct scsi_descr_sense_hdr)) { 3126 /* 3127 * target must return at least 8 bytes of data 3128 */ 3129 return; 3130 } 3131 3132 /* Print descriptor sense header */ 3133 fmt_print("%s0x%02x\n", *p++, (rq->ds_class << 4) + rq->ds_code); 3134 fmt_print("%s%d\n", *p++, rq->ds_key); 3135 3136 fmt_print("%s%d\n", *p++, rq->ds_addl_sense_length); 3137 fmt_print("%s0x%02x = %d\n", *p++, rq->ds_add_code, rq->ds_add_code); 3138 fmt_print("%s0x%02x = %d\n", *p++, rq->ds_qual_code, rq->ds_qual_code); 3139 fmt_print("\n"); 3140 3141 /* 3142 * Now print any sense descriptors. The first descriptor will 3143 * immediately follow the header 3144 */ 3145 descr_offset = (uint8_t *)(rq+1); /* Pointer arithmetic */ 3146 3147 /* 3148 * Calculate the amount of valid sense data 3149 */ 3150 valid_sense_length = 3151 min((sizeof (struct scsi_descr_sense_hdr) + 3152 rq->ds_addl_sense_length), rqlen); 3153 3154 /* 3155 * Iterate through the list of descriptors, stopping when we 3156 * run out of sense data. Descriptor format is: 3157 * 3158 * <Descriptor type> <Descriptor length> <Descriptor data> ... 3159 */ 3160 while ((descr_offset + *(descr_offset + 1)) <= 3161 (uint8_t *)rq + valid_sense_length) { 3162 /* 3163 * Determine descriptor type. We can use the 3164 * scsi_information_sense_descr structure as a 3165 * template since the first two fields are always the 3166 * same. 3167 */ 3168 isd = (struct scsi_information_sense_descr *)descr_offset; 3169 switch (isd->isd_descr_type) { 3170 case DESCR_INFORMATION: { 3171 uint64_t information; 3172 3173 information = 3174 (((uint64_t)isd->isd_information[0] << 56) | 3175 ((uint64_t)isd->isd_information[1] << 48) | 3176 ((uint64_t)isd->isd_information[2] << 40) | 3177 ((uint64_t)isd->isd_information[3] << 32) | 3178 ((uint64_t)isd->isd_information[4] << 24) | 3179 ((uint64_t)isd->isd_information[5] << 16) | 3180 ((uint64_t)isd->isd_information[6] << 8) | 3181 ((uint64_t)isd->isd_information[7])); 3182 fmt_print("Information field: " 3183 "%0llx\n", information); 3184 break; 3185 } 3186 case DESCR_COMMAND_SPECIFIC: { 3187 struct scsi_cmd_specific_sense_descr *c = 3188 (struct scsi_cmd_specific_sense_descr *)isd; 3189 uint64_t cmd_specific; 3190 3191 cmd_specific = 3192 (((uint64_t)c->css_cmd_specific_info[0] << 56) | 3193 ((uint64_t)c->css_cmd_specific_info[1] << 48) | 3194 ((uint64_t)c->css_cmd_specific_info[2] << 40) | 3195 ((uint64_t)c->css_cmd_specific_info[3] << 32) | 3196 ((uint64_t)c->css_cmd_specific_info[4] << 24) | 3197 ((uint64_t)c->css_cmd_specific_info[5] << 16) | 3198 ((uint64_t)c->css_cmd_specific_info[6] << 8) | 3199 ((uint64_t)c->css_cmd_specific_info[7])); 3200 fmt_print("Command-specific information: " 3201 "%0llx\n", cmd_specific); 3202 break; 3203 } 3204 case DESCR_SENSE_KEY_SPECIFIC: { 3205 struct scsi_sk_specific_sense_descr *ssd = 3206 (struct scsi_sk_specific_sense_descr *)isd; 3207 uint8_t *sk_spec_ptr = (uint8_t *)&ssd->sss_data; 3208 fmt_print("Sense-key specific: " 3209 "0x%02x 0x%02x 0x%02x\n", sk_spec_ptr[0], 3210 sk_spec_ptr[1], sk_spec_ptr[2]); 3211 break; 3212 } 3213 case DESCR_FRU: { 3214 struct scsi_fru_sense_descr *fsd = 3215 (struct scsi_fru_sense_descr *)isd; 3216 fmt_print("Field replaceable unit code: " 3217 "%d\n", fsd->fs_fru_code); 3218 break; 3219 } 3220 case DESCR_BLOCK_COMMANDS: { 3221 struct scsi_block_cmd_sense_descr *bsd = 3222 (struct scsi_block_cmd_sense_descr *)isd; 3223 fmt_print("Incorrect length indicator: " 3224 "%s\n", bsd->bcs_ili ? "yes" : "no"); 3225 break; 3226 } 3227 default: 3228 /* Ignore */ 3229 break; 3230 } 3231 3232 /* 3233 * Get pointer to the next descriptor. The "additional 3234 * length" field holds the length of the descriptor except 3235 * for the "type" and "additional length" fields, so 3236 * we need to add 2 to get the total length. 3237 */ 3238 descr_offset += (isd->isd_addl_length + 2); 3239 } 3240 3241 fmt_print("\n"); 3242 } 3243 3244 /* 3245 * Function checks if READ DEFECT DATA command is supported 3246 * on the current disk. 3247 */ 3248 static int 3249 check_support_for_defects() 3250 { 3251 struct uscsi_cmd ucmd; 3252 union scsi_cdb cdb; 3253 struct scsi_defect_list def_list; 3254 struct scsi_defect_hdr *hdr; 3255 int status; 3256 char rqbuf[255]; 3257 struct scsi_extended_sense *rq; 3258 3259 hdr = (struct scsi_defect_hdr *)&def_list; 3260 3261 /* 3262 * First get length of list by asking for the header only. 3263 */ 3264 (void) memset((char *)&def_list, 0, sizeof (def_list)); 3265 3266 /* 3267 * Build and execute the uscsi ioctl 3268 */ 3269 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 3270 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 3271 (void) memset((char *)rqbuf, 0, 255); 3272 cdb.scc_cmd = SCMD_READ_DEFECT_LIST; 3273 FORMG1COUNT(&cdb, sizeof (struct scsi_defect_hdr)); 3274 cdb.cdb_opaque[2] = DLD_MAN_DEF_LIST | DLD_BFI_FORMAT; 3275 ucmd.uscsi_cdb = (caddr_t)&cdb; 3276 ucmd.uscsi_cdblen = CDB_GROUP1; 3277 ucmd.uscsi_bufaddr = (caddr_t)hdr; 3278 ucmd.uscsi_buflen = sizeof (struct scsi_defect_hdr); 3279 ucmd.uscsi_rqbuf = rqbuf; 3280 ucmd.uscsi_rqlen = sizeof (rqbuf); 3281 ucmd.uscsi_rqresid = sizeof (rqbuf); 3282 rq = (struct scsi_extended_sense *)ucmd.uscsi_rqbuf; 3283 3284 status = uscsi_cmd(cur_file, &ucmd, 3285 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 3286 3287 if (status != 0) { 3288 /* 3289 * check if read_defect_list_is_supported. 3290 */ 3291 if (ucmd.uscsi_rqstatus == STATUS_GOOD && 3292 rq->es_key == KEY_ILLEGAL_REQUEST && 3293 rq->es_add_code == INVALID_OPCODE) 3294 return (0); 3295 } 3296 return (1); 3297 } 3298 3299 /* 3300 * Format the disk, the whole disk, and nothing but the disk. 3301 * Function will be called only for disks 3302 * which do not support read defect list command. 3303 */ 3304 static int 3305 scsi_format_without_defects() 3306 { 3307 struct uscsi_cmd ucmd; 3308 union scsi_cdb cdb; 3309 struct scsi_defect_hdr defect_hdr; 3310 int status; 3311 3312 /* 3313 * Construct the uscsi format ioctl. 3314 * Use fmtdata = 0 , indicating the no source of 3315 * defects information is provided . 3316 * Function will be called only for disks 3317 * which do not support read defect list command. 3318 */ 3319 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 3320 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 3321 (void) memset((char *)&defect_hdr, 0, sizeof (defect_hdr)); 3322 cdb.scc_cmd = SCMD_FORMAT; 3323 ucmd.uscsi_cdb = (caddr_t)&cdb; 3324 ucmd.uscsi_cdblen = CDB_GROUP0; 3325 ucmd.uscsi_bufaddr = (caddr_t)&defect_hdr; 3326 ucmd.uscsi_buflen = sizeof (defect_hdr); 3327 cdb.cdb_opaque[1] = 0; 3328 /* 3329 * Issue the format ioctl 3330 */ 3331 status = uscsi_cmd(cur_file, &ucmd, 3332 (option_msg && diag_msg) ? F_NORMAL : F_SILENT); 3333 return (status); 3334 } 3335 3336 /* 3337 * Name: test_until_ready 3338 * 3339 * Description: This function is used by scsi_format and 3340 * scsi_format_raw to poll the device while the FORMAT 3341 * UNIT cdb in in progress. 3342 * 3343 * Parameters: 3344 * file descriptor to poll 3345 * 3346 * Returns: 3347 * 0 - good status 3348 * !0 - bad status 3349 */ 3350 static int test_until_ready(int fd) { 3351 int status = 1; 3352 struct uscsi_cmd ucmd; 3353 union scsi_cdb cdb; 3354 struct scsi_extended_sense sense; 3355 time_t start, check, time_left; 3356 uint16_t progress; 3357 int hour, min, sec; 3358 3359 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 3360 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 3361 3362 ucmd.uscsi_cdb = (caddr_t)&cdb; 3363 ucmd.uscsi_cdblen = CDB_GROUP0; 3364 ucmd.uscsi_rqbuf = (caddr_t)&sense; 3365 ucmd.uscsi_rqlen = SENSE_LEN; 3366 3367 start = check = time((time_t *)0); 3368 3369 /* Loop sending TEST UNIT READY until format is complete */ 3370 while (status) { 3371 /* clear last request sense data */ 3372 ucmd.uscsi_rqstatus = 0; 3373 ucmd.uscsi_rqresid = 0; 3374 (void) memset((char *)&sense, 0, SENSE_LEN); 3375 3376 /* issue test unit ready */ 3377 status = uscsi_cmd(fd, &ucmd, F_SILENT 3378 | F_RQENABLE); 3379 3380 check = time((time_t *)0); 3381 3382 /* If device returns not ready we get EIO */ 3383 if (status != 0 && errno == EIO) { 3384 /* Check SKSV if progress indication is avail */ 3385 if (sense.es_skey_specific[0] == 0x80) { 3386 /* Store progress indication */ 3387 progress = ((uint16_t)sense. 3388 es_skey_specific[1]) << 8; 3389 progress |= (uint16_t)sense. 3390 es_skey_specific[2]; 3391 progress = (uint16_t)(((float)progress / 3392 (float)PROGRESS_INDICATION_BASE)*100); 3393 3394 fmt_print("\015"); 3395 3396 /* 3397 * check to see if we can estimate 3398 * time remaining - wait until the format 3399 * is at least 5 percent complete to avoid 3400 * wildly-fluctuating time estimates 3401 */ 3402 if ((check - start) <= 0 || progress <= 5) { 3403 /* unable to estimate */ 3404 fmt_print(" %02d%% complete ", 3405 progress); 3406 } else { 3407 /* display with estimated time */ 3408 time_left = (time_t)(((float)(check 3409 - start) / (float)progress) * 3410 (float)(100 - progress)); 3411 sec = time_left % 60; 3412 min = (time_left / 60) % 60; 3413 hour = time_left / 3600; 3414 3415 fmt_print(" %02d%% complete " 3416 "(%02d:%02d:%02d remaining) ", 3417 progress, hour, min, sec); 3418 } 3419 /* flush or the screen will not update */ 3420 (void) fflush(stdout); 3421 } 3422 } else { 3423 /* format not in progress */ 3424 if (option_msg) { 3425 fmt_print("\nRequest Sense ASC=0x%x ASCQ=0x%x", 3426 sense.es_add_code, sense.es_qual_code); 3427 } 3428 break; 3429 } 3430 3431 /* delay so we don't waste cpu time */ 3432 (void) sleep(RETRY_DELAY); 3433 } 3434 return (status); 3435 } 3436