PATCH ncr5380/53c400, lp module

Kevin Lentin (kevinl@cs.monash.edu.au)
Wed, 20 Mar 1996 15:08:21 +1100 (EST)


This is a patch to the NCR5380/NCR53C400 SCSI driver and to the lp module
loading code.

Firstly, this fixes a type problem which causes 1.3.75 (and probably many
previous versions, I'm not sure, my copy was fixed) to fail to compile with
this SCSI driver enabled. generic_NCR5380_info was not prototyped.

It also contains greatly increased /proc/scsi/g_NCR5380 reporting including
collection of throughput stats using a mechanism I learned in Image
Processing for working out areas based on contours. This allows you to work
out how long each request takes without needing to keep track of starting
and ending times for each request!

Thirdly, it contains a fix for an OOPS in the 'lp' module loading code. The
current code does very nasty things with insmod supplied irq's and if it
fails to find one can lead to an OOPS. The code which looks at insmod
supplied info scribbles on the probe list and then falls through to the
probe code. Bad Karma. Fixed.

I've seen a few people moan about the lp problem and several have
complained to me about the SCSI problem. Hopefully these can get into the
next 1.3 release.

diff -u3 -r --exclude-from=/work/PATCH_EXCLUDE /u/tmp/linux-1.3.59.orig/drivers/char/lp.c /usr/src/linux/drivers/char/lp.c
--- /u/tmp/linux-1.3.59.orig/drivers/char/lp.c Tue Mar 19 21:19:18 1996
+++ /usr/src/linux/drivers/char/lp.c Tue Mar 19 20:13:17 1996
@@ -602,6 +602,7 @@
{
int offset = 0;
int count = 0;
+ int failed = 0;

if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
printk("lp: unable to get major %d\n", LP_MAJOR);
@@ -623,13 +624,25 @@
if (specified) {
if (lp_probe(offset) <= 0) {
printk(KERN_INFO "lp%d: Not found\n", offset);
- return -EIO;
+ failed++;
} else
count++;
}
}
+ /* Successful specified devices increase count
+ * Unsuccessful specified devices increase failed
+ */
if (count)
return 0;
+ if (failed) {
+ printk(KERN_INFO "lp: No override devices found.\n");
+ unregister_chrdev(LP_MAJOR,"lp");
+ return -EIO;
+ }
+ /* Only get here if there were no specified devices. To continue
+ * would be silly since the above code has scribbled all over the
+ * probe list.
+ */
#endif
/* take on all known port values */
for (offset = 0; offset < LP_NO; offset++) {
diff -u3 -r --exclude-from=/work/PATCH_EXCLUDE /u/tmp/linux-1.3.59.orig/drivers/scsi/NCR5380.c /usr/src/linux/drivers/scsi/NCR5380.c
--- /u/tmp/linux-1.3.59.orig/drivers/scsi/NCR5380.c Tue Mar 19 21:17:05 1996
+++ /usr/src/linux/drivers/scsi/NCR5380.c Tue Mar 19 20:11:02 1996
@@ -809,6 +809,17 @@
hostdata->connected = NULL;
hostdata->issue_queue = NULL;
hostdata->disconnected_queue = NULL;
+#ifdef NCR5380_STATS
+ for (i = 0; i < 8; ++i) {
+ hostdata->time_read[i] = 0;
+ hostdata->time_write[i] = 0;
+ hostdata->bytes_read[i] = 0;
+ hostdata->bytes_write[i] = 0;
+ }
+ hostdata->timebase = 0;
+ hostdata->pendingw = 0;
+ hostdata->pendingr = 0;
+#endif

/* The CHECK code seems to break the 53C400. Will check it later maybe */
if (flags & FLAG_NCR53C400)
@@ -916,6 +927,7 @@
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
case WRITE:
+ case WRITE_6:
case WRITE_10:
printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
instance->host_no);
@@ -925,6 +937,34 @@
}
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */

+#ifdef NCR5380_STATS
+# if 0
+ if (!hostdata->connected && !hostdata->issue_queue &&
+ !hostdata->disconnected_queue) {
+ hostdata->timebase = jiffies;
+ }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+ switch (cmd->cmnd[0])
+ {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+ hostdata->pendingw++;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+ hostdata->pendingr++;
+ break;
+ }
+#endif

