xref: /openbsd-src/sys/scsi/scsi_base.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: scsi_base.c,v 1.29 2001/06/22 14:35:42 deraadt 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/malloc.h>
45 #include <sys/errno.h>
46 #include <sys/device.h>
47 #include <sys/proc.h>
48 
49 #include <scsi/scsi_all.h>
50 #include <scsi/scsi_disk.h>
51 #include <scsi/scsiconf.h>
52 
53 LIST_HEAD(xs_free_list, scsi_xfer) xs_free_list;
54 
55 static __inline struct scsi_xfer *scsi_make_xs __P((struct scsi_link *,
56     struct scsi_generic *, int cmdlen, u_char *data_addr,
57     int datalen, int retries, int timeout, struct buf *, int flags));
58 static __inline void asc2ascii __P((u_char asc, u_char ascq, char *result));
59 int sc_err1 __P((struct scsi_xfer *, int));
60 int scsi_interpret_sense __P((struct scsi_xfer *));
61 char *scsi_decode_sense __P((void *, int));
62 
63 /*
64  * Get a scsi transfer structure for the caller. Charge the structure
65  * to the device that is referenced by the sc_link structure. If the
66  * sc_link structure has no 'credits' then the device already has the
67  * maximum number or outstanding operations under way. In this stage,
68  * wait on the structure so that when one is freed, we are awoken again
69  * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return
70  * a NULL pointer, signifying that no slots were available
71  * Note in the link structure, that we are waiting on it.
72  */
73 
74 struct scsi_xfer *
75 scsi_get_xs(sc_link, flags)
76 	struct scsi_link *sc_link;	/* who to charge the xs to */
77 	int flags;			/* if this call can sleep */
78 {
79 	struct scsi_xfer *xs;
80 	int s;
81 
82 	SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n"));
83 	s = splbio();
84 	while (sc_link->openings <= 0) {
85 		SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));
86 		if ((flags & SCSI_NOSLEEP) != 0) {
87 			splx(s);
88 			return 0;
89 		}
90 		sc_link->flags |= SDEV_WAITING;
91 		(void) tsleep(sc_link, PRIBIO, "getxs", 0);
92 	}
93 	sc_link->openings--;
94 	if ((xs = xs_free_list.lh_first) != NULL) {
95 		LIST_REMOVE(xs, free_list);
96 		splx(s);
97 	} else {
98 		splx(s);
99 		SC_DEBUG(sc_link, SDEV_DB3, ("making\n"));
100 		xs = malloc(sizeof(*xs), M_DEVBUF,
101 		    ((flags & SCSI_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));
102 		if (!xs) {
103 			sc_print_addr(sc_link);
104 			printf("cannot allocate scsi xs\n");
105 			return 0;
106 		}
107 	}
108 
109 	SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));
110 	xs->flags = INUSE | flags;
111 	return xs;
112 }
113 
114 /*
115  * Given a scsi_xfer struct, and a device (referenced through sc_link)
116  * return the struct to the free pool and credit the device with it
117  * If another process is waiting for an xs, do a wakeup, let it proceed
118  */
119 void
120 scsi_free_xs(xs, flags)
121 	struct scsi_xfer *xs;
122 	int flags;
123 {
124 	struct scsi_link *sc_link = xs->sc_link;
125 
126 	xs->flags &= ~INUSE;
127 	LIST_INSERT_HEAD(&xs_free_list, xs, free_list);
128 
129 	SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n"));
130 	/* if was 0 and someone waits, wake them up */
131 	sc_link->openings++;
132 	if ((sc_link->flags & SDEV_WAITING) != 0) {
133 		sc_link->flags &= ~SDEV_WAITING;
134 		wakeup(sc_link);
135 	} else {
136 		if (sc_link->device->start) {
137 			SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n"));
138 			(*(sc_link->device->start)) (sc_link->device_softc);
139 		}
140 	}
141 }
142 
143 /*
144  * Make a scsi_xfer, and return a pointer to it.
145  */
146 static __inline struct scsi_xfer *
147 scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
148     retries, timeout, bp, flags)
149 	struct scsi_link *sc_link;
150 	struct scsi_generic *scsi_cmd;
151 	int cmdlen;
152 	u_char *data_addr;
153 	int datalen;
154 	int retries;
155 	int timeout;
156 	struct buf *bp;
157 	int flags;
158 {
159 	struct scsi_xfer *xs;
160 
161 	if ((xs = scsi_get_xs(sc_link, flags)) == NULL)
162 		return NULL;
163 
164 	/*
165 	 * Fill out the scsi_xfer structure.  We don't know whose context
166 	 * the cmd is in, so copy it.
167 	 */
168 	xs->sc_link = sc_link;
169 	bcopy(scsi_cmd, &xs->cmdstore, cmdlen);
170 	xs->cmd = &xs->cmdstore;
171 	xs->cmdlen = cmdlen;
172 	xs->data = data_addr;
173 	xs->datalen = datalen;
174 	xs->retries = retries;
175 	xs->timeout = timeout;
176 	xs->bp = bp;
177 	xs->req_sense_length = 0;	/* XXX - not used by scsi internals */
178 
179 	/*
180 	 * Set the LUN in the CDB.  This may only be needed if we have an
181 	 * older device.  However, we also set it for more modern SCSI
182 	 * devices "just in case".  The old code assumed everything newer
183 	 * than SCSI-2 would not need it, but why risk it?  This was the
184 	 * old conditional:
185 	 *
186 	 * if ((sc_link->scsi_version & SID_ANSII) <= 2)
187 	 */
188 	xs->cmd->bytes[0] &= ~SCSI_CMD_LUN_MASK;
189 	xs->cmd->bytes[0] |=
190 	    ((sc_link->lun << SCSI_CMD_LUN_SHIFT) & SCSI_CMD_LUN_MASK);
191 
192 	return xs;
193 }
194 
195 /*
196  * Find out from the device what its capacity is.
197  */
198 u_long
199 scsi_size(sc_link, flags)
200 	struct scsi_link *sc_link;
201 	int flags;
202 {
203 	struct scsi_read_cap_data rdcap;
204 	struct scsi_read_capacity scsi_cmd;
205 
206 	/*
207 	 * make up a scsi command and ask the scsi driver to do
208 	 * it for you.
209 	 */
210 	bzero(&scsi_cmd, sizeof(scsi_cmd));
211 	scsi_cmd.opcode = READ_CAPACITY;
212 
213 	/*
214 	 * If the command works, interpret the result as a 4 byte
215 	 * number of blocks
216 	 */
217 	if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
218 			  sizeof(scsi_cmd), (u_char *)&rdcap, sizeof(rdcap),
219 			  2, 20000, NULL, flags | SCSI_DATA_IN) != 0) {
220 		sc_print_addr(sc_link);
221 		printf("could not get size\n");
222 		return 0;
223 	}
224 
225 	return _4btol(rdcap.addr) + 1;
226 }
227 
228 /*
229  * Get scsi driver to send a "are you ready?" command
230  */
231 int
232 scsi_test_unit_ready(sc_link, flags)
233 	struct scsi_link *sc_link;
234 	int flags;
235 {
236 	struct scsi_test_unit_ready scsi_cmd;
237 
238 	bzero(&scsi_cmd, sizeof(scsi_cmd));
239 	scsi_cmd.opcode = TEST_UNIT_READY;
240 
241 	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,
242 	    sizeof(scsi_cmd), 0, 0, 5, 10000, NULL, flags);
243 }
244 
245 /*
246  * Do a scsi operation, asking a device to run as SCSI-II if it can.
247  */
248 int
249 scsi_change_def(sc_link, flags)
250 	struct scsi_link *sc_link;
251 	int flags;
252 {
253 	struct scsi_changedef scsi_cmd;
254 
255 	bzero(&scsi_cmd, sizeof(scsi_cmd));
256 	scsi_cmd.opcode = CHANGE_DEFINITION;
257 	scsi_cmd.how = SC_SCSI_2;
258 
259 	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,
260 	    sizeof(scsi_cmd), 0, 0, 2, 100000, NULL, flags);
261 }
262 
263 /*
264  * Do a scsi operation asking a device what it is
265  * Use the scsi_cmd routine in the switch table.
266  */
267 int
268 scsi_inquire(sc_link, inqbuf, flags)
269 	struct scsi_link *sc_link;
270 	struct scsi_inquiry_data *inqbuf;
271 	int flags;
272 {
273 	struct scsi_inquiry scsi_cmd;
274 
275 	bzero(&scsi_cmd, sizeof(scsi_cmd));
276 	scsi_cmd.opcode = INQUIRY;
277 	scsi_cmd.length = sizeof(struct scsi_inquiry_data);
278 
279 	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,
280 	    sizeof(scsi_cmd), (u_char *) inqbuf,
281 	    sizeof(struct scsi_inquiry_data), 2, 10000, NULL,
282 	    SCSI_DATA_IN | flags);
283 }
284 
285 /*
286  * Prevent or allow the user to remove the media
287  */
288 int
289 scsi_prevent(sc_link, type, flags)
290 	struct scsi_link *sc_link;
291 	int type, flags;
292 {
293 	struct scsi_prevent scsi_cmd;
294 
295 	bzero(&scsi_cmd, sizeof(scsi_cmd));
296 	scsi_cmd.opcode = PREVENT_ALLOW;
297 	scsi_cmd.how = type;
298 	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,
299 	    sizeof(scsi_cmd), 0, 0, 2, 5000, NULL, flags);
300 }
301 
302 /*
303  * Get scsi driver to send a "start up" command
304  */
305 int
306 scsi_start(sc_link, type, flags)
307 	struct scsi_link *sc_link;
308 	int type, flags;
309 {
310 	struct scsi_start_stop scsi_cmd;
311 
312 	if ((sc_link->quirks & SDEV_NOSTARTUNIT) == SDEV_NOSTARTUNIT)
313 		return 0;
314 
315 	bzero(&scsi_cmd, sizeof(scsi_cmd));
316 	scsi_cmd.opcode = START_STOP;
317 	scsi_cmd.byte2 = 0x00;
318 	scsi_cmd.how = type;
319 	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,
320 	    sizeof(scsi_cmd), 0, 0, 2,
321 	    type == SSS_START ? 30000 : 10000, NULL, flags);
322 }
323 
324 /*
325  * This routine is called by the scsi interrupt when the transfer is complete.
326  */
327 void
328 scsi_done(xs)
329 	struct scsi_xfer *xs;
330 {
331 	struct scsi_link *sc_link = xs->sc_link;
332 	struct buf *bp;
333 	int error;
334 
335 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n"));
336 #ifdef	SCSIDEBUG
337 	if ((sc_link->flags & SDEV_DB1) != 0)
338 		show_scsi_cmd(xs);
339 #endif /* SCSIDEBUG */
340 
341 	/*
342  	 * If it's a user level request, bypass all usual completion processing,
343  	 * let the user work it out.. We take reponsibility for freeing the
344  	 * xs when the user returns. (and restarting the device's queue).
345  	 */
346 	if ((xs->flags & SCSI_USER) != 0) {
347 		SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));
348 		scsi_user_done(xs); /* to take a copy of the sense etc. */
349 		SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n "));
350 
351 		scsi_free_xs(xs, SCSI_NOSLEEP); /* restarts queue too */
352 		SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));
353 		return;
354 	}
355 
356 	if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) {
357 		/*
358 		 * if it's a normal upper level request, then ask
359 		 * the upper level code to handle error checking
360 		 * rather than doing it here at interrupt time
361 		 */
362 		wakeup(xs);
363 		return;
364 	}
365 
366 	/*
367 	 * Go and handle errors now.
368 	 * If it returns ERESTART then we should RETRY
369 	 */
370 retry:
371 	error = sc_err1(xs, 1);
372 	if (error == ERESTART) {
373 		switch ((*(sc_link->adapter->scsi_cmd)) (xs)) {
374 		case SUCCESSFULLY_QUEUED:
375 			return;
376 
377 		case TRY_AGAIN_LATER:
378 			xs->error = XS_BUSY;
379 		case COMPLETE:
380 			goto retry;
381 		}
382 	}
383 
384 	bp = xs->bp;
385 	if (bp) {
386 		if (error) {
387 			bp->b_error = error;
388 			bp->b_flags |= B_ERROR;
389 			bp->b_resid = bp->b_bcount;
390 		} else {
391 			bp->b_error = 0;
392 			bp->b_resid = xs->resid;
393 		}
394 	}
395 	if (sc_link->device->done) {
396 		/*
397 		 * Tell the device the operation is actually complete.
398 		 * No more will happen with this xfer.  This for
399 		 * notification of the upper-level driver only; they
400 		 * won't be returning any meaningful information to us.
401 		 */
402 		(*sc_link->device->done)(xs);
403 	}
404 	scsi_free_xs(xs, SCSI_NOSLEEP);
405 	if (bp)
406 		biodone(bp);
407 }
408 
409 int
410 scsi_execute_xs(xs)
411 	struct scsi_xfer *xs;
412 {
413 	int error;
414 	int s;
415 
416 	xs->flags &= ~ITSDONE;
417 	xs->error = XS_NOERROR;
418 	xs->resid = xs->datalen;
419 	xs->status = 0;
420 
421 retry:
422 	/*
423 	 * Do the transfer. If we are polling we will return:
424 	 * COMPLETE,  Was poll, and scsi_done has been called
425 	 * TRY_AGAIN_LATER, Adapter short resources, try again
426 	 *
427 	 * if under full steam (interrupts) it will return:
428 	 * SUCCESSFULLY_QUEUED, will do a wakeup when complete
429 	 * TRY_AGAIN_LATER, (as for polling)
430 	 * After the wakeup, we must still check if it succeeded
431 	 *
432 	 * If we have a SCSI_NOSLEEP (typically because we have a buf)
433 	 * we just return.  All the error proccessing and the buffer
434 	 * code both expect us to return straight to them, so as soon
435 	 * as the command is queued, return.
436 	 */
437 	switch ((*(xs->sc_link->adapter->scsi_cmd)) (xs)) {
438 	case SUCCESSFULLY_QUEUED:
439 		if ((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)
440 			return EJUSTRETURN;
441 #ifdef DIAGNOSTIC
442 		if (xs->flags & SCSI_NOSLEEP)
443 			panic("scsi_execute_xs: NOSLEEP and POLL");
444 #endif
445 		s = splbio();
446 		while ((xs->flags & ITSDONE) == 0)
447 			tsleep(xs, PRIBIO + 1, "scsi_scsi_cmd", 0);
448 		splx(s);
449 	case COMPLETE:		/* Polling command completed ok */
450 		if (xs->bp)
451 			return EJUSTRETURN;
452 	doit:
453 		SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n"));
454 		if ((error = sc_err1(xs, 0)) != ERESTART)
455 			return error;
456 		goto retry;
457 
458 	case TRY_AGAIN_LATER:	/* adapter resource shortage */
459 		xs->error = XS_BUSY;
460 		goto doit;
461 
462 	default:
463 		panic("scsi_execute_xs: invalid return code");
464 	}
465 
466 #ifdef DIAGNOSTIC
467 	panic("scsi_execute_xs: impossible");
468 #endif
469 	return EINVAL;
470 }
471 
472 /*
473  * ask the scsi driver to perform a command for us.
474  * tell it where to read/write the data, and how
475  * long the data is supposed to be. If we have  a buf
476  * to associate with the transfer, we need that too.
477  */
478 int
479 scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
480     retries, timeout, bp, flags)
481 	struct scsi_link *sc_link;
482 	struct scsi_generic *scsi_cmd;
483 	int cmdlen;
484 	u_char *data_addr;
485 	int datalen;
486 	int retries;
487 	int timeout;
488 	struct buf *bp;
489 	int flags;
490 {
491 	struct scsi_xfer *xs;
492 	int error;
493 
494 	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n"));
495 
496 #ifdef DIAGNOSTIC
497 	if (bp != 0 && (flags & SCSI_NOSLEEP) == 0)
498 		panic("scsi_scsi_cmd: buffer without nosleep");
499 #endif
500 
501 	if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
502 	    retries, timeout, bp, flags)) == NULL)
503 		return ENOMEM;
504 
505 	if ((error = scsi_execute_xs(xs)) == EJUSTRETURN)
506 		return 0;
507 
508 	/*
509 	 * we have finished with the xfer stuct, free it and
510 	 * check if anyone else needs to be started up.
511 	 */
512 	scsi_free_xs(xs, flags);
513 	return error;
514 }
515 
516 int
517 sc_err1(xs, async)
518 	struct scsi_xfer *xs;
519 	int async;
520 {
521 	int error;
522 
523 	SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error));
524 
525 	/*
526 	 * If it has a buf, we might be working with
527 	 * a request from the buffer cache or some other
528 	 * piece of code that requires us to process
529 	 * errors at interrupt time. We have probably
530 	 * been called by scsi_done()
531 	 */
532 	switch (xs->error) {
533 	case XS_NOERROR:	/* nearly always hit this one */
534 		error = 0;
535 		break;
536 
537 	case XS_SENSE:
538 	case XS_SHORTSENSE:
539 		if ((error = scsi_interpret_sense(xs)) == ERESTART) {
540 			if (xs->error == XS_BUSY) {
541 				xs->error = XS_SENSE;
542 				goto sense_retry;
543 			}
544 			goto retry;
545 		}
546 		SC_DEBUG(xs->sc_link, SDEV_DB3,
547 		    ("scsi_interpret_sense returned %d\n", error));
548 		break;
549 
550 	case XS_BUSY:
551 	sense_retry:
552 		if (xs->retries) {
553 			if ((xs->flags & SCSI_POLL) != 0)
554 				delay(1000000);
555 			else if ((xs->flags & SCSI_NOSLEEP) == 0) {
556 				tsleep(&lbolt, PRIBIO, "scbusy", 0);
557 			} else
558 #if 0
559 				timeout(scsi_requeue, xs, hz);
560 #else
561 				goto lose;
562 #endif
563 		}
564 	case XS_TIMEOUT:
565 	retry:
566 		if (xs->retries--) {
567 			xs->error = XS_NOERROR;
568 			xs->flags &= ~ITSDONE;
569 			return ERESTART;
570 		}
571 	case XS_DRIVER_STUFFUP:
572 	lose:
573 		error = EIO;
574 		break;
575 
576 	case XS_SELTIMEOUT:
577 		/* XXX Disable device? */
578 		error = EIO;
579 		break;
580 
581 	case XS_RESET:
582 		if (xs->retries) {
583 			SC_DEBUG(xs->sc_link, SDEV_DB3,
584 			    ("restarting command destroyed by reset\n"));
585 			goto retry;
586 		}
587 		error = EIO;
588 		break;
589 
590 	default:
591 		sc_print_addr(xs->sc_link);
592 		printf("unknown error category from scsi driver\n");
593 		error = EIO;
594 		break;
595 	}
596 
597 	return error;
598 }
599 
600 /*
601  * Look at the returned sense and act on the error, determining
602  * the unix error number to pass back.  (0 = report no error)
603  *
604  * THIS IS THE DEFAULT ERROR HANDLER
605  */
606 int
607 scsi_interpret_sense(xs)
608 	struct scsi_xfer *xs;
609 {
610 	struct scsi_sense_data *sense;
611 	struct scsi_link *sc_link = xs->sc_link;
612 	u_int8_t key;
613 	u_int32_t info;
614 	int error;
615 
616 	sense = &xs->sense;
617 #ifdef	SCSIDEBUG
618 	if ((sc_link->flags & SDEV_DB1) != 0) {
619 		int count;
620 		printf("code%x valid%x ",
621 		    sense->error_code & SSD_ERRCODE,
622 		    sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
623 		printf("seg%x key%x ili%x eom%x fmark%x\n",
624 		    sense->segment,
625 		    sense->flags & SSD_KEY,
626 		    sense->flags & SSD_ILI ? 1 : 0,
627 		    sense->flags & SSD_EOM ? 1 : 0,
628 		    sense->flags & SSD_FILEMARK ? 1 : 0);
629 		printf("info: %x %x %x %x followed by %d extra bytes\n",
630 		    sense->info[0],
631 		    sense->info[1],
632 		    sense->info[2],
633 		    sense->info[3],
634 		    sense->extra_len);
635 		printf("extra: ");
636 		for (count = 0; count < sense->extra_len; count++)
637 			printf("%x ", sense->cmd_spec_info[count]);
638 		printf("\n");
639 	}
640 #endif	/* SCSIDEBUG */
641 	/*
642 	 * If the device has it's own error handler, call it first.
643 	 * If it returns a legit error value, return that, otherwise
644 	 * it wants us to continue with normal error processing.
645 	 */
646 	if (sc_link->device->err_handler) {
647 		SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n"));
648 		error = (*sc_link->device->err_handler) (xs);
649 		if (error != SCSIRET_CONTINUE)
650 			return error;		/* error >= 0  better ? */
651 	}
652 	/* otherwise use the default */
653 	switch (sense->error_code & SSD_ERRCODE) {
654 		/*
655 		 * If it's code 70, use the extended stuff and interpret the key
656 		 */
657 	case 0x71:		/* delayed error */
658 		sc_print_addr(sc_link);
659 		key = sense->flags & SSD_KEY;
660 		printf(" DEFERRED ERROR, key = 0x%x\n", key);
661 		/* FALLTHROUGH */
662 	case 0x70:
663 		if ((sense->error_code & SSD_ERRCODE_VALID) != 0)
664 			info = _4btol(sense->info);
665 		else
666 			info = 0;
667 		key = sense->flags & SSD_KEY;
668 
669 		switch (key) {
670 		case SKEY_NO_SENSE:
671 		case SKEY_RECOVERED_ERROR:
672 			if (xs->resid == xs->datalen)
673 				xs->resid = 0;	/* not short read */
674 		case SKEY_EQUAL:
675 			error = 0;
676 			break;
677 		case SKEY_NOT_READY:
678 			if ((sc_link->flags & SDEV_REMOVABLE) != 0)
679 				sc_link->flags &= ~SDEV_MEDIA_LOADED;
680 			if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
681 				return 0;
682 			if (xs->retries && sense->add_sense_code == 0x04 &&
683 			    sense->add_sense_code_qual == 0x01) {
684 				xs->error = XS_BUSY;	/* ie. sense_retry */
685 				return ERESTART;
686 			}
687 			if (xs->retries && !(sc_link->flags & SDEV_REMOVABLE)) {
688 				delay(1000000);
689 				return ERESTART;
690 			}
691 			if ((xs->flags & SCSI_SILENT) != 0)
692 				return EIO;
693 			error = EIO;
694 			break;
695 		case SKEY_ILLEGAL_REQUEST:
696 			if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0)
697 				return 0;
698 			if ((xs->flags & SCSI_SILENT) != 0)
699 				return EIO;
700 			error = EINVAL;
701 			break;
702 		case SKEY_UNIT_ATTENTION:
703 			if (sense->add_sense_code == 0x29 &&
704 			    sense->add_sense_code_qual == 0x00)
705 				return (ERESTART); /* device or bus reset */
706 			if ((sc_link->flags & SDEV_REMOVABLE) != 0)
707 				sc_link->flags &= ~SDEV_MEDIA_LOADED;
708 			if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 ||
709 			    /* XXX Should reupload any transient state. */
710 			    (sc_link->flags & SDEV_REMOVABLE) == 0)
711 				return ERESTART;
712 			if ((xs->flags & SCSI_SILENT) != 0)
713 				return EIO;
714 			error = EIO;
715 			break;
716 		case SKEY_WRITE_PROTECT:
717 			error = EROFS;
718 			break;
719 		case SKEY_BLANK_CHECK:
720 			error = 0;
721 			break;
722 		case SKEY_ABORTED_COMMAND:
723 			error = ERESTART;
724 			break;
725 		case SKEY_VOLUME_OVERFLOW:
726 			error = ENOSPC;
727 			break;
728 		default:
729 			error = EIO;
730 			break;
731 		}
732 
733 		if ((xs->flags & SCSI_SILENT) == 0)
734 			scsi_print_sense(xs, 0);
735 
736 		return error;
737 
738 	/*
739 	 * Not code 70, just report it
740 	 */
741 	default:
742 		sc_print_addr(sc_link);
743 		printf("Sense Error Code %d",
744 		    sense->error_code & SSD_ERRCODE);
745 		if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
746 			struct scsi_sense_data_unextended *usense =
747 			    (struct scsi_sense_data_unextended *)sense;
748 			printf(" at block no. %d (decimal)",
749 			    _3btol(usense->block));
750 		}
751 		printf("\n");
752 		return EIO;
753 	}
754 }
755 
756 /*
757  * Utility routines often used in SCSI stuff
758  */
759 
760 
761 /*
762  * Print out the scsi_link structure's address info.
763  */
764 void
765 sc_print_addr(sc_link)
766 	struct scsi_link *sc_link;
767 {
768 
769 	printf("%s(%s:%d:%d): ",
770 	    sc_link->device_softc ?
771 	    ((struct device *)sc_link->device_softc)->dv_xname : "probe",
772 	    ((struct device *)sc_link->adapter_softc)->dv_xname,
773 	    sc_link->target, sc_link->lun);
774 }
775 
776 static const char *sense_keys[16] = {
777 	"No Additional Sense",
778 	"Soft Error",
779 	"Not Ready",
780 	"Media Error",
781 	"Hardware Error",
782 	"Illegal Request",
783 	"Unit Attention",
784 	"Write Protected",
785 	"Blank Check",
786 	"Vendor Unique",
787 	"Copy Aborted",
788 	"Aborted Command",
789 	"Equal Error",
790 	"Volume Overflow",
791 	"Miscompare Error",
792 	"Reserved"
793 };
794 #ifndef SCSITERSE
795 static const struct {
796 	u_char asc, ascq;
797 	char *description;
798 } adesc[] = {
799 	{ 0x00, 0x00, "No Additional Sense Information" },
800 	{ 0x00, 0x01, "Filemark Detected" },
801 	{ 0x00, 0x02, "End-Of-Partition/Medium Detected" },
802 	{ 0x00, 0x03, "Setmark Detected" },
803 	{ 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" },
804 	{ 0x00, 0x05, "End-Of-Data Detected" },
805 	{ 0x00, 0x06, "I/O Process Terminated" },
806 	{ 0x00, 0x11, "Audio Play Operation In Progress" },
807 	{ 0x00, 0x12, "Audio Play Operation Paused" },
808 	{ 0x00, 0x13, "Audio Play Operation Successfully Completed" },
809 	{ 0x00, 0x14, "Audio Play Operation Stopped Due to Error" },
810 	{ 0x00, 0x15, "No Current Audio Status To Return" },
811 	{ 0x01, 0x00, "No Index/Sector Signal" },
812 	{ 0x02, 0x00, "No Seek Complete" },
813 	{ 0x03, 0x00, "Peripheral Device Write Fault" },
814 	{ 0x03, 0x01, "No Write Current" },
815 	{ 0x03, 0x02, "Excessive Write Errors" },
816 	{ 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" },
817 	{ 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" },
818 	{ 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" },
819 	{ 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" },
820 	{ 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" },
821 	{ 0x05, 0x00, "Logical Unit Does Not Respond To Selection" },
822 	{ 0x06, 0x00, "No Reference Position Found" },
823 	{ 0x07, 0x00, "Multiple Peripheral Devices Selected" },
824 	{ 0x08, 0x00, "Logical Unit Communication Failure" },
825 	{ 0x08, 0x01, "Logical Unit Communication Timeout" },
826 	{ 0x08, 0x02, "Logical Unit Communication Parity Error" },
827 	{ 0x09, 0x00, "Track Following Error" },
828 	{ 0x09, 0x01, "Tracking Servo Failure" },
829 	{ 0x09, 0x02, "Focus Servo Failure" },
830 	{ 0x09, 0x03, "Spindle Servo Failure" },
831 	{ 0x0A, 0x00, "Error Log Overflow" },
832 	{ 0x0C, 0x00, "Write Error" },
833 	{ 0x0C, 0x01, "Write Error Recovered with Auto Reallocation" },
834 	{ 0x0C, 0x02, "Write Error - Auto Reallocate Failed" },
835 	{ 0x10, 0x00, "ID CRC Or ECC Error" },
836 	{ 0x11, 0x00, "Unrecovered Read Error" },
837 	{ 0x11, 0x01, "Read Retried Exhausted" },
838 	{ 0x11, 0x02, "Error Too Long To Correct" },
839 	{ 0x11, 0x03, "Multiple Read Errors" },
840 	{ 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" },
841 	{ 0x11, 0x05, "L-EC Uncorrectable Error" },
842 	{ 0x11, 0x06, "CIRC Unrecovered Error" },
843 	{ 0x11, 0x07, "Data Resynchronization Error" },
844 	{ 0x11, 0x08, "Incomplete Block Found" },
845 	{ 0x11, 0x09, "No Gap Found" },
846 	{ 0x11, 0x0A, "Miscorrected Error" },
847 	{ 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" },
848 	{ 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite the Data" },
849 	{ 0x12, 0x00, "Address Mark Not Found for ID Field" },
850 	{ 0x13, 0x00, "Address Mark Not Found for Data Field" },
851 	{ 0x14, 0x00, "Recorded Entity Not Found" },
852 	{ 0x14, 0x01, "Record Not Found" },
853 	{ 0x14, 0x02, "Filemark or Setmark Not Found" },
854 	{ 0x14, 0x03, "End-Of-Data Not Found" },
855 	{ 0x14, 0x04, "Block Sequence Error" },
856 	{ 0x15, 0x00, "Random Positioning Error" },
857 	{ 0x15, 0x01, "Mechanical Positioning Error" },
858 	{ 0x15, 0x02, "Positioning Error Detected By Read of Medium" },
859 	{ 0x16, 0x00, "Data Synchronization Mark Error" },
860 	{ 0x17, 0x00, "Recovered Data With No Error Correction Applied" },
861 	{ 0x17, 0x01, "Recovered Data With Retries" },
862 	{ 0x17, 0x02, "Recovered Data With Positive Head Offset" },
863 	{ 0x17, 0x03, "Recovered Data With Negative Head Offset" },
864 	{ 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" },
865 	{ 0x17, 0x05, "Recovered Data Using Previous Sector ID" },
866 	{ 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" },
867 	{ 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" },
868 	{ 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" },
869 	{ 0x18, 0x00, "Recovered Data With Error Correction Applied" },
870 	{ 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" },
871 	{ 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" },
872 	{ 0x18, 0x03, "Recovered Data With CIRC" },
873 	{ 0x18, 0x04, "Recovered Data With LEC" },
874 	{ 0x18, 0x05, "Recovered Data - Recommend Reassignment" },
875 	{ 0x18, 0x06, "Recovered Data - Recommend Rewrite" },
876 	{ 0x19, 0x00, "Defect List Error" },
877 	{ 0x19, 0x01, "Defect List Not Available" },
878 	{ 0x19, 0x02, "Defect List Error in Primary List" },
879 	{ 0x19, 0x03, "Defect List Error in Grown List" },
880 	{ 0x1A, 0x00, "Parameter List Length Error" },
881 	{ 0x1B, 0x00, "Synchronous Data Transfer Error" },
882 	{ 0x1C, 0x00, "Defect List Not Found" },
883 	{ 0x1C, 0x01, "Primary Defect List Not Found" },
884 	{ 0x1C, 0x02, "Grown Defect List Not Found" },
885 	{ 0x1D, 0x00, "Miscompare During Verify Operation" },
886 	{ 0x1E, 0x00, "Recovered ID with ECC" },
887 	{ 0x20, 0x00, "Invalid Command Operation Code" },
888 	{ 0x21, 0x00, "Logical Block Address Out of Range" },
889 	{ 0x21, 0x01, "Invalid Element Address" },
890 	{ 0x22, 0x00, "Illegal Function (Should 20 00, 24 00, or 26 00)" },
891 	{ 0x24, 0x00, "Illegal Field in CDB" },
892 	{ 0x25, 0x00, "Logical Unit Not Supported" },
893 	{ 0x26, 0x00, "Invalid Field In Parameter List" },
894 	{ 0x26, 0x01, "Parameter Not Supported" },
895 	{ 0x26, 0x02, "Parameter Value Invalid" },
896 	{ 0x26, 0x03, "Threshold Parameters Not Supported" },
897 	{ 0x27, 0x00, "Write Protected" },
898 	{ 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" },
899 	{ 0x28, 0x01, "Import Or Export Element Accessed" },
900 	{ 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" },
901 	{ 0x2A, 0x00, "Parameters Changed" },
902 	{ 0x2A, 0x01, "Mode Parameters Changed" },
903 	{ 0x2A, 0x02, "Log Parameters Changed" },
904 	{ 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" },
905 	{ 0x2C, 0x00, "Command Sequence Error" },
906 	{ 0x2C, 0x01, "Too Many Windows Specified" },
907 	{ 0x2C, 0x02, "Invalid Combination of Windows Specified" },
908 	{ 0x2D, 0x00, "Overwrite Error On Update In Place" },
909 	{ 0x2F, 0x00, "Commands Cleared By Another Initiator" },
910 	{ 0x30, 0x00, "Incompatible Medium Installed" },
911 	{ 0x30, 0x01, "Cannot Read Medium - Unknown Format" },
912 	{ 0x30, 0x02, "Cannot Read Medium - Incompatible Format" },
913 	{ 0x30, 0x03, "Cleaning Cartridge Installed" },
914 	{ 0x31, 0x00, "Medium Format Corrupted" },
915 	{ 0x31, 0x01, "Format Command Failed" },
916 	{ 0x32, 0x00, "No Defect Spare Location Available" },
917 	{ 0x32, 0x01, "Defect List Update Failure" },
918 	{ 0x33, 0x00, "Tape Length Error" },
919 	{ 0x36, 0x00, "Ribbon, Ink, or Toner Failure" },
920 	{ 0x37, 0x00, "Rounded Parameter" },
921 	{ 0x39, 0x00, "Saving Parameters Not Supported" },
922 	{ 0x3A, 0x00, "Medium Not Present" },
923 	{ 0x3B, 0x00, "Positioning Error" },
924 	{ 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" },
925 	{ 0x3B, 0x02, "Tape Position Error At End-of-Medium" },
926 	{ 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" },
927 	{ 0x3B, 0x04, "Slew Failure" },
928 	{ 0x3B, 0x05, "Paper Jam" },
929 	{ 0x3B, 0x06, "Failed To Sense Top-Of-Form" },
930 	{ 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" },
931 	{ 0x3B, 0x08, "Reposition Error" },
932 	{ 0x3B, 0x09, "Read Past End Of Medium" },
933 	{ 0x3B, 0x0A, "Read Past Begining Of Medium" },
934 	{ 0x3B, 0x0B, "Position Past End Of Medium" },
935 	{ 0x3B, 0x0C, "Position Past Beginning Of Medium" },
936 	{ 0x3B, 0x0D, "Medium Destination Element Full" },
937 	{ 0x3B, 0x0E, "Medium Source Element Empty" },
938 	{ 0x3D, 0x00, "Invalid Bits In IDENTFY Message" },
939 	{ 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" },
940 	{ 0x3F, 0x00, "Target Operating Conditions Have Changed" },
941 	{ 0x3F, 0x01, "Microcode Has Changed" },
942 	{ 0x3F, 0x02, "Changed Operating Definition" },
943 	{ 0x3F, 0x03, "INQUIRY Data Has Changed" },
944 	{ 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" },
945 	{ 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" },
946 	{ 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" },
947 	{ 0x43, 0x00, "Message Error" },
948 	{ 0x44, 0x00, "Internal Target Failure" },
949 	{ 0x45, 0x00, "Select Or Reselect Failure" },
950 	{ 0x46, 0x00, "Unsuccessful Soft Reset" },
951 	{ 0x47, 0x00, "SCSI Parity Error" },
952 	{ 0x48, 0x00, "INITIATOR DETECTED ERROR Message Received" },
953 	{ 0x49, 0x00, "Invalid Message Error" },
954 	{ 0x4A, 0x00, "Command Phase Error" },
955 	{ 0x4B, 0x00, "Data Phase Error" },
956 	{ 0x4C, 0x00, "Logical Unit Failed Self-Configuration" },
957 	{ 0x4E, 0x00, "Overlapped Commands Attempted" },
958 	{ 0x50, 0x00, "Write Append Error" },
959 	{ 0x50, 0x01, "Write Append Position Error" },
960 	{ 0x50, 0x02, "Position Error Related To Timing" },
961 	{ 0x51, 0x00, "Erase Failure" },
962 	{ 0x52, 0x00, "Cartridge Fault" },
963 	{ 0x53, 0x00, "Media Load or Eject Failed" },
964 	{ 0x53, 0x01, "Unload Tape Failure" },
965 	{ 0x53, 0x02, "Medium Removal Prevented" },
966 	{ 0x54, 0x00, "SCSI To Host System Interface Failure" },
967 	{ 0x55, 0x00, "System Resource Failure" },
968 	{ 0x57, 0x00, "Unable To Recover Table-Of-Contents" },
969 	{ 0x58, 0x00, "Generation Does Not Exist" },
970 	{ 0x59, 0x00, "Updated Block Read" },
971 	{ 0x5A, 0x00, "Operator Request or State Change Input (Unspecified)" },
972 	{ 0x5A, 0x01, "Operator Medium Removal Requested" },
973 	{ 0x5A, 0x02, "Operator Selected Write Protect" },
974 	{ 0x5A, 0x03, "Operator Selected Write Permit" },
975 	{ 0x5B, 0x00, "Log Exception" },
976 	{ 0x5B, 0x01, "Threshold Condition Met" },
977 	{ 0x5B, 0x02, "Log Counter At Maximum" },
978 	{ 0x5B, 0x03, "Log List Codes Exhausted" },
979 	{ 0x5C, 0x00, "RPL Status Change" },
980 	{ 0x5C, 0x01, "Spindles Synchronized" },
981 	{ 0x5C, 0x02, "Spindles Not Synchronized" },
982 	{ 0x60, 0x00, "Lamp Failure" },
983 	{ 0x61, 0x00, "Video Acquisition Error" },
984 	{ 0x61, 0x01, "Unable To Acquire Video" },
985 	{ 0x61, 0x02, "Out Of Focus" },
986 	{ 0x62, 0x00, "Scan Head Positioning Error" },
987 	{ 0x63, 0x00, "End Of User Area Encountered On This Track" },
988 	{ 0x64, 0x00, "Illegal Mode For This Track" },
989 	{ 0x00, 0x00, NULL }
990 };
991 
992 static __inline void
993 asc2ascii(asc, ascq, result)
994 	u_char asc, ascq;
995 	char *result;
996 {
997 	register int i = 0;
998 
999 	while (adesc[i].description != NULL) {
1000 		if (adesc[i].asc == asc && adesc[i].ascq == ascq)
1001 			break;
1002 		i++;
1003 	}
1004 	if (adesc[i].description == NULL) {
1005 		if (asc == 0x40 && ascq != 0) {
1006 			(void) sprintf(result,
1007 			    "Diagnostic Failure on Component 0x%02x",
1008 			    ascq & 0xff);
1009 		} else {
1010 			(void) sprintf(result, "ASC 0x%02x ASCQ 0x%02x",
1011 			    asc & 0xff, ascq & 0xff);
1012 		}
1013 	} else {
1014 		(void) strcpy(result, adesc[i].description);
1015 	}
1016 }
1017 
1018 #else
1019 
1020 static __inline void
1021 asc2ascii(asc, ascq, result)
1022 	u_char asc, ascq;
1023 	char *result;
1024 {
1025 	(void) sprintf(result, "ASC 0x%02x ASCQ 0x%02x", asc & 0xff,
1026 	    ascq & 0xff);
1027 }
1028 #endif /* SCSITERSE */
1029 
1030 void
1031 scsi_print_sense(xs, verbosity)
1032 	struct scsi_xfer *xs;
1033 	int verbosity;
1034 {
1035 	int32_t info;
1036 	register int i, j, k;
1037 	char *sbs, *s;
1038 
1039 	sc_print_addr(xs->sc_link);
1040 	s = (char *) &xs->sense;
1041 	printf("Check Condition on opcode 0x%x\n", xs->cmd->opcode);
1042 
1043 	/*
1044 	 * Basics- print out SENSE KEY
1045 	 */
1046 	printf("    SENSE KEY: %s\n", scsi_decode_sense(s, 0));
1047 
1048 	/*
1049  	 * Print out, unqualified but aligned, FMK, EOM and ILI status.
1050 	 */
1051 	if (s[2] & 0xe0) {
1052 		char pad = ' ';
1053 
1054 		printf("             ");
1055 		if (s[2] & SSD_FILEMARK) {
1056 			printf("%c Filemark Detected", pad);
1057 			pad = ',';
1058 		}
1059 		if (s[2] & SSD_EOM) {
1060 			printf("%c EOM Detected", pad);
1061 			pad = ',';
1062 		}
1063 		if (s[2] & SSD_ILI)
1064 			printf("%c Incorrect Length Indicator Set", pad);
1065 		printf("\n");
1066 	}
1067 	/*
1068 	 * Now we should figure out, based upon device type, how
1069 	 * to format the information field. Unfortunately, that's
1070 	 * not convenient here, so we'll print it as a signed
1071 	 * 32 bit integer.
1072 	 */
1073 	info = _4btol(&s[3]);
1074 	if (info)
1075 		printf("   INFO FIELD: %u\n", info);
1076 
1077 	/*
1078 	 * Now we check additional length to see whether there is
1079 	 * more information to extract.
1080 	 */
1081 
1082 	/* enough for command specific information? */
1083 	if (s[7] < 4)
1084 		return;
1085 	info = _4btol(&s[8]);
1086 	if (info)
1087 		printf(" COMMAND INFO: %d (0x%x)\n", info, info);
1088 
1089 	/*
1090 	 * Decode ASC && ASCQ info, plus FRU, plus the rest...
1091 	 */
1092 
1093 	sbs = scsi_decode_sense(s, 1);
1094 	if (sbs)
1095 		printf("     ASC/ASCQ: %s\n", sbs);
1096 	if (s[14] != 0)
1097 		printf("     FRU CODE: 0x%x\n", s[14] & 0xff);
1098 	sbs = scsi_decode_sense(s, 3);
1099 	if (sbs)
1100 		printf("         SKSV: %s\n", sbs);
1101 	if (verbosity == 0)
1102 		return;
1103 
1104 	/*
1105 	 * Now figure whether we should print any additional informtion.
1106 	 *
1107 	 * Where should we start from? If we had SKSV data,
1108 	 * start from offset 18, else from offset 15.
1109 	 *
1110 	 * From that point until the end of the buffer, check for any
1111 	 * nonzero data. If we have some, go back and print the lot,
1112 	 * otherwise we're done.
1113 	 */
1114 	if (sbs)
1115 		i = 18;
1116 	else
1117 		i = 15;
1118 
1119 	for (j = i; j < sizeof (xs->sense); j++)
1120 		if (s[j])
1121 			break;
1122 	if (j == sizeof (xs->sense))
1123 		return;
1124 
1125 	printf(" Additional Sense Information (byte %d out...):\n", i);
1126 	if (i == 15) {
1127 		printf("        %2d:", i);
1128 		k = 7;
1129 	} else {
1130 		printf("        %2d:", i);
1131 		k = 2;
1132 		j -= 2;
1133 	}
1134 	while (j > 0) {
1135 		if (i >= sizeof (xs->sense))
1136 			break;
1137 		if (k == 8) {
1138 			k = 0;
1139 			printf("\n        %2d:", i);
1140 		}
1141 		printf(" 0x%02x", s[i] & 0xff);
1142 		k++;
1143 		j--;
1144 		i++;
1145 	}
1146 	printf("\n");
1147 }
1148 
1149 char *
1150 scsi_decode_sense(sinfo, flag)
1151 	void *sinfo;
1152 	int flag;
1153 {
1154 	u_char *snsbuf, skey;
1155 	static char rqsbuf[132];
1156 
1157 	skey = 0;
1158 
1159 	snsbuf = (u_char *) sinfo;
1160 	if (flag == 0 || flag == 2 || flag == 3) {
1161 		skey = snsbuf[2] & 0xf;
1162 	}
1163 	if (flag == 0) {		/* Sense Key Only */
1164 		(void) strcpy(rqsbuf, sense_keys[skey]);
1165 		return (rqsbuf);
1166 	} else if (flag == 1) {		/* ASC/ASCQ Only */
1167 		asc2ascii(snsbuf[12], snsbuf[13], rqsbuf);
1168 		return (rqsbuf);
1169 	} else  if (flag == 2) {	/* Sense Key && ASC/ASCQ */
1170 		asc2ascii(snsbuf[12], snsbuf[13],
1171 		    rqsbuf + sprintf(rqsbuf, "%s, ", sense_keys[skey]));
1172 		return (rqsbuf);
1173 	} else if (flag == 3  && snsbuf[7] >= 9 && (snsbuf[15] & 0x80)) {
1174 		/*
1175 		 * SKSV Data
1176 		 */
1177 		switch (skey) {
1178 		case 0x5:	/* Illegal Request */
1179 			if (snsbuf[15] & 0x8) {
1180 				(void) sprintf(rqsbuf,
1181 				    "Error in %s, Offset %d, bit %d",
1182 				    (snsbuf[15] & 0x40)? "CDB" : "Parameters",
1183 				    (snsbuf[16] & 0xff) << 8 |
1184 				    (snsbuf[17] & 0xff), snsbuf[15] & 0xf);
1185 			} else {
1186 				(void) sprintf(rqsbuf,
1187 				    "Error in %s, Offset %d",
1188 				    (snsbuf[15] & 0x40)? "CDB" : "Parameters",
1189 				    (snsbuf[16] & 0xff) << 8 |
1190 				    (snsbuf[17] & 0xff));
1191 			}
1192 			return (rqsbuf);
1193 		case 0x1:
1194 		case 0x3:
1195 		case 0x4:
1196 			(void) sprintf(rqsbuf, "Actual Retry Count: %d",
1197 			    (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff));
1198 			return (rqsbuf);
1199 		case 0x2:
1200 			(void) sprintf(rqsbuf, "Progress Indicator: %d",
1201 			    (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff));
1202 			return (rqsbuf);
1203 		default:
1204 			break;
1205 		}
1206 	}
1207 	return (NULL);
1208 }
1209 
1210 #ifdef	SCSIDEBUG
1211 /*
1212  * Given a scsi_xfer, dump the request, in all it's glory
1213  */
1214 void
1215 show_scsi_xs(xs)
1216 	struct scsi_xfer *xs;
1217 {
1218 	printf("xs(%p): ", xs);
1219 	printf("flg(0x%x)", xs->flags);
1220 	printf("sc_link(%p)", xs->sc_link);
1221 	printf("retr(0x%x)", xs->retries);
1222 	printf("timo(0x%x)", xs->timeout);
1223 	printf("cmd(%p)", xs->cmd);
1224 	printf("len(0x%x)", xs->cmdlen);
1225 	printf("data(%p)", xs->data);
1226 	printf("len(0x%x)", xs->datalen);
1227 	printf("res(0x%x)", xs->resid);
1228 	printf("err(0x%x)", xs->error);
1229 	printf("bp(%p)", xs->bp);
1230 	show_scsi_cmd(xs);
1231 }
1232 
1233 void
1234 show_scsi_cmd(xs)
1235 	struct scsi_xfer *xs;
1236 {
1237 	u_char *b = (u_char *) xs->cmd;
1238 	int	i = 0;
1239 
1240 	sc_print_addr(xs->sc_link);
1241 	printf("command: ");
1242 
1243 	if ((xs->flags & SCSI_RESET) == 0) {
1244 		while (i < xs->cmdlen) {
1245 			if (i)
1246 				printf(",");
1247 			printf("%x", b[i++]);
1248 		}
1249 		printf("-[%d bytes]\n", xs->datalen);
1250 		if (xs->datalen)
1251 			show_mem(xs->data, min(64, xs->datalen));
1252 	} else
1253 		printf("-RESET-\n");
1254 }
1255 
1256 void
1257 show_mem(address, num)
1258 	u_char *address;
1259 	int num;
1260 {
1261 	int x;
1262 
1263 	printf("------------------------------");
1264 	for (x = 0; x < num; x++) {
1265 		if ((x % 16) == 0)
1266 			printf("\n%03d: ", x);
1267 		printf("%02x ", *address++);
1268 	}
1269 	printf("\n------------------------------\n");
1270 }
1271 #endif /* SCSIDEBUG */
1272