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