diff mbox

[v3] m68k/amiga - Amiga Zorro NCR53C9x boards: new zorro_esp.c

Message ID 72c19f0c923c4625bf57263e02637237@aalto.fi (mailing list archive)
State Changes Requested
Headers show

Commit Message

Tuomas Vainikka March 14, 2018, 7:13 a.m. UTC
The config description lists 53c700 devices, not ESP devices?

-Tuomas

Comments

Michael Schmitz March 14, 2018, 8:36 a.m. UTC | #1
Hi Tuomas,

oddly enough, it does. How embarrassing...

Hope I got the names of the boards right this time.

Thanks for spotting this!

Cheers,

	Michael

Am 14.03.2018 um 20:13 schrieb Vainikka Tuomas:
> The config description lists 53c700 devices, not ESP devices?
> 
> -Tuomas
> ________________________________________
> From: linux-m68k-owner@vger.kernel.org <linux-m68k-owner@vger.kernel.org> on behalf of Michael Schmitz <schmitzmic@gmail.com>
> Sent: 12 March 2018 09:26:40
> To: linux-scsi@vger.kernel.org
> Cc: linux-m68k@vger.kernel.org; davem@davemloft.net; geert@linux-m68k.org; fthain@telegraphics.com.au; Michael Schmitz; Michael Schmitz
> Subject: [PATCH v3] m68k/amiga - Amiga Zorro NCR53C9x boards: new zorro_esp.c
> 
> From: Michael Schmitz <schmitz@debian.org>
> 
> New combined SCSI driver for all ESP based Zorro SCSI boards for
> m68k Amiga.
> 
> Code largely based on board specific parts of the old drivers (blz1230.c,
> blz2060.c, cyberstorm.c, cyberstormII.c, fastlane.c which were removed
> after the 2.6 kernel series for lack of maintenance) with contributions
> by Tuomas Vainikka (TCQ bug tests and workaround) and Finn Thain (TCQ
> bugfix by use of PIO in extended message in transfer).
> 
> New Kconfig option and Makefile entries for new Amiga Zorro ESP SCSI
> driver included in this patch.
> 
> Use DMA transfers wherever possible, with board-specific DMA set-up
> functions copied from the old driver code. Three byte reselection messages
>  do appear to cause DMA timeouts. So wire up a PIO transfer routine for
> these instead.
> 
> PIO code taken from mac_esp.c where the reselection timeout issue was
> debugged and fixed first, with the following modifications:
> 
> esp_reselect_with_tag explicitly sets esp->cmd_block_dma as target address
> for the message bytes. Fixup to use kernel virtual address esp->cmd_block
> in PIO transfer if DMA address is esp->cmd_block_dma.
> 
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
> 
> ---
> 
> Changes since v1:
> 
> Fixed issues raised by Finn Thain in initial code review:
> 
> - use KBUILD_MODNAME for driver name string.
> - use pr_fmt() for pr_* format prefix.
> - clean up DMA error reporting: clear error flag before each DMA
>   operation, set error flag on PIO error. Don't test phase in dma_err hook.
> - change confusing comment about semantics of read flag, add comments
>   indicating DMA direction to DMA setup hooks.
> - drop spurious braces around switch clauses.
> - lift cfreq setting out of ID switch clauses.
> - fix indentation.
> - fix error codes on probe fail.
> - drop check for board ID when unmapping DMA regs in error handling:
>   the ioaddr > 0xffffff test already catches all cases where the DMA
>   registers were ioremapped.
> - dynamically alloc zorro_private_data.
> - fix use of driver_data field (don't mix host and zorro_esp_priv
>   pointers). Note: require esp pointer in zorro_esp_priv to find host
>   pointer!
> - back out phase bits changes to pio_cmd !write branch introduced
>   to cope with ESP SELAS command. We don't use that code so keep
>   it in sync with Finn's version.
> - use esp_ops.dma_length_limit() to limit transfer size. After review
>   of old driver code, use 0xffffff max transfer size throughout.
> 
> Fixed issues raised by Geert Uytterhoven:
> 
> - dynamically alloc zorro_private_data, store as device drvdata.
> - store ctrl_data for CyberStormI in driver private data.
> - use dma_sync_single_for_device() instead of cache_push/clear.
> - handle case of duplicate board identity - check whether board is
>   Zorro III or Zorro II (use ROM resource data for this). Also fix
>   up DMA mask for Zorro II boards to 32 bits (these are really CPU
>   expansion slot boards).
> - remove zorro3 field from driver_data struct (now in private data).
> - add braces around ambiguous if - else construct.
> - use named structs instead of array for board config data.
> - use scsi_option driver data flag for boards with optional ESP.
> 
> Other improvements and bugfixes
> 
> - fix Zorro device table error (duplicate ID used, also raised
>   by Kars de Jong).
> - error code fixup in error handling path.
> - add separate DMA setup for Blizzard 1230 II board.
> - add support for Cyberstorm II board.
> - add register structs and DMA setup for Zorro III Fastlane board,
>   following logic from old fastlane.c driver. Wire up Fastlane DMA
>   and interrupt status routines, map the necessary low 24 bit board
>   address space used for DMA target address setting. Clean up DMA
>   register space ioremap() branch for Zorro III boards (currently
>   Fastlane only) to end confusion about what to do in error recovery.
> - use esp_ops.fastlane_esp_dma_invalidate() on Fastlane (and skip
>   fastlane_esp_reset_dma() in DMA setup).
> - credit Tuomas Vainikka for contributing Blizzard 1230 code (and
>   testing).
> - clarify comment about unsupported Oktagon SCSI board.
> - remove unused const definitions carried over from old driver.
> 
> Changes since v2:
> 
> Issues raised by Finn Thain:
> 
> - add SPDX-License-Identifier.
> - remove unused ratelimit.h.
> - drop phys_to_virt() in PIO transfer routine, after ensuring PIO is only
>   used for message in transfers to esp->command_block. This obviates any
>   need for finding the virtual address corresponding to a DMA handle.
> - drop BUG_ON(!(cmd & ESP_CMD_DMA)) assertion in DMA setup. Short of changes
>   to the core ESP driver, this can never trigger.
> - make ioremap() of DMA address range conditional on zep->zorro3 and use
>   that same condition to unmap in error handling and driver exit.
>   Omit board ID test as we only support a single Zorro III board, and add
>   comment on what to do when adding support for more boards.
> - free driver private data in driver exit.
> - various whitespace related cleanup.
> 
> ---
>  drivers/scsi/Kconfig     |   16 +
>  drivers/scsi/Makefile    |    1 +
>  drivers/scsi/zorro_esp.c | 1136 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1153 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/scsi/zorro_esp.c
> 
> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
> index 8a739b7..c7d337f 100644
> --- a/drivers/scsi/Kconfig
> +++ b/drivers/scsi/Kconfig
> @@ -1462,6 +1462,22 @@ config SCSI_ZORRO7XX
>               accelerator card for the Amiga 1200,
>             - the SCSI controller on the GVP Turbo 040/060 accelerator.
> 
> +config SCSI_ZORRO_ESP
> +       tristate "Zorro ESP SCSI support"
> +       depends on ZORRO && SCSI
> +       select SCSI_SPI_ATTRS
> +       help
> +         Support for various ESP-based SCSI controllers on Zorro
> +         expansion boards for the Amiga.
> +         This includes:
> +           - the Amiga 4091 Zorro III SCSI-2 controller,
> +           - the MacroSystem Development's WarpEngine Amiga SCSI-2 controller
> +             (info at
> +             <http://www.lysator.liu.se/amiga/ar/guide/ar310.guide?FEATURE5>),
> +           - the SCSI controller on the Phase5 Blizzard PowerUP 603e+
> +             accelerator card for the Amiga 1200,
> +           - the SCSI controller on the GVP Turbo 040/060 accelerator.
> +
>  config ATARI_SCSI
>         tristate "Atari native SCSI support"
>         depends on ATARI && SCSI
> diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
> index fcfd28d..6f13c03 100644
> --- a/drivers/scsi/Makefile
> +++ b/drivers/scsi/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_INFINIBAND_ISER)         += libiscsi.o
>  obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
>  obj-$(CONFIG_SCSI_A4000T)      += 53c700.o     a4000t.o
>  obj-$(CONFIG_SCSI_ZORRO7XX)    += 53c700.o     zorro7xx.o
> +obj-$(CONFIG_SCSI_ZORRO_ESP)   += esp_scsi.o   zorro_esp.o
>  obj-$(CONFIG_A3000_SCSI)       += a3000.o      wd33c93.o
>  obj-$(CONFIG_A2091_SCSI)       += a2091.o      wd33c93.o
>  obj-$(CONFIG_GVP11_SCSI)       += gvp11.o      wd33c93.o
> diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c
> new file mode 100644
> index 0000000..47053d1
> --- /dev/null
> +++ b/drivers/scsi/zorro_esp.c
> @@ -0,0 +1,1136 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* zorro_esp.c: ESP front-end for Amiga ZORRO SCSI systems.
> + *
> + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
> + *
> + * Copyright (C) 2011,2018 Michael Schmitz (schmitz@debian.org) for
> + *               migration to ESP SCSI core
> + *
> + * Copyright (C) 2013 Tuomas Vainikka (tuomas.vainikka@aalto.fi) for
> + *               Blizzard 1230 DMA and probe function fixes
> + *
> + * Copyright (C) 2017 Finn Thain for PIO code from Mac ESP driver adapted here
> + */
> +/*
> + * ZORRO bus code from:
> + */
> +/*
> + * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
> + *             Amiga MacroSystemUS WarpEngine SCSI controller.
> + *             Amiga Technologies/DKB A4091 SCSI controller.
> + *
> + * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
> + * plus modifications of the 53c7xx.c driver to support the Amiga.
> + *
> + * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
> + */
> +
> +#define KBUILD_MODNAME     "zorro_esp"
> +#define pr_fmt(fmt)        KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/scatterlist.h>
> +#include <linux/delay.h>
> +#include <linux/zorro.h>
> +#include <linux/slab.h>
> +
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +#include <asm/cacheflush.h>
> +#include <asm/amigahw.h>
> +#include <asm/amigaints.h>
> +
> +#include <scsi/scsi_host.h>
> +#include <scsi/scsi_transport_spi.h>
> +#include <scsi/scsi_device.h>
> +#include <scsi/scsi_tcq.h>
> +
> +#include "esp_scsi.h"
> +
> +MODULE_AUTHOR("Michael Schmitz <schmitz@debian.org>");
> +MODULE_DESCRIPTION("Amiga Zorro NCR5C9x (ESP) driver");
> +MODULE_LICENSE("GPL");
> +
> +struct zorro_driver_data {
> +       const char *name;
> +       unsigned long offset;
> +       unsigned long dma_offset;
> +       int absolute;   /* offset is absolute address */
> +       int scsi_option;
> +};
> +
> +static struct zorro_driver_data cyberstormI_data = {
> +       .name = "CyberStormI",
> +       .offset = 0xf400,
> +       .dma_offset = 0xf800,
> +       .absolute = 0,
> +       .scsi_option = 0,
> +};
> +
> +static struct zorro_driver_data cyberstormII_data = {
> +       .name = "CyberStormII",
> +       .offset = 0x1ff03,
> +       .dma_offset = 0x1ff43,
> +       .absolute = 0,
> +       .scsi_option = 1,
> +};
> +
> +static struct zorro_driver_data blizzard2060_data = {
> +       .name = "Blizzard 2060",
> +       .offset = 0x1ff00,
> +       .dma_offset = 0x1ffe0,
> +       .absolute = 0,
> +       .scsi_option = 0,
> +};
> +
> +static struct zorro_driver_data blizzard1230_data = {
> +       .name = "Blizzard 1230",
> +       .offset = 0x8000,
> +       .dma_offset = 0x10000,
> +       .absolute = 0,
> +       .scsi_option = 1,
> +};
> +
> +static struct zorro_driver_data blizzard1230II_data = {
> +       .name = "Blizzard 1230II",
> +       .offset = 0x10000,
> +       .dma_offset = 0x10021,
> +       .absolute = 0,
> +       .scsi_option = 1,
> +};
> +
> +static struct zorro_driver_data fastlanez3_data = {
> +       .name = "Fastlane",
> +       .offset = 0x1000001,
> +       .dma_offset = 0x1000041,
> +       .absolute = 0,
> +       .scsi_option = 0,
> +};
> +
> +static struct zorro_device_id zorro_esp_zorro_tbl[] = {
> +       {
> +               .id = ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM,
> +               .driver_data = (unsigned long)&cyberstormI_data,
> +       },
> +       {
> +               .id = ZORRO_PROD_PHASE5_CYBERSTORM_MK_II,
> +               .driver_data = (unsigned long)&cyberstormII_data,
> +       },
> +       {
> +               .id = ZORRO_PROD_PHASE5_BLIZZARD_2060,
> +               .driver_data = (unsigned long)&blizzard2060_data,
> +       },
> +       {
> +               .id = ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260,
> +               .driver_data = (unsigned long)&blizzard1230_data,
> +       },
> +       {
> +               .id = ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060,
> +               .driver_data = (unsigned long)&blizzard1230II_data,
> +       },
> +       { 0 }
> +};
> +MODULE_DEVICE_TABLE(zorro, zorro_esp_zorro_tbl);
> +
> +/* Blizzard 1230 DMA interface */
> +
> +struct blz1230_dma_registers {
> +       volatile unsigned char dma_addr;        /* DMA address      [0x0000] */
> +       unsigned char dmapad2[0x7fff];
> +       volatile unsigned char dma_latch;       /* DMA latch        [0x8000] */
> +};
> +
> +/* Blizzard 1230II DMA interface */
> +
> +struct blz1230II_dma_registers {
> +       volatile unsigned char dma_addr;        /* DMA address      [0x0000] */
> +       unsigned char dmapad2[0xf];
> +       volatile unsigned char dma_latch;       /* DMA latch        [0x0010] */
> +};
> +
> +/* Blizzard 2060 DMA interface */
> +
> +struct blz2060_dma_registers {
> +       volatile unsigned char dma_led_ctrl;    /* DMA led control   [0x000] */
> +       unsigned char dmapad1[0x0f];
> +       volatile unsigned char dma_addr0;       /* DMA address (MSB) [0x010] */
> +       unsigned char dmapad2[0x03];
> +       volatile unsigned char dma_addr1;       /* DMA address       [0x014] */
> +       unsigned char dmapad3[0x03];
> +       volatile unsigned char dma_addr2;       /* DMA address       [0x018] */
> +       unsigned char dmapad4[0x03];
> +       volatile unsigned char dma_addr3;       /* DMA address (LSB) [0x01c] */
> +};
> +
> +/* DMA control bits */
> +#define DMA_WRITE 0x80000000
> +
> +/* Cyberstorm DMA interface */
> +
> +struct cyber_dma_registers {
> +       volatile unsigned char dma_addr0;       /* DMA address (MSB) [0x000] */
> +       unsigned char dmapad1[1];
> +       volatile unsigned char dma_addr1;       /* DMA address       [0x002] */
> +       unsigned char dmapad2[1];
> +       volatile unsigned char dma_addr2;       /* DMA address       [0x004] */
> +       unsigned char dmapad3[1];
> +       volatile unsigned char dma_addr3;       /* DMA address (LSB) [0x006] */
> +       unsigned char dmapad4[0x3fb];
> +       volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x402] */
> +#define ctrl_reg  cond_reg                     /* DMA control (wo)  [0x402] */
> +};
> +
> +/* DMA control bits */
> +#define CYBER_DMA_WRITE  0x40  /* DMA direction. 1 = write */
> +#define CYBER_DMA_Z3     0x20  /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
> +
> +/* DMA status bits */
> +#define CYBER_DMA_HNDL_INTR 0x80       /* DMA IRQ pending? */
> +
> +/* The CyberStorm II DMA interface */
> +struct cyberII_dma_registers {
> +       volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x000] */
> +#define ctrl_reg  cond_reg                     /* DMA control (wo)  [0x000] */
> +       unsigned char dmapad4[0x3f];
> +       volatile unsigned char dma_addr0;       /* DMA address (MSB) [0x040] */
> +       unsigned char dmapad1[3];
> +       volatile unsigned char dma_addr1;       /* DMA address       [0x044] */
> +       unsigned char dmapad2[3];
> +       volatile unsigned char dma_addr2;       /* DMA address       [0x048] */
> +       unsigned char dmapad3[3];
> +       volatile unsigned char dma_addr3;       /* DMA address (LSB) [0x04c] */
> +};
> +
> +/* Fastlane DMA interface */
> +
> +struct fastlane_dma_registers {
> +       volatile unsigned char cond_reg;        /* DMA status  (ro) [0x0000] */
> +#define ctrl_reg  cond_reg                     /* DMA control (wo) [0x0000] */
> +       unsigned char dmapad1[0x3f];
> +       volatile unsigned char clear_strobe;    /* DMA clear   (wo) [0x0040] */
> +};
> +
> +/* The controller registers can be found in the Z2 config area at these
> + * offsets:
> + */
> +#define FASTLANE_ESP_ADDR      0x1000001
> +
> +/* DMA status bits */
> +#define FASTLANE_DMA_MINT      0x80
> +#define FASTLANE_DMA_IACT      0x40
> +#define FASTLANE_DMA_CREQ      0x20
> +
> +/* DMA control bits */
> +#define FASTLANE_DMA_FCODE     0xa0
> +#define FASTLANE_DMA_MASK      0xf3
> +#define FASTLANE_DMA_WRITE     0x08    /* 1 = write */
> +#define FASTLANE_DMA_ENABLE    0x04    /* Enable DMA */
> +#define FASTLANE_DMA_EDI       0x02    /* Enable DMA IRQ ? */
> +#define FASTLANE_DMA_ESI       0x01    /* Enable SCSI IRQ */
> +
> +/*
> + * private data used for driver
> + */
> +struct zorro_esp_priv {
> +       struct esp *esp;                /* our ESP instance - for Scsi_host* */
> +       unsigned long *board_base;      /* virtual address (Zorro III board) */
> +       int error;                      /* PIO error flag */
> +       int zorro3;                     /* board is Zorro III */
> +       unsigned char ctrl_data;        /* shadow copy of ctrl_reg */
> +};
> +
> +#define ZORRO_ESP_GET_PRIV(esp) ((struct zorro_esp_priv *) \
> +                               dev_get_drvdata(esp->dev))
> +
> +/*
> + * On all implementations except for the Oktagon, padding between ESP
> + * registers is three bytes.
> + * On Oktagon, it is one byte - use a different accessor there.
> + *
> + * Oktagon needs PDMA - currently unsupported!
> + */
> +
> +static void zorro_esp_write8(struct esp *esp, u8 val, unsigned long reg)
> +{
> +       writeb(val, esp->regs + (reg * 4UL));
> +}
> +
> +static u8 zorro_esp_read8(struct esp *esp, unsigned long reg)
> +{
> +       return readb(esp->regs + (reg * 4UL));
> +}
> +
> +static dma_addr_t zorro_esp_map_single(struct esp *esp, void *buf,
> +                                     size_t sz, int dir)
> +{
> +       return dma_map_single(esp->dev, buf, sz, dir);
> +}
> +
> +static int zorro_esp_map_sg(struct esp *esp, struct scatterlist *sg,
> +                                 int num_sg, int dir)
> +{
> +       return dma_map_sg(esp->dev, sg, num_sg, dir);
> +}
> +
> +static void zorro_esp_unmap_single(struct esp *esp, dma_addr_t addr,
> +                                 size_t sz, int dir)
> +{
> +       dma_unmap_single(esp->dev, addr, sz, dir);
> +}
> +
> +static void zorro_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
> +                             int num_sg, int dir)
> +{
> +       dma_unmap_sg(esp->dev, sg, num_sg, dir);
> +}
> +
> +static int zorro_esp_irq_pending(struct esp *esp)
> +{
> +       /* check ESP status register; DMA has no status reg. */
> +
> +       if (zorro_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR)
> +               return 1;
> +
> +       return 0;
> +}
> +
> +static int cyber_esp_irq_pending(struct esp *esp)
> +{
> +       /* It's important to check the DMA IRQ bit in the correct way! */
> +       return ((zorro_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) &&
> +               ((((struct cyber_dma_registers *)(esp->dma_regs))->cond_reg) &
> +                CYBER_DMA_HNDL_INTR));
> +       return 0;
> +}
> +
> +static int fastlane_esp_irq_pending(struct esp *esp)
> +{
> +       struct fastlane_dma_registers *dregs =
> +               (struct fastlane_dma_registers *) (esp->dma_regs);
> +       unsigned char dma_status;
> +
> +       dma_status = dregs->cond_reg;
> +
> +       if (dma_status & FASTLANE_DMA_IACT)
> +               return 0;       /* not our IRQ */
> +
> +       /* Return non-zero if ESP requested IRQ */
> +       return (
> +          (dma_status & FASTLANE_DMA_CREQ) &&
> +          (!(dma_status & FASTLANE_DMA_MINT)) &&
> +          (zorro_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR));
> +}
> +
> +static u32 zorro_esp_dma_length_limit(struct esp *esp, u32 dma_addr,
> +                                       u32 dma_len)
> +{
> +       return dma_len > 0xFFFFFF ? 0xFFFFFF : dma_len;
> +}
> +
> +static void zorro_esp_reset_dma(struct esp *esp)
> +{
> +       /* nothing to do here */
> +}
> +
> +static void zorro_esp_dma_drain(struct esp *esp)
> +{
> +       /* nothing to do here */
> +}
> +
> +static void zorro_esp_dma_invalidate(struct esp *esp)
> +{
> +       /* nothing to do here */
> +}
> +
> +static void fastlane_esp_dma_invalidate(struct esp *esp)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct fastlane_dma_registers *dregs =
> +               (struct fastlane_dma_registers *) (esp->dma_regs);
> +       unsigned char *ctrl_data = &zep->ctrl_data;
> +       unsigned long *t;
> +
> +       *ctrl_data = (*ctrl_data & FASTLANE_DMA_MASK);
> +       dregs->ctrl_reg = *ctrl_data;
> +
> +       t = (unsigned long *)(zep->board_base);
> +
> +       dregs->clear_strobe = 0;
> +       *t = 0;
> +}
> +
> +/*
> + * Programmed IO routines follow.
> + */
> +
> +static inline unsigned int zorro_esp_wait_for_fifo(struct esp *esp)
> +{
> +       int i = 500000;
> +
> +       do {
> +               unsigned int fbytes = zorro_esp_read8(esp, ESP_FFLAGS)
> +                                                       & ESP_FF_FBYTES;
> +
> +               if (fbytes)
> +                       return fbytes;
> +
> +               udelay(2);
> +       } while (--i);
> +
> +       pr_err("FIFO is empty (sreg %02x)\n",
> +              zorro_esp_read8(esp, ESP_STATUS));
> +       return 0;
> +}
> +
> +static inline int zorro_esp_wait_for_intr(struct esp *esp)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       int i = 500000;
> +
> +       do {
> +               esp->sreg = zorro_esp_read8(esp, ESP_STATUS);
> +               if (esp->sreg & ESP_STAT_INTR)
> +                       return 0;
> +
> +               udelay(2);
> +       } while (--i);
> +
> +       pr_err("IRQ timeout (sreg %02x)\n", esp->sreg);
> +       zep->error = 1;
> +       return 1;
> +}
> +
> +#define ZORRO_ESP_PIO_LOOP(operands, reg1) \
> +       { \
> +       asm volatile ( \
> +            "1:     moveb " operands "\n" \
> +            "       subqw #1,%1       \n" \
> +            "       jbne 1b           \n" \
> +            : "+a" (addr), "+r" (reg1) \
> +            : "a" (fifo)); \
> +       }
> +
> +#define ZORRO_ESP_PIO_FILL(operands, reg1) \
> +       { \
> +       asm volatile ( \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       moveb " operands "\n" \
> +            "       subqw #8,%1       \n" \
> +            "       subqw #8,%1       \n" \
> +            : "+a" (addr), "+r" (reg1) \
> +            : "a" (fifo)); \
> +       }
> +
> +#define ZORRO_ESP_FIFO_SIZE 16
> +
> +static void zorro_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
> +                                u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       u8 __iomem *fifo = esp->regs + ESP_FDATA * 16;
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +
> +       cmd &= ~ESP_CMD_DMA;
> +
> +       /* We are passed DMA addresses i.e. physical addresses, but must use
> +        * kernel virtual addresses here, so convert to virtual. This is easy
> +        * enough for the case of residual bytes of an extended message in
> +        * transfer - we know the address must be esp->command_block_dma.
> +        * In other cases, more work is needed to find a mapping.
> +        * Sidestep the issue by making sure we only end up here when using
> +        * esp->command_block as transfer buffer.
> +        */
> +       if (addr == esp->command_block_dma)
> +               addr = (u32) esp->command_block;
> +
> +       if (write) {
> +               u8 *dst = (u8 *)addr;
> +               u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV);
> +
> +               scsi_esp_cmd(esp, cmd);
> +
> +               while (1) {
> +                       if (!zorro_esp_wait_for_fifo(esp))
> +                               break;
> +
> +                       *dst++ = zorro_esp_read8(esp, ESP_FDATA);
> +                       --esp_count;
> +
> +                       if (!esp_count)
> +                               break;
> +
> +                       if (zorro_esp_wait_for_intr(esp))
> +                               break;
> +
> +                       if ((esp->sreg & ESP_STAT_PMASK) != phase)
> +                               break;
> +
> +                       esp->ireg = zorro_esp_read8(esp, ESP_INTRPT);
> +                       if (esp->ireg & mask) {
> +                               zep->error = 1;
> +                               break;
> +                       }
> +
> +                       if (phase == ESP_MIP)
> +                               scsi_esp_cmd(esp, ESP_CMD_MOK);
> +
> +                       scsi_esp_cmd(esp, ESP_CMD_TI);
> +               }
> +       } else {        /* unused, as long as we only handle MIP here */
> +               scsi_esp_cmd(esp, ESP_CMD_FLUSH);
> +
> +               if (esp_count >= ZORRO_ESP_FIFO_SIZE) {
> +                       ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count);
> +               } else
> +                       ZORRO_ESP_PIO_LOOP("%0@+,%2@", esp_count);
> +
> +               scsi_esp_cmd(esp, cmd);
> +
> +               while (esp_count) {
> +                       unsigned int n;
> +
> +                       if (zorro_esp_wait_for_intr(esp))
> +                               break;
> +
> +                       if ((esp->sreg & ESP_STAT_PMASK) != phase)
> +                               break;
> +
> +                       esp->ireg = zorro_esp_read8(esp, ESP_INTRPT);
> +                       if (esp->ireg & ~ESP_INTR_BSERV) {
> +                               zep->error = 1;
> +                               break;
> +                       }
> +
> +                       n = ZORRO_ESP_FIFO_SIZE -
> +                           (zorro_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES);
> +                       if (n > esp_count)
> +                               n = esp_count;
> +
> +                       if (n == ZORRO_ESP_FIFO_SIZE) {
> +                               ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count);
> +                       } else {
> +                               esp_count -= n;
> +                               ZORRO_ESP_PIO_LOOP("%0@+,%2@", n);
> +                       }
> +
> +                       scsi_esp_cmd(esp, ESP_CMD_TI);
> +               }
> +       }
> +}
> +
> +// Blizzard 1230/60 SCSI-IV DMA
> +
> +static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr,
> +                       u32 esp_count, u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct blz1230_dma_registers *dregs =
> +                       (struct blz1230_dma_registers *) (esp->dma_regs);
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +
> +       zep->error = 0;
> +       /* Use PIO if transferring message bytes to esp->command_block_dma */
> +       if (phase == ESP_MIP && addr == esp->command_block_dma) {
> +               zorro_esp_send_pio_cmd(esp, addr, esp_count,
> +                                       dma_count, write, cmd);
> +               return;
> +       }
> +
> +       if (write)
> +               /* DMA receive */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_FROM_DEVICE);
> +       else
> +               /* DMA send */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_TO_DEVICE);
> +
> +       addr >>= 1;
> +       if (write)
> +               addr &= ~(DMA_WRITE);
> +       else
> +               addr |= DMA_WRITE;
> +
> +       dregs->dma_latch = (addr >> 24) & 0xff;
> +       dregs->dma_addr  = (addr >> 24) & 0xff;
> +       dregs->dma_addr  = (addr >> 16) & 0xff;
> +       dregs->dma_addr  = (addr >>  8) & 0xff;
> +       dregs->dma_addr  =  addr & 0xff;
> +
> +       scsi_esp_cmd(esp, ESP_CMD_DMA);
> +       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
> +       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
> +       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
> +
> +       scsi_esp_cmd(esp, cmd);
> +}
> +
> +// Blizzard 1230-II DMA
> +
> +static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr,
> +                       u32 esp_count, u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct blz1230II_dma_registers *dregs =
> +                       (struct blz1230II_dma_registers *) (esp->dma_regs);
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +
> +       zep->error = 0;
> +       /* Use PIO if transferring message bytes to esp->command_block_dma */
> +       if (phase == ESP_MIP && addr == esp->command_block_dma) {
> +               zorro_esp_send_pio_cmd(esp, addr, esp_count,
> +                                       dma_count, write, cmd);
> +               return;
> +       }
> +
> +       if (write)
> +               /* DMA receive */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_FROM_DEVICE);
> +       else
> +               /* DMA send */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_TO_DEVICE);
> +
> +       addr >>= 1;
> +       if (write)
> +               addr &= ~(DMA_WRITE);
> +       else
> +               addr |= DMA_WRITE;
> +
> +       dregs->dma_latch = (addr >> 24) & 0xff;
> +       dregs->dma_addr  = (addr >> 16) & 0xff;
> +       dregs->dma_addr  = (addr >>  8) & 0xff;
> +       dregs->dma_addr  =  addr & 0xff;
> +
> +       scsi_esp_cmd(esp, ESP_CMD_DMA);
> +       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
> +       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
> +       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
> +
> +       scsi_esp_cmd(esp, cmd);
> +}
> +
> +// Blizzard 2060 DMA
> +
> +static void zorro_esp_send_blz2060_dma_cmd(struct esp *esp, u32 addr,
> +                       u32 esp_count, u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct blz2060_dma_registers *dregs =
> +                       (struct blz2060_dma_registers *) (esp->dma_regs);
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +
> +       zep->error = 0;
> +       /* Use PIO if transferring message bytes to esp->command_block_dma */
> +       if (phase == ESP_MIP && addr == esp->command_block_dma) {
> +               zorro_esp_send_pio_cmd(esp, addr, esp_count,
> +                                       dma_count, write, cmd);
> +               return;
> +       }
> +
> +       if (write)
> +               /* DMA receive */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_FROM_DEVICE);
> +       else
> +               /* DMA send */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_TO_DEVICE);
> +
> +       addr >>= 1;
> +       if (write)
> +               addr &= ~(DMA_WRITE);
> +       else
> +               addr |= DMA_WRITE;
> +
> +       dregs->dma_addr3 =  addr & 0xff;
> +       dregs->dma_addr2 = (addr >>  8) & 0xff;
> +       dregs->dma_addr1 = (addr >> 16) & 0xff;
> +       dregs->dma_addr0 = (addr >> 24) & 0xff;
> +
> +       scsi_esp_cmd(esp, ESP_CMD_DMA);
> +       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
> +       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
> +       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
> +
> +       scsi_esp_cmd(esp, cmd);
> +}
> +
> +// Cyberstorm I DMA
> +
> +static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr,
> +                       u32 esp_count, u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct cyber_dma_registers *dregs =
> +               (struct cyber_dma_registers *) (esp->dma_regs);
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +       unsigned char *ctrl_data = &zep->ctrl_data;
> +
> +       zep->error = 0;
> +       /* Use PIO if transferring message bytes to esp->command_block_dma */
> +       if (phase == ESP_MIP && addr == esp->command_block_dma) {
> +               zorro_esp_send_pio_cmd(esp, addr, esp_count,
> +                                       dma_count, write, cmd);
> +               return;
> +       }
> +
> +       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
> +       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
> +       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
> +
> +       if (write) {
> +               /* DMA receive */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_FROM_DEVICE);
> +               addr &= ~(1);
> +       } else {
> +               /* DMA send */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_TO_DEVICE);
> +               addr |= 1;
> +       }
> +
> +       dregs->dma_addr0 = (addr >> 24) & 0xff;
> +       dregs->dma_addr1 = (addr >> 16) & 0xff;
> +       dregs->dma_addr2 = (addr >>  8) & 0xff;
> +       dregs->dma_addr3 =  addr & 0xff;
> +
> +       if (write)
> +               *ctrl_data &= ~(CYBER_DMA_WRITE);
> +       else
> +               *ctrl_data |= CYBER_DMA_WRITE;
> +
> +       *ctrl_data &= ~(CYBER_DMA_Z3);  /* Z2, do 16 bit DMA */
> +
> +       dregs->ctrl_reg = *ctrl_data;
> +
> +       scsi_esp_cmd(esp, cmd);
> +}
> +
> +// Cyberstorm II DMA
> +
> +static void zorro_esp_send_cyberII_dma_cmd(struct esp *esp, u32 addr,
> +                       u32 esp_count, u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct cyberII_dma_registers *dregs =
> +               (struct cyberII_dma_registers *) (esp->dma_regs);
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +
> +       zep->error = 0;
> +       /* Use PIO if transferring message bytes to esp->command_block_dma */
> +       if (phase == ESP_MIP && addr == esp->command_block_dma) {
> +               zorro_esp_send_pio_cmd(esp, addr, esp_count,
> +                                       dma_count, write, cmd);
> +               return;
> +       }
> +
> +       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
> +       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
> +       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
> +
> +       if (write) {
> +               /* DMA receive */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_FROM_DEVICE);
> +               addr &= ~(1);
> +       } else {
> +               /* DMA send */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_TO_DEVICE);
> +               addr |= 1;
> +       }
> +
> +       dregs->dma_addr0 = (addr >> 24) & 0xff;
> +       dregs->dma_addr1 = (addr >> 16) & 0xff;
> +       dregs->dma_addr2 = (addr >>  8) & 0xff;
> +       dregs->dma_addr3 =  addr & 0xff;
> +
> +       scsi_esp_cmd(esp, cmd);
> +}
> +
> +// Fastlane DMA
> +
> +static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr,
> +                       u32 esp_count, u32 dma_count, int write, u8 cmd)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +       struct fastlane_dma_registers *dregs =
> +               (struct fastlane_dma_registers *) (esp->dma_regs);
> +       u8 phase = esp->sreg & ESP_STAT_PMASK;
> +               unsigned char *ctrl_data = &zep->ctrl_data;
> +       unsigned long *t;
> +
> +       zep->error = 0;
> +       /* Use PIO if transferring message bytes to esp->command_block_dma */
> +       if (phase == ESP_MIP && addr == esp->command_block_dma) {
> +               zorro_esp_send_pio_cmd(esp, addr, esp_count,
> +                                       dma_count, write, cmd);
> +               return;
> +       }
> +
> +       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
> +       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
> +       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
> +
> +       if (write) {
> +               /* DMA receive */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_FROM_DEVICE);
> +               addr &= ~(1);
> +       } else {
> +               /* DMA send */
> +               dma_sync_single_for_device(esp->dev, addr, esp_count,
> +                               DMA_TO_DEVICE);
> +               addr |= 1;
> +       }
> +
> +       t = (unsigned long *)((addr & 0x00ffffff) + zep->board_base);
> +
> +       dregs->clear_strobe = 0;
> +       *t = addr;
> +
> +       if (write) {
> +               *ctrl_data = (*ctrl_data & FASTLANE_DMA_MASK) |
> +                               FASTLANE_DMA_ENABLE;
> +       } else {
> +               *ctrl_data = ((*ctrl_data & FASTLANE_DMA_MASK) |
> +                               FASTLANE_DMA_ENABLE |
> +                               FASTLANE_DMA_WRITE);
> +       }
> +
> +       dregs->ctrl_reg = *ctrl_data;
> +
> +       scsi_esp_cmd(esp, cmd);
> +}
> +
> +static int zorro_esp_dma_error(struct esp *esp)
> +{
> +       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
> +
> +       /* check for error in case we've been doing PIO */
> +       if (zep->error == 1)
> +               return 1;
> +
> +       /* do nothing - there seems to be no way to check for DMA errors */
> +       return 0;
> +}
> +
> +static struct esp_driver_ops zorro_esp_ops = {
> +       .esp_write8       =     zorro_esp_write8,
> +       .esp_read8        =     zorro_esp_read8,
> +       .map_single       =     zorro_esp_map_single,
> +       .map_sg           =     zorro_esp_map_sg,
> +       .unmap_single     =     zorro_esp_unmap_single,
> +       .unmap_sg         =     zorro_esp_unmap_sg,
> +       .irq_pending      =     zorro_esp_irq_pending,
> +       .dma_length_limit =     zorro_esp_dma_length_limit,
> +       .reset_dma        =     zorro_esp_reset_dma,
> +       .dma_drain        =     zorro_esp_dma_drain,
> +       .dma_invalidate   =     zorro_esp_dma_invalidate,
> +       .send_dma_cmd     =     zorro_esp_send_blz2060_dma_cmd,
> +       .dma_error        =     zorro_esp_dma_error,
> +};
> +
> +static int zorro_esp_probe(struct zorro_dev *z,
> +                                      const struct zorro_device_id *ent)
> +{
> +       struct scsi_host_template *tpnt = &scsi_esp_template;
> +       struct Scsi_Host *host;
> +       struct esp *esp;
> +       struct zorro_driver_data *zdd;
> +       struct zorro_esp_priv *zep;
> +       unsigned long board, ioaddr, dmaaddr;
> +       int err;
> +
> +       board = zorro_resource_start(z);
> +       zdd = (struct zorro_driver_data *)ent->driver_data;
> +
> +       pr_info("%s found at address 0x%lx.\n", zdd->name, board);
> +
> +       zep = kmalloc(sizeof(*zep), GFP_KERNEL);
> +       if (!zep) {
> +               pr_err("Can't allocate device private data!\n");
> +               return -ENOMEM;
> +       }
> +
> +       /* let's figure out whether we have a Zorro II or Zorro III board */
> +       if ((z->rom.er_Type & ERT_TYPEMASK) == ERT_ZORROIII) {
> +               /* note this is a Zorro III board */
> +               if (board > 0xffffff)
> +                       zep->zorro3 = 1;
> +       } else
> +               /* Even though most of these boards identify as Zorro II,
> +                * they are in fact CPU expansion slot boards and have full
> +                * access to all of memory. Fix up DMA bitmask here.
> +                */
> +               z->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> +       /* If Zorro III and ID matches Fastlane, our device table entry
> +        * contains data for the Blizzard 1230 II board which does share the
> +        * same ID. Fix up device table entry here.
> +        * TODO: Some Cyberstom060 boards also share this ID but would need
> +        * to use the Cyberstorm I driver data ... we catch this by checking
> +        * for presence of ESP chip later, but don't try to fix up yet.
> +        */
> +       if (zep->zorro3 && ent->id ==
> +       ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) {
> +               pr_info("%s at address 0x%lx is Fastlane Z3, fixing data!\n",
> +                       zdd->name, board);
> +               zdd = &fastlanez3_data;
> +       }
> +
> +       if (zdd->absolute) {
> +               ioaddr  = zdd->offset;
> +               dmaaddr = zdd->dma_offset;
> +       } else {
> +               ioaddr  = board + zdd->offset;
> +               dmaaddr = board + zdd->dma_offset;
> +       }
> +
> +       if (!zorro_request_device(z, zdd->name)) {
> +               pr_err("cannot reserve region 0x%lx, abort\n",
> +                      board);
> +               err = -EBUSY;
> +               goto fail_free_zep;
> +       }
> +
> +       /* Fill in the required pieces of hostdata */
> +
> +       host = scsi_host_alloc(tpnt, sizeof(struct esp));
> +
> +       if (!host) {
> +               pr_err("No host detected; board configuration problem?\n");
> +               err = -ENOMEM;
> +               goto fail_release_device;
> +       }
> +
> +       host->base              = ioaddr;
> +       host->this_id           = 7;
> +
> +       esp                     = shost_priv(host);
> +       esp->host               = host;
> +       esp->dev                = &z->dev;
> +
> +       esp->scsi_id            = host->this_id;
> +       esp->scsi_id_mask       = (1 << esp->scsi_id);
> +
> +       esp->cfreq = 40000000;
> +
> +       zep->error = 0;
> +       zep->esp = esp;
> +
> +       dev_set_drvdata(esp->dev, zep);
> +
> +       /* Switch to the correct the DMA routine and clock frequency. */
> +       switch (ent->id) {
> +       case ZORRO_PROD_PHASE5_BLIZZARD_2060:
> +               zorro_esp_ops.send_dma_cmd = zorro_esp_send_blz2060_dma_cmd;
> +               break;
> +       case ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260:
> +               zorro_esp_ops.send_dma_cmd = zorro_esp_send_blz1230_dma_cmd;
> +               break;
> +       case ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM:
> +               zorro_esp_ops.send_dma_cmd = zorro_esp_send_cyber_dma_cmd;
> +               zorro_esp_ops.irq_pending  = cyber_esp_irq_pending;
> +               break;
> +       case ZORRO_PROD_PHASE5_CYBERSTORM_MK_II:
> +               zorro_esp_ops.send_dma_cmd = zorro_esp_send_cyberII_dma_cmd;
> +               break;
> +       case ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060:
> +               if (zep->zorro3) {
> +                       /* Fastlane Zorro III board */
> +                       /* map address space up to ESP address for DMA */
> +                       zep->board_base = ioremap_nocache(board,
> +                                                       FASTLANE_ESP_ADDR-1);
> +                       if (!zep->board_base) {
> +                               pr_err("Cannot allocate board address space\n");
> +                               err = -ENOMEM;
> +                               goto fail_free_host;
> +                       }
> +                       /* initialize DMA control shadow register */
> +                       zep->ctrl_data = (FASTLANE_DMA_FCODE |
> +                                         FASTLANE_DMA_EDI | FASTLANE_DMA_ESI);
> +                       zorro_esp_ops.send_dma_cmd =
> +                                       zorro_esp_send_fastlane_dma_cmd;
> +                       zorro_esp_ops.irq_pending  = fastlane_esp_irq_pending;
> +                       zorro_esp_ops.dma_invalidate =
> +                                       fastlane_esp_dma_invalidate;
> +               } else {
> +                       /* Blizzard 1230 II Zorro II board */
> +                       zorro_esp_ops.send_dma_cmd =
> +                                       zorro_esp_send_blz1230II_dma_cmd;
> +               }
> +               break;
> +       default:
> +               /* Oh noes */
> +               pr_err("Unsupported board!\n");
> +               err = -ENODEV;
> +               goto fail_free_host;
> +       }
> +
> +       esp->ops = &zorro_esp_ops;
> +
> +       if (ioaddr > 0xffffff)
> +               esp->regs = ioremap_nocache(ioaddr, 0x20);
> +       else
> +               esp->regs = (void __iomem *)ZTWO_VADDR(ioaddr);
> +
> +       if (!esp->regs) {
> +               err = -ENOMEM;
> +               goto fail_unmap_fastlane;
> +       }
> +
> +       /* Check whether a Blizzard 12x0 or CyberstormII really has SCSI */
> +       if (zdd->scsi_option) {
> +               zorro_esp_write8(esp, (ESP_CONFIG1_PENABLE | 7), ESP_CFG1);
> +               if (zorro_esp_read8(esp, ESP_CFG1) != (ESP_CONFIG1_PENABLE|7)) {
> +                       err = -ENODEV;
> +                       goto fail_unmap_regs;
> +               }
> +       }
> +
> +       if (zep->zorro3) {
> +               /* Only Fastlane Z3 for now - add switch for correct struct
> +                * dma_registers size if adding any more
> +                */
> +               esp->dma_regs = ioremap_nocache(dmaaddr,
> +                               sizeof(struct fastlane_dma_registers));
> +       } else
> +               esp->dma_regs = (void __iomem *)ZTWO_VADDR(dmaaddr);
> +
> +       if (!esp->dma_regs) {
> +               err = -ENOMEM;
> +               goto fail_unmap_regs;
> +       }
> +
> +       esp->command_block = dma_alloc_coherent(esp->dev, 16,
> +                                               &esp->command_block_dma,
> +                                               GFP_KERNEL);
> +
> +       if (!esp->command_block) {
> +               err = -ENOMEM;
> +               goto fail_unmap_dma_regs;
> +       }
> +
> +       host->irq = IRQ_AMIGA_PORTS;
> +       err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
> +                         "Amiga Zorro ESP", esp);
> +       if (err < 0) {
> +               err = -ENODEV;
> +               goto fail_free_command_block;
> +       }
> +
> +       /* register the chip */
> +       err = scsi_esp_register(esp, &z->dev);
> +
> +       if (err) {
> +               err = -ENOMEM;
> +               goto fail_free_irq;
> +       }
> +
> +       //zorro_set_drvdata(z, host);
> +
> +       return 0;
> +
> +fail_free_irq:
> +       free_irq(host->irq, esp);
> +
> +fail_free_command_block:
> +       dma_free_coherent(esp->dev, 16,
> +                         esp->command_block,
> +                         esp->command_block_dma);
> +
> +fail_unmap_dma_regs:
> +       if (zep->zorro3)
> +               iounmap(esp->dma_regs);
> +
> +fail_unmap_regs:
> +       if (ioaddr > 0xffffff)
> +               iounmap(esp->regs);
> +
> +fail_unmap_fastlane:
> +       if (zep->zorro3)
> +               iounmap(zep->board_base);
> +
> +fail_free_host:
> +       scsi_host_put(host);
> +
> +fail_release_device:
> +       zorro_release_device(z);
> +
> +fail_free_zep:
> +       kfree(zep);
> +
> +       return err;
> +}
> +
> +static void zorro_esp_remove(struct zorro_dev *z)
> +{
> +       /* equivalent to dev_get_drvdata(z->dev) */
> +       struct zorro_esp_priv *zep = zorro_get_drvdata(z);
> +       struct esp *esp = zep->esp;
> +       struct Scsi_Host *host = esp->host;
> +
> +       scsi_esp_unregister(esp);
> +
> +       /* Disable interrupts. Perhaps use disable_irq instead ... */
> +
> +       free_irq(host->irq, esp);
> +       dma_free_coherent(esp->dev, 16,
> +                         esp->command_block,
> +                         esp->command_block_dma);
> +
> +       if (zep->zorro3) {
> +               iounmap(zep->board_base);
> +               iounmap(esp->dma_regs);
> +       }
> +
> +       if (host->base > 0xffffff)
> +               iounmap(esp->regs);
> +
> +       scsi_host_put(host);
> +
> +       zorro_release_device(z);
> +
> +       kfree(zep);
> +}
> +
> +static struct zorro_driver zorro_esp_driver = {
> +       .name     = KBUILD_MODNAME,
> +       .id_table = zorro_esp_zorro_tbl,
> +       .probe    = zorro_esp_probe,
> +       .remove   = zorro_esp_remove,
> +};
> +
> +static int __init zorro_esp_scsi_init(void)
> +{
> +       return zorro_register_driver(&zorro_esp_driver);
> +}
> +
> +static void __exit zorro_esp_scsi_exit(void)
> +{
> +       zorro_unregister_driver(&zorro_esp_driver);
> +}
> +
> +module_init(zorro_esp_scsi_init);
> +module_exit(zorro_esp_scsi_exit);
> --
> 1.7.0.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
diff mbox

