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