1 /*-
2 * Implementation of Utility functions for all SCSI device types.
3 *
4 * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
5 * Copyright (c) 1997, 1998, 2003 Kenneth D. Merry.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions, and the following disclaimer,
13 * without modification, immediately at the beginning of the file.
14 * 2. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.53 2008/08/16 21:26:58 ken Exp $");
32
33 #include <sys/param.h>
34
35 #ifdef _KERNEL
36 #include <opt_scsi.h>
37
38 #include <sys/systm.h>
39 #include <sys/libkern.h>
40 #include <sys/kernel.h>
41 #include <sys/sysctl.h>
42 #else
43 #include <errno.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #endif
48
49 #include <cam/cam.h>
50 #include <cam/cam_ccb.h>
51 #include <cam/cam_xpt.h>
52 #include <cam/scsi/scsi_all.h>
53 #include <sys/sbuf.h>
54 #ifndef _KERNEL
55 #include <camlib.h>
56
57 #ifndef FALSE
58 #define FALSE 0
59 #endif /* FALSE */
60 #ifndef TRUE
61 #define TRUE 1
62 #endif /* TRUE */
63 #define ERESTART -1 /* restart syscall */
64 #define EJUSTRETURN -2 /* don't modify regs, just return */
65 #endif /* !_KERNEL */
66
67 /*
68 * This is the default number of milliseconds we wait for devices to settle
69 * after a SCSI bus reset.
70 */
71 #ifndef SCSI_DELAY
72 #define SCSI_DELAY 2000
73 #endif
74 /*
75 * All devices need _some_ sort of bus settle delay, so we'll set it to
76 * a minimum value of 100ms. Note that this is pertinent only for SPI-
77 * not transport like Fibre Channel or iSCSI where 'delay' is completely
78 * meaningless.
79 */
80 #ifndef SCSI_MIN_DELAY
81 #define SCSI_MIN_DELAY 100
82 #endif
83 /*
84 * Make sure the user isn't using seconds instead of milliseconds.
85 */
86 #if (SCSI_DELAY < SCSI_MIN_DELAY && SCSI_DELAY != 0)
87 #error "SCSI_DELAY is in milliseconds, not seconds! Please use a larger value"
88 #endif
89
90 int scsi_delay;
91
92 static int ascentrycomp(const void *key, const void *member);
93 static int senseentrycomp(const void *key, const void *member);
94 static void fetchtableentries(int sense_key, int asc, int ascq,
95 struct scsi_inquiry_data *,
96 const struct sense_key_table_entry **,
97 const struct asc_table_entry **);
98 #ifdef _KERNEL
99 static void init_scsi_delay(void);
100 static int sysctl_scsi_delay(SYSCTL_HANDLER_ARGS);
101 static int set_scsi_delay(int delay);
102 #endif
103
104 #if !defined(SCSI_NO_OP_STRINGS)
105
106 #define D (1 << T_DIRECT)
107 #define T (1 << T_SEQUENTIAL)
108 #define L (1 << T_PRINTER)
109 #define P (1 << T_PROCESSOR)
110 #define W (1 << T_WORM)
111 #define R (1 << T_CDROM)
112 #define O (1 << T_OPTICAL)
113 #define M (1 << T_CHANGER)
114 #define A (1 << T_STORARRAY)
115 #define E (1 << T_ENCLOSURE)
116 #define B (1 << T_RBC)
117 #define K (1 << T_OCRW)
118 #define V (1 << T_ADC)
119 #define F (1 << T_OSD)
120 #define S (1 << T_SCANNER)
121 #define C (1 << T_COMM)
122
123 #define ALL (D | T | L | P | W | R | O | M | A | E | B | K | V | F | S | C)
124
125 static struct op_table_entry plextor_cd_ops[] = {
126 { 0xD8, R, "CD-DA READ" }
127 };
128
129 static struct scsi_op_quirk_entry scsi_op_quirk_table[] = {
130 {
131 /*
132 * I believe that 0xD8 is the Plextor proprietary command
133 * to read CD-DA data. I'm not sure which Plextor CDROM
134 * models support the command, though. I know for sure
135 * that the 4X, 8X, and 12X models do, and presumably the
136 * 12-20X does. I don't know about any earlier models,
137 * though. If anyone has any more complete information,
138 * feel free to change this quirk entry.
139 */
140 {T_CDROM, SIP_MEDIA_REMOVABLE, "PLEXTOR", "CD-ROM PX*", "*"},
141 sizeof(plextor_cd_ops)/sizeof(struct op_table_entry),
142 plextor_cd_ops
143 }
144 };
145
146 static struct op_table_entry scsi_op_codes[] = {
147 /*
148 * From: http://www.t10.org/lists/op-num.txt
149 * Modifications by Kenneth Merry (ken@FreeBSD.ORG)
150 * and Jung-uk Kim (jkim@FreeBSD.org)
151 *
152 * Note: order is important in this table, scsi_op_desc() currently
153 * depends on the opcodes in the table being in order to save
154 * search time.
155 * Note: scanner and comm. devices are carried over from the previous
156 * version because they were removed in the latest spec.
157 */
158 /* File: OP-NUM.TXT
159 *
160 * SCSI Operation Codes
161 * Numeric Sorted Listing
162 * as of 3/11/08
163 *
164 * D - DIRECT ACCESS DEVICE (SBC-2) device column key
165 * .T - SEQUENTIAL ACCESS DEVICE (SSC-2) -----------------
166 * . L - PRINTER DEVICE (SSC) M = Mandatory
167 * . P - PROCESSOR DEVICE (SPC) O = Optional
168 * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) V = Vendor spec.
169 * . . R - CD/DVE DEVICE (MMC-3) Z = Obsolete
170 * . . O - OPTICAL MEMORY DEVICE (SBC-2)
171 * . . .M - MEDIA CHANGER DEVICE (SMC-2)
172 * . . . A - STORAGE ARRAY DEVICE (SCC-2)
173 * . . . .E - ENCLOSURE SERVICES DEVICE (SES)
174 * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC)
175 * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW)
176 * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC)
177 * . . . . .F - OBJECT-BASED STORAGE (OSD)
178 * OP DTLPWROMAEBKVF Description
179 * -- -------------- ---------------------------------------------- */
180 /* 00 MMMMMMMMMMMMMM TEST UNIT READY */
181 { 0x00, ALL, "TEST UNIT READY" },
182 /* 01 M REWIND */
183 { 0x01, T, "REWIND" },
184 /* 01 Z V ZZZZ REZERO UNIT */
185 { 0x01, D | W | R | O | M, "REZERO UNIT" },
186 /* 02 VVVVVV V */
187 /* 03 MMMMMMMMMMOMMM REQUEST SENSE */
188 { 0x03, ALL, "REQUEST SENSE" },
189 /* 04 M OO FORMAT UNIT */
190 { 0x04, D | R | O, "FORMAT UNIT" },
191 /* 04 O FORMAT MEDIUM */
192 { 0x04, T, "FORMAT MEDIUM" },
193 /* 04 O FORMAT */
194 { 0x04, L, "FORMAT" },
195 /* 05 VMVVVV V READ BLOCK LIMITS */
196 { 0x05, T, "READ BLOCK LIMITS" },
197 /* 06 VVVVVV V */
198 /* 07 OVV O OV REASSIGN BLOCKS */
199 { 0x07, D | W | O, "REASSIGN BLOCKS" },
200 /* 07 O INITIALIZE ELEMENT STATUS */
201 { 0x07, M, "INITIALIZE ELEMENT STATUS" },
202 /* 08 MOV O OV READ(6) */
203 { 0x08, D | T | W | O, "READ(6)" },
204 /* 08 O RECEIVE */
205 { 0x08, P, "RECEIVE" },
206 /* 08 GET MESSAGE(6) */
207 { 0x08, C, "GET MESSAGE(6)" },
208 /* 09 VVVVVV V */
209 /* 0A OO O OV WRITE(6) */
210 { 0x0A, D | T | W | O, "WRITE(6)" },
211 /* 0A M SEND(6) */
212 { 0x0A, P, "SEND(6)" },
213 /* 0A SEND MESSAGE(6) */
214 { 0x0A, C, "SEND MESSAGE(6)" },
215 /* 0A M PRINT */
216 { 0x0A, L, "PRINT" },
217 /* 0B Z ZOZV SEEK(6) */
218 { 0x0B, D | W | R | O, "SEEK(6)" },
219 /* 0B O SET CAPACITY */
220 { 0x0B, T, "SET CAPACITY" },
221 /* 0B O SLEW AND PRINT */
222 { 0x0B, L, "SLEW AND PRINT" },
223 /* 0C VVVVVV V */
224 /* 0D VVVVVV V */
225 /* 0E VVVVVV V */
226 /* 0F VOVVVV V READ REVERSE(6) */
227 { 0x0F, T, "READ REVERSE(6)" },
228 /* 10 VM VVV WRITE FILEMARKS(6) */
229 { 0x10, T, "WRITE FILEMARKS(6)" },
230 /* 10 O SYNCHRONIZE BUFFER */
231 { 0x10, L, "SYNCHRONIZE BUFFER" },
232 /* 11 VMVVVV SPACE(6) */
233 { 0x11, T, "SPACE(6)" },
234 /* 12 MMMMMMMMMMMMMM INQUIRY */
235 { 0x12, ALL, "INQUIRY" },
236 /* 13 V VVVV */
237 /* 13 O VERIFY(6) */
238 { 0x13, T, "VERIFY(6)" },
239 /* 14 VOOVVV RECOVER BUFFERED DATA */
240 { 0x14, T | L, "RECOVER BUFFERED DATA" },
241 /* 15 OMO O OOOO OO MODE SELECT(6) */
242 { 0x15, ALL & ~(P | R | B | F), "MODE SELECT(6)" },
243 /* 16 ZZMZO OOOZ O RESERVE(6) */
244 { 0x16, ALL & ~(R | B | V | F | C), "RESERVE(6)" },
245 /* 16 Z RESERVE ELEMENT(6) */
246 { 0x16, M, "RESERVE ELEMENT(6)" },
247 /* 17 ZZMZO OOOZ O RELEASE(6) */
248 { 0x17, ALL & ~(R | B | V | F | C), "RELEASE(6)" },
249 /* 17 Z RELEASE ELEMENT(6) */
250 { 0x17, M, "RELEASE ELEMENT(6)" },
251 /* 18 ZZZZOZO Z COPY */
252 { 0x18, D | T | L | P | W | R | O | K | S, "COPY" },
253 /* 19 VMVVVV ERASE(6) */
254 { 0x19, T, "ERASE(6)" },
255 /* 1A OMO O OOOO OO MODE SENSE(6) */
256 { 0x1A, ALL & ~(P | R | B | F), "MODE SENSE(6)" },
257 /* 1B O OOO O MO O START STOP UNIT */
258 { 0x1B, D | W | R | O | A | B | K | F, "START STOP UNIT" },
259 /* 1B O M LOAD UNLOAD */
260 { 0x1B, T | V, "LOAD UNLOAD" },
261 /* 1B SCAN */
262 { 0x1B, S, "SCAN" },
263 /* 1B O STOP PRINT */
264 { 0x1B, L, "STOP PRINT" },
265 /* 1B O OPEN/CLOSE IMPORT/EXPORT ELEMENT */
266 { 0x1B, M, "OPEN/CLOSE IMPORT/EXPORT ELEMENT" },
267 /* 1C OOOOO OOOM OOO RECEIVE DIAGNOSTIC RESULTS */
268 { 0x1C, ALL & ~(R | B), "RECEIVE DIAGNOSTIC RESULTS" },
269 /* 1D MMMMM MMOM MMM SEND DIAGNOSTIC */
270 { 0x1D, ALL & ~(R | B), "SEND DIAGNOSTIC" },
271 /* 1E OO OOOO O O PREVENT ALLOW MEDIUM REMOVAL */
272 { 0x1E, D | T | W | R | O | M | K | F, "PREVENT ALLOW MEDIUM REMOVAL" },
273 /* 1F */
274 /* 20 V VVV V */
275 /* 21 V VVV V */
276 /* 22 V VVV V */
277 /* 23 V V V V */
278 /* 23 O READ FORMAT CAPACITIES */
279 { 0x23, R, "READ FORMAT CAPACITIES" },
280 /* 24 V VV SET WINDOW */
281 { 0x24, S, "SET WINDOW" },
282 /* 25 M M M M READ CAPACITY(10) */
283 { 0x25, D | W | O | B, "READ CAPACITY(10)" },
284 /* 25 O READ CAPACITY */
285 { 0x25, R, "READ CAPACITY" },
286 /* 25 M READ CARD CAPACITY */
287 { 0x25, K, "READ CARD CAPACITY" },
288 /* 25 GET WINDOW */
289 { 0x25, S, "GET WINDOW" },
290 /* 26 V VV */
291 /* 27 V VV */
292 /* 28 M MOM MM READ(10) */
293 { 0x28, D | W | R | O | B | K | S, "READ(10)" },
294 /* 28 GET MESSAGE(10) */
295 { 0x28, C, "GET MESSAGE(10)" },
296 /* 29 V VVO READ GENERATION */
297 { 0x29, O, "READ GENERATION" },
298 /* 2A O MOM MO WRITE(10) */
299 { 0x2A, D | W | R | O | B | K, "WRITE(10)" },
300 /* 2A SEND(10) */
301 { 0x2A, S, "SEND(10)" },
302 /* 2A SEND MESSAGE(10) */
303 { 0x2A, C, "SEND MESSAGE(10)" },
304 /* 2B Z OOO O SEEK(10) */
305 { 0x2B, D | W | R | O | K, "SEEK(10)" },
306 /* 2B O LOCATE(10) */
307 { 0x2B, T, "LOCATE(10)" },
308 /* 2B O POSITION TO ELEMENT */
309 { 0x2B, M, "POSITION TO ELEMENT" },
310 /* 2C V OO ERASE(10) */
311 { 0x2C, R | O, "ERASE(10)" },
312 /* 2D O READ UPDATED BLOCK */
313 { 0x2D, O, "READ UPDATED BLOCK" },
314 /* 2D V */
315 /* 2E O OOO MO WRITE AND VERIFY(10) */
316 { 0x2E, D | W | R | O | B | K, "WRITE AND VERIFY(10)" },
317 /* 2F O OOO VERIFY(10) */
318 { 0x2F, D | W | R | O, "VERIFY(10)" },
319 /* 30 Z ZZZ SEARCH DATA HIGH(10) */
320 { 0x30, D | W | R | O, "SEARCH DATA HIGH(10)" },
321 /* 31 Z ZZZ SEARCH DATA EQUAL(10) */
322 { 0x31, D | W | R | O, "SEARCH DATA EQUAL(10)" },
323 /* 31 OBJECT POSITION */
324 { 0x31, S, "OBJECT POSITION" },
325 /* 32 Z ZZZ SEARCH DATA LOW(10) */
326 { 0x32, D | W | R | O, "SEARCH DATA LOW(10)" },
327 /* 33 Z OZO SET LIMITS(10) */
328 { 0x33, D | W | R | O, "SET LIMITS(10)" },
329 /* 34 O O O O PRE-FETCH(10) */
330 { 0x34, D | W | O | K, "PRE-FETCH(10)" },
331 /* 34 M READ POSITION */
332 { 0x34, T, "READ POSITION" },
333 /* 34 GET DATA BUFFER STATUS */
334 { 0x34, S, "GET DATA BUFFER STATUS" },
335 /* 35 O OOO MO SYNCHRONIZE CACHE(10) */
336 { 0x35, D | W | R | O | B | K, "SYNCHRONIZE CACHE(10)" },
337 /* 36 Z O O O LOCK UNLOCK CACHE(10) */
338 { 0x36, D | W | O | K, "LOCK UNLOCK CACHE(10)" },
339 /* 37 O O READ DEFECT DATA(10) */
340 { 0x37, D | O, "READ DEFECT DATA(10)" },
341 /* 37 O INITIALIZE ELEMENT STATUS WITH RANGE */
342 { 0x37, M, "INITIALIZE ELEMENT STATUS WITH RANGE" },
343 /* 38 O O O MEDIUM SCAN */
344 { 0x38, W | O | K, "MEDIUM SCAN" },
345 /* 39 ZZZZOZO Z COMPARE */
346 { 0x39, D | T | L | P | W | R | O | K | S, "COMPARE" },
347 /* 3A ZZZZOZO Z COPY AND VERIFY */
348 { 0x3A, D | T | L | P | W | R | O | K | S, "COPY AND VERIFY" },
349 /* 3B OOOOOOOOOOMOOO WRITE BUFFER */
350 { 0x3B, ALL, "WRITE BUFFER" },
351 /* 3C OOOOOOOOOO OOO READ BUFFER */
352 { 0x3C, ALL & ~(B), "READ BUFFER" },
353 /* 3D O UPDATE BLOCK */
354 { 0x3D, O, "UPDATE BLOCK" },
355 /* 3E O O O READ LONG(10) */
356 { 0x3E, D | W | O, "READ LONG(10)" },
357 /* 3F O O O WRITE LONG(10) */
358 { 0x3F, D | W | O, "WRITE LONG(10)" },
359 /* 40 ZZZZOZOZ CHANGE DEFINITION */
360 { 0x40, D | T | L | P | W | R | O | M | S | C, "CHANGE DEFINITION" },
361 /* 41 O WRITE SAME(10) */
362 { 0x41, D, "WRITE SAME(10)" },
363 /* 42 O READ SUB-CHANNEL */
364 { 0x42, R, "READ SUB-CHANNEL" },
365 /* 43 O READ TOC/PMA/ATIP */
366 { 0x43, R, "READ TOC/PMA/ATIP" },
367 /* 44 M M REPORT DENSITY SUPPORT */
368 { 0x44, T | V, "REPORT DENSITY SUPPORT" },
369 /* 44 READ HEADER */
370 /* 45 O PLAY AUDIO(10) */
371 { 0x45, R, "PLAY AUDIO(10)" },
372 /* 46 M GET CONFIGURATION */
373 { 0x46, R, "GET CONFIGURATION" },
374 /* 47 O PLAY AUDIO MSF */
375 { 0x47, R, "PLAY AUDIO MSF" },
376 /* 48 */
377 /* 49 */
378 /* 4A M GET EVENT STATUS NOTIFICATION */
379 { 0x4A, R, "GET EVENT STATUS NOTIFICATION" },
380 /* 4B O PAUSE/RESUME */
381 { 0x4B, R, "PAUSE/RESUME" },
382 /* 4C OOOOO OOOO OOO LOG SELECT */
383 { 0x4C, ALL & ~(R | B), "LOG SELECT" },
384 /* 4D OOOOO OOOO OMO LOG SENSE */
385 { 0x4D, ALL & ~(R | B), "LOG SENSE" },
386 /* 4E O STOP PLAY/SCAN */
387 { 0x4E, R, "STOP PLAY/SCAN" },
388 /* 4F */
389 /* 50 O XDWRITE(10) */
390 { 0x50, D, "XDWRITE(10)" },
391 /* 51 O XPWRITE(10) */
392 { 0x51, D, "XPWRITE(10)" },
393 /* 51 O READ DISC INFORMATION */
394 { 0x51, R, "READ DISC INFORMATION" },
395 /* 52 O XDREAD(10) */
396 { 0x52, D, "XDREAD(10)" },
397 /* 52 O READ TRACK INFORMATION */
398 { 0x52, R, "READ TRACK INFORMATION" },
399 /* 53 O RESERVE TRACK */
400 { 0x53, R, "RESERVE TRACK" },
401 /* 54 O SEND OPC INFORMATION */
402 { 0x54, R, "SEND OPC INFORMATION" },
403 /* 55 OOO OMOOOOMOMO MODE SELECT(10) */
404 { 0x55, ALL & ~(P), "MODE SELECT(10)" },
405 /* 56 ZZMZO OOOZ RESERVE(10) */
406 { 0x56, ALL & ~(R | B | K | V | F | C), "RESERVE(10)" },
407 /* 56 Z RESERVE ELEMENT(10) */
408 { 0x56, M, "RESERVE ELEMENT(10)" },
409 /* 57 ZZMZO OOOZ RELEASE(10) */
410 { 0x57, ALL & ~(R | B | K | V | F | C), "RELEASE(10)" },
411 /* 57 Z RELEASE ELEMENT(10) */
412 { 0x57, M, "RELEASE ELEMENT(10)" },
413 /* 58 O REPAIR TRACK */
414 { 0x58, R, "REPAIR TRACK" },
415 /* 59 */
416 /* 5A OOO OMOOOOMOMO MODE SENSE(10) */
417 { 0x5A, ALL & ~(P), "MODE SENSE(10)" },
418 /* 5B O CLOSE TRACK/SESSION */
419 { 0x5B, R, "CLOSE TRACK/SESSION" },
420 /* 5C O READ BUFFER CAPACITY */
421 { 0x5C, R, "READ BUFFER CAPACITY" },
422 /* 5D O SEND CUE SHEET */
423 { 0x5D, R, "SEND CUE SHEET" },
424 /* 5E OOOOO OOOO M PERSISTENT RESERVE IN */
425 { 0x5E, ALL & ~(R | B | K | V | C), "PERSISTENT RESERVE IN" },
426 /* 5F OOOOO OOOO M PERSISTENT RESERVE OUT */
427 { 0x5F, ALL & ~(R | B | K | V | C), "PERSISTENT RESERVE OUT" },
428 /* 7E OO O OOOO O extended CDB */
429 { 0x7E, D | T | R | M | A | E | B | V, "extended CDB" },
430 /* 7F O M variable length CDB (more than 16 bytes) */
431 { 0x7F, D | F, "variable length CDB (more than 16 bytes)" },
432 /* 80 Z XDWRITE EXTENDED(16) */
433 { 0x80, D, "XDWRITE EXTENDED(16)" },
434 /* 80 M WRITE FILEMARKS(16) */
435 { 0x80, T, "WRITE FILEMARKS(16)" },
436 /* 81 Z REBUILD(16) */
437 { 0x81, D, "REBUILD(16)" },
438 /* 81 O READ REVERSE(16) */
439 { 0x81, T, "READ REVERSE(16)" },
440 /* 82 Z REGENERATE(16) */
441 { 0x82, D, "REGENERATE(16)" },
442 /* 83 OOOOO O OO EXTENDED COPY */
443 { 0x83, D | T | L | P | W | O | K | V, "EXTENDED COPY" },
444 /* 84 OOOOO O OO RECEIVE COPY RESULTS */
445 { 0x84, D | T | L | P | W | O | K | V, "RECEIVE COPY RESULTS" },
446 /* 85 O O O ATA COMMAND PASS THROUGH(16) */
447 { 0x85, D | R | B, "ATA COMMAND PASS THROUGH(16)" },
448 /* 86 OO OO OOOOOOO ACCESS CONTROL IN */
449 { 0x86, ALL & ~(L | R | F), "ACCESS CONTROL IN" },
450 /* 87 OO OO OOOOOOO ACCESS CONTROL OUT */
451 { 0x87, ALL & ~(L | R | F), "ACCESS CONTROL OUT" },
452 /*
453 * XXX READ(16)/WRITE(16) were not listed for CD/DVE in op-num.txt
454 * but we had it since r1.40. Do we really want them?
455 */
456 /* 88 MM O O O READ(16) */
457 { 0x88, D | T | W | O | B, "READ(16)" },
458 /* 89 */
459 /* 8A OM O O O WRITE(16) */
460 { 0x8A, D | T | W | O | B, "WRITE(16)" },
461 /* 8B O ORWRITE */
462 { 0x8B, D, "ORWRITE" },
463 /* 8C OO O OO O M READ ATTRIBUTE */
464 { 0x8C, D | T | W | O | M | B | V, "READ ATTRIBUTE" },
465 /* 8D OO O OO O O WRITE ATTRIBUTE */
466 { 0x8D, D | T | W | O | M | B | V, "WRITE ATTRIBUTE" },
467 /* 8E O O O O WRITE AND VERIFY(16) */
468 { 0x8E, D | W | O | B, "WRITE AND VERIFY(16)" },
469 /* 8F OO O O O VERIFY(16) */
470 { 0x8F, D | T | W | O | B, "VERIFY(16)" },
471 /* 90 O O O O PRE-FETCH(16) */
472 { 0x90, D | W | O | B, "PRE-FETCH(16)" },
473 /* 91 O O O O SYNCHRONIZE CACHE(16) */
474 { 0x91, D | W | O | B, "SYNCHRONIZE CACHE(16)" },
475 /* 91 O SPACE(16) */
476 { 0x91, T, "SPACE(16)" },
477 /* 92 Z O O LOCK UNLOCK CACHE(16) */
478 { 0x92, D | W | O, "LOCK UNLOCK CACHE(16)" },
479 /* 92 O LOCATE(16) */
480 { 0x92, T, "LOCATE(16)" },
481 /* 93 O WRITE SAME(16) */
482 { 0x93, D, "WRITE SAME(16)" },
483 /* 93 M ERASE(16) */
484 { 0x93, T, "ERASE(16)" },
485 /* 94 [usage proposed by SCSI Socket Services project] */
486 /* 95 [usage proposed by SCSI Socket Services project] */
487 /* 96 [usage proposed by SCSI Socket Services project] */
488 /* 97 [usage proposed by SCSI Socket Services project] */
489 /* 98 */
490 /* 99 */
491 /* 9A */
492 /* 9B */
493 /* 9C */
494 /* 9D */
495 /* XXX KDM ALL for this? op-num.txt defines it for none.. */
496 /* 9E SERVICE ACTION IN(16) */
497 { 0x9E, ALL, "SERVICE ACTION IN(16)" },
498 /* XXX KDM ALL for this? op-num.txt defines it for ADC.. */
499 /* 9F M SERVICE ACTION OUT(16) */
500 { 0x9F, ALL, "SERVICE ACTION OUT(16)" },
501 /* A0 MMOOO OMMM OMO REPORT LUNS */
502 { 0xA0, ALL & ~(R | B), "REPORT LUNS" },
503 /* A1 O BLANK */
504 { 0xA1, R, "BLANK" },
505 /* A1 O O ATA COMMAND PASS THROUGH(12) */
506 { 0xA1, D | B, "ATA COMMAND PASS THROUGH(12)" },
507 /* A2 OO O O SECURITY PROTOCOL IN */
508 { 0xA2, D | T | R | V, "SECURITY PROTOCOL IN" },
509 /* A3 OOO O OOMOOOM MAINTENANCE (IN) */
510 { 0xA3, ALL & ~(P | R | F), "MAINTENANCE (IN)" },
511 /* A3 O SEND KEY */
512 { 0xA3, R, "SEND KEY" },
513 /* A4 OOO O OOOOOOO MAINTENANCE (OUT) */
514 { 0xA4, ALL & ~(P | R | F), "MAINTENANCE (OUT)" },
515 /* A4 O REPORT KEY */
516 { 0xA4, R, "REPORT KEY" },
517 /* A5 O O OM MOVE MEDIUM */
518 { 0xA5, T | W | O | M, "MOVE MEDIUM" },
519 /* A5 O PLAY AUDIO(12) */
520 { 0xA5, R, "PLAY AUDIO(12)" },
521 /* A6 O EXCHANGE MEDIUM */
522 { 0xA6, M, "EXCHANGE MEDIUM" },
523 /* A6 O LOAD/UNLOAD C/DVD */
524 { 0xA6, R, "LOAD/UNLOAD C/DVD" },
525 /* A7 ZZ O O MOVE MEDIUM ATTACHED */
526 { 0xA7, D | T | W | O, "MOVE MEDIUM ATTACHED" },
527 /* A7 O SET READ AHEAD */
528 { 0xA7, R, "SET READ AHEAD" },
529 /* A8 O OOO READ(12) */
530 { 0xA8, D | W | R | O, "READ(12)" },
531 /* A8 GET MESSAGE(12) */
532 { 0xA8, C, "GET MESSAGE(12)" },
533 /* A9 O SERVICE ACTION OUT(12) */
534 { 0xA9, V, "SERVICE ACTION OUT(12)" },
535 /* AA O OOO WRITE(12) */
536 { 0xAA, D | W | R | O, "WRITE(12)" },
537 /* AA SEND MESSAGE(12) */
538 { 0xAA, C, "SEND MESSAGE(12)" },
539 /* AB O O SERVICE ACTION IN(12) */
540 { 0xAB, R | V, "SERVICE ACTION IN(12)" },
541 /* AC O ERASE(12) */
542 { 0xAC, O, "ERASE(12)" },
543 /* AC O GET PERFORMANCE */
544 { 0xAC, R, "GET PERFORMANCE" },
545 /* AD O READ DVD STRUCTURE */
546 { 0xAD, R, "READ DVD STRUCTURE" },
547 /* AE O O O WRITE AND VERIFY(12) */
548 { 0xAE, D | W | O, "WRITE AND VERIFY(12)" },
549 /* AF O OZO VERIFY(12) */
550 { 0xAF, D | W | R | O, "VERIFY(12)" },
551 /* B0 ZZZ SEARCH DATA HIGH(12) */
552 { 0xB0, W | R | O, "SEARCH DATA HIGH(12)" },
553 /* B1 ZZZ SEARCH DATA EQUAL(12) */
554 { 0xB1, W | R | O, "SEARCH DATA EQUAL(12)" },
555 /* B2 ZZZ SEARCH DATA LOW(12) */
556 { 0xB2, W | R | O, "SEARCH DATA LOW(12)" },
557 /* B3 Z OZO SET LIMITS(12) */
558 { 0xB3, D | W | R | O, "SET LIMITS(12)" },
559 /* B4 ZZ OZO READ ELEMENT STATUS ATTACHED */
560 { 0xB4, D | T | W | R | O, "READ ELEMENT STATUS ATTACHED" },
561 /* B5 OO O O SECURITY PROTOCOL OUT */
562 { 0xB5, D | T | R | V, "SECURITY PROTOCOL OUT" },
563 /* B5 O REQUEST VOLUME ELEMENT ADDRESS */
564 { 0xB5, M, "REQUEST VOLUME ELEMENT ADDRESS" },
565 /* B6 O SEND VOLUME TAG */
566 { 0xB6, M, "SEND VOLUME TAG" },
567 /* B6 O SET STREAMING */
568 { 0xB6, R, "SET STREAMING" },
569 /* B7 O O READ DEFECT DATA(12) */
570 { 0xB7, D | O, "READ DEFECT DATA(12)" },
571 /* B8 O OZOM READ ELEMENT STATUS */
572 { 0xB8, T | W | R | O | M, "READ ELEMENT STATUS" },
573 /* B9 O READ CD MSF */
574 { 0xB9, R, "READ CD MSF" },
575 /* BA O O OOMO REDUNDANCY GROUP (IN) */
576 { 0xBA, D | W | O | M | A | E, "REDUNDANCY GROUP (IN)" },
577 /* BA O SCAN */
578 { 0xBA, R, "SCAN" },
579 /* BB O O OOOO REDUNDANCY GROUP (OUT) */
580 { 0xBB, D | W | O | M | A | E, "REDUNDANCY GROUP (OUT)" },
581 /* BB O SET CD SPEED */
582 { 0xBB, R, "SET CD SPEED" },
583 /* BC O O OOMO SPARE (IN) */
584 { 0xBC, D | W | O | M | A | E, "SPARE (IN)" },
585 /* BD O O OOOO SPARE (OUT) */
586 { 0xBD, D | W | O | M | A | E, "SPARE (OUT)" },
587 /* BD O MECHANISM STATUS */
588 { 0xBD, R, "MECHANISM STATUS" },
589 /* BE O O OOMO VOLUME SET (IN) */
590 { 0xBE, D | W | O | M | A | E, "VOLUME SET (IN)" },
591 /* BE O READ CD */
592 { 0xBE, R, "READ CD" },
593 /* BF O O OOOO VOLUME SET (OUT) */
594 { 0xBF, D | W | O | M | A | E, "VOLUME SET (OUT)" },
595 /* BF O SEND DVD STRUCTURE */
596 { 0xBF, R, "SEND DVD STRUCTURE" }
597 };
598
599 const char *
600 scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
601 {
602 caddr_t match;
603 int i, j;
604 u_int32_t opmask;
605 u_int16_t pd_type;
606 int num_ops[2];
607 struct op_table_entry *table[2];
608 int num_tables;
609
610 pd_type = SID_TYPE(inq_data);
611
612 match = cam_quirkmatch((caddr_t)inq_data,
613 (caddr_t)scsi_op_quirk_table,
614 sizeof(scsi_op_quirk_table)/
615 sizeof(*scsi_op_quirk_table),
616 sizeof(*scsi_op_quirk_table),
617 scsi_inquiry_match);
618
619 if (match != NULL) {
620 table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
621 num_ops[0] = ((struct scsi_op_quirk_entry *)match)->num_ops;
622 table[1] = scsi_op_codes;
623 num_ops[1] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
624 num_tables = 2;
625 } else {
626 /*
627 * If this is true, we have a vendor specific opcode that
628 * wasn't covered in the quirk table.
629 */
630 if ((opcode > 0xBF) || ((opcode > 0x5F) && (opcode < 0x80)))
631 return("Vendor Specific Command");
632
633 table[0] = scsi_op_codes;
634 num_ops[0] = sizeof(scsi_op_codes)/sizeof(scsi_op_codes[0]);
635 num_tables = 1;
636 }
637
638 /* RBC is 'Simplified' Direct Access Device */
639 if (pd_type == T_RBC)
640 pd_type = T_DIRECT;
641
642 opmask = 1 << pd_type;
643
644 for (j = 0; j < num_tables; j++) {
645 for (i = 0;i < num_ops[j] && table[j][i].opcode <= opcode; i++){
646 if ((table[j][i].opcode == opcode)
647 && ((table[j][i].opmask & opmask) != 0))
648 return(table[j][i].desc);
649 }
650 }
651
652 /*
653 * If we can't find a match for the command in the table, we just
654 * assume it's a vendor specifc command.
655 */
656 return("Vendor Specific Command");
657
658 }
659
660 #else /* SCSI_NO_OP_STRINGS */
661
662 const char *
663 scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
664 {
665 return("");
666 }
667
668 #endif
669
670
671 #if !defined(SCSI_NO_SENSE_STRINGS)
672 #define SST(asc, ascq, action, desc) \
673 asc, ascq, action, desc
674 #else
675 const char empty_string[] = "";
676
677 #define SST(asc, ascq, action, desc) \
678 asc, ascq, action, empty_string
679 #endif
680
681 const struct sense_key_table_entry sense_key_table[] =
682 {
683 { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
684 { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
685 {
686 SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
687 "NOT READY"
688 },
689 { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
690 { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
691 { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
692 { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" },
693 { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" },
694 { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" },
695 { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" },
696 { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" },
697 { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" },
698 { SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
699 { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
700 { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
701 { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
702 };
703
704 const int sense_key_table_size =
705 sizeof(sense_key_table)/sizeof(sense_key_table[0]);
706
707 static struct asc_table_entry quantum_fireball_entries[] = {
708 { SST(0x04, 0x0b, SS_START | SSQ_DECREMENT_COUNT | ENXIO,
709 "Logical unit not ready, initializing cmd. required") }
710 };
711
712 static struct asc_table_entry sony_mo_entries[] = {
713 { SST(0x04, 0x00, SS_START | SSQ_DECREMENT_COUNT | ENXIO,
714 "Logical unit not ready, cause not reportable") }
715 };
716
717 static struct scsi_sense_quirk_entry sense_quirk_table[] = {
718 {
719 /*
720 * XXX The Quantum Fireball ST and SE like to return 0x04 0x0b
721 * when they really should return 0x04 0x02.
722 */
723 {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
724 /*num_sense_keys*/0,
725 sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
726 /*sense key entries*/NULL,
727 quantum_fireball_entries
728 },
729 {
730 /*
731 * This Sony MO drive likes to return 0x04, 0x00 when it
732 * isn't spun up.
733 */
734 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
735 /*num_sense_keys*/0,
736 sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
737 /*sense key entries*/NULL,
738 sony_mo_entries
739 }
740 };
741
742 const int sense_quirk_table_size =
743 sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
744
745 static struct asc_table_entry asc_table[] = {
746 /*
747 * From: http://www.t10.org/lists/asc-num.txt
748 * Modifications by Jung-uk Kim (jkim@FreeBSD.org)
749 */
750 /*
751 * File: ASC-NUM.TXT
752 *
753 * SCSI ASC/ASCQ Assignments
754 * Numeric Sorted Listing
755 * as of 7/29/08
756 *
757 * D - DIRECT ACCESS DEVICE (SBC-2) device column key
758 * .T - SEQUENTIAL ACCESS DEVICE (SSC) -------------------
759 * . L - PRINTER DEVICE (SSC) blank = reserved
760 * . P - PROCESSOR DEVICE (SPC) not blank = allowed
761 * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2)
762 * . . R - CD DEVICE (MMC)
763 * . . O - OPTICAL MEMORY DEVICE (SBC-2)
764 * . . .M - MEDIA CHANGER DEVICE (SMC)
765 * . . . A - STORAGE ARRAY DEVICE (SCC)
766 * . . . E - ENCLOSURE SERVICES DEVICE (SES)
767 * . . . .B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC)
768 * . . . . K - OPTICAL CARD READER/WRITER DEVICE (OCRW)
769 * . . . . V - AUTOMATION/DRIVE INTERFACE (ADC)
770 * . . . . .F - OBJECT-BASED STORAGE (OSD)
771 * DTLPWROMAEBKVF
772 * ASC ASCQ Action
773 * Description
774 */
775 /* DTLPWROMAEBKVF */
776 { SST(0x00, 0x00, SS_NOP,
777 "No additional sense information") },
778 /* T */
779 { SST(0x00, 0x01, SS_RDEF,
780 "Filemark detected") },
781 /* T */
782 { SST(0x00, 0x02, SS_RDEF,
783 "End-of-partition/medium detected") },
784 /* T */
785 { SST(0x00, 0x03, SS_RDEF,
786 "Setmark detected") },
787 /* T */
788 { SST(0x00, 0x04, SS_RDEF,
789 "Beginning-of-partition/medium detected") },
790 /* TL */
791 { SST(0x00, 0x05, SS_RDEF,
792 "End-of-data detected") },
793 /* DTLPWROMAEBKVF */
794 { SST(0x00, 0x06, SS_RDEF,
795 "I/O process terminated") },
796 /* T */
797 { SST(0x00, 0x07, SS_RDEF, /* XXX TBD */
798 "Programmable early warning detected") },
799 /* R */
800 { SST(0x00, 0x11, SS_FATAL | EBUSY,
801 "Audio play operation in progress") },
802 /* R */
803 { SST(0x00, 0x12, SS_NOP,
804 "Audio play operation paused") },
805 /* R */
806 { SST(0x00, 0x13, SS_NOP,
807 "Audio play operation successfully completed") },
808 /* R */
809 { SST(0x00, 0x14, SS_RDEF,
810 "Audio play operation stopped due to error") },
811 /* R */
812 { SST(0x00, 0x15, SS_NOP,
813 "No current audio status to return") },
814 /* DTLPWROMAEBKVF */
815 { SST(0x00, 0x16, SS_FATAL | EBUSY,
816 "Operation in progress") },
817 /* DTL WROMAEBKVF */
818 { SST(0x00, 0x17, SS_RDEF,
819 "Cleaning requested") },
820 /* T */
821 { SST(0x00, 0x18, SS_RDEF, /* XXX TBD */
822 "Erase operation in progress") },
823 /* T */
824 { SST(0x00, 0x19, SS_RDEF, /* XXX TBD */
825 "Locate operation in progress") },
826 /* T */
827 { SST(0x00, 0x1A, SS_RDEF, /* XXX TBD */
828 "Rewind operation in progress") },
829 /* T */
830 { SST(0x00, 0x1B, SS_RDEF, /* XXX TBD */
831 "Set capacity operation in progress") },
832 /* T */
833 { SST(0x00, 0x1C, SS_RDEF, /* XXX TBD */
834 "Verify operation in progress") },
835 /* DT B */
836 { SST(0x00, 0x1D, SS_RDEF, /* XXX TBD */
837 "ATA pass through information available") },
838 /* DT R MAEBKV */
839 { SST(0x00, 0x1E, SS_RDEF, /* XXX TBD */
840 "Conflicting SA creation request") },
841 /* D W O BK */
842 { SST(0x01, 0x00, SS_RDEF,
843 "No index/sector signal") },
844 /* D WRO BK */
845 { SST(0x02, 0x00, SS_RDEF,
846 "No seek complete") },
847 /* DTL W O BK */
848 { SST(0x03, 0x00, SS_RDEF,
849 "Peripheral device write fault") },
850 /* T */
851 { SST(0x03, 0x01, SS_RDEF,
852 "No write current") },
853 /* T */
854 { SST(0x03, 0x02, SS_RDEF,
855 "Excessive write errors") },
856 /* DTLPWROMAEBKVF */
857 { SST(0x04, 0x00, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EIO,
858 "Logical unit not ready, cause not reportable") },
859 /* DTLPWROMAEBKVF */
860 { SST(0x04, 0x01, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY,
861 "Logical unit is in process of becoming ready") },
862 /* DTLPWROMAEBKVF */
863 { SST(0x04, 0x02, SS_START | SSQ_DECREMENT_COUNT | ENXIO,
864 "Logical unit not ready, initializing command required") },
865 /* DTLPWROMAEBKVF */
866 { SST(0x04, 0x03, SS_FATAL | ENXIO,
867 "Logical unit not ready, manual intervention required") },
868 /* DTL RO B */
869 { SST(0x04, 0x04, SS_FATAL | EBUSY,
870 "Logical unit not ready, format in progress") },
871 /* DT W O A BK F */
872 { SST(0x04, 0x05, SS_FATAL | EBUSY,
873 "Logical unit not ready, rebuild in progress") },
874 /* DT W O A BK */
875 { SST(0x04, 0x06, SS_FATAL | EBUSY,
876 "Logical unit not ready, recalculation in progress") },
877 /* DTLPWROMAEBKVF */
878 { SST(0x04, 0x07, SS_FATAL | EBUSY,
879 "Logical unit not ready, operation in progress") },
880 /* R */
881 { SST(0x04, 0x08, SS_FATAL | EBUSY,
882 "Logical unit not ready, long write in progress") },
883 /* DTLPWROMAEBKVF */
884 { SST(0x04, 0x09, SS_RDEF, /* XXX TBD */
885 "Logical unit not ready, self-test in progress") },
886 /* DTLPWROMAEBKVF */
887 { SST(0x04, 0x0A, SS_RDEF, /* XXX TBD */
888 "Logical unit not accessible, asymmetric access state transition")},
889 /* DTLPWROMAEBKVF */
890 { SST(0x04, 0x0B, SS_RDEF, /* XXX TBD */
891 "Logical unit not accessible, target port in standby state") },
892 /* DTLPWROMAEBKVF */
893 { SST(0x04, 0x0C, SS_RDEF, /* XXX TBD */
894 "Logical unit not accessible, target port in unavailable state") },
895 /* F */
896 { SST(0x04, 0x0D, SS_RDEF, /* XXX TBD */
897 "Logical unit not ready, structure check required") },
898 /* DT WROM B */
899 { SST(0x04, 0x10, SS_RDEF, /* XXX TBD */
900 "Logical unit not ready, auxiliary memory not accessible") },
901 /* DT WRO AEB VF */
902 { SST(0x04, 0x11, SS_RDEF, /* XXX TBD */
903 "Logical unit not ready, notify (enable spinup) required") },
904 /* M V */
905 { SST(0x04, 0x12, SS_RDEF, /* XXX TBD */
906 "Logical unit not ready, offline") },
907 /* DT R MAEBKV */
908 { SST(0x04, 0x13, SS_RDEF, /* XXX TBD */
909 "Logical unit not ready, SA creation in progress") },
910 /* DTL WROMAEBKVF */
911 { SST(0x05, 0x00, SS_RDEF,
912 "Logical unit does not respond to selection") },
913 /* D WROM BK */
914 { SST(0x06, 0x00, |