Message ID | 1520839600-29807-1-git-send-email-schmitzmic@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
On Mon, 12 Mar 2018, Michael Schmitz wrote: > 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" You don't need to define this. The compiler should be invoked with -DKBUILD_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; Since you've removed the alternative branch and phys_to_virt(), I suggest you do this at function invocation... (see below) > + > + 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; > + } ... that is, if (phase == ESP_MIP && addr == esp->command_block_dma) { /* The virtual address is needed for PIO. Unfortunately we * don't always know the virtual address, so this * workaround is not as useful as it could be. */ zorro_esp_send_pio_cmd(esp, (u32)esp->command_block, 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; The comment here seems to be redundant (?) More importantly, I think you have to initialize zep->zorro3 = 0 in the other branch, or else use kzalloc() instead of kmalloc() above. > + } 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 */ Redundant comment? > + > + 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 */ Same here? > + 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); > + Can that be deleted? > + 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) */ If zorro_get_drvdata(z) needs a comment to explain it then why not just write dev_get_drvdata(z->dev) instead? That way you can omit the explanation, as the code is consistent with the dev_set_drvdata(esp->dev, zep) and dev_get_drvdata(esp->dev) used elsewhere. > + 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 ... */ > + Can you clarify? free_irq() calls irq_shutdown()... > + 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); > Thanks! --
Hi Finn, Am 12.03.2018 um 22:04 schrieb Finn Thain: >> + if (addr == esp->command_block_dma) >> + addr = (u32) esp->command_block; > > Since you've removed the alternative branch and phys_to_virt(), I suggest > you do this at function invocation... (see below) Keeps it together with the phase and address tests, so easier to follow. >> +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; > > The comment here seems to be redundant (?) Not the only one. > More importantly, I think you have to initialize zep->zorro3 = 0 in the > other branch, or else use kzalloc() instead of kmalloc() above. Using kzalloc() saves the zep->error=0 initialization later on so it's a win. >> + 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 */ > > Same here? I've left the comment explaining what the board low address space is used for. >> + 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 */ and that one - the board might be a Cyberstorm060 which would require replacement of driver data, and replacement of the ESP register mapping. Might need to clarify that here again... >> + zorro_esp_ops.send_dma_cmd = >> + zorro_esp_send_blz1230II_dma_cmd; >> + //zorro_set_drvdata(z, host); >> + > > Can that be deleted? Leftover from when private data were static, so can go now. >> +static void zorro_esp_remove(struct zorro_dev *z) >> +{ >> + /* equivalent to dev_get_drvdata(z->dev) */ > > If zorro_get_drvdata(z) needs a comment to explain it then why not just > write dev_get_drvdata(z->dev) instead? dev_get_drvdata(&z->dev) (struct zorro device incorporates the whole struct device, not a pointer), but yes. >> + 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 ... */ >> + > > Can you clarify? free_irq() calls irq_shutdown()... Which calls disable_irq() eventually if it's the last of shared interrupts, true. disable_irq() would clearly be wrong here. > > Thanks! > My pleasure. I forgot to add your Reviewed-by tag - will do that for the next version, OK? Cheers, Michael
> > I forgot to add your Reviewed-by tag - will do that for the next > version, OK? Sure. Geert's tag may be harder to bag though :-) --
Hi Michael, On Mon, Mar 12, 2018 at 8:26 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > 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: [...] Thanks for the update! A few more comments below, mostly stylistic / practice. > --- /dev/null > +++ b/drivers/scsi/zorro_esp.c > +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 = { const > +static struct zorro_device_id zorro_esp_zorro_tbl[] = { const > + { > + .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] */ volatile considered harmful. If you would use proper *{read,write}*() accessors instead of direct assignments, you can drop the volatile's here. > +#define ZORRO_ESP_GET_PRIV(esp) ((struct zorro_esp_priv *) \ > + dev_get_drvdata(esp->dev)) This macro can be dropped, just use "dev_get_drvdata(esp->dev)" directly. No cast is needed. > +static int fastlane_esp_irq_pending(struct esp *esp) > +{ > + struct fastlane_dma_registers *dregs = > + (struct fastlane_dma_registers *) (esp->dma_regs); struct fastlane_dma_registers __iomem *dregs = esp->dma_regs; (and make C=1 will become (more) happy) > + unsigned char dma_status; > + > + dma_status = dregs->cond_reg; readb(). > +#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)); \ > + } Please pass "addr" and "fifo" as macro parameters, too, so it's easier for the reviewer to notice they are used. > +#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)); \ > + } Likewise. > +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 } 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); } > + /* 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; Please use function pointers in struct zorro_driver_data, so you don't need a switch() here (except for Fastlane vs. B1230II). Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Geert, thanks for the review - largely uncontroversial except for the volatile... Am 14.03.2018 um 20:49 schrieb Geert Uytterhoeven: >> +/* Blizzard 1230 DMA interface */ >> + >> +struct blz1230_dma_registers { >> + volatile unsigned char dma_addr; /* DMA address [0x0000] */ > > volatile considered harmful. Yes, I saw that. I also saw gcc miscompile the DMA set-up (in particular, the case where three bytes of the transfer address are stuffed consecutively into the same DMA address register). > If you would use proper *{read,write}*() accessors instead of direct > assignments, > you can drop the volatile's here. Meaning writeb(val, reg) instead of reg = val? #define out_8(addr,b) (void)((*(__force volatile u8 *) (addr)) = (b)) nicely hides the 'volatile' but suggests I also need to pass it a pointer, so writeb((addr >> 24) & 0xff, &dregs->dma_addr) would do the same as dregs->dma_addr = (addr >> 24) & 0xff; ?? I'll have to compare the assembly generated by the two versions before I dare test that, but I'll give that a try. Liberal use of wmb() did fix the miscompile but that just looked too ugly. >> +#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)); \ >> + } > > Please pass "addr" and "fifo" as macro parameters, too, so it's easier for > the reviewer to notice they are used. Yes, I can do that (meaning Finn would need to make the same change to keep our versions in sync). >> + /* 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; > > Please use function pointers in struct zorro_driver_data, so you don't need > a switch() here (except for Fastlane vs. B1230II). At that point, the Blizzard 1230 II zorro_driver_data has been replaced by the Fastlane one so the correct function pointer would be used. I didn't realize that also nicely solves my problem here. Thanks! Cheers, Michael
Hi Michael, On Wed, Mar 14, 2018 at 9:23 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > thanks for the review - largely uncontroversial except for the volatile... The presence of volatile in drivers is always considered controversial ;-) > Am 14.03.2018 um 20:49 schrieb Geert Uytterhoeven: >>> +/* Blizzard 1230 DMA interface */ >>> + >>> +struct blz1230_dma_registers { >>> + volatile unsigned char dma_addr; /* DMA address [0x0000] */ >> >> volatile considered harmful. > > Yes, I saw that. I also saw gcc miscompile the DMA set-up (in > particular, the case where three bytes of the transfer address are > stuffed consecutively into the same DMA address register). > >> If you would use proper *{read,write}*() accessors instead of direct >> assignments, >> you can drop the volatile's here. > > Meaning writeb(val, reg) instead of reg = val? > > #define out_8(addr,b) (void)((*(__force volatile u8 *) (addr)) = (b)) > > nicely hides the 'volatile' but suggests I also need to pass it a > pointer, so > > writeb((addr >> 24) & 0xff, &dregs->dma_addr) Yes, you have to pass it an (__iomem) pointer. > would do the same as > > dregs->dma_addr = (addr >> 24) & 0xff; ?? Right. > I'll have to compare the assembly generated by the two versions before I > dare test that, but I'll give that a try. Liberal use of wmb() did fix > the miscompile but that just looked too ugly. Using the macros should have the same effect due to the embedded volatile. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Geert, Am 14.03.2018 um 21:30 schrieb Geert Uytterhoeven: > Hi Michael, > > On Wed, Mar 14, 2018 at 9:23 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: >> thanks for the review - largely uncontroversial except for the volatile... > > The presence of volatile in drivers is always considered controversial ;-) Yes indeed. I just hadn't looked at raw_io.h in ages (too many unhappy memories), and didn't remember the __force volatile trick there. >> Meaning writeb(val, reg) instead of reg = val? >> >> #define out_8(addr,b) (void)((*(__force volatile u8 *) (addr)) = (b)) >> >> nicely hides the 'volatile' but suggests I also need to pass it a >> pointer, so >> >> writeb((addr >> 24) & 0xff, &dregs->dma_addr) > > Yes, you have to pass it an (__iomem) pointer. Thanks. >> I'll have to compare the assembly generated by the two versions before I >> dare test that, but I'll give that a try. Liberal use of wmb() did fix >> the miscompile but that just looked too ugly. > > Using the macros should have the same effect due to the embedded volatile. I tend to agree, but crashing elgar or trashing the SCSI filesystem there isn't something I would like to risk (Adrian has been very accommodating allowing me to test the driver there, but a reset tends to be taking a few hours thanks to the time zone difference). So I'd rather make sure nothing can go wrong. Cheers, Michael > > Gr{oetje,eeting}s, > > Geert > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like that. > -- Linus Torvalds >
On Wed, 14 Mar 2018, Michael Schmitz wrote: > > > > Please pass "addr" and "fifo" as macro parameters, too, so it's easier > > for the reviewer to notice they are used. > > Yes, I can do that (meaning Finn would need to make the same change to > keep our versions in sync). Personally, I wouldn't want to change it. This wasn't an oversight. Maybe if you (Geert) take a look at MAC_ESP_PDMA_LOOP, etc. this style might make more sense. These are not macros in a header file that might get used in any random scope. There is exactly one scope in which the macro appears, and the variables that appear in the macro are simply the variables from that scope. If you apply the rule, "the macro's parameters should exhaustively list all the macro's symbols", then (in this case) you'd violate the rule "Don't Repeat Yourself". And if you'd adhere to the latter rule then you'd violate the former. So I chose the more readable option. The preprocessor allows us to pretend we are doing symbolic code transformation, but that's not needed here. This was meant to be a textual device. --
Hi Finn, Geert, In the interest of making minimal changes between the Mac and Amiga versions, I'd leave the macros as they are, and add a comment to the macro definitions stating that both addr and fifo are local-scope variables in the only scope the macro is used in, to address reviewer's concerns. Can you both live with that? Placing the two macros in a suitable header in arch/m68k/include/asm/ so Mac and Amiga can share the same code without duplicating it in two files would be another option (that forces use of addr and fifo as parameters), but let's not overengineer things. I don't expect any other driver would need to share this code, or the PDMA macros also in the Mac driver... Other than that, I've implemented and tested all the suggested changes and could post v4 of this patch now. Cheers, Â Â Â Michael Am 16.03.18 um 00:17 schrieb Finn Thain: > On Wed, 14 Mar 2018, Michael Schmitz wrote: > >>> Please pass "addr" and "fifo" as macro parameters, too, so it's easier >>> for the reviewer to notice they are used. >> Yes, I can do that (meaning Finn would need to make the same change to >> keep our versions in sync). > Personally, I wouldn't want to change it. This wasn't an oversight. Maybe > if you (Geert) take a look at MAC_ESP_PDMA_LOOP, etc. this style might > make more sense. > > These are not macros in a header file that might get used in any random > scope. There is exactly one scope in which the macro appears, and the > variables that appear in the macro are simply the variables from that > scope. > > If you apply the rule, "the macro's parameters should exhaustively list > all the macro's symbols", then (in this case) you'd violate the rule > "Don't Repeat Yourself". And if you'd adhere to the latter rule then you'd > violate the former. So I chose the more readable option. > > The preprocessor allows us to pretend we are doing symbolic code > transformation, but that's not needed here. This was meant to be a textual > device. >
Hi Michael, On Fri, Mar 16, 2018 at 8:26 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > In the interest of making minimal changes between the Mac and Amiga > versions, I'd leave the macros as they are, and add a comment to the > macro definitions stating that both addr and fifo are local-scope > variables in the only scope the macro is used in, to address reviewer's > concerns. Can you both live with that? Yes I can. Thanks! Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
On Fri, 16 Mar 2018, Michael Schmitz wrote: > Hi Finn, Geert, > > In the interest of making minimal changes between the Mac and Amiga > versions, I'd leave the macros as they are, and add a comment to the > macro definitions stating that both addr and fifo are local-scope > variables in the only scope the macro is used in, to address reviewer's > concerns. Can you both live with that? > OK. > Placing the two macros in a suitable header in arch/m68k/include/asm/ so > Mac and Amiga can share the same code without duplicating it in two > files would be another option (that forces use of addr and fifo as > parameters), but let's not overengineer things. Yes, deduplication would be nice but I'd like to extend that to the entire PIO implementation. We should be using the portable IO routines but I'd want to do some timings first. Inline assembly was unavoidable for the PDMA loops. Later when I came to write the PIO versions, I just re-used the existing code without benchmarking. So there's a slim chance that insb/outsb are not slower. It might be sufficient to unroll the m68k raw_insb() and raw_outsb() loops, just as raw_insw() and raw_outsw() have been unrolled. But again, I'd want to measure that.
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);