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