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

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

diff -u --recursive --new-file v1.3.45/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
@@ -62,6 +62,10 @@
 static int update_timeout (Scsi_Cmnd *, int);
 static void print_inquiry(unsigned char *data);
 static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
+static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
+                 Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
+                 struct Scsi_Host *shpnt, char * scsi_result);
+
 
 static unsigned char * dma_malloc_freelist = NULL;
 static int scsi_need_isa_bounce_buffers;
@@ -371,392 +375,365 @@
  *  lun address of all sequential devices to the tape driver, all random
  *  devices to the disk driver.
  */
-static
-void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded, 
-		 unchar hchannel, unchar hid, unchar hlun)
-{
-    int dev, lun, type, channel;
-    unsigned char scsi_cmd [12];
-    unsigned char scsi_result0 [256];
-    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;
-    lun = 0;
-    type = -1;
-    SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA);
-    SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
-    SDtail = scsi_devices;
-    
-    if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
-    
-    /* Make sure we have something that is valid for DMA purposes */
-    scsi_result = ((!dma_malloc_freelist  || !shpnt->unchecked_isa_dma)
-		   ?  &scsi_result0[0] : scsi_malloc(512));
-    
-    if(scsi_result == NULL) {
-	printk("Unable to obtain scsi_result buffer\n");
-	goto leave;
-    }
-    
-    shpnt->host_queue = SCpnt; /* We need this so that commands can time out */
+static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
+                 unchar hchannel, unchar hid, unchar hlun)
+{
+  int dev, lun, channel;
+  unsigned char scsi_result0[256];
+  unsigned char *scsi_result;
+  Scsi_Device *SDpnt;
+  int max_dev_lun;
+  Scsi_Cmnd *SCpnt;
 
-    if(hardcoded == 1) {
-	channel = hchannel;
-	dev = hid;
-	lun = hlun;
-	goto crude; /* Anyone remember good ol' BASIC ?  :-) */
-    }
+  in_scan_scsis++;
+  SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
+  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
+
+  /* Make sure we have something that is valid for DMA purposes */
+  scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma)
+                 ? &scsi_result0[0] : scsi_malloc (512));
+
+  if (scsi_result == NULL) {
+    printk ("Unable to obtain scsi_result buffer\n");
+    goto leave;
+  }
+
+  shpnt->host_queue = SCpnt;    /* We need this so that commands can time out */
+
+  if (hardcoded == 1) {
+    channel = hchannel;
+    if(channel > shpnt->max_channel) goto leave;
+    dev = hid;
+    if(dev >= shpnt->max_id) goto leave;
+    lun = hlun;
+    if(lun >= shpnt->max_lun) goto leave;
+    scan_scsis_single (channel, dev, lun, &max_dev_lun,
+                   &SDpnt, SCpnt, shpnt, scsi_result);
+  }
+  else {
+    for (channel = 0; channel <= shpnt->max_channel; channel++) {
+      for (dev = 0; dev < shpnt->max_id; ++dev) {
+        if (shpnt->this_id != dev) {
+          /*
+           * 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.
+           */
+          max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
+                         max_scsi_luns : shpnt->max_lun);
+
+          for (lun = 0; lun < max_dev_lun; ++lun) {
+
+            if (!scan_scsis_single (channel, dev, lun, &max_dev_lun,
+                                    &SDpnt, SCpnt, shpnt, scsi_result))
+              break; /* break means don't probe for luns!=0 */
+          }                     /* for lun ends */
+        }                       /* if this_id != id ends */
+      }                         /* for dev ends */
+    }                           /* for channel ends */
+
+leave:
+    shpnt->host_queue = NULL;   /* No longer needed here */
+
+     /* Last device block does not exist.  Free memory. */
+    if (SDpnt != NULL)
+      scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device));
 
