Commit 134240c3 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by James Bottomley

[PATCH] wd7000 updates

Avoid old APIs and fix a bad bug were the irq handler argument was
derefenced as struct Scsi_Host * instead of Adpater * which made the
driver instantly crash on SMP.
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent f354a51a
...@@ -183,7 +183,9 @@ ...@@ -183,7 +183,9 @@
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/io.h> #include <asm/io.h>
#include "scsi.h" #include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsicam.h> #include <scsi/scsicam.h>
...@@ -218,7 +220,7 @@ ...@@ -218,7 +220,7 @@
* In this version, sg_tablesize now defaults to WD7000_SG, and will * In this version, sg_tablesize now defaults to WD7000_SG, and will
* be set to SG_NONE for older boards. This is the reverse of the * be set to SG_NONE for older boards. This is the reverse of the
* previous default, and was changed so that the driver-level * previous default, and was changed so that the driver-level
* Scsi_Host_Template would reflect the driver's support for scatter/ * scsi_host_template would reflect the driver's support for scatter/
* gather. * gather.
* *
* Also, it has been reported that boards at Revision 6 support scatter/ * Also, it has been reported that boards at Revision 6 support scatter/
...@@ -435,8 +437,8 @@ typedef struct initCmd { ...@@ -435,8 +437,8 @@ typedef struct initCmd {
* carrying SCB addresses to/from the 7000-FASST2. * carrying SCB addresses to/from the 7000-FASST2.
* *
* Note also since SCBs are not "permanently" associated with mailboxes, * Note also since SCBs are not "permanently" associated with mailboxes,
* there is no need to keep a global list of Scsi_Cmnd pointers indexed * there is no need to keep a global list of scsi_cmnd pointers indexed
* by OGMB. Again, SCBs reference their Scsi_Cmnds directly, so mailbox * by OGMB. Again, SCBs reference their scsi_cmnds directly, so mailbox
* indices need not be involved. * indices need not be involved.
*/ */
...@@ -463,7 +465,7 @@ typedef struct scb { /* Command Control Block 5.4.1 */ ...@@ -463,7 +465,7 @@ typedef struct scb { /* Command Control Block 5.4.1 */
unchar direc; /* Transfer Direction */ unchar direc; /* Transfer Direction */
unchar reserved2[6]; /* SCSI Command Descriptor Block */ unchar reserved2[6]; /* SCSI Command Descriptor Block */
/* end of hardware SCB */ /* end of hardware SCB */
Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */ struct scsi_cmnd *SCpnt;/* scsi_cmnd using this SCB */
Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */ Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */
Adapter *host; /* host adapter */ Adapter *host; /* host adapter */
struct scb *next; /* for lists of scbs */ struct scb *next; /* for lists of scbs */
...@@ -799,8 +801,8 @@ static inline void wd7000_enable_dma(Adapter * host) ...@@ -799,8 +801,8 @@ static inline void wd7000_enable_dma(Adapter * host)
static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof) static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof)
{ {
register unsigned WAITbits; unsigned WAITbits;
register unsigned long WAITtimeout = jiffies + WAITnexttimeout; unsigned long WAITtimeout = jiffies + WAITnexttimeout;
while (time_before_eq(jiffies, WAITtimeout)) { while (time_before_eq(jiffies, WAITtimeout)) {
WAITbits = inb(port) & mask; WAITbits = inb(port) & mask;
...@@ -846,10 +848,10 @@ static inline int command_out(Adapter * host, unchar * cmd, int len) ...@@ -846,10 +848,10 @@ 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 = NULL; Scb *scb, *p = NULL;
unsigned long flags; unsigned long flags;
register unsigned long timeout = jiffies + WAITnexttimeout; unsigned long timeout = jiffies + WAITnexttimeout;
register unsigned long now; unsigned long now;
int i; int i;
if (needed <= 0) if (needed <= 0)
...@@ -936,7 +938,7 @@ static int mail_out(Adapter * host, Scb * scbptr) ...@@ -936,7 +938,7 @@ static int mail_out(Adapter * host, Scb * scbptr)
* Note: this can also be used for ICBs; just cast to the parm type. * Note: this can also be used for ICBs; just cast to the parm type.
*/ */
{ {
register int i, ogmb; int i, ogmb;
unsigned long flags; unsigned long flags;
unchar start_ogmb; unchar start_ogmb;
Mailbox *ogmbs = host->mb.ogmb; Mailbox *ogmbs = host->mb.ogmb;
...@@ -1034,23 +1036,26 @@ static int make_code(unsigned hosterr, unsigned scsierr) ...@@ -1034,23 +1036,26 @@ static int make_code(unsigned hosterr, unsigned scsierr)
#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) #define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
static void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t wd7000_intr(int irq, void *dev_id, struct pt_regs *regs)
{ {
register int flag, icmb, errstatus, icmb_status;
register int host_error, scsi_error;
register Scb *scb; /* for SCSI commands */
register IcbAny *icb; /* for host commands */
register Scsi_Cmnd *SCpnt;
Adapter *host = (Adapter *) dev_id; Adapter *host = (Adapter *) dev_id;
int flag, icmb, errstatus, icmb_status;
int host_error, scsi_error;
Scb *scb; /* for SCSI commands */
IcbAny *icb; /* for host commands */
struct scsi_cmnd *SCpnt;
Mailbox *icmbs = host->mb.icmb; Mailbox *icmbs = host->mb.icmb;
unsigned long flags;
spin_lock_irqsave(host->sh->host_lock, flags);
host->int_counter++; host->int_counter++;
dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host); dprintk("wd7000_intr: irq = %d, host = 0x%06lx\n", irq, (long) host);
flag = inb(host->iobase + ASC_INTR_STAT); flag = inb(host->iobase + ASC_INTR_STAT);
dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag); dprintk("wd7000_intr: intr stat = 0x%02x\n", flag);
if (!(inb(host->iobase + ASC_STAT) & INT_IM)) { if (!(inb(host->iobase + ASC_STAT) & INT_IM)) {
/* NB: these are _very_ possible if IRQ 15 is being used, since /* NB: these are _very_ possible if IRQ 15 is being used, since
...@@ -1061,79 +1066,70 @@ static void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1061,79 +1066,70 @@ static void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
* can sort these out. Otherwise, electrical noise and other such * can sort these out. Otherwise, electrical noise and other such
* problems would be indistinguishable from valid interrupts... * problems would be indistinguishable from valid interrupts...
*/ */
dprintk("wd7000_intr_handle: phantom interrupt...\n"); dprintk("wd7000_intr: phantom interrupt...\n");
wd7000_intr_ack(host); goto ack;
return;
} }
if (flag & MB_INTR) { if (!(flag & MB_INTR))
/* The interrupt is for a mailbox */ goto ack;
if (!(flag & IMB_INTR)) {
dprintk("wd7000_intr_handle: free outgoing mailbox\n"); /* The interrupt is for a mailbox */
/* if (!(flag & IMB_INTR)) {
* If sleep_on() and the "interrupt on free OGMB" command are dprintk("wd7000_intr: free outgoing mailbox\n");
* used in mail_out(), wake_up() should correspondingly be called /*
* here. For now, we don't need to do anything special. * If sleep_on() and the "interrupt on free OGMB" command are
*/ * used in mail_out(), wake_up() should correspondingly be called
wd7000_intr_ack(host); * here. For now, we don't need to do anything special.
return; */
} else { goto ack;
/* The interrupt is for an incoming mailbox */
icmb = flag & MB_MASK;
icmb_status = icmbs[icmb].status;
if (icmb_status & 0x80) { /* unsolicited - result in ICMB */
dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n", icmb_status);
wd7000_intr_ack(host);
return;
}
/* Aaaargh! (Zaga) */
scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
icmbs[icmb].status = 0;
if (!(scb->op & ICB_OP_MASK)) { /* an SCB is done */
SCpnt = scb->SCpnt;
if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
host_error = scb->vue | (icmb_status << 8);
scsi_error = scb->status;
errstatus = make_code(host_error, scsi_error);
SCpnt->result = errstatus;
free_scb(scb);
SCpnt->scsi_done(SCpnt);
}
} else { /* an ICB is done */
icb = (IcbAny *) scb;
icb->status = icmb_status;
icb->phase = 0;
}
} /* incoming mailbox */
} }
wd7000_intr_ack(host); /* The interrupt is for an incoming mailbox */
icmb = flag & MB_MASK;
icmb_status = icmbs[icmb].status;
if (icmb_status & 0x80) { /* unsolicited - result in ICMB */
dprintk("wd7000_intr: unsolicited interrupt 0x%02x\n", icmb_status);
goto ack;
}
dprintk("wd7000_intr_handle: return from interrupt handler\n"); /* Aaaargh! (Zaga) */
} scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
icmbs[icmb].status = 0;
if (scb->op & ICB_OP_MASK) { /* an SCB is done */
icb = (IcbAny *) scb;
icb->status = icmb_status;
icb->phase = 0;
goto ack;
}
static irqreturn_t do_wd7000_intr_handle(int irq, void *dev_id, SCpnt = scb->SCpnt;
struct pt_regs *regs) if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
{ host_error = scb->vue | (icmb_status << 8);
unsigned long flags; scsi_error = scb->status;
struct Scsi_Host *host = dev_id; errstatus = make_code(host_error, scsi_error);
SCpnt->result = errstatus;
spin_lock_irqsave(host->host_lock, flags); free_scb(scb);
wd7000_intr_handle(irq, dev_id, regs);
spin_unlock_irqrestore(host->host_lock, flags); SCpnt->scsi_done(SCpnt);
}
ack:
dprintk("wd7000_intr: return from interrupt handler\n");
wd7000_intr_ack(host);
spin_unlock_irqrestore(host->sh->host_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
static int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) void (*done)(struct scsi_cmnd *))
{ {
register Scb *scb; Scb *scb;
register Sgb *sgb; Sgb *sgb;
register unchar *cdb = (unchar *) SCpnt->cmnd; unchar *cdb = (unchar *) SCpnt->cmnd;
register unchar idlun; unchar idlun;
register short cdblen; short cdblen;
Adapter *host = (Adapter *) SCpnt->device->host->hostdata; Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
cdblen = SCpnt->cmd_len; cdblen = SCpnt->cmd_len;
...@@ -1293,7 +1289,7 @@ static int wd7000_init(Adapter * host) ...@@ -1293,7 +1289,7 @@ static int wd7000_init(Adapter * host)
return 0; return 0;
if (request_irq(host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", host)) { if (request_irq(host->irq, wd7000_intr, 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);
} }
...@@ -1434,7 +1430,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, ...@@ -1434,7 +1430,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start,
* *
*/ */
static int wd7000_detect(Scsi_Host_Template * tpnt) static int wd7000_detect(struct 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];
...@@ -1622,25 +1618,11 @@ static int wd7000_abort(Scsi_Cmnd * SCpnt) ...@@ -1622,25 +1618,11 @@ static int wd7000_abort(Scsi_Cmnd * SCpnt)
} }
#endif #endif
/*
* I also have no idea how to do a reset...
*/
static int wd7000_bus_reset(Scsi_Cmnd * SCpnt)
{
return FAILED;
}
static int wd7000_device_reset(Scsi_Cmnd * SCpnt)
{
return FAILED;
}
/* /*
* Last resort. Reinitialize the board. * Last resort. Reinitialize the board.
*/ */
static int wd7000_host_reset(Scsi_Cmnd * SCpnt) static int wd7000_host_reset(struct scsi_cmnd *SCpnt)
{ {
Adapter *host = (Adapter *) SCpnt->device->host->hostdata; Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
...@@ -1650,7 +1632,6 @@ static int wd7000_host_reset(Scsi_Cmnd * SCpnt) ...@@ -1650,7 +1632,6 @@ static int wd7000_host_reset(Scsi_Cmnd * SCpnt)
return SUCCESS; return SUCCESS;
} }
/* /*
* This was borrowed directly from aha1542.c. (Zaga) * This was borrowed directly from aha1542.c. (Zaga)
*/ */
...@@ -1706,15 +1687,13 @@ MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac"); ...@@ -1706,15 +1687,13 @@ MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers"); MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static Scsi_Host_Template driver_template = { static struct scsi_host_template driver_template = {
.proc_name = "wd7000", .proc_name = "wd7000",
.proc_info = wd7000_proc_info, .proc_info = wd7000_proc_info,
.name = "Western Digital WD-7000", .name = "Western Digital WD-7000",
.detect = wd7000_detect, .detect = wd7000_detect,
.release = wd7000_release, .release = wd7000_release,
.queuecommand = wd7000_queuecommand, .queuecommand = wd7000_queuecommand,
.eh_bus_reset_handler = wd7000_bus_reset,
.eh_device_reset_handler = wd7000_device_reset,
.eh_host_reset_handler = wd7000_host_reset, .eh_host_reset_handler = wd7000_host_reset,
.bios_param = wd7000_biosparam, .bios_param = wd7000_biosparam,
.can_queue = WD7000_Q, .can_queue = WD7000_Q,
......
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