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