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