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