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