Skip to contentSkip to conversation

Improve SCSI device type decoding

PATCH In review Matthew Wilcox 2 participants 5 messages Jun 21, 2006 – Jun 22, 2006

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 Improve SCSI device type decoding

Change API from the scsi_device_types array to the scsi_device_type function. Gets rid of a lot of common code, as well as being easier to use. Also add the new device types in SPC4 r05a.

Index: ./drivers/block/cciss_scsi.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/block/cciss_scsi.c,v retrieving revision 1.16

drivers/block/cciss_scsi.c +5 -9
diff -u -p -r1.16 cciss_scsi.c
@@ -251,10 +251,6 @@ scsi_cmd_stack_free(int ctlr)
 	stk->pool = NULL;
 }
 
-/* scsi_device_types comes from scsi.h */
-#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
-	"Unknown" : scsi_device_types[n]
-
 #if 0
 static int xmargin=8;
 static int amargin=60;
@@ -389,7 +385,7 @@ cciss_scsi_add_entry(int ctlr, int hostn
 	   time anyway (the scsi layer's inquiries will show that info) */
 	if (hostno != -1)
 		printk("cciss%d: %s device c%db%dt%dl%d added.\n", 
-			ctlr, DEVICETYPE(sd->devtype), hostno, 
+			ctlr, scsi_device_type(sd->devtype), hostno, 
 			sd->bus, sd->target, sd->lun);
 	return 0;
 }
@@ -407,7 +403,7 @@ cciss_scsi_remove_entry(int ctlr, int ho
 		ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
 	ccissscsi[ctlr].ndevices--;
 	printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
-		ctlr, DEVICETYPE(sd.devtype), hostno, 
+		ctlr, scsi_device_type(sd.devtype), hostno, 
 			sd.bus, sd.target, sd.lun);
 }
 
