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