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