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