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