aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2016-04-04 05:44:04 -0400
committerTejun Heo <tj@kernel.org>2016-04-04 12:07:42 -0400
commit78db6e30281aa056a6773cb4def00afc158c097f (patch)
tree1eb35641be9d2663fb56ce70e35e7889237954be
parent06dbde5f3a44248fc02e24d662ac4849202abb48 (diff)
scsi: add scsi_set_sense_field_pointer()
Add a function to set the field pointer for SCSI sense codes. Signed-off-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--drivers/scsi/scsi_common.c53
-rw-r--r--include/scsi/scsi_common.h1
2 files changed, 54 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c
index ce79de822e46..b1383a71400e 100644
--- a/drivers/scsi/scsi_common.c
+++ b/drivers/scsi/scsi_common.c
@@ -293,3 +293,56 @@ int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
293 return 0; 293 return 0;
294} 294}
295EXPORT_SYMBOL(scsi_set_sense_information); 295EXPORT_SYMBOL(scsi_set_sense_information);
296
297/**
298 * scsi_set_sense_field_pointer - set the field pointer sense key
299 * specific information in a formatted sense data buffer
300 * @buf: Where to build sense data
301 * @buf_len: buffer length
302 * @fp: field pointer to be set
303 * @bp: bit pointer to be set
304 * @cd: command/data bit
305 *
306 * Return value:
307 * 0 on success or EINVAL for invalid sense buffer length
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 /* Not enough room for info */
323 return -EINVAL;
324
325 ucp[0] = 2;
326 ucp[1] = 6;
327 ucp[4] = 0x80; /* Valid bit */
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);
diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h
index 11571b2a831e..20bf7eaef05a 100644
--- a/include/scsi/scsi_common.h
+++ b/include/scsi/scsi_common.h
@@ -63,6 +63,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
63 63
64extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); 64extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
65int scsi_set_sense_information(u8 *buf, int buf_len, u64 info); 65int scsi_set_sense_information(u8 *buf, int buf_len, u64 info);
66int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd);
66extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, 67extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
67 int desc_type); 68 int desc_type);
68 69