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