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