patch-2.3.29 linux/drivers/scsi/scsi.c
Next file: linux/drivers/scsi/scsi_proc.c
Previous file: linux/drivers/scsi/script_asm.pl
Back to the patch index
Back to the overall index
- Lines: 554
- Date:
Sun Nov 21 11:13:56 1999
- Orig file:
v2.3.28/linux/drivers/scsi/scsi.c
- Orig date:
Thu Nov 11 20:11:48 1999
diff -u --recursive --new-file v2.3.28/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
@@ -59,6 +59,7 @@
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>
+#include <asm/uaccess.h>
#include "scsi.h"
#include "hosts.h"
@@ -73,8 +74,7 @@
struct proc_dir_entry *proc_scsi = NULL;
#ifdef CONFIG_PROC_FS
-static int scsi_proc_info(char *buffer, char **start, off_t offset,
- int length, int inout);
+static int scsi_proc_info(char *buffer, char **start, off_t offset, int length);
static void scsi_dump_status(int level);
#endif
@@ -112,14 +112,19 @@
* lock up.
*/
-#define BLIST_NOLUN 0x01
-#define BLIST_FORCELUN 0x02
-#define BLIST_BORKEN 0x04
-#define BLIST_KEY 0x08
-#define BLIST_SINGLELUN 0x10
-#define BLIST_NOTQ 0x20
-#define BLIST_SPARSELUN 0x40
-#define BLIST_MAX5LUN 0x80
+#define BLIST_NOLUN 0x001
+#define BLIST_FORCELUN 0x002
+#define BLIST_BORKEN 0x004
+#define BLIST_KEY 0x008
+#define BLIST_SINGLELUN 0x010
+#define BLIST_NOTQ 0x020
+#define BLIST_SPARSELUN 0x040
+#define BLIST_MAX5LUN 0x080
+#define BLIST_ISDISK 0x100
+#define BLIST_ISROM 0x200
+#define BLIST_GHOST 0x400
+
+
/*
* Data declarations.
@@ -187,11 +192,11 @@
extern void scsi_old_done(Scsi_Cmnd * SCpnt);
extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);
-#define SCSI_BLOCK(DEVICE, HOST) \
- ((HOST->block && host_active && HOST != host_active) \
- || ((HOST)->can_queue && HOST->host_busy >= HOST->can_queue) \
- || ((HOST)->host_blocked) \
- || ((DEVICE) != NULL && (DEVICE)->device_blocked) )
+#define SCSI_BLOCK(DEVICE, HOST) \
+ ((HOST->block && host_active && HOST != host_active) \
+ || ((HOST)->can_queue && HOST->host_busy >= HOST->can_queue) \
+ || ((HOST)->host_blocked) \
+ || ((DEVICE) != NULL && (DEVICE)->device_blocked) )
@@ -243,6 +248,7 @@
{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
* for seagate controller, which causes
* SCSI code to reset bus.*/
+ {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN}, /* Responds to all lun */
{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1
* for seagate controller, which causes
* SCSI code to reset bus.*/
@@ -254,7 +260,9 @@
{"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */
{"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */
{"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */
- {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* extra reset */
+ {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0
+ * extra reset */
{"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */
/*
@@ -277,10 +285,12 @@
{"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
{"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
- {"MATSHITA", "PD", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
- {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
- {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+ {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+ {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
+ {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
+ {"HITACHI", "GF-1050","*", BLIST_GHOST}, /* Hitachi SCSI DVD-RAM */
+ {"TOSHIBA","CDROM","*", BLIST_ISROM},
/*
* Must be at end of list...
@@ -471,7 +481,7 @@
SCpnt->request.rq_status = RQ_SCSI_BUSY;
spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd (SCpnt, (void *) cmnd,
- buffer, bufflen, done, timeout, retries);
+ buffer, bufflen, done, timeout, retries);
spin_unlock_irqrestore(&io_request_lock, flags);
down (&sem);
SCpnt->request.sem = NULL;
@@ -690,6 +700,8 @@
struct Scsi_Device_Template *sdtpnt;
Scsi_Device *SDtail, *SDpnt = *SDpnt2;
int bflags, type = -1;
+ static int ghost_channel=-1, ghost_dev=-1;
+ int org_lun = lun;
SDpnt->host = shpnt;
SDpnt->id = dev;
@@ -697,6 +709,14 @@
SDpnt->channel = channel;
SDpnt->online = TRUE;
+
+ if ((channel == ghost_channel) && (dev == ghost_dev) && (lun == 1)) {
+ SDpnt->lun = 0;
+ } else {
+ ghost_channel = ghost_dev = -1;
+ }
+
+
/* Some low level driver could use device->type (DB) */
SDpnt->type = -1;
@@ -719,8 +739,8 @@
SCpnt->channel = SDpnt->channel;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
- (void *) NULL,
- 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+ (void *) NULL,
+ 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
dev, lun, SCpnt->result));
@@ -752,8 +772,8 @@
SCpnt->cmd_len = 0;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
- (void *) scsi_result,
- 256, scan_scsis_done, SCSI_TIMEOUT, 3);
+ (void *) scsi_result,
+ 256, scan_scsis_done, SCSI_TIMEOUT, 3);
SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
SCpnt->result ? "failed" : "successful", SCpnt->result));
@@ -768,15 +788,41 @@
if ((scsi_result[0] >> 5) == 3) {
return 0; /* assume no peripheral if any sort of error */
}
+
/*
- * It would seem some TOSHIBA CDROM gets things wrong
+ * Get any flags for this device.
*/
- if (!strncmp(scsi_result + 8, "TOSHIBA", 7) &&
- !strncmp(scsi_result + 16, "CD-ROM", 6) &&
- scsi_result[0] == TYPE_DISK) {
+ bflags = get_device_flags (scsi_result);
+
+
+ /* The Toshiba ROM was "gender-changed" here as an inline hack.
+ This is now much more generic.
+ This is a mess: What we really want is to leave the scsi_result
+ alone, and just change the SDpnt structure. And the SDpnt is what
+ we want print_inquiry to print. -- REW
+ */
+ if (bflags & BLIST_ISDISK) {
+ scsi_result[0] = TYPE_DISK;
+ scsi_result[1] |= 0x80; /* removable */
+ }
+
+ if (bflags & BLIST_ISROM) {
scsi_result[0] = TYPE_ROM;
- scsi_result[1] |= 0x80; /* removable */
+ scsi_result[1] |= 0x80; /* removable */
+ }
+
+ if (bflags & BLIST_GHOST) {
+ if ((ghost_channel == channel) && (ghost_dev == dev) && (org_lun == 1)) {
+ lun=1;
+ } else {
+ ghost_channel = channel;
+ ghost_dev = dev;
+ scsi_result[0] = TYPE_MOD;
+ scsi_result[1] |= 0x80; /* removable */
+ }
}
+
+
memcpy(SDpnt->vendor, scsi_result + 8, 8);
memcpy(SDpnt->model, scsi_result + 16, 16);
memcpy(SDpnt->rev, scsi_result + 32, 4);
@@ -839,10 +885,6 @@
*/
SDpnt->disconnect = 0;
- /*
- * Get any flags for this device.
- */
- bflags = get_device_flags(scsi_result);
/*
* Set the tagged_queue flag for SCSI-II devices that purport to support
@@ -885,8 +927,8 @@
scsi_cmd[5] = 0;
SCpnt->cmd_len = 0;
scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
- (void *) scsi_result, 0x2a,
- scan_scsis_done, SCSI_TIMEOUT, 3);
+ (void *) scsi_result, 0x2a,
+ scan_scsis_done, SCSI_TIMEOUT, 3);
}
/*
* Detach the command from the device. It was just a temporary to be used while
@@ -961,6 +1003,17 @@
*max_dev_lun = 5;
return 1;
}
+
+ /*
+ * If this device is Ghosted, scan upto two luns. (It physically only
+ * has one). -- REW
+ */
+ if (bflags & BLIST_GHOST) {
+ *max_dev_lun = 2;
+ return 1;
+ }
+
+
/*
* 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
@@ -1201,9 +1254,14 @@
}
if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) { /* Might have changed */
if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE) {
- spin_unlock(&io_request_lock); /* FIXME!!!! */
- sleep_on(&device->device_wait);
- spin_lock_irq(&io_request_lock); /* FIXME!!!! */
+ DECLARE_WAITQUEUE(wait,current);
+ add_wait_queue(&device->device_wait,&wait);
+ current->state=TASK_UNINTERRUPTIBLE;
+ spin_unlock(&io_request_lock);
+ schedule();
+ current->state=TASK_RUNNING;
+ remove_wait_queue(&device->device_wait,&wait);
+ spin_lock_irq(&io_request_lock);
} else {
if (!wait)
return NULL;
@@ -1966,6 +2024,9 @@
SDpnt->has_cmdblocks = 1;
}
+static ssize_t proc_scsi_gen_write(struct file * file, const char * buf,
+ unsigned long length, void *data);
+
#ifndef MODULE /* { */
/*
* scsi_dev_init() is our initialization routine, which in turn calls host
@@ -1977,6 +2038,7 @@
Scsi_Device *SDpnt;
struct Scsi_Host *shpnt;
struct Scsi_Device_Template *sdtpnt;
+ struct proc_dir_entry *generic;
#ifdef FOO_ON_YOU
return;
#endif
@@ -1993,7 +2055,13 @@
return -ENOMEM;
}
- create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info);
+ generic = create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info);
+ if (!generic) {
+ printk (KERN_ERR "cannot init /proc/scsi/scsi\n");
+ remove_proc_entry("scsi", 0);
+ return -ENOMEM;
+ }
+ generic->write_proc = proc_scsi_gen_write;
#endif
/* Init a few things so we can "malloc" memory. */
@@ -2102,63 +2170,77 @@
printk("\n");
}
-
#ifdef CONFIG_PROC_FS
-static int scsi_proc_info(char *buffer, char **start, off_t offset,
- int length, int inout)
+static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
{
- Scsi_Cmnd *SCpnt;
- struct Scsi_Device_Template *SDTpnt;
Scsi_Device *scd;
struct Scsi_Host *HBA_ptr;
- char *p;
- int host, channel, id, lun;
int size, len = 0;
off_t begin = 0;
off_t pos = 0;
- if (inout == 0) {
- /*
- * First, see if there are any attached devices or not.
- */
- for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
- if (HBA_ptr->host_queue != NULL) {
- break;
- }
+ /*
+ * First, see if there are any attached devices or not.
+ */
+ for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
+ if (HBA_ptr->host_queue != NULL) {
+ break;
}
- size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");
+ }
+ size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");
+ len += size;
+ pos = begin + len;
+ for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
+#if 0
+ size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,
+ HBA_ptr->hostt->procname);
len += size;
pos = begin + len;
- for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
-#if 0
- size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,
- HBA_ptr->hostt->procname);
+#endif
+ for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
+ proc_print_scsidevice(scd, buffer, &size, len);
len += size;
pos = begin + len;
-#endif
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- proc_print_scsidevice(scd, buffer, &size, len);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
}
+ if (pos > offset + length)
+ goto stop_output;
}
-
- stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
}
- if (!buffer || length < 11 || strncmp("scsi", buffer, 4))
- return (-EINVAL);
+
+stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ return (len);
+}
+
+static ssize_t proc_scsi_gen_write(struct file * file, const char * buf,
+ unsigned long length, void *data)
+{
+ Scsi_Cmnd *SCpnt;
+ struct Scsi_Device_Template *SDTpnt;
+ Scsi_Device *scd;
+ struct Scsi_Host *HBA_ptr;
+ char *p;
+ int host, channel, id, lun;
+ char * buffer;
+ int err;
+
+ if (!buf || length>PAGE_SIZE)
+ return -EINVAL;
+
+ if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ copy_from_user(buffer, buf, length);
+
+ err = -EINVAL;
+ if (length < 11 || strncmp("scsi", buffer, 4))
+ goto out;
/*
* Usage: echo "scsi dump #N" > /proc/scsi/scsi
@@ -2171,7 +2253,7 @@
p = buffer + 10;
if (*p == '\0')
- return (-EINVAL);
+ goto out;
level = simple_strtoul(p, NULL, 0);
scsi_dump_status(level);
@@ -2205,7 +2287,7 @@
*/
scsi_logging_level = 0;
} else {
- return (-EINVAL);
+ goto out;
}
} else {
*p++ = '\0';
@@ -2236,7 +2318,7 @@
} else if (strcmp(token, "ioctl") == 0) {
SCSI_SET_IOCTL_LOGGING(level);
} else {
- return (-EINVAL);
+ goto out;
}
}
@@ -2271,8 +2353,9 @@
break;
}
}
+ err = -ENXIO;
if (!HBA_ptr)
- return (-ENXIO);
+ goto out;
for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
if ((scd->channel == channel
@@ -2282,8 +2365,9 @@
}
}
+ err = -ENOSYS;
if (scd)
- return (-ENOSYS); /* We do not yet support unplugging */
+ goto out; /* We do not yet support unplugging */
scan_scsis(HBA_ptr, 1, channel, id, lun);
@@ -2293,8 +2377,8 @@
if (HBA_ptr->select_queue_depths != NULL)
(HBA_ptr->select_queue_depths) (HBA_ptr, HBA_ptr->host_queue);
- return (length);
-
+ err = length;
+ goto out;
}
/*
* Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
@@ -2321,8 +2405,9 @@
break;
}
}
+ err = -ENODEV;
if (!HBA_ptr)
- return (-ENODEV);
+ goto out;
for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
if ((scd->channel == channel
@@ -2333,10 +2418,11 @@
}
if (scd == NULL)
- return (-ENODEV); /* there is no such device attached */
+ goto out; /* there is no such device attached */
+ err = -EBUSY;
if (scd->access_count)
- return (-EBUSY);
+ goto out;
SDTpnt = scsi_devicelist;
while (SDTpnt != NULL) {
@@ -2366,11 +2452,14 @@
}
scsi_init_free((char *) scd, sizeof(Scsi_Device));
} else {
- return (-EBUSY);
+ goto out;
}
- return (0);
+ err = 0;
}
- return (-EINVAL);
+out:
+
+ free_page((unsigned long) buffer);
+ return err;
}
#endif
@@ -2746,6 +2835,7 @@
struct Scsi_Host *shpnt;
Scsi_Host_Template *SHT;
Scsi_Host_Template *SHTp;
+ char name[10]; /* host_no>=10^9? I don't think so. */
/*
* First verify that this host adapter is completely free with no pending
@@ -2887,7 +2977,8 @@
continue;
pcount = next_scsi_host;
/* Remove the /proc/scsi directory entry */
- remove_proc_entry(shpnt->proc_name, tpnt->proc_dir);
+ sprintf(name,"%d",shpnt->host_no);
+ remove_proc_entry(name, tpnt->proc_dir);
if (tpnt->release)
(*tpnt->release) (shpnt);
else {
@@ -3238,6 +3329,7 @@
{
unsigned long size;
int has_space = 0;
+ struct proc_dir_entry *generic;
/*
* This makes /proc/scsi and /proc/scsi/scsi visible.
@@ -3248,7 +3340,13 @@
printk (KERN_ERR "cannot init /proc/scsi\n");
return -ENOMEM;
}
- create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info);
+ generic = create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info);
+ if (!generic) {
+ printk (KERN_ERR "cannot init /proc/scsi/scsi\n");
+ remove_proc_entry("scsi", 0);
+ return -ENOMEM;
+ }
+ generic->write_proc = proc_scsi_gen_write;
#endif
scsi_loadable_module_flag = 1;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)