-    for (channel = 0; channel <= shpnt->max_channel; channel++)
-    {
-	for (dev = 0; dev < shpnt->max_id; ++dev) {
-	    if (shpnt->this_id != dev) {
-		
-		/*
-		 * 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.
-		 */
-		max_dev_lun = (max_scsi_luns < shpnt->max_lun ? 
-			       max_scsi_luns : shpnt->max_lun);
+    if (SCpnt != NULL)
+      scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd));
 
-		for (lun = 0; lun < max_dev_lun; ++lun)
-		{
-		crude:
-		    memset(SDpnt, 0, sizeof(Scsi_Device));
-		    SDpnt->host = shpnt;
-		    SDpnt->id = dev;
-		    SDpnt->lun = lun;
-		    SDpnt->channel = channel;
+    /* If we allocated a buffer so we could do DMA, free it now */
+    if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+      scsi_free (scsi_result, 512);
 
-		    /* Some low level driver could use device->type (DB) */
-		    SDpnt->type = -1;
-		    /*
-		     * Assume that the device will have handshaking problems, 
-		     * and then fix this field later if it turns out it doesn't
-		     */
-		    SDpnt->borken = 1;
-                    SDpnt->was_reset = 0;
-                    SDpnt->expecting_cc_ua = 0;
-		    
-		    scsi_cmd[0] = TEST_UNIT_READY;
-		    scsi_cmd[1] = lun << 5;
-		    scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
-		    
-		    memset(SCpnt, 0,  sizeof(Scsi_Cmnd));
-		    SCpnt->host = SDpnt->host;
-		    SCpnt->device = SDpnt;
-		    SCpnt->target = SDpnt->id;
-		    SCpnt->lun = SDpnt->lun;
-		    SCpnt->channel = SDpnt->channel;
+    in_scan_scsis--;
+  }
+}
 