/*
* We use the host_scribble field as a pointer to the next command
@@ -1224,6 +1264,32 @@
} while (!done);
}

+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+ switch (cmd->cmnd[0])
+ {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+ hostdata->pendingw--;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+ hostdata->pendingr--;
+ break;
+ }
+}
+#endif
+
/*
* Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
* int tag);
@@ -1469,6 +1535,9 @@
return -1;
}
cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
#if (NDEBUG & NDEBUG_SELECTION)
@@ -2322,6 +2391,9 @@
printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n",
instance->host_no, cmd->target, cmd->lun);
#endif
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
cmd->scsi_done(cmd);
cmd = hostdata->connected;
break;
@@ -2387,9 +2459,13 @@
#if (NDEBUG & NDEBUG_QUEUES)
printk("scsi%d : REQUEST SENSE added to head of issue queue\n",instance->host_no);
#endif
- } else
+ } else {
#endif /* def AUTOSENSE */
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
cmd->scsi_done(cmd);
+ }

NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
@@ -2557,6 +2633,9 @@
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+ collect_stats(hostdata, cmd);
+#endif
cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
@@ -2841,7 +2920,7 @@

cli();
NCR5380_setup(instance);
-
+
#if (NDEBUG & NDEBUG_ABORT)
printk("scsi%d : abort called\n", instance->host_no);
printk(" basr 0x%X, sr 0x%X\n",
diff -u3 -r --exclude-from=/work/PATCH_EXCLUDE /u/tmp/linux-1.3.59.orig/drivers/scsi/NCR5380.h /usr/src/linux/drivers/scsi/NCR5380.h
--- /u/tmp/linux-1.3.59.orig/drivers/scsi/NCR5380.h Tue Mar 19 21:17:05 1996
+++ /usr/src/linux/drivers/scsi/NCR5380.h Tue Mar 19 20:11:02 1996
@@ -265,6 +265,15 @@
unsigned long time_expires; /* in jiffies, set prior to sleeping */
struct Scsi_Host *next_timer;
#endif
+#ifdef NCR5380_STATS
+ unsigned timebase; /* Base for time calcs */
+ long time_read[8]; /* time to do reads */
+ long time_write[8]; /* time to do writes */
+ unsigned long bytes_read[8]; /* bytes read */
+ unsigned long bytes_write[8]; /* byytes written */
+ unsigned pendingr;
+ unsigned pendingw;
+#endif
};

#ifdef __KERNEL__
diff -u3 -r --exclude-from=/work/PATCH_EXCLUDE /u/tmp/linux-1.3.59.orig/drivers/scsi/README.g_NCR5380 /usr/src/linux/drivers/scsi/README.g_NCR5380
--- /u/tmp/linux-1.3.59.orig/drivers/scsi/README.g_NCR5380 Tue Mar 19 21:12:29 1996
+++ /usr/src/linux/drivers/scsi/README.g_NCR5380 Sat Feb 10 01:20:54 1996
@@ -44,3 +44,49 @@

Kevin Lentin
K.Lentin@cs.monash.edu.au
+REAME file for the Linux g_NCR5380 driver.
+
+(c) 1993 Drew Eckhard
+NCR53c400 extensions (c) 1994,1995,1996 Kevin Lentin
+
+This file documents the NCR53c400 extensions by Kevin Lentin and some
+enhancements to the NCR5380 core.
+
+This driver supports both NCR5380 and NCR53c400 cards in port or memory
+mapped modes. Currently this driver can only support one of those mapping
+modes at a time but it does support both of these chips at the same time.
+The next release of this driver will support port & memory mapped cards at
+the same time. It should be able to handle multiple different cards in the
+same machine.
+
+The drivers/scsi/Makefile has an override in it for the most common
+NCR53c400 card, the Trantor T130B in its default configuration:
+ Port: 0x350
+ IRQ : 5
+
+The NCR53c400 does not support DMA but it does have Pseudo-DMA which is
+supported by the driver.
+
+If the default configuration does not work for you, you can use the kernel
+command lines (eg using the lilo append command):
+ ncr5380=port,irq,dma
+ ncr53c400=port,irq
+or
+ ncr5380=base,irq,dma
+ ncr53c400=base,irq
+
+The driver does not probe for any addresses or ports other than those in
+the OVERRIDE or given to the kernel as above.
+
+This driver provides some information on what it has detected in
+/proc/scsi/g_NCR5380/x where x is the scsi card number as detected at boot
+time. More info to come in the future.
+
+When NCR53c400 support is compiled in, BIOS paramaters will be returned by
+the driver (the raw 5380 driver does not and I don't plan to fiddle with
+it!).
+
+This driver works as a module.
+
+Kevin Lentin
+K.Lentin@cs.monash.edu.au
diff -u3 -r --exclude-from=/work/PATCH_EXCLUDE /u/tmp/linux-1.3.59.orig/drivers/scsi/g_NCR5380.c /usr/src/linux/drivers/scsi/g_NCR5380.c
--- /u/tmp/linux-1.3.59.orig/drivers/scsi/g_NCR5380.c Tue Mar 19 21:17:10 1996
+++ /usr/src/linux/drivers/scsi/g_NCR5380.c Tue Mar 19 20:11:05 1996
@@ -65,6 +65,8 @@
#define NCR53C400_PSEUDO_DMA 1
#define PSEUDO_DMA
#define NCR53C400
+#define NCR5380_STATS
+#undef NCR5380_STAT_LIMIT
#endif
#if defined(CONFIG_SCSI_G_NCR5380_PORT) && defined(CONFIG_SCSI_G_NCR5380_MEM)
#error You can not configure the Generic NCR 5380 SCSI Driver for memory mapped I/O and port mapped I/O at the same time (yet)
@@ -238,8 +240,8 @@
return count;
}

