Skip to contentSkip to conversation

normalize fixed and descriptor sense data

PATCH In review Douglas Gilbert 5 participants 9 messages Aug 27, 2004 – Aug 29, 2004 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 normalize fixed and descriptor sense data

This is a retransmission. My previous post on this subject doesn't seem to have got through to the list.

After the comments on the RFC for this thread, here is a patch against lk 2.6.9-rc1 to kick around.

The patch only touches two files: scsi.h and scsi_lib.c It adds the proposed facility and then uses it in scsi_lib in roughly 4 locations. IMO there were 3 sense processing errors:
- block SG_IO did not get passed back deferred errors [SG_IO is a __pass-through__ interface!!]
- MEDIUM_ERRORs _do_ get processed for deferred sense errors in scsi_io_completion() which seems unintended
[I did not fix this one.]
- invalid command operation code handling in __scsi_mode_sense() was just wrong

If people think this is a reasonable approach, then the rest of the scsi mid-level and upper level driver could be converted. As Kai pointed we may need some general routines to pick up the sense data "extras".

The benefit of doing this conversion is that it may well highlight a lot more sense data processing errors (if the above is any guide).

Changes:
- add structure to receive normalized sense data from either fixed or descriptor format sense data
- add scsi_normalize_sense() function to populate that structure
- add scsi_sense_is_deferred() function so deferred errors can be ignored in many contexts
- apply new mechanism to sense data processing within the scsi_lib.c file

Doug Gilbert

include/scsi/scsi.h269rc1sdesc renamed from include/scsi/scsi.h +27 -0
@@ -236,6 +236,33 @@
 	__u8 scsi_lun[8];
 };
 
+/* This is a slightly modified SCSI sense "descriptor" format header.
+ * The addition is to allow the 0x70 and 0x71 response codes. The idea
+ * is to place the salient data from either "fixed" or "descriptor" sense
+ * format into one structure to ease application processing.
+ * The original sense buffer should be kept around for those cases
+ * in which more information is required (e.g. the LBA of a MEDIUM ERROR).
+ */
+struct scsi_sense_hd {     /* See SPC-3 section 4.5 */
+    uint8_t response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+    uint8_t sense_key;
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t byte4;
+    uint8_t byte5;
+    uint8_t byte6;
+    uint8_t additional_length; /* always 0 for fixed sense format */
+};
+
+extern int scsi_normalize_sense(const uint8_t * sense_buffer, int sb_len,
+                                struct scsi_sense_hd * sshd);
+
+static inline int scsi_sense_is_deferred(struct scsi_sense_hd * sshd)
+{
+	return (sshd && (sshd->response_code >= 0x70) && 
+		(sshd->response_code & 1)) ? 1 : 0;
+}
+ 
 /*
  *  MESSAGE CODES
  */
drivers/scsi/scsi_lib.c269rc1sdesc renamed from drivers/scsi/scsi_lib.c +79 -16

141 lines not on this page · raw message

#1 lore raw

