patch-2.4.7 linux/drivers/scsi/scsi_scan.c

Next file: linux/drivers/scsi/sd.c
Previous file: linux/drivers/scsi/scsi_obsolete.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
@@ -40,9 +40,13 @@
 #define BLIST_ISROM     	0x200
 
 static void print_inquiry(unsigned char *data);
-static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
-		int *sparse_lun, Scsi_Device ** SDpnt,
-			     struct Scsi_Host *shpnt, char *scsi_result);
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+		unsigned int lun, int lun0_scsi_level, 
+		unsigned int *max_scsi_dev, unsigned int *sparse_lun, 
+		Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, 
+		char *scsi_result);
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+				struct Scsi_Host *shpnt);
 
 struct dev_info {
 	const char *vendor;
@@ -135,6 +139,7 @@
 	{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
 	{"DEC","HSG80","*", BLIST_FORCELUN},
 	{"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
+	{"COMPAQ","CR3500","*", BLIST_FORCELUN},
 	{"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
@@ -143,7 +148,11 @@
 	{"MegaRAID", "LD", "*", BLIST_FORCELUN},
 	{"DGC",  "RAID",      "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0)
 	{"DGC",  "DISK",      "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) 
+	{"DELL", "PV660F",   "*", BLIST_SPARSELUN},
+	{"DELL", "PV660F   PSEUDO",   "*", BLIST_SPARSELUN},
+	{"DELL", "PSEUDO DEVICE .",   "*", BLIST_SPARSELUN}, // Dell PV 530F
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN}, // Dell PV 530F
+	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN},
 	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
 	{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
 	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
@@ -154,29 +163,31 @@
 	{NULL, NULL, NULL}
 };
 
+#define MAX_SCSI_LUNS 0xFFFFFFFF
+
 #ifdef CONFIG_SCSI_MULTI_LUN
-static int max_scsi_luns = 8;
+static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
 #else
-static int max_scsi_luns = 1;
+static unsigned int max_scsi_luns = 1;
 #endif
 
 #ifdef MODULE
 
 MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
+MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
 
 #else
 
 static int __init scsi_luns_setup(char *str)
 {
-	int tmp;
+	unsigned int tmp;
 
 	if (get_option(&str, &tmp) == 1) {
 		max_scsi_luns = tmp;
 		return 1;
 	} else {
 		printk("scsi_luns_setup : usage max_scsi_luns=n "
-		       "(n should be between 1 and 8)\n");
+		       "(n should be between 1 and 2^32-1)\n");
 		return 0;
 	}
 }
@@ -264,14 +275,15 @@
 		       uint hlun)
 {
 	uint channel;
-	int dev;
-	int lun;
-	int max_dev_lun;
+	unsigned int dev;
+	unsigned int lun;
+	unsigned int max_dev_lun;
 	unsigned char *scsi_result;
 	unsigned char scsi_result0[256];
 	Scsi_Device *SDpnt;
 	Scsi_Device *SDtail;
-	int sparse_lun;
+	unsigned int sparse_lun;
+	int lun0_sl;
 
 	scsi_result = NULL;
 
@@ -343,8 +355,12 @@
 		lun = hlun;
 		if (lun >= shpnt->max_lun)
 			goto leave;
-		scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
-				  &SDpnt, shpnt, scsi_result);
+		if ((0 == lun) || (lun > 7))
+			lun0_sl = SCSI_3; /* actually don't care for 0 == lun */
+		else
+			lun0_sl = find_lun0_scsi_level(channel, dev, shpnt);
+		scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, 
+				  &sparse_lun, &SDpnt, shpnt, scsi_result);
 		if (SDpnt != oldSDpnt) {
 
 			/* it could happen the blockdevice hasn't yet been inited */
@@ -400,12 +416,14 @@
 					max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
 					 max_scsi_luns : shpnt->max_lun);
 					sparse_lun = 0;
-					for (lun = 0; lun < max_dev_lun; ++lun) {
-						if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
-								       &sparse_lun, &SDpnt, shpnt,
-							     scsi_result)
+					for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) {
+						if (!scan_scsis_single(channel, order_dev, lun, lun0_sl,
+							 	       &max_dev_lun, &sparse_lun, &SDpnt, shpnt,
+								       scsi_result)
 						    && !sparse_lun)
 							break;	/* break means don't probe further for luns!=0 */
+						if (SDpnt && (0 == lun))
+							lun0_sl = SDpnt->scsi_level;
 					}	/* for lun ends */
 				}	/* if this_id != id ends */
 			}	/* for dev ends */
