pre-2.1, AHA1542 fixes, WD7000

Keith Owens (kaos@audio.apana.org.au)
Thu, 26 Sep 1996 15:22:13 +1000 (EST)


aha1542.c assumes kernel == real in quite a few places, fixes follow. I
don't claim to have got all of them but it works for my 1542C with 2 disks
(Micropolis 3243, IBM DORS-32160) and a cdrom (Panasonic CR-533). I also
changed the 16M tests slightly to look at the end of the data, not just
the start.

One thing worries me, accessing the cdrom using workbone resulted in a
zero buff address and a non-zero length, hence the "buff && SCSI_PA"
around line 654. Eric, is this sensible? Also is the test "if
(SCSI_PA(shpnt+1) > ISA_DMA_THRESHOLD)" around line 953 still needed since
kmalloc supports DMA?

BTW, it looks like WD7000 has similar problems but I don't have a card to
test with.

--- linux/drivers/scsi/aha1542.c.orig Thu Aug 1 22:43:04 1996
+++ linux/drivers/scsi/aha1542.c Thu Sep 26 14:46:27 1996
@@ -35,6 +35,14 @@

#include "aha1542.h"

+#define SCSI_PA(address) (address ? __pa(address) : 0)
+
+#define BAD_DMA(msg, address, length) \
+ { \
+ printk(KERN_CRIT "%s address %p length %d\n", msg, address, length); \
+ panic("Buffer at physical address > 16Mb used for aha1542"); \
+ }
+
#include<linux/stat.h>

struct proc_dir_entry proc_scsi_aha1542 = {
@@ -427,7 +435,7 @@
return;
};

- mbo = (scsi2int(mb[mbi].ccbptr) - ((unsigned int) &ccb[0])) / sizeof(struct ccb);
+ mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_PA(&ccb[0]))) / sizeof(struct ccb);
mbistatus = mb[mbi].status;
mb[mbi].status = 0;
HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
@@ -587,7 +595,7 @@
printk("Sending command (%d %x)...",mbo, done);
#endif

- any2scsi(mb[mbo].ccbptr, &ccb[mbo]); /* This gets trashed for some reason*/
+ any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/

memset(&ccb[mbo], 0, sizeof(struct ccb));

@@ -627,12 +635,13 @@
for(i=0;i<18;i++) printk("%02x ", ptr[i]);
panic("Foooooooood fight!");
};
- any2scsi(cptr[i].dataptr, sgpnt[i].address);
- if(((unsigned int) sgpnt[i].address) & 0xff000000) goto baddma;
+ any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
+ if(SCSI_PA(sgpnt[i].address+sgpnt[i].length) > ISA_DMA_THRESHOLD)
+ BAD_DMA("sgpnt", sgpnt[i].address, sgpnt[i].length);
any2scsi(cptr[i].datalen, sgpnt[i].length);
};
any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
- any2scsi(ccb[mbo].dataptr, cptr);
+ any2scsi(ccb[mbo].dataptr, SCSI_PA(cptr));
#ifdef DEBUG
printk("cptr %x: ",cptr);
ptr = (unsigned char *) cptr;
@@ -642,8 +651,9 @@
ccb[mbo].op = 0; /* SCSI Initiator Command */
SCpnt->host_scribble = NULL;
any2scsi(ccb[mbo].datalen, bufflen);
- if(((unsigned int) buff & 0xff000000)) goto baddma;
- any2scsi(ccb[mbo].dataptr, buff);
+ if(buff && SCSI_PA(buff+bufflen) > ISA_DMA_THRESHOLD)
+ BAD_DMA("buff", buff, bufflen);
+ any2scsi(ccb[mbo].dataptr, SCSI_PA(buff));
};
ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/
ccb[mbo].rsalen = 16;
@@ -669,8 +679,6 @@
printk("aha1542_queuecommand: done can't be NULL\n");

return 0;
- baddma:
- panic("Buffer at address > 16Mb used for 1542B");
}

static void internal_done(Scsi_Cmnd * SCpnt)
@@ -704,10 +712,10 @@

for(i=0; i<AHA1542_MAILBOXES; i++){
mb[i].status = mb[AHA1542_MAILBOXES+i].status = 0;
- any2scsi(mb[i].ccbptr, &ccb[i]);
+ any2scsi(mb[i].ccbptr, SCSI_PA(&ccb[i]));
};
aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
- any2scsi((cmd+2), mb);
+ any2scsi((cmd+2), SCSI_PA(mb));
aha1542_out(bse, cmd, 5);
WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
while (0) {
@@ -942,7 +950,7 @@

/* For now we do this - until kmalloc is more intelligent
we are resigned to stupid hacks like this */
- if ((unsigned int) shpnt > 0xffffff) {
+ if (SCSI_PA(shpnt+1) > ISA_DMA_THRESHOLD) {
printk("Invalid address for shpnt with 1542.\n");
goto unregister;
}