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