xref: /onnv-gate/usr/src/uts/common/io/scsi/impl/scsi_subr.c (revision 12045:c8a185097d95)
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