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