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