+struct scsi_sense_hd { /* See SPC-3 section 4.5 */

maybe scsi_sense_desc insted?

+    uint8_t response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+    uint8_t sense_key;
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t byte4;
+    uint8_t byte5;
+    uint8_t byte6;
+    uint8_t additional_length; /* always 0 for fixed sense format */

We use u8 elsewhere in the scsi code, please stay consistant.

+static inline int scsi_sense_is_deferred(struct scsi_sense_hd * sshd) +{
+ return (sshd && (sshd->response_code >= 0x70) &&
+ (sshd->response_code & 1)) ? 1 : 0;
+}

I don't think we need the NULL check for sshd here, do we?

+/**
+ * scsi_normalize_sense - normalize main elements from either fixed
+ * or descriptor sense data format into a common format.
+ * @sense_buffer: byte array containing sense data returned by
+ * device
+ * @sb_len: number of valid bytes in sense_buffer
+ * @sshd: pointer to instance of structure that common
+ * elements are written to. Ignored if NULL.
+ *
+ * The "main elements" from sense data are: response_code, sense_key,
+ * asc, ascq and additional_length (only for descriptor format).
+ * Typically this function can be called after a device has
+ * responded to a SCSI command with the CHECK_CONDITION status.
+ *
+ * Returns 1 if valid sense data information found, else 0;
+ **/
+int scsi_normalize_sense(const uint8_t * sense_buffer, int sb_len,
+ struct scsi_sense_hd * sshd)
+{
+ if (sshd)
+ memset(sshd, 0, sizeof(struct scsi_sense_hd));

Again, checking for a NULL sshd here doesn't make much sense.

Also I think this function should get a __ prefix and we should add two small helpers that take a scsi_cmnd/scsi_request and use the sense_buffer and len from it.

+ if ((NULL == sense_buffer) || (0 == sb_len) ||
+ (0x70 != (0x70 & sense_buffer[0])))
+ return 0;
+ if (NULL == sshd)
+ return 1;

Wrong way around vs normal scsi style. Should be more like:

	if (!sense_buffer || !sb_len || (0x70 & sense_buffer[0]) != 0x70)
		return 0;

(and the sshd check gone again)
(same issues come up below again a few times)

#2 lore raw
Quoted 4 lines · Christoph Hellwig

+struct scsi_sense_hd { /* See SPC-3 section 4.5 */

maybe scsi_sense_desc insted?

Why, when it's neither in descriptor format nor in fixed format?

It is just a header of the _consolidated_ format of the sense data, thus the name used makes sense.

Quoted 41 lines
include/scsi/scsi.h269rc1sdesc renamed from include/scsi/scsi.h +8 -0
+    uint8_t response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+    uint8_t sense_key;
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t byte4;
+    uint8_t byte5;
+    uint8_t byte6;
+    uint8_t additional_length; /* always 0 for fixed sense format */

We use u8 elsewhere in the scsi code, please stay consistant.

include/scsi/scsi.h269rc1sdesc renamed from include/scsi/scsi.h +5 -0
+static inline int scsi_sense_is_deferred(struct scsi_sense_hd * sshd)
+{
+       return (sshd && (sshd->response_code >= 0x70) &&
+               (sshd->response_code & 1)) ? 1 : 0;
+}

I don't think we need the NULL check for sshd here, do we?

drivers/scsi/scsi_lib.c269rc1sdesc renamed from drivers/scsi/scsi_lib.c +21 -0
+/**
+ *     scsi_normalize_sense - normalize main elements from either fixed
+ *             or descriptor sense data format into a common format.
+ *     @sense_buffer:  byte array containing sense data returned by
+ *                     device
+ *     @sb_len:        number of valid bytes in sense_buffer
+ *     @sshd:          pointer to instance of structure that common
+ *                     elements are written to. Ignored if NULL.
+ *
+ *     The "main elements" from sense data are: response_code, sense_key,
+ *     asc, ascq and additional_length (only for descriptor format).
+ *     Typically this function can be called after a device has
+ *     responded to a SCSI command with the CHECK_CONDITION status.
+ *
+ *     Returns 1 if valid sense data information found, else 0;
+ **/
+int scsi_normalize_sense(const uint8_t * sense_buffer, int sb_len,
+                         struct scsi_sense_hd * sshd)
+{
+       if (sshd)
+               memset(sshd, 0, sizeof(struct scsi_sense_hd));
Quoted 5 lines

Again, checking for a NULL sshd here doesn't make much sense.

Also I think this function should get a __ prefix and we should add two small helpers that take a scsi_cmnd/scsi_request and use the sense_buffer and len from it.

But it should be exported nevertheless, as LLDDs may like to use it.

Luben

Quoted 19 lines
drivers/scsi/scsi_lib.c269rc1sdesc renamed from drivers/scsi/scsi_lib.c +5 -0
+       if ((NULL == sense_buffer) || (0 == sb_len) ||
+           (0x70 != (0x70 & sense_buffer[0])))
+               return 0;
+       if (NULL == sshd)
+               return 1;

Wrong way around vs normal scsi style. Should be more like:

        if (!sense_buffer || !sb_len || (0x70 & sense_buffer[0]) != 0x70)
                return 0;

(and the sshd check gone again)
(same issues come up below again a few times)

-
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

#3 lore raw
Quoted 11 lines · Luben Tuikov
Quoted 4 lines · Christoph Hellwig

+struct scsi_sense_hd { /* See SPC-3 section 4.5 */

maybe scsi_sense_desc insted?

Why, when it's neither in descriptor format nor in fixed format?

It is just a header of the _consolidated_ format of the sense data, thus the name used makes sense.

Umm, right, makes sense. the _hd postfix still looks strange to me. Either _hdr as standard short-notation for header or even better just remove it.

Quoted 6 lines
Quoted 3 lines

Also I think this function should get a __ prefix and we should add two small helpers that take a scsi_cmnd/scsi_request and use the sense_buffer and len from it.

But it should be exported nevertheless, as LLDDs may like to use it.

Makes sense.

#4 lore raw
In reply to Douglas Gilbert

On Fri, 27 Aug 2004 18:56:42 +1000 Douglas Gilbert wrote:

| After the comments on the RFC for this thread, here is
| a patch against lk 2.6.9-rc1 to kick around.
| 

A few more style comments to go along with Christoph's comments.

a. Linux long comment style begins with "/*" on a line by itself.

b. sizeof xyz: style is usually sizeof(xyz)

[I find 440 of: sizeof xyz

	2106 of:	sizeof (xyz)
	26948 of:	sizeof(xyz)

in 2.6.8.1]

c. + (! scsi_sense_is_deferred(&sshd))) {

Drop the space after '!' [from someone who loves to use spaces :]

--
~Randy

#5 lore raw
In reply to Douglas Gilbert
Quoted 23 lines · Douglas Gilbert

After the comments on the RFC for this thread, here is a patch against lk 2.6.9-rc1 to kick around.

The patch only touches two files: scsi.h and scsi_lib.c It adds the proposed facility and then uses it in scsi_lib in roughly 4 locations. IMO there were 3 sense processing errors:
- block SG_IO did not get passed back deferred errors [SG_IO is a __pass-through__ interface!!]
- MEDIUM_ERRORs _do_ get processed for deferred sense errors in scsi_io_completion() which seems unintended
[I did not fix this one.]
- invalid command operation code handling in __scsi_mode_sense() was just wrong

If people think this is a reasonable approach, then the rest of the scsi mid-level and upper level driver could be converted. As Kai pointed we may need some general routines to pick up the sense data "extras".

The benefit of doing this conversion is that it may well highlight a lot more sense data processing errors (if the above is any guide).

Quoted 8 lines

Changes:
- add structure to receive normalized sense data from either fixed or descriptor format sense data
- add scsi_normalize_sense() function to populate that structure
- add scsi_sense_is_deferred() function so deferred errors can be ignored in many contexts
- apply new mechanism to sense data processing within the scsi_lib.c file

Here is a second cut of the patch.

If James accepts it naturally he is free to enforce the appropriate coding style.

I believe that cleaning up scsi error processing is going to be a "work in progress" for a while.

Doug Gilbert

include/scsi/scsi.h269rc1sdesc2 renamed from include/scsi/scsi.h +27 -0
@@ -236,6 +236,33 @@
 	__u8 scsi_lun[8];
 };
 
+/* This is a slightly modified SCSI sense "descriptor" format header.
+ * The addition is to allow the 0x70 and 0x71 response codes. The idea
+ * is to place the salient data from either "fixed" or "descriptor" sense
+ * format into one structure to ease application processing.
+ * The original sense buffer should be kept around for those cases
+ * in which more information is required (e.g. the LBA of a MEDIUM ERROR).
+ */
+struct scsi_sense_hdr {	   /* See SPC-3 section 4.5 */
+    uint8_t response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+    uint8_t sense_key;
+    uint8_t asc;
+    uint8_t ascq;
+    uint8_t byte4;
+    uint8_t byte5;
+    uint8_t byte6;
+    uint8_t additional_length; /* always 0 for fixed sense format */
+};
+
+extern int scsi_normalize_sense(const uint8_t * sense_buffer, int sb_len,
+                                struct scsi_sense_hdr * sshdr);
+
+static inline int scsi_sense_is_deferred(struct scsi_sense_hdr * sshdr)
+{
+	return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1))
+	       ? 1 : 0;
+}
+ 
 /*
  *  MESSAGE CODES
  */
drivers/scsi/scsi_lib.c269rc1sdesc2 renamed from drivers/scsi/scsi_lib.c +87 -18

157 lines not on this page · raw message

#6 lore raw
Quoted 7 lines · Douglas Gilbert

Here is a second cut of the patch.

If James accepts it naturally he is free to enforce the appropriate coding style.

I believe that cleaning up scsi error processing is going to be a "work in progress" for a while.

Here's a version with a few small adjustments:

- moved the code to the scsi_error.c/scsi_eh.c
- small style cleanups
- added the two helpers I suggested
- don't do the memset if we return failure, callers shouldn't look at it then

drivers/scsi/scsi_error.c +76 -0
@@ -1850,3 +1850,79 @@
 	scsi_next_command(scmd);
 	return rtn;
 }
+
+/**
+ * scsi_normalize_sense - normalize main elements from either fixed or
+ *			descriptor sense data format into a common format.
+ *
+ * @sense_buffer:	byte array containing sense data returned by device
+ * @sb_len:		number of valid bytes in sense_buffer
+ * @sshdr:		pointer to instance of structure that common
+ *			elements are written to. Ignored if NULL.
+ *
+ * Notes:
+ *	The "main elements" from sense data are: response_code, sense_key,
+ *	asc, ascq and additional_length (only for descriptor format).
+ *
+ *	Typically this function can be called after a device has
+ *	responded to a SCSI command with the CHECK_CONDITION status.
+ *
+ * Return value:
+ *	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)
+{
+	if (!sense_buffer || !sb_len || (sense_buffer[0] & 0x70) != 0x70)
+		return 0;
+
+	memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
+
+	sshdr->response_code = (sense_buffer[0] & 0x7f);
+	if (sshdr->response_code >= 0x72) {
+		/*
+		 * descriptor format
+		 */
+		if (sb_len > 1)
+			sshdr->sense_key = (sense_buffer[1] & 0xf);
+		if (sb_len > 2)
+			sshdr->asc = sense_buffer[2];
+		if (sb_len > 3)
+			sshdr->ascq = sense_buffer[3];
+		if (sb_len > 7)
+			sshdr->additional_length = sense_buffer[7];
+	} else {
+		/* 
+		 * fixed format
+		 */
+		if (sb_len > 2)
+			sshdr->sense_key = (sense_buffer[2] & 0xf);
+		if (sb_len > 7) {
+			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];
+		}
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL(scsi_normalize_sense);
+
+int scsi_request_normalize_sense(struct scsi_request *sreq,
+				 struct scsi_sense_hdr *sshdr)
+{
+	return scsi_normalize_sense(sreq->sr_sense_buffer,
+			sizeof(sreq->sr_sense_buffer), sshdr);
+}
+EXPORT_SYMBOL(scsi_request_normalize_sense);
+
+int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
+				 struct scsi_sense_hdr *sshdr)
+{
+	return scsi_normalize_sense(cmd->sense_buffer,
+			sizeof(cmd->sense_buffer), sshdr);
+}
+EXPORT_SYMBOL(scsi_command_normalize_sense);
drivers/scsi/scsi_lib.c +30 -19