@@ -461,9 +479,11 @@
  * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
  * Global variables used : scsi_devices(linked list)
  */
-static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
-	       int *sparse_lun, Scsi_Device ** SDpnt2, 
-		      struct Scsi_Host *shpnt, char *scsi_result)
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+		unsigned int lun, int lun0_scsi_level,
+		unsigned int *max_dev_lun, unsigned int *sparse_lun, 
+		Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, 
+		char *scsi_result)
 {
 	char devname[64];
 	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -509,7 +529,10 @@
 	 * Build an INQUIRY command block.
 	 */
 	scsi_cmd[0] = INQUIRY;
-	scsi_cmd[1] = (lun << 5) & 0xe0;
+	if ((lun > 0) && (lun0_scsi_level <= SCSI_2))
+		scsi_cmd[1] = (lun << 5) & 0xe0;
+	else	
+		scsi_cmd[1] = 0;	/* SCSI_3 and higher, don't touch */
 	scsi_cmd[2] = 0;
 	scsi_cmd[3] = 0;
 	scsi_cmd[4] = 255;
@@ -677,7 +700,9 @@
 		printk("Unlocked floptical drive.\n");
 		SDpnt->lockable = 0;
 		scsi_cmd[0] = MODE_SENSE;
-		scsi_cmd[1] = (lun << 5) & 0xe0;
+		if (shpnt->max_lun <= 8)
+			scsi_cmd[1] = (lun << 5) & 0xe0;
+		else	scsi_cmd[1] = 0;	/* any other idea? */
 		scsi_cmd[2] = 0x2e;
 		scsi_cmd[3] = 0;
 		scsi_cmd[4] = 0x2a;
@@ -760,7 +785,19 @@
 	 * other settings, and scan all of them.
 	 */
 	if (bflags & BLIST_SPARSELUN) {
-		*max_dev_lun = 8;
+		/*
+		 * Scanning MAX_SCSI_LUNS units would be a bad idea.
+		 * Any better idea?
+		 * I think we need REPORT LUNS in future to avoid scanning
+		 * of unused LUNs. But, that is another item.
+		 *
+		 * FIXME(eric) - perhaps this should be a kernel configurable?
+		 */
+		if (*max_dev_lun < shpnt->max_lun)
+			*max_dev_lun = shpnt->max_lun;
+		else 	if ((max_scsi_luns >> 1) >= *max_dev_lun)
+				*max_dev_lun += shpnt->max_lun;
+			else	*max_dev_lun = max_scsi_luns;
 		*sparse_lun = 1;
 		return 1;
 	}
@@ -769,7 +806,17 @@
 	 * settings, and scan all of them.
 	 */
 	if (bflags & BLIST_FORCELUN) {
-		*max_dev_lun = 8;
+		/* 
+		 * Scanning MAX_SCSI_LUNS units would be a bad idea.
+		 * Any better idea?
+		 * I think we need REPORT LUNS in future to avoid scanning
+		 * of unused LUNs. But, that is another item.
+		 */
+		if (*max_dev_lun < shpnt->max_lun)
+			*max_dev_lun = shpnt->max_lun;
+		else 	if ((max_scsi_luns >> 1) >= *max_dev_lun)
+				*max_dev_lun += shpnt->max_lun;
+			else	*max_dev_lun = max_scsi_luns;
 		return 1;
 	}
 	/*
@@ -793,3 +840,23 @@
 	return 1;
 }
 
+/*
+ * The worker for scan_scsis.
+ * Returns the scsi_level of lun0 on this host, channel and dev (if already
+ * known), otherwise returns SCSI_2.
+ */
+static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
+				struct Scsi_Host *shpnt)
+{
+	int res = SCSI_2;
+	Scsi_Device *SDpnt;
+
+	for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+	{
+		if ((0 == SDpnt->lun) && (dev == SDpnt->id) &&
+		    (channel == SDpnt->channel))
+			return (int)SDpnt->scsi_level;
+	}
+	/* haven't found lun0, should send INQUIRY but take easy route */
+	return res;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)