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