101 lines not on this page · raw message

include/scsi/scsi_eh.h +34 -1
@@ -3,15 +3,48 @@
 
 struct scsi_cmnd;
 struct scsi_device;
+struct scsi_request;
 struct Scsi_Host;
 
+/*
+ * This is a slightly modified SCSI sense "descriptor" format header.
+ * The addition is to allow the 0x70 and 0x71 response codes. The idea
+ * is to place the salient data from either "fixed" or "descriptor" sense
+ * format into one structure to ease application processing.
+ *
+ * The original sense buffer should be kept around for those cases
+ * in which more information is required (e.g. the LBA of a MEDIUM ERROR).
+ */
+struct scsi_sense_hdr {		/* See SPC-3 section 4.5 */
+	u8 response_code;	/* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+	u8 sense_key;
+	u8 asc;
+	u8 ascq;
+	u8 byte4;
+	u8 byte5;
+	u8 byte6;
+	u8 additional_length;	/* always 0 for fixed sense format */
+};
+
+
 extern void scsi_add_timer(struct scsi_cmnd *, int,
-			   void (*)(struct scsi_cmnd *));
+		void (*)(struct scsi_cmnd *));
 extern int scsi_delete_timer(struct scsi_cmnd *);
 extern void scsi_report_bus_reset(struct Scsi_Host *, int);
 extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
 extern int scsi_block_when_processing_errors(struct scsi_device *);
