10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51106Smrj * Common Development and Distribution License (the "License").
61106Smrj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*12045SLi.He@Sun.COM
220Sstevel@tonic-gate /*
23*12045SLi.He@Sun.COM * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/scsi/scsi.h>
273368Slh195018 #include <sys/file.h>
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Utility SCSI routines
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate * Polling support routines
350Sstevel@tonic-gate */
360Sstevel@tonic-gate
37*12045SLi.He@Sun.COM int scsi_pkt_allow_naca = 0;
380Sstevel@tonic-gate extern uintptr_t scsi_callback_id;
390Sstevel@tonic-gate
407001Slh195018 extern uchar_t scsi_cdb_size[];
417001Slh195018
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate * Common buffer for scsi_log
440Sstevel@tonic-gate */
450Sstevel@tonic-gate
460Sstevel@tonic-gate extern kmutex_t scsi_log_mutex;
470Sstevel@tonic-gate static char scsi_log_buffer[MAXPATHLEN + 1];
480Sstevel@tonic-gate
490Sstevel@tonic-gate
500Sstevel@tonic-gate #define A_TO_TRAN(ap) (ap->a_hba_tran)
510Sstevel@tonic-gate #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran)
520Sstevel@tonic-gate #define P_TO_ADDR(pkt) (&((pkt)->pkt_address))
530Sstevel@tonic-gate
540Sstevel@tonic-gate #define CSEC 10000 /* usecs */
550Sstevel@tonic-gate #define SEC_TO_CSEC (1000000/CSEC)
560Sstevel@tonic-gate
571106Smrj extern ddi_dma_attr_t scsi_alloc_attr;
580Sstevel@tonic-gate
590Sstevel@tonic-gate /*PRINTFLIKE4*/
600Sstevel@tonic-gate static void impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
610Sstevel@tonic-gate const char *fmt, ...) __KPRINTFLIKE(4);
620Sstevel@tonic-gate /*PRINTFLIKE4*/
630Sstevel@tonic-gate static void v_scsi_log(dev_info_t *dev, char *label, uint_t level,
640Sstevel@tonic-gate const char *fmt, va_list ap) __KVPRINTFLIKE(4);
650Sstevel@tonic-gate
662148Spd144616 static int
672148Spd144616 scsi_get_next_descr(uint8_t *sdsp,
682148Spd144616 int sense_buf_len, struct scsi_descr_template **descrpp);
692148Spd144616
702148Spd144616 #define DESCR_GOOD 0
712148Spd144616 #define DESCR_PARTIAL 1
722148Spd144616 #define DESCR_END 2
732148Spd144616
742148Spd144616 static int
752148Spd144616 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
762148Spd144616 int valid_sense_length, struct scsi_descr_template *descrp);
772148Spd144616
780Sstevel@tonic-gate int
scsi_poll(struct scsi_pkt * pkt)790Sstevel@tonic-gate scsi_poll(struct scsi_pkt *pkt)
800Sstevel@tonic-gate {
816142Scth int rval = -1;
826142Scth int savef;
836142Scth long savet;
846142Scth void (*savec)();
856142Scth int timeout;
866142Scth int busy_count;
876142Scth int poll_delay;
886142Scth int rc;
896142Scth uint8_t *sensep;
906142Scth struct scsi_arq_status *arqstat;
916142Scth extern int do_polled_io;
926142Scth
936142Scth ASSERT(pkt->pkt_scbp);
940Sstevel@tonic-gate
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * save old flags..
970Sstevel@tonic-gate */
980Sstevel@tonic-gate savef = pkt->pkt_flags;
990Sstevel@tonic-gate savec = pkt->pkt_comp;
1000Sstevel@tonic-gate savet = pkt->pkt_time;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate pkt->pkt_flags |= FLAG_NOINTR;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate * XXX there is nothing in the SCSA spec that states that we should not
1060Sstevel@tonic-gate * do a callback for polled cmds; however, removing this will break sd
1070Sstevel@tonic-gate * and probably other target drivers
1080Sstevel@tonic-gate */
1096142Scth pkt->pkt_comp = NULL;
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate * we don't like a polled command without timeout.
1130Sstevel@tonic-gate * 60 seconds seems long enough.
1140Sstevel@tonic-gate */
1150Sstevel@tonic-gate if (pkt->pkt_time == 0)
1160Sstevel@tonic-gate pkt->pkt_time = SCSI_POLL_TIMEOUT;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate * Send polled cmd.
1200Sstevel@tonic-gate *
1210Sstevel@tonic-gate * We do some error recovery for various errors. Tran_busy,
1220Sstevel@tonic-gate * queue full, and non-dispatched commands are retried every 10 msec.
1236142Scth * as they are typically transient failures. Busy status and Not
1246142Scth * Ready are retried every second as this status takes a while to
1256142Scth * change.
1260Sstevel@tonic-gate */
1276142Scth timeout = pkt->pkt_time * SEC_TO_CSEC;
1280Sstevel@tonic-gate
1296142Scth for (busy_count = 0; busy_count < timeout; busy_count++) {
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate * Initialize pkt status variables.
1320Sstevel@tonic-gate */
1330Sstevel@tonic-gate *pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate if ((rc = scsi_transport(pkt)) != TRAN_ACCEPT) {
1360Sstevel@tonic-gate if (rc != TRAN_BUSY) {
1370Sstevel@tonic-gate /* Transport failed - give up. */
1380Sstevel@tonic-gate break;
1390Sstevel@tonic-gate } else {
1400Sstevel@tonic-gate /* Transport busy - try again. */
1416142Scth poll_delay = 1 * CSEC; /* 10 msec. */
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate } else {
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate * Transport accepted - check pkt status.
1460Sstevel@tonic-gate */
1470Sstevel@tonic-gate rc = (*pkt->pkt_scbp) & STATUS_MASK;
1486142Scth if ((pkt->pkt_reason == CMD_CMPLT) &&
1496142Scth (rc == STATUS_CHECK) &&
1506142Scth (pkt->pkt_state & STATE_ARQ_DONE)) {
1516142Scth arqstat =
1526142Scth (struct scsi_arq_status *)(pkt->pkt_scbp);
1536142Scth sensep = (uint8_t *)&arqstat->sts_sensedata;
1546142Scth } else {
1556142Scth sensep = NULL;
1566142Scth }
1570Sstevel@tonic-gate
1586142Scth if ((pkt->pkt_reason == CMD_CMPLT) &&
1596142Scth (rc == STATUS_GOOD)) {
1600Sstevel@tonic-gate /* No error - we're done */
1610Sstevel@tonic-gate rval = 0;
1620Sstevel@tonic-gate break;
1630Sstevel@tonic-gate
1646142Scth } else if (pkt->pkt_reason == CMD_DEV_GONE) {
1656142Scth /* Lost connection - give up */
1666142Scth break;
1676142Scth
1686142Scth } else if ((pkt->pkt_reason == CMD_INCOMPLETE) &&
1696142Scth (pkt->pkt_state == 0)) {
1700Sstevel@tonic-gate /* Pkt not dispatched - try again. */
1716142Scth poll_delay = 1 * CSEC; /* 10 msec. */
1726142Scth
1736142Scth } else if ((pkt->pkt_reason == CMD_CMPLT) &&
1746142Scth (rc == STATUS_QFULL)) {
1756142Scth /* Queue full - try again. */
1766142Scth poll_delay = 1 * CSEC; /* 10 msec. */
1770Sstevel@tonic-gate
1786142Scth } else if ((pkt->pkt_reason == CMD_CMPLT) &&
1796142Scth (rc == STATUS_BUSY)) {
1806142Scth /* Busy - try again. */
1816142Scth poll_delay = 100 * CSEC; /* 1 sec. */
1826142Scth busy_count += (SEC_TO_CSEC - 1);
1830Sstevel@tonic-gate
1846142Scth } else if ((sensep != NULL) &&
1856142Scth (scsi_sense_key(sensep) == KEY_NOT_READY) &&
1866142Scth (scsi_sense_asc(sensep) == 0x04) &&
1876142Scth (scsi_sense_ascq(sensep) == 0x01)) {
1886142Scth /*
1896142Scth * Not ready -> ready - try again.
1906142Scth * 04h/01h: LUN IS IN PROCESS OF BECOMING READY
1916142Scth * ...same as STATUS_BUSY
1926142Scth */
1936142Scth poll_delay = 100 * CSEC; /* 1 sec. */
1940Sstevel@tonic-gate busy_count += (SEC_TO_CSEC - 1);
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate } else {
1970Sstevel@tonic-gate /* BAD status - give up. */
1980Sstevel@tonic-gate break;
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2026142Scth if (((curthread->t_flag & T_INTR_THREAD) == 0) &&
2030Sstevel@tonic-gate !do_polled_io) {
2040Sstevel@tonic-gate delay(drv_usectohz(poll_delay));
2050Sstevel@tonic-gate } else {
2060Sstevel@tonic-gate /* we busy wait during cpr_dump or interrupt threads */
2070Sstevel@tonic-gate drv_usecwait(poll_delay);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate pkt->pkt_flags = savef;
2120Sstevel@tonic-gate pkt->pkt_comp = savec;
2130Sstevel@tonic-gate pkt->pkt_time = savet;
2146142Scth
2156142Scth /* return on error */
2166142Scth if (rval)
2176142Scth return (rval);
2186142Scth
2196142Scth /*
2206142Scth * This is not a performance critical code path.
2216142Scth *
2226142Scth * As an accommodation for scsi_poll callers, to avoid ddi_dma_sync()
2236142Scth * issues associated with looking at DMA memory prior to
2246142Scth * scsi_pkt_destroy(), we scsi_sync_pkt() prior to return.
2256142Scth */
2266142Scth scsi_sync_pkt(pkt);
2276142Scth return (0);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate * Command packaging routines.
2320Sstevel@tonic-gate *
2330Sstevel@tonic-gate * makecom_g*() are original routines and scsi_setup_cdb()
2340Sstevel@tonic-gate * is the new and preferred routine.
2350Sstevel@tonic-gate */
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate * These routines put LUN information in CDB byte 1 bits 7-5.
2390Sstevel@tonic-gate * This was required in SCSI-1. SCSI-2 allowed it but it preferred
2400Sstevel@tonic-gate * sending LUN information as part of IDENTIFY message.
2410Sstevel@tonic-gate * This is not allowed in SCSI-3.
2420Sstevel@tonic-gate */
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate void
makecom_g0(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)2450Sstevel@tonic-gate makecom_g0(struct scsi_pkt *pkt, struct scsi_device *devp,
2460Sstevel@tonic-gate int flag, int cmd, int addr, int cnt)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate MAKECOM_G0(pkt, devp, flag, cmd, addr, (uchar_t)cnt);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate void
makecom_g0_s(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int cnt,int fixbit)2520Sstevel@tonic-gate makecom_g0_s(struct scsi_pkt *pkt, struct scsi_device *devp,
2530Sstevel@tonic-gate int flag, int cmd, int cnt, int fixbit)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate MAKECOM_G0_S(pkt, devp, flag, cmd, cnt, (uchar_t)fixbit);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate void
makecom_g1(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)2590Sstevel@tonic-gate makecom_g1(struct scsi_pkt *pkt, struct scsi_device *devp,
2600Sstevel@tonic-gate int flag, int cmd, int addr, int cnt)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate MAKECOM_G1(pkt, devp, flag, cmd, addr, cnt);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate void
makecom_g5(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)2660Sstevel@tonic-gate makecom_g5(struct scsi_pkt *pkt, struct scsi_device *devp,
2670Sstevel@tonic-gate int flag, int cmd, int addr, int cnt)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate MAKECOM_G5(pkt, devp, flag, cmd, addr, cnt);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * Following routine does not put LUN information in CDB.
2740Sstevel@tonic-gate * This interface must be used for SCSI-2 targets having
2750Sstevel@tonic-gate * more than 8 LUNs or a SCSI-3 target.
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate int
scsi_setup_cdb(union scsi_cdb * cdbp,uchar_t cmd,uint_t addr,uint_t cnt,uint_t addtl_cdb_data)2780Sstevel@tonic-gate scsi_setup_cdb(union scsi_cdb *cdbp, uchar_t cmd, uint_t addr, uint_t cnt,
2790Sstevel@tonic-gate uint_t addtl_cdb_data)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate uint_t addr_cnt;
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate cdbp->scc_cmd = cmd;
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate switch (CDB_GROUPID(cmd)) {
2860Sstevel@tonic-gate case CDB_GROUPID_0:
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate * The following calculation is to take care of
2890Sstevel@tonic-gate * the fact that format of some 6 bytes tape
2900Sstevel@tonic-gate * command is different (compare 6 bytes disk and
2910Sstevel@tonic-gate * tape read commands).
2920Sstevel@tonic-gate */
2930Sstevel@tonic-gate addr_cnt = (addr << 8) + cnt;
2940Sstevel@tonic-gate addr = (addr_cnt & 0x1fffff00) >> 8;
2950Sstevel@tonic-gate cnt = addr_cnt & 0xff;
2960Sstevel@tonic-gate FORMG0ADDR(cdbp, addr);
2970Sstevel@tonic-gate FORMG0COUNT(cdbp, cnt);
2980Sstevel@tonic-gate break;
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate case CDB_GROUPID_1:
3010Sstevel@tonic-gate case CDB_GROUPID_2:
3020Sstevel@tonic-gate FORMG1ADDR(cdbp, addr);
3030Sstevel@tonic-gate FORMG1COUNT(cdbp, cnt);
3040Sstevel@tonic-gate break;
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate case CDB_GROUPID_4:
3070Sstevel@tonic-gate FORMG4ADDR(cdbp, addr);
3080Sstevel@tonic-gate FORMG4COUNT(cdbp, cnt);
3090Sstevel@tonic-gate FORMG4ADDTL(cdbp, addtl_cdb_data);
3100Sstevel@tonic-gate break;
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate case CDB_GROUPID_5:
3130Sstevel@tonic-gate FORMG5ADDR(cdbp, addr);
3140Sstevel@tonic-gate FORMG5COUNT(cdbp, cnt);
3150Sstevel@tonic-gate break;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate default:
3180Sstevel@tonic-gate return (0);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate return (1);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /*
3260Sstevel@tonic-gate * Common iopbmap data area packet allocation routines
3270Sstevel@tonic-gate */
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate struct scsi_pkt *
get_pktiopb(struct scsi_address * ap,caddr_t * datap,int cdblen,int statuslen,int datalen,int readflag,int (* func)())3300Sstevel@tonic-gate get_pktiopb(struct scsi_address *ap, caddr_t *datap, int cdblen, int statuslen,
3310Sstevel@tonic-gate int datalen, int readflag, int (*func)())
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate scsi_hba_tran_t *tran = A_TO_TRAN(ap);
3340Sstevel@tonic-gate dev_info_t *pdip = tran->tran_hba_dip;
3350Sstevel@tonic-gate struct scsi_pkt *pkt = NULL;
3360Sstevel@tonic-gate struct buf local;
3371106Smrj size_t rlen;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate if (!datap)
3400Sstevel@tonic-gate return (pkt);
3410Sstevel@tonic-gate *datap = (caddr_t)0;
3420Sstevel@tonic-gate bzero((caddr_t)&local, sizeof (struct buf));
3431106Smrj
3441106Smrj /*
3451106Smrj * use i_ddi_mem_alloc() for now until we have an interface to allocate
3461106Smrj * memory for DMA which doesn't require a DMA handle. ddi_iopb_alloc()
3471106Smrj * is obsolete and we want more flexibility in controlling the DMA
3481106Smrj * address constraints.
3491106Smrj */
3501106Smrj if (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
3511106Smrj ((func == SLEEP_FUNC) ? 1 : 0), 0, NULL, &local.b_un.b_addr, &rlen,
3521106Smrj NULL) != DDI_SUCCESS) {
3530Sstevel@tonic-gate return (pkt);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate if (readflag)
3560Sstevel@tonic-gate local.b_flags = B_READ;
3570Sstevel@tonic-gate local.b_bcount = datalen;
3580Sstevel@tonic-gate pkt = (*tran->tran_init_pkt) (ap, NULL, &local,
3594851Scth cdblen, statuslen, 0, PKT_CONSISTENT,
3604851Scth (func == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC, NULL);
3610Sstevel@tonic-gate if (!pkt) {
3621900Seota i_ddi_mem_free(local.b_un.b_addr, NULL);
3630Sstevel@tonic-gate if (func != NULL_FUNC) {
3640Sstevel@tonic-gate ddi_set_callback(func, NULL, &scsi_callback_id);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate } else {
3670Sstevel@tonic-gate *datap = local.b_un.b_addr;
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate return (pkt);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate * Equivalent deallocation wrapper
3740Sstevel@tonic-gate */
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate void
free_pktiopb(struct scsi_pkt * pkt,caddr_t datap,int datalen)3770Sstevel@tonic-gate free_pktiopb(struct scsi_pkt *pkt, caddr_t datap, int datalen)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate register struct scsi_address *ap = P_TO_ADDR(pkt);
3800Sstevel@tonic-gate register scsi_hba_tran_t *tran = A_TO_TRAN(ap);
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate (*tran->tran_destroy_pkt)(ap, pkt);
3830Sstevel@tonic-gate if (datap && datalen) {
3841900Seota i_ddi_mem_free(datap, NULL);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate if (scsi_callback_id != 0) {
3870Sstevel@tonic-gate ddi_run_callback(&scsi_callback_id);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate /*
3920Sstevel@tonic-gate * Common naming functions
3930Sstevel@tonic-gate */
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate static char scsi_tmpname[64];
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate char *
scsi_dname(int dtyp)3980Sstevel@tonic-gate scsi_dname(int dtyp)
3990Sstevel@tonic-gate {
4008017SChris.Horne@Sun.COM static char *dnames[] = DTYPE_ASCII;
4018017SChris.Horne@Sun.COM char *dname = NULL;
4020Sstevel@tonic-gate
4038017SChris.Horne@Sun.COM if ((dtyp & DTYPE_MASK) < (sizeof (dnames) / sizeof (*dnames)))
4048017SChris.Horne@Sun.COM dname = dnames[dtyp&DTYPE_MASK];
4058017SChris.Horne@Sun.COM else if (dtyp == DTYPE_NOTPRESENT)
4068017SChris.Horne@Sun.COM dname = "Not Present";
4078017SChris.Horne@Sun.COM if ((dname == NULL) || (*dname == '\0'))
4088017SChris.Horne@Sun.COM dname = "<unknown device type>";
4098017SChris.Horne@Sun.COM return (dname);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate char *
scsi_rname(uchar_t reason)4130Sstevel@tonic-gate scsi_rname(uchar_t reason)
4140Sstevel@tonic-gate {
4158017SChris.Horne@Sun.COM static char *rnames[] = CMD_REASON_ASCII;
4168017SChris.Horne@Sun.COM char *rname = NULL;
4175628Srralphs
4188017SChris.Horne@Sun.COM if (reason < (sizeof (rnames) / sizeof (*rnames)))
4198017SChris.Horne@Sun.COM rname = rnames[reason];
4208017SChris.Horne@Sun.COM if ((rname == NULL) || (*rname == '\0'))
4218017SChris.Horne@Sun.COM rname = "<unknown reason>";
4228017SChris.Horne@Sun.COM return (rname);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate char *
scsi_mname(uchar_t msg)4260Sstevel@tonic-gate scsi_mname(uchar_t msg)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate static char *imsgs[23] = {
4290Sstevel@tonic-gate "COMMAND COMPLETE",
4300Sstevel@tonic-gate "EXTENDED",
4310Sstevel@tonic-gate "SAVE DATA POINTER",
4320Sstevel@tonic-gate "RESTORE POINTERS",
4330Sstevel@tonic-gate "DISCONNECT",
4340Sstevel@tonic-gate "INITIATOR DETECTED ERROR",
4350Sstevel@tonic-gate "ABORT",
4360Sstevel@tonic-gate "REJECT",
4370Sstevel@tonic-gate "NO-OP",
4380Sstevel@tonic-gate "MESSAGE PARITY",
4390Sstevel@tonic-gate "LINKED COMMAND COMPLETE",
4400Sstevel@tonic-gate "LINKED COMMAND COMPLETE (W/FLAG)",
4410Sstevel@tonic-gate "BUS DEVICE RESET",
4420Sstevel@tonic-gate "ABORT TAG",
4430Sstevel@tonic-gate "CLEAR QUEUE",
4440Sstevel@tonic-gate "INITIATE RECOVERY",
4450Sstevel@tonic-gate "RELEASE RECOVERY",
4460Sstevel@tonic-gate "TERMINATE PROCESS",
4470Sstevel@tonic-gate "CONTINUE TASK",
4480Sstevel@tonic-gate "TARGET TRANSFER DISABLE",
4490Sstevel@tonic-gate "RESERVED (0x14)",
4500Sstevel@tonic-gate "RESERVED (0x15)",
4510Sstevel@tonic-gate "CLEAR ACA"
4520Sstevel@tonic-gate };
4530Sstevel@tonic-gate static char *imsgs_2[6] = {
4540Sstevel@tonic-gate "SIMPLE QUEUE TAG",
4550Sstevel@tonic-gate "HEAD OF QUEUE TAG",
4560Sstevel@tonic-gate "ORDERED QUEUE TAG",
4570Sstevel@tonic-gate "IGNORE WIDE RESIDUE",
4580Sstevel@tonic-gate "ACA",
4590Sstevel@tonic-gate "LOGICAL UNIT RESET"
4600Sstevel@tonic-gate };
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate if (msg < 23) {
4630Sstevel@tonic-gate return (imsgs[msg]);
4640Sstevel@tonic-gate } else if (IS_IDENTIFY_MSG(msg)) {
4650Sstevel@tonic-gate return ("IDENTIFY");
4660Sstevel@tonic-gate } else if (IS_2BYTE_MSG(msg) &&
4670Sstevel@tonic-gate (int)((msg) & 0xF) < (sizeof (imsgs_2) / sizeof (char *))) {
4680Sstevel@tonic-gate return (imsgs_2[msg & 0xF]);
4690Sstevel@tonic-gate } else {
4700Sstevel@tonic-gate return ("<unknown msg>");
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate char *
scsi_cname(uchar_t cmd,register char ** cmdvec)4760Sstevel@tonic-gate scsi_cname(uchar_t cmd, register char **cmdvec)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate while (*cmdvec != (char *)0) {
4790Sstevel@tonic-gate if (cmd == **cmdvec) {
4800Sstevel@tonic-gate return ((char *)((long)(*cmdvec)+1));
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate cmdvec++;
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate return (sprintf(scsi_tmpname, "<undecoded cmd 0x%x>", cmd));
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate char *
scsi_cmd_name(uchar_t cmd,struct scsi_key_strings * cmdlist,char * tmpstr)4880Sstevel@tonic-gate scsi_cmd_name(uchar_t cmd, struct scsi_key_strings *cmdlist, char *tmpstr)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate int i = 0;
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate while (cmdlist[i].key != -1) {
4930Sstevel@tonic-gate if (cmd == cmdlist[i].key) {
4940Sstevel@tonic-gate return ((char *)cmdlist[i].message);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate i++;
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate return (sprintf(tmpstr, "<undecoded cmd 0x%x>", cmd));
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate static struct scsi_asq_key_strings extended_sense_list[] = {
5020Sstevel@tonic-gate 0x00, 0x00, "no additional sense info",
5030Sstevel@tonic-gate 0x00, 0x01, "filemark detected",
5040Sstevel@tonic-gate 0x00, 0x02, "end of partition/medium detected",
5050Sstevel@tonic-gate 0x00, 0x03, "setmark detected",
5068017SChris.Horne@Sun.COM 0x00, 0x04, "beginning of partition/medium detected",
5070Sstevel@tonic-gate 0x00, 0x05, "end of data detected",
5080Sstevel@tonic-gate 0x00, 0x06, "i/o process terminated",
5090Sstevel@tonic-gate 0x00, 0x11, "audio play operation in progress",
5100Sstevel@tonic-gate 0x00, 0x12, "audio play operation paused",
5110Sstevel@tonic-gate 0x00, 0x13, "audio play operation successfully completed",
5120Sstevel@tonic-gate 0x00, 0x14, "audio play operation stopped due to error",
5130Sstevel@tonic-gate 0x00, 0x15, "no current audio status to return",
5140Sstevel@tonic-gate 0x00, 0x16, "operation in progress",
5150Sstevel@tonic-gate 0x00, 0x17, "cleaning requested",
5160Sstevel@tonic-gate 0x00, 0x18, "erase operation in progress",
5170Sstevel@tonic-gate 0x00, 0x19, "locate operation in progress",
5180Sstevel@tonic-gate 0x00, 0x1A, "rewind operation in progress",
5190Sstevel@tonic-gate 0x00, 0x1B, "set capacity operation in progress",
5200Sstevel@tonic-gate 0x00, 0x1C, "verify operation in progress",
5210Sstevel@tonic-gate 0x01, 0x00, "no index/sector signal",
5220Sstevel@tonic-gate 0x02, 0x00, "no seek complete",
5230Sstevel@tonic-gate 0x03, 0x00, "peripheral device write fault",
5240Sstevel@tonic-gate 0x03, 0x01, "no write current",
5250Sstevel@tonic-gate 0x03, 0x02, "excessive write errors",
5260Sstevel@tonic-gate 0x04, 0x00, "LUN not ready",
5270Sstevel@tonic-gate 0x04, 0x01, "LUN is becoming ready",
5280Sstevel@tonic-gate 0x04, 0x02, "LUN initializing command required",
5290Sstevel@tonic-gate 0x04, 0x03, "LUN not ready intervention required",
5300Sstevel@tonic-gate 0x04, 0x04, "LUN not ready format in progress",
5310Sstevel@tonic-gate 0x04, 0x05, "LUN not ready, rebuild in progress",
5320Sstevel@tonic-gate 0x04, 0x06, "LUN not ready, recalculation in progress",
5330Sstevel@tonic-gate 0x04, 0x07, "LUN not ready, operation in progress",
5340Sstevel@tonic-gate 0x04, 0x08, "LUN not ready, long write in progress",
5350Sstevel@tonic-gate 0x04, 0x09, "LUN not ready, self-test in progress",
5360Sstevel@tonic-gate 0x04, 0x0A, "LUN not accessible, asymmetric access state transition",
5370Sstevel@tonic-gate 0x04, 0x0B, "LUN not accessible, target port in standby state",
5380Sstevel@tonic-gate 0x04, 0x0C, "LUN not accessible, target port in unavailable state",
5390Sstevel@tonic-gate 0x04, 0x10, "LUN not ready, auxiliary memory not accessible",
5400Sstevel@tonic-gate 0x05, 0x00, "LUN does not respond to selection",
5410Sstevel@tonic-gate 0x06, 0x00, "reference position found",
5420Sstevel@tonic-gate 0x07, 0x00, "multiple peripheral devices selected",
5430Sstevel@tonic-gate 0x08, 0x00, "LUN communication failure",
5440Sstevel@tonic-gate 0x08, 0x01, "LUN communication time-out",
5450Sstevel@tonic-gate 0x08, 0x02, "LUN communication parity error",
5460Sstevel@tonic-gate 0x08, 0x03, "LUN communication crc error (ultra-DMA/32)",
5470Sstevel@tonic-gate 0x08, 0x04, "unreachable copy target",
5480Sstevel@tonic-gate 0x09, 0x00, "track following error",
5490Sstevel@tonic-gate 0x09, 0x01, "tracking servo failure",
5500Sstevel@tonic-gate 0x09, 0x02, "focus servo failure",
5510Sstevel@tonic-gate 0x09, 0x03, "spindle servo failure",
5520Sstevel@tonic-gate 0x09, 0x04, "head select fault",
5530Sstevel@tonic-gate 0x0a, 0x00, "error log overflow",
5540Sstevel@tonic-gate 0x0b, 0x00, "warning",
5550Sstevel@tonic-gate 0x0b, 0x01, "warning - specified temperature exceeded",
5560Sstevel@tonic-gate 0x0b, 0x02, "warning - enclosure degraded",
5570Sstevel@tonic-gate 0x0c, 0x00, "write error",
5580Sstevel@tonic-gate 0x0c, 0x01, "write error - recovered with auto reallocation",
5590Sstevel@tonic-gate 0x0c, 0x02, "write error - auto reallocation failed",
5600Sstevel@tonic-gate 0x0c, 0x03, "write error - recommend reassignment",
5610Sstevel@tonic-gate 0x0c, 0x04, "compression check miscompare error",
5620Sstevel@tonic-gate 0x0c, 0x05, "data expansion occurred during compression",
5630Sstevel@tonic-gate 0x0c, 0x06, "block not compressible",
5640Sstevel@tonic-gate 0x0c, 0x07, "write error - recovery needed",
5650Sstevel@tonic-gate 0x0c, 0x08, "write error - recovery failed",
5660Sstevel@tonic-gate 0x0c, 0x09, "write error - loss of streaming",
5670Sstevel@tonic-gate 0x0c, 0x0a, "write error - padding blocks added",
5680Sstevel@tonic-gate 0x0c, 0x0b, "auxiliary memory write error",
5690Sstevel@tonic-gate 0x0c, 0x0c, "write error - unexpected unsolicited data",
5700Sstevel@tonic-gate 0x0c, 0x0d, "write error - not enough unsolicited data",
5710Sstevel@tonic-gate 0x0d, 0x00, "error detected by third party temporary initiator",
5720Sstevel@tonic-gate 0x0d, 0x01, "third party device failure",
5730Sstevel@tonic-gate 0x0d, 0x02, "copy target device not reachable",
5740Sstevel@tonic-gate 0x0d, 0x03, "incorrect copy target device type",
5750Sstevel@tonic-gate 0x0d, 0x04, "copy target device data underrun",
5760Sstevel@tonic-gate 0x0d, 0x05, "copy target device data overrun",
5770Sstevel@tonic-gate 0x0e, 0x00, "invalid information unit",
5780Sstevel@tonic-gate 0x0e, 0x01, "information unit too short",
5790Sstevel@tonic-gate 0x0e, 0x02, "information unit too long",
5800Sstevel@tonic-gate 0x10, 0x00, "ID CRC or ECC error",
5810Sstevel@tonic-gate 0x11, 0x00, "unrecovered read error",
5820Sstevel@tonic-gate 0x11, 0x01, "read retries exhausted",
5830Sstevel@tonic-gate 0x11, 0x02, "error too long to correct",
5840Sstevel@tonic-gate 0x11, 0x03, "multiple read errors",
5850Sstevel@tonic-gate 0x11, 0x04, "unrecovered read error - auto reallocate failed",
5860Sstevel@tonic-gate 0x11, 0x05, "L-EC uncorrectable error",
5870Sstevel@tonic-gate 0x11, 0x06, "CIRC unrecovered error",
5880Sstevel@tonic-gate 0x11, 0x07, "data re-synchronization error",
5890Sstevel@tonic-gate 0x11, 0x08, "incomplete block read",
5900Sstevel@tonic-gate 0x11, 0x09, "no gap found",
5910Sstevel@tonic-gate 0x11, 0x0a, "miscorrected error",
5920Sstevel@tonic-gate 0x11, 0x0b, "unrecovered read error - recommend reassignment",
5930Sstevel@tonic-gate 0x11, 0x0c, "unrecovered read error - recommend rewrite the data",
5940Sstevel@tonic-gate 0x11, 0x0d, "de-compression crc error",
5950Sstevel@tonic-gate 0x11, 0x0e, "cannot decompress using declared algorithm",
5960Sstevel@tonic-gate 0x11, 0x0f, "error reading UPC/EAN number",
5970Sstevel@tonic-gate 0x11, 0x10, "error reading ISRC number",
5980Sstevel@tonic-gate 0x11, 0x11, "read error - loss of streaming",
5990Sstevel@tonic-gate 0x11, 0x12, "auxiliary memory read error",
6000Sstevel@tonic-gate 0x11, 0x13, "read error - failed retransmission request",
6010Sstevel@tonic-gate 0x12, 0x00, "address mark not found for ID field",
6020Sstevel@tonic-gate 0x13, 0x00, "address mark not found for data field",
6030Sstevel@tonic-gate 0x14, 0x00, "recorded entity not found",
6040Sstevel@tonic-gate 0x14, 0x01, "record not found",
6050Sstevel@tonic-gate 0x14, 0x02, "filemark or setmark not found",
6060Sstevel@tonic-gate 0x14, 0x03, "end-of-data not found",
6070Sstevel@tonic-gate 0x14, 0x04, "block sequence error",
6080Sstevel@tonic-gate 0x14, 0x05, "record not found - recommend reassignment",
6090Sstevel@tonic-gate 0x14, 0x06, "record not found - data auto-reallocated",
6100Sstevel@tonic-gate 0x14, 0x07, "locate operation failure",
6110Sstevel@tonic-gate 0x15, 0x00, "random positioning error",
6120Sstevel@tonic-gate 0x15, 0x01, "mechanical positioning error",
6130Sstevel@tonic-gate 0x15, 0x02, "positioning error detected by read of medium",
6140Sstevel@tonic-gate 0x16, 0x00, "data sync mark error",
6150Sstevel@tonic-gate 0x16, 0x01, "data sync error - data rewritten",
6160Sstevel@tonic-gate 0x16, 0x02, "data sync error - recommend rewrite",
6170Sstevel@tonic-gate 0x16, 0x03, "data sync error - data auto-reallocated",
6180Sstevel@tonic-gate 0x16, 0x04, "data sync error - recommend reassignment",
6190Sstevel@tonic-gate 0x17, 0x00, "recovered data with no error correction",
6200Sstevel@tonic-gate 0x17, 0x01, "recovered data with retries",
6210Sstevel@tonic-gate 0x17, 0x02, "recovered data with positive head offset",
6220Sstevel@tonic-gate 0x17, 0x03, "recovered data with negative head offset",
6230Sstevel@tonic-gate 0x17, 0x04, "recovered data with retries and/or CIRC applied",
6240Sstevel@tonic-gate 0x17, 0x05, "recovered data using previous sector id",
6250Sstevel@tonic-gate 0x17, 0x06, "recovered data without ECC - data auto-reallocated",
6260Sstevel@tonic-gate 0x17, 0x07, "recovered data without ECC - recommend reassignment",
6270Sstevel@tonic-gate 0x17, 0x08, "recovered data without ECC - recommend rewrite",
6280Sstevel@tonic-gate 0x17, 0x09, "recovered data without ECC - data rewritten",
6290Sstevel@tonic-gate 0x18, 0x00, "recovered data with error correction",
6300Sstevel@tonic-gate 0x18, 0x01, "recovered data with error corr. & retries applied",
6310Sstevel@tonic-gate 0x18, 0x02, "recovered data - data auto-reallocated",
6320Sstevel@tonic-gate 0x18, 0x03, "recovered data with CIRC",
6330Sstevel@tonic-gate 0x18, 0x04, "recovered data with L-EC",
6340Sstevel@tonic-gate 0x18, 0x05, "recovered data - recommend reassignment",
6350Sstevel@tonic-gate 0x18, 0x06, "recovered data - recommend rewrite",
6360Sstevel@tonic-gate 0x18, 0x07, "recovered data with ECC - data rewritten",
6370Sstevel@tonic-gate 0x18, 0x08, "recovered data with linking",
6380Sstevel@tonic-gate 0x19, 0x00, "defect list error",
6390Sstevel@tonic-gate 0x1a, 0x00, "parameter list length error",
6400Sstevel@tonic-gate 0x1b, 0x00, "synchronous data xfer error",
6410Sstevel@tonic-gate 0x1c, 0x00, "defect list not found",
6420Sstevel@tonic-gate 0x1c, 0x01, "primary defect list not found",
6430Sstevel@tonic-gate 0x1c, 0x02, "grown defect list not found",
6440Sstevel@tonic-gate 0x1d, 0x00, "miscompare during verify",
6450Sstevel@tonic-gate 0x1e, 0x00, "recovered ID with ECC",
6460Sstevel@tonic-gate 0x1f, 0x00, "partial defect list transfer",
6470Sstevel@tonic-gate 0x20, 0x00, "invalid command operation code",
6480Sstevel@tonic-gate 0x20, 0x01, "access denied - initiator pending-enrolled",
6490Sstevel@tonic-gate 0x20, 0x02, "access denied - no access rights",
6500Sstevel@tonic-gate 0x20, 0x03, "access denied - invalid mgmt id key",
6510Sstevel@tonic-gate 0x20, 0x04, "illegal command while in write capable state",
6520Sstevel@tonic-gate 0x20, 0x06, "illegal command while in explicit address mode",
6530Sstevel@tonic-gate 0x20, 0x07, "illegal command while in implicit address mode",
6540Sstevel@tonic-gate 0x20, 0x08, "access denied - enrollment conflict",
6550Sstevel@tonic-gate 0x20, 0x09, "access denied - invalid lu identifier",
6560Sstevel@tonic-gate 0x20, 0x0a, "access denied - invalid proxy token",
6570Sstevel@tonic-gate 0x20, 0x0b, "access denied - ACL LUN conflict",
6580Sstevel@tonic-gate 0x21, 0x00, "logical block address out of range",
6590Sstevel@tonic-gate 0x21, 0x01, "invalid element address",
6600Sstevel@tonic-gate 0x21, 0x02, "invalid address for write",
6610Sstevel@tonic-gate 0x22, 0x00, "illegal function",
6620Sstevel@tonic-gate 0x24, 0x00, "invalid field in cdb",
6630Sstevel@tonic-gate 0x24, 0x01, "cdb decryption error",
6640Sstevel@tonic-gate 0x25, 0x00, "LUN not supported",
6650Sstevel@tonic-gate 0x26, 0x00, "invalid field in param list",
6660Sstevel@tonic-gate 0x26, 0x01, "parameter not supported",
6670Sstevel@tonic-gate 0x26, 0x02, "parameter value invalid",
6680Sstevel@tonic-gate 0x26, 0x03, "threshold parameters not supported",
6690Sstevel@tonic-gate 0x26, 0x04, "invalid release of persistent reservation",
6700Sstevel@tonic-gate 0x26, 0x05, "data decryption error",
6710Sstevel@tonic-gate 0x26, 0x06, "too many target descriptors",
6720Sstevel@tonic-gate 0x26, 0x07, "unsupported target descriptor type code",
6730Sstevel@tonic-gate 0x26, 0x08, "too many segment descriptors",
6740Sstevel@tonic-gate 0x26, 0x09, "unsupported segment descriptor type code",
6750Sstevel@tonic-gate 0x26, 0x0a, "unexpected inexact segment",
6760Sstevel@tonic-gate 0x26, 0x0b, "inline data length exceeded",
6770Sstevel@tonic-gate 0x26, 0x0c, "invalid operation for copy source or destination",
6780Sstevel@tonic-gate 0x26, 0x0d, "copy segment granularity violation",
6790Sstevel@tonic-gate 0x27, 0x00, "write protected",
6800Sstevel@tonic-gate 0x27, 0x01, "hardware write protected",
6810Sstevel@tonic-gate 0x27, 0x02, "LUN software write protected",
6820Sstevel@tonic-gate 0x27, 0x03, "associated write protect",
6830Sstevel@tonic-gate 0x27, 0x04, "persistent write protect",
6840Sstevel@tonic-gate 0x27, 0x05, "permanent write protect",
6850Sstevel@tonic-gate 0x27, 0x06, "conditional write protect",
6862537Srralphs 0x27, 0x80, "unable to overwrite data",
6870Sstevel@tonic-gate 0x28, 0x00, "medium may have changed",
6880Sstevel@tonic-gate 0x28, 0x01, "import or export element accessed",
6890Sstevel@tonic-gate 0x29, 0x00, "power on, reset, or bus reset occurred",
6900Sstevel@tonic-gate 0x29, 0x01, "power on occurred",
6910Sstevel@tonic-gate 0x29, 0x02, "scsi bus reset occurred",
6920Sstevel@tonic-gate 0x29, 0x03, "bus device reset message occurred",
6930Sstevel@tonic-gate 0x29, 0x04, "device internal reset",
6940Sstevel@tonic-gate 0x29, 0x05, "transceiver mode changed to single-ended",
6950Sstevel@tonic-gate 0x29, 0x06, "transceiver mode changed to LVD",
6960Sstevel@tonic-gate 0x29, 0x07, "i_t nexus loss occurred",
6970Sstevel@tonic-gate 0x2a, 0x00, "parameters changed",
6980Sstevel@tonic-gate 0x2a, 0x01, "mode parameters changed",
6990Sstevel@tonic-gate 0x2a, 0x02, "log parameters changed",
7000Sstevel@tonic-gate 0x2a, 0x03, "reservations preempted",
7010Sstevel@tonic-gate 0x2a, 0x04, "reservations released",
7020Sstevel@tonic-gate 0x2a, 0x05, "registrations preempted",
7030Sstevel@tonic-gate 0x2a, 0x06, "asymmetric access state changed",
7040Sstevel@tonic-gate 0x2a, 0x07, "implicit asymmetric access state transition failed",
7050Sstevel@tonic-gate 0x2b, 0x00, "copy cannot execute since host cannot disconnect",
7060Sstevel@tonic-gate 0x2c, 0x00, "command sequence error",
7070Sstevel@tonic-gate 0x2c, 0x03, "current program area is not empty",
7080Sstevel@tonic-gate 0x2c, 0x04, "current program area is empty",
7090Sstevel@tonic-gate 0x2c, 0x06, "persistent prevent conflict",
7100Sstevel@tonic-gate 0x2c, 0x07, "previous busy status",
7110Sstevel@tonic-gate 0x2c, 0x08, "previous task set full status",
7120Sstevel@tonic-gate 0x2c, 0x09, "previous reservation conflict status",
7130Sstevel@tonic-gate 0x2d, 0x00, "overwrite error on update in place",
7140Sstevel@tonic-gate 0x2e, 0x00, "insufficient time for operation",
7150Sstevel@tonic-gate 0x2f, 0x00, "commands cleared by another initiator",
7160Sstevel@tonic-gate 0x30, 0x00, "incompatible medium installed",
7170Sstevel@tonic-gate 0x30, 0x01, "cannot read medium - unknown format",
7180Sstevel@tonic-gate 0x30, 0x02, "cannot read medium - incompatible format",
7190Sstevel@tonic-gate 0x30, 0x03, "cleaning cartridge installed",
7200Sstevel@tonic-gate 0x30, 0x04, "cannot write medium - unknown format",
7210Sstevel@tonic-gate 0x30, 0x05, "cannot write medium - incompatible format",
7220Sstevel@tonic-gate 0x30, 0x06, "cannot format medium - incompatible medium",
7230Sstevel@tonic-gate 0x30, 0x07, "cleaning failure",
7240Sstevel@tonic-gate 0x30, 0x08, "cannot write - application code mismatch",
7250Sstevel@tonic-gate 0x30, 0x09, "current session not fixated for append",
7262537Srralphs 0x30, 0x0b, "WORM medium - Overwrite attempted",
7272537Srralphs 0x30, 0x0c, "WORM medium - Cannot Erase",
7282537Srralphs 0x30, 0x0d, "WORM medium - Integrity Check",
7290Sstevel@tonic-gate 0x30, 0x10, "medium not formatted",
7300Sstevel@tonic-gate 0x31, 0x00, "medium format corrupted",
7310Sstevel@tonic-gate 0x31, 0x01, "format command failed",
7320Sstevel@tonic-gate 0x31, 0x02, "zoned formatting failed due to spare linking",
7332537Srralphs 0x31, 0x94, "WORM media corrupted",
7340Sstevel@tonic-gate 0x32, 0x00, "no defect spare location available",
7350Sstevel@tonic-gate 0x32, 0x01, "defect list update failure",
7360Sstevel@tonic-gate 0x33, 0x00, "tape length error",
7370Sstevel@tonic-gate 0x34, 0x00, "enclosure failure",
7380Sstevel@tonic-gate 0x35, 0x00, "enclosure services failure",
7390Sstevel@tonic-gate 0x35, 0x01, "unsupported enclosure function",
7400Sstevel@tonic-gate 0x35, 0x02, "enclosure services unavailable",
7410Sstevel@tonic-gate 0x35, 0x03, "enclosure services transfer failure",
7420Sstevel@tonic-gate 0x35, 0x04, "enclosure services transfer refused",
7430Sstevel@tonic-gate 0x36, 0x00, "ribbon, ink, or toner failure",
7440Sstevel@tonic-gate 0x37, 0x00, "rounded parameter",
7450Sstevel@tonic-gate 0x39, 0x00, "saving parameters not supported",
7460Sstevel@tonic-gate 0x3a, 0x00, "medium not present",
7470Sstevel@tonic-gate 0x3a, 0x01, "medium not present - tray closed",
7480Sstevel@tonic-gate 0x3a, 0x02, "medium not present - tray open",
7490Sstevel@tonic-gate 0x3a, 0x03, "medium not present - loadable",
7500Sstevel@tonic-gate 0x3a, 0x04, "medium not present - medium auxiliary memory accessible",
7510Sstevel@tonic-gate 0x3b, 0x00, "sequential positioning error",
7520Sstevel@tonic-gate 0x3b, 0x01, "tape position error at beginning-of-medium",
7530Sstevel@tonic-gate 0x3b, 0x02, "tape position error at end-of-medium",
7540Sstevel@tonic-gate 0x3b, 0x08, "reposition error",
7550Sstevel@tonic-gate 0x3b, 0x0c, "position past beginning of medium",
7560Sstevel@tonic-gate 0x3b, 0x0d, "medium destination element full",
7570Sstevel@tonic-gate 0x3b, 0x0e, "medium source element empty",
7580Sstevel@tonic-gate 0x3b, 0x0f, "end of medium reached",
7590Sstevel@tonic-gate 0x3b, 0x11, "medium magazine not accessible",
7600Sstevel@tonic-gate 0x3b, 0x12, "medium magazine removed",
7610Sstevel@tonic-gate 0x3b, 0x13, "medium magazine inserted",
7620Sstevel@tonic-gate 0x3b, 0x14, "medium magazine locked",
7630Sstevel@tonic-gate 0x3b, 0x15, "medium magazine unlocked",
7640Sstevel@tonic-gate 0x3b, 0x16, "mechanical positioning or changer error",
7650Sstevel@tonic-gate 0x3d, 0x00, "invalid bits in indentify message",
7660Sstevel@tonic-gate 0x3e, 0x00, "LUN has not self-configured yet",
7670Sstevel@tonic-gate 0x3e, 0x01, "LUN failure",
7680Sstevel@tonic-gate 0x3e, 0x02, "timeout on LUN",
7690Sstevel@tonic-gate 0x3e, 0x03, "LUN failed self-test",
7700Sstevel@tonic-gate 0x3e, 0x04, "LUN unable to update self-test log",
7710Sstevel@tonic-gate 0x3f, 0x00, "target operating conditions have changed",
7720Sstevel@tonic-gate 0x3f, 0x01, "microcode has been changed",
7730Sstevel@tonic-gate 0x3f, 0x02, "changed operating definition",
7740Sstevel@tonic-gate 0x3f, 0x03, "inquiry data has changed",
7750Sstevel@tonic-gate 0x3f, 0x04, "component device attached",
7760Sstevel@tonic-gate 0x3f, 0x05, "device identifier changed",
7770Sstevel@tonic-gate 0x3f, 0x06, "redundancy group created or modified",
7780Sstevel@tonic-gate 0x3f, 0x07, "redundancy group deleted",
7790Sstevel@tonic-gate 0x3f, 0x08, "spare created or modified",
7800Sstevel@tonic-gate 0x3f, 0x09, "spare deleted",
7810Sstevel@tonic-gate 0x3f, 0x0a, "volume set created or modified",
7820Sstevel@tonic-gate 0x3f, 0x0b, "volume set deleted",
7830Sstevel@tonic-gate 0x3f, 0x0c, "volume set deassigned",
7840Sstevel@tonic-gate 0x3f, 0x0d, "volume set reassigned",
7850Sstevel@tonic-gate 0x3f, 0x0e, "reported LUNs data has changed",
7860Sstevel@tonic-gate 0x3f, 0x0f, "echo buffer overwritten",
7870Sstevel@tonic-gate 0x3f, 0x10, "medium loadable",
7880Sstevel@tonic-gate 0x3f, 0x11, "medium auxiliary memory accessible",
7890Sstevel@tonic-gate 0x40, 0x00, "ram failure",
7900Sstevel@tonic-gate 0x41, 0x00, "data path failure",
7910Sstevel@tonic-gate 0x42, 0x00, "power-on or self-test failure",
7920Sstevel@tonic-gate 0x43, 0x00, "message error",
7930Sstevel@tonic-gate 0x44, 0x00, "internal target failure",
7940Sstevel@tonic-gate 0x45, 0x00, "select or reselect failure",
7950Sstevel@tonic-gate 0x46, 0x00, "unsuccessful soft reset",
7960Sstevel@tonic-gate 0x47, 0x00, "scsi parity error",
7970Sstevel@tonic-gate 0x47, 0x01, "data phase crc error detected",
7980Sstevel@tonic-gate 0x47, 0x02, "scsi parity error detected during st data phase",
7990Sstevel@tonic-gate 0x47, 0x03, "information unit iucrc error detected",
8000Sstevel@tonic-gate 0x47, 0x04, "asynchronous information protection error detected",
8010Sstevel@tonic-gate 0x47, 0x05, "protocol service crc error",
8020Sstevel@tonic-gate 0x47, 0x7f, "some commands cleared by iscsi protocol event",
8030Sstevel@tonic-gate 0x48, 0x00, "initiator detected error message received",
8040Sstevel@tonic-gate 0x49, 0x00, "invalid message error",
8050Sstevel@tonic-gate 0x4a, 0x00, "command phase error",
8060Sstevel@tonic-gate 0x4b, 0x00, "data phase error",
8070Sstevel@tonic-gate 0x4b, 0x01, "invalid target port transfer tag received",
8080Sstevel@tonic-gate 0x4b, 0x02, "too much write data",
8090Sstevel@tonic-gate 0x4b, 0x03, "ack/nak timeout",
8100Sstevel@tonic-gate 0x4b, 0x04, "nak received",
8110Sstevel@tonic-gate 0x4b, 0x05, "data offset error",
8120Sstevel@tonic-gate 0x4c, 0x00, "logical unit failed self-configuration",
8130Sstevel@tonic-gate 0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)",
8140Sstevel@tonic-gate 0x4e, 0x00, "overlapped commands attempted",
8150Sstevel@tonic-gate 0x50, 0x00, "write append error",
8162537Srralphs 0x50, 0x01, "data protect write append error",
8172537Srralphs 0x50, 0x95, "data protect write append error",
8180Sstevel@tonic-gate 0x51, 0x00, "erase failure",
8190Sstevel@tonic-gate 0x52, 0x00, "cartridge fault",
8200Sstevel@tonic-gate 0x53, 0x00, "media load or eject failed",
8210Sstevel@tonic-gate 0x53, 0x01, "unload tape failure",
8220Sstevel@tonic-gate 0x53, 0x02, "medium removal prevented",
8230Sstevel@tonic-gate 0x54, 0x00, "scsi to host system interface failure",
8240Sstevel@tonic-gate 0x55, 0x00, "system resource failure",
8250Sstevel@tonic-gate 0x55, 0x01, "system buffer full",
8260Sstevel@tonic-gate 0x55, 0x02, "insufficient reservation resources",
8270Sstevel@tonic-gate 0x55, 0x03, "insufficient resources",
8280Sstevel@tonic-gate 0x55, 0x04, "insufficient registration resources",
8290Sstevel@tonic-gate 0x55, 0x05, "insufficient access control resources",
8300Sstevel@tonic-gate 0x55, 0x06, "auxiliary memory out of space",
8310Sstevel@tonic-gate 0x57, 0x00, "unable to recover TOC",
8320Sstevel@tonic-gate 0x58, 0x00, "generation does not exist",
8330Sstevel@tonic-gate 0x59, 0x00, "updated block read",
8340Sstevel@tonic-gate 0x5a, 0x00, "operator request or state change input",
8350Sstevel@tonic-gate 0x5a, 0x01, "operator medium removal request",
8360Sstevel@tonic-gate 0x5a, 0x02, "operator selected write protect",
8370Sstevel@tonic-gate 0x5a, 0x03, "operator selected write permit",
8380Sstevel@tonic-gate 0x5b, 0x00, "log exception",
8390Sstevel@tonic-gate 0x5b, 0x01, "threshold condition met",
8400Sstevel@tonic-gate 0x5b, 0x02, "log counter at maximum",
8410Sstevel@tonic-gate 0x5b, 0x03, "log list codes exhausted",
8420Sstevel@tonic-gate 0x5c, 0x00, "RPL status change",
8430Sstevel@tonic-gate 0x5c, 0x01, "spindles synchronized",
8440Sstevel@tonic-gate 0x5c, 0x02, "spindles not synchronized",
8450Sstevel@tonic-gate 0x5d, 0x00, "drive operation marginal, service immediately"
8460Sstevel@tonic-gate " (failure prediction threshold exceeded)",
8470Sstevel@tonic-gate 0x5d, 0x01, "media failure prediction threshold exceeded",
8480Sstevel@tonic-gate 0x5d, 0x02, "LUN failure prediction threshold exceeded",
8490Sstevel@tonic-gate 0x5d, 0x03, "spare area exhaustion prediction threshold exceeded",
8500Sstevel@tonic-gate 0x5d, 0x10, "hardware impending failure general hard drive failure",
8510Sstevel@tonic-gate 0x5d, 0x11, "hardware impending failure drive error rate too high",
8520Sstevel@tonic-gate 0x5d, 0x12, "hardware impending failure data error rate too high",
8530Sstevel@tonic-gate 0x5d, 0x13, "hardware impending failure seek error rate too high",
8540Sstevel@tonic-gate 0x5d, 0x14, "hardware impending failure too many block reassigns",
8550Sstevel@tonic-gate 0x5d, 0x15, "hardware impending failure access times too high",
8560Sstevel@tonic-gate 0x5d, 0x16, "hardware impending failure start unit times too high",
8570Sstevel@tonic-gate 0x5d, 0x17, "hardware impending failure channel parametrics",
8580Sstevel@tonic-gate 0x5d, 0x18, "hardware impending failure controller detected",
8590Sstevel@tonic-gate 0x5d, 0x19, "hardware impending failure throughput performance",
8600Sstevel@tonic-gate 0x5d, 0x1a, "hardware impending failure seek time performance",
8610Sstevel@tonic-gate 0x5d, 0x1b, "hardware impending failure spin-up retry count",
8620Sstevel@tonic-gate 0x5d, 0x1c, "hardware impending failure drive calibration retry count",
8630Sstevel@tonic-gate 0x5d, 0x20, "controller impending failure general hard drive failure",
8640Sstevel@tonic-gate 0x5d, 0x21, "controller impending failure drive error rate too high",
8650Sstevel@tonic-gate 0x5d, 0x22, "controller impending failure data error rate too high",
8660Sstevel@tonic-gate 0x5d, 0x23, "controller impending failure seek error rate too high",
8670Sstevel@tonic-gate 0x5d, 0x24, "controller impending failure too many block reassigns",
8680Sstevel@tonic-gate 0x5d, 0x25, "controller impending failure access times too high",
8690Sstevel@tonic-gate 0x5d, 0x26, "controller impending failure start unit times too high",
8700Sstevel@tonic-gate 0x5d, 0x27, "controller impending failure channel parametrics",
8710Sstevel@tonic-gate 0x5d, 0x28, "controller impending failure controller detected",
8720Sstevel@tonic-gate 0x5d, 0x29, "controller impending failure throughput performance",
8730Sstevel@tonic-gate 0x5d, 0x2a, "controller impending failure seek time performance",
8740Sstevel@tonic-gate 0x5d, 0x2b, "controller impending failure spin-up retry count",
8750Sstevel@tonic-gate 0x5d, 0x2c, "controller impending failure drive calibration retry cnt",
8760Sstevel@tonic-gate 0x5d, 0x30, "data channel impending failure general hard drive failure",
8770Sstevel@tonic-gate 0x5d, 0x31, "data channel impending failure drive error rate too high",
8780Sstevel@tonic-gate 0x5d, 0x32, "data channel impending failure data error rate too high",
8790Sstevel@tonic-gate 0x5d, 0x33, "data channel impending failure seek error rate too high",
8800Sstevel@tonic-gate 0x5d, 0x34, "data channel impending failure too many block reassigns",
8810Sstevel@tonic-gate 0x5d, 0x35, "data channel impending failure access times too high",
8820Sstevel@tonic-gate 0x5d, 0x36, "data channel impending failure start unit times too high",
8830Sstevel@tonic-gate 0x5d, 0x37, "data channel impending failure channel parametrics",
8840Sstevel@tonic-gate 0x5d, 0x38, "data channel impending failure controller detected",
8850Sstevel@tonic-gate 0x5d, 0x39, "data channel impending failure throughput performance",
8860Sstevel@tonic-gate 0x5d, 0x3a, "data channel impending failure seek time performance",
8870Sstevel@tonic-gate 0x5d, 0x3b, "data channel impending failure spin-up retry count",
8880Sstevel@tonic-gate 0x5d, 0x3c, "data channel impending failure drive calibrate retry cnt",
8890Sstevel@tonic-gate 0x5d, 0x40, "servo impending failure general hard drive failure",
8900Sstevel@tonic-gate 0x5d, 0x41, "servo impending failure drive error rate too high",
8910Sstevel@tonic-gate 0x5d, 0x42, "servo impending failure data error rate too high",
8920Sstevel@tonic-gate 0x5d, 0x43, "servo impending failure seek error rate too high",
8930Sstevel@tonic-gate 0x5d, 0x44, "servo impending failure too many block reassigns",
8940Sstevel@tonic-gate 0x5d, 0x45, "servo impending failure access times too high",
8950Sstevel@tonic-gate 0x5d, 0x46, "servo impending failure start unit times too high",
8960Sstevel@tonic-gate 0x5d, 0x47, "servo impending failure channel parametrics",
8970Sstevel@tonic-gate 0x5d, 0x48, "servo impending failure controller detected",
8980Sstevel@tonic-gate 0x5d, 0x49, "servo impending failure throughput performance",
8990Sstevel@tonic-gate 0x5d, 0x4a, "servo impending failure seek time performance",
9000Sstevel@tonic-gate 0x5d, 0x4b, "servo impending failure spin-up retry count",
9010Sstevel@tonic-gate 0x5d, 0x4c, "servo impending failure drive calibration retry count",
9020Sstevel@tonic-gate 0x5d, 0x50, "spindle impending failure general hard drive failure",
9030Sstevel@tonic-gate 0x5d, 0x51, "spindle impending failure drive error rate too high",
9040Sstevel@tonic-gate 0x5d, 0x52, "spindle impending failure data error rate too high",
9050Sstevel@tonic-gate 0x5d, 0x53, "spindle impending failure seek error rate too high",
9060Sstevel@tonic-gate 0x5d, 0x54, "spindle impending failure too many block reassigns",
9070Sstevel@tonic-gate 0x5d, 0x55, "spindle impending failure access times too high",
9080Sstevel@tonic-gate 0x5d, 0x56, "spindle impending failure start unit times too high",
9090Sstevel@tonic-gate 0x5d, 0x57, "spindle impending failure channel parametrics",
9100Sstevel@tonic-gate 0x5d, 0x58, "spindle impending failure controller detected",
9110Sstevel@tonic-gate 0x5d, 0x59, "spindle impending failure throughput performance",
9120Sstevel@tonic-gate 0x5d, 0x5a, "spindle impending failure seek time performance",
9130Sstevel@tonic-gate 0x5d, 0x5b, "spindle impending failure spin-up retry count",
9140Sstevel@tonic-gate 0x5d, 0x5c, "spindle impending failure drive calibration retry count",
9150Sstevel@tonic-gate 0x5d, 0x60, "firmware impending failure general hard drive failure",
9160Sstevel@tonic-gate 0x5d, 0x61, "firmware impending failure drive error rate too high",
9170Sstevel@tonic-gate 0x5d, 0x62, "firmware impending failure data error rate too high",
9180Sstevel@tonic-gate 0x5d, 0x63, "firmware impending failure seek error rate too high",
9190Sstevel@tonic-gate 0x5d, 0x64, "firmware impending failure too many block reassigns",
9200Sstevel@tonic-gate 0x5d, 0x65, "firmware impending failure access times too high",
9210Sstevel@tonic-gate 0x5d, 0x66, "firmware impending failure start unit times too high",
9220Sstevel@tonic-gate 0x5d, 0x67, "firmware impending failure channel parametrics",
9230Sstevel@tonic-gate 0x5d, 0x68, "firmware impending failure controller detected",
9240Sstevel@tonic-gate 0x5d, 0x69, "firmware impending failure throughput performance",
9250Sstevel@tonic-gate 0x5d, 0x6a, "firmware impending failure seek time performance",
9260Sstevel@tonic-gate 0x5d, 0x6b, "firmware impending failure spin-up retry count",
9270Sstevel@tonic-gate 0x5d, 0x6c, "firmware impending failure drive calibration retry count",
9280Sstevel@tonic-gate 0x5d, 0xff, "failure prediction threshold exceeded (false)",
9290Sstevel@tonic-gate 0x5e, 0x00, "low power condition active",
9300Sstevel@tonic-gate 0x5e, 0x01, "idle condition activated by timer",
9310Sstevel@tonic-gate 0x5e, 0x02, "standby condition activated by timer",
9320Sstevel@tonic-gate 0x5e, 0x03, "idle condition activated by command",
9330Sstevel@tonic-gate 0x5e, 0x04, "standby condition activated by command",
9340Sstevel@tonic-gate 0x60, 0x00, "lamp failure",
9358017SChris.Horne@Sun.COM 0x61, 0x00, "video acquisition error",
9360Sstevel@tonic-gate 0x62, 0x00, "scan head positioning error",
9370Sstevel@tonic-gate 0x63, 0x00, "end of user area encountered on this track",
9380Sstevel@tonic-gate 0x63, 0x01, "packet does not fit in available space",
9390Sstevel@tonic-gate 0x64, 0x00, "illegal mode for this track",
9400Sstevel@tonic-gate 0x64, 0x01, "invalid packet size",
9410Sstevel@tonic-gate 0x65, 0x00, "voltage fault",
9420Sstevel@tonic-gate 0x66, 0x00, "automatic document feeder cover up",
9430Sstevel@tonic-gate 0x67, 0x00, "configuration failure",
9440Sstevel@tonic-gate 0x67, 0x01, "configuration of incapable LUNs failed",
9450Sstevel@tonic-gate 0x67, 0x02, "add LUN failed",
9460Sstevel@tonic-gate 0x67, 0x03, "modification of LUN failed",
9470Sstevel@tonic-gate 0x67, 0x04, "exchange of LUN failed",
9480Sstevel@tonic-gate 0x67, 0x05, "remove of LUN failed",
9490Sstevel@tonic-gate 0x67, 0x06, "attachment of LUN failed",
9500Sstevel@tonic-gate 0x67, 0x07, "creation of LUN failed",
9510Sstevel@tonic-gate 0x67, 0x08, "assign failure occurred",
9520Sstevel@tonic-gate 0x67, 0x09, "multiply assigned LUN",
9530Sstevel@tonic-gate 0x67, 0x0a, "set target port groups command failed",
9540Sstevel@tonic-gate 0x68, 0x00, "logical unit not configured",
9550Sstevel@tonic-gate 0x69, 0x00, "data loss on logical unit",
9560Sstevel@tonic-gate 0x69, 0x01, "multiple LUN failures",
9570Sstevel@tonic-gate 0x69, 0x02, "parity/data mismatch",
9580Sstevel@tonic-gate 0x6a, 0x00, "informational, refer to log",
9598017SChris.Horne@Sun.COM 0x6b, 0x00, "state change has occurred",
9600Sstevel@tonic-gate 0x6b, 0x01, "redundancy level got better",
9610Sstevel@tonic-gate 0x6b, 0x02, "redundancy level got worse",
9628017SChris.Horne@Sun.COM 0x6c, 0x00, "rebuild failure occurred",
9638017SChris.Horne@Sun.COM 0x6d, 0x00, "recalculate failure occurred",
9640Sstevel@tonic-gate 0x6e, 0x00, "command to logical unit failed",
9650Sstevel@tonic-gate 0x6f, 0x00, "copy protect key exchange failure authentication failure",
9660Sstevel@tonic-gate 0x6f, 0x01, "copy protect key exchange failure key not present",
9670Sstevel@tonic-gate 0x6f, 0x02, "copy protect key exchange failure key not established",
9680Sstevel@tonic-gate 0x6f, 0x03, "read of scrambled sector without authentication",
9690Sstevel@tonic-gate 0x6f, 0x04, "media region code is mismatched to LUN region",
9700Sstevel@tonic-gate 0x6f, 0x05, "drive region must be permanent/region reset count error",
9710Sstevel@tonic-gate 0x70, 0xffff, "decompression exception short algorithm id of ASCQ",
9720Sstevel@tonic-gate 0x71, 0x00, "decompression exception long algorithm id",
9730Sstevel@tonic-gate 0x72, 0x00, "session fixation error",
9740Sstevel@tonic-gate 0x72, 0x01, "session fixation error writing lead-in",
9750Sstevel@tonic-gate 0x72, 0x02, "session fixation error writing lead-out",
9760Sstevel@tonic-gate 0x72, 0x03, "session fixation error - incomplete track in session",
9770Sstevel@tonic-gate 0x72, 0x04, "empty or partially written reserved track",
9780Sstevel@tonic-gate 0x72, 0x05, "no more track reservations allowed",
9790Sstevel@tonic-gate 0x73, 0x00, "cd control error",
9800Sstevel@tonic-gate 0x73, 0x01, "power calibration area almost full",
9810Sstevel@tonic-gate 0x73, 0x02, "power calibration area is full",
9820Sstevel@tonic-gate 0x73, 0x03, "power calibration area error",
9830Sstevel@tonic-gate 0x73, 0x04, "program memory area update failure",
9840Sstevel@tonic-gate 0x73, 0x05, "program memory area is full",
9850Sstevel@tonic-gate 0x73, 0x06, "rma/pma is almost full",
9860Sstevel@tonic-gate 0xffff, 0xffff, NULL
9870Sstevel@tonic-gate };
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate char *
scsi_esname(uint_t key,char * tmpstr)9900Sstevel@tonic-gate scsi_esname(uint_t key, char *tmpstr)
9910Sstevel@tonic-gate {
9920Sstevel@tonic-gate int i = 0;
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate while (extended_sense_list[i].asc != 0xffff) {
9950Sstevel@tonic-gate if (key == extended_sense_list[i].asc) {
9960Sstevel@tonic-gate return ((char *)extended_sense_list[i].message);
9970Sstevel@tonic-gate }
9980Sstevel@tonic-gate i++;
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate return (sprintf(tmpstr, "<vendor unique code 0x%x>", key));
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate char *
scsi_asc_name(uint_t asc,uint_t ascq,char * tmpstr)10040Sstevel@tonic-gate scsi_asc_name(uint_t asc, uint_t ascq, char *tmpstr)
10050Sstevel@tonic-gate {
10060Sstevel@tonic-gate int i = 0;
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate while (extended_sense_list[i].asc != 0xffff) {
10090Sstevel@tonic-gate if ((asc == extended_sense_list[i].asc) &&
10100Sstevel@tonic-gate ((ascq == extended_sense_list[i].ascq) ||
10110Sstevel@tonic-gate (extended_sense_list[i].ascq == 0xffff))) {
10120Sstevel@tonic-gate return ((char *)extended_sense_list[i].message);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate i++;
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate char *
scsi_sname(uchar_t sense_key)10200Sstevel@tonic-gate scsi_sname(uchar_t sense_key)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate if (sense_key >= (uchar_t)(NUM_SENSE_KEYS+NUM_IMPL_SENSE_KEYS)) {
10230Sstevel@tonic-gate return ("<unknown sense key>");
10240Sstevel@tonic-gate } else {
10250Sstevel@tonic-gate return (sense_keys[sense_key]);
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate /*
10310Sstevel@tonic-gate * Print a piece of inquiry data- cleaned up for non-printable characters.
10320Sstevel@tonic-gate */
10330Sstevel@tonic-gate static void
inq_fill(char * p,int l,char * s)10340Sstevel@tonic-gate inq_fill(char *p, int l, char *s)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate register unsigned i = 0;
10370Sstevel@tonic-gate char c;
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate if (!p)
10400Sstevel@tonic-gate return;
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate while (i++ < l) {
10430Sstevel@tonic-gate /* clean string of non-printing chars */
10440Sstevel@tonic-gate if ((c = *p++) < ' ' || c >= 0177) {
10450Sstevel@tonic-gate c = ' ';
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate *s++ = c;
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate *s++ = 0;
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate static char *
scsi_asc_search(uint_t asc,uint_t ascq,struct scsi_asq_key_strings * list)10530Sstevel@tonic-gate scsi_asc_search(uint_t asc, uint_t ascq,
10540Sstevel@tonic-gate struct scsi_asq_key_strings *list)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate int i = 0;
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate while (list[i].asc != 0xffff) {
10590Sstevel@tonic-gate if ((asc == list[i].asc) &&
10600Sstevel@tonic-gate ((ascq == list[i].ascq) ||
10610Sstevel@tonic-gate (list[i].ascq == 0xffff))) {
10620Sstevel@tonic-gate return ((char *)list[i].message);
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate i++;
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate return (NULL);
10670Sstevel@tonic-gate }
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate static char *
scsi_asc_ascq_name(uint_t asc,uint_t ascq,char * tmpstr,struct scsi_asq_key_strings * list)10700Sstevel@tonic-gate scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr,
10710Sstevel@tonic-gate struct scsi_asq_key_strings *list)
10720Sstevel@tonic-gate {
10730Sstevel@tonic-gate char *message;
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate if (list) {
10760Sstevel@tonic-gate if (message = scsi_asc_search(asc, ascq, list)) {
10770Sstevel@tonic-gate return (message);
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate if (message = scsi_asc_search(asc, ascq, extended_sense_list)) {
10810Sstevel@tonic-gate return (message);
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
10850Sstevel@tonic-gate }
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate /*
10880Sstevel@tonic-gate * The first part/column of the error message will be at least this length.
10890Sstevel@tonic-gate * This number has been calculated so that each line fits in 80 chars.
10900Sstevel@tonic-gate */
10910Sstevel@tonic-gate #define SCSI_ERRMSG_COLUMN_LEN 42
10920Sstevel@tonic-gate #define SCSI_ERRMSG_BUF_LEN 256
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate void
scsi_generic_errmsg(struct scsi_device * devp,char * label,int severity,daddr_t blkno,daddr_t err_blkno,uchar_t cmd_name,struct scsi_key_strings * cmdlist,uint8_t * sensep,struct scsi_asq_key_strings * asc_list,char * (* decode_fru)(struct scsi_device *,char *,int,uchar_t))10957570SDavid.Zhang@Sun.COM scsi_generic_errmsg(struct scsi_device *devp, char *label, int severity,
10967570SDavid.Zhang@Sun.COM daddr_t blkno, daddr_t err_blkno,
10977570SDavid.Zhang@Sun.COM uchar_t cmd_name, struct scsi_key_strings *cmdlist,
10987570SDavid.Zhang@Sun.COM uint8_t *sensep, struct scsi_asq_key_strings *asc_list,
10990Sstevel@tonic-gate char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
11000Sstevel@tonic-gate {
11010Sstevel@tonic-gate uchar_t com;
11020Sstevel@tonic-gate static char buf[SCSI_ERRMSG_BUF_LEN];
11030Sstevel@tonic-gate static char buf1[SCSI_ERRMSG_BUF_LEN];
11040Sstevel@tonic-gate static char tmpbuf[64];
11050Sstevel@tonic-gate static char pad[SCSI_ERRMSG_COLUMN_LEN];
11060Sstevel@tonic-gate dev_info_t *dev = devp->sd_dev;
11070Sstevel@tonic-gate static char *error_classes[] = {
11080Sstevel@tonic-gate "All", "Unknown", "Informational",
11090Sstevel@tonic-gate "Recovered", "Retryable", "Fatal"
11100Sstevel@tonic-gate };
11112148Spd144616 uchar_t sense_key, asc, ascq, fru_code;
11122148Spd144616 uchar_t *fru_code_ptr;
11130Sstevel@tonic-gate int i, buflen;
11140Sstevel@tonic-gate
11150Sstevel@tonic-gate mutex_enter(&scsi_log_mutex);
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate /*
11180Sstevel@tonic-gate * We need to put our space padding code because kernel version
11190Sstevel@tonic-gate * of sprintf(9F) doesn't support %-<number>s type of left alignment.
11200Sstevel@tonic-gate */
11210Sstevel@tonic-gate for (i = 0; i < SCSI_ERRMSG_COLUMN_LEN; i++) {
11220Sstevel@tonic-gate pad[i] = ' ';
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate
11258017SChris.Horne@Sun.COM bzero(buf, SCSI_ERRMSG_BUF_LEN);
11267570SDavid.Zhang@Sun.COM com = cmd_name;
11270Sstevel@tonic-gate (void) sprintf(buf, "Error for Command: %s",
11280Sstevel@tonic-gate scsi_cmd_name(com, cmdlist, tmpbuf));
11290Sstevel@tonic-gate buflen = strlen(buf);
11300Sstevel@tonic-gate if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11310Sstevel@tonic-gate pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
11320Sstevel@tonic-gate (void) sprintf(&buf[buflen], "%s Error Level: %s",
11330Sstevel@tonic-gate pad, error_classes[severity]);
11340Sstevel@tonic-gate pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
11350Sstevel@tonic-gate } else {
11360Sstevel@tonic-gate (void) sprintf(&buf[buflen], " Error Level: %s",
11370Sstevel@tonic-gate error_classes[severity]);
11380Sstevel@tonic-gate }
11390Sstevel@tonic-gate impl_scsi_log(dev, label, CE_WARN, buf);
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate if (blkno != -1 || err_blkno != -1 &&
11420Sstevel@tonic-gate ((com & 0xf) == SCMD_READ) || ((com & 0xf) == SCMD_WRITE)) {
11438017SChris.Horne@Sun.COM bzero(buf, SCSI_ERRMSG_BUF_LEN);
11440Sstevel@tonic-gate (void) sprintf(buf, "Requested Block: %ld", blkno);
11450Sstevel@tonic-gate buflen = strlen(buf);
11460Sstevel@tonic-gate if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11470Sstevel@tonic-gate pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
11480Sstevel@tonic-gate (void) sprintf(&buf[buflen], "%s Error Block: %ld\n",
11490Sstevel@tonic-gate pad, err_blkno);
11500Sstevel@tonic-gate pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
11510Sstevel@tonic-gate } else {
11520Sstevel@tonic-gate (void) sprintf(&buf[buflen], " Error Block: %ld\n",
11530Sstevel@tonic-gate err_blkno);
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate impl_scsi_log(dev, label, CE_CONT, buf);
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate
11588017SChris.Horne@Sun.COM bzero(buf, SCSI_ERRMSG_BUF_LEN);
11590Sstevel@tonic-gate (void) strcpy(buf, "Vendor: ");
11600Sstevel@tonic-gate inq_fill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]);
11610Sstevel@tonic-gate buflen = strlen(buf);
11620Sstevel@tonic-gate if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11630Sstevel@tonic-gate pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
11640Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], "%s Serial Number: ", pad);
11650Sstevel@tonic-gate pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
11660Sstevel@tonic-gate } else {
11670Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], " Serial Number: ");
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate inq_fill(devp->sd_inq->inq_serial, 12, &buf[strlen(buf)]);
11700Sstevel@tonic-gate impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
11710Sstevel@tonic-gate
11720Sstevel@tonic-gate if (sensep) {
11737570SDavid.Zhang@Sun.COM sense_key = scsi_sense_key(sensep);
11747570SDavid.Zhang@Sun.COM asc = scsi_sense_asc(sensep);
11757570SDavid.Zhang@Sun.COM ascq = scsi_sense_ascq(sensep);
11767570SDavid.Zhang@Sun.COM scsi_ext_sense_fields(sensep, SENSE_LENGTH,
11772148Spd144616 NULL, NULL, &fru_code_ptr, NULL, NULL);
11782148Spd144616 fru_code = (fru_code_ptr ? *fru_code_ptr : 0);
11792148Spd144616
11808017SChris.Horne@Sun.COM bzero(buf, SCSI_ERRMSG_BUF_LEN);
11810Sstevel@tonic-gate (void) sprintf(buf, "Sense Key: %s\n",
11822148Spd144616 sense_keys[sense_key]);
11830Sstevel@tonic-gate impl_scsi_log(dev, label, CE_CONT, buf);
11840Sstevel@tonic-gate
11858017SChris.Horne@Sun.COM bzero(buf, SCSI_ERRMSG_BUF_LEN);
11862148Spd144616 if ((fru_code != 0) &&
11870Sstevel@tonic-gate (decode_fru != NULL)) {
11880Sstevel@tonic-gate (*decode_fru)(devp, buf, SCSI_ERRMSG_BUF_LEN,
11892148Spd144616 fru_code);
11900Sstevel@tonic-gate if (buf[0] != NULL) {
11918017SChris.Horne@Sun.COM bzero(buf1, SCSI_ERRMSG_BUF_LEN);
11920Sstevel@tonic-gate (void) sprintf(&buf1[strlen(buf1)],
11932148Spd144616 "ASC: 0x%x (%s)", asc,
11942148Spd144616 scsi_asc_ascq_name(asc, ascq,
11954851Scth tmpbuf, asc_list));
11960Sstevel@tonic-gate buflen = strlen(buf1);
11970Sstevel@tonic-gate if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11984851Scth pad[SCSI_ERRMSG_COLUMN_LEN - buflen] =
11994851Scth '\0';
12004851Scth (void) sprintf(&buf1[buflen],
12014851Scth "%s ASCQ: 0x%x", pad, ascq);
12020Sstevel@tonic-gate } else {
12034851Scth (void) sprintf(&buf1[buflen],
12044851Scth " ASCQ: 0x%x", ascq);
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate impl_scsi_log(dev,
12074851Scth label, CE_CONT, "%s\n", buf1);
12084851Scth impl_scsi_log(dev,
12094851Scth label, CE_CONT, "FRU: 0x%x (%s)\n",
12104851Scth fru_code, buf);
12110Sstevel@tonic-gate mutex_exit(&scsi_log_mutex);
12120Sstevel@tonic-gate return;
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)],
12160Sstevel@tonic-gate "ASC: 0x%x (%s), ASCQ: 0x%x, FRU: 0x%x",
12172148Spd144616 asc, scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list),
12182148Spd144616 ascq, fru_code);
12190Sstevel@tonic-gate impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate mutex_exit(&scsi_log_mutex);
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate
12240Sstevel@tonic-gate void
scsi_vu_errmsg(struct scsi_device * devp,struct scsi_pkt * pkt,char * label,int severity,daddr_t blkno,daddr_t err_blkno,struct scsi_key_strings * cmdlist,struct scsi_extended_sense * sensep,struct scsi_asq_key_strings * asc_list,char * (* decode_fru)(struct scsi_device *,char *,int,uchar_t))12257570SDavid.Zhang@Sun.COM scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
12267570SDavid.Zhang@Sun.COM int severity, daddr_t blkno, daddr_t err_blkno,
12277570SDavid.Zhang@Sun.COM struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep,
12287570SDavid.Zhang@Sun.COM struct scsi_asq_key_strings *asc_list,
12297570SDavid.Zhang@Sun.COM char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
12307570SDavid.Zhang@Sun.COM {
12317570SDavid.Zhang@Sun.COM uchar_t com;
12327570SDavid.Zhang@Sun.COM
12337570SDavid.Zhang@Sun.COM com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd;
12347570SDavid.Zhang@Sun.COM
12357570SDavid.Zhang@Sun.COM scsi_generic_errmsg(devp, label, severity, blkno, err_blkno,
12367570SDavid.Zhang@Sun.COM com, cmdlist, (uint8_t *)sensep, asc_list, decode_fru);
12377570SDavid.Zhang@Sun.COM
12387570SDavid.Zhang@Sun.COM
12397570SDavid.Zhang@Sun.COM }
12407570SDavid.Zhang@Sun.COM
12417570SDavid.Zhang@Sun.COM void
scsi_errmsg(struct scsi_device * devp,struct scsi_pkt * pkt,char * label,int severity,daddr_t blkno,daddr_t err_blkno,struct scsi_key_strings * cmdlist,struct scsi_extended_sense * sensep)12420Sstevel@tonic-gate scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
12430Sstevel@tonic-gate int severity, daddr_t blkno, daddr_t err_blkno,
12440Sstevel@tonic-gate struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep)
12450Sstevel@tonic-gate {
12460Sstevel@tonic-gate scsi_vu_errmsg(devp, pkt, label, severity, blkno,
12474851Scth err_blkno, cmdlist, sensep, NULL, NULL);
12480Sstevel@tonic-gate }
12490Sstevel@tonic-gate
12500Sstevel@tonic-gate /*PRINTFLIKE4*/
12510Sstevel@tonic-gate void
scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)12520Sstevel@tonic-gate scsi_log(dev_info_t *dev, char *label, uint_t level,
12530Sstevel@tonic-gate const char *fmt, ...)
12540Sstevel@tonic-gate {
12550Sstevel@tonic-gate va_list ap;
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate va_start(ap, fmt);
12580Sstevel@tonic-gate mutex_enter(&scsi_log_mutex);
12590Sstevel@tonic-gate v_scsi_log(dev, label, level, fmt, ap);
12600Sstevel@tonic-gate mutex_exit(&scsi_log_mutex);
12610Sstevel@tonic-gate va_end(ap);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate /*PRINTFLIKE4*/
12650Sstevel@tonic-gate static void
impl_scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)12660Sstevel@tonic-gate impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
12670Sstevel@tonic-gate const char *fmt, ...)
12680Sstevel@tonic-gate {
12690Sstevel@tonic-gate va_list ap;
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate ASSERT(mutex_owned(&scsi_log_mutex));
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate va_start(ap, fmt);
12740Sstevel@tonic-gate v_scsi_log(dev, label, level, fmt, ap);
12750Sstevel@tonic-gate va_end(ap);
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate char *ddi_pathname(dev_info_t *dip, char *path);
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate /*PRINTFLIKE4*/
12820Sstevel@tonic-gate static void
v_scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,va_list ap)12830Sstevel@tonic-gate v_scsi_log(dev_info_t *dev, char *label, uint_t level,
12840Sstevel@tonic-gate const char *fmt, va_list ap)
12850Sstevel@tonic-gate {
12860Sstevel@tonic-gate static char name[256];
12870Sstevel@tonic-gate int log_only = 0;
12880Sstevel@tonic-gate int boot_only = 0;
12890Sstevel@tonic-gate int console_only = 0;
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate ASSERT(mutex_owned(&scsi_log_mutex));
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate if (dev) {
12940Sstevel@tonic-gate if (level == CE_PANIC || level == CE_WARN ||
12950Sstevel@tonic-gate level == CE_NOTE) {
12960Sstevel@tonic-gate (void) sprintf(name, "%s (%s%d):\n",
12974851Scth ddi_pathname(dev, scsi_log_buffer),
12984851Scth label, ddi_get_instance(dev));
12990Sstevel@tonic-gate } else if (level >= (uint_t)SCSI_DEBUG) {
13000Sstevel@tonic-gate (void) sprintf(name,
13010Sstevel@tonic-gate "%s%d:", label, ddi_get_instance(dev));
13020Sstevel@tonic-gate } else {
13030Sstevel@tonic-gate name[0] = '\0';
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate } else {
13060Sstevel@tonic-gate (void) sprintf(name, "%s:", label);
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate (void) vsprintf(scsi_log_buffer, fmt, ap);
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate switch (scsi_log_buffer[0]) {
13120Sstevel@tonic-gate case '!':
13130Sstevel@tonic-gate log_only = 1;
13140Sstevel@tonic-gate break;
13150Sstevel@tonic-gate case '?':
13160Sstevel@tonic-gate boot_only = 1;
13170Sstevel@tonic-gate break;
13180Sstevel@tonic-gate case '^':
13190Sstevel@tonic-gate console_only = 1;
13200Sstevel@tonic-gate break;
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate switch (level) {
13240Sstevel@tonic-gate case CE_NOTE:
13250Sstevel@tonic-gate level = CE_CONT;
13260Sstevel@tonic-gate /* FALLTHROUGH */
13270Sstevel@tonic-gate case CE_CONT:
13280Sstevel@tonic-gate case CE_WARN:
13290Sstevel@tonic-gate case CE_PANIC:
13300Sstevel@tonic-gate if (boot_only) {
13314851Scth cmn_err(level, "?%s\t%s", name, &scsi_log_buffer[1]);
13320Sstevel@tonic-gate } else if (console_only) {
13334851Scth cmn_err(level, "^%s\t%s", name, &scsi_log_buffer[1]);
13340Sstevel@tonic-gate } else if (log_only) {
13354851Scth cmn_err(level, "!%s\t%s", name, &scsi_log_buffer[1]);
13360Sstevel@tonic-gate } else {
13374851Scth cmn_err(level, "%s\t%s", name, scsi_log_buffer);
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate break;
13400Sstevel@tonic-gate case (uint_t)SCSI_DEBUG:
13410Sstevel@tonic-gate default:
13424851Scth cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, scsi_log_buffer);
13430Sstevel@tonic-gate break;
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate
13474851Scth /*
13484851Scth * Lookup the 'prop_name' string array property and walk thru its list of
13494851Scth * tuple values looking for a tuple who's VID/PID string (first part of tuple)
13504851Scth * matches the inquiry VID/PID information for the scsi_device. On a match,
13514851Scth * return a duplicate of the second part of the tuple. If no match is found,
13524851Scth * return NULL. On non-NULL return, caller is responsible for freeing return
13534851Scth * result via:
13544851Scth * kmem_free(string, strlen(string) + 1);
13554851Scth *
13564851Scth * This interface can either be used directly, or indirectly by
13574851Scth * scsi_get_device_type_scsi_options.
13584851Scth */
13594851Scth char *
scsi_get_device_type_string(char * prop_name,dev_info_t * dip,struct scsi_device * devp)13604851Scth scsi_get_device_type_string(char *prop_name,
13614851Scth dev_info_t *dip, struct scsi_device *devp)
13620Sstevel@tonic-gate {
13634851Scth struct scsi_inquiry *inq = devp->sd_inq;
13644851Scth char **tuples;
13654851Scth uint_t ntuples;
13664851Scth int i;
13674851Scth char *tvp; /* tuple vid/pid */
13684851Scth char *trs; /* tuple return string */
13694851Scth int tvp_len;
13700Sstevel@tonic-gate
13714851Scth /* if we have no inquiry data then we can't do this */
13724851Scth if (inq == NULL)
13734851Scth return (NULL);
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate /*
13764851Scth * So that we can establish a 'prop_name' for all instances of a
13774851Scth * device in the system in a single place if needed (via options.conf),
13784851Scth * we loop going up to the root ourself. This way root lookup does
13794851Scth * *not* specify DDI_PROP_DONTPASS, and the code will look on the
13804851Scth * options node.
13810Sstevel@tonic-gate */
13824851Scth do {
13834851Scth if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
13844851Scth (ddi_get_parent(dip) ? DDI_PROP_DONTPASS : 0) |
13854851Scth DDI_PROP_NOTPROM, prop_name, &tuples, &ntuples) ==
13864851Scth DDI_PROP_SUCCESS) {
13874851Scth
13884851Scth /* loop over tuples */
13894851Scth for (i = 0; i < (ntuples/2); i++) {
13904851Scth /* split into vid/pid and return-string */
13914851Scth tvp = tuples[i * 2];
13924851Scth trs = tuples[(i * 2) + 1];
13934851Scth tvp_len = strlen(tvp);
13940Sstevel@tonic-gate
13954851Scth /* check for vid/pid match */
13964851Scth if ((tvp_len == 0) ||
13974851Scth bcmp(tvp, inq->inq_vid, tvp_len))
13984851Scth continue; /* no match */
13994851Scth
14004851Scth /* match, dup return-string */
14014851Scth trs = i_ddi_strdup(trs, KM_SLEEP);
14024851Scth ddi_prop_free(tuples);
14034851Scth return (trs);
14044851Scth }
14054851Scth ddi_prop_free(tuples);
14064851Scth }
14070Sstevel@tonic-gate
14084851Scth /* climb up to root one step at a time */
14094851Scth dip = ddi_get_parent(dip);
14104851Scth } while (dip);
14114851Scth
14124851Scth return (NULL);
14134851Scth }
14140Sstevel@tonic-gate
14154851Scth /*
14164851Scth * The 'device-type-scsi-options' mechanism can be used to establish a device
14174851Scth * specific scsi_options value for a particular device. This mechanism uses
14184851Scth * paired strings ("vendor_info", "options_property_name") from the string
14194851Scth * array "device-type-scsi-options" definition. A bcmp of the vendor info is
14204851Scth * done against the inquiry data (inq_vid). Here is an example of use:
14214851Scth *
14224851Scth * device-type-scsi-options-list =
14234851Scth * "FOOLCO Special x1000", "foolco-scsi-options",
14244851Scth * "FOOLCO Special y1000", "foolco-scsi-options";
14254851Scth * foolco-scsi-options = 0xXXXXXXXX;
14264851Scth */
14274851Scth int
scsi_get_device_type_scsi_options(dev_info_t * dip,struct scsi_device * devp,int options)14284851Scth scsi_get_device_type_scsi_options(dev_info_t *dip,
14294851Scth struct scsi_device *devp, int options)
14304851Scth {
14314851Scth char *string;
14324851Scth
14334851Scth if ((string = scsi_get_device_type_string(
14344851Scth "device-type-scsi-options-list", dip, devp)) != NULL) {
14354851Scth options = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
14364851Scth string, options);
14374851Scth kmem_free(string, strlen(string) + 1);
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate return (options);
14400Sstevel@tonic-gate }
14412148Spd144616
14422148Spd144616 /*
14438017SChris.Horne@Sun.COM * Find the scsi_options for a scsi_device. The precedence is:
14448017SChris.Horne@Sun.COM *
14458017SChris.Horne@Sun.COM * target<%d>-scsi-options highest
14468017SChris.Horne@Sun.COM * device-type-scsi-options
14478017SChris.Horne@Sun.COM * per bus scsi-options (parent)
14488017SChris.Horne@Sun.COM * global scsi-options
14498017SChris.Horne@Sun.COM * default_scsi_options argument lowest
14508017SChris.Horne@Sun.COM *
14518017SChris.Horne@Sun.COM * If the global is used then it has already been established
14528017SChris.Horne@Sun.COM * on the parent scsi_hba_attach_setup.
14538017SChris.Horne@Sun.COM */
14548017SChris.Horne@Sun.COM int
scsi_get_scsi_options(struct scsi_device * sd,int default_scsi_options)14558017SChris.Horne@Sun.COM scsi_get_scsi_options(struct scsi_device *sd, int default_scsi_options)
14568017SChris.Horne@Sun.COM {
14578017SChris.Horne@Sun.COM dev_info_t *parent;
14588017SChris.Horne@Sun.COM int options = -1;
14598017SChris.Horne@Sun.COM int tgt;
14608017SChris.Horne@Sun.COM char topt[32];
14618017SChris.Horne@Sun.COM
14628017SChris.Horne@Sun.COM if ((sd == NULL) || (sd->sd_dev == NULL))
14638017SChris.Horne@Sun.COM return (default_scsi_options);
14648017SChris.Horne@Sun.COM
14658017SChris.Horne@Sun.COM parent = ddi_get_parent(sd->sd_dev);
14668017SChris.Horne@Sun.COM
14678017SChris.Horne@Sun.COM if ((tgt = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev,
14688017SChris.Horne@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "target", -1)) != -1) {
14698017SChris.Horne@Sun.COM (void) sprintf(topt, "target%d-scsi-options", tgt);
14708017SChris.Horne@Sun.COM options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
14718017SChris.Horne@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, topt, -1);
14728017SChris.Horne@Sun.COM }
14738017SChris.Horne@Sun.COM
14748017SChris.Horne@Sun.COM if (options == -1)
14758017SChris.Horne@Sun.COM options = scsi_get_device_type_scsi_options(parent, sd, -1);
14768017SChris.Horne@Sun.COM
14778017SChris.Horne@Sun.COM if (options == -1)
14788017SChris.Horne@Sun.COM options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
14798017SChris.Horne@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "scsi-options", -1);
14808017SChris.Horne@Sun.COM
14818017SChris.Horne@Sun.COM if (options == -1)
14828017SChris.Horne@Sun.COM options = default_scsi_options;
14838017SChris.Horne@Sun.COM
14848017SChris.Horne@Sun.COM return (options);
14858017SChris.Horne@Sun.COM }
14868017SChris.Horne@Sun.COM
14878017SChris.Horne@Sun.COM /*
14888017SChris.Horne@Sun.COM * Use scsi-options to return the maximum number of LUNs.
14898017SChris.Horne@Sun.COM */
14908017SChris.Horne@Sun.COM int
scsi_get_scsi_maxluns(struct scsi_device * sd)14918017SChris.Horne@Sun.COM scsi_get_scsi_maxluns(struct scsi_device *sd)
14928017SChris.Horne@Sun.COM {
14938017SChris.Horne@Sun.COM int options;
14948017SChris.Horne@Sun.COM int maxluns;
14958017SChris.Horne@Sun.COM
14968017SChris.Horne@Sun.COM ASSERT(sd && sd->sd_inq);
14978017SChris.Horne@Sun.COM options = scsi_get_scsi_options(sd, SCSI_OPTIONS_NLUNS_DEFAULT);
14988017SChris.Horne@Sun.COM
14998017SChris.Horne@Sun.COM switch (SCSI_OPTIONS_NLUNS(options)) {
15008017SChris.Horne@Sun.COM default:
15018017SChris.Horne@Sun.COM case SCSI_OPTIONS_NLUNS_DEFAULT:
15028017SChris.Horne@Sun.COM /* based on scsi version of target */
15038017SChris.Horne@Sun.COM if (sd->sd_inq->inq_ansi < SCSI_VERSION_3)
15048017SChris.Horne@Sun.COM maxluns = SCSI_8LUN_PER_TARGET; /* 8 */
15058017SChris.Horne@Sun.COM else
15068017SChris.Horne@Sun.COM maxluns = SCSI_16LUNS_PER_TARGET; /* 16 */
15078017SChris.Horne@Sun.COM break;
15088017SChris.Horne@Sun.COM case SCSI_OPTIONS_NLUNS_1:
15098017SChris.Horne@Sun.COM maxluns = SCSI_1LUN_PER_TARGET; /* 1 */
15108017SChris.Horne@Sun.COM break;
15118017SChris.Horne@Sun.COM case SCSI_OPTIONS_NLUNS_8:
15128017SChris.Horne@Sun.COM maxluns = SCSI_8LUN_PER_TARGET; /* 8 */
15138017SChris.Horne@Sun.COM break;
15148017SChris.Horne@Sun.COM case SCSI_OPTIONS_NLUNS_16:
15158017SChris.Horne@Sun.COM maxluns = SCSI_16LUNS_PER_TARGET; /* 16 */
15168017SChris.Horne@Sun.COM break;
15178017SChris.Horne@Sun.COM case SCSI_OPTIONS_NLUNS_32:
15188017SChris.Horne@Sun.COM maxluns = SCSI_32LUNS_PER_TARGET; /* 32 */
15198017SChris.Horne@Sun.COM break;
15208017SChris.Horne@Sun.COM }
15218017SChris.Horne@Sun.COM
15228017SChris.Horne@Sun.COM /* For SCSI-1 we never support > 8 LUNs */
15238017SChris.Horne@Sun.COM if ((sd->sd_inq->inq_ansi <= SCSI_VERSION_1) &&
15248017SChris.Horne@Sun.COM (maxluns > SCSI_8LUN_PER_TARGET))
15258017SChris.Horne@Sun.COM maxluns = SCSI_8LUN_PER_TARGET;
15268017SChris.Horne@Sun.COM
15278017SChris.Horne@Sun.COM return (maxluns);
15288017SChris.Horne@Sun.COM }
15298017SChris.Horne@Sun.COM
15308017SChris.Horne@Sun.COM /*
15312148Spd144616 * Functions for format-neutral sense data functions
15322148Spd144616 */
15332148Spd144616 int
scsi_validate_sense(uint8_t * sense_buffer,int sense_buf_len,int * flags)15342148Spd144616 scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags)
15352148Spd144616 {
15362148Spd144616 int result;
15372148Spd144616 struct scsi_extended_sense *es =
15382148Spd144616 (struct scsi_extended_sense *)sense_buffer;
15392148Spd144616
15402148Spd144616 /*
15412148Spd144616 * Init flags if present
15422148Spd144616 */
15432148Spd144616 if (flags != NULL) {
15442148Spd144616 *flags = 0;
15452148Spd144616 }
15462148Spd144616
15472148Spd144616 /*
15482148Spd144616 * Check response code (Solaris breaks this into a 3-bit class
15492148Spd144616 * and 4-bit code field.
15502148Spd144616 */
15512148Spd144616 if ((es->es_class != CLASS_EXTENDED_SENSE) ||
15522148Spd144616 ((es->es_code != CODE_FMT_FIXED_CURRENT) &&
15534851Scth (es->es_code != CODE_FMT_FIXED_DEFERRED) &&
15544851Scth (es->es_code != CODE_FMT_DESCR_CURRENT) &&
15554851Scth (es->es_code != CODE_FMT_DESCR_DEFERRED))) {
15562148Spd144616 /*
15572148Spd144616 * Sense data (if there's actually anything here) is not
15582148Spd144616 * in a format we can handle).
15592148Spd144616 */
15602148Spd144616 return (SENSE_UNUSABLE);
15612148Spd144616 }
15622148Spd144616
15632148Spd144616 /*
15642148Spd144616 * Check if this is deferred sense
15652148Spd144616 */
15662148Spd144616 if ((flags != NULL) &&
15672148Spd144616 ((es->es_code == CODE_FMT_FIXED_DEFERRED) ||
15684851Scth (es->es_code == CODE_FMT_DESCR_DEFERRED))) {
15692148Spd144616 *flags |= SNS_BUF_DEFERRED;
15702148Spd144616 }
15712148Spd144616
15722148Spd144616 /*
15732148Spd144616 * Make sure length is OK
15742148Spd144616 */
15752148Spd144616 if (es->es_code == CODE_FMT_FIXED_CURRENT ||
15762148Spd144616 es->es_code == CODE_FMT_FIXED_DEFERRED) {
15772148Spd144616 /*
15782148Spd144616 * We can get by with a buffer that only includes the key,
15792148Spd144616 * asc, and ascq. In reality the minimum length we should
15802148Spd144616 * ever see is 18 bytes.
15812148Spd144616 */
15822148Spd144616 if ((sense_buf_len < MIN_FIXED_SENSE_LEN) ||
15832148Spd144616 ((es->es_add_len + ADDL_SENSE_ADJUST) <
15844851Scth MIN_FIXED_SENSE_LEN)) {
15852148Spd144616 result = SENSE_UNUSABLE;
15862148Spd144616 } else {
15872148Spd144616 /*
15882148Spd144616 * The es_add_len field contains the number of sense
15892148Spd144616 * data bytes that follow the es_add_len field.
15902148Spd144616 */
15912148Spd144616 if ((flags != NULL) &&
15922148Spd144616 (sense_buf_len <
15934851Scth (es->es_add_len + ADDL_SENSE_ADJUST))) {
15942148Spd144616 *flags |= SNS_BUF_OVERFLOW;
15952148Spd144616 }
15962148Spd144616
15972148Spd144616 result = SENSE_FIXED_FORMAT;
15982148Spd144616 }
15992148Spd144616 } else {
16002148Spd144616 struct scsi_descr_sense_hdr *ds =
16012148Spd144616 (struct scsi_descr_sense_hdr *)sense_buffer;
16022148Spd144616
16032148Spd144616 /*
16042148Spd144616 * For descriptor format we need at least the descriptor
16052148Spd144616 * header
16062148Spd144616 */
16072148Spd144616 if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) {
16082148Spd144616 result = SENSE_UNUSABLE;
16092148Spd144616 } else {
16102148Spd144616 /*
16112148Spd144616 * Check for overflow
16122148Spd144616 */
16132148Spd144616 if ((flags != NULL) &&
16142148Spd144616 (sense_buf_len <
16154851Scth (ds->ds_addl_sense_length + sizeof (*ds)))) {
16162148Spd144616 *flags |= SNS_BUF_OVERFLOW;
16172148Spd144616 }
16182148Spd144616
16192148Spd144616 result = SENSE_DESCR_FORMAT;
16202148Spd144616 }
16212148Spd144616 }
16222148Spd144616
16232148Spd144616 return (result);
16242148Spd144616 }
16252148Spd144616
16262148Spd144616
16272148Spd144616 uint8_t
scsi_sense_key(uint8_t * sense_buffer)16282148Spd144616 scsi_sense_key(uint8_t *sense_buffer)
16292148Spd144616 {
16302148Spd144616 uint8_t skey;
16312148Spd144616 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
16322148Spd144616 struct scsi_descr_sense_hdr *sdsp =
16332148Spd144616 (struct scsi_descr_sense_hdr *)sense_buffer;
16342148Spd144616 skey = sdsp->ds_key;
16352148Spd144616 } else {
16362148Spd144616 struct scsi_extended_sense *ext_sensep =
16372148Spd144616 (struct scsi_extended_sense *)sense_buffer;
16382148Spd144616 skey = ext_sensep->es_key;
16392148Spd144616 }
16402148Spd144616 return (skey);
16412148Spd144616 }
16422148Spd144616
16432148Spd144616 uint8_t
scsi_sense_asc(uint8_t * sense_buffer)16442148Spd144616 scsi_sense_asc(uint8_t *sense_buffer)
16452148Spd144616 {
16462148Spd144616 uint8_t asc;
16472148Spd144616 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
16482148Spd144616 struct scsi_descr_sense_hdr *sdsp =
16492148Spd144616 (struct scsi_descr_sense_hdr *)sense_buffer;
16502148Spd144616 asc = sdsp->ds_add_code;
16512148Spd144616 } else {
16522148Spd144616 struct scsi_extended_sense *ext_sensep =
16532148Spd144616 (struct scsi_extended_sense *)sense_buffer;
16542148Spd144616 asc = ext_sensep->es_add_code;
16552148Spd144616 }
16562148Spd144616 return (asc);
16572148Spd144616 }
16582148Spd144616
16592148Spd144616 uint8_t
scsi_sense_ascq(uint8_t * sense_buffer)16602148Spd144616 scsi_sense_ascq(uint8_t *sense_buffer)
16612148Spd144616 {
16622148Spd144616 uint8_t ascq;
16632148Spd144616 if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
16642148Spd144616 struct scsi_descr_sense_hdr *sdsp =
16652148Spd144616 (struct scsi_descr_sense_hdr *)sense_buffer;
16662148Spd144616 ascq = sdsp->ds_qual_code;
16672148Spd144616 } else {
16682148Spd144616 struct scsi_extended_sense *ext_sensep =
16692148Spd144616 (struct scsi_extended_sense *)sense_buffer;
16702148Spd144616 ascq = ext_sensep->es_qual_code;
16712148Spd144616 }
16722148Spd144616 return (ascq);
16732148Spd144616 }
16742148Spd144616
scsi_ext_sense_fields(uint8_t * sense_buffer,int sense_buf_len,uint8_t ** information,uint8_t ** cmd_spec_info,uint8_t ** fru_code,uint8_t ** sk_specific,uint8_t ** stream_flags)16752148Spd144616 void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len,
16762148Spd144616 uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code,
16772148Spd144616 uint8_t **sk_specific, uint8_t **stream_flags)
16782148Spd144616 {
16792148Spd144616 int sense_fmt;
16802148Spd144616
16812148Spd144616 /*
16822148Spd144616 * Sanity check sense data and determine the format
16832148Spd144616 */
16842148Spd144616 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
16852148Spd144616
16862148Spd144616 /*
16872148Spd144616 * Initialize any requested data to 0
16882148Spd144616 */
16892148Spd144616 if (information) {
16902148Spd144616 *information = NULL;
16912148Spd144616 }
16922148Spd144616 if (cmd_spec_info) {
16932148Spd144616 *cmd_spec_info = NULL;
16942148Spd144616 }
16952148Spd144616 if (fru_code) {
16962148Spd144616 *fru_code = NULL;
16972148Spd144616 }
16982148Spd144616 if (sk_specific) {
16992148Spd144616 *sk_specific = NULL;
17002148Spd144616 }
17012148Spd144616 if (stream_flags) {
17022148Spd144616 *stream_flags = NULL;
17032148Spd144616 }
17042148Spd144616
17052148Spd144616 if (sense_fmt == SENSE_DESCR_FORMAT) {
17062148Spd144616 struct scsi_descr_template *sdt = NULL;
17072148Spd144616
17082148Spd144616 while (scsi_get_next_descr(sense_buffer,
17092148Spd144616 sense_buf_len, &sdt) != -1) {
17102148Spd144616 switch (sdt->sdt_descr_type) {
17112148Spd144616 case DESCR_INFORMATION: {
17122148Spd144616 struct scsi_information_sense_descr *isd =
17132148Spd144616 (struct scsi_information_sense_descr *)
17142148Spd144616 sdt;
17152148Spd144616 if (information) {
17162148Spd144616 *information =
17172148Spd144616 &isd->isd_information[0];
17182148Spd144616 }
17192148Spd144616 break;
17202148Spd144616 }
17212148Spd144616 case DESCR_COMMAND_SPECIFIC: {
17222148Spd144616 struct scsi_cmd_specific_sense_descr *csd =
17232148Spd144616 (struct scsi_cmd_specific_sense_descr *)
17242148Spd144616 sdt;
17252148Spd144616 if (cmd_spec_info) {
17262148Spd144616 *cmd_spec_info =
17272148Spd144616 &csd->css_cmd_specific_info[0];
17282148Spd144616 }
17292148Spd144616 break;
17302148Spd144616 }
17312148Spd144616 case DESCR_SENSE_KEY_SPECIFIC: {
17322148Spd144616 struct scsi_sk_specific_sense_descr *ssd =
17332148Spd144616 (struct scsi_sk_specific_sense_descr *)
17342148Spd144616 sdt;
17352148Spd144616 if (sk_specific) {
17362148Spd144616 *sk_specific =
17372148Spd144616 (uint8_t *)&ssd->sss_data;
17382148Spd144616 }
17392148Spd144616 break;
17402148Spd144616 }
17412148Spd144616 case DESCR_FRU: {
17422148Spd144616 struct scsi_fru_sense_descr *fsd =
17432148Spd144616 (struct scsi_fru_sense_descr *)
17442148Spd144616 sdt;
17452148Spd144616 if (fru_code) {
17462148Spd144616 *fru_code = &fsd->fs_fru_code;
17472148Spd144616 }
17482148Spd144616 break;
17492148Spd144616 }
17502148Spd144616 case DESCR_STREAM_COMMANDS: {
17512148Spd144616 struct scsi_stream_cmd_sense_descr *strsd =
17522148Spd144616 (struct scsi_stream_cmd_sense_descr *)
17532148Spd144616 sdt;
17542148Spd144616 if (stream_flags) {
17552148Spd144616 *stream_flags =
17562148Spd144616 (uint8_t *)&strsd->scs_data;
17572148Spd144616 }
17582148Spd144616 break;
17592148Spd144616 }
17602148Spd144616 case DESCR_BLOCK_COMMANDS: {
17612148Spd144616 struct scsi_block_cmd_sense_descr *bsd =
17622148Spd144616 (struct scsi_block_cmd_sense_descr *)
17632148Spd144616 sdt;
17642148Spd144616 /*
17652148Spd144616 * The "Block Command" sense descriptor
17662148Spd144616 * contains an ili bit that we can store
17672148Spd144616 * in the stream specific data if it is
17682148Spd144616 * available. We shouldn't see both
17692148Spd144616 * a block command and a stream command
17702148Spd144616 * descriptor in the same collection
17712148Spd144616 * of sense data.
17722148Spd144616 */
17732148Spd144616 if (stream_flags) {
17742148Spd144616 /*
17752148Spd144616 * Can't take an address of a bitfield,
17762148Spd144616 * but the flags are just after the
17772148Spd144616 * bcs_reserved field.
17782148Spd144616 */
17792148Spd144616 *stream_flags =
17802148Spd144616 (uint8_t *)&bsd->bcs_reserved + 1;
17812148Spd144616 }
17822148Spd144616 break;
17832148Spd144616 }
17842148Spd144616 }
17852148Spd144616 }
17862148Spd144616 } else {
17872148Spd144616 struct scsi_extended_sense *es =
17882148Spd144616 (struct scsi_extended_sense *)sense_buffer;
17892148Spd144616
17902148Spd144616 /* Get data from fixed sense buffer */
17912148Spd144616 if (information && es->es_valid) {
17922148Spd144616 *information = &es->es_info_1;
17932148Spd144616 }
17942148Spd144616 if (cmd_spec_info && es->es_valid) {
17952148Spd144616 *cmd_spec_info = &es->es_cmd_info[0];
17962148Spd144616 }
17972148Spd144616 if (fru_code) {
17982148Spd144616 *fru_code = &es->es_fru_code;
17992148Spd144616 }
18002148Spd144616 if (sk_specific) {
18012148Spd144616 *sk_specific = &es->es_skey_specific[0];
18022148Spd144616 }
18032148Spd144616 if (stream_flags) {
18042148Spd144616 /*
18052148Spd144616 * Can't take the address of a bit field,
18062148Spd144616 * but the stream flags are located just after
18072148Spd144616 * the es_segnum field;
18082148Spd144616 */
18092148Spd144616 *stream_flags = &es->es_segnum + 1;
18102148Spd144616 }
18112148Spd144616 }
18122148Spd144616 }
18132148Spd144616
18142148Spd144616 boolean_t
scsi_sense_info_uint64(uint8_t * sense_buffer,int sense_buf_len,uint64_t * information)18152148Spd144616 scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len,
18162148Spd144616 uint64_t *information)
18172148Spd144616 {
18182148Spd144616 boolean_t valid;
18192148Spd144616 int sense_fmt;
18202148Spd144616
18212148Spd144616 ASSERT(sense_buffer != NULL);
18222148Spd144616 ASSERT(information != NULL);
18232148Spd144616
18242148Spd144616 /* Validate sense data and get format */
18252148Spd144616 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
18262148Spd144616
18272148Spd144616 if (sense_fmt == SENSE_UNUSABLE) {
18282148Spd144616 /* Information is not valid */
18292148Spd144616 valid = 0;
18302148Spd144616 } else if (sense_fmt == SENSE_FIXED_FORMAT) {
18312148Spd144616 struct scsi_extended_sense *es =
18322148Spd144616 (struct scsi_extended_sense *)sense_buffer;
18332148Spd144616
18342148Spd144616 *information = (uint64_t)SCSI_READ32(&es->es_info_1);
18352148Spd144616
18362148Spd144616 valid = es->es_valid;
18372148Spd144616 } else {
18382148Spd144616 /* Sense data is descriptor format */
18392148Spd144616 struct scsi_information_sense_descr *isd;
18402148Spd144616
18412148Spd144616 isd = (struct scsi_information_sense_descr *)
18422148Spd144616 scsi_find_sense_descr(sense_buffer, sense_buf_len,
18434851Scth DESCR_INFORMATION);
18442148Spd144616
18452148Spd144616 if (isd) {
18462148Spd144616 *information = SCSI_READ64(isd->isd_information);
18472148Spd144616 valid = 1;
18482148Spd144616 } else {
18492148Spd144616 valid = 0;
18502148Spd144616 }
18512148Spd144616 }
18522148Spd144616
18532148Spd144616 return (valid);
18542148Spd144616 }
18552148Spd144616
18562148Spd144616 boolean_t
scsi_sense_cmdspecific_uint64(uint8_t * sense_buffer,int sense_buf_len,uint64_t * cmd_specific_info)18572148Spd144616 scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len,
18582148Spd144616 uint64_t *cmd_specific_info)
18592148Spd144616 {
18602148Spd144616 boolean_t valid;
18612148Spd144616 int sense_fmt;
18622148Spd144616
18632148Spd144616 ASSERT(sense_buffer != NULL);
18642148Spd144616 ASSERT(cmd_specific_info != NULL);
18652148Spd144616
18662148Spd144616 /* Validate sense data and get format */
18672148Spd144616 sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
18682148Spd144616
18692148Spd144616 if (sense_fmt == SENSE_UNUSABLE) {
18702148Spd144616 /* Command specific info is not valid */
18712148Spd144616 valid = 0;
18722148Spd144616 } else if (sense_fmt == SENSE_FIXED_FORMAT) {
18732148Spd144616 struct scsi_extended_sense *es =
18742148Spd144616 (struct scsi_extended_sense *)sense_buffer;
18752148Spd144616
18762148Spd144616 *cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info);
18772148Spd144616
18782148Spd144616 valid = es->es_valid;
18792148Spd144616 } else {
18802148Spd144616 /* Sense data is descriptor format */
18812148Spd144616 struct scsi_cmd_specific_sense_descr *c;
18822148Spd144616
18832148Spd144616 c = (struct scsi_cmd_specific_sense_descr *)
18842148Spd144616 scsi_find_sense_descr(sense_buffer, sense_buf_len,
18854851Scth DESCR_COMMAND_SPECIFIC);
18862148Spd144616
18872148Spd144616 if (c) {
18882148Spd144616 valid = 1;
18892148Spd144616 *cmd_specific_info =
18902148Spd144616 SCSI_READ64(c->css_cmd_specific_info);
18912148Spd144616 } else {
18922148Spd144616 valid = 0;
18932148Spd144616 }
18942148Spd144616 }
18952148Spd144616
18962148Spd144616 return (valid);
18972148Spd144616 }
18982148Spd144616
18992148Spd144616 uint8_t *
scsi_find_sense_descr(uint8_t * sdsp,int sense_buf_len,int req_descr_type)19002148Spd144616 scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type)
19012148Spd144616 {
19022148Spd144616 struct scsi_descr_template *sdt = NULL;
19032148Spd144616
19042148Spd144616 while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) {
19052148Spd144616 ASSERT(sdt != NULL);
19062148Spd144616 if (sdt->sdt_descr_type == req_descr_type) {
19072148Spd144616 /* Found requested descriptor type */
19082148Spd144616 break;
19092148Spd144616 }
19102148Spd144616 }
19112148Spd144616
19122148Spd144616 return ((uint8_t *)sdt);
19132148Spd144616 }
19142148Spd144616
19152148Spd144616 /*
19162148Spd144616 * Sense Descriptor format is:
19172148Spd144616 *
19182148Spd144616 * <Descriptor type> <Descriptor length> <Descriptor data> ...
19192148Spd144616 *
19202148Spd144616 * 2 must be added to the descriptor length value to get the
19212148Spd144616 * total descriptor length sense the stored length does not
19222148Spd144616 * include the "type" and "additional length" fields.
19232148Spd144616 */
19242148Spd144616
19252148Spd144616 #define NEXT_DESCR_PTR(ndp_descr) \
19262148Spd144616 ((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \
19272148Spd144616 ((ndp_descr)->sdt_addl_length + \
19282148Spd144616 sizeof (struct scsi_descr_template))))
19292148Spd144616
19302148Spd144616 static int
scsi_get_next_descr(uint8_t * sense_buffer,int sense_buf_len,struct scsi_descr_template ** descrpp)19312148Spd144616 scsi_get_next_descr(uint8_t *sense_buffer,
19322148Spd144616 int sense_buf_len, struct scsi_descr_template **descrpp)
19332148Spd144616 {
19342148Spd144616 struct scsi_descr_sense_hdr *sdsp =
19352148Spd144616 (struct scsi_descr_sense_hdr *)sense_buffer;
19362148Spd144616 struct scsi_descr_template *cur_descr;
19372148Spd144616 boolean_t find_first;
19382148Spd144616 int valid_sense_length;
19392148Spd144616
19402148Spd144616 ASSERT(descrpp != NULL);
19412148Spd144616 find_first = (*descrpp == NULL);
19422148Spd144616
19432148Spd144616 /*
19442148Spd144616 * If no descriptor is passed in then return the first
19452148Spd144616 * descriptor
19462148Spd144616 */
19472148Spd144616 if (find_first) {
19482148Spd144616 /*
19492148Spd144616 * The first descriptor will immediately follow the header
19502148Spd144616 * (Pointer arithmetic)
19512148Spd144616 */
19522148Spd144616 cur_descr = (struct scsi_descr_template *)(sdsp+1);
19532148Spd144616 } else {
19542148Spd144616 cur_descr = *descrpp;
19552148Spd144616 ASSERT(cur_descr > (struct scsi_descr_template *)sdsp);
19562148Spd144616 }
19572148Spd144616
19582148Spd144616 /* Assume no more descriptors are available */
19592148Spd144616 *descrpp = NULL;
19602148Spd144616
19612148Spd144616 /*
19622148Spd144616 * Calculate the amount of valid sense data -- make sure the length
19632148Spd144616 * byte in this descriptor lies within the valid sense data.
19642148Spd144616 */
19652148Spd144616 valid_sense_length =
19662148Spd144616 min((sizeof (struct scsi_descr_sense_hdr) +
19672148Spd144616 sdsp->ds_addl_sense_length),
19682148Spd144616 sense_buf_len);
19692148Spd144616
19702148Spd144616 /*
19712148Spd144616 * Make sure this descriptor is complete (either the first
19722148Spd144616 * descriptor or the descriptor passed in)
19732148Spd144616 */
19742148Spd144616 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
19752148Spd144616 DESCR_GOOD) {
19762148Spd144616 return (-1);
19772148Spd144616 }
19782148Spd144616
19792148Spd144616 /*
19802148Spd144616 * If we were looking for the first descriptor go ahead and return it
19812148Spd144616 */
19822148Spd144616 if (find_first) {
19832148Spd144616 *descrpp = cur_descr;
19842148Spd144616 return ((*descrpp)->sdt_descr_type);
19852148Spd144616 }
19862148Spd144616
19872148Spd144616 /*
19882148Spd144616 * Get pointer to next descriptor
19892148Spd144616 */
19902148Spd144616 cur_descr = NEXT_DESCR_PTR(cur_descr);
19912148Spd144616
19922148Spd144616 /*
19932148Spd144616 * Make sure this descriptor is also complete.
19942148Spd144616 */
19952148Spd144616 if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
19962148Spd144616 DESCR_GOOD) {
19972148Spd144616 return (-1);
19982148Spd144616 }
19992148Spd144616
20002148Spd144616 *descrpp = (struct scsi_descr_template *)cur_descr;
20012148Spd144616 return ((*descrpp)->sdt_descr_type);
20022148Spd144616 }
20032148Spd144616
20042148Spd144616 static int
scsi_validate_descr(struct scsi_descr_sense_hdr * sdsp,int valid_sense_length,struct scsi_descr_template * descrp)20052148Spd144616 scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
20062148Spd144616 int valid_sense_length, struct scsi_descr_template *descrp)
20072148Spd144616 {
20082148Spd144616 int descr_offset, next_descr_offset;
20092148Spd144616
20102148Spd144616 /*
20112148Spd144616 * Make sure length is present
20122148Spd144616 */
20132148Spd144616 descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp;
20142148Spd144616 if (descr_offset + sizeof (struct scsi_descr_template) >
20152148Spd144616 valid_sense_length) {
20162148Spd144616 return (DESCR_PARTIAL);
20172148Spd144616 }
20182148Spd144616
20192148Spd144616 /*
20202148Spd144616 * Check if length is 0 (no more descriptors)
20212148Spd144616 */
20222148Spd144616 if (descrp->sdt_addl_length == 0) {
20232148Spd144616 return (DESCR_END);
20242148Spd144616 }
20252148Spd144616
20262148Spd144616 /*
20272148Spd144616 * Make sure the rest of the descriptor is present
20282148Spd144616 */
20292148Spd144616 next_descr_offset =
20302148Spd144616 (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp;
20312148Spd144616 if (next_descr_offset > valid_sense_length) {
20322148Spd144616 return (DESCR_PARTIAL);
20332148Spd144616 }
20342148Spd144616
20352148Spd144616 return (DESCR_GOOD);
20362148Spd144616 }
20373368Slh195018
20383368Slh195018 /*
20393368Slh195018 * Internal data structure for handling uscsi command.
20403368Slh195018 */
20413368Slh195018 typedef struct uscsi_i_cmd {
20423368Slh195018 struct uscsi_cmd uic_cmd;
20433368Slh195018 caddr_t uic_rqbuf;
20443368Slh195018 uchar_t uic_rqlen;
20453368Slh195018 caddr_t uic_cdb;
20463368Slh195018 int uic_flag;
20473368Slh195018 struct scsi_address *uic_ap;
20483368Slh195018 } uscsi_i_cmd_t;
20493368Slh195018
20503368Slh195018 #if !defined(lint)
20513368Slh195018 _NOTE(SCHEME_PROTECTS_DATA("unshared data", uscsi_i_cmd))
20523368Slh195018 #endif
20533368Slh195018
20543368Slh195018 /*ARGSUSED*/
20553368Slh195018 static void
scsi_uscsi_mincnt(struct buf * bp)20563368Slh195018 scsi_uscsi_mincnt(struct buf *bp)
20573368Slh195018 {
20583368Slh195018 /*
20593368Slh195018 * Do not break up because the CDB count would then be
20603368Slh195018 * incorrect and create spurious data underrun errors.
20613368Slh195018 */
20623368Slh195018 }
20633368Slh195018
20643368Slh195018 /*
20656640Scth * Function: scsi_uscsi_alloc_and_copyin
20663368Slh195018 *
20673368Slh195018 * Description: Target drivers call this function to allocate memeory,
20686640Scth * copy in, and convert ILP32/LP64 to make preparations for handling
20696640Scth * uscsi commands.
20703368Slh195018 *
20716640Scth * Arguments:
20726640Scth * arg - pointer to the caller's uscsi command struct
20736640Scth * flag - mode, corresponds to ioctl(9e) 'mode'
20746640Scth * ap - SCSI address structure
20756640Scth * uscmdp - pointer to the converted uscsi command
20763368Slh195018 *
20773368Slh195018 * Return code: 0
20786640Scth * EFAULT
20796640Scth * EINVAL
20803368Slh195018 *
20816640Scth * Context: Never called at interrupt context.
20823368Slh195018 */
20833368Slh195018
20843368Slh195018 int
scsi_uscsi_alloc_and_copyin(intptr_t arg,int flag,struct scsi_address * ap,struct uscsi_cmd ** uscmdp)20853368Slh195018 scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
20863368Slh195018 struct uscsi_cmd **uscmdp)
20873368Slh195018 {
20887570SDavid.Zhang@Sun.COM int rval = 0;
20897570SDavid.Zhang@Sun.COM struct uscsi_cmd *uscmd;
20903368Slh195018
20913368Slh195018 /*
20923368Slh195018 * In order to not worry about where the uscsi structure came
20933368Slh195018 * from (or where the cdb it points to came from) we're going
20943368Slh195018 * to make kmem_alloc'd copies of them here. This will also
20953368Slh195018 * allow reference to the data they contain long after this
20963368Slh195018 * process has gone to sleep and its kernel stack has been
20973368Slh195018 * unmapped, etc. First get some memory for the uscsi_cmd
20983368Slh195018 * struct and copy the contents of the given uscsi_cmd struct
20993368Slh195018 * into it. We also save infos of the uscsi command by using
21003368Slh195018 * uicmd to supply referrence for the copyout operation.
21013368Slh195018 */
21027570SDavid.Zhang@Sun.COM uscmd = scsi_uscsi_alloc();
21037570SDavid.Zhang@Sun.COM
21047570SDavid.Zhang@Sun.COM if ((rval = scsi_uscsi_copyin(arg, flag, ap, &uscmd)) != 0) {
21057570SDavid.Zhang@Sun.COM scsi_uscsi_free(uscmd);
21067570SDavid.Zhang@Sun.COM *uscmdp = NULL;
21077570SDavid.Zhang@Sun.COM rval = EFAULT;
21087570SDavid.Zhang@Sun.COM } else {
21097570SDavid.Zhang@Sun.COM *uscmdp = uscmd;
21107570SDavid.Zhang@Sun.COM }
21117570SDavid.Zhang@Sun.COM
21127570SDavid.Zhang@Sun.COM return (rval);
21137570SDavid.Zhang@Sun.COM }
21147570SDavid.Zhang@Sun.COM
21157570SDavid.Zhang@Sun.COM struct uscsi_cmd *
scsi_uscsi_alloc()21167570SDavid.Zhang@Sun.COM scsi_uscsi_alloc()
21177570SDavid.Zhang@Sun.COM {
21187570SDavid.Zhang@Sun.COM struct uscsi_i_cmd *uicmd;
21197570SDavid.Zhang@Sun.COM
21203368Slh195018 uicmd = (struct uscsi_i_cmd *)
21213368Slh195018 kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP);
21227570SDavid.Zhang@Sun.COM
21237570SDavid.Zhang@Sun.COM /*
21247570SDavid.Zhang@Sun.COM * It is supposed that the uscsi_cmd has been alloced correctly,
21257570SDavid.Zhang@Sun.COM * we need to check is it NULL or mis-created.
21267570SDavid.Zhang@Sun.COM */
21277570SDavid.Zhang@Sun.COM ASSERT(uicmd && (offsetof(struct uscsi_i_cmd, uic_cmd) == 0));
21287570SDavid.Zhang@Sun.COM
21297570SDavid.Zhang@Sun.COM return (&uicmd->uic_cmd);
21307570SDavid.Zhang@Sun.COM }
21317570SDavid.Zhang@Sun.COM
21327570SDavid.Zhang@Sun.COM int
scsi_uscsi_copyin(intptr_t arg,int flag,struct scsi_address * ap,struct uscsi_cmd ** uscmdp)21337570SDavid.Zhang@Sun.COM scsi_uscsi_copyin(intptr_t arg, int flag, struct scsi_address *ap,
21347570SDavid.Zhang@Sun.COM struct uscsi_cmd **uscmdp)
21357570SDavid.Zhang@Sun.COM {
21367570SDavid.Zhang@Sun.COM #ifdef _MULTI_DATAMODEL
21377570SDavid.Zhang@Sun.COM /*
21387570SDavid.Zhang@Sun.COM * For use when a 32 bit app makes a call into a
21397570SDavid.Zhang@Sun.COM * 64 bit ioctl
21407570SDavid.Zhang@Sun.COM */
21417570SDavid.Zhang@Sun.COM struct uscsi_cmd32 uscsi_cmd_32_for_64;
21427570SDavid.Zhang@Sun.COM struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
21437570SDavid.Zhang@Sun.COM #endif /* _MULTI_DATAMODEL */
21447570SDavid.Zhang@Sun.COM struct uscsi_cmd *uscmd = *uscmdp;
21457570SDavid.Zhang@Sun.COM struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)(uscmd);
21467570SDavid.Zhang@Sun.COM int max_hba_cdb;
21477570SDavid.Zhang@Sun.COM int rval;
21487570SDavid.Zhang@Sun.COM extern dev_info_t *scsi_vhci_dip;
21497570SDavid.Zhang@Sun.COM
21507570SDavid.Zhang@Sun.COM ASSERT(uscmd != NULL);
21517570SDavid.Zhang@Sun.COM ASSERT(uicmd != NULL);
21527570SDavid.Zhang@Sun.COM
21537570SDavid.Zhang@Sun.COM /*
21547570SDavid.Zhang@Sun.COM * To be able to issue multiple commands off a single uscmdp
21557570SDavid.Zhang@Sun.COM * We need to free the original cdb, rqbuf and bzero the uscmdp
21567570SDavid.Zhang@Sun.COM * if the cdb, rqbuf and uscmdp is not NULL
21577570SDavid.Zhang@Sun.COM */
21587570SDavid.Zhang@Sun.COM if (uscmd->uscsi_rqbuf != NULL)
21597570SDavid.Zhang@Sun.COM kmem_free(uscmd->uscsi_rqbuf, uscmd->uscsi_rqlen);
21607570SDavid.Zhang@Sun.COM if (uscmd->uscsi_cdb != NULL)
21617570SDavid.Zhang@Sun.COM kmem_free(uscmd->uscsi_cdb, uscmd->uscsi_cdblen);
21627570SDavid.Zhang@Sun.COM bzero(uscmd, sizeof (struct uscsi_cmd));
21637570SDavid.Zhang@Sun.COM
21643368Slh195018
21653368Slh195018 #ifdef _MULTI_DATAMODEL
21663368Slh195018 switch (ddi_model_convert_from(flag & FMODELS)) {
21673368Slh195018 case DDI_MODEL_ILP32:
21683368Slh195018 if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) {
21693368Slh195018 rval = EFAULT;
21707570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
21713368Slh195018 }
21723368Slh195018 /*
21733368Slh195018 * Convert the ILP32 uscsi data from the
21743368Slh195018 * application to LP64 for internal use.
21753368Slh195018 */
21763368Slh195018 uscsi_cmd32touscsi_cmd(ucmd32, uscmd);
21773368Slh195018 break;
21783368Slh195018 case DDI_MODEL_NONE:
21793368Slh195018 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
21803368Slh195018 rval = EFAULT;
21817570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
21823368Slh195018 }
21833368Slh195018 break;
21847570SDavid.Zhang@Sun.COM default:
21857570SDavid.Zhang@Sun.COM rval = EFAULT;
21867570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
21873368Slh195018 }
21883368Slh195018 #else /* ! _MULTI_DATAMODEL */
21893368Slh195018 if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
21903368Slh195018 rval = EFAULT;
21917570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
21923368Slh195018 }
21933368Slh195018 #endif /* _MULTI_DATAMODEL */
21943368Slh195018
21957570SDavid.Zhang@Sun.COM /*
21967570SDavid.Zhang@Sun.COM * We are going to allocate kernel virtual addresses for
21977570SDavid.Zhang@Sun.COM * uscsi_rqbuf and uscsi_cdb pointers, so save off the
21987570SDavid.Zhang@Sun.COM * original, possibly user virtual, uscsi_addresses
21997570SDavid.Zhang@Sun.COM * in uic_fields
22007570SDavid.Zhang@Sun.COM */
22013368Slh195018 uicmd->uic_rqbuf = uscmd->uscsi_rqbuf;
22023368Slh195018 uicmd->uic_rqlen = uscmd->uscsi_rqlen;
22033368Slh195018 uicmd->uic_cdb = uscmd->uscsi_cdb;
22043368Slh195018 uicmd->uic_flag = flag;
22053368Slh195018 uicmd->uic_ap = ap;
22063368Slh195018
22073368Slh195018 /*
22083368Slh195018 * Skip the following steps if we meet RESET commands.
22093368Slh195018 */
22103368Slh195018 if (uscmd->uscsi_flags &
22113368Slh195018 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
22123368Slh195018 uscmd->uscsi_rqbuf = NULL;
22133368Slh195018 uscmd->uscsi_cdb = NULL;
22143368Slh195018 return (0);
22153368Slh195018 }
22163368Slh195018
22173368Slh195018 /*
22186640Scth * Currently, USCSI_PATH_INSTANCE is only valid when directed
22196640Scth * to scsi_vhci.
22206640Scth */
22216640Scth if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
22226640Scth (A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) {
22236640Scth rval = EFAULT;
22247570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22256640Scth }
22266640Scth
22276640Scth /*
22283368Slh195018 * Perfunctory sanity checks. Get the maximum hba supported
22293368Slh195018 * cdb length first.
22303368Slh195018 */
22313368Slh195018 max_hba_cdb = scsi_ifgetcap(ap, "max-cdb-length", 1);
22323368Slh195018 if (max_hba_cdb < CDB_GROUP0) {
22333368Slh195018 max_hba_cdb = CDB_GROUP4;
22343368Slh195018 }
22353368Slh195018 if (uscmd->uscsi_cdblen < CDB_GROUP0 ||
22363368Slh195018 uscmd->uscsi_cdblen > max_hba_cdb) {
22373368Slh195018 rval = EINVAL;
22387570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22393368Slh195018 }
22403368Slh195018 if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
22413368Slh195018 (uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) {
22423368Slh195018 rval = EINVAL;
22437570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22443368Slh195018 }
22453368Slh195018
22463368Slh195018 /*
22476640Scth * To extend uscsi_cmd in the future, we need to ensure current
22486640Scth * reserved bits remain unused (zero).
22496640Scth */
22506640Scth if (uscmd->uscsi_flags & USCSI_RESERVED) {
22516640Scth rval = EINVAL;
22527570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22536640Scth }
22546640Scth
22556640Scth /*
22563368Slh195018 * Now we get some space for the CDB, and copy the given CDB into
22573368Slh195018 * it. Use ddi_copyin() in case the data is in user space.
22583368Slh195018 */
22593368Slh195018 uscmd->uscsi_cdb = kmem_zalloc((size_t)uscmd->uscsi_cdblen, KM_SLEEP);
22603368Slh195018 if (ddi_copyin(uicmd->uic_cdb, uscmd->uscsi_cdb,
22613368Slh195018 (uint_t)uscmd->uscsi_cdblen, flag) != 0) {
22623368Slh195018 kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
22633368Slh195018 rval = EFAULT;
22647570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22653368Slh195018 }
22663368Slh195018
22677001Slh195018 if (uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) {
22687001Slh195018 if (uscmd->uscsi_cdblen > SCSI_CDB_SIZE ||
22697001Slh195018 scsi_cdb_size[CDB_GROUPID(uscmd->uscsi_cdb[0])] >
22707001Slh195018 uscmd->uscsi_cdblen) {
22717001Slh195018 kmem_free(uscmd->uscsi_cdb,
22727001Slh195018 (size_t)uscmd->uscsi_cdblen);
22737001Slh195018 rval = EINVAL;
22747570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22757001Slh195018 }
22767001Slh195018 } else {
22777001Slh195018 if ((uscmd->uscsi_cdblen % 4) != 0) {
22787001Slh195018 kmem_free(uscmd->uscsi_cdb,
22797001Slh195018 (size_t)uscmd->uscsi_cdblen);
22807001Slh195018 rval = EINVAL;
22817570SDavid.Zhang@Sun.COM goto scsi_uscsi_copyin_failed;
22827001Slh195018 }
22833368Slh195018 }
22843368Slh195018
22853368Slh195018 /*
22863368Slh195018 * Initialize Request Sense buffering, if requested.
22873368Slh195018 */
22883368Slh195018 if (uscmd->uscsi_flags & USCSI_RQENABLE) {
22893368Slh195018 /*
22903368Slh195018 * Here uscmd->uscsi_rqbuf currently points to the caller's
22913368Slh195018 * buffer, but we replace this with a kernel buffer that
22923368Slh195018 * we allocate to use with the sense data. The sense data
22933368Slh195018 * (if present) gets copied into this new buffer before the
22943368Slh195018 * command is completed. Then we copy the sense data from
22953368Slh195018 * our allocated buf into the caller's buffer below. Note
22963368Slh195018 * that uscmd->uscsi_rqbuf and uscmd->uscsi_rqlen are used
22973368Slh195018 * below to perform the copy back to the caller's buf.
22983368Slh195018 */
22995597Slh195018 if (uicmd->uic_rqlen <= SENSE_LENGTH) {
23005597Slh195018 uscmd->uscsi_rqlen = SENSE_LENGTH;
23015597Slh195018 uscmd->uscsi_rqbuf = kmem_zalloc(SENSE_LENGTH,
23025597Slh195018 KM_SLEEP);
23035597Slh195018 } else {
23045597Slh195018 uscmd->uscsi_rqlen = MAX_SENSE_LENGTH;
23055597Slh195018 uscmd->uscsi_rqbuf = kmem_zalloc(MAX_SENSE_LENGTH,
23065597Slh195018 KM_SLEEP);
23075597Slh195018 }
23083368Slh195018 uscmd->uscsi_rqresid = uscmd->uscsi_rqlen;
23093368Slh195018 } else {
23103368Slh195018 uscmd->uscsi_rqbuf = NULL;
23113368Slh195018 uscmd->uscsi_rqlen = 0;
23123368Slh195018 uscmd->uscsi_rqresid = 0;
23133368Slh195018 }
23143368Slh195018 return (0);
23153368Slh195018
23167570SDavid.Zhang@Sun.COM scsi_uscsi_copyin_failed:
23177570SDavid.Zhang@Sun.COM /*
23187570SDavid.Zhang@Sun.COM * The uscsi_rqbuf and uscsi_cdb is refering to user-land
23197570SDavid.Zhang@Sun.COM * address now, no need to free them.
23207570SDavid.Zhang@Sun.COM */
23217570SDavid.Zhang@Sun.COM uscmd->uscsi_rqbuf = NULL;
23227570SDavid.Zhang@Sun.COM uscmd->uscsi_cdb = NULL;
23237570SDavid.Zhang@Sun.COM
23243368Slh195018 return (rval);
23253368Slh195018 }
23263368Slh195018
23273368Slh195018 /*
23286640Scth * Function: scsi_uscsi_handle_cmd
23293368Slh195018 *
23303368Slh195018 * Description: Target drivers call this function to handle uscsi commands.
23313368Slh195018 *
23326640Scth * Arguments:
23336640Scth * dev - device number
23346640Scth * dataspace - UIO_USERSPACE or UIO_SYSSPACE
23356640Scth * uscmd - pointer to the converted uscsi command
23366640Scth * strat - pointer to the driver's strategy routine
23376640Scth * bp - buf struct ptr
23386640Scth * private_data - pointer to bp->b_private
23393368Slh195018 *
23403368Slh195018 * Return code: 0
23416640Scth * EIO - scsi_reset() failed, or see biowait()/physio() codes.
23423368Slh195018 * EINVAL
23433368Slh195018 * return code of biowait(9F) or physio(9F):
23446640Scth * EIO - IO error
23453368Slh195018 * ENXIO
23466640Scth * EACCES - reservation conflict
23473368Slh195018 *
23486640Scth * Context: Never called at interrupt context.
23493368Slh195018 */
23503368Slh195018
23513368Slh195018 int
scsi_uscsi_handle_cmd(dev_t dev,enum uio_seg dataspace,struct uscsi_cmd * uscmd,int (* strat)(struct buf *),struct buf * bp,void * private_data)23523368Slh195018 scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace,
23533368Slh195018 struct uscsi_cmd *uscmd, int (*strat)(struct buf *),
23543368Slh195018 struct buf *bp, void *private_data)
23553368Slh195018 {
23563368Slh195018 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
23573368Slh195018 int bp_alloc_flag = 0;
23583368Slh195018 int rval;
23593368Slh195018
23603368Slh195018 /*
23613368Slh195018 * Perform resets directly; no need to generate a command to do it.
23623368Slh195018 */
23633368Slh195018 if (uscmd->uscsi_flags &
23643368Slh195018 (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
23653368Slh195018 int flags = (uscmd->uscsi_flags & USCSI_RESET_ALL) ?
23663368Slh195018 RESET_ALL : ((uscmd->uscsi_flags & USCSI_RESET_TARGET) ?
23673368Slh195018 RESET_TARGET : RESET_LUN);
23683368Slh195018 if (scsi_reset(uicmd->uic_ap, flags) == 0) {
23693368Slh195018 /* Reset attempt was unsuccessful */
23703368Slh195018 return (EIO);
23713368Slh195018 }
23723368Slh195018 return (0);
23733368Slh195018 }
23743368Slh195018
23753368Slh195018 /*
23763368Slh195018 * Force asynchronous mode, if necessary. Doing this here
23773368Slh195018 * has the unfortunate effect of running other queued
23783368Slh195018 * commands async also, but since the main purpose of this
23793368Slh195018 * capability is downloading new drive firmware, we can
23803368Slh195018 * probably live with it.
23813368Slh195018 */
23823368Slh195018 if (uscmd->uscsi_flags & USCSI_ASYNC) {
23833368Slh195018 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 1) {
23843368Slh195018 if (scsi_ifsetcap(uicmd->uic_ap, "synchronous",
23853368Slh195018 0, 1) != 1) {
23863368Slh195018 return (EINVAL);
23873368Slh195018 }
23883368Slh195018 }
23893368Slh195018 }
23903368Slh195018
23913368Slh195018 /*
23923368Slh195018 * Re-enable synchronous mode, if requested.
23933368Slh195018 */
23943368Slh195018 if (uscmd->uscsi_flags & USCSI_SYNC) {
23953368Slh195018 if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 0) {
23963368Slh195018 rval = scsi_ifsetcap(uicmd->uic_ap, "synchronous",
23973368Slh195018 1, 1);
23983368Slh195018 }
23993368Slh195018 }
24003368Slh195018
24013368Slh195018 /*
24023368Slh195018 * If bp is NULL, allocate space here.
24033368Slh195018 */
24043368Slh195018 if (bp == NULL) {
24053368Slh195018 bp = getrbuf(KM_SLEEP);
24063368Slh195018 bp->b_private = private_data;
24073368Slh195018 bp_alloc_flag = 1;
24083368Slh195018 }
24093368Slh195018
24103368Slh195018 /*
24113368Slh195018 * If we're going to do actual I/O, let physio do all the right things.
24123368Slh195018 */
24133368Slh195018 if (uscmd->uscsi_buflen != 0) {
24143368Slh195018 struct iovec aiov;
24153368Slh195018 struct uio auio;
24163368Slh195018 struct uio *uio = &auio;
24173368Slh195018
24183368Slh195018 bzero(&auio, sizeof (struct uio));
24193368Slh195018 bzero(&aiov, sizeof (struct iovec));
24203368Slh195018 aiov.iov_base = uscmd->uscsi_bufaddr;
24213368Slh195018 aiov.iov_len = uscmd->uscsi_buflen;
24223368Slh195018 uio->uio_iov = &aiov;
24233368Slh195018
24243368Slh195018 uio->uio_iovcnt = 1;
24253368Slh195018 uio->uio_resid = uscmd->uscsi_buflen;
24263368Slh195018 uio->uio_segflg = dataspace;
24273368Slh195018
24283368Slh195018 /*
24293368Slh195018 * physio() will block here until the command completes....
24303368Slh195018 */
24313368Slh195018 rval = physio(strat, bp, dev,
24323368Slh195018 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE),
24333368Slh195018 scsi_uscsi_mincnt, uio);
24343368Slh195018 } else {
24353368Slh195018 /*
24363368Slh195018 * We have to mimic that physio would do here! Argh!
24373368Slh195018 */
24383368Slh195018 bp->b_flags = B_BUSY |
24393368Slh195018 ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE);
24403368Slh195018 bp->b_edev = dev;
24413368Slh195018 bp->b_dev = cmpdev(dev); /* maybe unnecessary? */
24423368Slh195018 bp->b_bcount = 0;
24433368Slh195018 bp->b_blkno = 0;
24443368Slh195018 bp->b_resid = 0;
24453368Slh195018
24463368Slh195018 (void) (*strat)(bp);
24473368Slh195018 rval = biowait(bp);
24483368Slh195018 }
24493368Slh195018 uscmd->uscsi_resid = bp->b_resid;
24503368Slh195018
24513368Slh195018 if (bp_alloc_flag == 1) {
24523368Slh195018 bp_mapout(bp);
24533368Slh195018 freerbuf(bp);
24543368Slh195018 }
24553368Slh195018
24563368Slh195018 return (rval);
24573368Slh195018 }
24583368Slh195018
24593368Slh195018 /*
24606640Scth * Function: scsi_uscsi_pktinit
24616640Scth *
24626640Scth * Description: Target drivers call this function to transfer uscsi_cmd
24636640Scth * information into a scsi_pkt before sending the scsi_pkt.
24646640Scth *
24656640Scth * NB: At this point the implementation is limited to path_instance.
24666640Scth * At some point more code could be removed from the target driver by
24676640Scth * enhancing this function - with the added benifit of making the uscsi
24686640Scth * implementation more consistent accross all drivers.
24696640Scth *
24706640Scth * Arguments:
24716640Scth * uscmd - pointer to the uscsi command
24726640Scth * pkt - pointer to the scsi_pkt
24736640Scth *
24746640Scth * Return code: 1 on successfull transfer, 0 on failure.
24756640Scth */
24766640Scth int
scsi_uscsi_pktinit(struct uscsi_cmd * uscmd,struct scsi_pkt * pkt)24776640Scth scsi_uscsi_pktinit(struct uscsi_cmd *uscmd, struct scsi_pkt *pkt)
24786640Scth {
24796640Scth
24806640Scth /*
2481*12045SLi.He@Sun.COM * Check if the NACA flag is set. If one initiator sets it
2482*12045SLi.He@Sun.COM * but does not clear it, other initiators would end up
2483*12045SLi.He@Sun.COM * waiting indefinitely for the first to clear NACA. If the
2484*12045SLi.He@Sun.COM * the system allows NACA to be set, then warn the user but
2485*12045SLi.He@Sun.COM * still pass the command down, otherwise, clear the flag.
2486*12045SLi.He@Sun.COM */
2487*12045SLi.He@Sun.COM if (uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] & CDB_FLAG_NACA) {
2488*12045SLi.He@Sun.COM if (scsi_pkt_allow_naca) {
2489*12045SLi.He@Sun.COM cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
2490*12045SLi.He@Sun.COM "NACA flag is set");
2491*12045SLi.He@Sun.COM } else {
2492*12045SLi.He@Sun.COM uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] &=
2493*12045SLi.He@Sun.COM ~CDB_FLAG_NACA;
2494*12045SLi.He@Sun.COM cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
2495*12045SLi.He@Sun.COM "NACA flag is cleared");
2496*12045SLi.He@Sun.COM }
2497*12045SLi.He@Sun.COM }
2498*12045SLi.He@Sun.COM
2499*12045SLi.He@Sun.COM /*
25007389SRandall.Ralphs@Sun.COM * See if path_instance was requested in uscsi_cmd.
25016640Scth */
25027389SRandall.Ralphs@Sun.COM if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
25037389SRandall.Ralphs@Sun.COM (uscmd->uscsi_path_instance != 0)) {
25047389SRandall.Ralphs@Sun.COM /*
25057389SRandall.Ralphs@Sun.COM * Check to make sure the scsi_pkt was allocated correctly
25067389SRandall.Ralphs@Sun.COM * before transferring uscsi(7i) path_instance to scsi_pkt(9S).
25077389SRandall.Ralphs@Sun.COM */
25087389SRandall.Ralphs@Sun.COM if (scsi_pkt_allocated_correctly(pkt)) {
25097389SRandall.Ralphs@Sun.COM /* set pkt_path_instance and flag. */
25107389SRandall.Ralphs@Sun.COM pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
25117389SRandall.Ralphs@Sun.COM pkt->pkt_path_instance = uscmd->uscsi_path_instance;
25127389SRandall.Ralphs@Sun.COM } else {
25137389SRandall.Ralphs@Sun.COM return (0); /* failure */
25147389SRandall.Ralphs@Sun.COM }
25157389SRandall.Ralphs@Sun.COM } else {
25167389SRandall.Ralphs@Sun.COM /*
25177389SRandall.Ralphs@Sun.COM * Can only use pkt_path_instance if the packet
25187389SRandall.Ralphs@Sun.COM * was correctly allocated.
25197389SRandall.Ralphs@Sun.COM */
25207389SRandall.Ralphs@Sun.COM if (scsi_pkt_allocated_correctly(pkt)) {
25217389SRandall.Ralphs@Sun.COM pkt->pkt_path_instance = 0;
25227389SRandall.Ralphs@Sun.COM }
25237389SRandall.Ralphs@Sun.COM pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
25246640Scth }
25256640Scth
25266640Scth return (1); /* success */
25276640Scth }
25286640Scth
25296640Scth /*
25306640Scth * Function: scsi_uscsi_pktfini
25316640Scth *
25326640Scth * Description: Target drivers call this function to transfer completed
25336640Scth * scsi_pkt information back into uscsi_cmd.
25346640Scth *
25356640Scth * NB: At this point the implementation is limited to path_instance.
25366640Scth * At some point more code could be removed from the target driver by
25376640Scth * enhancing this function - with the added benifit of making the uscsi
25386640Scth * implementation more consistent accross all drivers.
25396640Scth *
25406640Scth * Arguments:
25416640Scth * pkt - pointer to the scsi_pkt
25426640Scth * uscmd - pointer to the uscsi command
25436640Scth *
25446640Scth * Return code: 1 on successfull transfer, 0 on failure.
25456640Scth */
25466640Scth int
scsi_uscsi_pktfini(struct scsi_pkt * pkt,struct uscsi_cmd * uscmd)25476640Scth scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd)
25486640Scth {
25496640Scth /*
25506640Scth * Check to make sure the scsi_pkt was allocated correctly before
25516640Scth * transferring scsi_pkt(9S) path_instance to uscsi(7i).
25526640Scth */
25536640Scth if (!scsi_pkt_allocated_correctly(pkt)) {
25546640Scth uscmd->uscsi_path_instance = 0;
25556640Scth return (0); /* failure */
25566640Scth }
25576640Scth
25586640Scth uscmd->uscsi_path_instance = pkt->pkt_path_instance;
25597047Sgap /* reset path_instance */
25607047Sgap pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
25616640Scth pkt->pkt_path_instance = 0;
25626640Scth return (1); /* success */
25636640Scth }
25646640Scth
25656640Scth /*
25663368Slh195018 * Function: scsi_uscsi_copyout_and_free
25673368Slh195018 *
25683368Slh195018 * Description: Target drivers call this function to undo what was done by
25693368Slh195018 * scsi_uscsi_alloc_and_copyin.
25703368Slh195018 *
25713368Slh195018 * Arguments: arg - pointer to the uscsi command to be returned
25723368Slh195018 * uscmd - pointer to the converted uscsi command
25733368Slh195018 *
25743368Slh195018 * Return code: 0
25753368Slh195018 * EFAULT
25763368Slh195018 *
25773368Slh195018 * Context: Never called at interrupt context.
25783368Slh195018 */
25793368Slh195018 int
scsi_uscsi_copyout_and_free(intptr_t arg,struct uscsi_cmd * uscmd)25803368Slh195018 scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
25813368Slh195018 {
25827570SDavid.Zhang@Sun.COM int rval = 0;
25837570SDavid.Zhang@Sun.COM
25847570SDavid.Zhang@Sun.COM rval = scsi_uscsi_copyout(arg, uscmd);
25857570SDavid.Zhang@Sun.COM
25867570SDavid.Zhang@Sun.COM scsi_uscsi_free(uscmd);
25877570SDavid.Zhang@Sun.COM
25887570SDavid.Zhang@Sun.COM return (rval);
25897570SDavid.Zhang@Sun.COM }
25907570SDavid.Zhang@Sun.COM
25917570SDavid.Zhang@Sun.COM int
scsi_uscsi_copyout(intptr_t arg,struct uscsi_cmd * uscmd)25927570SDavid.Zhang@Sun.COM scsi_uscsi_copyout(intptr_t arg, struct uscsi_cmd *uscmd)
25937570SDavid.Zhang@Sun.COM {
25943368Slh195018 #ifdef _MULTI_DATAMODEL
25953368Slh195018 /*
25963368Slh195018 * For use when a 32 bit app makes a call into a
25973368Slh195018 * 64 bit ioctl.
25983368Slh195018 */
25993368Slh195018 struct uscsi_cmd32 uscsi_cmd_32_for_64;
26003368Slh195018 struct uscsi_cmd32 *ucmd32 = &uscsi_cmd_32_for_64;
26013368Slh195018 #endif /* _MULTI_DATAMODEL */
26023368Slh195018 struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
26033368Slh195018 caddr_t k_rqbuf;
26045597Slh195018 int k_rqlen;
26053368Slh195018 caddr_t k_cdb;
26063368Slh195018 int rval = 0;
26073368Slh195018
26083368Slh195018 /*
26093368Slh195018 * If the caller wants sense data, copy back whatever sense data
26103368Slh195018 * we may have gotten, and update the relevant rqsense info.
26113368Slh195018 */
26123368Slh195018 if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
26133368Slh195018 (uscmd->uscsi_rqbuf != NULL)) {
26143368Slh195018 int rqlen = uscmd->uscsi_rqlen - uscmd->uscsi_rqresid;
26153368Slh195018 rqlen = min(((int)uicmd->uic_rqlen), rqlen);
26163368Slh195018 uscmd->uscsi_rqresid = uicmd->uic_rqlen - rqlen;
26173368Slh195018 /*
26183368Slh195018 * Copy out the sense data for user process.
26193368Slh195018 */
26203368Slh195018 if ((uicmd->uic_rqbuf != NULL) && (rqlen != 0)) {
26213368Slh195018 if (ddi_copyout(uscmd->uscsi_rqbuf,
26223368Slh195018 uicmd->uic_rqbuf, rqlen, uicmd->uic_flag) != 0) {
26233368Slh195018 rval = EFAULT;
26243368Slh195018 }
26253368Slh195018 }
26263368Slh195018 }
26273368Slh195018
26283368Slh195018 /*
26297570SDavid.Zhang@Sun.COM * Restore original uscsi_values, saved in uic_fields for
26307570SDavid.Zhang@Sun.COM * copyout (so caller does not experience a change in these
26317570SDavid.Zhang@Sun.COM * fields)
26323368Slh195018 */
26333368Slh195018 k_rqbuf = uscmd->uscsi_rqbuf;
26345597Slh195018 k_rqlen = uscmd->uscsi_rqlen;
26353368Slh195018 k_cdb = uscmd->uscsi_cdb;
26363368Slh195018 uscmd->uscsi_rqbuf = uicmd->uic_rqbuf;
26373368Slh195018 uscmd->uscsi_rqlen = uicmd->uic_rqlen;
26383368Slh195018 uscmd->uscsi_cdb = uicmd->uic_cdb;
26393368Slh195018
26403368Slh195018 #ifdef _MULTI_DATAMODEL
26413368Slh195018 switch (ddi_model_convert_from(uicmd->uic_flag & FMODELS)) {
26423368Slh195018 case DDI_MODEL_ILP32:
26433368Slh195018 /*
26443368Slh195018 * Convert back to ILP32 before copyout to the
26453368Slh195018 * application
26463368Slh195018 */
26473368Slh195018 uscsi_cmdtouscsi_cmd32(uscmd, ucmd32);
26483368Slh195018 if (ddi_copyout(ucmd32, (void *)arg, sizeof (*ucmd32),
26493368Slh195018 uicmd->uic_flag)) {
26503368Slh195018 rval = EFAULT;
26513368Slh195018 }
26523368Slh195018 break;
26533368Slh195018 case DDI_MODEL_NONE:
26543368Slh195018 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd),
26553368Slh195018 uicmd->uic_flag)) {
26563368Slh195018 rval = EFAULT;
26573368Slh195018 }
26583368Slh195018 break;
26597570SDavid.Zhang@Sun.COM default:
26607570SDavid.Zhang@Sun.COM rval = EFAULT;
26613368Slh195018 }
26623368Slh195018 #else /* _MULTI_DATAMODE */
26633368Slh195018 if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) {
26643368Slh195018 rval = EFAULT;
26653368Slh195018 }
26663368Slh195018 #endif /* _MULTI_DATAMODE */
26673368Slh195018
26687570SDavid.Zhang@Sun.COM /*
26697570SDavid.Zhang@Sun.COM * Copyout done, restore kernel virtual addresses for further
26707570SDavid.Zhang@Sun.COM * scsi_uscsi_free().
26717570SDavid.Zhang@Sun.COM */
26727570SDavid.Zhang@Sun.COM uscmd->uscsi_rqbuf = k_rqbuf;
26737570SDavid.Zhang@Sun.COM uscmd->uscsi_rqlen = k_rqlen;
26747570SDavid.Zhang@Sun.COM uscmd->uscsi_cdb = k_cdb;
26753368Slh195018
26763368Slh195018 return (rval);
26773368Slh195018 }
26787570SDavid.Zhang@Sun.COM
26797570SDavid.Zhang@Sun.COM void
scsi_uscsi_free(struct uscsi_cmd * uscmd)26807570SDavid.Zhang@Sun.COM scsi_uscsi_free(struct uscsi_cmd *uscmd)
26817570SDavid.Zhang@Sun.COM {
26827570SDavid.Zhang@Sun.COM struct uscsi_i_cmd *uicmd = (struct uscsi_i_cmd *)uscmd;
26837570SDavid.Zhang@Sun.COM
26847570SDavid.Zhang@Sun.COM ASSERT(uicmd != NULL);
26857570SDavid.Zhang@Sun.COM
26867570SDavid.Zhang@Sun.COM if ((uscmd->uscsi_rqbuf != NULL) && (uscmd->uscsi_rqlen != 0)) {
26877570SDavid.Zhang@Sun.COM kmem_free(uscmd->uscsi_rqbuf, (size_t)uscmd->uscsi_rqlen);
26887570SDavid.Zhang@Sun.COM uscmd->uscsi_rqbuf = NULL;
26897570SDavid.Zhang@Sun.COM }
26907570SDavid.Zhang@Sun.COM
26917570SDavid.Zhang@Sun.COM if ((uscmd->uscsi_cdb != NULL) && (uscmd->uscsi_cdblen != 0)) {
26927570SDavid.Zhang@Sun.COM kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
26937570SDavid.Zhang@Sun.COM uscmd->uscsi_cdb = NULL;
26947570SDavid.Zhang@Sun.COM }
26957570SDavid.Zhang@Sun.COM
26967570SDavid.Zhang@Sun.COM kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
26977570SDavid.Zhang@Sun.COM }
2698