1
2
3
4
5
6
7
8
9
10#include <linux/blkdev.h>
11#include <linux/module.h>
12#include <linux/kernel.h>
13
14#include <scsi/scsi.h>
15#include <scsi/scsi_cmnd.h>
16#include <scsi/scsi_device.h>
17#include <scsi/scsi_host.h>
18#include <scsi/scsi_eh.h>
19#include <scsi/scsi_dbg.h>
20
21
22#define THIRD_PARTY_COPY_OUT 0x83
23#define THIRD_PARTY_COPY_IN 0x84
24
25struct sa_name_list {
26 int opcode;
27 const struct value_name_pair *arr;
28 int arr_sz;
29};
30
31struct value_name_pair {
32 int value;
33 const char * name;
34};
35
36static const char * cdb_byte0_names[] = {
37 "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
38 "Format Unit/Medium", "Read Block Limits", NULL,
39 "Reassign Blocks",
40 "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
41 NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
42 "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
43 "Reserve(6)",
44 "Release(6)", "Copy", "Erase", "Mode Sense(6)",
45 "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
46 "Prevent/Allow Medium Removal", NULL,
47 NULL, NULL, NULL,
48 "Read Format Capacities", "Set Window",
49 "Read Capacity(10)", NULL, NULL, "Read(10)",
50 "Read Generation", "Write(10)", "Seek(10)", "Erase(10)",
51 "Read updated block",
52 "Write Verify(10)", "Verify(10)", "Search High", "Search Equal",
53 "Search Low", "Set Limits", "Prefetch/Read Position",
54 "Synchronize Cache(10)", "Lock/Unlock Cache(10)",
55 "Read Defect Data(10)",
56 "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
57 "Read Buffer",
58 "Update Block", "Read Long(10)", "Write Long(10)",
59 "Change Definition", "Write Same(10)",
60 "Unmap/Read sub-channel", "Read TOC/PMA/ATIP",
61 "Read density support", "Play audio(10)", "Get configuration",
62 "Play audio msf", "Sanitize/Play audio track/index",
63 "Play track relative(10)", "Get event status notification",
64 "Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
65 NULL,
66 "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info",
67 "Reserve track", "Send OPC info", "Mode Select(10)",
68 "Reserve(10)", "Release(10)", "Repair track", "Read master cue",
69 "Mode Sense(10)", "Close track/session",
70 "Read buffer capacity", "Send cue sheet", "Persistent reserve in",
71 "Persistent reserve out",
72 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
73 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
74 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
75 NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB",
76 "Variable length",
77 "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)",
78 "Third party copy out", "Third party copy in",
79 "ATA command pass through(16)", "Access control in",
80 "Access control out", "Read(16)", "Compare and Write",
81 "Write(16)", "ORWrite", "Read attributes", "Write attributes",
82 "Write and verify(16)", "Verify(16)",
83 "Pre-fetch(16)", "Synchronize cache(16)",
84 "Lock/unlock cache(16)", "Write same(16)", NULL,
85 NULL, NULL, NULL, NULL, NULL,
86 NULL, NULL, NULL, "Service action bidirectional",
87 "Service action in(16)", "Service action out(16)",
88 "Report luns", "ATA command pass through(12)/Blank",
89 "Security protocol in", "Maintenance in", "Maintenance out",
90 "Move medium/play audio(12)",
91 "Exchange medium", "Move medium attached", "Read(12)",
92 "Play track relative(12)",
93 "Write(12)", NULL, "Erase(12), Get Performance",
94 "Read DVD structure", "Write and verify(12)",
95 "Verify(12)", "Search data high(12)", "Search data equal(12)",
96 "Search data low(12)", "Set limits(12)",
97 "Read element status attached",
98 "Security protocol out", "Send volume tag, set streaming",
99 "Read defect data(12)", "Read element status", "Read CD msf",
100 "Redundancy group (in), Scan",
101 "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd",
102 "Spare (out), Mechanism status", "Volume set (in), Read cd",
103 "Volume set (out), Send DVD structure",
104};
105
106static const struct value_name_pair maint_in_arr[] = {
107 {0x5, "Report identifying information"},
108 {0xa, "Report target port groups"},
109 {0xb, "Report aliases"},
110 {0xc, "Report supported operation codes"},
111 {0xd, "Report supported task management functions"},
112 {0xe, "Report priority"},
113 {0xf, "Report timestamp"},
114 {0x10, "Management protocol in"},
115};
116#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr)
117
118static const struct value_name_pair maint_out_arr[] = {
119 {0x6, "Set identifying information"},
120 {0xa, "Set target port groups"},
121 {0xb, "Change aliases"},
122 {0xc, "Remove I_T nexus"},
123 {0xe, "Set priority"},
124 {0xf, "Set timestamp"},
125 {0x10, "Management protocol out"},
126};
127#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr)
128
129static const struct value_name_pair serv_in12_arr[] = {
130 {0x1, "Read media serial number"},
131};
132#define SERV_IN12_SZ ARRAY_SIZE(serv_in12_arr)
133
134static const struct value_name_pair serv_out12_arr[] = {
135 {-1, "dummy entry"},
136};
137#define SERV_OUT12_SZ ARRAY_SIZE(serv_out12_arr)
138
139static const struct value_name_pair serv_bidi_arr[] = {
140 {-1, "dummy entry"},
141};
142#define SERV_BIDI_SZ ARRAY_SIZE(serv_bidi_arr)
143
144static const struct value_name_pair serv_in16_arr[] = {
145 {0x10, "Read capacity(16)"},
146 {0x11, "Read long(16)"},
147 {0x12, "Get LBA status"},
148 {0x13, "Report referrals"},
149};
150#define SERV_IN16_SZ ARRAY_SIZE(serv_in16_arr)
151
152static const struct value_name_pair serv_out16_arr[] = {
153 {0x11, "Write long(16)"},
154 {0x1f, "Notify data transfer device(16)"},
155};
156#define SERV_OUT16_SZ ARRAY_SIZE(serv_out16_arr)
157
158static const struct value_name_pair pr_in_arr[] = {
159 {0x0, "Persistent reserve in, read keys"},
160 {0x1, "Persistent reserve in, read reservation"},
161 {0x2, "Persistent reserve in, report capabilities"},
162 {0x3, "Persistent reserve in, read full status"},
163};
164#define PR_IN_SZ ARRAY_SIZE(pr_in_arr)
165
166static const struct value_name_pair pr_out_arr[] = {
167 {0x0, "Persistent reserve out, register"},
168 {0x1, "Persistent reserve out, reserve"},
169 {0x2, "Persistent reserve out, release"},
170 {0x3, "Persistent reserve out, clear"},
171 {0x4, "Persistent reserve out, preempt"},
172 {0x5, "Persistent reserve out, preempt and abort"},
173 {0x6, "Persistent reserve out, register and ignore existing key"},
174 {0x7, "Persistent reserve out, register and move"},
175};
176#define PR_OUT_SZ ARRAY_SIZE(pr_out_arr)
177
178
179
180
181static const struct value_name_pair tpc_out_arr[] = {
182 {0x0, "Extended copy(LID1)"},
183 {0x1, "Extended copy(LID4)"},
184 {0x10, "Populate token"},
185 {0x11, "Write using token"},
186 {0x1c, "Copy operation abort"},
187};
188#define TPC_OUT_SZ ARRAY_SIZE(tpc_out_arr)
189
190static const struct value_name_pair tpc_in_arr[] = {
191 {0x0, "Receive copy status(LID1)"},
192 {0x1, "Receive copy data(LID1)"},
193 {0x3, "Receive copy operating parameters"},
194 {0x4, "Receive copy failure details(LID1)"},
195 {0x5, "Receive copy status(LID4)"},
196 {0x6, "Receive copy data(LID4)"},
197 {0x7, "Receive ROD token information"},
198 {0x8, "Report all ROD tokens"},
199};
200#define TPC_IN_SZ ARRAY_SIZE(tpc_in_arr)
201
202
203static const struct value_name_pair variable_length_arr[] = {
204 {0x1, "Rebuild(32)"},
205 {0x2, "Regenerate(32)"},
206 {0x3, "Xdread(32)"},
207 {0x4, "Xdwrite(32)"},
208 {0x5, "Xdwrite extended(32)"},
209 {0x6, "Xpwrite(32)"},
210 {0x7, "Xdwriteread(32)"},
211 {0x8, "Xdwrite extended(64)"},
212 {0x9, "Read(32)"},
213 {0xa, "Verify(32)"},
214 {0xb, "Write(32)"},
215 {0xc, "Write an verify(32)"},
216 {0xd, "Write same(32)"},
217 {0x8801, "Format OSD"},
218 {0x8802, "Create (osd)"},
219 {0x8803, "List (osd)"},
220 {0x8805, "Read (osd)"},
221 {0x8806, "Write (osd)"},
222 {0x8807, "Append (osd)"},
223 {0x8808, "Flush (osd)"},
224 {0x880a, "Remove (osd)"},
225 {0x880b, "Create partition (osd)"},
226 {0x880c, "Remove partition (osd)"},
227 {0x880e, "Get attributes (osd)"},
228 {0x880f, "Set attributes (osd)"},
229 {0x8812, "Create and write (osd)"},
230 {0x8815, "Create collection (osd)"},
231 {0x8816, "Remove collection (osd)"},
232 {0x8817, "List collection (osd)"},
233 {0x8818, "Set key (osd)"},
234 {0x8819, "Set master key (osd)"},
235 {0x881a, "Flush collection (osd)"},
236 {0x881b, "Flush partition (osd)"},
237 {0x881c, "Flush OSD"},
238 {0x8f7e, "Perform SCSI command (osd)"},
239 {0x8f7f, "Perform task management function (osd)"},
240};
241#define VARIABLE_LENGTH_SZ ARRAY_SIZE(variable_length_arr)
242
243static struct sa_name_list sa_names_arr[] = {
244 {VARIABLE_LENGTH_CMD, variable_length_arr, VARIABLE_LENGTH_SZ},
245 {MAINTENANCE_IN, maint_in_arr, MAINT_IN_SZ},
246 {MAINTENANCE_OUT, maint_out_arr, MAINT_OUT_SZ},
247 {PERSISTENT_RESERVE_IN, pr_in_arr, PR_IN_SZ},
248 {PERSISTENT_RESERVE_OUT, pr_out_arr, PR_OUT_SZ},
249 {SERVICE_ACTION_IN_12, serv_in12_arr, SERV_IN12_SZ},
250 {SERVICE_ACTION_OUT_12, serv_out12_arr, SERV_OUT12_SZ},
251 {SERVICE_ACTION_BIDIRECTIONAL, serv_bidi_arr, SERV_BIDI_SZ},
252 {SERVICE_ACTION_IN_16, serv_in16_arr, SERV_IN16_SZ},
253 {SERVICE_ACTION_OUT_16, serv_out16_arr, SERV_OUT16_SZ},
254 {THIRD_PARTY_COPY_IN, tpc_in_arr, TPC_IN_SZ},
255 {THIRD_PARTY_COPY_OUT, tpc_out_arr, TPC_OUT_SZ},
256 {0, NULL, 0},
257};
258
259bool scsi_opcode_sa_name(int opcode, int service_action,
260 const char **cdb_name, const char **sa_name)
261{
262 struct sa_name_list *sa_name_ptr;
263 const struct value_name_pair *arr = NULL;
264 int arr_sz, k;
265
266 *cdb_name = NULL;
267 if (opcode >= VENDOR_SPECIFIC_CDB)
268 return false;
269
270 if (opcode < ARRAY_SIZE(cdb_byte0_names))
271 *cdb_name = cdb_byte0_names[opcode];
272
273 for (sa_name_ptr = sa_names_arr; sa_name_ptr->arr; ++sa_name_ptr) {
274 if (sa_name_ptr->opcode == opcode) {
275 arr = sa_name_ptr->arr;
276 arr_sz = sa_name_ptr->arr_sz;
277 break;
278 }
279 }
280 if (!arr)
281 return false;
282
283 for (k = 0; k < arr_sz; ++k, ++arr) {
284 if (service_action == arr->value)
285 break;
286 }
287 if (k < arr_sz)
288 *sa_name = arr->name;
289
290 return true;
291}
292
293struct error_info {
294 unsigned short code12;
295 unsigned short size;
296};
297
298
299
300
301
302
303
304
305
306static const struct error_info additional[] =
307{
308#define SENSE_CODE(c, s) {c, sizeof(s)},
309#include "sense_codes.h"
310#undef SENSE_CODE
311};
312
313static const char *additional_text =
314#define SENSE_CODE(c, s) s "\0"
315#include "sense_codes.h"
316#undef SENSE_CODE
317 ;
318
319struct error_info2 {
320 unsigned char code1, code2_min, code2_max;
321 const char * str;
322 const char * fmt;
323};
324
325static const struct error_info2 additional2[] =
326{
327 {0x40, 0x00, 0x7f, "Ram failure", ""},
328 {0x40, 0x80, 0xff, "Diagnostic failure on component", ""},
329 {0x41, 0x00, 0xff, "Data path failure", ""},
330 {0x42, 0x00, 0xff, "Power-on or self-test failure", ""},
331 {0x4D, 0x00, 0xff, "Tagged overlapped commands", "task tag "},
332 {0x70, 0x00, 0xff, "Decompression exception", "short algorithm id of "},
333 {0, 0, 0, NULL, NULL}
334};
335
336
337static const char * const snstext[] = {
338 "No Sense",
339 "Recovered Error",
340
341 "Not Ready",
342 "Medium Error",
343 "Hardware Error",
344 "Illegal Request",
345 "Unit Attention",
346
347 "Data Protect",
348 "Blank Check",
349
350 "Vendor Specific(9)",
351 "Copy Aborted",
352 "Aborted Command",
353 "Equal",
354
355 "Volume Overflow",
356 "Miscompare",
357
358 "Completed",
359
360};
361
362
363const char *
364scsi_sense_key_string(unsigned char key)
365{
366 if (key < ARRAY_SIZE(snstext))
367 return snstext[key];
368 return NULL;
369}
370EXPORT_SYMBOL(scsi_sense_key_string);
371
372
373
374
375
376const char *
377scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt)
378{
379 int i;
380 unsigned short code = ((asc << 8) | ascq);
381 unsigned offset = 0;
382
383 *fmt = NULL;
384 for (i = 0; i < ARRAY_SIZE(additional); i++) {
385 if (additional[i].code12 == code)
386 return additional_text + offset;
387 offset += additional[i].size;
388 }
389 for (i = 0; additional2[i].fmt; i++) {
390 if (additional2[i].code1 == asc &&
391 ascq >= additional2[i].code2_min &&
392 ascq <= additional2[i].code2_max) {
393 *fmt = additional2[i].fmt;
394 return additional2[i].str;
395 }
396 }
397 return NULL;
398}
399EXPORT_SYMBOL(scsi_extd_sense_format);
400
401static const char * const hostbyte_table[]={
402"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
403"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
404"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE",
405"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE",
406"DID_NEXUS_FAILURE" };
407
408static const char * const driverbyte_table[]={
409"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
410"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
411
412const char *scsi_hostbyte_string(int result)
413{
414 const char *hb_string = NULL;
415 int hb = host_byte(result);
416
417 if (hb < ARRAY_SIZE(hostbyte_table))
418 hb_string = hostbyte_table[hb];
419 return hb_string;
420}
421EXPORT_SYMBOL(scsi_hostbyte_string);
422
423const char *scsi_driverbyte_string(int result)
424{
425 const char *db_string = NULL;
426 int db = driver_byte(result);
427
428 if (db < ARRAY_SIZE(driverbyte_table))
429 db_string = driverbyte_table[db];
430 return db_string;
431}
432EXPORT_SYMBOL(scsi_driverbyte_string);
433
434#define scsi_mlreturn_name(result) { result, #result }
435static const struct value_name_pair scsi_mlreturn_arr[] = {
436 scsi_mlreturn_name(NEEDS_RETRY),
437 scsi_mlreturn_name(SUCCESS),
438 scsi_mlreturn_name(FAILED),
439 scsi_mlreturn_name(QUEUED),
440 scsi_mlreturn_name(SOFT_ERROR),
441 scsi_mlreturn_name(ADD_TO_MLQUEUE),
442 scsi_mlreturn_name(TIMEOUT_ERROR),
443 scsi_mlreturn_name(SCSI_RETURN_NOT_HANDLED),
444 scsi_mlreturn_name(FAST_IO_FAIL)
445};
446
447const char *scsi_mlreturn_string(int result)
448{
449 const struct value_name_pair *arr = scsi_mlreturn_arr;
450 int k;
451
452 for (k = 0; k < ARRAY_SIZE(scsi_mlreturn_arr); ++k, ++arr) {
453 if (result == arr->value)
454 return arr->name;
455 }
456 return NULL;
457}
458EXPORT_SYMBOL(scsi_mlreturn_string);
459