Re: Problems with Adaptec 2940 as a module

Michael Neuffer (neuffer@nomis.i-connect.net)
Tue, 22 Oct 1996 03:49:08 -0700 (PDT)


On Mon, 21 Oct 1996, Michael K. Johnson wrote:
> I think that this bug is fairly generic. Here at Red Hat, we've had
> reports that moving from modularized low-level SCSI drivers to drivers
> compiled into the kernel has fixed the exact same problem (the card
> being found, but no devices being found on the bus) for people with
> aha174x's and DPT's using the eata_dma driver. I'm currently looking
> into ncr53c8xx (the driver that appeared not to work is Drew's, not
> Gerard's) and various aic7xxx controllers. Others I'm not sure about;
> the Advansys driver *might* be exhibiting the same problem, but the
> bug reports aren't clear in this case.

> I get the impression that with the aic7xxx, it at least sometimes
> works as a module, but I've heard at least one report from someone
> else that one card (I think a 3940) which did not work with a module
> did work with a compiled-in driver. There may be issues like the
> amount of RAM involved, but I haven't seen a pattern yet.

No, see my explanation below.

> It shows up a little more spectacularly with Red Hat Linux 4.0
> because we use initrd and SCSI modules to have a single boot
> image for everyone. Unfortunately, it took a while to track
> down, because at least some of these drivers appeared to work
> for some people and not others, and we're still working on getting
> more information. But I think we've got enough information at this
> point to indicate that this isn't a red herring.
>
> Any guesses as to the cause?

Now that I have the fix, it is trivial.
It is part of the patch below which I've also send to Linus for
inclusion in 2.0.24.

When Leonard and I were working on easing the tight skin
syndrome of the SCSI subsystem, Leonard wrote the code to handle
individual queues for every device.

For this we created a new callback function called select_queue_depths().
Unfortunately he forgot about the fact that scsi lowlevel drivers also
need to get this function called when beeing loaded as modules, otherwise
the device queues never get set up.

So every driver which supported select_queue_depths() was domed to fail as
a module.

The drivers which followed the development actively where hit by this:

eata_dma.c, ncr53c8xx.c, aic7xxx.c, advansys.c, BusLogic.c

Mike

Michael Neuffer i-Connect.Net, a Division of iConnect Corp.
mike@i-Connect.Net Home of the Debian Master Server.
14355 SW Allen Blvd., Suite 140
503.677.2900 Beaverton, OR 97008

diff -uNr linux.c/drivers/block/ide.c linux/drivers/block/ide.c
--- linux.c/drivers/block/ide.c Thu Sep 26 22:27:37 1996
+++ linux/drivers/block/ide.c Tue Oct 22 03:32:56 1996
@@ -2272,11 +2272,13 @@
unsigned long capacity, check;

id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL);
- ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
+ ide_input_data(drive, id, SECTOR_WORDS);/* read 512 bytes of id info */
sti();

+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO)
/*
- * EATA SCSI controllers do a hardware ATA emulation: ignore them
+ * EATA SCSI controllers do a hardware ATA emulation:
+ * Ignore them if there is a driver for them available.
*/
if ((id->model[0] == 'P' && id->model[1] == 'M')
|| (id->model[0] == 'S' && id->model[1] == 'K')) {
@@ -2284,6 +2286,7 @@
drive->present = 0;
return;
}
+#endif

/*
* WIN_IDENTIFY returns little-endian info,
diff -uNr linux.c/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- linux.c/drivers/scsi/Config.in Sun Jul 7 01:18:51 1996
+++ linux/drivers/scsi/Config.in Tue Oct 22 04:50:20 1996
@@ -24,9 +24,9 @@
bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
-dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
+dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
diff -uNr linux.c/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- linux.c/drivers/scsi/eata_dma.c Sat Aug 17 11:19:27 1996
+++ linux/drivers/scsi/eata_dma.c Tue Oct 22 03:41:21 1996
@@ -58,7 +58,7 @@
* Jagdis who did a lot of testing and found quite a number *
* of bugs during the development. *
************************************************************
- * last change: 96/08/13 OS: Linux 2.0.12 *
+ * last change: 96/10/21 OS: Linux 2.0.23 *
************************************************************/

/* Look in eata_dma.h for configuration and revision information */
@@ -295,12 +295,9 @@
sp->EOC = FALSE; /* Clean out this flag */

if (ccb->status == LOCKED || ccb->status == RESET) {
- ccb->status = FREE;
- eata_stat = inb(base + HA_RSTATUS);
- printk("eata_dma: int_handler, reseted command returned,"
- " freeing reseted queueslot\n");
+ printk("eata_dma: int_handler, reseted command pid %ld returned"
+ "\n", cmd->pid);
DBG(DBG_INTR && DBG_DELAY, DELAY(1));
- break;
}

eata_stat = inb(base + HA_RSTATUS);
@@ -467,23 +464,33 @@
struct Scsi_Host *sh;
struct eata_ccb *ccb;
struct scatterlist *sl;
+

save_flags(flags);
cli();
+
+#if 0
+ for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+ if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
+ printk("eata_dma: scsi%d interrupt pending in eata_queue.\n"
+ " Calling interrupt handler.\n", sh->host_no);
+ eata_int_handler(sh->irq, 0, 0);
+ }
+ }
+#endif

queue_counter++;

hd = HD(cmd);
sh = cmd->host;