Patch

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8a739b7..c7d337f 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1462,6 +1462,22 @@  config SCSI_ZORRO7XX
              accelerator card for the Amiga 1200,
            - the SCSI controller on the GVP Turbo 040/060 accelerator.

+config SCSI_ZORRO_ESP
+       tristate "Zorro ESP SCSI support"
+       depends on ZORRO && SCSI
+       select SCSI_SPI_ATTRS
+       help
+         Support for various ESP-based SCSI controllers on Zorro
+         expansion boards for the Amiga.
+         This includes:
+           - the Amiga 4091 Zorro III SCSI-2 controller,
+           - the MacroSystem Development's WarpEngine Amiga SCSI-2 controller
+             (info at
+             <http://www.lysator.liu.se/amiga/ar/guide/ar310.guide?FEATURE5>),
+           - the SCSI controller on the Phase5 Blizzard PowerUP 603e+
+             accelerator card for the Amiga 1200,
+           - the SCSI controller on the GVP Turbo 040/060 accelerator.
+
 config ATARI_SCSI
        tristate "Atari native SCSI support"
        depends on ATARI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index fcfd28d..6f13c03 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -48,6 +48,7 @@  obj-$(CONFIG_INFINIBAND_ISER)         += libiscsi.o
 obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
 obj-$(CONFIG_SCSI_A4000T)      += 53c700.o     a4000t.o
 obj-$(CONFIG_SCSI_ZORRO7XX)    += 53c700.o     zorro7xx.o
+obj-$(CONFIG_SCSI_ZORRO_ESP)   += esp_scsi.o   zorro_esp.o
 obj-$(CONFIG_A3000_SCSI)       += a3000.o      wd33c93.o
 obj-$(CONFIG_A2091_SCSI)       += a2091.o      wd33c93.o
 obj-$(CONFIG_GVP11_SCSI)       += gvp11.o      wd33c93.o
diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c
new file mode 100644
index 0000000..47053d1
--- /dev/null
+++ b/drivers/scsi/zorro_esp.c
@@ -0,0 +1,1136 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* zorro_esp.c: ESP front-end for Amiga ZORRO SCSI systems.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Copyright (C) 2011,2018 Michael Schmitz (schmitz@debian.org) for
+ *               migration to ESP SCSI core
+ *
+ * Copyright (C) 2013 Tuomas Vainikka (tuomas.vainikka@aalto.fi) for
+ *               Blizzard 1230 DMA and probe function fixes
+ *
+ * Copyright (C) 2017 Finn Thain for PIO code from Mac ESP driver adapted here
+ */
+/*
+ * ZORRO bus code from:
+ */
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ *             Amiga MacroSystemUS WarpEngine SCSI controller.
+ *             Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#define KBUILD_MODNAME     "zorro_esp"
+#define pr_fmt(fmt)        KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/delay.h>
+#include <linux/zorro.h>
+#include <linux/slab.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_spi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+
+#include "esp_scsi.h"
+
+MODULE_AUTHOR("Michael Schmitz <schmitz@debian.org>");
+MODULE_DESCRIPTION("Amiga Zorro NCR5C9x (ESP) driver");
+MODULE_LICENSE("GPL");
+
+struct zorro_driver_data {
+       const char *name;
+       unsigned long offset;
+       unsigned long dma_offset;
+       int absolute;   /* offset is absolute address */
+       int scsi_option;
+};
+
+static struct zorro_driver_data cyberstormI_data = {
+       .name = "CyberStormI",
+       .offset = 0xf400,
+       .dma_offset = 0xf800,
+       .absolute = 0,
+       .scsi_option = 0,
+};
+
+static struct zorro_driver_data cyberstormII_data = {
+       .name = "CyberStormII",
+       .offset = 0x1ff03,
+       .dma_offset = 0x1ff43,
+       .absolute = 0,
+       .scsi_option = 1,
+};
+
+static struct zorro_driver_data blizzard2060_data = {
+       .name = "Blizzard 2060",
+       .offset = 0x1ff00,
+       .dma_offset = 0x1ffe0,
+       .absolute = 0,
+       .scsi_option = 0,
+};
+
+static struct zorro_driver_data blizzard1230_data = {
+       .name = "Blizzard 1230",
+       .offset = 0x8000,
+       .dma_offset = 0x10000,
+       .absolute = 0,
+       .scsi_option = 1,
+};
+
+static struct zorro_driver_data blizzard1230II_data = {
+       .name = "Blizzard 1230II",
+       .offset = 0x10000,
+       .dma_offset = 0x10021,
+       .absolute = 0,
+       .scsi_option = 1,
+};
+
+static struct zorro_driver_data fastlanez3_data = {
+       .name = "Fastlane",
+       .offset = 0x1000001,
+       .dma_offset = 0x1000041,
+       .absolute = 0,
+       .scsi_option = 0,
+};
+
+static struct zorro_device_id zorro_esp_zorro_tbl[] = {
+       {
+               .id = ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM,
+               .driver_data = (unsigned long)&cyberstormI_data,
+       },
+       {
+               .id = ZORRO_PROD_PHASE5_CYBERSTORM_MK_II,
+               .driver_data = (unsigned long)&cyberstormII_data,
+       },
+       {
+               .id = ZORRO_PROD_PHASE5_BLIZZARD_2060,
+               .driver_data = (unsigned long)&blizzard2060_data,
+       },
+       {
+               .id = ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260,
+               .driver_data = (unsigned long)&blizzard1230_data,
+       },
+       {
+               .id = ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060,
+               .driver_data = (unsigned long)&blizzard1230II_data,
+       },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(zorro, zorro_esp_zorro_tbl);
+
+/* Blizzard 1230 DMA interface */
+
+struct blz1230_dma_registers {
+       volatile unsigned char dma_addr;        /* DMA address      [0x0000] */
+       unsigned char dmapad2[0x7fff];
+       volatile unsigned char dma_latch;       /* DMA latch        [0x8000] */
+};
+
+/* Blizzard 1230II DMA interface */
+
+struct blz1230II_dma_registers {
+       volatile unsigned char dma_addr;        /* DMA address      [0x0000] */
+       unsigned char dmapad2[0xf];
+       volatile unsigned char dma_latch;       /* DMA latch        [0x0010] */
+};
+
+/* Blizzard 2060 DMA interface */
+
+struct blz2060_dma_registers {
+       volatile unsigned char dma_led_ctrl;    /* DMA led control   [0x000] */
+       unsigned char dmapad1[0x0f];
+       volatile unsigned char dma_addr0;       /* DMA address (MSB) [0x010] */
+       unsigned char dmapad2[0x03];
+       volatile unsigned char dma_addr1;       /* DMA address       [0x014] */
+       unsigned char dmapad3[0x03];
+       volatile unsigned char dma_addr2;       /* DMA address       [0x018] */
+       unsigned char dmapad4[0x03];
+       volatile unsigned char dma_addr3;       /* DMA address (LSB) [0x01c] */
+};
+
+/* DMA control bits */
+#define DMA_WRITE 0x80000000
+
+/* Cyberstorm DMA interface */
+
+struct cyber_dma_registers {
+       volatile unsigned char dma_addr0;       /* DMA address (MSB) [0x000] */
+       unsigned char dmapad1[1];
+       volatile unsigned char dma_addr1;       /* DMA address       [0x002] */
+       unsigned char dmapad2[1];
+       volatile unsigned char dma_addr2;       /* DMA address       [0x004] */
+       unsigned char dmapad3[1];
+       volatile unsigned char dma_addr3;       /* DMA address (LSB) [0x006] */
+       unsigned char dmapad4[0x3fb];
+       volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x402] */
+#define ctrl_reg  cond_reg                     /* DMA control (wo)  [0x402] */
+};
+
+/* DMA control bits */
+#define CYBER_DMA_WRITE  0x40  /* DMA direction. 1 = write */
+#define CYBER_DMA_Z3     0x20  /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
+
+/* DMA status bits */
+#define CYBER_DMA_HNDL_INTR 0x80       /* DMA IRQ pending? */
+
+/* The CyberStorm II DMA interface */
+struct cyberII_dma_registers {
+       volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x000] */
+#define ctrl_reg  cond_reg                     /* DMA control (wo)  [0x000] */
+       unsigned char dmapad4[0x3f];
+       volatile unsigned char dma_addr0;       /* DMA address (MSB) [0x040] */
+       unsigned char dmapad1[3];
+       volatile unsigned char dma_addr1;       /* DMA address       [0x044] */
+       unsigned char dmapad2[3];
+       volatile unsigned char dma_addr2;       /* DMA address       [0x048] */
+       unsigned char dmapad3[3];
+       volatile unsigned char dma_addr3;       /* DMA address (LSB) [0x04c] */
+};
+
+/* Fastlane DMA interface */
+
+struct fastlane_dma_registers {
+       volatile unsigned char cond_reg;        /* DMA status  (ro) [0x0000] */
+#define ctrl_reg  cond_reg                     /* DMA control (wo) [0x0000] */
+       unsigned char dmapad1[0x3f];
+       volatile unsigned char clear_strobe;    /* DMA clear   (wo) [0x0040] */
+};
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define FASTLANE_ESP_ADDR      0x1000001
+
+/* DMA status bits */
+#define FASTLANE_DMA_MINT      0x80
+#define FASTLANE_DMA_IACT      0x40
+#define FASTLANE_DMA_CREQ      0x20
+
+/* DMA control bits */
+#define FASTLANE_DMA_FCODE     0xa0
+#define FASTLANE_DMA_MASK      0xf3
+#define FASTLANE_DMA_WRITE     0x08    /* 1 = write */
+#define FASTLANE_DMA_ENABLE    0x04    /* Enable DMA */
+#define FASTLANE_DMA_EDI       0x02    /* Enable DMA IRQ ? */
+#define FASTLANE_DMA_ESI       0x01    /* Enable SCSI IRQ */
+
+/*
+ * private data used for driver
+ */
+struct zorro_esp_priv {
+       struct esp *esp;                /* our ESP instance - for Scsi_host* */
+       unsigned long *board_base;      /* virtual address (Zorro III board) */
+       int error;                      /* PIO error flag */
+       int zorro3;                     /* board is Zorro III */
+       unsigned char ctrl_data;        /* shadow copy of ctrl_reg */
+};
+
+#define ZORRO_ESP_GET_PRIV(esp) ((struct zorro_esp_priv *) \
+                               dev_get_drvdata(esp->dev))
+
+/*
+ * On all implementations except for the Oktagon, padding between ESP
+ * registers is three bytes.
+ * On Oktagon, it is one byte - use a different accessor there.
+ *
+ * Oktagon needs PDMA - currently unsupported!
+ */
+
+static void zorro_esp_write8(struct esp *esp, u8 val, unsigned long reg)
+{
+       writeb(val, esp->regs + (reg * 4UL));
+}
+
+static u8 zorro_esp_read8(struct esp *esp, unsigned long reg)
+{
+       return readb(esp->regs + (reg * 4UL));
+}
+
+static dma_addr_t zorro_esp_map_single(struct esp *esp, void *buf,
+                                     size_t sz, int dir)
+{
+       return dma_map_single(esp->dev, buf, sz, dir);
+}
+
+static int zorro_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+                                 int num_sg, int dir)
+{
+       return dma_map_sg(esp->dev, sg, num_sg, dir);
+}
+
+static void zorro_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+                                 size_t sz, int dir)
+{
+       dma_unmap_single(esp->dev, addr, sz, dir);
+}
+
+static void zorro_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+                             int num_sg, int dir)
+{
+       dma_unmap_sg(esp->dev, sg, num_sg, dir);
+}
+
+static int zorro_esp_irq_pending(struct esp *esp)
+{
+       /* check ESP status register; DMA has no status reg. */
+
+       if (zorro_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR)
+               return 1;
+
+       return 0;
+}
+
+static int cyber_esp_irq_pending(struct esp *esp)
+{
+       /* It's important to check the DMA IRQ bit in the correct way! */
+       return ((zorro_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) &&
+               ((((struct cyber_dma_registers *)(esp->dma_regs))->cond_reg) &
+                CYBER_DMA_HNDL_INTR));
+       return 0;
+}
+
+static int fastlane_esp_irq_pending(struct esp *esp)
+{
+       struct fastlane_dma_registers *dregs =
+               (struct fastlane_dma_registers *) (esp->dma_regs);
+       unsigned char dma_status;
+
+       dma_status = dregs->cond_reg;
+
+       if (dma_status & FASTLANE_DMA_IACT)
+               return 0;       /* not our IRQ */
+
+       /* Return non-zero if ESP requested IRQ */
+       return (
+          (dma_status & FASTLANE_DMA_CREQ) &&
+          (!(dma_status & FASTLANE_DMA_MINT)) &&
+          (zorro_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR));
+}
+
+static u32 zorro_esp_dma_length_limit(struct esp *esp, u32 dma_addr,
+                                       u32 dma_len)
+{
+       return dma_len > 0xFFFFFF ? 0xFFFFFF : dma_len;
+}
+
+static void zorro_esp_reset_dma(struct esp *esp)
+{
+       /* nothing to do here */
+}
+
+static void zorro_esp_dma_drain(struct esp *esp)
+{
+       /* nothing to do here */
+}
+
+static void zorro_esp_dma_invalidate(struct esp *esp)
+{
+       /* nothing to do here */
+}
+
+static void fastlane_esp_dma_invalidate(struct esp *esp)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct fastlane_dma_registers *dregs =
+               (struct fastlane_dma_registers *) (esp->dma_regs);
+       unsigned char *ctrl_data = &zep->ctrl_data;
+       unsigned long *t;
+
+       *ctrl_data = (*ctrl_data & FASTLANE_DMA_MASK);
+       dregs->ctrl_reg = *ctrl_data;
+
+       t = (unsigned long *)(zep->board_base);
+
+       dregs->clear_strobe = 0;
+       *t = 0;
+}
+
+/*
+ * Programmed IO routines follow.
+ */
+
+static inline unsigned int zorro_esp_wait_for_fifo(struct esp *esp)
+{
+       int i = 500000;
+
+       do {
+               unsigned int fbytes = zorro_esp_read8(esp, ESP_FFLAGS)
+                                                       & ESP_FF_FBYTES;
+
+               if (fbytes)
+                       return fbytes;
+
+               udelay(2);
+       } while (--i);
+
+       pr_err("FIFO is empty (sreg %02x)\n",
+              zorro_esp_read8(esp, ESP_STATUS));
+       return 0;
+}
+
+static inline int zorro_esp_wait_for_intr(struct esp *esp)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       int i = 500000;
+
+       do {
+               esp->sreg = zorro_esp_read8(esp, ESP_STATUS);
+               if (esp->sreg & ESP_STAT_INTR)
+                       return 0;
+
+               udelay(2);
+       } while (--i);
+
+       pr_err("IRQ timeout (sreg %02x)\n", esp->sreg);
+       zep->error = 1;
+       return 1;
+}
+
+#define ZORRO_ESP_PIO_LOOP(operands, reg1) \
+       { \
+       asm volatile ( \
+            "1:     moveb " operands "\n" \
+            "       subqw #1,%1       \n" \
+            "       jbne 1b           \n" \
+            : "+a" (addr), "+r" (reg1) \
+            : "a" (fifo)); \
+       }
+
+#define ZORRO_ESP_PIO_FILL(operands, reg1) \
+       { \
+       asm volatile ( \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       moveb " operands "\n" \
+            "       subqw #8,%1       \n" \
+            "       subqw #8,%1       \n" \
+            : "+a" (addr), "+r" (reg1) \
+            : "a" (fifo)); \
+       }
+
+#define ZORRO_ESP_FIFO_SIZE 16
+
+static void zorro_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
+                                u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       u8 __iomem *fifo = esp->regs + ESP_FDATA * 16;
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+
+       cmd &= ~ESP_CMD_DMA;
+
+       /* We are passed DMA addresses i.e. physical addresses, but must use
+        * kernel virtual addresses here, so convert to virtual. This is easy
+        * enough for the case of residual bytes of an extended message in
+        * transfer - we know the address must be esp->command_block_dma.
+        * In other cases, more work is needed to find a mapping.
+        * Sidestep the issue by making sure we only end up here when using
+        * esp->command_block as transfer buffer.
+        */
+       if (addr == esp->command_block_dma)
+               addr = (u32) esp->command_block;
+
+       if (write) {
+               u8 *dst = (u8 *)addr;
+               u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV);
+
+               scsi_esp_cmd(esp, cmd);
+
+               while (1) {
+                       if (!zorro_esp_wait_for_fifo(esp))
+                               break;
+
+                       *dst++ = zorro_esp_read8(esp, ESP_FDATA);
+                       --esp_count;
+
+                       if (!esp_count)
+                               break;
+
+                       if (zorro_esp_wait_for_intr(esp))
+                               break;
+
+                       if ((esp->sreg & ESP_STAT_PMASK) != phase)
+                               break;
+
+                       esp->ireg = zorro_esp_read8(esp, ESP_INTRPT);
+                       if (esp->ireg & mask) {
+                               zep->error = 1;
+                               break;
+                       }
+
+                       if (phase == ESP_MIP)
+                               scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+                       scsi_esp_cmd(esp, ESP_CMD_TI);
+               }
+       } else {        /* unused, as long as we only handle MIP here */
+               scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+               if (esp_count >= ZORRO_ESP_FIFO_SIZE) {
+                       ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count);
+               } else
+                       ZORRO_ESP_PIO_LOOP("%0@+,%2@", esp_count);
+
+               scsi_esp_cmd(esp, cmd);
+
+               while (esp_count) {
+                       unsigned int n;
+
+                       if (zorro_esp_wait_for_intr(esp))
+                               break;
+
+                       if ((esp->sreg & ESP_STAT_PMASK) != phase)
+                               break;
+
+                       esp->ireg = zorro_esp_read8(esp, ESP_INTRPT);
+                       if (esp->ireg & ~ESP_INTR_BSERV) {
+                               zep->error = 1;
+                               break;
+                       }
+
+                       n = ZORRO_ESP_FIFO_SIZE -
+                           (zorro_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES);
+                       if (n > esp_count)
+                               n = esp_count;
+
+                       if (n == ZORRO_ESP_FIFO_SIZE) {
+                               ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count);
+                       } else {
+                               esp_count -= n;
+                               ZORRO_ESP_PIO_LOOP("%0@+,%2@", n);
+                       }
+
+                       scsi_esp_cmd(esp, ESP_CMD_TI);
+               }
+       }
+}
+
+// Blizzard 1230/60 SCSI-IV DMA
+
+static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr,
+                       u32 esp_count, u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct blz1230_dma_registers *dregs =
+                       (struct blz1230_dma_registers *) (esp->dma_regs);
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+
+       zep->error = 0;
+       /* Use PIO if transferring message bytes to esp->command_block_dma */
+       if (phase == ESP_MIP && addr == esp->command_block_dma) {
+               zorro_esp_send_pio_cmd(esp, addr, esp_count,
+                                       dma_count, write, cmd);
+               return;
+       }
+
+       if (write)
+               /* DMA receive */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_FROM_DEVICE);
+       else
+               /* DMA send */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_TO_DEVICE);
+
+       addr >>= 1;
+       if (write)
+               addr &= ~(DMA_WRITE);
+       else
+               addr |= DMA_WRITE;
+
+       dregs->dma_latch = (addr >> 24) & 0xff;
+       dregs->dma_addr  = (addr >> 24) & 0xff;
+       dregs->dma_addr  = (addr >> 16) & 0xff;
+       dregs->dma_addr  = (addr >>  8) & 0xff;
+       dregs->dma_addr  =  addr & 0xff;
+
+       scsi_esp_cmd(esp, ESP_CMD_DMA);
+       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+       scsi_esp_cmd(esp, cmd);
+}
+
+// Blizzard 1230-II DMA
+
+static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr,
+                       u32 esp_count, u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct blz1230II_dma_registers *dregs =
+                       (struct blz1230II_dma_registers *) (esp->dma_regs);
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+
+       zep->error = 0;
+       /* Use PIO if transferring message bytes to esp->command_block_dma */
+       if (phase == ESP_MIP && addr == esp->command_block_dma) {
+               zorro_esp_send_pio_cmd(esp, addr, esp_count,
+                                       dma_count, write, cmd);
+               return;
+       }
+
+       if (write)
+               /* DMA receive */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_FROM_DEVICE);
+       else
+               /* DMA send */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_TO_DEVICE);
+
+       addr >>= 1;
+       if (write)
+               addr &= ~(DMA_WRITE);
+       else
+               addr |= DMA_WRITE;
+
+       dregs->dma_latch = (addr >> 24) & 0xff;
+       dregs->dma_addr  = (addr >> 16) & 0xff;
+       dregs->dma_addr  = (addr >>  8) & 0xff;
+       dregs->dma_addr  =  addr & 0xff;
+
+       scsi_esp_cmd(esp, ESP_CMD_DMA);
+       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+       scsi_esp_cmd(esp, cmd);
+}
+
+// Blizzard 2060 DMA
+
+static void zorro_esp_send_blz2060_dma_cmd(struct esp *esp, u32 addr,
+                       u32 esp_count, u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct blz2060_dma_registers *dregs =
+                       (struct blz2060_dma_registers *) (esp->dma_regs);
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+
+       zep->error = 0;
+       /* Use PIO if transferring message bytes to esp->command_block_dma */
+       if (phase == ESP_MIP && addr == esp->command_block_dma) {
+               zorro_esp_send_pio_cmd(esp, addr, esp_count,
+                                       dma_count, write, cmd);
+               return;
+       }
+
+       if (write)
+               /* DMA receive */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_FROM_DEVICE);
+       else
+               /* DMA send */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_TO_DEVICE);
+
+       addr >>= 1;
+       if (write)
+               addr &= ~(DMA_WRITE);
+       else
+               addr |= DMA_WRITE;
+
+       dregs->dma_addr3 =  addr & 0xff;
+       dregs->dma_addr2 = (addr >>  8) & 0xff;
+       dregs->dma_addr1 = (addr >> 16) & 0xff;
+       dregs->dma_addr0 = (addr >> 24) & 0xff;
+
+       scsi_esp_cmd(esp, ESP_CMD_DMA);
+       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+       scsi_esp_cmd(esp, cmd);
+}
+
+// Cyberstorm I DMA
+
+static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr,
+                       u32 esp_count, u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct cyber_dma_registers *dregs =
+               (struct cyber_dma_registers *) (esp->dma_regs);
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+       unsigned char *ctrl_data = &zep->ctrl_data;
+
+       zep->error = 0;
+       /* Use PIO if transferring message bytes to esp->command_block_dma */
+       if (phase == ESP_MIP && addr == esp->command_block_dma) {
+               zorro_esp_send_pio_cmd(esp, addr, esp_count,
+                                       dma_count, write, cmd);
+               return;
+       }
+
+       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+       if (write) {
+               /* DMA receive */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_FROM_DEVICE);
+               addr &= ~(1);
+       } else {
+               /* DMA send */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_TO_DEVICE);
+               addr |= 1;
+       }
+
+       dregs->dma_addr0 = (addr >> 24) & 0xff;
+       dregs->dma_addr1 = (addr >> 16) & 0xff;
+       dregs->dma_addr2 = (addr >>  8) & 0xff;
+       dregs->dma_addr3 =  addr & 0xff;
+
+       if (write)
+               *ctrl_data &= ~(CYBER_DMA_WRITE);
+       else
+               *ctrl_data |= CYBER_DMA_WRITE;
+
+       *ctrl_data &= ~(CYBER_DMA_Z3);  /* Z2, do 16 bit DMA */
+
+       dregs->ctrl_reg = *ctrl_data;
+
+       scsi_esp_cmd(esp, cmd);
+}
+
+// Cyberstorm II DMA
+
+static void zorro_esp_send_cyberII_dma_cmd(struct esp *esp, u32 addr,
+                       u32 esp_count, u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct cyberII_dma_registers *dregs =
+               (struct cyberII_dma_registers *) (esp->dma_regs);
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+
+       zep->error = 0;
+       /* Use PIO if transferring message bytes to esp->command_block_dma */
+       if (phase == ESP_MIP && addr == esp->command_block_dma) {
+               zorro_esp_send_pio_cmd(esp, addr, esp_count,
+                                       dma_count, write, cmd);
+               return;
+       }
+
+       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+       if (write) {
+               /* DMA receive */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_FROM_DEVICE);
+               addr &= ~(1);
+       } else {
+               /* DMA send */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_TO_DEVICE);
+               addr |= 1;
+       }
+
+       dregs->dma_addr0 = (addr >> 24) & 0xff;
+       dregs->dma_addr1 = (addr >> 16) & 0xff;
+       dregs->dma_addr2 = (addr >>  8) & 0xff;
+       dregs->dma_addr3 =  addr & 0xff;
+
+       scsi_esp_cmd(esp, cmd);
+}
+
+// Fastlane DMA
+
+static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr,
+                       u32 esp_count, u32 dma_count, int write, u8 cmd)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+       struct fastlane_dma_registers *dregs =
+               (struct fastlane_dma_registers *) (esp->dma_regs);
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
+               unsigned char *ctrl_data = &zep->ctrl_data;
+       unsigned long *t;
+
+       zep->error = 0;
+       /* Use PIO if transferring message bytes to esp->command_block_dma */
+       if (phase == ESP_MIP && addr == esp->command_block_dma) {
+               zorro_esp_send_pio_cmd(esp, addr, esp_count,
+                                       dma_count, write, cmd);
+               return;
+       }
+
+       zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+       zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+       zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+       if (write) {
+               /* DMA receive */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_FROM_DEVICE);
+               addr &= ~(1);
+       } else {
+               /* DMA send */
+               dma_sync_single_for_device(esp->dev, addr, esp_count,
+                               DMA_TO_DEVICE);
+               addr |= 1;
+       }
+
+       t = (unsigned long *)((addr & 0x00ffffff) + zep->board_base);
+
+       dregs->clear_strobe = 0;
+       *t = addr;
+
+       if (write) {
+               *ctrl_data = (*ctrl_data & FASTLANE_DMA_MASK) |
+                               FASTLANE_DMA_ENABLE;
+       } else {
+               *ctrl_data = ((*ctrl_data & FASTLANE_DMA_MASK) |
+                               FASTLANE_DMA_ENABLE |
+                               FASTLANE_DMA_WRITE);
+       }
+
+       dregs->ctrl_reg = *ctrl_data;
+
+       scsi_esp_cmd(esp, cmd);
+}
+
+static int zorro_esp_dma_error(struct esp *esp)
+{
+       struct zorro_esp_priv *zep = ZORRO_ESP_GET_PRIV(esp);
+
+       /* check for error in case we've been doing PIO */
+       if (zep->error == 1)
+               return 1;
+
+       /* do nothing - there seems to be no way to check for DMA errors */
+       return 0;
+}
+
+static struct esp_driver_ops zorro_esp_ops = {
+       .esp_write8       =     zorro_esp_write8,
+       .esp_read8        =     zorro_esp_read8,
+       .map_single       =     zorro_esp_map_single,
+       .map_sg           =     zorro_esp_map_sg,
+       .unmap_single     =     zorro_esp_unmap_single,
+       .unmap_sg         =     zorro_esp_unmap_sg,
+       .irq_pending      =     zorro_esp_irq_pending,
+       .dma_length_limit =     zorro_esp_dma_length_limit,
+       .reset_dma        =     zorro_esp_reset_dma,
+       .dma_drain        =     zorro_esp_dma_drain,
+       .dma_invalidate   =     zorro_esp_dma_invalidate,
+       .send_dma_cmd     =     zorro_esp_send_blz2060_dma_cmd,
+       .dma_error        =     zorro_esp_dma_error,
+};
+
+static int zorro_esp_probe(struct zorro_dev *z,
+                                      const struct zorro_device_id *ent)
+{
+       struct scsi_host_template *tpnt = &scsi_esp_template;
+       struct Scsi_Host *host;
+       struct esp *esp;
+       struct zorro_driver_data *zdd;
+       struct zorro_esp_priv *zep;
+       unsigned long board, ioaddr, dmaaddr;
+       int err;
+
+       board = zorro_resource_start(z);
+       zdd = (struct zorro_driver_data *)ent->driver_data;
+
+       pr_info("%s found at address 0x%lx.\n", zdd->name, board);
+
+       zep = kmalloc(sizeof(*zep), GFP_KERNEL);
+       if (!zep) {
+               pr_err("Can't allocate device private data!\n");
+               return -ENOMEM;
+       }
+
+       /* let's figure out whether we have a Zorro II or Zorro III board */
+       if ((z->rom.er_Type & ERT_TYPEMASK) == ERT_ZORROIII) {
+               /* note this is a Zorro III board */
+               if (board > 0xffffff)
+                       zep->zorro3 = 1;
+       } else
+               /* Even though most of these boards identify as Zorro II,
+                * they are in fact CPU expansion slot boards and have full
+                * access to all of memory. Fix up DMA bitmask here.
+                */
+               z->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+       /* If Zorro III and ID matches Fastlane, our device table entry
+        * contains data for the Blizzard 1230 II board which does share the
+        * same ID. Fix up device table entry here.
+        * TODO: Some Cyberstom060 boards also share this ID but would need
+        * to use the Cyberstorm I driver data ... we catch this by checking
+        * for presence of ESP chip later, but don't try to fix up yet.
+        */
+       if (zep->zorro3 && ent->id ==
+       ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) {
+               pr_info("%s at address 0x%lx is Fastlane Z3, fixing data!\n",
+                       zdd->name, board);
+               zdd = &fastlanez3_data;
+       }
+
+       if (zdd->absolute) {
+               ioaddr  = zdd->offset;
+               dmaaddr = zdd->dma_offset;
+       } else {
+               ioaddr  = board + zdd->offset;
+               dmaaddr = board + zdd->dma_offset;
+       }
+
+       if (!zorro_request_device(z, zdd->name)) {
+               pr_err("cannot reserve region 0x%lx, abort\n",
+                      board);
+               err = -EBUSY;
+               goto fail_free_zep;
+       }
+
+       /* Fill in the required pieces of hostdata */
+
+       host = scsi_host_alloc(tpnt, sizeof(struct esp));
+
+       if (!host) {
+               pr_err("No host detected; board configuration problem?\n");
+               err = -ENOMEM;
+               goto fail_release_device;
+       }
+
+       host->base              = ioaddr;
+       host->this_id           = 7;
+
+       esp                     = shost_priv(host);
+       esp->host               = host;
+       esp->dev                = &z->dev;
+
+       esp->scsi_id            = host->this_id;
+       esp->scsi_id_mask       = (1 << esp->scsi_id);
+
+       esp->cfreq = 40000000;
+
+       zep->error = 0;
+       zep->esp = esp;
+
+       dev_set_drvdata(esp->dev, zep);
+
+       /* Switch to the correct the DMA routine and clock frequency. */
+       switch (ent->id) {
+       case ZORRO_PROD_PHASE5_BLIZZARD_2060:
+               zorro_esp_ops.send_dma_cmd = zorro_esp_send_blz2060_dma_cmd;
+               break;
+       case ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260:
+               zorro_esp_ops.send_dma_cmd = zorro_esp_send_blz1230_dma_cmd;
+               break;
+       case ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM:
+               zorro_esp_ops.send_dma_cmd = zorro_esp_send_cyber_dma_cmd;
+               zorro_esp_ops.irq_pending  = cyber_esp_irq_pending;
+               break;
+       case ZORRO_PROD_PHASE5_CYBERSTORM_MK_II:
+               zorro_esp_ops.send_dma_cmd = zorro_esp_send_cyberII_dma_cmd;
+               break;
+       case ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060:
+               if (zep->zorro3) {
+                       /* Fastlane Zorro III board */
+                       /* map address space up to ESP address for DMA */
+                       zep->board_base = ioremap_nocache(board,
+                                                       FASTLANE_ESP_ADDR-1);
+                       if (!zep->board_base) {
+                               pr_err("Cannot allocate board address space\n");
+                               err = -ENOMEM;
+                               goto fail_free_host;
+                       }
+                       /* initialize DMA control shadow register */
+                       zep->ctrl_data = (FASTLANE_DMA_FCODE |
+                                         FASTLANE_DMA_EDI | FASTLANE_DMA_ESI);
+                       zorro_esp_ops.send_dma_cmd =
+                                       zorro_esp_send_fastlane_dma_cmd;
+                       zorro_esp_ops.irq_pending  = fastlane_esp_irq_pending;
+                       zorro_esp_ops.dma_invalidate =
+                                       fastlane_esp_dma_invalidate;
+               } else {
+                       /* Blizzard 1230 II Zorro II board */
+                       zorro_esp_ops.send_dma_cmd =
+                                       zorro_esp_send_blz1230II_dma_cmd;
+               }
+               break;
+       default:
+               /* Oh noes */
+               pr_err("Unsupported board!\n");
+               err = -ENODEV;
+               goto fail_free_host;
+       }
+
+       esp->ops = &zorro_esp_ops;
+
+       if (ioaddr > 0xffffff)
+               esp->regs = ioremap_nocache(ioaddr, 0x20);
+       else
+               esp->regs = (void __iomem *)ZTWO_VADDR(ioaddr);
+
+       if (!esp->regs) {
+               err = -ENOMEM;
+               goto fail_unmap_fastlane;
+       }
+
+       /* Check whether a Blizzard 12x0 or CyberstormII really has SCSI */
+       if (zdd->scsi_option) {
+               zorro_esp_write8(esp, (ESP_CONFIG1_PENABLE | 7), ESP_CFG1);
+               if (zorro_esp_read8(esp, ESP_CFG1) != (ESP_CONFIG1_PENABLE|7)) {
+                       err = -ENODEV;
+                       goto fail_unmap_regs;
+               }
+       }
+
+       if (zep->zorro3) {
+               /* Only Fastlane Z3 for now - add switch for correct struct
+                * dma_registers size if adding any more
+                */
+               esp->dma_regs = ioremap_nocache(dmaaddr,
+                               sizeof(struct fastlane_dma_registers));
+       } else
+               esp->dma_regs = (void __iomem *)ZTWO_VADDR(dmaaddr);
+
+       if (!esp->dma_regs) {
+               err = -ENOMEM;
+               goto fail_unmap_regs;
+       }
+
+       esp->command_block = dma_alloc_coherent(esp->dev, 16,
+                                               &esp->command_block_dma,
+                                               GFP_KERNEL);
+
+       if (!esp->command_block) {
+               err = -ENOMEM;
+               goto fail_unmap_dma_regs;
+       }
+
+       host->irq = IRQ_AMIGA_PORTS;
+       err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
+                         "Amiga Zorro ESP", esp);
+       if (err < 0) {
+               err = -ENODEV;
+               goto fail_free_command_block;
+       }
+
+       /* register the chip */
+       err = scsi_esp_register(esp, &z->dev);
+
+       if (err) {
+               err = -ENOMEM;
+               goto fail_free_irq;
+       }
+
+       //zorro_set_drvdata(z, host);
+
+       return 0;
+
+fail_free_irq:
+       free_irq(host->irq, esp);
+
+fail_free_command_block:
+       dma_free_coherent(esp->dev, 16,
+                         esp->command_block,
+                         esp->command_block_dma);
+
+fail_unmap_dma_regs:
+       if (zep->zorro3)
+               iounmap(esp->dma_regs);
+
+fail_unmap_regs:
+       if (ioaddr > 0xffffff)
+               iounmap(esp->regs);
+
+fail_unmap_fastlane:
+       if (zep->zorro3)
+               iounmap(zep->board_base);
+
+fail_free_host:
+       scsi_host_put(host);
+
+fail_release_device:
+       zorro_release_device(z);
+
+fail_free_zep:
+       kfree(zep);
+
+       return err;
+}
+
+static void zorro_esp_remove(struct zorro_dev *z)
+{
+       /* equivalent to dev_get_drvdata(z->dev) */
+       struct zorro_esp_priv *zep = zorro_get_drvdata(z);
+       struct esp *esp = zep->esp;
+       struct Scsi_Host *host = esp->host;
+
+       scsi_esp_unregister(esp);
+
+       /* Disable interrupts. Perhaps use disable_irq instead ... */
+
+       free_irq(host->irq, esp);
+       dma_free_coherent(esp->dev, 16,
+                         esp->command_block,
+                         esp->command_block_dma);
+
+       if (zep->zorro3) {
+               iounmap(zep->board_base);
+               iounmap(esp->dma_regs);
+       }
+
+       if (host->base > 0xffffff)
+               iounmap(esp->regs);
+
+       scsi_host_put(host);
+
+       zorro_release_device(z);
+
+       kfree(zep);
+}
+
+static struct zorro_driver zorro_esp_driver = {
+       .name     = KBUILD_MODNAME,
+       .id_table = zorro_esp_zorro_tbl,
+       .probe    = zorro_esp_probe,
+       .remove   = zorro_esp_remove,
+};
+
+static int __init zorro_esp_scsi_init(void)
+{
+       return zorro_register_driver(&zorro_esp_driver);
+}
+
+static void __exit zorro_esp_scsi_exit(void)
+{
+       zorro_unregister_driver(&zorro_esp_driver);
+}
+
+module_init(zorro_esp_scsi_init);
+module_exit(zorro_esp_scsi_exit);