scsi_all.c revision 133662
1/*
2 * Implementation of Utility functions for all SCSI device types.
3 *
4 * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
5 * Copyright (c) 1997, 1998, 2003 Kenneth D. Merry.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions, and the following disclaimer,
13 *    without modification, immediately at the beginning of the file.
14 * 2. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_all.c 133662 2004-08-13 18:45:04Z mjacob $");
32
33#include <sys/param.h>
34
35#ifdef _KERNEL
36#include <opt_scsi.h>
37
38#include <sys/systm.h>
39#include <sys/libkern.h>
40#include <sys/kernel.h>
41#include <sys/sysctl.h>
42#else
43#include <errno.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#endif
48
49#include <cam/cam.h>
50#include <cam/cam_ccb.h>
51#include <cam/cam_xpt.h>
52#include <cam/scsi/scsi_all.h>
53#include <sys/sbuf.h>
54#ifndef _KERNEL
55#include <camlib.h>
56
57#ifndef FALSE
58#define FALSE   0
59#endif /* FALSE */
60#ifndef TRUE
61#define TRUE    1
62#endif /* TRUE */
63#define ERESTART        -1              /* restart syscall */
64#define EJUSTRETURN     -2              /* don't modify regs, just return */
65#endif /* !_KERNEL */
66
67/*
68 * This is the default number of seconds we wait for devices to settle
69 * after a SCSI bus reset.
70 */
71#ifndef SCSI_DELAY
72#define SCSI_DELAY 2000
73#endif
74/*
75 * All devices need _some_ sort of bus settle delay, so we'll set it to
76 * a minimum value of 100ms. Note that this is pertinent only for SPI-
77 * not transport like Fibre Channel or iSCSI where 'delay' is completely
78 * meaningless.
79 */
80#ifndef SCSI_MIN_DELAY
81#define SCSI_MIN_DELAY 100
82#endif
83/*
84 * Make sure the user isn't using seconds instead of milliseconds.
85 */
86#if (SCSI_DELAY < SCSI_MIN_DELAY && SCSI_DELAY != 0)
87#error "SCSI_DELAY is in milliseconds, not seconds!  Please use a larger value"
88#endif
89
90int scsi_delay;
91
92static int	ascentrycomp(const void *key, const void *member);
93static int	senseentrycomp(const void *key, const void *member);
94static void	fetchtableentries(int sense_key, int asc, int ascq,
95				  struct scsi_inquiry_data *,
96				  const struct sense_key_table_entry **,
97				  const struct asc_table_entry **);
98#ifdef _KERNEL
99static void	init_scsi_delay(void);
100static int	sysctl_scsi_delay(SYSCTL_HANDLER_ARGS);
101static int	set_scsi_delay(int delay);
102#endif
103
104#if !defined(SCSI_NO_OP_STRINGS)
105
106#define D 0x001
107#define T 0x002
108#define L 0x004
109#define P 0x008
110#define W 0x010
111#define R 0x020
112#define S 0x040
113#define O 0x080
114#define M 0x100
115#define C 0x200
116#define A 0x400
117#define E 0x800
118
119#define ALL 0xFFF
120
121static struct op_table_entry plextor_cd_ops[] = {
122	{0xD8, R, "CD-DA READ"}
123};
124
125static struct scsi_op_quirk_entry scsi_op_quirk_table[] = {
126	{
127		/*
128		 * I believe that 0xD8 is the Plextor proprietary command
129		 * to read CD-DA data.  I'm not sure which Plextor CDROM
130		 * models support the command, though.  I know for sure
131		 * that the 4X, 8X, and 12X models do, and presumably the
132		 * 12-20X does.  I don't know about any earlier models,
133		 * though.  If anyone has any more complete information,
134		 * feel free to change this quirk entry.
135		 */
136		{T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"},
137		sizeof(plextor_cd_ops)/sizeof(struct op_table_entry),
138		plextor_cd_ops
139	}
140};
141
142static struct op_table_entry scsi_op_codes[] = {
143/*
144 * From: ftp://ftp.symbios.com/pub/standards/io/t10/drafts/spc/op-num.txt
145 * Modifications by Kenneth Merry (ken@FreeBSD.ORG)
146 *
147 * Note:  order is important in this table, scsi_op_desc() currently
148 * depends on the opcodes in the table being in order to save search time.
149 */
150/*
151 * File: OP-NUM.TXT
152 *
153 * SCSI Operation Codes
154 * Numeric Sorted Listing
155 * as of 11/13/96
156 *
157 *     D - DIRECT ACCESS DEVICE (SBC)                    device column key
158 *     .T - SEQUENTIAL ACCESS DEVICE (SSC)              -------------------
159 *     . L - PRINTER DEVICE (SSC)                       M = Mandatory
160 *     .  P - PROCESSOR DEVICE (SPC)                    O = Optional
161 *     .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)    V = Vendor specific
162 *     .  . R - CD DEVICE (MMC)                         R = Reserved
163 *     .  .  S - SCANNER DEVICE (SGC)                   Z = Obsolete
164 *     .  .  .O - OPTICAL MEMORY DEVICE (SBC)
165 *     .  .  . M - MEDIA CHANGER DEVICE (SMC)
166 *     .  .  .  C - COMMUNICATION DEVICE (SSC)
167 *     .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
168 *     .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
169 * OP  DTLPWRSOMCAE  Description
170 * --  ------------  ---------------------------------------------------- */
171/* 00  MMMMMMMMMMMM  TEST UNIT READY */
172{0x00, ALL, 		"TEST UNIT READY"},
173
174/* 01   M            REWIND */
175{0x01, T,           "REWIND"},
176/* 01  Z V ZO ZO     REZERO UNIT */
177{0x01, D|L|W|O|M,   "REZERO UNIT"},
178
179/* 02  VVVVVV  V   */
180
181/* 03  MMMMMMMMMMMM  REQUEST SENSE */
182{0x03, ALL,         "REQUEST SENSE"},
183
184/* 04  M    O O      FORMAT UNIT */
185{0x04, D|R|O,       "FORMAT UNIT"},
186/* 04   O            FORMAT MEDIUM */
187{0x04, T,           "FORMAT MEDIUM"},
188/* 04    O           FORMAT */
189{0x04, L,           "FORMAT"},
190
191/* 05  VMVVVV  V     READ BLOCK LIMITS */
192{0x05, T,           "READ BLOCK LIMITS"},
193
194/* 06  VVVVVV  V   */
195
196/* 07  OVV O  OV     REASSIGN BLOCKS */
197{0x07, D|W|O,       "REASSIGN BLOCKS"},
198/* 07          O     INITIALIZE ELEMENT STATUS */
199{0x07, M,           "INITIALIZE ELEMENT STATUS"},
200
201/* 08  OMV OO OV     READ(06) */
202{0x08, D|T|W|R|O,   "READ(06)"},
203/* 08     O          RECEIVE */
204{0x08, P,           "RECEIVE"},
205/* 08           M    GET MESSAGE(06) */
206{0x08, C,           "GET MESSAGE(06)"},
207
208/* 09  VVVVVV  V   */
209
210/* 0A  OM  O  OV     WRITE(06) */
211{0x0A, D|T|W|O, "WRITE(06)"},
212/* 0A     M          SEND(06) */
213{0x0A, P,           "SEND(06)"},
214/* 0A           M    SEND MESSAGE(06) */
215{0x0A, C,           "SEND MESSAGE(06)"},
216/* 0A    M           PRINT */
217{0x0A, L,           "PRINT"},
218
219/* 0B  Z   ZO ZV     SEEK(06) */
220{0x0B, D|W|R|O,     "SEEK(06)"},
221/* 0B    O           SLEW AND PRINT */
222{0x0B, L,           "SLEW AND PRINT"},
223
224/* 0C  VVVVVV  V   */
225/* 0D  VVVVVV  V   */
226/* 0E  VVVVVV  V   */
227/* 0F  VOVVVV  V     READ REVERSE */
228{0x0F, T,           "READ REVERSE"},
229
230/* 10  VM VVV        WRITE FILEMARKS */
231{0x10, T,           "WRITE FILEMARKS"},
232/* 10    O O         SYNCHRONIZE BUFFER */
233{0x10, L|W,         "SYNCHRONIZE BUFFER"},
234
235/* 11  VMVVVV        SPACE */
236{0x11, T,           "SPACE"},
237
238/* 12  MMMMMMMMMMMM  INQUIRY */
239{0x12, ALL,         "INQUIRY"},
240
241/* 13  VOVVVV        VERIFY(06) */
242{0x13, T,           "VERIFY(06)"},
243
244/* 14  VOOVVV        RECOVER BUFFERED DATA */
245{0x14, T|L,         "RECOVER BUFFERED DATA"},
246
247/* 15  OMO OOOOOOOO  MODE SELECT(06) */
248{0x15, ALL & ~(P),    "MODE SELECT(06)"},
249
250/* 16  MMMOMMMM   O  RESERVE(06) */
251{0x16, D|T|L|P|W|R|S|O|E, "RESERVE(06)"},
252/* 16          M     RESERVE ELEMENT(06) */
253{0x16, M,           "RESERVE ELEMENT(06)"},
254
255/* 17  MMMOMMMM   O  RELEASE(06) */
256{0x17, ALL & ~(M|C|A), "RELEASE(06)"},
257/* 17          M     RELEASE ELEMENT(06) */
258{0x17, M,           "RELEASE ELEMENT(06)"},
259
260/* 18  OOOOOOOO      COPY */
261{0x18, ALL & ~(M|C|A|E), "COPY"},
262
263/* 19  VMVVVV        ERASE */
264{0x19, T,           "ERASE"},
265
266/* 1A  OMO OOOOOOOO  MODE SENSE(06) */
267{0x1A, ALL & ~(P),  "MODE SENSE(06)"},
268
269/* 1B  O   OM O      STOP START UNIT */
270{0x1B, D|W|R|O,     "STOP START UNIT"},
271/* 1B   O            LOAD UNLOAD */
272{0x1B, T,           "LOAD UNLOAD"},
273/* 1B        O       SCAN */
274{0x1B, S,           "SCAN"},
275/* 1B    O           STOP PRINT */
276{0x1B, L,           "STOP PRINT"},
277
278/* 1C  OOOOOOOOOO M  RECEIVE DIAGNOSTIC RESULTS */
279{0x1C, ALL & ~(A),  "RECEIVE DIAGNOSTIC RESULTS"},
280
281/* 1D  MMMMMMMMMMMM  SEND DIAGNOSTIC */
282{0x1D, ALL,         "SEND DIAGNOSTIC"},
283
284/* 1E  OO  OM OO     PREVENT ALLOW MEDIUM REMOVAL */
285{0x1E, D|T|W|R|O|M, "PREVENT ALLOW MEDIUM REMOVAL"},
286
287/* 1F */
288/* 20  V   VV V */
289/* 21  V   VV V */
290/* 22  V   VV V */
291/* 23  V   VV V */
292
293/* 24  V   VVM       SET WINDOW */
294{0x24, S,           "SET WINDOW"},
295
296/* 25  M   M  M      READ CAPACITY */
297{0x25, D|W|O,       "READ CAPACITY"},
298/* 25       M        READ CD RECORDED CAPACITY */
299{0x25, R,           "READ CD RECORDED CAPACITY"},
300/* 25        O       GET WINDOW */
301{0x25, S,           "GET WINDOW"},
302
303/* 26  V   VV */
304/* 27  V   VV */
305
306/* 28  M   MMMM      READ(10) */
307{0x28, D|W|R|S|O,   "READ(10)"},
308/* 28           O    GET MESSAGE(10) */
309{0x28, C,           "GET MESSAGE(10)"},
310
311/* 29  V   VV O      READ GENERATION */
312{0x29, O,           "READ GENERATION"},
313
314/* 2A  M   MM M      WRITE(10) */
315{0x2A, D|W|R|O,     "WRITE(10)"},
316/* 2A        O       SEND(10) */
317{0x2A, S,           "SEND(10)"},
318/* 2A           O    SEND MESSAGE(10) */
319{0x2A, C,           "SEND MESSAGE(10)"},
320
321/* 2B  O   OM O      SEEK(10) */
322{0x2B, D|W|R|O,     "SEEK(10)"},
323/* 2B   O            LOCATE */
324{0x2B, T,           "LOCATE"},
325/* 2B          O     POSITION TO ELEMENT */
326{0x2B, M,           "POSITION TO ELEMENT"},
327
328/* 2C  V      O      ERASE(10) */
329{0x2C, O,           "ERASE(10)"},
330
331/* 2D  V   O  O      READ UPDATED BLOCK */
332{0x2D, W|O,         "READ UPDATED BLOCK"},
333
334/* 2E  O   O  O      WRITE AND VERIFY(10) */
335{0x2E, D|W|O,       "WRITE AND VERIFY(10)"},
336
337/* 2F  O   OO O      VERIFY(10) */
338{0x2F, D|W|R|O,     "VERIFY(10)"},
339
340/* 30  Z   ZO Z      SEARCH DATA HIGH(10) */
341{0x30, D|W|R|O,     "SEARCH DATA HIGH(10)"},
342
343/* 31  Z   ZO Z      SEARCH DATA EQUAL(10) */
344{0x31, D|W|R|O,     "SEARCH DATA EQUAL(10)"},
345/* 31        O       OBJECT POSITION */
346{0x31, S,           "OBJECT POSITION"},
347
348/* 32  Z   ZO Z      SEARCH DATA LOW(10) */
349{0x32, D|W|R|O,     "SEARCH DATA LOW(10"},
350
351/* 33  O   OO O      SET LIMITS(10) */
352{0x33, D|W|R|O,     "SET LIMITS(10)"},
353
354/* 34  O   OO O      PRE-FETCH */
355{0x34, D|W|R|O,     "PRE-FETCH"},
356/* 34   O            READ POSITION */
357{0x34, T,           "READ POSITION"},
358/* 34        O       GET DATA BUFFER STATUS */
359{0x34, S,           "GET DATA BUFFER STATUS"},
360
361/* 35  O   OM O      SYNCHRONIZE CACHE */
362{0x35, D|W|R|O,     "SYNCHRONIZE CACHE"},
363
364/* 36  O   OO O      LOCK UNLOCK CACHE */
365{0x36, D|W|R|O,     "LOCK UNLOCK CACHE"},
366
367/* 37  O      O      READ DEFECT DATA(10) */
368{0x37, D|O,         "READ DEFECT DATA(10)"},
369
370/* 38      O  O      MEDIUM SCAN */
371{0x38, W|O,         "MEDIUM SCAN"},
372
373/* 39  OOOOOOOO      COMPARE */
374{0x39, ALL & ~(M|C|A|E), "COMPARE"},
375
376/* 3A  OOOOOOOO      COPY AND VERIFY */
377{0x3A, ALL & ~(M|C|A|E), "COPY AND VERIFY"},
378
379/* 3B  OOOOOOOOOO O  WRITE BUFFER */
380{0x3B, ALL & ~(A),  "WRITE BUFFER"},
381
382/* 3C  OOOOOOOOOO    READ BUFFER */
383{0x3C, ALL & ~(A|E),"READ BUFFER"},
384
385/* 3D      O  O      UPDATE BLOCK */
386{0x3D, W|O,         "UPDATE BLOCK"},
387
388/* 3E  O   OO O      READ LONG */
389{0x3E, D|W|R|O,     "READ LONG"},
390
391/* 3F  O   O  O      WRITE LONG */
392{0x3F, D|W|O,       "WRITE LONG"},
393
394/* 40  OOOOOOOOOO    CHANGE DEFINITION */
395{0x40, ALL & ~(A|E),"CHANGE DEFINITION"},
396
397/* 41  O             WRITE SAME */
398{0x41, D,           "WRITE SAME"},
399
400/* 42       M        READ SUB-CHANNEL */
401{0x42, R,           "READ SUB-CHANNEL"},
402
403/* 43       M        READ TOC/PMA/ATIP {MMC Proposed} */
404{0x43, R,           "READ TOC/PMA/ATIP {MMC Proposed}"},
405
406/* 44   M            REPORT DENSITY SUPPORT */
407{0x44, T,           "REPORT DENSITY SUPPORT"},
408/* 44       M        READ HEADER */
409{0x44, R,           "READ HEADER"},
410
411/* 45       O        PLAY AUDIO(10) */
412{0x45, R,           "PLAY AUDIO(10)"},
413
414/* 46 */
415
416/* 47       O        PLAY AUDIO MSF */
417{0x47, R,           "PLAY AUDIO MSF"},
418
419/* 48       O        PLAY AUDIO TRACK INDEX */
420{0x48, R,           "PLAY AUDIO TRACK INDEX"},
421
422/* 49       O        PLAY TRACK RELATIVE(10) */
423{0x49, R,           "PLAY TRACK RELATIVE(10)"},
424
425/* 4A */
426
427/* 4B       O        PAUSE/RESUME */
428{0x4B, R,           "PAUSE/RESUME"},
429
430/* 4C  OOOOOOOOOOO   LOG SELECT */
431{0x4C, ALL & ~(E),  "LOG SELECT"},
432
433/* 4D  OOOOOOOOOOO   LOG SENSE */
434{0x4D, ALL & ~(E),  "LOG SENSE"},
435
436/* 4E       O        STOP PLAY/SCAN {MMC Proposed} */
437{0x4E, R,           "STOP PLAY/SCAN {MMC Proposed}"},
438
439/* 4F */
440
441/* 50  O             XDWRITE(10) */
442{0x50, D,           "XDWRITE(10)"},
443
444/* 51  O             XPWRITE(10) */
445{0x51, D,           "XPWRITE(10)"},
446/* 51       M        READ DISC INFORMATION {MMC Proposed} */
447{0x51, R,           "READ DISC INFORMATION {MMC Proposed}"},
448
449/* 52  O             XDREAD(10) */
450{0x52, D,           "XDREAD(10)"},
451/* 52       M        READ TRACK INFORMATION {MMC Proposed} */
452{0x52, R,           "READ TRACK INFORMATION {MMC Proposed}"},
453
454/* 53       M        RESERVE TRACK {MMC Proposed} */
455{0x53, R,           "RESERVE TRACK {MMC Proposed}"},
456
457/* 54       O        SEND OPC INFORMATION {MMC Proposed} */
458{0x54, R,           "SEND OPC INFORMATION {MMC Proposed}"},
459
460/* 55  OOO OOOOOOOO  MODE SELECT(10) */
461{0x55, ALL & ~(P),  "MODE SELECT(10)"},
462
463/* 56  MMMOMMMM   O  RESERVE(10) */
464{0x56, ALL & ~(M|C|A), "RESERVE(10)"},
465/* 56          M     RESERVE ELEMENT(10) */
466{0x56, M,           "RESERVE ELEMENT(10)"},
467
468/* 57  MMMOMMMM   O  RELEASE(10) */
469{0x57, ALL & ~(M|C|A), "RELEASE(10"},
470/* 57          M     RELEASE ELEMENT(10) */
471{0x57, M,           "RELEASE ELEMENT(10)"},
472
473/* 58       O        REPAIR TRACK {MMC Proposed} */
474{0x58, R,           "REPAIR TRACK {MMC Proposed}"},
475
476/* 59       O        READ MASTER CUE {MMC Proposed} */
477{0x59, R,           "READ MASTER CUE {MMC Proposed}"},
478
479/* 5A  OOO OOOOOOOO  MODE SENSE(10) */
480{0x5A, ALL & ~(P),  "MODE SENSE(10)"},
481
482/* 5B       M        CLOSE TRACK/SESSION {MMC Proposed} */
483{0x5B, R,           "CLOSE TRACK/SESSION {MMC Proposed}"},
484
485/* 5C       O        READ BUFFER CAPACITY {MMC Proposed} */
486{0x5C, R,           "READ BUFFER CAPACITY {MMC Proposed}"},
487
488/* 5D       O        SEND CUE SHEET {MMC Proposed} */
489{0x5D, R,           "SEND CUE SHEET {MMC Proposed}"},
490
491/* 5E  OOOOOOOOO  O  PERSISTENT RESERVE IN */
492{0x5E, ALL & ~(C|A),"PERSISTENT RESERVE IN"},
493
494/* 5F  OOOOOOOOO  O  PERSISTENT RESERVE OUT */
495{0x5F, ALL & ~(C|A),"PERSISTENT RESERVE OUT"},
496
497/* 80  O             XDWRITE EXTENDED(16) */
498{0x80, D,           "XDWRITE EXTENDED(16)"},
499
500/* 81  O             REBUILD(16) */
501{0x81, D,           "REBUILD(16)"},
502
503/* 82  O             REGENERATE(16) */
504{0x82, D,           "REGENERATE(16)"},
505
506/* 83 */
507/* 84 */
508/* 85 */
509/* 86 */
510/* 87 */
511/* 88  MM  OO O    O   READ(16) */
512{0x88, D|T|W|R|O,     "READ(16)"},
513/* 89 */
514/* 8A  OM  O  O    O   WRITE(16) */
515{0x8A, D|T|W|R|O,     "WRITE(16)"},
516/* 8B */
517/* 8C */
518/* 8D */
519/* 8E */
520/* 8F */
521/* 90 */
522/* 91 */
523/* 92 */
524/* 93 */
525/* 94 */
526/* 95 */
527/* 96 */
528/* 97 */
529/* 98 */
530/* 99 */
531/* 9A */
532/* 9B */
533/* 9C */
534/* 9D */
535/* XXX KDM ALL for these?  op-num.txt defines them for none.. */
536/* 9E                  SERVICE ACTION IN(16) */
537{0x9E, ALL,           "SERVICE ACTION IN(16)"},
538/* 9F                  SERVICE ACTION OUT(16) */
539{0x9F, ALL,           "SERVICE ACTION OUT(16)"},
540
541/* A0  OOOOOOOOOOO   REPORT LUNS */
542{0xA0, ALL & ~(E),  "REPORT LUNS"},
543
544/* A1       O        BLANK {MMC Proposed} */
545{0xA1, R,           "BLANK {MMC Proposed}"},
546
547/* A2       O        WRITE CD MSF {MMC Proposed} */
548{0xA2, R,           "WRITE CD MSF {MMC Proposed}"},
549
550/* A3            M   MAINTENANCE (IN) */
551{0xA3, A,           "MAINTENANCE (IN)"},
552
553/* A4            O   MAINTENANCE (OUT) */
554{0xA4, A,           "MAINTENANCE (OUT)"},
555
556/* A5   O      M     MOVE MEDIUM */
557{0xA5, T|M,         "MOVE MEDIUM"},
558/* A5       O        PLAY AUDIO(12) */
559{0xA5, R,           "PLAY AUDIO(12)"},
560
561/* A6          O     EXCHANGE MEDIUM */
562{0xA6, M,           "EXCHANGE MEDIUM"},
563/* A6       O        LOAD/UNLOAD CD {MMC Proposed} */
564{0xA6, R,           "LOAD/UNLOAD CD {MMC Proposed}"},
565
566/* A7  OO  OO OO     MOVE MEDIUM ATTACHED */
567{0xA7, D|T|W|R|O|M, "MOVE MEDIUM ATTACHED"},
568
569/* A8  O   OM O      READ(12) */
570{0xA8,D|W|R|O,      "READ(12)"},
571/* A8           O    GET MESSAGE(12) */
572{0xA8, C,           "GET MESSAGE(12)"},
573
574/* A9       O        PLAY TRACK RELATIVE(12) */
575{0xA9, R,           "PLAY TRACK RELATIVE(12)"},
576
577/* AA  O   O  O      WRITE(12) */
578{0xAA,D|W|O,        "WRITE(12)"},
579/* AA       O        WRITE CD(12) {MMC Proposed} */
580{0xAA, R,           "WRITE CD(12) {MMC Proposed}"},
581/* AA           O    SEND MESSAGE(12) */
582{0xAA, C,           "SEND MESSAGE(12)"},
583
584/* AB */
585
586/* AC         O      ERASE(12) */
587{0xAC, O,           "ERASE(12)"},
588
589/* AD */
590
591/* AE      O  O      WRITE AND VERIFY(12) */
592{0xAE, W|O,         "WRITE AND VERIFY(12)"},
593
594/* AF      OO O      VERIFY(12) */
595{0xAF, W|R|O,       "VERIFY(12)"},
596
597/* B0      ZO Z      SEARCH DATA HIGH(12) */
598{0xB0, W|R|O,       "SEARCH DATA HIGH(12)"},
599
600/* B1      ZO Z      SEARCH DATA EQUAL(12) */
601{0xB1, W|R|O,       "SEARCH DATA EQUAL(12)"},
602
603/* B2      ZO Z      SEARCH DATA LOW(12) */
604{0xB2, W|R|O,       "SEARCH DATA LOW(12)"},
605
606/* B3      OO O      SET LIMITS(12) */
607{0xB3, W|R|O,       "SET LIMITS(12)"},
608
609/* B4  OO  OO OO     READ ELEMENT STATUS ATTACHED */
610{0xB4, D|T|W|R|O|M, "READ ELEMENT STATUS ATTACHED"},
611
612/* B5          O     REQUEST VOLUME ELEMENT ADDRESS */
613{0xB5, M,           "REQUEST VOLUME ELEMENT ADDRESS"},
614
615/* B6          O     SEND VOLUME TAG */
616{0xB6, M,           "SEND VOLUME TAG"},
617
618/* B7         O      READ DEFECT DATA(12) */
619{0xB7, O,           "READ DEFECT DATA(12)"},
620
621/* B8   O      M     READ ELEMENT STATUS */
622{0xB8, T|M,         "READ ELEMENT STATUS"},
623/* B8       O        SET CD SPEED {MMC Proposed} */
624{0xB8, R,           "SET CD SPEED {MMC Proposed}"},
625
626/* B9       M        READ CD MSF {MMC Proposed} */
627{0xB9, R,           "READ CD MSF {MMC Proposed}"},
628
629/* BA       O        SCAN {MMC Proposed} */
630{0xBA, R,           "SCAN {MMC Proposed}"},
631/* BA            M   REDUNDANCY GROUP (IN) */
632{0xBA, A,           "REDUNDANCY GROUP (IN)"},
633
634/* BB       O        SET CD-ROM SPEED {proposed} */
635{0xBB, R,           "SET CD-ROM SPEED {proposed}"},
636/* BB            O   REDUNDANCY GROUP (OUT) */
637{0xBB, A,           "REDUNDANCY GROUP (OUT)"},
638
639/* BC       O        PLAY CD {MMC Proposed} */
640{0xBC, R,           "PLAY CD {MMC Proposed}"},
641/* BC            M   SPARE (IN) */
642{0xBC, A,           "SPARE (IN)"},
643
644/* BD       M        MECHANISM STATUS {MMC Proposed} */
645{0xBD, R,           "MECHANISM STATUS {MMC Proposed}"},
646/* BD            O   SPARE (OUT) */
647{0xBD, A,           "SPARE (OUT)"},
648
649/* BE       O        READ CD {MMC Proposed} */
650{0xBE, R,           "READ CD {MMC Proposed}"},
651/* BE            M   VOLUME SET (IN) */
652{0xBE, A,           "VOLUME SET (IN)"},
653
654/* BF            O   VOLUME SET (OUT) */
655{0xBF, A,           "VOLUME SET (OUT)"}
656};
657
658const char *
659scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
660{
661	caddr_t match;
662	int i, j;
663	u_int16_t opmask;
664	u_int16_t pd_type;
665	int       num_ops[2];
666	struct op_table_entry *table[2];
667	int num_tables;
668
669	pd_type = SID_TYPE(inq_data);
670
671	match = cam_quirkmatch((caddr_t)inq_data,
672			       (caddr_t)scsi_op_quirk_table,
673			       sizeof(scsi_op_quirk_table)/
674			       sizeof(*scsi_op_quirk_table),
675			       sizeof(*scsi_op_quirk_table),
676			       scsi_inquiry_match);
677
678	if (match != NULL) {
679		table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
680		num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops;
681		table[1] = scsi_op_codes;
682		num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
683		num_tables = 2;
684	} else {
685		/*
686		 * If this is true, we have a vendor specific opcode that
687		 * wasn't covered in the quirk table.
688		 */
689		if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80)))
690			return("Vendor Specific Command");
691
692		table[0] = scsi_op_codes;
693		num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
694		num_tables = 1;
695	}
696
697	/* RBC is 'Simplified' Direct Access Device */
698	if (pd_type == T_RBC)
699		pd_type = T_DIRECT;
700
701	opmask = 1 << pd_type;
702
703	for (j = 0; j < num_tables; j++) {
704		for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){
705			if ((table[j][i].opcode == opcode)
706			 && ((table[j][i].opmask & opmask) != 0))
707				return(table[j][i].desc);
708		}
709	}
710
711	/*
712	 * If we can't find a match for the command in the table, we just
713	 * assume it's a vendor specifc command.
714	 */
715	return("Vendor Specific Command");
716
717}
718
719#else /* SCSI_NO_OP_STRINGS */
720
721const char *
722scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
723{
724	return("");
725}
726
727#endif
728
729
730#include <sys/param.h>
731
732#if !defined(SCSI_NO_SENSE_STRINGS)
733#define SST(asc, ascq, action, desc) \
734	asc, ascq, action, desc
735#else
736const char empty_string[] = "";
737
738#define SST(asc, ascq, action, desc) \
739	asc, ascq, action, empty_string
740#endif
741
742const struct sense_key_table_entry sense_key_table[] =
743{
744	{ SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
745	{ SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
746	{
747	  SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
748	  "NOT READY"
749	},
750	{ SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
751	{ SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
752	{ SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
753	{ SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" },
754	{ SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" },
755	{ SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" },
756	{ SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" },
757	{ SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" },
758	{ SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" },
759	{ SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
760	{ SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
761	{ SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
762	{ SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
763};
764
765const int sense_key_table_size =
766    sizeof(sense_key_table)/sizeof(sense_key_table[0]);
767
768static struct asc_table_entry quantum_fireball_entries[] = {
769	{SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
770	     "Logical unit not ready, initializing cmd. required")}
771};
772
773static struct asc_table_entry sony_mo_entries[] = {
774	{SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
775	     "Logical unit not ready, cause not reportable")}
776};
777
778static struct scsi_sense_quirk_entry sense_quirk_table[] = {
779	{
780		/*
781		 * The Quantum Fireball ST and SE like to return 0x04 0x0b when
782		 * they really should return 0x04 0x02.  0x04,0x0b isn't
783		 * defined in any SCSI spec, and it isn't mentioned in the
784		 * hardware manual for these drives.
785		 */
786		{T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
787		/*num_sense_keys*/0,
788		sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
789		/*sense key entries*/NULL,
790		quantum_fireball_entries
791	},
792	{
793		/*
794		 * This Sony MO drive likes to return 0x04, 0x00 when it
795		 * isn't spun up.
796		 */
797		{T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
798		/*num_sense_keys*/0,
799		sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
800		/*sense key entries*/NULL,
801		sony_mo_entries
802	}
803};
804
805const int sense_quirk_table_size =
806    sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
807
808static struct asc_table_entry asc_table[] = {
809/*
810 * From File: ASC-NUM.TXT
811 * SCSI ASC/ASCQ Assignments
812 * Numeric Sorted Listing
813 * as of  5/12/97
814 *
815 * D - DIRECT ACCESS DEVICE (SBC)                     device column key
816 * .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
817 * . L - PRINTER DEVICE (SSC)                           blank = reserved
818 * .  P - PROCESSOR DEVICE (SPC)                     not blank = allowed
819 * .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)
820 * .  . R - CD DEVICE (MMC)
821 * .  .  S - SCANNER DEVICE (SGC)
822 * .  .  .O - OPTICAL MEMORY DEVICE (SBC)
823 * .  .  . M - MEDIA CHANGER DEVICE (SMC)
824 * .  .  .  C - COMMUNICATION DEVICE (SSC)
825 * .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
826 * .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
827 * DTLPWRSOMCAE        ASC   ASCQ  Action  Description
828 * ------------        ----  ----  ------  -----------------------------------*/
829/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP,
830			"No additional sense information") },
831/*  T    S      */{SST(0x00, 0x01, SS_RDEF,
832			"Filemark detected") },
833/*  T    S      */{SST(0x00, 0x02, SS_RDEF,
834			"End-of-partition/medium detected") },
835/*  T           */{SST(0x00, 0x03, SS_RDEF,
836			"Setmark detected") },
837/*  T    S      */{SST(0x00, 0x04, SS_RDEF,
838			"Beginning-of-partition/medium detected") },
839/*  T    S      */{SST(0x00, 0x05, SS_RDEF,
840			"End-of-data detected") },
841/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF,
842			"I/O process terminated") },
843/*      R       */{SST(0x00, 0x11, SS_FATAL|EBUSY,
844			"Audio play operation in progress") },
845/*      R       */{SST(0x00, 0x12, SS_NOP,
846			"Audio play operation paused") },
847/*      R       */{SST(0x00, 0x13, SS_NOP,
848			"Audio play operation successfully completed") },
849/*      R       */{SST(0x00, 0x14, SS_RDEF,
850			"Audio play operation stopped due to error") },
851/*      R       */{SST(0x00, 0x15, SS_NOP,
852			"No current audio status to return") },
853/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY,
854			"Operation in progress") },
855/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF,
856			"Cleaning requested") },
857/* D   W  O     */{SST(0x01, 0x00, SS_RDEF,
858			"No index/sector signal") },
859/* D   WR OM    */{SST(0x02, 0x00, SS_RDEF,
860			"No seek complete") },
861/* DTL W SO     */{SST(0x03, 0x00, SS_RDEF,
862			"Peripheral device write fault") },
863/*  T           */{SST(0x03, 0x01, SS_RDEF,
864			"No write current") },
865/*  T           */{SST(0x03, 0x02, SS_RDEF,
866			"Excessive write errors") },
867/* DTLPWRSOMCAE */{SST(0x04, 0x00, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO,
868			"Logical unit not ready, cause not reportable") },
869/* DTLPWRSOMCAE */{SST(0x04, 0x01, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
870			"Logical unit is in process of becoming ready") },
871/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
872			"Logical unit not ready, initializing cmd. required") },
873/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO,
874			"Logical unit not ready, manual intervention required")},
875/* DTL    O     */{SST(0x04, 0x04, SS_FATAL|EBUSY,
876			"Logical unit not ready, format in progress") },
877/* DT  W  OMCA  */{SST(0x04, 0x05, SS_FATAL|EBUSY,
878			"Logical unit not ready, rebuild in progress") },
879/* DT  W  OMCA  */{SST(0x04, 0x06, SS_FATAL|EBUSY,
880			"Logical unit not ready, recalculation in progress") },
881/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY,
882			"Logical unit not ready, operation in progress") },
883/*      R       */{SST(0x04, 0x08, SS_FATAL|EBUSY,
884			"Logical unit not ready, long write in progress") },
885/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF,
886			"Logical unit does not respond to selection") },
887/* D   WR OM    */{SST(0x06, 0x00, SS_RDEF,
888			"No reference position found") },
889/* DTL WRSOM    */{SST(0x07, 0x00, SS_RDEF,
890			"Multiple peripheral devices selected") },
891/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF,
892			"Logical unit communication failure") },
893/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF,
894			"Logical unit communication time-out") },
895/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF,
896			"Logical unit communication parity error") },
897/* DT   R OM    */{SST(0x08, 0x03, SS_RDEF,
898			"Logical unit communication crc error (ultra-dma/32)")},
899/* DT  WR O     */{SST(0x09, 0x00, SS_RDEF,
900			"Track following error") },
901/*     WR O     */{SST(0x09, 0x01, SS_RDEF,
902			"Tracking servo failure") },
903/*     WR O     */{SST(0x09, 0x02, SS_RDEF,
904			"Focus servo failure") },
905/*     WR O     */{SST(0x09, 0x03, SS_RDEF,
906			"Spindle servo failure") },
907/* DT  WR O     */{SST(0x09, 0x04, SS_RDEF,
908			"Head select fault") },
909/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC,
910			"Error log overflow") },
911/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF,
912			"Warning") },
913/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF,
914			"Specified temperature exceeded") },
915/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF,
916			"Enclosure degraded") },
917/*  T   RS      */{SST(0x0C, 0x00, SS_RDEF,
918			"Write error") },
919/* D   W  O     */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
920			"Write error - recovered with auto reallocation") },
921/* D   W  O     */{SST(0x0C, 0x02, SS_RDEF,
922			"Write error - auto reallocation failed") },
923/* D   W  O     */{SST(0x0C, 0x03, SS_RDEF,
924			"Write error - recommend reassignment") },
925/* DT  W  O     */{SST(0x0C, 0x04, SS_RDEF,
926			"Compression check miscompare error") },
927/* DT  W  O     */{SST(0x0C, 0x05, SS_RDEF,
928			"Data expansion occurred during compression") },
929/* DT  W  O     */{SST(0x0C, 0x06, SS_RDEF,
930			"Block not compressible") },
931/*      R       */{SST(0x0C, 0x07, SS_RDEF,
932			"Write error - recovery needed") },
933/*      R       */{SST(0x0C, 0x08, SS_RDEF,
934			"Write error - recovery failed") },
935/*      R       */{SST(0x0C, 0x09, SS_RDEF,
936			"Write error - loss of streaming") },
937/*      R       */{SST(0x0C, 0x0A, SS_RDEF,
938			"Write error - padding blocks added") },
939/* D   W  O     */{SST(0x10, 0x00, SS_RDEF,
940			"ID CRC or ECC error") },
941/* DT  WRSO     */{SST(0x11, 0x00, SS_RDEF,
942			"Unrecovered read error") },
943/* DT  W SO     */{SST(0x11, 0x01, SS_RDEF,
944			"Read retries exhausted") },
945/* DT  W SO     */{SST(0x11, 0x02, SS_RDEF,
946			"Error too long to correct") },
947/* DT  W SO     */{SST(0x11, 0x03, SS_RDEF,
948			"Multiple read errors") },
949/* D   W  O     */{SST(0x11, 0x04, SS_RDEF,
950			"Unrecovered read error - auto reallocate failed") },
951/*     WR O     */{SST(0x11, 0x05, SS_RDEF,
952			"L-EC uncorrectable error") },
953/*     WR O     */{SST(0x11, 0x06, SS_RDEF,
954			"CIRC unrecovered error") },
955/*     W  O     */{SST(0x11, 0x07, SS_RDEF,
956			"Data re-synchronization error") },
957/*  T           */{SST(0x11, 0x08, SS_RDEF,
958			"Incomplete block read") },
959/*  T           */{SST(0x11, 0x09, SS_RDEF,
960			"No gap found") },
961/* DT     O     */{SST(0x11, 0x0A, SS_RDEF,
962			"Miscorrected error") },
963/* D   W  O     */{SST(0x11, 0x0B, SS_RDEF,
964			"Unrecovered read error - recommend reassignment") },
965/* D   W  O     */{SST(0x11, 0x0C, SS_RDEF,
966			"Unrecovered read error - recommend rewrite the data")},
967/* DT  WR O     */{SST(0x11, 0x0D, SS_RDEF,
968			"De-compression CRC error") },
969/* DT  WR O     */{SST(0x11, 0x0E, SS_RDEF,
970			"Cannot decompress using declared algorithm") },
971/*      R       */{SST(0x11, 0x0F, SS_RDEF,
972			"Error reading UPC/EAN number") },
973/*      R       */{SST(0x11, 0x10, SS_RDEF,
974			"Error reading ISRC number") },
975/*      R       */{SST(0x11, 0x11, SS_RDEF,
976			"Read error - loss of streaming") },
977/* D   W  O     */{SST(0x12, 0x00, SS_RDEF,
978			"Address mark not found for id field") },
979/* D   W  O     */{SST(0x13, 0x00, SS_RDEF,
980			"Address mark not found for data field") },
981/* DTL WRSO     */{SST(0x14, 0x00, SS_RDEF,
982			"Recorded entity not found") },
983/* DT  WR O     */{SST(0x14, 0x01, SS_RDEF,
984			"Record not found") },
985/*  T           */{SST(0x14, 0x02, SS_RDEF,
986			"Filemark or setmark not found") },
987/*  T           */{SST(0x14, 0x03, SS_RDEF,
988			"End-of-data not found") },
989/*  T           */{SST(0x14, 0x04, SS_RDEF,
990			"Block sequence error") },
991/* DT  W  O     */{SST(0x14, 0x05, SS_RDEF,
992			"Record not found - recommend reassignment") },
993/* DT  W  O     */{SST(0x14, 0x06, SS_RDEF,
994			"Record not found - data auto-reallocated") },
995/* DTL WRSOM    */{SST(0x15, 0x00, SS_RDEF,
996			"Random positioning error") },
997/* DTL WRSOM    */{SST(0x15, 0x01, SS_RDEF,
998			"Mechanical positioning error") },
999/* DT  WR O     */{SST(0x15, 0x02, SS_RDEF,
1000			"Positioning error detected by read of medium") },
1001/* D   W  O     */{SST(0x16, 0x00, SS_RDEF,
1002			"Data synchronization mark error") },
1003/* D   W  O     */{SST(0x16, 0x01, SS_RDEF,
1004			"Data sync error - data rewritten") },
1005/* D   W  O     */{SST(0x16, 0x02, SS_RDEF,
1006			"Data sync error - recommend rewrite") },
1007/* D   W  O     */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE,
1008			"Data sync error - data auto-reallocated") },
1009/* D   W  O     */{SST(0x16, 0x04, SS_RDEF,
1010			"Data sync error - recommend reassignment") },
1011/* DT  WRSO     */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE,
1012			"Recovered data with no error correction applied") },
1013/* DT  WRSO     */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE,
1014			"Recovered data with retries") },
1015/* DT  WR O     */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE,
1016			"Recovered data with positive head offset") },
1017/* DT  WR O     */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE,
1018			"Recovered data with negative head offset") },
1019/*     WR O     */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE,
1020			"Recovered data with retries and/or CIRC applied") },
1021/* D   WR O     */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE,
1022			"Recovered data using previous sector id") },
1023/* D   W  O     */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE,
1024			"Recovered data without ECC - data auto-reallocated") },
1025/* D   W  O     */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE,
1026			"Recovered data without ECC - recommend reassignment")},
1027/* D   W  O     */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE,
1028			"Recovered data without ECC - recommend rewrite") },
1029/* D   W  O     */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE,
1030			"Recovered data without ECC - data rewritten") },
1031/* D   W  O     */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE,
1032			"Recovered data with error correction applied") },
1033/* D   WR O     */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE,
1034			"Recovered data with error corr. & retries applied") },
1035/* D   WR O     */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE,
1036			"Recovered data - data auto-reallocated") },
1037/*      R       */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE,
1038			"Recovered data with CIRC") },
1039/*      R       */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE,
1040			"Recovered data with L-EC") },
1041/* D   WR O     */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE,
1042			"Recovered data - recommend reassignment") },
1043/* D   WR O     */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE,
1044			"Recovered data - recommend rewrite") },
1045/* D   W  O     */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE,
1046			"Recovered data with ECC - data rewritten") },
1047/* D      O     */{SST(0x19, 0x00, SS_RDEF,
1048			"Defect list error") },
1049/* D      O     */{SST(0x19, 0x01, SS_RDEF,
1050			"Defect list not available") },
1051/* D      O     */{SST(0x19, 0x02, SS_RDEF,
1052			"Defect list error in primary list") },
1053/* D      O     */{SST(0x19, 0x03, SS_RDEF,
1054			"Defect list error in grown list") },
1055/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF,
1056			"Parameter list length error") },
1057/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF,
1058			"Synchronous data transfer error") },
1059/* D      O     */{SST(0x1C, 0x00, SS_RDEF,
1060			"Defect list not found") },
1061/* D      O     */{SST(0x1C, 0x01, SS_RDEF,
1062			"Primary defect list not found") },
1063/* D      O     */{SST(0x1C, 0x02, SS_RDEF,
1064			"Grown defect list not found") },
1065/* D   W  O     */{SST(0x1D, 0x00, SS_FATAL,
1066			"Miscompare during verify operation" )},
1067/* D   W  O     */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE,
1068			"Recovered id with ecc correction") },
1069/* D      O     */{SST(0x1F, 0x00, SS_RDEF,
1070			"Partial defect list transfer") },
1071/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL,
1072			"Invalid command operation code") },
1073/* DT  WR OM    */{SST(0x21, 0x00, SS_FATAL|EINVAL,
1074			"Logical block address out of range" )},
1075/* DT  WR OM    */{SST(0x21, 0x01, SS_FATAL|EINVAL,
1076			"Invalid element address") },
1077/* D            */{SST(0x22, 0x00, SS_FATAL|EINVAL,
1078			"Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */
1079/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL,
1080			"Invalid field in CDB") },
1081/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO,
1082			"Logical unit not supported") },
1083/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL,
1084			"Invalid field in parameter list") },
1085/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL,
1086			"Parameter not supported") },
1087/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL,
1088			"Parameter value invalid") },
1089/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL,
1090			"Threshold parameters not supported") },
1091/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL,
1092			"Invalid release of active persistent reservation") },
1093/* DT  W  O     */{SST(0x27, 0x00, SS_FATAL|EACCES,
1094			"Write protected") },
1095/* DT  W  O     */{SST(0x27, 0x01, SS_FATAL|EACCES,
1096			"Hardware write protected") },
1097/* DT  W  O     */{SST(0x27, 0x02, SS_FATAL|EACCES,
1098			"Logical unit software write protected") },
1099/*  T           */{SST(0x27, 0x03, SS_FATAL|EACCES,
1100			"Associated write protect") },
1101/*  T           */{SST(0x27, 0x04, SS_FATAL|EACCES,
1102			"Persistent write protect") },
1103/*  T           */{SST(0x27, 0x05, SS_FATAL|EACCES,
1104			"Permanent write protect") },
1105/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_FATAL|ENXIO,
1106			"Not ready to ready change, medium may have changed") },
1107/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO,
1108			"Import or export element accessed") },
1109/*
1110 * XXX JGibbs - All of these should use the same errno, but I don't think
1111 * ENXIO is the correct choice.  Should we borrow from the networking
1112 * errnos?  ECONNRESET anyone?
1113 */
1114/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_FATAL|ENXIO,
1115			"Power on, reset, or bus device reset occurred") },
1116/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF,
1117			"Power on occurred") },
1118/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF,
1119			"Scsi bus reset occurred") },
1120/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF,
1121			"Bus device reset function occurred") },
1122/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF,
1123			"Device internal reset") },
1124/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF,
1125			"Transceiver mode changed to single-ended") },
1126/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF,
1127			"Transceiver mode changed to LVD") },
1128/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF,
1129			"Parameters changed") },
1130/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF,
1131			"Mode parameters changed") },
1132/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF,
1133			"Log parameters changed") },
1134/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF,
1135			"Reservations preempted") },
1136/* DTLPWRSO C   */{SST(0x2B, 0x00, SS_RDEF,
1137			"Copy cannot execute since host cannot disconnect") },
1138/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF,
1139			"Command sequence error") },
1140/*       S      */{SST(0x2C, 0x01, SS_RDEF,
1141			"Too many windows specified") },
1142/*       S      */{SST(0x2C, 0x02, SS_RDEF,
1143			"Invalid combination of windows specified") },
1144/*      R       */{SST(0x2C, 0x03, SS_RDEF,
1145			"Current program area is not empty") },
1146/*      R       */{SST(0x2C, 0x04, SS_RDEF,
1147			"Current program area is empty") },
1148/*  T           */{SST(0x2D, 0x00, SS_RDEF,
1149			"Overwrite error on update in place") },
1150/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF,
1151			"Commands cleared by another initiator") },
1152/* DT  WR OM    */{SST(0x30, 0x00, SS_RDEF,
1153			"Incompatible medium installed") },
1154/* DT  WR O     */{SST(0x30, 0x01, SS_RDEF,
1155			"Cannot read medium - unknown format") },
1156/* DT  WR O     */{SST(0x30, 0x02, SS_RDEF,
1157			"Cannot read medium - incompatible format") },
1158/* DT           */{SST(0x30, 0x03, SS_RDEF,
1159			"Cleaning cartridge installed") },
1160/* DT  WR O     */{SST(0x30, 0x04, SS_RDEF,
1161			"Cannot write medium - unknown format") },
1162/* DT  WR O     */{SST(0x30, 0x05, SS_RDEF,
1163			"Cannot write medium - incompatible format") },
1164/* DT  W  O     */{SST(0x30, 0x06, SS_RDEF,
1165			"Cannot format medium - incompatible medium") },
1166/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF,
1167			"Cleaning failure") },
1168/*      R       */{SST(0x30, 0x08, SS_RDEF,
1169			"Cannot write - application code mismatch") },
1170/*      R       */{SST(0x30, 0x09, SS_RDEF,
1171			"Current session not fixated for append") },
1172/* DT  WR O     */{SST(0x31, 0x00, SS_RDEF,
1173			"Medium format corrupted") },
1174/* D L  R O     */{SST(0x31, 0x01, SS_RDEF,
1175			"Format command failed") },
1176/* D   W  O     */{SST(0x32, 0x00, SS_RDEF,
1177			"No defect spare location available") },
1178/* D   W  O     */{SST(0x32, 0x01, SS_RDEF,
1179			"Defect list update failure") },
1180/*  T           */{SST(0x33, 0x00, SS_RDEF,
1181			"Tape length error") },
1182/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF,
1183			"Enclosure failure") },
1184/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF,
1185			"Enclosure services failure") },
1186/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF,
1187			"Unsupported enclosure function") },
1188/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF,
1189			"Enclosure services unavailable") },
1190/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF,
1191			"Enclosure services transfer failure") },
1192/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF,
1193			"Enclosure services transfer refused") },
1194/*   L          */{SST(0x36, 0x00, SS_RDEF,
1195			"Ribbon, ink, or toner failure") },
1196/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF,
1197			"Rounded parameter") },
1198/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF,
1199			"Saving parameters not supported") },
1200/* DTL WRSOM    */{SST(0x3A, 0x00, SS_FATAL|ENXIO,
1201			"Medium not present") },
1202/* DT  WR OM    */{SST(0x3A, 0x01, SS_FATAL|ENXIO,
1203			"Medium not present - tray closed") },
1204/* DT  WR OM    */{SST(0x3A, 0x02, SS_FATAL|ENXIO,
1205			"Medium not present - tray open") },
1206/*  TL          */{SST(0x3B, 0x00, SS_RDEF,
1207			"Sequential positioning error") },
1208/*  T           */{SST(0x3B, 0x01, SS_RDEF,
1209			"Tape position error at beginning-of-medium") },
1210/*  T           */{SST(0x3B, 0x02, SS_RDEF,
1211			"Tape position error at end-of-medium") },
1212/*   L          */{SST(0x3B, 0x03, SS_RDEF,
1213			"Tape or electronic vertical forms unit not ready") },
1214/*   L          */{SST(0x3B, 0x04, SS_RDEF,
1215			"Slew failure") },
1216/*   L          */{SST(0x3B, 0x05, SS_RDEF,
1217			"Paper jam") },
1218/*   L          */{SST(0x3B, 0x06, SS_RDEF,
1219			"Failed to sense top-of-form") },
1220/*   L          */{SST(0x3B, 0x07, SS_RDEF,
1221			"Failed to sense bottom-of-form") },
1222/*  T           */{SST(0x3B, 0x08, SS_RDEF,
1223			"Reposition error") },
1224/*       S      */{SST(0x3B, 0x09, SS_RDEF,
1225			"Read past end of medium") },
1226/*       S      */{SST(0x3B, 0x0A, SS_RDEF,
1227			"Read past beginning of medium") },
1228/*       S      */{SST(0x3B, 0x0B, SS_RDEF,
1229			"Position past end of medium") },
1230/*  T    S      */{SST(0x3B, 0x0C, SS_RDEF,
1231			"Position past beginning of medium") },
1232/* DT  WR OM    */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC,
1233			"Medium destination element full") },
1234/* DT  WR OM    */{SST(0x3B, 0x0E, SS_RDEF,
1235			"Medium source element empty") },
1236/*      R       */{SST(0x3B, 0x0F, SS_RDEF,
1237			"End of medium reached") },
1238/* DT  WR OM    */{SST(0x3B, 0x11, SS_RDEF,
1239			"Medium magazine not accessible") },
1240/* DT  WR OM    */{SST(0x3B, 0x12, SS_RDEF,
1241			"Medium magazine removed") },
1242/* DT  WR OM    */{SST(0x3B, 0x13, SS_RDEF,
1243			"Medium magazine inserted") },
1244/* DT  WR OM    */{SST(0x3B, 0x14, SS_RDEF,
1245			"Medium magazine locked") },
1246/* DT  WR OM    */{SST(0x3B, 0x15, SS_RDEF,
1247			"Medium magazine unlocked") },
1248/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF,
1249			"Invalid bits in identify message") },
1250/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF,
1251			"Logical unit has not self-configured yet") },
1252/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF,
1253			"Logical unit failure") },
1254/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF,
1255			"Timeout on logical unit") },
1256/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF,
1257			"Target operating conditions have changed") },
1258/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF,
1259			"Microcode has been changed") },
1260/* DTLPWRSOMC   */{SST(0x3F, 0x02, SS_RDEF,
1261			"Changed operating definition") },
1262/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_RDEF,
1263			"Inquiry data has changed") },
1264/* DT  WR OMCAE */{SST(0x3F, 0x04, SS_RDEF,
1265			"Component device attached") },
1266/* DT  WR OMCAE */{SST(0x3F, 0x05, SS_RDEF,
1267			"Device identifier changed") },
1268/* DT  WR OMCAE */{SST(0x3F, 0x06, SS_RDEF,
1269			"Redundancy group created or modified") },
1270/* DT  WR OMCAE */{SST(0x3F, 0x07, SS_RDEF,
1271			"Redundancy group deleted") },
1272/* DT  WR OMCAE */{SST(0x3F, 0x08, SS_RDEF,
1273			"Spare created or modified") },
1274/* DT  WR OMCAE */{SST(0x3F, 0x09, SS_RDEF,
1275			"Spare deleted") },
1276/* DT  WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF,
1277			"Volume set created or modified") },
1278/* DT  WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF,
1279			"Volume set deleted") },
1280/* DT  WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF,
1281			"Volume set deassigned") },
1282/* DT  WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF,
1283			"Volume set reassigned") },
1284/* D            */{SST(0x40, 0x00, SS_RDEF,
1285			"Ram failure") }, /* deprecated - use 40 NN instead */
1286/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF,
1287			"Diagnostic failure: ASCQ = Component ID") },
1288/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE,
1289			NULL) },/* Range 0x80->0xFF */
1290/* D            */{SST(0x41, 0x00, SS_RDEF,
1291			"Data path failure") }, /* deprecated - use 40 NN instead */
1292/* D            */{SST(0x42, 0x00, SS_RDEF,
1293			"Power-on or self-test failure") }, /* deprecated - use 40 NN instead */
1294/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF,
1295			"Message error") },
1296/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF,
1297			"Internal target failure") },
1298/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF,
1299			"Select or reselect failure") },
1300/* DTLPWRSOMC   */{SST(0x46, 0x00, SS_RDEF,
1301			"Unsuccessful soft reset") },
1302/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF,
1303			"SCSI parity error") },
1304/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF,
1305			"Initiator detected error message received") },
1306/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF,
1307			"Invalid message error") },
1308/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF,
1309			"Command phase error") },
1310/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF,
1311			"Data phase error") },
1312/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF,
1313			"Logical unit failed self-configuration") },
1314/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF,
1315			"Tagged overlapped commands: ASCQ = Queue tag ID") },
1316/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE,
1317			NULL)}, /* Range 0x00->0xFF */
1318/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF,
1319			"Overlapped commands attempted") },
1320/*  T           */{SST(0x50, 0x00, SS_RDEF,
1321			"Write append error") },
1322/*  T           */{SST(0x50, 0x01, SS_RDEF,
1323			"Write append position error") },
1324/*  T           */{SST(0x50, 0x02, SS_RDEF,
1325			"Position error related to timing") },
1326/*  T     O     */{SST(0x51, 0x00, SS_RDEF,
1327			"Erase failure") },
1328/*  T           */{SST(0x52, 0x00, SS_RDEF,
1329			"Cartridge fault") },
1330/* DTL WRSOM    */{SST(0x53, 0x00, SS_RDEF,
1331			"Media load or eject failed") },
1332/*  T           */{SST(0x53, 0x01, SS_RDEF,
1333			"Unload tape failure") },
1334/* DT  WR OM    */{SST(0x53, 0x02, SS_RDEF,
1335			"Medium removal prevented") },
1336/*    P         */{SST(0x54, 0x00, SS_RDEF,
1337			"Scsi to host system interface failure") },
1338/*    P         */{SST(0x55, 0x00, SS_RDEF,
1339			"System resource failure") },
1340/* D      O     */{SST(0x55, 0x01, SS_FATAL|ENOSPC,
1341			"System buffer full") },
1342/*      R       */{SST(0x57, 0x00, SS_RDEF,
1343			"Unable to recover table-of-contents") },
1344/*        O     */{SST(0x58, 0x00, SS_RDEF,
1345			"Generation does not exist") },
1346/*        O     */{SST(0x59, 0x00, SS_RDEF,
1347			"Updated block read") },
1348/* DTLPWRSOM    */{SST(0x5A, 0x00, SS_RDEF,
1349			"Operator request or state change input") },
1350/* DT  WR OM    */{SST(0x5A, 0x01, SS_RDEF,
1351			"Operator medium removal request") },
1352/* DT  W  O     */{SST(0x5A, 0x02, SS_RDEF,
1353			"Operator selected write protect") },
1354/* DT  W  O     */{SST(0x5A, 0x03, SS_RDEF,
1355			"Operator selected write permit") },
1356/* DTLPWRSOM    */{SST(0x5B, 0x00, SS_RDEF,
1357			"Log exception") },
1358/* DTLPWRSOM    */{SST(0x5B, 0x01, SS_RDEF,
1359			"Threshold condition met") },
1360/* DTLPWRSOM    */{SST(0x5B, 0x02, SS_RDEF,
1361			"Log counter at maximum") },
1362/* DTLPWRSOM    */{SST(0x5B, 0x03, SS_RDEF,
1363			"Log list codes exhausted") },
1364/* D      O     */{SST(0x5C, 0x00, SS_RDEF,
1365			"RPL status change") },
1366/* D      O     */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
1367			"Spindles synchronized") },
1368/* D      O     */{SST(0x5C, 0x02, SS_RDEF,
1369			"Spindles not synchronized") },
1370/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF,
1371			"Failure prediction threshold exceeded") },
1372/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF,
1373			"Failure prediction threshold exceeded (false)") },
1374/* DTLPWRSO CA  */{SST(0x5E, 0x00, SS_RDEF,
1375			"Low power condition on") },
1376/* DTLPWRSO CA  */{SST(0x5E, 0x01, SS_RDEF,
1377			"Idle condition activated by timer") },
1378/* DTLPWRSO CA  */{SST(0x5E, 0x02, SS_RDEF,
1379			"Standby condition activated by timer") },
1380/* DTLPWRSO CA  */{SST(0x5E, 0x03, SS_RDEF,
1381			"Idle condition activated by command") },
1382/* DTLPWRSO CA  */{SST(0x5E, 0x04, SS_RDEF,
1383			"Standby condition activated by command") },
1384/*       S      */{SST(0x60, 0x00, SS_RDEF,
1385			"Lamp failure") },
1386/*       S      */{SST(0x61, 0x00, SS_RDEF,
1387			"Video acquisition error") },
1388/*       S      */{SST(0x61, 0x01, SS_RDEF,
1389			"Unable to acquire video") },
1390/*       S      */{SST(0x61, 0x02, SS_RDEF,
1391			"Out of focus") },
1392/*       S      */{SST(0x62, 0x00, SS_RDEF,
1393			"Scan head positioning error") },
1394/*      R       */{SST(0x63, 0x00, SS_RDEF,
1395			"End of user area encountered on this track") },
1396/*      R       */{SST(0x63, 0x01, SS_FATAL|ENOSPC,
1397			"Packet does not fit in available space") },
1398/*      R       */{SST(0x64, 0x00, SS_FATAL|ENXIO,
1399			"Illegal mode for this track") },
1400/*      R       */{SST(0x64, 0x01, SS_RDEF,
1401			"Invalid packet size") },
1402/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF,
1403			"Voltage fault") },
1404/*       S      */{SST(0x66, 0x00, SS_RDEF,
1405			"Automatic document feeder cover up") },
1406/*       S      */{SST(0x66, 0x01, SS_RDEF,
1407			"Automatic document feeder lift up") },
1408/*       S      */{SST(0x66, 0x02, SS_RDEF,
1409			"Document jam in automatic document feeder") },
1410/*       S      */{SST(0x66, 0x03, SS_RDEF,
1411			"Document miss feed automatic in document feeder") },
1412/*           A  */{SST(0x67, 0x00, SS_RDEF,
1413			"Configuration failure") },
1414/*           A  */{SST(0x67, 0x01, SS_RDEF,
1415			"Configuration of incapable logical units failed") },
1416/*           A  */{SST(0x67, 0x02, SS_RDEF,
1417			"Add logical unit failed") },
1418/*           A  */{SST(0x67, 0x03, SS_RDEF,
1419			"Modification of logical unit failed") },
1420/*           A  */{SST(0x67, 0x04, SS_RDEF,
1421			"Exchange of logical unit failed") },
1422/*           A  */{SST(0x67, 0x05, SS_RDEF,
1423			"Remove of logical unit failed") },
1424/*           A  */{SST(0x67, 0x06, SS_RDEF,
1425			"Attachment of logical unit failed") },
1426/*           A  */{SST(0x67, 0x07, SS_RDEF,
1427			"Creation of logical unit failed") },
1428/*           A  */{SST(0x68, 0x00, SS_RDEF,
1429			"Logical unit not configured") },
1430/*           A  */{SST(0x69, 0x00, SS_RDEF,
1431			"Data loss on logical unit") },
1432/*           A  */{SST(0x69, 0x01, SS_RDEF,
1433			"Multiple logical unit failures") },
1434/*           A  */{SST(0x69, 0x02, SS_RDEF,
1435			"Parity/data mismatch") },
1436/*           A  */{SST(0x6A, 0x00, SS_RDEF,
1437			"Informational, refer to log") },
1438/*           A  */{SST(0x6B, 0x00, SS_RDEF,
1439			"State change has occurred") },
1440/*           A  */{SST(0x6B, 0x01, SS_RDEF,
1441			"Redundancy level got better") },
1442/*           A  */{SST(0x6B, 0x02, SS_RDEF,
1443			"Redundancy level got worse") },
1444/*           A  */{SST(0x6C, 0x00, SS_RDEF,
1445			"Rebuild failure occurred") },
1446/*           A  */{SST(0x6D, 0x00, SS_RDEF,
1447			"Recalculate failure occurred") },
1448/*           A  */{SST(0x6E, 0x00, SS_RDEF,
1449			"Command to logical unit failed") },
1450/*  T           */{SST(0x70, 0x00, SS_RDEF,
1451			"Decompression exception short: ASCQ = Algorithm ID") },
1452/*  T           */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE,
1453			NULL) }, /* Range 0x00 -> 0xFF */
1454/*  T           */{SST(0x71, 0x00, SS_RDEF,
1455			"Decompression exception long: ASCQ = Algorithm ID") },
1456/*  T           */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE,
1457			NULL) }, /* Range 0x00 -> 0xFF */
1458/*      R       */{SST(0x72, 0x00, SS_RDEF,
1459			"Session fixation error") },
1460/*      R       */{SST(0x72, 0x01, SS_RDEF,
1461			"Session fixation error writing lead-in") },
1462/*      R       */{SST(0x72, 0x02, SS_RDEF,
1463			"Session fixation error writing lead-out") },
1464/*      R       */{SST(0x72, 0x03, SS_RDEF,
1465			"Session fixation error - incomplete track in session") },
1466/*      R       */{SST(0x72, 0x04, SS_RDEF,
1467			"Empty or partially written reserved track") },
1468/*      R       */{SST(0x73, 0x00, SS_RDEF,
1469			"CD control error") },
1470/*      R       */{SST(0x73, 0x01, SS_RDEF,
1471			"Power calibration area almost full") },
1472/*      R       */{SST(0x73, 0x02, SS_FATAL|ENOSPC,
1473			"Power calibration area is full") },
1474/*      R       */{SST(0x73, 0x03, SS_RDEF,
1475			"Power calibration area error") },
1476/*      R       */{SST(0x73, 0x04, SS_RDEF,
1477			"Program memory area update failure") },
1478/*      R       */{SST(0x73, 0x05, SS_RDEF,
1479			"program memory area is full") }
1480};
1481
1482const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]);
1483
1484struct asc_key
1485{
1486	int asc;
1487	int ascq;
1488};
1489
1490static int
1491ascentrycomp(const void *key, const void *member)
1492{
1493	int asc;
1494	int ascq;
1495	const struct asc_table_entry *table_entry;
1496
1497	asc = ((const struct asc_key *)key)->asc;
1498	ascq = ((const struct asc_key *)key)->ascq;
1499	table_entry = (const struct asc_table_entry *)member;
1500
1501	if (asc >= table_entry->asc) {
1502
1503		if (asc > table_entry->asc)
1504			return (1);
1505
1506		if (ascq <= table_entry->ascq) {
1507			/* Check for ranges */
1508			if (ascq == table_entry->ascq
1509		 	 || ((table_entry->action & SSQ_RANGE) != 0
1510		  	   && ascq >= (table_entry - 1)->ascq))
1511				return (0);
1512			return (-1);
1513		}
1514		return (1);
1515	}
1516	return (-1);
1517}
1518
1519static int
1520senseentrycomp(const void *key, const void *member)
1521{
1522	int sense_key;
1523	const struct sense_key_table_entry *table_entry;
1524
1525	sense_key = *((const int *)key);
1526	table_entry = (const struct sense_key_table_entry *)member;
1527
1528	if (sense_key >= table_entry->sense_key) {
1529		if (sense_key == table_entry->sense_key)
1530			return (0);
1531		return (1);
1532	}
1533	return (-1);
1534}
1535
1536static void
1537fetchtableentries(int sense_key, int asc, int ascq,
1538		  struct scsi_inquiry_data *inq_data,
1539		  const struct sense_key_table_entry **sense_entry,
1540		  const struct asc_table_entry **asc_entry)
1541{
1542	caddr_t match;
1543	const struct asc_table_entry *asc_tables[2];
1544	const struct sense_key_table_entry *sense_tables[2];
1545	struct asc_key asc_ascq;
1546	size_t asc_tables_size[2];
1547	size_t sense_tables_size[2];
1548	int num_asc_tables;
1549	int num_sense_tables;
1550	int i;
1551
1552	/* Default to failure */
1553	*sense_entry = NULL;
1554	*asc_entry = NULL;
1555	match = NULL;
1556	if (inq_data != NULL)
1557		match = cam_quirkmatch((caddr_t)inq_data,
1558				       (caddr_t)sense_quirk_table,
1559				       sense_quirk_table_size,
1560				       sizeof(*sense_quirk_table),
1561				       scsi_inquiry_match);
1562
1563	if (match != NULL) {
1564		struct scsi_sense_quirk_entry *quirk;
1565
1566		quirk = (struct scsi_sense_quirk_entry *)match;
1567		asc_tables[0] = quirk->asc_info;
1568		asc_tables_size[0] = quirk->num_ascs;
1569		asc_tables[1] = asc_table;
1570		asc_tables_size[1] = asc_table_size;
1571		num_asc_tables = 2;
1572		sense_tables[0] = quirk->sense_key_info;
1573		sense_tables_size[0] = quirk->num_sense_keys;
1574		sense_tables[1] = sense_key_table;
1575		sense_tables_size[1] = sense_key_table_size;
1576		num_sense_tables = 2;
1577	} else {
1578		asc_tables[0] = asc_table;
1579		asc_tables_size[0] = asc_table_size;
1580		num_asc_tables = 1;
1581		sense_tables[0] = sense_key_table;
1582		sense_tables_size[0] = sense_key_table_size;
1583		num_sense_tables = 1;
1584	}
1585
1586	asc_ascq.asc = asc;
1587	asc_ascq.ascq = ascq;
1588	for (i = 0; i < num_asc_tables; i++) {
1589		void *found_entry;
1590
1591		found_entry = bsearch(&asc_ascq, asc_tables[i],
1592				      asc_tables_size[i],
1593				      sizeof(**asc_tables),
1594				      ascentrycomp);
1595
1596		if (found_entry) {
1597			*asc_entry = (struct asc_table_entry *)found_entry;
1598			break;
1599		}
1600	}
1601
1602	for (i = 0; i < num_sense_tables; i++) {
1603		void *found_entry;
1604
1605		found_entry = bsearch(&sense_key, sense_tables[i],
1606				      sense_tables_size[i],
1607				      sizeof(**sense_tables),
1608				      senseentrycomp);
1609
1610		if (found_entry) {
1611			*sense_entry =
1612			    (struct sense_key_table_entry *)found_entry;
1613			break;
1614		}
1615	}
1616}
1617
1618void
1619scsi_sense_desc(int sense_key, int asc, int ascq,
1620		struct scsi_inquiry_data *inq_data,
1621		const char **sense_key_desc, const char **asc_desc)
1622{
1623	const struct asc_table_entry *asc_entry;
1624	const struct sense_key_table_entry *sense_entry;
1625
1626	fetchtableentries(sense_key, asc, ascq,
1627			  inq_data,
1628			  &sense_entry,
1629			  &asc_entry);
1630
1631	*sense_key_desc = sense_entry->desc;
1632
1633	if (asc_entry != NULL)
1634		*asc_desc = asc_entry->desc;
1635	else if (asc >= 0x80 && asc <= 0xff)
1636		*asc_desc = "Vendor Specific ASC";
1637	else if (ascq >= 0x80 && ascq <= 0xff)
1638		*asc_desc = "Vendor Specific ASCQ";
1639	else
1640		*asc_desc = "Reserved ASC/ASCQ pair";
1641}
1642
1643/*
1644 * Given sense and device type information, return the appropriate action.
1645 * If we do not understand the specific error as identified by the ASC/ASCQ
1646 * pair, fall back on the more generic actions derived from the sense key.
1647 */
1648scsi_sense_action
1649scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
1650		  u_int32_t sense_flags)
1651{
1652	const struct asc_table_entry *asc_entry;
1653	const struct sense_key_table_entry *sense_entry;
1654	int error_code, sense_key, asc, ascq;
1655	scsi_sense_action action;
1656
1657	scsi_extract_sense(&csio->sense_data, &error_code,
1658			   &sense_key, &asc, &ascq);
1659
1660	if (error_code == SSD_DEFERRED_ERROR) {
1661		/*
1662		 * XXX dufault@FreeBSD.org
1663		 * This error doesn't relate to the command associated
1664		 * with this request sense.  A deferred error is an error
1665		 * for a command that has already returned GOOD status
1666		 * (see SCSI2 8.2.14.2).
1667		 *
1668		 * By my reading of that section, it looks like the current
1669		 * command has been cancelled, we should now clean things up
1670		 * (hopefully recovering any lost data) and then retry the
1671		 * current command.  There are two easy choices, both wrong:
1672		 *
1673		 * 1. Drop through (like we had been doing), thus treating
1674		 *    this as if the error were for the current command and
1675		 *    return and stop the current command.
1676		 *
1677		 * 2. Issue a retry (like I made it do) thus hopefully
1678		 *    recovering the current transfer, and ignoring the
1679		 *    fact that we've dropped a command.
1680		 *
1681		 * These should probably be handled in a device specific
1682		 * sense handler or punted back up to a user mode daemon
1683		 */
1684		action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
1685	} else {
1686		fetchtableentries(sense_key, asc, ascq,
1687				  inq_data,
1688				  &sense_entry,
1689				  &asc_entry);
1690
1691		/*
1692		 * Override the 'No additional Sense' entry (0,0)
1693		 * with the error action of the sense key.
1694		 */
1695		if (asc_entry != NULL
1696		 && (asc != 0 || ascq != 0))
1697			action = asc_entry->action;
1698		else
1699			action = sense_entry->action;
1700
1701		if (sense_key == SSD_KEY_RECOVERED_ERROR) {
1702			/*
1703			 * The action succeeded but the device wants
1704			 * the user to know that some recovery action
1705			 * was required.
1706			 */
1707			action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK);
1708			action |= SS_NOP|SSQ_PRINT_SENSE;
1709		} else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) {
1710			if ((sense_flags & SF_QUIET_IR) != 0)
1711				action &= ~SSQ_PRINT_SENSE;
1712		} else if (sense_key == SSD_KEY_UNIT_ATTENTION) {
1713			if ((sense_flags & SF_RETRY_UA) != 0
1714			 && (action & SS_MASK) == SS_FAIL) {
1715				action &= ~(SS_MASK|SSQ_MASK);
1716				action |= SS_RETRY|SSQ_DECREMENT_COUNT|
1717					  SSQ_PRINT_SENSE;
1718			}
1719		}
1720	}
1721#ifdef KERNEL
1722	if (bootverbose)
1723		sense_flags |= SF_PRINT_ALWAYS;
1724#endif
1725	if ((sense_flags & SF_PRINT_ALWAYS) != 0)
1726		action |= SSQ_PRINT_SENSE;
1727	else if ((sense_flags & SF_NO_PRINT) != 0)
1728		action &= ~SSQ_PRINT_SENSE;
1729
1730	return (action);
1731}
1732
1733char *
1734scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string, size_t len)
1735{
1736	u_int8_t cdb_len;
1737	int i;
1738
1739	if (cdb_ptr == NULL)
1740		return("");
1741
1742	/* Silence warnings */
1743	cdb_len = 0;
1744
1745	/*
1746	 * This is taken from the SCSI-3 draft spec.
1747	 * (T10/1157D revision 0.3)
1748	 * The top 3 bits of an opcode are the group code.  The next 5 bits
1749	 * are the command code.
1750	 * Group 0:  six byte commands
1751	 * Group 1:  ten byte commands
1752	 * Group 2:  ten byte commands
1753	 * Group 3:  reserved
1754	 * Group 4:  sixteen byte commands
1755	 * Group 5:  twelve byte commands
1756	 * Group 6:  vendor specific
1757	 * Group 7:  vendor specific
1758	 */
1759	switch((*cdb_ptr >> 5) & 0x7) {
1760		case 0:
1761			cdb_len = 6;
1762			break;
1763		case 1:
1764		case 2:
1765			cdb_len = 10;
1766			break;
1767		case 3:
1768		case 6:
1769		case 7:
1770			/* in this case, just print out the opcode */
1771			cdb_len = 1;
1772			break;
1773		case 4:
1774			cdb_len = 16;
1775			break;
1776		case 5:
1777			cdb_len = 12;
1778			break;
1779	}
1780	*cdb_string = '\0';
1781	for (i = 0; i < cdb_len; i++)
1782		snprintf(cdb_string + strlen(cdb_string),
1783			 len - strlen(cdb_string), "%x ", cdb_ptr[i]);
1784
1785	return(cdb_string);
1786}
1787
1788const char *
1789scsi_status_string(struct ccb_scsiio *csio)
1790{
1791	switch(csio->scsi_status) {
1792	case SCSI_STATUS_OK:
1793		return("OK");
1794	case SCSI_STATUS_CHECK_COND:
1795		return("Check Condition");
1796	case SCSI_STATUS_BUSY:
1797		return("Busy");
1798	case SCSI_STATUS_INTERMED:
1799		return("Intermediate");
1800	case SCSI_STATUS_INTERMED_COND_MET:
1801		return("Intermediate-Condition Met");
1802	case SCSI_STATUS_RESERV_CONFLICT:
1803		return("Reservation Conflict");
1804	case SCSI_STATUS_CMD_TERMINATED:
1805		return("Command Terminated");
1806	case SCSI_STATUS_QUEUE_FULL:
1807		return("Queue Full");
1808	case SCSI_STATUS_ACA_ACTIVE:
1809		return("ACA Active");
1810	case SCSI_STATUS_TASK_ABORTED:
1811		return("Task Aborted");
1812	default: {
1813		static char unkstr[64];
1814		snprintf(unkstr, sizeof(unkstr), "Unknown %#x",
1815			 csio->scsi_status);
1816		return(unkstr);
1817	}
1818	}
1819}
1820
1821/*
1822 * scsi_command_string() returns 0 for success and -1 for failure.
1823 */
1824#ifdef _KERNEL
1825int
1826scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb)
1827#else /* !_KERNEL */
1828int
1829scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
1830		    struct sbuf *sb)
1831#endif /* _KERNEL/!_KERNEL */
1832{
1833	struct scsi_inquiry_data *inq_data;
1834	char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
1835#ifdef _KERNEL
1836	struct	  ccb_getdev cgd;
1837#endif /* _KERNEL */
1838
1839#ifdef _KERNEL
1840	/*
1841	 * Get the device information.
1842	 */
1843	xpt_setup_ccb(&cgd.ccb_h,
1844		      csio->ccb_h.path,
1845		      /*priority*/ 1);
1846	cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1847	xpt_action((union ccb *)&cgd);
1848
1849	/*
1850	 * If the device is unconfigured, just pretend that it is a hard
1851	 * drive.  scsi_op_desc() needs this.
1852	 */
1853	if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
1854		cgd.inq_data.device = T_DIRECT;
1855
1856	inq_data = &cgd.inq_data;
1857
1858#else /* !_KERNEL */
1859
1860	inq_data = &device->inq_data;
1861
1862#endif /* _KERNEL/!_KERNEL */
1863
1864	if ((csio->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1865		sbuf_printf(sb, "%s. CDB: %s",
1866			    scsi_op_desc(csio->cdb_io.cdb_ptr[0], inq_data),
1867			    scsi_cdb_string(csio->cdb_io.cdb_ptr, cdb_str,
1868					    sizeof(cdb_str)));
1869	} else {
1870		sbuf_printf(sb, "%s. CDB: %s",
1871			    scsi_op_desc(csio->cdb_io.cdb_bytes[0], inq_data),
1872			    scsi_cdb_string(csio->cdb_io.cdb_bytes, cdb_str,
1873					    sizeof(cdb_str)));
1874	}
1875
1876	return(0);
1877}
1878
1879
1880/*
1881 * scsi_sense_sbuf() returns 0 for success and -1 for failure.
1882 */
1883#ifdef _KERNEL
1884int
1885scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb,
1886		scsi_sense_string_flags flags)
1887#else /* !_KERNEL */
1888int
1889scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
1890		struct sbuf *sb, scsi_sense_string_flags flags)
1891#endif /* _KERNEL/!_KERNEL */
1892{
1893	struct	  scsi_sense_data *sense;
1894	struct	  scsi_inquiry_data *inq_data;
1895#ifdef _KERNEL
1896	struct	  ccb_getdev cgd;
1897#endif /* _KERNEL */
1898	u_int32_t info;
1899	int	  error_code;
1900	int	  sense_key;
1901	int	  asc, ascq;
1902	char	  path_str[64];
1903
1904#ifndef _KERNEL
1905	if (device == NULL)
1906		return(-1);
1907#endif /* !_KERNEL */
1908	if ((csio == NULL) || (sb == NULL))
1909		return(-1);
1910
1911	/*
1912	 * If the CDB is a physical address, we can't deal with it..
1913	 */
1914	if ((csio->ccb_h.flags & CAM_CDB_PHYS) != 0)
1915		flags &= ~SSS_FLAG_PRINT_COMMAND;
1916
1917#ifdef _KERNEL
1918	xpt_path_string(csio->ccb_h.path, path_str, sizeof(path_str));
1919#else /* !_KERNEL */
1920	cam_path_string(device, path_str, sizeof(path_str));
1921#endif /* _KERNEL/!_KERNEL */
1922
1923#ifdef _KERNEL
1924	/*
1925	 * Get the device information.
1926	 */
1927	xpt_setup_ccb(&cgd.ccb_h,
1928		      csio->ccb_h.path,
1929		      /*priority*/ 1);
1930	cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1931	xpt_action((union ccb *)&cgd);
1932
1933	/*
1934	 * If the device is unconfigured, just pretend that it is a hard
1935	 * drive.  scsi_op_desc() needs this.
1936	 */
1937	if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
1938		cgd.inq_data.device = T_DIRECT;
1939
1940	inq_data = &cgd.inq_data;
1941
1942#else /* !_KERNEL */
1943
1944	inq_data = &device->inq_data;
1945
1946#endif /* _KERNEL/!_KERNEL */
1947
1948	sense = NULL;
1949
1950	if (flags & SSS_FLAG_PRINT_COMMAND) {
1951
1952		sbuf_cat(sb, path_str);
1953
1954#ifdef _KERNEL
1955		scsi_command_string(csio, sb);
1956#else /* !_KERNEL */
1957		scsi_command_string(device, csio, sb);
1958#endif /* _KERNEL/!_KERNEL */
1959		sbuf_printf(sb, "\n");
1960	}
1961
1962	/*
1963	 * If the sense data is a physical pointer, forget it.
1964	 */
1965	if (csio->ccb_h.flags & CAM_SENSE_PTR) {
1966		if (csio->ccb_h.flags & CAM_SENSE_PHYS)
1967			return(-1);
1968		else {
1969			/*
1970			 * bcopy the pointer to avoid unaligned access
1971			 * errors on finicky architectures.  We don't
1972			 * ensure that the sense data is pointer aligned.
1973			 */
1974			bcopy(&csio->sense_data, sense,
1975			      sizeof(struct scsi_sense_data *));
1976		}
1977	} else {
1978		/*
1979		 * If the physical sense flag is set, but the sense pointer
1980		 * is not also set, we assume that the user is an idiot and
1981		 * return.  (Well, okay, it could be that somehow, the
1982		 * entire csio is physical, but we would have probably core
1983		 * dumped on one of the bogus pointer deferences above
1984		 * already.)
1985		 */
1986		if (csio->ccb_h.flags & CAM_SENSE_PHYS)
1987			return(-1);
1988		else
1989			sense = &csio->sense_data;
1990	}
1991
1992
1993	sbuf_cat(sb, path_str);
1994
1995	error_code = sense->error_code & SSD_ERRCODE;
1996	sense_key = sense->flags & SSD_KEY;
1997
1998	switch (error_code) {
1999	case SSD_DEFERRED_ERROR:
2000		sbuf_printf(sb, "Deferred Error: ");
2001
2002		/* FALLTHROUGH */
2003	case SSD_CURRENT_ERROR:
2004	{
2005		const char *sense_key_desc;
2006		const char *asc_desc;
2007
2008		asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
2009		ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
2010		scsi_sense_desc(sense_key, asc, ascq, inq_data,
2011				&sense_key_desc, &asc_desc);
2012		sbuf_cat(sb, sense_key_desc);
2013
2014		info = scsi_4btoul(sense->info);
2015
2016		if (sense->error_code & SSD_ERRCODE_VALID) {
2017
2018			switch (sense_key) {
2019			case SSD_KEY_NOT_READY:
2020			case SSD_KEY_ILLEGAL_REQUEST:
2021			case SSD_KEY_UNIT_ATTENTION:
2022			case SSD_KEY_DATA_PROTECT:
2023				break;
2024			case SSD_KEY_BLANK_CHECK:
2025				sbuf_printf(sb, " req sz: %d (decimal)", info);
2026				break;
2027			default:
2028				if (info) {
2029					if (sense->flags & SSD_ILI) {
2030						sbuf_printf(sb, " ILI (length "
2031							"mismatch): %d", info);
2032
2033					} else {
2034						sbuf_printf(sb, " info:%x",
2035							    info);
2036					}
2037				}
2038			}
2039		} else if (info) {
2040			sbuf_printf(sb, " info?:%x", info);
2041		}
2042
2043		if (sense->extra_len >= 4) {
2044			if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
2045				sbuf_printf(sb, " csi:%x,%x,%x,%x",
2046					    sense->cmd_spec_info[0],
2047					    sense->cmd_spec_info[1],
2048					    sense->cmd_spec_info[2],
2049					    sense->cmd_spec_info[3]);
2050			}
2051		}
2052
2053		sbuf_printf(sb, " asc:%x,%x\n%s%s", asc, ascq,
2054			    path_str, asc_desc);
2055
2056		if (sense->extra_len >= 7 && sense->fru) {
2057			sbuf_printf(sb, " field replaceable unit: %x",
2058				    sense->fru);
2059		}
2060
2061		if ((sense->extra_len >= 10)
2062		 && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
2063			switch(sense_key) {
2064			case SSD_KEY_ILLEGAL_REQUEST: {
2065				int bad_command;
2066				char tmpstr2[40];
2067
2068				if (sense->sense_key_spec[0] & 0x40)
2069					bad_command = 1;
2070				else
2071					bad_command = 0;
2072
2073				tmpstr2[0] = '\0';
2074
2075				/* Bit pointer is valid */
2076				if (sense->sense_key_spec[0] & 0x08)
2077					snprintf(tmpstr2, sizeof(tmpstr2),
2078						 "bit %d ",
2079						sense->sense_key_spec[0] & 0x7);
2080				sbuf_printf(sb, ": %s byte %d %sis invalid",
2081					    bad_command ? "Command" : "Data",
2082					    scsi_2btoul(
2083					    &sense->sense_key_spec[1]),
2084					    tmpstr2);
2085				break;
2086			}
2087			case SSD_KEY_RECOVERED_ERROR:
2088			case SSD_KEY_HARDWARE_ERROR:
2089			case SSD_KEY_MEDIUM_ERROR:
2090				sbuf_printf(sb, " actual retry count: %d",
2091					    scsi_2btoul(
2092					    &sense->sense_key_spec[1]));
2093				break;
2094			default:
2095				sbuf_printf(sb, " sks:%#x,%#x",
2096					    sense->sense_key_spec[0],
2097					    scsi_2btoul(
2098					    &sense->sense_key_spec[1]));
2099				break;
2100			}
2101		}
2102		break;
2103
2104	}
2105	default:
2106		sbuf_printf(sb, "Sense Error Code 0x%x", sense->error_code);
2107		if (sense->error_code & SSD_ERRCODE_VALID) {
2108			sbuf_printf(sb, " at block no. %d (decimal)",
2109				    info = scsi_4btoul(sense->info));
2110		}
2111	}
2112
2113	sbuf_printf(sb, "\n");
2114
2115	return(0);
2116}
2117
2118
2119
2120#ifdef _KERNEL
2121char *
2122scsi_sense_string(struct ccb_scsiio *csio, char *str, int str_len)
2123#else /* !_KERNEL */
2124char *
2125scsi_sense_string(struct cam_device *device, struct ccb_scsiio *csio,
2126		  char *str, int str_len)
2127#endif /* _KERNEL/!_KERNEL */
2128{
2129	struct sbuf sb;
2130
2131	sbuf_new(&sb, str, str_len, 0);
2132
2133#ifdef _KERNEL
2134	scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND);
2135#else /* !_KERNEL */
2136	scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND);
2137#endif /* _KERNEL/!_KERNEL */
2138
2139	sbuf_finish(&sb);
2140
2141	return(sbuf_data(&sb));
2142}
2143
2144#ifdef _KERNEL
2145void
2146scsi_sense_print(struct ccb_scsiio *csio)
2147{
2148	struct sbuf sb;
2149	char str[512];
2150
2151	sbuf_new(&sb, str, sizeof(str), 0);
2152
2153	scsi_sense_sbuf(csio, &sb, SSS_FLAG_PRINT_COMMAND);
2154
2155	sbuf_finish(&sb);
2156
2157	printf("%s", sbuf_data(&sb));
2158}
2159
2160#else /* !_KERNEL */
2161void
2162scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio,
2163		 FILE *ofile)
2164{
2165	struct sbuf sb;
2166	char str[512];
2167
2168	if ((device == NULL) || (csio == NULL) || (ofile == NULL))
2169		return;
2170
2171	sbuf_new(&sb, str, sizeof(str), 0);
2172
2173	scsi_sense_sbuf(device, csio, &sb, SSS_FLAG_PRINT_COMMAND);
2174
2175	sbuf_finish(&sb);
2176
2177	fprintf(ofile, "%s", sbuf_data(&sb));
2178}
2179
2180#endif /* _KERNEL/!_KERNEL */
2181
2182/*
2183 * This function currently requires at least 36 bytes, or
2184 * SHORT_INQUIRY_LENGTH, worth of data to function properly.  If this
2185 * function needs more or less data in the future, another length should be
2186 * defined in scsi_all.h to indicate the minimum amount of data necessary
2187 * for this routine to function properly.
2188 */
2189void
2190scsi_print_inquiry(struct scsi_inquiry_data *inq_data)
2191{
2192	u_int8_t type;
2193	char *dtype, *qtype;
2194	char vendor[16], product[48], revision[16], rstr[4];
2195
2196	type = SID_TYPE(inq_data);
2197
2198	/*
2199	 * Figure out basic device type and qualifier.
2200	 */
2201	if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) {
2202		qtype = "(vendor-unique qualifier)";
2203	} else {
2204		switch (SID_QUAL(inq_data)) {
2205		case SID_QUAL_LU_CONNECTED:
2206			qtype = "";
2207			break;
2208
2209		case SID_QUAL_LU_OFFLINE:
2210			qtype = "(offline)";
2211			break;
2212
2213		case SID_QUAL_RSVD:
2214			qtype = "(reserved qualifier)";
2215			break;
2216		default:
2217		case SID_QUAL_BAD_LU:
2218			qtype = "(lun not supported)";
2219			break;
2220		}
2221	}
2222
2223	switch (type) {
2224	case T_DIRECT:
2225		dtype = "Direct Access";
2226		break;
2227	case T_SEQUENTIAL:
2228		dtype = "Sequential Access";
2229		break;
2230	case T_PRINTER:
2231		dtype = "Printer";
2232		break;
2233	case T_PROCESSOR:
2234		dtype = "Processor";
2235		break;
2236	case T_CDROM:
2237		dtype = "CD-ROM";
2238		break;
2239	case T_WORM:
2240		dtype = "Worm";
2241		break;
2242	case T_SCANNER:
2243		dtype = "Scanner";
2244		break;
2245	case T_OPTICAL:
2246		dtype = "Optical";
2247		break;
2248	case T_CHANGER:
2249		dtype = "Changer";
2250		break;
2251	case T_COMM:
2252		dtype = "Communication";
2253		break;
2254	case T_STORARRAY:
2255		dtype = "Storage Array";
2256		break;
2257	case T_ENCLOSURE:
2258		dtype = "Enclosure Services";
2259		break;
2260	case T_RBC:
2261		dtype = "Simplified Direct Access";
2262		break;
2263	case T_OCRW:
2264		dtype = "Optical Card Read/Write";
2265		break;
2266	case T_NODEVICE:
2267		dtype = "Uninstalled";
2268	default:
2269		dtype = "unknown";
2270		break;
2271	}
2272
2273	cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor),
2274		   sizeof(vendor));
2275	cam_strvis(product, inq_data->product, sizeof(inq_data->product),
2276		   sizeof(product));
2277	cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision),
2278		   sizeof(revision));
2279
2280	if (SID_ANSI_REV(inq_data) == SCSI_REV_CCS)
2281		bcopy("CCS", rstr, 4);
2282	else
2283		snprintf(rstr, sizeof (rstr), "%d", SID_ANSI_REV(inq_data));
2284	printf("<%s %s %s> %s %s SCSI-%s device %s\n",
2285	       vendor, product, revision,
2286	       SID_IS_REMOVABLE(inq_data) ? "Removable" : "Fixed",
2287	       dtype, rstr, qtype);
2288}
2289
2290/*
2291 * Table of syncrates that don't follow the "divisible by 4"
2292 * rule. This table will be expanded in future SCSI specs.
2293 */
2294static struct {
2295	u_int period_factor;
2296	u_int period;	/* in 100ths of ns */
2297} scsi_syncrates[] = {
2298	{ 0x08, 625 },	/* FAST-160 */
2299	{ 0x09, 1250 },	/* FAST-80 */
2300	{ 0x0a, 2500 },	/* FAST-40 40MHz */
2301	{ 0x0b, 3030 },	/* FAST-40 33MHz */
2302	{ 0x0c, 5000 }	/* FAST-20 */
2303};
2304
2305/*
2306 * Return the frequency in kHz corresponding to the given
2307 * sync period factor.
2308 */
2309u_int
2310scsi_calc_syncsrate(u_int period_factor)
2311{
2312	int i;
2313	int num_syncrates;
2314
2315	num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2316	/* See if the period is in the "exception" table */
2317	for (i = 0; i < num_syncrates; i++) {
2318
2319		if (period_factor == scsi_syncrates[i].period_factor) {
2320			/* Period in kHz */
2321			return (100000000 / scsi_syncrates[i].period);
2322		}
2323	}
2324
2325	/*
2326	 * Wasn't in the table, so use the standard
2327	 * 4 times conversion.
2328	 */
2329	return (10000000 / (period_factor * 4 * 10));
2330}
2331
2332/*
2333 * Return the SCSI sync parameter that corresponsd to
2334 * the passed in period in 10ths of ns.
2335 */
2336u_int
2337scsi_calc_syncparam(u_int period)
2338{
2339	int i;
2340	int num_syncrates;
2341
2342	if (period == 0)
2343		return (~0);	/* Async */
2344
2345	/* Adjust for exception table being in 100ths. */
2346	period *= 10;
2347	num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
2348	/* See if the period is in the "exception" table */
2349	for (i = 0; i < num_syncrates; i++) {
2350
2351		if (period <= scsi_syncrates[i].period) {
2352			/* Period in 100ths of ns */
2353			return (scsi_syncrates[i].period_factor);
2354		}
2355	}
2356
2357	/*
2358	 * Wasn't in the table, so use the standard
2359	 * 1/4 period in ns conversion.
2360	 */
2361	return (period/400);
2362}
2363
2364void
2365scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries,
2366		     void (*cbfcnp)(struct cam_periph *, union ccb *),
2367		     u_int8_t tag_action, u_int8_t sense_len, u_int32_t timeout)
2368{
2369	struct scsi_test_unit_ready *scsi_cmd;
2370
2371	cam_fill_csio(csio,
2372		      retries,
2373		      cbfcnp,
2374		      CAM_DIR_NONE,
2375		      tag_action,
2376		      /*data_ptr*/NULL,
2377		      /*dxfer_len*/0,
2378		      sense_len,
2379		      sizeof(*scsi_cmd),
2380		      timeout);
2381
2382	scsi_cmd = (struct scsi_test_unit_ready *)&csio->cdb_io.cdb_bytes;
2383	bzero(scsi_cmd, sizeof(*scsi_cmd));
2384	scsi_cmd->opcode = TEST_UNIT_READY;
2385}
2386
2387void
2388scsi_request_sense(struct ccb_scsiio *csio, u_int32_t retries,
2389		   void (*cbfcnp)(struct cam_periph *, union ccb *),
2390		   void *data_ptr, u_int8_t dxfer_len, u_int8_t tag_action,
2391		   u_int8_t sense_len, u_int32_t timeout)
2392{
2393	struct scsi_request_sense *scsi_cmd;
2394
2395	cam_fill_csio(csio,
2396		      retries,
2397		      cbfcnp,
2398		      CAM_DIR_IN,
2399		      tag_action,
2400		      data_ptr,
2401		      dxfer_len,
2402		      sense_len,
2403		      sizeof(*scsi_cmd),
2404		      timeout);
2405
2406	scsi_cmd = (struct scsi_request_sense *)&csio->cdb_io.cdb_bytes;
2407	bzero(scsi_cmd, sizeof(*scsi_cmd));
2408	scsi_cmd->opcode = REQUEST_SENSE;
2409	scsi_cmd->length = dxfer_len;
2410}
2411
2412void
2413scsi_inquiry(struct ccb_scsiio *csio, u_int32_t retries,
2414	     void (*cbfcnp)(struct cam_periph *, union ccb *),
2415	     u_int8_t tag_action, u_int8_t *inq_buf, u_int32_t inq_len,
2416	     int evpd, u_int8_t page_code, u_int8_t sense_len,
2417	     u_int32_t timeout)
2418{
2419	struct scsi_inquiry *scsi_cmd;
2420
2421	cam_fill_csio(csio,
2422		      retries,
2423		      cbfcnp,
2424		      /*flags*/CAM_DIR_IN,
2425		      tag_action,
2426		      /*data_ptr*/inq_buf,
2427		      /*dxfer_len*/inq_len,
2428		      sense_len,
2429		      sizeof(*scsi_cmd),
2430		      timeout);
2431
2432	scsi_cmd = (struct scsi_inquiry *)&csio->cdb_io.cdb_bytes;
2433	bzero(scsi_cmd, sizeof(*scsi_cmd));
2434	scsi_cmd->opcode = INQUIRY;
2435	if (evpd) {
2436		scsi_cmd->byte2 |= SI_EVPD;
2437		scsi_cmd->page_code = page_code;
2438	}
2439	/*
2440	 * A 'transfer units' count of 256 is coded as
2441	 * zero for all commands with a single byte count
2442	 * field.
2443	 */
2444	if (inq_len == 256)
2445		inq_len = 0;
2446	scsi_cmd->length = inq_len;
2447}
2448
2449void
2450scsi_mode_sense(struct ccb_scsiio *csio, u_int32_t retries,
2451		void (*cbfcnp)(struct cam_periph *, union ccb *),
2452		u_int8_t tag_action, int dbd, u_int8_t page_code,
2453		u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2454		u_int8_t sense_len, u_int32_t timeout)
2455{
2456
2457	scsi_mode_sense_len(csio, retries, cbfcnp, tag_action, dbd,
2458			    page_code, page, param_buf, param_len, 0,
2459			    sense_len, timeout);
2460}
2461
2462void
2463scsi_mode_sense_len(struct ccb_scsiio *csio, u_int32_t retries,
2464		    void (*cbfcnp)(struct cam_periph *, union ccb *),
2465		    u_int8_t tag_action, int dbd, u_int8_t page_code,
2466		    u_int8_t page, u_int8_t *param_buf, u_int32_t param_len,
2467		    int minimum_cmd_size, u_int8_t sense_len, u_int32_t timeout)
2468{
2469	u_int8_t cdb_len;
2470
2471	/*
2472	 * Use the smallest possible command to perform the operation.
2473	 */
2474	if ((param_len < 256)
2475	 && (minimum_cmd_size < 10)) {
2476		/*
2477		 * We can fit in a 6 byte cdb.
2478		 */
2479		struct scsi_mode_sense_6 *scsi_cmd;
2480
2481		scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2482		bzero(scsi_cmd, sizeof(*scsi_cmd));
2483		scsi_cmd->opcode = MODE_SENSE_6;
2484		if (dbd != 0)
2485			scsi_cmd->byte2 |= SMS_DBD;
2486		scsi_cmd->page = page_code | page;
2487		scsi_cmd->length = param_len;
2488		cdb_len = sizeof(*scsi_cmd);
2489	} else {
2490		/*
2491		 * Need a 10 byte cdb.
2492		 */
2493		struct scsi_mode_sense_10 *scsi_cmd;
2494
2495		scsi_cmd = (struct scsi_mode_sense_10 *)&csio->cdb_io.cdb_bytes;
2496		bzero(scsi_cmd, sizeof(*scsi_cmd));
2497		scsi_cmd->opcode = MODE_SENSE_10;
2498		if (dbd != 0)
2499			scsi_cmd->byte2 |= SMS_DBD;
2500		scsi_cmd->page = page_code | page;
2501		scsi_ulto2b(param_len, scsi_cmd->length);
2502		cdb_len = sizeof(*scsi_cmd);
2503	}
2504	cam_fill_csio(csio,
2505		      retries,
2506		      cbfcnp,
2507		      CAM_DIR_IN,
2508		      tag_action,
2509		      param_buf,
2510		      param_len,
2511		      sense_len,
2512		      cdb_len,
2513		      timeout);
2514}
2515
2516void
2517scsi_mode_select(struct ccb_scsiio *csio, u_int32_t retries,
2518		 void (*cbfcnp)(struct cam_periph *, union ccb *),
2519		 u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2520		 u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2521		 u_int32_t timeout)
2522{
2523	scsi_mode_select_len(csio, retries, cbfcnp, tag_action,
2524			     scsi_page_fmt, save_pages, param_buf,
2525			     param_len, 0, sense_len, timeout);
2526}
2527
2528void
2529scsi_mode_select_len(struct ccb_scsiio *csio, u_int32_t retries,
2530		     void (*cbfcnp)(struct cam_periph *, union ccb *),
2531		     u_int8_t tag_action, int scsi_page_fmt, int save_pages,
2532		     u_int8_t *param_buf, u_int32_t param_len,
2533		     int minimum_cmd_size, u_int8_t sense_len,
2534		     u_int32_t timeout)
2535{
2536	u_int8_t cdb_len;
2537
2538	/*
2539	 * Use the smallest possible command to perform the operation.
2540	 */
2541	if ((param_len < 256)
2542	 && (minimum_cmd_size < 10)) {
2543		/*
2544		 * We can fit in a 6 byte cdb.
2545		 */
2546		struct scsi_mode_select_6 *scsi_cmd;
2547
2548		scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2549		bzero(scsi_cmd, sizeof(*scsi_cmd));
2550		scsi_cmd->opcode = MODE_SELECT_6;
2551		if (scsi_page_fmt != 0)
2552			scsi_cmd->byte2 |= SMS_PF;
2553		if (save_pages != 0)
2554			scsi_cmd->byte2 |= SMS_SP;
2555		scsi_cmd->length = param_len;
2556		cdb_len = sizeof(*scsi_cmd);
2557	} else {
2558		/*
2559		 * Need a 10 byte cdb.
2560		 */
2561		struct scsi_mode_select_10 *scsi_cmd;
2562
2563		scsi_cmd =
2564		    (struct scsi_mode_select_10 *)&csio->cdb_io.cdb_bytes;
2565		bzero(scsi_cmd, sizeof(*scsi_cmd));
2566		scsi_cmd->opcode = MODE_SELECT_10;
2567		if (scsi_page_fmt != 0)
2568			scsi_cmd->byte2 |= SMS_PF;
2569		if (save_pages != 0)
2570			scsi_cmd->byte2 |= SMS_SP;
2571		scsi_ulto2b(param_len, scsi_cmd->length);
2572		cdb_len = sizeof(*scsi_cmd);
2573	}
2574	cam_fill_csio(csio,
2575		      retries,
2576		      cbfcnp,
2577		      CAM_DIR_OUT,
2578		      tag_action,
2579		      param_buf,
2580		      param_len,
2581		      sense_len,
2582		      cdb_len,
2583		      timeout);
2584}
2585
2586void
2587scsi_log_sense(struct ccb_scsiio *csio, u_int32_t retries,
2588	       void (*cbfcnp)(struct cam_periph *, union ccb *),
2589	       u_int8_t tag_action, u_int8_t page_code, u_int8_t page,
2590	       int save_pages, int ppc, u_int32_t paramptr,
2591	       u_int8_t *param_buf, u_int32_t param_len, u_int8_t sense_len,
2592	       u_int32_t timeout)
2593{
2594	struct scsi_log_sense *scsi_cmd;
2595	u_int8_t cdb_len;
2596
2597	scsi_cmd = (struct scsi_log_sense *)&csio->cdb_io.cdb_bytes;
2598	bzero(scsi_cmd, sizeof(*scsi_cmd));
2599	scsi_cmd->opcode = LOG_SENSE;
2600	scsi_cmd->page = page_code | page;
2601	if (save_pages != 0)
2602		scsi_cmd->byte2 |= SLS_SP;
2603	if (ppc != 0)
2604		scsi_cmd->byte2 |= SLS_PPC;
2605	scsi_ulto2b(paramptr, scsi_cmd->paramptr);
2606	scsi_ulto2b(param_len, scsi_cmd->length);
2607	cdb_len = sizeof(*scsi_cmd);
2608
2609	cam_fill_csio(csio,
2610		      retries,
2611		      cbfcnp,
2612		      /*flags*/CAM_DIR_IN,
2613		      tag_action,
2614		      /*data_ptr*/param_buf,
2615		      /*dxfer_len*/param_len,
2616		      sense_len,
2617		      cdb_len,
2618		      timeout);
2619}
2620
2621void
2622scsi_log_select(struct ccb_scsiio *csio, u_int32_t retries,
2623		void (*cbfcnp)(struct cam_periph *, union ccb *),
2624		u_int8_t tag_action, u_int8_t page_code, int save_pages,
2625		int pc_reset, u_int8_t *param_buf, u_int32_t param_len,
2626		u_int8_t sense_len, u_int32_t timeout)
2627{
2628	struct scsi_log_select *scsi_cmd;
2629	u_int8_t cdb_len;
2630
2631	scsi_cmd = (struct scsi_log_select *)&csio->cdb_io.cdb_bytes;
2632	bzero(scsi_cmd, sizeof(*scsi_cmd));
2633	scsi_cmd->opcode = LOG_SELECT;
2634	scsi_cmd->page = page_code & SLS_PAGE_CODE;
2635	if (save_pages != 0)
2636		scsi_cmd->byte2 |= SLS_SP;
2637	if (pc_reset != 0)
2638		scsi_cmd->byte2 |= SLS_PCR;
2639	scsi_ulto2b(param_len, scsi_cmd->length);
2640	cdb_len = sizeof(*scsi_cmd);
2641
2642	cam_fill_csio(csio,
2643		      retries,
2644		      cbfcnp,
2645		      /*flags*/CAM_DIR_OUT,
2646		      tag_action,
2647		      /*data_ptr*/param_buf,
2648		      /*dxfer_len*/param_len,
2649		      sense_len,
2650		      cdb_len,
2651		      timeout);
2652}
2653
2654/*
2655 * Prevent or allow the user to remove the media
2656 */
2657void
2658scsi_prevent(struct ccb_scsiio *csio, u_int32_t retries,
2659	     void (*cbfcnp)(struct cam_periph *, union ccb *),
2660	     u_int8_t tag_action, u_int8_t action,
2661	     u_int8_t sense_len, u_int32_t timeout)
2662{
2663	struct scsi_prevent *scsi_cmd;
2664
2665	cam_fill_csio(csio,
2666		      retries,
2667		      cbfcnp,
2668		      /*flags*/CAM_DIR_NONE,
2669		      tag_action,
2670		      /*data_ptr*/NULL,
2671		      /*dxfer_len*/0,
2672		      sense_len,
2673		      sizeof(*scsi_cmd),
2674		      timeout);
2675
2676	scsi_cmd = (struct scsi_prevent *)&csio->cdb_io.cdb_bytes;
2677	bzero(scsi_cmd, sizeof(*scsi_cmd));
2678	scsi_cmd->opcode = PREVENT_ALLOW;
2679	scsi_cmd->how = action;
2680}
2681
2682/* XXX allow specification of address and PMI bit and LBA */
2683void
2684scsi_read_capacity(struct ccb_scsiio *csio, u_int32_t retries,
2685		   void (*cbfcnp)(struct cam_periph *, union ccb *),
2686		   u_int8_t tag_action,
2687		   struct scsi_read_capacity_data *rcap_buf,
2688		   u_int8_t sense_len, u_int32_t timeout)
2689{
2690	struct scsi_read_capacity *scsi_cmd;
2691
2692	cam_fill_csio(csio,
2693		      retries,
2694		      cbfcnp,
2695		      /*flags*/CAM_DIR_IN,
2696		      tag_action,
2697		      /*data_ptr*/(u_int8_t *)rcap_buf,
2698		      /*dxfer_len*/sizeof(*rcap_buf),
2699		      sense_len,
2700		      sizeof(*scsi_cmd),
2701		      timeout);
2702
2703	scsi_cmd = (struct scsi_read_capacity *)&csio->cdb_io.cdb_bytes;
2704	bzero(scsi_cmd, sizeof(*scsi_cmd));
2705	scsi_cmd->opcode = READ_CAPACITY;
2706}
2707
2708void
2709scsi_read_capacity_16(struct ccb_scsiio *csio, uint32_t retries,
2710		      void (*cbfcnp)(struct cam_periph *, union ccb *),
2711		      uint8_t tag_action, uint64_t lba, int reladr, int pmi,
2712		      struct scsi_read_capacity_data_long *rcap_buf,
2713		      uint8_t sense_len, uint32_t timeout)
2714{
2715	struct scsi_read_capacity_16 *scsi_cmd;
2716
2717
2718	cam_fill_csio(csio,
2719		      retries,
2720		      cbfcnp,
2721		      /*flags*/CAM_DIR_IN,
2722		      tag_action,
2723		      /*data_ptr*/(u_int8_t *)rcap_buf,
2724		      /*dxfer_len*/sizeof(*rcap_buf),
2725		      sense_len,
2726		      sizeof(*scsi_cmd),
2727		      timeout);
2728	scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
2729	bzero(scsi_cmd, sizeof(*scsi_cmd));
2730	scsi_cmd->opcode = SERVICE_ACTION_IN;
2731	scsi_cmd->service_action = SRC16_SERVICE_ACTION;
2732	scsi_u64to8b(lba, scsi_cmd->addr);
2733	scsi_ulto4b(sizeof(*rcap_buf), scsi_cmd->alloc_len);
2734	if (pmi)
2735		reladr |= SRC16_PMI;
2736	if (reladr)
2737		reladr |= SRC16_RELADR;
2738}
2739
2740void
2741scsi_report_luns(struct ccb_scsiio *csio, u_int32_t retries,
2742		 void (*cbfcnp)(struct cam_periph *, union ccb *),
2743		 u_int8_t tag_action, struct scsi_report_luns_data *rpl_buf,
2744		 u_int32_t alloc_len, u_int8_t sense_len, u_int32_t timeout)
2745{
2746	struct scsi_report_luns *scsi_cmd;
2747
2748	cam_fill_csio(csio,
2749		      retries,
2750		      cbfcnp,
2751		      /*flags*/CAM_DIR_IN,
2752		      tag_action,
2753		      /*data_ptr*/(u_int8_t *)rpl_buf,
2754		      /*dxfer_len*/alloc_len,
2755		      sense_len,
2756		      sizeof(*scsi_cmd),
2757		      timeout);
2758	scsi_cmd = (struct scsi_report_luns *)&csio->cdb_io.cdb_bytes;
2759	bzero(scsi_cmd, sizeof(*scsi_cmd));
2760	scsi_cmd->opcode = REPORT_LUNS;
2761	scsi_ulto4b(alloc_len, scsi_cmd->addr);
2762}
2763
2764/*
2765 * Syncronize the media to the contents of the cache for
2766 * the given lba/count pair.  Specifying 0/0 means sync
2767 * the whole cache.
2768 */
2769void
2770scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries,
2771		       void (*cbfcnp)(struct cam_periph *, union ccb *),
2772		       u_int8_t tag_action, u_int32_t begin_lba,
2773		       u_int16_t lb_count, u_int8_t sense_len,
2774		       u_int32_t timeout)
2775{
2776	struct scsi_sync_cache *scsi_cmd;
2777
2778	cam_fill_csio(csio,
2779		      retries,
2780		      cbfcnp,
2781		      /*flags*/CAM_DIR_NONE,
2782		      tag_action,
2783		      /*data_ptr*/NULL,
2784		      /*dxfer_len*/0,
2785		      sense_len,
2786		      sizeof(*scsi_cmd),
2787		      timeout);
2788
2789	scsi_cmd = (struct scsi_sync_cache *)&csio->cdb_io.cdb_bytes;
2790	bzero(scsi_cmd, sizeof(*scsi_cmd));
2791	scsi_cmd->opcode = SYNCHRONIZE_CACHE;
2792	scsi_ulto4b(begin_lba, scsi_cmd->begin_lba);
2793	scsi_ulto2b(lb_count, scsi_cmd->lb_count);
2794}
2795
2796void
2797scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
2798		void (*cbfcnp)(struct cam_periph *, union ccb *),
2799		u_int8_t tag_action, int readop, u_int8_t byte2,
2800		int minimum_cmd_size, u_int64_t lba, u_int32_t block_count,
2801		u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
2802		u_int32_t timeout)
2803{
2804	u_int8_t cdb_len;
2805	/*
2806	 * Use the smallest possible command to perform the operation
2807	 * as some legacy hardware does not support the 10 byte commands.
2808	 * If any of the bits in byte2 is set, we have to go with a larger
2809	 * command.
2810	 */
2811	if ((minimum_cmd_size < 10)
2812	 && ((lba & 0x1fffff) == lba)
2813	 && ((block_count & 0xff) == block_count)
2814	 && (byte2 == 0)) {
2815		/*
2816		 * We can fit in a 6 byte cdb.
2817		 */
2818		struct scsi_rw_6 *scsi_cmd;
2819
2820		scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes;
2821		scsi_cmd->opcode = readop ? READ_6 : WRITE_6;
2822		scsi_ulto3b(lba, scsi_cmd->addr);
2823		scsi_cmd->length = block_count & 0xff;
2824		scsi_cmd->control = 0;
2825		cdb_len = sizeof(*scsi_cmd);
2826
2827		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2828			  ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0],
2829			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2830			   scsi_cmd->length, dxfer_len));
2831	} else if ((minimum_cmd_size < 12)
2832		&& ((block_count & 0xffff) == block_count)
2833		&& ((lba & 0xffffffff) == lba)) {
2834		/*
2835		 * Need a 10 byte cdb.
2836		 */
2837		struct scsi_rw_10 *scsi_cmd;
2838
2839		scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes;
2840		scsi_cmd->opcode = readop ? READ_10 : WRITE_10;
2841		scsi_cmd->byte2 = byte2;
2842		scsi_ulto4b(lba, scsi_cmd->addr);
2843		scsi_cmd->reserved = 0;
2844		scsi_ulto2b(block_count, scsi_cmd->length);
2845		scsi_cmd->control = 0;
2846		cdb_len = sizeof(*scsi_cmd);
2847
2848		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2849			  ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0],
2850			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2851			   scsi_cmd->addr[3], scsi_cmd->length[0],
2852			   scsi_cmd->length[1], dxfer_len));
2853	} else if ((minimum_cmd_size < 16)
2854		&& ((block_count & 0xffffffff) == block_count)
2855		&& ((lba & 0xffffffff) == lba)) {
2856		/*
2857		 * The block count is too big for a 10 byte CDB, use a 12
2858		 * byte CDB.
2859		 */
2860		struct scsi_rw_12 *scsi_cmd;
2861
2862		scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes;
2863		scsi_cmd->opcode = readop ? READ_12 : WRITE_12;
2864		scsi_cmd->byte2 = byte2;
2865		scsi_ulto4b(lba, scsi_cmd->addr);
2866		scsi_cmd->reserved = 0;
2867		scsi_ulto4b(block_count, scsi_cmd->length);
2868		scsi_cmd->control = 0;
2869		cdb_len = sizeof(*scsi_cmd);
2870
2871		CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE,
2872			  ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0],
2873			   scsi_cmd->addr[1], scsi_cmd->addr[2],
2874			   scsi_cmd->addr[3], scsi_cmd->length[0],
2875			   scsi_cmd->length[1], scsi_cmd->length[2],
2876			   scsi_cmd->length[3], dxfer_len));
2877	} else {
2878		/*
2879		 * 16 byte CDB.  We'll only get here if the LBA is larger
2880		 * than 2^32, or if the user asks for a 16 byte command.
2881		 */
2882		struct scsi_rw_16 *scsi_cmd;
2883
2884		scsi_cmd = (struct scsi_rw_16 *)&csio->cdb_io.cdb_bytes;
2885		scsi_cmd->opcode = readop ? READ_16 : WRITE_16;
2886		scsi_cmd->byte2 = byte2;
2887		scsi_u64to8b(lba, scsi_cmd->addr);
2888		scsi_cmd->reserved = 0;
2889		scsi_ulto4b(block_count, scsi_cmd->length);
2890		scsi_cmd->control = 0;
2891		cdb_len = sizeof(*scsi_cmd);
2892	}
2893	cam_fill_csio(csio,
2894		      retries,
2895		      cbfcnp,
2896		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
2897		      tag_action,
2898		      data_ptr,
2899		      dxfer_len,
2900		      sense_len,
2901		      cdb_len,
2902		      timeout);
2903}
2904
2905void
2906scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
2907		void (*cbfcnp)(struct cam_periph *, union ccb *),
2908		u_int8_t tag_action, int start, int load_eject,
2909		int immediate, u_int8_t sense_len, u_int32_t timeout)
2910{
2911	struct scsi_start_stop_unit *scsi_cmd;
2912	int extra_flags = 0;
2913
2914	scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes;
2915	bzero(scsi_cmd, sizeof(*scsi_cmd));
2916	scsi_cmd->opcode = START_STOP_UNIT;
2917	if (start != 0) {
2918		scsi_cmd->how |= SSS_START;
2919		/* it takes a lot of power to start a drive */
2920		extra_flags |= CAM_HIGH_POWER;
2921	}
2922	if (load_eject != 0)
2923		scsi_cmd->how |= SSS_LOEJ;
2924	if (immediate != 0)
2925		scsi_cmd->byte2 |= SSS_IMMED;
2926
2927	cam_fill_csio(csio,
2928		      retries,
2929		      cbfcnp,
2930		      /*flags*/CAM_DIR_NONE | extra_flags,
2931		      tag_action,
2932		      /*data_ptr*/NULL,
2933		      /*dxfer_len*/0,
2934		      sense_len,
2935		      sizeof(*scsi_cmd),
2936		      timeout);
2937
2938}
2939
2940
2941/*
2942 * Try make as good a match as possible with
2943 * available sub drivers
2944 */
2945int
2946scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2947{
2948	struct scsi_inquiry_pattern *entry;
2949	struct scsi_inquiry_data *inq;
2950
2951	entry = (struct scsi_inquiry_pattern *)table_entry;
2952	inq = (struct scsi_inquiry_data *)inqbuffer;
2953
2954	if (((SID_TYPE(inq) == entry->type)
2955	  || (entry->type == T_ANY))
2956	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2957				   : entry->media_type & SIP_MEDIA_FIXED)
2958	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2959	 && (cam_strmatch(inq->product, entry->product,
2960			  sizeof(inq->product)) == 0)
2961	 && (cam_strmatch(inq->revision, entry->revision,
2962			  sizeof(inq->revision)) == 0)) {
2963		return (0);
2964	}
2965        return (-1);
2966}
2967
2968/*
2969 * Try make as good a match as possible with
2970 * available sub drivers
2971 */
2972int
2973scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
2974{
2975	struct scsi_static_inquiry_pattern *entry;
2976	struct scsi_inquiry_data *inq;
2977
2978	entry = (struct scsi_static_inquiry_pattern *)table_entry;
2979	inq = (struct scsi_inquiry_data *)inqbuffer;
2980
2981	if (((SID_TYPE(inq) == entry->type)
2982	  || (entry->type == T_ANY))
2983	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
2984				   : entry->media_type & SIP_MEDIA_FIXED)
2985	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
2986	 && (cam_strmatch(inq->product, entry->product,
2987			  sizeof(inq->product)) == 0)
2988	 && (cam_strmatch(inq->revision, entry->revision,
2989			  sizeof(inq->revision)) == 0)) {
2990		return (0);
2991	}
2992        return (-1);
2993}
2994
2995#ifdef _KERNEL
2996static void
2997init_scsi_delay(void)
2998{
2999	int delay;
3000
3001	delay = SCSI_DELAY;
3002	TUNABLE_INT_FETCH("kern.cam.scsi_delay", &delay);
3003
3004	if (set_scsi_delay(delay) != 0) {
3005		printf("cam: invalid value for tunable kern.cam.scsi_delay\n");
3006		set_scsi_delay(SCSI_DELAY);
3007	}
3008}
3009SYSINIT(scsi_delay, SI_SUB_TUNABLES, SI_ORDER_ANY, init_scsi_delay, NULL);
3010
3011static int
3012sysctl_scsi_delay(SYSCTL_HANDLER_ARGS)
3013{
3014	int error, delay;
3015
3016	delay = scsi_delay;
3017	error = sysctl_handle_int(oidp, &delay, sizeof(delay), req);
3018	if (error != 0 || req->newptr == NULL)
3019		return (error);
3020	return (set_scsi_delay(delay));
3021}
3022SYSCTL_PROC(_kern_cam, OID_AUTO, scsi_delay, CTLTYPE_INT|CTLFLAG_RW,
3023    0, 0, sysctl_scsi_delay, "I",
3024    "Delay to allow devices to settle after a SCSI bus reset (ms)");
3025
3026static int
3027set_scsi_delay(int delay)
3028{
3029	/*
3030         * If someone sets this to 0, we assume that they want the
3031         * minimum allowable bus settle delay.
3032	 */
3033	if (delay == 0) {
3034		printf("cam: using minimum scsi_delay (%dms)\n",
3035		    SCSI_MIN_DELAY);
3036		delay = SCSI_MIN_DELAY;
3037	}
3038	if (delay < SCSI_MIN_DELAY)
3039		return (EINVAL);
3040	scsi_delay = delay;
3041	return (0);
3042}
3043#endif /* _KERNEL */
3044