-#if 1
if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
cmd->result = DID_OK << 16;
done(cmd);
+
return(0);
}
-#endif

/* check for free slot */
for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
@@ -678,7 +685,6 @@
" reason %x\n", cmd->pid, cmd->target, cmd->lun,
cmd->abort_reason));

- /* Some interrupt controllers seem to loose interrupts */
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"
@@ -686,6 +692,7 @@
eata_int_handler(sh->irq, 0, 0);
}
}
+
if (HD(cmd)->state == RESET) {
printk("eata_reset: exit, already in reset.\n");
restore_flags(flags);
@@ -766,9 +773,9 @@
restore_flags(flags);

if (success) {
- DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
+ DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
- return (SCSI_RESET_SUCCESS);
+ return (SCSI_RESET_PENDING);
} else {
DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
@@ -852,8 +859,9 @@
device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10;
break;
}
- } else /* ISA forces us to limit the QS because of bounce buffers*/
- device->queue_depth = 2; /* I know this is cruel */
+ } else /* ISA forces us to limit the queue depth because of the
+ * bounce buffer memory overhead. I know this is cruel */
+ device->queue_depth = 2;

/*
* It showed that we need to set an upper limit of commands
@@ -863,6 +871,8 @@
*/
if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT)
device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT;
+ if(device->queue_depth == 0)
+ device->queue_depth = 1;

printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
"set to %d\n", host->host_no, device->id, device->channel,
diff -uNr linux.c/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h
--- linux.c/drivers/scsi/eata_dma.h Sat Aug 17 11:19:27 1996
+++ linux/drivers/scsi/eata_dma.h Tue Oct 22 03:39:26 1996
@@ -4,7 +4,7 @@
* mike@i-Connect.Net *
* neuffer@mail.uni-mainz.de *
*********************************************************
-* last change: 96/08/14 *
+* last change: 96/10/14 *
********************************************************/

#ifndef _EATA_DMA_H
@@ -17,7 +17,7 @@

#define VER_MAJOR 2
#define VER_MINOR 5
-#define VER_SUB "9a"
+#define VER_SUB "9b"


/************************************************************************
diff -uNr linux.c/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h
--- linux.c/drivers/scsi/eata_generic.h Sat Aug 17 11:19:27 1996
+++ linux/drivers/scsi/eata_generic.h Tue Oct 22 03:32:56 1996
@@ -68,7 +68,7 @@
#define SG_SIZE 64
#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */

-#define UPPER_DEVICE_QUEUE_LIMIT 24 /* The limit we have to set for the
+#define UPPER_DEVICE_QUEUE_LIMIT 64 /* The limit we have to set for the
* device queue to keep the broken
* midlevel SCSI code from producing
* bogus timeouts
diff -uNr linux.c/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- linux.c/drivers/scsi/hosts.c Sat Aug 10 00:03:15 1996
+++ linux/drivers/scsi/hosts.c Tue Oct 22 03:32:56 1996
@@ -224,6 +224,12 @@
#ifdef CONFIG_SCSI_ADVANSYS
ADVANSYS,
#endif
+#ifdef CONFIG_SCSI_EATA_DMA
+ EATA_DMA,
+#endif
+#ifdef CONFIG_SCSI_EATA_PIO
+ EATA_PIO,
+#endif
/* BusLogic must come before aha1542.c */
#ifdef CONFIG_SCSI_BUSLOGIC
BUSLOGIC,
@@ -281,12 +287,6 @@
#endif
#ifdef CONFIG_SCSI_NCR53C8XX
NCR53C8XX,
-#endif
-#ifdef CONFIG_SCSI_EATA_DMA
- EATA_DMA,
-#endif
-#ifdef CONFIG_SCSI_EATA_PIO
- EATA_PIO,
#endif
#ifdef CONFIG_SCSI_7000FASST
WD7000,
diff -uNr linux.c/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- linux.c/drivers/scsi/scsi.c Sat Oct 5 02:17:45 1996
+++ linux/drivers/scsi/scsi.c Tue Oct 22 03:38:09 1996
@@ -17,8 +17,8 @@
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
- * Native multichannel and wide scsi support added
- * by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ * Native multichannel, wide scsi, /proc/scsi and hot plugging
+ * support added by Michael Neuffer <mike@i-connect.net>
*
* Added request_module("scsi_hostadapter") for kerneld:
* (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
@@ -3062,8 +3062,12 @@
*/

for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- if(shpnt->hostt == tpnt) scan_scsis(shpnt,0,0,0,0);
-
+ if(shpnt->hostt == tpnt) {
+ scan_scsis(shpnt,0,0,0,0);
+ if (shpnt->select_queue_depths != NULL)
+ (shpnt->select_queue_depths)(shpnt, scsi_devices);
+ }
+
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();

diff -uNr linux.c/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- linux.c/drivers/scsi/sd.c Fri Sep 20 07:00:34 1996
+++ linux/drivers/scsi/sd.c Tue Oct 22 03:32:56 1996
@@ -512,7 +512,7 @@

if (flag++ == 0)
SCpnt = allocate_device(&CURRENT,
- rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
+ rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
else SCpnt = NULL;

/*
@@ -537,7 +537,8 @@
cli();
req = CURRENT;
while(req){
- SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(req->rq_dev)].device);
+ SCpnt = request_queueable(req,
+ rscsi_disks[DEVICE_NR(req->rq_dev)].device);
if(SCpnt) break;
req1 = req;
req = req->next;