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