-		    {
-			/*
-			 * Do the actual command, and wait for it to finish
-			 */
-			struct semaphore sem = MUTEX_LOCKED;
-			SCpnt->request.sem = &sem;
-			SCpnt->request.rq_status = RQ_SCSI_BUSY;
-			scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
-				     (void *) scsi_result,
-				     256,  scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
-			down(&sem);
-		    }
+/*
+ * The worker for scan_scsis.
+ * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
+ * Global variables used : scsi_devices(linked list), the_result
+ */
+int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
+    Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt, 
+    char *scsi_result)
+{
+  unsigned char scsi_cmd[12];
+  struct Scsi_Device_Template *sdtpnt;
+  Scsi_Device * SDtail, *SDpnt=*SDpnt2;
+  int bflags, type=-1;
+
+  SDtail = scsi_devices;
+  if (scsi_devices)
+    while (SDtail->next)
+      SDtail = SDtail->next;
+
+  memset (SDpnt, 0, sizeof (Scsi_Device));
+  SDpnt->host = shpnt;
+  SDpnt->id = dev;
+  SDpnt->lun = lun;
+  SDpnt->channel = channel;
+
+  /* Some low level driver could use device->type (DB) */
+  SDpnt->type = -1;
+
+  /*
+   * Assume that the device will have handshaking problems, and then fix this
+   * field later if it turns out it doesn't
+   */
+  SDpnt->borken = 1;
+  SDpnt->was_reset = 0;
+  SDpnt->expecting_cc_ua = 0;
+
+  scsi_cmd[0] = TEST_UNIT_READY;
+  scsi_cmd[1] = lun << 5;
+  scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+
+  memset (SCpnt, 0, sizeof (Scsi_Cmnd));
+  SCpnt->host = SDpnt->host;
+  SCpnt->device = SDpnt;
+  SCpnt->target = SDpnt->id;
+  SCpnt->lun = SDpnt->lun;
+  SCpnt->channel = SDpnt->channel;
+  {
+    struct semaphore sem = MUTEX_LOCKED;
+    SCpnt->request.sem = &sem;
+    SCpnt->request.rq_status = RQ_SCSI_BUSY;
+    scsi_do_cmd (SCpnt, (void *) scsi_cmd,
+                 (void *) scsi_result,
+                 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+    down (&sem);
+  }
 
 #if defined(DEBUG) || defined(DEBUG_INIT)
-		    printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
-		    printk("scsi: return code %08x\n", SCpnt->result);
+  printk ("scsi: scan_scsis_single id %d lun %d. Return code %d\n",
+          dev, lun, SCpnt->result);
 #endif
 
-		    if(SCpnt->result) {
-			if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
-			     (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
-			    ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
-			    if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
-			       ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
-				continue;
-			}
-			else
-			    break;
-		    }
-		    
+  if (SCpnt->result) {
+    if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
+         (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
+        ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
+      if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+          ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
+        return 1;
+    }
+    else
+      return 0;
+  }
+
 #if defined (DEBUG) || defined(DEBUG_INIT)
-		    printk("scsi: performing INQUIRY\n");
+  printk ("scsi: performing INQUIRY\n");
 #endif
+  /*
+   * Build an INQUIRY command block.
+   */
+  scsi_cmd[0] = INQUIRY;
+  scsi_cmd[1] = (lun << 5) & 0xe0;
+  scsi_cmd[2] = 0;
+  scsi_cmd[3] = 0;
+  scsi_cmd[4] = 255;
+  scsi_cmd[5] = 0;
+  SCpnt->cmd_len = 0;
+  {
+    struct semaphore sem = MUTEX_LOCKED;
+    SCpnt->request.sem = &sem;
+    SCpnt->request.rq_status = RQ_SCSI_BUSY;
+    scsi_do_cmd (SCpnt, (void *) scsi_cmd,
+                 (void *) scsi_result,
+                 256, scan_scsis_done, SCSI_TIMEOUT, 3);
+    down (&sem);
+  }
 
-		    /*
-		     * Build an INQUIRY command block.
-		     */
-		    scsi_cmd[0] = INQUIRY;
-		    scsi_cmd[1] = (lun << 5) & 0xe0;
-		    scsi_cmd[2] = 0;
-		    scsi_cmd[3] = 0;
-		    scsi_cmd[4] = 255;
-		    scsi_cmd[5] = 0;
-		    
-		    SCpnt->cmd_len = 0;
-
-		    {
-			struct semaphore sem = MUTEX_LOCKED;
-			SCpnt->request.sem = &sem;
-			SCpnt->request.rq_status = RQ_SCSI_BUSY;
-			scsi_do_cmd (SCpnt, (void *)  scsi_cmd, 
-				 (void *) scsi_result,
-				 256,  scan_scsis_done, SCSI_TIMEOUT, 3);
-			down(&sem);
-		    }
-		    
-		    the_result = SCpnt->result;
-		    
+  the_result = SCpnt->result;
 #if defined(DEBUG) || defined(DEBUG_INIT)
-		    if (!the_result)
-			printk("scsi: INQUIRY successful\n");
-		    else
-			printk("scsi: INQUIRY failed with code %08x\n", the_result);
-#endif
-		    
-		    if(the_result) break;
-		    
-		    /* skip other luns on this device */
-		    
-		    if (!the_result)
-		    {
-			/* It would seem some TOSHIBA CDROM 
-			 * gets things wrong 
-			 */
-			if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
-			    !strncmp(scsi_result+16,"CD-ROM",6) &&
-			    scsi_result[0] == TYPE_DISK) {
-			    scsi_result[0] = TYPE_ROM;
-			    scsi_result[1] |= 0x80;  /* removable */
-			}
-			
-			if (!strncmp(scsi_result+8,"NEC",3)) {
-			    if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) || 
-				!strncmp(scsi_result+16,"CD-ROM DRIVE:25",15))
-				SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
-			    else
-				SDpnt->manufacturer = SCSI_MAN_NEC;
-			} else if (!strncmp(scsi_result+8,"TOSHIBA",7))
-			    SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
-			else if (!strncmp(scsi_result+8,"SONY",4))
-			    SDpnt->manufacturer = SCSI_MAN_SONY;
-                        else if (!strncmp(scsi_result+8, "PIONEER", 7))
-                            SDpnt->manufacturer = SCSI_MAN_PIONEER;
-			else
-			    SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
-			
-			memcpy(SDpnt->vendor, scsi_result+8, 8);
-			memcpy(SDpnt->model, scsi_result+16, 16);
-			memcpy(SDpnt->rev, scsi_result+32, 4);
- 
-			SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
-			SDpnt->lockable = SDpnt->removable;
-			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
-			 * read only flags set for ROM / WORM treated as RO.
-			 */
-			
-			switch (type = (scsi_result[0] & 0x1f))
-			{
-			case TYPE_TAPE :
-			case TYPE_DISK :
-			case TYPE_MOD :
-			case TYPE_PROCESSOR :
-			case TYPE_SCANNER :
-			    SDpnt->writeable = 1;
-			    break;
-			case TYPE_WORM :
-			case TYPE_ROM :
-			    SDpnt->writeable = 0;
-			    break;
-			default :
-#if 0
-#ifdef DEBUG
-			    printk("scsi: unknown type %d\n", type);
-			    print_inquiry(scsi_result);
-#endif
-			    type = -1;
+  printk ("scsi: INQUIRY %s with code 0x%x\n",
+          the_result ? "failed" : "successful", the->result);
 #endif
-			}
-			
-			SDpnt->single_lun = 0;
-			SDpnt->soft_reset =
-			    (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
-			SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
-			SDpnt->type = (type & 0x1f);
-			
-			if (type != -1)
-			{
-			    print_inquiry(scsi_result);
-			    
-			    for(sdtpnt = scsi_devicelist; sdtpnt; 
-				sdtpnt = sdtpnt->next)
-				if(sdtpnt->detect) SDpnt->attached +=
-				    (*sdtpnt->detect)(SDpnt);
-			    
-			    SDpnt->scsi_level = scsi_result[2] & 0x07;
-			    if (SDpnt->scsi_level >= 2 ||
-				(SDpnt->scsi_level == 1 &&
-				 (scsi_result[3] & 0x0f) == 1))
-				SDpnt->scsi_level++;
-			    /*
-			     * Set the tagged_queue flag for SCSI-II devices 
-			     * that purport to support
-			     * tagged queuing in the INQUIRY data.
-			     */
-			    
-			    SDpnt->tagged_queue = 0;
-			    
-			    if ((SDpnt->scsi_level >= SCSI_2) &&
-				(scsi_result[7] & 2)) {
-				SDpnt->tagged_supported = 1;
-				SDpnt->current_tag = 0;
-			    }
-			    
-			    /*
-			     * Accommodate drivers that want to sleep when 
-			     * they should be in a polling loop.
-			     */
-
-			    SDpnt->disconnect = 0;
-
-			    /*
-			     * Get any flags for this device.
-			     */
-			    bflags = get_device_flags(scsi_result);
-
-			    
-			    /*
-			     * Some revisions of the Texel CD ROM drives have 
-			     * handshaking problems when used with the Seagate
-			     * controllers.  Before we know what type of device
-			     * we're talking to, we assume it's borken and then
-			     * change it here if it turns out that it isn't
-			     * a TEXEL drive.
-			     */
-			    if( (bflags & BLIST_BORKEN) == 0 )
-			    {
-				SDpnt->borken = 0;
-			    }
-			    
-			    
-			    /* These devices need this "key" to unlock the
-			     * devices so we can use it 
-			     */
-			    if( (bflags & BLIST_KEY) != 0 ) {
-				printk("Unlocked floptical drive.\n");
-				SDpnt->lockable = 0;
-				scsi_cmd[0] = MODE_SENSE;
-				scsi_cmd[1] = (lun << 5) & 0xe0;
-				scsi_cmd[2] = 0x2e;
-				scsi_cmd[3] = 0;
-				scsi_cmd[4] = 0x2a;
-				scsi_cmd[5] = 0;
-				
-				SCpnt->cmd_len = 0;
-				{
-				    struct semaphore sem = MUTEX_LOCKED;
-				    SCpnt->request.rq_status = RQ_SCSI_BUSY;
-				    SCpnt->request.sem = &sem;
-				    scsi_do_cmd (SCpnt, (void *)  scsi_cmd,
-					     (void *) scsi_result, 0x2a,  
-					     scan_scsis_done, SCSI_TIMEOUT, 3);
-				    down(&sem);
-				}
-			    }
-			    /* Add this device to the linked list at the end */
-			    if(SDtail)
-				SDtail->next = SDpnt;
-			    else
-				scsi_devices = SDpnt;
-			    SDtail = SDpnt;
-			    
-			    SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
-			    /* Some scsi devices cannot be polled for lun != 0
-			     * due to firmware bugs 
-			     */
-			    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;
-			    /* Some scsi-1 peripherals do not handle lun != 0.
-			     * I am assuming that scsi-2 peripherals do better 
-			     */
-			    if((scsi_result[2] & 0x07) == 1 &&
-			       (scsi_result[3] & 0x0f) == 0) break;
-			}
-		    }       /* if result == DID_OK ends */
+  if (the_result)
+    return 0;     /* assume no peripheral if any sort of error */
 
