Commit cc805359 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] first pass at the ancient wd7000 crap

(Wants indenting but I'll do an indenting pass after the code changes
are accepted)
parent 3ca1a0bb
...@@ -145,6 +145,19 @@ ...@@ -145,6 +145,19 @@
* 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* *
* use host->host_lock, not io_request_lock, cleanups * use host->host_lock, not io_request_lock, cleanups
*
* 2002/10/04 - Alan Cox <alan@redhat.com>
*
* Use dev_id for interrupts, kill __FUNCTION__ pasting
* Add a lock for the scb pool, clean up all other cli/sti usage stuff
* Use the adapter lock for the other places we had the cli's
*
* 2002/10/06 - Alan Cox <alan@redhat.com>
*
* Switch to new style error handling
* Clean up delay to udelay, and yielding sleeps
* Make host reset actually reset the card
* Make everything static
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -254,19 +267,12 @@ static const short wd7000_dma[] = { 5, 6, 7 }; ...@@ -254,19 +267,12 @@ static const short wd7000_dma[] = { 5, 6, 7 };
#define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short)) #define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short))
/* /*
* possible irq range * The following is set up by wd7000_detect, and used thereafter for
* proc and other global ookups
*/ */
#define IRQ_MIN 3
#define IRQ_MAX 15 #define UNITS 8
#define IRQS (IRQ_MAX - IRQ_MIN + 1) static struct Scsi_Host *wd7000_host[UNITS];
/*
* The following is set up by wd7000_detect, and used thereafter by
* wd7000_intr_handle to map the irq level to the corresponding Adapter.
* Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be
* changed to pick up the IRQ level correctly.
*/
static struct Scsi_Host *wd7000_host[IRQS];
#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */ #define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */
#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */ #define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */
...@@ -580,6 +586,7 @@ MODULE_PARM(wd7000, "s"); ...@@ -580,6 +586,7 @@ MODULE_PARM(wd7000, "s");
static Scb scbs[MAX_SCBS]; static Scb scbs[MAX_SCBS];
static Scb *scbfree; /* free list */ static Scb *scbfree; /* free list */
static int freescbs = MAX_SCBS; /* free list counter */ static int freescbs = MAX_SCBS; /* free list counter */
static spinlock_t scbpool_lock; /* guards the scb free list and count */
/* /*
* END of data/declarations - code follows. * END of data/declarations - code follows.
...@@ -621,16 +628,16 @@ static int __init wd7000_setup(char *str) ...@@ -621,16 +628,16 @@ static int __init wd7000_setup(char *str)
(void)get_options(str, ARRAY_SIZE(ints), ints); (void)get_options(str, ARRAY_SIZE(ints), ints);
if (wd7000_card_num >= NUM_CONFIGS) { if (wd7000_card_num >= NUM_CONFIGS) {
printk(KERN_ERR __FUNCTION__ printk(KERN_ERR
": Too many \"wd7000=\" configurations in " "%s: Too many \"wd7000=\" configurations in "
"command line!\n"); "command line!\n", __FUNCTION__);
return 0; return 0;
} }
if ((ints[0] < 3) || (ints[0] > 5)) { if ((ints[0] < 3) || (ints[0] > 5)) {
printk(KERN_ERR __FUNCTION__ ": Error in command line! " printk(KERN_ERR "%s: Error in command line! "
"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>"
"[,<BUS_OFF>]]\n"); "[,<BUS_OFF>]]\n", __FUNCTION__);
} else { } else {
for (i = 0; i < NUM_IRQS; i++) for (i = 0; i < NUM_IRQS; i++)
if (ints[1] == wd7000_irq[i]) if (ints[1] == wd7000_irq[i])
...@@ -812,14 +819,6 @@ static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned ...@@ -812,14 +819,6 @@ static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned
} }
static inline void delay (unsigned how_long)
{
register unsigned long time = jiffies + how_long;
while (time_before(jiffies, time));
}
static inline int command_out (Adapter * host, unchar * cmd, int len) static inline int command_out (Adapter * host, unchar * cmd, int len)
{ {
if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
...@@ -853,43 +852,44 @@ static inline int command_out (Adapter * host, unchar * cmd, int len) ...@@ -853,43 +852,44 @@ static inline int command_out (Adapter * host, unchar * cmd, int len)
*/ */
static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed) static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
{ {
register Scb *scb, *p; register Scb *scb, *p = NULL;
register unsigned long flags; register unsigned long flags;
register unsigned long timeout = jiffies + WAITnexttimeout; register unsigned long timeout = jiffies + WAITnexttimeout;
register unsigned long now; register unsigned long now;
static int busy = 0;
int i; int i;
if (needed <= 0) if (needed <= 0)
return (NULL); /* sanity check */ return (NULL); /* sanity check */
save_flags (flags); spin_unlock_irq(host->host_lock);
cli ();
while (busy) { /* someone else is allocating */ retry:
spin_unlock_irq(host->host_lock);
for (now = jiffies; now == jiffies; ); /* wait a jiffy */
spin_lock_irq(host->host_lock);
}
busy = 1; /* not busy now; it's our turn */
while (freescbs < needed) { while (freescbs < needed) {
timeout = jiffies + WAITnexttimeout; timeout = jiffies + WAITnexttimeout;
do { do {
spin_unlock_irq(host->host_lock); /* FIXME: can we actually just yield here ?? */
for (now = jiffies; now == jiffies; ); /* wait a jiffy */ for (now = jiffies; now == jiffies; )
spin_lock_irq(host->host_lock); cpu_relax(); /* wait a jiffy */
} while (freescbs < needed && time_before_eq(jiffies, timeout)); } while (freescbs < needed && time_before_eq(jiffies, timeout));
/* /*
* If we get here with enough free Scbs, we can take them. * If we get here with enough free Scbs, we can take them.
* Otherwise, we timed out and didn't get enough. * Otherwise, we timed out and didn't get enough.
*/ */
if (freescbs < needed) { if (freescbs < needed) {
busy = 0;
printk (KERN_ERR "wd7000: can't get enough free SCBs.\n"); printk (KERN_ERR "wd7000: can't get enough free SCBs.\n");
restore_flags (flags); spin_unlock_irq(host->host_lock);
return (NULL); return (NULL);
} }
} }
/* Take the lock, then check we didnt get beaten, if so try again */
spin_lock_irqsave(&scbpool_lock, flags);
if(freescbs < needed)
{
spin_unlock_irqrestore(&scbpool_lock, flags);
goto retry;
}
scb = scbfree; scb = scbfree;
freescbs -= needed; freescbs -= needed;
for (i = 0; i < needed; i++) { for (i = 0; i < needed; i++) {
...@@ -897,10 +897,10 @@ static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed) ...@@ -897,10 +897,10 @@ static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
scbfree = p->next; scbfree = p->next;
} }
p->next = NULL; p->next = NULL;
busy = 0; /* we're done */
spin_unlock_irqrestore(&scbpool_lock, flags);
restore_flags (flags);
spin_lock_irq(host->host_lock);
return (scb); return (scb);
} }
...@@ -909,26 +909,25 @@ static inline void free_scb (Scb *scb) ...@@ -909,26 +909,25 @@ static inline void free_scb (Scb *scb)
{ {
register unsigned long flags; register unsigned long flags;
save_flags (flags); spin_lock_irqsave(&scbpool_lock, flags);
cli ();
memset (scb, 0, sizeof (Scb)); memset (scb, 0, sizeof (Scb));
scb->next = scbfree; scb->next = scbfree;
scbfree = scb; scbfree = scb;
freescbs++; freescbs++;
restore_flags (flags); spin_unlock_irqrestore(&scbpool_lock, flags);
} }
static inline void init_scbs (void) static inline void init_scbs (void)
{ {
int i; int i;
unsigned long flags;
save_flags (flags); spin_lock_init(&scbpool_lock);
cli ();
/* This is only ever called before the SCB pool is active */
scbfree = &(scbs[0]); scbfree = &(scbs[0]);
memset (scbs, 0, sizeof (scbs)); memset (scbs, 0, sizeof (scbs));
for (i = 0; i < MAX_SCBS - 1; i++) { for (i = 0; i < MAX_SCBS - 1; i++) {
...@@ -937,8 +936,6 @@ static inline void init_scbs (void) ...@@ -937,8 +936,6 @@ static inline void init_scbs (void)
} }
scbs[MAX_SCBS - 1].next = NULL; scbs[MAX_SCBS - 1].next = NULL;
scbs[MAX_SCBS - 1].SCpnt = NULL; scbs[MAX_SCBS - 1].SCpnt = NULL;
restore_flags (flags);
} }
...@@ -956,8 +953,7 @@ static int mail_out (Adapter *host, Scb *scbptr) ...@@ -956,8 +953,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr); dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
/* We first look for a free outgoing mailbox */ /* We first look for a free outgoing mailbox */
save_flags (flags); spin_lock_irqsave(host->sh->host_lock, flags);
cli ();
ogmb = *next_ogmb; ogmb = *next_ogmb;
for (i = 0; i < OGMB_CNT; i++) { for (i = 0; i < OGMB_CNT; i++) {
if (ogmbs[ogmb].status == 0) { if (ogmbs[ogmb].status == 0) {
...@@ -971,8 +967,8 @@ static int mail_out (Adapter *host, Scb *scbptr) ...@@ -971,8 +967,8 @@ static int mail_out (Adapter *host, Scb *scbptr)
else else
ogmb = (ogmb + 1) % OGMB_CNT; ogmb = (ogmb + 1) % OGMB_CNT;
} }
restore_flags (flags); spin_unlock_irqrestore(host->sh->host_lock, flags);
dprintk(", scb is 0x%06lx", (long) scbptr); dprintk(", scb is 0x%06lx", (long) scbptr);
if (i >= OGMB_CNT) { if (i >= OGMB_CNT) {
...@@ -999,7 +995,7 @@ static int mail_out (Adapter *host, Scb *scbptr) ...@@ -999,7 +995,7 @@ static int mail_out (Adapter *host, Scb *scbptr)
} }
int make_code (unsigned hosterr, unsigned scsierr) static int make_code (unsigned hosterr, unsigned scsierr)
{ {
#ifdef WD7000_DEBUG #ifdef WD7000_DEBUG
int in_error = hosterr; int in_error = hosterr;
...@@ -1056,14 +1052,14 @@ static void wd7000_scsi_done (Scsi_Cmnd *SCpnt) ...@@ -1056,14 +1052,14 @@ static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) #define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs) static void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
{ {
register int flag, icmb, errstatus, icmb_status; register int flag, icmb, errstatus, icmb_status;
register int host_error, scsi_error; register int host_error, scsi_error;
register Scb *scb; /* for SCSI commands */ register Scb *scb; /* for SCSI commands */
register IcbAny *icb; /* for host commands */ register IcbAny *icb; /* for host commands */
register Scsi_Cmnd *SCpnt; register Scsi_Cmnd *SCpnt;
Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata; /* This MUST be set!!! */ Adapter *host = (Adapter *)dev_id;
Mailbox *icmbs = host->mb.icmb; Mailbox *icmbs = host->mb.icmb;
host->int_counter++; host->int_counter++;
...@@ -1139,7 +1135,7 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1139,7 +1135,7 @@ void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
dprintk("wd7000_intr_handle: return from interrupt handler\n"); dprintk("wd7000_intr_handle: return from interrupt handler\n");
} }
void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs) static void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
{ {
unsigned long flags; unsigned long flags;
struct Scsi_Host *host = dev_id; struct Scsi_Host *host = dev_id;
...@@ -1150,7 +1146,7 @@ void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1150,7 +1146,7 @@ void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
} }
int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *)) static int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
{ {
register Scb *scb; register Scb *scb;
register Sgb *sgb; register Sgb *sgb;
...@@ -1197,25 +1193,31 @@ int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *)) ...@@ -1197,25 +1193,31 @@ int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
any2scsi (scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer)); any2scsi (scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer));
any2scsi (scb->maxlen, SCpnt->request_bufflen); any2scsi (scb->maxlen, SCpnt->request_bufflen);
} }
/* FIXME: drop lock and yield here ? */
while (!mail_out (host, scb)); /* keep trying */ while (!mail_out (host, scb))
cpu_relax(); /* keep trying */
return (1); return 0;
} }
int wd7000_command (Scsi_Cmnd *SCpnt) static int wd7000_command (Scsi_Cmnd *SCpnt)
{ {
wd7000_queuecommand (SCpnt, wd7000_scsi_done); wd7000_queuecommand (SCpnt, wd7000_scsi_done);
while (SCpnt->SCp.phase > 0) while (SCpnt->SCp.phase > 0)
barrier (); /* phase counts scbs down to 0 */ {
cpu_relax();
barrier(); /* phase counts scbs down to 0 */
}
return (SCpnt->result); return (SCpnt->result);
} }
int wd7000_diagnostics (Adapter *host, int code) static int wd7000_diagnostics (Adapter *host, int code)
{ {
static IcbDiag icb = {ICB_OP_DIAGNOSTICS}; static IcbDiag icb = {ICB_OP_DIAGNOSTICS};
static unchar buf[256]; static unchar buf[256];
...@@ -1233,7 +1235,10 @@ int wd7000_diagnostics (Adapter *host, int code) ...@@ -1233,7 +1235,10 @@ int wd7000_diagnostics (Adapter *host, int code)
mail_out (host, (struct scb *) &icb); mail_out (host, (struct scb *) &icb);
timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */ timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */
while (icb.phase && time_before(jiffies, timeout)) while (icb.phase && time_before(jiffies, timeout))
barrier (); /* wait for completion */ {
cpu_relax(); /* wait for completion */
barrier();
}
if (icb.phase) { if (icb.phase) {
printk ("wd7000_diagnostics: timed out.\n"); printk ("wd7000_diagnostics: timed out.\n");
...@@ -1249,7 +1254,7 @@ int wd7000_diagnostics (Adapter *host, int code) ...@@ -1249,7 +1254,7 @@ int wd7000_diagnostics (Adapter *host, int code)
} }
int wd7000_init (Adapter *host) static int wd7000_adapter_reset(Adapter *host)
{ {
InitCmd init_cmd = InitCmd init_cmd =
{ {
...@@ -1263,19 +1268,18 @@ int wd7000_init (Adapter *host) ...@@ -1263,19 +1268,18 @@ int wd7000_init (Adapter *host)
ICMB_CNT ICMB_CNT
}; };
int diag; int diag;
/* /*
* Reset the adapter - only. The SCSI bus was initialized at power-up, * Reset the adapter - only. The SCSI bus was initialized at power-up,
* and we need to do this just so we control the mailboxes, etc. * and we need to do this just so we control the mailboxes, etc.
*/ */
outb (ASC_RES, host->iobase + ASC_CONTROL); outb (ASC_RES, host->iobase + ASC_CONTROL);
delay (1); /* reset pulse: this is 10ms, only need 25us */ udelay(40); /* reset pulse: this is 40us, only need 25us */
outb (0, host->iobase + ASC_CONTROL); outb (0, host->iobase + ASC_CONTROL);
host->control = 0; /* this must always shadow ASC_CONTROL */ host->control = 0; /* this must always shadow ASC_CONTROL */
if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
printk ("wd7000_init: WAIT timed out.\n"); printk ("wd7000_init: WAIT timed out.\n");
return (0); /* 0 = not ok */ return -1; /* -1 = not ok */
} }
if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) { if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) {
...@@ -1296,31 +1300,38 @@ int wd7000_init (Adapter *host) ...@@ -1296,31 +1300,38 @@ int wd7000_init (Adapter *host)
break; break;
default: printk ("diagnostic code 0x%02Xh received.\n", diag); default: printk ("diagnostic code 0x%02Xh received.\n", diag);
} }
return (0); return -1;
} }
/* Clear mailboxes */
/* Clear mailboxes */
memset (&(host->mb), 0, sizeof (host->mb)); memset (&(host->mb), 0, sizeof (host->mb));
/* Execute init command */ /* Execute init command */
any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb)); any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) { if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) {
printk ("wd7000_init: adapter initialization failed.\n"); printk (KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n");
return (0); return -1;
} }
if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) { if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
printk ("wd7000_init: WAIT timed out.\n"); printk ("wd7000_adapter_reset: WAIT timed out.\n");
return (0); return -1;
} }
return 0;
}
if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) { static int wd7000_init (Adapter *host)
{
if(wd7000_adapter_reset(host) == -1)
return 0;
if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", host)) {
printk ("wd7000_init: can't get IRQ %d.\n", host->irq); printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
return (0); return (0);
} }
if (request_dma (host->dma, "wd7000")) { if (request_dma (host->dma, "wd7000")) {
printk ("wd7000_init: can't get DMA channel %d.\n", host->dma); printk ("wd7000_init: can't get DMA channel %d.\n", host->dma);
free_irq (host->irq, NULL); free_irq (host->irq, host);
return (0); return (0);
} }
wd7000_enable_dma (host); wd7000_enable_dma (host);
...@@ -1336,7 +1347,7 @@ int wd7000_init (Adapter *host) ...@@ -1336,7 +1347,7 @@ int wd7000_init (Adapter *host)
} }
void wd7000_revision (Adapter *host) static void wd7000_revision (Adapter *host)
{ {
static IcbRevLvl icb = static IcbRevLvl icb =
{ICB_OP_GET_REVISION}; {ICB_OP_GET_REVISION};
...@@ -1350,7 +1361,10 @@ void wd7000_revision (Adapter *host) ...@@ -1350,7 +1361,10 @@ void wd7000_revision (Adapter *host)
*/ */
mail_out (host, (struct scb *) &icb); mail_out (host, (struct scb *) &icb);
while (icb.phase) while (icb.phase)
barrier (); /* wait for completion */ {
cpu_relax(); /* wait for completion */
barrier();
}
host->rev1 = icb.primary; host->rev1 = icb.primary;
host->rev2 = icb.secondary; host->rev2 = icb.secondary;
} }
...@@ -1359,27 +1373,19 @@ void wd7000_revision (Adapter *host) ...@@ -1359,27 +1373,19 @@ void wd7000_revision (Adapter *host)
#undef SPRINTF #undef SPRINTF
#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } #define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host) static int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host)
{ {
unsigned long flags;
save_flags (flags);
cli ();
dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length); dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
/* /*
* Currently this is a no-op * Currently this is a no-op
*/ */
dprintk("Sorry, this function is currently out of order...\n"); dprintk("Sorry, this function is currently out of order...\n");
restore_flags (flags);
return (length); return (length);
} }
int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) static int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout)
{ {
struct Scsi_Host *host = NULL; struct Scsi_Host *host = NULL;
Scsi_Device *scd; Scsi_Device *scd;
...@@ -1396,7 +1402,7 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int ...@@ -1396,7 +1402,7 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int
/* /*
* Find the specified host board. * Find the specified host board.
*/ */
for (i = 0; i < IRQS; i++) for (i = 0; i < UNITS; i++)
if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) { if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
host = wd7000_host[i]; host = wd7000_host[i];
...@@ -1417,9 +1423,7 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int ...@@ -1417,9 +1423,7 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int
adapter = (Adapter *) host->hostdata; adapter = (Adapter *) host->hostdata;
save_flags (flags); spin_lock_irqsave(host->host_lock, flags);
cli ();
SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2); SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
SPRINTF (" IO base: 0x%x\n", adapter->iobase); SPRINTF (" IO base: 0x%x\n", adapter->iobase);
SPRINTF (" IRQ: %d\n", adapter->irq); SPRINTF (" IRQ: %d\n", adapter->irq);
...@@ -1484,7 +1488,7 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int ...@@ -1484,7 +1488,7 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int
SPRINTF ("\n"); SPRINTF ("\n");
restore_flags (flags); spin_unlock_irqrestore(host->host_lock, flags);
/* /*
* Calculate start of next buffer, and return value. * Calculate start of next buffer, and return value.
...@@ -1510,13 +1514,15 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int ...@@ -1510,13 +1514,15 @@ int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int
* calling scsi_unregister. * calling scsi_unregister.
* *
*/ */
int wd7000_detect (Scsi_Host_Template *tpnt)
static int wd7000_detect (Scsi_Host_Template *tpnt)
{ {
short present = 0, biosaddr_ptr, sig_ptr, i, pass; short present = 0, biosaddr_ptr, sig_ptr, i, pass;
short biosptr[NUM_CONFIGS]; short biosptr[NUM_CONFIGS];
unsigned iobase; unsigned iobase;
Adapter *host = NULL; Adapter *host = NULL;
struct Scsi_Host *sh; struct Scsi_Host *sh;
int unit = 0;
dprintk("wd7000_detect: started\n"); dprintk("wd7000_detect: started\n");
...@@ -1525,7 +1531,7 @@ int wd7000_detect (Scsi_Host_Template *tpnt) ...@@ -1525,7 +1531,7 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
wd7000_setup(wd7000); wd7000_setup(wd7000);
#endif #endif
for (i = 0; i < IRQS; wd7000_host[i++] = NULL) ; for (i = 0; i < UNITS; wd7000_host[i++] = NULL) ;
for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1) ; for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1) ;
tpnt->proc_name = "wd7000"; tpnt->proc_name = "wd7000";
...@@ -1579,6 +1585,9 @@ int wd7000_detect (Scsi_Host_Template *tpnt) ...@@ -1579,6 +1585,9 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
if (configs[pass].irq < 0) if (configs[pass].irq < 0)
continue; continue;
if (unit == UNITS)
continue;
iobase = configs[pass].iobase; iobase = configs[pass].iobase;
...@@ -1591,7 +1600,8 @@ int wd7000_detect (Scsi_Host_Template *tpnt) ...@@ -1591,7 +1600,8 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
* ASC reset... * ASC reset...
*/ */
outb (ASC_RES, iobase + ASC_CONTROL); outb (ASC_RES, iobase + ASC_CONTROL);
delay (1); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
outb (0, iobase + ASC_CONTROL); outb (0, iobase + ASC_CONTROL);
if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
...@@ -1624,7 +1634,8 @@ int wd7000_detect (Scsi_Host_Template *tpnt) ...@@ -1624,7 +1634,8 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
host->int_counter = 0; host->int_counter = 0;
host->bus_on = configs[pass].bus_on; host->bus_on = configs[pass].bus_on;
host->bus_off = configs[pass].bus_off; host->bus_off = configs[pass].bus_off;
host->sh = wd7000_host[host->irq - IRQ_MIN] = sh; host->sh = wd7000_host[unit] = sh;
unit++;
dprintk("wd7000_detect: Trying init WD-7000 card at IO " dprintk("wd7000_detect: Trying init WD-7000 card at IO "
"0x%x, IRQ %d, DMA %d...\n", "0x%x, IRQ %d, DMA %d...\n",
...@@ -1649,7 +1660,7 @@ int wd7000_detect (Scsi_Host_Template *tpnt) ...@@ -1649,7 +1660,7 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
if (biosaddr_ptr != NUM_ADDRS) if (biosaddr_ptr != NUM_ADDRS)
biosptr[pass] = biosaddr_ptr; biosptr[pass] = biosaddr_ptr;
printk ("Western Digital WD-7000 (rev %d.%d) ", printk (KERN_INFO "Western Digital WD-7000 (rev %d.%d) ",
host->rev1, host->rev2); host->rev1, host->rev2);
printk ("using IO 0x%x, IRQ %d, DMA %d.\n", printk ("using IO 0x%x, IRQ %d, DMA %d.\n",
host->iobase, host->irq, host->dma); host->iobase, host->irq, host->dma);
...@@ -1679,34 +1690,53 @@ int wd7000_detect (Scsi_Host_Template *tpnt) ...@@ -1679,34 +1690,53 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
/* /*
* I have absolutely NO idea how to do an abort with the WD7000... * I have absolutely NO idea how to do an abort with the WD7000...
*/ */
int wd7000_abort (Scsi_Cmnd *SCpnt) static int wd7000_abort (Scsi_Cmnd *SCpnt)
{ {
Adapter *host = (Adapter *) SCpnt->host->hostdata; Adapter *host = (Adapter *) SCpnt->host->hostdata;
if (inb (host->iobase + ASC_STAT) & INT_IM) { if (inb (host->iobase + ASC_STAT) & INT_IM) {
printk ("wd7000_abort: lost interrupt\n"); printk ("wd7000_abort: lost interrupt\n");
wd7000_intr_handle (host->irq, NULL, NULL); wd7000_intr_handle (host->irq, NULL, NULL);
return FAILED;
return (SCSI_ABORT_SUCCESS);
} }
return FAILED;
return (SCSI_ABORT_SNOOZE);
} }
/* /*
* I also have no idea how to do a reset... * I also have no idea how to do a reset...
*/ */
int wd7000_reset (Scsi_Cmnd *SCpnt, unsigned int unused)
static int wd7000_bus_reset (Scsi_Cmnd *SCpnt)
{ {
return (SCSI_RESET_PUNT); return FAILED;
}
static int wd7000_device_reset (Scsi_Cmnd *SCpnt)
{
return FAILED;
}
/*
* Last resort. Reinitialize the board.
*/
static int wd7000_host_reset (Scsi_Cmnd *SCpnt)
{
Adapter *host = (Adapter *) SCpnt->host->hostdata;
if(wd7000_adapter_reset(host)<0)
return FAILED;
wd7000_enable_intr (host);
return SUCCESS;
} }
/* /*
* This was borrowed directly from aha1542.c. (Zaga) * This was borrowed directly from aha1542.c. (Zaga)
*/ */
int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip)
static int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip)
{ {
dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev), dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev),
disk->capacity); disk->capacity);
...@@ -1743,8 +1773,8 @@ int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip) ...@@ -1743,8 +1773,8 @@ int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip)
ip[2] = info[2]; ip[2] = info[2];
if (info[0] == 255) if (info[0] == 255)
printk(KERN_INFO __FUNCTION__ ": current partition table is " printk(KERN_INFO "%s: current partition table is "
"using extended translation.\n"); "using extended translation.\n", __FUNCTION__);
} }
} }
...@@ -1754,6 +1784,8 @@ int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip) ...@@ -1754,6 +1784,8 @@ int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip)
return (0); return (0);
} }
MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* Eventually this will go into an include file, but this will be later */ /* Eventually this will go into an include file, but this will be later */
......
...@@ -13,14 +13,16 @@ ...@@ -13,14 +13,16 @@
#include <linux/types.h> #include <linux/types.h>
int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host); static int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host);
int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); static int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout);
int wd7000_detect (Scsi_Host_Template *); static int wd7000_detect (Scsi_Host_Template *);
int wd7000_command (Scsi_Cmnd *); static int wd7000_command (Scsi_Cmnd *);
int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd7000_abort (Scsi_Cmnd *); static int wd7000_abort (Scsi_Cmnd *);
int wd7000_reset (Scsi_Cmnd *, unsigned int); static int wd7000_bus_reset (Scsi_Cmnd *);
int wd7000_biosparam (Disk *, struct block_device *, int *); static int wd7000_host_reset (Scsi_Cmnd *);
static int wd7000_device_reset (Scsi_Cmnd *);
static int wd7000_biosparam (Disk *, struct block_device *, int *);
#ifndef NULL #ifndef NULL
#define NULL 0L #define NULL 0L
...@@ -48,7 +50,9 @@ int wd7000_biosparam (Disk *, struct block_device *, int *); ...@@ -48,7 +50,9 @@ int wd7000_biosparam (Disk *, struct block_device *, int *);
command: wd7000_command, \ command: wd7000_command, \
queuecommand: wd7000_queuecommand, \ queuecommand: wd7000_queuecommand, \
abort: wd7000_abort, \ abort: wd7000_abort, \
reset: wd7000_reset, \ eh_bus_reset_handler: wd7000_bus_reset, \
eh_device_reset_handler:wd7000_device_reset, \
eh_host_reset_handler: wd7000_host_reset, \
bios_param: wd7000_biosparam, \ bios_param: wd7000_biosparam, \
can_queue: WD7000_Q, \ can_queue: WD7000_Q, \
this_id: 7, \ this_id: 7, \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment