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