summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_common.c
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2016-04-04 11:44:04 +0200
committerTejun Heo <tj@kernel.org>2016-04-04 18:07:42 +0200
commit78db6e30281aa056a6773cb4def00afc158c097f (patch)
tree1eb35641be9d2663fb56ce70e35e7889237954be /drivers/scsi/scsi_common.c
parentlibata: Implement control mode page to select sense format (diff)
downloadlinux-78db6e30281aa056a6773cb4def00afc158c097f.tar.xz
linux-78db6e30281aa056a6773cb4def00afc158c097f.zip
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>
Diffstat (limited to 'drivers/scsi/scsi_common.c')
-rw-r--r--drivers/scsi/scsi_common.c53
1 files changed, 53 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)
return 0;
}
EXPORT_SYMBOL(scsi_set_sense_information);
+
+/**
+ * scsi_set_sense_field_pointer - set the field pointer sense key
+ * specific information in a formatted sense data buffer
+ * @buf: Where to build sense data
+ * @buf_len: buffer length
+ * @fp: field pointer to be set
+ * @bp: bit pointer to be set
+ * @cd: command/data bit
+ *
+ * Return value:
+ * 0 on success or EINVAL for invalid sense buffer length
+ */
+int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
+{
+ u8 *ucp, len;
+
+ if ((buf[0] & 0x7f) == 0x72) {
+ len = buf[7];
+ ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
+ if (!ucp) {
+ buf[7] = len + 8;
+ ucp = buf + 8 + len;
+ }
+
+ if (buf_len < len + 8)
+ /* Not enough room for info */
+ return -EINVAL;
+
+ ucp[0] = 2;
+ ucp[1] = 6;
+ ucp[4] = 0x80; /* Valid bit */
+ if (cd)
+ ucp[4] |= 0x40;
+ if (bp < 0x8)
+ ucp[4] |= 0x8 | bp;
+ put_unaligned_be16(fp, &ucp[5]);
+ } else if ((buf[0] & 0x7f) == 0x70) {
+ len = buf[7];
+ if (len < 18)
+ buf[7] = 18;
+
+ buf[15] = 0x80;
+ if (cd)
+ buf[15] |= 0x40;
+ if (bp < 0x8)
+ buf[15] |= 0x8 | bp;
+ put_unaligned_be16(fp, &buf[16]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(scsi_set_sense_field_pointer);