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