-const char * generic_NCR5380_info (void) {
- static const char string[]="Generic NCR5380/53C400 Info";
+const char * generic_NCR5380_info (struct Scsi_Host* host) {
+ static const char string[]="Generic NCR5380/53C400 Driver";
return string;
}

@@ -285,40 +287,6 @@
}
#endif

-int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
-{
- int len = 0;
- struct Scsi_Host *scsi_ptr;
-
- for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
- if (scsi_ptr->host_no == hostno)
- break;
-
- len += sprintf(buffer+len, "SCSI host number %d : %s\n", scsi_ptr->host_no, scsi_ptr->hostt->name);
- len += sprintf(buffer+len, "Generic NCR5380 driver version %d\n", GENERIC_NCR5380_PUBLIC_RELEASE);
- len += sprintf(buffer+len, "NCR5380 driver core version %d\n", NCR5380_PUBLIC_RELEASE);
-#ifdef NCR53C400
- len += sprintf(buffer+len, "NCR53C400 driver extension version %d\n", NCR53C400_PUBLIC_RELEASE);
- len += sprintf(buffer+len, "NCR53C400 card%s detected\n", (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not");
-# if NCR53C400_PSEUDO_DMA
- len += sprintf(buffer+len, "NCR53C400 pseudo DMA being used\n");
-# endif
-#else
- len += sprintf(buffer+len, "NO NCR53C400 driver extensions\n");
-#endif
- len += sprintf(buffer+len, "Using %s mapping at %s 0x%x, ", STRVAL(NCR5380_map_config), STRVAL(NCR5380_map_name), scsi_ptr->NCR5380_instance_name);
- if (scsi_ptr->irq == IRQ_NONE)
- len += sprintf(buffer+len, "interrupts disabled\n");
- else
- len += sprintf(buffer+len, "on interrupt %d\n", scsi_ptr->irq);
-
- *start = buffer + offset;
- len -= offset;
- if (len > length)
- len = length;
- return len;
-}
-
#if NCR53C400_PSEUDO_DMA
static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, int len)
{
@@ -564,6 +532,169 @@
#endif /* PSEUDO_DMA */

#include "NCR5380.c"
+
+#define PRINTP(x) len += sprintf(buffer+len, x)
+#define ANDP ,
+
+static int sprint_opcode(char* buffer, int len, int opcode) {
+ int start = len;
+ PRINTP("0x%02x " ANDP opcode);
+ return len-start;
+}
+
+static int sprint_command (char* buffer, int len, unsigned char *command) {
+ int i,s,start=len;
+ len += sprint_opcode(buffer, len, command[0]);
+ for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ PRINTP("%02x " ANDP command[i]);
+ PRINTP("\n");
+ return len-start;
+}
+
+static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) {
+ int start = len;
+ PRINTP("destination target %d, lun %d\n" ANDP
+ cmd->host->host_no ANDP
+ cmd->target ANDP
+ cmd->lun);
+ PRINTP(" command = ");
+ len += sprint_command (buffer, len, cmd->cmnd);
+ return len-start;
+}
+
+const char *const scsi_device_types[] =
+{
+ "Direct-Access ",
+ "Sequential-Access",
+ "Printer ",
+ "Processor ",
+ "WORM ",
+ "CD-ROM ",
+ "Scanner ",
+ "Optical Device ",
+ "Medium Changer ",
+ "Communications "
+};
+#define MAX_SCSI_DEVICE_CODE sizeof(scsi_device_types)/sizeof(char*)
+
+int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
+{
+ int len = 0;
+ NCR5380_local_declare();
+ unsigned char status;
+ int i;
+ struct Scsi_Host *scsi_ptr;
+ Scsi_Device *dev;
+ Scsi_Cmnd *ptr;
+ struct NCR5380_hostdata *hostdata;
+
+ cli();
+
+ for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
+ if (scsi_ptr->host_no == hostno)
+ break;
+ NCR5380_setup(scsi_ptr);
+ hostdata = (struct NCR5380_hostdata *)scsi_ptr->hostdata;
+
+ PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
+ PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
+ PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
+#ifdef NCR53C400
+ PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
+ PRINTP("NCR53C400 card%s detected\n" ANDP (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not");
+# if NCR53C400_PSEUDO_DMA
+ PRINTP("NCR53C400 pseudo DMA used\n");
+# endif
+#else
+ PRINTP("NO NCR53C400 driver extensions\n");
+#endif
+ PRINTP("Using %s mapping at %s 0x%x, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
+ if (scsi_ptr->irq == IRQ_NONE)
+ PRINTP("no interrupt\n");
+ else
+ PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
+
+#ifdef NCR5380_STATS
+ if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
+ PRINTP("There are commands pending, transfer rates may be crud\n");
+ if (hostdata->pendingr)
+ PRINTP(" %d pending reads" ANDP hostdata->pendingr);
+ if (hostdata->pendingw)
+ PRINTP(" %d pending writes" ANDP hostdata->pendingw);
+ if (hostdata->pendingr || hostdata->pendingw)
+ PRINTP("\n");
+ for (dev = scsi_devices; dev; dev=dev->next) {
+ if (dev->host == scsi_ptr) {
+ unsigned long br = hostdata->bytes_read[dev->id];
+ unsigned long bw = hostdata->bytes_write[dev->id];
+ 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");
+ for (i=0; i<8; i++)
+ if (dev->vendor[i] >= 0x20)
+ *(buffer+(len++)) = dev->vendor[i];
+ *(buffer+(len++)) = ' ';
+ for (i=0; i<16; i++)
+ if (dev->model[i] >= 0x20)
+ *(buffer+(len++)) = dev->model[i];
+ *(buffer+(len++)) = ' ';
+ for (i=0; i<4; i++)
+ if (dev->rev[i] >= 0x20)
+ *(buffer+(len++)) = dev->rev[i];
+ *(buffer+(len++)) = ' ';
+
+ PRINTP("\n%10d kb read in %5d secs" ANDP br/1024 ANDP tr);
+ if (tr)
+ PRINTP(" @ %5d bps" ANDP br / tr);
+
+ PRINTP("\n%10d kb written in %5d secs" ANDP bw/1024 ANDP tw);
+ if (tw)
+ PRINTP(" @ %5d bps" ANDP bw / tw);
+ PRINTP("\n");
+ }
+ }
+#endif
+
+ status = NCR5380_read(STATUS_REG);
+ if (!(status & SR_REQ))
+ PRINTP("REQ not asserted, phase unknown.\n");
+ else {
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i)
+ ;
+ PRINTP("Phase %s\n" ANDP phases[i].name);
+ }
+
+ if (!hostdata->connected) {
+ PRINTP("No currently connected command\n");
+ } else {
+ len += sprint_Scsi_Cmnd (buffer, len, (Scsi_Cmnd *) hostdata->connected);
+ }
+
+ PRINTP("issue_queue\n");
+
+ for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr;
+ ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ len += sprint_Scsi_Cmnd (buffer, len, ptr);
+
+ PRINTP("disconnected_queue\n");
+
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ len += sprint_Scsi_Cmnd (buffer, len, ptr);
+
+ *start = buffer + offset;
+ len -= offset;
+ if (len > length)
+ len = length;
+ sti();
+ return len;
+}
+
+#undef PRINTP
+#undef ANDP
+
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = GENERIC_NCR5380;
diff -u3 -r --exclude-from=/work/PATCH_EXCLUDE /u/tmp/linux-1.3.59.orig/drivers/scsi/g_NCR5380.h /usr/src/linux/drivers/scsi/g_NCR5380.h
--- /u/tmp/linux-1.3.59.orig/drivers/scsi/g_NCR5380.h Tue Mar 19 21:12:29 1996
+++ /usr/src/linux/drivers/scsi/g_NCR5380.h Sat Jan 27 15:58:22 1996
@@ -47,6 +47,7 @@
int generic_NCR5380_release_resources(struct Scsi_Host *);
int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int generic_NCR5380_reset(Scsi_Cmnd *);
+const char* generic_NCR5380_info(struct Scsi_Host *);
#ifdef BIOSPARAM
int generic_NCR5380_biosparam(Disk *, kdev_t, int *);
#endif

-- 
[=======================================================================]
[ Kevin Lentin                 |finger kevinl@fangorn.cs.monash.edu.au| ]
[ K.Lentin@cs.monash.edu.au    |for PGP public key block. Fingerprint | ]
[ Macintrash: 'Just say NO!'   |6024308DE1F84314  811B511DBA6FD596    | ]
[=======================================================================]