From patchwork Wed Mar 14 07:13:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tuomas Vainikka X-Patchwork-Id: 10281547 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 99732602BD for ; Wed, 14 Mar 2018 07:13:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7540128696 for ; Wed, 14 Mar 2018 07:13:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 696F0286F4; Wed, 14 Mar 2018 07:13:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9916928696 for ; Wed, 14 Mar 2018 07:13:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753063AbeCNHNV convert rfc822-to-8bit (ORCPT ); Wed, 14 Mar 2018 03:13:21 -0400 Received: from smtp-out-01.aalto.fi ([130.233.228.120]:56796 "EHLO smtp-out-01.aalto.fi" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750862AbeCNHNU (ORCPT ); Wed, 14 Mar 2018 03:13:20 -0400 Received: from smtp-out-01.aalto.fi (localhost.localdomain [127.0.0.1]) by localhost (Email Security Appliance) with SMTP id C6009115395_AA8CBC6B; Wed, 14 Mar 2018 07:14:14 +0000 (GMT) Received: from exng2.org.aalto.fi (exng2.org.aalto.fi [130.233.223.21]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (Client CN "exng2.org.aalto.fi", Issuer "org.aalto.fi RootCA" (not verified)) by smtp-out-01.aalto.fi (Sophos Email Appliance) with ESMTPS id 2B825115378_AA8CBC6F; Wed, 14 Mar 2018 07:14:14 +0000 (GMT) Received: from exng1.org.aalto.fi (130.233.223.20) by exng2.org.aalto.fi (130.233.223.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1261.35; Wed, 14 Mar 2018 09:13:16 +0200 Received: from exng1.org.aalto.fi ([fe80::80c3:a9b6:79ec:a14e]) by exng1.org.aalto.fi ([fe80::80c3:a9b6:79ec:a14e%19]) with mapi id 15.01.1261.036; Wed, 14 Mar 2018 09:13:16 +0200 From: Vainikka Tuomas To: Michael Schmitz , "linux-scsi@vger.kernel.org" CC: "linux-m68k@vger.kernel.org" , "davem@davemloft.net" , "geert@linux-m68k.org" , "fthain@telegraphics.com.au" , Michael Schmitz Subject: Re: [PATCH v3] m68k/amiga - Amiga Zorro NCR53C9x boards: new zorro_esp.c Thread-Topic: [PATCH v3] m68k/amiga - Amiga Zorro NCR53C9x boards: new zorro_esp.c Thread-Index: AQHTudOC7YWpQo1gsEaYEGuzGx8iIqPPU53S Date: Wed, 14 Mar 2018 07:13:16 +0000 Message-ID: <72c19f0c923c4625bf57263e02637237@aalto.fi> References: <1520121265-18449-1-git-send-email-schmitzmic@gmail.com>, <1520839600-29807-1-git-send-email-schmitzmic@gmail.com> In-Reply-To: <1520839600-29807-1-git-send-email-schmitzmic@gmail.com> Accept-Language: en-GB, fi-FI, en-US Content-Language: en-GB X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [130.233.0.5] MIME-Version: 1.0 X-SASI-RCODE: 200 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The config description lists 53c700 devices, not ESP devices? -Tuomas 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 + ), + - 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 + * plus modifications of the 53c7xx.c driver to support the Amiga. + * + * Rewritten to use 53c700.c by Kars de Jong + */ + +#define KBUILD_MODNAME "zorro_esp" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "esp_scsi.h" + +MODULE_AUTHOR("Michael Schmitz "); +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);