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