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