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