diff options
Diffstat (limited to 'drivers/scsi/aha1542.c')
| -rw-r--r-- | drivers/scsi/aha1542.c | 1902 |
1 files changed, 695 insertions, 1207 deletions
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 770c48ddbe5e..371e8300f029 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -1,28 +1,10 @@ -/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $ - * linux/kernel/aha1542.c +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Adaptec AHA-1542 SCSI host adapters * * Copyright (C) 1992 Tommy Thorn * Copyright (C) 1993, 1994, 1995 Eric Youngdale - * - * Modified by Eric Youngdale - * Use request_irq and request_dma to help prevent unexpected conflicts - * Set up on-board DMA controller, such that we do not have to - * have the bios enabled to use the aha1542. - * Modified by David Gentzel - * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus - * controller). - * Modified by Matti Aarnio - * Accept parameters from LILO cmd-line. -- 1-Oct-94 - * Modified by Mike McLagan <mike.mclagan@linux.org> - * Recognise extended mode on AHA1542CP, different bit than 1542CF - * 1-Jan-97 - * Modified by Bjorn L. Thordarson and Einar Thor Einarsson - * Recognize that DMA0 is valid DMA channel -- 13-Jul-98 - * Modified by Chris Faulhaber <jedgar@fxp.org> - * Added module command-line options - * 19-Jul-99 - * Modified by Adam Fritzler - * Added proper detection of the AHA-1640 (MCA, now deleted) + * Copyright (C) 2015 Ondrej Zary */ #include <linux/module.h> @@ -30,96 +12,44 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h> -#include <linux/ioport.h> #include <linux/delay.h> -#include <linux/proc_fs.h> #include <linux/init.h> #include <linux/spinlock.h> -#include <linux/isapnp.h> -#include <linux/blkdev.h> +#include <linux/isa.h> +#include <linux/pnp.h> #include <linux/slab.h> - +#include <linux/io.h> #include <asm/dma.h> -#include <asm/io.h> - -#include "scsi.h" +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include "aha1542.h" -#define SCSI_BUF_PA(address) isa_virt_to_bus(address) -#define SCSI_SG_PA(sgent) (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset) - -#include <linux/stat.h> - -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -/* - static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $"; - */ - -/* The adaptec can be configured for quite a number of addresses, but - I generally do not want the card poking around at random. We allow - two addresses - this allows people to use the Adaptec with a Midi - card, which also used 0x330 -- can be overridden with LILO! */ - -#define MAXBOARDS 4 /* Increase this and the sizes of the - arrays below, if you need more.. */ +#define MAXBOARDS 4 -/* Boards 3,4 slots are reserved for ISAPnP scans */ - -static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0}; - -/* set by aha1542_setup according to the command line; they also may - be marked __initdata, but require zero initializers then */ - -static int setup_called[MAXBOARDS]; -static int setup_buson[MAXBOARDS]; -static int setup_busoff[MAXBOARDS]; -static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 }; - -/* - * LILO/Module params: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]] - * - * Where: <PORTBASE> is any of the valid AHA addresses: - * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 - * <BUSON> is the time (in microsecs) that AHA spends on the AT-bus - * when transferring data. 1542A power-on default is 11us, - * valid values are in range: 2..15 (decimal) - * <BUSOFF> is the time that AHA spends OFF THE BUS after while - * it is transferring data (not to monopolize the bus). - * Power-on default is 4us, valid range: 1..64 microseconds. - * <DMASPEED> Default is jumper selected (1542A: on the J1), - * but experimenter can alter it with this. - * Valid values: 5, 6, 7, 8, 10 (MB/s) - * Factory default is 5 MB/s. - */ - -#if defined(MODULE) -static bool isapnp = 0; -static int aha1542[] = {0x330, 11, 4, -1}; -module_param_array(aha1542, int, NULL, 0); +static bool isapnp = 1; module_param(isapnp, bool, 0); +MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)"); -static struct isapnp_device_id id_table[] __initdata = { - { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1542), - 0 - }, - {0} -}; +static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 }; +module_param_hw_array(io, int, ioport, NULL, 0); +MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)"); -MODULE_DEVICE_TABLE(isapnp, id_table); +/* time AHA spends on the AT-bus during data transfer */ +static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */ +module_param_array(bus_on, int, NULL, 0); +MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])"); -#else -static int isapnp = 1; -#endif +/* time AHA spends off the bus (not to monopolize it) during data transfer */ +static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */ +module_param_array(bus_off, int, NULL, 0); +MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])"); + +/* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */ +static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 }; +module_param_array(dma_speed, int, NULL, 0); +MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])"); -#define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */ #define BIOS_TRANSLATION_6432 1 /* Default case these days */ #define BIOS_TRANSLATION_25563 2 /* Big disk case */ @@ -128,134 +58,83 @@ struct aha1542_hostdata { int bios_translation; /* Mapping bios uses - for compatibility */ int aha1542_last_mbi_used; int aha1542_last_mbo_used; - Scsi_Cmnd *SCint[AHA1542_MAILBOXES]; - struct mailbox mb[2 * AHA1542_MAILBOXES]; - struct ccb ccb[AHA1542_MAILBOXES]; + struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES]; + struct mailbox *mb; + dma_addr_t mb_handle; + struct ccb *ccb; + dma_addr_t ccb_handle; }; -#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata) - -static DEFINE_SPINLOCK(aha1542_lock); +#define AHA1542_MAX_SECTORS 16 +struct aha1542_cmd { + /* bounce buffer */ + void *data_buffer; + dma_addr_t data_buffer_handle; +}; +static inline void aha1542_intr_reset(u16 base) +{ + outb(IRST, CONTROL(base)); +} -#define WAITnexttimeout 3000000 - -static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt); -static int aha1542_restart(struct Scsi_Host *shost); -static void aha1542_intr_handle(struct Scsi_Host *shost); - -#define aha1542_intr_reset(base) outb(IRST, CONTROL(base)) +static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout) +{ + bool delayed = true; -#define WAIT(port, mask, allof, noneof) \ - { register int WAITbits; \ - register int WAITtimeout = WAITnexttimeout; \ - while (1) { \ - WAITbits = inb(port) & (mask); \ - if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ - break; \ - if (--WAITtimeout == 0) goto fail; \ - } \ - } + if (timeout == 0) { + timeout = 3000000; + delayed = false; + } -/* Similar to WAIT, except we use the udelay call to regulate the - amount of time we wait. */ -#define WAITd(port, mask, allof, noneof, timeout) \ - { register int WAITbits; \ - register int WAITtimeout = timeout; \ - while (1) { \ - WAITbits = inb(port) & (mask); \ - if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ - break; \ - mdelay(1); \ - if (--WAITtimeout == 0) goto fail; \ - } \ - } + while (1) { + u8 bits = inb(port) & mask; + if ((bits & allof) == allof && ((bits & noneof) == 0)) + break; + if (delayed) + mdelay(1); + if (--timeout == 0) + return false; + } -static void aha1542_stat(void) -{ -/* int s = inb(STATUS), i = inb(INTRFLAGS); - printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */ + return true; } -/* This is a bit complicated, but we need to make sure that an interrupt - routine does not send something out while we are in the middle of this. - Fortunately, it is only at boot time that multi-byte messages - are ever sent. */ -static int aha1542_out(unsigned int base, unchar * cmdp, int len) +static int aha1542_outb(unsigned int base, u8 val) { - unsigned long flags = 0; - int got_lock; - - if (len == 1) { - got_lock = 0; - while (1 == 1) { - WAIT(STATUS(base), CDF, 0, CDF); - spin_lock_irqsave(&aha1542_lock, flags); - if (inb(STATUS(base)) & CDF) { - spin_unlock_irqrestore(&aha1542_lock, flags); - continue; - } - outb(*cmdp, DATA(base)); - spin_unlock_irqrestore(&aha1542_lock, flags); - return 0; - } - } else { - spin_lock_irqsave(&aha1542_lock, flags); - got_lock = 1; - while (len--) { - WAIT(STATUS(base), CDF, 0, CDF); - outb(*cmdp++, DATA(base)); - } - spin_unlock_irqrestore(&aha1542_lock, flags); - } + if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) + return 1; + outb(val, DATA(base)); + return 0; -fail: - if (got_lock) - spin_unlock_irqrestore(&aha1542_lock, flags); - printk(KERN_ERR "aha1542_out failed(%d): ", len + 1); - aha1542_stat(); - return 1; } -/* Only used at boot time, so we do not need to worry about latency as much - here */ - -static int __init aha1542_in(unsigned int base, unchar * cmdp, int len) +static int aha1542_out(unsigned int base, u8 *buf, int len) { - unsigned long flags; - - spin_lock_irqsave(&aha1542_lock, flags); while (len--) { - WAIT(STATUS(base), DF, DF, 0); - *cmdp++ = inb(DATA(base)); + if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) + return 1; + outb(*buf++, DATA(base)); } - spin_unlock_irqrestore(&aha1542_lock, flags); + if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0)) + return 1; + return 0; -fail: - spin_unlock_irqrestore(&aha1542_lock, flags); - printk(KERN_ERR "aha1542_in failed(%d): ", len + 1); - aha1542_stat(); - return 1; } -/* Similar to aha1542_in, except that we wait a very short period of time. - We use this if we know the board is alive and awake, but we are not sure - if the board will respond to the command we are about to send or not */ -static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len) -{ - unsigned long flags; +/* + * Only used at boot time, so we do not need to worry about latency as much + * here + */ - spin_lock_irqsave(&aha1542_lock, flags); +static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout) +{ while (len--) { - WAITd(STATUS(base), DF, DF, 0, 100); - *cmdp++ = inb(DATA(base)); + if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) + return 1; + *buf++ = inb(DATA(base)); } - spin_unlock_irqrestore(&aha1542_lock, flags); return 0; -fail: - spin_unlock_irqrestore(&aha1542_lock, flags); - return 1; } static int makecode(unsigned hosterr, unsigned scsierr) @@ -268,43 +147,54 @@ static int makecode(unsigned hosterr, unsigned scsierr) break; case 0x11: /* Selection time out-The initiator selection or target - reselection was not complete within the SCSI Time out period */ + * reselection was not complete within the SCSI Time out period + */ hosterr = DID_TIME_OUT; break; case 0x12: /* Data overrun/underrun-The target attempted to transfer more data - than was allocated by the Data Length field or the sum of the - Scatter / Gather Data Length fields. */ + * than was allocated by the Data Length field or the sum of the + * Scatter / Gather Data Length fields. + */ case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was - invalid. This usually indicates a software failure. */ + * invalid. This usually indicates a software failure. + */ case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. - This usually indicates a software failure. */ + * This usually indicates a software failure. + */ case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set - of linked CCB's does not specify the same logical unit number as - the first. */ + * of linked CCB's does not specify the same logical unit number as + * the first. + */ case 0x18: /* Invalid Target Direction received from Host-The direction of a - Target Mode CCB was invalid. */ + * Target Mode CCB was invalid. + */ case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was - received to service data transfer between the same target LUN - and initiator SCSI ID in the same direction. */ + * received to service data transfer between the same target LUN + * and initiator SCSI ID in the same direction. + */ case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero - length segment or invalid segment list boundaries was received. - A CCB parameter was invalid. */ - DEB(printk("Aha1542: %x %x\n", hosterr, scsierr)); + * length segment or invalid segment list boundaries was received. + * A CCB parameter was invalid. + */ +#ifdef DEBUG + printk("Aha1542: %x %x\n", hosterr, scsierr); +#endif hosterr = DID_ERROR; /* Couldn't find any better */ break; case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus - phase sequence was requested by the target. The host adapter - will generate a SCSI Reset Condition, notifying the host with - a SCRD interrupt */ + * phase sequence was requested by the target. The host adapter + * will generate a SCSI Reset Condition, notifying the host with + * a SCRD interrupt + */ hosterr = DID_RESET; break; default: @@ -314,106 +204,93 @@ static int makecode(unsigned hosterr, unsigned scsierr) return scsierr | (hosterr << 16); } -static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt) +static int aha1542_test_port(struct Scsi_Host *sh) { - unchar inquiry_cmd[] = {CMD_INQUIRY}; - unchar inquiry_result[4]; - unchar *cmdp; - int len; - volatile int debug = 0; + int i; /* Quick and dirty test for presence of the card. */ - if (inb(STATUS(bse)) == 0xff) + if (inb(STATUS(sh->io_port)) == 0xff) return 0; /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */ - /* DEB(printk("aha1542_test_port called \n")); */ - /* In case some other card was probing here, reset interrupts */ - aha1542_intr_reset(bse); /* reset interrupts, so they don't block */ + aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ - outb(SRST | IRST /*|SCRST */ , CONTROL(bse)); + outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port)); mdelay(20); /* Wait a little bit for things to settle down. */ - debug = 1; /* Expect INIT and IDLE, any of the others are bad */ - WAIT(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); + if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) + return 0; - debug = 2; /* Shouldn't have generated any interrupts during reset */ - if (inb(INTRFLAGS(bse)) & INTRMASK) - goto fail; - - - /* Perform a host adapter inquiry instead so we do not need to set - up the mailboxes ahead of time */ + if (inb(INTRFLAGS(sh->io_port)) & INTRMASK) + return 0; - aha1542_out(bse, inquiry_cmd, 1); + /* + * Perform a host adapter inquiry instead so we do not need to set + * up the mailboxes ahead of time + */ - debug = 3; - len = 4; - cmdp = &inquiry_result[0]; + aha1542_outb(sh->io_port, CMD_INQUIRY); - while (len--) { - WAIT(STATUS(bse), DF, DF, 0); - *cmdp++ = inb(DATA(bse)); + for (i = 0; i < 4; i++) { + if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0)) + return 0; + (void)inb(DATA(sh->io_port)); } - debug = 8; /* Reading port should reset DF */ - if (inb(STATUS(bse)) & DF) - goto fail; + if (inb(STATUS(sh->io_port)) & DF) + return 0; - debug = 9; /* When HACC, command is completed, and we're though testing */ - WAIT(INTRFLAGS(bse), HACC, HACC, 0); - /* now initialize adapter */ + if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0)) + return 0; - debug = 10; /* Clear interrupts */ - outb(IRST, CONTROL(bse)); - - debug = 11; + outb(IRST, CONTROL(sh->io_port)); - return debug; /* 1 = ok */ -fail: - return 0; /* 0 = not ok */ + return 1; } -/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */ -static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id) +static void aha1542_free_cmd(struct scsi_cmnd *cmd) { - unsigned long flags; - struct Scsi_Host *shost = dev_id; + struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); - spin_lock_irqsave(shost->host_lock, flags); - aha1542_intr_handle(shost); - spin_unlock_irqrestore(shost->host_lock, flags); - return IRQ_HANDLED; + if (cmd->sc_data_direction == DMA_FROM_DEVICE) { + struct request *rq = scsi_cmd_to_rq(cmd); + void *buf = acmd->data_buffer; + struct req_iterator iter; + struct bio_vec bv; + + rq_for_each_segment(bv, rq, iter) { + memcpy_to_bvec(&bv, buf); + buf += bv.bv_len; + } + } + + scsi_dma_unmap(cmd); } -/* A "high" level interrupt handler */ -static void aha1542_intr_handle(struct Scsi_Host *shost) +static irqreturn_t aha1542_interrupt(int irq, void *dev_id) { - void (*my_done) (Scsi_Cmnd *) = NULL; + struct Scsi_Host *sh = dev_id; + struct aha1542_hostdata *aha1542 = shost_priv(sh); int errstatus, mbi, mbo, mbistatus; int number_serviced; unsigned long flags; - Scsi_Cmnd *SCtmp; + struct scsi_cmnd *tmp_cmd; int flag; - int needs_restart; - struct mailbox *mb; - struct ccb *ccb; - - mb = HOSTDATA(shost)->mb; - ccb = HOSTDATA(shost)->ccb; + struct mailbox *mb = aha1542->mb; + struct ccb *ccb = aha1542->ccb; #ifdef DEBUG { - flag = inb(INTRFLAGS(shost->io_port)); - printk(KERN_DEBUG "aha1542_intr_handle: "); + flag = inb(INTRFLAGS(sh->io_port)); + shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: "); if (!(flag & ANYINTR)) printk("no interrupt?"); if (flag & MBIF) @@ -424,33 +301,32 @@ static void aha1542_intr_handle(struct Scsi_Host *shost) printk("HACC "); if (flag & SCRD) printk("SCRD "); - printk("status %02x\n", inb(STATUS(shost->io_port))); - }; + printk("status %02x\n", inb(STATUS(sh->io_port))); + } #endif number_serviced = 0; - needs_restart = 0; - while (1 == 1) { - flag = inb(INTRFLAGS(shost->io_port)); + spin_lock_irqsave(sh->host_lock, flags); + while (1) { + flag = inb(INTRFLAGS(sh->io_port)); - /* Check for unusual interrupts. If any of these happen, we should - probably do something special, but for now just printing a message - is sufficient. A SCSI reset detected is something that we really - need to deal with in some way. */ + /* + * Check for unusual interrupts. If any of these happen, we should + * probably do something special, but for now just printing a message + * is sufficient. A SCSI reset detected is something that we really + * need to deal with in some way. + */ if (flag & ~MBIF) { if (flag & MBOA) printk("MBOF "); if (flag & HACC) printk("HACC "); - if (flag & SCRD) { - needs_restart = 1; + if (flag & SCRD) printk("SCRD "); - } } - aha1542_intr_reset(shost->io_port); + aha1542_intr_reset(sh->io_port); - spin_lock_irqsave(&aha1542_lock, flags); - mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1; + mbi = aha1542->aha1542_last_mbi_used + 1; if (mbi >= 2 * AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; @@ -460,57 +336,51 @@ static void aha1542_intr_handle(struct Scsi_Host *shost) mbi++; if (mbi >= 2 * AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; - } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used); + } while (mbi != aha1542->aha1542_last_mbi_used); if (mb[mbi].status == 0) { - spin_unlock_irqrestore(&aha1542_lock, flags); + spin_unlock_irqrestore(sh->host_lock, flags); /* Hmm, no mail. Must have read it the last time around */ - if (!number_serviced && !needs_restart) - printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n"); - /* We detected a reset. Restart all pending commands for - devices that use the hard reset option */ - if (needs_restart) - aha1542_restart(shost); - return; - }; - - mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_BUF_PA(&ccb[0]))) / sizeof(struct ccb); + if (!number_serviced) + shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n"); + return IRQ_HANDLED; + } + + mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb); mbistatus = mb[mbi].status; mb[mbi].status = 0; - HOSTDATA(shost)->aha1542_last_mbi_used = mbi; - spin_unlock_irqrestore(&aha1542_lock, flags); + aha1542->aha1542_last_mbi_used = mbi; #ifdef DEBUG - { - if (ccb[mbo].tarstat | ccb[mbo].hastat) - printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n", - ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); - }; + if (ccb[mbo].tarstat | ccb[mbo].hastat) + shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n", + ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); #endif if (mbistatus == 3) continue; /* Aborted command not found */ #ifdef DEBUG - printk(KERN_DEBUG "...done %d %d\n", mbo, mbi); + shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi); #endif - SCtmp = HOSTDATA(shost)->SCint[mbo]; + tmp_cmd = aha1542->int_cmds[mbo]; - if (!SCtmp || !SCtmp->scsi_done) { - printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n"); - printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat, + if (!tmp_cmd) { + spin_unlock_irqrestore(sh->host_lock, flags); + shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n"); + shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat, ccb[mbo].hastat, ccb[mbo].idlun, mbo); - return; + return IRQ_HANDLED; } - my_done = SCtmp->scsi_done; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - /* Fetch the sense data, and tuck it away, in the required slot. The - Adaptec automatically fetches it, and there is no guarantee that - we will still have it in the cdb when we come back */ + aha1542_free_cmd(tmp_cmd); + /* + * Fetch the sense data, and tuck it away, in the required slot. The + * Adaptec automatically fetches it, and there is no guarantee that + * we will still have it in the cdb when we come back + */ if (ccb[mbo].tarstat == 2) - memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], + memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], SCSI_SENSE_BUFFERSIZE); @@ -525,308 +395,236 @@ static void aha1542_intr_handle(struct Scsi_Host *shost) #ifdef DEBUG if (errstatus) - printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus, + shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus, ccb[mbo].hastat, ccb[mbo].tarstat); + if (ccb[mbo].tarstat == 2) + print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12); + if (errstatus) + printk("aha1542_intr_handle: returning %6x\n", errstatus); #endif - - if (ccb[mbo].tarstat == 2) { -#ifdef DEBUG - int i; -#endif - DEB(printk("aha1542_intr_handle: sense:")); -#ifdef DEBUG - for (i = 0; i < 12; i++) - printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]); - printk("\n"); -#endif - /* - DEB(printk("aha1542_intr_handle: buf:")); - for (i = 0; i < bufflen; i++) - printk("%02x ", ((unchar *)buff)[i]); - printk("\n"); - */ - } - DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus)); - SCtmp->result = errstatus; - HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as - far as queuecommand is concerned */ - my_done(SCtmp); + tmp_cmd->result = errstatus; + aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as + * far as queuecommand is concerned + */ + scsi_done(tmp_cmd); number_serviced++; - }; + } } -static int aha1542_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { - unchar ahacmd = CMD_START_SCSI; - unchar direction; - unchar *cmd = (unchar *) SCpnt->cmnd; - unchar target = SCpnt->device->id; - unchar lun = SCpnt->device->lun; + struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); + struct aha1542_hostdata *aha1542 = shost_priv(sh); + u8 direction; + u8 target = cmd->device->id; + u8 lun = cmd->device->lun; unsigned long flags; - int bufflen = scsi_bufflen(SCpnt); + int bufflen = scsi_bufflen(cmd); int mbo; - struct mailbox *mb; - struct ccb *ccb; - - DEB(int i); - - mb = HOSTDATA(SCpnt->device->host)->mb; - ccb = HOSTDATA(SCpnt->device->host)->ccb; + struct mailbox *mb = aha1542->mb; + struct ccb *ccb = aha1542->ccb; - DEB(if (target > 1) { - SCpnt->result = DID_TIME_OUT << 16; - done(SCpnt); return 0; - } - ); - - if (*cmd == REQUEST_SENSE) { + if (*cmd->cmnd == REQUEST_SENSE) { /* Don't do the command - we have the sense data already */ -#if 0 - /* scsi_request_sense() provides a buffer of size 256, - so there is no reason to expect equality */ - if (bufflen != SCSI_SENSE_BUFFERSIZE) - printk(KERN_CRIT "aha1542: Wrong buffer length supplied " - "for request sense (%d)\n", bufflen); -#endif - SCpnt->result = 0; - done(SCpnt); + cmd->result = 0; + scsi_done(cmd); return 0; } #ifdef DEBUG - if (*cmd == READ_10 || *cmd == WRITE_10) - i = xscsi2int(cmd + 2); - else if (*cmd == READ_6 || *cmd == WRITE_6) - i = scsi2int(cmd + 2); - else - i = -1; - if (done) - printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); - else - printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); - aha1542_stat(); - printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:"); - for (i = 0; i < SCpnt->cmd_len; i++) - printk("%02x ", cmd[i]); - printk("\n"); - if (*cmd == WRITE_10 || *cmd == WRITE_6) - return 0; /* we are still testing, so *don't* write */ + { + int i = -1; + if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) + i = xscsi2int(cmd->cmnd + 2); + else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6) + i = scsi2int(cmd->cmnd + 2); + shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d", + target, *cmd->cmnd, i, bufflen); + print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len); + } #endif - /* Use the outgoing mailboxes in a round-robin fashion, because this - is how the host adapter will scan for them */ - spin_lock_irqsave(&aha1542_lock, flags); - mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1; + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + struct request *rq = scsi_cmd_to_rq(cmd); + void *buf = acmd->data_buffer; + struct req_iterator iter; + struct bio_vec bv; + + rq_for_each_segment(bv, rq, iter) { + memcpy_from_bvec(buf, &bv); + buf += bv.bv_len; + } + } + + /* + * Use the outgoing mailboxes in a round-robin fashion, because this + * is how the host adapter will scan for them + */ + + spin_lock_irqsave(sh->host_lock, flags); + mbo = aha1542->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; do { - if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL) + if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) break; mbo++; if (mbo >= AHA1542_MAILBOXES) mbo = 0; - } while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used); + } while (mbo != aha1542->aha1542_last_mbo_used); - if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo]) + if (mb[mbo].status || aha1542->int_cmds[mbo]) panic("Unable to find empty mailbox for aha1542.\n"); - HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from - screwing with this cdb. */ + aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from + * screwing with this cdb. + */ - HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo; - spin_unlock_irqrestore(&aha1542_lock, flags); + aha1542->aha1542_last_mbo_used = mbo; #ifdef DEBUG - printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done); + shost_printk(KERN_DEBUG, sh, "Sending command (%d)...", mbo); #endif - any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo])); /* This gets trashed for some reason */ + /* This gets trashed for some reason */ + any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); memset(&ccb[mbo], 0, sizeof(struct ccb)); - ccb[mbo].cdblen = SCpnt->cmd_len; + ccb[mbo].cdblen = cmd->cmd_len; direction = 0; - if (*cmd == READ_10 || *cmd == READ_6) + if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) direction = 8; - else if (*cmd == WRITE_10 || *cmd == WRITE_6) + else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) direction = 16; - memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); - - if (bufflen) { - struct scatterlist *sg; - struct chain *cptr; -#ifdef DEBUG - unsigned char *ptr; -#endif - int i, sg_count = scsi_sg_count(SCpnt); - ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ - SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count, - GFP_KERNEL | GFP_DMA); - cptr = (struct chain *) SCpnt->host_scribble; - if (cptr == NULL) { - /* free the claimed mailbox slot */ - HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL; - return SCSI_MLQUEUE_HOST_BUSY; - } - scsi_for_each_sg(SCpnt, sg, sg_count, i) { - any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg)); - any2scsi(cptr[i].datalen, sg->length); - }; - any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); - any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr)); -#ifdef DEBUG - printk("cptr %x: ", cptr); - ptr = (unsigned char *) cptr; - for (i = 0; i < 18; i++) - printk("%02x ", ptr[i]); -#endif - } else { - ccb[mbo].op = 0; /* SCSI Initiator Command */ - SCpnt->host_scribble = NULL; - any2scsi(ccb[mbo].datalen, 0); + memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); + ccb[mbo].op = 0; /* SCSI Initiator Command */ + any2scsi(ccb[mbo].datalen, bufflen); + if (bufflen) + any2scsi(ccb[mbo].dataptr, acmd->data_buffer_handle); + else any2scsi(ccb[mbo].dataptr, 0); - }; ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ ccb[mbo].rsalen = 16; ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; ccb[mbo].commlinkid = 0; #ifdef DEBUG - { - int i; - printk(KERN_DEBUG "aha1542_command: sending.. "); - for (i = 0; i < sizeof(ccb[mbo]) - 10; i++) - printk("%02x ", ((unchar *) & ccb[mbo])[i]); - }; + print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10); + printk("aha1542_queuecommand: now waiting for interrupt "); #endif - - if (done) { - DEB(printk("aha1542_queuecommand: now waiting for interrupt "); - aha1542_stat()); - SCpnt->scsi_done = done; - mb[mbo].status = 1; - aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1); /* start scsi command */ - DEB(aha1542_stat()); - } else - printk("aha1542_queuecommand: done can't be NULL\n"); + mb[mbo].status = 1; + aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI); + spin_unlock_irqrestore(sh->host_lock, flags); return 0; } -static DEF_SCSI_QCMD(aha1542_queuecommand) - /* Initialize mailboxes */ -static void setup_mailboxes(int bse, struct Scsi_Host *shpnt) +static void setup_mailboxes(struct Scsi_Host *sh) { + struct aha1542_hostdata *aha1542 = shost_priv(sh); + u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; int i; - struct mailbox *mb; - struct ccb *ccb; - - unchar cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; - - mb = HOSTDATA(shpnt)->mb; - ccb = HOSTDATA(shpnt)->ccb; for (i = 0; i < AHA1542_MAILBOXES; i++) { - mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0; - any2scsi(mb[i].ccbptr, SCSI_BUF_PA(&ccb[i])); - }; - aha1542_intr_reset(bse); /* reset interrupts, so they don't block */ - any2scsi((cmd + 2), SCSI_BUF_PA(mb)); - aha1542_out(bse, cmd, 5); - WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0); - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n"); + aha1542->mb[i].status = 0; + any2scsi(aha1542->mb[i].ccbptr, + aha1542->ccb_handle + i * sizeof(struct ccb)); + aha1542->mb[AHA1542_MAILBOXES + i].status = 0; } - aha1542_intr_reset(bse); + aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ + any2scsi(mb_cmd + 2, aha1542->mb_handle); + if (aha1542_out(sh->io_port, mb_cmd, 5)) + shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); + aha1542_intr_reset(sh->io_port); } -static int __init aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id) +static int aha1542_getconfig(struct Scsi_Host *sh) { - unchar inquiry_cmd[] = {CMD_RETCONF}; - unchar inquiry_result[3]; + u8 inquiry_result[3]; int i; - i = inb(STATUS(base_io)); + i = inb(STATUS(sh->io_port)); if (i & DF) { - i = inb(DATA(base_io)); - }; - aha1542_out(base_io, inquiry_cmd, 1); - aha1542_in(base_io, inquiry_result, 3); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: query board settings\n"); + i = inb(DATA(sh->io_port)); } - aha1542_intr_reset(base_io); + aha1542_outb(sh->io_port, CMD_RETCONF); + aha1542_in(sh->io_port, inquiry_result, 3, 0); + if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) + shost_printk(KERN_ERR, sh, "error querying board settings\n"); + aha1542_intr_reset(sh->io_port); switch (inquiry_result[0]) { case 0x80: - *dma_chan = 7; + sh->dma_channel = 7; break; case 0x40: - *dma_chan = 6; + sh->dma_channel = 6; break; case 0x20: - *dma_chan = 5; + sh->dma_channel = 5; break; case 0x01: - *dma_chan = 0; + sh->dma_channel = 0; break; case 0: - /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. - Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */ - *dma_chan = 0xFF; + /* + * This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. + * Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. + */ + sh->dma_channel = 0xFF; break; default: - printk(KERN_ERR "Unable to determine Adaptec DMA priority. Disabling board\n"); + shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n"); return -1; - }; + } switch (inquiry_result[1]) { case 0x40: - *irq_level = 15; + sh->irq = 15; break; case 0x20: - *irq_level = 14; + sh->irq = 14; break; case 0x8: - *irq_level = 12; + sh->irq = 12; break; case 0x4: - *irq_level = 11; + sh->irq = 11; break; case 0x2: - *irq_level = 10; + sh->irq = 10; break; case 0x1: - *irq_level = 9; + sh->irq = 9; break; default: - printk(KERN_ERR "Unable to determine Adaptec IRQ level. Disabling board\n"); + shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n"); return -1; - }; - *scsi_id = inquiry_result[2] & 7; + } + sh->this_id = inquiry_result[2] & 7; return 0; } -/* This function should only be called for 1542C boards - we can detect - the special firmware settings and unlock the board */ +/* + * This function should only be called for 1542C boards - we can detect + * the special firmware settings and unlock the board + */ -static int __init aha1542_mbenable(int base) +static int aha1542_mbenable(struct Scsi_Host *sh) { - static unchar mbenable_cmd[3]; - static unchar mbenable_result[2]; + static u8 mbenable_cmd[3]; + static u8 mbenable_result[2]; int retval; retval = BIOS_TRANSLATION_6432; - mbenable_cmd[0] = CMD_EXTBIOS; - aha1542_out(base, mbenable_cmd, 1); - if (aha1542_in1(base, mbenable_result, 2)) + aha1542_outb(sh->io_port, CMD_EXTBIOS); + if (aha1542_in(sh->io_port, mbenable_result, 2, 100)) return retval; - WAITd(INTRFLAGS(base), INTRMASK, HACC, 0, 100); - aha1542_intr_reset(base); + if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100)) + goto fail; + aha1542_intr_reset(sh->io_port); if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { mbenable_cmd[0] = CMD_MBENABLE; @@ -836,430 +634,269 @@ static int __init aha1542_mbenable(int base) if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) retval = BIOS_TRANSLATION_25563; - aha1542_out(base, mbenable_cmd, 3); - WAIT(INTRFLAGS(base), INTRMASK, HACC, 0); - }; + if (aha1542_out(sh->io_port, mbenable_cmd, 3)) + goto fail; + } while (0) { fail: - printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n"); + shost_printk(KERN_ERR, sh, "Mailbox init failed\n"); } - aha1542_intr_reset(base); + aha1542_intr_reset(sh->io_port); return retval; } /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ -static int __init aha1542_query(int base_io, int *transl) +static int aha1542_query(struct Scsi_Host *sh) { - unchar inquiry_cmd[] = {CMD_INQUIRY}; - unchar inquiry_result[4]; + struct aha1542_hostdata *aha1542 = shost_priv(sh); + u8 inquiry_result[4]; int i; - i = inb(STATUS(base_io)); + i = inb(STATUS(sh->io_port)); if (i & DF) { - i = inb(DATA(base_io)); - }; - aha1542_out(base_io, inquiry_cmd, 1); - aha1542_in(base_io, inquiry_result, 4); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: query card type\n"); + i = inb(DATA(sh->io_port)); } - aha1542_intr_reset(base_io); + aha1542_outb(sh->io_port, CMD_INQUIRY); + aha1542_in(sh->io_port, inquiry_result, 4, 0); + if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) + shost_printk(KERN_ERR, sh, "error querying card type\n"); + aha1542_intr_reset(sh->io_port); - *transl = BIOS_TRANSLATION_6432; /* Default case */ + aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */ - /* For an AHA1740 series board, we ignore the board since there is a - hardware bug which can lead to wrong blocks being returned if the board - is operating in the 1542 emulation mode. Since there is an extended mode - driver, we simply ignore the board and let the 1740 driver pick it up. + /* + * For an AHA1740 series board, we ignore the board since there is a + * hardware bug which can lead to wrong blocks being returned if the board + * is operating in the 1542 emulation mode. Since there is an extended mode + * driver, we simply ignore the board and let the 1740 driver pick it up. */ if (inquiry_result[0] == 0x43) { - printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n"); + shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n"); return 1; - }; + } - /* Always call this - boards that do not support extended bios translation - will ignore the command, and we will set the proper default */ + /* + * Always call this - boards that do not support extended bios translation + * will ignore the command, and we will set the proper default + */ - *transl = aha1542_mbenable(base_io); + aha1542->bios_translation = aha1542_mbenable(sh); return 0; } -#ifndef MODULE -static char *setup_str[MAXBOARDS] __initdata; -static int setup_idx = 0; - -static void __init aha1542_setup(char *str, int *ints) +static u8 dma_speed_hw(int dma_speed) { - const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n"; - int setup_portbase; - - if (setup_idx >= MAXBOARDS) { - printk(KERN_ERR "aha1542: aha1542_setup called too many times! Bad LILO params ?\n"); - printk(KERN_ERR " Entryline 1: %s\n", setup_str[0]); - printk(KERN_ERR " Entryline 2: %s\n", setup_str[1]); - printk(KERN_ERR " This line: %s\n", str); - return; - } - if (ints[0] < 1 || ints[0] > 4) { - printk(KERN_ERR "aha1542: %s\n", str); - printk(ahausage); - printk(KERN_ERR "aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n"); + switch (dma_speed) { + case 5: + return 0x00; + case 6: + return 0x04; + case 7: + return 0x01; + case 8: + return 0x02; + case 10: + return 0x03; } - setup_called[setup_idx] = ints[0]; - setup_str[setup_idx] = str; - setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */ - setup_buson[setup_idx] = ints[0] >= 2 ? ints[2] : 7; - setup_busoff[setup_idx] = ints[0] >= 3 ? ints[3] : 5; - if (ints[0] >= 4) - { - int atbt = -1; - switch (ints[4]) { - case 5: - atbt = 0x00; - break; - case 6: - atbt = 0x04; - break; - case 7: - atbt = 0x01; - break; - case 8: - atbt = 0x02; - break; - case 10: - atbt = 0x03; - break; - default: - printk(KERN_ERR "aha1542: %s\n", str); - printk(ahausage); - printk(KERN_ERR "aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. Using jumper defaults.\n"); - break; - } - setup_dmaspeed[setup_idx] = atbt; - } - if (setup_portbase != 0) - bases[setup_idx] = setup_portbase; - - ++setup_idx; + return 0xff; /* invalid */ } -static int __init do_setup(char *str) +/* Set the Bus on/off-times as not to ruin floppy performance */ +static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed) { - int ints[5]; + if (bus_on > 0) { + u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) }; - int count=setup_idx; + aha1542_intr_reset(sh->io_port); + if (aha1542_out(sh->io_port, oncmd, 2)) + goto fail; + } - get_options(str, ARRAY_SIZE(ints), ints); - aha1542_setup(str,ints); + if (bus_off > 0) { + u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) }; - return count<setup_idx; -} + aha1542_intr_reset(sh->io_port); + if (aha1542_out(sh->io_port, offcmd, 2)) + goto fail; + } -__setup("aha1542=",do_setup); -#endif + if (dma_speed_hw(dma_speed) != 0xff) { + u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) }; + + aha1542_intr_reset(sh->io_port); + if (aha1542_out(sh->io_port, dmacmd, 2)) + goto fail; + } + aha1542_intr_reset(sh->io_port); + return; +fail: + shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n"); + aha1542_intr_reset(sh->io_port); +} /* return non-zero on detection */ -static int __init aha1542_detect(struct scsi_host_template * tpnt) +static struct Scsi_Host *aha1542_hw_init(const struct scsi_host_template *tpnt, + struct device *pdev, int indx) { - unsigned char dma_chan; - unsigned char irq_level; - unsigned char scsi_id; - unsigned long flags; - unsigned int base_io; - int trans; - struct Scsi_Host *shpnt = NULL; - int count = 0; - int indx; - - DEB(printk("aha1542_detect: \n")); - - tpnt->proc_name = "aha1542"; - -#ifdef MODULE - bases[0] = aha1542[0]; - setup_buson[0] = aha1542[1]; - setup_busoff[0] = aha1542[2]; - { - int atbt = -1; - switch (aha1542[3]) { - case 5: - atbt = 0x00; - break; - case 6: - atbt = 0x04; - break; - case 7: - atbt = 0x01; - break; - case 8: - atbt = 0x02; - break; - case 10: - atbt = 0x03; - break; - }; - setup_dmaspeed[0] = atbt; + unsigned int base_io = io[indx]; + struct Scsi_Host *sh; + struct aha1542_hostdata *aha1542; + char dma_info[] = "no DMA"; + + if (base_io == 0) + return NULL; + + if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542")) + return NULL; + + sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata)); + if (!sh) + goto release; + aha1542 = shost_priv(sh); + + sh->unique_id = base_io; + sh->io_port = base_io; + sh->n_io_port = AHA1542_REGION_SIZE; + aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1; + aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1; + + if (!aha1542_test_port(sh)) + goto unregister; + + aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]); + if (aha1542_query(sh)) + goto unregister; + if (aha1542_getconfig(sh) == -1) + goto unregister; + + if (sh->dma_channel != 0xFF) + snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel); + shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n", + sh->this_id, base_io, sh->irq, dma_info); + if (aha1542->bios_translation == BIOS_TRANSLATION_25563) + shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); + + if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0) + goto unregister; + + aha1542->mb = dma_alloc_coherent(pdev, + AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), + &aha1542->mb_handle, GFP_KERNEL); + if (!aha1542->mb) + goto unregister; + + aha1542->ccb = dma_alloc_coherent(pdev, + AHA1542_MAILBOXES * sizeof(struct ccb), + &aha1542->ccb_handle, GFP_KERNEL); + if (!aha1542->ccb) + goto free_mb; + + setup_mailboxes(sh); + + if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { + shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); + goto free_ccb; } -#endif - - /* - * Hunt for ISA Plug'n'Pray Adaptecs (AHA1535) - */ - - if(isapnp) - { - struct pnp_dev *pdev = NULL; - for(indx = 0; indx < ARRAY_SIZE(bases); indx++) { - if(bases[indx]) - continue; - pdev = pnp_find_dev(NULL, ISAPNP_VENDOR('A', 'D', 'P'), - ISAPNP_FUNCTION(0x1542), pdev); - if(pdev==NULL) - break; - /* - * Activate the PnP card - */ - - if(pnp_device_attach(pdev)<0) - continue; - - if(pnp_activate_dev(pdev)<0) { - pnp_device_detach(pdev); - continue; - } - - if(!pnp_port_valid(pdev, 0)) { - pnp_device_detach(pdev); - continue; - } - - bases[indx] = pnp_port_start(pdev, 0); - - /* The card can be queried for its DMA, we have - the DMA set up that is enough */ - - printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", bases[indx]); + if (sh->dma_channel != 0xFF) { + if (request_dma(sh->dma_channel, "aha1542")) { + shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n"); + goto free_irq; + } + if (sh->dma_channel == 0 || sh->dma_channel >= 5) { + set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE); + enable_dma(sh->dma_channel); } } - for (indx = 0; indx < ARRAY_SIZE(bases); indx++) - if (bases[indx] != 0 && request_region(bases[indx], 4, "aha1542")) { - shpnt = scsi_register(tpnt, - sizeof(struct aha1542_hostdata)); - - if(shpnt==NULL) { - release_region(bases[indx], 4); - continue; - } - if (!aha1542_test_port(bases[indx], shpnt)) - goto unregister; - - base_io = bases[indx]; - - /* Set the Bus on/off-times as not to ruin floppy performance */ - { - unchar oncmd[] = {CMD_BUSON_TIME, 7}; - unchar offcmd[] = {CMD_BUSOFF_TIME, 5}; - - if (setup_called[indx]) { - oncmd[1] = setup_buson[indx]; - offcmd[1] = setup_busoff[indx]; - } - aha1542_intr_reset(base_io); - aha1542_out(base_io, oncmd, 2); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - aha1542_intr_reset(base_io); - aha1542_out(base_io, offcmd, 2); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - if (setup_dmaspeed[indx] >= 0) { - unchar dmacmd[] = {CMD_DMASPEED, 0}; - dmacmd[1] = setup_dmaspeed[indx]; - aha1542_intr_reset(base_io); - aha1542_out(base_io, dmacmd, 2); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - } - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: setting bus on/off-time failed\n"); - } - aha1542_intr_reset(base_io); - } - if (aha1542_query(base_io, &trans)) - goto unregister; - - if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1) - goto unregister; - printk(KERN_INFO "Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level); - if (dma_chan != 0xFF) - printk(", DMA priority %d", dma_chan); - printk("\n"); + if (scsi_add_host(sh, pdev)) + goto free_dma; - DEB(aha1542_stat()); - setup_mailboxes(base_io, shpnt); + scsi_scan_host(sh); - DEB(aha1542_stat()); - - DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level)); - spin_lock_irqsave(&aha1542_lock, flags); - if (request_irq(irq_level, do_aha1542_intr_handle, 0, - "aha1542", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n"); - spin_unlock_irqrestore(&aha1542_lock, flags); - goto unregister; - } - if (dma_chan != 0xFF) { - if (request_dma(dma_chan, "aha1542")) { - printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n"); - free_irq(irq_level, shpnt); - spin_unlock_irqrestore(&aha1542_lock, flags); - goto unregister; - } - if (dma_chan == 0 || dma_chan >= 5) { - set_dma_mode(dma_chan, DMA_MODE_CASCADE); - enable_dma(dma_chan); - } - } - - shpnt->this_id = scsi_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 4; /* Number of bytes of I/O space used */ - shpnt->dma_channel = dma_chan; - shpnt->irq = irq_level; - HOSTDATA(shpnt)->bios_translation = trans; - if (trans == BIOS_TRANSLATION_25563) - printk(KERN_INFO "aha1542.c: Using extended bios translation\n"); - HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1); - HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1); - memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint)); - spin_unlock_irqrestore(&aha1542_lock, flags); -#if 0 - DEB(printk(" *** READ CAPACITY ***\n")); - - { - unchar buf[8]; - static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int i; - - for (i = 0; i < sizeof(buf); ++i) - buf[i] = 0x87; - for (i = 0; i < 2; ++i) - if (!aha1542_command(i, cmd, buf, sizeof(buf))) { - printk(KERN_DEBUG "aha_detect: LU %d sector_size %d device_size %d\n", - i, xscsi2int(buf + 4), xscsi2int(buf)); - } - } + return sh; - DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n")); - - for (i = 0; i < 4; ++i) { - unsigned char cmd[10]; - static buffer[512]; - - cmd[0] = READ_10; - cmd[1] = 0; - xany2scsi(cmd + 2, i); - cmd[6] = 0; - cmd[7] = 0; - cmd[8] = 1; - cmd[9] = 0; - aha1542_command(0, cmd, buffer, 512); - } -#endif - count++; - continue; +free_dma: + if (sh->dma_channel != 0xff) + free_dma(sh->dma_channel); +free_irq: + free_irq(sh->irq, sh); +free_ccb: + dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb), + aha1542->ccb, aha1542->ccb_handle); +free_mb: + dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), + aha1542->mb, aha1542->mb_handle); unregister: - release_region(bases[indx], 4); - scsi_unregister(shpnt); - continue; + scsi_host_put(sh); +release: + release_region(base_io, AHA1542_REGION_SIZE); - }; - - return count; + return NULL; } -static int aha1542_release(struct Scsi_Host *shost) +static int aha1542_release(struct Scsi_Host *sh) { - if (shost->irq) - free_irq(shost->irq, shost); - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); + struct aha1542_hostdata *aha1542 = shost_priv(sh); + struct device *dev = sh->dma_dev; + + scsi_remove_host(sh); + if (sh->dma_channel != 0xff) + free_dma(sh->dma_channel); + dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb), + aha1542->ccb, aha1542->ccb_handle); + dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), + aha1542->mb, aha1542->mb_handle); + if (sh->irq) + free_irq(sh->irq, sh); + if (sh->io_port && sh->n_io_port) + release_region(sh->io_port, sh->n_io_port); + scsi_host_put(sh); return 0; } -static int aha1542_restart(struct Scsi_Host *shost) -{ - int i; - int count = 0; -#if 0 - unchar ahacmd = CMD_START_SCSI; -#endif - - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(shost)->SCint[i] && - !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) { -#if 0 - HOSTDATA(shost)->mb[i].status = 1; /* Indicate ready to restart... */ -#endif - count++; - } - printk(KERN_DEBUG "Potential to restart %d stalled commands...\n", count); -#if 0 - /* start scsi command */ - if (count) - aha1542_out(shost->io_port, &ahacmd, 1); -#endif - return 0; -} /* * This is a device reset. This is handled by sending a special command * to the device. */ -static int aha1542_dev_reset(Scsi_Cmnd * SCpnt) +static int aha1542_dev_reset(struct scsi_cmnd *cmd) { + struct Scsi_Host *sh = cmd->device->host; + struct aha1542_hostdata *aha1542 = shost_priv(sh); unsigned long flags; - struct mailbox *mb; - unchar target = SCpnt->device->id; - unchar lun = SCpnt->device->lun; + struct mailbox *mb = aha1542->mb; + u8 target = cmd->device->id; + u8 lun = cmd->device->lun; int mbo; - struct ccb *ccb; - unchar ahacmd = CMD_START_SCSI; + struct ccb *ccb = aha1542->ccb; - ccb = HOSTDATA(SCpnt->device->host)->ccb; - mb = HOSTDATA(SCpnt->device->host)->mb; - - spin_lock_irqsave(&aha1542_lock, flags); - mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1; + spin_lock_irqsave(sh->host_lock, flags); + mbo = aha1542->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; do { - if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL) + if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) break; mbo++; if (mbo >= AHA1542_MAILBOXES) mbo = 0; - } while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used); + } while (mbo != aha1542->aha1542_last_mbo_used); - if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo]) + if (mb[mbo].status || aha1542->int_cmds[mbo]) panic("Unable to find empty mailbox for aha1542.\n"); - HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt; /* This will effectively - prevent someone else from - screwing with this cdb. */ + aha1542->int_cmds[mbo] = cmd; /* This will effectively + * prevent someone else from + * screwing with this cdb. + */ - HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo; - spin_unlock_irqrestore(&aha1542_lock, flags); + aha1542->aha1542_last_mbo_used = mbo; - any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo])); /* This gets trashed for some reason */ + /* This gets trashed for some reason */ + any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); memset(&ccb[mbo], 0, sizeof(struct ccb)); @@ -1270,92 +907,62 @@ static int aha1542_dev_reset(Scsi_Cmnd * SCpnt) ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; ccb[mbo].commlinkid = 0; - /* - * Now tell the 1542 to flush all pending commands for this - * target + /* + * Now tell the 1542 to flush all pending commands for this + * target */ - aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1); + aha1542_outb(sh->io_port, CMD_START_SCSI); + spin_unlock_irqrestore(sh->host_lock, flags); - scmd_printk(KERN_WARNING, SCpnt, + scmd_printk(KERN_WARNING, cmd, "Trying device reset for target\n"); return SUCCESS; - - -#ifdef ERIC_neverdef - /* - * With the 1542 we apparently never get an interrupt to - * acknowledge a device reset being sent. Then again, Leonard - * says we are doing this wrong in the first place... - * - * Take a wait and see attitude. If we get spurious interrupts, - * then the device reset is doing something sane and useful, and - * we will wait for the interrupt to post completion. - */ - printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target); - - /* - * Free the command block for all commands running on this - * target... - */ - for (i = 0; i < AHA1542_MAILBOXES; i++) { - if (HOSTDATA(SCpnt->host)->SCint[i] && - HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; - } - } - return SUCCESS; - - return FAILED; -#endif /* ERIC_neverdef */ } -static int aha1542_bus_reset(Scsi_Cmnd * SCpnt) +static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd) { + struct Scsi_Host *sh = cmd->device->host; + struct aha1542_hostdata *aha1542 = shost_priv(sh); + unsigned long flags; int i; - /* + spin_lock_irqsave(sh->host_lock, flags); + /* * This does a scsi reset for all devices on the bus. * In principle, we could also reset the 1542 - should * we do this? Try this first, and we can add that later * if it turns out to be useful. */ - outb(SCRST, CONTROL(SCpnt->device->host->io_port)); + outb(reset_cmd, CONTROL(cmd->device->host->io_port)); + + if (!wait_mask(STATUS(cmd->device->host->io_port), + STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) { + spin_unlock_irqrestore(sh->host_lock, flags); + return FAILED; + } /* - * Wait for the thing to settle down a bit. Unfortunately - * this is going to basically lock up the machine while we - * wait for this to complete. To be 100% correct, we need to - * check for timeout, and if we are doing something like this - * we are pretty desperate anyways. + * We need to do this too before the 1542 can interact with + * us again after host reset. */ - ssleep(4); - - spin_lock_irq(SCpnt->device->host->host_lock); - - WAIT(STATUS(SCpnt->device->host->io_port), - STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); + if (reset_cmd & HRST) + setup_mailboxes(cmd->device->host); /* * Now try to pick up the pieces. For all pending commands, * free any internal data structures, and basically clear things - * out. We do not try and restart any commands or anything - + * out. We do not try and restart any commands or anything - * the strategy handler takes care of that crap. */ - printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no); + shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no); for (i = 0; i < AHA1542_MAILBOXES; i++) { - if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i]; - + if (aha1542->int_cmds[i] != NULL) { + struct scsi_cmnd *tmp_cmd; + tmp_cmd = aha1542->int_cmds[i]; - if (SCtmp->device->soft_reset) { + if (tmp_cmd->device->soft_reset) { /* * If this device implements the soft reset option, * then it is still holding onto the command, and @@ -1364,319 +971,200 @@ static int aha1542_bus_reset(Scsi_Cmnd * SCpnt) */ continue; } - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - HOSTDATA(SCpnt->device->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->device->host)->mb[i].status = 0; + aha1542_free_cmd(tmp_cmd); + aha1542->int_cmds[i] = NULL; + aha1542->mb[i].status = 0; } } - spin_unlock_irq(SCpnt->device->host->host_lock); + spin_unlock_irqrestore(sh->host_lock, flags); return SUCCESS; - -fail: - spin_unlock_irq(SCpnt->device->host->host_lock); - return FAILED; } -static int aha1542_host_reset(Scsi_Cmnd * SCpnt) +static int aha1542_bus_reset(struct scsi_cmnd *cmd) { - int i; - - /* - * This does a scsi reset for all devices on the bus. - * In principle, we could also reset the 1542 - should - * we do this? Try this first, and we can add that later - * if it turns out to be useful. - */ - outb(HRST | SCRST, CONTROL(SCpnt->device->host->io_port)); - - /* - * Wait for the thing to settle down a bit. Unfortunately - * this is going to basically lock up the machine while we - * wait for this to complete. To be 100% correct, we need to - * check for timeout, and if we are doing something like this - * we are pretty desperate anyways. - */ - ssleep(4); - spin_lock_irq(SCpnt->device->host->host_lock); + return aha1542_reset(cmd, SCRST); +} - WAIT(STATUS(SCpnt->device->host->io_port), - STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); +static int aha1542_host_reset(struct scsi_cmnd *cmd) +{ + return aha1542_reset(cmd, HRST | SCRST); +} - /* - * We need to do this too before the 1542 can interact with - * us again. - */ - setup_mailboxes(SCpnt->device->host->io_port, SCpnt->device->host); +static int aha1542_biosparam(struct scsi_device *sdev, + struct gendisk *unused, sector_t capacity, int geom[]) +{ + struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); - /* - * Now try to pick up the pieces. For all pending commands, - * free any internal data structures, and basically clear things - * out. We do not try and restart any commands or anything - - * the strategy handler takes care of that crap. - */ - printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no); + if (capacity >= 0x200000 && + aha1542->bios_translation == BIOS_TRANSLATION_25563) { + /* Please verify that this is the same as what DOS returns */ + geom[0] = 255; /* heads */ + geom[1] = 63; /* sectors */ + } else { + geom[0] = 64; /* heads */ + geom[1] = 32; /* sectors */ + } + geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */ - for (i = 0; i < AHA1542_MAILBOXES; i++) { - if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i]; + return 0; +} - if (SCtmp->device->soft_reset) { - /* - * If this device implements the soft reset option, - * then it is still holding onto the command, and - * may yet complete it. In this case, we don't - * flush the data. - */ - continue; - } - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - HOSTDATA(SCpnt->device->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->device->host)->mb[i].status = 0; - } - } +MODULE_DESCRIPTION("Adaptec AHA-1542 SCSI host adapter driver"); +MODULE_LICENSE("GPL"); - spin_unlock_irq(SCpnt->device->host->host_lock); - return SUCCESS; +static int aha1542_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) +{ + struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); -fail: - spin_unlock_irq(SCpnt->device->host->host_lock); - return FAILED; + acmd->data_buffer = dma_alloc_coherent(shost->dma_dev, + SECTOR_SIZE * AHA1542_MAX_SECTORS, + &acmd->data_buffer_handle, GFP_KERNEL); + if (!acmd->data_buffer) + return -ENOMEM; + return 0; } -#if 0 -/* - * These are the old error handling routines. They are only temporarily - * here while we play with the new error handling code. - */ -static int aha1542_old_abort(Scsi_Cmnd * SCpnt) +static int aha1542_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) { -#if 0 - unchar ahacmd = CMD_START_SCSI; - unsigned long flags; - struct mailbox *mb; - int mbi, mbo, i; + struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); - printk(KERN_DEBUG "In aha1542_abort: %x %x\n", - inb(STATUS(SCpnt->host->io_port)), - inb(INTRFLAGS(SCpnt->host->io_port))); + dma_free_coherent(shost->dma_dev, SECTOR_SIZE * AHA1542_MAX_SECTORS, + acmd->data_buffer, acmd->data_buffer_handle); + return 0; +} - spin_lock_irqsave(&aha1542_lock, flags); - mb = HOSTDATA(SCpnt->host)->mb; - mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1; - if (mbi >= 2 * AHA1542_MAILBOXES) - mbi = AHA1542_MAILBOXES; +static const struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .proc_name = "aha1542", + .name = "Adaptec 1542", + .cmd_size = sizeof(struct aha1542_cmd), + .queuecommand = aha1542_queuecommand, + .eh_device_reset_handler= aha1542_dev_reset, + .eh_bus_reset_handler = aha1542_bus_reset, + .eh_host_reset_handler = aha1542_host_reset, + .bios_param = aha1542_biosparam, + .init_cmd_priv = aha1542_init_cmd_priv, + .exit_cmd_priv = aha1542_exit_cmd_priv, + .can_queue = AHA1542_MAILBOXES, + .this_id = 7, + .max_sectors = AHA1542_MAX_SECTORS, + .sg_tablesize = SG_ALL, +}; - do { - if (mb[mbi].status != 0) - break; - mbi++; - if (mbi >= 2 * AHA1542_MAILBOXES) - mbi = AHA1542_MAILBOXES; - } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used); - spin_unlock_irqrestore(&aha1542_lock, flags); +static int aha1542_isa_match(struct device *pdev, unsigned int ndev) +{ + struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev); - if (mb[mbi].status) { - printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n", - SCpnt->host->irq); - aha1542_intr_handle(SCpnt->host, NULL); + if (!sh) return 0; - } - /* OK, no lost interrupt. Try looking to see how many pending commands - we think we have. */ - - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i]) { - if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { - printk(KERN_ERR "Timed out command pending for %s\n", - SCpnt->request->rq_disk ? - SCpnt->request->rq_disk->disk_name : "?" - ); - if (HOSTDATA(SCpnt->host)->mb[i].status) { - printk(KERN_ERR "OGMB still full - restarting\n"); - aha1542_out(SCpnt->host->io_port, &ahacmd, 1); - }; - } else - printk(KERN_ERR "Other pending command %s\n", - SCpnt->request->rq_disk ? - SCpnt->request->rq_disk->disk_name : "?" - ); - } -#endif - DEB(printk("aha1542_abort\n")); -#if 0 - spin_lock_irqsave(&aha1542_lock, flags); - for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) { - if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) { - mb[mbo].status = 2; /* Abort command */ - aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */ - spin_unlock_irqrestore(&aha1542_lock, flags); - break; - } - } - if (AHA1542_MAILBOXES == mbo) - spin_unlock_irqrestore(&aha1542_lock, flags); -#endif - return SCSI_ABORT_SNOOZE; + dev_set_drvdata(pdev, sh); + return 1; +} + +static void aha1542_isa_remove(struct device *pdev, + unsigned int ndev) +{ + aha1542_release(dev_get_drvdata(pdev)); + dev_set_drvdata(pdev, NULL); } -/* We do not implement a reset function here, but the upper level code - assumes that it will get some kind of response for the command in - SCpnt. We must oblige, or the command will hang the scsi system. - For a first go, we assume that the 1542 notifies us with all of the - pending commands (it does implement soft reset, after all). */ +static struct isa_driver aha1542_isa_driver = { + .match = aha1542_isa_match, + .remove = aha1542_isa_remove, + .driver = { + .name = "aha1542" + }, +}; +static int isa_registered; + +#ifdef CONFIG_PNP +static const struct pnp_device_id aha1542_pnp_ids[] = { + { .id = "ADP1542" }, + { .id = "" } +}; +MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids); -static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id) { - unchar ahacmd = CMD_START_SCSI; - int i; + int indx; + struct Scsi_Host *sh; - /* - * See if a bus reset was suggested. - */ - if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) { - /* - * This does a scsi reset for all devices on the bus. - * In principle, we could also reset the 1542 - should - * we do this? Try this first, and we can add that later - * if it turns out to be useful. - */ - outb(HRST | SCRST, CONTROL(SCpnt->host->io_port)); + for (indx = 0; indx < ARRAY_SIZE(io); indx++) { + if (io[indx]) + continue; - /* - * Wait for the thing to settle down a bit. Unfortunately - * this is going to basically lock up the machine while we - * wait for this to complete. To be 100% correct, we need to - * check for timeout, and if we are doing something like this - * we are pretty desperate anyways. - */ - WAIT(STATUS(SCpnt->host->io_port), - STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); + if (pnp_activate_dev(pdev) < 0) + continue; - /* - * We need to do this too before the 1542 can interact with - * us again. - */ - setup_mailboxes(SCpnt->host->io_port, SCpnt->host); + io[indx] = pnp_port_start(pdev, 0); /* - * Now try to pick up the pieces. Restart all commands - * that are currently active on the bus, and reset all of - * the datastructures. We have some time to kill while - * things settle down, so print a nice message. - */ - printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no); - - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - SCtmp->result = DID_RESET << 16; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); - SCtmp->scsi_done(SCpnt); - - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; - } - /* - * Now tell the mid-level code what we did here. Since - * we have restarted all of the outstanding commands, - * then report SUCCESS. + * The card can be queried for its DMA, we have + * the DMA set up that is enough */ - return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); -fail: - printk(KERN_CRIT "aha1542.c: Unable to perform hard reset.\n"); - printk(KERN_CRIT "Power cycle machine to reset\n"); - return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET); - - } else { - /* This does a selective reset of just the one device */ - /* First locate the ccb for this command */ - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { - HOSTDATA(SCpnt->host)->ccb[i].op = 0x81; /* BUS DEVICE RESET */ - /* Now tell the 1542 to flush all pending commands for this target */ - aha1542_out(SCpnt->host->io_port, &ahacmd, 1); - - /* Here is the tricky part. What to do next. Do we get an interrupt - for the commands that we aborted with the specified target, or - do we generate this on our own? Try it without first and see - what happens */ - printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target); - - /* If the first does not work, then try the second. I think the - first option is more likely to be correct. Free the command - block for all commands running on this target... */ - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i] && - HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - SCtmp->result = DID_RESET << 16; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); - SCtmp->scsi_done(SCpnt); - - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; - } - return SCSI_RESET_SUCCESS; - } + dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]); } - /* No active command at this time, so this means that each time we got - some kind of response the last time through. Tell the mid-level code - to request sense information in order to decide what to do next. */ - return SCSI_RESET_PUNT; + + sh = aha1542_hw_init(&driver_template, &pdev->dev, indx); + if (!sh) + return -ENODEV; + + pnp_set_drvdata(pdev, sh); + return 0; } -#endif /* end of big comment block around old_abort + old_reset */ -static int aha1542_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *ip) +static void aha1542_pnp_remove(struct pnp_dev *pdev) { - int translation_algorithm; - int size = capacity; + aha1542_release(pnp_get_drvdata(pdev)); + pnp_set_drvdata(pdev, NULL); +} - translation_algorithm = HOSTDATA(sdev->host)->bios_translation; +static struct pnp_driver aha1542_pnp_driver = { + .name = "aha1542", + .id_table = aha1542_pnp_ids, + .probe = aha1542_pnp_probe, + .remove = aha1542_pnp_remove, +}; +static int pnp_registered; +#endif /* CONFIG_PNP */ - if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) { - /* Please verify that this is the same as what DOS returns */ - ip[0] = 255; - ip[1] = 63; - ip[2] = size / 255 / 63; - } else { - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; +static int __init aha1542_init(void) +{ + int ret = 0; + +#ifdef CONFIG_PNP + if (isapnp) { + ret = pnp_register_driver(&aha1542_pnp_driver); + if (!ret) + pnp_registered = 1; } +#endif + ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS); + if (!ret) + isa_registered = 1; - return 0; +#ifdef CONFIG_PNP + if (pnp_registered) + ret = 0; +#endif + if (isa_registered) + ret = 0; + + return ret; } -MODULE_LICENSE("GPL"); +static void __exit aha1542_exit(void) +{ +#ifdef CONFIG_PNP + if (pnp_registered) + pnp_unregister_driver(&aha1542_pnp_driver); +#endif + if (isa_registered) + isa_unregister_driver(&aha1542_isa_driver); +} -static struct scsi_host_template driver_template = { - .proc_name = "aha1542", - .name = "Adaptec 1542", - .detect = aha1542_detect, - .release = aha1542_release, - .queuecommand = aha1542_queuecommand, - .eh_device_reset_handler= aha1542_dev_reset, - .eh_bus_reset_handler = aha1542_bus_reset, - .eh_host_reset_handler = aha1542_host_reset, - .bios_param = aha1542_biosparam, - .can_queue = AHA1542_MAILBOXES, - .this_id = 7, - .sg_tablesize = AHA1542_SCATTER, - .cmd_per_lun = AHA1542_CMDLUN, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; -#include "scsi_module.c" +module_init(aha1542_init); +module_exit(aha1542_exit); |
