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