patch-1.3.9 linux/drivers/scsi/scsi.c

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

diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
@@ -51,7 +51,6 @@
 
 #undef USE_STATIC_SCSI_MEMORY
 
-
 /*
 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $";
 */
@@ -164,65 +163,94 @@
  * lock up. 
  */
 
-struct blist{
+#define BLIST_NOLUN     0x01
+#define BLIST_FORCELUN  0x02
+#define BLIST_BORKEN    0x04
+#define BLIST_KEY       0x08
+#define BLIST_SINGLELUN 0x10
+
+struct dev_info{
     char * vendor;
     char * model;
     char * revision; /* Latest revision known to be bad.  Not used yet */
+    unsigned flags;
 };
 
-static struct blist blacklist[] =
-{
-{"CHINON","CD-ROM CDS-431","H42"}, /* Locks up if polled for lun != 0 */
-{"CHINON","CD-ROM CDS-535","Q14"}, /* Locks up if polled for lun != 0 */
-{"DENON","DRD-25X","V"},           /* Locks up if probed for lun != 0 */
-{"HITACHI","DK312C","CM81"},       /* Responds to all lun - dtg */
-{"HITACHI","DK314C","CR21" },      /* responds to all lun */
-{"IMS", "CDD521/10","2.06"},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","XT-3280","PR02"},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","XT-4380S","B3C"},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","MXT-1240S","I1.2"},     /* Locks up when LUN>0 polled */
-{"MAXTOR","XT-4170S","B5A"},       /* Locks-up sometimes when LUN>0 polled. */
-{"MAXTOR","XT-8760S","B7B"},       /* guess what? */
-{"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
-{"RODIME","RO3000S","2.33"},       /* Locks up if polled for lun != 0 */
-{"SEAGATE", "ST157N", "\004|j"},   /* causes failed REQUEST SENSE on lun 1 
-				    * for aha152x controller, which causes 
-				    * SCSI code to reset bus.*/
-{"SEAGATE", "ST296","921"},        /* Responds to all lun */
-{"SONY","CD-ROM CDU-541","4.3d"},
-{"SONY","CD-ROM CDU-55S","1.0i"},
-{"TANDBERG","TDC 3600","U07"},     /* Locks up if polled for lun != 0 */
-{"TEAC","CD-ROM","1.06"},          /* causes failed REQUEST SENSE on lun 1 
-				    * for seagate controller, which causes 
-				    * SCSI code to reset bus.*/
-{"TEXEL","CD-ROM","1.06"},         /* causes failed REQUEST SENSE on lun 1 
-				    * for seagate controller, which causes 
-				    * SCSI code to reset bus.*/
-{"QUANTUM","LPS525S","3110"},      /* Locks sometimes if polled for lun != 0 */
-{"QUANTUM","PD1225S","3110"},      /* Locks sometimes if polled for lun != 0 */
-{"MEDIAVIS","CDR-H93MV","1.31"},   /* Locks up if polled for lun != 0 */
-{"SANKYO", "CP525","6.64"},        /* causes failed REQ SENSE, extra reset */
-{"HP", "C1750A", "3226"},          /* scanjet iic */
-{"HP", "C1790A", ""},              /* scanjet iip */
-{"HP", "C2500A", ""},              /* scanjet iicx */
+/*
+ * This is what was previously known as the blacklist.  The concept
+ * has been expanded so that we can specify other 
+ * The blacklist is used to determine which devices cannot tolerate a
+ * lun probe because of buggy firmware.  Far too many for my liking,
+ * which is why the default is now for there to be no lun scan. 
+ */
+static struct dev_info device_list[] =
+{
+{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+{"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
+{"HITACHI","DK312C","CM81", BLIST_NOLUN},       /* Responds to all lun - dtg */
+{"HITACHI","DK314C","CR21" , BLIST_NOLUN},      /* responds to all lun */
+{"IMS", "CDD521/10","2.06", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-3280","PR02", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN},     /* Locks up when LUN>0 polled */
+{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
+{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
+{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
+{"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
+{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1 
+                                                 * for aha152x controller, which causes 
+                                                 * SCSI code to reset bus.*/
+{"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
+{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
+{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
+{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
+{"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
+{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1 
+                                                 * for seagate controller, which causes 
+                                                 * SCSI code to reset bus.*/
+{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1 
+                                                 * for seagate controller, which causes 
+                                                 * SCSI code to reset bus.*/
+{"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
+{"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
+{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */
+{"SANKYO", "CP525","6.64", BLIST_NOLUN},        /* causes failed REQ SENSE, extra reset */
+{"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
+{"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
+{"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
+
+/*
+ * Other types of devices that have special flags.
+ */
+{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
+{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
+{"INSITE","Floptical   F*8I","*", BLIST_KEY},
+{"INSITE","I325VM","*", BLIST_KEY},
+{"PIONEER","CD-ROMDRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+{"PIONEER","CD-ROMDRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+/*
+ * Must be at end of list...
+ */
 {NULL, NULL, NULL}
 };
 
-static int blacklisted(unsigned char * response_data){
+static int get_device_flags(unsigned char * response_data){
     int i = 0;
     unsigned char * pnt;
     for(i=0; 1; i++){
-	if(blacklist[i].vendor == NULL) return 0;
+	if(device_list[i].vendor == NULL) return 0;
 	pnt = &response_data[8];
 	while(*pnt && *pnt == ' ') pnt++;
-	if(memcmp(blacklist[i].vendor, pnt,
-		  strlen(blacklist[i].vendor))) continue;
+	if(memcmp(device_list[i].vendor, pnt,
+		  strlen(device_list[i].vendor))) continue;
 	pnt = &response_data[16];
 	while(*pnt && *pnt == ' ') pnt++;
-	if(memcmp(blacklist[i].model, pnt,
-		  strlen(blacklist[i].model))) continue;
-	return 1;
+	if(memcmp(device_list[i].model, pnt,
+		  strlen(device_list[i].model))) continue;
+	return device_list[i].flags;
     }
+    return 0;
 }
 
 /*
@@ -323,7 +351,7 @@
 
 /*
  *  Detecting SCSI devices :
- *  We scan all present host adapter's busses,  from ID 0 to ID 6.
+ *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
  *  We use the INQUIRY command, determine device type, and pass the ID /
  *  lun address of all sequential devices to the tape driver, all random
  *  devices to the disk driver.
@@ -338,6 +366,8 @@
     unsigned char * scsi_result;
     Scsi_Device * SDpnt, *SDtail;
     struct Scsi_Device_Template * sdtpnt;
+    int                 bflags;
+    int                 max_dev_lun = 0;
     Scsi_Cmnd  *SCpnt;
     
     ++in_scan_scsis;
@@ -364,7 +394,7 @@
 	channel = hchannel;
 	dev = hid;
 	lun = hlun;
-	goto crude;
+	goto crude; /* Anyone remember good ol' BASIC ?  :-) */
     }
 
     for (channel = 0; channel <= shpnt->max_channel; channel++)
@@ -374,9 +404,14 @@
 		
 		/*
 		 * We need the for so our continue, etc. work fine.
+                 * We put this in a variable so that we can override
+                 * it during the scan if we detect a device *KNOWN*
+                 * to have multiple logical units.
 		 */
-		for (lun = 0; lun < (max_scsi_luns < shpnt->max_lun ? 
-				     max_scsi_luns : shpnt->max_lun); ++lun)
+                max_dev_lun = (max_scsi_luns < shpnt->max_lun ? 
+                               max_scsi_luns : shpnt->max_lun);
+
+		for (lun = 0; lun < max_dev_lun; ++lun)
 		{
 		crude:
 		    memset(SDpnt, 0, sizeof(Scsi_Device));
@@ -531,6 +566,7 @@
 			SDpnt->changed = 0;
 			SDpnt->access_count = 0;
 			SDpnt->busy = 0;
+                        SDpnt->has_cmdblocks = 0;
 			/*
 			 * Currently, all sequential devices are assumed to be
 			 * tapes, all random devices disk, with the appropriate
@@ -560,6 +596,7 @@
 #endif
 			}
 			
+                        SDpnt->single_lun = 0;
 			SDpnt->soft_reset =
 			    (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
 			SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
@@ -599,6 +636,12 @@
 			     */
 
 			    SDpnt->disconnect = 0;
+
+                            /*
+                             * Get any flags for this device.
+                             */
+                            bflags = get_device_flags(scsi_result);
+
 			    
 			    /*
 			     * Some revisions of the Texel CD ROM drives have 
@@ -608,38 +651,16 @@
 			     * change it here if it turns out that it isn't
 			     * a TEXEL drive.
 			     */
-			    if((strncmp("SONY",(char *) &scsi_result[8], 4)!= 0
-				|| strncmp("CD-ROM CDU-8001",
-					   (char *) &scsi_result[16], 15) != 0)
-			       && (strncmp("TEXEL", 
-					   (char *) &scsi_result[8], 5) != 0 
-				   || strncmp("CD-ROM", 
-					      (char *) &scsi_result[16], 6) != 0
-				/*
-				 * XXX 1.06 has problems, some one should 
-				 * figure out the others too so ALL TEXEL 
-				 * drives don't suffer in performance, 
-				 * especially when I finish integrating my 
-				 * seagate patches which do multiple I_T_L 
-				 * nexuses.
-				 */
-				
-#ifdef notyet
-				|| (strncmp("1.06", 
-					    (char *) &scsi_result, 4) != 0)
-#endif
-				))
+                            if( (bflags & BLIST_BORKEN) == 0 )
+                            {
 				SDpnt->borken = 0;
+                            }
 			    
 			    
 			    /* These devices need this "key" to unlock the
 			     * devices so we can use it 
 			     */
-			    if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
-			       (memcmp("Floptical   F*8I", 
-				       &scsi_result[16], 16) == 0
-				|| memcmp("I325VM", 
-					  &scsi_result[16], 6) == 0)) {
+                            if( (bflags & BLIST_KEY) != 0 ) {
 				printk("Unlocked floptical drive.\n");
 				SDpnt->lockable = 0;
 				scsi_cmd[0] = MODE_SENSE;
@@ -680,7 +701,32 @@
 			    /* Some scsi devices cannot be polled for lun != 0
 			     * due to firmware bugs 
 			     */
-			    if(blacklisted(scsi_result)) break;
+			    if(bflags & BLIST_NOLUN) break;
+
+                            /*
+                             * If we want to only allow I/O to one of the luns
+                             * attached to this device at a time, then we set this
+                             * flag.
+                             */
+                            if(bflags & BLIST_SINGLELUN)
+                            {
+                                SDpnt->single_lun = 1;
+                            }
+
+                            /*
+                             * If this device is known to support multiple units, override
+                             * the other settings, and scan all of them.
+                             */
+                            if(bflags & BLIST_FORCELUN)
+                            {
+                                /*
+                                 * We probably want to make this a variable, but this
+                                 * will do for now.
+                                 */
+                                max_dev_lun = 8;
+                            }
+ 
+
 			    /* Old drives like the MAXTOR XT-3280 say vers=0 */
 			    if ((scsi_result[2] & 0x07) == 0)
 				break;
@@ -692,6 +738,10 @@
 			}
 		    }       /* if result == DID_OK ends */
 
+                    /*
+                     * This might screw us up with multi-lun devices, but the user can
+                     * scan for them too.
+                     */
 		    if(hardcoded == 1)
 			goto leave;
 		} /* for lun ends */
@@ -778,6 +828,7 @@
 {
     Scsi_Cmnd * SCpnt = NULL;
     int tablesize;
+    Scsi_Cmnd * found = NULL;
     struct buffer_head * bh, *bhp;
     
     if (!device)
@@ -787,11 +838,44 @@
 	panic("Invalid device in request_queueable");
     
     SCpnt =  device->host->host_queue;
-    while(SCpnt){
-	if(SCpnt->target == device->id && SCpnt->lun == device->lun 
-	   && SCpnt->channel == device->channel)
-	    if(SCpnt->request.dev < 0) break;
-	SCpnt = SCpnt->next;
+
+    /*
+     * Look for a free command block.  If we have been instructed not to queue
+     * multiple commands to multi-lun devices, then check to see what else is going on
+     * for this device first.
+     */
+      
+    SCpnt = device->host->host_queue;
+    if (!device->single_lun) {
+        while(SCpnt){
+            if(SCpnt->target == device->id &&
+               SCpnt->lun == device->lun) {
+                if(SCpnt->request.dev < 0) break;
+            }
+            SCpnt = SCpnt->next;
+        }
+    } else {
+        while(SCpnt){
+            if(SCpnt->target == device->id) {
+                if (SCpnt->lun == device->lun) {
+                    if(found == NULL 
+                       && SCpnt->request.dev < 0) 
+                    {
+                        found=SCpnt;
+                    }
+                } 
+                if(SCpnt->request.dev >= 0) {
+                    /*
+                     * I think that we should really limit things to one
+                     * outstanding command per device - this is what tends to trip
+                     * up buggy firmware.
+                     */
+                    return NULL;
+                }
+            }
+            SCpnt = SCpnt->next;
+        }
+        SCpnt = found;
     }
     
     if (!SCpnt) return NULL;
@@ -841,14 +925,14 @@
     SCpnt->transfersize = 0;
     SCpnt->underflow = 0;
     SCpnt->cmd_len = 0;
-#if 1
+
 /* Since not everyone seems to set the device info correctly
  * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
  */ 
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
-#endif
+
     return SCpnt;
 }
 
@@ -873,6 +957,7 @@
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Cmnd * SCwait = NULL;
+    Scsi_Cmnd * found = NULL;
     
     if (!device)
 	panic ("No device passed to allocate_device().\n");
@@ -887,15 +972,40 @@
     if (intr_count && SCSI_BLOCK(host)) return NULL;
     
     while (1==1){
-	SCpnt = host->host_queue;
-	while(SCpnt){
-	    if(SCpnt->target == device->id && SCpnt->lun == device->lun
-	       && SCpnt->channel == device->channel) {
-		SCwait = SCpnt;
-		if(SCpnt->request.dev < 0) break;
-	    }
-	    SCpnt = SCpnt->next;
-	}
+        SCpnt = device->host->host_queue;
+        if (!device->single_lun) {
+            while(SCpnt){
+                if(SCpnt->target == device->id &&
+                   SCpnt->lun == device->lun) {
+                    if(SCpnt->request.dev < 0) break;
+                }
+                SCpnt = SCpnt->next;
+            }
+        } else {
+            while(SCpnt){
+                if(SCpnt->target == device->id) {
+                    if (SCpnt->lun == device->lun) {
+                        if(found == NULL 
+                           && SCpnt->request.dev < 0) 
+                        {
+                            found=SCpnt;
+                        }
+                    } 
+                    if(SCpnt->request.dev >= 0) {
+                        /*
+                         * I think that we should really limit things to one
+                         * outstanding command per device - this is what tends to trip
+                         * up buggy firmware.
+                         */
+                        found = NULL;
+                        break;
+                    }
+                }
+                SCpnt = SCpnt->next;
+            }
+            SCpnt = found;
+        }
+
 	save_flags(flags);
 	cli();
 	/* See if this request has already been queued by an interrupt routine
@@ -964,15 +1074,16 @@
     SCpnt->old_use_sg  = 0;
     SCpnt->transfersize = 0;      /* No default transfer size */
     SCpnt->cmd_len = 0;
+
     SCpnt->underflow = 0;         /* Do not flag underflow conditions */
-#if 1
-/* Since not everyone seems to set the device info correctly
- * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
- */ 
+
+    /* Since not everyone seems to set the device info correctly
+     * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+     */ 
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
-#endif
+
     return SCpnt;
 }
 
@@ -2139,6 +2250,7 @@
 	SCpnt->prev = NULL;
 	host->host_queue = SCpnt;
     }
+    SDpnt->has_cmdblocks = 1;
 }
 
 /*
@@ -2196,6 +2308,7 @@
 	if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
     }
     
+
     if (scsi_devicelist)
 	dma_sectors = 16;  /* Base value we use */
     
@@ -2584,6 +2697,7 @@
 		scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
 		sdpnt->host->host_queue = SCpnt;
 		if (SCpnt) SCpnt->prev = NULL;
+                sdpnt->has_cmdblocks = 0;
 	    }
     
     /* Next free up the Scsi_Device structures for this host */
@@ -2672,7 +2786,6 @@
 static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
 {
     Scsi_Device * SDpnt;
-    int previous_attachment;
     
     if (tpnt->next) return 1;
     
@@ -2686,7 +2799,7 @@
     
     /*
      * If any of the devices would match this driver, then perform the
-     * init function.  +
+     * init function.
      */
     if(tpnt->init && tpnt->dev_noticed) (*tpnt->init)();
     
@@ -2695,13 +2808,12 @@
      */
     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
     {
-	previous_attachment = SDpnt->attached;
 	if(tpnt->attach)  (*tpnt->attach)(SDpnt);
 	/*
 	 * If this driver attached to the device, and we no longer
 	 * have anything attached, release the scso command blocks.
 	 */
-	if(SDpnt->attached && previous_attachment == 0)
+	if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
 	    scsi_build_commandblocks(SDpnt);
     }
     
@@ -2750,6 +2862,7 @@
 		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
 		}
 	    }
+            SDpnt->has_cmdblocks = 0;
 	}
     }
     /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this