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