-		    /*
-		     * 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 */
-	    } /* if this_id != id ends */
-	} /* for dev ends */
-    } /* for channel ends */
-    
- leave:
-    shpnt->host_queue = NULL;  /* No longer needed here */
-    
-    /* Last device block does not exist.  Free memory. */
-    if(SDpnt != NULL)
-	scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
-    
-    if(SCpnt != NULL)
-	scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
-    
-    /* If we allocated a buffer so we could do DMA, free it now */
-    if (scsi_result != &scsi_result0[0] && scsi_result != NULL) 
-	scsi_free(scsi_result, 512);
-    
-    in_scan_scsis = 0;
-}       /* scan_scsis  ends */
+  /*
+   * It would seem some TOSHIBA CDROM gets things wrong
+   */
+  if (!strncmp (scsi_result + 8, "TOSHIBA", 7) &&
+      !strncmp (scsi_result + 16, "CD-ROM", 6) &&
+      scsi_result[0] == TYPE_DISK) {
+    scsi_result[0] = TYPE_ROM;
+    scsi_result[1] |= 0x80;     /* removable */
+  }
+
+  if (!strncmp (scsi_result + 8, "NEC", 3)) {
+    if (!strncmp (scsi_result + 16, "CD-ROM DRIVE:84 ", 16) ||
+        !strncmp (scsi_result + 16, "CD-ROM DRIVE:25", 15))
+      SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
+    else
+      SDpnt->manufacturer = SCSI_MAN_NEC;
+  }
+  else if (!strncmp (scsi_result + 8, "TOSHIBA", 7))
+    SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
+  else if (!strncmp (scsi_result + 8, "SONY", 4))
+    SDpnt->manufacturer = SCSI_MAN_SONY;
+  else if (!strncmp (scsi_result + 8, "PIONEER", 7))
+    SDpnt->manufacturer = SCSI_MAN_PIONEER;
+  else
+    SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
+
+  memcpy (SDpnt->vendor, scsi_result + 8, 8);
+  memcpy (SDpnt->model, scsi_result + 16, 16);
+  memcpy (SDpnt->rev, scsi_result + 32, 4);
+
+  SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+  SDpnt->lockable = SDpnt->removable;
+  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 read only flags set for ROM / WORM
+   * treated as RO.
+   */
+  switch (type = (scsi_result[0] & 0x1f)) {
+  case TYPE_TAPE:
+  case TYPE_DISK:
+  case TYPE_MOD:
+  case TYPE_PROCESSOR:
+  case TYPE_SCANNER:
+    SDpnt->writeable = 1;
+    break;
+  case TYPE_WORM:
+  case TYPE_ROM:
+    SDpnt->writeable = 0;
+    break;
+  default:
+    printk ("scsi: unknown type %d\n", type);
+  }
+
+  SDpnt->single_lun = 0;
+  SDpnt->soft_reset =
+    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
+  SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
+  SDpnt->type = (type & 0x1f);
+
+  print_inquiry (scsi_result);
+
+  for (sdtpnt = scsi_devicelist; sdtpnt;
+       sdtpnt = sdtpnt->next)
+    if (sdtpnt->detect)
+      SDpnt->attached +=
+        (*sdtpnt->detect) (SDpnt);
+
+  SDpnt->scsi_level = scsi_result[2] & 0x07;
+  if (SDpnt->scsi_level >= 2 ||
+      (SDpnt->scsi_level == 1 &&
+       (scsi_result[3] & 0x0f) == 1))
+    SDpnt->scsi_level++;
+
+  /*
+   * Set the tagged_queue flag for SCSI-II devices that purport to support
+   * tagged queuing in the INQUIRY data.
+   */
+  SDpnt->tagged_queue = 0;
+  if ((SDpnt->scsi_level >= SCSI_2) &&
+      (scsi_result[7] & 2)) {
+    SDpnt->tagged_supported = 1;
+    SDpnt->current_tag = 0;
+  }
+
+  /*
+   * Accommodate drivers that want to sleep when they should be in a polling
+   * loop.
+   */
+  SDpnt->disconnect = 0;
+
+  /*
+   * Get any flags for this device.
+   */
+  bflags = get_device_flags (scsi_result);
+
+  /*
+   * Some revisions of the Texel CD ROM drives have handshaking problems when
+   * used with the Seagate controllers.  Before we know what type of device
+   * we're talking to, we assume it's borken and then change it here if it
+   * turns out that it isn't a TEXEL drive.
+   */
+  if ((bflags & BLIST_BORKEN) == 0)
+    SDpnt->borken = 0;
+
+  /*
+   * These devices need this "key" to unlock the devices so we can use it
+   */
+  if ((bflags & BLIST_KEY) != 0) {
+    printk ("Unlocked floptical drive.\n");
+    SDpnt->lockable = 0;
+    scsi_cmd[0] = MODE_SENSE;
+    scsi_cmd[1] = (lun << 5) & 0xe0;
+    scsi_cmd[2] = 0x2e;
+    scsi_cmd[3] = 0;
+    scsi_cmd[4] = 0x2a;
+    scsi_cmd[5] = 0;
+    SCpnt->cmd_len = 0;
+    {
+      struct semaphore sem = MUTEX_LOCKED;
+      SCpnt->request.rq_status = RQ_SCSI_BUSY;
+      SCpnt->request.sem = &sem;
+      scsi_do_cmd (SCpnt, (void *) scsi_cmd,
+                   (void *) scsi_result, 0x2a,
+                   scan_scsis_done, SCSI_TIMEOUT, 3);
+      down (&sem);
+    }
+  }
+  /* Add this device to the linked list at the end */
+  if (SDtail)
+    SDtail->next = SDpnt;
+  else
+    scsi_devices = SDpnt;
+  SDtail = SDpnt;
+
+  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
+  *SDpnt2=SDpnt;
+  if (!SDpnt)
+    printk ("scsi: scan_scsis_single: No memory\n");
+
+
+  /*
+   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+   */
+  if (bflags & BLIST_NOLUN)
+    return 0;                   /* 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)
+    *max_dev_lun = 8;
+  /*
+   * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
+   * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
+   * (ANSI SCSI Revision 1) and Response Data Format 0
+   */
+  if (((scsi_result[2] & 0x07) == 0)
+      ||
+      ((scsi_result[2] & 0x07) == 1 &&
+       (scsi_result[3] & 0x0f) == 0))
+    return 0;
+  return 1;
+}
 
 /*
  *  Flag bits for the internal_timeout array
  */