@@ -458,7 +454,7 @@ adjust_cciss_scsi_table(int ctlr, int ho
 		if (found == 0) { /* device no longer present. */ 
 			changes++;
 			/* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
-				ctlr, DEVICETYPE(csd->devtype), hostno, 
+				ctlr, scsi_device_type(csd->devtype), hostno, 
 					csd->bus, csd->target, csd->lun); */
 			cciss_scsi_remove_entry(ctlr, hostno, i);
 			/* note, i not incremented */
@@ -468,7 +464,7 @@ adjust_cciss_scsi_table(int ctlr, int ho
 			printk("cciss%d: device c%db%dt%dl%d type changed "
 				"(device type now %s).\n",
 				ctlr, hostno, csd->bus, csd->target, csd->lun,
-					DEVICETYPE(csd->devtype));
+					scsi_device_type(csd->devtype));
 			csd->devtype = sd[j].devtype;
 			i++;	/* so just move along. */
 		} else 		/* device is same as it ever was, */
@@ -1098,7 +1094,7 @@ cciss_update_non_disk_devices(int cntl_n
 			if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
 				printk(KERN_INFO "cciss%d: %s ignored, "
 					"too many devices.\n", cntl_num,
-					DEVICETYPE(devtype));
+					scsi_device_type(devtype));
 				break;
 			}
 			memcpy(&currentsd[ncurrent].scsi3addr[0], 

Index: ./drivers/scsi/fcal.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/fcal.c,v retrieving revision 1.8

drivers/scsi/fcal.c +1 -2
diff -u -p -r1.8 fcal.c
@@ -249,8 +249,7 @@ int fcal_proc_info (struct Scsi_Host *ho
 				if (scd->id == target) {
 					SPRINTF ("  [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x]  ",
 						alpa, target, u1[0], u1[1], u2[0], u2[1]);
-					SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
-						scsi_device_types[(short) scd->type] : "Unknown device");
+					SPRINTF ("%s ", scsi_device_type(scd->type));
 
 					for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
 						SPRINTF ("%c", scd->vendor[j]);

Index: ./drivers/scsi/g_NCR5380.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/g_NCR5380.c,v retrieving revision 1.14

drivers/scsi/g_NCR5380.c +1 -2
diff -u -p -r1.14 g_NCR5380.c
@@ -813,7 +813,6 @@ static int generic_NCR5380_proc_info(str
 	struct NCR5380_hostdata *hostdata;
 #ifdef NCR5380_STATS
 	struct scsi_device *dev;
-	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #endif
 
 	NCR5380_setup(scsi_ptr);
@@ -853,7 +852,7 @@ static int generic_NCR5380_proc_info(str
 		long tr = hostdata->time_read[dev->id] / HZ;
 		long tw = hostdata->time_write[dev->id] / HZ;
 
-		PRINTP("  T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
+		PRINTP("  T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
 		for (i = 0; i < 8; i++)
 			if (dev->vendor[i] >= 0x20)
 				*(buffer + (len++)) = dev->vendor[i];

Index: ./drivers/scsi/megaraid.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/megaraid.c,v retrieving revision 1.26

drivers/scsi/megaraid.c +1 -3
diff -u -p -r1.26 megaraid.c
@@ -2822,9 +2822,7 @@ mega_print_inquiry(char *page, char *scs
 
 	i = scsi_inq[0] & 0x1f;
 
-	len += sprintf(page+len, "  Type:   %s ",
-		i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
-		   "Unknown          ");
+	len += sprintf(page+len, "  Type:   %s ", scsi_device_type(i));
 
 	len += sprintf(page+len,
 	"                 ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);

Index: ./drivers/scsi/scsi.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/scsi.c,v retrieving revision 1.34

drivers/scsi/scsi.c +18 -4
diff -u -p -r1.34 scsi.c
@@ -97,7 +97,7 @@ unsigned int scsi_logging_level;
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
 
-const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
+static const char *const scsi_device_types[] = {
 	"Direct-Access    ",
 	"Sequential-Access",
 	"Printer          ",
@@ -108,13 +108,27 @@ const char *const scsi_device_types[MAX_
 	"Optical Device   ",
 	"Medium Changer   ",
 	"Communications   ",
-	"Unknown          ",
-	"Unknown          ",
+	"ASC IT8          ",
+	"ASC IT8          ",
 	"RAID             ",
 	"Enclosure        ",
 	"Direct-Access-RBC",
+	"Optical Card     ",
+	"Bridge Controller",
+	"Object Storage   ",
+	"Automation/Drive ",
 };
-EXPORT_SYMBOL(scsi_device_types);
+
+const char * scsi_device_type(unsigned type)
+{
+	if (type == 0x1e)
+		return "Well-known LUN   ";
+	if (type > ARRAY_SIZE(scsi_device_types))
+		return "Unknown          ";
+	return scsi_device_types[type];
+}
+
+EXPORT_SYMBOL(scsi_device_type);
 
 /*
  * Function:    scsi_allocate_request

Index: ./drivers/scsi/scsi_proc.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/scsi_proc.c,v retrieving revision 1.9

drivers/scsi/scsi_proc.c +1 -3
diff -u -p -r1.9 scsi_proc.c
@@ -178,9 +178,7 @@ static int proc_print_scsidevice(struct 
 
 	seq_printf(s, "\n");
 
-	seq_printf(s, "  Type:   %s ",
-		     sdev->type < MAX_SCSI_DEVICE_CODE ?
-	       scsi_device_types[(int) sdev->type] : "Unknown          ");
+	seq_printf(s, "  Type:   %s ", scsi_device_type(sdev->type));
 	seq_printf(s, "               ANSI"
 		     " SCSI revision: %02x", (sdev->scsi_level - 1) ?
 		     sdev->scsi_level - 1 : 1);

Index: ./drivers/scsi/scsi_scan.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/scsi_scan.c,v retrieving revision 1.41

drivers/scsi/scsi_scan.c +1 -4
diff -u -p -r1.41 scsi_scan.c
@@ -226,10 +226,7 @@ static void print_inquiry(unsigned char 
 
 	i = inq_result[0] & 0x1f;
 
-	printk(KERN_NOTICE "  Type:   %s ",
-	       i <
-	       MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
-	       "Unknown          ");
+	printk(KERN_NOTICE "  Type:   %s ", scsi_device_type(i));
 	printk("                 ANSI SCSI revision: %02x",
 	       inq_result[2] & 0x07);
 	if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)

Index: ./include/scsi/scsi.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/scsi/scsi.h,v retrieving revision 1.19

include/scsi/scsi.h +3 -7
diff -u -p -r1.19 scsi.h
@@ -25,13 +25,6 @@ extern const unsigned char scsi_command_
 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
 
 /*
- *	SCSI device types
- */
-
-#define MAX_SCSI_DEVICE_CODE 15
-extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
-
-/*
  * Special value for scanning to specify scanning or rescanning of all
  * possible channels, (target) ids, or luns on a given shost.
  */
@@ -224,6 +217,9 @@ static inline int scsi_status_is_good(in
 #define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
 #define TYPE_RBC	    0x0e
 #define TYPE_NO_LUN         0x7f
+
+/* Returns a human-readable name for the device */
+extern const char * scsi_device_type(unsigned type);
 
 /*
  * standard mode-select header prepended to all mode-select commands
#1 lore raw

PATCH 2/2 Print SCSI Inquiry data more compactly

print_inquiry is rather verbose, both in implementation and in output. This patch reduces the output from two lines to one and reduces the implementation to a single printk.

Sample output:
Vendor: HP 18.2G Model: ATLAS10K3_18_SCA Rev: HP05
Type: Direct-Access ANSI SCSI revision: 02

becomes:

scsi 2:0:1:0: Direct-Access HP 18.2G ATLAS10K3_18_SCA HP05 ANSI ver: 02

Index: drivers/scsi/scsi_scan.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/scsi/scsi_scan.c,v retrieving revision 1.41

drivers/scsi/scsi_scan.c +7 -54
diff -u -p -r1.41 scsi_scan.c
@@ -186,56 +186,6 @@ static void scsi_unlock_floptical(struct
 }
 
 /**
- * print_inquiry - printk the inquiry information
- * @inq_result:	printk this SCSI INQUIRY
- *
- * Description:
- *     printk the vendor, model, and other information found in the
- *     INQUIRY data in @inq_result.
- *
- * Notes:
- *     Remove this, and replace with a hotplug event that logs any
- *     relevant information.
- **/
-static void print_inquiry(unsigned char *inq_result)
-{
-	int i;
-
-	printk(KERN_NOTICE "  Vendor: ");
-	for (i = 8; i < 16; i++)
-		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
-			printk("%c", inq_result[i]);
-		else
-			printk(" ");
-
-	printk("  Model: ");
-	for (i = 16; i < 32; i++)
-		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
-			printk("%c", inq_result[i]);
-		else
-			printk(" ");
-
-	printk("  Rev: ");
-	for (i = 32; i < 36; i++)
-		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
-			printk("%c", inq_result[i]);
-		else
-			printk(" ");
-
-	printk("\n");
-
-	i = inq_result[0] & 0x1f;
-
-	printk(KERN_NOTICE "  Type:   %s ", scsi_device_type(i));
-	printk("                 ANSI SCSI revision: %02x",
-	       inq_result[2] & 0x07);
-	if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)
-		printk(" CCS\n");
-	else
-		printk("\n");
-}
-
-/**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
  *
  * Description:
@@ -703,9 +653,8 @@ static int scsi_add_lun(struct scsi_devi
 	if (*bflags & BLIST_ISROM) {
 		/*
 		 * It would be better to modify sdev->type, and set
-		 * sdev->removable, but then the print_inquiry() output
-		 * would not show TYPE_ROM; if print_inquiry() is removed
-		 * the issue goes away.
+		 * sdev->removable; this can now be done since
+		 * print_inquiry has gone away.
 		 */
 		inq_result[0] = TYPE_ROM;
 		inq_result[1] |= 0x80;	/* removable */
@@ -734,7 +683,11 @@ static int scsi_add_lun(struct scsi_devi
 		printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
 	}
 
-	print_inquiry(inq_result);
+	sdev_printk(KERN_NOTICE "scsi", sdev, "%s %.8s %.16s %.4s "
+			"ANSI ver: %02x%s\n", scsi_device_type(sdev->type),
+			sdev->vendor, sdev->model,
+			sdev->rev, inq_result[2] & 0x07,
+			(inq_result[3] & 0x0f) == 1 ? " CCS" : "");
 
 	/*
 	 * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
#2 lore raw
In reply to Matthew Wilcox
Quoted 3 lines · Matthew Wilcox

Change API from the scsi_device_types array to the scsi_device_type function. Gets rid of a lot of common code, as well as being easier to use. Also add the new device types in SPC4 r05a.

Not forgetting peripheral device types 1eh and 1fh which are well known logical unit and unknown or no device type respectively.

Reference: the bottom of table 84 in spc4r05a.pdf .

Well known logical units are out there, linux just doesn't look for them (see the "select report" field in REPORT LUNS command).
I have been told of special devices yielding pdf 1fh.

BTW I have tried to add these in the past but my patch wasn't accepted.

Doug Gilbert

#3 lore raw
Quoted 3 lines · Douglas Gilbert

Not forgetting peripheral device types 1eh and 1fh which are well known logical unit and unknown or no device type respectively.

I don't think you read the whole patch ;-)

+ if (type == 0x1e)
+ return "Well-known LUN ";
+ if (type > ARRAY_SIZE(scsi_device_types))
+ return "Unknown ";

Did you want to distinguish between a device of type unknown and a device type Linux doesn't know about?

#4 lore raw
Quoted 8 lines · Matthew Wilcox
Quoted 3 lines · Douglas Gilbert

Not forgetting peripheral device types 1eh and 1fh which are well known logical unit and unknown or no device type respectively.

I don't think you read the whole patch ;-)

Obviously not closely enough.

Quoted 7 lines
drivers/scsi/scsi.c +4 -0
+       if (type == 0x1e)
+               return "Well-known LUN   ";
+       if (type > ARRAY_SIZE(scsi_device_types))
+               return "Unknown          ";

Did you want to distinguish between a device of type unknown and a device type Linux doesn't know about?

If a device server yields a peripheral qualifier of 3 in a INQUIRY response (e.g. for the "lun 0" trick when there are lun_s>0) then the associated pdt should be set to 1fh. The unallocated pdt_s are marked as "reserved" in the draft.
It is also possible that a drive with removable media may not want to commit to a pdt before it sees media. So I would prefer to see the distinction.

Doug Gilbert