+extern int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
+		struct scsi_sense_hdr *sshdr);
+extern int scsi_request_normalize_sense(struct scsi_request *sreq,
+		struct scsi_sense_hdr *sshdr);
+extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
+		struct scsi_sense_hdr *sshdr);
 
+static inline int scsi_sense_is_deferred(struct scsi_sense_hdr *sshdr)
+{
+	return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1));
+}
+ 
 /*
  * Reset request from external source
  */
#7 lore raw
Quoted 24 lines · Christoph Hellwig
Quoted 7 lines · Douglas Gilbert

Here is a second cut of the patch.

If James accepts it naturally he is free to enforce the appropriate coding style.

I believe that cleaning up scsi error processing is going to be a "work in progress" for a while.

Here's a version with a few small adjustments:

- moved the code to the scsi_error.c/scsi_eh.c
- small style cleanups
- added the two helpers I suggested
- don't do the memset if we return failure, callers shouldn't look at it then

drivers/scsi/scsi_error.c +0 -0
@@ -1850,3 +1850,79 @@
 	scsi_next_command(scmd);
 	return rtn;

drivers/scsi/scsi_error.c line 1861

Quoted 10 lines
drivers/scsi/scsi_error.c +9 -0
 }
+
+/**
+ * scsi_normalize_sense - normalize main elements from either fixed or
+ *			descriptor sense data format into a common format.
+ *
+ * @sense_buffer:	byte array containing sense data returned by device
+ * @sb_len:		number of valid bytes in sense_buffer
+ * @sshdr:		pointer to instance of structure that common
+ *			elements are written to. Ignored if NULL.

Christoph,
I'm happy with this patch. Now it's my turn to be a reviewer ... The "Ignored if NULL." sentence above is no longer correct and should be removed. Actually it's my oversight.

So if this could be applied we could refine an error reporting policy after the comments from Kai. Obviously if the midlevel issues the command then it should handle all of the errors/alerts (e.g. midlevel device discovery). At the other extreme are pass through interfaces which want no retries and all errors and alerts "returned to sender". Then there are the cases in between.

Doug Gilbert

#8 lore raw
Quoted 3 lines · Douglas Gilbert

I'm happy with this patch. Now it's my turn to be a reviewer ... The "Ignored if NULL." sentence above is no longer correct and should be removed. Actually it's my oversight.

Heh, indeed. James, can you just remove " Ignored if NULL." from the sshdr paramter description when applying?