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