Decode descriptor sense buffer to provide the same information as
we are already getting from fixed format sense.

Cc: Kay Sievers <[email protected]>
Signed-off-by: Hannes Reinecke <[email protected]>
---
 drivers/scsi/constants.c  |   79 +++++++++++++++------------------------------
 drivers/scsi/scsi_error.c |   43 +++++++++++++++++++++++-
 include/scsi/scsi_eh.h    |    8 +++-
 3 files changed, 73 insertions(+), 57 deletions(-)

diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 8bf2616..df69ba3 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -1376,61 +1376,34 @@ static void
 scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
                         struct scsi_sense_hdr *sshdr)
 {
-       int k, num, res;
-
-       if (sshdr->response_code < 0x72)
-       {
-               /* only decode extras for "fixed" format now */
-               char buff[80];
-               int blen, fixed_valid;
-               unsigned int info;
-
-               fixed_valid = sense_buffer[0] & 0x80;
-               info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
-                       (sense_buffer[5] << 8) | sense_buffer[6]);
-               res = 0;
-               memset(buff, 0, sizeof(buff));
-               blen = sizeof(buff) - 1;
-               if (fixed_valid)
-                       res += snprintf(buff + res, blen - res,
-                                       "Info fld=0x%x", info);
-               if (sense_buffer[2] & 0x80) {
-                       /* current command has read a filemark */
-                       if (res > 0)
-                               res += snprintf(buff + res, blen - res, ", ");
-                       res += snprintf(buff + res, blen - res, "FMK");
-               }
-               if (sense_buffer[2] & 0x40) {
-                       /* end-of-medium condition exists */
-                       if (res > 0)
-                               res += snprintf(buff + res, blen - res, ", ");
-                       res += snprintf(buff + res, blen - res, "EOM");
-               }
-               if (sense_buffer[2] & 0x20) {
-                       /* incorrect block length requested */
-                       if (res > 0)
-                               res += snprintf(buff + res, blen - res, ", ");
-                       res += snprintf(buff + res, blen - res, "ILI");
-               }
-               if (res > 0)
-                       printk("%s\n", buff);
-       } else if (sshdr->additional_length > 0) {
-               /* descriptor format with sense descriptors */
-               num = 8 + sshdr->additional_length;
-               num = (sense_len < num) ? sense_len : num;
-               printk("Descriptor sense data with sense descriptors "
-                      "(in hex):");
-               for (k = 0; k < num; ++k) {
-                       if (0 == (k % 16)) {
-                               printk("\n");
-                               printk(KERN_INFO "        ");
-                       }
-                       printk("%02x ", sense_buffer[k]);
-               }
+       int res = 0;
+       char buff[80];
+       int blen = sense_len;
 
-               printk("\n");
-       }
+       if (sshdr->info)
+               res += snprintf(buff + res, blen - res,
+                               "Info fld=0x%llx", sshdr->info);
 
+       if (sshdr->flags & SCSI_SENSE_FLAG_FMK) {
+               /* current command has read a filemark */
+               if (res > 0)
+                       res += snprintf(buff + res, blen - res, ", ");
+               res += snprintf(buff + res, blen - res, "FMK");
+       }
+       if (sshdr->flags & SCSI_SENSE_FLAG_EOM) {
+               /* end-of-medium condition exists */
+               if (res > 0)
+                       res += snprintf(buff + res, blen - res, ", ");
+               res += snprintf(buff + res, blen - res, "EOM");
+       }
+       if (sshdr->flags & SCSI_SENSE_FLAG_ILI) {
+               /* incorrect block length requested */
+               if (res > 0)
+                       res += snprintf(buff + res, blen - res, ", ");
+               res += snprintf(buff + res, blen - res, "ILI");
+       }
+       if (res > 0)
+               pr_info("%s\n", buff);
 }
 
 /* Normalize and print sense buffer with name prefix */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f8d51c5..e8ff276 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2086,7 +2086,7 @@ EXPORT_SYMBOL(scsi_reset_provider);
  *     1 if valid sense data information found, else 0;
  */
 int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
-                         struct scsi_sense_hdr *sshdr)
+                        struct scsi_sense_hdr *sshdr)
 {
        if (!sense_buffer || !sb_len)
                return 0;
@@ -2099,6 +2099,9 @@ int scsi_normalize_sense(const u8 *sense_buffer, int 
sb_len,
                return 0;
 
        if (sshdr->response_code >= 0x72) {
+               int i;
+               const char *sdesc;
+
                /*
                 * descriptor format
                 */
@@ -2110,19 +2113,55 @@ int scsi_normalize_sense(const u8 *sense_buffer, int 
sb_len,
                        sshdr->ascq = sense_buffer[3];
                if (sb_len > 7)
                        sshdr->additional_length = sense_buffer[7];
+               i = 0;
+               while ((i < sshdr->additional_length) && (i + 8 < sb_len)) {
+                       sdesc = &sense_buffer[i + 8];
+                       switch (sdesc[0]) {
+                       case 0: /* Information */
+                               if (!(sdesc[2] & 0x80))
+                                       break;
+                               sshdr->info = (u64)sdesc[4] << 56 |
+                                       (u64)sdesc[5] << 48 |
+                                       (u64)sdesc[6] << 40 |
+                                       (u64)sdesc[7] << 32 |
+                                       (u64)sdesc[8] << 24 |
+                                       (u64)sdesc[9] << 16 |
+                                       (u64)sdesc[10] << 8 |
+                                       (u64)sdesc[11];
+                               break;
+                       case 3: /* Field replaceable unit */
+                               sshdr->fru = sdesc[3];
+                               break;
+                       case 4: /* Stream commands */
+                               sshdr->flags = sdesc[3] >> 4;
+                               break;
+                       case 5: /* Block commands */
+                               sshdr->flags = sdesc[3] >> 4;
+                       }
+                       i += sdesc[1];
+               }
        } else {
                /*
                 * fixed format
                 */
-               if (sb_len > 2)
+               if (sb_len > 2) {
                        sshdr->sense_key = (sense_buffer[2] & 0xf);
+                       sshdr->flags = (sense_buffer[2] >> 4);
+               }
                if (sb_len > 7) {
+                       if (sense_buffer[0] & 0x80)
+                               sshdr->info = ((sense_buffer[3] << 24) |
+                                              (sense_buffer[4] << 16) |
+                                              (sense_buffer[5] << 8) |
+                                              sense_buffer[6]);
                        sb_len = (sb_len < (sense_buffer[7] + 8)) ?
                                         sb_len : (sense_buffer[7] + 8);
                        if (sb_len > 12)
                                sshdr->asc = sense_buffer[12];
                        if (sb_len > 13)
                                sshdr->ascq = sense_buffer[13];
+                       if (sb_len > 14)
+                               sshdr->fru = sense_buffer[14];
                }
        }
 
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 06a8790..3472448 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -21,10 +21,14 @@ struct scsi_sense_hdr {             /* See SPC-3 section 
4.5 */
        u8 sense_key;
        u8 asc;
        u8 ascq;
-       u8 byte4;
-       u8 byte5;
+       u8 flags;
+#define SCSI_SENSE_FLAG_FMK  0x8
+#define SCSI_SENSE_FLAG_EOM 0x4
+#define SCSI_SENSE_FLAG_ILI 0x2
+       u8 fru;
        u8 byte6;
        u8 additional_length;   /* always 0 for fixed sense format */
+       u64 info;
 };
 
 static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
-- 
1.7.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to