17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54ab75253Smrj  * Common Development and Distribution License (the "License").
64ab75253Smrj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215bd3d017SNikko He 
227c478bd9Sstevel@tonic-gate /*
235bd3d017SNikko He  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24*f81518d2SGarrett D'Amore  * Copyright 2022 Garrett D'Amore
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
286567eb0aSlh #include <sys/file.h>
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Utility SCSI routines
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Polling support routines
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
385bd3d017SNikko He int		scsi_pkt_allow_naca = 0;
397c478bd9Sstevel@tonic-gate extern uintptr_t scsi_callback_id;
407c478bd9Sstevel@tonic-gate 
4160572c45Slh extern uchar_t scsi_cdb_size[];
4260572c45Slh 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * Common buffer for scsi_log
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate extern kmutex_t scsi_log_mutex;
487c478bd9Sstevel@tonic-gate static char scsi_log_buffer[MAXPATHLEN + 1];
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #define	A_TO_TRAN(ap)	(ap->a_hba_tran)
527c478bd9Sstevel@tonic-gate #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
537c478bd9Sstevel@tonic-gate #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define	CSEC		10000			/* usecs */
567c478bd9Sstevel@tonic-gate #define	SEC_TO_CSEC	(1000000/CSEC)
577c478bd9Sstevel@tonic-gate 
584ab75253Smrj extern ddi_dma_attr_t scsi_alloc_attr;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
617c478bd9Sstevel@tonic-gate static void impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
627c478bd9Sstevel@tonic-gate     const char *fmt, ...) __KPRINTFLIKE(4);
637c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
647c478bd9Sstevel@tonic-gate static void v_scsi_log(dev_info_t *dev, char *label, uint_t level,
657c478bd9Sstevel@tonic-gate     const char *fmt, va_list ap) __KVPRINTFLIKE(4);
667c478bd9Sstevel@tonic-gate 
675c46c6a0Spd static int
685c46c6a0Spd scsi_get_next_descr(uint8_t *sdsp,
695c46c6a0Spd     int sense_buf_len, struct scsi_descr_template **descrpp);
705c46c6a0Spd 
715c46c6a0Spd #define	DESCR_GOOD	0
725c46c6a0Spd #define	DESCR_PARTIAL	1
735c46c6a0Spd #define	DESCR_END	2
745c46c6a0Spd 
755c46c6a0Spd static int
765c46c6a0Spd scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
775c46c6a0Spd     int valid_sense_length, struct scsi_descr_template *descrp);
785c46c6a0Spd 
797c478bd9Sstevel@tonic-gate int
scsi_poll(struct scsi_pkt * pkt)807c478bd9Sstevel@tonic-gate scsi_poll(struct scsi_pkt *pkt)
817c478bd9Sstevel@tonic-gate {
82e43a78cfScth 	int			rval = -1;
83e43a78cfScth 	int			savef;
84e43a78cfScth 	long			savet;
85e43a78cfScth 	void			(*savec)();
86e43a78cfScth 	int			timeout;
87e43a78cfScth 	int			busy_count;
88e43a78cfScth 	int			poll_delay;
89e43a78cfScth 	int			rc;
90e43a78cfScth 	uint8_t			*sensep;
91e43a78cfScth 	struct scsi_arq_status	*arqstat;
92e43a78cfScth 	extern int		do_polled_io;
93e43a78cfScth 
94e43a78cfScth 	ASSERT(pkt->pkt_scbp);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/*
977c478bd9Sstevel@tonic-gate 	 * save old flags..
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	savef = pkt->pkt_flags;
1007c478bd9Sstevel@tonic-gate 	savec = pkt->pkt_comp;
1017c478bd9Sstevel@tonic-gate 	savet = pkt->pkt_time;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	pkt->pkt_flags |= FLAG_NOINTR;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/*
1067c478bd9Sstevel@tonic-gate 	 * XXX there is nothing in the SCSA spec that states that we should not
1077c478bd9Sstevel@tonic-gate 	 * do a callback for polled cmds; however, removing this will break sd
1087c478bd9Sstevel@tonic-gate 	 * and probably other target drivers
1097c478bd9Sstevel@tonic-gate 	 */
110e43a78cfScth 	pkt->pkt_comp = NULL;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * we don't like a polled command without timeout.
1147c478bd9Sstevel@tonic-gate 	 * 60 seconds seems long enough.
1157c478bd9Sstevel@tonic-gate 	 */
1167c478bd9Sstevel@tonic-gate 	if (pkt->pkt_time == 0)
1177c478bd9Sstevel@tonic-gate 		pkt->pkt_time = SCSI_POLL_TIMEOUT;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/*
1207c478bd9Sstevel@tonic-gate 	 * Send polled cmd.
1217c478bd9Sstevel@tonic-gate 	 *
1227c478bd9Sstevel@tonic-gate 	 * We do some error recovery for various errors.  Tran_busy,
1237c478bd9Sstevel@tonic-gate 	 * queue full, and non-dispatched commands are retried every 10 msec.
124e43a78cfScth 	 * as they are typically transient failures.  Busy status and Not
125e43a78cfScth 	 * Ready are retried every second as this status takes a while to
126e43a78cfScth 	 * change.
1277c478bd9Sstevel@tonic-gate 	 */
128e43a78cfScth 	timeout = pkt->pkt_time * SEC_TO_CSEC;
1297c478bd9Sstevel@tonic-gate 
130e43a78cfScth 	for (busy_count = 0; busy_count < timeout; busy_count++) {
1317c478bd9Sstevel@tonic-gate 		/*
1327c478bd9Sstevel@tonic-gate 		 * Initialize pkt status variables.
1337c478bd9Sstevel@tonic-gate 		 */
1347c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 		if ((rc = scsi_transport(pkt)) != TRAN_ACCEPT) {
1377c478bd9Sstevel@tonic-gate 			if (rc != TRAN_BUSY) {
1387c478bd9Sstevel@tonic-gate 				/* Transport failed - give up. */
1397c478bd9Sstevel@tonic-gate 				break;
1407c478bd9Sstevel@tonic-gate 			} else {
1417c478bd9Sstevel@tonic-gate 				/* Transport busy - try again. */
142e43a78cfScth 				poll_delay = 1 * CSEC;		/* 10 msec. */
1437c478bd9Sstevel@tonic-gate 			}
1447c478bd9Sstevel@tonic-gate 		} else {
1457c478bd9Sstevel@tonic-gate 			/*
1467c478bd9Sstevel@tonic-gate 			 * Transport accepted - check pkt status.
1477c478bd9Sstevel@tonic-gate 			 */
1487c478bd9Sstevel@tonic-gate 			rc = (*pkt->pkt_scbp) & STATUS_MASK;
149e43a78cfScth 			if ((pkt->pkt_reason == CMD_CMPLT) &&
150e43a78cfScth 			    (rc == STATUS_CHECK) &&
151e43a78cfScth 			    (pkt->pkt_state & STATE_ARQ_DONE)) {
152e43a78cfScth 				arqstat =
153e43a78cfScth 				    (struct scsi_arq_status *)(pkt->pkt_scbp);
154e43a78cfScth 				sensep = (uint8_t *)&arqstat->sts_sensedata;
155e43a78cfScth 			} else {
156e43a78cfScth 				sensep = NULL;
157e43a78cfScth 			}
1587c478bd9Sstevel@tonic-gate 
159e43a78cfScth 			if ((pkt->pkt_reason == CMD_CMPLT) &&
160e43a78cfScth 			    (rc == STATUS_GOOD)) {
1617c478bd9Sstevel@tonic-gate 				/* No error - we're done */
1627c478bd9Sstevel@tonic-gate 				rval = 0;
1637c478bd9Sstevel@tonic-gate 				break;
1647c478bd9Sstevel@tonic-gate 
165e43a78cfScth 			} else if (pkt->pkt_reason == CMD_DEV_GONE) {
166e43a78cfScth 				/* Lost connection - give up */
167e43a78cfScth 				break;
168e43a78cfScth 
169e43a78cfScth 			} else if ((pkt->pkt_reason == CMD_INCOMPLETE) &&
170e43a78cfScth 			    (pkt->pkt_state == 0)) {
1717c478bd9Sstevel@tonic-gate 				/* Pkt not dispatched - try again. */
172e43a78cfScth 				poll_delay = 1 * CSEC;		/* 10 msec. */
1737c478bd9Sstevel@tonic-gate 
174e43a78cfScth 			} else if ((pkt->pkt_reason == CMD_CMPLT) &&
175e43a78cfScth 			    (rc == STATUS_QFULL)) {
1767c478bd9Sstevel@tonic-gate 				/* Queue full - try again. */
177e43a78cfScth 				poll_delay = 1 * CSEC;		/* 10 msec. */
1787c478bd9Sstevel@tonic-gate 
179e43a78cfScth 			} else if ((pkt->pkt_reason == CMD_CMPLT) &&
180e43a78cfScth 			    (rc == STATUS_BUSY)) {
1817c478bd9Sstevel@tonic-gate 				/* Busy - try again. */
182e43a78cfScth 				poll_delay = 100 * CSEC;	/* 1 sec. */
183e43a78cfScth 				busy_count += (SEC_TO_CSEC - 1);
184e43a78cfScth 
185e43a78cfScth 			} else if ((sensep != NULL) &&
186e43a78cfScth 			    (scsi_sense_key(sensep) == KEY_NOT_READY) &&
187e43a78cfScth 			    (scsi_sense_asc(sensep) == 0x04) &&
188e43a78cfScth 			    (scsi_sense_ascq(sensep) == 0x01)) {
189e43a78cfScth 				/*
190e43a78cfScth 				 * Not ready -> ready - try again.
191e43a78cfScth 				 * 04h/01h: LUN IS IN PROCESS OF BECOMING READY
192e43a78cfScth 				 * ...same as STATUS_BUSY
193e43a78cfScth 				 */
194e43a78cfScth 				poll_delay = 100 * CSEC;	/* 1 sec. */
1957c478bd9Sstevel@tonic-gate 				busy_count += (SEC_TO_CSEC - 1);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 			} else {
1987c478bd9Sstevel@tonic-gate 				/* BAD status - give up. */
1997c478bd9Sstevel@tonic-gate 				break;
2007c478bd9Sstevel@tonic-gate 			}
2017c478bd9Sstevel@tonic-gate 		}
2027c478bd9Sstevel@tonic-gate 
203e43a78cfScth 		if (((curthread->t_flag & T_INTR_THREAD) == 0) &&
2047c478bd9Sstevel@tonic-gate 		    !do_polled_io) {
2057c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(poll_delay));
2067c478bd9Sstevel@tonic-gate 		} else {
2077c478bd9Sstevel@tonic-gate 			/* we busy wait during cpr_dump or interrupt threads */
2087c478bd9Sstevel@tonic-gate 			drv_usecwait(poll_delay);
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	pkt->pkt_flags = savef;
2137c478bd9Sstevel@tonic-gate 	pkt->pkt_comp = savec;
2147c478bd9Sstevel@tonic-gate 	pkt->pkt_time = savet;
215e43a78cfScth 
216e43a78cfScth 	/* return on error */
217e43a78cfScth 	if (rval)
218e43a78cfScth 		return (rval);
219e43a78cfScth 
220e43a78cfScth 	/*
221e43a78cfScth 	 * This is not a performance critical code path.
222e43a78cfScth 	 *
223e43a78cfScth 	 * As an accommodation for scsi_poll callers, to avoid ddi_dma_sync()
224e43a78cfScth 	 * issues associated with looking at DMA memory prior to
225e43a78cfScth 	 * scsi_pkt_destroy(), we scsi_sync_pkt() prior to return.
226e43a78cfScth 	 */
227e43a78cfScth 	scsi_sync_pkt(pkt);
228e43a78cfScth 	return (0);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate  * Command packaging routines.
2337c478bd9Sstevel@tonic-gate  *
2347c478bd9Sstevel@tonic-gate  * makecom_g*() are original routines and scsi_setup_cdb()
2357c478bd9Sstevel@tonic-gate  * is the new and preferred routine.
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * These routines put LUN information in CDB byte 1 bits 7-5.
2407c478bd9Sstevel@tonic-gate  * This was required in SCSI-1. SCSI-2 allowed it but it preferred
2417c478bd9Sstevel@tonic-gate  * sending LUN information as part of IDENTIFY message.
2427c478bd9Sstevel@tonic-gate  * This is not allowed in SCSI-3.
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate void
makecom_g0(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)2467c478bd9Sstevel@tonic-gate makecom_g0(struct scsi_pkt *pkt, struct scsi_device *devp,
2477c478bd9Sstevel@tonic-gate     int flag, int cmd, int addr, int cnt)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	MAKECOM_G0(pkt, devp, flag, cmd, addr, (uchar_t)cnt);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate void
makecom_g0_s(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int cnt,int fixbit)2537c478bd9Sstevel@tonic-gate makecom_g0_s(struct scsi_pkt *pkt, struct scsi_device *devp,
2547c478bd9Sstevel@tonic-gate     int flag, int cmd, int cnt, int fixbit)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	MAKECOM_G0_S(pkt, devp, flag, cmd, cnt, (uchar_t)fixbit);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate void
makecom_g1(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)2607c478bd9Sstevel@tonic-gate makecom_g1(struct scsi_pkt *pkt, struct scsi_device *devp,
2617c478bd9Sstevel@tonic-gate     int flag, int cmd, int addr, int cnt)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	MAKECOM_G1(pkt, devp, flag, cmd, addr, cnt);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate void
makecom_g5(struct scsi_pkt * pkt,struct scsi_device * devp,int flag,int cmd,int addr,int cnt)2677c478bd9Sstevel@tonic-gate makecom_g5(struct scsi_pkt *pkt, struct scsi_device *devp,
2687c478bd9Sstevel@tonic-gate     int flag, int cmd, int addr, int cnt)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	MAKECOM_G5(pkt, devp, flag, cmd, addr, cnt);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * Following routine does not put LUN information in CDB.
2757c478bd9Sstevel@tonic-gate  * This interface must be used for SCSI-2 targets having
2767c478bd9Sstevel@tonic-gate  * more than 8 LUNs or a SCSI-3 target.
2777c478bd9Sstevel@tonic-gate  */
2787c478bd9Sstevel@tonic-gate int
scsi_setup_cdb(union scsi_cdb * cdbp,uchar_t cmd,uint_t addr,uint_t cnt,uint_t addtl_cdb_data)2797c478bd9Sstevel@tonic-gate scsi_setup_cdb(union scsi_cdb *cdbp, uchar_t cmd, uint_t addr, uint_t cnt,
2807c478bd9Sstevel@tonic-gate     uint_t addtl_cdb_data)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	uint_t	addr_cnt;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	cdbp->scc_cmd = cmd;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	switch (CDB_GROUPID(cmd)) {
2877c478bd9Sstevel@tonic-gate 		case CDB_GROUPID_0:
2887c478bd9Sstevel@tonic-gate 			/*
2897c478bd9Sstevel@tonic-gate 			 * The following calculation is to take care of
2907c478bd9Sstevel@tonic-gate 			 * the fact that format of some 6 bytes tape
2917c478bd9Sstevel@tonic-gate 			 * command is different (compare 6 bytes disk and
2927c478bd9Sstevel@tonic-gate 			 * tape read commands).
2937c478bd9Sstevel@tonic-gate 			 */
2947c478bd9Sstevel@tonic-gate 			addr_cnt = (addr << 8) + cnt;
2957c478bd9Sstevel@tonic-gate 			addr = (addr_cnt & 0x1fffff00) >> 8;
2967c478bd9Sstevel@tonic-gate 			cnt = addr_cnt & 0xff;
2977c478bd9Sstevel@tonic-gate 			FORMG0ADDR(cdbp, addr);
2987c478bd9Sstevel@tonic-gate 			FORMG0COUNT(cdbp, cnt);
2997c478bd9Sstevel@tonic-gate 			break;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		case CDB_GROUPID_1:
3027c478bd9Sstevel@tonic-gate 		case CDB_GROUPID_2:
3037c478bd9Sstevel@tonic-gate 			FORMG1ADDR(cdbp, addr);
3047c478bd9Sstevel@tonic-gate 			FORMG1COUNT(cdbp, cnt);
3057c478bd9Sstevel@tonic-gate 			break;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		case CDB_GROUPID_4:
3087c478bd9Sstevel@tonic-gate 			FORMG4ADDR(cdbp, addr);
3097c478bd9Sstevel@tonic-gate 			FORMG4COUNT(cdbp, cnt);
3107c478bd9Sstevel@tonic-gate 			FORMG4ADDTL(cdbp, addtl_cdb_data);
3117c478bd9Sstevel@tonic-gate 			break;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		case CDB_GROUPID_5:
3147c478bd9Sstevel@tonic-gate 			FORMG5ADDR(cdbp, addr);
3157c478bd9Sstevel@tonic-gate 			FORMG5COUNT(cdbp, cnt);
3167c478bd9Sstevel@tonic-gate 			break;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 		default:
3197c478bd9Sstevel@tonic-gate 			return (0);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	return (1);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate  * Common iopbmap data area packet allocation routines
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate struct scsi_pkt *
get_pktiopb(struct scsi_address * ap,caddr_t * datap,int cdblen,int statuslen,int datalen,int readflag,int (* func)())3317c478bd9Sstevel@tonic-gate get_pktiopb(struct scsi_address *ap, caddr_t *datap, int cdblen, int statuslen,
3327c478bd9Sstevel@tonic-gate     int datalen, int readflag, int (*func)())
3337c478bd9Sstevel@tonic-gate {
3347c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t	*tran = A_TO_TRAN(ap);
3357c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip = tran->tran_hba_dip;
3367c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = NULL;
3377c478bd9Sstevel@tonic-gate 	struct buf	local;
3384ab75253Smrj 	size_t		rlen;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (!datap)
3417c478bd9Sstevel@tonic-gate 		return (pkt);
3427c478bd9Sstevel@tonic-gate 	*datap = (caddr_t)0;
3437c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&local, sizeof (struct buf));
3444ab75253Smrj 
3454ab75253Smrj 	/*
3464ab75253Smrj 	 * use i_ddi_mem_alloc() for now until we have an interface to allocate
347b89e420aSGarrett D'Amore 	 * memory for DMA which doesn't require a DMA handle.
3484ab75253Smrj 	 */
3494ab75253Smrj 	if (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
3504ab75253Smrj 	    ((func == SLEEP_FUNC) ? 1 : 0), 0, NULL, &local.b_un.b_addr, &rlen,
3514ab75253Smrj 	    NULL) != DDI_SUCCESS) {
3527c478bd9Sstevel@tonic-gate 		return (pkt);
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	if (readflag)
3557c478bd9Sstevel@tonic-gate 		local.b_flags = B_READ;
3567c478bd9Sstevel@tonic-gate 	local.b_bcount = datalen;
3577c478bd9Sstevel@tonic-gate 	pkt = (*tran->tran_init_pkt) (ap, NULL, &local,
3581e1ddd6cScth 	    cdblen, statuslen, 0, PKT_CONSISTENT,
3591e1ddd6cScth 	    (func == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC, NULL);
3607c478bd9Sstevel@tonic-gate 	if (!pkt) {
3617b93957cSeota 		i_ddi_mem_free(local.b_un.b_addr, NULL);
3627c478bd9Sstevel@tonic-gate 		if (func != NULL_FUNC) {
3637c478bd9Sstevel@tonic-gate 			ddi_set_callback(func, NULL, &scsi_callback_id);
3647c478bd9Sstevel@tonic-gate 		}
3657c478bd9Sstevel@tonic-gate 	} else {
3667c478bd9Sstevel@tonic-gate 		*datap = local.b_un.b_addr;
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	return (pkt);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  *  Equivalent deallocation wrapper
3737c478bd9Sstevel@tonic-gate  */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate void
free_pktiopb(struct scsi_pkt * pkt,caddr_t datap,int datalen)3767c478bd9Sstevel@tonic-gate free_pktiopb(struct scsi_pkt *pkt, caddr_t datap, int datalen)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	register struct scsi_address	*ap = P_TO_ADDR(pkt);
3797c478bd9Sstevel@tonic-gate 	register scsi_hba_tran_t	*tran = A_TO_TRAN(ap);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	(*tran->tran_destroy_pkt)(ap, pkt);
3827c478bd9Sstevel@tonic-gate 	if (datap && datalen) {
3837b93957cSeota 		i_ddi_mem_free(datap, NULL);
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 	if (scsi_callback_id != 0) {
3867c478bd9Sstevel@tonic-gate 		ddi_run_callback(&scsi_callback_id);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * Common naming functions
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate char *
scsi_dname(int dtyp)3957c478bd9Sstevel@tonic-gate scsi_dname(int dtyp)
3967c478bd9Sstevel@tonic-gate {
397d91393a8SChris Horne 	static char	*dnames[] = DTYPE_ASCII;
398d91393a8SChris Horne 	char		*dname = NULL;
399d91393a8SChris Horne 
400d91393a8SChris Horne 	if ((dtyp & DTYPE_MASK) < (sizeof (dnames) / sizeof (*dnames)))
401d91393a8SChris Horne 		dname = dnames[dtyp&DTYPE_MASK];
402d91393a8SChris Horne 	else if (dtyp == DTYPE_NOTPRESENT)
403d91393a8SChris Horne 		dname = "Not Present";
404d91393a8SChris Horne 	if ((dname == NULL) || (*dname == '\0'))
405d91393a8SChris Horne 		dname = "<unknown device type>";
406d91393a8SChris Horne 	return (dname);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate char *
scsi_rname(uchar_t reason)4107c478bd9Sstevel@tonic-gate scsi_rname(uchar_t reason)
4117c478bd9Sstevel@tonic-gate {
412d91393a8SChris Horne 	static char	*rnames[] = CMD_REASON_ASCII;
413d91393a8SChris Horne 	char		*rname = NULL;
414d91393a8SChris Horne 
415d91393a8SChris Horne 	if (reason < (sizeof (rnames) / sizeof (*rnames)))
416d91393a8SChris Horne 		rname = rnames[reason];
417d91393a8SChris Horne 	if ((rname == NULL) || (*rname == '\0'))
418d91393a8SChris Horne 		rname = "<unknown reason>";
419d91393a8SChris Horne 	return (rname);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate char *
scsi_mname(uchar_t msg)4237c478bd9Sstevel@tonic-gate scsi_mname(uchar_t msg)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	static char *imsgs[23] = {
4267c478bd9Sstevel@tonic-gate 		"COMMAND COMPLETE",
4277c478bd9Sstevel@tonic-gate 		"EXTENDED",
4287c478bd9Sstevel@tonic-gate 		"SAVE DATA POINTER",
4297c478bd9Sstevel@tonic-gate 		"RESTORE POINTERS",
4307c478bd9Sstevel@tonic-gate 		"DISCONNECT",
4317c478bd9Sstevel@tonic-gate 		"INITIATOR DETECTED ERROR",
4327c478bd9Sstevel@tonic-gate 		"ABORT",
4337c478bd9Sstevel@tonic-gate 		"REJECT",
4347c478bd9Sstevel@tonic-gate 		"NO-OP",
4357c478bd9Sstevel@tonic-gate 		"MESSAGE PARITY",
4367c478bd9Sstevel@tonic-gate 		"LINKED COMMAND COMPLETE",
4377c478bd9Sstevel@tonic-gate 		"LINKED COMMAND COMPLETE (W/FLAG)",
4387c478bd9Sstevel@tonic-gate 		"BUS DEVICE RESET",
4397c478bd9Sstevel@tonic-gate 		"ABORT TAG",
4407c478bd9Sstevel@tonic-gate 		"CLEAR QUEUE",
4417c478bd9Sstevel@tonic-gate 		"INITIATE RECOVERY",
4427c478bd9Sstevel@tonic-gate 		"RELEASE RECOVERY",
4437c478bd9Sstevel@tonic-gate 		"TERMINATE PROCESS",
4447c478bd9Sstevel@tonic-gate 		"CONTINUE TASK",
4457c478bd9Sstevel@tonic-gate 		"TARGET TRANSFER DISABLE",
4467c478bd9Sstevel@tonic-gate 		"RESERVED (0x14)",
4477c478bd9Sstevel@tonic-gate 		"RESERVED (0x15)",
4487c478bd9Sstevel@tonic-gate 		"CLEAR ACA"
4497c478bd9Sstevel@tonic-gate 	};
4507c478bd9Sstevel@tonic-gate 	static char *imsgs_2[6] = {
4517c478bd9Sstevel@tonic-gate 		"SIMPLE QUEUE TAG",
4527c478bd9Sstevel@tonic-gate 		"HEAD OF QUEUE TAG",
4537c478bd9Sstevel@tonic-gate 		"ORDERED QUEUE TAG",
4547c478bd9Sstevel@tonic-gate 		"IGNORE WIDE RESIDUE",
4557c478bd9Sstevel@tonic-gate 		"ACA",
4567c478bd9Sstevel@tonic-gate 		"LOGICAL UNIT RESET"
4577c478bd9Sstevel@tonic-gate 	};
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (msg < 23) {
4607c478bd9Sstevel@tonic-gate 		return (imsgs[msg]);
4617c478bd9Sstevel@tonic-gate 	} else if (IS_IDENTIFY_MSG(msg)) {
4627c478bd9Sstevel@tonic-gate 		return ("IDENTIFY");
4637c478bd9Sstevel@tonic-gate 	} else if (IS_2BYTE_MSG(msg) &&
4647c478bd9Sstevel@tonic-gate 	    (int)((msg) & 0xF) < (sizeof (imsgs_2) / sizeof (char *))) {
4657c478bd9Sstevel@tonic-gate 		return (imsgs_2[msg & 0xF]);
4667c478bd9Sstevel@tonic-gate 	} else {
4677c478bd9Sstevel@tonic-gate 		return ("<unknown msg>");
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate char *
scsi_cname(uchar_t cmd,register char ** cmdvec)4737c478bd9Sstevel@tonic-gate scsi_cname(uchar_t cmd, register char **cmdvec)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	while (*cmdvec != (char *)0) {
4767c478bd9Sstevel@tonic-gate 		if (cmd == **cmdvec) {
4777c478bd9Sstevel@tonic-gate 			return ((char *)((long)(*cmdvec)+1));
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 		cmdvec++;
4807c478bd9Sstevel@tonic-gate 	}
481*f81518d2SGarrett D'Amore 	return ("<undecoded cmd>");
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate char *
scsi_cmd_name(uchar_t cmd,struct scsi_key_strings * cmdlist,char * tmpstr)4857c478bd9Sstevel@tonic-gate scsi_cmd_name(uchar_t cmd, struct scsi_key_strings *cmdlist, char *tmpstr)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	int i = 0;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	while (cmdlist[i].key !=  -1) {
4907c478bd9Sstevel@tonic-gate 		if (cmd == cmdlist[i].key) {
4917c478bd9Sstevel@tonic-gate 			return ((char *)cmdlist[i].message);
4927c478bd9Sstevel@tonic-gate 		}
4937c478bd9Sstevel@tonic-gate 		i++;
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	return (sprintf(tmpstr, "<undecoded cmd 0x%x>", cmd));
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate static struct scsi_asq_key_strings extended_sense_list[] = {
4997c478bd9Sstevel@tonic-gate 	0x00, 0x00, "no additional sense info",
5007c478bd9Sstevel@tonic-gate 	0x00, 0x01, "filemark detected",
5017c478bd9Sstevel@tonic-gate 	0x00, 0x02, "end of partition/medium detected",
5027c478bd9Sstevel@tonic-gate 	0x00, 0x03, "setmark detected",
503d91393a8SChris Horne 	0x00, 0x04, "beginning of partition/medium detected",
5047c478bd9Sstevel@tonic-gate 	0x00, 0x05, "end of data detected",
5057c478bd9Sstevel@tonic-gate 	0x00, 0x06, "i/o process terminated",
5067c478bd9Sstevel@tonic-gate 	0x00, 0x11, "audio play operation in progress",
5077c478bd9Sstevel@tonic-gate 	0x00, 0x12, "audio play operation paused",
5087c478bd9Sstevel@tonic-gate 	0x00, 0x13, "audio play operation successfully completed",
5097c478bd9Sstevel@tonic-gate 	0x00, 0x14, "audio play operation stopped due to error",
5107c478bd9Sstevel@tonic-gate 	0x00, 0x15, "no current audio status to return",
5117c478bd9Sstevel@tonic-gate 	0x00, 0x16, "operation in progress",
5127c478bd9Sstevel@tonic-gate 	0x00, 0x17, "cleaning requested",
5137c478bd9Sstevel@tonic-gate 	0x00, 0x18, "erase operation in progress",
5147c478bd9Sstevel@tonic-gate 	0x00, 0x19, "locate operation in progress",
5157c478bd9Sstevel@tonic-gate 	0x00, 0x1A, "rewind operation in progress",
5167c478bd9Sstevel@tonic-gate 	0x00, 0x1B, "set capacity operation in progress",
5177c478bd9Sstevel@tonic-gate 	0x00, 0x1C, "verify operation in progress",
5182acf01fdSYuri Pankov 	0x00, 0x1D, "ATA passthrough information available",
5197c478bd9Sstevel@tonic-gate 	0x01, 0x00, "no index/sector signal",
5207c478bd9Sstevel@tonic-gate 	0x02, 0x00, "no seek complete",
5217c478bd9Sstevel@tonic-gate 	0x03, 0x00, "peripheral device write fault",
5227c478bd9Sstevel@tonic-gate 	0x03, 0x01, "no write current",
5237c478bd9Sstevel@tonic-gate 	0x03, 0x02, "excessive write errors",
5247c478bd9Sstevel@tonic-gate 	0x04, 0x00, "LUN not ready",
5257c478bd9Sstevel@tonic-gate 	0x04, 0x01, "LUN is becoming ready",
5267c478bd9Sstevel@tonic-gate 	0x04, 0x02, "LUN initializing command required",
5277c478bd9Sstevel@tonic-gate 	0x04, 0x03, "LUN not ready intervention required",
5287c478bd9Sstevel@tonic-gate 	0x04, 0x04, "LUN not ready format in progress",
5297c478bd9Sstevel@tonic-gate 	0x04, 0x05, "LUN not ready, rebuild in progress",
5307c478bd9Sstevel@tonic-gate 	0x04, 0x06, "LUN not ready, recalculation in progress",
5317c478bd9Sstevel@tonic-gate 	0x04, 0x07, "LUN not ready, operation in progress",
5327c478bd9Sstevel@tonic-gate 	0x04, 0x08, "LUN not ready, long write in progress",
5337c478bd9Sstevel@tonic-gate 	0x04, 0x09, "LUN not ready, self-test in progress",
5347c478bd9Sstevel@tonic-gate 	0x04, 0x0A, "LUN not accessible, asymmetric access state transition",
5357c478bd9Sstevel@tonic-gate 	0x04, 0x0B, "LUN not accessible, target port in standby state",
5367c478bd9Sstevel@tonic-gate 	0x04, 0x0C, "LUN not accessible, target port in unavailable state",
5377c478bd9Sstevel@tonic-gate 	0x04, 0x10, "LUN not ready, auxiliary memory not accessible",
5387c478bd9Sstevel@tonic-gate 	0x05, 0x00, "LUN does not respond to selection",
5397c478bd9Sstevel@tonic-gate 	0x06, 0x00, "reference position found",
5407c478bd9Sstevel@tonic-gate 	0x07, 0x00, "multiple peripheral devices selected",
5417c478bd9Sstevel@tonic-gate 	0x08, 0x00, "LUN communication failure",
5427c478bd9Sstevel@tonic-gate 	0x08, 0x01, "LUN communication time-out",
5437c478bd9Sstevel@tonic-gate 	0x08, 0x02, "LUN communication parity error",
5447c478bd9Sstevel@tonic-gate 	0x08, 0x03, "LUN communication crc error (ultra-DMA/32)",
5457c478bd9Sstevel@tonic-gate 	0x08, 0x04, "unreachable copy target",
5467c478bd9Sstevel@tonic-gate 	0x09, 0x00, "track following error",
5477c478bd9Sstevel@tonic-gate 	0x09, 0x01, "tracking servo failure",
5487c478bd9Sstevel@tonic-gate 	0x09, 0x02, "focus servo failure",
5497c478bd9Sstevel@tonic-gate 	0x09, 0x03, "spindle servo failure",
5507c478bd9Sstevel@tonic-gate 	0x09, 0x04, "head select fault",
5517c478bd9Sstevel@tonic-gate 	0x0a, 0x00, "error log overflow",
5527c478bd9Sstevel@tonic-gate 	0x0b, 0x00, "warning",
5537c478bd9Sstevel@tonic-gate 	0x0b, 0x01, "warning - specified temperature exceeded",
5547c478bd9Sstevel@tonic-gate 	0x0b, 0x02, "warning - enclosure degraded",
5557c478bd9Sstevel@tonic-gate 	0x0c, 0x00, "write error",
5567c478bd9Sstevel@tonic-gate 	0x0c, 0x01, "write error - recovered with auto reallocation",
5577c478bd9Sstevel@tonic-gate 	0x0c, 0x02, "write error - auto reallocation failed",
5587c478bd9Sstevel@tonic-gate 	0x0c, 0x03, "write error - recommend reassignment",
5597c478bd9Sstevel@tonic-gate 	0x0c, 0x04, "compression check miscompare error",
5607c478bd9Sstevel@tonic-gate 	0x0c, 0x05, "data expansion occurred during compression",
5617c478bd9Sstevel@tonic-gate 	0x0c, 0x06, "block not compressible",
5627c478bd9Sstevel@tonic-gate 	0x0c, 0x07, "write error - recovery needed",
5637c478bd9Sstevel@tonic-gate 	0x0c, 0x08, "write error - recovery failed",
5647c478bd9Sstevel@tonic-gate 	0x0c, 0x09, "write error - loss of streaming",
5657c478bd9Sstevel@tonic-gate 	0x0c, 0x0a, "write error - padding blocks added",
5667c478bd9Sstevel@tonic-gate 	0x0c, 0x0b, "auxiliary memory write error",
5677c478bd9Sstevel@tonic-gate 	0x0c, 0x0c, "write error - unexpected unsolicited data",
5687c478bd9Sstevel@tonic-gate 	0x0c, 0x0d, "write error - not enough unsolicited data",
5697c478bd9Sstevel@tonic-gate 	0x0d, 0x00, "error detected by third party temporary initiator",
5707c478bd9Sstevel@tonic-gate 	0x0d, 0x01, "third party device failure",
5717c478bd9Sstevel@tonic-gate 	0x0d, 0x02, "copy target device not reachable",
5727c478bd9Sstevel@tonic-gate 	0x0d, 0x03, "incorrect copy target device type",
5737c478bd9Sstevel@tonic-gate 	0x0d, 0x04, "copy target device data underrun",
5747c478bd9Sstevel@tonic-gate 	0x0d, 0x05, "copy target device data overrun",
5757c478bd9Sstevel@tonic-gate 	0x0e, 0x00, "invalid information unit",
5767c478bd9Sstevel@tonic-gate 	0x0e, 0x01, "information unit too short",
5777c478bd9Sstevel@tonic-gate 	0x0e, 0x02, "information unit too long",
5787c478bd9Sstevel@tonic-gate 	0x10, 0x00, "ID CRC or ECC error",
5797c478bd9Sstevel@tonic-gate 	0x11, 0x00, "unrecovered read error",
5807c478bd9Sstevel@tonic-gate 	0x11, 0x01, "read retries exhausted",
5817c478bd9Sstevel@tonic-gate 	0x11, 0x02, "error too long to correct",
5827c478bd9Sstevel@tonic-gate 	0x11, 0x03, "multiple read errors",
5837c478bd9Sstevel@tonic-gate 	0x11, 0x04, "unrecovered read error - auto reallocate failed",
5847c478bd9Sstevel@tonic-gate 	0x11, 0x05, "L-EC uncorrectable error",
5857c478bd9Sstevel@tonic-gate 	0x11, 0x06, "CIRC unrecovered error",
5867c478bd9Sstevel@tonic-gate 	0x11, 0x07, "data re-synchronization error",
5877c478bd9Sstevel@tonic-gate 	0x11, 0x08, "incomplete block read",
5887c478bd9Sstevel@tonic-gate 	0x11, 0x09, "no gap found",
5897c478bd9Sstevel@tonic-gate 	0x11, 0x0a, "miscorrected error",
5907c478bd9Sstevel@tonic-gate 	0x11, 0x0b, "unrecovered read error - recommend reassignment",
5917c478bd9Sstevel@tonic-gate 	0x11, 0x0c, "unrecovered read error - recommend rewrite the data",
5927c478bd9Sstevel@tonic-gate 	0x11, 0x0d, "de-compression crc error",
5937c478bd9Sstevel@tonic-gate 	0x11, 0x0e, "cannot decompress using declared algorithm",
5947c478bd9Sstevel@tonic-gate 	0x11, 0x0f, "error reading UPC/EAN number",
5957c478bd9Sstevel@tonic-gate 	0x11, 0x10, "error reading ISRC number",
5967c478bd9Sstevel@tonic-gate 	0x11, 0x11, "read error - loss of streaming",
5977c478bd9Sstevel@tonic-gate 	0x11, 0x12, "auxiliary memory read error",
5987c478bd9Sstevel@tonic-gate 	0x11, 0x13, "read error - failed retransmission request",
5997c478bd9Sstevel@tonic-gate 	0x12, 0x00, "address mark not found for ID field",
6007c478bd9Sstevel@tonic-gate 	0x13, 0x00, "address mark not found for data field",
6017c478bd9Sstevel@tonic-gate 	0x14, 0x00, "recorded entity not found",
6027c478bd9Sstevel@tonic-gate 	0x14, 0x01, "record not found",
6037c478bd9Sstevel@tonic-gate 	0x14, 0x02, "filemark or setmark not found",
6047c478bd9Sstevel@tonic-gate 	0x14, 0x03, "end-of-data not found",
6057c478bd9Sstevel@tonic-gate 	0x14, 0x04, "block sequence error",
6067c478bd9Sstevel@tonic-gate 	0x14, 0x05, "record not found - recommend reassignment",
6077c478bd9Sstevel@tonic-gate 	0x14, 0x06, "record not found - data auto-reallocated",
6087c478bd9Sstevel@tonic-gate 	0x14, 0x07, "locate operation failure",
6097c478bd9Sstevel@tonic-gate 	0x15, 0x00, "random positioning error",
6107c478bd9Sstevel@tonic-gate 	0x15, 0x01, "mechanical positioning error",
6117c478bd9Sstevel@tonic-gate 	0x15, 0x02, "positioning error detected by read of medium",
6127c478bd9Sstevel@tonic-gate 	0x16, 0x00, "data sync mark error",
6137c478bd9Sstevel@tonic-gate 	0x16, 0x01, "data sync error - data rewritten",
6147c478bd9Sstevel@tonic-gate 	0x16, 0x02, "data sync error - recommend rewrite",
6157c478bd9Sstevel@tonic-gate 	0x16, 0x03, "data sync error - data auto-reallocated",
6167c478bd9Sstevel@tonic-gate 	0x16, 0x04, "data sync error - recommend reassignment",
6177c478bd9Sstevel@tonic-gate 	0x17, 0x00, "recovered data with no error correction",
6187c478bd9Sstevel@tonic-gate 	0x17, 0x01, "recovered data with retries",
6197c478bd9Sstevel@tonic-gate 	0x17, 0x02, "recovered data with positive head offset",
6207c478bd9Sstevel@tonic-gate 	0x17, 0x03, "recovered data with negative head offset",
6217c478bd9Sstevel@tonic-gate 	0x17, 0x04, "recovered data with retries and/or CIRC applied",
6227c478bd9Sstevel@tonic-gate 	0x17, 0x05, "recovered data using previous sector id",
6237c478bd9Sstevel@tonic-gate 	0x17, 0x06, "recovered data without ECC - data auto-reallocated",
6247c478bd9Sstevel@tonic-gate 	0x17, 0x07, "recovered data without ECC - recommend reassignment",
6257c478bd9Sstevel@tonic-gate 	0x17, 0x08, "recovered data without ECC - recommend rewrite",
6267c478bd9Sstevel@tonic-gate 	0x17, 0x09, "recovered data without ECC - data rewritten",
6277c478bd9Sstevel@tonic-gate 	0x18, 0x00, "recovered data with error correction",
6287c478bd9Sstevel@tonic-gate 	0x18, 0x01, "recovered data with error corr. & retries applied",
6297c478bd9Sstevel@tonic-gate 	0x18, 0x02, "recovered data - data auto-reallocated",
6307c478bd9Sstevel@tonic-gate 	0x18, 0x03, "recovered data with CIRC",
6317c478bd9Sstevel@tonic-gate 	0x18, 0x04, "recovered data with L-EC",
6327c478bd9Sstevel@tonic-gate 	0x18, 0x05, "recovered data - recommend reassignment",
6337c478bd9Sstevel@tonic-gate 	0x18, 0x06, "recovered data - recommend rewrite",
6347c478bd9Sstevel@tonic-gate 	0x18, 0x07, "recovered data with ECC - data rewritten",
6357c478bd9Sstevel@tonic-gate 	0x18, 0x08, "recovered data with linking",
6367c478bd9Sstevel@tonic-gate 	0x19, 0x00, "defect list error",
6377c478bd9Sstevel@tonic-gate 	0x1a, 0x00, "parameter list length error",
6387c478bd9Sstevel@tonic-gate 	0x1b, 0x00, "synchronous data xfer error",
6397c478bd9Sstevel@tonic-gate 	0x1c, 0x00, "defect list not found",
6407c478bd9Sstevel@tonic-gate 	0x1c, 0x01, "primary defect list not found",
6417c478bd9Sstevel@tonic-gate 	0x1c, 0x02, "grown defect list not found",
6427c478bd9Sstevel@tonic-gate 	0x1d, 0x00, "miscompare during verify",
6437c478bd9Sstevel@tonic-gate 	0x1e, 0x00, "recovered ID with ECC",
6447c478bd9Sstevel@tonic-gate 	0x1f, 0x00, "partial defect list transfer",
6457c478bd9Sstevel@tonic-gate 	0x20, 0x00, "invalid command operation code",
6467c478bd9Sstevel@tonic-gate 	0x20, 0x01, "access denied - initiator pending-enrolled",
6477c478bd9Sstevel@tonic-gate 	0x20, 0x02, "access denied - no access rights",
6487c478bd9Sstevel@tonic-gate 	0x20, 0x03, "access denied - invalid mgmt id key",
6497c478bd9Sstevel@tonic-gate 	0x20, 0x04, "illegal command while in write capable state",
6507c478bd9Sstevel@tonic-gate 	0x20, 0x06, "illegal command while in explicit address mode",
6517c478bd9Sstevel@tonic-gate 	0x20, 0x07, "illegal command while in implicit address mode",
6527c478bd9Sstevel@tonic-gate 	0x20, 0x08, "access denied - enrollment conflict",
6537c478bd9Sstevel@tonic-gate 	0x20, 0x09, "access denied - invalid lu identifier",
6547c478bd9Sstevel@tonic-gate 	0x20, 0x0a, "access denied - invalid proxy token",
6557c478bd9Sstevel@tonic-gate 	0x20, 0x0b, "access denied - ACL LUN conflict",
6567c478bd9Sstevel@tonic-gate 	0x21, 0x00, "logical block address out of range",
6577c478bd9Sstevel@tonic-gate 	0x21, 0x01, "invalid element address",
6587c478bd9Sstevel@tonic-gate 	0x21, 0x02, "invalid address for write",
6597c478bd9Sstevel@tonic-gate 	0x22, 0x00, "illegal function",
6607c478bd9Sstevel@tonic-gate 	0x24, 0x00, "invalid field in cdb",
6617c478bd9Sstevel@tonic-gate 	0x24, 0x01, "cdb decryption error",
6627c478bd9Sstevel@tonic-gate 	0x25, 0x00, "LUN not supported",
6637c478bd9Sstevel@tonic-gate 	0x26, 0x00, "invalid field in param list",
6647c478bd9Sstevel@tonic-gate 	0x26, 0x01, "parameter not supported",
6657c478bd9Sstevel@tonic-gate 	0x26, 0x02, "parameter value invalid",
6667c478bd9Sstevel@tonic-gate 	0x26, 0x03, "threshold parameters not supported",
6677c478bd9Sstevel@tonic-gate 	0x26, 0x04, "invalid release of persistent reservation",
6687c478bd9Sstevel@tonic-gate 	0x26, 0x05, "data decryption error",
6697c478bd9Sstevel@tonic-gate 	0x26, 0x06, "too many target descriptors",
6707c478bd9Sstevel@tonic-gate 	0x26, 0x07, "unsupported target descriptor type code",
6717c478bd9Sstevel@tonic-gate 	0x26, 0x08, "too many segment descriptors",
6727c478bd9Sstevel@tonic-gate 	0x26, 0x09, "unsupported segment descriptor type code",
6737c478bd9Sstevel@tonic-gate 	0x26, 0x0a, "unexpected inexact segment",
6747c478bd9Sstevel@tonic-gate 	0x26, 0x0b, "inline data length exceeded",
6757c478bd9Sstevel@tonic-gate 	0x26, 0x0c, "invalid operation for copy source or destination",
6767c478bd9Sstevel@tonic-gate 	0x26, 0x0d, "copy segment granularity violation",
6777c478bd9Sstevel@tonic-gate 	0x27, 0x00, "write protected",
6787c478bd9Sstevel@tonic-gate 	0x27, 0x01, "hardware write protected",
6797c478bd9Sstevel@tonic-gate 	0x27, 0x02, "LUN software write protected",
6807c478bd9Sstevel@tonic-gate 	0x27, 0x03, "associated write protect",
6817c478bd9Sstevel@tonic-gate 	0x27, 0x04, "persistent write protect",
6827c478bd9Sstevel@tonic-gate 	0x27, 0x05, "permanent write protect",
6837c478bd9Sstevel@tonic-gate 	0x27, 0x06, "conditional write protect",
6845988135dSrralphs 	0x27, 0x80, "unable to overwrite data",
6857c478bd9Sstevel@tonic-gate 	0x28, 0x00, "medium may have changed",
6867c478bd9Sstevel@tonic-gate 	0x28, 0x01, "import or export element accessed",
6877c478bd9Sstevel@tonic-gate 	0x29, 0x00, "power on, reset, or bus reset occurred",
6887c478bd9Sstevel@tonic-gate 	0x29, 0x01, "power on occurred",
6897c478bd9Sstevel@tonic-gate 	0x29, 0x02, "scsi bus reset occurred",
6907c478bd9Sstevel@tonic-gate 	0x29, 0x03, "bus device reset message occurred",
6917c478bd9Sstevel@tonic-gate 	0x29, 0x04, "device internal reset",
6927c478bd9Sstevel@tonic-gate 	0x29, 0x05, "transceiver mode changed to single-ended",
6937c478bd9Sstevel@tonic-gate 	0x29, 0x06, "transceiver mode changed to LVD",
6947c478bd9Sstevel@tonic-gate 	0x29, 0x07, "i_t nexus loss occurred",
6957c478bd9Sstevel@tonic-gate 	0x2a, 0x00, "parameters changed",
6967c478bd9Sstevel@tonic-gate 	0x2a, 0x01, "mode parameters changed",
6977c478bd9Sstevel@tonic-gate 	0x2a, 0x02, "log parameters changed",
6987c478bd9Sstevel@tonic-gate 	0x2a, 0x03, "reservations preempted",
6997c478bd9Sstevel@tonic-gate 	0x2a, 0x04, "reservations released",
7007c478bd9Sstevel@tonic-gate 	0x2a, 0x05, "registrations preempted",
7017c478bd9Sstevel@tonic-gate 	0x2a, 0x06, "asymmetric access state changed",
7027c478bd9Sstevel@tonic-gate 	0x2a, 0x07, "implicit asymmetric access state transition failed",
7037c478bd9Sstevel@tonic-gate 	0x2b, 0x00, "copy cannot execute since host cannot disconnect",
7047c478bd9Sstevel@tonic-gate 	0x2c, 0x00, "command sequence error",
7057c478bd9Sstevel@tonic-gate 	0x2c, 0x03, "current program area is not empty",
7067c478bd9Sstevel@tonic-gate 	0x2c, 0x04, "current program area is empty",
7077c478bd9Sstevel@tonic-gate 	0x2c, 0x06, "persistent prevent conflict",
7087c478bd9Sstevel@tonic-gate 	0x2c, 0x07, "previous busy status",
7097c478bd9Sstevel@tonic-gate 	0x2c, 0x08, "previous task set full status",
7107c478bd9Sstevel@tonic-gate 	0x2c, 0x09, "previous reservation conflict status",
7117c478bd9Sstevel@tonic-gate 	0x2d, 0x00, "overwrite error on update in place",
7127c478bd9Sstevel@tonic-gate 	0x2e, 0x00, "insufficient time for operation",
7137c478bd9Sstevel@tonic-gate 	0x2f, 0x00, "commands cleared by another initiator",
7147c478bd9Sstevel@tonic-gate 	0x30, 0x00, "incompatible medium installed",
7157c478bd9Sstevel@tonic-gate 	0x30, 0x01, "cannot read medium - unknown format",
7167c478bd9Sstevel@tonic-gate 	0x30, 0x02, "cannot read medium - incompatible format",
7177c478bd9Sstevel@tonic-gate 	0x30, 0x03, "cleaning cartridge installed",
7187c478bd9Sstevel@tonic-gate 	0x30, 0x04, "cannot write medium - unknown format",
7197c478bd9Sstevel@tonic-gate 	0x30, 0x05, "cannot write medium - incompatible format",
7207c478bd9Sstevel@tonic-gate 	0x30, 0x06, "cannot format medium - incompatible medium",
7217c478bd9Sstevel@tonic-gate 	0x30, 0x07, "cleaning failure",
7227c478bd9Sstevel@tonic-gate 	0x30, 0x08, "cannot write - application code mismatch",
7237c478bd9Sstevel@tonic-gate 	0x30, 0x09, "current session not fixated for append",
7245988135dSrralphs 	0x30, 0x0b, "WORM medium - Overwrite attempted",
7255988135dSrralphs 	0x30, 0x0c, "WORM medium - Cannot Erase",
7265988135dSrralphs 	0x30, 0x0d, "WORM medium - Integrity Check",
7277c478bd9Sstevel@tonic-gate 	0x30, 0x10, "medium not formatted",
7287c478bd9Sstevel@tonic-gate 	0x31, 0x00, "medium format corrupted",
7297c478bd9Sstevel@tonic-gate 	0x31, 0x01, "format command failed",
7307c478bd9Sstevel@tonic-gate 	0x31, 0x02, "zoned formatting failed due to spare linking",
7315988135dSrralphs 	0x31, 0x94, "WORM media corrupted",
7327c478bd9Sstevel@tonic-gate 	0x32, 0x00, "no defect spare location available",
7337c478bd9Sstevel@tonic-gate 	0x32, 0x01, "defect list update failure",
7347c478bd9Sstevel@tonic-gate 	0x33, 0x00, "tape length error",
7357c478bd9Sstevel@tonic-gate 	0x34, 0x00, "enclosure failure",
7367c478bd9Sstevel@tonic-gate 	0x35, 0x00, "enclosure services failure",
7377c478bd9Sstevel@tonic-gate 	0x35, 0x01, "unsupported enclosure function",
7387c478bd9Sstevel@tonic-gate 	0x35, 0x02, "enclosure services unavailable",
7397c478bd9Sstevel@tonic-gate 	0x35, 0x03, "enclosure services transfer failure",
7407c478bd9Sstevel@tonic-gate 	0x35, 0x04, "enclosure services transfer refused",
7417c478bd9Sstevel@tonic-gate 	0x36, 0x00, "ribbon, ink, or toner failure",
7427c478bd9Sstevel@tonic-gate 	0x37, 0x00, "rounded parameter",
7437c478bd9Sstevel@tonic-gate 	0x39, 0x00, "saving parameters not supported",
7447c478bd9Sstevel@tonic-gate 	0x3a, 0x00, "medium not present",
7457c478bd9Sstevel@tonic-gate 	0x3a, 0x01, "medium not present - tray closed",
7467c478bd9Sstevel@tonic-gate 	0x3a, 0x02, "medium not present - tray open",
7477c478bd9Sstevel@tonic-gate 	0x3a, 0x03, "medium not present - loadable",
7487c478bd9Sstevel@tonic-gate 	0x3a, 0x04, "medium not present - medium auxiliary memory accessible",
7497c478bd9Sstevel@tonic-gate 	0x3b, 0x00, "sequential positioning error",
7507c478bd9Sstevel@tonic-gate 	0x3b, 0x01, "tape position error at beginning-of-medium",
7517c478bd9Sstevel@tonic-gate 	0x3b, 0x02, "tape position error at end-of-medium",
7527c478bd9Sstevel@tonic-gate 	0x3b, 0x08, "reposition error",
7537c478bd9Sstevel@tonic-gate 	0x3b, 0x0c, "position past beginning of medium",
7547c478bd9Sstevel@tonic-gate 	0x3b, 0x0d, "medium destination element full",
7557c478bd9Sstevel@tonic-gate 	0x3b, 0x0e, "medium source element empty",
7567c478bd9Sstevel@tonic-gate 	0x3b, 0x0f, "end of medium reached",
7577c478bd9Sstevel@tonic-gate 	0x3b, 0x11, "medium magazine not accessible",
7587c478bd9Sstevel@tonic-gate 	0x3b, 0x12, "medium magazine removed",
7597c478bd9Sstevel@tonic-gate 	0x3b, 0x13, "medium magazine inserted",
7607c478bd9Sstevel@tonic-gate 	0x3b, 0x14, "medium magazine locked",
7617c478bd9Sstevel@tonic-gate 	0x3b, 0x15, "medium magazine unlocked",
7627c478bd9Sstevel@tonic-gate 	0x3b, 0x16, "mechanical positioning or changer error",
7637c478bd9Sstevel@tonic-gate 	0x3d, 0x00, "invalid bits in indentify message",
7647c478bd9Sstevel@tonic-gate 	0x3e, 0x00, "LUN has not self-configured yet",
7657c478bd9Sstevel@tonic-gate 	0x3e, 0x01, "LUN failure",
7667c478bd9Sstevel@tonic-gate 	0x3e, 0x02, "timeout on LUN",
7677c478bd9Sstevel@tonic-gate 	0x3e, 0x03, "LUN failed self-test",
7687c478bd9Sstevel@tonic-gate 	0x3e, 0x04, "LUN unable to update self-test log",
7697c478bd9Sstevel@tonic-gate 	0x3f, 0x00, "target operating conditions have changed",
7707c478bd9Sstevel@tonic-gate 	0x3f, 0x01, "microcode has been changed",
7717c478bd9Sstevel@tonic-gate 	0x3f, 0x02, "changed operating definition",
7727c478bd9Sstevel@tonic-gate 	0x3f, 0x03, "inquiry data has changed",
7737c478bd9Sstevel@tonic-gate 	0x3f, 0x04, "component device attached",
7747c478bd9Sstevel@tonic-gate 	0x3f, 0x05, "device identifier changed",
7757c478bd9Sstevel@tonic-gate 	0x3f, 0x06, "redundancy group created or modified",
7767c478bd9Sstevel@tonic-gate 	0x3f, 0x07, "redundancy group deleted",
7777c478bd9Sstevel@tonic-gate 	0x3f, 0x08, "spare created or modified",
7787c478bd9Sstevel@tonic-gate 	0x3f, 0x09, "spare deleted",
7797c478bd9Sstevel@tonic-gate 	0x3f, 0x0a, "volume set created or modified",
7807c478bd9Sstevel@tonic-gate 	0x3f, 0x0b, "volume set deleted",
7817c478bd9Sstevel@tonic-gate 	0x3f, 0x0c, "volume set deassigned",
7827c478bd9Sstevel@tonic-gate 	0x3f, 0x0d, "volume set reassigned",
7837c478bd9Sstevel@tonic-gate 	0x3f, 0x0e, "reported LUNs data has changed",
7847c478bd9Sstevel@tonic-gate 	0x3f, 0x0f, "echo buffer overwritten",
7857c478bd9Sstevel@tonic-gate 	0x3f, 0x10, "medium loadable",
7867c478bd9Sstevel@tonic-gate 	0x3f, 0x11, "medium auxiliary memory accessible",
7877c478bd9Sstevel@tonic-gate 	0x40, 0x00, "ram failure",
7887c478bd9Sstevel@tonic-gate 	0x41, 0x00, "data path failure",
7897c478bd9Sstevel@tonic-gate 	0x42, 0x00, "power-on or self-test failure",
7907c478bd9Sstevel@tonic-gate 	0x43, 0x00, "message error",
7917c478bd9Sstevel@tonic-gate 	0x44, 0x00, "internal target failure",
7927c478bd9Sstevel@tonic-gate 	0x45, 0x00, "select or reselect failure",
7937c478bd9Sstevel@tonic-gate 	0x46, 0x00, "unsuccessful soft reset",
7947c478bd9Sstevel@tonic-gate 	0x47, 0x00, "scsi parity error",
7957c478bd9Sstevel@tonic-gate 	0x47, 0x01, "data phase crc error detected",
7967c478bd9Sstevel@tonic-gate 	0x47, 0x02, "scsi parity error detected during st data phase",
7977c478bd9Sstevel@tonic-gate 	0x47, 0x03, "information unit iucrc error detected",
7987c478bd9Sstevel@tonic-gate 	0x47, 0x04, "asynchronous information protection error detected",
7997c478bd9Sstevel@tonic-gate 	0x47, 0x05, "protocol service crc error",
8007c478bd9Sstevel@tonic-gate 	0x47, 0x7f, "some commands cleared by iscsi protocol event",
8017c478bd9Sstevel@tonic-gate 	0x48, 0x00, "initiator detected error message received",
8027c478bd9Sstevel@tonic-gate 	0x49, 0x00, "invalid message error",
8037c478bd9Sstevel@tonic-gate 	0x4a, 0x00, "command phase error",
8047c478bd9Sstevel@tonic-gate 	0x4b, 0x00, "data phase error",
8057c478bd9Sstevel@tonic-gate 	0x4b, 0x01, "invalid target port transfer tag received",
8067c478bd9Sstevel@tonic-gate 	0x4b, 0x02, "too much write data",
8077c478bd9Sstevel@tonic-gate 	0x4b, 0x03, "ack/nak timeout",
8087c478bd9Sstevel@tonic-gate 	0x4b, 0x04, "nak received",
8097c478bd9Sstevel@tonic-gate 	0x4b, 0x05, "data offset error",
8107c478bd9Sstevel@tonic-gate 	0x4c, 0x00, "logical unit failed self-configuration",
8117c478bd9Sstevel@tonic-gate 	0x4d, 0x00, "tagged overlapped commands (ASCQ = queue tag)",
8127c478bd9Sstevel@tonic-gate 	0x4e, 0x00, "overlapped commands attempted",
8137c478bd9Sstevel@tonic-gate 	0x50, 0x00, "write append error",
8145988135dSrralphs 	0x50, 0x01, "data protect write append error",
8155988135dSrralphs 	0x50, 0x95, "data protect write append error",
8167c478bd9Sstevel@tonic-gate 	0x51, 0x00, "erase failure",
8177c478bd9Sstevel@tonic-gate 	0x52, 0x00, "cartridge fault",
8187c478bd9Sstevel@tonic-gate 	0x53, 0x00, "media load or eject failed",
8197c478bd9Sstevel@tonic-gate 	0x53, 0x01, "unload tape failure",
8207c478bd9Sstevel@tonic-gate 	0x53, 0x02, "medium removal prevented",
8217c478bd9Sstevel@tonic-gate 	0x54, 0x00, "scsi to host system interface failure",
8227c478bd9Sstevel@tonic-gate 	0x55, 0x00, "system resource failure",
8237c478bd9Sstevel@tonic-gate 	0x55, 0x01, "system buffer full",
8247c478bd9Sstevel@tonic-gate 	0x55, 0x02, "insufficient reservation resources",
8257c478bd9Sstevel@tonic-gate 	0x55, 0x03, "insufficient resources",
8267c478bd9Sstevel@tonic-gate 	0x55, 0x04, "insufficient registration resources",
8277c478bd9Sstevel@tonic-gate 	0x55, 0x05, "insufficient access control resources",
8287c478bd9Sstevel@tonic-gate 	0x55, 0x06, "auxiliary memory out of space",
8297c478bd9Sstevel@tonic-gate 	0x57, 0x00, "unable to recover TOC",
8307c478bd9Sstevel@tonic-gate 	0x58, 0x00, "generation does not exist",
8317c478bd9Sstevel@tonic-gate 	0x59, 0x00, "updated block read",
8327c478bd9Sstevel@tonic-gate 	0x5a, 0x00, "operator request or state change input",
8337c478bd9Sstevel@tonic-gate 	0x5a, 0x01, "operator medium removal request",
8347c478bd9Sstevel@tonic-gate 	0x5a, 0x02, "operator selected write protect",
8357c478bd9Sstevel@tonic-gate 	0x5a, 0x03, "operator selected write permit",
8367c478bd9Sstevel@tonic-gate 	0x5b, 0x00, "log exception",
8377c478bd9Sstevel@tonic-gate 	0x5b, 0x01, "threshold condition met",
8387c478bd9Sstevel@tonic-gate 	0x5b, 0x02, "log counter at maximum",
8397c478bd9Sstevel@tonic-gate 	0x5b, 0x03, "log list codes exhausted",
8407c478bd9Sstevel@tonic-gate 	0x5c, 0x00, "RPL status change",
8417c478bd9Sstevel@tonic-gate 	0x5c, 0x01, "spindles synchronized",
8427c478bd9Sstevel@tonic-gate 	0x5c, 0x02, "spindles not synchronized",
8437c478bd9Sstevel@tonic-gate 	0x5d, 0x00, "drive operation marginal, service immediately"
8447c478bd9Sstevel@tonic-gate 		    " (failure prediction threshold exceeded)",
8457c478bd9Sstevel@tonic-gate 	0x5d, 0x01, "media failure prediction threshold exceeded",
8467c478bd9Sstevel@tonic-gate 	0x5d, 0x02, "LUN failure prediction threshold exceeded",
8477c478bd9Sstevel@tonic-gate 	0x5d, 0x03, "spare area exhaustion prediction threshold exceeded",
8487c478bd9Sstevel@tonic-gate 	0x5d, 0x10, "hardware impending failure general hard drive failure",
8497c478bd9Sstevel@tonic-gate 	0x5d, 0x11, "hardware impending failure drive error rate too high",
8507c478bd9Sstevel@tonic-gate 	0x5d, 0x12, "hardware impending failure data error rate too high",
8517c478bd9Sstevel@tonic-gate 	0x5d, 0x13, "hardware impending failure seek error rate too high",
8527c478bd9Sstevel@tonic-gate 	0x5d, 0x14, "hardware impending failure too many block reassigns",
8537c478bd9Sstevel@tonic-gate 	0x5d, 0x15, "hardware impending failure access times too high",
8547c478bd9Sstevel@tonic-gate 	0x5d, 0x16, "hardware impending failure start unit times too high",
8557c478bd9Sstevel@tonic-gate 	0x5d, 0x17, "hardware impending failure channel parametrics",
8567c478bd9Sstevel@tonic-gate 	0x5d, 0x18, "hardware impending failure controller detected",
8577c478bd9Sstevel@tonic-gate 	0x5d, 0x19, "hardware impending failure throughput performance",
8587c478bd9Sstevel@tonic-gate 	0x5d, 0x1a, "hardware impending failure seek time performance",
8597c478bd9Sstevel@tonic-gate 	0x5d, 0x1b, "hardware impending failure spin-up retry count",
8607c478bd9Sstevel@tonic-gate 	0x5d, 0x1c, "hardware impending failure drive calibration retry count",
8617c478bd9Sstevel@tonic-gate 	0x5d, 0x20, "controller impending failure general hard drive failure",
8627c478bd9Sstevel@tonic-gate 	0x5d, 0x21, "controller impending failure drive error rate too high",
8637c478bd9Sstevel@tonic-gate 	0x5d, 0x22, "controller impending failure data error rate too high",
8647c478bd9Sstevel@tonic-gate 	0x5d, 0x23, "controller impending failure seek error rate too high",
8657c478bd9Sstevel@tonic-gate 	0x5d, 0x24, "controller impending failure too many block reassigns",
8667c478bd9Sstevel@tonic-gate 	0x5d, 0x25, "controller impending failure access times too high",
8677c478bd9Sstevel@tonic-gate 	0x5d, 0x26, "controller impending failure start unit times too high",
8687c478bd9Sstevel@tonic-gate 	0x5d, 0x27, "controller impending failure channel parametrics",
8697c478bd9Sstevel@tonic-gate 	0x5d, 0x28, "controller impending failure controller detected",
8707c478bd9Sstevel@tonic-gate 	0x5d, 0x29, "controller impending failure throughput performance",
8717c478bd9Sstevel@tonic-gate 	0x5d, 0x2a, "controller impending failure seek time performance",
8727c478bd9Sstevel@tonic-gate 	0x5d, 0x2b, "controller impending failure spin-up retry count",
8737c478bd9Sstevel@tonic-gate 	0x5d, 0x2c, "controller impending failure drive calibration retry cnt",
8747c478bd9Sstevel@tonic-gate 	0x5d, 0x30, "data channel impending failure general hard drive failure",
8757c478bd9Sstevel@tonic-gate 	0x5d, 0x31, "data channel impending failure drive error rate too high",
8767c478bd9Sstevel@tonic-gate 	0x5d, 0x32, "data channel impending failure data error rate too high",
8777c478bd9Sstevel@tonic-gate 	0x5d, 0x33, "data channel impending failure seek error rate too high",
8787c478bd9Sstevel@tonic-gate 	0x5d, 0x34, "data channel impending failure too many block reassigns",
8797c478bd9Sstevel@tonic-gate 	0x5d, 0x35, "data channel impending failure access times too high",
8807c478bd9Sstevel@tonic-gate 	0x5d, 0x36, "data channel impending failure start unit times too high",
8817c478bd9Sstevel@tonic-gate 	0x5d, 0x37, "data channel impending failure channel parametrics",
8827c478bd9Sstevel@tonic-gate 	0x5d, 0x38, "data channel impending failure controller detected",
8837c478bd9Sstevel@tonic-gate 	0x5d, 0x39, "data channel impending failure throughput performance",
8847c478bd9Sstevel@tonic-gate 	0x5d, 0x3a, "data channel impending failure seek time performance",
8857c478bd9Sstevel@tonic-gate 	0x5d, 0x3b, "data channel impending failure spin-up retry count",
8867c478bd9Sstevel@tonic-gate 	0x5d, 0x3c, "data channel impending failure drive calibrate retry cnt",
8877c478bd9Sstevel@tonic-gate 	0x5d, 0x40, "servo impending failure general hard drive failure",
8887c478bd9Sstevel@tonic-gate 	0x5d, 0x41, "servo impending failure drive error rate too high",
8897c478bd9Sstevel@tonic-gate 	0x5d, 0x42, "servo impending failure data error rate too high",
8907c478bd9Sstevel@tonic-gate 	0x5d, 0x43, "servo impending failure seek error rate too high",
8917c478bd9Sstevel@tonic-gate 	0x5d, 0x44, "servo impending failure too many block reassigns",
8927c478bd9Sstevel@tonic-gate 	0x5d, 0x45, "servo impending failure access times too high",
8937c478bd9Sstevel@tonic-gate 	0x5d, 0x46, "servo impending failure start unit times too high",
8947c478bd9Sstevel@tonic-gate 	0x5d, 0x47, "servo impending failure channel parametrics",
8957c478bd9Sstevel@tonic-gate 	0x5d, 0x48, "servo impending failure controller detected",
8967c478bd9Sstevel@tonic-gate 	0x5d, 0x49, "servo impending failure throughput performance",
8977c478bd9Sstevel@tonic-gate 	0x5d, 0x4a, "servo impending failure seek time performance",
8987c478bd9Sstevel@tonic-gate 	0x5d, 0x4b, "servo impending failure spin-up retry count",
8997c478bd9Sstevel@tonic-gate 	0x5d, 0x4c, "servo impending failure drive calibration retry count",
9007c478bd9Sstevel@tonic-gate 	0x5d, 0x50, "spindle impending failure general hard drive failure",
9017c478bd9Sstevel@tonic-gate 	0x5d, 0x51, "spindle impending failure drive error rate too high",
9027c478bd9Sstevel@tonic-gate 	0x5d, 0x52, "spindle impending failure data error rate too high",
9037c478bd9Sstevel@tonic-gate 	0x5d, 0x53, "spindle impending failure seek error rate too high",
9047c478bd9Sstevel@tonic-gate 	0x5d, 0x54, "spindle impending failure too many block reassigns",
9057c478bd9Sstevel@tonic-gate 	0x5d, 0x55, "spindle impending failure access times too high",
9067c478bd9Sstevel@tonic-gate 	0x5d, 0x56, "spindle impending failure start unit times too high",
9077c478bd9Sstevel@tonic-gate 	0x5d, 0x57, "spindle impending failure channel parametrics",
9087c478bd9Sstevel@tonic-gate 	0x5d, 0x58, "spindle impending failure controller detected",
9097c478bd9Sstevel@tonic-gate 	0x5d, 0x59, "spindle impending failure throughput performance",
9107c478bd9Sstevel@tonic-gate 	0x5d, 0x5a, "spindle impending failure seek time performance",
9117c478bd9Sstevel@tonic-gate 	0x5d, 0x5b, "spindle impending failure spin-up retry count",
9127c478bd9Sstevel@tonic-gate 	0x5d, 0x5c, "spindle impending failure drive calibration retry count",
9137c478bd9Sstevel@tonic-gate 	0x5d, 0x60, "firmware impending failure general hard drive failure",
9147c478bd9Sstevel@tonic-gate 	0x5d, 0x61, "firmware impending failure drive error rate too high",
9157c478bd9Sstevel@tonic-gate 	0x5d, 0x62, "firmware impending failure data error rate too high",
9167c478bd9Sstevel@tonic-gate 	0x5d, 0x63, "firmware impending failure seek error rate too high",
9177c478bd9Sstevel@tonic-gate 	0x5d, 0x64, "firmware impending failure too many block reassigns",
9187c478bd9Sstevel@tonic-gate 	0x5d, 0x65, "firmware impending failure access times too high",
9197c478bd9Sstevel@tonic-gate 	0x5d, 0x66, "firmware impending failure start unit times too high",
9207c478bd9Sstevel@tonic-gate 	0x5d, 0x67, "firmware impending failure channel parametrics",
9217c478bd9Sstevel@tonic-gate 	0x5d, 0x68, "firmware impending failure controller detected",
9227c478bd9Sstevel@tonic-gate 	0x5d, 0x69, "firmware impending failure throughput performance",
9237c478bd9Sstevel@tonic-gate 	0x5d, 0x6a, "firmware impending failure seek time performance",
9247c478bd9Sstevel@tonic-gate 	0x5d, 0x6b, "firmware impending failure spin-up retry count",
9257c478bd9Sstevel@tonic-gate 	0x5d, 0x6c, "firmware impending failure drive calibration retry count",
9267c478bd9Sstevel@tonic-gate 	0x5d, 0xff, "failure prediction threshold exceeded (false)",
9277c478bd9Sstevel@tonic-gate 	0x5e, 0x00, "low power condition active",
9287c478bd9Sstevel@tonic-gate 	0x5e, 0x01, "idle condition activated by timer",
9297c478bd9Sstevel@tonic-gate 	0x5e, 0x02, "standby condition activated by timer",
9307c478bd9Sstevel@tonic-gate 	0x5e, 0x03, "idle condition activated by command",
9317c478bd9Sstevel@tonic-gate 	0x5e, 0x04, "standby condition activated by command",
9327c478bd9Sstevel@tonic-gate 	0x60, 0x00, "lamp failure",
933d91393a8SChris Horne 	0x61, 0x00, "video acquisition error",
9347c478bd9Sstevel@tonic-gate 	0x62, 0x00, "scan head positioning error",
9357c478bd9Sstevel@tonic-gate 	0x63, 0x00, "end of user area encountered on this track",
9367c478bd9Sstevel@tonic-gate 	0x63, 0x01, "packet does not fit in available space",
9377c478bd9Sstevel@tonic-gate 	0x64, 0x00, "illegal mode for this track",
9387c478bd9Sstevel@tonic-gate 	0x64, 0x01, "invalid packet size",
9397c478bd9Sstevel@tonic-gate 	0x65, 0x00, "voltage fault",
9407c478bd9Sstevel@tonic-gate 	0x66, 0x00, "automatic document feeder cover up",
9417c478bd9Sstevel@tonic-gate 	0x67, 0x00, "configuration failure",
9427c478bd9Sstevel@tonic-gate 	0x67, 0x01, "configuration of incapable LUNs failed",
9437c478bd9Sstevel@tonic-gate 	0x67, 0x02, "add LUN failed",
9447c478bd9Sstevel@tonic-gate 	0x67, 0x03, "modification of LUN failed",
9457c478bd9Sstevel@tonic-gate 	0x67, 0x04, "exchange of LUN failed",
9467c478bd9Sstevel@tonic-gate 	0x67, 0x05, "remove of LUN failed",
9477c478bd9Sstevel@tonic-gate 	0x67, 0x06, "attachment of LUN failed",
9487c478bd9Sstevel@tonic-gate 	0x67, 0x07, "creation of LUN failed",
9497c478bd9Sstevel@tonic-gate 	0x67, 0x08, "assign failure occurred",
9507c478bd9Sstevel@tonic-gate 	0x67, 0x09, "multiply assigned LUN",
9517c478bd9Sstevel@tonic-gate 	0x67, 0x0a, "set target port groups command failed",
9527c478bd9Sstevel@tonic-gate 	0x68, 0x00, "logical unit not configured",
9537c478bd9Sstevel@tonic-gate 	0x69, 0x00, "data loss on logical unit",
9547c478bd9Sstevel@tonic-gate 	0x69, 0x01, "multiple LUN failures",
9557c478bd9Sstevel@tonic-gate 	0x69, 0x02, "parity/data mismatch",
9567c478bd9Sstevel@tonic-gate 	0x6a, 0x00, "informational, refer to log",
957d91393a8SChris Horne 	0x6b, 0x00, "state change has occurred",
9587c478bd9Sstevel@tonic-gate 	0x6b, 0x01, "redundancy level got better",
9597c478bd9Sstevel@tonic-gate 	0x6b, 0x02, "redundancy level got worse",
960d91393a8SChris Horne 	0x6c, 0x00, "rebuild failure occurred",
961d91393a8SChris Horne 	0x6d, 0x00, "recalculate failure occurred",
9627c478bd9Sstevel@tonic-gate 	0x6e, 0x00, "command to logical unit failed",
9637c478bd9Sstevel@tonic-gate 	0x6f, 0x00, "copy protect key exchange failure authentication failure",
9647c478bd9Sstevel@tonic-gate 	0x6f, 0x01, "copy protect key exchange failure key not present",
9657c478bd9Sstevel@tonic-gate 	0x6f, 0x02, "copy protect key exchange failure key not established",
9667c478bd9Sstevel@tonic-gate 	0x6f, 0x03, "read of scrambled sector without authentication",
9677c478bd9Sstevel@tonic-gate 	0x6f, 0x04, "media region code is mismatched to LUN region",
9687c478bd9Sstevel@tonic-gate 	0x6f, 0x05, "drive region must be permanent/region reset count error",
9697c478bd9Sstevel@tonic-gate 	0x70, 0xffff, "decompression exception short algorithm id of ASCQ",
9707c478bd9Sstevel@tonic-gate 	0x71, 0x00, "decompression exception long algorithm id",
9717c478bd9Sstevel@tonic-gate 	0x72, 0x00, "session fixation error",
9727c478bd9Sstevel@tonic-gate 	0x72, 0x01, "session fixation error writing lead-in",
9737c478bd9Sstevel@tonic-gate 	0x72, 0x02, "session fixation error writing lead-out",
9747c478bd9Sstevel@tonic-gate 	0x72, 0x03, "session fixation error - incomplete track in session",
9757c478bd9Sstevel@tonic-gate 	0x72, 0x04, "empty or partially written reserved track",
9767c478bd9Sstevel@tonic-gate 	0x72, 0x05, "no more track reservations allowed",
9777c478bd9Sstevel@tonic-gate 	0x73, 0x00, "cd control error",
9787c478bd9Sstevel@tonic-gate 	0x73, 0x01, "power calibration area almost full",
9797c478bd9Sstevel@tonic-gate 	0x73, 0x02, "power calibration area is full",
9807c478bd9Sstevel@tonic-gate 	0x73, 0x03, "power calibration area error",
9817c478bd9Sstevel@tonic-gate 	0x73, 0x04, "program memory area update failure",
9827c478bd9Sstevel@tonic-gate 	0x73, 0x05, "program memory area is full",
9837c478bd9Sstevel@tonic-gate 	0x73, 0x06, "rma/pma is almost full",
9847c478bd9Sstevel@tonic-gate 	0xffff, 0xffff, NULL
9857c478bd9Sstevel@tonic-gate };
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate char *
scsi_esname(uint_t key,char * tmpstr)9887c478bd9Sstevel@tonic-gate scsi_esname(uint_t key, char *tmpstr)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	int i = 0;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	while (extended_sense_list[i].asc != 0xffff) {
9937c478bd9Sstevel@tonic-gate 		if (key == extended_sense_list[i].asc) {
9947c478bd9Sstevel@tonic-gate 			return ((char *)extended_sense_list[i].message);
9957c478bd9Sstevel@tonic-gate 		}
9967c478bd9Sstevel@tonic-gate 		i++;
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 	return (sprintf(tmpstr, "<vendor unique code 0x%x>", key));
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate char *
scsi_asc_name(uint_t asc,uint_t ascq,char * tmpstr)10027c478bd9Sstevel@tonic-gate scsi_asc_name(uint_t asc, uint_t ascq, char *tmpstr)
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate 	int i = 0;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	while (extended_sense_list[i].asc != 0xffff) {
10077c478bd9Sstevel@tonic-gate 		if ((asc == extended_sense_list[i].asc) &&
10087c478bd9Sstevel@tonic-gate 		    ((ascq == extended_sense_list[i].ascq) ||
10097c478bd9Sstevel@tonic-gate 		    (extended_sense_list[i].ascq == 0xffff))) {
10107c478bd9Sstevel@tonic-gate 			return ((char *)extended_sense_list[i].message);
10117c478bd9Sstevel@tonic-gate 		}
10127c478bd9Sstevel@tonic-gate 		i++;
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate 	return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate char *
scsi_sname(uchar_t sense_key)10187c478bd9Sstevel@tonic-gate scsi_sname(uchar_t sense_key)
10197c478bd9Sstevel@tonic-gate {
10207c478bd9Sstevel@tonic-gate 	if (sense_key >= (uchar_t)(NUM_SENSE_KEYS+NUM_IMPL_SENSE_KEYS)) {
10217c478bd9Sstevel@tonic-gate 		return ("<unknown sense key>");
10227c478bd9Sstevel@tonic-gate 	} else {
10237c478bd9Sstevel@tonic-gate 		return (sense_keys[sense_key]);
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate /*
10297c478bd9Sstevel@tonic-gate  * Print a piece of inquiry data- cleaned up for non-printable characters.
10307c478bd9Sstevel@tonic-gate  */
10317c478bd9Sstevel@tonic-gate static void
inq_fill(char * p,int l,char * s)10327c478bd9Sstevel@tonic-gate inq_fill(char *p, int l, char *s)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	register unsigned i = 0;
10357c478bd9Sstevel@tonic-gate 	char c;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if (!p)
10387c478bd9Sstevel@tonic-gate 		return;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	while (i++ < l) {
10417c478bd9Sstevel@tonic-gate 		/* clean string of non-printing chars */
10427c478bd9Sstevel@tonic-gate 		if ((c = *p++) < ' ' || c >= 0177) {
10437c478bd9Sstevel@tonic-gate 			c = ' ';
10447c478bd9Sstevel@tonic-gate 		}
10457c478bd9Sstevel@tonic-gate 		*s++ = c;
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 	*s++ = 0;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate static char *
scsi_asc_search(uint_t asc,uint_t ascq,struct scsi_asq_key_strings * list)10517c478bd9Sstevel@tonic-gate scsi_asc_search(uint_t asc, uint_t ascq,
10527c478bd9Sstevel@tonic-gate     struct scsi_asq_key_strings *list)
10537c478bd9Sstevel@tonic-gate {
10547c478bd9Sstevel@tonic-gate 	int i = 0;
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	while (list[i].asc != 0xffff) {
10577c478bd9Sstevel@tonic-gate 		if ((asc == list[i].asc) &&
10587c478bd9Sstevel@tonic-gate 		    ((ascq == list[i].ascq) ||
10597c478bd9Sstevel@tonic-gate 		    (list[i].ascq == 0xffff))) {
10607c478bd9Sstevel@tonic-gate 			return ((char *)list[i].message);
10617c478bd9Sstevel@tonic-gate 		}
10627c478bd9Sstevel@tonic-gate 		i++;
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	return (NULL);
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate static char *
scsi_asc_ascq_name(uint_t asc,uint_t ascq,char * tmpstr,struct scsi_asq_key_strings * list)10687c478bd9Sstevel@tonic-gate scsi_asc_ascq_name(uint_t asc, uint_t ascq, char *tmpstr,
1069e6915ea4SToomas Soome     struct scsi_asq_key_strings *list)
10707c478bd9Sstevel@tonic-gate {
10717c478bd9Sstevel@tonic-gate 	char *message;
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	if (list) {
10747c478bd9Sstevel@tonic-gate 		if (message = scsi_asc_search(asc, ascq, list)) {
10757c478bd9Sstevel@tonic-gate 			return (message);
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 	if (message = scsi_asc_search(asc, ascq, extended_sense_list)) {
10797c478bd9Sstevel@tonic-gate 		return (message);
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	return (sprintf(tmpstr, "<vendor unique code 0x%x>", asc));
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate /*
10867c478bd9Sstevel@tonic-gate  * The first part/column of the error message will be at least this length.
10877c478bd9Sstevel@tonic-gate  * This number has been calculated so that each line fits in 80 chars.
10887c478bd9Sstevel@tonic-gate  */
10897c478bd9Sstevel@tonic-gate #define	SCSI_ERRMSG_COLUMN_LEN	42
10907c478bd9Sstevel@tonic-gate #define	SCSI_ERRMSG_BUF_LEN	256
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@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))10939e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_generic_errmsg(struct scsi_device *devp, char *label, int severity,
10949e1c849eSDavid Zhang - Sun Microsystems - Beijing China     daddr_t blkno, daddr_t err_blkno,
10959e1c849eSDavid Zhang - Sun Microsystems - Beijing China     uchar_t cmd_name, struct scsi_key_strings *cmdlist,
10969e1c849eSDavid Zhang - Sun Microsystems - Beijing China     uint8_t *sensep, struct scsi_asq_key_strings *asc_list,
10977c478bd9Sstevel@tonic-gate     char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
10987c478bd9Sstevel@tonic-gate {
10997c478bd9Sstevel@tonic-gate 	uchar_t com;
11007c478bd9Sstevel@tonic-gate 	static char buf[SCSI_ERRMSG_BUF_LEN];
11017c478bd9Sstevel@tonic-gate 	static char buf1[SCSI_ERRMSG_BUF_LEN];
11027c478bd9Sstevel@tonic-gate 	static char tmpbuf[64];
11037c478bd9Sstevel@tonic-gate 	static char pad[SCSI_ERRMSG_COLUMN_LEN];
11047c478bd9Sstevel@tonic-gate 	dev_info_t *dev = devp->sd_dev;
11057c478bd9Sstevel@tonic-gate 	static char *error_classes[] = {
11067c478bd9Sstevel@tonic-gate 		"All", "Unknown", "Informational",
11077c478bd9Sstevel@tonic-gate 		"Recovered", "Retryable", "Fatal"
11087c478bd9Sstevel@tonic-gate 	};
11095c46c6a0Spd 	uchar_t sense_key, asc, ascq, fru_code;
11105c46c6a0Spd 	uchar_t *fru_code_ptr;
11117c478bd9Sstevel@tonic-gate 	int i, buflen;
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	mutex_enter(&scsi_log_mutex);
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	/*
11167c478bd9Sstevel@tonic-gate 	 * We need to put our space padding code because kernel version
11177c478bd9Sstevel@tonic-gate 	 * of sprintf(9F) doesn't support %-<number>s type of left alignment.
11187c478bd9Sstevel@tonic-gate 	 */
11197c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCSI_ERRMSG_COLUMN_LEN; i++) {
11207c478bd9Sstevel@tonic-gate 		pad[i] = ' ';
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 
1123d91393a8SChris Horne 	bzero(buf, SCSI_ERRMSG_BUF_LEN);
11249e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	com = cmd_name;
11257c478bd9Sstevel@tonic-gate 	(void) sprintf(buf, "Error for Command: %s",
11267c478bd9Sstevel@tonic-gate 	    scsi_cmd_name(com, cmdlist, tmpbuf));
11277c478bd9Sstevel@tonic-gate 	buflen = strlen(buf);
11287c478bd9Sstevel@tonic-gate 	if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11297c478bd9Sstevel@tonic-gate 		pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
11307c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[buflen], "%s Error Level: %s",
11317c478bd9Sstevel@tonic-gate 		    pad, error_classes[severity]);
11327c478bd9Sstevel@tonic-gate 		pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
11337c478bd9Sstevel@tonic-gate 	} else {
11347c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[buflen], " Error Level: %s",
11357c478bd9Sstevel@tonic-gate 		    error_classes[severity]);
11367c478bd9Sstevel@tonic-gate 	}
11377c478bd9Sstevel@tonic-gate 	impl_scsi_log(dev, label, CE_WARN, buf);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	if (blkno != -1 || err_blkno != -1 &&
11407c478bd9Sstevel@tonic-gate 	    ((com & 0xf) == SCMD_READ) || ((com & 0xf) == SCMD_WRITE)) {
1141d91393a8SChris Horne 		bzero(buf, SCSI_ERRMSG_BUF_LEN);
11427c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "Requested Block: %ld", blkno);
11437c478bd9Sstevel@tonic-gate 		buflen = strlen(buf);
11447c478bd9Sstevel@tonic-gate 		if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11457c478bd9Sstevel@tonic-gate 			pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
11467c478bd9Sstevel@tonic-gate 			(void) sprintf(&buf[buflen], "%s Error Block: %ld\n",
11477c478bd9Sstevel@tonic-gate 			    pad, err_blkno);
11487c478bd9Sstevel@tonic-gate 			pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
11497c478bd9Sstevel@tonic-gate 		} else {
11507c478bd9Sstevel@tonic-gate 			(void) sprintf(&buf[buflen], " Error Block: %ld\n",
11517c478bd9Sstevel@tonic-gate 			    err_blkno);
11527c478bd9Sstevel@tonic-gate 		}
11537c478bd9Sstevel@tonic-gate 		impl_scsi_log(dev, label, CE_CONT, buf);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 
1156d91393a8SChris Horne 	bzero(buf, SCSI_ERRMSG_BUF_LEN);
11577c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, "Vendor: ");
11587c478bd9Sstevel@tonic-gate 	inq_fill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]);
11597c478bd9Sstevel@tonic-gate 	buflen = strlen(buf);
11607c478bd9Sstevel@tonic-gate 	if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11617c478bd9Sstevel@tonic-gate 		pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = '\0';
11627c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[strlen(buf)], "%s Serial Number: ", pad);
11637c478bd9Sstevel@tonic-gate 		pad[SCSI_ERRMSG_COLUMN_LEN - buflen] = ' ';
11647c478bd9Sstevel@tonic-gate 	} else {
11657c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[strlen(buf)], " Serial Number: ");
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 	inq_fill(devp->sd_inq->inq_serial, 12, &buf[strlen(buf)]);
11687c478bd9Sstevel@tonic-gate 	impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	if (sensep) {
11719e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		sense_key = scsi_sense_key(sensep);
11729e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		asc = scsi_sense_asc(sensep);
11739e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		ascq = scsi_sense_ascq(sensep);
11749e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		scsi_ext_sense_fields(sensep, SENSE_LENGTH,
11755c46c6a0Spd 		    NULL, NULL, &fru_code_ptr, NULL, NULL);
11765c46c6a0Spd 		fru_code = (fru_code_ptr ? *fru_code_ptr : 0);
11775c46c6a0Spd 
1178d91393a8SChris Horne 		bzero(buf, SCSI_ERRMSG_BUF_LEN);
11797c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "Sense Key: %s\n",
11805c46c6a0Spd 		    sense_keys[sense_key]);
11817c478bd9Sstevel@tonic-gate 		impl_scsi_log(dev, label, CE_CONT, buf);
11827c478bd9Sstevel@tonic-gate 
1183d91393a8SChris Horne 		bzero(buf, SCSI_ERRMSG_BUF_LEN);
11845c46c6a0Spd 		if ((fru_code != 0) &&
11857c478bd9Sstevel@tonic-gate 		    (decode_fru != NULL)) {
11867c478bd9Sstevel@tonic-gate 			(*decode_fru)(devp, buf, SCSI_ERRMSG_BUF_LEN,
11875c46c6a0Spd 			    fru_code);
1188e6915ea4SToomas Soome 			if (buf[0] != '\0') {
1189d91393a8SChris Horne 				bzero(buf1, SCSI_ERRMSG_BUF_LEN);
11907c478bd9Sstevel@tonic-gate 				(void) sprintf(&buf1[strlen(buf1)],
11915c46c6a0Spd 				    "ASC: 0x%x (%s)", asc,
11925c46c6a0Spd 				    scsi_asc_ascq_name(asc, ascq,
11931e1ddd6cScth 				    tmpbuf, asc_list));
11947c478bd9Sstevel@tonic-gate 				buflen = strlen(buf1);
11957c478bd9Sstevel@tonic-gate 				if (buflen < SCSI_ERRMSG_COLUMN_LEN) {
11961e1ddd6cScth 					pad[SCSI_ERRMSG_COLUMN_LEN - buflen] =
11971e1ddd6cScth 					    '\0';
11981e1ddd6cScth 					(void) sprintf(&buf1[buflen],
11991e1ddd6cScth 					    "%s ASCQ: 0x%x", pad, ascq);
12007c478bd9Sstevel@tonic-gate 				} else {
12011e1ddd6cScth 					(void) sprintf(&buf1[buflen],
12021e1ddd6cScth 					    " ASCQ: 0x%x", ascq);
12037c478bd9Sstevel@tonic-gate 				}
12047c478bd9Sstevel@tonic-gate 				impl_scsi_log(dev,
12051e1ddd6cScth 				    label, CE_CONT, "%s\n", buf1);
12061e1ddd6cScth 				impl_scsi_log(dev,
12071e1ddd6cScth 				    label, CE_CONT, "FRU: 0x%x (%s)\n",
12081e1ddd6cScth 				    fru_code, buf);
12097c478bd9Sstevel@tonic-gate 				mutex_exit(&scsi_log_mutex);
12107c478bd9Sstevel@tonic-gate 				return;
12117c478bd9Sstevel@tonic-gate 			}
12127c478bd9Sstevel@tonic-gate 		}
12137c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[strlen(buf)],
12147c478bd9Sstevel@tonic-gate 		    "ASC: 0x%x (%s), ASCQ: 0x%x, FRU: 0x%x",
12155c46c6a0Spd 		    asc, scsi_asc_ascq_name(asc, ascq, tmpbuf, asc_list),
12165c46c6a0Spd 		    ascq, fru_code);
12177c478bd9Sstevel@tonic-gate 		impl_scsi_log(dev, label, CE_CONT, "%s\n", buf);
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 	mutex_exit(&scsi_log_mutex);
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate 
12229e1c849eSDavid Zhang - Sun Microsystems - Beijing China 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))12239e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_vu_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
12249e1c849eSDavid Zhang - Sun Microsystems - Beijing China     int severity, daddr_t blkno, daddr_t err_blkno,
12259e1c849eSDavid Zhang - Sun Microsystems - Beijing China     struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep,
12269e1c849eSDavid Zhang - Sun Microsystems - Beijing China     struct scsi_asq_key_strings *asc_list,
12279e1c849eSDavid Zhang - Sun Microsystems - Beijing China     char *(*decode_fru)(struct scsi_device *, char *, int, uchar_t))
12289e1c849eSDavid Zhang - Sun Microsystems - Beijing China {
12299e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uchar_t com;
12309e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
12319e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	com = ((union scsi_cdb *)pkt->pkt_cdbp)->scc_cmd;
12329e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
12339e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	scsi_generic_errmsg(devp, label, severity, blkno, err_blkno,
12349e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	    com, cmdlist, (uint8_t *)sensep, asc_list, decode_fru);
12359e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
12369e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
12379e1c849eSDavid Zhang - Sun Microsystems - Beijing China }
12389e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
12397c478bd9Sstevel@tonic-gate 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)12407c478bd9Sstevel@tonic-gate scsi_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, char *label,
12417c478bd9Sstevel@tonic-gate     int severity, daddr_t blkno, daddr_t err_blkno,
12427c478bd9Sstevel@tonic-gate     struct scsi_key_strings *cmdlist, struct scsi_extended_sense *sensep)
12437c478bd9Sstevel@tonic-gate {
12447c478bd9Sstevel@tonic-gate 	scsi_vu_errmsg(devp, pkt, label, severity, blkno,
12451e1ddd6cScth 	    err_blkno, cmdlist, sensep, NULL, NULL);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
12497c478bd9Sstevel@tonic-gate void
scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)12507c478bd9Sstevel@tonic-gate scsi_log(dev_info_t *dev, char *label, uint_t level,
12517c478bd9Sstevel@tonic-gate     const char *fmt, ...)
12527c478bd9Sstevel@tonic-gate {
12537c478bd9Sstevel@tonic-gate 	va_list ap;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
12567c478bd9Sstevel@tonic-gate 	mutex_enter(&scsi_log_mutex);
12577c478bd9Sstevel@tonic-gate 	v_scsi_log(dev, label, level, fmt, ap);
12587c478bd9Sstevel@tonic-gate 	mutex_exit(&scsi_log_mutex);
12597c478bd9Sstevel@tonic-gate 	va_end(ap);
12607c478bd9Sstevel@tonic-gate }
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
12637c478bd9Sstevel@tonic-gate static void
impl_scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)12647c478bd9Sstevel@tonic-gate impl_scsi_log(dev_info_t *dev, char *label, uint_t level,
12657c478bd9Sstevel@tonic-gate     const char *fmt, ...)
12667c478bd9Sstevel@tonic-gate {
12677c478bd9Sstevel@tonic-gate 	va_list ap;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsi_log_mutex));
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
12727c478bd9Sstevel@tonic-gate 	v_scsi_log(dev, label, level, fmt, ap);
12737c478bd9Sstevel@tonic-gate 	va_end(ap);
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate char *ddi_pathname(dev_info_t *dip, char *path);
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate /*PRINTFLIKE4*/
12807c478bd9Sstevel@tonic-gate static void
v_scsi_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,va_list ap)12817c478bd9Sstevel@tonic-gate v_scsi_log(dev_info_t *dev, char *label, uint_t level,
12827c478bd9Sstevel@tonic-gate     const char *fmt, va_list ap)
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate 	static char name[256];
12857c478bd9Sstevel@tonic-gate 	int log_only = 0;
12867c478bd9Sstevel@tonic-gate 	int boot_only = 0;
12877c478bd9Sstevel@tonic-gate 	int console_only = 0;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&scsi_log_mutex));
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	if (dev) {
12927c478bd9Sstevel@tonic-gate 		if (level == CE_PANIC || level == CE_WARN ||
12937c478bd9Sstevel@tonic-gate 		    level == CE_NOTE) {
12947c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%s (%s%d):\n",
12951e1ddd6cScth 			    ddi_pathname(dev, scsi_log_buffer),
12961e1ddd6cScth 			    label, ddi_get_instance(dev));
12977c478bd9Sstevel@tonic-gate 		} else if (level >= (uint_t)SCSI_DEBUG) {
12987c478bd9Sstevel@tonic-gate 			(void) sprintf(name,
12997c478bd9Sstevel@tonic-gate 			    "%s%d:", label, ddi_get_instance(dev));
13007c478bd9Sstevel@tonic-gate 		} else {
13017c478bd9Sstevel@tonic-gate 			name[0] = '\0';
13027c478bd9Sstevel@tonic-gate 		}
13037c478bd9Sstevel@tonic-gate 	} else {
13047c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "%s:", label);
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	(void) vsprintf(scsi_log_buffer, fmt, ap);
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	switch (scsi_log_buffer[0]) {
13107c478bd9Sstevel@tonic-gate 	case '!':
13117c478bd9Sstevel@tonic-gate 		log_only = 1;
13127c478bd9Sstevel@tonic-gate 		break;
13137c478bd9Sstevel@tonic-gate 	case '?':
13147c478bd9Sstevel@tonic-gate 		boot_only = 1;
13157c478bd9Sstevel@tonic-gate 		break;
13167c478bd9Sstevel@tonic-gate 	case '^':
13177c478bd9Sstevel@tonic-gate 		console_only = 1;
13187c478bd9Sstevel@tonic-gate 		break;
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	switch (level) {
13227c478bd9Sstevel@tonic-gate 	case CE_NOTE:
13237c478bd9Sstevel@tonic-gate 		level = CE_CONT;
13247c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
13257c478bd9Sstevel@tonic-gate 	case CE_CONT:
13267c478bd9Sstevel@tonic-gate 	case CE_WARN:
13277c478bd9Sstevel@tonic-gate 	case CE_PANIC:
13287c478bd9Sstevel@tonic-gate 		if (boot_only) {
13291e1ddd6cScth 			cmn_err(level, "?%s\t%s", name, &scsi_log_buffer[1]);
13307c478bd9Sstevel@tonic-gate 		} else if (console_only) {
13311e1ddd6cScth 			cmn_err(level, "^%s\t%s", name, &scsi_log_buffer[1]);
13327c478bd9Sstevel@tonic-gate 		} else if (log_only) {
13331e1ddd6cScth 			cmn_err(level, "!%s\t%s", name, &scsi_log_buffer[1]);
13347c478bd9Sstevel@tonic-gate 		} else {
13351e1ddd6cScth 			cmn_err(level, "%s\t%s", name, scsi_log_buffer);
13367c478bd9Sstevel@tonic-gate 		}
13377c478bd9Sstevel@tonic-gate 		break;
13387c478bd9Sstevel@tonic-gate 	case (uint_t)SCSI_DEBUG:
13397c478bd9Sstevel@tonic-gate 	default:
13401e1ddd6cScth 		cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, scsi_log_buffer);
13417c478bd9Sstevel@tonic-gate 		break;
13427c478bd9Sstevel@tonic-gate 	}
13437c478bd9Sstevel@tonic-gate }
13447c478bd9Sstevel@tonic-gate 
13451e1ddd6cScth /*
13461e1ddd6cScth  * Lookup the 'prop_name' string array property and walk thru its list of
13471e1ddd6cScth  * tuple values looking for a tuple who's VID/PID string (first part of tuple)
13481e1ddd6cScth  * matches the inquiry VID/PID information for the scsi_device.  On a match,
13491e1ddd6cScth  * return a duplicate of the second part of the tuple.  If no match is found,
13501e1ddd6cScth  * return NULL. On non-NULL return, caller is responsible for freeing return
13511e1ddd6cScth  * result via:
13521e1ddd6cScth  *	kmem_free(string, strlen(string) + 1);
13531e1ddd6cScth  *
13541e1ddd6cScth  * This interface can either be used directly, or indirectly by
13551e1ddd6cScth  * scsi_get_device_type_scsi_options.
13561e1ddd6cScth  */
13571e1ddd6cScth char	*
scsi_get_device_type_string(char * prop_name,dev_info_t * dip,struct scsi_device * devp)13581e1ddd6cScth scsi_get_device_type_string(char *prop_name,
13591e1ddd6cScth     dev_info_t *dip, struct scsi_device *devp)
13607c478bd9Sstevel@tonic-gate {
13611e1ddd6cScth 	struct scsi_inquiry	*inq = devp->sd_inq;
13621e1ddd6cScth 	char			**tuples;
13631e1ddd6cScth 	uint_t			ntuples;
13641e1ddd6cScth 	int			i;
13651e1ddd6cScth 	char			*tvp;		/* tuple vid/pid */
13661e1ddd6cScth 	char			*trs;		/* tuple return string */
13671e1ddd6cScth 	int			tvp_len;
13681e1ddd6cScth 
13691e1ddd6cScth 	/* if we have no inquiry data then we can't do this */
13701e1ddd6cScth 	if (inq == NULL)
13711e1ddd6cScth 		return (NULL);
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	/*
13741e1ddd6cScth 	 * So that we can establish a 'prop_name' for all instances of a
13751e1ddd6cScth 	 * device in the system in a single place if needed (via options.conf),
13761e1ddd6cScth 	 * we loop going up to the root ourself. This way root lookup does
13771e1ddd6cScth 	 * *not* specify DDI_PROP_DONTPASS, and the code will look on the
13781e1ddd6cScth 	 * options node.
13797c478bd9Sstevel@tonic-gate 	 */
13801e1ddd6cScth 	do {
13811e1ddd6cScth 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
13821e1ddd6cScth 		    (ddi_get_parent(dip) ? DDI_PROP_DONTPASS : 0) |
13831e1ddd6cScth 		    DDI_PROP_NOTPROM, prop_name, &tuples, &ntuples) ==
13841e1ddd6cScth 		    DDI_PROP_SUCCESS) {
13851e1ddd6cScth 
13861e1ddd6cScth 			/* loop over tuples */
13871e1ddd6cScth 			for (i = 0;  i < (ntuples/2); i++) {
13881e1ddd6cScth 				/* split into vid/pid and return-string */
13891e1ddd6cScth 				tvp = tuples[i * 2];
13901e1ddd6cScth 				trs = tuples[(i * 2) + 1];
13911e1ddd6cScth 				tvp_len = strlen(tvp);
13921e1ddd6cScth 
13931e1ddd6cScth 				/* check for vid/pid match */
13941e1ddd6cScth 				if ((tvp_len == 0) ||
13951e1ddd6cScth 				    bcmp(tvp, inq->inq_vid, tvp_len))
13961e1ddd6cScth 					continue;	/* no match */
13971e1ddd6cScth 
13981e1ddd6cScth 				/* match, dup return-string */
13991e1ddd6cScth 				trs = i_ddi_strdup(trs, KM_SLEEP);
14001e1ddd6cScth 				ddi_prop_free(tuples);
14011e1ddd6cScth 				return (trs);
14021e1ddd6cScth 			}
14031e1ddd6cScth 			ddi_prop_free(tuples);
14041e1ddd6cScth 		}
14057c478bd9Sstevel@tonic-gate 
14061e1ddd6cScth 		/* climb up to root one step at a time */
14071e1ddd6cScth 		dip = ddi_get_parent(dip);
14081e1ddd6cScth 	} while (dip);
14097c478bd9Sstevel@tonic-gate 
14101e1ddd6cScth 	return (NULL);
14111e1ddd6cScth }
14127c478bd9Sstevel@tonic-gate 
14131e1ddd6cScth /*
14141e1ddd6cScth  * The 'device-type-scsi-options' mechanism can be used to establish a device
14151e1ddd6cScth  * specific scsi_options value for a particular device. This mechanism uses
14161e1ddd6cScth  * paired strings ("vendor_info", "options_property_name") from the string
14171e1ddd6cScth  * array "device-type-scsi-options" definition. A bcmp of the vendor info is
14181e1ddd6cScth  * done against the inquiry data (inq_vid). Here is an example of use:
14191e1ddd6cScth  *
14201e1ddd6cScth  * device-type-scsi-options-list =
14211e1ddd6cScth  *	"FOOLCO  Special x1000", "foolco-scsi-options",
14221e1ddd6cScth  *	"FOOLCO  Special y1000", "foolco-scsi-options";
14231e1ddd6cScth  * foolco-scsi-options = 0xXXXXXXXX;
14241e1ddd6cScth  */
14251e1ddd6cScth int
scsi_get_device_type_scsi_options(dev_info_t * dip,struct scsi_device * devp,int options)14261e1ddd6cScth scsi_get_device_type_scsi_options(dev_info_t *dip,
14271e1ddd6cScth     struct scsi_device *devp, int options)
14281e1ddd6cScth {
14291e1ddd6cScth 	char	*string;
14307c478bd9Sstevel@tonic-gate 
14311e1ddd6cScth 	if ((string = scsi_get_device_type_string(
14321e1ddd6cScth 	    "device-type-scsi-options-list", dip, devp)) != NULL) {
14331e1ddd6cScth 		options = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
14341e1ddd6cScth 		    string, options);
14351e1ddd6cScth 		kmem_free(string, strlen(string) + 1);
14361e1ddd6cScth 	}
14377c478bd9Sstevel@tonic-gate 	return (options);
14387c478bd9Sstevel@tonic-gate }
14395c46c6a0Spd 
1440d91393a8SChris Horne /*
1441d91393a8SChris Horne  * Find the scsi_options for a scsi_device. The precedence is:
1442d91393a8SChris Horne  *
1443d91393a8SChris Horne  *	target<%d>-scsi-options		highest
1444d91393a8SChris Horne  *	device-type-scsi-options
1445d91393a8SChris Horne  *	per bus scsi-options (parent)
1446d91393a8SChris Horne  *	global scsi-options
1447d91393a8SChris Horne  *	default_scsi_options argument	lowest
1448d91393a8SChris Horne  *
1449d91393a8SChris Horne  * If the global is used then it has already been established
1450d91393a8SChris Horne  * on the parent scsi_hba_attach_setup.
1451d91393a8SChris Horne  */
1452d91393a8SChris Horne int
scsi_get_scsi_options(struct scsi_device * sd,int default_scsi_options)1453d91393a8SChris Horne scsi_get_scsi_options(struct scsi_device *sd, int default_scsi_options)
1454d91393a8SChris Horne {
1455d91393a8SChris Horne 	dev_info_t	*parent;
1456d91393a8SChris Horne 	int		options = -1;
1457d91393a8SChris Horne 	int		tgt;
1458d91393a8SChris Horne 	char		topt[32];
1459d91393a8SChris Horne 
1460d91393a8SChris Horne 	if ((sd == NULL) || (sd->sd_dev == NULL))
1461d91393a8SChris Horne 		return (default_scsi_options);
1462d91393a8SChris Horne 
1463d91393a8SChris Horne 	parent = ddi_get_parent(sd->sd_dev);
1464d91393a8SChris Horne 
1465d91393a8SChris Horne 	if ((tgt = ddi_prop_get_int(DDI_DEV_T_ANY, sd->sd_dev,
1466d91393a8SChris Horne 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "target", -1)) != -1) {
1467d91393a8SChris Horne 		(void) sprintf(topt, "target%d-scsi-options", tgt);
1468d91393a8SChris Horne 		options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1469d91393a8SChris Horne 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, topt, -1);
1470d91393a8SChris Horne 	}
1471d91393a8SChris Horne 
1472d91393a8SChris Horne 	if (options == -1)
1473d91393a8SChris Horne 		options = scsi_get_device_type_scsi_options(parent, sd, -1);
1474d91393a8SChris Horne 
1475d91393a8SChris Horne 	if (options == -1)
1476d91393a8SChris Horne 		options = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1477d91393a8SChris Horne 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "scsi-options", -1);
1478d91393a8SChris Horne 
1479d91393a8SChris Horne 	if (options == -1)
1480d91393a8SChris Horne 		options = default_scsi_options;
1481d91393a8SChris Horne 
1482d91393a8SChris Horne 	return (options);
1483d91393a8SChris Horne }
1484d91393a8SChris Horne 
1485d91393a8SChris Horne /*
1486d91393a8SChris Horne  * Use scsi-options to return the maximum number of LUNs.
1487d91393a8SChris Horne  */
1488d91393a8SChris Horne int
scsi_get_scsi_maxluns(struct scsi_device * sd)1489d91393a8SChris Horne scsi_get_scsi_maxluns(struct scsi_device *sd)
1490d91393a8SChris Horne {
1491d91393a8SChris Horne 	int	options;
1492d91393a8SChris Horne 	int	maxluns;
1493d91393a8SChris Horne 
1494d91393a8SChris Horne 	ASSERT(sd && sd->sd_inq);
1495d91393a8SChris Horne 	options = scsi_get_scsi_options(sd, SCSI_OPTIONS_NLUNS_DEFAULT);
1496d91393a8SChris Horne 
1497d91393a8SChris Horne 	switch (SCSI_OPTIONS_NLUNS(options)) {
1498d91393a8SChris Horne 	default:
1499d91393a8SChris Horne 	case SCSI_OPTIONS_NLUNS_DEFAULT:
1500d91393a8SChris Horne 		/* based on scsi version of target */
1501d91393a8SChris Horne 		if (sd->sd_inq->inq_ansi < SCSI_VERSION_3)
1502d91393a8SChris Horne 			maxluns = SCSI_8LUN_PER_TARGET;		/* 8 */
1503d91393a8SChris Horne 		else
1504d91393a8SChris Horne 			maxluns = SCSI_16LUNS_PER_TARGET;	/* 16 */
1505d91393a8SChris Horne 		break;
1506d91393a8SChris Horne 	case SCSI_OPTIONS_NLUNS_1:
1507d91393a8SChris Horne 		maxluns = SCSI_1LUN_PER_TARGET;		/* 1 */
1508d91393a8SChris Horne 		break;
1509d91393a8SChris Horne 	case SCSI_OPTIONS_NLUNS_8:
1510d91393a8SChris Horne 		maxluns = SCSI_8LUN_PER_TARGET;		/* 8 */
1511d91393a8SChris Horne 		break;
1512d91393a8SChris Horne 	case SCSI_OPTIONS_NLUNS_16:
1513d91393a8SChris Horne 		maxluns = SCSI_16LUNS_PER_TARGET;	/* 16 */
1514d91393a8SChris Horne 		break;
1515d91393a8SChris Horne 	case SCSI_OPTIONS_NLUNS_32:
1516d91393a8SChris Horne 		maxluns = SCSI_32LUNS_PER_TARGET;	/* 32 */
1517d91393a8SChris Horne 		break;
1518d91393a8SChris Horne 	}
1519d91393a8SChris Horne 
1520d91393a8SChris Horne 	/* For SCSI-1 we never support > 8 LUNs */
1521d91393a8SChris Horne 	if ((sd->sd_inq->inq_ansi <= SCSI_VERSION_1) &&
1522d91393a8SChris Horne 	    (maxluns > SCSI_8LUN_PER_TARGET))
1523d91393a8SChris Horne 		maxluns = SCSI_8LUN_PER_TARGET;
1524d91393a8SChris Horne 
1525d91393a8SChris Horne 	return (maxluns);
1526d91393a8SChris Horne }
1527d91393a8SChris Horne 
15285c46c6a0Spd /*
15295c46c6a0Spd  * Functions for format-neutral sense data functions
15305c46c6a0Spd  */
15315c46c6a0Spd int
scsi_validate_sense(uint8_t * sense_buffer,int sense_buf_len,int * flags)15325c46c6a0Spd scsi_validate_sense(uint8_t *sense_buffer, int sense_buf_len, int *flags)
15335c46c6a0Spd {
15345c46c6a0Spd 	int result;
15355c46c6a0Spd 	struct scsi_extended_sense *es =
15365c46c6a0Spd 	    (struct scsi_extended_sense *)sense_buffer;
15375c46c6a0Spd 
15385c46c6a0Spd 	/*
15395c46c6a0Spd 	 * Init flags if present
15405c46c6a0Spd 	 */
15415c46c6a0Spd 	if (flags != NULL) {
15425c46c6a0Spd 		*flags = 0;
15435c46c6a0Spd 	}
15445c46c6a0Spd 
15455c46c6a0Spd 	/*
15465c46c6a0Spd 	 * Check response code (Solaris breaks this into a 3-bit class
15475c46c6a0Spd 	 * and 4-bit code field.
15485c46c6a0Spd 	 */
15495c46c6a0Spd 	if ((es->es_class != CLASS_EXTENDED_SENSE) ||
15505c46c6a0Spd 	    ((es->es_code != CODE_FMT_FIXED_CURRENT) &&
15511e1ddd6cScth 	    (es->es_code != CODE_FMT_FIXED_DEFERRED) &&
15521e1ddd6cScth 	    (es->es_code != CODE_FMT_DESCR_CURRENT) &&
15531e1ddd6cScth 	    (es->es_code != CODE_FMT_DESCR_DEFERRED))) {
15545c46c6a0Spd 		/*
15555c46c6a0Spd 		 * Sense data (if there's actually anything here) is not
15565c46c6a0Spd 		 * in a format we can handle).
15575c46c6a0Spd 		 */
15585c46c6a0Spd 		return (SENSE_UNUSABLE);
15595c46c6a0Spd 	}
15605c46c6a0Spd 
15615c46c6a0Spd 	/*
15625c46c6a0Spd 	 * Check if this is deferred sense
15635c46c6a0Spd 	 */
15645c46c6a0Spd 	if ((flags != NULL) &&
15655c46c6a0Spd 	    ((es->es_code == CODE_FMT_FIXED_DEFERRED) ||
15661e1ddd6cScth 	    (es->es_code == CODE_FMT_DESCR_DEFERRED))) {
15675c46c6a0Spd 		*flags |= SNS_BUF_DEFERRED;
15685c46c6a0Spd 	}
15695c46c6a0Spd 
15705c46c6a0Spd 	/*
15715c46c6a0Spd 	 * Make sure length is OK
15725c46c6a0Spd 	 */
15735c46c6a0Spd 	if (es->es_code == CODE_FMT_FIXED_CURRENT ||
15745c46c6a0Spd 	    es->es_code == CODE_FMT_FIXED_DEFERRED) {
15755c46c6a0Spd 		/*
15765c46c6a0Spd 		 * We can get by with a buffer that only includes the key,
15775c46c6a0Spd 		 * asc, and ascq.  In reality the minimum length we should
15785c46c6a0Spd 		 * ever see is 18 bytes.
15795c46c6a0Spd 		 */
15805c46c6a0Spd 		if ((sense_buf_len < MIN_FIXED_SENSE_LEN) ||
15815c46c6a0Spd 		    ((es->es_add_len + ADDL_SENSE_ADJUST) <
15821e1ddd6cScth 		    MIN_FIXED_SENSE_LEN)) {
15835c46c6a0Spd 			result = SENSE_UNUSABLE;
15845c46c6a0Spd 		} else {
15855c46c6a0Spd 			/*
15865c46c6a0Spd 			 * The es_add_len field contains the number of sense
15875c46c6a0Spd 			 * data bytes that follow the es_add_len field.
15885c46c6a0Spd 			 */
15895c46c6a0Spd 			if ((flags != NULL) &&
15905c46c6a0Spd 			    (sense_buf_len <
15911e1ddd6cScth 			    (es->es_add_len + ADDL_SENSE_ADJUST))) {
15925c46c6a0Spd 				*flags |= SNS_BUF_OVERFLOW;
15935c46c6a0Spd 			}
15945c46c6a0Spd 
15955c46c6a0Spd 			result = SENSE_FIXED_FORMAT;
15965c46c6a0Spd 		}
15975c46c6a0Spd 	} else {
15985c46c6a0Spd 		struct scsi_descr_sense_hdr *ds =
15995c46c6a0Spd 		    (struct scsi_descr_sense_hdr *)sense_buffer;
16005c46c6a0Spd 
16015c46c6a0Spd 		/*
16025c46c6a0Spd 		 * For descriptor format we need at least the descriptor
16035c46c6a0Spd 		 * header
16045c46c6a0Spd 		 */
16055c46c6a0Spd 		if (sense_buf_len < sizeof (struct scsi_descr_sense_hdr)) {
16065c46c6a0Spd 			result = SENSE_UNUSABLE;
16075c46c6a0Spd 		} else {
16085c46c6a0Spd 			/*
16095c46c6a0Spd 			 * Check for overflow
16105c46c6a0Spd 			 */
16115c46c6a0Spd 			if ((flags != NULL) &&
16125c46c6a0Spd 			    (sense_buf_len <
16131e1ddd6cScth 			    (ds->ds_addl_sense_length + sizeof (*ds)))) {
16145c46c6a0Spd 				*flags |= SNS_BUF_OVERFLOW;
16155c46c6a0Spd 			}
16165c46c6a0Spd 
16175c46c6a0Spd 			result = SENSE_DESCR_FORMAT;
16185c46c6a0Spd 		}
16195c46c6a0Spd 	}
16205c46c6a0Spd 
16215c46c6a0Spd 	return (result);
16225c46c6a0Spd }
16235c46c6a0Spd 
16245c46c6a0Spd 
16255c46c6a0Spd uint8_t
scsi_sense_key(uint8_t * sense_buffer)16265c46c6a0Spd scsi_sense_key(uint8_t *sense_buffer)
16275c46c6a0Spd {
16285c46c6a0Spd 	uint8_t skey;
16295c46c6a0Spd 	if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
16305c46c6a0Spd 		struct scsi_descr_sense_hdr *sdsp =
16315c46c6a0Spd 		    (struct scsi_descr_sense_hdr *)sense_buffer;
16325c46c6a0Spd 		skey = sdsp->ds_key;
16335c46c6a0Spd 	} else {
16345c46c6a0Spd 		struct scsi_extended_sense *ext_sensep =
16355c46c6a0Spd 		    (struct scsi_extended_sense *)sense_buffer;
16365c46c6a0Spd 		skey = ext_sensep->es_key;
16375c46c6a0Spd 	}
16385c46c6a0Spd 	return (skey);
16395c46c6a0Spd }
16405c46c6a0Spd 
16415c46c6a0Spd uint8_t
scsi_sense_asc(uint8_t * sense_buffer)16425c46c6a0Spd scsi_sense_asc(uint8_t *sense_buffer)
16435c46c6a0Spd {
16445c46c6a0Spd 	uint8_t asc;
16455c46c6a0Spd 	if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
16465c46c6a0Spd 		struct scsi_descr_sense_hdr *sdsp =
16475c46c6a0Spd 		    (struct scsi_descr_sense_hdr *)sense_buffer;
16485c46c6a0Spd 		asc = sdsp->ds_add_code;
16495c46c6a0Spd 	} else {
16505c46c6a0Spd 		struct scsi_extended_sense *ext_sensep =
16515c46c6a0Spd 		    (struct scsi_extended_sense *)sense_buffer;
16525c46c6a0Spd 		asc = ext_sensep->es_add_code;
16535c46c6a0Spd 	}
16545c46c6a0Spd 	return (asc);
16555c46c6a0Spd }
16565c46c6a0Spd 
16575c46c6a0Spd uint8_t
scsi_sense_ascq(uint8_t * sense_buffer)16585c46c6a0Spd scsi_sense_ascq(uint8_t *sense_buffer)
16595c46c6a0Spd {
16605c46c6a0Spd 	uint8_t ascq;
16615c46c6a0Spd 	if (SCSI_IS_DESCR_SENSE(sense_buffer)) {
16625c46c6a0Spd 		struct scsi_descr_sense_hdr *sdsp =
16635c46c6a0Spd 		    (struct scsi_descr_sense_hdr *)sense_buffer;
16645c46c6a0Spd 		ascq = sdsp->ds_qual_code;
16655c46c6a0Spd 	} else {
16665c46c6a0Spd 		struct scsi_extended_sense *ext_sensep =
16675c46c6a0Spd 		    (struct scsi_extended_sense *)sense_buffer;
16685c46c6a0Spd 		ascq = ext_sensep->es_qual_code;
16695c46c6a0Spd 	}
16705c46c6a0Spd 	return (ascq);
16715c46c6a0Spd }
16725c46c6a0Spd 
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)16735c46c6a0Spd void scsi_ext_sense_fields(uint8_t *sense_buffer, int sense_buf_len,
16745c46c6a0Spd     uint8_t **information, uint8_t **cmd_spec_info, uint8_t **fru_code,
16755c46c6a0Spd     uint8_t **sk_specific, uint8_t **stream_flags)
16765c46c6a0Spd {
16775c46c6a0Spd 	int sense_fmt;
16785c46c6a0Spd 
16795c46c6a0Spd 	/*
16805c46c6a0Spd 	 * Sanity check sense data and determine the format
16815c46c6a0Spd 	 */
16825c46c6a0Spd 	sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
16835c46c6a0Spd 
16845c46c6a0Spd 	/*
16855c46c6a0Spd 	 * Initialize any requested data to 0
16865c46c6a0Spd 	 */
16875c46c6a0Spd 	if (information) {
16885c46c6a0Spd 		*information = NULL;
16895c46c6a0Spd 	}
16905c46c6a0Spd 	if (cmd_spec_info) {
16915c46c6a0Spd 		*cmd_spec_info = NULL;
16925c46c6a0Spd 	}
16935c46c6a0Spd 	if (fru_code) {
16945c46c6a0Spd 		*fru_code = NULL;
16955c46c6a0Spd 	}
16965c46c6a0Spd 	if (sk_specific) {
16975c46c6a0Spd 		*sk_specific = NULL;
16985c46c6a0Spd 	}
16995c46c6a0Spd 	if (stream_flags) {
17005c46c6a0Spd 		*stream_flags = NULL;
17015c46c6a0Spd 	}
17025c46c6a0Spd 
17035c46c6a0Spd 	if (sense_fmt == SENSE_DESCR_FORMAT) {
17045c46c6a0Spd 		struct scsi_descr_template *sdt = NULL;
17055c46c6a0Spd 
17065c46c6a0Spd 		while (scsi_get_next_descr(sense_buffer,
17075c46c6a0Spd 		    sense_buf_len, &sdt) != -1) {
17085c46c6a0Spd 			switch (sdt->sdt_descr_type) {
17095c46c6a0Spd 			case DESCR_INFORMATION: {
17105c46c6a0Spd 				struct scsi_information_sense_descr *isd =
17115c46c6a0Spd 				    (struct scsi_information_sense_descr *)
17125c46c6a0Spd 				    sdt;
17135c46c6a0Spd 				if (information) {
17145c46c6a0Spd 					*information =
17155c46c6a0Spd 					    &isd->isd_information[0];
17165c46c6a0Spd 				}
17175c46c6a0Spd 				break;
17185c46c6a0Spd 			}
17195c46c6a0Spd 			case DESCR_COMMAND_SPECIFIC: {
17205c46c6a0Spd 				struct scsi_cmd_specific_sense_descr *csd =
17215c46c6a0Spd 				    (struct scsi_cmd_specific_sense_descr *)
17225c46c6a0Spd 				    sdt;
17235c46c6a0Spd 				if (cmd_spec_info) {
17245c46c6a0Spd 					*cmd_spec_info =
17255c46c6a0Spd 					    &csd->css_cmd_specific_info[0];
17265c46c6a0Spd 				}
17275c46c6a0Spd 				break;
17285c46c6a0Spd 			}
17295c46c6a0Spd 			case DESCR_SENSE_KEY_SPECIFIC: {
17305c46c6a0Spd 				struct scsi_sk_specific_sense_descr *ssd =
17315c46c6a0Spd 				    (struct scsi_sk_specific_sense_descr *)
17325c46c6a0Spd 				    sdt;
17335c46c6a0Spd 				if (sk_specific) {
17345c46c6a0Spd 					*sk_specific =
17355c46c6a0Spd 					    (uint8_t *)&ssd->sss_data;
17365c46c6a0Spd 				}
17375c46c6a0Spd 				break;
17385c46c6a0Spd 			}
17395c46c6a0Spd 			case DESCR_FRU: {
17405c46c6a0Spd 				struct scsi_fru_sense_descr *fsd =
17415c46c6a0Spd 				    (struct scsi_fru_sense_descr *)
17425c46c6a0Spd 				    sdt;
17435c46c6a0Spd 				if (fru_code) {
17445c46c6a0Spd 					*fru_code = &fsd->fs_fru_code;
17455c46c6a0Spd 				}
17465c46c6a0Spd 				break;
17475c46c6a0Spd 			}
17485c46c6a0Spd 			case DESCR_STREAM_COMMANDS: {
17495c46c6a0Spd 				struct scsi_stream_cmd_sense_descr *strsd =
17505c46c6a0Spd 				    (struct scsi_stream_cmd_sense_descr *)
17515c46c6a0Spd 				    sdt;
17525c46c6a0Spd 				if (stream_flags) {
17535c46c6a0Spd 					*stream_flags =
17545c46c6a0Spd 					    (uint8_t *)&strsd->scs_data;
17555c46c6a0Spd 				}
17565c46c6a0Spd 				break;
17575c46c6a0Spd 			}
17585c46c6a0Spd 			case DESCR_BLOCK_COMMANDS: {
17595c46c6a0Spd 				struct scsi_block_cmd_sense_descr *bsd =
17605c46c6a0Spd 				    (struct scsi_block_cmd_sense_descr *)
17615c46c6a0Spd 				    sdt;
17625c46c6a0Spd 				/*
17635c46c6a0Spd 				 * The "Block Command" sense descriptor
17645c46c6a0Spd 				 * contains an ili bit that we can store
17655c46c6a0Spd 				 * in the stream specific data if it is
17665c46c6a0Spd 				 * available.  We shouldn't see both
17675c46c6a0Spd 				 * a block command and a stream command
17685c46c6a0Spd 				 * descriptor in the same collection
17695c46c6a0Spd 				 * of sense data.
17705c46c6a0Spd 				 */
17715c46c6a0Spd 				if (stream_flags) {
17725c46c6a0Spd 					/*
17735c46c6a0Spd 					 * Can't take an address of a bitfield,
17745c46c6a0Spd 					 * but the flags are just after the
17755c46c6a0Spd 					 * bcs_reserved field.
17765c46c6a0Spd 					 */
17775c46c6a0Spd 					*stream_flags =
17785c46c6a0Spd 					    (uint8_t *)&bsd->bcs_reserved + 1;
17795c46c6a0Spd 				}
17805c46c6a0Spd 				break;
17815c46c6a0Spd 			}
17825c46c6a0Spd 			}
17835c46c6a0Spd 		}
17845c46c6a0Spd 	} else {
17855c46c6a0Spd 		struct scsi_extended_sense *es =
17865c46c6a0Spd 		    (struct scsi_extended_sense *)sense_buffer;
17875c46c6a0Spd 
17885c46c6a0Spd 		/* Get data from fixed sense buffer */
17895c46c6a0Spd 		if (information && es->es_valid) {
17905c46c6a0Spd 			*information = &es->es_info_1;
17915c46c6a0Spd 		}
17925c46c6a0Spd 		if (cmd_spec_info && es->es_valid) {
17935c46c6a0Spd 			*cmd_spec_info = &es->es_cmd_info[0];
17945c46c6a0Spd 		}
17955c46c6a0Spd 		if (fru_code) {
17965c46c6a0Spd 			*fru_code = &es->es_fru_code;
17975c46c6a0Spd 		}
17985c46c6a0Spd 		if (sk_specific) {
17995c46c6a0Spd 			*sk_specific = &es->es_skey_specific[0];
18005c46c6a0Spd 		}
18015c46c6a0Spd 		if (stream_flags) {
18025c46c6a0Spd 			/*
18035c46c6a0Spd 			 * Can't take the address of a bit field,
18045c46c6a0Spd 			 * but the stream flags are located just after
18055c46c6a0Spd 			 * the es_segnum field;
18065c46c6a0Spd 			 */
18075c46c6a0Spd 			*stream_flags = &es->es_segnum + 1;
18085c46c6a0Spd 		}
18095c46c6a0Spd 	}
18105c46c6a0Spd }
18115c46c6a0Spd 
18125c46c6a0Spd boolean_t
scsi_sense_info_uint64(uint8_t * sense_buffer,int sense_buf_len,uint64_t * information)18135c46c6a0Spd scsi_sense_info_uint64(uint8_t *sense_buffer, int sense_buf_len,
18145c46c6a0Spd     uint64_t *information)
18155c46c6a0Spd {
18165c46c6a0Spd 	boolean_t valid;
18175c46c6a0Spd 	int sense_fmt;
18185c46c6a0Spd 
18195c46c6a0Spd 	ASSERT(sense_buffer != NULL);
18205c46c6a0Spd 	ASSERT(information != NULL);
18215c46c6a0Spd 
18225c46c6a0Spd 	/* Validate sense data and get format */
18235c46c6a0Spd 	sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
18245c46c6a0Spd 
18255c46c6a0Spd 	if (sense_fmt == SENSE_UNUSABLE) {
18265c46c6a0Spd 		/* Information is not valid */
18275c46c6a0Spd 		valid = 0;
18285c46c6a0Spd 	} else if (sense_fmt == SENSE_FIXED_FORMAT) {
18295c46c6a0Spd 		struct scsi_extended_sense *es =
18305c46c6a0Spd 		    (struct scsi_extended_sense *)sense_buffer;
18315c46c6a0Spd 
18325c46c6a0Spd 		*information = (uint64_t)SCSI_READ32(&es->es_info_1);
18335c46c6a0Spd 
18345c46c6a0Spd 		valid = es->es_valid;
18355c46c6a0Spd 	} else {
18365c46c6a0Spd 		/* Sense data is descriptor format */
18375c46c6a0Spd 		struct scsi_information_sense_descr *isd;
18385c46c6a0Spd 
18395c46c6a0Spd 		isd = (struct scsi_information_sense_descr *)
18405c46c6a0Spd 		    scsi_find_sense_descr(sense_buffer, sense_buf_len,
18411e1ddd6cScth 		    DESCR_INFORMATION);
18425c46c6a0Spd 
18435c46c6a0Spd 		if (isd) {
18445c46c6a0Spd 			*information = SCSI_READ64(isd->isd_information);
18455c46c6a0Spd 			valid = 1;
18465c46c6a0Spd 		} else {
18475c46c6a0Spd 			valid = 0;
18485c46c6a0Spd 		}
18495c46c6a0Spd 	}
18505c46c6a0Spd 
18515c46c6a0Spd 	return (valid);
18525c46c6a0Spd }
18535c46c6a0Spd 
18545c46c6a0Spd boolean_t
scsi_sense_cmdspecific_uint64(uint8_t * sense_buffer,int sense_buf_len,uint64_t * cmd_specific_info)18555c46c6a0Spd scsi_sense_cmdspecific_uint64(uint8_t *sense_buffer, int sense_buf_len,
18565c46c6a0Spd     uint64_t *cmd_specific_info)
18575c46c6a0Spd {
18585c46c6a0Spd 	boolean_t valid;
18595c46c6a0Spd 	int sense_fmt;
18605c46c6a0Spd 
18615c46c6a0Spd 	ASSERT(sense_buffer != NULL);
18625c46c6a0Spd 	ASSERT(cmd_specific_info != NULL);
18635c46c6a0Spd 
18645c46c6a0Spd 	/* Validate sense data and get format */
18655c46c6a0Spd 	sense_fmt = scsi_validate_sense(sense_buffer, sense_buf_len, NULL);
18665c46c6a0Spd 
18675c46c6a0Spd 	if (sense_fmt == SENSE_UNUSABLE) {
18685c46c6a0Spd 		/* Command specific info is not valid */
18695c46c6a0Spd 		valid = 0;
18705c46c6a0Spd 	} else if (sense_fmt == SENSE_FIXED_FORMAT) {
18715c46c6a0Spd 		struct scsi_extended_sense *es =
18725c46c6a0Spd 		    (struct scsi_extended_sense *)sense_buffer;
18735c46c6a0Spd 
18745c46c6a0Spd 		*cmd_specific_info = (uint64_t)SCSI_READ32(es->es_cmd_info);
18755c46c6a0Spd 
18765c46c6a0Spd 		valid = es->es_valid;
18775c46c6a0Spd 	} else {
18785c46c6a0Spd 		/* Sense data is descriptor format */
18795c46c6a0Spd 		struct scsi_cmd_specific_sense_descr *c;
18805c46c6a0Spd 
18815c46c6a0Spd 		c = (struct scsi_cmd_specific_sense_descr *)
18825c46c6a0Spd 		    scsi_find_sense_descr(sense_buffer, sense_buf_len,
18831e1ddd6cScth 		    DESCR_COMMAND_SPECIFIC);
18845c46c6a0Spd 
18855c46c6a0Spd 		if (c) {
18865c46c6a0Spd 			valid = 1;
18875c46c6a0Spd 			*cmd_specific_info =
18885c46c6a0Spd 			    SCSI_READ64(c->css_cmd_specific_info);
18895c46c6a0Spd 		} else {
18905c46c6a0Spd 			valid = 0;
18915c46c6a0Spd 		}
18925c46c6a0Spd 	}
18935c46c6a0Spd 
18945c46c6a0Spd 	return (valid);
18955c46c6a0Spd }
18965c46c6a0Spd 
18975c46c6a0Spd uint8_t *
scsi_find_sense_descr(uint8_t * sdsp,int sense_buf_len,int req_descr_type)18985c46c6a0Spd scsi_find_sense_descr(uint8_t *sdsp, int sense_buf_len, int req_descr_type)
18995c46c6a0Spd {
19005c46c6a0Spd 	struct scsi_descr_template *sdt = NULL;
19015c46c6a0Spd 
19025c46c6a0Spd 	while (scsi_get_next_descr(sdsp, sense_buf_len, &sdt) != -1) {
19035c46c6a0Spd 		ASSERT(sdt != NULL);
19045c46c6a0Spd 		if (sdt->sdt_descr_type == req_descr_type) {
19055c46c6a0Spd 			/* Found requested descriptor type */
19065c46c6a0Spd 			break;
19075c46c6a0Spd 		}
19085c46c6a0Spd 	}
19095c46c6a0Spd 
19105c46c6a0Spd 	return ((uint8_t *)sdt);
19115c46c6a0Spd }
19125c46c6a0Spd 
19135c46c6a0Spd /*
19145c46c6a0Spd  * Sense Descriptor format is:
19155c46c6a0Spd  *
19165c46c6a0Spd  * <Descriptor type> <Descriptor length> <Descriptor data> ...
19175c46c6a0Spd  *
19185c46c6a0Spd  * 2 must be added to the descriptor length value to get the
19195c46c6a0Spd  * total descriptor length sense the stored length does not
19205c46c6a0Spd  * include the "type" and "additional length" fields.
19215c46c6a0Spd  */
19225c46c6a0Spd 
19235c46c6a0Spd #define	NEXT_DESCR_PTR(ndp_descr) \
19245c46c6a0Spd 	((struct scsi_descr_template *)(((uint8_t *)(ndp_descr)) + \
19255c46c6a0Spd 	    ((ndp_descr)->sdt_addl_length + \
19265c46c6a0Spd 	    sizeof (struct scsi_descr_template))))
19275c46c6a0Spd 
19285c46c6a0Spd static int
scsi_get_next_descr(uint8_t * sense_buffer,int sense_buf_len,struct scsi_descr_template ** descrpp)19295c46c6a0Spd scsi_get_next_descr(uint8_t *sense_buffer,
19305c46c6a0Spd     int sense_buf_len, struct scsi_descr_template **descrpp)
19315c46c6a0Spd {
19325c46c6a0Spd 	struct scsi_descr_sense_hdr *sdsp =
19335c46c6a0Spd 	    (struct scsi_descr_sense_hdr *)sense_buffer;
19345c46c6a0Spd 	struct scsi_descr_template *cur_descr;
19355c46c6a0Spd 	boolean_t find_first;
19365c46c6a0Spd 	int valid_sense_length;
19375c46c6a0Spd 
19385c46c6a0Spd 	ASSERT(descrpp != NULL);
19395c46c6a0Spd 	find_first = (*descrpp == NULL);
19405c46c6a0Spd 
19415c46c6a0Spd 	/*
19425c46c6a0Spd 	 * If no descriptor is passed in then return the first
19435c46c6a0Spd 	 * descriptor
19445c46c6a0Spd 	 */
19455c46c6a0Spd 	if (find_first) {
19465c46c6a0Spd 		/*
19475c46c6a0Spd 		 * The first descriptor will immediately follow the header
19485c46c6a0Spd 		 * (Pointer arithmetic)
19495c46c6a0Spd 		 */
19505c46c6a0Spd 		cur_descr = (struct scsi_descr_template *)(sdsp+1);
19515c46c6a0Spd 	} else {
19525c46c6a0Spd 		cur_descr = *descrpp;
19535c46c6a0Spd 		ASSERT(cur_descr > (struct scsi_descr_template *)sdsp);
19545c46c6a0Spd 	}
19555c46c6a0Spd 
19565c46c6a0Spd 	/* Assume no more descriptors are available */
19575c46c6a0Spd 	*descrpp = NULL;
19585c46c6a0Spd 
19595c46c6a0Spd 	/*
19605c46c6a0Spd 	 * Calculate the amount of valid sense data -- make sure the length
19615c46c6a0Spd 	 * byte in this descriptor lies within the valid sense data.
19625c46c6a0Spd 	 */
19635c46c6a0Spd 	valid_sense_length =
19645c46c6a0Spd 	    min((sizeof (struct scsi_descr_sense_hdr) +
19655c46c6a0Spd 	    sdsp->ds_addl_sense_length),
19665c46c6a0Spd 	    sense_buf_len);
19675c46c6a0Spd 
19685c46c6a0Spd 	/*
19695c46c6a0Spd 	 * Make sure this descriptor is complete (either the first
19705c46c6a0Spd 	 * descriptor or the descriptor passed in)
19715c46c6a0Spd 	 */
19725c46c6a0Spd 	if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
19735c46c6a0Spd 	    DESCR_GOOD) {
19745c46c6a0Spd 		return (-1);
19755c46c6a0Spd 	}
19765c46c6a0Spd 
19775c46c6a0Spd 	/*
19785c46c6a0Spd 	 * If we were looking for the first descriptor go ahead and return it
19795c46c6a0Spd 	 */
19805c46c6a0Spd 	if (find_first) {
19815c46c6a0Spd 		*descrpp = cur_descr;
19825c46c6a0Spd 		return ((*descrpp)->sdt_descr_type);
19835c46c6a0Spd 	}
19845c46c6a0Spd 
19855c46c6a0Spd 	/*
19865c46c6a0Spd 	 * Get pointer to next descriptor
19875c46c6a0Spd 	 */
19885c46c6a0Spd 	cur_descr = NEXT_DESCR_PTR(cur_descr);
19895c46c6a0Spd 
19905c46c6a0Spd 	/*
19915c46c6a0Spd 	 * Make sure this descriptor is also complete.
19925c46c6a0Spd 	 */
19935c46c6a0Spd 	if (scsi_validate_descr(sdsp, valid_sense_length, cur_descr) !=
19945c46c6a0Spd 	    DESCR_GOOD) {
19955c46c6a0Spd 		return (-1);
19965c46c6a0Spd 	}
19975c46c6a0Spd 
19985c46c6a0Spd 	*descrpp = (struct scsi_descr_template *)cur_descr;
19995c46c6a0Spd 	return ((*descrpp)->sdt_descr_type);
20005c46c6a0Spd }
20015c46c6a0Spd 
20025c46c6a0Spd static int
scsi_validate_descr(struct scsi_descr_sense_hdr * sdsp,int valid_sense_length,struct scsi_descr_template * descrp)20035c46c6a0Spd scsi_validate_descr(struct scsi_descr_sense_hdr *sdsp,
20045c46c6a0Spd     int valid_sense_length, struct scsi_descr_template *descrp)
20055c46c6a0Spd {
20065c46c6a0Spd 	int descr_offset, next_descr_offset;
20075c46c6a0Spd 
20085c46c6a0Spd 	/*
20095c46c6a0Spd 	 * Make sure length is present
20105c46c6a0Spd 	 */
20115c46c6a0Spd 	descr_offset = (uint8_t *)descrp - (uint8_t *)sdsp;
20125c46c6a0Spd 	if (descr_offset + sizeof (struct scsi_descr_template) >
20135c46c6a0Spd 	    valid_sense_length) {
20145c46c6a0Spd 		return (DESCR_PARTIAL);
20155c46c6a0Spd 	}
20165c46c6a0Spd 
20175c46c6a0Spd 	/*
20185c46c6a0Spd 	 * Check if length is 0 (no more descriptors)
20195c46c6a0Spd 	 */
20205c46c6a0Spd 	if (descrp->sdt_addl_length == 0) {
20215c46c6a0Spd 		return (DESCR_END);
20225c46c6a0Spd 	}
20235c46c6a0Spd 
20245c46c6a0Spd 	/*
20255c46c6a0Spd 	 * Make sure the rest of the descriptor is present
20265c46c6a0Spd 	 */
20275c46c6a0Spd 	next_descr_offset =
20285c46c6a0Spd 	    (uint8_t *)NEXT_DESCR_PTR(descrp) - (uint8_t *)sdsp;
20295c46c6a0Spd 	if (next_descr_offset > valid_sense_length) {
20305c46c6a0Spd 		return (DESCR_PARTIAL);
20315c46c6a0Spd 	}
20325c46c6a0Spd 
20335c46c6a0Spd 	return (DESCR_GOOD);
20345c46c6a0Spd }
20356567eb0aSlh 
20366567eb0aSlh /*
20376567eb0aSlh  * Internal data structure for handling uscsi command.
20386567eb0aSlh  */
20396567eb0aSlh typedef	struct	uscsi_i_cmd {
20406567eb0aSlh 	struct uscsi_cmd	uic_cmd;
20416567eb0aSlh 	caddr_t			uic_rqbuf;
20426567eb0aSlh 	uchar_t			uic_rqlen;
20436567eb0aSlh 	caddr_t			uic_cdb;
20446567eb0aSlh 	int			uic_flag;
20456567eb0aSlh 	struct scsi_address	*uic_ap;
20466567eb0aSlh } uscsi_i_cmd_t;
20476567eb0aSlh 
20486567eb0aSlh #if !defined(lint)
20496567eb0aSlh _NOTE(SCHEME_PROTECTS_DATA("unshared data", uscsi_i_cmd))
20506567eb0aSlh #endif
20516567eb0aSlh 
20526567eb0aSlh /*ARGSUSED*/
20536567eb0aSlh static void
scsi_uscsi_mincnt(struct buf * bp)20546567eb0aSlh scsi_uscsi_mincnt(struct buf *bp)
20556567eb0aSlh {
20566567eb0aSlh 	/*
20576567eb0aSlh 	 * Do not break up because the CDB count would then be
20586567eb0aSlh 	 * incorrect and create spurious data underrun errors.
20596567eb0aSlh 	 */
20606567eb0aSlh }
20616567eb0aSlh 
20626567eb0aSlh /*
2063602ca9eaScth  * Function: scsi_uscsi_alloc_and_copyin
20646567eb0aSlh  *
20656567eb0aSlh  * Description: Target drivers call this function to allocate memeory,
2066602ca9eaScth  *	copy in, and convert ILP32/LP64 to make preparations for handling
2067602ca9eaScth  *	uscsi commands.
20686567eb0aSlh  *
2069602ca9eaScth  * Arguments:
2070602ca9eaScth  *	arg	- pointer to the caller's uscsi command struct
2071602ca9eaScth  *	flag	- mode, corresponds to ioctl(9e) 'mode'
2072602ca9eaScth  *	ap	- SCSI address structure
2073602ca9eaScth  *	uscmdp	- pointer to the converted uscsi command
20746567eb0aSlh  *
20756567eb0aSlh  * Return code: 0
2076602ca9eaScth  *	EFAULT
2077602ca9eaScth  *	EINVAL
20786567eb0aSlh  *
2079602ca9eaScth  * Context: Never called at interrupt context.
20806567eb0aSlh  */
20816567eb0aSlh 
20826567eb0aSlh int
scsi_uscsi_alloc_and_copyin(intptr_t arg,int flag,struct scsi_address * ap,struct uscsi_cmd ** uscmdp)20836567eb0aSlh scsi_uscsi_alloc_and_copyin(intptr_t arg, int flag, struct scsi_address *ap,
20846567eb0aSlh     struct uscsi_cmd **uscmdp)
20856567eb0aSlh {
20869e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	int	rval = 0;
20879e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_cmd *uscmd;
20886567eb0aSlh 
20896567eb0aSlh 	/*
20906567eb0aSlh 	 * In order to not worry about where the uscsi structure came
20916567eb0aSlh 	 * from (or where the cdb it points to came from) we're going
20926567eb0aSlh 	 * to make kmem_alloc'd copies of them here. This will also
20936567eb0aSlh 	 * allow reference to the data they contain long after this
20946567eb0aSlh 	 * process has gone to sleep and its kernel stack has been
20956567eb0aSlh 	 * unmapped, etc. First get some memory for the uscsi_cmd
20966567eb0aSlh 	 * struct and copy the contents of the given uscsi_cmd struct
20976567eb0aSlh 	 * into it. We also save infos of the uscsi command by using
20986567eb0aSlh 	 * uicmd to supply referrence for the copyout operation.
20996567eb0aSlh 	 */
21009e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uscmd = scsi_uscsi_alloc();
21019e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21029e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	if ((rval = scsi_uscsi_copyin(arg, flag, ap, &uscmd)) != 0) {
21039e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		scsi_uscsi_free(uscmd);
21049e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		*uscmdp = NULL;
21059e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		rval = EFAULT;
21069e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	} else {
21079e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		*uscmdp = uscmd;
21089e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	}
21099e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21109e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	return (rval);
21119e1c849eSDavid Zhang - Sun Microsystems - Beijing China }
21129e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21139e1c849eSDavid Zhang - Sun Microsystems - Beijing China struct uscsi_cmd *
scsi_uscsi_alloc()21149e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_uscsi_alloc()
21159e1c849eSDavid Zhang - Sun Microsystems - Beijing China {
21169e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_i_cmd	*uicmd;
21179e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21186567eb0aSlh 	uicmd = (struct uscsi_i_cmd *)
21196567eb0aSlh 	    kmem_zalloc(sizeof (struct uscsi_i_cmd), KM_SLEEP);
21209e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21219e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	/*
21229e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * It is supposed that the uscsi_cmd has been alloced correctly,
21239e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * we need to check is it NULL or mis-created.
21249e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 */
21259e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	ASSERT(uicmd && (offsetof(struct uscsi_i_cmd, uic_cmd) == 0));
21269e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21279e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	return (&uicmd->uic_cmd);
21289e1c849eSDavid Zhang - Sun Microsystems - Beijing China }
21299e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21309e1c849eSDavid Zhang - Sun Microsystems - Beijing China int
scsi_uscsi_copyin(intptr_t arg,int flag,struct scsi_address * ap,struct uscsi_cmd ** uscmdp)21319e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_uscsi_copyin(intptr_t arg, int flag, struct scsi_address *ap,
21329e1c849eSDavid Zhang - Sun Microsystems - Beijing China     struct uscsi_cmd **uscmdp)
21339e1c849eSDavid Zhang - Sun Microsystems - Beijing China {
21349e1c849eSDavid Zhang - Sun Microsystems - Beijing China #ifdef _MULTI_DATAMODEL
21359e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	/*
21369e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * For use when a 32 bit app makes a call into a
21379e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * 64 bit ioctl
21389e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 */
21399e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_cmd32	uscsi_cmd_32_for_64;
21409e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_cmd32	*ucmd32 = &uscsi_cmd_32_for_64;
21419e1c849eSDavid Zhang - Sun Microsystems - Beijing China #endif /* _MULTI_DATAMODEL */
21429e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_cmd	*uscmd = *uscmdp;
21439e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_i_cmd	*uicmd = (struct uscsi_i_cmd *)(uscmd);
21449e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	int			max_hba_cdb;
21459e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	int			rval;
21469e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	extern dev_info_t	*scsi_vhci_dip;
21479e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21489e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	ASSERT(uscmd != NULL);
21499e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	ASSERT(uicmd != NULL);
21509e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21519e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	/*
21529e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * To be able to issue multiple commands off a single uscmdp
21539e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * We need to free the original cdb, rqbuf and bzero the uscmdp
21549e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * if the cdb, rqbuf and uscmdp is not NULL
21559e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 */
21569e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	if (uscmd->uscsi_rqbuf != NULL)
21579e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		kmem_free(uscmd->uscsi_rqbuf, uscmd->uscsi_rqlen);
21589e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	if (uscmd->uscsi_cdb != NULL)
21599e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		kmem_free(uscmd->uscsi_cdb, uscmd->uscsi_cdblen);
21609e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	bzero(uscmd, sizeof (struct uscsi_cmd));
21619e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
21626567eb0aSlh 
21636567eb0aSlh #ifdef _MULTI_DATAMODEL
21646567eb0aSlh 	switch (ddi_model_convert_from(flag & FMODELS)) {
21656567eb0aSlh 	case DDI_MODEL_ILP32:
21666567eb0aSlh 		if (ddi_copyin((void *)arg, ucmd32, sizeof (*ucmd32), flag)) {
21676567eb0aSlh 			rval = EFAULT;
21689e1c849eSDavid Zhang - Sun Microsystems - Beijing China 			goto scsi_uscsi_copyin_failed;
21696567eb0aSlh 		}
21706567eb0aSlh 		/*
21716567eb0aSlh 		 * Convert the ILP32 uscsi data from the
21726567eb0aSlh 		 * application to LP64 for internal use.
21736567eb0aSlh 		 */
21746567eb0aSlh 		uscsi_cmd32touscsi_cmd(ucmd32, uscmd);
21756567eb0aSlh 		break;
21766567eb0aSlh 	case DDI_MODEL_NONE:
21776567eb0aSlh 		if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
21786567eb0aSlh 			rval = EFAULT;
21799e1c849eSDavid Zhang - Sun Microsystems - Beijing China 			goto scsi_uscsi_copyin_failed;
21806567eb0aSlh 		}
21816567eb0aSlh 		break;
21829e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	default:
21839e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		rval = EFAULT;
21849e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
21856567eb0aSlh 	}
21866567eb0aSlh #else /* ! _MULTI_DATAMODEL */
21876567eb0aSlh 	if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) {
21886567eb0aSlh 		rval = EFAULT;
21899e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
21906567eb0aSlh 	}
21916567eb0aSlh #endif /* _MULTI_DATAMODEL */
21926567eb0aSlh 
21939e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	/*
21949e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * We are going to allocate kernel virtual addresses for
21959e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * uscsi_rqbuf and uscsi_cdb pointers, so save off the
21969e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * original, possibly user virtual, uscsi_addresses
21979e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * in uic_fields
21989e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 */
21996567eb0aSlh 	uicmd->uic_rqbuf = uscmd->uscsi_rqbuf;
22006567eb0aSlh 	uicmd->uic_rqlen = uscmd->uscsi_rqlen;
22016567eb0aSlh 	uicmd->uic_cdb   = uscmd->uscsi_cdb;
22026567eb0aSlh 	uicmd->uic_flag  = flag;
22036567eb0aSlh 	uicmd->uic_ap    = ap;
22046567eb0aSlh 
22056567eb0aSlh 	/*
22066567eb0aSlh 	 * Skip the following steps if we meet RESET commands.
22076567eb0aSlh 	 */
22086567eb0aSlh 	if (uscmd->uscsi_flags &
22096567eb0aSlh 	    (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
22106567eb0aSlh 		uscmd->uscsi_rqbuf = NULL;
22116567eb0aSlh 		uscmd->uscsi_cdb = NULL;
22126567eb0aSlh 		return (0);
22136567eb0aSlh 	}
22146567eb0aSlh 
2215602ca9eaScth 	/*
2216602ca9eaScth 	 * Currently, USCSI_PATH_INSTANCE is only valid when directed
2217602ca9eaScth 	 * to scsi_vhci.
2218602ca9eaScth 	 */
2219602ca9eaScth 	if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
2220602ca9eaScth 	    (A_TO_TRAN(ap)->tran_hba_dip != scsi_vhci_dip)) {
2221602ca9eaScth 		rval = EFAULT;
22229e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
2223602ca9eaScth 	}
2224602ca9eaScth 
22256567eb0aSlh 	/*
22266567eb0aSlh 	 * Perfunctory sanity checks. Get the maximum hba supported
22276567eb0aSlh 	 * cdb length first.
22286567eb0aSlh 	 */
22296567eb0aSlh 	max_hba_cdb = scsi_ifgetcap(ap, "max-cdb-length", 1);
22306567eb0aSlh 	if (max_hba_cdb < CDB_GROUP0) {
22316567eb0aSlh 		max_hba_cdb = CDB_GROUP4;
22326567eb0aSlh 	}
22336567eb0aSlh 	if (uscmd->uscsi_cdblen < CDB_GROUP0 ||
22346567eb0aSlh 	    uscmd->uscsi_cdblen > max_hba_cdb) {
22356567eb0aSlh 		rval = EINVAL;
22369e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
22376567eb0aSlh 	}
22386567eb0aSlh 	if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
22396567eb0aSlh 	    (uscmd->uscsi_rqlen == 0 || uscmd->uscsi_rqbuf == NULL)) {
22406567eb0aSlh 		rval = EINVAL;
22419e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
22426567eb0aSlh 	}
22436567eb0aSlh 
2244602ca9eaScth 	/*
2245602ca9eaScth 	 * To extend uscsi_cmd in the future, we need to ensure current
2246602ca9eaScth 	 * reserved bits remain unused (zero).
2247602ca9eaScth 	 */
2248602ca9eaScth 	if (uscmd->uscsi_flags & USCSI_RESERVED) {
2249602ca9eaScth 		rval = EINVAL;
22509e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
2251602ca9eaScth 	}
2252602ca9eaScth 
22536567eb0aSlh 	/*
22546567eb0aSlh 	 * Now we get some space for the CDB, and copy the given CDB into
22556567eb0aSlh 	 * it. Use ddi_copyin() in case the data is in user space.
22566567eb0aSlh 	 */
22576567eb0aSlh 	uscmd->uscsi_cdb = kmem_zalloc((size_t)uscmd->uscsi_cdblen, KM_SLEEP);
22586567eb0aSlh 	if (ddi_copyin(uicmd->uic_cdb, uscmd->uscsi_cdb,
22596567eb0aSlh 	    (uint_t)uscmd->uscsi_cdblen, flag) != 0) {
22606567eb0aSlh 		kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
22616567eb0aSlh 		rval = EFAULT;
22629e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		goto scsi_uscsi_copyin_failed;
22636567eb0aSlh 	}
22646567eb0aSlh 
226560572c45Slh 	if (uscmd->uscsi_cdb[0] != SCMD_VAR_LEN) {
226660572c45Slh 		if (uscmd->uscsi_cdblen > SCSI_CDB_SIZE ||
226760572c45Slh 		    scsi_cdb_size[CDB_GROUPID(uscmd->uscsi_cdb[0])] >
226860572c45Slh 		    uscmd->uscsi_cdblen) {
226960572c45Slh 			kmem_free(uscmd->uscsi_cdb,
227060572c45Slh 			    (size_t)uscmd->uscsi_cdblen);
227160572c45Slh 			rval = EINVAL;
22729e1c849eSDavid Zhang - Sun Microsystems - Beijing China 			goto scsi_uscsi_copyin_failed;
227360572c45Slh 		}
227460572c45Slh 	} else {
227560572c45Slh 		if ((uscmd->uscsi_cdblen % 4) != 0) {
227660572c45Slh 			kmem_free(uscmd->uscsi_cdb,
227760572c45Slh 			    (size_t)uscmd->uscsi_cdblen);
227860572c45Slh 			rval = EINVAL;
22799e1c849eSDavid Zhang - Sun Microsystems - Beijing China 			goto scsi_uscsi_copyin_failed;
228060572c45Slh 		}
22816567eb0aSlh 	}
22826567eb0aSlh 
22836567eb0aSlh 	/*
22846567eb0aSlh 	 * Initialize Request Sense buffering, if requested.
22856567eb0aSlh 	 */
22866567eb0aSlh 	if (uscmd->uscsi_flags & USCSI_RQENABLE) {
22876567eb0aSlh 		/*
22886567eb0aSlh 		 * Here uscmd->uscsi_rqbuf currently points to the caller's
22896567eb0aSlh 		 * buffer, but we replace this with a kernel buffer that
22906567eb0aSlh 		 * we allocate to use with the sense data. The sense data
22916567eb0aSlh 		 * (if present) gets copied into this new buffer before the
22926567eb0aSlh 		 * command is completed.  Then we copy the sense data from
22936567eb0aSlh 		 * our allocated buf into the caller's buffer below. Note
22946567eb0aSlh 		 * that uscmd->uscsi_rqbuf and uscmd->uscsi_rqlen are used
22956567eb0aSlh 		 * below to perform the copy back to the caller's buf.
22966567eb0aSlh 		 */
229730ab6db6Slh 		if (uicmd->uic_rqlen <= SENSE_LENGTH) {
229830ab6db6Slh 			uscmd->uscsi_rqlen = SENSE_LENGTH;
229930ab6db6Slh 			uscmd->uscsi_rqbuf = kmem_zalloc(SENSE_LENGTH,
230030ab6db6Slh 			    KM_SLEEP);
230130ab6db6Slh 		} else {
230230ab6db6Slh 			uscmd->uscsi_rqlen = MAX_SENSE_LENGTH;
230330ab6db6Slh 			uscmd->uscsi_rqbuf = kmem_zalloc(MAX_SENSE_LENGTH,
230430ab6db6Slh 			    KM_SLEEP);
230530ab6db6Slh 		}
23066567eb0aSlh 		uscmd->uscsi_rqresid = uscmd->uscsi_rqlen;
23076567eb0aSlh 	} else {
23086567eb0aSlh 		uscmd->uscsi_rqbuf = NULL;
23096567eb0aSlh 		uscmd->uscsi_rqlen = 0;
23106567eb0aSlh 		uscmd->uscsi_rqresid = 0;
23116567eb0aSlh 	}
23126567eb0aSlh 	return (0);
23136567eb0aSlh 
23149e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_uscsi_copyin_failed:
23159e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	/*
23169e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * The uscsi_rqbuf and uscsi_cdb is refering to user-land
23179e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * address now, no need to free them.
23189e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 */
23199e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uscmd->uscsi_rqbuf = NULL;
23209e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uscmd->uscsi_cdb = NULL;
23219e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
23226567eb0aSlh 	return (rval);
23236567eb0aSlh }
23246567eb0aSlh 
23256567eb0aSlh /*
2326602ca9eaScth  * Function: scsi_uscsi_handle_cmd
23276567eb0aSlh  *
23286567eb0aSlh  * Description: Target drivers call this function to handle uscsi commands.
23296567eb0aSlh  *
2330602ca9eaScth  * Arguments:
2331602ca9eaScth  *	dev		- device number
2332602ca9eaScth  *	dataspace	- UIO_USERSPACE or UIO_SYSSPACE
2333602ca9eaScth  *	uscmd		- pointer to the converted uscsi command
2334602ca9eaScth  *	strat		- pointer to the driver's strategy routine
2335602ca9eaScth  *	bp		- buf struct ptr
2336602ca9eaScth  *	private_data	- pointer to bp->b_private
23376567eb0aSlh  *
23386567eb0aSlh  * Return code: 0
2339602ca9eaScth  *    EIO	- scsi_reset() failed, or see biowait()/physio() codes.
23406567eb0aSlh  *    EINVAL
23416567eb0aSlh  *    return code of biowait(9F) or physio(9F):
2342602ca9eaScth  *      EIO	- IO error
23436567eb0aSlh  *      ENXIO
2344602ca9eaScth  *      EACCES	- reservation conflict
23456567eb0aSlh  *
2346602ca9eaScth  * Context: Never called at interrupt context.
23476567eb0aSlh  */
23486567eb0aSlh 
23496567eb0aSlh 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)23506567eb0aSlh scsi_uscsi_handle_cmd(dev_t dev, enum uio_seg dataspace,
23516567eb0aSlh     struct uscsi_cmd *uscmd, int (*strat)(struct buf *),
23526567eb0aSlh     struct buf *bp, void *private_data)
23536567eb0aSlh {
23546567eb0aSlh 	struct uscsi_i_cmd	*uicmd = (struct uscsi_i_cmd *)uscmd;
23556567eb0aSlh 	int	bp_alloc_flag = 0;
23566567eb0aSlh 	int	rval;
23576567eb0aSlh 
23586567eb0aSlh 	/*
23596567eb0aSlh 	 * Perform resets directly; no need to generate a command to do it.
23606567eb0aSlh 	 */
23616567eb0aSlh 	if (uscmd->uscsi_flags &
23626567eb0aSlh 	    (USCSI_RESET_LUN | USCSI_RESET_TARGET | USCSI_RESET_ALL)) {
23636567eb0aSlh 		int flags = (uscmd->uscsi_flags & USCSI_RESET_ALL) ?
23646567eb0aSlh 		    RESET_ALL : ((uscmd->uscsi_flags & USCSI_RESET_TARGET) ?
23656567eb0aSlh 		    RESET_TARGET : RESET_LUN);
23666567eb0aSlh 		if (scsi_reset(uicmd->uic_ap, flags) == 0) {
23676567eb0aSlh 			/* Reset attempt was unsuccessful */
23686567eb0aSlh 			return (EIO);
23696567eb0aSlh 		}
23706567eb0aSlh 		return (0);
23716567eb0aSlh 	}
23726567eb0aSlh 
23736567eb0aSlh 	/*
23746567eb0aSlh 	 * Force asynchronous mode, if necessary.  Doing this here
23756567eb0aSlh 	 * has the unfortunate effect of running other queued
23766567eb0aSlh 	 * commands async also, but since the main purpose of this
23776567eb0aSlh 	 * capability is downloading new drive firmware, we can
23786567eb0aSlh 	 * probably live with it.
23796567eb0aSlh 	 */
23806567eb0aSlh 	if (uscmd->uscsi_flags & USCSI_ASYNC) {
23816567eb0aSlh 		if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 1) {
23826567eb0aSlh 			if (scsi_ifsetcap(uicmd->uic_ap, "synchronous",
23836567eb0aSlh 			    0, 1) != 1) {
23846567eb0aSlh 				return (EINVAL);
23856567eb0aSlh 			}
23866567eb0aSlh 		}
23876567eb0aSlh 	}
23886567eb0aSlh 
23896567eb0aSlh 	/*
23906567eb0aSlh 	 * Re-enable synchronous mode, if requested.
23916567eb0aSlh 	 */
23926567eb0aSlh 	if (uscmd->uscsi_flags & USCSI_SYNC) {
23936567eb0aSlh 		if (scsi_ifgetcap(uicmd->uic_ap, "synchronous", 1) == 0) {
23946567eb0aSlh 			rval = scsi_ifsetcap(uicmd->uic_ap, "synchronous",
23956567eb0aSlh 			    1, 1);
23966567eb0aSlh 		}
23976567eb0aSlh 	}
23986567eb0aSlh 
23996567eb0aSlh 	/*
24006567eb0aSlh 	 * If bp is NULL, allocate space here.
24016567eb0aSlh 	 */
24026567eb0aSlh 	if (bp == NULL) {
24036567eb0aSlh 		bp = getrbuf(KM_SLEEP);
24046567eb0aSlh 		bp->b_private = private_data;
24056567eb0aSlh 		bp_alloc_flag = 1;
24066567eb0aSlh 	}
24076567eb0aSlh 
24086567eb0aSlh 	/*
24096567eb0aSlh 	 * If we're going to do actual I/O, let physio do all the right things.
24106567eb0aSlh 	 */
24116567eb0aSlh 	if (uscmd->uscsi_buflen != 0) {
24126567eb0aSlh 		struct iovec	aiov;
24136567eb0aSlh 		struct uio	auio;
24146567eb0aSlh 		struct uio	*uio = &auio;
24156567eb0aSlh 
24166567eb0aSlh 		bzero(&auio, sizeof (struct uio));
24176567eb0aSlh 		bzero(&aiov, sizeof (struct iovec));
24186567eb0aSlh 		aiov.iov_base = uscmd->uscsi_bufaddr;
24196567eb0aSlh 		aiov.iov_len  = uscmd->uscsi_buflen;
24206567eb0aSlh 		uio->uio_iov  = &aiov;
24216567eb0aSlh 
24226567eb0aSlh 		uio->uio_iovcnt  = 1;
24236567eb0aSlh 		uio->uio_resid   = uscmd->uscsi_buflen;
24246567eb0aSlh 		uio->uio_segflg  = dataspace;
24256567eb0aSlh 
24266567eb0aSlh 		/*
24276567eb0aSlh 		 * physio() will block here until the command completes....
24286567eb0aSlh 		 */
24296567eb0aSlh 		rval = physio(strat, bp, dev,
24306567eb0aSlh 		    ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE),
24316567eb0aSlh 		    scsi_uscsi_mincnt, uio);
24326567eb0aSlh 	} else {
24336567eb0aSlh 		/*
24346567eb0aSlh 		 * We have to mimic that physio would do here! Argh!
24356567eb0aSlh 		 */
24366567eb0aSlh 		bp->b_flags  = B_BUSY |
24376567eb0aSlh 		    ((uscmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE);
24386567eb0aSlh 		bp->b_edev   = dev;
24396567eb0aSlh 		bp->b_dev    = cmpdev(dev);	/* maybe unnecessary? */
24406567eb0aSlh 		bp->b_bcount = 0;
24416567eb0aSlh 		bp->b_blkno  = 0;
24426567eb0aSlh 		bp->b_resid  = 0;
24436567eb0aSlh 
24446567eb0aSlh 		(void) (*strat)(bp);
24456567eb0aSlh 		rval = biowait(bp);
24466567eb0aSlh 	}
24476567eb0aSlh 	uscmd->uscsi_resid = bp->b_resid;
24486567eb0aSlh 
24496567eb0aSlh 	if (bp_alloc_flag == 1) {
24506567eb0aSlh 		bp_mapout(bp);
24516567eb0aSlh 		freerbuf(bp);
24526567eb0aSlh 	}
24536567eb0aSlh 
24546567eb0aSlh 	return (rval);
24556567eb0aSlh }
24566567eb0aSlh 
2457602ca9eaScth /*
2458602ca9eaScth  * Function: scsi_uscsi_pktinit
2459602ca9eaScth  *
2460602ca9eaScth  * Description: Target drivers call this function to transfer uscsi_cmd
2461602ca9eaScth  *	information into a scsi_pkt before sending the scsi_pkt.
2462602ca9eaScth  *
2463602ca9eaScth  *	NB: At this point the implementation is limited to path_instance.
2464602ca9eaScth  *	At some point more code could be removed from the target driver by
2465602ca9eaScth  *	enhancing this function - with the added benifit of making the uscsi
2466602ca9eaScth  *	implementation more consistent accross all drivers.
2467602ca9eaScth  *
2468602ca9eaScth  * Arguments:
2469602ca9eaScth  *    uscmd     - pointer to the uscsi command
2470602ca9eaScth  *    pkt	- pointer to the scsi_pkt
2471602ca9eaScth  *
2472602ca9eaScth  * Return code: 1 on successfull transfer, 0 on failure.
2473602ca9eaScth  */
2474602ca9eaScth int
scsi_uscsi_pktinit(struct uscsi_cmd * uscmd,struct scsi_pkt * pkt)2475602ca9eaScth scsi_uscsi_pktinit(struct uscsi_cmd *uscmd, struct scsi_pkt *pkt)
2476602ca9eaScth {
2477602ca9eaScth 
24785bd3d017SNikko He 	/*
24795bd3d017SNikko He 	 * Check if the NACA flag is set. If one initiator sets it
24805bd3d017SNikko He 	 * but does not clear it, other initiators would end up
24815bd3d017SNikko He 	 * waiting indefinitely for the first to clear NACA. If the
24825bd3d017SNikko He 	 * the system allows NACA to be set, then warn the user but
24835bd3d017SNikko He 	 * still pass the command down, otherwise, clear the flag.
24845bd3d017SNikko He 	 */
24855bd3d017SNikko He 	if (uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] & CDB_FLAG_NACA) {
24865bd3d017SNikko He 		if (scsi_pkt_allow_naca) {
24875bd3d017SNikko He 			cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
24885bd3d017SNikko He 			    "NACA flag is set");
24895bd3d017SNikko He 		} else {
24905bd3d017SNikko He 			uscmd->uscsi_cdb[uscmd->uscsi_cdblen - 1] &=
24915bd3d017SNikko He 			    ~CDB_FLAG_NACA;
24925bd3d017SNikko He 			cmn_err(CE_WARN, "scsi_uscsi_pktinit: "
24935bd3d017SNikko He 			    "NACA flag is cleared");
24945bd3d017SNikko He 		}
24955bd3d017SNikko He 	}
24965bd3d017SNikko He 
2497602ca9eaScth 	/*
249873803a45SRandall Ralphs 	 * See if path_instance was requested in uscsi_cmd.
2499602ca9eaScth 	 */
250073803a45SRandall Ralphs 	if ((uscmd->uscsi_flags & USCSI_PATH_INSTANCE) &&
250173803a45SRandall Ralphs 	    (uscmd->uscsi_path_instance != 0)) {
250273803a45SRandall Ralphs 		/*
250373803a45SRandall Ralphs 		 * Check to make sure the scsi_pkt was allocated correctly
2504bbf21555SRichard Lowe 		 * before transferring uscsi(4I) path_instance to scsi_pkt(9S).
250573803a45SRandall Ralphs 		 */
250673803a45SRandall Ralphs 		if (scsi_pkt_allocated_correctly(pkt)) {
250773803a45SRandall Ralphs 			/* set pkt_path_instance and flag. */
250873803a45SRandall Ralphs 			pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
250973803a45SRandall Ralphs 			pkt->pkt_path_instance = uscmd->uscsi_path_instance;
251073803a45SRandall Ralphs 		} else {
251173803a45SRandall Ralphs 			return (0);	/* failure */
251273803a45SRandall Ralphs 		}
251373803a45SRandall Ralphs 	} else {
251473803a45SRandall Ralphs 		/*
251573803a45SRandall Ralphs 		 * Can only use pkt_path_instance if the packet
251673803a45SRandall Ralphs 		 * was correctly allocated.
251773803a45SRandall Ralphs 		 */
251873803a45SRandall Ralphs 		if (scsi_pkt_allocated_correctly(pkt)) {
251973803a45SRandall Ralphs 			pkt->pkt_path_instance = 0;
252073803a45SRandall Ralphs 		}
252173803a45SRandall Ralphs 		pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
2522602ca9eaScth 	}
2523602ca9eaScth 
2524602ca9eaScth 	return (1);			/* success */
2525602ca9eaScth }
2526602ca9eaScth 
2527602ca9eaScth /*
2528602ca9eaScth  * Function: scsi_uscsi_pktfini
2529602ca9eaScth  *
2530602ca9eaScth  * Description: Target drivers call this function to transfer completed
2531e6915ea4SToomas Soome  *	scsi_pkt information back into uscsi_cmd.
2532602ca9eaScth  *
2533602ca9eaScth  *	NB: At this point the implementation is limited to path_instance.
2534602ca9eaScth  *	At some point more code could be removed from the target driver by
2535602ca9eaScth  *	enhancing this function - with the added benifit of making the uscsi
2536602ca9eaScth  *	implementation more consistent accross all drivers.
2537602ca9eaScth  *
2538602ca9eaScth  * Arguments:
2539602ca9eaScth  *    pkt	- pointer to the scsi_pkt
2540602ca9eaScth  *    uscmd     - pointer to the uscsi command
2541602ca9eaScth  *
2542602ca9eaScth  * Return code: 1 on successfull transfer, 0 on failure.
2543602ca9eaScth  */
2544602ca9eaScth int
scsi_uscsi_pktfini(struct scsi_pkt * pkt,struct uscsi_cmd * uscmd)2545602ca9eaScth scsi_uscsi_pktfini(struct scsi_pkt *pkt, struct uscsi_cmd *uscmd)
2546602ca9eaScth {
2547602ca9eaScth 	/*
2548602ca9eaScth 	 * Check to make sure the scsi_pkt was allocated correctly before
2549bbf21555SRichard Lowe 	 * transferring scsi_pkt(9S) path_instance to uscsi(4I).
2550602ca9eaScth 	 */
2551602ca9eaScth 	if (!scsi_pkt_allocated_correctly(pkt)) {
2552602ca9eaScth 		uscmd->uscsi_path_instance = 0;
2553602ca9eaScth 		return (0);		/* failure */
2554602ca9eaScth 	}
2555602ca9eaScth 
2556602ca9eaScth 	uscmd->uscsi_path_instance = pkt->pkt_path_instance;
25571cb30f30Sgap 	/* reset path_instance */
25581cb30f30Sgap 	pkt->pkt_flags &= ~FLAG_PKT_PATH_INSTANCE;
2559602ca9eaScth 	pkt->pkt_path_instance = 0;
2560602ca9eaScth 	return (1);			/* success */
2561602ca9eaScth }
2562602ca9eaScth 
25636567eb0aSlh /*
25646567eb0aSlh  *    Function: scsi_uscsi_copyout_and_free
25656567eb0aSlh  *
25666567eb0aSlh  * Description: Target drivers call this function to undo what was done by
25676567eb0aSlh  *    scsi_uscsi_alloc_and_copyin.
25686567eb0aSlh  *
25696567eb0aSlh  *   Arguments: arg - pointer to the uscsi command to be returned
25706567eb0aSlh  *    uscmd     - pointer to the converted uscsi command
25716567eb0aSlh  *
25726567eb0aSlh  * Return code: 0
25736567eb0aSlh  *    EFAULT
25746567eb0aSlh  *
25756567eb0aSlh  *     Context: Never called at interrupt context.
25766567eb0aSlh  */
25776567eb0aSlh int
scsi_uscsi_copyout_and_free(intptr_t arg,struct uscsi_cmd * uscmd)25786567eb0aSlh scsi_uscsi_copyout_and_free(intptr_t arg, struct uscsi_cmd *uscmd)
25799e1c849eSDavid Zhang - Sun Microsystems - Beijing China {
25809e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	int	rval = 0;
25819e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
25829e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	rval = scsi_uscsi_copyout(arg, uscmd);
25839e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
25849e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	scsi_uscsi_free(uscmd);
25859e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
25869e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	return (rval);
25879e1c849eSDavid Zhang - Sun Microsystems - Beijing China }
25889e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
25899e1c849eSDavid Zhang - Sun Microsystems - Beijing China int
scsi_uscsi_copyout(intptr_t arg,struct uscsi_cmd * uscmd)25909e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_uscsi_copyout(intptr_t arg, struct uscsi_cmd *uscmd)
25916567eb0aSlh {
25926567eb0aSlh #ifdef _MULTI_DATAMODEL
25936567eb0aSlh 	/*
25946567eb0aSlh 	 * For use when a 32 bit app makes a call into a
25956567eb0aSlh 	 * 64 bit ioctl.
25966567eb0aSlh 	 */
25976567eb0aSlh 	struct uscsi_cmd32	uscsi_cmd_32_for_64;
25986567eb0aSlh 	struct uscsi_cmd32	*ucmd32 = &uscsi_cmd_32_for_64;
25996567eb0aSlh #endif /* _MULTI_DATAMODEL */
26006567eb0aSlh 	struct uscsi_i_cmd	*uicmd = (struct uscsi_i_cmd *)uscmd;
26016567eb0aSlh 	caddr_t	k_rqbuf;
260230ab6db6Slh 	int	k_rqlen;
26036567eb0aSlh 	caddr_t	k_cdb;
26046567eb0aSlh 	int	rval = 0;
26056567eb0aSlh 
26066567eb0aSlh 	/*
26076567eb0aSlh 	 * If the caller wants sense data, copy back whatever sense data
26086567eb0aSlh 	 * we may have gotten, and update the relevant rqsense info.
26096567eb0aSlh 	 */
26106567eb0aSlh 	if ((uscmd->uscsi_flags & USCSI_RQENABLE) &&
26116567eb0aSlh 	    (uscmd->uscsi_rqbuf != NULL)) {
26126567eb0aSlh 		int rqlen = uscmd->uscsi_rqlen - uscmd->uscsi_rqresid;
26136567eb0aSlh 		rqlen = min(((int)uicmd->uic_rqlen), rqlen);
26146567eb0aSlh 		uscmd->uscsi_rqresid = uicmd->uic_rqlen - rqlen;
26156567eb0aSlh 		/*
26166567eb0aSlh 		 * Copy out the sense data for user process.
26176567eb0aSlh 		 */
26186567eb0aSlh 		if ((uicmd->uic_rqbuf != NULL) && (rqlen != 0)) {
26196567eb0aSlh 			if (ddi_copyout(uscmd->uscsi_rqbuf,
26206567eb0aSlh 			    uicmd->uic_rqbuf, rqlen, uicmd->uic_flag) != 0) {
26216567eb0aSlh 				rval = EFAULT;
26226567eb0aSlh 			}
26236567eb0aSlh 		}
26246567eb0aSlh 	}
26256567eb0aSlh 
26266567eb0aSlh 	/*
26279e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * Restore original uscsi_values, saved in uic_fields for
26289e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * copyout (so caller does not experience a change in these
26299e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * fields)
26306567eb0aSlh 	 */
26316567eb0aSlh 	k_rqbuf = uscmd->uscsi_rqbuf;
263230ab6db6Slh 	k_rqlen = uscmd->uscsi_rqlen;
26336567eb0aSlh 	k_cdb   = uscmd->uscsi_cdb;
26346567eb0aSlh 	uscmd->uscsi_rqbuf = uicmd->uic_rqbuf;
26356567eb0aSlh 	uscmd->uscsi_rqlen = uicmd->uic_rqlen;
26366567eb0aSlh 	uscmd->uscsi_cdb   = uicmd->uic_cdb;
26376567eb0aSlh 
26386567eb0aSlh #ifdef _MULTI_DATAMODEL
26396567eb0aSlh 	switch (ddi_model_convert_from(uicmd->uic_flag & FMODELS)) {
26406567eb0aSlh 	case DDI_MODEL_ILP32:
26416567eb0aSlh 		/*
26426567eb0aSlh 		 * Convert back to ILP32 before copyout to the
26436567eb0aSlh 		 * application
26446567eb0aSlh 		 */
26456567eb0aSlh 		uscsi_cmdtouscsi_cmd32(uscmd, ucmd32);
26466567eb0aSlh 		if (ddi_copyout(ucmd32, (void *)arg, sizeof (*ucmd32),
26476567eb0aSlh 		    uicmd->uic_flag)) {
26486567eb0aSlh 			rval = EFAULT;
26496567eb0aSlh 		}
26506567eb0aSlh 		break;
26516567eb0aSlh 	case DDI_MODEL_NONE:
26526567eb0aSlh 		if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd),
26536567eb0aSlh 		    uicmd->uic_flag)) {
26546567eb0aSlh 			rval = EFAULT;
26556567eb0aSlh 		}
26566567eb0aSlh 		break;
26579e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	default:
26589e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		rval = EFAULT;
26596567eb0aSlh 	}
26606567eb0aSlh #else /* _MULTI_DATAMODE */
26616567eb0aSlh 	if (ddi_copyout(uscmd, (void *)arg, sizeof (*uscmd), uicmd->uic_flag)) {
26626567eb0aSlh 		rval = EFAULT;
26636567eb0aSlh 	}
26646567eb0aSlh #endif /* _MULTI_DATAMODE */
26656567eb0aSlh 
26669e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	/*
26679e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * Copyout done, restore kernel virtual addresses for further
26689e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 * scsi_uscsi_free().
26699e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	 */
26709e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uscmd->uscsi_rqbuf = k_rqbuf;
26719e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uscmd->uscsi_rqlen = k_rqlen;
26729e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	uscmd->uscsi_cdb = k_cdb;
26739e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
26749e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	return (rval);
26759e1c849eSDavid Zhang - Sun Microsystems - Beijing China }
26769e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
26779e1c849eSDavid Zhang - Sun Microsystems - Beijing China void
scsi_uscsi_free(struct uscsi_cmd * uscmd)26789e1c849eSDavid Zhang - Sun Microsystems - Beijing China scsi_uscsi_free(struct uscsi_cmd *uscmd)
26799e1c849eSDavid Zhang - Sun Microsystems - Beijing China {
26809e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	struct uscsi_i_cmd	*uicmd = (struct uscsi_i_cmd *)uscmd;
26819e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
26829e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	ASSERT(uicmd != NULL);
26839e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
26849e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	if ((uscmd->uscsi_rqbuf != NULL) && (uscmd->uscsi_rqlen != 0)) {
26859e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		kmem_free(uscmd->uscsi_rqbuf, (size_t)uscmd->uscsi_rqlen);
26869e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		uscmd->uscsi_rqbuf = NULL;
26876567eb0aSlh 	}
26889e1c849eSDavid Zhang - Sun Microsystems - Beijing China 
26899e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	if ((uscmd->uscsi_cdb != NULL) && (uscmd->uscsi_cdblen != 0)) {
26909e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		kmem_free(uscmd->uscsi_cdb, (size_t)uscmd->uscsi_cdblen);
26919e1c849eSDavid Zhang - Sun Microsystems - Beijing China 		uscmd->uscsi_cdb = NULL;
26926567eb0aSlh 	}
26936567eb0aSlh 
26949e1c849eSDavid Zhang - Sun Microsystems - Beijing China 	kmem_free(uicmd, sizeof (struct uscsi_i_cmd));
26956567eb0aSlh }
2696