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 }