xref: /openbsd-src/sys/scsi/scsi_base.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: scsi_base.c,v 1.200 2011/06/15 01:10:05 dlg Exp $	*/
2 /*	$NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1994, 1995, 1997 Charles M. Hannum.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Charles M. Hannum.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Originally written by Julian Elischer (julian@dialix.oz.au)
35  * Detailed SCSI error printing Copyright 1997 by Matthew Jacob.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/buf.h>
43 #include <sys/uio.h>
44 #include <sys/errno.h>
45 #include <sys/device.h>
46 #include <sys/proc.h>
47 #include <sys/pool.h>
48 
49 #include <scsi/scsi_all.h>
50 #include <scsi/scsi_disk.h>
51 #include <scsi/scsiconf.h>
52 
53 static __inline void asc2ascii(u_int8_t, u_int8_t ascq, char *result,
54     size_t len);
55 int	scsi_xs_error(struct scsi_xfer *);
56 char   *scsi_decode_sense(struct scsi_sense_data *, int);
57 
58 void	scsi_xs_sync_done(struct scsi_xfer *);
59 
60 /* Values for flag parameter to scsi_decode_sense. */
61 #define	DECODE_SENSE_KEY	1
62 #define	DECODE_ASC_ASCQ		2
63 #define DECODE_SKSV		3
64 
65 struct pool		scsi_xfer_pool;
66 struct pool		scsi_plug_pool;
67 
68 struct scsi_plug {
69 	struct workq_task	wqt;
70 	int			target;
71 	int			lun;
72 	int			how;
73 };
74 
75 void	scsi_plug_probe(void *, void *);
76 void	scsi_plug_detach(void *, void *);
77 
78 struct scsi_xfer *	scsi_xs_io(struct scsi_link *, void *, int);
79 
80 int			scsi_ioh_pending(struct scsi_iopool *);
81 struct scsi_iohandler *	scsi_ioh_deq(struct scsi_iopool *);
82 void			scsi_ioh_runqueue(struct scsi_iopool *);
83 
84 void			scsi_xsh_runqueue(struct scsi_link *);
85 void			scsi_xsh_ioh(void *, void *);
86 
87 int			scsi_link_open(struct scsi_link *);
88 void			scsi_link_close(struct scsi_link *);
89 
90 int			scsi_sem_enter(struct mutex *, u_int *);
91 int			scsi_sem_leave(struct mutex *, u_int *);
92 
93 /* ioh/xsh queue state */
94 #define RUNQ_IDLE	0
95 #define RUNQ_LINKQ	1
96 #define RUNQ_POOLQ	2
97 
98 /* synchronous api for allocating an io. */
99 struct scsi_io_mover {
100 	struct mutex mtx;
101 	void *io;
102 	u_int done;
103 };
104 #define SCSI_IO_MOVER_INITIALIZER { MUTEX_INITIALIZER(IPL_BIO), NULL, 0 }
105 
106 void scsi_move(struct scsi_io_mover *);
107 void scsi_move_done(void *, void *);
108 
109 void scsi_io_get_done(void *, void *);
110 void scsi_xs_get_done(void *, void *);
111 
112 /*
113  * Called when a scsibus is attached to initialize global data.
114  */
115 void
116 scsi_init()
117 {
118 	static int scsi_init_done;
119 
120 	if (scsi_init_done)
121 		return;
122 	scsi_init_done = 1;
123 
124 #if defined(SCSI_DELAY) && SCSI_DELAY > 0
125 	/* Historical. Older buses may need a moment to stabilize. */
126 	delay(1000000 * SCSI_DELAY);
127 #endif
128 
129 	/* Initialize the scsi_xfer pool. */
130 	pool_init(&scsi_xfer_pool, sizeof(struct scsi_xfer), 0,
131 	    0, 0, "scxspl", NULL);
132 	pool_setipl(&scsi_xfer_pool, IPL_BIO);
133 	/* Initialize the scsi_plug pool */
134 	pool_init(&scsi_plug_pool, sizeof(struct scsi_plug), 0,
135 	    0, 0, "scsiplug", NULL);
136 	pool_setipl(&scsi_plug_pool, IPL_BIO);
137 }
138 
139 int
140 scsi_req_probe(struct scsibus_softc *sc, int target, int lun)
141 {
142 	struct scsi_plug *p;
143 
144 	p = pool_get(&scsi_plug_pool, PR_NOWAIT);
145 	if (p == NULL)
146 		return (ENOMEM);
147 
148 	p->target = target;
149 	p->lun = lun;
150 
151 	workq_queue_task(NULL, &p->wqt, 0, scsi_plug_probe, sc, p);
152 
153 	return (0);
154 }
155 
156 int
157 scsi_req_detach(struct scsibus_softc *sc, int target, int lun, int how)
158 {
159 	struct scsi_plug *p;
160 
161 	p = pool_get(&scsi_plug_pool, PR_NOWAIT);
162 	if (p == NULL)
163 		return (ENOMEM);
164 
165 	p->target = target;
166 	p->lun = lun;
167 	p->how = how;
168 
169 	workq_queue_task(NULL, &p->wqt, 0, scsi_plug_detach, sc, p);
170 
171 	return (0);
172 }
173 
174 void
175 scsi_plug_probe(void *xsc, void *xp)
176 {
177 	struct scsibus_softc *sc = xsc;
178 	struct scsi_plug *p = xp;
179 	int target = p->target, lun = p->lun;
180 
181 	pool_put(&scsi_plug_pool, p);
182 
183 	if (target == -1 && lun == -1)
184 		scsi_probe_bus(sc);
185 
186 	/* specific lun and wildcard target is bad */
187 	if (target == -1)
188 		return;
189 
190 	if (lun == -1)
191 		scsi_probe_target(sc, target);
192 
193 	scsi_probe_lun(sc, target, lun);
194 }
195 
196 void
197 scsi_plug_detach(void *xsc, void *xp)
198 {
199 	struct scsibus_softc *sc = xsc;
200 	struct scsi_plug *p = xp;
201 	int target = p->target, lun = p->lun;
202 	int how = p->how;
203 
204 	pool_put(&scsi_plug_pool, p);
205 
206 	if (target == -1 && lun == -1)
207 		scsi_detach_bus(sc, how);
208 
209 	/* specific lun and wildcard target is bad */
210 	if (target == -1)
211 		return;
212 
213 	if (lun == -1)
214 		scsi_detach_target(sc, target, how);
215 
216 	scsi_detach_lun(sc, target, lun, how);
217 }
218 
219 int
220 scsi_sem_enter(struct mutex *mtx, u_int *running)
221 {
222 	int rv = 1;
223 
224 	mtx_enter(mtx);
225 	(*running)++;
226 	if ((*running) > 1)
227 		rv = 0;
228 	mtx_leave(mtx);
229 
230 	return (rv);
231 }
232 
233 int
234 scsi_sem_leave(struct mutex *mtx, u_int *running)
235 {
236 	int rv = 1;
237 
238 	mtx_enter(mtx);
239 	(*running)--;
240 	if ((*running) > 0)
241 		rv = 0;
242 	mtx_leave(mtx);
243 
244 	return (rv);
245 }
246 
247 void
248 scsi_iopool_init(struct scsi_iopool *iopl, void *iocookie,
249     void *(*io_get)(void *), void (*io_put)(void *, void *))
250 {
251 	iopl->iocookie = iocookie;
252 	iopl->io_get = io_get;
253 	iopl->io_put = io_put;
254 
255 	TAILQ_INIT(&iopl->queue);
256 	iopl->running = 0;
257 	mtx_init(&iopl->mtx, IPL_BIO);
258 }
259 
260 void
261 scsi_iopool_destroy(struct scsi_iopool *iopl)
262 {
263 	struct scsi_runq sleepers = TAILQ_HEAD_INITIALIZER(sleepers);
264 	struct scsi_iohandler *ioh = NULL;
265 
266 	mtx_enter(&iopl->mtx);
267 	while ((ioh = TAILQ_FIRST(&iopl->queue)) != NULL) {
268 		TAILQ_REMOVE(&iopl->queue, ioh, q_entry);
269 		ioh->q_state = RUNQ_IDLE;
270 
271 		if (ioh->handler == scsi_io_get_done)
272 			TAILQ_INSERT_TAIL(&sleepers, ioh, q_entry);
273 #ifdef DIAGNOSTIC
274 		else
275 			panic("scsi_iopool_destroy: scsi_iohandler on pool");
276 #endif
277 	}
278 	mtx_leave(&iopl->mtx);
279 
280 	while ((ioh = TAILQ_FIRST(&sleepers)) != NULL) {
281 		TAILQ_REMOVE(&sleepers, ioh, q_entry);
282 		ioh->handler(ioh->cookie, NULL);
283 	}
284 }
285 
286 void *
287 scsi_default_get(void *iocookie)
288 {
289 	return (iocookie);
290 }
291 
292 void
293 scsi_default_put(void *iocookie, void *io)
294 {
295 #ifdef DIAGNOSTIC
296 	if (iocookie != io)
297 		panic("unexpected opening returned");
298 #endif
299 }
300 
301 /*
302  * public interface to the ioh api.
303  */
304 
305 void
306 scsi_ioh_set(struct scsi_iohandler *ioh, struct scsi_iopool *iopl,
307     void (*handler)(void *, void *), void *cookie)
308 {
309 	ioh->q_state = RUNQ_IDLE;
310 	ioh->pool = iopl;
311 	ioh->handler = handler;
312 	ioh->cookie = cookie;
313 }
314 
315 void
316 scsi_ioh_add(struct scsi_iohandler *ioh)
317 {
318 	struct scsi_iopool *iopl = ioh->pool;
319 
320 	mtx_enter(&iopl->mtx);
321 	switch (ioh->q_state) {
322 	case RUNQ_IDLE:
323 		TAILQ_INSERT_TAIL(&iopl->queue, ioh, q_entry);
324 		ioh->q_state = RUNQ_POOLQ;
325 		break;
326 #ifdef DIAGNOSTIC
327 	case RUNQ_POOLQ:
328 		break;
329 	default:
330 		panic("scsi_ioh_add: unexpected state %u", ioh->q_state);
331 #endif
332 	}
333 	mtx_leave(&iopl->mtx);
334 
335 	/* lets get some io up in the air */
336 	scsi_ioh_runqueue(iopl);
337 }
338 
339 void
340 scsi_ioh_del(struct scsi_iohandler *ioh)
341 {
342 	struct scsi_iopool *iopl = ioh->pool;
343 
344 	mtx_enter(&iopl->mtx);
345 	switch (ioh->q_state) {
346 	case RUNQ_POOLQ:
347 		TAILQ_REMOVE(&iopl->queue, ioh, q_entry);
348 		ioh->q_state = RUNQ_IDLE;
349 		break;
350 #ifdef DIAGNOSTIC
351 	case RUNQ_IDLE:
352 		break;
353 	default:
354 		panic("scsi_ioh_del: unexpected state %u", ioh->q_state);
355 #endif
356 	}
357 
358 	mtx_leave(&iopl->mtx);
359 }
360 
361 /*
362  * internal iopool runqueue handling.
363  */
364 
365 struct scsi_iohandler *
366 scsi_ioh_deq(struct scsi_iopool *iopl)
367 {
368 	struct scsi_iohandler *ioh = NULL;
369 
370 	mtx_enter(&iopl->mtx);
371 	ioh = TAILQ_FIRST(&iopl->queue);
372 	if (ioh != NULL) {
373 		TAILQ_REMOVE(&iopl->queue, ioh, q_entry);
374 		ioh->q_state = RUNQ_IDLE;
375 	}
376 	mtx_leave(&iopl->mtx);
377 
378 	return (ioh);
379 }
380 
381 int
382 scsi_ioh_pending(struct scsi_iopool *iopl)
383 {
384 	int rv;
385 
386 	mtx_enter(&iopl->mtx);
387 	rv = !TAILQ_EMPTY(&iopl->queue);
388 	mtx_leave(&iopl->mtx);
389 
390 	return (rv);
391 }
392 
393 void
394 scsi_ioh_runqueue(struct scsi_iopool *iopl)
395 {
396 	struct scsi_iohandler *ioh;
397 	void *io;
398 
399 	if (!scsi_sem_enter(&iopl->mtx, &iopl->running))
400 		return;
401 	do {
402 		while (scsi_ioh_pending(iopl)) {
403 			io = iopl->io_get(iopl->iocookie);
404 			if (io == NULL)
405 				break;
406 
407 			ioh = scsi_ioh_deq(iopl);
408 			if (ioh == NULL) {
409 				iopl->io_put(iopl->iocookie, io);
410 				break;
411 			}
412 
413 			ioh->handler(ioh->cookie, io);
414 		}
415 	} while (!scsi_sem_leave(&iopl->mtx, &iopl->running));
416 }
417 
418 /*
419  * move an io from a runq to a proc thats waiting for an io.
420  */
421 
422 void
423 scsi_move(struct scsi_io_mover *m)
424 {
425 	mtx_enter(&m->mtx);
426 	while (!m->done)
427 		msleep(m, &m->mtx, PRIBIO, "scsiiomv", 0);
428 	mtx_leave(&m->mtx);
429 }
430 
431 void
432 scsi_move_done(void *cookie, void *io)
433 {
434 	struct scsi_io_mover *m = cookie;
435 
436 	mtx_enter(&m->mtx);
437 	m->io = io;
438 	m->done = 1;
439 	wakeup_one(m);
440 	mtx_leave(&m->mtx);
441 }
442 
443 /*
444  * synchronous api for allocating an io.
445  */
446 
447 void *
448 scsi_io_get(struct scsi_iopool *iopl, int flags)
449 {
450 	struct scsi_io_mover m = SCSI_IO_MOVER_INITIALIZER;
451 	struct scsi_iohandler ioh;
452 	void *io;
453 
454 	/* try and sneak an io off the backend immediately */
455 	io = iopl->io_get(iopl->iocookie);
456 	if (io != NULL)
457 		return (io);
458 	else if (ISSET(flags, SCSI_NOSLEEP))
459 		return (NULL);
460 
461 	/* otherwise sleep until we get one */
462 	scsi_ioh_set(&ioh, iopl, scsi_io_get_done, &m);
463 	scsi_ioh_add(&ioh);
464 	scsi_move(&m);
465 
466 	return (m.io);
467 }
468 
469 void
470 scsi_io_get_done(void *cookie, void *io)
471 {
472 	scsi_move_done(cookie, io);
473 }
474 
475 void
476 scsi_io_put(struct scsi_iopool *iopl, void *io)
477 {
478 	iopl->io_put(iopl->iocookie, io);
479 	scsi_ioh_runqueue(iopl);
480 }
481 
482 /*
483  * public interface to the xsh api.
484  */
485 
486 void
487 scsi_xsh_set(struct scsi_xshandler *xsh, struct scsi_link *link,
488     void (*handler)(struct scsi_xfer *))
489 {
490 	scsi_ioh_set(&xsh->ioh, link->pool, scsi_xsh_ioh, xsh);
491 
492 	xsh->link = link;
493 	xsh->handler = handler;
494 }
495 
496 void
497 scsi_xsh_add(struct scsi_xshandler *xsh)
498 {
499 	struct scsi_link *link = xsh->link;
500 
501 	if (ISSET(link->state, SDEV_S_DYING))
502 		return;
503 
504 	mtx_enter(&link->pool->mtx);
505 	if (xsh->ioh.q_state == RUNQ_IDLE) {
506 		TAILQ_INSERT_TAIL(&link->queue, &xsh->ioh, q_entry);
507 		xsh->ioh.q_state = RUNQ_LINKQ;
508 	}
509 	mtx_leave(&link->pool->mtx);
510 
511 	/* lets get some io up in the air */
512 	scsi_xsh_runqueue(link);
513 }
514 
515 void
516 scsi_xsh_del(struct scsi_xshandler *xsh)
517 {
518 	struct scsi_link *link = xsh->link;
519 
520 	mtx_enter(&link->pool->mtx);
521 	switch (xsh->ioh.q_state) {
522 	case RUNQ_IDLE:
523 		break;
524 	case RUNQ_LINKQ:
525 		TAILQ_REMOVE(&link->queue, &xsh->ioh, q_entry);
526 		break;
527 	case RUNQ_POOLQ:
528 		TAILQ_REMOVE(&link->pool->queue, &xsh->ioh, q_entry);
529 		link->pending--;
530 		if (ISSET(link->state, SDEV_S_DYING) && link->pending == 0)
531 			wakeup_one(&link->pending);
532 		break;
533 	default:
534 		panic("unexpected xsh state %u", xsh->ioh.q_state);
535 	}
536 	xsh->ioh.q_state = RUNQ_IDLE;
537 	mtx_leave(&link->pool->mtx);
538 }
539 
540 /*
541  * internal xs runqueue handling.
542  */
543 
544 void
545 scsi_xsh_runqueue(struct scsi_link *link)
546 {
547 	struct scsi_iohandler *ioh;
548 	int runq;
549 
550 	if (!scsi_sem_enter(&link->pool->mtx, &link->running))
551 		return;
552 	do {
553 		runq = 0;
554 
555 		mtx_enter(&link->pool->mtx);
556 		while (!ISSET(link->state, SDEV_S_DYING) &&
557 		    link->pending < link->openings &&
558 		    ((ioh = TAILQ_FIRST(&link->queue)) != NULL)) {
559 			link->pending++;
560 
561 			TAILQ_REMOVE(&link->queue, ioh, q_entry);
562 			TAILQ_INSERT_TAIL(&link->pool->queue, ioh, q_entry);
563 			ioh->q_state = RUNQ_POOLQ;
564 
565 			runq = 1;
566 		}
567 		mtx_leave(&link->pool->mtx);
568 
569 		if (runq)
570 			scsi_ioh_runqueue(link->pool);
571 	} while (!scsi_sem_leave(&link->pool->mtx, &link->running));
572 }
573 
574 void
575 scsi_xsh_ioh(void *cookie, void *io)
576 {
577 	struct scsi_xshandler *xsh = cookie;
578 	struct scsi_xfer *xs;
579 
580 	xs = scsi_xs_io(xsh->link, io, SCSI_NOSLEEP);
581 	if (xs == NULL) {
582 		/*
583 		 * in this situation we should queue things waiting for an
584 		 * xs and then give them xses when they were supposed be to
585 		 * returned to the pool.
586 		 */
587 
588 		printf("scsi_xfer pool exhausted!\n");
589 		scsi_xsh_add(xsh);
590 		return;
591 	}
592 
593 	xsh->handler(xs);
594 }
595 
596 /*
597  * Get a scsi transfer structure for the caller.
598  * Go to the iopool backend for an "opening" and then attach an xs to it.
599  */
600 
601 struct scsi_xfer *
602 scsi_xs_get(struct scsi_link *link, int flags)
603 {
604 	struct scsi_xshandler xsh;
605 	struct scsi_io_mover m = SCSI_IO_MOVER_INITIALIZER;
606 
607 	struct scsi_iopool *iopl = link->pool;
608 	void *io;
609 
610 	if (ISSET(link->state, SDEV_S_DYING))
611 		return (NULL);
612 
613 	/* really custom xs handler to avoid scsi_xsh_ioh */
614 	scsi_ioh_set(&xsh.ioh, iopl, scsi_xs_get_done, &m);
615 	xsh.link = link;
616 
617 	if (!scsi_link_open(link)) {
618 		if (ISSET(flags, SCSI_NOSLEEP))
619 			return (NULL);
620 
621 		scsi_xsh_add(&xsh);
622 		scsi_move(&m);
623 		if (m.io == NULL)
624 			return (NULL);
625 
626 		io = m.io;
627 	} else if ((io = iopl->io_get(iopl->iocookie)) == NULL) {
628 		if (ISSET(flags, SCSI_NOSLEEP)) {
629 			scsi_link_close(link);
630 			return (NULL);
631 		}
632 
633 		scsi_ioh_add(&xsh.ioh);
634 		scsi_move(&m);
635 		if (m.io == NULL)
636 			return (NULL);
637 
638 		io = m.io;
639 	}
640 
641 	return (scsi_xs_io(link, io, flags));
642 }
643 
644 void
645 scsi_xs_get_done(void *cookie, void *io)
646 {
647 	scsi_move_done(cookie, io);
648 }
649 
650 void
651 scsi_link_shutdown(struct scsi_link *link)
652 {
653 	struct scsi_runq sleepers = TAILQ_HEAD_INITIALIZER(sleepers);
654 	struct scsi_iopool *iopl = link->pool;
655 	struct scsi_iohandler *ioh;
656 	struct scsi_xshandler *xsh;
657 
658 	mtx_enter(&iopl->mtx);
659 	while ((ioh = TAILQ_FIRST(&link->queue)) != NULL) {
660 		TAILQ_REMOVE(&link->queue, ioh, q_entry);
661 		ioh->q_state = RUNQ_IDLE;
662 
663 		if (ioh->handler == scsi_xs_get_done)
664 			TAILQ_INSERT_TAIL(&sleepers, ioh, q_entry);
665 #ifdef DIAGNOSTIC
666 		else
667 			panic("scsi_link_shutdown: scsi_xshandler on link");
668 #endif
669 	}
670 
671 	ioh = TAILQ_FIRST(&iopl->queue);
672 	while (ioh != NULL) {
673 		xsh = (struct scsi_xshandler *)ioh;
674 		ioh = TAILQ_NEXT(ioh, q_entry);
675 
676 #ifdef DIAGNOSTIC
677 		if (xsh->ioh.handler == scsi_xsh_ioh &&
678 		    xsh->link == link)
679 			panic("scsi_link_shutdown: scsi_xshandler on pool");
680 #endif
681 
682 		if (xsh->ioh.handler == scsi_xs_get_done &&
683 		    xsh->link == link) {
684 			TAILQ_REMOVE(&iopl->queue, &xsh->ioh, q_entry);
685 			xsh->ioh.q_state = RUNQ_IDLE;
686 			link->pending--;
687 
688 			TAILQ_INSERT_TAIL(&sleepers, &xsh->ioh, q_entry);
689 		}
690 	}
691 
692 	while (link->pending > 0)
693 		msleep(&link->pending, &iopl->mtx, PRIBIO, "pendxs", 0);
694 	mtx_leave(&iopl->mtx);
695 
696 	while ((ioh = TAILQ_FIRST(&sleepers)) != NULL) {
697 		TAILQ_REMOVE(&sleepers, ioh, q_entry);
698 		ioh->handler(ioh->cookie, NULL);
699 	}
700 }
701 
702 int
703 scsi_link_open(struct scsi_link *link)
704 {
705 	int open = 0;
706 
707 	mtx_enter(&link->pool->mtx);
708 	if (link->pending < link->openings) {
709 		link->pending++;
710 		open = 1;
711 	}
712 	mtx_leave(&link->pool->mtx);
713 
714 	return (open);
715 }
716 
717 void
718 scsi_link_close(struct scsi_link *link)
719 {
720 	mtx_enter(&link->pool->mtx);
721 	link->pending--;
722 	if (ISSET(link->state, SDEV_S_DYING) && link->pending == 0)
723 		wakeup_one(&link->pending);
724 	mtx_leave(&link->pool->mtx);
725 
726 	scsi_xsh_runqueue(link);
727 }
728 
729 struct scsi_xfer *
730 scsi_xs_io(struct scsi_link *link, void *io, int flags)
731 {
732 	struct scsi_xfer *xs;
733 
734 	xs = pool_get(&scsi_xfer_pool, PR_ZERO |
735 	    (ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK));
736 	if (xs == NULL) {
737 		scsi_io_put(link->pool, io);
738 		scsi_link_close(link);
739 	} else {
740 		xs->flags = flags;
741 		xs->sc_link = link;
742 		xs->retries = SCSI_RETRIES;
743 		xs->timeout = 10000;
744 		xs->cmd = &xs->cmdstore;
745 		xs->io = io;
746 	}
747 
748 	return (xs);
749 }
750 
751 void
752 scsi_xs_put(struct scsi_xfer *xs)
753 {
754 	struct scsi_link *link = xs->sc_link;
755 	void *io = xs->io;
756 
757 	pool_put(&scsi_xfer_pool, xs);
758 
759 	scsi_io_put(link->pool, io);
760 	scsi_link_close(link);
761 }
762 
763 /*
764  * Find out from the device what its capacity is.
765  */
766 daddr64_t
767 scsi_size(struct scsi_link *sc_link, int flags, u_int32_t *blksize)
768 {
769 	struct scsi_read_cap_data_16 *rdcap16;
770 	struct scsi_read_capacity_16 *cmd;
771 	struct scsi_read_cap_data *rdcap;
772 	struct scsi_read_capacity *cmd10;
773 	struct scsi_xfer *xs;
774 	daddr64_t max_addr;
775 	int error;
776 
777 	if (blksize != NULL)
778 		*blksize = 0;
779 
780 	CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST);
781 
782 	/*
783 	 * Start with a READ CAPACITY(10).
784 	 */
785 	rdcap = dma_alloc(sizeof(*rdcap), ((flags & SCSI_NOSLEEP) ?
786 	    PR_NOWAIT : PR_WAITOK) | PR_ZERO);
787 	if (rdcap == NULL)
788 		return (0);
789 
790 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
791 	if (xs == NULL) {
792 		dma_free(rdcap, sizeof(*rdcap));
793 		return (0);
794 	}
795 	xs->cmdlen = sizeof(*cmd10);
796 	xs->data = (void *)rdcap;
797 	xs->datalen = sizeof(*rdcap);
798 	xs->timeout = 20000;
799 
800 	cmd10 = (struct scsi_read_capacity *)xs->cmd;
801 	cmd10->opcode = READ_CAPACITY;
802 
803 	error = scsi_xs_sync(xs);
804 	scsi_xs_put(xs);
805 
806 	if (error) {
807 		SC_DEBUG(sc_link, SDEV_DB1, ("READ CAPACITY error (%#x)\n",
808 		    error));
809 		dma_free(rdcap, sizeof(*rdcap));
810 		return (0);
811 	}
812 
813 	max_addr = _4btol(rdcap->addr);
814 	if (blksize != NULL)
815 		*blksize = _4btol(rdcap->length);
816 	dma_free(rdcap, sizeof(*rdcap));
817 
818 	if (SCSISPC(sc_link->inqdata.version) < 3 && max_addr != 0xffffffff)
819 		goto exit;
820 
821 	/*
822 	 * SCSI-3 devices, or devices reporting more than 2^32-1 sectors can
823 	 * try READ CAPACITY(16).
824 	 */
825 	rdcap16 = dma_alloc(sizeof(*rdcap16), ((flags & SCSI_NOSLEEP) ?
826 	    PR_NOWAIT : PR_WAITOK) | PR_ZERO);
827 	if (rdcap16 == NULL)
828 		goto exit;
829 
830 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
831 	if (xs == NULL) {
832 		dma_free(rdcap16, sizeof(*rdcap16));
833 		goto exit;
834 	}
835 	xs->cmdlen = sizeof(*cmd);
836 	xs->data = (void *)rdcap16;
837 	xs->datalen = sizeof(*rdcap16);
838 	xs->timeout = 20000;
839 
840 	cmd = (struct scsi_read_capacity_16 *)xs->cmd;
841 	cmd->opcode = READ_CAPACITY_16;
842 	cmd->byte2 = SRC16_SERVICE_ACTION;
843 	_lto4b(sizeof(*rdcap16), cmd->length);
844 
845 	error = scsi_xs_sync(xs);
846 	scsi_xs_put(xs);
847 	if (error) {
848 		SC_DEBUG(sc_link, SDEV_DB1, ("READ CAPACITY 16 error (%#x)\n",
849 		    error));
850 		dma_free(rdcap16, sizeof(*rdcap16));
851 		goto exit;
852 	}
853 
854 	max_addr = _8btol(rdcap16->addr);
855 	if (blksize != NULL)
856 		*blksize = _4btol(rdcap16->length);
857 	/* XXX The other READ CAPACITY(16) info could be stored away. */
858 	dma_free(rdcap16, sizeof(*rdcap16));
859 
860 	return (max_addr + 1);
861 
862 exit:
863 	/* Return READ CAPACITY 10 values. */
864 	if (max_addr != 0xffffffff)
865 		return (max_addr + 1);
866 	else if (blksize != NULL)
867 		*blksize = 0;
868 	return (0);
869 }
870 
871 /*
872  * Get scsi driver to send a "are you ready?" command
873  */
874 int
875 scsi_test_unit_ready(struct scsi_link *sc_link, int retries, int flags)
876 {
877 	struct scsi_test_unit_ready *cmd;
878 	struct scsi_xfer *xs;
879 	int error;
880 
881 	xs = scsi_xs_get(sc_link, flags);
882 	if (xs == NULL)
883 		return (ENOMEM);
884 	xs->cmdlen = sizeof(*cmd);
885 	xs->retries = retries;
886 	xs->timeout = 10000;
887 
888 	cmd = (struct scsi_test_unit_ready *)xs->cmd;
889 	cmd->opcode = TEST_UNIT_READY;
890 
891 	error = scsi_xs_sync(xs);
892 	scsi_xs_put(xs);
893 
894 	return (error);
895 }
896 
897 void
898 scsi_init_inquiry(struct scsi_xfer *xs, u_int8_t flags, u_int8_t pagecode,
899     void *data, size_t len)
900 {
901 	struct scsi_inquiry *cmd;
902 
903 	cmd = (struct scsi_inquiry *)xs->cmd;
904 	cmd->opcode = INQUIRY;
905 	cmd->flags = flags;
906 	cmd->pagecode = pagecode;
907 	_lto2b(len, cmd->length);
908 
909 	xs->cmdlen = sizeof(*cmd);
910 
911 	xs->flags |= SCSI_DATA_IN;
912 	xs->data = data;
913 	xs->datalen = len;
914 }
915 
916 /*
917  * Do a scsi operation asking a device what it is.
918  * Use the scsi_cmd routine in the switch table.
919  */
920 int
921 scsi_inquire(struct scsi_link *link, struct scsi_inquiry_data *inqbuf,
922     int flags)
923 {
924 	struct scsi_xfer *xs;
925 	int error;
926 
927 	xs = scsi_xs_get(link, flags);
928 	if (xs == NULL)
929 		return (EBUSY);
930 
931 	/*
932 	 * Ask for only the basic 36 bytes of SCSI2 inquiry information. This
933 	 * avoids problems with devices that choke trying to supply more.
934 	 */
935 	scsi_init_inquiry(xs, 0, 0, inqbuf, SID_INQUIRY_HDR + SID_SCSI2_ALEN);
936 
937 	bzero(inqbuf, sizeof(*inqbuf));
938 	memset(&inqbuf->vendor, ' ', sizeof inqbuf->vendor);
939 	memset(&inqbuf->product, ' ', sizeof inqbuf->product);
940 	memset(&inqbuf->revision, ' ', sizeof inqbuf->revision);
941 	memset(&inqbuf->extra, ' ', sizeof inqbuf->extra);
942 
943 	error = scsi_xs_sync(xs);
944 
945 	scsi_xs_put(xs);
946 
947 	return (error);
948 }
949 
950 /*
951  * Query a VPD inquiry page
952  */
953 int
954 scsi_inquire_vpd(struct scsi_link *sc_link, void *buf, u_int buflen,
955     u_int8_t page, int flags)
956 {
957 	struct scsi_xfer *xs;
958 	int error;
959 
960 	if (sc_link->flags & SDEV_UMASS)
961 		return (EJUSTRETURN);
962 
963 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
964 	if (xs == NULL)
965 		return (ENOMEM);
966 
967 	xs->retries = 2;
968 	xs->timeout = 10000;
969 
970 	scsi_init_inquiry(xs, SI_EVPD, page, buf, buflen);
971 
972 	error = scsi_xs_sync(xs);
973 
974 	scsi_xs_put(xs);
975 
976 	return (error);
977 }
978 
979 /*
980  * Prevent or allow the user to remove the media
981  */
982 int
983 scsi_prevent(struct scsi_link *sc_link, int type, int flags)
984 {
985 	struct scsi_prevent *cmd;
986 	struct scsi_xfer *xs;
987 	int error;
988 
989 	if (sc_link->quirks & ADEV_NODOORLOCK)
990 		return (0);
991 
992 	xs = scsi_xs_get(sc_link, flags);
993 	if (xs == NULL)
994 		return (ENOMEM);
995 	xs->cmdlen = sizeof(*cmd);
996 	xs->retries = 2;
997 	xs->timeout = 5000;
998 
999 	cmd = (struct scsi_prevent *)xs->cmd;
1000 	cmd->opcode = PREVENT_ALLOW;
1001 	cmd->how = type;
1002 
1003 	error = scsi_xs_sync(xs);
1004 	scsi_xs_put(xs);
1005 
1006 	return (error);
1007 }
1008 
1009 /*
1010  * Get scsi driver to send a "start up" command
1011  */
1012 int
1013 scsi_start(struct scsi_link *sc_link, int type, int flags)
1014 {
1015 	struct scsi_start_stop *cmd;
1016 	struct scsi_xfer *xs;
1017 	int error;
1018 
1019 	xs = scsi_xs_get(sc_link, flags);
1020 	if (xs == NULL)
1021 		return (ENOMEM);
1022 	xs->cmdlen = sizeof(*cmd);
1023 	xs->retries = 2;
1024 	xs->timeout = (type == SSS_START) ? 30000 : 10000;
1025 
1026 	cmd = (struct scsi_start_stop *)xs->cmd;
1027 	cmd->opcode = START_STOP;
1028 	cmd->how = type;
1029 
1030 	error = scsi_xs_sync(xs);
1031 	scsi_xs_put(xs);
1032 
1033 	return (error);
1034 }
1035 
1036 int
1037 scsi_mode_sense(struct scsi_link *sc_link, int byte2, int page,
1038     struct scsi_mode_header *data, size_t len, int flags, int timeout)
1039 {
1040 	struct scsi_mode_sense *cmd;
1041 	struct scsi_xfer *xs;
1042 	int error;
1043 
1044 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN);
1045 	if (xs == NULL)
1046 		return (ENOMEM);
1047 	xs->cmdlen = sizeof(*cmd);
1048 	xs->data = (void *)data;
1049 	xs->datalen = len;
1050 	xs->timeout = timeout;
1051 
1052 	/*
1053 	 * Make sure the sense buffer is clean before we do the mode sense, so
1054 	 * that checks for bogus values of 0 will work in case the mode sense
1055 	 * fails.
1056 	 */
1057 	bzero(data, len);
1058 
1059 	cmd = (struct scsi_mode_sense *)xs->cmd;
1060 	cmd->opcode = MODE_SENSE;
1061 	cmd->byte2 = byte2;
1062 	cmd->page = page;
1063 
1064 	if (len > 0xff)
1065 		len = 0xff;
1066 	cmd->length = len;
1067 
1068 	error = scsi_xs_sync(xs);
1069 	scsi_xs_put(xs);
1070 
1071 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_sense: page %#x, error = %d\n",
1072 	    page, error));
1073 
1074 	return (error);
1075 }
1076 
1077 int
1078 scsi_mode_sense_big(struct scsi_link *sc_link, int byte2, int page,
1079     struct scsi_mode_header_big *data, size_t len, int flags, int timeout)
1080 {
1081 	struct scsi_mode_sense_big *cmd;
1082 	struct scsi_xfer *xs;
1083 	int error;
1084 
1085 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN);
1086 	if (xs == NULL)
1087 		return (ENOMEM);
1088 	xs->cmdlen = sizeof(*cmd);
1089 	xs->data = (void *)data;
1090 	xs->datalen = len;
1091 	xs->timeout = timeout;
1092 
1093 	/*
1094 	 * Make sure the sense buffer is clean before we do the mode sense, so
1095 	 * that checks for bogus values of 0 will work in case the mode sense
1096 	 * fails.
1097 	 */
1098 	bzero(data, len);
1099 
1100 	cmd = (struct scsi_mode_sense_big *)xs->cmd;
1101 	cmd->opcode = MODE_SENSE_BIG;
1102 	cmd->byte2 = byte2;
1103 	cmd->page = page;
1104 
1105 	if (len > 0xffff)
1106 		len = 0xffff;
1107 	_lto2b(len, cmd->length);
1108 
1109 	error = scsi_xs_sync(xs);
1110 	scsi_xs_put(xs);
1111 
1112 	SC_DEBUG(sc_link, SDEV_DB2,
1113 	    ("scsi_mode_sense_big: page %#x, error = %d\n", page, error));
1114 
1115 	return (error);
1116 }
1117 
1118 void *
1119 scsi_mode_sense_page(struct scsi_mode_header *hdr, const int page_len)
1120 {
1121 	int					total_length, header_length;
1122 
1123 	total_length = hdr->data_length + sizeof(hdr->data_length);
1124 	header_length = sizeof(*hdr) + hdr->blk_desc_len;
1125 
1126 	if ((total_length - header_length) < page_len)
1127 		return (NULL);
1128 
1129 	return ((u_char *)hdr + header_length);
1130 }
1131 
1132 void *
1133 scsi_mode_sense_big_page(struct scsi_mode_header_big *hdr, const int page_len)
1134 {
1135 	int					total_length, header_length;
1136 
1137 	total_length = _2btol(hdr->data_length) + sizeof(hdr->data_length);
1138 	header_length = sizeof(*hdr) + _2btol(hdr->blk_desc_len);
1139 
1140 	if ((total_length - header_length) < page_len)
1141 		return (NULL);
1142 
1143 	return ((u_char *)hdr + header_length);
1144 }
1145 
1146 int
1147 scsi_do_mode_sense(struct scsi_link *sc_link, int page,
1148     union scsi_mode_sense_buf *buf, void **page_data, u_int32_t *density,
1149     u_int64_t *block_count, u_int32_t *block_size, int page_len, int flags,
1150     int *big)
1151 {
1152 	struct scsi_direct_blk_desc		*direct;
1153 	struct scsi_blk_desc			*general;
1154 	int					error, blk_desc_len, offset;
1155 
1156 	*page_data = NULL;
1157 
1158 	if (density != NULL)
1159 		*density = 0;
1160 	if (block_count != NULL)
1161 		*block_count = 0;
1162 	if (block_size != NULL)
1163 		*block_size = 0;
1164 	if (big != NULL)
1165 		*big = 0;
1166 
1167 	if ((sc_link->flags & SDEV_ATAPI) == 0 ||
1168 	    (sc_link->inqdata.device & SID_TYPE) == T_SEQUENTIAL) {
1169 		/*
1170 		 * Try 6 byte mode sense request first. Some devices don't
1171 		 * distinguish between 6 and 10 byte MODE SENSE commands,
1172 		 * returning 6 byte data for 10 byte requests. ATAPI tape
1173 		 * drives use MODE SENSE (6) even though ATAPI uses 10 byte
1174 		 * everything else. Don't bother with SMS_DBD. Check returned
1175 		 * data length to ensure that at least a header (3 additional
1176 		 * bytes) is returned.
1177 		 */
1178 		error = scsi_mode_sense(sc_link, 0, page, &buf->hdr,
1179 		    sizeof(*buf), flags, 20000);
1180 		if (error == 0) {
1181 			*page_data = scsi_mode_sense_page(&buf->hdr, page_len);
1182 			if (*page_data == NULL) {
1183 				/*
1184 				 * XXX
1185 				 * Page data may be invalid (e.g. all zeros)
1186 				 * but we accept the device's word that this is
1187 				 * the best it can do. Some devices will freak
1188 				 * out if their word is not accepted and
1189 				 * MODE_SENSE_BIG is attempted.
1190 				 */
1191 				return (0);
1192 			}
1193 			offset = sizeof(struct scsi_mode_header);
1194 			blk_desc_len = buf->hdr.blk_desc_len;
1195 			goto blk_desc;
1196 		}
1197 	}
1198 
1199 	/*
1200 	 * Try 10 byte mode sense request. Don't bother with SMS_DBD or
1201 	 * SMS_LLBAA. Bail out if the returned information is less than
1202 	 * a big header in size (6 additional bytes).
1203 	 */
1204 	error = scsi_mode_sense_big(sc_link, 0, page, &buf->hdr_big,
1205 	    sizeof(*buf), flags, 20000);
1206 	if (error != 0)
1207 		return (error);
1208 	if (_2btol(buf->hdr_big.data_length) < 6)
1209 		return (EIO);
1210 
1211 	if (big != NULL)
1212 		*big = 1;
1213 	offset = sizeof(struct scsi_mode_header_big);
1214 	*page_data = scsi_mode_sense_big_page(&buf->hdr_big, page_len);
1215 	blk_desc_len = _2btol(buf->hdr_big.blk_desc_len);
1216 
1217 blk_desc:
1218 	/* Both scsi_blk_desc and scsi_direct_blk_desc are 8 bytes. */
1219 	if (blk_desc_len == 0 || (blk_desc_len % 8 != 0))
1220 		return (0);
1221 
1222 	switch (sc_link->inqdata.device & SID_TYPE) {
1223 	case T_SEQUENTIAL:
1224 		/*
1225 		 * XXX What other device types return general block descriptors?
1226 		 */
1227 		general = (struct scsi_blk_desc *)&buf->buf[offset];
1228 		if (density != NULL)
1229 			*density = general->density;
1230 		if (block_size != NULL)
1231 			*block_size = _3btol(general->blklen);
1232 		if (block_count != NULL)
1233 			*block_count = (u_int64_t)_3btol(general->nblocks);
1234 		break;
1235 
1236 	default:
1237 		direct = (struct scsi_direct_blk_desc *)&buf->buf[offset];
1238 		if (density != NULL)
1239 			*density = direct->density;
1240 		if (block_size != NULL)
1241 			*block_size = _3btol(direct->blklen);
1242 		if (block_count != NULL)
1243 			*block_count = (u_int64_t)_4btol(direct->nblocks);
1244 		break;
1245 	}
1246 
1247 	return (0);
1248 }
1249 
1250 int
1251 scsi_mode_select(struct scsi_link *sc_link, int byte2,
1252     struct scsi_mode_header *data, int flags, int timeout)
1253 {
1254 	struct scsi_mode_select *cmd;
1255 	struct scsi_xfer *xs;
1256 	u_int32_t len;
1257 	int error;
1258 
1259 	len = data->data_length + 1; /* 1 == sizeof(data_length) */
1260 
1261 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_OUT);
1262 	if (xs == NULL)
1263 		return (ENOMEM);
1264 	xs->cmdlen = sizeof(*cmd);
1265 	xs->data = (void *)data;
1266 	xs->datalen = len;
1267 	xs->timeout = timeout;
1268 
1269 	cmd = (struct scsi_mode_select *)xs->cmd;
1270 	cmd->opcode = MODE_SELECT;
1271 	cmd->byte2 = byte2;
1272 	cmd->length = len;
1273 
1274 	/* Length is reserved when doing mode select so zero it. */
1275 	data->data_length = 0;
1276 
1277 	error = scsi_xs_sync(xs);
1278 	scsi_xs_put(xs);
1279 
1280 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_select: error = %d\n", error));
1281 
1282 	return (error);
1283 }
1284 
1285 int
1286 scsi_mode_select_big(struct scsi_link *sc_link, int byte2,
1287     struct scsi_mode_header_big *data, int flags, int timeout)
1288 {
1289 	struct scsi_mode_select_big *cmd;
1290 	struct scsi_xfer *xs;
1291 	u_int32_t len;
1292 	int error;
1293 
1294 	len = _2btol(data->data_length) + 2; /* 2 == sizeof data_length */
1295 
1296 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_OUT);
1297 	if (xs == NULL)
1298 		return (ENOMEM);
1299 	xs->cmdlen = sizeof(*cmd);
1300 	xs->data = (void *)data;
1301 	xs->datalen = len;
1302 	xs->timeout = timeout;
1303 
1304 	cmd = (struct scsi_mode_select_big *)xs->cmd;
1305 	cmd->opcode = MODE_SELECT_BIG;
1306 	cmd->byte2 = byte2;
1307 	_lto2b(len, cmd->length);
1308 
1309 	/* Length is reserved when doing mode select so zero it. */
1310 	_lto2b(0, data->data_length);
1311 
1312 	error = scsi_xs_sync(xs);
1313 	scsi_xs_put(xs);
1314 
1315 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_select_big: error = %d\n",
1316 	    error));
1317 
1318 	return (error);
1319 }
1320 
1321 int
1322 scsi_report_luns(struct scsi_link *sc_link, int selectreport,
1323     struct scsi_report_luns_data *data, u_int32_t datalen, int flags,
1324     int timeout)
1325 {
1326 	struct scsi_report_luns *cmd;
1327 	struct scsi_xfer *xs;
1328 	int error;
1329 
1330 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN);
1331 	if (xs == NULL)
1332 		return (ENOMEM);
1333 	xs->cmdlen = sizeof(*cmd);
1334 	xs->data = (void *)data;
1335 	xs->datalen = datalen;
1336 	xs->timeout = timeout;
1337 
1338 	bzero(data, datalen);
1339 
1340 	cmd = (struct scsi_report_luns *)xs->cmd;
1341 	cmd->opcode = REPORT_LUNS;
1342 	cmd->selectreport = selectreport;
1343 	_lto4b(datalen, cmd->length);
1344 
1345 	error = scsi_xs_sync(xs);
1346 	scsi_xs_put(xs);
1347 
1348 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_report_luns: error = %d\n", error));
1349 
1350 	return (error);
1351 }
1352 
1353 void
1354 scsi_xs_exec(struct scsi_xfer *xs)
1355 {
1356 	xs->error = XS_NOERROR;
1357 	xs->resid = xs->datalen;
1358 	xs->status = 0;
1359 	CLR(xs->flags, ITSDONE);
1360 
1361 #ifdef SCSIDEBUG
1362 	if (xs->sc_link->flags & SDEV_DB1) {
1363 		scsi_xs_show(xs);
1364 		if (xs->datalen && (xs->flags & SCSI_DATA_OUT))
1365 			scsi_show_mem(xs->data, min(64, xs->datalen));
1366 	}
1367 #endif
1368 
1369 	/* The adapter's scsi_cmd() is responsible for callng scsi_done(). */
1370 	xs->sc_link->adapter->scsi_cmd(xs);
1371 }
1372 
1373 /*
1374  * This routine is called by the adapter when its xs handling is done.
1375  */
1376 void
1377 scsi_done(struct scsi_xfer *xs)
1378 {
1379 #ifdef SCSIDEBUG
1380 	if (xs->sc_link->flags & SDEV_DB1) {
1381 		if (xs->datalen && (xs->flags & SCSI_DATA_IN))
1382 			scsi_show_mem(xs->data, min(64, xs->datalen));
1383 	}
1384 #endif /* SCSIDEBUG */
1385 
1386 	SET(xs->flags, ITSDONE);
1387 	xs->done(xs);
1388 }
1389 
1390 int
1391 scsi_xs_sync(struct scsi_xfer *xs)
1392 {
1393 	struct mutex cookie = MUTEX_INITIALIZER(IPL_BIO);
1394 	int error;
1395 
1396 #ifdef DIAGNOSTIC
1397 	if (xs->cookie != NULL)
1398 		panic("xs->cookie != NULL in scsi_xs_sync");
1399 	if (xs->done != NULL)
1400 		panic("xs->done != NULL in scsi_xs_sync");
1401 #endif
1402 
1403 	/*
1404 	 * If we cant sleep while waiting for completion, get the adapter to
1405 	 * complete it for us.
1406 	 */
1407 	if (ISSET(xs->flags, SCSI_NOSLEEP))
1408 		SET(xs->flags, SCSI_POLL);
1409 
1410 	xs->done = scsi_xs_sync_done;
1411 
1412 	do {
1413 		xs->cookie = &cookie;
1414 
1415 		scsi_xs_exec(xs);
1416 
1417 		mtx_enter(&cookie);
1418 		while (xs->cookie != NULL)
1419 			msleep(xs, &cookie, PRIBIO, "syncxs", 0);
1420 		mtx_leave(&cookie);
1421 
1422 		error = scsi_xs_error(xs);
1423 	} while (error == ERESTART);
1424 
1425 	return (error);
1426 }
1427 
1428 void
1429 scsi_xs_sync_done(struct scsi_xfer *xs)
1430 {
1431 	struct mutex *cookie = xs->cookie;
1432 
1433 	if (cookie == NULL)
1434 		panic("scsi_done called twice on xs(%p)", xs);
1435 
1436 	mtx_enter(cookie);
1437 	xs->cookie = NULL;
1438 	if (!ISSET(xs->flags, SCSI_NOSLEEP))
1439 		wakeup_one(xs);
1440 	mtx_leave(cookie);
1441 }
1442 
1443 int
1444 scsi_xs_error(struct scsi_xfer *xs)
1445 {
1446 	int error = EIO;
1447 
1448 	SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_xs_error,err = 0x%x\n",
1449 	    xs->error));
1450 
1451 	if (ISSET(xs->sc_link->state, SDEV_S_DYING))
1452 		return (ENXIO);
1453 
1454 	switch (xs->error) {
1455 	case XS_NOERROR:	/* nearly always hit this one */
1456 		error = 0;
1457 		break;
1458 
1459 	case XS_SENSE:
1460 	case XS_SHORTSENSE:
1461 #ifdef SCSIDEBUG
1462 		scsi_sense_print_debug(xs);
1463 #endif
1464 		error = xs->sc_link->interpret_sense(xs);
1465 		SC_DEBUG(xs->sc_link, SDEV_DB3,
1466 		    ("scsi_interpret_sense returned %#x\n", error));
1467 		break;
1468 
1469 	case XS_NO_CCB:
1470 	case XS_BUSY:
1471 		error = scsi_delay(xs, 1);
1472 		break;
1473 
1474 	case XS_TIMEOUT:
1475 	case XS_RESET:
1476 		error = ERESTART;
1477 		break;
1478 
1479 	case XS_DRIVER_STUFFUP:
1480 	case XS_SELTIMEOUT:
1481 		break;
1482 
1483 	default:
1484 		sc_print_addr(xs->sc_link);
1485 		printf("unknown error category (0x%x) from scsi driver\n",
1486 		    xs->error);
1487 		break;
1488 	}
1489 
1490 	if (error == ERESTART && xs->retries-- < 1)
1491 		return (EIO);
1492 	else
1493 		return (error);
1494 }
1495 
1496 int
1497 scsi_delay(struct scsi_xfer *xs, int seconds)
1498 {
1499 	switch (xs->flags & (SCSI_POLL | SCSI_NOSLEEP)) {
1500 	case SCSI_POLL:
1501 		delay(1000000 * seconds);
1502 		return (ERESTART);
1503 	case SCSI_NOSLEEP:
1504 		/* Retry the command immediately since we can't delay. */
1505 		return (ERESTART);
1506 	case (SCSI_POLL | SCSI_NOSLEEP):
1507 		/* Invalid combination! */
1508 		return (EIO);
1509 	}
1510 
1511 	while (seconds-- > 0) {
1512 		if (tsleep(&lbolt, PRIBIO|PCATCH, "scbusy", 0)) {
1513 			/* Signal == abort xs. */
1514 			return (EIO);
1515 		}
1516 	}
1517 
1518 	return (ERESTART);
1519 }
1520 
1521 #ifdef SCSIDEBUG
1522 /*
1523  * Print out sense data details.
1524  */
1525 void
1526 scsi_sense_print_debug(struct scsi_xfer *xs)
1527 {
1528 	struct scsi_sense_data *sense = &xs->sense;
1529 	struct scsi_link *sc_link = xs->sc_link;
1530 
1531 	SC_DEBUG(sc_link, SDEV_DB1,
1532 	    ("code:%#x valid:%d key:%#x ili:%d eom:%d fmark:%d extra:%d\n",
1533 	    sense->error_code & SSD_ERRCODE,
1534 	    sense->error_code & SSD_ERRCODE_VALID ? 1 : 0,
1535 	    sense->flags & SSD_KEY,
1536 	    sense->flags & SSD_ILI ? 1 : 0,
1537 	    sense->flags & SSD_EOM ? 1 : 0,
1538 	    sense->flags & SSD_FILEMARK ? 1 : 0,
1539 	    sense->extra_len));
1540 
1541 	if (xs->sc_link->flags & SDEV_DB1)
1542 		scsi_show_mem((u_char *)&xs->sense, sizeof(xs->sense));
1543 
1544 	scsi_print_sense(xs);
1545 }
1546 #endif
1547 
1548 /*
1549  * Look at the returned sense and act on the error, determining
1550  * the unix error number to pass back.  (0 = report no error)
1551  *
1552  * THIS IS THE DEFAULT ERROR HANDLER
1553  */
1554 int
1555 scsi_interpret_sense(struct scsi_xfer *xs)
1556 {
1557 	struct scsi_sense_data			*sense = &xs->sense;
1558 	struct scsi_link			*sc_link = xs->sc_link;
1559 	u_int8_t				serr, skey;
1560 	int					error;
1561 
1562 	/* Default sense interpretation. */
1563 	serr = sense->error_code & SSD_ERRCODE;
1564 	if (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED)
1565 		skey = 0xff;	/* Invalid value, since key is 4 bit value. */
1566 	else
1567 		skey = sense->flags & SSD_KEY;
1568 
1569 	/*
1570 	 * Interpret the key/asc/ascq information where appropriate.
1571 	 */
1572 	error = 0;
1573 	switch (skey) {
1574 	case SKEY_NO_SENSE:
1575 	case SKEY_RECOVERED_ERROR:
1576 		if (xs->resid == xs->datalen)
1577 			xs->resid = 0;	/* not short read */
1578 		break;
1579 	case SKEY_BLANK_CHECK:
1580 	case SKEY_EQUAL:
1581 		break;
1582 	case SKEY_NOT_READY:
1583 		if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
1584 			return (0);
1585 		error = EIO;
1586 		if (xs->retries) {
1587 			switch (ASC_ASCQ(sense)) {
1588 			case SENSE_NOT_READY_BECOMING_READY:
1589 			case SENSE_NOT_READY_FORMAT:
1590 			case SENSE_NOT_READY_REBUILD:
1591 			case SENSE_NOT_READY_RECALC:
1592 			case SENSE_NOT_READY_INPROGRESS:
1593 			case SENSE_NOT_READY_LONGWRITE:
1594 			case SENSE_NOT_READY_SELFTEST:
1595 			case SENSE_NOT_READY_INIT_REQUIRED:
1596 				SC_DEBUG(sc_link, SDEV_DB1,
1597 		    		    ("not ready (ASC_ASCQ == %#x)\n",
1598 				    ASC_ASCQ(sense)));
1599 				return (scsi_delay(xs, 1));
1600 			case SENSE_NOMEDIUM:
1601 			case SENSE_NOMEDIUM_TCLOSED:
1602 			case SENSE_NOMEDIUM_TOPEN:
1603 			case SENSE_NOMEDIUM_LOADABLE:
1604 			case SENSE_NOMEDIUM_AUXMEM:
1605 				sc_link->flags &= ~SDEV_MEDIA_LOADED;
1606 				error = ENOMEDIUM;
1607 				break;
1608 			default:
1609 				break;
1610 			}
1611 		}
1612 		break;
1613 	case SKEY_MEDIUM_ERROR:
1614 		switch (ASC_ASCQ(sense)) {
1615 		case SENSE_NOMEDIUM:
1616 		case SENSE_NOMEDIUM_TCLOSED:
1617 		case SENSE_NOMEDIUM_TOPEN:
1618 		case SENSE_NOMEDIUM_LOADABLE:
1619 		case SENSE_NOMEDIUM_AUXMEM:
1620 			sc_link->flags &= ~SDEV_MEDIA_LOADED;
1621 			error = ENOMEDIUM;
1622 			break;
1623 		case SENSE_BAD_MEDIUM:
1624 		case SENSE_NR_MEDIUM_UNKNOWN_FORMAT:
1625 		case SENSE_NR_MEDIUM_INCOMPATIBLE_FORMAT:
1626 		case SENSE_NW_MEDIUM_UNKNOWN_FORMAT:
1627 		case SENSE_NW_MEDIUM_INCOMPATIBLE_FORMAT:
1628 		case SENSE_NF_MEDIUM_INCOMPATIBLE_FORMAT:
1629 		case SENSE_NW_MEDIUM_AC_MISMATCH:
1630 			error = EMEDIUMTYPE;
1631 			break;
1632 		default:
1633 			error = EIO;
1634 			break;
1635 		}
1636 		break;
1637 	case SKEY_ILLEGAL_REQUEST:
1638 		if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0)
1639 			return (0);
1640 		if (ASC_ASCQ(sense) == SENSE_MEDIUM_REMOVAL_PREVENTED)
1641 			return(EBUSY);
1642 		error = EINVAL;
1643 		break;
1644 	case SKEY_UNIT_ATTENTION:
1645 		switch (ASC_ASCQ(sense)) {
1646 		case SENSE_POWER_RESET_OR_BUS:
1647 		case SENSE_POWER_ON:
1648 		case SENSE_BUS_RESET:
1649 		case SENSE_BUS_DEVICE_RESET:
1650 		case SENSE_DEVICE_INTERNAL_RESET:
1651 		case SENSE_TSC_CHANGE_SE:
1652 		case SENSE_TSC_CHANGE_LVD:
1653 		case SENSE_IT_NEXUS_LOSS:
1654 			return (scsi_delay(xs, 1));
1655 		default:
1656 			break;
1657 		}
1658 		if ((sc_link->flags & SDEV_REMOVABLE) != 0)
1659 			sc_link->flags &= ~SDEV_MEDIA_LOADED;
1660 		if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 ||
1661 		    /* XXX Should reupload any transient state. */
1662 		    (sc_link->flags & SDEV_REMOVABLE) == 0) {
1663 			return (scsi_delay(xs, 1));
1664 		}
1665 		error = EIO;
1666 		break;
1667 	case SKEY_WRITE_PROTECT:
1668 		error = EROFS;
1669 		break;
1670 	case SKEY_ABORTED_COMMAND:
1671 		error = ERESTART;
1672 		break;
1673 	case SKEY_VOLUME_OVERFLOW:
1674 		error = ENOSPC;
1675 		break;
1676 	case SKEY_HARDWARE_ERROR:
1677 		if (ASC_ASCQ(sense) == SENSE_CARTRIDGE_FAULT)
1678 			return(EMEDIUMTYPE);
1679 		error = EIO;
1680 		break;
1681 	default:
1682 		error = EIO;
1683 		break;
1684 	}
1685 
1686 #ifndef SCSIDEBUG
1687 	/* SCSIDEBUG would mean it has already been printed. */
1688 	if (skey && (xs->flags & SCSI_SILENT) == 0)
1689 		scsi_print_sense(xs);
1690 #endif /* SCSIDEBUG */
1691 
1692 	return (error);
1693 }
1694 
1695 /*
1696  * Utility routines often used in SCSI stuff
1697  */
1698 
1699 
1700 /*
1701  * Print out the scsi_link structure's address info.
1702  */
1703 void
1704 sc_print_addr(struct scsi_link *sc_link)
1705 {
1706 	struct device *adapter_device = sc_link->bus->sc_dev.dv_parent;
1707 
1708 	printf("%s(%s:%d:%d): ",
1709 	    sc_link->device_softc ?
1710 	    ((struct device *)sc_link->device_softc)->dv_xname : "probe",
1711 	    adapter_device->dv_xname,
1712 	    sc_link->target, sc_link->lun);
1713 }
1714 
1715 static const char *sense_keys[16] = {
1716 	"No Additional Sense",
1717 	"Soft Error",
1718 	"Not Ready",
1719 	"Media Error",
1720 	"Hardware Error",
1721 	"Illegal Request",
1722 	"Unit Attention",
1723 	"Write Protected",
1724 	"Blank Check",
1725 	"Vendor Unique",
1726 	"Copy Aborted",
1727 	"Aborted Command",
1728 	"Equal Error",
1729 	"Volume Overflow",
1730 	"Miscompare Error",
1731 	"Reserved"
1732 };
1733 
1734 #ifdef SCSITERSE
1735 static __inline void
1736 asc2ascii(u_int8_t asc, u_int8_t ascq, char *result, size_t len)
1737 {
1738 	snprintf(result, len, "ASC 0x%02x ASCQ 0x%02x", asc, ascq);
1739 }
1740 #else
1741 static const struct {
1742 	u_int8_t asc, ascq;
1743 	char *description;
1744 } adesc[] = {
1745 	/* www.t10.org/lists/asc-num.txt as of 11/15/10. */
1746 	{ 0x00, 0x00, "No Additional Sense Information" },
1747 	{ 0x00, 0x01, "Filemark Detected" },
1748 	{ 0x00, 0x02, "End-Of-Partition/Medium Detected" },
1749 	{ 0x00, 0x03, "Setmark Detected" },
1750 	{ 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" },
1751 	{ 0x00, 0x05, "End-Of-Data Detected" },
1752 	{ 0x00, 0x06, "I/O Process Terminated" },
1753 	{ 0x00, 0x11, "Audio Play Operation In Progress" },
1754 	{ 0x00, 0x12, "Audio Play Operation Paused" },
1755 	{ 0x00, 0x13, "Audio Play Operation Successfully Completed" },
1756 	{ 0x00, 0x14, "Audio Play Operation Stopped Due to Error" },
1757 	{ 0x00, 0x15, "No Current Audio Status To Return" },
1758 	{ 0x00, 0x16, "Operation In Progress" },
1759 	{ 0x00, 0x17, "Cleaning Requested" },
1760 	{ 0x00, 0x18, "Erase Operation In Progress" },
1761 	{ 0x00, 0x19, "Locate Operation In Progress" },
1762 	{ 0x00, 0x1A, "Rewind Operation In Progress" },
1763 	{ 0x00, 0x1B, "Set Capacity Operation In Progress" },
1764 	{ 0x00, 0x1C, "Verify Operation In Progress" },
1765 	{ 0x01, 0x00, "No Index/Sector Signal" },
1766 	{ 0x02, 0x00, "No Seek Complete" },
1767 	{ 0x03, 0x00, "Peripheral Device Write Fault" },
1768 	{ 0x03, 0x01, "No Write Current" },
1769 	{ 0x03, 0x02, "Excessive Write Errors" },
1770 	{ 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" },
1771 	{ 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" },
1772 	{ 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" },
1773 	{ 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" },
1774 	{ 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" },
1775 	{ 0x04, 0x05, "Logical Unit Not Ready, Rebuild In Progress" },
1776 	{ 0x04, 0x06, "Logical Unit Not Ready, Recalculation In Progress" },
1777 	{ 0x04, 0x07, "Logical Unit Not Ready, Operation In Progress" },
1778 	{ 0x04, 0x08, "Logical Unit Not Ready, Long Write In Progress" },
1779 	{ 0x04, 0x09, "Logical Unit Not Ready, Self-Test In Progress" },
1780 	{ 0x04, 0x0A, "Logical Unit Not Accessible, Asymmetric Access State Transition" },
1781 	{ 0x04, 0x0B, "Logical Unit Not Accessible, Target Port In Standby State" },
1782 	{ 0x04, 0x0C, "Logical Unit Not Accessible, Target Port In Unavailable State" },
1783 	{ 0x04, 0x0D, "Logical Unit Not Ready, Structure Check Required" },
1784 	{ 0x04, 0x10, "Logical Unit Not Ready, Auxiliary Memory Not Accessible" },
1785 	{ 0x04, 0x11, "Logical Unit Not Ready, Notify (Enable Spinup) Required" },
1786 	{ 0x04, 0x12, "Logical Unit Not Ready, Offline" },
1787 	{ 0x04, 0x13, "Logical Unit Not Ready, SA Creation In Progress" },
1788 	{ 0x04, 0x14, "Logical Unit Not Ready, Space Allocation In Progress" },
1789 	{ 0x04, 0x15, "Logical Unit Not Ready, Robotics Disabled" },
1790 	{ 0x04, 0x16, "Logical Unit Not Ready, Configuration Required" },
1791 	{ 0x04, 0x17, "Logical Unit Not Ready, Calibration Required" },
1792 	{ 0x04, 0x18, "Logical Unit Not Ready, A Door Is Open" },
1793 	{ 0x04, 0x19, "Logical Unit Not Ready, Operating In Sequential Mode" },
1794 	{ 0x04, 0x1A, "Logical Unit Not Ready, Start Stop Unit Command In Progress" },
1795 	{ 0x05, 0x00, "Logical Unit Does Not Respond To Selection" },
1796 	{ 0x06, 0x00, "No Reference Position Found" },
1797 	{ 0x07, 0x00, "Multiple Peripheral Devices Selected" },
1798 	{ 0x08, 0x00, "Logical Unit Communication Failure" },
1799 	{ 0x08, 0x01, "Logical Unit Communication Timeout" },
1800 	{ 0x08, 0x02, "Logical Unit Communication Parity Error" },
1801 	{ 0x08, 0x03, "Logical Unit Communication CRC Error (ULTRA-DMA/32)" },
1802 	{ 0x08, 0x04, "Unreachable Copy Target" },
1803 	{ 0x09, 0x00, "Track Following Error" },
1804 	{ 0x09, 0x01, "Tracking Servo Failure" },
1805 	{ 0x09, 0x02, "Focus Servo Failure" },
1806 	{ 0x09, 0x03, "Spindle Servo Failure" },
1807 	{ 0x09, 0x04, "Head Select Fault" },
1808 	{ 0x0A, 0x00, "Error Log Overflow" },
1809 	{ 0x0B, 0x00, "Warning" },
1810 	{ 0x0B, 0x01, "Warning - Specified Temperature Exceeded" },
1811 	{ 0x0B, 0x02, "Warning - Enclosure Degraded" },
1812 	{ 0x0B, 0x03, "Warning - Background Self-Test Failed" },
1813 	{ 0x0B, 0x04, "Warning - Background Pre-Scan Detected Medium Error" },
1814 	{ 0x0B, 0x05, "Warning - Background Medium Scan Detected Medium Error" },
1815 	{ 0x0B, 0x06, "Warning - Non-Volatile Cache Now Volatile" },
1816 	{ 0x0B, 0x07, "Warning - Degraded Power To Non-Volatile Cache" },
1817 	{ 0x0B, 0x08, "Warning - Power Loss Expected" },
1818 	{ 0x0C, 0x00, "Write Error" },
1819 	{ 0x0C, 0x01, "Write Error Recovered with Auto Reallocation" },
1820 	{ 0x0C, 0x02, "Write Error - Auto Reallocate Failed" },
1821 	{ 0x0C, 0x03, "Write Error - Recommend Reassignment" },
1822 	{ 0x0C, 0x04, "Compression Check Miscompare Error" },
1823 	{ 0x0C, 0x05, "Data Expansion Occurred During Compression" },
1824 	{ 0x0C, 0x06, "Block Not Compressible" },
1825 	{ 0x0C, 0x07, "Write Error - Recovery Needed" },
1826 	{ 0x0C, 0x08, "Write Error - Recovery Failed" },
1827 	{ 0x0C, 0x09, "Write Error - Loss Of Streaming" },
1828 	{ 0x0C, 0x0A, "Write Error - Padding Blocks Added" },
1829 	{ 0x0C, 0x0B, "Auxiliary Memory Write Error" },
1830 	{ 0x0C, 0x0C, "Write Error - Unexpected Unsolicited Data" },
1831 	{ 0x0C, 0x0D, "Write Error - Not Enough Unsolicited Data" },
1832 	{ 0x0C, 0x0F, "Defects In Error Window" },
1833 	{ 0x0D, 0x00, "Error Detected By Third Party Temporary Initiator" },
1834 	{ 0x0D, 0x01, "Third Party Device Failure" },
1835 	{ 0x0D, 0x02, "Copy Target Device Not Reachable" },
1836 	{ 0x0D, 0x03, "Incorrect Copy Target Device Type" },
1837 	{ 0x0D, 0x04, "Copy Target Device Data Underrun" },
1838 	{ 0x0D, 0x05, "Copy Target Device Data Overrun" },
1839 	{ 0x0E, 0x00, "Invalid Information Unit" },
1840 	{ 0x0E, 0x01, "Information Unit Too Short" },
1841 	{ 0x0E, 0x02, "Information Unit Too Long" },
1842 	{ 0x10, 0x00, "ID CRC Or ECC Error" },
1843 	{ 0x10, 0x01, "Logical Block Guard Check Failed" },
1844 	{ 0x10, 0x02, "Logical Block Application Tag Check Failed" },
1845 	{ 0x10, 0x03, "Logical Block Reference Tag Check Failed" },
1846 	{ 0x10, 0x04, "Logical Block Protection Error On Recover Buffered Data" },
1847 	{ 0x10, 0x05, "Logical Block Protection Method Error" },
1848 	{ 0x11, 0x00, "Unrecovered Read Error" },
1849 	{ 0x11, 0x01, "Read Retries Exhausted" },
1850 	{ 0x11, 0x02, "Error Too Long To Correct" },
1851 	{ 0x11, 0x03, "Multiple Read Errors" },
1852 	{ 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" },
1853 	{ 0x11, 0x05, "L-EC Uncorrectable Error" },
1854 	{ 0x11, 0x06, "CIRC Unrecovered Error" },
1855 	{ 0x11, 0x07, "Data Resynchronization Error" },
1856 	{ 0x11, 0x08, "Incomplete Block Read" },
1857 	{ 0x11, 0x09, "No Gap Found" },
1858 	{ 0x11, 0x0A, "Miscorrected Error" },
1859 	{ 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" },
1860 	{ 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite The Data" },
1861 	{ 0x11, 0x0D, "De-Compression CRC Error" },
1862 	{ 0x11, 0x0E, "Cannot Decompress Using Declared Algorithm" },
1863 	{ 0x11, 0x0F, "Error Reading UPC/EAN Number" },
1864 	{ 0x11, 0x10, "Error Reading ISRC Number" },
1865 	{ 0x11, 0x11, "Read Error - Loss Of Streaming" },
1866 	{ 0x11, 0x12, "Auxiliary Memory Read Error" },
1867 	{ 0x11, 0x13, "Read Error - Failed Retransmission Request" },
1868 	{ 0x11, 0x14, "Read Error - LBA Marked Bad By Application Client" },
1869 	{ 0x12, 0x00, "Address Mark Not Found for ID Field" },
1870 	{ 0x13, 0x00, "Address Mark Not Found for Data Field" },
1871 	{ 0x14, 0x00, "Recorded Entity Not Found" },
1872 	{ 0x14, 0x01, "Record Not Found" },
1873 	{ 0x14, 0x02, "Filemark or Setmark Not Found" },
1874 	{ 0x14, 0x03, "End-Of-Data Not Found" },
1875 	{ 0x14, 0x04, "Block Sequence Error" },
1876 	{ 0x14, 0x05, "Record Not Found - Recommend Reassignment" },
1877 	{ 0x14, 0x06, "Record Not Found - Data Auto-Reallocated" },
1878 	{ 0x14, 0x07, "Locate Operation Failure" },
1879 	{ 0x15, 0x00, "Random Positioning Error" },
1880 	{ 0x15, 0x01, "Mechanical Positioning Error" },
1881 	{ 0x15, 0x02, "Positioning Error Detected By Read of Medium" },
1882 	{ 0x16, 0x00, "Data Synchronization Mark Error" },
1883 	{ 0x16, 0x01, "Data Sync Error - Data Rewritten" },
1884 	{ 0x16, 0x02, "Data Sync Error - Recommend Rewrite" },
1885 	{ 0x16, 0x03, "Data Sync Error - Data Auto-Reallocated" },
1886 	{ 0x16, 0x04, "Data Sync Error - Recommend Reassignment" },
1887 	{ 0x17, 0x00, "Recovered Data With No Error Correction Applied" },
1888 	{ 0x17, 0x01, "Recovered Data With Retries" },
1889 	{ 0x17, 0x02, "Recovered Data With Positive Head Offset" },
1890 	{ 0x17, 0x03, "Recovered Data With Negative Head Offset" },
1891 	{ 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" },
1892 	{ 0x17, 0x05, "Recovered Data Using Previous Sector ID" },
1893 	{ 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" },
1894 	{ 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" },
1895 	{ 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" },
1896 	{ 0x17, 0x09, "Recovered Data Without ECC - Data Rewritten" },
1897 	{ 0x18, 0x00, "Recovered Data With Error Correction Applied" },
1898 	{ 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" },
1899 	{ 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" },
1900 	{ 0x18, 0x03, "Recovered Data With CIRC" },
1901 	{ 0x18, 0x04, "Recovered Data With L-EC" },
1902 	{ 0x18, 0x05, "Recovered Data - Recommend Reassignment" },
1903 	{ 0x18, 0x06, "Recovered Data - Recommend Rewrite" },
1904 	{ 0x18, 0x07, "Recovered Data With ECC - Data Rewritten" },
1905 	{ 0x18, 0x08, "Recovered Data With Linking" },
1906 	{ 0x19, 0x00, "Defect List Error" },
1907 	{ 0x19, 0x01, "Defect List Not Available" },
1908 	{ 0x19, 0x02, "Defect List Error in Primary List" },
1909 	{ 0x19, 0x03, "Defect List Error in Grown List" },
1910 	{ 0x1A, 0x00, "Parameter List Length Error" },
1911 	{ 0x1B, 0x00, "Synchronous Data Transfer Error" },
1912 	{ 0x1C, 0x00, "Defect List Not Found" },
1913 	{ 0x1C, 0x01, "Primary Defect List Not Found" },
1914 	{ 0x1C, 0x02, "Grown Defect List Not Found" },
1915 	{ 0x1D, 0x00, "Miscompare During Verify Operation" },
1916 	{ 0x1D, 0x01, "Miscompare Verify Of Unmapped Lba" },
1917 	{ 0x1E, 0x00, "Recovered ID with ECC" },
1918 	{ 0x1F, 0x00, "Partial Defect List Transfer" },
1919 	{ 0x20, 0x00, "Invalid Command Operation Code" },
1920 	{ 0x20, 0x01, "Access Denied - Initiator Pending-Enrolled" },
1921 	{ 0x20, 0x02, "Access Denied - No Access rights" },
1922 	{ 0x20, 0x03, "Access Denied - Invalid Mgmt ID Key" },
1923 	{ 0x20, 0x04, "Illegal Command While In Write Capable State" },
1924 	{ 0x20, 0x05, "Obsolete" },
1925 	{ 0x20, 0x06, "Illegal Command While In Explicit Address Mode" },
1926 	{ 0x20, 0x07, "Illegal Command While In Implicit Address Mode" },
1927 	{ 0x20, 0x08, "Access Denied - Enrollment Conflict" },
1928 	{ 0x20, 0x09, "Access Denied - Invalid LU Identifier" },
1929 	{ 0x20, 0x0A, "Access Denied - Invalid Proxy Token" },
1930 	{ 0x20, 0x0B, "Access Denied - ACL LUN Conflict" },
1931 	{ 0x20, 0x0C, "Illegal Command When Not In Append-Only Mode" },
1932 	{ 0x21, 0x00, "Logical Block Address Out of Range" },
1933 	{ 0x21, 0x01, "Invalid Element Address" },
1934 	{ 0x21, 0x02, "Invalid Address For Write" },
1935 	{ 0x21, 0x03, "Invalid Write Crossing Layer Jump" },
1936 	{ 0x22, 0x00, "Illegal Function (Should 20 00, 24 00, or 26 00)" },
1937 	{ 0x24, 0x00, "Illegal Field in CDB" },
1938 	{ 0x24, 0x01, "CDB Decryption Error" },
1939 	{ 0x24, 0x02, "Obsolete" },
1940 	{ 0x24, 0x03, "Obsolete" },
1941 	{ 0x24, 0x04, "Security Audit Value Frozen" },
1942 	{ 0x24, 0x05, "Security Working Key Frozen" },
1943 	{ 0x24, 0x06, "Nonce Not Unique" },
1944 	{ 0x24, 0x07, "Nonce Timestamp Out Of Range" },
1945 	{ 0x24, 0x08, "Invalid XCDB" },
1946 	{ 0x25, 0x00, "Logical Unit Not Supported" },
1947 	{ 0x26, 0x00, "Invalid Field In Parameter List" },
1948 	{ 0x26, 0x01, "Parameter Not Supported" },
1949 	{ 0x26, 0x02, "Parameter Value Invalid" },
1950 	{ 0x26, 0x03, "Threshold Parameters Not Supported" },
1951 	{ 0x26, 0x04, "Invalid Release Of Persistent Reservation" },
1952 	{ 0x26, 0x05, "Data Decryption Error" },
1953 	{ 0x26, 0x06, "Too Many Target Descriptors" },
1954 	{ 0x26, 0x07, "Unsupported Target Descriptor Type Code" },
1955 	{ 0x26, 0x08, "Too Many Segment Descriptors" },
1956 	{ 0x26, 0x09, "Unsupported Segment Descriptor Type Code" },
1957 	{ 0x26, 0x0A, "Unexpected Inexact Segment" },
1958 	{ 0x26, 0x0B, "Inline Data Length Exceeded" },
1959 	{ 0x26, 0x0C, "Invalid Operation For Copy Source Or Destination" },
1960 	{ 0x26, 0x0D, "Copy Segment Granularity Violation" },
1961 	{ 0x26, 0x0E, "Invalid Parameter While Port Is Enabled" },
1962 	{ 0x26, 0x0F, "Invalid Data-Out Buffer Integrity Check Value" },
1963 	{ 0x26, 0x10, "Data Decryption Key Fail Limit Reached" },
1964 	{ 0x26, 0x11, "Incomplete Key-Associated Data Set" },
1965 	{ 0x26, 0x12, "Vendor Specific Key Reference Not Found" },
1966 	{ 0x27, 0x00, "Write Protected" },
1967 	{ 0x27, 0x01, "Hardware Write Protected" },
1968 	{ 0x27, 0x02, "Logical Unit Software Write Protected" },
1969 	{ 0x27, 0x03, "Associated Write Protect" },
1970 	{ 0x27, 0x04, "Persistent Write Protect" },
1971 	{ 0x27, 0x05, "Permanent Write Protect" },
1972 	{ 0x27, 0x06, "Conditional Write Protect" },
1973 	{ 0x27, 0x07, "Space Allocation Failed Write Protect" },
1974 	{ 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" },
1975 	{ 0x28, 0x01, "Import Or Export Element Accessed" },
1976 	{ 0x28, 0x02, "Format-Layer May Have Changed" },
1977 	{ 0x28, 0x03, "Import/Export Element Accessed, Medium Changed" },
1978 	{ 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" },
1979 	{ 0x29, 0x01, "Power On Occurred" },
1980 	{ 0x29, 0x02, "SCSI Bus Reset Occurred" },
1981 	{ 0x29, 0x03, "Bus Device Reset Function Occurred" },
1982 	{ 0x29, 0x04, "Device Internal Reset" },
1983 	{ 0x29, 0x05, "Transceiver Mode Changed to Single Ended" },
1984 	{ 0x29, 0x06, "Transceiver Mode Changed to LVD" },
1985 	{ 0x29, 0x07, "I_T Nexus Loss Occurred" },
1986 	{ 0x2A, 0x00, "Parameters Changed" },
1987 	{ 0x2A, 0x01, "Mode Parameters Changed" },
1988 	{ 0x2A, 0x02, "Log Parameters Changed" },
1989 	{ 0x2A, 0x03, "Reservations Preempted" },
1990 	{ 0x2A, 0x04, "Reservations Released" },
1991 	{ 0x2A, 0x05, "Registrations Preempted" },
1992 	{ 0x2A, 0x06, "Asymmetric Access State Changed" },
1993 	{ 0x2A, 0x07, "Implicit Asymmetric Access State Transition Failed" },
1994 	{ 0x2A, 0x08, "Priority Changed" },
1995 	{ 0x2A, 0x09, "Capacity Data Has Changed" },
1996 	{ 0x2A, 0x0A, "Error History I_T Nexus Cleared" },
1997 	{ 0x2A, 0x0B, "Error History Snapshot Released" },
1998 	{ 0x2A, 0x0C, "Error Recovery Attributes Have Changed" },
1999 	{ 0x2A, 0x0D, "Data Encryption Capabilities Changed" },
2000 	{ 0x2A, 0x10, "Timestamp Changed" },
2001 	{ 0x2A, 0x11, "Data Encryption Parameters Changed By Another I_T Nexus" },
2002 	{ 0x2A, 0x12, "Data Encryption Parameters Changed By Vendor Specific Event" },
2003 	{ 0x2A, 0x13, "Data Encryption Key Instance Counter Has Changed" },
2004 	{ 0x2A, 0x14, "SA Creation Capabilities Data Has Changed" },
2005 	{ 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" },
2006 	{ 0x2C, 0x00, "Command Sequence Error" },
2007 	{ 0x2C, 0x01, "Too Many Windows Specified" },
2008 	{ 0x2C, 0x02, "Invalid Combination of Windows Specified" },
2009 	{ 0x2C, 0x03, "Current Program Area Is Not Empty" },
2010 	{ 0x2C, 0x04, "Current Program Area Is Empty" },
2011 	{ 0x2C, 0x05, "Illegal Power Condition Request" },
2012 	{ 0x2C, 0x06, "Persistent Prevent Conflict" },
2013 	{ 0x2C, 0x07, "Previous Busy Status" },
2014 	{ 0x2C, 0x08, "Previous Task Set Full Status" },
2015 	{ 0x2C, 0x09, "Previous Reservation Conflict Status" },
2016 	{ 0x2C, 0x0A, "Partition Or Collection Contains User Objects" },
2017 	{ 0x2C, 0x0B, "Not Reserved" },
2018 	{ 0x2C, 0x0C, "ORWrite Generation Does Not Match" },
2019 	{ 0x2D, 0x00, "Overwrite Error On Update In Place" },
2020 	{ 0x2E, 0x00, "Insufficient Time For Operation" },
2021 	{ 0x2F, 0x00, "Commands Cleared By Another Initiator" },
2022 	{ 0x2F, 0x01, "Commands Cleared By Power Loss Notification" },
2023 	{ 0x2F, 0x02, "Commands Cleared By Device Server" },
2024 	{ 0x30, 0x00, "Incompatible Medium Installed" },
2025 	{ 0x30, 0x01, "Cannot Read Medium - Unknown Format" },
2026 	{ 0x30, 0x02, "Cannot Read Medium - Incompatible Format" },
2027 	{ 0x30, 0x03, "Cleaning Cartridge Installed" },
2028 	{ 0x30, 0x04, "Cannot Write Medium - Unknown Format" },
2029 	{ 0x30, 0x05, "Cannot Write Medium - Incompatible Format" },
2030 	{ 0x30, 0x06, "Cannot Format Medium - Incompatible Medium" },
2031 	{ 0x30, 0x07, "Cleaning Failure" },
2032 	{ 0x30, 0x08, "Cannot Write - Application Code Mismatch" },
2033 	{ 0x30, 0x09, "Current Session Not Fixated For Append" },
2034 	{ 0x30, 0x0A, "Cleaning Request Rejected" },
2035 	{ 0x30, 0x10, "Medium Not Formatted" },
2036 	{ 0x30, 0x11, "Incompatible Volume Type" },
2037 	{ 0x30, 0x12, "Incompatible Volume Qualifier" },
2038 	{ 0x30, 0x13, "Cleaning Volume Expired" },
2039 	{ 0x31, 0x00, "Medium Format Corrupted" },
2040 	{ 0x31, 0x01, "Format Command Failed" },
2041 	{ 0x31, 0x02, "Zoned Formatting Failed Due To Spare Linking" },
2042 	{ 0x32, 0x00, "No Defect Spare Location Available" },
2043 	{ 0x32, 0x01, "Defect List Update Failure" },
2044 	{ 0x33, 0x00, "Tape Length Error" },
2045 	{ 0x34, 0x00, "Enclosure Failure" },
2046 	{ 0x35, 0x00, "Enclosure Services Failure" },
2047 	{ 0x35, 0x01, "Unsupported Enclosure Function" },
2048 	{ 0x35, 0x02, "Enclosure Services Unavailable" },
2049 	{ 0x35, 0x03, "Enclosure Services Transfer Failure" },
2050 	{ 0x35, 0x04, "Enclosure Services Transfer Refused" },
2051 	{ 0x36, 0x00, "Ribbon, Ink, or Toner Failure" },
2052 	{ 0x37, 0x00, "Rounded Parameter" },
2053 	{ 0x38, 0x00, "Event Status Notification" },
2054 	{ 0x38, 0x02, "ESN - Power Management Class Event" },
2055 	{ 0x38, 0x04, "ESN - Media Class Event" },
2056 	{ 0x38, 0x06, "ESN - Device Busy Class Event" },
2057 	{ 0x39, 0x00, "Saving Parameters Not Supported" },
2058 	{ 0x3A, 0x00, "Medium Not Present" },
2059 	{ 0x3A, 0x01, "Medium Not Present - Tray Closed" },
2060 	{ 0x3A, 0x02, "Medium Not Present - Tray Open" },
2061 	{ 0x3A, 0x03, "Medium Not Present - Loadable" },
2062 	{ 0x3A, 0x04, "Medium Not Present - Medium Auxiliary Memory Accessible" },
2063 	{ 0x3B, 0x00, "Sequential Positioning Error" },
2064 	{ 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" },
2065 	{ 0x3B, 0x02, "Tape Position Error At End-of-Medium" },
2066 	{ 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" },
2067 	{ 0x3B, 0x04, "Slew Failure" },
2068 	{ 0x3B, 0x05, "Paper Jam" },
2069 	{ 0x3B, 0x06, "Failed To Sense Top-Of-Form" },
2070 	{ 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" },
2071 	{ 0x3B, 0x08, "Reposition Error" },
2072 	{ 0x3B, 0x09, "Read Past End Of Medium" },
2073 	{ 0x3B, 0x0A, "Read Past Beginning Of Medium" },
2074 	{ 0x3B, 0x0B, "Position Past End Of Medium" },
2075 	{ 0x3B, 0x0C, "Position Past Beginning Of Medium" },
2076 	{ 0x3B, 0x0D, "Medium Destination Element Full" },
2077 	{ 0x3B, 0x0E, "Medium Source Element Empty" },
2078 	{ 0x3B, 0x0F, "End Of Medium Reached" },
2079 	{ 0x3B, 0x11, "Medium Magazine Not Accessible" },
2080 	{ 0x3B, 0x12, "Medium Magazine Removed" },
2081 	{ 0x3B, 0x13, "Medium Magazine Inserted" },
2082 	{ 0x3B, 0x14, "Medium Magazine Locked" },
2083 	{ 0x3B, 0x15, "Medium Magazine Unlocked" },
2084 	{ 0x3B, 0x16, "Mechanical Positioning Or Changer Error" },
2085 	{ 0x3B, 0x17, "Read Past End Of User Object" },
2086 	{ 0x3B, 0x18, "Element Disabled" },
2087 	{ 0x3B, 0x19, "Element Enabled" },
2088 	{ 0x3B, 0x1A, "Data Transfer Device Removed" },
2089 	{ 0x3B, 0x1B, "Data Transfer Device Inserted" },
2090 	{ 0x3D, 0x00, "Invalid Bits In IDENTIFY Message" },
2091 	{ 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" },
2092 	{ 0x3E, 0x01, "Logical Unit Failure" },
2093 	{ 0x3E, 0x02, "Timeout On Logical Unit" },
2094 	{ 0x3E, 0x03, "Logical Unit Failed Self-Test" },
2095 	{ 0x3E, 0x04, "Logical Unit Unable To Update Self-Test Log" },
2096 	{ 0x3F, 0x00, "Target Operating Conditions Have Changed" },
2097 	{ 0x3F, 0x01, "Microcode Has Changed" },
2098 	{ 0x3F, 0x02, "Changed Operating Definition" },
2099 	{ 0x3F, 0x03, "INQUIRY Data Has Changed" },
2100 	{ 0x3F, 0x04, "component Device Attached" },
2101 	{ 0x3F, 0x05, "Device Identifier Changed" },
2102 	{ 0x3F, 0x06, "Redundancy Group Created Or Modified" },
2103 	{ 0x3F, 0x07, "Redundancy Group Deleted" },
2104 	{ 0x3F, 0x08, "Spare Created Or Modified" },
2105 	{ 0x3F, 0x09, "Spare Deleted" },
2106 	{ 0x3F, 0x0A, "Volume Set Created Or Modified" },
2107 	{ 0x3F, 0x0B, "Volume Set Deleted" },
2108 	{ 0x3F, 0x0C, "Volume Set Deassigned" },
2109 	{ 0x3F, 0x0D, "Volume Set Reassigned" },
2110 	{ 0x3F, 0x0E, "Reported LUNs Data Has Changed" },
2111 	{ 0x3F, 0x0F, "Echo Buffer Overwritten" },
2112 	{ 0x3F, 0x10, "Medium Loadable" },
2113 	{ 0x3F, 0x11, "Medium Auxiliary Memory Accessible" },
2114 	{ 0x3F, 0x12, "iSCSI IP Address Added" },
2115 	{ 0x3F, 0x13, "iSCSI IP Address Removed" },
2116 	{ 0x3F, 0x14, "iSCSI IP Address Changed" },
2117 	{ 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" },
2118 	/*
2119 	 * ASC 0x40 also has an ASCQ range from 0x80 to 0xFF.
2120 	 * 0x40 0xNN DIAGNOSTIC FAILURE ON COMPONENT NN
2121 	 */
2122 	{ 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" },
2123 	{ 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" },
2124 	{ 0x43, 0x00, "Message Error" },
2125 	{ 0x44, 0x00, "Internal Target Failure" },
2126 	{ 0x44, 0x71, "ATA Device Failed Set Features" },
2127 	{ 0x45, 0x00, "Select Or Reselect Failure" },
2128 	{ 0x46, 0x00, "Unsuccessful Soft Reset" },
2129 	{ 0x47, 0x00, "SCSI Parity Error" },
2130 	{ 0x47, 0x01, "Data Phase CRC Error Detected" },
2131 	{ 0x47, 0x02, "SCSI Parity Error Detected During ST Data Phase" },
2132 	{ 0x47, 0x03, "Information Unit iuCRC Error Detected" },
2133 	{ 0x47, 0x04, "Asynchronous Information Protection Error Detected" },
2134 	{ 0x47, 0x05, "Protocol Service CRC Error" },
2135 	{ 0x47, 0x06, "PHY Test Function In Progress" },
2136 	{ 0x47, 0x7F, "Some Commands Cleared By iSCSI Protocol Event" },
2137 	{ 0x48, 0x00, "Initiator Detected Error Message Received" },
2138 	{ 0x49, 0x00, "Invalid Message Error" },
2139 	{ 0x4A, 0x00, "Command Phase Error" },
2140 	{ 0x4B, 0x00, "Data Phase Error" },
2141 	{ 0x4B, 0x01, "Invalid Target Port Transfer Tag Received" },
2142 	{ 0x4B, 0x02, "Too Much Write Data" },
2143 	{ 0x4B, 0x03, "ACK/NAK Timeout" },
2144 	{ 0x4B, 0x04, "NAK Received" },
2145 	{ 0x4B, 0x05, "Data Offset Error" },
2146 	{ 0x4B, 0x06, "Initiator Response Timeout" },
2147 	{ 0x4B, 0x07, "Connection Lost" },
2148 	{ 0x4C, 0x00, "Logical Unit Failed Self-Configuration" },
2149 	/*
2150 	 * ASC 0x4D has an ASCQ range from 0x00 to 0xFF.
2151 	 * 0x4D 0xNN TAGGED OVERLAPPED COMMANDS (NN = TASK TAG)
2152 	 */
2153 	{ 0x4E, 0x00, "Overlapped Commands Attempted" },
2154 	{ 0x50, 0x00, "Write Append Error" },
2155 	{ 0x50, 0x01, "Write Append Position Error" },
2156 	{ 0x50, 0x02, "Position Error Related To Timing" },
2157 	{ 0x51, 0x00, "Erase Failure" },
2158 	{ 0x51, 0x01, "Erase Failure - Incomplete Erase Operation Detected" },
2159 	{ 0x52, 0x00, "Cartridge Fault" },
2160 	{ 0x53, 0x00, "Media Load or Eject Failed" },
2161 	{ 0x53, 0x01, "Unload Tape Failure" },
2162 	{ 0x53, 0x02, "Medium Removal Prevented" },
2163 	{ 0x53, 0x03, "Medium Removal Prevented By Data Transfer Element" },
2164 	{ 0x53, 0x04, "Medium Thread Or Unthread Failure" },
2165 	{ 0x53, 0x05, "Volume Identifier Invalid" },
2166 	{ 0x53, 0x06, "Volume Identifier Missing" },
2167 	{ 0x53, 0x07, "Duplicate Volume Identifier" },
2168 	{ 0x53, 0x08, "Element Status Unknown" },
2169 	{ 0x54, 0x00, "SCSI To Host System Interface Failure" },
2170 	{ 0x55, 0x00, "System Resource Failure" },
2171 	{ 0x55, 0x01, "System Buffer Full" },
2172 	{ 0x55, 0x02, "Insufficient Reservation Resources" },
2173 	{ 0x55, 0x03, "Insufficient Resources" },
2174 	{ 0x55, 0x04, "Insufficient Registration Resources" },
2175 	{ 0x55, 0x05, "Insufficient Access Control Resources" },
2176 	{ 0x55, 0x06, "Auxiliary Memory Out Of Space" },
2177 	{ 0x55, 0x07, "Quota Error" },
2178 	{ 0x55, 0x08, "Maximum Number Of Supplemental Decryption Keys Exceeded" },
2179 	{ 0x55, 0x09, "Medium Auxiliary Memory Not Accessible" },
2180 	{ 0x55, 0x0A, "Data Currently Unavailable" },
2181 	{ 0x55, 0x0B, "Insufficient Power For Operation" },
2182 	{ 0x57, 0x00, "Unable To Recover Table-Of-Contents" },
2183 	{ 0x58, 0x00, "Generation Does Not Exist" },
2184 	{ 0x59, 0x00, "Updated Block Read" },
2185 	{ 0x5A, 0x00, "Operator Request or State Change Input" },
2186 	{ 0x5A, 0x01, "Operator Medium Removal Requested" },
2187 	{ 0x5A, 0x02, "Operator Selected Write Protect" },
2188 	{ 0x5A, 0x03, "Operator Selected Write Permit" },
2189 	{ 0x5B, 0x00, "Log Exception" },
2190 	{ 0x5B, 0x01, "Threshold Condition Met" },
2191 	{ 0x5B, 0x02, "Log Counter At Maximum" },
2192 	{ 0x5B, 0x03, "Log List Codes Exhausted" },
2193 	{ 0x5C, 0x00, "RPL Status Change" },
2194 	{ 0x5C, 0x01, "Spindles Synchronized" },
2195 	{ 0x5C, 0x02, "Spindles Not Synchronized" },
2196 	{ 0x5D, 0x00, "Failure Prediction Threshold Exceeded" },
2197 	{ 0x5D, 0x01, "Media Failure Prediction Threshold Exceeded" },
2198 	{ 0x5D, 0x02, "Logical Unit Failure Prediction Threshold Exceeded" },
2199 	{ 0x5D, 0x03, "Spare Area Exhaustion Prediction Threshold Exceeded" },
2200 	{ 0x5D, 0x10, "Hardware Impending Failure General Hard Drive Failure" },
2201 	{ 0x5D, 0x11, "Hardware Impending Failure Drive Error Rate Too High" },
2202 	{ 0x5D, 0x12, "Hardware Impending Failure Data Error Rate Too High" },
2203 	{ 0x5D, 0x13, "Hardware Impending Failure Seek Error Rate Too High" },
2204 	{ 0x5D, 0x14, "Hardware Impending Failure Too Many Block Reassigns" },
2205 	{ 0x5D, 0x15, "Hardware Impending Failure Access Times Too High" },
2206 	{ 0x5D, 0x16, "Hardware Impending Failure Start Unit Times Too High" },
2207 	{ 0x5D, 0x17, "Hardware Impending Failure Channel Parametrics" },
2208 	{ 0x5D, 0x18, "Hardware Impending Failure Controller Detected" },
2209 	{ 0x5D, 0x19, "Hardware Impending Failure Throughput Performance" },
2210 	{ 0x5D, 0x1A, "Hardware Impending Failure Seek Time Performance" },
2211 	{ 0x5D, 0x1B, "Hardware Impending Failure Spin-Up Retry Count" },
2212 	{ 0x5D, 0x1C, "Hardware Impending Failure Drive Calibration Retry Count" },
2213 	{ 0x5D, 0x20, "Controller Impending Failure General Hard Drive Failure" },
2214 	{ 0x5D, 0x21, "Controller Impending Failure Drive Error Rate Too High" },
2215 	{ 0x5D, 0x22, "Controller Impending Failure Data Error Rate Too High" },
2216 	{ 0x5D, 0x23, "Controller Impending Failure Seek Error Rate Too High" },
2217 	{ 0x5D, 0x24, "Controller Impending Failure Too Many Block Reassigns" },
2218 	{ 0x5D, 0x25, "Controller Impending Failure Access Times Too High" },
2219 	{ 0x5D, 0x26, "Controller Impending Failure Start Unit Times Too High" },
2220 	{ 0x5D, 0x27, "Controller Impending Failure Channel Parametrics" },
2221 	{ 0x5D, 0x28, "Controller Impending Failure Controller Detected" },
2222 	{ 0x5D, 0x29, "Controller Impending Failure Throughput Performance" },
2223 	{ 0x5D, 0x2A, "Controller Impending Failure Seek Time Performance" },
2224 	{ 0x5D, 0x2B, "Controller Impending Failure Spin-Up Retry Count" },
2225 	{ 0x5D, 0x2C, "Controller Impending Failure Drive Calibration Retry Count" },
2226 	{ 0x5D, 0x30, "Data Channel Impending Failure General Hard Drive Failure" },
2227 	{ 0x5D, 0x31, "Data Channel Impending Failure Drive Error Rate Too High" },
2228 	{ 0x5D, 0x32, "Data Channel Impending Failure Data Error Rate Too High" },
2229 	{ 0x5D, 0x33, "Data Channel Impending Failure Seek Error Rate Too High" },
2230 	{ 0x5D, 0x34, "Data Channel Impending Failure Too Many Block Reassigns" },
2231 	{ 0x5D, 0x35, "Data Channel Impending Failure Access Times Too High" },
2232 	{ 0x5D, 0x36, "Data Channel Impending Failure Start Unit Times Too High" },
2233 	{ 0x5D, 0x37, "Data Channel Impending Failure Channel Parametrics" },
2234 	{ 0x5D, 0x38, "Data Channel Impending Failure Controller Detected" },
2235 	{ 0x5D, 0x39, "Data Channel Impending Failure Throughput Performance" },
2236 	{ 0x5D, 0x3A, "Data Channel Impending Failure Seek Time Performance" },
2237 	{ 0x5D, 0x3B, "Data Channel Impending Failure Spin-Up Retry Count" },
2238 	{ 0x5D, 0x3C, "Data Channel Impending Failure Drive Calibration Retry Count" },
2239 	{ 0x5D, 0x40, "Servo Impending Failure General Hard Drive Failure" },
2240 	{ 0x5D, 0x41, "Servo Impending Failure Drive Error Rate Too High" },
2241 	{ 0x5D, 0x42, "Servo Impending Failure Data Error Rate Too High" },
2242 	{ 0x5D, 0x43, "Servo Impending Failure Seek Error Rate Too High" },
2243 	{ 0x5D, 0x44, "Servo Impending Failure Too Many Block Reassigns" },
2244 	{ 0x5D, 0x45, "Servo Impending Failure Access Times Too High" },
2245 	{ 0x5D, 0x46, "Servo Impending Failure Start Unit Times Too High" },
2246 	{ 0x5D, 0x47, "Servo Impending Failure Channel Parametrics" },
2247 	{ 0x5D, 0x48, "Servo Impending Failure Controller Detected" },
2248 	{ 0x5D, 0x49, "Servo Impending Failure Throughput Performance" },
2249 	{ 0x5D, 0x4A, "Servo Impending Failure Seek Time Performance" },
2250 	{ 0x5D, 0x4B, "Servo Impending Failure Spin-Up Retry Count" },
2251 	{ 0x5D, 0x4C, "Servo Impending Failure Drive Calibration Retry Count" },
2252 	{ 0x5D, 0x50, "Spindle Impending Failure General Hard Drive Failure" },
2253 	{ 0x5D, 0x51, "Spindle Impending Failure Drive Error Rate Too High" },
2254 	{ 0x5D, 0x52, "Spindle Impending Failure Data Error Rate Too High" },
2255 	{ 0x5D, 0x53, "Spindle Impending Failure Seek Error Rate Too High" },
2256 	{ 0x5D, 0x54, "Spindle Impending Failure Too Many Block Reassigns" },
2257 	{ 0x5D, 0x55, "Spindle Impending Failure Access Times Too High" },
2258 	{ 0x5D, 0x56, "Spindle Impending Failure Start Unit Times Too High" },
2259 	{ 0x5D, 0x57, "Spindle Impending Failure Channel Parametrics" },
2260 	{ 0x5D, 0x58, "Spindle Impending Failure Controller Detected" },
2261 	{ 0x5D, 0x59, "Spindle Impending Failure Throughput Performance" },
2262 	{ 0x5D, 0x5A, "Spindle Impending Failure Seek Time Performance" },
2263 	{ 0x5D, 0x5B, "Spindle Impending Failure Spin-Up Retry Count" },
2264 	{ 0x5D, 0x5C, "Spindle Impending Failure Drive Calibration Retry Count" },
2265 	{ 0x5D, 0x60, "Firmware Impending Failure General Hard Drive Failure" },
2266 	{ 0x5D, 0x61, "Firmware Impending Failure Drive Error Rate Too High" },
2267 	{ 0x5D, 0x62, "Firmware Impending Failure Data Error Rate Too High" },
2268 	{ 0x5D, 0x63, "Firmware Impending Failure Seek Error Rate Too High" },
2269 	{ 0x5D, 0x64, "Firmware Impending Failure Too Many Block Reassigns" },
2270 	{ 0x5D, 0x65, "Firmware Impending Failure Access Times Too High" },
2271 	{ 0x5D, 0x66, "Firmware Impending Failure Start Unit Times Too High" },
2272 	{ 0x5D, 0x67, "Firmware Impending Failure Channel Parametrics" },
2273 	{ 0x5D, 0x68, "Firmware Impending Failure Controller Detected" },
2274 	{ 0x5D, 0x69, "Firmware Impending Failure Throughput Performance" },
2275 	{ 0x5D, 0x6A, "Firmware Impending Failure Seek Time Performance" },
2276 	{ 0x5D, 0x6B, "Firmware Impending Failure Spin-Up Retry Count" },
2277 	{ 0x5D, 0x6C, "Firmware Impending Failure Drive Calibration Retry Count" },
2278 	{ 0x5D, 0xFF, "Failure Prediction Threshold Exceeded (false)" },
2279 	{ 0x5E, 0x00, "Low Power Condition On" },
2280 	{ 0x5E, 0x01, "Idle Condition Activated By Timer" },
2281 	{ 0x5E, 0x02, "Standby Condition Activated By Timer" },
2282 	{ 0x5E, 0x03, "Idle Condition Activated By Command" },
2283 	{ 0x5E, 0x04, "Standby Condition Activated By Command" },
2284 	{ 0x5E, 0x05, "IDLE_B Condition Activated By Timer" },
2285 	{ 0x5E, 0x06, "IDLE_B Condition Activated By Command" },
2286 	{ 0x5E, 0x07, "IDLE_C Condition Activated By Timer" },
2287 	{ 0x5E, 0x08, "IDLE_C Condition Activated By Command" },
2288 	{ 0x5E, 0x09, "STANDBY_Y Condition Activated By Timer" },
2289 	{ 0x5E, 0x0A, "STANDBY_Y Condition Activated By Command" },
2290 	{ 0x5E, 0x41, "Power State Change To Active" },
2291 	{ 0x5E, 0x42, "Power State Change To Idle" },
2292 	{ 0x5E, 0x43, "Power State Change To Standby" },
2293 	{ 0x5E, 0x45, "Power State Change To Sleep" },
2294 	{ 0x5E, 0x47, "Power State Change To Device Control" },
2295 	{ 0x60, 0x00, "Lamp Failure" },
2296 	{ 0x61, 0x00, "Video Acquisition Error" },
2297 	{ 0x61, 0x01, "Unable To Acquire Video" },
2298 	{ 0x61, 0x02, "Out Of Focus" },
2299 	{ 0x62, 0x00, "Scan Head Positioning Error" },
2300 	{ 0x63, 0x00, "End Of User Area Encountered On This Track" },
2301 	{ 0x63, 0x01, "Packet Does Not Fit In Available Space" },
2302 	{ 0x64, 0x00, "Illegal Mode For This Track" },
2303 	{ 0x64, 0x01, "Invalid Packet Size" },
2304 	{ 0x65, 0x00, "Voltage Fault" },
2305 	{ 0x66, 0x00, "Automatic Document Feeder Cover Up" },
2306 	{ 0x66, 0x01, "Automatic Document Feeder Lift Up" },
2307 	{ 0x66, 0x02, "Document Jam In Automatic Document Feeder" },
2308 	{ 0x66, 0x03, "Document Miss Feed Automatic In Document Feeder" },
2309 	{ 0x67, 0x00, "Configuration Failure" },
2310 	{ 0x67, 0x01, "Configuration Of Incapable Logical Units Failed" },
2311 	{ 0x67, 0x02, "Add Logical Unit Failed" },
2312 	{ 0x67, 0x03, "Modification Of Logical Unit Failed" },
2313 	{ 0x67, 0x04, "Exchange Of Logical Unit Failed" },
2314 	{ 0x67, 0x05, "Remove Of Logical Unit Failed" },
2315 	{ 0x67, 0x06, "Attachment Of Logical Unit Failed" },
2316 	{ 0x67, 0x07, "Creation Of Logical Unit Failed" },
2317 	{ 0x67, 0x08, "Assign Failure Occurred" },
2318 	{ 0x67, 0x09, "Multiply Assigned Logical Unit" },
2319 	{ 0x67, 0x0A, "Set Target Port Groups Command Failed" },
2320 	{ 0x67, 0x0B, "ATA Device Feature Not Enabled" },
2321 	{ 0x68, 0x00, "Logical Unit Not Configured" },
2322 	{ 0x69, 0x00, "Data Loss On Logical Unit" },
2323 	{ 0x69, 0x01, "Multiple Logical Unit Failures" },
2324 	{ 0x69, 0x02, "Parity/Data Mismatch" },
2325 	{ 0x6A, 0x00, "Informational, Refer To Log" },
2326 	{ 0x6B, 0x00, "State Change Has Occurred" },
2327 	{ 0x6B, 0x01, "Redundancy Level Got Better" },
2328 	{ 0x6B, 0x02, "Redundancy Level Got Worse" },
2329 	{ 0x6C, 0x00, "Rebuild Failure Occurred" },
2330 	{ 0x6D, 0x00, "Recalculate Failure Occurred" },
2331 	{ 0x6E, 0x00, "Command To Logical Unit Failed" },
2332 	{ 0x6F, 0x00, "Copy Protection Key Exchange Failure - Authentication Failure" },
2333 	{ 0x6F, 0x01, "Copy Protection Key Exchange Failure - Key Not Present" },
2334 	{ 0x6F, 0x02, "Copy Protection Key Exchange Failure - Key Not Established" },
2335 	{ 0x6F, 0x03, "Read Of Scrambled Sector Without Authentication" },
2336 	{ 0x6F, 0x04, "Media Region Code Is Mismatched To Logical Unit Region" },
2337 	{ 0x6F, 0x05, "Drive Region Must Be Permanent/Region Reset Count Error" },
2338 	/*
2339 	 * ASC 0x70 has an ASCQ range from 0x00 to 0xFF.
2340 	 * 0x70 0xNN DECOMPRESSION EXCEPTION SHORT ALGORITHM ID Of NN
2341 	 */
2342 	{ 0x71, 0x00, "Decompression Exception Long Algorithm ID" },
2343 	{ 0x72, 0x00, "Session Fixation Error" },
2344 	{ 0x72, 0x01, "Session Fixation Error Writing Lead-In" },
2345 	{ 0x72, 0x02, "Session Fixation Error Writing Lead-Out" },
2346 	{ 0x72, 0x03, "Session Fixation Error - Incomplete Track In Session" },
2347 	{ 0x72, 0x04, "Empty Or Partially Written Reserved Track" },
2348 	{ 0x72, 0x05, "No More Track Reservations Allowed" },
2349 	{ 0x72, 0x06, "RMZ Extension Is Not Allowed" },
2350 	{ 0x72, 0x07, "No More Test Zone Extensions Are Allowed" },
2351 	{ 0x73, 0x00, "CD Control Error" },
2352 	{ 0x73, 0x01, "Power Calibration Area Almost Full" },
2353 	{ 0x73, 0x02, "Power Calibration Area Is Full" },
2354 	{ 0x73, 0x03, "Power Calibration Area Error" },
2355 	{ 0x73, 0x04, "Program Memory Area Update Failure" },
2356 	{ 0x73, 0x05, "Program Memory Area Is Full" },
2357 	{ 0x73, 0x06, "RMA/PMA Is Almost Full" },
2358 	{ 0x73, 0x10, "Current Power Calibration Area Almost Full" },
2359 	{ 0x73, 0x11, "Current Power Calibration Area Is Full" },
2360 	{ 0x73, 0x17, "RDZ Is Full" },
2361 	{ 0x74, 0x00, "Security Error" },
2362 	{ 0x74, 0x01, "Unable To Decrypt Data" },
2363 	{ 0x74, 0x02, "Unencrypted Data Encountered While Decrypting" },
2364 	{ 0x74, 0x03, "Incorrect Data Encryption Key" },
2365 	{ 0x74, 0x04, "Cryptographic Integrity Validation Failed" },
2366 	{ 0x74, 0x05, "Error Decrypting Data" },
2367 	{ 0x74, 0x06, "Unknown Signature Verification Key" },
2368 	{ 0x74, 0x07, "Encryption Parameters Not Useable" },
2369 	{ 0x74, 0x08, "Digital Signature Validation Failure" },
2370 	{ 0x74, 0x09, "Encryption Mode Mismatch On Read" },
2371 	{ 0x74, 0x0A, "Encrypted Block Not Raw Read Enabled" },
2372 	{ 0x74, 0x0B, "Incorrect Encryption Parameters" },
2373 	{ 0x74, 0x0C, "Unable To Decrypt Parameter List" },
2374 	{ 0x74, 0x0D, "Encryption Algorithm Disabled" },
2375 	{ 0x74, 0x10, "SA Creation Parameter Value Invalid" },
2376 	{ 0x74, 0x11, "SA Creation Parameter Value Rejected" },
2377 	{ 0x74, 0x12, "Invalid SA Usage" },
2378 	{ 0x74, 0x21, "Data Encryption Configuration Prevented" },
2379 	{ 0x74, 0x30, "SA Creation Parameter Not Supported" },
2380 	{ 0x74, 0x40, "Authentication Failed" },
2381 	{ 0x74, 0x61, "External Data Encryption Key Manager Access Error" },
2382 	{ 0x74, 0x62, "External Data Encryption Key Manager Error" },
2383 	{ 0x74, 0x63, "External Data Encryption Key Not Found" },
2384 	{ 0x74, 0x64, "External Data Encryption Request Not Authorized" },
2385 	{ 0x74, 0x6E, "External Data Encryption Control Timeout" },
2386 	{ 0x74, 0x6F, "External Data Encryption Control Error" },
2387 	{ 0x74, 0x71, "Logical Unit Access Not Authorized" },
2388 	{ 0x74, 0x79, "Security Conflict In Translated Device" },
2389 	{ 0x00, 0x00, NULL }
2390 };
2391 
2392 static __inline void
2393 asc2ascii(u_int8_t asc, u_int8_t ascq, char *result, size_t len)
2394 {
2395 	int					i;
2396 
2397 	/* Check for a dynamically built description. */
2398 	switch (asc) {
2399 	case 0x40:
2400 		if (ascq >= 0x80) {
2401 			snprintf(result, len,
2402 		            "Diagnostic Failure on Component 0x%02x", ascq);
2403 			return;
2404 		}
2405 		break;
2406 	case 0x4d:
2407 		snprintf(result, len,
2408 	 	    "Tagged Overlapped Commands (0x%02x = TASK TAG)", ascq);
2409 		return;
2410 	case 0x70:
2411 		snprintf(result, len,
2412 		    "Decompression Exception Short Algorithm ID OF 0x%02x",
2413 		    ascq);
2414 		return;
2415 	default:
2416 		break;
2417 	}
2418 
2419 	/* Check for a fixed description. */
2420 	for (i = 0; adesc[i].description != NULL; i++) {
2421 		if (adesc[i].asc == asc && adesc[i].ascq == ascq) {
2422 			strlcpy(result, adesc[i].description, len);
2423 			return;
2424 		}
2425 	}
2426 
2427 	/* Just print out the ASC and ASCQ values as a description. */
2428 	snprintf(result, len, "ASC 0x%02x ASCQ 0x%02x", asc, ascq);
2429 }
2430 #endif /* SCSITERSE */
2431 
2432 void
2433 scsi_print_sense(struct scsi_xfer *xs)
2434 {
2435 	struct scsi_sense_data			*sense = &xs->sense;
2436 	u_int8_t				serr = sense->error_code &
2437 						    SSD_ERRCODE;
2438 	int32_t					info;
2439 	char					*sbs;
2440 
2441 	sc_print_addr(xs->sc_link);
2442 
2443 	/* XXX For error 0x71, current opcode is not the relevant one. */
2444 	printf("%sCheck Condition (error %#x) on opcode 0x%x\n",
2445 	    (serr == SSD_ERRCODE_DEFERRED) ? "DEFERRED " : "", serr,
2446 	    xs->cmd->opcode);
2447 
2448 	if (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED) {
2449 		if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
2450 			struct scsi_sense_data_unextended *usense =
2451 			    (struct scsi_sense_data_unextended *)sense;
2452 			printf("   AT BLOCK #: %d (decimal)",
2453 			    _3btol(usense->block));
2454 		}
2455 		return;
2456 	}
2457 
2458 	printf("    SENSE KEY: %s\n", scsi_decode_sense(sense,
2459 	    DECODE_SENSE_KEY));
2460 
2461 	if (sense->flags & (SSD_FILEMARK | SSD_EOM | SSD_ILI)) {
2462 		char pad = ' ';
2463 
2464 		printf("             ");
2465 		if (sense->flags & SSD_FILEMARK) {
2466 			printf("%c Filemark Detected", pad);
2467 			pad = ',';
2468 		}
2469 		if (sense->flags & SSD_EOM) {
2470 			printf("%c EOM Detected", pad);
2471 			pad = ',';
2472 		}
2473 		if (sense->flags & SSD_ILI)
2474 			printf("%c Incorrect Length Indicator Set", pad);
2475 		printf("\n");
2476 	}
2477 
2478 	/*
2479 	 * It is inconvenient to use device type to figure out how to
2480 	 * format the info fields. So print them as 32 bit integers.
2481 	 */
2482 	info = _4btol(&sense->info[0]);
2483 	if (info)
2484 		printf("         INFO: 0x%x (VALID flag %s)\n", info,
2485 		    sense->error_code & SSD_ERRCODE_VALID ? "on" : "off");
2486 
2487 	if (sense->extra_len < 4)
2488 		return;
2489 
2490 	info = _4btol(&sense->cmd_spec_info[0]);
2491 	if (info)
2492 		printf(" COMMAND INFO: 0x%x\n", info);
2493 	sbs = scsi_decode_sense(sense, DECODE_ASC_ASCQ);
2494 	if (strlen(sbs) > 0)
2495 		printf("     ASC/ASCQ: %s\n", sbs);
2496 	if (sense->fru != 0)
2497 		printf("     FRU CODE: 0x%x\n", sense->fru);
2498 	sbs = scsi_decode_sense(sense, DECODE_SKSV);
2499 	if (strlen(sbs) > 0)
2500 		printf("         SKSV: %s\n", sbs);
2501 }
2502 
2503 char *
2504 scsi_decode_sense(struct scsi_sense_data *sense, int flag)
2505 {
2506 	static char				rqsbuf[132];
2507 	u_int16_t				count;
2508 	u_int8_t				skey, spec_1;
2509 	int					len;
2510 
2511 	bzero(rqsbuf, sizeof(rqsbuf));
2512 
2513 	skey = sense->flags & SSD_KEY;
2514 	spec_1 = sense->sense_key_spec_1;
2515 	count = _2btol(&sense->sense_key_spec_2);
2516 
2517 	switch (flag) {
2518 	case DECODE_SENSE_KEY:
2519 		strlcpy(rqsbuf, sense_keys[skey], sizeof(rqsbuf));
2520 		break;
2521 	case DECODE_ASC_ASCQ:
2522 		asc2ascii(sense->add_sense_code, sense->add_sense_code_qual,
2523 		    rqsbuf, sizeof(rqsbuf));
2524 		break;
2525 	case DECODE_SKSV:
2526 		if (sense->extra_len < 9 || ((spec_1 & SSD_SCS_VALID) == 0))
2527 			break;
2528 		switch (skey) {
2529 		case SKEY_ILLEGAL_REQUEST:
2530 			len = snprintf(rqsbuf, sizeof rqsbuf,
2531 			    "Error in %s, Offset %d",
2532 			    (spec_1 & SSD_SCS_CDB_ERROR) ? "CDB" : "Parameters",
2533 			    count);
2534 			if ((len != -1 && len < sizeof rqsbuf) &&
2535 			    (spec_1 & SSD_SCS_VALID_BIT_INDEX))
2536 				snprintf(rqsbuf+len, sizeof rqsbuf - len,
2537 				    ", bit %d", spec_1 & SSD_SCS_BIT_INDEX);
2538 			break;
2539 		case SKEY_RECOVERED_ERROR:
2540 		case SKEY_MEDIUM_ERROR:
2541 		case SKEY_HARDWARE_ERROR:
2542 			snprintf(rqsbuf, sizeof rqsbuf,
2543 			    "Actual Retry Count: %d", count);
2544 			break;
2545 		case SKEY_NOT_READY:
2546 			snprintf(rqsbuf, sizeof rqsbuf,
2547 			    "Progress Indicator: %d", count);
2548 			break;
2549 		default:
2550 			break;
2551 		}
2552 		break;
2553 	default:
2554 		break;
2555 	}
2556 
2557 	return (rqsbuf);
2558 }
2559 
2560 #ifdef SCSIDEBUG
2561 /*
2562  * Given a scsi_xfer, dump the request, in all its glory
2563  */
2564 void
2565 scsi_xs_show(struct scsi_xfer *xs)
2566 {
2567 	u_char *b = (u_char *)xs->cmd;
2568 	int i = 0;
2569 
2570 	sc_print_addr(xs->sc_link);
2571 	printf("xs  (%p): ", xs);
2572 
2573 	printf("flg(0x%x)", xs->flags);
2574 	printf("sc_link(%p)", xs->sc_link);
2575 	printf("retr(0x%x)", xs->retries);
2576 	printf("timo(0x%x)", xs->timeout);
2577 	printf("data(%p)", xs->data);
2578 	printf("res(0x%x)", xs->resid);
2579 	printf("err(0x%x)", xs->error);
2580 	printf("bp(%p)\n", xs->bp);
2581 
2582 	sc_print_addr(xs->sc_link);
2583 	printf("cmd (%p): ", xs->cmd);
2584 
2585 	if ((xs->flags & SCSI_RESET) == 0) {
2586 		while (i < xs->cmdlen) {
2587 			if (i)
2588 				printf(",");
2589 			printf("%x", b[i++]);
2590 		}
2591 		printf("-[%d bytes]\n", xs->datalen);
2592 	} else
2593 		printf("-RESET-\n");
2594 }
2595 
2596 void
2597 scsi_show_mem(u_char *address, int num)
2598 {
2599 	int x;
2600 
2601 	printf("------------------------------");
2602 	for (x = 0; x < num; x++) {
2603 		if ((x % 16) == 0)
2604 			printf("\n%03d: ", x);
2605 		printf("%02x ", *address++);
2606 	}
2607 	printf("\n------------------------------\n");
2608 }
2609 #endif /* SCSIDEBUG */
2610 
2611 void
2612 scsi_cmd_rw_decode(struct scsi_generic *cmd, u_int64_t *blkno,
2613     u_int32_t *nblks)
2614 {
2615 	switch (cmd->opcode) {
2616 	case READ_COMMAND:
2617 	case WRITE_COMMAND: {
2618 		struct scsi_rw *rw = (struct scsi_rw *)cmd;
2619 		*blkno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
2620 		*nblks = rw->length ? rw->length : 0x100;
2621 		break;
2622 	}
2623 	case READ_BIG:
2624 	case WRITE_BIG: {
2625 		struct scsi_rw_big *rwb = (struct scsi_rw_big *)cmd;
2626 		*blkno = _4btol(rwb->addr);
2627 		*nblks = _2btol(rwb->length);
2628 		break;
2629 	}
2630 	case READ_12:
2631 	case WRITE_12: {
2632 		struct scsi_rw_12 *rw12 = (struct scsi_rw_12 *)cmd;
2633 		*blkno = _4btol(rw12->addr);
2634 		*nblks = _4btol(rw12->length);
2635 		break;
2636 	}
2637 	case READ_16:
2638 	case WRITE_16: {
2639 		struct scsi_rw_16 *rw16 = (struct scsi_rw_16 *)cmd;
2640 		*blkno = _8btol(rw16->addr);
2641 		*nblks = _4btol(rw16->length);
2642 		break;
2643 	}
2644 	default:
2645 		panic("scsi_cmd_rw_decode: bad opcode 0x%02x", cmd->opcode);
2646 	}
2647 }
2648