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 static void 1044 inq_fill(char *p, int l, char *s) 1045 { 1046 register unsigned i = 0; 1047 char c; 1048 1049 if (!p) 1050 return; 1051 1052 while (i++ < l) { 1053 /* clean string of non-printing chars */ 1054 if ((c = *p++) < ' ' || c >= 0177) { 1055 c = ' '; 1056 } 1057 *s++ = c; 1058 } 1059 *s++ = 0; 1060 } 1061 1062 static char * 1063 scsi_asc_search(uint_t asc, uint_t ascq, 1064 struct scsi_asq_key_strings *list) 1065 { 1066 int i = 0; 1067 1068 while (list[i].asc != 0xffff) { 1069 if ((asc == list[i].asc) && 1070 ((ascq == list[i].ascq) || 1071 (list[i].ascq == 0xffff))) { 1072 return ((char *)list[i].message); 1073 } 1074 i++; 1075 } 1076 return (NULL); 1077 } 1078 1079 static char * 1080 scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr, 1081 struct scsi_asq_key_strings *list) 1082 { 1083 char *message; 1084 1085 if (list) { 1086 if (message = scsi_asc_search(asc, ascq, list)) { 1087 return (message); 1088 } 1089 } 1090 if (message = scsi_asc_search(asc, ascq, extended_sense_list)) { 1091 return (message); 1092 } 1093 1094 return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc)); 1095 } 1096 1097 /* 1098 * The first part/column of the error message will be at least this length. 1099 * This number has been calculated so that each line fits in 80 chars. 1100 */ 1101 #define SCSI_ERRMSG_COLUMN_LEN 42 1102 #define SCSI_ERRMSG_BUF_LEN 256 1103 1104 void 1105 scsi_generic_errmsg(struct scsi_device *devp, char *label, int severity, 1106 daddr_t blkno, daddr_t err_blkno, 1107 uchar_t cmd_name, struct scsi_key_strings *cmdlist, 1108 uint8_t *sensep, struct scsi_asq_key_strings *asc_list, 1109 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t)) 1110 { 1111 uchar_t com; 1112 static char buf[SCSI_ERRMSG_BUF_LEN]; 1113 static char buf1[SCSI_ERRMSG_BUF_LEN]; 1114 static char tmpbuf[64]; 1115 static char pad[SCSI_ERRMSG_COLUMN_LEN]; 1116 dev_info_t *dev = devp->sd_dev; 1117 static char *error_classes[] = { 1118 "All", "Unknown", "Informational", 1119 "Recovered", "Retryable", "Fatal" 1120 }; 1121 uchar_t sense_key, asc, ascq, fru_code; 1122 uchar_t *fru_code_ptr; 1123 int i, buflen; 1124 1125 mutex_enter(&scsi_log_mutex); 1126 1127 /* 1128 * We need to put our space padding code because kernel version 1129 * of sprintf(9F) doesn't support %-<number>s type of left alignment. 1130 */ 1131 for (i = 0; i < SCSI_ERRMSG_COLUMN_LEN; i++) { 1132 pad[i] = ' '; 1133 } 1134 1135 bzero(buf, 256); 1136 com = cmd_name; 1137 (void) sprintf(buf, "Error for Command: %s", 1138 scsi_cmd_name(com, cmdlist, tmpbuf)); 1139 buflen = strlen(buf); 1140 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1141 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1142 (void) sprintf(&buf[buflen], "%s Error Level: %s", 1143 pad, error_classes[severity]); 1144 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1145 } else { 1146 (void) sprintf(&buf[buflen], " Error Level: %s", 1147 error_classes[severity]); 1148 } 1149 impl_scsi_log(dev, label, CE_WARN, buf); 1150 1151 if (blkno != -1 || err_blkno != -1 && 1152 ((com & 0xf) == SCMD_READ) || ((com & 0xf) == SCMD_WRITE)) { 1153 bzero(buf, 256); 1154 (void) sprintf(buf, "Requested Block: %ld", blkno); 1155 buflen = strlen(buf); 1156 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1157 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1158 (void) sprintf(&buf[buflen], "%s Error Block: %ld\n", 1159 pad, err_blkno); 1160 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1161 } else { 1162 (void) sprintf(&buf[buflen], " Error Block: %ld\n", 1163 err_blkno); 1164 } 1165 impl_scsi_log(dev, label, CE_CONT, buf); 1166 } 1167 1168 bzero(buf, 256); 1169 (void) strcpy(buf, "Vendor: "); 1170 inq_fill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]); 1171 buflen = strlen(buf); 1172 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1173 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0'; 1174 (void) sprintf(&buf[strlen(buf)], "%s Serial Number: ", pad); 1175 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' '; 1176 } else { 1177 (void) sprintf(&buf[strlen(buf)], " Serial Number: "); 1178 } 1179 inq_fill(devp->sd_inq->inq_serial, 12, &buf[strlen(buf)]); 1180 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf); 1181 1182 if (sensep) { 1183 sense_key = scsi_sense_key(sensep); 1184 asc = scsi_sense_asc(sensep); 1185 ascq = scsi_sense_ascq(sensep); 1186 scsi_ext_sense_fields(sensep, SENSE_LENGTH, 1187 NULL, NULL, &fru_code_ptr, NULL, NULL); 1188 fru_code = (fru_code_ptr ? *fru_code_ptr : 0); 1189 1190 bzero(buf, 256); 1191 (void) sprintf(buf, "Sense Key: %s\n", 1192 sense_keys[sense_key]); 1193 impl_scsi_log(dev, label, CE_CONT, buf); 1194 1195 bzero(buf, 256); 1196 if ((fru_code != 0) && 1197 (decode_fru != NULL)) { 1198 (*decode_fru)(devp, buf, SCSI_ERRMSG_BUF_LEN, 1199 fru_code); 1200 if (buf[0] != NULL) { 1201 bzero(buf1, 256); 1202 (void) sprintf(&buf1[strlen(buf1)], 1203 "ASC: 0x%x (%s)", asc, 1204 scsi_asc_ascq_name(asc, ascq, 1205 tmpbuf, asc_list)); 1206 buflen = strlen(buf1); 1207 if (buflen < SCSI_ERRMSG_COLUMN_LEN) { 1208 pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = 1209 '\0'; 1210 (void) sprintf(&buf1[buflen], 1211 "%s ASCQ: 0x%x", pad, ascq); 1212 } else { 1213 (void) sprintf(&buf1[buflen], 1214 " ASCQ: 0x%x", ascq); 1215 } 1216 impl_scsi_log(dev, 1217 label, CE_CONT, "%s\n", buf1); 1218 impl_scsi_log(dev, 1219 label, CE_CONT, "FRU: 0x%x (%s)\n", 1220 fru_code, buf); 1221 mutex_exit(&scsi_log_mutex); 1222 return; 1223 } 1224 } 1225 (void) sprintf(&buf[strlen(buf)], 1226 "ASC: 0x%x (%s), ASCQ: 0x%x, FRU: 0x%x", 1227 asc, scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list), 1228 ascq, fru_code); 1229 impl_scsi_log(dev, label, CE_CONT, "%s\n", buf); 1230 } 1231 mutex_exit(&scsi_log_mutex); 1232 } 1233 1234 void 1235 scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label, 1236 int severity, daddr_t blkno, daddr_t err_blkno, 1237 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep, 1238 struct scsi_asq_key_strings *asc_list, 1239 char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t)) 1240 { 1241 uchar_t com; 1242 1243 com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd; 1244 1245 scsi_generic_errmsg(devp, label, severity, blkno, err_blkno, 1246 com, cmdlist, (uint8_t *)sensep, asc_list, decode_fru); 1247 1248 1249 } 1250 1251 void 1252 scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label, 1253 int severity, daddr_t blkno, daddr_t err_blkno, 1254 struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep) 1255 { 1256 scsi_vu_errmsg(devp, pkt, label, severity, blkno, 1257 err_blkno, cmdlist, sensep, NULL, NULL); 1258 } 1259 1260 /*PRINTFLIKE4*/ 1261 void 1262 scsi_log(dev_info_t *dev, char *label, uint_t level, 1263 const char *fmt, ...) 1264 { 1265 va_list ap; 1266 1267 va_start(ap, fmt); 1268 mutex_enter(&scsi_log_mutex); 1269 v_scsi_log(dev, label, level, fmt, ap); 1270 mutex_exit(&scsi_log_mutex); 1271 va_end(ap); 1272 } 1273 1274 /*PRINTFLIKE4*/ 1275 static void 1276 impl_scsi_log(dev_info_t *dev, char *label, uint_t level, 1277 const char *fmt, ...) 1278 { 1279 va_list ap; 1280 1281 ASSERT(mutex_owned(&scsi_log_mutex)); 1282 1283 va_start(ap, fmt); 1284 v_scsi_log(dev, label, level, fmt, ap); 1285 va_end(ap); 1286 } 1287 1288 1289 char *ddi_pathname(dev_info_t *dip, char *path); 1290 1291 /*PRINTFLIKE4*/ 1292 static void 1293 v_scsi_log(dev_info_t *dev, char *label, uint_t level, 1294 const char *fmt, va_list ap) 1295 { 1296 static char name[256]; 1297 int log_only = 0; 1298 int boot_only = 0; 1299 int console_only = 0; 1300 1301 ASSERT(mutex_owned(&scsi_log_mutex)); 1302 1303 if (dev) { 1304 if (level == CE_PANIC || level == CE_WARN || 1305 level == CE_NOTE) { 1306 (void) sprintf(name, "%s (%s%d):\n", 1307 ddi_pathname(dev, scsi_log_buffer), 1308 label, ddi_get_instance(dev)); 1309 } else if (level >= (uint_t)SCSI_DEBUG) { 1310 (void) sprintf(name, 1311 "%s%d:", label, ddi_get_instance(dev)); 1312 } else { 1313 name[0] = '\0'; 1314 } 1315 } else { 1316 (void) sprintf(name, "%s:", label); 1317 } 1318 1319 (void) vsprintf(scsi_log_buffer, fmt, ap); 1320 1321 switch (scsi_log_buffer[0]) { 1322 case '!': 1323 log_only = 1; 1324 break; 1325 case '?': 1326 boot_only = 1; 1327 break; 1328 case '^': 1329 console_only = 1; 1330 break; 1331 } 1332 1333 switch (level) { 1334 case CE_NOTE: 1335 level = CE_CONT; 1336 /* FALLTHROUGH */ 1337 case CE_CONT: 1338 case CE_WARN: 1339 case CE_PANIC: 1340 if (boot_only) { 1341 cmn_err(level, "?%s\t%s", name, &scsi_log_buffer[1]); 1342 } else if (console_only) { 1343 cmn_err(level, "^%s\t%s", name, &scsi_log_buffer[1]); 1344 } else if (log_only) { 1345 cmn_err(level, "!%s\t%s", name, &scsi_log_buffer[1]); 1346 } else { 1347 cmn_err(level, "%s\t%s", name, scsi_log_buffer); 1348 } 1349 break; 1350 case (uint_t)SCSI_DEBUG: 1351 default: 1352 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, scsi_log_buffer); 1353 break; 1354 } 1355 } 1356 1357 /* 1358 * Lookup the 'prop_name' string array property and walk thru its list of 1359 * tuple values looking for a tuple who's VID/PID string (first part of tuple) 1360 * matches the inquiry VID/PID information for the scsi_device. On a match, 1361 * return a duplicate of the second part of the tuple. If no match is found, 1362 * return NULL. On non-NULL return, caller is responsible for freeing return 1363 * result via: 1364 * kmem_free(string, strlen(string) + 1); 1365 * 1366 * This interface can either be used directly, or indirectly by 1367 * scsi_get_device_type_scsi_options. 1368 */ 1369 char * 1370 scsi_get_device_type_string(char *prop_name, 1371 dev_info_t *dip, struct scsi_device *devp) 1372 { 1373 struct scsi_inquiry *inq = devp->sd_inq; 1374 char **tuples; 1375 uint_t ntuples; 1376 int i; 1377 char *tvp; /* tuple vid/pid */ 1378 char *trs; /* tuple return string */ 1379 int tvp_len; 1380 1381 /* if we have no inquiry data then we can't do this */ 1382 if (inq == NULL) 1383 return (NULL); 1384 1385 /* 1386 * So that we can establish a 'prop_name' for all instances of a 1387 * device in the system in a single place if needed (via options.conf), 1388 * we loop going up to the root ourself. This way root lookup does 1389 * *not* specify DDI_PROP_DONTPASS, and the code will look on the 1390 * options node. 1391 */ 1392 do { 1393 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 1394 (ddi_get_parent(dip) ? DDI_PROP_DONTPASS : 0) | 1395 DDI_PROP_NOTPROM, prop_name, &tuples, &ntuples) == 1396 DDI_PROP_SUCCESS) { 1397 1398 /* loop over tuples */ 1399 for (i = 0; i < (ntuples/2); i++) { 1400 /* split into vid/pid and return-string */ 1401 tvp = tuples[i * 2]; 1402 trs = tuples[(i * 2) + 1]; 1403 tvp_len = strlen(tvp); 1404 1405 /* check for vid/pid match */ 1406 if ((tvp_len == 0) || 1407 bcmp(tvp, inq->inq_vid, tvp_len)) 1408 continue; /* no match */ 1409 1410 /* match, dup return-string */ 1411 trs = i_ddi_strdup(trs, KM_SLEEP); 1412 ddi_prop_free(tuples); 1413 return (trs); 1414 } 1415 ddi_prop_free(tuples); 1416 } 1417 1418 /* climb up to root one step at a time */ 1419 dip = ddi_get_parent(dip); 1420 } while (dip); 1421 1422 return (NULL); 1423 } 1424 1425 /* 1426 * The 'device-type-scsi-options' mechanism can be used to establish a device 1427 * specific scsi_options value for a particular device. This mechanism uses 1428 * paired strings ("vendor_info", "options_property_name") from the string 1429 * array "device-type-scsi-options" definition. A bcmp of the vendor info is 1430 * done against the inquiry data (inq_vid). Here is an example of use: 1431 * 1432 * device-type-scsi-options-list = 1433 * "FOOLCO Special x1000", "foolco-scsi-options", 1434 * "FOOLCO Special y1000", "foolco-scsi-options"; 1435 * foolco-scsi-options = 0xXXXXXXXX; 1436 */ 1437 int 1438 scsi_get_device_type_scsi_options(dev_info_t *dip, 1439 struct scsi_device *devp, int options) 1440 { 1441 char *string; 1442 1443 if ((string = scsi_get_device_type_string( 1444 "device-type-scsi-options-list", dip, devp)) != NULL) { 1445 options = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 1446 string, options); 1447 kmem_free(string, strlen(string) + 1); 1448 } 1449 return (options); 1450 } 1451 1452 /* 1453 * Functions for format-neutral sense data functions 1454 */ 1455 int 1456 scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags) 1457 { 1458 int result; 1459 struct scsi_extended_sense *es = 1460 (struct scsi_extended_sense *)sense_buffer; 1461 1462 /* 1463 * Init flags if present 1464 */ 1465 if (flags != NULL) { 1466 *flags = 0; 1467 } 1468 1469 /* 1470 * Check response code (Solaris breaks this into a 3-bit class 1471 * and 4-bit code field. 1472 */ 1473 if ((es->es_class != CLASS_EXTENDED_SENSE) || 1474 ((es->es_code != CODE_FMT_FIXED_CURRENT) && 1475 (es->es_code != CODE_FMT_FIXED_DEFERRED) && 1476 (es->es_code != CODE_FMT_DESCR_CURRENT) && 1477 (es->es_code != CODE_FMT_DESCR_DEFERRED))) { 1478 /* 1479 * Sense data (if there's actually anything here) is not 1480 * in a format we can handle). 1481 */ 1482 return (SENSE_UNUSABLE); 1483 } 1484 1485 /* 1486 * Check if this is deferred sense 1487 */ 1488 if ((flags != NULL) && 1489 ((es->es_code == CODE_FMT_FIXED_DEFERRED) || 1490 (es->es_code == CODE_FMT_DESCR_DEFERRED))) { 1491 *flags |= SNS_BUF_DEFERRED; 1492 } 1493 1494 /* 1495 * Make sure length is OK 1496 */ 1497 if (es->es_code == CODE_FMT_FIXED_CURRENT || 1498 es->es_code == CODE_FMT_FIXED_DEFERRED) { 1499 /* 1500 * We can get by with a buffer that only includes the key, 1501 * asc, and ascq. In reality the minimum length we should 1502 * ever see is 18 bytes. 1503 */ 1504 if ((sense_buf_len < MIN_FIXED_SENSE_LEN) || 1505 ((es->es_add_len + ADDL_SENSE_ADJUST) < 1506 MIN_FIXED_SENSE_LEN)) { 1507 result = SENSE_UNUSABLE; 1508 } else { 1509 /* 1510 * The es_add_len field contains the number of sense 1511 * data bytes that follow the es_add_len field. 1512 */ 1513 if ((flags != NULL) && 1514 (sense_buf_len < 1515 (es->es_add_len + ADDL_SENSE_ADJUST))) { 1516 *flags |= SNS_BUF_OVERFLOW; 1517 } 1518 1519 result = SENSE_FIXED_FORMAT; 1520 } 1521 } else { 1522 struct scsi_descr_sense_hdr *ds = 1523 (struct scsi_descr_sense_hdr *)sense_buffer; 1524 1525 /* 1526 * For descriptor format we need at least the descriptor 1527 * header 1528 */ 1529 if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) { 1530 result = SENSE_UNUSABLE; 1531 } else { 1532 /* 1533 * Check for overflow 1534 */ 1535 if ((flags != NULL) && 1536 (sense_buf_len < 1537 (ds->ds_addl_sense_length + sizeof (*ds)))) { 1538 *flags |= SNS_BUF_OVERFLOW; 1539 } 1540 1541 result = SENSE_DESCR_FORMAT; 1542 } 1543 } 1544 1545 return (result); 1546 } 1547 1548 1549 uint8_t 1550 scsi_sense_key(uint8_t *sense_buffer) 1551 { 1552 uint8_t skey; 1553 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1554 struct scsi_descr_sense_hdr *sdsp = 1555 (struct scsi_descr_sense_hdr *)sense_buffer; 1556 skey = sdsp->ds_key; 1557 } else { 1558 struct scsi_extended_sense *ext_sensep = 1559 (struct scsi_extended_sense *)sense_buffer; 1560 skey = ext_sensep->es_key; 1561 } 1562 return (skey); 1563 } 1564 1565 uint8_t 1566 scsi_sense_asc(uint8_t *sense_buffer) 1567 { 1568 uint8_t asc; 1569 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1570 struct scsi_descr_sense_hdr *sdsp = 1571 (struct scsi_descr_sense_hdr *)sense_buffer; 1572 asc = sdsp->ds_add_code; 1573 } else { 1574 struct scsi_extended_sense *ext_sensep = 1575 (struct scsi_extended_sense *)sense_buffer; 1576 asc = ext_sensep->es_add_code; 1577 } 1578 return (asc); 1579 } 1580 1581 uint8_t 1582 scsi_sense_ascq(uint8_t *sense_buffer) 1583 { 1584 uint8_t ascq; 1585 if (SCSI_IS_DESCR_SENSE(sense_buffer)) { 1586 struct scsi_descr_sense_hdr *sdsp = 1587 (struct scsi_descr_sense_hdr *)sense_buffer; 1588 ascq = sdsp->ds_qual_code; 1589 } else { 1590 struct scsi_extended_sense *ext_sensep = 1591 (struct scsi_extended_sense *)sense_buffer; 1592 ascq = ext_sensep->es_qual_code; 1593 } 1594 return (ascq); 1595 } 1596 1597 void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len, 1598 uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code, 1599 uint8_t **sk_specific, uint8_t **stream_flags) 1600 { 1601 int sense_fmt; 1602 1603 /* 1604 * Sanity check sense data and determine the format 1605 */ 1606 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1607 1608 /* 1609 * Initialize any requested data to 0 1610 */ 1611 if (information) { 1612 *information = NULL; 1613 } 1614 if (cmd_spec_info) { 1615 *cmd_spec_info = NULL; 1616 } 1617 if (fru_code) { 1618 *fru_code = NULL; 1619 } 1620 if (sk_specific) { 1621 *sk_specific = NULL; 1622 } 1623 if (stream_flags) { 1624 *stream_flags = NULL; 1625 } 1626 1627 if (sense_fmt == SENSE_DESCR_FORMAT) { 1628 struct scsi_descr_template *sdt = NULL; 1629 1630 while (scsi_get_next_descr(sense_buffer, 1631 sense_buf_len, &sdt) != -1) { 1632 switch (sdt->sdt_descr_type) { 1633 case DESCR_INFORMATION: { 1634 struct scsi_information_sense_descr *isd = 1635 (struct scsi_information_sense_descr *) 1636 sdt; 1637 if (information) { 1638 *information = 1639 &isd->isd_information[0]; 1640 } 1641 break; 1642 } 1643 case DESCR_COMMAND_SPECIFIC: { 1644 struct scsi_cmd_specific_sense_descr *csd = 1645 (struct scsi_cmd_specific_sense_descr *) 1646 sdt; 1647 if (cmd_spec_info) { 1648 *cmd_spec_info = 1649 &csd->css_cmd_specific_info[0]; 1650 } 1651 break; 1652 } 1653 case DESCR_SENSE_KEY_SPECIFIC: { 1654 struct scsi_sk_specific_sense_descr *ssd = 1655 (struct scsi_sk_specific_sense_descr *) 1656 sdt; 1657 if (sk_specific) { 1658 *sk_specific = 1659 (uint8_t *)&ssd->sss_data; 1660 } 1661 break; 1662 } 1663 case DESCR_FRU: { 1664 struct scsi_fru_sense_descr *fsd = 1665 (struct scsi_fru_sense_descr *) 1666 sdt; 1667 if (fru_code) { 1668 *fru_code = &fsd->fs_fru_code; 1669 } 1670 break; 1671 } 1672 case DESCR_STREAM_COMMANDS: { 1673 struct scsi_stream_cmd_sense_descr *strsd = 1674 (struct scsi_stream_cmd_sense_descr *) 1675 sdt; 1676 if (stream_flags) { 1677 *stream_flags = 1678 (uint8_t *)&strsd->scs_data; 1679 } 1680 break; 1681 } 1682 case DESCR_BLOCK_COMMANDS: { 1683 struct scsi_block_cmd_sense_descr *bsd = 1684 (struct scsi_block_cmd_sense_descr *) 1685 sdt; 1686 /* 1687 * The "Block Command" sense descriptor 1688 * contains an ili bit that we can store 1689 * in the stream specific data if it is 1690 * available. We shouldn't see both 1691 * a block command and a stream command 1692 * descriptor in the same collection 1693 * of sense data. 1694 */ 1695 if (stream_flags) { 1696 /* 1697 * Can't take an address of a bitfield, 1698 * but the flags are just after the 1699 * bcs_reserved field. 1700 */ 1701 *stream_flags = 1702 (uint8_t *)&bsd->bcs_reserved + 1; 1703 } 1704 break; 1705 } 1706 } 1707 } 1708 } else { 1709 struct scsi_extended_sense *es = 1710 (struct scsi_extended_sense *)sense_buffer; 1711 1712 /* Get data from fixed sense buffer */ 1713 if (information && es->es_valid) { 1714 *information = &es->es_info_1; 1715 } 1716 if (cmd_spec_info && es->es_valid) { 1717 *cmd_spec_info = &es->es_cmd_info[0]; 1718 } 1719 if (fru_code) { 1720 *fru_code = &es->es_fru_code; 1721 } 1722 if (sk_specific) { 1723 *sk_specific = &es->es_skey_specific[0]; 1724 } 1725 if (stream_flags) { 1726 /* 1727 * Can't take the address of a bit field, 1728 * but the stream flags are located just after 1729 * the es_segnum field; 1730 */ 1731 *stream_flags = &es->es_segnum + 1; 1732 } 1733 } 1734 } 1735 1736 boolean_t 1737 scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len, 1738 uint64_t *information) 1739 { 1740 boolean_t valid; 1741 int sense_fmt; 1742 1743 ASSERT(sense_buffer != NULL); 1744 ASSERT(information != NULL); 1745 1746 /* Validate sense data and get format */ 1747 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1748 1749 if (sense_fmt == SENSE_UNUSABLE) { 1750 /* Information is not valid */ 1751 valid = 0; 1752 } else if (sense_fmt == SENSE_FIXED_FORMAT) { 1753 struct scsi_extended_sense *es = 1754 (struct scsi_extended_sense *)sense_buffer; 1755 1756 *information = (uint64_t)SCSI_READ32(&es->es_info_1); 1757 1758 valid = es->es_valid; 1759 } else { 1760 /* Sense data is descriptor format */ 1761 struct scsi_information_sense_descr *isd; 1762 1763 isd = (struct scsi_information_sense_descr *) 1764 scsi_find_sense_descr(sense_buffer, sense_buf_len, 1765 DESCR_INFORMATION); 1766 1767 if (isd) { 1768 *information = SCSI_READ64(isd->isd_information); 1769 valid = 1; 1770 } else { 1771 valid = 0; 1772 } 1773 } 1774 1775 return (valid); 1776 } 1777 1778 boolean_t 1779 scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len, 1780 uint64_t *cmd_specific_info) 1781 { 1782 boolean_t valid; 1783 int sense_fmt; 1784 1785 ASSERT(sense_buffer != NULL); 1786 ASSERT(cmd_specific_info != NULL); 1787 1788 /* Validate sense data and get format */ 1789 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL); 1790 1791 if (sense_fmt == SENSE_UNUSABLE) { 1792 /* Command specific info is not valid */ 1793 valid = 0; 1794 } else if (sense_fmt == SENSE_FIXED_FORMAT) { 1795 struct scsi_extended_sense *es = 1796 (struct scsi_extended_sense *)sense_buffer; 1797 1798 *cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info); 1799 1800 valid = es->es_valid; 1801 } else { 1802 /* Sense data is descriptor format */ 1803 struct scsi_cmd_specific_sense_descr *c; 1804 1805 c = (struct scsi_cmd_specific_sense_descr *) 1806 scsi_find_sense_descr(sense_buffer, sense_buf_len, 1807 DESCR_COMMAND_SPECIFIC); 1808 1809 if (c) { 1810 valid = 1; 1811 *cmd_specific_info = 1812 SCSI_READ64(c->css_cmd_specific_info); 1813 } else { 1814 valid = 0; 1815 } 1816 } 1817 1818 return (valid); 1819 } 1820 1821 uint8_t * 1822 scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type) 1823 { 1824 struct scsi_descr_template *sdt = NULL; 1825 1826 while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) { 1827 ASSERT(sdt != NULL); 1828 if (sdt->sdt_descr_type == req_descr_type) { 1829 /* Found requested descriptor type */ 1830 break; 1831 } 1832 } 1833 1834 return ((uint8_t *)sdt); 1835 } 1836 1837 /* 1838 * Sense Descriptor format is: 1839 * 1840 * <Descriptor type> <Descriptor length> <Descriptor data> ... 1841 * 1842 * 2 must be added to the descriptor length value to get the 1843 * total descriptor length sense the stored length does not 1844 * include the "type" and "additional length" fields. 1845 */ 1846 1847 #define NEXT_DESCR_PTR(ndp_descr) \ 1848 ((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \ 1849 ((ndp_descr)->sdt_addl_length + \ 1850 sizeof (struct scsi_descr_template)))) 1851 1852 static int 1853 scsi_get_next_descr(uint8_t *sense_buffer, 1854 int sense_buf_len, struct scsi_descr_template **descrpp) 1855 { 1856 struct scsi_descr_sense_hdr *sdsp = 1857 (struct scsi_descr_sense_hdr *)sense_buffer; 1858 struct scsi_descr_template *cur_descr; 1859 boolean_t find_first; 1860 int valid_sense_length; 1861 1862 ASSERT(descrpp != NULL); 1863 find_first = (*descrpp == NULL); 1864 1865 /* 1866 * If no descriptor is passed in then return the first 1867 * descriptor 1868 */ 1869 if (find_first) { 1870 /* 1871 * The first descriptor will immediately follow the header 1872 * (Pointer arithmetic) 1873 */ 1874 cur_descr = (struct scsi_descr_template *)(sdsp+1); 1875 } else { 1876 cur_descr = *descrpp; 1877 ASSERT(cur_descr > (struct scsi_descr_template *)sdsp); 1878 } 1879 1880 /* Assume no more descriptors are available */ 1881 *descrpp = NULL; 1882 1883 /* 1884 * Calculate the amount of valid sense data -- make sure the length 1885 * byte in this descriptor lies within the valid sense data. 1886 */ 1887 valid_sense_length = 1888 min((sizeof (struct scsi_descr_sense_hdr) + 1889 sdsp->ds_addl_sense_length), 1890 sense_buf_len); 1891 1892 /* 1893 * Make sure this descriptor is complete (either the first 1894 * descriptor or the descriptor passed in) 1895 */ 1896 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) != 1897 DESCR_GOOD) { 1898 return (-1); 1899 } 1900 1901 /* 1902 * If we were looking for the first descriptor go ahead and return it 1903 */ 1904 if (find_first) { 1905 *descrpp = cur_descr; 1906 return ((*descrpp)->sdt_descr_type); 1907 } 1908 1909 /* 1910 * Get pointer to next descriptor 1911 */ 1912 cur_descr = NEXT_DESCR_PTR(cur_descr); 1913 1914 /* 1915 * Make sure this descriptor is also complete. 1916 */ 1917 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) != 1918 DESCR_GOOD) { 1919 return (-1); 1920 } 1921 1922 *descrpp = (struct scsi_descr_template *)cur_descr; 1923 return ((*descrpp)->sdt_descr_type); 1924 } 1925 1926 static int 1927 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp, 1928 int valid_sense_length, struct scsi_descr_template *descrp) 1929 { 1930 int descr_offset, next_descr_offset; 1931 1932 /* 1933 * Make sure length is present 1934 */ 1935 descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp; 1936 if (descr_offset + sizeof (struct scsi_descr_template) > 1937 valid_sense_length) { 1938 return (DESCR_PARTIAL); 1939 } 1940 1941 /* 1942 * Check if length is 0 (no more descriptors) 1943 */ 1944 if (descrp->sdt_addl_length == 0) { 1945 return (DESCR_END); 1946 } 1947 1948 /* 1949 * Make sure the rest of the descriptor is present 1950 */ 1951 next_descr_offset = 1952 (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp; 1953 if (next_descr_offset > valid_sense_length) { 1954 return (DESCR_PARTIAL); 1955 } 1956 1957 return (DESCR_GOOD); 1958 } 1959 1960 /* 1961 * Internal data structure for handling uscsi command. 1962 */ 1963 typedef struct uscsi_i_cmd { 1964 struct uscsi_cmd uic_cmd; 1965 caddr_t uic_rqbuf; 1966 uchar_t uic_rqlen; 1967 caddr_t uic_cdb; 1968 int uic_flag; 1969 struct scsi_address *uic_ap; 1970 } uscsi_i_cmd_t; 1971 1972 #if !defined(lint) 1973 _NOTE(SCHEME_PROTECTS_DATA("unshared data", uscsi_i_cmd)) 1974 #endif 1975 1976 /*ARGSUSED*/ 1977 static void 1978 scsi_uscsi_mincnt(struct buf *bp) 1979 { 1980 /* 1981 * Do not break up because the CDB count would then be 1982 * incorrect and create spurious data underrun errors. 1983 */ 1984 } 1985 1986 /* 1987 * Function: scsi_uscsi_alloc_and_copyin 1988 * 1989 * Description: Target drivers call this function to allocate memeory, 1990 * copy in, and convert ILP32/LP64 to make preparations for handling 1991 * uscsi commands. 1992 * 1993 * Arguments: 1994 * arg - pointer to the caller's uscsi command struct 1995 * flag - mode, corresponds to ioctl(9e) 'mode' 1996 * ap - SCSI address structure 1997 * uscmdp - pointer to the converted uscsi command 1998 * 1999 * Return code: 0 2000 * EFAULT 2001 * EINVAL 2002 * 2003 * Context: Never called at interrupt context. 2004 */ 2005 2006 int 2007 scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap, 2008 struct uscsi_cmd **uscmdp) 2009 { 2010 int rval = 0; 2011 struct uscsi_cmd *uscmd; 2012 2013 /* 2014 * In order to not worry about where the uscsi structure came 2015 * from (or where the cdb it points to came from) we're going 2016 * to make kmem_alloc'd copies of them here. This will also 2017 * allow reference to the data they contain long after this 2018 * process has gone to sleep and its kernel stack has been 2019 * unmapped, etc. First get some memory for the uscsi_cmd 2020 * struct and copy the contents of the given uscsi_cmd struct 2021 * into it. We also save infos of the uscsi command by using 2022 * uicmd to supply referrence for the copyout operation. 2023 */ 2024 uscmd = scsi_uscsi_alloc(); 2025 2026 if ((rval = scsi_uscsi_copyin(arg, flag, ap, &uscmd)) != 0) { 2027 scsi_uscsi_free(uscmd); 2028 *uscmdp = NULL; 2029 rval = EFAULT; 2030 } else { 2031 *uscmdp = uscmd; 2032 } 2033 2034 return (rval); 2035 } 2036 2037 struct uscsi_cmd * 2038 scsi_uscsi_alloc() 2039 { 2040 struct uscsi_i_cmd *uicmd; 2041 2042 uicmd = (struct uscsi_i_cmd *) 2043 kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP); 2044 2045 /* 2046 * It is supposed that the uscsi_cmd has been alloced correctly, 2047 * we need to check is it NULL or mis-created. 2048 */ 2049 ASSERT(uicmd && (offsetof(struct uscsi_i_cmd, uic_cmd) == 0)); 2050 2051 return (&uicmd->uic_cmd); 2052 } 2053 2054 int 2055 scsi_uscsi_copyin(intptr_t arg, int flag, struct scsi_address *ap, 2056 struct uscsi_cmd **uscmdp) 2057 { 2058 #ifdef _MULTI_DATAMODEL 2059 /* 2060 * For use when a 32 bit app makes a call into a 2061 * 64 bit ioctl 2062 */ 2063 struct uscsi_cmd32 uscsi_cmd_32_for_64; 2064 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64; 2065 #endif /* _MULTI_DATAMODEL */ 2066 struct uscsi_cmd *uscmd = *uscmdp; 2067 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)(uscmd); 2068 int max_hba_cdb; 2069 int rval; 2070 extern dev_info_t *scsi_vhci_dip; 2071 2072 ASSERT(uscmd != NULL); 2073 ASSERT(uicmd != NULL); 2074 2075 /* 2076 * To be able to issue multiple commands off a single uscmdp 2077 * We need to free the original cdb, rqbuf and bzero the uscmdp 2078 * if the cdb, rqbuf and uscmdp is not NULL 2079 */ 2080 if (uscmd->uscsi_rqbuf != NULL) 2081 kmem_free(uscmd->uscsi_rqbuf, uscmd->uscsi_rqlen); 2082 if (uscmd->uscsi_cdb != NULL) 2083 kmem_free(uscmd->uscsi_cdb, uscmd->uscsi_cdblen); 2084 bzero(uscmd, sizeof (struct uscsi_cmd)); 2085 2086 2087 #ifdef _MULTI_DATAMODEL 2088 switch (ddi_model_convert_from(flag & FMODELS)) { 2089 case DDI_MODEL_ILP32: 2090 if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) { 2091 rval = EFAULT; 2092 goto scsi_uscsi_copyin_failed; 2093 } 2094 /* 2095 * Convert the ILP32 uscsi data from the 2096 * application to LP64 for internal use. 2097 */ 2098 uscsi_cmd32touscsi_cmd(ucmd32, uscmd); 2099 break; 2100 case DDI_MODEL_NONE: 2101 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) { 2102 rval = EFAULT; 2103 goto scsi_uscsi_copyin_failed; 2104 } 2105 break; 2106 default: 2107 rval = EFAULT; 2108 goto scsi_uscsi_copyin_failed; 2109 } 2110 #else /* ! _MULTI_DATAMODEL */ 2111 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) { 2112 rval = EFAULT; 2113 goto scsi_uscsi_copyin_failed; 2114 } 2115 #endif /* _MULTI_DATAMODEL */ 2116 2117 /* 2118 * We are going to allocate kernel virtual addresses for 2119 * uscsi_rqbuf and uscsi_cdb pointers, so save off the 2120 * original, possibly user virtual, uscsi_addresses 2121 * in uic_fields 2122 */ 2123 uicmd->uic_rqbuf = uscmd->uscsi_rqbuf; 2124 uicmd->uic_rqlen = uscmd->uscsi_rqlen; 2125 uicmd->uic_cdb = uscmd->uscsi_cdb; 2126 uicmd->uic_flag = flag; 2127 uicmd->uic_ap = ap; 2128 2129 /* 2130 * Skip the following steps if we meet RESET commands. 2131 */ 2132 if (uscmd->uscsi_flags & 2133 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) { 2134 uscmd->uscsi_rqbuf = NULL; 2135 uscmd->uscsi_cdb = NULL; 2136 return (0); 2137 } 2138 2139 /* 2140 * Currently, USCSI_PATH_INSTANCE is only valid when directed 2141 * to scsi_vhci. 2142 */ 2143 if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) && 2144 (A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) { 2145 rval = EFAULT; 2146 goto scsi_uscsi_copyin_failed; 2147 } 2148 2149 /* 2150 * Perfunctory sanity checks. Get the maximum hba supported 2151 * cdb length first. 2152 */ 2153 max_hba_cdb = scsi_ifgetcap(ap, "max-cdb-length", 1); 2154 if (max_hba_cdb < CDB_GROUP0) { 2155 max_hba_cdb = CDB_GROUP4; 2156 } 2157 if (uscmd->uscsi_cdblen < CDB_GROUP0 || 2158 uscmd->uscsi_cdblen > max_hba_cdb) { 2159 rval = EINVAL; 2160 goto scsi_uscsi_copyin_failed; 2161 } 2162 if ((uscmd->uscsi_flags & USCSI_RQENABLE) && 2163 (uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) { 2164 rval = EINVAL; 2165 goto scsi_uscsi_copyin_failed; 2166 } 2167 2168 /* 2169 * To extend uscsi_cmd in the future, we need to ensure current 2170 * reserved bits remain unused (zero). 2171 */ 2172 if (uscmd->uscsi_flags & USCSI_RESERVED) { 2173 rval = EINVAL; 2174 goto scsi_uscsi_copyin_failed; 2175 } 2176 2177 /* 2178 * Now we get some space for the CDB, and copy the given CDB into 2179 * it. Use ddi_copyin() in case the data is in user space. 2180 */ 2181 uscmd->uscsi_cdb = kmem_zalloc((size_t)uscmd->uscsi_cdblen, KM_SLEEP); 2182 if (ddi_copyin(uicmd->uic_cdb, uscmd->uscsi_cdb, 2183 (uint_t)uscmd->uscsi_cdblen, flag) != 0) { 2184 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen); 2185 rval = EFAULT; 2186 goto scsi_uscsi_copyin_failed; 2187 } 2188 2189 if (uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) { 2190 if (uscmd->uscsi_cdblen > SCSI_CDB_SIZE || 2191 scsi_cdb_size[CDB_GROUPID(uscmd->uscsi_cdb[0])] > 2192 uscmd->uscsi_cdblen) { 2193 kmem_free(uscmd->uscsi_cdb, 2194 (size_t)uscmd->uscsi_cdblen); 2195 rval = EINVAL; 2196 goto scsi_uscsi_copyin_failed; 2197 } 2198 } else { 2199 if ((uscmd->uscsi_cdblen % 4) != 0) { 2200 kmem_free(uscmd->uscsi_cdb, 2201 (size_t)uscmd->uscsi_cdblen); 2202 rval = EINVAL; 2203 goto scsi_uscsi_copyin_failed; 2204 } 2205 } 2206 2207 /* 2208 * Initialize Request Sense buffering, if requested. 2209 */ 2210 if (uscmd->uscsi_flags & USCSI_RQENABLE) { 2211 /* 2212 * Here uscmd->uscsi_rqbuf currently points to the caller's 2213 * buffer, but we replace this with a kernel buffer that 2214 * we allocate to use with the sense data. The sense data 2215 * (if present) gets copied into this new buffer before the 2216 * command is completed. Then we copy the sense data from 2217 * our allocated buf into the caller's buffer below. Note 2218 * that uscmd->uscsi_rqbuf and uscmd->uscsi_rqlen are used 2219 * below to perform the copy back to the caller's buf. 2220 */ 2221 if (uicmd->uic_rqlen <= SENSE_LENGTH) { 2222 uscmd->uscsi_rqlen = SENSE_LENGTH; 2223 uscmd->uscsi_rqbuf = kmem_zalloc(SENSE_LENGTH, 2224 KM_SLEEP); 2225 } else { 2226 uscmd->uscsi_rqlen = MAX_SENSE_LENGTH; 2227 uscmd->uscsi_rqbuf = kmem_zalloc(MAX_SENSE_LENGTH, 2228 KM_SLEEP); 2229 } 2230 uscmd->uscsi_rqresid = uscmd->uscsi_rqlen; 2231 } else { 2232 uscmd->uscsi_rqbuf = NULL; 2233 uscmd->uscsi_rqlen = 0; 2234 uscmd->uscsi_rqresid = 0; 2235 } 2236 return (0); 2237 2238 scsi_uscsi_copyin_failed: 2239 /* 2240 * The uscsi_rqbuf and uscsi_cdb is refering to user-land 2241 * address now, no need to free them. 2242 */ 2243 uscmd->uscsi_rqbuf = NULL; 2244 uscmd->uscsi_cdb = NULL; 2245 2246 return (rval); 2247 } 2248 2249 /* 2250 * Function: scsi_uscsi_handle_cmd 2251 * 2252 * Description: Target drivers call this function to handle uscsi commands. 2253 * 2254 * Arguments: 2255 * dev - device number 2256 * dataspace - UIO_USERSPACE or UIO_SYSSPACE 2257 * uscmd - pointer to the converted uscsi command 2258 * strat - pointer to the driver's strategy routine 2259 * bp - buf struct ptr 2260 * private_data - pointer to bp->b_private 2261 * 2262 * Return code: 0 2263 * EIO - scsi_reset() failed, or see biowait()/physio() codes. 2264 * EINVAL 2265 * return code of biowait(9F) or physio(9F): 2266 * EIO - IO error 2267 * ENXIO 2268 * EACCES - reservation conflict 2269 * 2270 * Context: Never called at interrupt context. 2271 */ 2272 2273 int 2274 scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace, 2275 struct uscsi_cmd *uscmd, int (*strat)(struct buf *), 2276 struct buf *bp, void *private_data) 2277 { 2278 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd; 2279 int bp_alloc_flag = 0; 2280 int rval; 2281 2282 /* 2283 * Perform resets directly; no need to generate a command to do it. 2284 */ 2285 if (uscmd->uscsi_flags & 2286 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) { 2287 int flags = (uscmd->uscsi_flags & USCSI_RESET_ALL) ? 2288 RESET_ALL : ((uscmd->uscsi_flags & USCSI_RESET_TARGET) ? 2289 RESET_TARGET : RESET_LUN); 2290 if (scsi_reset(uicmd->uic_ap, flags) == 0) { 2291 /* Reset attempt was unsuccessful */ 2292 return (EIO); 2293 } 2294 return (0); 2295 } 2296 2297 /* 2298 * Force asynchronous mode, if necessary. Doing this here 2299 * has the unfortunate effect of running other queued 2300 * commands async also, but since the main purpose of this 2301 * capability is downloading new drive firmware, we can 2302 * probably live with it. 2303 */ 2304 if (uscmd->uscsi_flags & USCSI_ASYNC) { 2305 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 1) { 2306 if (scsi_ifsetcap(uicmd->uic_ap, "synchronous", 2307 0, 1) != 1) { 2308 return (EINVAL); 2309 } 2310 } 2311 } 2312 2313 /* 2314 * Re-enable synchronous mode, if requested. 2315 */ 2316 if (uscmd->uscsi_flags & USCSI_SYNC) { 2317 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 0) { 2318 rval = scsi_ifsetcap(uicmd->uic_ap, "synchronous", 2319 1, 1); 2320 } 2321 } 2322 2323 /* 2324 * If bp is NULL, allocate space here. 2325 */ 2326 if (bp == NULL) { 2327 bp = getrbuf(KM_SLEEP); 2328 bp->b_private = private_data; 2329 bp_alloc_flag = 1; 2330 } 2331 2332 /* 2333 * If we're going to do actual I/O, let physio do all the right things. 2334 */ 2335 if (uscmd->uscsi_buflen != 0) { 2336 struct iovec aiov; 2337 struct uio auio; 2338 struct uio *uio = &auio; 2339 2340 bzero(&auio, sizeof (struct uio)); 2341 bzero(&aiov, sizeof (struct iovec)); 2342 aiov.iov_base = uscmd->uscsi_bufaddr; 2343 aiov.iov_len = uscmd->uscsi_buflen; 2344 uio->uio_iov = &aiov; 2345 2346 uio->uio_iovcnt = 1; 2347 uio->uio_resid = uscmd->uscsi_buflen; 2348 uio->uio_segflg = dataspace; 2349 2350 /* 2351 * physio() will block here until the command completes.... 2352 */ 2353 rval = physio(strat, bp, dev, 2354 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE), 2355 scsi_uscsi_mincnt, uio); 2356 } else { 2357 /* 2358 * We have to mimic that physio would do here! Argh! 2359 */ 2360 bp->b_flags = B_BUSY | 2361 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE); 2362 bp->b_edev = dev; 2363 bp->b_dev = cmpdev(dev); /* maybe unnecessary? */ 2364 bp->b_bcount = 0; 2365 bp->b_blkno = 0; 2366 bp->b_resid = 0; 2367 2368 (void) (*strat)(bp); 2369 rval = biowait(bp); 2370 } 2371 uscmd->uscsi_resid = bp->b_resid; 2372 2373 if (bp_alloc_flag == 1) { 2374 bp_mapout(bp); 2375 freerbuf(bp); 2376 } 2377 2378 return (rval); 2379 } 2380 2381 /* 2382 * Function: scsi_uscsi_pktinit 2383 * 2384 * Description: Target drivers call this function to transfer uscsi_cmd 2385 * information into a scsi_pkt before sending the scsi_pkt. 2386 * 2387 * NB: At this point the implementation is limited to path_instance. 2388 * At some point more code could be removed from the target driver by 2389 * enhancing this function - with the added benifit of making the uscsi 2390 * implementation more consistent accross all drivers. 2391 * 2392 * Arguments: 2393 * uscmd - pointer to the uscsi command 2394 * pkt - pointer to the scsi_pkt 2395 * 2396 * Return code: 1 on successfull transfer, 0 on failure. 2397 */ 2398 int 2399 scsi_uscsi_pktinit(struct uscsi_cmd *uscmd, struct scsi_pkt *pkt) 2400 { 2401 2402 /* 2403 * See if path_instance was requested in uscsi_cmd. 2404 */ 2405 if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) && 2406 (uscmd->uscsi_path_instance != 0)) { 2407 /* 2408 * Check to make sure the scsi_pkt was allocated correctly 2409 * before transferring uscsi(7i) path_instance to scsi_pkt(9S). 2410 */ 2411 if (scsi_pkt_allocated_correctly(pkt)) { 2412 /* set pkt_path_instance and flag. */ 2413 pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE; 2414 pkt->pkt_path_instance = uscmd->uscsi_path_instance; 2415 } else { 2416 return (0); /* failure */ 2417 } 2418 } else { 2419 /* 2420 * Can only use pkt_path_instance if the packet 2421 * was correctly allocated. 2422 */ 2423 if (scsi_pkt_allocated_correctly(pkt)) { 2424 pkt->pkt_path_instance = 0; 2425 } 2426 pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE; 2427 } 2428 2429 return (1); /* success */ 2430 } 2431 2432 /* 2433 * Function: scsi_uscsi_pktfini 2434 * 2435 * Description: Target drivers call this function to transfer completed 2436 * scsi_pkt information back into uscsi_cmd. 2437 * 2438 * NB: At this point the implementation is limited to path_instance. 2439 * At some point more code could be removed from the target driver by 2440 * enhancing this function - with the added benifit of making the uscsi 2441 * implementation more consistent accross all drivers. 2442 * 2443 * Arguments: 2444 * pkt - pointer to the scsi_pkt 2445 * uscmd - pointer to the uscsi command 2446 * 2447 * Return code: 1 on successfull transfer, 0 on failure. 2448 */ 2449 int 2450 scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd) 2451 { 2452 /* 2453 * Check to make sure the scsi_pkt was allocated correctly before 2454 * transferring scsi_pkt(9S) path_instance to uscsi(7i). 2455 */ 2456 if (!scsi_pkt_allocated_correctly(pkt)) { 2457 uscmd->uscsi_path_instance = 0; 2458 return (0); /* failure */ 2459 } 2460 2461 uscmd->uscsi_path_instance = pkt->pkt_path_instance; 2462 /* reset path_instance */ 2463 pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE; 2464 pkt->pkt_path_instance = 0; 2465 return (1); /* success */ 2466 } 2467 2468 /* 2469 * Function: scsi_uscsi_copyout_and_free 2470 * 2471 * Description: Target drivers call this function to undo what was done by 2472 * scsi_uscsi_alloc_and_copyin. 2473 * 2474 * Arguments: arg - pointer to the uscsi command to be returned 2475 * uscmd - pointer to the converted uscsi command 2476 * 2477 * Return code: 0 2478 * EFAULT 2479 * 2480 * Context: Never called at interrupt context. 2481 */ 2482 int 2483 scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd) 2484 { 2485 int rval = 0; 2486 2487 rval = scsi_uscsi_copyout(arg, uscmd); 2488 2489 scsi_uscsi_free(uscmd); 2490 2491 return (rval); 2492 } 2493 2494 int 2495 scsi_uscsi_copyout(intptr_t arg, struct uscsi_cmd *uscmd) 2496 { 2497 #ifdef _MULTI_DATAMODEL 2498 /* 2499 * For use when a 32 bit app makes a call into a 2500 * 64 bit ioctl. 2501 */ 2502 struct uscsi_cmd32 uscsi_cmd_32_for_64; 2503 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64; 2504 #endif /* _MULTI_DATAMODEL */ 2505 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd; 2506 caddr_t k_rqbuf; 2507 int k_rqlen; 2508 caddr_t k_cdb; 2509 int rval = 0; 2510 2511 /* 2512 * If the caller wants sense data, copy back whatever sense data 2513 * we may have gotten, and update the relevant rqsense info. 2514 */ 2515 if ((uscmd->uscsi_flags & USCSI_RQENABLE) && 2516 (uscmd->uscsi_rqbuf != NULL)) { 2517 int rqlen = uscmd->uscsi_rqlen - uscmd->uscsi_rqresid; 2518 rqlen = min(((int)uicmd->uic_rqlen), rqlen); 2519 uscmd->uscsi_rqresid = uicmd->uic_rqlen - rqlen; 2520 /* 2521 * Copy out the sense data for user process. 2522 */ 2523 if ((uicmd->uic_rqbuf != NULL) && (rqlen != 0)) { 2524 if (ddi_copyout(uscmd->uscsi_rqbuf, 2525 uicmd->uic_rqbuf, rqlen, uicmd->uic_flag) != 0) { 2526 rval = EFAULT; 2527 } 2528 } 2529 } 2530 2531 /* 2532 * Restore original uscsi_values, saved in uic_fields for 2533 * copyout (so caller does not experience a change in these 2534 * fields) 2535 */ 2536 k_rqbuf = uscmd->uscsi_rqbuf; 2537 k_rqlen = uscmd->uscsi_rqlen; 2538 k_cdb = uscmd->uscsi_cdb; 2539 uscmd->uscsi_rqbuf = uicmd->uic_rqbuf; 2540 uscmd->uscsi_rqlen = uicmd->uic_rqlen; 2541 uscmd->uscsi_cdb = uicmd->uic_cdb; 2542 2543 #ifdef _MULTI_DATAMODEL 2544 switch (ddi_model_convert_from(uicmd->uic_flag & FMODELS)) { 2545 case DDI_MODEL_ILP32: 2546 /* 2547 * Convert back to ILP32 before copyout to the 2548 * application 2549 */ 2550 uscsi_cmdtouscsi_cmd32(uscmd, ucmd32); 2551 if (ddi_copyout(ucmd32, (void *)arg, sizeof (*ucmd32), 2552 uicmd->uic_flag)) { 2553 rval = EFAULT; 2554 } 2555 break; 2556 case DDI_MODEL_NONE: 2557 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), 2558 uicmd->uic_flag)) { 2559 rval = EFAULT; 2560 } 2561 break; 2562 default: 2563 rval = EFAULT; 2564 } 2565 #else /* _MULTI_DATAMODE */ 2566 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) { 2567 rval = EFAULT; 2568 } 2569 #endif /* _MULTI_DATAMODE */ 2570 2571 /* 2572 * Copyout done, restore kernel virtual addresses for further 2573 * scsi_uscsi_free(). 2574 */ 2575 uscmd->uscsi_rqbuf = k_rqbuf; 2576 uscmd->uscsi_rqlen = k_rqlen; 2577 uscmd->uscsi_cdb = k_cdb; 2578 2579 return (rval); 2580 } 2581 2582 void 2583 scsi_uscsi_free(struct uscsi_cmd *uscmd) 2584 { 2585 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd; 2586 2587 ASSERT(uicmd != NULL); 2588 2589 if ((uscmd->uscsi_rqbuf != NULL) && (uscmd->uscsi_rqlen != 0)) { 2590 kmem_free(uscmd->uscsi_rqbuf, (size_t)uscmd->uscsi_rqlen); 2591 uscmd->uscsi_rqbuf = NULL; 2592 } 2593 2594 if ((uscmd->uscsi_cdb != NULL) && (uscmd->uscsi_cdblen != 0)) { 2595 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen); 2596 uscmd->uscsi_cdb = NULL; 2597 } 2598 2599 kmem_free(uicmd, sizeof (struct uscsi_i_cmd)); 2600 } 2601