patch-1.3.42 linux/drivers/scsi/buslogic.c

Next file: linux/drivers/scsi/buslogic.h
Previous file: linux/drivers/scsi/README.BusLogic
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.41/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c
@@ -1,1574 +0,0 @@
-/*
- *	buslogic.c	Copyright (C) 1993, 1994 David B. Gentzel
- *	Low-level scsi driver for BusLogic adapters
- *	by David B. Gentzel, Whitfield Software Services, Carnegie, PA
- *	    (gentzel@nova.enet.dec.com)
- *	Thanks to BusLogic for providing the necessary documentation
- *
- *	The original version of this driver was derived from aha1542.[ch],
- *	which is Copyright (C) 1992 Tommy Thorn.  Much has been reworked, but
- *	most of basic structure and substantial chunks of code still remain.
- *
- *	Furthermore, many subsequent fixes and improvements to the aha1542
- *	driver have been folded back into this driver.  These changes to
- *	aha1542.[ch] are Copyright (C) 1993, 1994 Eric Youngdale.
- *
- *	Thanks to the following individuals who have made contributions (of
- *	(code, information, support, or testing) to this driver:
- *		Eric Youngdale		Leonard Zubkoff
- *		Tomas Hurka		Andrew Walker
- */
-
-/*
- * TODO:
- *	1. Clean up error handling & reporting.
- *	2. Find out why scatter/gather is limited to 16 requests per command.
- *	3. Test/improve/fix abort & reset functions.
- *	4. Look at command linking.
- *	5. Allow multiple boards to share an IRQ if the bus allows (EISA, MCA,
- *	   and PCI).
- *	6. Avoid using the 445S workaround for board revs >= D.
- */
-
-/*
- * NOTES:
- *    BusLogic (formerly BusTek) manufactures an extensive family of
- *    intelligent, high performance SCSI-2 host adapters.  They all support
- *    command queueing and scatter/gather I/O.  Most importantly, they all
- *    support identical programming interfaces, so a single driver can be used
- *    for all boards.
- *
- *    Actually, they all support TWO identical programming interfaces!  They
- *    have an Adaptec 154x compatible interface (complete with 24 bit
- *    addresses) as well as a "native" 32 bit interface.  As such, the Linux
- *    aha1542 driver can be used to drive them, but with less than optimal
- *    performance (at least for the EISA, VESA, and MCA boards).
- *
- *    Here is the scoop on the various models:
- *	BT-542B - ISA first-party DMA with floppy support.
- *	BT-545S - 542B + FAST SCSI and active termination.
- *	BT-545D - 545S + differential termination.
- *	BT-640A - MCA bus-master with floppy support.
- *	BT-646S - 640A + FAST SCSI and active termination.
- *	BT-646D - 646S + differential termination.
- *	BT-742A - EISA bus-master with floppy support.
- *	BT-747S - 742A + FAST SCSI, active termination, and 2.88M floppy.
- *	BT-747D - 747S + differential termination.
- *	BT-757S - 747S + WIDE SCSI.
- *	BT-757D - 747D + WIDE SCSI.
- *	BT-445S - VESA bus-master FAST SCSI with active termination
- *		  and floppy support.
- *	BT-445C - 445S + enhanced BIOS & firmware options.
- *	BT-946C - PCI bus-master FAST SCSI.
- *	BT-956C - PCI bus-master FAST/WIDE SCSI.
- *
- *    ??? I believe other boards besides the 445 now have a "C" model, but I
- *    have no facts on them.
- *
- *    This driver SHOULD support all of these boards.  It has only been tested
- *    with a 747S, 445S, 946C, and 956C; there is no PCI-specific support as
- *    yet.
- *
- *    Should you require further information on any of these boards, BusLogic
- *    can be reached at (408)492-9090.  Their BBS # is (408)492-1984 (maybe BBS
- *    stands for "Big Brother System"?).
- *
- *    Places flagged with a triple question-mark are things which are either
- *    unfinished, questionable, or wrong.
- */
-
-#ifdef MODULE
-#include <linux/module.h>
-#endif
-
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/head.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/config.h>
-#include <linux/proc_fs.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/dma.h>
-
-#include <linux/blk.h>
-#include "scsi.h"
-#include "hosts.h"
-#include "sd.h"
-#define BUSLOGIC_PRIVATE_H	/* Get the "private" stuff */
-#include "buslogic.h"
-
-#ifndef BUSLOGIC_DEBUG
-# define BUSLOGIC_DEBUG 0
-#endif
-
-#include<linux/stat.h>
-
-struct proc_dir_entry proc_scsi_buslogic = {
-    PROC_SCSI_BUSLOGIC, 8, "buslogic",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-
-/* ??? Until kmalloc actually implements GFP_DMA, we can't depend on it... */
-#undef GFP_DMA
-
-/* If different port addresses are needed (e.g. to install more than two
-   cards), you must define BUSLOGIC_PORT_OVERRIDE to be a comma-separated list
-   of the addresses which will be checked.  This can also be used to resolve a
-   conflict if the port-probing at a standard port causes problems with
-   another board. */
-/* #define BUSLOGIC_PORT_OVERRIDE 0x330, 0x334, 0x130, 0x134, 0x230, 0x234 */
-
-/* Define this to be either BIOS_TRANSLATION_DEFAULT or BIOS_TRANSLATION_BIG
-   if you wish to bypass the test for this, which uses an undocumented port.
-   The test is believed to fail on at least some AMI BusLogic clones. */
-/* #define BIOS_TRANSLATION_OVERRIDE BIOS_TRANSLATION_BIG */
-
-#define BUSLOGIC_VERSION "1.15"
-
-/* Not a random value - if this is too large, the system hangs for a long time
-   waiting for something to happen if a board is not installed. */
-/* ??? I don't really like this as it will wait longer on slow machines.
-   Perhaps we should base this on the loops_per_second "Bogomips" value? */
-#define WAITNEXTTIMEOUT 3000000
-
-/* This is for the scsi_malloc call in buslogic_queuecommand. */
-/* ??? I'd up this to 4096, but would we be in danger of using up the
-   scsi_malloc memory pool? */
-/* This could be a concern, I guess.  It may be possible to fix things so that
-   the table generated in sd.c is compatible with the low-level code, but
-   don't hold your breath.  -ERY */
-#define BUSLOGIC_SG_MALLOC 512
-
-/* Since the SG list is malloced, we have to limit the length. */
-#define BUSLOGIC_MAX_SG (BUSLOGIC_SG_MALLOC / sizeof (struct chain))
-
-/* Since the host adapters have room to buffer 32 commands internally, there
-   is some virtue in setting BUSLOGIC_MAILBOXES to 32.  The maximum value
-   appears to be 255, since the Count parameter to the Initialize Extended
-   Mailbox command is limited to one byte. */
-#define BUSLOGIC_MAILBOXES 32
-
-#define BUSLOGIC_CMDLUN 4	/* Arbitrary, but seems to work well. */
-
-/* BusLogic boards can be configured for quite a number of port addresses (six
-   to be exact), but I generally do not want the driver poking around at
-   random.  We allow two port addresses - this allows people to use a BusLogic
-   with a MIDI card, which frequently also uses 0x330.
-
-   This can also be overridden on the command line to the kernel, via LILO or
-   LOADLIN. */
-static unsigned short bases[7] = {
-#ifdef BUSLOGIC_PORT_OVERRIDE
-    BUSLOGIC_PORT_OVERRIDE,
-#else
-    0x330, 0x334, /* 0x130, 0x134, 0x230, 0x234, */
-#endif
-    0
-};
-
-#define BIOS_TRANSLATION_DEFAULT 0	/* Default case */
-#define BIOS_TRANSLATION_BIG 1		/* Big disk (> 1G) case */
-
-struct hostdata {
-    unsigned int bus_type;
-    unsigned int bios_translation: 1;	/* BIOS mapping (for compatibility) */
-    int last_mbi_used;
-    int last_mbo_used;
-    char model[7];
-    char firmware_rev[6];
-    Scsi_Cmnd *sc[BUSLOGIC_MAILBOXES];
-    struct mailbox mb[2 * BUSLOGIC_MAILBOXES];
-    struct ccb ccbs[BUSLOGIC_MAILBOXES];
-};
-
-#define HOSTDATA(host) ((struct hostdata *)&(host)->hostdata)
-
-/* One for each IRQ level (9-15), although 13 will never be used. */
-static struct Scsi_Host *host[7] = { NULL, };
-
-static int setup_mailboxes(unsigned int base, struct Scsi_Host *shpnt);
-static int restart(struct Scsi_Host *shpnt);
-
-#define INTR_RESET(base) outb(RINT, CONTROL(base))
-
-#define buslogic_printk buslogic_prefix(__PRETTY_FUNCTION__),printk
-
-#if defined(MODULE) && !defined(GFP_DMA)
-# define CHECK_DMA_ADDR(isa, addr, badstmt) \
-    do { if ((isa) && ((const void *)addr) > (const void *)ISA_DMA_THRESHOLD) badstmt; } while (0)
-#else
-# define CHECK_DMA_ADDR(isa, addr, badstmt)
-#endif
-
-#define CHECK(cond) if (cond) ; else goto fail
-
-#define WAIT(port, allof, noneof) \
-    CHECK(wait(port, allof, noneof, WAITNEXTTIMEOUT, FALSE))
-#define WAIT_WHILE(port, mask) WAIT(port, 0, mask)
-#define WAIT_UNTIL(port, mask) WAIT(port, mask, 0)
-#define WAIT_FAST(port, allof, noneof) \
-    CHECK(wait(port, allof, noneof, 100, TRUE))
-#define WAIT_WHILE_FAST(port, mask) WAIT_FAST(port, 0, mask)
-#define WAIT_UNTIL_FAST(port, mask) WAIT_FAST(port, mask, 0)
-
-/* If delay != 0, we use the udelay call to regulate the amount of time we
-   wait.
-
-   This is inline as it is always called with constant arguments and hence
-   will be very well optimized. */
-static __inline__ int wait(unsigned short port,
-			   unsigned char allof, unsigned char noneof,
-			   unsigned int timeout, int delay)
-{
-    int bits;
-
-    for (;;) {
-	bits = inb(port);
-	if ((bits & allof) == allof && (bits & noneof) == 0)
-	    return TRUE;
-	if (delay)
-	    udelay(1000);
-	if (--timeout == 0)
-	    return FALSE;
-    }
-}
-
-static void buslogic_prefix(const char *func)
-{
-    printk("BusLogic SCSI: %s: ", func);
-}
-
-static void buslogic_stat(unsigned int base)
-{
-    int s = inb(STATUS(base)), i = inb(INTERRUPT(base));
-
-    buslogic_printk("status=%02X intrflags=%02X\n", s, i);
-}
-
-/* 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 buslogic_out(unsigned int base, const unsigned char *cmdp,
-			size_t len)
-{
-    unsigned long flags = 0;
-    
-    if (len == 1) {
-	for (;;) {
-	    WAIT_WHILE(STATUS(base), CPRBSY);
-	    save_flags(flags);
-	    cli();
-	    if (!(inb(STATUS(base)) & CPRBSY)) {
-		outb(*cmdp, COMMAND_PARAMETER(base));
-		restore_flags(flags);
-		return FALSE;
-	    }
-	    restore_flags(flags);
-	}
-    } else {
-	save_flags(flags);
-	cli();
-	while (len--) {
-	    WAIT_WHILE(STATUS(base), CPRBSY);
-	    outb(*cmdp++, COMMAND_PARAMETER(base));
-	}
-	restore_flags(flags);
-    }
-    return FALSE;
-  fail:
-    restore_flags(flags);
-    buslogic_printk("failed(%u): ", len + 1);
-    buslogic_stat(base);
-    return TRUE;
-}
-
-/* Only used at boot time, so we do not need to worry about latency as much
-   here.  This waits a very short period of time.  We use this if we are not
-   sure whether the board will respond to the command we just sent. */
-static int buslogic_in(unsigned int base, unsigned char *cmdp, size_t len)
-{
-    unsigned long flags;
-    
-    save_flags(flags);
-    cli();
-    while (len--) {
-	WAIT_UNTIL_FAST(STATUS(base), DIRRDY);
-	*cmdp++ = inb(DATA_IN(base));
-    }
-    restore_flags(flags);
-    return FALSE;
-  fail:
-    restore_flags(flags);
-#if (BUSLOGIC_DEBUG & BD_IO)
-    buslogic_printk("failed(%u): ", len + 1);
-    buslogic_stat(base);
-#endif
-    return TRUE;
-}
-
-static unsigned int makecode(unsigned int haerr, unsigned int scsierr)
-{
-    unsigned int hosterr;
-    const char *errstr = NULL;
-#if (BUSLOGIC_DEBUG & BD_ERRORS) && defined(CONFIG_SCSI_CONSTANTS)
-    static const char *const buslogic_status[] = {
-    /* 00 */	"Command completed normally",
-    /* 01-07 */	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    /* 08-09 */	NULL, NULL,
-    /* 0A */	"Linked command completed normally",
-    /* 0B */	"Linked command completed normally, interrupt generated",
-    /* 0C-0F */	NULL, NULL, NULL, NULL,
-    /* 10 */	NULL,
-    /* 11 */	"Selection timed out",
-    /* 12 */	"Data overrun/underrun",
-    /* 13 */	"Unexpected bus free",
-    /* 14 */	"Target bus phase sequence failure",
-    /* 15 */	"First byte of outgoing MB was invalid",
-    /* 16 */	"Invalid CCB Operation Code",
-    /* 17 */	"Linked CCB does not have the same LUN",
-    /* 18 */	"Invalid Target Direction received from Host",
-    /* 19 */	"Duplicate CCB Received in Target Mode",
-    /* 1A */	"Invalid CCB or Segment List Parameter",
-    /* 1B */	"Auto request sense failed",
-    /* 1C */	"SCSI-2 tagged queueing message was rejected by the target",
-    /* 1D-1F */	NULL, NULL, NULL,
-    /* 20 */	"Host adapter hardware failure",
-    /* 21 */	"Target did not respond to SCSI ATN and the HA SCSI bus reset",
-    /* 22 */	"Host adapter asserted a SCSI bus reset",
-    /* 23 */	"Other SCSI devices asserted a SCSI bus reset",
-    };
-#endif
-
-    switch (haerr) {
-      case 0x00:	/* Normal completion. */
-      case 0x0A:	/* Linked command complete without error and linked
-			   normally. */
-      case 0x0B:	/* Linked command complete without error, interrupt
-			   generated. */
-	hosterr = DID_OK;
-	break;
-
-      case 0x11:	/* Selection time out: the initiator selection or
-			   target reselection was not complete within the SCSI
-			   time out period. */
-	hosterr = DID_TIME_OUT;
-	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 RSTS
-			   interrupt. */
-      case 0x21:	/* The target did not respond to SCSI ATN and the host
-			   adapter consequently issued a SCSI bus reset to
-			   clear up the failure. */
-      case 0x22:	/* The host adapter asserted a SCSI bus reset. */
-	hosterr = DID_RESET;
-	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. */
-      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 MB was 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. */
-      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. */
-      case 0x18:	/* Invalid Target Direction received from Host - The
-			   direction of a 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. */
-      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. */
-      case 0x1B:	/* Auto request sense failed. */
-      case 0x1C:	/* SCSI-2 tagged queueing message was rejected by the
-			   target. */
-      case 0x20:	/* The host adapter hardware failed. */
-      case 0x23:	/* Other SCSI devices asserted a SCSI bus reset. */
-	hosterr = DID_ERROR;	/* ??? Couldn't find any better. */
-	break;
-
-      default:
-#ifndef CONFIG_SCSI_CONSTANTS
-	errstr = "unknown hoststatus";
-#endif
-	hosterr = DID_ERROR;
-	break;
-    }
-#if (BUSLOGIC_DEBUG & BD_ERRORS)
-# ifdef CONFIG_SCSI_CONSTANTS
-    if (hosterr != DID_OK) {
-	if (haerr < ARRAY_SIZE(buslogic_status))
-	    errstr = buslogic_status[haerr];
-	if (errstr == NULL)
-	    errstr = "unknown hoststatus";
-    }
-# else
-    if (hosterr == DID_ERROR)
-	errstr = "";
-# endif
-#endif
-    if (errstr != NULL)
-	buslogic_printk("%s (%02X)\n", errstr, haerr);
-    return (hosterr << 16) | scsierr;
-}
-
-/* ??? this should really be "const struct Scsi_Host *" */
-const char *buslogic_info(struct Scsi_Host *shpnt)
-{
-    return "BusLogic SCSI driver " BUSLOGIC_VERSION;
-}
-
-/*
-  This is a major rewrite of the interrupt handler to support the newer
-  and faster PCI cards.  While the previous interrupt handler was supposed
-  to handle multiple incoming becoming available mailboxes during the same
-  interrupt, my testing showed that in practice only a single mailbox was
-  ever made available.  With the 946C and 956C, multiple incoming mailboxes
-  being ready for processing during a single interrupt occurs much more
-  frequently, and so care must be taken to avoid race conditions managing
-  the Host Adapter Interrupt Register, which can lead to lost interrupts.
-
-  Leonard N. Zubkoff, 23-Mar-95
-*/
-
-static void buslogic_interrupt(int irq, struct pt_regs * regs)
-{
-    int mbi, saved_mbo[BUSLOGIC_MAILBOXES];
-    int base, interrupt_flags, found, i;
-    struct Scsi_Host *shpnt;
-    Scsi_Cmnd *sctmp;
-    struct mailbox *mb;
-    struct ccb *ccb;
-
-    shpnt = host[irq - 9];
-    if (shpnt == NULL)
-      panic("buslogic_interrupt: NULL SCSI host entry");
-
-    mb = HOSTDATA(shpnt)->mb;
-    ccb = HOSTDATA(shpnt)->ccbs;
-    base = shpnt->io_port;
-
-    /*
-      This interrupt handler is now specified to use the SA_INTERRUPT
-      protocol, so interrupts are inhibited on entry until explicitly
-      allowed again.  Read the Host Adapter Interrupt Register, and
-      complain if there is no pending interrupt being signaled.
-    */
-
-    interrupt_flags = inb(INTERRUPT(base));
-
-    if (!(interrupt_flags & INTV))
-      buslogic_printk("interrupt received, but INTV not set\n");
-
-    /*
-      Reset the Host Adapter Interrupt Register.  It appears to be
-      important that this is only done once per interrupt to avoid
-      losing interrupts under heavy loads.
-    */
-
-    INTR_RESET(base);
-
-    if (interrupt_flags & RSTS)
-      {
-	restart(shpnt);
-	return;
-      }
-
-    /*
-      With interrupts still inhibited, scan through the incoming mailboxes
-      in strict round robin fashion saving the status information and
-      then freeing the mailbox.  A second pass over the completed commands
-      will be made separately to complete their processing.
-    */
-
-    mbi = HOSTDATA(shpnt)->last_mbi_used + 1;
-    if (mbi >= 2*BUSLOGIC_MAILBOXES)
-      mbi = BUSLOGIC_MAILBOXES;
-
-    found = 0;
-
-    while (mb[mbi].status != MBX_NOT_IN_USE && found < BUSLOGIC_MAILBOXES)
-      {
-	int mbo = (struct ccb *)mb[mbi].ccbptr - ccb;
-
-	sctmp = HOSTDATA(shpnt)->sc[mbo];
-
-	/*
-	  If sctmp has become NULL, higher level code must have aborted
-	  this operation and called the necessary completion routine.
-	*/
-
-	if (sctmp != NULL && mb[mbi].status != MBX_COMPLETION_NOT_FOUND)
-	  {
-	    int result = 0;
-
-	    saved_mbo[found++] = mbo;
-
-	    if (mb[mbi].status != MBX_COMPLETION_OK)
-	      result = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
-
-	    sctmp->result = result;
-
-	    mb[mbi].status = MBX_NOT_IN_USE;
-	  }
-
-	HOSTDATA(shpnt)->last_mbi_used = mbi;
-
-	if (++mbi >= 2*BUSLOGIC_MAILBOXES)
-	  mbi = BUSLOGIC_MAILBOXES;
-      }
-
-    /*
-      With interrupts no longer inhibited, iterate over the completed
-      commands freeing resources and calling the completion routines.
-      Since we exit upon completion of this loop, there is no need to
-      inhibit interrupts before exit, as this will be handled by the
-      fast interrupt assembly code we return to.
-    */
-
-    sti();
-
-    for (i = 0; i < found; i++)
-      {
-	int mbo = saved_mbo[i];
-	sctmp = HOSTDATA(shpnt)->sc[mbo];
-	if (sctmp == NULL) continue;
-	/*
-	  First, free any storage allocated for a scatter/gather
-	  data segment list.
-	*/
-	if (sctmp->host_scribble)
-	  scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC);
-	/*
-	  Next, mark the SCSI Command as completed so it may be reused
-	  for another command by buslogic_queuecommand.  This also signals
-	  to buslogic_reset that the command is no longer active.
-	*/
-	HOSTDATA(shpnt)->sc[mbo] = NULL;
-	/*
-	  Finally, call the SCSI command completion handler.
-	*/
-	sctmp->scsi_done(sctmp);
-      }
-}
-
-
-/* ??? Why does queuecommand return a value?  scsi.c never looks at it... */
-int buslogic_queuecommand(Scsi_Cmnd *scpnt, void (*done)(Scsi_Cmnd *))
-{
-    static const unsigned char buscmd[] = { CMD_START_SCSI };
-    unsigned char direction;
-    unsigned char *cmd = (unsigned char *)scpnt->cmnd;
-    unsigned char target = scpnt->target;
-    unsigned char lun = scpnt->lun;
-    void *buff = scpnt->request_buffer;
-    int bufflen = scpnt->request_bufflen;
-    int mbo;
-    unsigned long flags;
-    struct Scsi_Host *shpnt = scpnt->host;
-    struct mailbox *mb = HOSTDATA(shpnt)->mb;
-    struct ccb *ccb;
-
-
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-    if (target > 1) {
-	scpnt->result = DID_TIME_OUT << 16;
-	done(scpnt);
-	return 0;
-    }
-#endif
-
-    if (*cmd == REQUEST_SENSE) {
-#if (BUSLOGIC_DEBUG & (BD_COMMAND | BD_ERRORS))
-	if (bufflen != sizeof scpnt->sense_buffer) {
-	    buslogic_printk("wrong buffer length supplied for request sense"
-			    " (%d).\n",
-			    bufflen);
-	}
-#endif
-	scpnt->result = 0;
-	done(scpnt);
-	return 0;
-    }
-
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-    {
-	int i;
-
-	if (*cmd == READ_10 || *cmd == WRITE_10
-	    || *cmd == READ_6 || *cmd == WRITE_6)
-	    i = *(int *)(cmd + 2);
-	else
-	    i = -1;
-	buslogic_printk("dev %d cmd %02X pos %d len %d ",
-			target, *cmd, i, bufflen);
-	buslogic_stat(shpnt->io_port);
-	buslogic_printk("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 */
-    }
-#endif
-
-    /* Use the outgoing mailboxes in a round-robin fashion, because this
-       is how the host adapter will scan for them. */
-
-    save_flags(flags);
-    cli();
-
-    mbo = HOSTDATA(shpnt)->last_mbo_used + 1;
-    if (mbo >= BUSLOGIC_MAILBOXES)
-	mbo = 0;
-
-    do {
-	if (mb[mbo].status == MBX_NOT_IN_USE
-	    && HOSTDATA(shpnt)->sc[mbo] == NULL)
-	    break;
-	mbo++;
-	if (mbo >= BUSLOGIC_MAILBOXES)
-	    mbo = 0;
-    } while (mbo != HOSTDATA(shpnt)->last_mbo_used);
-
-    if (mb[mbo].status != MBX_NOT_IN_USE || HOSTDATA(shpnt)->sc[mbo]) {
-	/* ??? Instead of failing, should we enable OMBR interrupts and sleep
-	   until we get one? */
-	restore_flags(flags);
-	buslogic_printk("unable to find empty mailbox.\n");
-	goto fail;
-    }
-
-    HOSTDATA(shpnt)->sc[mbo] = scpnt;		/* This will effectively
-						   prevent someone else from
-						   screwing with this cdb. */
-
-    HOSTDATA(shpnt)->last_mbo_used = mbo;
-
-    restore_flags(flags);
-
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-    buslogic_printk("sending command (%d %08X)...", mbo, done);
-#endif
-
-    ccb = &HOSTDATA(shpnt)->ccbs[mbo];
-
-    /* This gets trashed for some reason */
-    mb[mbo].ccbptr = ccb;
-
-    memset(ccb, 0, sizeof (struct ccb));
-
-    ccb->cdblen = scpnt->cmd_len;		/* SCSI Command Descriptor
-						   Block Length */
-
-    direction = 0;
-    if (*cmd == READ_10 || *cmd == READ_6)
-	direction = 8;
-    else if (*cmd == WRITE_10 || *cmd == WRITE_6)
-	direction = 16;
-
-    memcpy(ccb->cdb, cmd, ccb->cdblen);
-
-    if (scpnt->use_sg) {
-	struct scatterlist *sgpnt;
-	struct chain *cptr;
-	size_t i;
-
-	ccb->op = CCB_OP_INIT_SG;	/* SCSI Initiator Command
-					   w/scatter-gather */
-	scpnt->host_scribble
-	    = (unsigned char *)scsi_malloc(BUSLOGIC_SG_MALLOC);
-	if (scpnt->host_scribble == NULL) {
-	    buslogic_printk("unable to allocate DMA memory.\n");
-	    goto fail;
-	}
-	sgpnt = (struct scatterlist *)scpnt->request_buffer;
-	cptr = (struct chain *)scpnt->host_scribble;
-	if (scpnt->use_sg > shpnt->sg_tablesize) {
-	    buslogic_printk("bad segment list, %d > %d.\n",
-			    scpnt->use_sg, shpnt->sg_tablesize);
-	    goto fail;
-	}
-	for (i = 0; i < scpnt->use_sg; i++) {
-	    CHECK_DMA_ADDR(shpnt->unchecked_isa_dma, sgpnt[i].address,
-			   goto baddma);
-	    cptr[i].dataptr = sgpnt[i].address;
-	    cptr[i].datalen = sgpnt[i].length;
-	}
-	ccb->datalen = scpnt->use_sg * sizeof (struct chain);
-	ccb->dataptr = cptr;
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-	{
-	    unsigned char *ptr;
-
-	    buslogic_printk("cptr %08X:", cptr);
-	    ptr = (unsigned char *)cptr;
-	    for (i = 0; i < 18; i++)
-		printk(" %02X", ptr[i]);
-	    printk("\n");
-	}
-#endif
-    } else {
-	ccb->op = CCB_OP_INIT;	/* SCSI Initiator Command */
-	scpnt->host_scribble = NULL;
-	CHECK_DMA_ADDR(shpnt->unchecked_isa_dma, buff, goto baddma);
-	ccb->datalen = bufflen;
-	ccb->dataptr = buff;
-    }
-    ccb->id = target;
-    ccb->lun = lun;
-    ccb->dir = direction;
-    ccb->rsalen = sizeof scpnt->sense_buffer;
-    ccb->senseptr = scpnt->sense_buffer;
-    /* ccbcontrol, commlinkid, and linkptr are 0 due to above memset. */
-
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-    {
-	size_t i;
-
-	buslogic_printk("sending...");
-	for (i = 0; i < sizeof(struct ccb) - 10; i++)
-	    printk(" %02X", ((unsigned char *)ccb)[i]);
-	printk("\n");
-    }
-#endif
-
-    if (done) {
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-	buslogic_printk("now waiting for interrupt: ");
-	buslogic_stat(shpnt->io_port);
-#endif
-	scpnt->scsi_done = done;
-	mb[mbo].status = MBX_ACTION_START;
-	/* start scsi command */
-	buslogic_out(shpnt->io_port, buscmd, sizeof buscmd);
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-	buslogic_stat(shpnt->io_port);
-#endif
-    } else
-	buslogic_printk("done can't be NULL.\n");
-
-    while (0) {
-#if defined(MODULE) && !defined(GFP_DMA)
-      baddma:
-	buslogic_printk("address > 16MB used for ISA HA.\n");
-#endif
-      fail:
-	scpnt->result = DID_ERROR << 16;
-	done(scpnt);
-    }
-
-    return 0;
-}
-
-#if 0
-static void internal_done(Scsi_Cmnd *scpnt)
-{
-    scpnt->SCp.Status++;
-}
-
-int buslogic_command(Scsi_Cmnd *scpnt)
-{
-#if (BUSLOGIC_DEBUG & BD_COMMAND)
-    buslogic_printk("calling buslogic_queuecommand.\n");
-#endif
-
-    buslogic_queuecommand(scpnt, internal_done);
-
-    scpnt->SCp.Status = 0;
-    while (!scpnt->SCp.Status)
-	barrier();
-    return scpnt->result;
-}
-#endif
-
-/* Initialize mailboxes. */
-static int setup_mailboxes(unsigned int base, struct Scsi_Host *shpnt)
-{
-    size_t i;
-    int ok = FALSE;		/* Innocent until proven guilty... */
-    struct mailbox *mb = HOSTDATA(shpnt)->mb;
-    struct ccb *ccb = HOSTDATA(shpnt)->ccbs;
-    struct {
-	unsigned char cmd, count;
-	void *base PACKED;
-    } cmd = { CMD_INITEXTMB, BUSLOGIC_MAILBOXES, mb };
-
-    for (i = 0; i < BUSLOGIC_MAILBOXES; i++) {
-	mb[i].status = mb[BUSLOGIC_MAILBOXES + i].status = MBX_NOT_IN_USE;
-	mb[i].ccbptr = &ccb[i];
-    }
-    INTR_RESET(base);	/* reset interrupts, so they don't block */
-
-    if (buslogic_out(base, (unsigned char *)&cmd, sizeof cmd))
-	goto fail;
-    WAIT_UNTIL(INTERRUPT(base), CMDC);
-
-    ok = TRUE;
-
-    while (0) {
-      fail:
-	buslogic_printk("failed setting up mailboxes.\n");
-    }
-
-    INTR_RESET(base);
-
-    return !ok;
-}
-
-static int getconfig(unsigned int base, unsigned char *irq,
-		     unsigned char *dma, unsigned char *id,
-		     char *bus_type, unsigned short *max_sg,
-		     const unsigned char **bios)
-{
-    unsigned char inquiry_cmd[2];
-    unsigned char inquiry_result[4];
-    int i;
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-    buslogic_printk("called\n");
-#endif
-
-    i = inb(STATUS(base));
-    if (i & DIRRDY)
-	i = inb(DATA_IN(base));
-    inquiry_cmd[0] = CMD_RETCONF;
-    buslogic_out(base, inquiry_cmd, 1);
-    if (buslogic_in(base, inquiry_result, 3))
-	goto fail;
-    WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
-    INTR_RESET(base);
-    /* Defer using the DMA value until we know the bus type. */
-    *dma = inquiry_result[0];
-    switch (inquiry_result[1]) {
-      case 0x01:
-	*irq = 9;
-	break;
-      case 0x02:
-	*irq = 10;
-	break;
-      case 0x04:
-	*irq = 11;
-	break;
-      case 0x08:
-	*irq = 12;
-	break;
-      case 0x20:
-	*irq = 14;
-	break;
-      case 0x40:
-	*irq = 15;
-	break;
-      default:
-	buslogic_printk("unable to determine BusLogic IRQ level, "
-			" disabling board.\n");
-	goto fail;
-    }
-    *id = inquiry_result[2] & 0x7;
-
-    /* I expected Adaptec boards to fail on this, but it doesn't happen... */
-    inquiry_cmd[0] = CMD_INQEXTSETUP;
-    inquiry_cmd[1] = 4;
-    if (buslogic_out(base, inquiry_cmd, 2))
-	goto fail;
-    if (buslogic_in(base, inquiry_result, inquiry_cmd[1]))
-	goto fail;
-    WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
-    if (inb(STATUS(base)) & CMDINV)
-	goto fail;
-    INTR_RESET(base);
-
-    *bus_type = inquiry_result[0];
-    CHECK(*bus_type == 'A' || *bus_type == 'E' || *bus_type == 'M');
-
-    *bios = (const unsigned char *)((unsigned int)inquiry_result[1] << 12);
-
-    *max_sg = (inquiry_result[3] << 8) | inquiry_result[2];
-
-    /* We only need a DMA channel for ISA boards.  Some other types of boards
-       (such as the 747S) have an option to report a DMA channel even though
-       none is used (for compatibility with Adaptec drivers which require a
-       DMA channel).  We ignore this. */
-    if (*bus_type == 'A')
-	switch (*dma) {
-	  case 0:	/* This indicates that no DMA channel is used. */
-	    *dma = 0;
-	    break;
-	  case 0x20:
-	    *dma = 5;
-	    break;
-	  case 0x40:
-	    *dma = 6;
-	    break;
-	  case 0x80:
-	    *dma = 7;
-	    break;
-	  default:
-	    buslogic_printk("unable to determine BusLogic DMA channel,"
-			    " disabling board.\n");
-	    goto fail;
-	}
-    else
-	*dma = 0;
-
-    while (0) {
-      fail:
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-	buslogic_printk("query board settings\n");
-#endif
-	return TRUE;
-    }
-
-    return FALSE;
-}
-
-/* Query the board.  This acts both as part of the detection sequence and as a
-   means to get necessary configuration information. */
-static int buslogic_query(unsigned int base, unsigned char *trans,
-			  unsigned char *irq, unsigned char *dma,
-			  unsigned char *id, char *bus_type,
-			  unsigned short *max_sg, const unsigned char **bios,
-			  char *model, char *firmware_rev)
-{
-    unsigned char inquiry_cmd[2];
-    unsigned char inquiry_result[6];
-    unsigned char geo;
-    unsigned int i;
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-    buslogic_printk("called\n");
-#endif
-
-    /* Quick and dirty test for presence of the card. */
-    if (inb(STATUS(base)) == 0xFF)
-	goto fail;
-
-    /* Check the GEOMETRY port early for quick bailout on Adaptec boards. */
-    geo = inb(GEOMETRY(base));
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-    buslogic_printk("geometry bits: %02X\n", geo);
-#endif
-    /* Here is where we tell the men from the boys (i.e. Adaptec's don't
-       support the GEOMETRY port, the men do :-) */
-    if (geo == 0xFF)
-	goto fail;
-
-    /* In case some other card was probing here, reset interrupts. */
-    INTR_RESET(base);
-
-    /* Reset the adapter.  I ought to make a hard reset, but it's not really
-       necessary. */
-    outb(RSOFT | RINT/* | RSBUS*/, CONTROL(base));
-
-    /* Wait a little bit for things to settle down. */
-    i = jiffies + 2;
-    while (i > jiffies);
-
-    /* Expect INREQ and HARDY, any of the others are bad. */
-    WAIT(STATUS(base), INREQ | HARDY, DACT | DFAIL | CMDINV | DIRRDY | CPRBSY);
-
-    /* Shouldn't have generated any interrupts during reset. */
-    if (inb(INTERRUPT(base)) & INTRMASK)
-	goto fail;
-
-    /* Getting the BusLogic firmware revision level is a bit tricky.  We get
-       the first two digits (d.d) from CMD_INQUIRY and then use two undocumented
-       commands to get the remaining digit and letter (d.ddl as in 3.31C). */
-
-    inquiry_cmd[0] = CMD_INQUIRY;
-    buslogic_out(base, inquiry_cmd, 1);
-    if (buslogic_in(base, inquiry_result, 4))
-	goto fail;
-    /* Reading port should reset DIRRDY. */
-    if (inb(STATUS(base)) & DIRRDY)
-	goto fail;
-    WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
-    INTR_RESET(base);
-    firmware_rev[0] = inquiry_result[2];
-    firmware_rev[1] = '.';
-    firmware_rev[2] = inquiry_result[3];
-    firmware_rev[3] = '\0';
-#if 0
-    buslogic_printk("inquiry bytes: %02X(%c) %02X(%c)\n",
-		    inquiry_result[0], inquiry_result[0],
-		    inquiry_result[1], inquiry_result[1]);
-#endif
-
-    if (getconfig(base, irq, dma, id, bus_type, max_sg, bios))
-	goto fail;
-
-    /* Set up defaults */
-#ifdef BIOS_TRANSLATION_OVERRIDE
-    *trans = BIOS_TRANSLATION_OVERRIDE;
-#else
-    *trans = BIOS_TRANSLATION_DEFAULT;
-#endif
-    model[0] = '\0';
-    model[6] = 0;
-
-    /* ??? Begin undocumented command use.
-       These may not be supported by clones. */
-
-    do {
-	/* ??? It appears as though AMI BusLogic clones don't implement this
-	   feature.  As an experiment, if we read a 00 we ignore the GEO_GT_1GB
-	   bit and skip all further undocumented commands. */
-	if (geo == 0x00)
-	    break;
-#ifndef BIOS_TRANSLATION_OVERRIDE
-	*trans = ((geo & GEO_GT_1GB)
-		  ? BIOS_TRANSLATION_BIG : BIOS_TRANSLATION_DEFAULT);
-#endif
-
-	inquiry_cmd[0] = CMD_VER_NO_LAST;
-	buslogic_out(base, inquiry_cmd, 1);
-	if (buslogic_in(base, inquiry_result, 1))
-	    break;
-	WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
-	INTR_RESET(base);
-	firmware_rev[3] = inquiry_result[0];
-	firmware_rev[4] = '\0';
-
-	inquiry_cmd[0] = CMD_VER_NO_LETTER;
-	buslogic_out(base, inquiry_cmd, 1);
-	if (buslogic_in(base, inquiry_result, 1))
-	    break;
-	WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
-	INTR_RESET(base);
-	firmware_rev[4] = inquiry_result[0];
-	firmware_rev[5] = '\0';
-
-	/* Use undocumented command to get model number and revision. */
-
-	inquiry_cmd[0] = CMD_RET_MODEL_NO;
-	inquiry_cmd[1] = 6;
-	buslogic_out(base, inquiry_cmd, 2);
-	if (buslogic_in(base, inquiry_result, inquiry_cmd[1]))
-	    break;
-	WAIT_UNTIL_FAST(INTERRUPT(base), CMDC);
-	INTR_RESET(base);
-	memcpy(model, inquiry_result, 5);
-	model[5] = '\0';
-	model[6] = inquiry_result[5];
-    } while (0);
-
-    /* ??? End undocumented command use. */
-
-    /* bus_type from getconfig doesn't differentiate between EISA/VESA.  We
-       override using the model number here. */
-    switch (*bus_type) {
-      case 'E':
-	switch (model[0]) {
-	  case '4':
-	    *bus_type = 'V';
-	    break;
-	  case '9':
-	    *bus_type = 'P';
-	    break;
-	  case '7':
-	    break;
-	  default:
-	    *bus_type = 'X';
-	    break;
-	}
-	break;
-      default:
-	break;
-    }
-
-    while (0) {
-      fail:
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-	buslogic_printk("query board settings\n");
-#endif
-	return TRUE;
-    }
-
-    return FALSE;
-}
-
-/* return non-zero on detection */
-int buslogic_detect(Scsi_Host_Template *tpnt)
-{
-    unsigned char dma;
-    unsigned char irq;
-    unsigned int base;
-    unsigned char id;
-    char bus_type;
-    unsigned short max_sg;
-    unsigned char bios_translation;
-    unsigned long flags;
-    const unsigned char *bios;
-    char *model;
-    char *firmware_rev;
-    struct Scsi_Host *shpnt;
-    size_t indx;
-    int unchecked_isa_dma;
-    int count = 0;
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-    buslogic_printk("called\n");
-#endif
-
-    tpnt->proc_dir = &proc_scsi_buslogic; 
-    tpnt->can_queue = BUSLOGIC_MAILBOXES;
-    for (indx = 0; bases[indx] != 0; indx++)
-	if (!check_region(bases[indx], 4)) {
-	    shpnt = scsi_register(tpnt, sizeof (struct hostdata));
-
-	    base = bases[indx];
-
-	    model = HOSTDATA(shpnt)->model;
-	    firmware_rev = HOSTDATA(shpnt)->firmware_rev;
-	    if (buslogic_query(base, &bios_translation, &irq, &dma, &id,
-			       &bus_type, &max_sg, &bios, model, firmware_rev))
-		goto unregister;
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-	    buslogic_stat(base);
-#endif
-
-	    /* Only type 'A' (AT/ISA) bus adapters use unchecked DMA. */
-	    unchecked_isa_dma = (bus_type == 'A');
-#ifndef CONFIG_NO_BUGGY_BUSLOGIC
-	    /* There is a hardware bug in the BT-445S prior to revision D.
-	       When the BIOS is enabled and you have more than 16MB of memory,
-	       the card mishandles memory transfers over 16MB which (if viewed
-	       as a 24-bit address) overlap with the BIOS address space.  For
-	       example if you have the BIOS located at physical address
-	       0xDC000 and a DMA transfer from the card to RAM starts at
-	       physical address 0x10DC000 then the transfer is messed up.  To
-	       be more precise every fourth byte of the transfer is messed up.
-	       (This analysis courtesy of Tomas Hurka, author of the NeXTSTEP
-	       BusLogic driver.) */
-
-	    if (bus_type == 'V'				    /* 445 */
-		&& firmware_rev[0] <= '3'		    /* S */
-		&& bios != NULL) {			    /* BIOS enabled */
-#if 1
-		/* Now that LNZ's forbidden_addr stuff is in the higher level
-		   scsi code, we can use this instead. */
-		/* Avoid addresses which "mirror" the BIOS for DMA. */
-		shpnt->forbidden_addr = (unsigned long)bios;
-		shpnt->forbidden_size = 16 * 1024;
-#else
-		/* Use double-buffering. */
-		unchecked_isa_dma = TRUE;
-#endif
-	    }
-#endif
-
-	    CHECK_DMA_ADDR(unchecked_isa_dma, shpnt, goto unregister);
-
-	    if (setup_mailboxes(base, shpnt))
-		goto unregister;
-
-	    /* Set the Bus on/off-times as not to ruin floppy performance.
-	       CMD_BUSOFF_TIME is a noop for EISA boards (and possibly
-	       others???). */
-	    if (bus_type != 'E' && bus_type != 'P') {
-		/* The default ON/OFF times for BusLogic adapters is 7/4. */
-		static const unsigned char oncmd[] = { CMD_BUSON_TIME, 7 };
-		static const unsigned char offcmd[] = { CMD_BUSOFF_TIME, 5 };
-
-		INTR_RESET(base);
-		buslogic_out(base, oncmd, sizeof oncmd);
-		WAIT_UNTIL(INTERRUPT(base), CMDC);
-		INTR_RESET(base);
-		buslogic_out(base, offcmd, sizeof offcmd);
-		WAIT_UNTIL(INTERRUPT(base), CMDC);
-		while (0) {
-		  fail:
-		    buslogic_printk("setting bus on/off-time failed.\n");
-		}
-		INTR_RESET(base);
-	    }
-
-	    buslogic_printk("configuring %s HA at port 0x%03X, IRQ %u",
-			    (bus_type == 'A' ? "ISA"
-			     : (bus_type == 'E' ? "EISA"
-				: (bus_type == 'M' ? "MCA"
-				   : (bus_type == 'P' ? "PCI"
-				      : (bus_type == 'V' ? "VESA"
-					 : (bus_type == 'X' ? "EISA/VESA/PCI"
-					    : "Unknown")))))),
-			    base, irq);
-	    if (bios != NULL)
-		printk(", BIOS 0x%05X", (unsigned int)bios);
-	    if (dma != 0)
-		printk(", DMA %u", dma);
-	    printk(", ID %u\n", id);
-	    buslogic_printk("Model Number: %s",
-			    (model[0] ? model : "Unknown"));
-	    if (model[0])
-		printk(" (revision %d)", model[6]);
-	    printk("\n");
-	    buslogic_printk("firmware revision: %s\n", firmware_rev);
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-	    buslogic_stat(base);
-#endif
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-	    buslogic_printk("enable interrupt channel %d.\n", irq);
-#endif
-
-	    save_flags(flags);
-	    cli();
-	    if (request_irq(irq, buslogic_interrupt,
-			    SA_INTERRUPT, "buslogic")) {
-		buslogic_printk("unable to allocate IRQ for "
-				"BusLogic controller.\n");
-		restore_flags(flags);
-		goto unregister;
-	    }
-
-	    if (dma) {
-		if (request_dma(dma, "buslogic")) {
-		    buslogic_printk("unable to allocate DMA channel for "
-				    "BusLogic controller.\n");
-		    free_irq(irq);
-		    restore_flags(flags);
-		    goto unregister;
-		}
-
-		/* The DMA-Controller.  We need to fool with this because we
-		   want to be able to use an ISA BusLogic without having to
-		   have the BIOS enabled. */
-		set_dma_mode(dma, DMA_MODE_CASCADE);
-		enable_dma(dma);
-	    }
-
-	    host[irq - 9] = shpnt;
-	    shpnt->this_id = id;
-	    shpnt->unchecked_isa_dma = unchecked_isa_dma;
-	    /* Have to keep cmd_per_lun at 1 for ISA machines otherwise lots
-	       of memory gets sucked up for bounce buffers.  */
-	    shpnt->cmd_per_lun = (unchecked_isa_dma ? 1 : BUSLOGIC_CMDLUN);
-	    shpnt->sg_tablesize = max_sg;
-	    if (shpnt->sg_tablesize > BUSLOGIC_MAX_SG)
-		shpnt->sg_tablesize = BUSLOGIC_MAX_SG;
-	    /* ??? shpnt->base should really be "const unsigned char *"... */
-	    shpnt->base = (unsigned char *)bios;
-	    shpnt->io_port = base;
-	    shpnt->n_io_port = 4;	/* Number of bytes of I/O space used */
-	    shpnt->dma_channel = dma;
-	    shpnt->irq = irq;
-	    HOSTDATA(shpnt)->bios_translation = bios_translation;
-	    if (bios_translation == BIOS_TRANSLATION_BIG)
-		buslogic_printk("using extended bios translation.\n");
-	    HOSTDATA(shpnt)->last_mbi_used = 2 * BUSLOGIC_MAILBOXES - 1;
-	    HOSTDATA(shpnt)->last_mbo_used = BUSLOGIC_MAILBOXES - 1;
-	    memset(HOSTDATA(shpnt)->sc, 0, sizeof HOSTDATA(shpnt)->sc);
-	    restore_flags(flags);
-
-#if 0
-	    {
-		unsigned char buf[8];
-		unsigned char cmd[]
-		    = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-		size_t i;
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-		buslogic_printk("*** READ CAPACITY ***\n");
-#endif
-		for (i = 0; i < sizeof buf; i++)
-		    buf[i] = 0x87;
-		for (i = 0; i < 2; i++)
-		    if (!buslogic_command(i, cmd, buf, sizeof buf)) {
-			buslogic_printk("LU %u sector_size %d device_size %d\n",
-					i, *(int *)(buf + 4), *(int *)buf);
-		    }
-
-#if (BUSLOGIC_DEBUG & BD_DETECT)
-		buslogic_printk("*** NOW RUNNING MY OWN TEST ***\n");
-#endif
-		for (i = 0; i < 4; i++) {
-		    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;
-		    buslogic_command(0, cmd, buffer, sizeof buffer);
-		}
-	    }
-#endif
-
-	    request_region(bases[indx], 4,"buslogic");
-	    /* Register the IO ports that we use */
-	    count++;
-	    continue;
-	  unregister:
-	    scsi_unregister(shpnt);
-	}
-    return count;
-}
-
-static int restart(struct Scsi_Host *shpnt)
-{
-    unsigned int i;
-    unsigned int count = 0;
-#if 0
-    static const unsigned char buscmd[] = { CMD_START_SCSI };
-#endif
-
-    for (i = 0; i < BUSLOGIC_MAILBOXES; i++)
-	if (HOSTDATA(shpnt)->sc[i]
-	    && !HOSTDATA(shpnt)->sc[i]->device->soft_reset) {
-#if 0
-	    HOSTDATA(shpnt)->mb[i].status
-		= MBX_ACTION_START;	/* Indicate ready to restart... */
-#endif
-	    count++;
-	}
-
-    buslogic_printk("potential to restart %d stalled commands...\n", count);
-#if 0
-    /* start scsi command */
-    if (count)
-	buslogic_out(shpnt->host->io_port, buscmd, sizeof buscmd);
-#endif
-    return 0;
-}
-
-/* ??? The abort command for the aha1542 does not leave the device in a clean
-   state where it is available to be used again.  As it is not clear whether
-   the same problem exists with BusLogic boards, we will enable this and see
-   if it works. */
-int buslogic_abort(Scsi_Cmnd *scpnt)
-{
-#if 1
-    static const unsigned char buscmd[] = { CMD_START_SCSI };
-    struct mailbox *mb;
-    int mbi, mbo, last_mbi;
-    unsigned long flags;
-    unsigned int i;
-
-    buslogic_printk("%X %X\n",
-		    inb(STATUS(scpnt->host->io_port)),
-		    inb(INTERRUPT(scpnt->host->io_port)));
-
-    save_flags(flags);
-    cli();
-    mb = HOSTDATA(scpnt->host)->mb;
-    last_mbi = HOSTDATA(scpnt->host)->last_mbi_used;
-    mbi = last_mbi + 1;
-    if (mbi >= 2 * BUSLOGIC_MAILBOXES)
-	mbi = BUSLOGIC_MAILBOXES;
-
-    do {
-	if (mb[mbi].status != MBX_NOT_IN_USE)
-	    break;
-	last_mbi = mbi;
-	mbi++;
-	if (mbi >= 2 * BUSLOGIC_MAILBOXES)
-	    mbi = BUSLOGIC_MAILBOXES;
-    } while (mbi != HOSTDATA(scpnt->host)->last_mbi_used);
-
-    if (mb[mbi].status != MBX_NOT_IN_USE) {
-	buslogic_printk("lost interrupt discovered on irq %d, "
-			" - attempting to recover...\n",
-			scpnt->host->irq);
-	HOSTDATA(scpnt->host)->last_mbi_used = last_mbi;
-	buslogic_interrupt(scpnt->host->irq, NULL);
-	restore_flags(flags);
-	return SCSI_ABORT_SUCCESS;
-    }
-    restore_flags(flags);
-
-    /* OK, no lost interrupt.  Try looking to see how many pending commands we
-       think we have. */
-    for (i = 0; i < BUSLOGIC_MAILBOXES; i++)
-	if (HOSTDATA(scpnt->host)->sc[i]) {
-	    if (HOSTDATA(scpnt->host)->sc[i] == scpnt) {
-		buslogic_printk("timed out command pending for %s.\n",
-			kdevname(scpnt->request.rq_dev));
-		if (HOSTDATA(scpnt->host)->mb[i].status != MBX_NOT_IN_USE) {
-		    buslogic_printk("OGMB still full - restarting...\n");
-		    buslogic_out(scpnt->host->io_port, buscmd, sizeof buscmd);
-		}
-	    } else
-		buslogic_printk("other pending command: %s\n",
-			kdevname(scpnt->request.rq_dev));
-	}
-#endif
-
-#if (BUSLOGIC_DEBUG & BD_ABORT)
-    buslogic_printk("called\n");
-#endif
-
-#if 1
-    /* This section of code should be used carefully - some devices cannot
-       abort a command, and this merely makes it worse. */
-    save_flags(flags);
-    cli();
-    for (mbo = 0; mbo < BUSLOGIC_MAILBOXES; mbo++)
-	if (scpnt == HOSTDATA(scpnt->host)->sc[mbo]) {
-	    mb[mbo].status = MBX_ACTION_ABORT;
-	    buslogic_out(scpnt->host->io_port, buscmd, sizeof buscmd);
-	    break;
-	}
-    restore_flags(flags);
-#endif
-
-    return SCSI_ABORT_SNOOZE;
-}
-
-/* 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 BusLogic notifies us with all of the pending commands (it does
-   implement soft reset, after all). */
-int buslogic_reset(Scsi_Cmnd *scpnt)
-{
-    static const unsigned char buscmd[] = { CMD_START_SCSI };
-    unsigned int i;
-
-#if (BUSLOGIC_DEBUG & BD_RESET)
-    buslogic_printk("called\n");
-#endif
-#if 0
-    /* This does a scsi reset for all devices on the bus. */
-    outb(RSBUS, CONTROL(scpnt->host->io_port));
-#else
-    /* This does a selective reset of just the one device. */
-    /* First locate the ccb for this command. */
-    for (i = 0; i < BUSLOGIC_MAILBOXES; i++)
-	if (HOSTDATA(scpnt->host)->sc[i] == scpnt) {
-	    HOSTDATA(scpnt->host)->ccbs[i].op = CCB_OP_BUS_RESET;
-
-	    /* Now tell the BusLogic to flush all pending commands for this
-	       target. */
-	    buslogic_out(scpnt->host->io_port, buscmd, sizeof buscmd);
-
-	    /* 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. */
-	    buslogic_printk("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... */
-#if 1
-	    for (i = 0; i < BUSLOGIC_MAILBOXES; i++)
-		if (HOSTDATA(scpnt->host)->sc[i]
-		    && HOSTDATA(scpnt->host)->sc[i]->target == scpnt->target) {
-		    Scsi_Cmnd *sctmp = HOSTDATA(scpnt->host)->sc[i];
-
-		    sctmp->result = DID_RESET << 16;
-		    if (sctmp->host_scribble)
-			scsi_free(sctmp->host_scribble, BUSLOGIC_SG_MALLOC);
-		    buslogic_printk("sending DID_RESET for target %d.\n",
-				    scpnt->target);
-		    sctmp->scsi_done(scpnt);
-
-		    HOSTDATA(scpnt->host)->sc[i] = NULL;
-		    HOSTDATA(scpnt->host)->mb[i].status = MBX_NOT_IN_USE;
-		}
-	    return SCSI_RESET_SUCCESS;
-#else
-	    return SCSI_RESET_PENDING;
-#endif
-	}
-#endif
-    /* 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;
-}
-
-/* ??? This is probably not correct for series "C" boards.  I believe these
-   support separate mappings for each disk.  We would need to issue a
-   CMD_READ_FW_LOCAL_RAM command to check for the particular drive being
-   queried.  Note that series "C" boards can be differentiated by having
-   HOSTDATA(disk->device->host)->firmware_rev[0] >= '4'. */
-int buslogic_biosparam(Disk *disk, kdev_t dev, int *ip)
-{
-    unsigned int size = disk->capacity;
-
-    /* ip[0] == heads, ip[1] == sectors, ip[2] == cylinders */
-    if (HOSTDATA(disk->device->host)->bios_translation == BIOS_TRANSLATION_BIG
-	&& size >= 0x200000) {		/* 1GB */
-	if (size >= 0x400000) {		/* 2GB */
-#if 0	/* ??? Used in earlier kernels, but disagrees with BusLogic info. */
-	    if (mb >= 0x800000) {	/* 4GB */
-		ip[0] = 256;
-		ip[1] = 64;
-	    } else {
-		ip[0] = 256;
-		ip[1] = 32;
-	    }
-#else
-	    ip[0] = 255;
-	    ip[1] = 63;
-#endif
-	} else {
-	    ip[0] = 128;
-	    ip[1] = 32;
-	}
-    } else {
-	ip[0] = 64;
-	ip[1] = 32;
-    }
-    ip[2] = size / (ip[0] * ip[1]);
-/*    if (ip[2] > 1024)
-	ip[2] = 1024; */
-    return 0;
-}
-
-/* called from init/main.c */
-void buslogic_setup(char *str, int *ints)
-{
-    static const unsigned short valid_bases[]
-	= { 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 };
-    static size_t setup_idx = 0;
-    size_t i;
-
-    if (setup_idx >= ARRAY_SIZE(bases) - 1) {
-	buslogic_printk("called too many times.  Bad LILO params?\n");
-	return;
-    }
-    if (ints[0] != 1) {
-	buslogic_printk("malformed command line.\n");
-	buslogic_printk("usage: buslogic=<portbase>\n");
-	return;
-    }
-    for (i = 0; i < ARRAY_SIZE(valid_bases); i++)
-	if (valid_bases[i] == ints[1]) {
-	    bases[setup_idx++] = ints[1];
-	    bases[setup_idx] = 0;
-	    return;
-	}
-    buslogic_printk("invalid base 0x%X specified.\n", ints[1]);
-}
-
-#ifdef MODULE
-/* Eventually this will go into an include file, but that's later... */
-Scsi_Host_Template driver_template = BUSLOGIC;
-
-# include "scsi_module.c"
-#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this