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 2006 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 31 /* 32 * Utility SCSI routines 33 */ 34 35 /* 36 * Polling support routines 37 */ 38 39 extern uintptr_t scsi_callback_id; 40 41 /* 42 * Common buffer for scsi_log 43 */ 44 45 extern kmutex_t scsi_log_mutex; 46 static char scsi_log_buffer[MAXPATHLEN + 1]; 47 48 49 #define A_TO_TRAN(ap) (ap->a_hba_tran) 50 #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran) 51 #define P_TO_ADDR(pkt) (&((pkt)->pkt_address)) 52 53 #define CSEC 10000 /* usecs */ 54 #define SEC_TO_CSEC (1000000/CSEC) 55 56 extern ddi_dma_attr_t scsi_alloc_attr; 57 58 /*PRINTFLIKE4*/ 59 static void impl_scsi_log(dev_info_t *dev, char *label, uint_t level, 60 const char *fmt, ...) __KPRINTFLIKE(4); 61 /*PRINTFLIKE4*/ 62 static void v_scsi_log(dev_info_t *dev, char *label, uint_t level, 63 const char *fmt, va_list ap) __KVPRINTFLIKE(4); 64 65 static int 66 scsi_get_next_descr(uint8_t *sdsp, 67 int sense_buf_len, struct scsi_descr_template **descrpp); 68 69 #define DESCR_GOOD 0 70 #define DESCR_PARTIAL 1 71 #define DESCR_END 2 72 73 static int 74 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp, 75 int valid_sense_length, struct scsi_descr_template *descrp); 76 77 int 78 scsi_poll(struct scsi_pkt *pkt) 79 { 80 register int busy_count, rval = -1, savef; 81 long savet; 82 void (*savec)(); 83 extern int do_polled_io; 84 85 /* 86 * save old flags.. 87 */ 88 savef = pkt->pkt_flags; 89 savec = pkt->pkt_comp; 90 savet = pkt->pkt_time; 91 92 pkt->pkt_flags |= FLAG_NOINTR; 93 94 /* 95 * XXX there is nothing in the SCSA spec that states that we should not 96 * do a callback for polled cmds; however, removing this will break sd 97 * and probably other target drivers 98 */ 99 pkt->pkt_comp = 0; 100 101 /* 102 * we don't like a polled command without timeout. 103 * 60 seconds seems long enough. 104 */ 105 if (pkt->pkt_time == 0) 106 pkt->pkt_time = SCSI_POLL_TIMEOUT; 107 108 /* 109 * Send polled cmd. 110 * 111 * We do some error recovery for various errors. Tran_busy, 112 * queue full, and non-dispatched commands are retried every 10 msec. 113 * as they are typically transient failures. Busy status is retried 114 * every second as this status takes a while to change. 115 */ 116 for (busy_count = 0; busy_count < (pkt->pkt_time * SEC_TO_CSEC); 117 busy_count++) { 118 int rc; 119 int poll_delay; 120 121 /* 122 * Initialize pkt status variables. 123 */ 124 *pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0; 125 126 if ((rc = scsi_transport(pkt)) != TRAN_ACCEPT) { 127 if (rc != TRAN_BUSY) { 128 /* Transport failed - give up. */ 129 break; 130 } else { 131 /* Transport busy - try again. */ 132 poll_delay = 1 *CSEC; /* 10 msec. */ 133 } 134 } else { 135 /* 136 * Transport accepted - check pkt status. 137 */ 138 rc = (*pkt->pkt_scbp) & STATUS_MASK; 139 140 if (pkt->pkt_reason == CMD_CMPLT && 141 rc == STATUS_GOOD) { 142 /* No error - we're done */ 143 rval = 0; 144 break; 145 146 } else if (pkt->pkt_reason == CMD_INCOMPLETE && 147 pkt->pkt_state == 0) { 148 /* Pkt not dispatched - try again. */ 149 poll_delay = 1 *CSEC; /* 10 msec. */ 150 151 } else if (pkt->pkt_reason == CMD_CMPLT && 152 rc == STATUS_QFULL) { 153 /* Queue full - try again. */ 154 poll_delay = 1 *CSEC; /* 10 msec. */ 155 156 } else if (pkt->pkt_reason == CMD_CMPLT && 157 rc == STATUS_BUSY) { 158 /* Busy - try again. */ 159 poll_delay = 100 *CSEC; /* 1 sec. */ 160 busy_count += (SEC_TO_CSEC - 1); 161 162 } else { 163 /* BAD status - give up. */ 164 break; 165 } 166 } 167 168 if ((curthread->t_flag & T_INTR_THREAD) == 0 && 169 !do_polled_io) { 170 delay(drv_usectohz(poll_delay)); 171 } else { 172 /* we busy wait during cpr_dump or interrupt threads */ 173 drv_usecwait(poll_delay); 174 } 175 } 176 177 pkt->pkt_flags = savef; 178 pkt->pkt_comp = savec; 179 pkt->pkt_time = savet; 180 return (rval); 181 } 182 183 /* 184 * Command packaging routines. 185 * 186 * makecom_g*() are original routines and scsi_setup_cdb() 187 * is the new and preferred routine. 188 */ 189 190 /* 191 * These routines put LUN information in CDB byte 1 bits 7-5. 192 * This was required in SCSI-1. SCSI-2 allowed it but it preferred 193 * sending LUN information as part of IDENTIFY message. 194 * This is not allowed in SCSI-3. 195 */ 196 197 void 198 makecom_g0(struct scsi_pkt *pkt, struct scsi_device *devp, 199 int flag, int cmd, int addr, int cnt) 200 { 201 MAKECOM_G0(pkt, devp, flag, cmd, addr, (uchar_t)cnt); 202 } 203 204 void 205 makecom_g0_s(struct scsi_pkt *pkt, struct scsi_device *devp, 206 int flag, int cmd, int cnt, int fixbit) 207 { 208 MAKECOM_G0_S(pkt, devp, flag, cmd, cnt, (uchar_t)fixbit); 209 } 210 211 void 212 makecom_g1(struct scsi_pkt *pkt, struct scsi_device *devp, 213 int flag, int cmd, int addr, int cnt) 214 { 215 MAKECOM_G1(pkt, devp, flag, cmd, addr, cnt); 216 } 217 218 void 219 makecom_g5(struct scsi_pkt *pkt, struct scsi_device *devp, 220 int flag, int cmd, int addr, int cnt) 221 { 222 MAKECOM_G5(pkt, devp, flag, cmd, addr, cnt); 223 } 224 225 /* 226 * Following routine does not put LUN information in CDB. 227 * This interface must be used for SCSI-2 targets having 228 * more than 8 LUNs or a SCSI-3 target. 229 */ 230 int 231 scsi_setup_cdb(union scsi_cdb *cdbp, uchar_t cmd, uint_t addr, uint_t cnt, 232 uint_t addtl_cdb_data) 233 { 234 uint_t addr_cnt; 235 236 cdbp->scc_cmd = cmd; 237 238 switch (CDB_GROUPID(cmd)) { 239 case CDB_GROUPID_0: 240 /* 241 * The following calculation is to take care of 242 * the fact that format of some 6 bytes tape 243 * command is different (compare 6 bytes disk and 244 * tape read commands). 245 */ 246 addr_cnt = (addr << 8) + cnt; 247 addr = (addr_cnt & 0x1fffff00) >> 8; 248 cnt = addr_cnt & 0xff; 249 FORMG0ADDR(cdbp, addr); 250 FORMG0COUNT(cdbp, cnt); 251 break; 252 253 case CDB_GROUPID_1: 254 case CDB_GROUPID_2: 255 FORMG1ADDR(cdbp, addr); 256 FORMG1COUNT(cdbp, cnt); 257 break; 258 259 case CDB_GROUPID_4: 260 FORMG4ADDR(cdbp, addr); 261 FORMG4COUNT(cdbp, cnt); 262 FORMG4ADDTL(cdbp, addtl_cdb_data); 263 break; 264 265 case CDB_GROUPID_5: 266 FORMG5ADDR(cdbp, addr); 267 FORMG5COUNT(cdbp, cnt); 268 break; 269 270 default: 271 return (0); 272 } 273 274 return (1); 275 } 276 277 278 /* 279 * Common iopbmap data area packet allocation routines 280 */ 281 282 struct scsi_pkt * 283 get_pktiopb(struct scsi_address *ap, caddr_t *datap, int cdblen, int statuslen, 284 int datalen, int readflag, int (*func)()) 285 { 286 scsi_hba_tran_t *tran = A_TO_TRAN(ap); 287 dev_info_t *pdip = tran->tran_hba_dip; 288 struct scsi_pkt *pkt = NULL; 289 struct buf local; 290 size_t rlen; 291 292 if (!datap) 293 return (pkt); 294 *datap = (caddr_t)0; 295 bzero((caddr_t)&local, sizeof (struct buf)); 296 297 /* 298 * use i_ddi_mem_alloc() for now until we have an interface to allocate 299 * memory for DMA which doesn't require a DMA handle. ddi_iopb_alloc() 300 * is obsolete and we want more flexibility in controlling the DMA 301 * address constraints. 302 */ 303 if (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen, 304 ((func == SLEEP_FUNC) ? 1 : 0), 0, NULL, &local.b_un.b_addr, &rlen, 305 NULL) != DDI_SUCCESS) { 306 return (pkt); 307 } 308 if (readflag) 309 local.b_flags = B_READ; 310 local.b_bcount = datalen; 311 pkt = (*tran->tran_init_pkt) (ap, NULL, &local, 312 cdblen, statuslen, 0, PKT_CONSISTENT, 313 (func == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC, 314 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 330 void 331 free_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 349 static char scsi_tmpname[64]; 350 351 char * 352 scsi_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 377 char * 378 scsi_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 412 char * 413 scsi_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 462 char * 463 scsi_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 474 char * 475 scsi_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 488 static 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 0x28, 0x00, "medium may have changed", 674 0x28, 0x01, "import or export element accessed", 675 0x29, 0x00, "power on, reset, or bus reset occurred", 676 0x29, 0x01, "power on occurred", 677 0x29, 0x02, "scsi bus reset occurred", 678 0x29, 0x03, "bus device reset message occurred", 679 0x29, 0x04, "device internal reset", 680 0x29, 0x05, "transceiver mode changed to single-ended", 681 0x29, 0x06, "transceiver mode changed to LVD", 682 0x29, 0x07, "i_t nexus loss occurred", 683 0x2a, 0x00, "parameters changed", 684 0x2a, 0x01, "mode parameters changed", 685 0x2a, 0x02, "log parameters changed", 686 0x2a, 0x03, "reservations preempted", 687 0x2a, 0x04, "reservations released", 688 0x2a, 0x05, "registrations preempted", 689 0x2a, 0x06, "asymmetric access state changed", 690 0x2a, 0x07, "implicit asymmetric access state transition failed", 691 0x2b, 0x00, "copy cannot execute since host cannot disconnect", 692 0x2c, 0x00, "command sequence error", 693 0x2c, 0x03, "current program area is not empty", 694 0x2c, 0x04, "current program area is empty", 695 0x2c, 0x06, "persistent prevent conflict", 696 0x2c, 0x07, "previous busy status", 697 0x2c, 0x08, "previous task set full status", 698 0x2c, 0x09, "previous reservation conflict status", 699 0x2d, 0x00, "overwrite error on update in place", 700 0x2e, 0x00, "insufficient time for operation", 701 0x2f, 0x00, "commands cleared by another initiator", 702 0x30, 0x00, "incompatible medium installed", 703 0x30, 0x01, "cannot read medium - unknown format", 704 0x30, 0x02, "cannot read medium - incompatible format", 705 0x30, 0x03, "cleaning cartridge installed", 706 0x30, 0x04, "cannot write medium - unknown format", 707 0x30, 0x05, "cannot write medium - incompatible format", 708 0x30, 0x06, "cannot format medium - incompatible medium", 709 0x30, 0x07, "cleaning failure", 710 0x30, 0x08, "cannot write - application code mismatch", 711 0x30, 0x09, "current session not fixated for append", 712 0x30, 0x10, "medium not formatted", 713 0x31, 0x00, "medium format corrupted", 714 0x31, 0x01, "format command failed", 715 0x31, 0x02, "zoned formatting failed due to spare linking", 716 0x32, 0x00, "no defect spare location available", 717 0x32, 0x01, "defect list update failure", 718 0x33, 0x00, "tape length error", 719 0x34, 0x00, "enclosure failure", 720 0x35, 0x00, "enclosure services failure", 721 0x35, 0x01, "unsupported enclosure function", 722 0x35, 0x02, "enclosure services unavailable", 723 0x35, 0x03, "enclosure services transfer failure", 724 0x35, 0x04, "enclosure services transfer refused", 725 0x36, 0x00, "ribbon, ink, or toner failure", 726 0x37, 0x00, "rounded parameter", 727 0x39, 0x00, "saving parameters not supported", 728 0x3a, 0x00, "medium not present", 729 0x3a, 0x01, "medium not present - tray closed", 730 0x3a, 0x02, "medium not present - tray open", 731 0x3a, 0x03, "medium not present - loadable", 732 0x3a, 0x04, "medium not present - medium auxiliary memory accessible", 733 0x3b, 0x00, "sequential positioning error", 734 0x3b, 0x01, "tape position error at beginning-of-medium", 735 0x3b, 0x02, "tape position error at end-of-medium", 736 0x3b, 0x08, "reposition error", 737 0x3b, 0x0c, "position past beginning of medium", 738 0x3b, 0x0d, "medium destination element full", 739 0x3b, 0x0e, "medium source element empty", 740 0x3b, 0x0f, "end of medium reached", 741 0x3b, 0x11, "medium magazine not accessible", 742 0x3b, 0x12, "medium magazine removed", 743 0x3b, 0x13, "medium magazine inserted", 744 0x3b, 0x14, "medium magazine locked", 745 0x3b, 0x15, "medium magazine unlocked", 746 0x3b, 0x16, "mechanical positioning or changer error", 747 0x3d, 0x00, "invalid bits in indentify message", 748 0x3e, 0x00, "LUN has not self-configured yet", 749 0x3e, 0x01, "LUN failure", 750 0x3e, 0x02, "timeout on LUN", 751 0x3e, 0x03, "LUN failed self-test", 752 0x3e, 0x04, "LUN unable to update self-test log", 753 0x3f, 0x00, "target operating conditions have changed", 754 0x3f, 0x01, "microcode has been changed", 755 0x3f, 0x02, "changed operating definition", 756 0x3f, 0x03, "inquiry data has changed", 757 0x3f, 0x04, "component device attached", 758 0x3f, 0x05, "device identifier changed", 759 0x3f, 0x06, "redundancy group created or modified", 760 0x3f, 0x07, "redundancy group deleted", 761 0x3f, 0x08, "spare created or modified", 762 0x3f, 0x09, "spare deleted", 763 0x3f, 0x0a, "volume set created or modified", 764 0x3f, 0x0b, "volume set deleted", 765 0x3f, 0x0c, "volume set deassigned", 766 0x3f, 0x0d, "volume set reassigned", 767 0x3f, 0x0e, "reported LUNs data has changed", 768 0x3f, 0x0f, "echo buffer overwritten", 769 0x3f, 0x10, "medium loadable", 770 0x3f, 0x11, "medium auxiliary memory accessible", 771 0x40, 0x00, "ram failure", 772 0x41, 0x00, "data path failure", 773 0x42, 0x00, "power-on or self-test failure", 774 0x43, 0x00, "message error", 775 0x44, 0x00, "internal target failure", 776 0x45, 0x00, "select or reselect failure", 777 0x46, 0x00, "unsuccessful soft reset", 778 0x47, 0x00, "scsi parity error", 779 0x47, 0x01, "data phase crc error detected", 780 0x47, 0x02, "scsi parity error detected during st data phase", 781 0x47, 0x03, "information unit iucrc error detected", 782 0x47, 0x04, "asynchronous information protection error detected", 783 0x47, 0x05, "protocol service crc error", 784 0x47, 0x7f, "some commands cleared by iscsi protocol event", 785 0x48, 0x00, "initiator detected error message received", 786 0x49, 0x00, "invalid message error", 787 0x4a, 0x00, "command phase error", 788 0x4b, 0x00, "data phase error", 789 0x4b, 0x01, "invalid target port transfer tag received", 790 0x4b, 0x02, "too much write data", 791 0x4b, 0x03, "ack/nak timeout", 792 0x4b, 0x04, "nak received", 793 0x4b, 0x05, "data offset error", 794 0x4c, 0x00, "logical unit failed self-configuration", 795 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)", 796 0x4e, 0x00, "overlapped commands attempted", 797 0x50, 0x00, "write append error", 798 0x51, 0x00, "erase failure", 799 0x52, 0x00, "cartridge fault", 800 0x53, 0x00, "media load or eject failed", 801 0x53, 0x01, "unload tape failure", 802 0x53, 0x02, "medium removal prevented", 803 0x54, 0x00, "scsi to host system interface failure", 804 0x55, 0x00, "system resource failure", 805 0x55, 0x01, "system buffer full", 806 0x55, 0x02, "insufficient reservation resources", 807 0x55, 0x03, "insufficient resources", 808 0x55, 0x04, "insufficient registration resources", 809 0x55, 0x05, "insufficient access control resources", 810 0x55, 0x06, "auxiliary memory out of space", 811 0x57, 0x00, "unable to recover TOC", 812 0x58, 0x00, "generation does not exist", 813 0x59, 0x00, "updated block read", 814 0x5a, 0x00, "operator request or state change input", 815 0x5a, 0x01, "operator medium removal request", 816 0x5a, 0x02, "operator selected write protect", 817 0x5a, 0x03, "operator selected write permit", 818 0x5b, 0x00, "log exception", 819 0x5b, 0x01, "threshold condition met", 820 0x5b, 0x02, "log counter at maximum", 821 0x5b, 0x03, "log list codes exhausted", 822 0x5c, 0x00, "RPL status change", 823 0x5c, 0x01, "spindles synchronized", 824 0x5c, 0x02, "spindles not synchronized", 825 0x5d, 0x00, "drive operation marginal, service immediately" 826 " (failure prediction threshold exceeded)", 827 0x5d, 0x01, "media failure prediction threshold exceeded", 828 0x5d, 0x02, "LUN failure prediction threshold exceeded", 829 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded", 830 0x5d, 0x10, "hardware impending failure general hard drive failure", 831 0x5d, 0x11, "hardware impending failure drive error rate too high", 832 0x5d, 0x12, "hardware impending failure data error rate too high", 833 0x5d, 0x13, "hardware impending failure seek error rate too high", 834 0x5d, 0x14, "hardware impending failure too many block reassigns", 835 0x5d, 0x15, "hardware impending failure access times too high", 836 0x5d, 0x16, "hardware impending failure start unit times too high", 837 0x5d, 0x17, "hardware impending failure channel parametrics", 838 0x5d, 0x18, "hardware impending failure controller detected", 839 0x5d, 0x19, "hardware impending failure throughput performance", 840 0x5d, 0x1a, "hardware impending failure seek time performance", 841 0x5d, 0x1b, "hardware impending failure spin-up retry count", 842 0x5d, 0x1c, "hardware impending failure drive calibration retry count", 843 0x5d, 0x20, "controller impending failure general hard drive failure", 844 0x5d, 0x21, "controller impending failure drive error rate too high", 845 0x5d, 0x22, "controller impending failure data error rate too high", 846 0x5d, 0x23, "controller impending failure seek error rate too high", 847 0x5d, 0x24, "controller impending failure too many block reassigns", 848 0x5d, 0x25, "controller impending failure access times too high", 849 0x5d, 0x26, "controller impending failure start unit times too high", 850 0x5d, 0x27, "controller impending failure channel parametrics", 851 0x5d, 0x28, "controller impending failure controller detected", 852 0x5d, 0x29, "controller impending failure throughput performance", 853 0x5d, 0x2a, "controller impending failure seek time performance", 854 0x5d, 0x2b, "controller impending failure spin-up retry count", 855 0x5d, 0x2c, "controller impending failure drive calibration retry cnt", 856 0x5d, 0x30, "data channel impending failure general hard drive failure", 857 0x5d, 0x31, "data channel impending failure drive error rate too high", 858 0x5d, 0x32, "data channel impending failure data error rate too high", 859 0x5d, 0x33, "data channel impending failure seek error rate too high", 860 0x5d, 0x34, "data channel impending failure too many block reassigns", 861 0x5d, 0x35, "data channel impending failure access times too high", 862 0x5d, 0x36, "data channel impending failure start unit times too high", 863 0x5d, 0x37, "data channel impending failure channel parametrics", 864 0x5d, 0x38, "data channel impending failure controller detected", 865 0x5d, 0x39, "data channel impending failure throughput performance", 866 0x5d, 0x3a, "data channel impending failure seek time performance", 867 0x5d, 0x3b, "data channel impending failure spin-up retry count", 868 0x5d, 0x3c, "data channel impending failure drive calibrate retry cnt", 869 0x5d, 0x40, "servo impending failure general hard drive failure", 870 0x5d, 0x41, "servo impending failure drive error rate too high", 871 0x5d, 0x42, "servo impending failure data error rate too high", 872 0x5d, 0x43, "servo impending failure seek error rate too high", 873 0x5d, 0x44, "servo impending failure too many block reassigns", 874 0x5d, 0x45, "servo impending failure access times too high", 875 0x5d, 0x46, "servo impending failure start unit times too high", 876 0x5d, 0x47, "servo impending failure channel parametrics", 877 0x5d, 0x48, "servo impending failure controller detected", 878 0x5d, 0x49, "servo impending failure throughput performance", 879 0x5d, 0x4a, "servo impending failure seek time performance", 880 0x5d, 0x4b, "servo impending failure spin-up retry count", 881 0x5d, 0x4c, "servo impending failure drive calibration retry count", 882 0x5d, 0x50, "spindle impending failure general hard drive failure", 883 0x5d, 0x51, "spindle impending failure drive error rate too high", 884 0x5d, 0x52, "spindle impending failure data error rate too high", 885 0x5d, 0x53, "spindle impending failure seek error rate too high", 886 0x5d, 0x54, "spindle impending failure too many block reassigns", 887 0x5d, 0x55, "spindle impending failure access times too high", 888 0x5d, 0x56, "spindle impending failure start unit times too high", 889 0x5d, 0x57, "spindle impending failure channel parametrics", 890 0x5d, 0x58, "spindle impending failure controller detected", 891 0x5d, 0x59, "spindle impending failure throughput performance", 892 0x5d, 0x5a, "spindle impending failure seek time performance", 893 0x5d, 0x5b, "spindle impending failure spin-up retry count", 894 0x5d, 0x5c, "spindle impending failure drive calibration retry count", 895 0x5d, 0x60, "firmware impending failure general hard drive failure", 896 0x5d, 0x61, "firmware impending failure drive error rate too high", 897 0x5d, 0x62, "firmware impending failure data error rate too high", 898 0x5d, 0x63, "firmware impending failure seek error rate too high", 899 0x5d, 0x64, "firmware impending failure too many block reassigns", 900 0x5d, 0x65, "firmware impending failure access times too high", 901 0x5d, 0x66, "firmware impending failure start unit times too high", 902 0x5d, 0x67, "firmware impending failure channel parametrics", 903 0x5d, 0x68, "firmware impending failure controller detected", 904 0x5d, 0x69, "firmware impending failure throughput performance", 905 0x5d, 0x6a, "firmware impending failure seek time performance", 906 0x5d, 0x6b, "firmware impending failure spin-up retry count", 907 0x5d, 0x6c, "firmware impending failure drive calibration retry count", 908 0x5d, 0xff, "failure prediction threshold exceeded (false)", 909 0x5e, 0x00, "low power condition active", 910 0x5e, 0x01, "idle condition activated by timer", 911 0x5e, 0x02, "standby condition activated by timer", 912 0x5e, 0x03, "idle condition activated by command", 913 0x5e, 0x04, "standby condition activated by command", 914 0x60, 0x00, "lamp failure", 915 0x61, 0x00, "video aquisition error", 916 0x62, 0x00, "scan head positioning error", 917 0x63, 0x00, "end of user area encountered on this track", 918 0x63, 0x01, "packet does not fit in available space", 919 0x64, 0x00, "illegal mode for this track", 920 0x64, 0x01, "invalid packet size", 921 0x65, 0x00, "voltage fault", 922 0x66, 0x00, "automatic document feeder cover up", 923 0x67, 0x00, "configuration failure", 924 0x67, 0x01, "configuration of incapable LUNs failed", 925 0x67, 0x02, "add LUN failed", 926 0x67, 0x03, "modification of LUN failed", 927 0x67, 0x04, "exchange of LUN failed", 928 0x67, 0x05, "remove of LUN failed", 929 0x67, 0x06, "attachment of LUN failed", 930 0x67, 0x07, "creation of LUN failed", 931 0x67, 0x08, "assign failure occurred", 932 0x67, 0x09, "multiply assigned LUN", 933 0x67, 0x0a, "set target port groups command failed", 934 0x68, 0x00, "logical unit not configured", 935 0x69, 0x00, "data loss on logical unit", 936 0x69, 0x01, "multiple LUN failures", 937 0x69, 0x02, "parity/data mismatch", 938 0x6a, 0x00, "informational, refer to log", 939 0x6b, 0x00, "state change has occured", 940 0x6b, 0x01, "redundancy level got better", 941 0x6b, 0x02, "redundancy level got worse", 942 0x6c, 0x00, "rebuild failure occured", 943 0x6d, 0x00, "recalculate failure occured", 944 0x6e, 0x00, "command to logical unit failed", 945 0x6f, 0x00, "copy protect key exchange failure authentication failure", 946 0x6f, 0x01, "copy protect key exchange failure key not present", 947 0x6f, 0x02, "copy protect key exchange failure key not established", 948 0x6f, 0x03, "read of scrambled sector without authentication", 949 0x6f, 0x04, "media region code is mismatched to LUN region", 950 0x6f, 0x05, "drive region must be permanent/region reset count error", 951 0x70, 0xffff, "decompression exception short algorithm id of ASCQ", 952 0x71, 0x00, "decompression exception long algorithm id", 953 0x72, 0x00, "session fixation error", 954 0x72, 0x01, "session fixation error writing lead-in", 955 0x72, 0x02, "session fixation error writing lead-out", 956 0x72, 0x03, "session fixation error - incomplete track in session", 957 0x72, 0x04, "empty or partially written reserved track", 958 0x72, 0x05, "no more track reservations allowed", 959 0x73, 0x00, "cd control error", 960 0x73, 0x01, "power calibration area almost full", 961 0x73, 0x02, "power calibration area is full", 962 0x73, 0x03, "power calibration area error", 963 0x73, 0x04, "program memory area update failure", 964 0x73, 0x05, "program memory area is full", 965 0x73, 0x06, "rma/pma is almost full", 966 0xffff, 0xffff, NULL 967 }; 968 969 char * 970 scsi_esname(uint_t key, char *tmpstr) 971 { 972 int i = 0; 973 974 while (extended_sense_list[i].asc != 0xffff) { 975 if (key == extended_sense_list[i].asc) { 976 return ((char *)extended_sense_list[i].message); 977 } 978 i++; 979 } 980 return (sprintf(tmpstr, "<vendor unique code 0x%x>", key)); 981 } 982 983 char * 984 scsi_asc_name(uint_t asc, uint_t ascq, char *tmpstr) 985 { 986 int i = 0; 987 988 while (extended_sense_list[i].asc != 0xffff) { 989 if ((asc == extended_sense_list[i].asc) && 990 ((ascq == extended_sense_list[i].ascq) || 991 (extended_sense_list[i].ascq == 0xffff))) { 992 return ((char *)extended_sense_list[i].message); 993 } 994 i++; 995 } 996 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc)); 997 } 998 999 char * 1000 scsi_sname(uchar_t sense_key) 1001 { 1002 if (sense_key >= (uchar_t)(NUM_SENSE_KEYS+NUM_IMPL_SENSE_KEYS)) { 1003 return ("<unknown sense key>"); 1004 } else { 1005 return (sense_keys[sense_key]); 1006 } 1007 } 1008 1009 1010 /* 1011 * Print a piece of inquiry data- cleaned up for non-printable characters. 1012 */ 1013 1014 static void 1015 inq_fill(char *p, int l, char *s) 1016 { 1017 register unsigned i = 0; 1018 char c; 1019 1020 if (!p) 1021 return; 1022 1023 while (i++ < l) { 1024 /* clean string of non-printing chars */ 1025 if ((c = *p++) < ' ' || c >= 0177) { 1026 c = ' '; 1027 } 1028 *s++ = c; 1029 } 1030 *s++ = 0; 1031 } 1032 1033 static char * 1034 scsi_asc_search(uint_t asc, uint_t ascq, 1035 struct scsi_asq_key_strings *list) 1036 { 1037 int i = 0; 1038 1039 while (list[i].asc != 0xffff) { 1040 if ((asc == list[i].asc) && 1041 ((ascq == list[i].ascq) || 1042 (list[i].ascq == 0xffff))) { 1043 return ((char *)list[i].message); 1044 } 1045 i++; 1046 } 1047 return (NULL); 1048 } 1049 1050 static char * 1051 scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr, 1052 struct scsi_asq_key_strings *list) 1053 { 1054 char *message; 1055 1056 if (list) { 1057 if (message = scsi_asc_search(asc, ascq, list)) { 1058 return (message); 1059 } 1060 } 1061 if (message = scsi_asc_search(asc, ascq, extended_sense_list)) { 1062 return (message); 1063 } 1064 1065 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc)); 1066 } 1067 1068 /* 1069 * The first part/column of the error message will be at least this length. 1070 * This number has been calculated so that each line fits in 80 chars. 1071 */ 1072 #define SCSI_ERRMSG_COLUMN_LEN 42 1073 #define SCSI_ERRMSG_BUF_LEN 256 1074 1075 void 1076 scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label, 1077 int severity, daddr_t blkno, daddr_t err_blkno, 1078 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep, 1079 struct scsi_asq_key_strings *asc_list, 1080 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t)) 1081 { 1082 uchar_t com; 1083 static char buf[SCSI_ERRMSG_BUF_LEN]; 1084 static char buf1[SCSI_ERRMSG_BUF_LEN]; 1085 static char tmpbuf[64]; 1086 static char pad[SCSI_ERRMSG_COLUMN_LEN]; 1087 dev_info_t *dev = devp->sd_dev; 1088 static char *error_classes[] = { 1089 "All", "Unknown", "Informational", 1090 "Recovered", "Retryable", "Fatal" 1091 }; 1092 uchar_t sense_key, asc, ascq, fru_code; 1093 uchar_t *fru_code_ptr; 1094 int i, buflen; 1095 1096 mutex_enter(&scsi_log_mutex); 1097 1098 /* 1099 * We need to put our space padding code because kernel version 1100 * of sprintf(9F) doesn't support %-<number>s type of left alignment. 1101 */ 1102 for (i = 0; i < SCSI_ERRMSG_COLUMN_LEN; i++) { 1103 pad[i] = ' '; 1104 } 1105 1106 bzero(buf, 256); 1107 com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd; 1108 (void) sprintf(buf, "Error for Command: %s", 1109 scsi_cmd_name(com, cmdlist, tmpbuf)); 1110 buflen = strlen(buf); 1111 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1112 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1113 (void) sprintf(&buf[buflen], "%s Error Level: %s", 1114 pad, error_classes[severity]); 1115 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1116 } else { 1117 (void) sprintf(&buf[buflen], " Error Level: %s", 1118 error_classes[severity]); 1119 } 1120 impl_scsi_log(dev, label, CE_WARN, buf); 1121 1122 if (blkno != -1 || err_blkno != -1 && 1123 ((com & 0xf) == SCMD_READ) || ((com & 0xf) == SCMD_WRITE)) { 1124 bzero(buf, 256); 1125 (void) sprintf(buf, "Requested Block: %ld", blkno); 1126 buflen = strlen(buf); 1127 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1128 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1129 (void) sprintf(&buf[buflen], "%s Error Block: %ld\n", 1130 pad, err_blkno); 1131 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1132 } else { 1133 (void) sprintf(&buf[buflen], " Error Block: %ld\n", 1134 err_blkno); 1135 } 1136 impl_scsi_log(dev, label, CE_CONT, buf); 1137 } 1138 1139 bzero(buf, 256); 1140 (void) strcpy(buf, "Vendor: "); 1141 inq_fill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]); 1142 buflen = strlen(buf); 1143 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1144 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1145 (void) sprintf(&buf[strlen(buf)], "%s Serial Number: ", pad); 1146 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1147 } else { 1148 (void) sprintf(&buf[strlen(buf)], " Serial Number: "); 1149 } 1150 inq_fill(devp->sd_inq->inq_serial, 12, &buf[strlen(buf)]); 1151 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf); 1152 1153 if (sensep) { 1154 sense_key = scsi_sense_key((uint8_t *)sensep); 1155 asc = scsi_sense_asc((uint8_t *)sensep); 1156 ascq = scsi_sense_ascq((uint8_t *)sensep); 1157 scsi_ext_sense_fields((uint8_t *)sensep, SENSE_LENGTH, 1158 NULL, NULL, &fru_code_ptr, NULL, NULL); 1159 fru_code = (fru_code_ptr ? *fru_code_ptr : 0); 1160 1161 bzero(buf, 256); 1162 (void) sprintf(buf, "Sense Key: %s\n", 1163 sense_keys[sense_key]); 1164 impl_scsi_log(dev, label, CE_CONT, buf); 1165 1166 bzero(buf, 256); 1167 if ((fru_code != 0) && 1168 (decode_fru != NULL)) { 1169 (*decode_fru)(devp, buf, SCSI_ERRMSG_BUF_LEN, 1170 fru_code); 1171 if (buf[0] != NULL) { 1172 bzero(buf1, 256); 1173 (void) sprintf(&buf1[strlen(buf1)], 1174 "ASC: 0x%x (%s)", asc, 1175 scsi_asc_ascq_name(asc, ascq, 1176 tmpbuf, asc_list)); 1177 buflen = strlen(buf1); 1178 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1179 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1180 (void) sprintf(&buf1[buflen], 1181 "%s ASCQ: 0x%x", pad, ascq); 1182 } else { 1183 (void) sprintf(&buf1[buflen], " ASCQ: 0x%x", 1184 ascq); 1185 } 1186 impl_scsi_log(dev, 1187 label, CE_CONT, "%s\n", buf1); 1188 impl_scsi_log(dev, label, CE_CONT, 1189 "FRU: 0x%x (%s)\n", 1190 fru_code, buf); 1191 mutex_exit(&scsi_log_mutex); 1192 return; 1193 } 1194 } 1195 (void) sprintf(&buf[strlen(buf)], 1196 "ASC: 0x%x (%s), ASCQ: 0x%x, FRU: 0x%x", 1197 asc, scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list), 1198 ascq, fru_code); 1199 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf); 1200 } 1201 mutex_exit(&scsi_log_mutex); 1202 } 1203 1204 void 1205 scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label, 1206 int severity, daddr_t blkno, daddr_t err_blkno, 1207 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep) 1208 { 1209 scsi_vu_errmsg(devp, pkt, label, severity, blkno, 1210 err_blkno, cmdlist, sensep, NULL, NULL); 1211 } 1212 1213 /*PRINTFLIKE4*/ 1214 void 1215 scsi_log(dev_info_t *dev, char *label, uint_t level, 1216 const char *fmt, ...) 1217 { 1218 va_list ap; 1219 1220 va_start(ap, fmt); 1221 mutex_enter(&scsi_log_mutex); 1222 v_scsi_log(dev, label, level, fmt, ap); 1223 mutex_exit(&scsi_log_mutex); 1224 va_end(ap); 1225 } 1226 1227 /*PRINTFLIKE4*/ 1228 static void 1229 impl_scsi_log(dev_info_t *dev, char *label, uint_t level, 1230 const char *fmt, ...) 1231 { 1232 va_list ap; 1233 1234 ASSERT(mutex_owned(&scsi_log_mutex)); 1235 1236 va_start(ap, fmt); 1237 v_scsi_log(dev, label, level, fmt, ap); 1238 va_end(ap); 1239 } 1240 1241 1242 char *ddi_pathname(dev_info_t *dip, char *path); 1243 1244 /*PRINTFLIKE4*/ 1245 static void 1246 v_scsi_log(dev_info_t *dev, char *label, uint_t level, 1247 const char *fmt, va_list ap) 1248 { 1249 static char name[256]; 1250 int log_only = 0; 1251 int boot_only = 0; 1252 int console_only = 0; 1253 1254 ASSERT(mutex_owned(&scsi_log_mutex)); 1255 1256 if (dev) { 1257 if (level == CE_PANIC || level == CE_WARN || 1258 level == CE_NOTE) { 1259 (void) sprintf(name, "%s (%s%d):\n", 1260 ddi_pathname(dev, scsi_log_buffer), 1261 label, ddi_get_instance(dev)); 1262 } else if (level >= (uint_t)SCSI_DEBUG) { 1263 (void) sprintf(name, 1264 "%s%d:", label, ddi_get_instance(dev)); 1265 } else { 1266 name[0] = '\0'; 1267 } 1268 } else { 1269 (void) sprintf(name, "%s:", label); 1270 } 1271 1272 (void) vsprintf(scsi_log_buffer, fmt, ap); 1273 1274 switch (scsi_log_buffer[0]) { 1275 case '!': 1276 log_only = 1; 1277 break; 1278 case '?': 1279 boot_only = 1; 1280 break; 1281 case '^': 1282 console_only = 1; 1283 break; 1284 } 1285 1286 switch (level) { 1287 case CE_NOTE: 1288 level = CE_CONT; 1289 /* FALLTHROUGH */ 1290 case CE_CONT: 1291 case CE_WARN: 1292 case CE_PANIC: 1293 if (boot_only) { 1294 cmn_err(level, "?%s\t%s", name, 1295 &scsi_log_buffer[1]); 1296 } else if (console_only) { 1297 cmn_err(level, "^%s\t%s", name, 1298 &scsi_log_buffer[1]); 1299 } else if (log_only) { 1300 cmn_err(level, "!%s\t%s", name, 1301 &scsi_log_buffer[1]); 1302 } else { 1303 cmn_err(level, "%s\t%s", name, 1304 scsi_log_buffer); 1305 } 1306 break; 1307 case (uint_t)SCSI_DEBUG: 1308 default: 1309 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, 1310 scsi_log_buffer); 1311 break; 1312 } 1313 } 1314 1315 int 1316 scsi_get_device_type_scsi_options(dev_info_t *dip, 1317 struct scsi_device *devp, int default_scsi_options) 1318 { 1319 1320 caddr_t config_list = NULL; 1321 int options = default_scsi_options; 1322 struct scsi_inquiry *inq = devp->sd_inq; 1323 caddr_t vidptr, datanameptr; 1324 int vidlen, dupletlen; 1325 int config_list_len, len; 1326 1327 /* 1328 * look up the device-type-scsi-options-list and walk thru 1329 * the list 1330 * compare the vendor ids of the earlier inquiry command and 1331 * with those vids in the list 1332 * if there is a match, lookup the scsi-options value 1333 */ 1334 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1335 "device-type-scsi-options-list", 1336 (caddr_t)&config_list, &config_list_len) == DDI_PROP_SUCCESS) { 1337 1338 /* 1339 * Compare vids in each duplet - if it matches, get value for 1340 * dataname and then lookup scsi_options 1341 * dupletlen is calculated later. 1342 */ 1343 for (len = config_list_len, vidptr = config_list; len > 0; 1344 vidptr += dupletlen, len -= dupletlen) { 1345 1346 vidlen = strlen(vidptr); 1347 datanameptr = vidptr + vidlen + 1; 1348 1349 if ((vidlen != 0) && 1350 bcmp(inq->inq_vid, vidptr, vidlen) == 0) { 1351 /* 1352 * get the data list 1353 */ 1354 options = ddi_prop_get_int(DDI_DEV_T_ANY, 1355 dip, 0, 1356 datanameptr, default_scsi_options); 1357 break; 1358 } 1359 dupletlen = vidlen + strlen(datanameptr) + 2; 1360 } 1361 kmem_free(config_list, config_list_len); 1362 } 1363 1364 return (options); 1365 } 1366 1367 /* 1368 * Functions for format-neutral sense data functions 1369 */ 1370 1371 int 1372 scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags) 1373 { 1374 int result; 1375 struct scsi_extended_sense *es = 1376 (struct scsi_extended_sense *)sense_buffer; 1377 1378 /* 1379 * Init flags if present 1380 */ 1381 if (flags != NULL) { 1382 *flags = 0; 1383 } 1384 1385 /* 1386 * Check response code (Solaris breaks this into a 3-bit class 1387 * and 4-bit code field. 1388 */ 1389 if ((es->es_class != CLASS_EXTENDED_SENSE) || 1390 ((es->es_code != CODE_FMT_FIXED_CURRENT) && 1391 (es->es_code != CODE_FMT_FIXED_DEFERRED) && 1392 (es->es_code != CODE_FMT_DESCR_CURRENT) && 1393 (es->es_code != CODE_FMT_DESCR_DEFERRED))) { 1394 /* 1395 * Sense data (if there's actually anything here) is not 1396 * in a format we can handle). 1397 */ 1398 return (SENSE_UNUSABLE); 1399 } 1400 1401 /* 1402 * Check if this is deferred sense 1403 */ 1404 if ((flags != NULL) && 1405 ((es->es_code == CODE_FMT_FIXED_DEFERRED) || 1406 (es->es_code == CODE_FMT_DESCR_DEFERRED))) { 1407 *flags |= SNS_BUF_DEFERRED; 1408 } 1409 1410 /* 1411 * Make sure length is OK 1412 */ 1413 if (es->es_code == CODE_FMT_FIXED_CURRENT || 1414 es->es_code == CODE_FMT_FIXED_DEFERRED) { 1415 /* 1416 * We can get by with a buffer that only includes the key, 1417 * asc, and ascq. In reality the minimum length we should 1418 * ever see is 18 bytes. 1419 */ 1420 if ((sense_buf_len < MIN_FIXED_SENSE_LEN) || 1421 ((es->es_add_len + ADDL_SENSE_ADJUST) < 1422 MIN_FIXED_SENSE_LEN)) { 1423 result = SENSE_UNUSABLE; 1424 } else { 1425 /* 1426 * The es_add_len field contains the number of sense 1427 * data bytes that follow the es_add_len field. 1428 */ 1429 if ((flags != NULL) && 1430 (sense_buf_len < 1431 (es->es_add_len + ADDL_SENSE_ADJUST))) { 1432 *flags |= SNS_BUF_OVERFLOW; 1433 } 1434 1435 result = SENSE_FIXED_FORMAT; 1436 } 1437 } else { 1438 struct scsi_descr_sense_hdr *ds = 1439 (struct scsi_descr_sense_hdr *)sense_buffer; 1440 1441 /* 1442 * For descriptor format we need at least the descriptor 1443 * header 1444 */ 1445 if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) { 1446 result = SENSE_UNUSABLE; 1447 } else { 1448 /* 1449 * Check for overflow 1450 */ 1451 if ((flags != NULL) && 1452 (sense_buf_len < 1453 (ds->ds_addl_sense_length + sizeof (*ds)))) { 1454 *flags |= SNS_BUF_OVERFLOW; 1455 } 1456 1457 result = SENSE_DESCR_FORMAT; 1458 } 1459 } 1460 1461 return (result); 1462 } 1463 1464 1465 uint8_t 1466 scsi_sense_key(uint8_t *sense_buffer) 1467 { 1468 uint8_t skey; 1469 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1470 struct scsi_descr_sense_hdr *sdsp = 1471 (struct scsi_descr_sense_hdr *)sense_buffer; 1472 skey = sdsp->ds_key; 1473 } else { 1474 struct scsi_extended_sense *ext_sensep = 1475 (struct scsi_extended_sense *)sense_buffer; 1476 skey = ext_sensep->es_key; 1477 } 1478 return (skey); 1479 } 1480 1481 uint8_t 1482 scsi_sense_asc(uint8_t *sense_buffer) 1483 { 1484 uint8_t asc; 1485 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1486 struct scsi_descr_sense_hdr *sdsp = 1487 (struct scsi_descr_sense_hdr *)sense_buffer; 1488 asc = sdsp->ds_add_code; 1489 } else { 1490 struct scsi_extended_sense *ext_sensep = 1491 (struct scsi_extended_sense *)sense_buffer; 1492 asc = ext_sensep->es_add_code; 1493 } 1494 return (asc); 1495 } 1496 1497 uint8_t 1498 scsi_sense_ascq(uint8_t *sense_buffer) 1499 { 1500 uint8_t ascq; 1501 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1502 struct scsi_descr_sense_hdr *sdsp = 1503 (struct scsi_descr_sense_hdr *)sense_buffer; 1504 ascq = sdsp->ds_qual_code; 1505 } else { 1506 struct scsi_extended_sense *ext_sensep = 1507 (struct scsi_extended_sense *)sense_buffer; 1508 ascq = ext_sensep->es_qual_code; 1509 } 1510 return (ascq); 1511 } 1512 1513 void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len, 1514 uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code, 1515 uint8_t **sk_specific, uint8_t **stream_flags) 1516 { 1517 int sense_fmt; 1518 1519 /* 1520 * Sanity check sense data and determine the format 1521 */ 1522 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1523 1524 /* 1525 * Initialize any requested data to 0 1526 */ 1527 if (information) { 1528 *information = NULL; 1529 } 1530 if (cmd_spec_info) { 1531 *cmd_spec_info = NULL; 1532 } 1533 if (fru_code) { 1534 *fru_code = NULL; 1535 } 1536 if (sk_specific) { 1537 *sk_specific = NULL; 1538 } 1539 if (stream_flags) { 1540 *stream_flags = NULL; 1541 } 1542 1543 if (sense_fmt == SENSE_DESCR_FORMAT) { 1544 struct scsi_descr_template *sdt = NULL; 1545 1546 while (scsi_get_next_descr(sense_buffer, 1547 sense_buf_len, &sdt) != -1) { 1548 switch (sdt->sdt_descr_type) { 1549 case DESCR_INFORMATION: { 1550 struct scsi_information_sense_descr *isd = 1551 (struct scsi_information_sense_descr *) 1552 sdt; 1553 if (information) { 1554 *information = 1555 &isd->isd_information[0]; 1556 } 1557 break; 1558 } 1559 case DESCR_COMMAND_SPECIFIC: { 1560 struct scsi_cmd_specific_sense_descr *csd = 1561 (struct scsi_cmd_specific_sense_descr *) 1562 sdt; 1563 if (cmd_spec_info) { 1564 *cmd_spec_info = 1565 &csd->css_cmd_specific_info[0]; 1566 } 1567 break; 1568 } 1569 case DESCR_SENSE_KEY_SPECIFIC: { 1570 struct scsi_sk_specific_sense_descr *ssd = 1571 (struct scsi_sk_specific_sense_descr *) 1572 sdt; 1573 if (sk_specific) { 1574 *sk_specific = 1575 (uint8_t *)&ssd->sss_data; 1576 } 1577 break; 1578 } 1579 case DESCR_FRU: { 1580 struct scsi_fru_sense_descr *fsd = 1581 (struct scsi_fru_sense_descr *) 1582 sdt; 1583 if (fru_code) { 1584 *fru_code = &fsd->fs_fru_code; 1585 } 1586 break; 1587 } 1588 case DESCR_STREAM_COMMANDS: { 1589 struct scsi_stream_cmd_sense_descr *strsd = 1590 (struct scsi_stream_cmd_sense_descr *) 1591 sdt; 1592 if (stream_flags) { 1593 *stream_flags = 1594 (uint8_t *)&strsd->scs_data; 1595 } 1596 break; 1597 } 1598 case DESCR_BLOCK_COMMANDS: { 1599 struct scsi_block_cmd_sense_descr *bsd = 1600 (struct scsi_block_cmd_sense_descr *) 1601 sdt; 1602 /* 1603 * The "Block Command" sense descriptor 1604 * contains an ili bit that we can store 1605 * in the stream specific data if it is 1606 * available. We shouldn't see both 1607 * a block command and a stream command 1608 * descriptor in the same collection 1609 * of sense data. 1610 */ 1611 if (stream_flags) { 1612 /* 1613 * Can't take an address of a bitfield, 1614 * but the flags are just after the 1615 * bcs_reserved field. 1616 */ 1617 *stream_flags = 1618 (uint8_t *)&bsd->bcs_reserved + 1; 1619 } 1620 break; 1621 } 1622 } 1623 } 1624 } else { 1625 struct scsi_extended_sense *es = 1626 (struct scsi_extended_sense *)sense_buffer; 1627 1628 /* Get data from fixed sense buffer */ 1629 if (information && es->es_valid) { 1630 *information = &es->es_info_1; 1631 } 1632 if (cmd_spec_info && es->es_valid) { 1633 *cmd_spec_info = &es->es_cmd_info[0]; 1634 } 1635 if (fru_code) { 1636 *fru_code = &es->es_fru_code; 1637 } 1638 if (sk_specific) { 1639 *sk_specific = &es->es_skey_specific[0]; 1640 } 1641 if (stream_flags) { 1642 /* 1643 * Can't take the address of a bit field, 1644 * but the stream flags are located just after 1645 * the es_segnum field; 1646 */ 1647 *stream_flags = &es->es_segnum + 1; 1648 } 1649 } 1650 } 1651 1652 boolean_t 1653 scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len, 1654 uint64_t *information) 1655 { 1656 boolean_t valid; 1657 int sense_fmt; 1658 1659 ASSERT(sense_buffer != NULL); 1660 ASSERT(information != NULL); 1661 1662 /* Validate sense data and get format */ 1663 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1664 1665 if (sense_fmt == SENSE_UNUSABLE) { 1666 /* Information is not valid */ 1667 valid = 0; 1668 } else if (sense_fmt == SENSE_FIXED_FORMAT) { 1669 struct scsi_extended_sense *es = 1670 (struct scsi_extended_sense *)sense_buffer; 1671 1672 *information = (uint64_t)SCSI_READ32(&es->es_info_1); 1673 1674 valid = es->es_valid; 1675 } else { 1676 /* Sense data is descriptor format */ 1677 struct scsi_information_sense_descr *isd; 1678 1679 isd = (struct scsi_information_sense_descr *) 1680 scsi_find_sense_descr(sense_buffer, sense_buf_len, 1681 DESCR_INFORMATION); 1682 1683 if (isd) { 1684 *information = SCSI_READ64(isd->isd_information); 1685 valid = 1; 1686 } else { 1687 valid = 0; 1688 } 1689 } 1690 1691 return (valid); 1692 } 1693 1694 boolean_t 1695 scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len, 1696 uint64_t *cmd_specific_info) 1697 { 1698 boolean_t valid; 1699 int sense_fmt; 1700 1701 ASSERT(sense_buffer != NULL); 1702 ASSERT(cmd_specific_info != NULL); 1703 1704 /* Validate sense data and get format */ 1705 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1706 1707 if (sense_fmt == SENSE_UNUSABLE) { 1708 /* Command specific info is not valid */ 1709 valid = 0; 1710 } else if (sense_fmt == SENSE_FIXED_FORMAT) { 1711 struct scsi_extended_sense *es = 1712 (struct scsi_extended_sense *)sense_buffer; 1713 1714 *cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info); 1715 1716 valid = es->es_valid; 1717 } else { 1718 /* Sense data is descriptor format */ 1719 struct scsi_cmd_specific_sense_descr *c; 1720 1721 c = (struct scsi_cmd_specific_sense_descr *) 1722 scsi_find_sense_descr(sense_buffer, sense_buf_len, 1723 DESCR_COMMAND_SPECIFIC); 1724 1725 if (c) { 1726 valid = 1; 1727 *cmd_specific_info = 1728 SCSI_READ64(c->css_cmd_specific_info); 1729 } else { 1730 valid = 0; 1731 } 1732 } 1733 1734 return (valid); 1735 } 1736 1737 uint8_t * 1738 scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type) 1739 { 1740 struct scsi_descr_template *sdt = NULL; 1741 1742 while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) { 1743 ASSERT(sdt != NULL); 1744 if (sdt->sdt_descr_type == req_descr_type) { 1745 /* Found requested descriptor type */ 1746 break; 1747 } 1748 } 1749 1750 return ((uint8_t *)sdt); 1751 } 1752 1753 /* 1754 * Sense Descriptor format is: 1755 * 1756 * <Descriptor type> <Descriptor length> <Descriptor data> ... 1757 * 1758 * 2 must be added to the descriptor length value to get the 1759 * total descriptor length sense the stored length does not 1760 * include the "type" and "additional length" fields. 1761 */ 1762 1763 #define NEXT_DESCR_PTR(ndp_descr) \ 1764 ((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \ 1765 ((ndp_descr)->sdt_addl_length + \ 1766 sizeof (struct scsi_descr_template)))) 1767 1768 static int 1769 scsi_get_next_descr(uint8_t *sense_buffer, 1770 int sense_buf_len, struct scsi_descr_template **descrpp) 1771 { 1772 struct scsi_descr_sense_hdr *sdsp = 1773 (struct scsi_descr_sense_hdr *)sense_buffer; 1774 struct scsi_descr_template *cur_descr; 1775 boolean_t find_first; 1776 int valid_sense_length; 1777 1778 ASSERT(descrpp != NULL); 1779 find_first = (*descrpp == NULL); 1780 1781 /* 1782 * If no descriptor is passed in then return the first 1783 * descriptor 1784 */ 1785 if (find_first) { 1786 /* 1787 * The first descriptor will immediately follow the header 1788 * (Pointer arithmetic) 1789 */ 1790 cur_descr = (struct scsi_descr_template *)(sdsp+1); 1791 } else { 1792 cur_descr = *descrpp; 1793 ASSERT(cur_descr > (struct scsi_descr_template *)sdsp); 1794 } 1795 1796 /* Assume no more descriptors are available */ 1797 *descrpp = NULL; 1798 1799 /* 1800 * Calculate the amount of valid sense data -- make sure the length 1801 * byte in this descriptor lies within the valid sense data. 1802 */ 1803 valid_sense_length = 1804 min((sizeof (struct scsi_descr_sense_hdr) + 1805 sdsp->ds_addl_sense_length), 1806 sense_buf_len); 1807 1808 /* 1809 * Make sure this descriptor is complete (either the first 1810 * descriptor or the descriptor passed in) 1811 */ 1812 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) != 1813 DESCR_GOOD) { 1814 return (-1); 1815 } 1816 1817 /* 1818 * If we were looking for the first descriptor go ahead and return it 1819 */ 1820 if (find_first) { 1821 *descrpp = cur_descr; 1822 return ((*descrpp)->sdt_descr_type); 1823 } 1824 1825 /* 1826 * Get pointer to next descriptor 1827 */ 1828 cur_descr = NEXT_DESCR_PTR(cur_descr); 1829 1830 /* 1831 * Make sure this descriptor is also complete. 1832 */ 1833 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) != 1834 DESCR_GOOD) { 1835 return (-1); 1836 } 1837 1838 *descrpp = (struct scsi_descr_template *)cur_descr; 1839 return ((*descrpp)->sdt_descr_type); 1840 } 1841 1842 static int 1843 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp, 1844 int valid_sense_length, struct scsi_descr_template *descrp) 1845 { 1846 int descr_offset, next_descr_offset; 1847 1848 /* 1849 * Make sure length is present 1850 */ 1851 descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp; 1852 if (descr_offset + sizeof (struct scsi_descr_template) > 1853 valid_sense_length) { 1854 return (DESCR_PARTIAL); 1855 } 1856 1857 /* 1858 * Check if length is 0 (no more descriptors) 1859 */ 1860 if (descrp->sdt_addl_length == 0) { 1861 return (DESCR_END); 1862 } 1863 1864 /* 1865 * Make sure the rest of the descriptor is present 1866 */ 1867 next_descr_offset = 1868 (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp; 1869 if (next_descr_offset > valid_sense_length) { 1870 return (DESCR_PARTIAL); 1871 } 1872 1873 return (DESCR_GOOD); 1874 } 1875