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