patch-2.0.11 linux/drivers/scsi/eata_dma.c
Next file: linux/drivers/scsi/eata_dma.h
Previous file: linux/drivers/scsi/aha1542.c
Back to the patch index
Back to the overall index
- Lines: 466
- Date:
Thu Aug 1 15:43:04 1996
- Orig file:
v2.0.10/linux/drivers/scsi/eata_dma.c
- Orig date:
Wed May 8 07:20:02 1996
diff -u --recursive --new-file v2.0.10/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
@@ -19,6 +19,7 @@
* versions of the boards *
* -supports multiple HBAs with & without IRQ sharing *
* -supports all SCSI channels on multi channel boards *
+ * -supports ix86 and MIPS, untested on ALPHA *
* -needs identical IDs on all channels of a HBA *
* -can be loaded as module *
* -displays statistical and hardware information *
@@ -57,7 +58,7 @@
* Jagdis who did a lot of testing and found quite a number *
* of bugs during the development. *
************************************************************
- * last change: 95/05/05 OS: Linux 1.3.98 *
+ * last change: 96/07/20 OS: Linux 2.0.8 *
************************************************************/
/* Look in eata_dma.h for configuration and revision information */
@@ -77,6 +78,10 @@
#include <asm/types.h>
#include <asm/io.h>
#include <asm/dma.h>
+#include <asm/pgtable.h>
+#ifdef __mips__
+#include <asm/cachectl.h>
+#endif
#include <linux/blk.h>
#include "scsi.h"
#include "sd.h"
@@ -244,13 +249,9 @@
struct eata_ccb *ccb;
struct eata_sp *sp;
uint base;
- ulong flags;
uint x;
struct Scsi_Host *sh;
- save_flags(flags);
- cli();
-
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if (sh->irq != irq)
continue;
@@ -260,6 +261,9 @@
int_counter++;
sp = &SD(sh)->sp;
+#ifdef __mips__
+ sys_cacheflush(sp, sizeof(struct eata_sp), 2);
+#endif
ccb = sp->ccb;
if(ccb == NULL) {
@@ -288,16 +292,17 @@
break;
}
- if (ccb->status == LOCKED) {
- ccb->status = FREE;
- eata_stat = inb(base + HA_RSTATUS);
- printk("eata_dma: int_handler, freeing locked queueslot\n");
- DBG(DBG_INTR && DBG_DELAY, DELAY(1));
- break;
+ 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");
+ DBG(DBG_INTR && DBG_DELAY, DELAY(1));
+ break;
}
- sp->EOC = FALSE; /* Clean out this flag */
-
eata_stat = inb(base + HA_RSTATUS);
DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, "
"target: %x, lun: %x, ea_s: %#.2x, hba_s: "
@@ -306,11 +311,9 @@
switch (hba_stat) {
case HA_NO_ERROR: /* NO Error */
- HD(cmd)->t_state[ccb->cp_channel][ccb->cp_id] = OK;
if(HD(cmd)->do_latency == TRUE && ccb->timestamp)
eata_latency_in(ccb, HD(cmd));
result = DID_OK << 16;
- HD(cmd)->t_timeout[ccb->cp_channel][ccb->cp_id] = OK;
break;
case HA_ERR_SEL_TO: /* Selection Timeout */
case HA_ERR_CMD_TO: /* Command Timeout */
@@ -329,7 +332,6 @@
result = DID_ERROR << 16;
for (i = 0; i < MAXTARGET; i++)
- HD(cmd)->t_state[ccb->cp_channel][i] = RESET;
DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld "
"returned with INIT_POWERUP\n",
HD(cmd)->HBA_number, cmd->pid));
@@ -342,7 +344,6 @@
break;
case HA_CP_RESET_NA:
case HA_CP_RESET:
- HD(cmd)->t_state[cmd->channel][cmd->target] = OK;
HD(cmd)->resetlevel[cmd->channel] = 0;
result = DID_RESET << 16;
DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd "
@@ -385,8 +386,7 @@
cmd->scsi_done(cmd);
}
}
- restore_flags(flags);
-
+
return;
}
@@ -398,17 +398,26 @@
if (--loop == 0)
return(FALSE);
+ if(addr != (u32) NULL)
+ addr = virt_to_bus((void *)addr);
+
+ /*
+ * This is overkill.....but the MIPSen seem to need this
+ * and it will be optimized away for i86 and ALPHA machines.
+ */
+ flush_cache_all();
+
/* And now the address in nice little byte chunks */
#ifdef __LITTLE_ENDIAN
- outb( addr & 0x000000ff, base + HA_WDMAADDR);
- outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
- outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
- outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+ outb(addr, base + HA_WDMAADDR);
+ outb(addr >> 8, base + HA_WDMAADDR + 1);
+ outb(addr >> 16, base + HA_WDMAADDR + 2);
+ outb(addr >> 24, base + HA_WDMAADDR + 3);
#else
- outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
- outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
- outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2);
- outb((addr & 0x000000ff), base + HA_WDMAADDR + 3);
+ outb(addr >> 24, base + HA_WDMAADDR);
+ outb(addr >> 16, base + HA_WDMAADDR + 1);
+ outb(addr >> 8, base + HA_WDMAADDR + 2);
+ outb(addr, base + HA_WDMAADDR + 3);
#endif
outb(command, base + HA_WCOMMAND);
return(TRUE);
@@ -416,18 +425,27 @@
inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2)
{
+ if(addr != (u32) NULL)
+ addr = virt_to_bus((void *)addr);
+
+ /*
+ * This is overkill.....but the MIPSen seem to need this
+ * and it will be optimized away for i86 and ALPHA machines.
+ */
+ flush_cache_all();
+
outb(0x0, base + HA_WDMAADDR - 1);
if(addr){
#ifdef __LITTLE_ENDIAN
- outb( addr & 0x000000ff, base + HA_WDMAADDR);
- outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
- outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
- outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+ outb(addr, base + HA_WDMAADDR);
+ outb(addr >> 8, base + HA_WDMAADDR + 1);
+ outb(addr >> 16, base + HA_WDMAADDR + 2);
+ outb(addr >> 24, base + HA_WDMAADDR + 3);
#else
- outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
- outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
- outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2);
- outb((addr & 0x000000ff), base + HA_WDMAADDR + 3);
+ outb(addr >> 24, base + HA_WDMAADDR);
+ outb(addr >> 16, base + HA_WDMAADDR + 1);
+ outb(addr >> 8, base + HA_WDMAADDR + 2);
+ outb(addr, base + HA_WDMAADDR + 3);
#endif
} else {
outb(0x0, base + HA_WDMAADDR);
@@ -491,6 +509,8 @@
memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
ccb->status = USED; /* claim free slot */
+
+ restore_flags(flags);
DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
cmd->pid, cmd->target, cmd->lun, y));
@@ -562,7 +582,7 @@
ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to
- * convert it */
+ * convert it */
ccb->cmd = cmd;
cmd->host_scribble = (char *)&hd->ccb[y];
@@ -571,25 +591,26 @@
DBG(DBG_QUEUE && DBG_ABNORM,
printk("eata_queue target %d, pid %ld, HBA busy, "
"returning DID_BUS_BUSY\n",cmd->target, cmd->pid));
- done(cmd);
ccb->status = FREE;
- restore_flags(flags);
+ done(cmd);
return(0);
}
DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "
"slot %d irq %d\n", (s32)sh->base, cmd->pid,
cmd->target, cmd->lun, y, sh->irq));
DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
- restore_flags(flags);
+
return(0);
}
int eata_abort(Scsi_Cmnd * cmd)
{
- ulong loop = R_LIMIT;
+ ulong loop = HZ / 2;
ulong flags;
-
+ int x;
+ struct Scsi_Host *sh;
+
save_flags(flags);
cli();
@@ -598,6 +619,15 @@
cmd->abort_reason));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+ /* 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_abort.\n"
+ " Calling interrupt handler.\n", sh->host_no);
+ eata_int_handler(sh->irq, 0, 0);
+ }
+ }
+
while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) {
if (--loop == 0) {
printk("eata_dma: abort, timeout error.\n");
@@ -634,12 +664,12 @@
int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags)
{
- ushort x, z;
- ulong limit = 0;
+ uint x;
ulong loop = loops_per_sec / 3;
ulong flags;
unchar success = FALSE;
Scsi_Cmnd *sp;
+ struct Scsi_Host *sh;
save_flags(flags);
cli();
@@ -648,6 +678,14 @@
" 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"
+ " Calling interrupt handler.\n", sh->host_no);
+ eata_int_handler(sh->irq, 0, 0);
+ }
+ }
if (HD(cmd)->state == RESET) {
printk("eata_reset: exit, already in reset.\n");
restore_flags(flags);
@@ -663,30 +701,26 @@
return (SCSI_RESET_ERROR);
}
- for (x = 0; x < MAXCHANNEL; x++) {
- for (z = 0; z < MAXTARGET; z++) {
- HD(cmd)->t_state[x][z] = RESET;
- HD(cmd)->t_timeout[x][z] = NO_TIMEOUT;
- }
- }
-
for (x = 0; x < cmd->host->can_queue; x++) {
if (HD(cmd)->ccb[x].status == FREE)
continue;
-
+
if (HD(cmd)->ccb[x].status == LOCKED) {
HD(cmd)->ccb[x].status = FREE;
printk("eata_reset: locked slot %d forced free.\n", x);
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
continue;
}
+
+
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
- printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
- DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
if (sp == NULL)
panic("eata_reset: slot %d, sp==NULL.\n", x);
+
+ printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
if (sp == cmd)
@@ -697,18 +731,21 @@
inb((u32) (cmd->host->base) + HA_RSTATUS); /* This might cause trouble */
eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET);
- DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
HD(cmd)->state = RESET;
- DELAY(1);
+ DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling "
+ "interrupts.\n"));
+
+ DELAY(2); /* In theorie we should get interrupts and set free all
+ * used queueslots */
- DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n",
- limit));
+ DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled again.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
for (x = 0; x < cmd->host->can_queue; x++) {
- /* Skip slots already set free by interrupt */
+ /* Skip slots already set free by interrupt and those that
+ * are still LOCKED from the last reset */
if (HD(cmd)->ccb[x].status != RESET)
continue;
@@ -750,8 +787,13 @@
Scsi_Device *device;
int devcount = 0;
int factor = 0;
-
-
+
+#if CRIPPLE_QUEUE
+ for(device = devicelist; device != NULL; device = device->next) {
+ if(device->host == host)
+ device->queue_depth = 2;
+ }
+#else
/* First we do a sample run go find out what we have */
for(device = devicelist; device != NULL; device = device->next) {
if (device->host == host) {
@@ -818,8 +860,10 @@
device->queue_depth);
}
}
+#endif
}
+#if CHECK_BLINK
int check_blink_state(long base)
{
ushort loops = 10;
@@ -841,6 +885,7 @@
else
return (FALSE);
}
+#endif
char * get_board_data(u32 base, u32 irq, u32 id)
{
@@ -848,7 +893,6 @@
struct eata_sp *sp;
static char *buff;
ulong i;
- ulong limit = 0;
cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb),
GFP_ATOMIC | GFP_DMA);
@@ -1287,11 +1331,14 @@
register_HBA(base, buf, tpnt, IS_EISA);
} else
printk("eata_dma: No valid IRQ. HBA removed from list\n");
- } else {
+ }
+#if CHECK_BLINK
+ else {
if (check_blink_state(base))
printk("HBA is in BLINK state. Consult your HBAs "
"Manual to correct this.\n");
}
+#endif
/* Nothing found here so we take it from the list */
EISAbases[i] = 0;
#if CHECKPAL
@@ -1311,11 +1358,14 @@
if (get_conf_PIO(ISAbases[i],buf) == TRUE){
DBG(DBG_ISA, printk("Registering ISA HBA\n"));
register_HBA(ISAbases[i], buf, tpnt, IS_ISA);
- } else {
+ }
+#if CHECK_BLINK
+ else {
if (check_blink_state(ISAbases[i]))
printk("HBA is in BLINK state. Consult your HBAs "
"Manual to correct this.\n");
}
+#endif
ISAbases[i] = 0;
}
}
@@ -1356,7 +1406,8 @@
(u16 *) & com_adr))) {
if (!((com_adr & PCI_COMMAND_IO) &&
(com_adr & PCI_COMMAND_MASTER))) {
- printk("eata_dma: find_PCI, HBA has IO or BUSMASTER mode disabled\n");
+ printk("eata_dma: find_PCI, HBA has IO or"
+ " BUSMASTER mode disabled\n");
continue;
}
} else
@@ -1366,7 +1417,8 @@
printk("eata_dma: find_PCI, DEVICECLASSID %x didn't match\n",
rev_device);
} else {
- printk("eata_dma: find_PCI, error %x while reading PCI_CLASS_BASE\n",
+ printk("eata_dma: find_PCI, error %x while reading "
+ "PCI_CLASS_BASE\n",
error);
continue;
}
@@ -1411,10 +1463,13 @@
} else if ((base & 0x0fff) == 0x0c88)
EISAbases[(base >> 12) & 0x0f] = 0;
continue; /* break; */
- } else if (check_blink_state(base) == TRUE) {
+ }
+#if CHECK_BLINK
+ else if (check_blink_state(base) == TRUE) {
printk("eata_dma: HBA is in BLINK state.\n"
"Consult your HBAs manual to correct this.\n");
}
+#endif
}
}
} else {
@@ -1461,7 +1516,7 @@
for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we */
if (reg_IRQ[i] >= 1){ /* exchange the interrupt handler which */
free_irq(i, NULL); /* we used for probing with the real one */
- request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT,
+ request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT|SA_SHIRQ,
"eata_dma", NULL);
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov