xref: /openbsd-src/sys/scsi/scsi_base.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: scsi_base.c,v 1.201 2012/07/01 19:32:55 miod 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 	if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0 &&
1205 	    SCSISPC(sc_link->inqdata.version) < 2) {
1206 		/*
1207 		 * The 10 byte MODE_SENSE request appeared with SCSI-2,
1208 		 * so don't bother trying it on SCSI-1 devices, they are
1209 		 * not supposed to understand it.
1210 		 */
1211 		return (0);
1212 	}
1213 	error = scsi_mode_sense_big(sc_link, 0, page, &buf->hdr_big,
1214 	    sizeof(*buf), flags, 20000);
1215 	if (error != 0)
1216 		return (error);
1217 	if (_2btol(buf->hdr_big.data_length) < 6)
1218 		return (EIO);
1219 
1220 	if (big != NULL)
1221 		*big = 1;
1222 	offset = sizeof(struct scsi_mode_header_big);
1223 	*page_data = scsi_mode_sense_big_page(&buf->hdr_big, page_len);
1224 	blk_desc_len = _2btol(buf->hdr_big.blk_desc_len);
1225 
1226 blk_desc:
1227 	/* Both scsi_blk_desc and scsi_direct_blk_desc are 8 bytes. */
1228 	if (blk_desc_len == 0 || (blk_desc_len % 8 != 0))
1229 		return (0);
1230 
1231 	switch (sc_link->inqdata.device & SID_TYPE) {
1232 	case T_SEQUENTIAL:
1233 		/*
1234 		 * XXX What other device types return general block descriptors?
1235 		 */
1236 		general = (struct scsi_blk_desc *)&buf->buf[offset];
1237 		if (density != NULL)
1238 			*density = general->density;
1239 		if (block_size != NULL)
1240 			*block_size = _3btol(general->blklen);
1241 		if (block_count != NULL)
1242 			*block_count = (u_int64_t)_3btol(general->nblocks);
1243 		break;
1244 
1245 	default:
1246 		direct = (struct scsi_direct_blk_desc *)&buf->buf[offset];
1247 		if (density != NULL)
1248 			*density = direct->density;
1249 		if (block_size != NULL)
1250 			*block_size = _3btol(direct->blklen);
1251 		if (block_count != NULL)
1252 			*block_count = (u_int64_t)_4btol(direct->nblocks);
1253 		break;
1254 	}
1255 
1256 	return (0);
1257 }
1258 
1259 int
1260 scsi_mode_select(struct scsi_link *sc_link, int byte2,
1261     struct scsi_mode_header *data, int flags, int timeout)
1262 {
1263 	struct scsi_mode_select *cmd;
1264 	struct scsi_xfer *xs;
1265 	u_int32_t len;
1266 	int error;
1267 
1268 	len = data->data_length + 1; /* 1 == sizeof(data_length) */
1269 
1270 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_OUT);
1271 	if (xs == NULL)
1272 		return (ENOMEM);
1273 	xs->cmdlen = sizeof(*cmd);
1274 	xs->data = (void *)data;
1275 	xs->datalen = len;
1276 	xs->timeout = timeout;
1277 
1278 	cmd = (struct scsi_mode_select *)xs->cmd;
1279 	cmd->opcode = MODE_SELECT;
1280 	cmd->byte2 = byte2;
1281 	cmd->length = len;
1282 
1283 	/* Length is reserved when doing mode select so zero it. */
1284 	data->data_length = 0;
1285 
1286 	error = scsi_xs_sync(xs);
1287 	scsi_xs_put(xs);
1288 
1289 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_select: error = %d\n", error));
1290 
1291 	return (error);
1292 }
1293 
1294 int
1295 scsi_mode_select_big(struct scsi_link *sc_link, int byte2,
1296     struct scsi_mode_header_big *data, int flags, int timeout)
1297 {
1298 	struct scsi_mode_select_big *cmd;
1299 	struct scsi_xfer *xs;
1300 	u_int32_t len;
1301 	int error;
1302 
1303 	len = _2btol(data->data_length) + 2; /* 2 == sizeof data_length */
1304 
1305 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_OUT);
1306 	if (xs == NULL)
1307 		return (ENOMEM);
1308 	xs->cmdlen = sizeof(*cmd);
1309 	xs->data = (void *)data;
1310 	xs->datalen = len;
1311 	xs->timeout = timeout;
1312 
1313 	cmd = (struct scsi_mode_select_big *)xs->cmd;
1314 	cmd->opcode = MODE_SELECT_BIG;
1315 	cmd->byte2 = byte2;
1316 	_lto2b(len, cmd->length);
1317 
1318 	/* Length is reserved when doing mode select so zero it. */
1319 	_lto2b(0, data->data_length);
1320 
1321 	error = scsi_xs_sync(xs);
1322 	scsi_xs_put(xs);
1323 
1324 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_mode_select_big: error = %d\n",
1325 	    error));
1326 
1327 	return (error);
1328 }
1329 
1330 int
1331 scsi_report_luns(struct scsi_link *sc_link, int selectreport,
1332     struct scsi_report_luns_data *data, u_int32_t datalen, int flags,
1333     int timeout)
1334 {
1335 	struct scsi_report_luns *cmd;
1336 	struct scsi_xfer *xs;
1337 	int error;
1338 
1339 	xs = scsi_xs_get(sc_link, flags | SCSI_DATA_IN);
1340 	if (xs == NULL)
1341 		return (ENOMEM);
1342 	xs->cmdlen = sizeof(*cmd);
1343 	xs->data = (void *)data;
1344 	xs->datalen = datalen;
1345 	xs->timeout = timeout;
1346 
1347 	bzero(data, datalen);
1348 
1349 	cmd = (struct scsi_report_luns *)xs->cmd;
1350 	cmd->opcode = REPORT_LUNS;
1351 	cmd->selectreport = selectreport;
1352 	_lto4b(datalen, cmd->length);
1353 
1354 	error = scsi_xs_sync(xs);
1355 	scsi_xs_put(xs);
1356 
1357 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_report_luns: error = %d\n", error));
1358 
1359 	return (error);
1360 }
1361 
1362 void
1363 scsi_xs_exec(struct scsi_xfer *xs)
1364 {
1365 	xs->error = XS_NOERROR;
1366 	xs->resid = xs->datalen;
1367 	xs->status = 0;
1368 	CLR(xs->flags, ITSDONE);
1369 
1370 #ifdef SCSIDEBUG
1371 	if (xs->sc_link->flags & SDEV_DB1) {
1372 		scsi_xs_show(xs);
1373 		if (xs->datalen && (xs->flags & SCSI_DATA_OUT))
1374 			scsi_show_mem(xs->data, min(64, xs->datalen));
1375 	}
1376 #endif
1377 
1378 	/* The adapter's scsi_cmd() is responsible for callng scsi_done(). */
1379 	xs->sc_link->adapter->scsi_cmd(xs);
1380 }
1381 
1382 /*
1383  * This routine is called by the adapter when its xs handling is done.
1384  */
1385 void
1386 scsi_done(struct scsi_xfer *xs)
1387 {
1388 #ifdef SCSIDEBUG
1389 	if (xs->sc_link->flags & SDEV_DB1) {
1390 		if (xs->datalen && (xs->flags & SCSI_DATA_IN))
1391 			scsi_show_mem(xs->data, min(64, xs->datalen));
1392 	}
1393 #endif /* SCSIDEBUG */
1394 
1395 	SET(xs->flags, ITSDONE);
1396 	xs->done(xs);
1397 }
1398 
1399 int
1400 scsi_xs_sync(struct scsi_xfer *xs)
1401 {
1402 	struct mutex cookie = MUTEX_INITIALIZER(IPL_BIO);
1403 	int error;
1404 
1405 #ifdef DIAGNOSTIC
1406 	if (xs->cookie != NULL)
1407 		panic("xs->cookie != NULL in scsi_xs_sync");
1408 	if (xs->done != NULL)
1409 		panic("xs->done != NULL in scsi_xs_sync");
1410 #endif
1411 
1412 	/*
1413 	 * If we cant sleep while waiting for completion, get the adapter to
1414 	 * complete it for us.
1415 	 */
1416 	if (ISSET(xs->flags, SCSI_NOSLEEP))
1417 		SET(xs->flags, SCSI_POLL);
1418 
1419 	xs->done = scsi_xs_sync_done;
1420 
1421 	do {
1422 		xs->cookie = &cookie;
1423 
1424 		scsi_xs_exec(xs);
1425 
1426 		mtx_enter(&cookie);
1427 		while (xs->cookie != NULL)
1428 			msleep(xs, &cookie, PRIBIO, "syncxs", 0);
1429 		mtx_leave(&cookie);
1430 
1431 		error = scsi_xs_error(xs);
1432 	} while (error == ERESTART);
1433 
1434 	return (error);
1435 }
1436 
1437 void
1438 scsi_xs_sync_done(struct scsi_xfer *xs)
1439 {
1440 	struct mutex *cookie = xs->cookie;
1441 
1442 	if (cookie == NULL)
1443 		panic("scsi_done called twice on xs(%p)", xs);
1444 
1445 	mtx_enter(cookie);
1446 	xs->cookie = NULL;
1447 	if (!ISSET(xs->flags, SCSI_NOSLEEP))
1448 		wakeup_one(xs);
1449 	mtx_leave(cookie);
1450 }
1451 
1452 int
1453 scsi_xs_error(struct scsi_xfer *xs)
1454 {
1455 	int error = EIO;
1456 
1457 	SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_xs_error,err = 0x%x\n",
1458 	    xs->error));
1459 
1460 	if (ISSET(xs->sc_link->state, SDEV_S_DYING))
1461 		return (ENXIO);
1462 
1463 	switch (xs->error) {
1464 	case XS_NOERROR:	/* nearly always hit this one */
1465 		error = 0;
1466 		break;
1467 
1468 	case XS_SENSE:
1469 	case XS_SHORTSENSE:
1470 #ifdef SCSIDEBUG
1471 		scsi_sense_print_debug(xs);
1472 #endif
1473 		error = xs->sc_link->interpret_sense(xs);
1474 		SC_DEBUG(xs->sc_link, SDEV_DB3,
1475 		    ("scsi_interpret_sense returned %#x\n", error));
1476 		break;
1477 
1478 	case XS_NO_CCB:
1479 	case XS_BUSY:
1480 		error = scsi_delay(xs, 1);
1481 		break;
1482 
1483 	case XS_TIMEOUT:
1484 	case XS_RESET:
1485 		error = ERESTART;
1486 		break;
1487 
1488 	case XS_DRIVER_STUFFUP:
1489 	case XS_SELTIMEOUT:
1490 		break;
1491 
1492 	default:
1493 		sc_print_addr(xs->sc_link);
1494 		printf("unknown error category (0x%x) from scsi driver\n",
1495 		    xs->error);
1496 		break;
1497 	}
1498 
1499 	if (error == ERESTART && xs->retries-- < 1)
1500 		return (EIO);
1501 	else
1502 		return (error);
1503 }
1504 
1505 int
1506 scsi_delay(struct scsi_xfer *xs, int seconds)
1507 {
1508 	switch (xs->flags & (SCSI_POLL | SCSI_NOSLEEP)) {
1509 	case SCSI_POLL:
1510 		delay(1000000 * seconds);
1511 		return (ERESTART);
1512 	case SCSI_NOSLEEP:
1513 		/* Retry the command immediately since we can't delay. */
1514 		return (ERESTART);
1515 	case (SCSI_POLL | SCSI_NOSLEEP):
1516 		/* Invalid combination! */
1517 		return (EIO);
1518 	}
1519 
1520 	while (seconds-- > 0) {
1521 		if (tsleep(&lbolt, PRIBIO|PCATCH, "scbusy", 0)) {
1522 			/* Signal == abort xs. */
1523 			return (EIO);
1524 		}
1525 	}
1526 
1527 	return (ERESTART);
1528 }
1529 
1530 #ifdef SCSIDEBUG
1531 /*
1532  * Print out sense data details.
1533  */
1534 void
1535 scsi_sense_print_debug(struct scsi_xfer *xs)
1536 {
1537 	struct scsi_sense_data *sense = &xs->sense;
1538 	struct scsi_link *sc_link = xs->sc_link;
1539 
1540 	SC_DEBUG(sc_link, SDEV_DB1,
1541 	    ("code:%#x valid:%d key:%#x ili:%d eom:%d fmark:%d extra:%d\n",
1542 	    sense->error_code & SSD_ERRCODE,
1543 	    sense->error_code & SSD_ERRCODE_VALID ? 1 : 0,
1544 	    sense->flags & SSD_KEY,
1545 	    sense->flags & SSD_ILI ? 1 : 0,
1546 	    sense->flags & SSD_EOM ? 1 : 0,
1547 	    sense->flags & SSD_FILEMARK ? 1 : 0,
1548 	    sense->extra_len));
1549 
1550 	if (xs->sc_link->flags & SDEV_DB1)
1551 		scsi_show_mem((u_char *)&xs->sense, sizeof(xs->sense));
1552 
1553 	scsi_print_sense(xs);
1554 }
1555 #endif
1556 
1557 /*
1558  * Look at the returned sense and act on the error, determining
1559  * the unix error number to pass back.  (0 = report no error)
1560  *
1561  * THIS IS THE DEFAULT ERROR HANDLER
1562  */
1563 int
1564 scsi_interpret_sense(struct scsi_xfer *xs)
1565 {
1566 	struct scsi_sense_data			*sense = &xs->sense;
1567 	struct scsi_link			*sc_link = xs->sc_link;
1568 	u_int8_t				serr, skey;
1569 	int					error;
1570 
1571 	/* Default sense interpretation. */
1572 	serr = sense->error_code & SSD_ERRCODE;
1573 	if (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED)
1574 		skey = 0xff;	/* Invalid value, since key is 4 bit value. */
1575 	else
1576 		skey = sense->flags & SSD_KEY;
1577 
1578 	/*
1579 	 * Interpret the key/asc/ascq information where appropriate.
1580 	 */
1581 	error = 0;
1582 	switch (skey) {
1583 	case SKEY_NO_SENSE:
1584 	case SKEY_RECOVERED_ERROR:
1585 		if (xs->resid == xs->datalen)
1586 			xs->resid = 0;	/* not short read */
1587 		break;
1588 	case SKEY_BLANK_CHECK:
1589 	case SKEY_EQUAL:
1590 		break;
1591 	case SKEY_NOT_READY:
1592 		if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
1593 			return (0);
1594 		error = EIO;
1595 		if (xs->retries) {
1596 			switch (ASC_ASCQ(sense)) {
1597 			case SENSE_NOT_READY_BECOMING_READY:
1598 			case SENSE_NOT_READY_FORMAT:
1599 			case SENSE_NOT_READY_REBUILD:
1600 			case SENSE_NOT_READY_RECALC:
1601 			case SENSE_NOT_READY_INPROGRESS:
1602 			case SENSE_NOT_READY_LONGWRITE:
1603 			case SENSE_NOT_READY_SELFTEST:
1604 			case SENSE_NOT_READY_INIT_REQUIRED:
1605 				SC_DEBUG(sc_link, SDEV_DB1,
1606 		    		    ("not ready (ASC_ASCQ == %#x)\n",
1607 				    ASC_ASCQ(sense)));
1608 				return (scsi_delay(xs, 1));
1609 			case SENSE_NOMEDIUM:
1610 			case SENSE_NOMEDIUM_TCLOSED:
1611 			case SENSE_NOMEDIUM_TOPEN:
1612 			case SENSE_NOMEDIUM_LOADABLE:
1613 			case SENSE_NOMEDIUM_AUXMEM:
1614 				sc_link->flags &= ~SDEV_MEDIA_LOADED;
1615 				error = ENOMEDIUM;
1616 				break;
1617 			default:
1618 				break;
1619 			}
1620 		}
1621 		break;
1622 	case SKEY_MEDIUM_ERROR:
1623 		switch (ASC_ASCQ(sense)) {
1624 		case SENSE_NOMEDIUM:
1625 		case SENSE_NOMEDIUM_TCLOSED:
1626 		case SENSE_NOMEDIUM_TOPEN:
1627 		case SENSE_NOMEDIUM_LOADABLE:
1628 		case SENSE_NOMEDIUM_AUXMEM:
1629 			sc_link->flags &= ~SDEV_MEDIA_LOADED;
1630 			error = ENOMEDIUM;
1631 			break;
1632 		case SENSE_BAD_MEDIUM:
1633 		case SENSE_NR_MEDIUM_UNKNOWN_FORMAT:
1634 		case SENSE_NR_MEDIUM_INCOMPATIBLE_FORMAT:
1635 		case SENSE_NW_MEDIUM_UNKNOWN_FORMAT:
1636 		case SENSE_NW_MEDIUM_INCOMPATIBLE_FORMAT:
1637 		case SENSE_NF_MEDIUM_INCOMPATIBLE_FORMAT:
1638 		case SENSE_NW_MEDIUM_AC_MISMATCH:
1639 			error = EMEDIUMTYPE;
1640 			break;
1641 		default:
1642 			error = EIO;
1643 			break;
1644 		}
1645 		break;
1646 	case SKEY_ILLEGAL_REQUEST:
1647 		if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0)
1648 			return (0);
1649 		if (ASC_ASCQ(sense) == SENSE_MEDIUM_REMOVAL_PREVENTED)
1650 			return(EBUSY);
1651 		error = EINVAL;
1652 		break;
1653 	case SKEY_UNIT_ATTENTION:
1654 		switch (ASC_ASCQ(sense)) {
1655 		case SENSE_POWER_RESET_OR_BUS:
1656 		case SENSE_POWER_ON:
1657 		case SENSE_BUS_RESET:
1658 		case SENSE_BUS_DEVICE_RESET:
1659 		case SENSE_DEVICE_INTERNAL_RESET:
1660 		case SENSE_TSC_CHANGE_SE:
1661 		case SENSE_TSC_CHANGE_LVD:
1662 		case SENSE_IT_NEXUS_LOSS:
1663 			return (scsi_delay(xs, 1));
1664 		default:
1665 			break;
1666 		}
1667 		if ((sc_link->flags & SDEV_REMOVABLE) != 0)
1668 			sc_link->flags &= ~SDEV_MEDIA_LOADED;
1669 		if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 ||
1670 		    /* XXX Should reupload any transient state. */
1671 		    (sc_link->flags & SDEV_REMOVABLE) == 0) {
1672 			return (scsi_delay(xs, 1));
1673 		}
1674 		error = EIO;
1675 		break;
1676 	case SKEY_WRITE_PROTECT:
1677 		error = EROFS;
1678 		break;
1679 	case SKEY_ABORTED_COMMAND:
1680 		error = ERESTART;
1681 		break;
1682 	case SKEY_VOLUME_OVERFLOW:
1683 		error = ENOSPC;
1684 		break;
1685 	case SKEY_HARDWARE_ERROR:
1686 		if (ASC_ASCQ(sense) == SENSE_CARTRIDGE_FAULT)
1687 			return(EMEDIUMTYPE);
1688 		error = EIO;
1689 		break;
1690 	default:
1691 		error = EIO;
1692 		break;
1693 	}
1694 
1695 #ifndef SCSIDEBUG
1696 	/* SCSIDEBUG would mean it has already been printed. */
1697 	if (skey && (xs->flags & SCSI_SILENT) == 0)
1698 		scsi_print_sense(xs);
1699 #endif /* SCSIDEBUG */
1700 
1701 	return (error);
1702 }
1703 
1704 /*
1705  * Utility routines often used in SCSI stuff
1706  */
1707 
1708 
1709 /*
1710  * Print out the scsi_link structure's address info.
1711  */
1712 void
1713 sc_print_addr(struct scsi_link *sc_link)
1714 {
1715 	struct device *adapter_device = sc_link->bus->sc_dev.dv_parent;
1716 
1717 	printf("%s(%s:%d:%d): ",
1718 	    sc_link->device_softc ?
1719 	    ((struct device *)sc_link->device_softc)->dv_xname : "probe",
1720 	    adapter_device->dv_xname,
1721 	    sc_link->target, sc_link->lun);
1722 }
1723 
1724 static const char *sense_keys[16] = {
1725 	"No Additional Sense",
1726 	"Soft Error",
1727 	"Not Ready",
1728 	"Media Error",
1729 	"Hardware Error",
1730 	"Illegal Request",
1731 	"Unit Attention",
1732 	"Write Protected",
1733 	"Blank Check",
1734 	"Vendor Unique",
1735 	"Copy Aborted",
1736 	"Aborted Command",
1737 	"Equal Error",
1738 	"Volume Overflow",
1739 	"Miscompare Error",
1740 	"Reserved"
1741 };
1742 
1743 #ifdef SCSITERSE
1744 static __inline void
1745 asc2ascii(u_int8_t asc, u_int8_t ascq, char *result, size_t len)
1746 {
1747 	snprintf(result, len, "ASC 0x%02x ASCQ 0x%02x", asc, ascq);
1748 }
1749 #else
1750 static const struct {
1751 	u_int8_t asc, ascq;
1752 	char *description;
1753 } adesc[] = {
1754 	/* www.t10.org/lists/asc-num.txt as of 11/15/10. */
1755 	{ 0x00, 0x00, "No Additional Sense Information" },
1756 	{ 0x00, 0x01, "Filemark Detected" },
1757 	{ 0x00, 0x02, "End-Of-Partition/Medium Detected" },
1758 	{ 0x00, 0x03, "Setmark Detected" },
1759 	{ 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" },
1760 	{ 0x00, 0x05, "End-Of-Data Detected" },
1761 	{ 0x00, 0x06, "I/O Process Terminated" },
1762 	{ 0x00, 0x11, "Audio Play Operation In Progress" },
1763 	{ 0x00, 0x12, "Audio Play Operation Paused" },
1764 	{ 0x00, 0x13, "Audio Play Operation Successfully Completed" },
1765 	{ 0x00, 0x14, "Audio Play Operation Stopped Due to Error" },
1766 	{ 0x00, 0x15, "No Current Audio Status To Return" },
1767 	{ 0x00, 0x16, "Operation In Progress" },
1768 	{ 0x00, 0x17, "Cleaning Requested" },
1769 	{ 0x00, 0x18, "Erase Operation In Progress" },
1770 	{ 0x00, 0x19, "Locate Operation In Progress" },
1771 	{ 0x00, 0x1A, "Rewind Operation In Progress" },
1772 	{ 0x00, 0x1B, "Set Capacity Operation In Progress" },
1773 	{ 0x00, 0x1C, "Verify Operation In Progress" },
1774 	{ 0x01, 0x00, "No Index/Sector Signal" },
1775 	{ 0x02, 0x00, "No Seek Complete" },
1776 	{ 0x03, 0x00, "Peripheral Device Write Fault" },
1777 	{ 0x03, 0x01, "No Write Current" },
1778 	{ 0x03, 0x02, "Excessive Write Errors" },
1779 	{ 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" },
1780 	{ 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" },
1781 	{ 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" },
1782 	{ 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" },
1783 	{ 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" },
1784 	{ 0x04, 0x05, "Logical Unit Not Ready, Rebuild In Progress" },
1785 	{ 0x04, 0x06, "Logical Unit Not Ready, Recalculation In Progress" },
1786 	{ 0x04, 0x07, "Logical Unit Not Ready, Operation In Progress" },
1787 	{ 0x04, 0x08, "Logical Unit Not Ready, Long Write In Progress" },
1788 	{ 0x04, 0x09, "Logical Unit Not Ready, Self-Test In Progress" },
1789 	{ 0x04, 0x0A, "Logical Unit Not Accessible, Asymmetric Access State Transition" },
1790 	{ 0x04, 0x0B, "Logical Unit Not Accessible, Target Port In Standby State" },
1791 	{ 0x04, 0x0C, "Logical Unit Not Accessible, Target Port In Unavailable State" },
1792 	{ 0x04, 0x0D, "Logical Unit Not Ready, Structure Check Required" },
1793 	{ 0x04, 0x10, "Logical Unit Not Ready, Auxiliary Memory Not Accessible" },
1794 	{ 0x04, 0x11, "Logical Unit Not Ready, Notify (Enable Spinup) Required" },
1795 	{ 0x04, 0x12, "Logical Unit Not Ready, Offline" },
1796 	{ 0x04, 0x13, "Logical Unit Not Ready, SA Creation In Progress" },
1797 	{ 0x04, 0x14, "Logical Unit Not Ready, Space Allocation In Progress" },
1798 	{ 0x04, 0x15, "Logical Unit Not Ready, Robotics Disabled" },
1799 	{ 0x04, 0x16, "Logical Unit Not Ready, Configuration Required" },
1800 	{ 0x04, 0x17, "Logical Unit Not Ready, Calibration Required" },
1801 	{ 0x04, 0x18, "Logical Unit Not Ready, A Door Is Open" },
1802 	{ 0x04, 0x19, "Logical Unit Not Ready, Operating In Sequential Mode" },
1803 	{ 0x04, 0x1A, "Logical Unit Not Ready, Start Stop Unit Command In Progress" },
1804 	{ 0x05, 0x00, "Logical Unit Does Not Respond To Selection" },
1805 	{ 0x06, 0x00, "No Reference Position Found" },
1806 	{ 0x07, 0x00, "Multiple Peripheral Devices Selected" },
1807 	{ 0x08, 0x00, "Logical Unit Communication Failure" },
1808 	{ 0x08, 0x01, "Logical Unit Communication Timeout" },
1809 	{ 0x08, 0x02, "Logical Unit Communication Parity Error" },
1810 	{ 0x08, 0x03, "Logical Unit Communication CRC Error (ULTRA-DMA/32)" },
1811 	{ 0x08, 0x04, "Unreachable Copy Target" },
1812 	{ 0x09, 0x00, "Track Following Error" },
1813 	{ 0x09, 0x01, "Tracking Servo Failure" },
1814 	{ 0x09, 0x02, "Focus Servo Failure" },
1815 	{ 0x09, 0x03, "Spindle Servo Failure" },
1816 	{ 0x09, 0x04, "Head Select Fault" },
1817 	{ 0x0A, 0x00, "Error Log Overflow" },
1818 	{ 0x0B, 0x00, "Warning" },
1819 	{ 0x0B, 0x01, "Warning - Specified Temperature Exceeded" },
1820 	{ 0x0B, 0x02, "Warning - Enclosure Degraded" },
1821 	{ 0x0B, 0x03, "Warning - Background Self-Test Failed" },
1822 	{ 0x0B, 0x04, "Warning - Background Pre-Scan Detected Medium Error" },
1823 	{ 0x0B, 0x05, "Warning - Background Medium Scan Detected Medium Error" },
1824 	{ 0x0B, 0x06, "Warning - Non-Volatile Cache Now Volatile" },
1825 	{ 0x0B, 0x07, "Warning - Degraded Power To Non-Volatile Cache" },
1826 	{ 0x0B, 0x08, "Warning - Power Loss Expected" },
1827 	{ 0x0C, 0x00, "Write Error" },
1828 	{ 0x0C, 0x01, "Write Error Recovered with Auto Reallocation" },
1829 	{ 0x0C, 0x02, "Write Error - Auto Reallocate Failed" },
1830 	{ 0x0C, 0x03, "Write Error - Recommend Reassignment" },
1831 	{ 0x0C, 0x04, "Compression Check Miscompare Error" },
1832 	{ 0x0C, 0x05, "Data Expansion Occurred During Compression" },
1833 	{ 0x0C, 0x06, "Block Not Compressible" },
1834 	{ 0x0C, 0x07, "Write Error - Recovery Needed" },
1835 	{ 0x0C, 0x08, "Write Error - Recovery Failed" },
1836 	{ 0x0C, 0x09, "Write Error - Loss Of Streaming" },
1837 	{ 0x0C, 0x0A, "Write Error - Padding Blocks Added" },
1838 	{ 0x0C, 0x0B, "Auxiliary Memory Write Error" },
1839 	{ 0x0C, 0x0C, "Write Error - Unexpected Unsolicited Data" },
1840 	{ 0x0C, 0x0D, "Write Error - Not Enough Unsolicited Data" },
1841 	{ 0x0C, 0x0F, "Defects In Error Window" },
1842 	{ 0x0D, 0x00, "Error Detected By Third Party Temporary Initiator" },
1843 	{ 0x0D, 0x01, "Third Party Device Failure" },
1844 	{ 0x0D, 0x02, "Copy Target Device Not Reachable" },
1845 	{ 0x0D, 0x03, "Incorrect Copy Target Device Type" },
1846 	{ 0x0D, 0x04, "Copy Target Device Data Underrun" },
1847 	{ 0x0D, 0x05, "Copy Target Device Data Overrun" },
1848 	{ 0x0E, 0x00, "Invalid Information Unit" },
1849 	{ 0x0E, 0x01, "Information Unit Too Short" },
1850 	{ 0x0E, 0x02, "Information Unit Too Long" },
1851 	{ 0x10, 0x00, "ID CRC Or ECC Error" },
1852 	{ 0x10, 0x01, "Logical Block Guard Check Failed" },
1853 	{ 0x10, 0x02, "Logical Block Application Tag Check Failed" },
1854 	{ 0x10, 0x03, "Logical Block Reference Tag Check Failed" },
1855 	{ 0x10, 0x04, "Logical Block Protection Error On Recover Buffered Data" },
1856 	{ 0x10, 0x05, "Logical Block Protection Method Error" },
1857 	{ 0x11, 0x00, "Unrecovered Read Error" },
1858 	{ 0x11, 0x01, "Read Retries Exhausted" },
1859 	{ 0x11, 0x02, "Error Too Long To Correct" },
1860 	{ 0x11, 0x03, "Multiple Read Errors" },
1861 	{ 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" },
1862 	{ 0x11, 0x05, "L-EC Uncorrectable Error" },
1863 	{ 0x11, 0x06, "CIRC Unrecovered Error" },
1864 	{ 0x11, 0x07, "Data Resynchronization Error" },
1865 	{ 0x11, 0x08, "Incomplete Block Read" },
1866 	{ 0x11, 0x09, "No Gap Found" },
1867 	{ 0x11, 0x0A, "Miscorrected Error" },
1868 	{ 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" },
1869 	{ 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite The Data" },
1870 	{ 0x11, 0x0D, "De-Compression CRC Error" },
1871 	{ 0x11, 0x0E, "Cannot Decompress Using Declared Algorithm" },
1872 	{ 0x11, 0x0F, "Error Reading UPC/EAN Number" },
1873 	{ 0x11, 0x10, "Error Reading ISRC Number" },
1874 	{ 0x11, 0x11, "Read Error - Loss Of Streaming" },
1875 	{ 0x11, 0x12, "Auxiliary Memory Read Error" },
1876 	{ 0x11, 0x13, "Read Error - Failed Retransmission Request" },
1877 	{ 0x11, 0x14, "Read Error - LBA Marked Bad By Application Client" },
1878 	{ 0x12, 0x00, "Address Mark Not Found for ID Field" },
1879 	{ 0x13, 0x00, "Address Mark Not Found for Data Field" },
1880 	{ 0x14, 0x00, "Recorded Entity Not Found" },
1881 	{ 0x14, 0x01, "Record Not Found" },
1882 	{ 0x14, 0x02, "Filemark or Setmark Not Found" },
1883 	{ 0x14, 0x03, "End-Of-Data Not Found" },
1884 	{ 0x14, 0x04, "Block Sequence Error" },
1885 	{ 0x14, 0x05, "Record Not Found - Recommend Reassignment" },
1886 	{ 0x14, 0x06, "Record Not Found - Data Auto-Reallocated" },
1887 	{ 0x14, 0x07, "Locate Operation Failure" },
1888 	{ 0x15, 0x00, "Random Positioning Error" },
1889 	{ 0x15, 0x01, "Mechanical Positioning Error" },
1890 	{ 0x15, 0x02, "Positioning Error Detected By Read of Medium" },
1891 	{ 0x16, 0x00, "Data Synchronization Mark Error" },
1892 	{ 0x16, 0x01, "Data Sync Error - Data Rewritten" },
1893 	{ 0x16, 0x02, "Data Sync Error - Recommend Rewrite" },
1894 	{ 0x16, 0x03, "Data Sync Error - Data Auto-Reallocated" },
1895 	{ 0x16, 0x04, "Data Sync Error - Recommend Reassignment" },
1896 	{ 0x17, 0x00, "Recovered Data With No Error Correction Applied" },
1897 	{ 0x17, 0x01, "Recovered Data With Retries" },
1898 	{ 0x17, 0x02, "Recovered Data With Positive Head Offset" },
1899 	{ 0x17, 0x03, "Recovered Data With Negative Head Offset" },
1900 	{ 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" },
1901 	{ 0x17, 0x05, "Recovered Data Using Previous Sector ID" },
1902 	{ 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" },
1903 	{ 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" },
1904 	{ 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" },
1905 	{ 0x17, 0x09, "Recovered Data Without ECC - Data Rewritten" },
1906 	{ 0x18, 0x00, "Recovered Data With Error Correction Applied" },
1907 	{ 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" },
1908 	{ 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" },
1909 	{ 0x18, 0x03, "Recovered Data With CIRC" },
1910 	{ 0x18, 0x04, "Recovered Data With L-EC" },
1911 	{ 0x18, 0x05, "Recovered Data - Recommend Reassignment" },
1912 	{ 0x18, 0x06, "Recovered Data - Recommend Rewrite" },
1913 	{ 0x18, 0x07, "Recovered Data With ECC - Data Rewritten" },
1914 	{ 0x18, 0x08, "Recovered Data With Linking" },
1915 	{ 0x19, 0x00, "Defect List Error" },
1916 	{ 0x19, 0x01, "Defect List Not Available" },
1917 	{ 0x19, 0x02, "Defect List Error in Primary List" },
1918 	{ 0x19, 0x03, "Defect List Error in Grown List" },
1919 	{ 0x1A, 0x00, "Parameter List Length Error" },
1920 	{ 0x1B, 0x00, "Synchronous Data Transfer Error" },
1921 	{ 0x1C, 0x00, "Defect List Not Found" },
1922 	{ 0x1C, 0x01, "Primary Defect List Not Found" },
1923 	{ 0x1C, 0x02, "Grown Defect List Not Found" },
1924 	{ 0x1D, 0x00, "Miscompare During Verify Operation" },
1925 	{ 0x1D, 0x01, "Miscompare Verify Of Unmapped Lba" },
1926 	{ 0x1E, 0x00, "Recovered ID with ECC" },
1927 	{ 0x1F, 0x00, "Partial Defect List Transfer" },
1928 	{ 0x20, 0x00, "Invalid Command Operation Code" },
1929 	{ 0x20, 0x01, "Access Denied - Initiator Pending-Enrolled" },
1930 	{ 0x20, 0x02, "Access Denied - No Access rights" },
1931 	{ 0x20, 0x03, "Access Denied - Invalid Mgmt ID Key" },
1932 	{ 0x20, 0x04, "Illegal Command While In Write Capable State" },
1933 	{ 0x20, 0x05, "Obsolete" },
1934 	{ 0x20, 0x06, "Illegal Command While In Explicit Address Mode" },
1935 	{ 0x20, 0x07, "Illegal Command While In Implicit Address Mode" },
1936 	{ 0x20, 0x08, "Access Denied - Enrollment Conflict" },
1937 	{ 0x20, 0x09, "Access Denied - Invalid LU Identifier" },
1938 	{ 0x20, 0x0A, "Access Denied - Invalid Proxy Token" },
1939 	{ 0x20, 0x0B, "Access Denied - ACL LUN Conflict" },
1940 	{ 0x20, 0x0C, "Illegal Command When Not In Append-Only Mode" },
1941 	{ 0x21, 0x00, "Logical Block Address Out of Range" },
1942 	{ 0x21, 0x01, "Invalid Element Address" },
1943 	{ 0x21, 0x02, "Invalid Address For Write" },
1944 	{ 0x21, 0x03, "Invalid Write Crossing Layer Jump" },
1945 	{ 0x22, 0x00, "Illegal Function (Should 20 00, 24 00, or 26 00)" },
1946 	{ 0x24, 0x00, "Illegal Field in CDB" },
1947 	{ 0x24, 0x01, "CDB Decryption Error" },
1948 	{ 0x24, 0x02, "Obsolete" },
1949 	{ 0x24, 0x03, "Obsolete" },
1950 	{ 0x24, 0x04, "Security Audit Value Frozen" },
1951 	{ 0x24, 0x05, "Security Working Key Frozen" },
1952 	{ 0x24, 0x06, "Nonce Not Unique" },
1953 	{ 0x24, 0x07, "Nonce Timestamp Out Of Range" },
1954 	{ 0x24, 0x08, "Invalid XCDB" },
1955 	{ 0x25, 0x00, "Logical Unit Not Supported" },
1956 	{ 0x26, 0x00, "Invalid Field In Parameter List" },
1957 	{ 0x26, 0x01, "Parameter Not Supported" },
1958 	{ 0x26, 0x02, "Parameter Value Invalid" },
1959 	{ 0x26, 0x03, "Threshold Parameters Not Supported" },
1960 	{ 0x26, 0x04, "Invalid Release Of Persistent Reservation" },
1961 	{ 0x26, 0x05, "Data Decryption Error" },
1962 	{ 0x26, 0x06, "Too Many Target Descriptors" },
1963 	{ 0x26, 0x07, "Unsupported Target Descriptor Type Code" },
1964 	{ 0x26, 0x08, "Too Many Segment Descriptors" },
1965 	{ 0x26, 0x09, "Unsupported Segment Descriptor Type Code" },
1966 	{ 0x26, 0x0A, "Unexpected Inexact Segment" },
1967 	{ 0x26, 0x0B, "Inline Data Length Exceeded" },
1968 	{ 0x26, 0x0C, "Invalid Operation For Copy Source Or Destination" },
1969 	{ 0x26, 0x0D, "Copy Segment Granularity Violation" },
1970 	{ 0x26, 0x0E, "Invalid Parameter While Port Is Enabled" },
1971 	{ 0x26, 0x0F, "Invalid Data-Out Buffer Integrity Check Value" },
1972 	{ 0x26, 0x10, "Data Decryption Key Fail Limit Reached" },
1973 	{ 0x26, 0x11, "Incomplete Key-Associated Data Set" },
1974 	{ 0x26, 0x12, "Vendor Specific Key Reference Not Found" },
1975 	{ 0x27, 0x00, "Write Protected" },
1976 	{ 0x27, 0x01, "Hardware Write Protected" },
1977 	{ 0x27, 0x02, "Logical Unit Software Write Protected" },
1978 	{ 0x27, 0x03, "Associated Write Protect" },
1979 	{ 0x27, 0x04, "Persistent Write Protect" },
1980 	{ 0x27, 0x05, "Permanent Write Protect" },
1981 	{ 0x27, 0x06, "Conditional Write Protect" },
1982 	{ 0x27, 0x07, "Space Allocation Failed Write Protect" },
1983 	{ 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" },
1984 	{ 0x28, 0x01, "Import Or Export Element Accessed" },
1985 	{ 0x28, 0x02, "Format-Layer May Have Changed" },
1986 	{ 0x28, 0x03, "Import/Export Element Accessed, Medium Changed" },
1987 	{ 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" },
1988 	{ 0x29, 0x01, "Power On Occurred" },
1989 	{ 0x29, 0x02, "SCSI Bus Reset Occurred" },
1990 	{ 0x29, 0x03, "Bus Device Reset Function Occurred" },
1991 	{ 0x29, 0x04, "Device Internal Reset" },
1992 	{ 0x29, 0x05, "Transceiver Mode Changed to Single Ended" },
1993 	{ 0x29, 0x06, "Transceiver Mode Changed to LVD" },
1994 	{ 0x29, 0x07, "I_T Nexus Loss Occurred" },
1995 	{ 0x2A, 0x00, "Parameters Changed" },
1996 	{ 0x2A, 0x01, "Mode Parameters Changed" },
1997 	{ 0x2A, 0x02, "Log Parameters Changed" },
1998 	{ 0x2A, 0x03, "Reservations Preempted" },
1999 	{ 0x2A, 0x04, "Reservations Released" },
2000 	{ 0x2A, 0x05, "Registrations Preempted" },
2001 	{ 0x2A, 0x06, "Asymmetric Access State Changed" },
2002 	{ 0x2A, 0x07, "Implicit Asymmetric Access State Transition Failed" },
2003 	{ 0x2A, 0x08, "Priority Changed" },
2004 	{ 0x2A, 0x09, "Capacity Data Has Changed" },
2005 	{ 0x2A, 0x0A, "Error History I_T Nexus Cleared" },
2006 	{ 0x2A, 0x0B, "Error History Snapshot Released" },
2007 	{ 0x2A, 0x0C, "Error Recovery Attributes Have Changed" },
2008 	{ 0x2A, 0x0D, "Data Encryption Capabilities Changed" },
2009 	{ 0x2A, 0x10, "Timestamp Changed" },
2010 	{ 0x2A, 0x11, "Data Encryption Parameters Changed By Another I_T Nexus" },
2011 	{ 0x2A, 0x12, "Data Encryption Parameters Changed By Vendor Specific Event" },
2012 	{ 0x2A, 0x13, "Data Encryption Key Instance Counter Has Changed" },
2013 	{ 0x2A, 0x14, "SA Creation Capabilities Data Has Changed" },
2014 	{ 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" },
2015 	{ 0x2C, 0x00, "Command Sequence Error" },
2016 	{ 0x2C, 0x01, "Too Many Windows Specified" },
2017 	{ 0x2C, 0x02, "Invalid Combination of Windows Specified" },
2018 	{ 0x2C, 0x03, "Current Program Area Is Not Empty" },
2019 	{ 0x2C, 0x04, "Current Program Area Is Empty" },
2020 	{ 0x2C, 0x05, "Illegal Power Condition Request" },
2021 	{ 0x2C, 0x06, "Persistent Prevent Conflict" },
2022 	{ 0x2C, 0x07, "Previous Busy Status" },
2023 	{ 0x2C, 0x08, "Previous Task Set Full Status" },
2024 	{ 0x2C, 0x09, "Previous Reservation Conflict Status" },
2025 	{ 0x2C, 0x0A, "Partition Or Collection Contains User Objects" },
2026 	{ 0x2C, 0x0B, "Not Reserved" },
2027 	{ 0x2C, 0x0C, "ORWrite Generation Does Not Match" },
2028 	{ 0x2D, 0x00, "Overwrite Error On Update In Place" },
2029 	{ 0x2E, 0x00, "Insufficient Time For Operation" },
2030 	{ 0x2F, 0x00, "Commands Cleared By Another Initiator" },
2031 	{ 0x2F, 0x01, "Commands Cleared By Power Loss Notification" },
2032 	{ 0x2F, 0x02, "Commands Cleared By Device Server" },
2033 	{ 0x30, 0x00, "Incompatible Medium Installed" },
2034 	{ 0x30, 0x01, "Cannot Read Medium - Unknown Format" },
2035 	{ 0x30, 0x02, "Cannot Read Medium - Incompatible Format" },
2036 	{ 0x30, 0x03, "Cleaning Cartridge Installed" },
2037 	{ 0x30, 0x04, "Cannot Write Medium - Unknown Format" },
2038 	{ 0x30, 0x05, "Cannot Write Medium - Incompatible Format" },
2039 	{ 0x30, 0x06, "Cannot Format Medium - Incompatible Medium" },
2040 	{ 0x30, 0x07, "Cleaning Failure" },
2041 	{ 0x30, 0x08, "Cannot Write - Application Code Mismatch" },
2042 	{ 0x30, 0x09, "Current Session Not Fixated For Append" },
2043 	{ 0x30, 0x0A, "Cleaning Request Rejected" },
2044 	{ 0x30, 0x10, "Medium Not Formatted" },
2045 	{ 0x30, 0x11, "Incompatible Volume Type" },
2046 	{ 0x30, 0x12, "Incompatible Volume Qualifier" },
2047 	{ 0x30, 0x13, "Cleaning Volume Expired" },
2048 	{ 0x31, 0x00, "Medium Format Corrupted" },
2049 	{ 0x31, 0x01, "Format Command Failed" },
2050 	{ 0x31, 0x02, "Zoned Formatting Failed Due To Spare Linking" },
2051 	{ 0x32, 0x00, "No Defect Spare Location Available" },
2052 	{ 0x32, 0x01, "Defect List Update Failure" },
2053 	{ 0x33, 0x00, "Tape Length Error" },
2054 	{ 0x34, 0x00, "Enclosure Failure" },
2055 	{ 0x35, 0x00, "Enclosure Services Failure" },
2056 	{ 0x35, 0x01, "Unsupported Enclosure Function" },
2057 	{ 0x35, 0x02, "Enclosure Services Unavailable" },
2058 	{ 0x35, 0x03, "Enclosure Services Transfer Failure" },
2059 	{ 0x35, 0x04, "Enclosure Services Transfer Refused" },
2060 	{ 0x36, 0x00, "Ribbon, Ink, or Toner Failure" },
2061 	{ 0x37, 0x00, "Rounded Parameter" },
2062 	{ 0x38, 0x00, "Event Status Notification" },
2063 	{ 0x38, 0x02, "ESN - Power Management Class Event" },
2064 	{ 0x38, 0x04, "ESN - Media Class Event" },
2065 	{ 0x38, 0x06, "ESN - Device Busy Class Event" },
2066 	{ 0x39, 0x00, "Saving Parameters Not Supported" },
2067 	{ 0x3A, 0x00, "Medium Not Present" },
2068 	{ 0x3A, 0x01, "Medium Not Present - Tray Closed" },
2069 	{ 0x3A, 0x02, "Medium Not Present - Tray Open" },
2070 	{ 0x3A, 0x03, "Medium Not Present - Loadable" },
2071 	{ 0x3A, 0x04, "Medium Not Present - Medium Auxiliary Memory Accessible" },
2072 	{ 0x3B, 0x00, "Sequential Positioning Error" },
2073 	{ 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" },
2074 	{ 0x3B, 0x02, "Tape Position Error At End-of-Medium" },
2075 	{ 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" },
2076 	{ 0x3B, 0x04, "Slew Failure" },
2077 	{ 0x3B, 0x05, "Paper Jam" },
2078 	{ 0x3B, 0x06, "Failed To Sense Top-Of-Form" },
2079 	{ 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" },
2080 	{ 0x3B, 0x08, "Reposition Error" },
2081 	{ 0x3B, 0x09, "Read Past End Of Medium" },
2082 	{ 0x3B, 0x0A, "Read Past Beginning Of Medium" },
2083 	{ 0x3B, 0x0B, "Position Past End Of Medium" },
2084 	{ 0x3B, 0x0C, "Position Past Beginning Of Medium" },
2085 	{ 0x3B, 0x0D, "Medium Destination Element Full" },
2086 	{ 0x3B, 0x0E, "Medium Source Element Empty" },
2087 	{ 0x3B, 0x0F, "End Of Medium Reached" },
2088 	{ 0x3B, 0x11, "Medium Magazine Not Accessible" },
2089 	{ 0x3B, 0x12, "Medium Magazine Removed" },
2090 	{ 0x3B, 0x13, "Medium Magazine Inserted" },
2091 	{ 0x3B, 0x14, "Medium Magazine Locked" },
2092 	{ 0x3B, 0x15, "Medium Magazine Unlocked" },
2093 	{ 0x3B, 0x16, "Mechanical Positioning Or Changer Error" },
2094 	{ 0x3B, 0x17, "Read Past End Of User Object" },
2095 	{ 0x3B, 0x18, "Element Disabled" },
2096 	{ 0x3B, 0x19, "Element Enabled" },
2097 	{ 0x3B, 0x1A, "Data Transfer Device Removed" },
2098 	{ 0x3B, 0x1B, "Data Transfer Device Inserted" },
2099 	{ 0x3D, 0x00, "Invalid Bits In IDENTIFY Message" },
2100 	{ 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" },
2101 	{ 0x3E, 0x01, "Logical Unit Failure" },
2102 	{ 0x3E, 0x02, "Timeout On Logical Unit" },
2103 	{ 0x3E, 0x03, "Logical Unit Failed Self-Test" },
2104 	{ 0x3E, 0x04, "Logical Unit Unable To Update Self-Test Log" },
2105 	{ 0x3F, 0x00, "Target Operating Conditions Have Changed" },
2106 	{ 0x3F, 0x01, "Microcode Has Changed" },
2107 	{ 0x3F, 0x02, "Changed Operating Definition" },
2108 	{ 0x3F, 0x03, "INQUIRY Data Has Changed" },
2109 	{ 0x3F, 0x04, "component Device Attached" },
2110 	{ 0x3F, 0x05, "Device Identifier Changed" },
2111 	{ 0x3F, 0x06, "Redundancy Group Created Or Modified" },
2112 	{ 0x3F, 0x07, "Redundancy Group Deleted" },
2113 	{ 0x3F, 0x08, "Spare Created Or Modified" },
2114 	{ 0x3F, 0x09, "Spare Deleted" },
2115 	{ 0x3F, 0x0A, "Volume Set Created Or Modified" },
2116 	{ 0x3F, 0x0B, "Volume Set Deleted" },
2117 	{ 0x3F, 0x0C, "Volume Set Deassigned" },
2118 	{ 0x3F, 0x0D, "Volume Set Reassigned" },
2119 	{ 0x3F, 0x0E, "Reported LUNs Data Has Changed" },
2120 	{ 0x3F, 0x0F, "Echo Buffer Overwritten" },
2121 	{ 0x3F, 0x10, "Medium Loadable" },
2122 	{ 0x3F, 0x11, "Medium Auxiliary Memory Accessible" },
2123 	{ 0x3F, 0x12, "iSCSI IP Address Added" },
2124 	{ 0x3F, 0x13, "iSCSI IP Address Removed" },
2125 	{ 0x3F, 0x14, "iSCSI IP Address Changed" },
2126 	{ 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" },
2127 	/*
2128 	 * ASC 0x40 also has an ASCQ range from 0x80 to 0xFF.
2129 	 * 0x40 0xNN DIAGNOSTIC FAILURE ON COMPONENT NN
2130 	 */
2131 	{ 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" },
2132 	{ 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" },
2133 	{ 0x43, 0x00, "Message Error" },
2134 	{ 0x44, 0x00, "Internal Target Failure" },
2135 	{ 0x44, 0x71, "ATA Device Failed Set Features" },
2136 	{ 0x45, 0x00, "Select Or Reselect Failure" },
2137 	{ 0x46, 0x00, "Unsuccessful Soft Reset" },
2138 	{ 0x47, 0x00, "SCSI Parity Error" },
2139 	{ 0x47, 0x01, "Data Phase CRC Error Detected" },
2140 	{ 0x47, 0x02, "SCSI Parity Error Detected During ST Data Phase" },
2141 	{ 0x47, 0x03, "Information Unit iuCRC Error Detected" },
2142 	{ 0x47, 0x04, "Asynchronous Information Protection Error Detected" },
2143 	{ 0x47, 0x05, "Protocol Service CRC Error" },
2144 	{ 0x47, 0x06, "PHY Test Function In Progress" },
2145 	{ 0x47, 0x7F, "Some Commands Cleared By iSCSI Protocol Event" },
2146 	{ 0x48, 0x00, "Initiator Detected Error Message Received" },
2147 	{ 0x49, 0x00, "Invalid Message Error" },
2148 	{ 0x4A, 0x00, "Command Phase Error" },
2149 	{ 0x4B, 0x00, "Data Phase Error" },
2150 	{ 0x4B, 0x01, "Invalid Target Port Transfer Tag Received" },
2151 	{ 0x4B, 0x02, "Too Much Write Data" },
2152 	{ 0x4B, 0x03, "ACK/NAK Timeout" },
2153 	{ 0x4B, 0x04, "NAK Received" },
2154 	{ 0x4B, 0x05, "Data Offset Error" },
2155 	{ 0x4B, 0x06, "Initiator Response Timeout" },
2156 	{ 0x4B, 0x07, "Connection Lost" },
2157 	{ 0x4C, 0x00, "Logical Unit Failed Self-Configuration" },
2158 	/*
2159 	 * ASC 0x4D has an ASCQ range from 0x00 to 0xFF.
2160 	 * 0x4D 0xNN TAGGED OVERLAPPED COMMANDS (NN = TASK TAG)
2161 	 */
2162 	{ 0x4E, 0x00, "Overlapped Commands Attempted" },
2163 	{ 0x50, 0x00, "Write Append Error" },
2164 	{ 0x50, 0x01, "Write Append Position Error" },
2165 	{ 0x50, 0x02, "Position Error Related To Timing" },
2166 	{ 0x51, 0x00, "Erase Failure" },
2167 	{ 0x51, 0x01, "Erase Failure - Incomplete Erase Operation Detected" },
2168 	{ 0x52, 0x00, "Cartridge Fault" },
2169 	{ 0x53, 0x00, "Media Load or Eject Failed" },
2170 	{ 0x53, 0x01, "Unload Tape Failure" },
2171 	{ 0x53, 0x02, "Medium Removal Prevented" },
2172 	{ 0x53, 0x03, "Medium Removal Prevented By Data Transfer Element" },
2173 	{ 0x53, 0x04, "Medium Thread Or Unthread Failure" },
2174 	{ 0x53, 0x05, "Volume Identifier Invalid" },
2175 	{ 0x53, 0x06, "Volume Identifier Missing" },
2176 	{ 0x53, 0x07, "Duplicate Volume Identifier" },
2177 	{ 0x53, 0x08, "Element Status Unknown" },
2178 	{ 0x54, 0x00, "SCSI To Host System Interface Failure" },
2179 	{ 0x55, 0x00, "System Resource Failure" },
2180 	{ 0x55, 0x01, "System Buffer Full" },
2181 	{ 0x55, 0x02, "Insufficient Reservation Resources" },
2182 	{ 0x55, 0x03, "Insufficient Resources" },
2183 	{ 0x55, 0x04, "Insufficient Registration Resources" },
2184 	{ 0x55, 0x05, "Insufficient Access Control Resources" },
2185 	{ 0x55, 0x06, "Auxiliary Memory Out Of Space" },
2186 	{ 0x55, 0x07, "Quota Error" },
2187 	{ 0x55, 0x08, "Maximum Number Of Supplemental Decryption Keys Exceeded" },
2188 	{ 0x55, 0x09, "Medium Auxiliary Memory Not Accessible" },
2189 	{ 0x55, 0x0A, "Data Currently Unavailable" },
2190 	{ 0x55, 0x0B, "Insufficient Power For Operation" },
2191 	{ 0x57, 0x00, "Unable To Recover Table-Of-Contents" },
2192 	{ 0x58, 0x00, "Generation Does Not Exist" },
2193 	{ 0x59, 0x00, "Updated Block Read" },
2194 	{ 0x5A, 0x00, "Operator Request or State Change Input" },
2195 	{ 0x5A, 0x01, "Operator Medium Removal Requested" },
2196 	{ 0x5A, 0x02, "Operator Selected Write Protect" },
2197 	{ 0x5A, 0x03, "Operator Selected Write Permit" },
2198 	{ 0x5B, 0x00, "Log Exception" },
2199 	{ 0x5B, 0x01, "Threshold Condition Met" },
2200 	{ 0x5B, 0x02, "Log Counter At Maximum" },
2201 	{ 0x5B, 0x03, "Log List Codes Exhausted" },
2202 	{ 0x5C, 0x00, "RPL Status Change" },
2203 	{ 0x5C, 0x01, "Spindles Synchronized" },
2204 	{ 0x5C, 0x02, "Spindles Not Synchronized" },
2205 	{ 0x5D, 0x00, "Failure Prediction Threshold Exceeded" },
2206 	{ 0x5D, 0x01, "Media Failure Prediction Threshold Exceeded" },
2207 	{ 0x5D, 0x02, "Logical Unit Failure Prediction Threshold Exceeded" },
2208 	{ 0x5D, 0x03, "Spare Area Exhaustion Prediction Threshold Exceeded" },
2209 	{ 0x5D, 0x10, "Hardware Impending Failure General Hard Drive Failure" },
2210 	{ 0x5D, 0x11, "Hardware Impending Failure Drive Error Rate Too High" },
2211 	{ 0x5D, 0x12, "Hardware Impending Failure Data Error Rate Too High" },
2212 	{ 0x5D, 0x13, "Hardware Impending Failure Seek Error Rate Too High" },
2213 	{ 0x5D, 0x14, "Hardware Impending Failure Too Many Block Reassigns" },
2214 	{ 0x5D, 0x15, "Hardware Impending Failure Access Times Too High" },
2215 	{ 0x5D, 0x16, "Hardware Impending Failure Start Unit Times Too High" },
2216 	{ 0x5D, 0x17, "Hardware Impending Failure Channel Parametrics" },
2217 	{ 0x5D, 0x18, "Hardware Impending Failure Controller Detected" },
2218 	{ 0x5D, 0x19, "Hardware Impending Failure Throughput Performance" },
2219 	{ 0x5D, 0x1A, "Hardware Impending Failure Seek Time Performance" },
2220 	{ 0x5D, 0x1B, "Hardware Impending Failure Spin-Up Retry Count" },
2221 	{ 0x5D, 0x1C, "Hardware Impending Failure Drive Calibration Retry Count" },
2222 	{ 0x5D, 0x20, "Controller Impending Failure General Hard Drive Failure" },
2223 	{ 0x5D, 0x21, "Controller Impending Failure Drive Error Rate Too High" },
2224 	{ 0x5D, 0x22, "Controller Impending Failure Data Error Rate Too High" },
2225 	{ 0x5D, 0x23, "Controller Impending Failure Seek Error Rate Too High" },
2226 	{ 0x5D, 0x24, "Controller Impending Failure Too Many Block Reassigns" },
2227 	{ 0x5D, 0x25, "Controller Impending Failure Access Times Too High" },
2228 	{ 0x5D, 0x26, "Controller Impending Failure Start Unit Times Too High" },
2229 	{ 0x5D, 0x27, "Controller Impending Failure Channel Parametrics" },
2230 	{ 0x5D, 0x28, "Controller Impending Failure Controller Detected" },
2231 	{ 0x5D, 0x29, "Controller Impending Failure Throughput Performance" },
2232 	{ 0x5D, 0x2A, "Controller Impending Failure Seek Time Performance" },
2233 	{ 0x5D, 0x2B, "Controller Impending Failure Spin-Up Retry Count" },
2234 	{ 0x5D, 0x2C, "Controller Impending Failure Drive Calibration Retry Count" },
2235 	{ 0x5D, 0x30, "Data Channel Impending Failure General Hard Drive Failure" },
2236 	{ 0x5D, 0x31, "Data Channel Impending Failure Drive Error Rate Too High" },
2237 	{ 0x5D, 0x32, "Data Channel Impending Failure Data Error Rate Too High" },
2238 	{ 0x5D, 0x33, "Data Channel Impending Failure Seek Error Rate Too High" },
2239 	{ 0x5D, 0x34, "Data Channel Impending Failure Too Many Block Reassigns" },
2240 	{ 0x5D, 0x35, "Data Channel Impending Failure Access Times Too High" },
2241 	{ 0x5D, 0x36, "Data Channel Impending Failure Start Unit Times Too High" },
2242 	{ 0x5D, 0x37, "Data Channel Impending Failure Channel Parametrics" },
2243 	{ 0x5D, 0x38, "Data Channel Impending Failure Controller Detected" },
2244 	{ 0x5D, 0x39, "Data Channel Impending Failure Throughput Performance" },
2245 	{ 0x5D, 0x3A, "Data Channel Impending Failure Seek Time Performance" },
2246 	{ 0x5D, 0x3B, "Data Channel Impending Failure Spin-Up Retry Count" },
2247 	{ 0x5D, 0x3C, "Data Channel Impending Failure Drive Calibration Retry Count" },
2248 	{ 0x5D, 0x40, "Servo Impending Failure General Hard Drive Failure" },
2249 	{ 0x5D, 0x41, "Servo Impending Failure Drive Error Rate Too High" },
2250 	{ 0x5D, 0x42, "Servo Impending Failure Data Error Rate Too High" },
2251 	{ 0x5D, 0x43, "Servo Impending Failure Seek Error Rate Too High" },
2252 	{ 0x5D, 0x44, "Servo Impending Failure Too Many Block Reassigns" },
2253 	{ 0x5D, 0x45, "Servo Impending Failure Access Times Too High" },
2254 	{ 0x5D, 0x46, "Servo Impending Failure Start Unit Times Too High" },
2255 	{ 0x5D, 0x47, "Servo Impending Failure Channel Parametrics" },
2256 	{ 0x5D, 0x48, "Servo Impending Failure Controller Detected" },
2257 	{ 0x5D, 0x49, "Servo Impending Failure Throughput Performance" },
2258 	{ 0x5D, 0x4A, "Servo Impending Failure Seek Time Performance" },
2259 	{ 0x5D, 0x4B, "Servo Impending Failure Spin-Up Retry Count" },
2260 	{ 0x5D, 0x4C, "Servo Impending Failure Drive Calibration Retry Count" },
2261 	{ 0x5D, 0x50, "Spindle Impending Failure General Hard Drive Failure" },
2262 	{ 0x5D, 0x51, "Spindle Impending Failure Drive Error Rate Too High" },
2263 	{ 0x5D, 0x52, "Spindle Impending Failure Data Error Rate Too High" },
2264 	{ 0x5D, 0x53, "Spindle Impending Failure Seek Error Rate Too High" },
2265 	{ 0x5D, 0x54, "Spindle Impending Failure Too Many Block Reassigns" },
2266 	{ 0x5D, 0x55, "Spindle Impending Failure Access Times Too High" },
2267 	{ 0x5D, 0x56, "Spindle Impending Failure Start Unit Times Too High" },
2268 	{ 0x5D, 0x57, "Spindle Impending Failure Channel Parametrics" },
2269 	{ 0x5D, 0x58, "Spindle Impending Failure Controller Detected" },
2270 	{ 0x5D, 0x59, "Spindle Impending Failure Throughput Performance" },
2271 	{ 0x5D, 0x5A, "Spindle Impending Failure Seek Time Performance" },
2272 	{ 0x5D, 0x5B, "Spindle Impending Failure Spin-Up Retry Count" },
2273 	{ 0x5D, 0x5C, "Spindle Impending Failure Drive Calibration Retry Count" },
2274 	{ 0x5D, 0x60, "Firmware Impending Failure General Hard Drive Failure" },
2275 	{ 0x5D, 0x61, "Firmware Impending Failure Drive Error Rate Too High" },
2276 	{ 0x5D, 0x62, "Firmware Impending Failure Data Error Rate Too High" },
2277 	{ 0x5D, 0x63, "Firmware Impending Failure Seek Error Rate Too High" },
2278 	{ 0x5D, 0x64, "Firmware Impending Failure Too Many Block Reassigns" },
2279 	{ 0x5D, 0x65, "Firmware Impending Failure Access Times Too High" },
2280 	{ 0x5D, 0x66, "Firmware Impending Failure Start Unit Times Too High" },
2281 	{ 0x5D, 0x67, "Firmware Impending Failure Channel Parametrics" },
2282 	{ 0x5D, 0x68, "Firmware Impending Failure Controller Detected" },
2283 	{ 0x5D, 0x69, "Firmware Impending Failure Throughput Performance" },
2284 	{ 0x5D, 0x6A, "Firmware Impending Failure Seek Time Performance" },
2285 	{ 0x5D, 0x6B, "Firmware Impending Failure Spin-Up Retry Count" },
2286 	{ 0x5D, 0x6C, "Firmware Impending Failure Drive Calibration Retry Count" },
2287 	{ 0x5D, 0xFF, "Failure Prediction Threshold Exceeded (false)" },
2288 	{ 0x5E, 0x00, "Low Power Condition On" },
2289 	{ 0x5E, 0x01, "Idle Condition Activated By Timer" },
2290 	{ 0x5E, 0x02, "Standby Condition Activated By Timer" },
2291 	{ 0x5E, 0x03, "Idle Condition Activated By Command" },
2292 	{ 0x5E, 0x04, "Standby Condition Activated By Command" },
2293 	{ 0x5E, 0x05, "IDLE_B Condition Activated By Timer" },
2294 	{ 0x5E, 0x06, "IDLE_B Condition Activated By Command" },
2295 	{ 0x5E, 0x07, "IDLE_C Condition Activated By Timer" },
2296 	{ 0x5E, 0x08, "IDLE_C Condition Activated By Command" },
2297 	{ 0x5E, 0x09, "STANDBY_Y Condition Activated By Timer" },
2298 	{ 0x5E, 0x0A, "STANDBY_Y Condition Activated By Command" },
2299 	{ 0x5E, 0x41, "Power State Change To Active" },
2300 	{ 0x5E, 0x42, "Power State Change To Idle" },
2301 	{ 0x5E, 0x43, "Power State Change To Standby" },
2302 	{ 0x5E, 0x45, "Power State Change To Sleep" },
2303 	{ 0x5E, 0x47, "Power State Change To Device Control" },
2304 	{ 0x60, 0x00, "Lamp Failure" },
2305 	{ 0x61, 0x00, "Video Acquisition Error" },
2306 	{ 0x61, 0x01, "Unable To Acquire Video" },
2307 	{ 0x61, 0x02, "Out Of Focus" },
2308 	{ 0x62, 0x00, "Scan Head Positioning Error" },
2309 	{ 0x63, 0x00, "End Of User Area Encountered On This Track" },
2310 	{ 0x63, 0x01, "Packet Does Not Fit In Available Space" },
2311 	{ 0x64, 0x00, "Illegal Mode For This Track" },
2312 	{ 0x64, 0x01, "Invalid Packet Size" },
2313 	{ 0x65, 0x00, "Voltage Fault" },
2314 	{ 0x66, 0x00, "Automatic Document Feeder Cover Up" },
2315 	{ 0x66, 0x01, "Automatic Document Feeder Lift Up" },
2316 	{ 0x66, 0x02, "Document Jam In Automatic Document Feeder" },
2317 	{ 0x66, 0x03, "Document Miss Feed Automatic In Document Feeder" },
2318 	{ 0x67, 0x00, "Configuration Failure" },
2319 	{ 0x67, 0x01, "Configuration Of Incapable Logical Units Failed" },
2320 	{ 0x67, 0x02, "Add Logical Unit Failed" },
2321 	{ 0x67, 0x03, "Modification Of Logical Unit Failed" },
2322 	{ 0x67, 0x04, "Exchange Of Logical Unit Failed" },
2323 	{ 0x67, 0x05, "Remove Of Logical Unit Failed" },
2324 	{ 0x67, 0x06, "Attachment Of Logical Unit Failed" },
2325 	{ 0x67, 0x07, "Creation Of Logical Unit Failed" },
2326 	{ 0x67, 0x08, "Assign Failure Occurred" },
2327 	{ 0x67, 0x09, "Multiply Assigned Logical Unit" },
2328 	{ 0x67, 0x0A, "Set Target Port Groups Command Failed" },
2329 	{ 0x67, 0x0B, "ATA Device Feature Not Enabled" },
2330 	{ 0x68, 0x00, "Logical Unit Not Configured" },
2331 	{ 0x69, 0x00, "Data Loss On Logical Unit" },
2332 	{ 0x69, 0x01, "Multiple Logical Unit Failures" },
2333 	{ 0x69, 0x02, "Parity/Data Mismatch" },
2334 	{ 0x6A, 0x00, "Informational, Refer To Log" },
2335 	{ 0x6B, 0x00, "State Change Has Occurred" },
2336 	{ 0x6B, 0x01, "Redundancy Level Got Better" },
2337 	{ 0x6B, 0x02, "Redundancy Level Got Worse" },
2338 	{ 0x6C, 0x00, "Rebuild Failure Occurred" },
2339 	{ 0x6D, 0x00, "Recalculate Failure Occurred" },
2340 	{ 0x6E, 0x00, "Command To Logical Unit Failed" },
2341 	{ 0x6F, 0x00, "Copy Protection Key Exchange Failure - Authentication Failure" },
2342 	{ 0x6F, 0x01, "Copy Protection Key Exchange Failure - Key Not Present" },
2343 	{ 0x6F, 0x02, "Copy Protection Key Exchange Failure - Key Not Established" },
2344 	{ 0x6F, 0x03, "Read Of Scrambled Sector Without Authentication" },
2345 	{ 0x6F, 0x04, "Media Region Code Is Mismatched To Logical Unit Region" },
2346 	{ 0x6F, 0x05, "Drive Region Must Be Permanent/Region Reset Count Error" },
2347 	/*
2348 	 * ASC 0x70 has an ASCQ range from 0x00 to 0xFF.
2349 	 * 0x70 0xNN DECOMPRESSION EXCEPTION SHORT ALGORITHM ID Of NN
2350 	 */
2351 	{ 0x71, 0x00, "Decompression Exception Long Algorithm ID" },
2352 	{ 0x72, 0x00, "Session Fixation Error" },
2353 	{ 0x72, 0x01, "Session Fixation Error Writing Lead-In" },
2354 	{ 0x72, 0x02, "Session Fixation Error Writing Lead-Out" },
2355 	{ 0x72, 0x03, "Session Fixation Error - Incomplete Track In Session" },
2356 	{ 0x72, 0x04, "Empty Or Partially Written Reserved Track" },
2357 	{ 0x72, 0x05, "No More Track Reservations Allowed" },
2358 	{ 0x72, 0x06, "RMZ Extension Is Not Allowed" },
2359 	{ 0x72, 0x07, "No More Test Zone Extensions Are Allowed" },
2360 	{ 0x73, 0x00, "CD Control Error" },
2361 	{ 0x73, 0x01, "Power Calibration Area Almost Full" },
2362 	{ 0x73, 0x02, "Power Calibration Area Is Full" },
2363 	{ 0x73, 0x03, "Power Calibration Area Error" },
2364 	{ 0x73, 0x04, "Program Memory Area Update Failure" },
2365 	{ 0x73, 0x05, "Program Memory Area Is Full" },
2366 	{ 0x73, 0x06, "RMA/PMA Is Almost Full" },
2367 	{ 0x73, 0x10, "Current Power Calibration Area Almost Full" },
2368 	{ 0x73, 0x11, "Current Power Calibration Area Is Full" },
2369 	{ 0x73, 0x17, "RDZ Is Full" },
2370 	{ 0x74, 0x00, "Security Error" },
2371 	{ 0x74, 0x01, "Unable To Decrypt Data" },
2372 	{ 0x74, 0x02, "Unencrypted Data Encountered While Decrypting" },
2373 	{ 0x74, 0x03, "Incorrect Data Encryption Key" },
2374 	{ 0x74, 0x04, "Cryptographic Integrity Validation Failed" },
2375 	{ 0x74, 0x05, "Error Decrypting Data" },
2376 	{ 0x74, 0x06, "Unknown Signature Verification Key" },
2377 	{ 0x74, 0x07, "Encryption Parameters Not Useable" },
2378 	{ 0x74, 0x08, "Digital Signature Validation Failure" },
2379 	{ 0x74, 0x09, "Encryption Mode Mismatch On Read" },
2380 	{ 0x74, 0x0A, "Encrypted Block Not Raw Read Enabled" },
2381 	{ 0x74, 0x0B, "Incorrect Encryption Parameters" },
2382 	{ 0x74, 0x0C, "Unable To Decrypt Parameter List" },
2383 	{ 0x74, 0x0D, "Encryption Algorithm Disabled" },
2384 	{ 0x74, 0x10, "SA Creation Parameter Value Invalid" },
2385 	{ 0x74, 0x11, "SA Creation Parameter Value Rejected" },
2386 	{ 0x74, 0x12, "Invalid SA Usage" },
2387 	{ 0x74, 0x21, "Data Encryption Configuration Prevented" },
2388 	{ 0x74, 0x30, "SA Creation Parameter Not Supported" },
2389 	{ 0x74, 0x40, "Authentication Failed" },
2390 	{ 0x74, 0x61, "External Data Encryption Key Manager Access Error" },
2391 	{ 0x74, 0x62, "External Data Encryption Key Manager Error" },
2392 	{ 0x74, 0x63, "External Data Encryption Key Not Found" },
2393 	{ 0x74, 0x64, "External Data Encryption Request Not Authorized" },
2394 	{ 0x74, 0x6E, "External Data Encryption Control Timeout" },
2395 	{ 0x74, 0x6F, "External Data Encryption Control Error" },
2396 	{ 0x74, 0x71, "Logical Unit Access Not Authorized" },
2397 	{ 0x74, 0x79, "Security Conflict In Translated Device" },
2398 	{ 0x00, 0x00, NULL }
2399 };
2400 
2401 static __inline void
2402 asc2ascii(u_int8_t asc, u_int8_t ascq, char *result, size_t len)
2403 {
2404 	int					i;
2405 
2406 	/* Check for a dynamically built description. */
2407 	switch (asc) {
2408 	case 0x40:
2409 		if (ascq >= 0x80) {
2410 			snprintf(result, len,
2411 		            "Diagnostic Failure on Component 0x%02x", ascq);
2412 			return;
2413 		}
2414 		break;
2415 	case 0x4d:
2416 		snprintf(result, len,
2417 	 	    "Tagged Overlapped Commands (0x%02x = TASK TAG)", ascq);
2418 		return;
2419 	case 0x70:
2420 		snprintf(result, len,
2421 		    "Decompression Exception Short Algorithm ID OF 0x%02x",
2422 		    ascq);
2423 		return;
2424 	default:
2425 		break;
2426 	}
2427 
2428 	/* Check for a fixed description. */
2429 	for (i = 0; adesc[i].description != NULL; i++) {
2430 		if (adesc[i].asc == asc && adesc[i].ascq == ascq) {
2431 			strlcpy(result, adesc[i].description, len);
2432 			return;
2433 		}
2434 	}
2435 
2436 	/* Just print out the ASC and ASCQ values as a description. */
2437 	snprintf(result, len, "ASC 0x%02x ASCQ 0x%02x", asc, ascq);
2438 }
2439 #endif /* SCSITERSE */
2440 
2441 void
2442 scsi_print_sense(struct scsi_xfer *xs)
2443 {
2444 	struct scsi_sense_data			*sense = &xs->sense;
2445 	u_int8_t				serr = sense->error_code &
2446 						    SSD_ERRCODE;
2447 	int32_t					info;
2448 	char					*sbs;
2449 
2450 	sc_print_addr(xs->sc_link);
2451 
2452 	/* XXX For error 0x71, current opcode is not the relevant one. */
2453 	printf("%sCheck Condition (error %#x) on opcode 0x%x\n",
2454 	    (serr == SSD_ERRCODE_DEFERRED) ? "DEFERRED " : "", serr,
2455 	    xs->cmd->opcode);
2456 
2457 	if (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED) {
2458 		if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
2459 			struct scsi_sense_data_unextended *usense =
2460 			    (struct scsi_sense_data_unextended *)sense;
2461 			printf("   AT BLOCK #: %d (decimal)",
2462 			    _3btol(usense->block));
2463 		}
2464 		return;
2465 	}
2466 
2467 	printf("    SENSE KEY: %s\n", scsi_decode_sense(sense,
2468 	    DECODE_SENSE_KEY));
2469 
2470 	if (sense->flags & (SSD_FILEMARK | SSD_EOM | SSD_ILI)) {
2471 		char pad = ' ';
2472 
2473 		printf("             ");
2474 		if (sense->flags & SSD_FILEMARK) {
2475 			printf("%c Filemark Detected", pad);
2476 			pad = ',';
2477 		}
2478 		if (sense->flags & SSD_EOM) {
2479 			printf("%c EOM Detected", pad);
2480 			pad = ',';
2481 		}
2482 		if (sense->flags & SSD_ILI)
2483 			printf("%c Incorrect Length Indicator Set", pad);
2484 		printf("\n");
2485 	}
2486 
2487 	/*
2488 	 * It is inconvenient to use device type to figure out how to
2489 	 * format the info fields. So print them as 32 bit integers.
2490 	 */
2491 	info = _4btol(&sense->info[0]);
2492 	if (info)
2493 		printf("         INFO: 0x%x (VALID flag %s)\n", info,
2494 		    sense->error_code & SSD_ERRCODE_VALID ? "on" : "off");
2495 
2496 	if (sense->extra_len < 4)
2497 		return;
2498 
2499 	info = _4btol(&sense->cmd_spec_info[0]);
2500 	if (info)
2501 		printf(" COMMAND INFO: 0x%x\n", info);
2502 	sbs = scsi_decode_sense(sense, DECODE_ASC_ASCQ);
2503 	if (strlen(sbs) > 0)
2504 		printf("     ASC/ASCQ: %s\n", sbs);
2505 	if (sense->fru != 0)
2506 		printf("     FRU CODE: 0x%x\n", sense->fru);
2507 	sbs = scsi_decode_sense(sense, DECODE_SKSV);
2508 	if (strlen(sbs) > 0)
2509 		printf("         SKSV: %s\n", sbs);
2510 }
2511 
2512 char *
2513 scsi_decode_sense(struct scsi_sense_data *sense, int flag)
2514 {
2515 	static char				rqsbuf[132];
2516 	u_int16_t				count;
2517 	u_int8_t				skey, spec_1;
2518 	int					len;
2519 
2520 	bzero(rqsbuf, sizeof(rqsbuf));
2521 
2522 	skey = sense->flags & SSD_KEY;
2523 	spec_1 = sense->sense_key_spec_1;
2524 	count = _2btol(&sense->sense_key_spec_2);
2525 
2526 	switch (flag) {
2527 	case DECODE_SENSE_KEY:
2528 		strlcpy(rqsbuf, sense_keys[skey], sizeof(rqsbuf));
2529 		break;
2530 	case DECODE_ASC_ASCQ:
2531 		asc2ascii(sense->add_sense_code, sense->add_sense_code_qual,
2532 		    rqsbuf, sizeof(rqsbuf));
2533 		break;
2534 	case DECODE_SKSV:
2535 		if (sense->extra_len < 9 || ((spec_1 & SSD_SCS_VALID) == 0))
2536 			break;
2537 		switch (skey) {
2538 		case SKEY_ILLEGAL_REQUEST:
2539 			len = snprintf(rqsbuf, sizeof rqsbuf,
2540 			    "Error in %s, Offset %d",
2541 			    (spec_1 & SSD_SCS_CDB_ERROR) ? "CDB" : "Parameters",
2542 			    count);
2543 			if ((len != -1 && len < sizeof rqsbuf) &&
2544 			    (spec_1 & SSD_SCS_VALID_BIT_INDEX))
2545 				snprintf(rqsbuf+len, sizeof rqsbuf - len,
2546 				    ", bit %d", spec_1 & SSD_SCS_BIT_INDEX);
2547 			break;
2548 		case SKEY_RECOVERED_ERROR:
2549 		case SKEY_MEDIUM_ERROR:
2550 		case SKEY_HARDWARE_ERROR:
2551 			snprintf(rqsbuf, sizeof rqsbuf,
2552 			    "Actual Retry Count: %d", count);
2553 			break;
2554 		case SKEY_NOT_READY:
2555 			snprintf(rqsbuf, sizeof rqsbuf,
2556 			    "Progress Indicator: %d", count);
2557 			break;
2558 		default:
2559 			break;
2560 		}
2561 		break;
2562 	default:
2563 		break;
2564 	}
2565 
2566 	return (rqsbuf);
2567 }
2568 
2569 #ifdef SCSIDEBUG
2570 /*
2571  * Given a scsi_xfer, dump the request, in all its glory
2572  */
2573 void
2574 scsi_xs_show(struct scsi_xfer *xs)
2575 {
2576 	u_char *b = (u_char *)xs->cmd;
2577 	int i = 0;
2578 
2579 	sc_print_addr(xs->sc_link);
2580 	printf("xs  (%p): ", xs);
2581 
2582 	printf("flg(0x%x)", xs->flags);
2583 	printf("sc_link(%p)", xs->sc_link);
2584 	printf("retr(0x%x)", xs->retries);
2585 	printf("timo(0x%x)", xs->timeout);
2586 	printf("data(%p)", xs->data);
2587 	printf("res(0x%x)", xs->resid);
2588 	printf("err(0x%x)", xs->error);
2589 	printf("bp(%p)\n", xs->bp);
2590 
2591 	sc_print_addr(xs->sc_link);
2592 	printf("cmd (%p): ", xs->cmd);
2593 
2594 	if ((xs->flags & SCSI_RESET) == 0) {
2595 		while (i < xs->cmdlen) {
2596 			if (i)
2597 				printf(",");
2598 			printf("%x", b[i++]);
2599 		}
2600 		printf("-[%d bytes]\n", xs->datalen);
2601 	} else
2602 		printf("-RESET-\n");
2603 }
2604 
2605 void
2606 scsi_show_mem(u_char *address, int num)
2607 {
2608 	int x;
2609 
2610 	printf("------------------------------");
2611 	for (x = 0; x < num; x++) {
2612 		if ((x % 16) == 0)
2613 			printf("\n%03d: ", x);
2614 		printf("%02x ", *address++);
2615 	}
2616 	printf("\n------------------------------\n");
2617 }
2618 #endif /* SCSIDEBUG */
2619 
2620 void
2621 scsi_cmd_rw_decode(struct scsi_generic *cmd, u_int64_t *blkno,
2622     u_int32_t *nblks)
2623 {
2624 	switch (cmd->opcode) {
2625 	case READ_COMMAND:
2626 	case WRITE_COMMAND: {
2627 		struct scsi_rw *rw = (struct scsi_rw *)cmd;
2628 		*blkno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
2629 		*nblks = rw->length ? rw->length : 0x100;
2630 		break;
2631 	}
2632 	case READ_BIG:
2633 	case WRITE_BIG: {
2634 		struct scsi_rw_big *rwb = (struct scsi_rw_big *)cmd;
2635 		*blkno = _4btol(rwb->addr);
2636 		*nblks = _2btol(rwb->length);
2637 		break;
2638 	}
2639 	case READ_12:
2640 	case WRITE_12: {
2641 		struct scsi_rw_12 *rw12 = (struct scsi_rw_12 *)cmd;
2642 		*blkno = _4btol(rw12->addr);
2643 		*nblks = _4btol(rw12->length);
2644 		break;
2645 	}
2646 	case READ_16:
2647 	case WRITE_16: {
2648 		struct scsi_rw_16 *rw16 = (struct scsi_rw_16 *)cmd;
2649 		*blkno = _8btol(rw16->addr);
2650 		*nblks = _4btol(rw16->length);
2651 		break;
2652 	}
2653 	default:
2654 		panic("scsi_cmd_rw_decode: bad opcode 0x%02x", cmd->opcode);
2655 	}
2656 }
2657