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