-
 #define NORMAL_TIMEOUT 0
 #define IN_ABORT 1
 #define IN_RESET 2
@@ -1153,8 +1130,8 @@
 #ifdef DEBUG_DELAY
 	clock = jiffies + 4 * HZ;
 	while (jiffies < clock);
-	printk("done(host = %d, result = %04x) : routine at %08x\n", 
-	       host->host_no, temp);
+	printk("done(host = %d, result = %04x) : routine at %p\n", 
+	       host->host_no, temp, host->hostt->command);
 #endif
 	scsi_done(SCpnt);
     }
@@ -2413,7 +2390,7 @@
     struct Scsi_Host *HBA_ptr;
     int  parameter[4];
     char *p;
-    int	  size, len = 0;
+    int	  i,size, len = 0;
     off_t begin = 0;
     off_t pos = 0;
 
@@ -2458,21 +2435,29 @@
 	return (len);     
     }
 
+    /*
+     * Usage: echo "scsi singledevice 0 1 2 3" >/proc/scsi/scsi
+     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+     * Consider this feature ALPHA, as you can easily hang your
+     * scsi system (depending on your low level driver).
+     */
     if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
 	return(-EINVAL);
 
     if(!strncmp("singledevice", buffer + 5, 12)) {
 	p = buffer + 17;
 
-	parameter[0] = simple_strtoul(p , &p, 0);
-	parameter[1] = simple_strtoul(p , &p, 0);
-	parameter[2] = simple_strtoul(p , &p, 0);
-	parameter[3] = simple_strtoul(p , &p, 0);
-
-	while(scd && scd->host->host_no != parameter[0] 
-	      && scd->channel != parameter[1] 
-	      && scd->id != parameter[2] 
-	      && scd->lun != parameter[3]) {
+	for(i=0; i<4; i++)	{
+	    p++;
+	    parameter[i] = simple_strtoul(p, &p, 0);
+	}
+	printk("scsi singledevice %d %d %d %d\n", parameter[0], parameter[1],
+			parameter[2], parameter[3]);
+
+	while(scd && (scd->host->host_no != parameter[0] 
+	      || scd->channel != parameter[1] 
+	      || scd->id != parameter[2] 
+	      || scd->lun != parameter[3])) {
 	    scd = scd->next;
 	}
 	if(scd)
@@ -2484,7 +2469,7 @@
 	    return(-ENXIO);
 
 	scan_scsis (HBA_ptr, 1, parameter[1], parameter[2], parameter[3]);
-	return(0);
+	return(length);
     }
     return(-EINVAL);
 }
@@ -3035,7 +3020,7 @@
 	for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
 	{
 	    /*  (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x      */
-	    printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %ld) (%d %d %x) (%d %d %d) %x %x %x\n",
+	    printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %d) (%d %d %x) (%d %d %d) %x %x %x\n",
 		   i++, SCpnt->host->host_no,
 		   SCpnt->channel,
 		   SCpnt->target,

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