scsi_subr.c revision 4851:5e98cf4c2164
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2007 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#include <sys/scsi/scsi.h> 30#include <sys/file.h> 31 32/* 33 * Utility SCSI routines 34 */ 35 36/* 37 * Polling support routines 38 */ 39 40extern uintptr_t scsi_callback_id; 41 42/* 43 * Common buffer for scsi_log 44 */ 45 46extern kmutex_t scsi_log_mutex; 47static char scsi_log_buffer[MAXPATHLEN + 1]; 48 49 50#define A_TO_TRAN(ap) (ap->a_hba_tran) 51#define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran) 52#define P_TO_ADDR(pkt) (&((pkt)->pkt_address)) 53 54#define CSEC 10000 /* usecs */ 55#define SEC_TO_CSEC (1000000/CSEC) 56 57extern ddi_dma_attr_t scsi_alloc_attr; 58 59/*PRINTFLIKE4*/ 60static void impl_scsi_log(dev_info_t *dev, char *label, uint_t level, 61 const char *fmt, ...) __KPRINTFLIKE(4); 62/*PRINTFLIKE4*/ 63static void v_scsi_log(dev_info_t *dev, char *label, uint_t level, 64 const char *fmt, va_list ap) __KVPRINTFLIKE(4); 65 66static int 67scsi_get_next_descr(uint8_t *sdsp, 68 int sense_buf_len, struct scsi_descr_template **descrpp); 69 70#define DESCR_GOOD 0 71#define DESCR_PARTIAL 1 72#define DESCR_END 2 73 74static int 75scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp, 76 int valid_sense_length, struct scsi_descr_template *descrp); 77 78int 79scsi_poll(struct scsi_pkt *pkt) 80{ 81 register int busy_count, rval = -1, savef; 82 long savet; 83 void (*savec)(); 84 extern int do_polled_io; 85 86 /* 87 * save old flags.. 88 */ 89 savef = pkt->pkt_flags; 90 savec = pkt->pkt_comp; 91 savet = pkt->pkt_time; 92 93 pkt->pkt_flags |= FLAG_NOINTR; 94 95 /* 96 * XXX there is nothing in the SCSA spec that states that we should not 97 * do a callback for polled cmds; however, removing this will break sd 98 * and probably other target drivers 99 */ 100 pkt->pkt_comp = 0; 101 102 /* 103 * we don't like a polled command without timeout. 104 * 60 seconds seems long enough. 105 */ 106 if (pkt->pkt_time == 0) 107 pkt->pkt_time = SCSI_POLL_TIMEOUT; 108 109 /* 110 * Send polled cmd. 111 * 112 * We do some error recovery for various errors. Tran_busy, 113 * queue full, and non-dispatched commands are retried every 10 msec. 114 * as they are typically transient failures. Busy status is retried 115 * every second as this status takes a while to change. 116 */ 117 for (busy_count = 0; busy_count < (pkt->pkt_time * SEC_TO_CSEC); 118 busy_count++) { 119 int rc; 120 int poll_delay; 121 122 /* 123 * Initialize pkt status variables. 124 */ 125 *pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0; 126 127 if ((rc = scsi_transport(pkt)) != TRAN_ACCEPT) { 128 if (rc != TRAN_BUSY) { 129 /* Transport failed - give up. */ 130 break; 131 } else { 132 /* Transport busy - try again. */ 133 poll_delay = 1 *CSEC; /* 10 msec. */ 134 } 135 } else { 136 /* 137 * Transport accepted - check pkt status. 138 */ 139 rc = (*pkt->pkt_scbp) & STATUS_MASK; 140 141 if (pkt->pkt_reason == CMD_CMPLT && 142 rc == STATUS_GOOD) { 143 /* No error - we're done */ 144 rval = 0; 145 break; 146 147 } else if (pkt->pkt_reason == CMD_INCOMPLETE && 148 pkt->pkt_state == 0) { 149 /* Pkt not dispatched - try again. */ 150 poll_delay = 1 *CSEC; /* 10 msec. */ 151 152 } else if (pkt->pkt_reason == CMD_CMPLT && 153 rc == STATUS_QFULL) { 154 /* Queue full - try again. */ 155 poll_delay = 1 *CSEC; /* 10 msec. */ 156 157 } else if (pkt->pkt_reason == CMD_CMPLT && 158 rc == STATUS_BUSY) { 159 /* Busy - try again. */ 160 poll_delay = 100 *CSEC; /* 1 sec. */ 161 busy_count += (SEC_TO_CSEC - 1); 162 163 } else { 164 /* BAD status - give up. */ 165 break; 166 } 167 } 168 169 if ((curthread->t_flag & T_INTR_THREAD) == 0 && 170 !do_polled_io) { 171 delay(drv_usectohz(poll_delay)); 172 } else { 173 /* we busy wait during cpr_dump or interrupt threads */ 174 drv_usecwait(poll_delay); 175 } 176 } 177 178 pkt->pkt_flags = savef; 179 pkt->pkt_comp = savec; 180 pkt->pkt_time = savet; 181 return (rval); 182} 183 184/* 185 * Command packaging routines. 186 * 187 * makecom_g*() are original routines and scsi_setup_cdb() 188 * is the new and preferred routine. 189 */ 190 191/* 192 * These routines put LUN information in CDB byte 1 bits 7-5. 193 * This was required in SCSI-1. SCSI-2 allowed it but it preferred 194 * sending LUN information as part of IDENTIFY message. 195 * This is not allowed in SCSI-3. 196 */ 197 198void 199makecom_g0(struct scsi_pkt *pkt, struct scsi_device *devp, 200 int flag, int cmd, int addr, int cnt) 201{ 202 MAKECOM_G0(pkt, devp, flag, cmd, addr, (uchar_t)cnt); 203} 204 205void 206makecom_g0_s(struct scsi_pkt *pkt, struct scsi_device *devp, 207 int flag, int cmd, int cnt, int fixbit) 208{ 209 MAKECOM_G0_S(pkt, devp, flag, cmd, cnt, (uchar_t)fixbit); 210} 211 212void 213makecom_g1(struct scsi_pkt *pkt, struct scsi_device *devp, 214 int flag, int cmd, int addr, int cnt) 215{ 216 MAKECOM_G1(pkt, devp, flag, cmd, addr, cnt); 217} 218 219void 220makecom_g5(struct scsi_pkt *pkt, struct scsi_device *devp, 221 int flag, int cmd, int addr, int cnt) 222{ 223 MAKECOM_G5(pkt, devp, flag, cmd, addr, cnt); 224} 225 226/* 227 * Following routine does not put LUN information in CDB. 228 * This interface must be used for SCSI-2 targets having 229 * more than 8 LUNs or a SCSI-3 target. 230 */ 231int 232scsi_setup_cdb(union scsi_cdb *cdbp, uchar_t cmd, uint_t addr, uint_t cnt, 233 uint_t addtl_cdb_data) 234{ 235 uint_t addr_cnt; 236 237 cdbp->scc_cmd = cmd; 238 239 switch (CDB_GROUPID(cmd)) { 240 case CDB_GROUPID_0: 241 /* 242 * The following calculation is to take care of 243 * the fact that format of some 6 bytes tape 244 * command is different (compare 6 bytes disk and 245 * tape read commands). 246 */ 247 addr_cnt = (addr << 8) + cnt; 248 addr = (addr_cnt & 0x1fffff00) >> 8; 249 cnt = addr_cnt & 0xff; 250 FORMG0ADDR(cdbp, addr); 251 FORMG0COUNT(cdbp, cnt); 252 break; 253 254 case CDB_GROUPID_1: 255 case CDB_GROUPID_2: 256 FORMG1ADDR(cdbp, addr); 257 FORMG1COUNT(cdbp, cnt); 258 break; 259 260 case CDB_GROUPID_4: 261 FORMG4ADDR(cdbp, addr); 262 FORMG4COUNT(cdbp, cnt); 263 FORMG4ADDTL(cdbp, addtl_cdb_data); 264 break; 265 266 case CDB_GROUPID_5: 267 FORMG5ADDR(cdbp, addr); 268 FORMG5COUNT(cdbp, cnt); 269 break; 270 271 default: 272 return (0); 273 } 274 275 return (1); 276} 277 278 279/* 280 * Common iopbmap data area packet allocation routines 281 */ 282 283struct scsi_pkt * 284get_pktiopb(struct scsi_address *ap, caddr_t *datap, int cdblen, int statuslen, 285 int datalen, int readflag, int (*func)()) 286{ 287 scsi_hba_tran_t *tran = A_TO_TRAN(ap); 288 dev_info_t *pdip = tran->tran_hba_dip; 289 struct scsi_pkt *pkt = NULL; 290 struct buf local; 291 size_t rlen; 292 293 if (!datap) 294 return (pkt); 295 *datap = (caddr_t)0; 296 bzero((caddr_t)&local, sizeof (struct buf)); 297 298 /* 299 * use i_ddi_mem_alloc() for now until we have an interface to allocate 300 * memory for DMA which doesn't require a DMA handle. ddi_iopb_alloc() 301 * is obsolete and we want more flexibility in controlling the DMA 302 * address constraints. 303 */ 304 if (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen, 305 ((func == SLEEP_FUNC) ? 1 : 0), 0, NULL, &local.b_un.b_addr, &rlen, 306 NULL) != DDI_SUCCESS) { 307 return (pkt); 308 } 309 if (readflag) 310 local.b_flags = B_READ; 311 local.b_bcount = datalen; 312 pkt = (*tran->tran_init_pkt) (ap, NULL, &local, 313 cdblen, statuslen, 0, PKT_CONSISTENT, 314 (func == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC, NULL); 315 if (!pkt) { 316 i_ddi_mem_free(local.b_un.b_addr, NULL); 317 if (func != NULL_FUNC) { 318 ddi_set_callback(func, NULL, &scsi_callback_id); 319 } 320 } else { 321 *datap = local.b_un.b_addr; 322 } 323 return (pkt); 324} 325 326/* 327 * Equivalent deallocation wrapper 328 */ 329 330void 331free_pktiopb(struct scsi_pkt *pkt, caddr_t datap, int datalen) 332{ 333 register struct scsi_address *ap = P_TO_ADDR(pkt); 334 register scsi_hba_tran_t *tran = A_TO_TRAN(ap); 335 336 (*tran->tran_destroy_pkt)(ap, pkt); 337 if (datap && datalen) { 338 i_ddi_mem_free(datap, NULL); 339 } 340 if (scsi_callback_id != 0) { 341 ddi_run_callback(&scsi_callback_id); 342 } 343} 344 345/* 346 * Common naming functions 347 */ 348 349static char scsi_tmpname[64]; 350 351char * 352scsi_dname(int dtyp) 353{ 354 static char *dnames[] = { 355 "Direct Access", 356 "Sequential Access", 357 "Printer", 358 "Processor", 359 "Write-Once/Read-Many", 360 "Read-Only Direct Access", 361 "Scanner", 362 "Optical", 363 "Changer", 364 "Communications", 365 "Array Controller" 366 }; 367 368 if ((dtyp & DTYPE_MASK) <= DTYPE_COMM) { 369 return (dnames[dtyp&DTYPE_MASK]); 370 } else if (dtyp == DTYPE_NOTPRESENT) { 371 return ("Not Present"); 372 } 373 return ("<unknown device type>"); 374 375} 376 377char * 378scsi_rname(uchar_t reason) 379{ 380 static char *rnames[] = { 381 "cmplt", 382 "incomplete", 383 "dma_derr", 384 "tran_err", 385 "reset", 386 "aborted", 387 "timeout", 388 "data_ovr", 389 "cmd_ovr", 390 "sts_ovr", 391 "badmsg", 392 "nomsgout", 393 "xid_fail", 394 "ide_fail", 395 "abort_fail", 396 "reject_fail", 397 "nop_fail", 398 "per_fail", 399 "bdr_fail", 400 "id_fail", 401 "unexpected_bus_free", 402 "tag reject", 403 "terminated" 404 }; 405 if (reason > CMD_TAG_REJECT) { 406 return ("<unknown reason>"); 407 } else { 408 return (rnames[reason]); 409 } 410} 411 412char * 413scsi_mname(uchar_t msg) 414{ 415 static char *imsgs[23] = { 416 "COMMAND COMPLETE", 417 "EXTENDED", 418 "SAVE DATA POINTER", 419 "RESTORE POINTERS", 420 "DISCONNECT", 421 "INITIATOR DETECTED ERROR", 422 "ABORT", 423 "REJECT", 424 "NO-OP", 425 "MESSAGE PARITY", 426 "LINKED COMMAND COMPLETE", 427 "LINKED COMMAND COMPLETE (W/FLAG)", 428 "BUS DEVICE RESET", 429 "ABORT TAG", 430 "CLEAR QUEUE", 431 "INITIATE RECOVERY", 432 "RELEASE RECOVERY", 433 "TERMINATE PROCESS", 434 "CONTINUE TASK", 435 "TARGET TRANSFER DISABLE", 436 "RESERVED (0x14)", 437 "RESERVED (0x15)", 438 "CLEAR ACA" 439 }; 440 static char *imsgs_2[6] = { 441 "SIMPLE QUEUE TAG", 442 "HEAD OF QUEUE TAG", 443 "ORDERED QUEUE TAG", 444 "IGNORE WIDE RESIDUE", 445 "ACA", 446 "LOGICAL UNIT RESET" 447 }; 448 449 if (msg < 23) { 450 return (imsgs[msg]); 451 } else if (IS_IDENTIFY_MSG(msg)) { 452 return ("IDENTIFY"); 453 } else if (IS_2BYTE_MSG(msg) && 454 (int)((msg) & 0xF) < (sizeof (imsgs_2) / sizeof (char *))) { 455 return (imsgs_2[msg & 0xF]); 456 } else { 457 return ("<unknown msg>"); 458 } 459 460} 461 462char * 463scsi_cname(uchar_t cmd, register char **cmdvec) 464{ 465 while (*cmdvec != (char *)0) { 466 if (cmd == **cmdvec) { 467 return ((char *)((long)(*cmdvec)+1)); 468 } 469 cmdvec++; 470 } 471 return (sprintf(scsi_tmpname, "<undecoded cmd 0x%x>", cmd)); 472} 473 474char * 475scsi_cmd_name(uchar_t cmd, struct scsi_key_strings *cmdlist, char *tmpstr) 476{ 477 int i = 0; 478 479 while (cmdlist[i].key != -1) { 480 if (cmd == cmdlist[i].key) { 481 return ((char *)cmdlist[i].message); 482 } 483 i++; 484 } 485 return (sprintf(tmpstr, "<undecoded cmd 0x%x>", cmd)); 486} 487 488static struct scsi_asq_key_strings extended_sense_list[] = { 489 0x00, 0x00, "no additional sense info", 490 0x00, 0x01, "filemark detected", 491 0x00, 0x02, "end of partition/medium detected", 492 0x00, 0x03, "setmark detected", 493 0x00, 0x04, "begining of partition/medium detected", 494 0x00, 0x05, "end of data detected", 495 0x00, 0x06, "i/o process terminated", 496 0x00, 0x11, "audio play operation in progress", 497 0x00, 0x12, "audio play operation paused", 498 0x00, 0x13, "audio play operation successfully completed", 499 0x00, 0x14, "audio play operation stopped due to error", 500 0x00, 0x15, "no current audio status to return", 501 0x00, 0x16, "operation in progress", 502 0x00, 0x17, "cleaning requested", 503 0x00, 0x18, "erase operation in progress", 504 0x00, 0x19, "locate operation in progress", 505 0x00, 0x1A, "rewind operation in progress", 506 0x00, 0x1B, "set capacity operation in progress", 507 0x00, 0x1C, "verify operation in progress", 508 0x01, 0x00, "no index/sector signal", 509 0x02, 0x00, "no seek complete", 510 0x03, 0x00, "peripheral device write fault", 511 0x03, 0x01, "no write current", 512 0x03, 0x02, "excessive write errors", 513 0x04, 0x00, "LUN not ready", 514 0x04, 0x01, "LUN is becoming ready", 515 0x04, 0x02, "LUN initializing command required", 516 0x04, 0x03, "LUN not ready intervention required", 517 0x04, 0x04, "LUN not ready format in progress", 518 0x04, 0x05, "LUN not ready, rebuild in progress", 519 0x04, 0x06, "LUN not ready, recalculation in progress", 520 0x04, 0x07, "LUN not ready, operation in progress", 521 0x04, 0x08, "LUN not ready, long write in progress", 522 0x04, 0x09, "LUN not ready, self-test in progress", 523 0x04, 0x0A, "LUN not accessible, asymmetric access state transition", 524 0x04, 0x0B, "LUN not accessible, target port in standby state", 525 0x04, 0x0C, "LUN not accessible, target port in unavailable state", 526 0x04, 0x10, "LUN not ready, auxiliary memory not accessible", 527 0x05, 0x00, "LUN does not respond to selection", 528 0x06, 0x00, "reference position found", 529 0x07, 0x00, "multiple peripheral devices selected", 530 0x08, 0x00, "LUN communication failure", 531 0x08, 0x01, "LUN communication time-out", 532 0x08, 0x02, "LUN communication parity error", 533 0x08, 0x03, "LUN communication crc error (ultra-DMA/32)", 534 0x08, 0x04, "unreachable copy target", 535 0x09, 0x00, "track following error", 536 0x09, 0x01, "tracking servo failure", 537 0x09, 0x02, "focus servo failure", 538 0x09, 0x03, "spindle servo failure", 539 0x09, 0x04, "head select fault", 540 0x0a, 0x00, "error log overflow", 541 0x0b, 0x00, "warning", 542 0x0b, 0x01, "warning - specified temperature exceeded", 543 0x0b, 0x02, "warning - enclosure degraded", 544 0x0c, 0x00, "write error", 545 0x0c, 0x01, "write error - recovered with auto reallocation", 546 0x0c, 0x02, "write error - auto reallocation failed", 547 0x0c, 0x03, "write error - recommend reassignment", 548 0x0c, 0x04, "compression check miscompare error", 549 0x0c, 0x05, "data expansion occurred during compression", 550 0x0c, 0x06, "block not compressible", 551 0x0c, 0x07, "write error - recovery needed", 552 0x0c, 0x08, "write error - recovery failed", 553 0x0c, 0x09, "write error - loss of streaming", 554 0x0c, 0x0a, "write error - padding blocks added", 555 0x0c, 0x0b, "auxiliary memory write error", 556 0x0c, 0x0c, "write error - unexpected unsolicited data", 557 0x0c, 0x0d, "write error - not enough unsolicited data", 558 0x0d, 0x00, "error detected by third party temporary initiator", 559 0x0d, 0x01, "third party device failure", 560 0x0d, 0x02, "copy target device not reachable", 561 0x0d, 0x03, "incorrect copy target device type", 562 0x0d, 0x04, "copy target device data underrun", 563 0x0d, 0x05, "copy target device data overrun", 564 0x0e, 0x00, "invalid information unit", 565 0x0e, 0x01, "information unit too short", 566 0x0e, 0x02, "information unit too long", 567 0x10, 0x00, "ID CRC or ECC error", 568 0x11, 0x00, "unrecovered read error", 569 0x11, 0x01, "read retries exhausted", 570 0x11, 0x02, "error too long to correct", 571 0x11, 0x03, "multiple read errors", 572 0x11, 0x04, "unrecovered read error - auto reallocate failed", 573 0x11, 0x05, "L-EC uncorrectable error", 574 0x11, 0x06, "CIRC unrecovered error", 575 0x11, 0x07, "data re-synchronization error", 576 0x11, 0x08, "incomplete block read", 577 0x11, 0x09, "no gap found", 578 0x11, 0x0a, "miscorrected error", 579 0x11, 0x0b, "unrecovered read error - recommend reassignment", 580 0x11, 0x0c, "unrecovered read error - recommend rewrite the data", 581 0x11, 0x0d, "de-compression crc error", 582 0x11, 0x0e, "cannot decompress using declared algorithm", 583 0x11, 0x0f, "error reading UPC/EAN number", 584 0x11, 0x10, "error reading ISRC number", 585 0x11, 0x11, "read error - loss of streaming", 586 0x11, 0x12, "auxiliary memory read error", 587 0x11, 0x13, "read error - failed retransmission request", 588 0x12, 0x00, "address mark not found for ID field", 589 0x13, 0x00, "address mark not found for data field", 590 0x14, 0x00, "recorded entity not found", 591 0x14, 0x01, "record not found", 592 0x14, 0x02, "filemark or setmark not found", 593 0x14, 0x03, "end-of-data not found", 594 0x14, 0x04, "block sequence error", 595 0x14, 0x05, "record not found - recommend reassignment", 596 0x14, 0x06, "record not found - data auto-reallocated", 597 0x14, 0x07, "locate operation failure", 598 0x15, 0x00, "random positioning error", 599 0x15, 0x01, "mechanical positioning error", 600 0x15, 0x02, "positioning error detected by read of medium", 601 0x16, 0x00, "data sync mark error", 602 0x16, 0x01, "data sync error - data rewritten", 603 0x16, 0x02, "data sync error - recommend rewrite", 604 0x16, 0x03, "data sync error - data auto-reallocated", 605 0x16, 0x04, "data sync error - recommend reassignment", 606 0x17, 0x00, "recovered data with no error correction", 607 0x17, 0x01, "recovered data with retries", 608 0x17, 0x02, "recovered data with positive head offset", 609 0x17, 0x03, "recovered data with negative head offset", 610 0x17, 0x04, "recovered data with retries and/or CIRC applied", 611 0x17, 0x05, "recovered data using previous sector id", 612 0x17, 0x06, "recovered data without ECC - data auto-reallocated", 613 0x17, 0x07, "recovered data without ECC - recommend reassignment", 614 0x17, 0x08, "recovered data without ECC - recommend rewrite", 615 0x17, 0x09, "recovered data without ECC - data rewritten", 616 0x18, 0x00, "recovered data with error correction", 617 0x18, 0x01, "recovered data with error corr. & retries applied", 618 0x18, 0x02, "recovered data - data auto-reallocated", 619 0x18, 0x03, "recovered data with CIRC", 620 0x18, 0x04, "recovered data with L-EC", 621 0x18, 0x05, "recovered data - recommend reassignment", 622 0x18, 0x06, "recovered data - recommend rewrite", 623 0x18, 0x07, "recovered data with ECC - data rewritten", 624 0x18, 0x08, "recovered data with linking", 625 0x19, 0x00, "defect list error", 626 0x1a, 0x00, "parameter list length error", 627 0x1b, 0x00, "synchronous data xfer error", 628 0x1c, 0x00, "defect list not found", 629 0x1c, 0x01, "primary defect list not found", 630 0x1c, 0x02, "grown defect list not found", 631 0x1d, 0x00, "miscompare during verify", 632 0x1e, 0x00, "recovered ID with ECC", 633 0x1f, 0x00, "partial defect list transfer", 634 0x20, 0x00, "invalid command operation code", 635 0x20, 0x01, "access denied - initiator pending-enrolled", 636 0x20, 0x02, "access denied - no access rights", 637 0x20, 0x03, "access denied - invalid mgmt id key", 638 0x20, 0x04, "illegal command while in write capable state", 639 0x20, 0x06, "illegal command while in explicit address mode", 640 0x20, 0x07, "illegal command while in implicit address mode", 641 0x20, 0x08, "access denied - enrollment conflict", 642 0x20, 0x09, "access denied - invalid lu identifier", 643 0x20, 0x0a, "access denied - invalid proxy token", 644 0x20, 0x0b, "access denied - ACL LUN conflict", 645 0x21, 0x00, "logical block address out of range", 646 0x21, 0x01, "invalid element address", 647 0x21, 0x02, "invalid address for write", 648 0x22, 0x00, "illegal function", 649 0x24, 0x00, "invalid field in cdb", 650 0x24, 0x01, "cdb decryption error", 651 0x25, 0x00, "LUN not supported", 652 0x26, 0x00, "invalid field in param list", 653 0x26, 0x01, "parameter not supported", 654 0x26, 0x02, "parameter value invalid", 655 0x26, 0x03, "threshold parameters not supported", 656 0x26, 0x04, "invalid release of persistent reservation", 657 0x26, 0x05, "data decryption error", 658 0x26, 0x06, "too many target descriptors", 659 0x26, 0x07, "unsupported target descriptor type code", 660 0x26, 0x08, "too many segment descriptors", 661 0x26, 0x09, "unsupported segment descriptor type code", 662 0x26, 0x0a, "unexpected inexact segment", 663 0x26, 0x0b, "inline data length exceeded", 664 0x26, 0x0c, "invalid operation for copy source or destination", 665 0x26, 0x0d, "copy segment granularity violation", 666 0x27, 0x00, "write protected", 667 0x27, 0x01, "hardware write protected", 668 0x27, 0x02, "LUN software write protected", 669 0x27, 0x03, "associated write protect", 670 0x27, 0x04, "persistent write protect", 671 0x27, 0x05, "permanent write protect", 672 0x27, 0x06, "conditional write protect", 673 0x27, 0x80, "unable to overwrite data", 674 0x28, 0x00, "medium may have changed", 675 0x28, 0x01, "import or export element accessed", 676 0x29, 0x00, "power on, reset, or bus reset occurred", 677 0x29, 0x01, "power on occurred", 678 0x29, 0x02, "scsi bus reset occurred", 679 0x29, 0x03, "bus device reset message occurred", 680 0x29, 0x04, "device internal reset", 681 0x29, 0x05, "transceiver mode changed to single-ended", 682 0x29, 0x06, "transceiver mode changed to LVD", 683 0x29, 0x07, "i_t nexus loss occurred", 684 0x2a, 0x00, "parameters changed", 685 0x2a, 0x01, "mode parameters changed", 686 0x2a, 0x02, "log parameters changed", 687 0x2a, 0x03, "reservations preempted", 688 0x2a, 0x04, "reservations released", 689 0x2a, 0x05, "registrations preempted", 690 0x2a, 0x06, "asymmetric access state changed", 691 0x2a, 0x07, "implicit asymmetric access state transition failed", 692 0x2b, 0x00, "copy cannot execute since host cannot disconnect", 693 0x2c, 0x00, "command sequence error", 694 0x2c, 0x03, "current program area is not empty", 695 0x2c, 0x04, "current program area is empty", 696 0x2c, 0x06, "persistent prevent conflict", 697 0x2c, 0x07, "previous busy status", 698 0x2c, 0x08, "previous task set full status", 699 0x2c, 0x09, "previous reservation conflict status", 700 0x2d, 0x00, "overwrite error on update in place", 701 0x2e, 0x00, "insufficient time for operation", 702 0x2f, 0x00, "commands cleared by another initiator", 703 0x30, 0x00, "incompatible medium installed", 704 0x30, 0x01, "cannot read medium - unknown format", 705 0x30, 0x02, "cannot read medium - incompatible format", 706 0x30, 0x03, "cleaning cartridge installed", 707 0x30, 0x04, "cannot write medium - unknown format", 708 0x30, 0x05, "cannot write medium - incompatible format", 709 0x30, 0x06, "cannot format medium - incompatible medium", 710 0x30, 0x07, "cleaning failure", 711 0x30, 0x08, "cannot write - application code mismatch", 712 0x30, 0x09, "current session not fixated for append", 713 0x30, 0x0b, "WORM medium - Overwrite attempted", 714 0x30, 0x0c, "WORM medium - Cannot Erase", 715 0x30, 0x0d, "WORM medium - Integrity Check", 716 0x30, 0x10, "medium not formatted", 717 0x31, 0x00, "medium format corrupted", 718 0x31, 0x01, "format command failed", 719 0x31, 0x02, "zoned formatting failed due to spare linking", 720 0x31, 0x94, "WORM media corrupted", 721 0x32, 0x00, "no defect spare location available", 722 0x32, 0x01, "defect list update failure", 723 0x33, 0x00, "tape length error", 724 0x34, 0x00, "enclosure failure", 725 0x35, 0x00, "enclosure services failure", 726 0x35, 0x01, "unsupported enclosure function", 727 0x35, 0x02, "enclosure services unavailable", 728 0x35, 0x03, "enclosure services transfer failure", 729 0x35, 0x04, "enclosure services transfer refused", 730 0x36, 0x00, "ribbon, ink, or toner failure", 731 0x37, 0x00, "rounded parameter", 732 0x39, 0x00, "saving parameters not supported", 733 0x3a, 0x00, "medium not present", 734 0x3a, 0x01, "medium not present - tray closed", 735 0x3a, 0x02, "medium not present - tray open", 736 0x3a, 0x03, "medium not present - loadable", 737 0x3a, 0x04, "medium not present - medium auxiliary memory accessible", 738 0x3b, 0x00, "sequential positioning error", 739 0x3b, 0x01, "tape position error at beginning-of-medium", 740 0x3b, 0x02, "tape position error at end-of-medium", 741 0x3b, 0x08, "reposition error", 742 0x3b, 0x0c, "position past beginning of medium", 743 0x3b, 0x0d, "medium destination element full", 744 0x3b, 0x0e, "medium source element empty", 745 0x3b, 0x0f, "end of medium reached", 746 0x3b, 0x11, "medium magazine not accessible", 747 0x3b, 0x12, "medium magazine removed", 748 0x3b, 0x13, "medium magazine inserted", 749 0x3b, 0x14, "medium magazine locked", 750 0x3b, 0x15, "medium magazine unlocked", 751 0x3b, 0x16, "mechanical positioning or changer error", 752 0x3d, 0x00, "invalid bits in indentify message", 753 0x3e, 0x00, "LUN has not self-configured yet", 754 0x3e, 0x01, "LUN failure", 755 0x3e, 0x02, "timeout on LUN", 756 0x3e, 0x03, "LUN failed self-test", 757 0x3e, 0x04, "LUN unable to update self-test log", 758 0x3f, 0x00, "target operating conditions have changed", 759 0x3f, 0x01, "microcode has been changed", 760 0x3f, 0x02, "changed operating definition", 761 0x3f, 0x03, "inquiry data has changed", 762 0x3f, 0x04, "component device attached", 763 0x3f, 0x05, "device identifier changed", 764 0x3f, 0x06, "redundancy group created or modified", 765 0x3f, 0x07, "redundancy group deleted", 766 0x3f, 0x08, "spare created or modified", 767 0x3f, 0x09, "spare deleted", 768 0x3f, 0x0a, "volume set created or modified", 769 0x3f, 0x0b, "volume set deleted", 770 0x3f, 0x0c, "volume set deassigned", 771 0x3f, 0x0d, "volume set reassigned", 772 0x3f, 0x0e, "reported LUNs data has changed", 773 0x3f, 0x0f, "echo buffer overwritten", 774 0x3f, 0x10, "medium loadable", 775 0x3f, 0x11, "medium auxiliary memory accessible", 776 0x40, 0x00, "ram failure", 777 0x41, 0x00, "data path failure", 778 0x42, 0x00, "power-on or self-test failure", 779 0x43, 0x00, "message error", 780 0x44, 0x00, "internal target failure", 781 0x45, 0x00, "select or reselect failure", 782 0x46, 0x00, "unsuccessful soft reset", 783 0x47, 0x00, "scsi parity error", 784 0x47, 0x01, "data phase crc error detected", 785 0x47, 0x02, "scsi parity error detected during st data phase", 786 0x47, 0x03, "information unit iucrc error detected", 787 0x47, 0x04, "asynchronous information protection error detected", 788 0x47, 0x05, "protocol service crc error", 789 0x47, 0x7f, "some commands cleared by iscsi protocol event", 790 0x48, 0x00, "initiator detected error message received", 791 0x49, 0x00, "invalid message error", 792 0x4a, 0x00, "command phase error", 793 0x4b, 0x00, "data phase error", 794 0x4b, 0x01, "invalid target port transfer tag received", 795 0x4b, 0x02, "too much write data", 796 0x4b, 0x03, "ack/nak timeout", 797 0x4b, 0x04, "nak received", 798 0x4b, 0x05, "data offset error", 799 0x4c, 0x00, "logical unit failed self-configuration", 800 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)", 801 0x4e, 0x00, "overlapped commands attempted", 802 0x50, 0x00, "write append error", 803 0x50, 0x01, "data protect write append error", 804 0x50, 0x95, "data protect write append error", 805 0x51, 0x00, "erase failure", 806 0x52, 0x00, "cartridge fault", 807 0x53, 0x00, "media load or eject failed", 808 0x53, 0x01, "unload tape failure", 809 0x53, 0x02, "medium removal prevented", 810 0x54, 0x00, "scsi to host system interface failure", 811 0x55, 0x00, "system resource failure", 812 0x55, 0x01, "system buffer full", 813 0x55, 0x02, "insufficient reservation resources", 814 0x55, 0x03, "insufficient resources", 815 0x55, 0x04, "insufficient registration resources", 816 0x55, 0x05, "insufficient access control resources", 817 0x55, 0x06, "auxiliary memory out of space", 818 0x57, 0x00, "unable to recover TOC", 819 0x58, 0x00, "generation does not exist", 820 0x59, 0x00, "updated block read", 821 0x5a, 0x00, "operator request or state change input", 822 0x5a, 0x01, "operator medium removal request", 823 0x5a, 0x02, "operator selected write protect", 824 0x5a, 0x03, "operator selected write permit", 825 0x5b, 0x00, "log exception", 826 0x5b, 0x01, "threshold condition met", 827 0x5b, 0x02, "log counter at maximum", 828 0x5b, 0x03, "log list codes exhausted", 829 0x5c, 0x00, "RPL status change", 830 0x5c, 0x01, "spindles synchronized", 831 0x5c, 0x02, "spindles not synchronized", 832 0x5d, 0x00, "drive operation marginal, service immediately" 833 " (failure prediction threshold exceeded)", 834 0x5d, 0x01, "media failure prediction threshold exceeded", 835 0x5d, 0x02, "LUN failure prediction threshold exceeded", 836 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded", 837 0x5d, 0x10, "hardware impending failure general hard drive failure", 838 0x5d, 0x11, "hardware impending failure drive error rate too high", 839 0x5d, 0x12, "hardware impending failure data error rate too high", 840 0x5d, 0x13, "hardware impending failure seek error rate too high", 841 0x5d, 0x14, "hardware impending failure too many block reassigns", 842 0x5d, 0x15, "hardware impending failure access times too high", 843 0x5d, 0x16, "hardware impending failure start unit times too high", 844 0x5d, 0x17, "hardware impending failure channel parametrics", 845 0x5d, 0x18, "hardware impending failure controller detected", 846 0x5d, 0x19, "hardware impending failure throughput performance", 847 0x5d, 0x1a, "hardware impending failure seek time performance", 848 0x5d, 0x1b, "hardware impending failure spin-up retry count", 849 0x5d, 0x1c, "hardware impending failure drive calibration retry count", 850 0x5d, 0x20, "controller impending failure general hard drive failure", 851 0x5d, 0x21, "controller impending failure drive error rate too high", 852 0x5d, 0x22, "controller impending failure data error rate too high", 853 0x5d, 0x23, "controller impending failure seek error rate too high", 854 0x5d, 0x24, "controller impending failure too many block reassigns", 855 0x5d, 0x25, "controller impending failure access times too high", 856 0x5d, 0x26, "controller impending failure start unit times too high", 857 0x5d, 0x27, "controller impending failure channel parametrics", 858 0x5d, 0x28, "controller impending failure controller detected", 859 0x5d, 0x29, "controller impending failure throughput performance", 860 0x5d, 0x2a, "controller impending failure seek time performance", 861 0x5d, 0x2b, "controller impending failure spin-up retry count", 862 0x5d, 0x2c, "controller impending failure drive calibration retry cnt", 863 0x5d, 0x30, "data channel impending failure general hard drive failure", 864 0x5d, 0x31, "data channel impending failure drive error rate too high", 865 0x5d, 0x32, "data channel impending failure data error rate too high", 866 0x5d, 0x33, "data channel impending failure seek error rate too high", 867 0x5d, 0x34, "data channel impending failure too many block reassigns", 868 0x5d, 0x35, "data channel impending failure access times too high", 869 0x5d, 0x36, "data channel impending failure start unit times too high", 870 0x5d, 0x37, "data channel impending failure channel parametrics", 871 0x5d, 0x38, "data channel impending failure controller detected", 872 0x5d, 0x39, "data channel impending failure throughput performance", 873 0x5d, 0x3a, "data channel impending failure seek time performance", 874 0x5d, 0x3b, "data channel impending failure spin-up retry count", 875 0x5d, 0x3c, "data channel impending failure drive calibrate retry cnt", 876 0x5d, 0x40, "servo impending failure general hard drive failure", 877 0x5d, 0x41, "servo impending failure drive error rate too high", 878 0x5d, 0x42, "servo impending failure data error rate too high", 879 0x5d, 0x43, "servo impending failure seek error rate too high", 880 0x5d, 0x44, "servo impending failure too many block reassigns", 881 0x5d, 0x45, "servo impending failure access times too high", 882 0x5d, 0x46, "servo impending failure start unit times too high", 883 0x5d, 0x47, "servo impending failure channel parametrics", 884 0x5d, 0x48, "servo impending failure controller detected", 885 0x5d, 0x49, "servo impending failure throughput performance", 886 0x5d, 0x4a, "servo impending failure seek time performance", 887 0x5d, 0x4b, "servo impending failure spin-up retry count", 888 0x5d, 0x4c, "servo impending failure drive calibration retry count", 889 0x5d, 0x50, "spindle impending failure general hard drive failure", 890 0x5d, 0x51, "spindle impending failure drive error rate too high", 891 0x5d, 0x52, "spindle impending failure data error rate too high", 892 0x5d, 0x53, "spindle impending failure seek error rate too high", 893 0x5d, 0x54, "spindle impending failure too many block reassigns", 894 0x5d, 0x55, "spindle impending failure access times too high", 895 0x5d, 0x56, "spindle impending failure start unit times too high", 896 0x5d, 0x57, "spindle impending failure channel parametrics", 897 0x5d, 0x58, "spindle impending failure controller detected", 898 0x5d, 0x59, "spindle impending failure throughput performance", 899 0x5d, 0x5a, "spindle impending failure seek time performance", 900 0x5d, 0x5b, "spindle impending failure spin-up retry count", 901 0x5d, 0x5c, "spindle impending failure drive calibration retry count", 902 0x5d, 0x60, "firmware impending failure general hard drive failure", 903 0x5d, 0x61, "firmware impending failure drive error rate too high", 904 0x5d, 0x62, "firmware impending failure data error rate too high", 905 0x5d, 0x63, "firmware impending failure seek error rate too high", 906 0x5d, 0x64, "firmware impending failure too many block reassigns", 907 0x5d, 0x65, "firmware impending failure access times too high", 908 0x5d, 0x66, "firmware impending failure start unit times too high", 909 0x5d, 0x67, "firmware impending failure channel parametrics", 910 0x5d, 0x68, "firmware impending failure controller detected", 911 0x5d, 0x69, "firmware impending failure throughput performance", 912 0x5d, 0x6a, "firmware impending failure seek time performance", 913 0x5d, 0x6b, "firmware impending failure spin-up retry count", 914 0x5d, 0x6c, "firmware impending failure drive calibration retry count", 915 0x5d, 0xff, "failure prediction threshold exceeded (false)", 916 0x5e, 0x00, "low power condition active", 917 0x5e, 0x01, "idle condition activated by timer", 918 0x5e, 0x02, "standby condition activated by timer", 919 0x5e, 0x03, "idle condition activated by command", 920 0x5e, 0x04, "standby condition activated by command", 921 0x60, 0x00, "lamp failure", 922 0x61, 0x00, "video aquisition error", 923 0x62, 0x00, "scan head positioning error", 924 0x63, 0x00, "end of user area encountered on this track", 925 0x63, 0x01, "packet does not fit in available space", 926 0x64, 0x00, "illegal mode for this track", 927 0x64, 0x01, "invalid packet size", 928 0x65, 0x00, "voltage fault", 929 0x66, 0x00, "automatic document feeder cover up", 930 0x67, 0x00, "configuration failure", 931 0x67, 0x01, "configuration of incapable LUNs failed", 932 0x67, 0x02, "add LUN failed", 933 0x67, 0x03, "modification of LUN failed", 934 0x67, 0x04, "exchange of LUN failed", 935 0x67, 0x05, "remove of LUN failed", 936 0x67, 0x06, "attachment of LUN failed", 937 0x67, 0x07, "creation of LUN failed", 938 0x67, 0x08, "assign failure occurred", 939 0x67, 0x09, "multiply assigned LUN", 940 0x67, 0x0a, "set target port groups command failed", 941 0x68, 0x00, "logical unit not configured", 942 0x69, 0x00, "data loss on logical unit", 943 0x69, 0x01, "multiple LUN failures", 944 0x69, 0x02, "parity/data mismatch", 945 0x6a, 0x00, "informational, refer to log", 946 0x6b, 0x00, "state change has occured", 947 0x6b, 0x01, "redundancy level got better", 948 0x6b, 0x02, "redundancy level got worse", 949 0x6c, 0x00, "rebuild failure occured", 950 0x6d, 0x00, "recalculate failure occured", 951 0x6e, 0x00, "command to logical unit failed", 952 0x6f, 0x00, "copy protect key exchange failure authentication failure", 953 0x6f, 0x01, "copy protect key exchange failure key not present", 954 0x6f, 0x02, "copy protect key exchange failure key not established", 955 0x6f, 0x03, "read of scrambled sector without authentication", 956 0x6f, 0x04, "media region code is mismatched to LUN region", 957 0x6f, 0x05, "drive region must be permanent/region reset count error", 958 0x70, 0xffff, "decompression exception short algorithm id of ASCQ", 959 0x71, 0x00, "decompression exception long algorithm id", 960 0x72, 0x00, "session fixation error", 961 0x72, 0x01, "session fixation error writing lead-in", 962 0x72, 0x02, "session fixation error writing lead-out", 963 0x72, 0x03, "session fixation error - incomplete track in session", 964 0x72, 0x04, "empty or partially written reserved track", 965 0x72, 0x05, "no more track reservations allowed", 966 0x73, 0x00, "cd control error", 967 0x73, 0x01, "power calibration area almost full", 968 0x73, 0x02, "power calibration area is full", 969 0x73, 0x03, "power calibration area error", 970 0x73, 0x04, "program memory area update failure", 971 0x73, 0x05, "program memory area is full", 972 0x73, 0x06, "rma/pma is almost full", 973 0xffff, 0xffff, NULL 974}; 975 976char * 977scsi_esname(uint_t key, char *tmpstr) 978{ 979 int i = 0; 980 981 while (extended_sense_list[i].asc != 0xffff) { 982 if (key == extended_sense_list[i].asc) { 983 return ((char *)extended_sense_list[i].message); 984 } 985 i++; 986 } 987 return (sprintf(tmpstr, "<vendor unique code 0x%x>", key)); 988} 989 990char * 991scsi_asc_name(uint_t asc, uint_t ascq, char *tmpstr) 992{ 993 int i = 0; 994 995 while (extended_sense_list[i].asc != 0xffff) { 996 if ((asc == extended_sense_list[i].asc) && 997 ((ascq == extended_sense_list[i].ascq) || 998 (extended_sense_list[i].ascq == 0xffff))) { 999 return ((char *)extended_sense_list[i].message); 1000 } 1001 i++; 1002 } 1003 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc)); 1004} 1005 1006char * 1007scsi_sname(uchar_t sense_key) 1008{ 1009 if (sense_key >= (uchar_t)(NUM_SENSE_KEYS+NUM_IMPL_SENSE_KEYS)) { 1010 return ("<unknown sense key>"); 1011 } else { 1012 return (sense_keys[sense_key]); 1013 } 1014} 1015 1016 1017/* 1018 * Print a piece of inquiry data- cleaned up for non-printable characters. 1019 */ 1020 1021static void 1022inq_fill(char *p, int l, char *s) 1023{ 1024 register unsigned i = 0; 1025 char c; 1026 1027 if (!p) 1028 return; 1029 1030 while (i++ < l) { 1031 /* clean string of non-printing chars */ 1032 if ((c = *p++) < ' ' || c >= 0177) { 1033 c = ' '; 1034 } 1035 *s++ = c; 1036 } 1037 *s++ = 0; 1038} 1039 1040static char * 1041scsi_asc_search(uint_t asc, uint_t ascq, 1042 struct scsi_asq_key_strings *list) 1043{ 1044 int i = 0; 1045 1046 while (list[i].asc != 0xffff) { 1047 if ((asc == list[i].asc) && 1048 ((ascq == list[i].ascq) || 1049 (list[i].ascq == 0xffff))) { 1050 return ((char *)list[i].message); 1051 } 1052 i++; 1053 } 1054 return (NULL); 1055} 1056 1057static char * 1058scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr, 1059 struct scsi_asq_key_strings *list) 1060{ 1061 char *message; 1062 1063 if (list) { 1064 if (message = scsi_asc_search(asc, ascq, list)) { 1065 return (message); 1066 } 1067 } 1068 if (message = scsi_asc_search(asc, ascq, extended_sense_list)) { 1069 return (message); 1070 } 1071 1072 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc)); 1073} 1074 1075/* 1076 * The first part/column of the error message will be at least this length. 1077 * This number has been calculated so that each line fits in 80 chars. 1078 */ 1079#define SCSI_ERRMSG_COLUMN_LEN 42 1080#define SCSI_ERRMSG_BUF_LEN 256 1081 1082void 1083scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label, 1084 int severity, daddr_t blkno, daddr_t err_blkno, 1085 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep, 1086 struct scsi_asq_key_strings *asc_list, 1087 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t)) 1088{ 1089 uchar_t com; 1090 static char buf[SCSI_ERRMSG_BUF_LEN]; 1091 static char buf1[SCSI_ERRMSG_BUF_LEN]; 1092 static char tmpbuf[64]; 1093 static char pad[SCSI_ERRMSG_COLUMN_LEN]; 1094 dev_info_t *dev = devp->sd_dev; 1095 static char *error_classes[] = { 1096 "All", "Unknown", "Informational", 1097 "Recovered", "Retryable", "Fatal" 1098 }; 1099 uchar_t sense_key, asc, ascq, fru_code; 1100 uchar_t *fru_code_ptr; 1101 int i, buflen; 1102 1103 mutex_enter(&scsi_log_mutex); 1104 1105 /* 1106 * We need to put our space padding code because kernel version 1107 * of sprintf(9F) doesn't support %-<number>s type of left alignment. 1108 */ 1109 for (i = 0; i < SCSI_ERRMSG_COLUMN_LEN; i++) { 1110 pad[i] = ' '; 1111 } 1112 1113 bzero(buf, 256); 1114 com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd; 1115 (void) sprintf(buf, "Error for Command: %s", 1116 scsi_cmd_name(com, cmdlist, tmpbuf)); 1117 buflen = strlen(buf); 1118 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1119 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1120 (void) sprintf(&buf[buflen], "%s Error Level: %s", 1121 pad, error_classes[severity]); 1122 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1123 } else { 1124 (void) sprintf(&buf[buflen], " Error Level: %s", 1125 error_classes[severity]); 1126 } 1127 impl_scsi_log(dev, label, CE_WARN, buf); 1128 1129 if (blkno != -1 || err_blkno != -1 && 1130 ((com & 0xf) == SCMD_READ) || ((com & 0xf) == SCMD_WRITE)) { 1131 bzero(buf, 256); 1132 (void) sprintf(buf, "Requested Block: %ld", blkno); 1133 buflen = strlen(buf); 1134 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1135 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1136 (void) sprintf(&buf[buflen], "%s Error Block: %ld\n", 1137 pad, err_blkno); 1138 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1139 } else { 1140 (void) sprintf(&buf[buflen], " Error Block: %ld\n", 1141 err_blkno); 1142 } 1143 impl_scsi_log(dev, label, CE_CONT, buf); 1144 } 1145 1146 bzero(buf, 256); 1147 (void) strcpy(buf, "Vendor: "); 1148 inq_fill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]); 1149 buflen = strlen(buf); 1150 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1151 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1152 (void) sprintf(&buf[strlen(buf)], "%s Serial Number: ", pad); 1153 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1154 } else { 1155 (void) sprintf(&buf[strlen(buf)], " Serial Number: "); 1156 } 1157 inq_fill(devp->sd_inq->inq_serial, 12, &buf[strlen(buf)]); 1158 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf); 1159 1160 if (sensep) { 1161 sense_key = scsi_sense_key((uint8_t *)sensep); 1162 asc = scsi_sense_asc((uint8_t *)sensep); 1163 ascq = scsi_sense_ascq((uint8_t *)sensep); 1164 scsi_ext_sense_fields((uint8_t *)sensep, SENSE_LENGTH, 1165 NULL, NULL, &fru_code_ptr, NULL, NULL); 1166 fru_code = (fru_code_ptr ? *fru_code_ptr : 0); 1167 1168 bzero(buf, 256); 1169 (void) sprintf(buf, "Sense Key: %s\n", 1170 sense_keys[sense_key]); 1171 impl_scsi_log(dev, label, CE_CONT, buf); 1172 1173 bzero(buf, 256); 1174 if ((fru_code != 0) && 1175 (decode_fru != NULL)) { 1176 (*decode_fru)(devp, buf, SCSI_ERRMSG_BUF_LEN, 1177 fru_code); 1178 if (buf[0] != NULL) { 1179 bzero(buf1, 256); 1180 (void) sprintf(&buf1[strlen(buf1)], 1181 "ASC: 0x%x (%s)", asc, 1182 scsi_asc_ascq_name(asc, ascq, 1183 tmpbuf, asc_list)); 1184 buflen = strlen(buf1); 1185 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1186 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = 1187 '\0'; 1188 (void) sprintf(&buf1[buflen], 1189 "%s ASCQ: 0x%x", pad, ascq); 1190 } else { 1191 (void) sprintf(&buf1[buflen], 1192 " ASCQ: 0x%x", ascq); 1193 } 1194 impl_scsi_log(dev, 1195 label, CE_CONT, "%s\n", buf1); 1196 impl_scsi_log(dev, 1197 label, CE_CONT, "FRU: 0x%x (%s)\n", 1198 fru_code, buf); 1199 mutex_exit(&scsi_log_mutex); 1200 return; 1201 } 1202 } 1203 (void) sprintf(&buf[strlen(buf)], 1204 "ASC: 0x%x (%s), ASCQ: 0x%x, FRU: 0x%x", 1205 asc, scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list), 1206 ascq, fru_code); 1207 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf); 1208 } 1209 mutex_exit(&scsi_log_mutex); 1210} 1211 1212void 1213scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label, 1214 int severity, daddr_t blkno, daddr_t err_blkno, 1215 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep) 1216{ 1217 scsi_vu_errmsg(devp, pkt, label, severity, blkno, 1218 err_blkno, cmdlist, sensep, NULL, NULL); 1219} 1220 1221/*PRINTFLIKE4*/ 1222void 1223scsi_log(dev_info_t *dev, char *label, uint_t level, 1224 const char *fmt, ...) 1225{ 1226 va_list ap; 1227 1228 va_start(ap, fmt); 1229 mutex_enter(&scsi_log_mutex); 1230 v_scsi_log(dev, label, level, fmt, ap); 1231 mutex_exit(&scsi_log_mutex); 1232 va_end(ap); 1233} 1234 1235/*PRINTFLIKE4*/ 1236static void 1237impl_scsi_log(dev_info_t *dev, char *label, uint_t level, 1238 const char *fmt, ...) 1239{ 1240 va_list ap; 1241 1242 ASSERT(mutex_owned(&scsi_log_mutex)); 1243 1244 va_start(ap, fmt); 1245 v_scsi_log(dev, label, level, fmt, ap); 1246 va_end(ap); 1247} 1248 1249 1250char *ddi_pathname(dev_info_t *dip, char *path); 1251 1252/*PRINTFLIKE4*/ 1253static void 1254v_scsi_log(dev_info_t *dev, char *label, uint_t level, 1255 const char *fmt, va_list ap) 1256{ 1257 static char name[256]; 1258 int log_only = 0; 1259 int boot_only = 0; 1260 int console_only = 0; 1261 1262 ASSERT(mutex_owned(&scsi_log_mutex)); 1263 1264 if (dev) { 1265 if (level == CE_PANIC || level == CE_WARN || 1266 level == CE_NOTE) { 1267 (void) sprintf(name, "%s (%s%d):\n", 1268 ddi_pathname(dev, scsi_log_buffer), 1269 label, ddi_get_instance(dev)); 1270 } else if (level >= (uint_t)SCSI_DEBUG) { 1271 (void) sprintf(name, 1272 "%s%d:", label, ddi_get_instance(dev)); 1273 } else { 1274 name[0] = '\0'; 1275 } 1276 } else { 1277 (void) sprintf(name, "%s:", label); 1278 } 1279 1280 (void) vsprintf(scsi_log_buffer, fmt, ap); 1281 1282 switch (scsi_log_buffer[0]) { 1283 case '!': 1284 log_only = 1; 1285 break; 1286 case '?': 1287 boot_only = 1; 1288 break; 1289 case '^': 1290 console_only = 1; 1291 break; 1292 } 1293 1294 switch (level) { 1295 case CE_NOTE: 1296 level = CE_CONT; 1297 /* FALLTHROUGH */ 1298 case CE_CONT: 1299 case CE_WARN: 1300 case CE_PANIC: 1301 if (boot_only) { 1302 cmn_err(level, "?%s\t%s", name, &scsi_log_buffer[1]); 1303 } else if (console_only) { 1304 cmn_err(level, "^%s\t%s", name, &scsi_log_buffer[1]); 1305 } else if (log_only) { 1306 cmn_err(level, "!%s\t%s", name, &scsi_log_buffer[1]); 1307 } else { 1308 cmn_err(level, "%s\t%s", name, scsi_log_buffer); 1309 } 1310 break; 1311 case (uint_t)SCSI_DEBUG: 1312 default: 1313 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, scsi_log_buffer); 1314 break; 1315 } 1316} 1317 1318/* 1319 * Lookup the 'prop_name' string array property and walk thru its list of 1320 * tuple values looking for a tuple who's VID/PID string (first part of tuple) 1321 * matches the inquiry VID/PID information for the scsi_device. On a match, 1322 * return a duplicate of the second part of the tuple. If no match is found, 1323 * return NULL. On non-NULL return, caller is responsible for freeing return 1324 * result via: 1325 * kmem_free(string, strlen(string) + 1); 1326 * 1327 * This interface can either be used directly, or indirectly by 1328 * scsi_get_device_type_scsi_options. 1329 */ 1330char * 1331scsi_get_device_type_string(char *prop_name, 1332 dev_info_t *dip, struct scsi_device *devp) 1333{ 1334 struct scsi_inquiry *inq = devp->sd_inq; 1335 char **tuples; 1336 uint_t ntuples; 1337 int i; 1338 char *tvp; /* tuple vid/pid */ 1339 char *trs; /* tuple return string */ 1340 int tvp_len; 1341 1342 /* if we have no inquiry data then we can't do this */ 1343 if (inq == NULL) 1344 return (NULL); 1345 1346 /* 1347 * So that we can establish a 'prop_name' for all instances of a 1348 * device in the system in a single place if needed (via options.conf), 1349 * we loop going up to the root ourself. This way root lookup does 1350 * *not* specify DDI_PROP_DONTPASS, and the code will look on the 1351 * options node. 1352 */ 1353 do { 1354 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 1355 (ddi_get_parent(dip) ? DDI_PROP_DONTPASS : 0) | 1356 DDI_PROP_NOTPROM, prop_name, &tuples, &ntuples) == 1357 DDI_PROP_SUCCESS) { 1358 1359 /* loop over tuples */ 1360 for (i = 0; i < (ntuples/2); i++) { 1361 /* split into vid/pid and return-string */ 1362 tvp = tuples[i * 2]; 1363 trs = tuples[(i * 2) + 1]; 1364 tvp_len = strlen(tvp); 1365 1366 /* check for vid/pid match */ 1367 if ((tvp_len == 0) || 1368 bcmp(tvp, inq->inq_vid, tvp_len)) 1369 continue; /* no match */ 1370 1371 /* match, dup return-string */ 1372 trs = i_ddi_strdup(trs, KM_SLEEP); 1373 ddi_prop_free(tuples); 1374 return (trs); 1375 } 1376 ddi_prop_free(tuples); 1377 } 1378 1379 /* climb up to root one step at a time */ 1380 dip = ddi_get_parent(dip); 1381 } while (dip); 1382 1383 return (NULL); 1384} 1385 1386/* 1387 * The 'device-type-scsi-options' mechanism can be used to establish a device 1388 * specific scsi_options value for a particular device. This mechanism uses 1389 * paired strings ("vendor_info", "options_property_name") from the string 1390 * array "device-type-scsi-options" definition. A bcmp of the vendor info is 1391 * done against the inquiry data (inq_vid). Here is an example of use: 1392 * 1393 * device-type-scsi-options-list = 1394 * "FOOLCO Special x1000", "foolco-scsi-options", 1395 * "FOOLCO Special y1000", "foolco-scsi-options"; 1396 * foolco-scsi-options = 0xXXXXXXXX; 1397 */ 1398int 1399scsi_get_device_type_scsi_options(dev_info_t *dip, 1400 struct scsi_device *devp, int options) 1401{ 1402 char *string; 1403 1404 if ((string = scsi_get_device_type_string( 1405 "device-type-scsi-options-list", dip, devp)) != NULL) { 1406 options = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 1407 string, options); 1408 kmem_free(string, strlen(string) + 1); 1409 } 1410 return (options); 1411} 1412 1413/* 1414 * Functions for format-neutral sense data functions 1415 */ 1416int 1417scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags) 1418{ 1419 int result; 1420 struct scsi_extended_sense *es = 1421 (struct scsi_extended_sense *)sense_buffer; 1422 1423 /* 1424 * Init flags if present 1425 */ 1426 if (flags != NULL) { 1427 *flags = 0; 1428 } 1429 1430 /* 1431 * Check response code (Solaris breaks this into a 3-bit class 1432 * and 4-bit code field. 1433 */ 1434 if ((es->es_class != CLASS_EXTENDED_SENSE) || 1435 ((es->es_code != CODE_FMT_FIXED_CURRENT) && 1436 (es->es_code != CODE_FMT_FIXED_DEFERRED) && 1437 (es->es_code != CODE_FMT_DESCR_CURRENT) && 1438 (es->es_code != CODE_FMT_DESCR_DEFERRED))) { 1439 /* 1440 * Sense data (if there's actually anything here) is not 1441 * in a format we can handle). 1442 */ 1443 return (SENSE_UNUSABLE); 1444 } 1445 1446 /* 1447 * Check if this is deferred sense 1448 */ 1449 if ((flags != NULL) && 1450 ((es->es_code == CODE_FMT_FIXED_DEFERRED) || 1451 (es->es_code == CODE_FMT_DESCR_DEFERRED))) { 1452 *flags |= SNS_BUF_DEFERRED; 1453 } 1454 1455 /* 1456 * Make sure length is OK 1457 */ 1458 if (es->es_code == CODE_FMT_FIXED_CURRENT || 1459 es->es_code == CODE_FMT_FIXED_DEFERRED) { 1460 /* 1461 * We can get by with a buffer that only includes the key, 1462 * asc, and ascq. In reality the minimum length we should 1463 * ever see is 18 bytes. 1464 */ 1465 if ((sense_buf_len < MIN_FIXED_SENSE_LEN) || 1466 ((es->es_add_len + ADDL_SENSE_ADJUST) < 1467 MIN_FIXED_SENSE_LEN)) { 1468 result = SENSE_UNUSABLE; 1469 } else { 1470 /* 1471 * The es_add_len field contains the number of sense 1472 * data bytes that follow the es_add_len field. 1473 */ 1474 if ((flags != NULL) && 1475 (sense_buf_len < 1476 (es->es_add_len + ADDL_SENSE_ADJUST))) { 1477 *flags |= SNS_BUF_OVERFLOW; 1478 } 1479 1480 result = SENSE_FIXED_FORMAT; 1481 } 1482 } else { 1483 struct scsi_descr_sense_hdr *ds = 1484 (struct scsi_descr_sense_hdr *)sense_buffer; 1485 1486 /* 1487 * For descriptor format we need at least the descriptor 1488 * header 1489 */ 1490 if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) { 1491 result = SENSE_UNUSABLE; 1492 } else { 1493 /* 1494 * Check for overflow 1495 */ 1496 if ((flags != NULL) && 1497 (sense_buf_len < 1498 (ds->ds_addl_sense_length + sizeof (*ds)))) { 1499 *flags |= SNS_BUF_OVERFLOW; 1500 } 1501 1502 result = SENSE_DESCR_FORMAT; 1503 } 1504 } 1505 1506 return (result); 1507} 1508 1509 1510uint8_t 1511scsi_sense_key(uint8_t *sense_buffer) 1512{ 1513 uint8_t skey; 1514 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1515 struct scsi_descr_sense_hdr *sdsp = 1516 (struct scsi_descr_sense_hdr *)sense_buffer; 1517 skey = sdsp->ds_key; 1518 } else { 1519 struct scsi_extended_sense *ext_sensep = 1520 (struct scsi_extended_sense *)sense_buffer; 1521 skey = ext_sensep->es_key; 1522 } 1523 return (skey); 1524} 1525 1526uint8_t 1527scsi_sense_asc(uint8_t *sense_buffer) 1528{ 1529 uint8_t asc; 1530 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1531 struct scsi_descr_sense_hdr *sdsp = 1532 (struct scsi_descr_sense_hdr *)sense_buffer; 1533 asc = sdsp->ds_add_code; 1534 } else { 1535 struct scsi_extended_sense *ext_sensep = 1536 (struct scsi_extended_sense *)sense_buffer; 1537 asc = ext_sensep->es_add_code; 1538 } 1539 return (asc); 1540} 1541 1542uint8_t 1543scsi_sense_ascq(uint8_t *sense_buffer) 1544{ 1545 uint8_t ascq; 1546 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1547 struct scsi_descr_sense_hdr *sdsp = 1548 (struct scsi_descr_sense_hdr *)sense_buffer; 1549 ascq = sdsp->ds_qual_code; 1550 } else { 1551 struct scsi_extended_sense *ext_sensep = 1552 (struct scsi_extended_sense *)sense_buffer; 1553 ascq = ext_sensep->es_qual_code; 1554 } 1555 return (ascq); 1556} 1557 1558void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len, 1559 uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code, 1560 uint8_t **sk_specific, uint8_t **stream_flags) 1561{ 1562 int sense_fmt; 1563 1564 /* 1565 * Sanity check sense data and determine the format 1566 */ 1567 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1568 1569 /* 1570 * Initialize any requested data to 0 1571 */ 1572 if (information) { 1573 *information = NULL; 1574 } 1575 if (cmd_spec_info) { 1576 *cmd_spec_info = NULL; 1577 } 1578 if (fru_code) { 1579 *fru_code = NULL; 1580 } 1581 if (sk_specific) { 1582 *sk_specific = NULL; 1583 } 1584 if (stream_flags) { 1585 *stream_flags = NULL; 1586 } 1587 1588 if (sense_fmt == SENSE_DESCR_FORMAT) { 1589 struct scsi_descr_template *sdt = NULL; 1590 1591 while (scsi_get_next_descr(sense_buffer, 1592 sense_buf_len, &sdt) != -1) { 1593 switch (sdt->sdt_descr_type) { 1594 case DESCR_INFORMATION: { 1595 struct scsi_information_sense_descr *isd = 1596 (struct scsi_information_sense_descr *) 1597 sdt; 1598 if (information) { 1599 *information = 1600 &isd->isd_information[0]; 1601 } 1602 break; 1603 } 1604 case DESCR_COMMAND_SPECIFIC: { 1605 struct scsi_cmd_specific_sense_descr *csd = 1606 (struct scsi_cmd_specific_sense_descr *) 1607 sdt; 1608 if (cmd_spec_info) { 1609 *cmd_spec_info = 1610 &csd->css_cmd_specific_info[0]; 1611 } 1612 break; 1613 } 1614 case DESCR_SENSE_KEY_SPECIFIC: { 1615 struct scsi_sk_specific_sense_descr *ssd = 1616 (struct scsi_sk_specific_sense_descr *) 1617 sdt; 1618 if (sk_specific) { 1619 *sk_specific = 1620 (uint8_t *)&ssd->sss_data; 1621 } 1622 break; 1623 } 1624 case DESCR_FRU: { 1625 struct scsi_fru_sense_descr *fsd = 1626 (struct scsi_fru_sense_descr *) 1627 sdt; 1628 if (fru_code) { 1629 *fru_code = &fsd->fs_fru_code; 1630 } 1631 break; 1632 } 1633 case DESCR_STREAM_COMMANDS: { 1634 struct scsi_stream_cmd_sense_descr *strsd = 1635 (struct scsi_stream_cmd_sense_descr *) 1636 sdt; 1637 if (stream_flags) { 1638 *stream_flags = 1639 (uint8_t *)&strsd->scs_data; 1640 } 1641 break; 1642 } 1643 case DESCR_BLOCK_COMMANDS: { 1644 struct scsi_block_cmd_sense_descr *bsd = 1645 (struct scsi_block_cmd_sense_descr *) 1646 sdt; 1647 /* 1648 * The "Block Command" sense descriptor 1649 * contains an ili bit that we can store 1650 * in the stream specific data if it is 1651 * available. We shouldn't see both 1652 * a block command and a stream command 1653 * descriptor in the same collection 1654 * of sense data. 1655 */ 1656 if (stream_flags) { 1657 /* 1658 * Can't take an address of a bitfield, 1659 * but the flags are just after the 1660 * bcs_reserved field. 1661 */ 1662 *stream_flags = 1663 (uint8_t *)&bsd->bcs_reserved + 1; 1664 } 1665 break; 1666 } 1667 } 1668 } 1669 } else { 1670 struct scsi_extended_sense *es = 1671 (struct scsi_extended_sense *)sense_buffer; 1672 1673 /* Get data from fixed sense buffer */ 1674 if (information && es->es_valid) { 1675 *information = &es->es_info_1; 1676 } 1677 if (cmd_spec_info && es->es_valid) { 1678 *cmd_spec_info = &es->es_cmd_info[0]; 1679 } 1680 if (fru_code) { 1681 *fru_code = &es->es_fru_code; 1682 } 1683 if (sk_specific) { 1684 *sk_specific = &es->es_skey_specific[0]; 1685 } 1686 if (stream_flags) { 1687 /* 1688 * Can't take the address of a bit field, 1689 * but the stream flags are located just after 1690 * the es_segnum field; 1691 */ 1692 *stream_flags = &es->es_segnum + 1; 1693 } 1694 } 1695} 1696 1697boolean_t 1698scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len, 1699 uint64_t *information) 1700{ 1701 boolean_t valid; 1702 int sense_fmt; 1703 1704 ASSERT(sense_buffer != NULL); 1705 ASSERT(information != NULL); 1706 1707 /* Validate sense data and get format */ 1708 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1709 1710 if (sense_fmt == SENSE_UNUSABLE) { 1711 /* Information is not valid */ 1712 valid = 0; 1713 } else if (sense_fmt == SENSE_FIXED_FORMAT) { 1714 struct scsi_extended_sense *es = 1715 (struct scsi_extended_sense *)sense_buffer; 1716 1717 *information = (uint64_t)SCSI_READ32(&es->es_info_1); 1718 1719 valid = es->es_valid; 1720 } else { 1721 /* Sense data is descriptor format */ 1722 struct scsi_information_sense_descr *isd; 1723 1724 isd = (struct scsi_information_sense_descr *) 1725 scsi_find_sense_descr(sense_buffer, sense_buf_len, 1726 DESCR_INFORMATION); 1727 1728 if (isd) { 1729 *information = SCSI_READ64(isd->isd_information); 1730 valid = 1; 1731 } else { 1732 valid = 0; 1733 } 1734 } 1735 1736 return (valid); 1737} 1738 1739boolean_t 1740scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len, 1741 uint64_t *cmd_specific_info) 1742{ 1743 boolean_t valid; 1744 int sense_fmt; 1745 1746 ASSERT(sense_buffer != NULL); 1747 ASSERT(cmd_specific_info != NULL); 1748 1749 /* Validate sense data and get format */ 1750 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1751 1752 if (sense_fmt == SENSE_UNUSABLE) { 1753 /* Command specific info is not valid */ 1754 valid = 0; 1755 } else if (sense_fmt == SENSE_FIXED_FORMAT) { 1756 struct scsi_extended_sense *es = 1757 (struct scsi_extended_sense *)sense_buffer; 1758 1759 *cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info); 1760 1761 valid = es->es_valid; 1762 } else { 1763 /* Sense data is descriptor format */ 1764 struct scsi_cmd_specific_sense_descr *c; 1765 1766 c = (struct scsi_cmd_specific_sense_descr *) 1767 scsi_find_sense_descr(sense_buffer, sense_buf_len, 1768 DESCR_COMMAND_SPECIFIC); 1769 1770 if (c) { 1771 valid = 1; 1772 *cmd_specific_info = 1773 SCSI_READ64(c->css_cmd_specific_info); 1774 } else { 1775 valid = 0; 1776 } 1777 } 1778 1779 return (valid); 1780} 1781 1782uint8_t * 1783scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type) 1784{ 1785 struct scsi_descr_template *sdt = NULL; 1786 1787 while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) { 1788 ASSERT(sdt != NULL); 1789 if (sdt->sdt_descr_type == req_descr_type) { 1790 /* Found requested descriptor type */ 1791 break; 1792 } 1793 } 1794 1795 return ((uint8_t *)sdt); 1796} 1797 1798/* 1799 * Sense Descriptor format is: 1800 * 1801 * <Descriptor type> <Descriptor length> <Descriptor data> ... 1802 * 1803 * 2 must be added to the descriptor length value to get the 1804 * total descriptor length sense the stored length does not 1805 * include the "type" and "additional length" fields. 1806 */ 1807 1808#define NEXT_DESCR_PTR(ndp_descr) \ 1809 ((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \ 1810 ((ndp_descr)->sdt_addl_length + \ 1811 sizeof (struct scsi_descr_template)))) 1812 1813static int 1814scsi_get_next_descr(uint8_t *sense_buffer, 1815 int sense_buf_len, struct scsi_descr_template **descrpp) 1816{ 1817 struct scsi_descr_sense_hdr *sdsp = 1818 (struct scsi_descr_sense_hdr *)sense_buffer; 1819 struct scsi_descr_template *cur_descr; 1820 boolean_t find_first; 1821 int valid_sense_length; 1822 1823 ASSERT(descrpp != NULL); 1824 find_first = (*descrpp == NULL); 1825 1826 /* 1827 * If no descriptor is passed in then return the first 1828 * descriptor 1829 */ 1830 if (find_first) { 1831 /* 1832 * The first descriptor will immediately follow the header 1833 * (Pointer arithmetic) 1834 */ 1835 cur_descr = (struct scsi_descr_template *)(sdsp+1); 1836 } else { 1837 cur_descr = *descrpp; 1838 ASSERT(cur_descr > (struct scsi_descr_template *)sdsp); 1839 } 1840 1841 /* Assume no more descriptors are available */ 1842 *descrpp = NULL; 1843 1844 /* 1845 * Calculate the amount of valid sense data -- make sure the length 1846 * byte in this descriptor lies within the valid sense data. 1847 */ 1848 valid_sense_length = 1849 min((sizeof (struct scsi_descr_sense_hdr) + 1850 sdsp->ds_addl_sense_length), 1851 sense_buf_len); 1852 1853 /* 1854 * Make sure this descriptor is complete (either the first 1855 * descriptor or the descriptor passed in) 1856 */ 1857 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) != 1858 DESCR_GOOD) { 1859 return (-1); 1860 } 1861 1862 /* 1863 * If we were looking for the first descriptor go ahead and return it 1864 */ 1865 if (find_first) { 1866 *descrpp = cur_descr; 1867 return ((*descrpp)->sdt_descr_type); 1868 } 1869 1870 /* 1871 * Get pointer to next descriptor 1872 */ 1873 cur_descr = NEXT_DESCR_PTR(cur_descr); 1874 1875 /* 1876 * Make sure this descriptor is also complete. 1877 */ 1878 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) != 1879 DESCR_GOOD) { 1880 return (-1); 1881 } 1882 1883 *descrpp = (struct scsi_descr_template *)cur_descr; 1884 return ((*descrpp)->sdt_descr_type); 1885} 1886 1887static int 1888scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp, 1889 int valid_sense_length, struct scsi_descr_template *descrp) 1890{ 1891 int descr_offset, next_descr_offset; 1892 1893 /* 1894 * Make sure length is present 1895 */ 1896 descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp; 1897 if (descr_offset + sizeof (struct scsi_descr_template) > 1898 valid_sense_length) { 1899 return (DESCR_PARTIAL); 1900 } 1901 1902 /* 1903 * Check if length is 0 (no more descriptors) 1904 */ 1905 if (descrp->sdt_addl_length == 0) { 1906 return (DESCR_END); 1907 } 1908 1909 /* 1910 * Make sure the rest of the descriptor is present 1911 */ 1912 next_descr_offset = 1913 (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp; 1914 if (next_descr_offset > valid_sense_length) { 1915 return (DESCR_PARTIAL); 1916 } 1917 1918 return (DESCR_GOOD); 1919} 1920 1921/* 1922 * Internal data structure for handling uscsi command. 1923 */ 1924typedef struct uscsi_i_cmd { 1925 struct uscsi_cmd uic_cmd; 1926 caddr_t uic_rqbuf; 1927 uchar_t uic_rqlen; 1928 caddr_t uic_cdb; 1929 int uic_flag; 1930 struct scsi_address *uic_ap; 1931} uscsi_i_cmd_t; 1932 1933#if !defined(lint) 1934_NOTE(SCHEME_PROTECTS_DATA("unshared data", uscsi_i_cmd)) 1935#endif 1936 1937/*ARGSUSED*/ 1938static void 1939scsi_uscsi_mincnt(struct buf *bp) 1940{ 1941 /* 1942 * Do not break up because the CDB count would then be 1943 * incorrect and create spurious data underrun errors. 1944 */ 1945} 1946 1947/* 1948 * Function: scsi_uscsi_alloc_and_copyin 1949 * 1950 * Description: Target drivers call this function to allocate memeory, 1951 * copy in, and convert ILP32/LP64 to make preparations for handling 1952 * uscsi commands. 1953 * 1954 * Arguments: arg - pointer to the caller's uscsi command struct 1955 * flag - mode, corresponds to ioctl(9e) 'mode' 1956 * ap - SCSI address structure 1957 * uscmdp - pointer to the converted uscsi command 1958 * 1959 * Return code: 0 1960 * EFAULT 1961 * EINVAL 1962 * 1963 * Context: Never called at interrupt context. 1964 */ 1965 1966int 1967scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap, 1968 struct uscsi_cmd **uscmdp) 1969{ 1970#ifdef _MULTI_DATAMODEL 1971 /* 1972 * For use when a 32 bit app makes a call into a 1973 * 64 bit ioctl 1974 */ 1975 struct uscsi_cmd32 uscsi_cmd_32_for_64; 1976 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64; 1977#endif /* _MULTI_DATAMODEL */ 1978 struct uscsi_i_cmd *uicmd; 1979 struct uscsi_cmd *uscmd; 1980 int max_hba_cdb; 1981 int rval; 1982 1983 /* 1984 * In order to not worry about where the uscsi structure came 1985 * from (or where the cdb it points to came from) we're going 1986 * to make kmem_alloc'd copies of them here. This will also 1987 * allow reference to the data they contain long after this 1988 * process has gone to sleep and its kernel stack has been 1989 * unmapped, etc. First get some memory for the uscsi_cmd 1990 * struct and copy the contents of the given uscsi_cmd struct 1991 * into it. We also save infos of the uscsi command by using 1992 * uicmd to supply referrence for the copyout operation. 1993 */ 1994 uicmd = (struct uscsi_i_cmd *) 1995 kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP); 1996 *uscmdp = &(uicmd->uic_cmd); 1997 uscmd = *uscmdp; 1998 1999#ifdef _MULTI_DATAMODEL 2000 switch (ddi_model_convert_from(flag & FMODELS)) { 2001 case DDI_MODEL_ILP32: 2002 if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) { 2003 rval = EFAULT; 2004 goto done; 2005 } 2006 /* 2007 * Convert the ILP32 uscsi data from the 2008 * application to LP64 for internal use. 2009 */ 2010 uscsi_cmd32touscsi_cmd(ucmd32, uscmd); 2011 break; 2012 case DDI_MODEL_NONE: 2013 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) { 2014 rval = EFAULT; 2015 goto done; 2016 } 2017 break; 2018 } 2019#else /* ! _MULTI_DATAMODEL */ 2020 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) { 2021 rval = EFAULT; 2022 goto done; 2023 } 2024#endif /* _MULTI_DATAMODEL */ 2025 2026 uicmd->uic_rqbuf = uscmd->uscsi_rqbuf; 2027 uicmd->uic_rqlen = uscmd->uscsi_rqlen; 2028 uicmd->uic_cdb = uscmd->uscsi_cdb; 2029 uicmd->uic_flag = flag; 2030 uicmd->uic_ap = ap; 2031 2032 /* 2033 * Skip the following steps if we meet RESET commands. 2034 */ 2035 if (uscmd->uscsi_flags & 2036 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) { 2037 uscmd->uscsi_rqbuf = NULL; 2038 uscmd->uscsi_cdb = NULL; 2039 return (0); 2040 } 2041 2042 /* 2043 * Perfunctory sanity checks. Get the maximum hba supported 2044 * cdb length first. 2045 */ 2046 max_hba_cdb = scsi_ifgetcap(ap, "max-cdb-length", 1); 2047 if (max_hba_cdb < CDB_GROUP0) { 2048 max_hba_cdb = CDB_GROUP4; 2049 } 2050 if (uscmd->uscsi_cdblen < CDB_GROUP0 || 2051 uscmd->uscsi_cdblen > max_hba_cdb) { 2052 rval = EINVAL; 2053 goto done; 2054 } 2055 if ((uscmd->uscsi_flags & USCSI_RQENABLE) && 2056 (uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) { 2057 rval = EINVAL; 2058 goto done; 2059 } 2060 2061 /* 2062 * Now we get some space for the CDB, and copy the given CDB into 2063 * it. Use ddi_copyin() in case the data is in user space. 2064 */ 2065 uscmd->uscsi_cdb = kmem_zalloc((size_t)uscmd->uscsi_cdblen, KM_SLEEP); 2066 if (ddi_copyin(uicmd->uic_cdb, uscmd->uscsi_cdb, 2067 (uint_t)uscmd->uscsi_cdblen, flag) != 0) { 2068 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen); 2069 rval = EFAULT; 2070 goto done; 2071 } 2072 2073 /* 2074 * If the length of the CDB is greater than 16 bytes, it must be 2075 * a variable length CDB (i.e. the opcode must be 0x7f). 2076 */ 2077 if (uscmd->uscsi_cdblen > SCSI_CDB_SIZE && 2078 uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) { 2079 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen); 2080 rval = EINVAL; 2081 goto done; 2082 } 2083 2084 /* 2085 * Initialize Request Sense buffering, if requested. 2086 */ 2087 if (uscmd->uscsi_flags & USCSI_RQENABLE) { 2088 /* 2089 * Here uscmd->uscsi_rqbuf currently points to the caller's 2090 * buffer, but we replace this with a kernel buffer that 2091 * we allocate to use with the sense data. The sense data 2092 * (if present) gets copied into this new buffer before the 2093 * command is completed. Then we copy the sense data from 2094 * our allocated buf into the caller's buffer below. Note 2095 * that uscmd->uscsi_rqbuf and uscmd->uscsi_rqlen are used 2096 * below to perform the copy back to the caller's buf. 2097 */ 2098 uscmd->uscsi_rqlen = SENSE_LENGTH; 2099 uscmd->uscsi_rqbuf = kmem_zalloc(SENSE_LENGTH, KM_SLEEP); 2100 uscmd->uscsi_rqresid = uscmd->uscsi_rqlen; 2101 } else { 2102 uscmd->uscsi_rqbuf = NULL; 2103 uscmd->uscsi_rqlen = 0; 2104 uscmd->uscsi_rqresid = 0; 2105 } 2106 return (0); 2107 2108done: 2109 kmem_free(uicmd, sizeof (struct uscsi_i_cmd)); 2110 return (rval); 2111} 2112 2113/* 2114 * Function: scsi_uscsi_handle_cmd 2115 * 2116 * Description: Target drivers call this function to handle uscsi commands. 2117 * 2118 * Arguments: dev - device number 2119 * dataspace - UIO_USERSPACE or UIO_SYSSPACE 2120 * uscmd - pointer to the converted uscsi command 2121 * strat - pointer to the driver's strategy routine 2122 * bp - buf struct ptr 2123 * private_data - pointer to bp->b_private 2124 * 2125 * Return code: 0 2126 * EIO - scsi_reset() failed, or see biowait()/physio() codes. 2127 * EINVAL 2128 * return code of biowait(9F) or physio(9F): 2129 * EIO - IO error 2130 * ENXIO 2131 * EACCES - reservation conflict 2132 * 2133 * Context: Never called at interrupt context. 2134 */ 2135 2136int 2137scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace, 2138 struct uscsi_cmd *uscmd, int (*strat)(struct buf *), 2139 struct buf *bp, void *private_data) 2140{ 2141 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd; 2142 int bp_alloc_flag = 0; 2143 int rval; 2144 2145 /* 2146 * Perform resets directly; no need to generate a command to do it. 2147 */ 2148 if (uscmd->uscsi_flags & 2149 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) { 2150 int flags = (uscmd->uscsi_flags & USCSI_RESET_ALL) ? 2151 RESET_ALL : ((uscmd->uscsi_flags & USCSI_RESET_TARGET) ? 2152 RESET_TARGET : RESET_LUN); 2153 if (scsi_reset(uicmd->uic_ap, flags) == 0) { 2154 /* Reset attempt was unsuccessful */ 2155 return (EIO); 2156 } 2157 return (0); 2158 } 2159 2160 /* 2161 * Force asynchronous mode, if necessary. Doing this here 2162 * has the unfortunate effect of running other queued 2163 * commands async also, but since the main purpose of this 2164 * capability is downloading new drive firmware, we can 2165 * probably live with it. 2166 */ 2167 if (uscmd->uscsi_flags & USCSI_ASYNC) { 2168 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 1) { 2169 if (scsi_ifsetcap(uicmd->uic_ap, "synchronous", 2170 0, 1) != 1) { 2171 return (EINVAL); 2172 } 2173 } 2174 } 2175 2176 /* 2177 * Re-enable synchronous mode, if requested. 2178 */ 2179 if (uscmd->uscsi_flags & USCSI_SYNC) { 2180 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 0) { 2181 rval = scsi_ifsetcap(uicmd->uic_ap, "synchronous", 2182 1, 1); 2183 } 2184 } 2185 2186 /* 2187 * If bp is NULL, allocate space here. 2188 */ 2189 if (bp == NULL) { 2190 bp = getrbuf(KM_SLEEP); 2191 bp->b_private = private_data; 2192 bp_alloc_flag = 1; 2193 } 2194 2195 /* 2196 * If we're going to do actual I/O, let physio do all the right things. 2197 */ 2198 if (uscmd->uscsi_buflen != 0) { 2199 struct iovec aiov; 2200 struct uio auio; 2201 struct uio *uio = &auio; 2202 2203 bzero(&auio, sizeof (struct uio)); 2204 bzero(&aiov, sizeof (struct iovec)); 2205 aiov.iov_base = uscmd->uscsi_bufaddr; 2206 aiov.iov_len = uscmd->uscsi_buflen; 2207 uio->uio_iov = &aiov; 2208 2209 uio->uio_iovcnt = 1; 2210 uio->uio_resid = uscmd->uscsi_buflen; 2211 uio->uio_segflg = dataspace; 2212 2213 /* 2214 * physio() will block here until the command completes.... 2215 */ 2216 rval = physio(strat, bp, dev, 2217 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE), 2218 scsi_uscsi_mincnt, uio); 2219 } else { 2220 /* 2221 * We have to mimic that physio would do here! Argh! 2222 */ 2223 bp->b_flags = B_BUSY | 2224 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE); 2225 bp->b_edev = dev; 2226 bp->b_dev = cmpdev(dev); /* maybe unnecessary? */ 2227 bp->b_bcount = 0; 2228 bp->b_blkno = 0; 2229 bp->b_resid = 0; 2230 2231 (void) (*strat)(bp); 2232 rval = biowait(bp); 2233 } 2234 uscmd->uscsi_resid = bp->b_resid; 2235 2236 if (bp_alloc_flag == 1) { 2237 bp_mapout(bp); 2238 freerbuf(bp); 2239 } 2240 2241 return (rval); 2242} 2243 2244/* 2245 * Function: scsi_uscsi_copyout_and_free 2246 * 2247 * Description: Target drivers call this function to undo what was done by 2248 * scsi_uscsi_alloc_and_copyin. 2249 * 2250 * Arguments: arg - pointer to the uscsi command to be returned 2251 * uscmd - pointer to the converted uscsi command 2252 * 2253 * Return code: 0 2254 * EFAULT 2255 * 2256 * Context: Never called at interrupt context. 2257 */ 2258 2259int 2260scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd) 2261{ 2262#ifdef _MULTI_DATAMODEL 2263 /* 2264 * For use when a 32 bit app makes a call into a 2265 * 64 bit ioctl. 2266 */ 2267 struct uscsi_cmd32 uscsi_cmd_32_for_64; 2268 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64; 2269#endif /* _MULTI_DATAMODEL */ 2270 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd; 2271 caddr_t k_rqbuf; 2272 caddr_t k_cdb; 2273 int rval = 0; 2274 2275 /* 2276 * If the caller wants sense data, copy back whatever sense data 2277 * we may have gotten, and update the relevant rqsense info. 2278 */ 2279 if ((uscmd->uscsi_flags & USCSI_RQENABLE) && 2280 (uscmd->uscsi_rqbuf != NULL)) { 2281 int rqlen = uscmd->uscsi_rqlen - uscmd->uscsi_rqresid; 2282 rqlen = min(((int)uicmd->uic_rqlen), rqlen); 2283 uscmd->uscsi_rqresid = uicmd->uic_rqlen - rqlen; 2284 /* 2285 * Copy out the sense data for user process. 2286 */ 2287 if ((uicmd->uic_rqbuf != NULL) && (rqlen != 0)) { 2288 if (ddi_copyout(uscmd->uscsi_rqbuf, 2289 uicmd->uic_rqbuf, rqlen, uicmd->uic_flag) != 0) { 2290 rval = EFAULT; 2291 } 2292 } 2293 } 2294 2295 /* 2296 * Free allocated resources and return, mapout the buf in case it was 2297 * mapped in by a lower layer. 2298 */ 2299 k_rqbuf = uscmd->uscsi_rqbuf; 2300 k_cdb = uscmd->uscsi_cdb; 2301 uscmd->uscsi_rqbuf = uicmd->uic_rqbuf; 2302 uscmd->uscsi_rqlen = uicmd->uic_rqlen; 2303 uscmd->uscsi_cdb = uicmd->uic_cdb; 2304 2305#ifdef _MULTI_DATAMODEL 2306 switch (ddi_model_convert_from(uicmd->uic_flag & FMODELS)) { 2307 case DDI_MODEL_ILP32: 2308 /* 2309 * Convert back to ILP32 before copyout to the 2310 * application 2311 */ 2312 uscsi_cmdtouscsi_cmd32(uscmd, ucmd32); 2313 if (ddi_copyout(ucmd32, (void *)arg, sizeof (*ucmd32), 2314 uicmd->uic_flag)) { 2315 rval = EFAULT; 2316 } 2317 break; 2318 case DDI_MODEL_NONE: 2319 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), 2320 uicmd->uic_flag)) { 2321 rval = EFAULT; 2322 } 2323 break; 2324 } 2325#else /* _MULTI_DATAMODE */ 2326 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) { 2327 rval = EFAULT; 2328 } 2329#endif /* _MULTI_DATAMODE */ 2330 2331 if (k_rqbuf != NULL) { 2332 kmem_free(k_rqbuf, SENSE_LENGTH); 2333 } 2334 if (k_cdb != NULL) { 2335 kmem_free(k_cdb, (size_t)uscmd->uscsi_cdblen); 2336 } 2337 kmem_free(uicmd, sizeof (struct uscsi_i_cmd)); 2338 2339 return (rval); 2340} 2341