scsi: Fix wrong additional sense length in descriptor format
[linux-2.6-block.git] / drivers / scsi / scsi_common.c
CommitLineData
07e38420
BVA
1/*
2 * SCSI functions used by both the initiator and the target code.
3 */
4
5#include <linux/bug.h>
6#include <linux/kernel.h>
7#include <linux/string.h>
7708c165 8#include <asm/unaligned.h>
07e38420
BVA
9#include <scsi/scsi_common.h>
10
11/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
12 * You may not alter any existing entry (although adding new ones is
13 * encouraged once assigned by ANSI/INCITS T10
14 */
15static const char *const scsi_device_types[] = {
16 "Direct-Access ",
17 "Sequential-Access",
18 "Printer ",
19 "Processor ",
20 "WORM ",
21 "CD-ROM ",
22 "Scanner ",
23 "Optical Device ",
24 "Medium Changer ",
25 "Communications ",
26 "ASC IT8 ",
27 "ASC IT8 ",
28 "RAID ",
29 "Enclosure ",
30 "Direct-Access-RBC",
31 "Optical card ",
32 "Bridge controller",
33 "Object storage ",
34 "Automation/Drive ",
35 "Security Manager ",
36 "Direct-Access-ZBC",
37};
38
39/**
40 * scsi_device_type - Return 17 char string indicating device type.
41 * @type: type number to look up
42 */
43const char *scsi_device_type(unsigned type)
44{
45 if (type == 0x1e)
46 return "Well-known LUN ";
47 if (type == 0x1f)
48 return "No Device ";
49 if (type >= ARRAY_SIZE(scsi_device_types))
50 return "Unknown ";
51 return scsi_device_types[type];
52}
53EXPORT_SYMBOL(scsi_device_type);
54
55/**
56 * scsilun_to_int - convert a scsi_lun to an int
57 * @scsilun: struct scsi_lun to be converted.
58 *
59 * Description:
60 * Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered
61 * integer, and return the result. The caller must check for
62 * truncation before using this function.
63 *
64 * Notes:
65 * For a description of the LUN format, post SCSI-3 see the SCSI
66 * Architecture Model, for SCSI-3 see the SCSI Controller Commands.
67 *
68 * Given a struct scsi_lun of: d2 04 0b 03 00 00 00 00, this function
69 * returns the integer: 0x0b03d204
70 *
71 * This encoding will return a standard integer LUN for LUNs smaller
72 * than 256, which typically use a single level LUN structure with
73 * addressing method 0.
74 */
75u64 scsilun_to_int(struct scsi_lun *scsilun)
76{
77 int i;
78 u64 lun;
79
80 lun = 0;
81 for (i = 0; i < sizeof(lun); i += 2)
82 lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |
83 ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));
84 return lun;
85}
86EXPORT_SYMBOL(scsilun_to_int);
87
88/**
89 * int_to_scsilun - reverts an int into a scsi_lun
90 * @lun: integer to be reverted
91 * @scsilun: struct scsi_lun to be set.
92 *
93 * Description:
94 * Reverts the functionality of the scsilun_to_int, which packed
95 * an 8-byte lun value into an int. This routine unpacks the int
96 * back into the lun value.
97 *
98 * Notes:
99 * Given an integer : 0x0b03d204, this function returns a
100 * struct scsi_lun of: d2 04 0b 03 00 00 00 00
101 *
102 */
103void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)
104{
105 int i;
106
107 memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
108
109 for (i = 0; i < sizeof(lun); i += 2) {
110 scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
111 scsilun->scsi_lun[i+1] = lun & 0xFF;
112 lun = lun >> 16;
113 }
114}
115EXPORT_SYMBOL(int_to_scsilun);
116
117/**
118 * scsi_normalize_sense - normalize main elements from either fixed or
119 * descriptor sense data format into a common format.
120 *
121 * @sense_buffer: byte array containing sense data returned by device
122 * @sb_len: number of valid bytes in sense_buffer
123 * @sshdr: pointer to instance of structure that common
124 * elements are written to.
125 *
126 * Notes:
127 * The "main elements" from sense data are: response_code, sense_key,
128 * asc, ascq and additional_length (only for descriptor format).
129 *
130 * Typically this function can be called after a device has
131 * responded to a SCSI command with the CHECK_CONDITION status.
132 *
133 * Return value:
134 * true if valid sense data information found, else false;
135 */
136bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
137 struct scsi_sense_hdr *sshdr)
138{
139 if (!sense_buffer || !sb_len)
140 return false;
141
142 memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
143
144 sshdr->response_code = (sense_buffer[0] & 0x7f);
145
146 if (!scsi_sense_valid(sshdr))
147 return false;
148
149 if (sshdr->response_code >= 0x72) {
150 /*
151 * descriptor format
152 */
153 if (sb_len > 1)
154 sshdr->sense_key = (sense_buffer[1] & 0xf);
155 if (sb_len > 2)
156 sshdr->asc = sense_buffer[2];
157 if (sb_len > 3)
158 sshdr->ascq = sense_buffer[3];
159 if (sb_len > 7)
160 sshdr->additional_length = sense_buffer[7];
161 } else {
162 /*
163 * fixed format
164 */
165 if (sb_len > 2)
166 sshdr->sense_key = (sense_buffer[2] & 0xf);
167 if (sb_len > 7) {
168 sb_len = (sb_len < (sense_buffer[7] + 8)) ?
169 sb_len : (sense_buffer[7] + 8);
170 if (sb_len > 12)
171 sshdr->asc = sense_buffer[12];
172 if (sb_len > 13)
173 sshdr->ascq = sense_buffer[13];
174 }
175 }
176
177 return true;
178}
179EXPORT_SYMBOL(scsi_normalize_sense);
7708c165
SG
180
181/**
182 * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format.
183 * @sense_buffer: byte array of descriptor format sense data
184 * @sb_len: number of valid bytes in sense_buffer
185 * @desc_type: value of descriptor type to find
186 * (e.g. 0 -> information)
187 *
188 * Notes:
189 * only valid when sense data is in descriptor format
190 *
191 * Return value:
192 * pointer to start of (first) descriptor if found else NULL
193 */
194const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
195 int desc_type)
196{
197 int add_sen_len, add_len, desc_len, k;
198 const u8 * descp;
199
200 if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
201 return NULL;
202 if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
203 return NULL;
204 add_sen_len = (add_sen_len < (sb_len - 8)) ?
205 add_sen_len : (sb_len - 8);
206 descp = &sense_buffer[8];
207 for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
208 descp += desc_len;
209 add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
210 desc_len = add_len + 2;
211 if (descp[0] == desc_type)
212 return descp;
213 if (add_len < 0) // short descriptor ??
214 break;
215 }
216 return NULL;
217}
218EXPORT_SYMBOL(scsi_sense_desc_find);
219
220/**
221 * scsi_build_sense_buffer - build sense data in a buffer
222 * @desc: Sense format (non zero == descriptor format,
223 * 0 == fixed format)
224 * @buf: Where to build sense data
225 * @key: Sense key
226 * @asc: Additional sense code
227 * @ascq: Additional sense code qualifier
228 *
229 **/
230void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
231{
232 if (desc) {
233 buf[0] = 0x72; /* descriptor, current */
234 buf[1] = key;
235 buf[2] = asc;
236 buf[3] = ascq;
237 buf[7] = 0;
238 } else {
239 buf[0] = 0x70; /* fixed, current */
240 buf[2] = key;
241 buf[7] = 0xa;
242 buf[12] = asc;
243 buf[13] = ascq;
244 }
245}
246EXPORT_SYMBOL(scsi_build_sense_buffer);
247
248/**
249 * scsi_set_sense_information - set the information field in a
250 * formatted sense data buffer
251 * @buf: Where to build sense data
252 * @info: 64-bit information value to be set
253 *
254 **/
255void scsi_set_sense_information(u8 *buf, u64 info)
256{
257 if ((buf[0] & 0x7f) == 0x72) {
258 u8 *ucp, len;
259
260 len = buf[7];
261 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
262 if (!ucp) {
12306b42 263 buf[7] = len + 0xc;
7708c165
SG
264 ucp = buf + 8 + len;
265 }
266 ucp[0] = 0;
267 ucp[1] = 0xa;
268 ucp[2] = 0x80; /* Valid bit */
269 ucp[3] = 0;
270 put_unaligned_be64(info, &ucp[4]);
271 } else if ((buf[0] & 0x7f) == 0x70) {
272 buf[0] |= 0x80;
273 put_unaligned_be64(info, &buf[3]);
274 }
275}
276EXPORT_SYMBOL(scsi_set_sense_information);