1
2
3
4
5
6#include <linux/bug.h>
7#include <linux/kernel.h>
8#include <linux/string.h>
9#include <linux/errno.h>
10#include <linux/module.h>
11#include <asm/unaligned.h>
12#include <scsi/scsi_common.h>
13
14MODULE_LICENSE("GPL v2");
15
16
17const unsigned char scsi_command_size_tbl[8] = {
18 6, 10, 10, 12, 16, 12, 10, 10
19};
20EXPORT_SYMBOL(scsi_command_size_tbl);
21
22
23
24
25
26static const char *const scsi_device_types[] = {
27 "Direct-Access ",
28 "Sequential-Access",
29 "Printer ",
30 "Processor ",
31 "WORM ",
32 "CD-ROM ",
33 "Scanner ",
34 "Optical Device ",
35 "Medium Changer ",
36 "Communications ",
37 "ASC IT8 ",
38 "ASC IT8 ",
39 "RAID ",
40 "Enclosure ",
41 "Direct-Access-RBC",
42 "Optical card ",
43 "Bridge controller",
44 "Object storage ",
45 "Automation/Drive ",
46 "Security Manager ",
47 "Direct-Access-ZBC",
48};
49
50
51
52
53
54const char *scsi_device_type(unsigned type)
55{
56 if (type == 0x1e)
57 return "Well-known LUN ";
58 if (type == 0x1f)
59 return "No Device ";
60 if (type >= ARRAY_SIZE(scsi_device_types))
61 return "Unknown ";
62 return scsi_device_types[type];
63}
64EXPORT_SYMBOL(scsi_device_type);
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86u64 scsilun_to_int(struct scsi_lun *scsilun)
87{
88 int i;
89 u64 lun;
90
91 lun = 0;
92 for (i = 0; i < sizeof(lun); i += 2)
93 lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |
94 ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));
95 return lun;
96}
97EXPORT_SYMBOL(scsilun_to_int);
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)
115{
116 int i;
117
118 memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
119
120 for (i = 0; i < sizeof(lun); i += 2) {
121 scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
122 scsilun->scsi_lun[i+1] = lun & 0xFF;
123 lun = lun >> 16;
124 }
125}
126EXPORT_SYMBOL(int_to_scsilun);
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
148 struct scsi_sense_hdr *sshdr)
149{
150 memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
151
152 if (!sense_buffer || !sb_len)
153 return false;
154
155 sshdr->response_code = (sense_buffer[0] & 0x7f);
156
157 if (!scsi_sense_valid(sshdr))
158 return false;
159
160 if (sshdr->response_code >= 0x72) {
161
162
163
164 if (sb_len > 1)
165 sshdr->sense_key = (sense_buffer[1] & 0xf);
166 if (sb_len > 2)
167 sshdr->asc = sense_buffer[2];
168 if (sb_len > 3)
169 sshdr->ascq = sense_buffer[3];
170 if (sb_len > 7)
171 sshdr->additional_length = sense_buffer[7];
172 } else {
173
174
175
176 if (sb_len > 2)
177 sshdr->sense_key = (sense_buffer[2] & 0xf);
178 if (sb_len > 7) {
179 sb_len = (sb_len < (sense_buffer[7] + 8)) ?
180 sb_len : (sense_buffer[7] + 8);
181 if (sb_len > 12)
182 sshdr->asc = sense_buffer[12];
183 if (sb_len > 13)
184 sshdr->ascq = sense_buffer[13];
185 }
186 }
187
188 return true;
189}
190EXPORT_SYMBOL(scsi_normalize_sense);
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
206 int desc_type)
207{
208 int add_sen_len, add_len, desc_len, k;
209 const u8 * descp;
210
211 if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
212 return NULL;
213 if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
214 return NULL;
215 add_sen_len = (add_sen_len < (sb_len - 8)) ?
216 add_sen_len : (sb_len - 8);
217 descp = &sense_buffer[8];
218 for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
219 descp += desc_len;
220 add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
221 desc_len = add_len + 2;
222 if (descp[0] == desc_type)
223 return descp;
224 if (add_len < 0)
225 break;
226 }
227 return NULL;
228}
229EXPORT_SYMBOL(scsi_sense_desc_find);
230
231
232
233
234
235
236
237
238
239
240
241void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
242{
243 if (desc) {
244 buf[0] = 0x72;
245 buf[1] = key;
246 buf[2] = asc;
247 buf[3] = ascq;
248 buf[7] = 0;
249 } else {
250 buf[0] = 0x70;
251 buf[2] = key;
252 buf[7] = 0xa;
253 buf[12] = asc;
254 buf[13] = ascq;
255 }
256}
257EXPORT_SYMBOL(scsi_build_sense_buffer);
258
259
260
261
262
263
264
265
266
267
268
269int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
270{
271 if ((buf[0] & 0x7f) == 0x72) {
272 u8 *ucp, len;
273
274 len = buf[7];
275 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
276 if (!ucp) {
277 buf[7] = len + 0xc;
278 ucp = buf + 8 + len;
279 }
280
281 if (buf_len < len + 0xc)
282
283 return -EINVAL;
284
285 ucp[0] = 0;
286 ucp[1] = 0xa;
287 ucp[2] = 0x80;
288 ucp[3] = 0;
289 put_unaligned_be64(info, &ucp[4]);
290 } else if ((buf[0] & 0x7f) == 0x70) {
291
292
293
294
295
296 if (info <= 0xffffffffUL)
297 buf[0] |= 0x80;
298 else
299 buf[0] &= 0x7f;
300 put_unaligned_be32((u32)info, &buf[3]);
301 }
302
303 return 0;
304}
305EXPORT_SYMBOL(scsi_set_sense_information);
306
307
308
309
310
311
312
313
314
315
316
317
318
319int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
320{
321 u8 *ucp, len;
322
323 if ((buf[0] & 0x7f) == 0x72) {
324 len = buf[7];
325 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
326 if (!ucp) {
327 buf[7] = len + 8;
328 ucp = buf + 8 + len;
329 }
330
331 if (buf_len < len + 8)
332
333 return -EINVAL;
334
335 ucp[0] = 2;
336 ucp[1] = 6;
337 ucp[4] = 0x80;
338 if (cd)
339 ucp[4] |= 0x40;
340 if (bp < 0x8)
341 ucp[4] |= 0x8 | bp;
342 put_unaligned_be16(fp, &ucp[5]);
343 } else if ((buf[0] & 0x7f) == 0x70) {
344 len = buf[7];
345 if (len < 18)
346 buf[7] = 18;
347
348 buf[15] = 0x80;
349 if (cd)
350 buf[15] |= 0x40;
351 if (bp < 0x8)
352 buf[15] |= 0x8 | bp;
353 put_unaligned_be16(fp, &buf[16]);
354 }
355
356 return 0;
357}
358EXPORT_SYMBOL(scsi_set_sense_field_pointer);
359