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