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