[PATCH 2/2] m68k/amiga - Zorro ESP: convert old driver to ESP core

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 drivers/scsi/zorro_esp.c |  414 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 414 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/zorro_esp.c

diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c
new file mode 100644
index 0000000..b0d4a56
--- /dev/null
+++ b/drivers/scsi/zorro_esp.c
@@ -0,0 +1,414 @@
+/* zorrro_esp.c: ESP front-end for Amiga ZORRO SCSI systems.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@xxxxxxxxxxxx)
+ *
+ * Copyright (C) 2011 Michael Schmitz (schmitz@xxxxxxxxxx) for 
+ *               migration to ESP SCSI core
+ */
+/*
+ * 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@xxxxxxxxxxxxxxxxxxxx>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@xxxxxxxxxxxxxx>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.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 "esp_scsi.h"
+
+MODULE_AUTHOR("Michael Schmitz <schmitz@xxxxxxxxxx>");
+MODULE_DESCRIPTION("Amiga Zorro NCR5C9x (ESP) driver");
+MODULE_LICENSE("GPL");
+
+
+static struct scsi_host_template zorro_esp_scsi_driver_template = {
+	.proc_name	= "zorro-esp",
+	.this_id	= 7,
+	.module		= THIS_MODULE,
+};
+
+static struct zorro_driver_data {
+	const char *name;
+	unsigned long offset;
+	unsigned long dma_offset;
+	int absolute;
+	int zorro3;	/* offset is absolute address */
+} zorro_esp_driver_data[] = {
+	{ .name = "CyberStormI", .offset = 0xf400, .dma_offset = 0xf800 },
+	{ .name = "CyberStormII", .offset = 0x1ff03, .dma_offset = 0x1ff43 },
+	{ .name = "Blizzard 2060", .offset = 0x1ff00, .dma_offset = 0x1ffe0 },
+	{ .name = "Blizzard 1230", .offset = 0x8000, .dma_offset = 0x10000 },
+	{ .name = "Blizzard 1230II", .offset = 0x10000, .dma_offset = 0x10021 },
+	{ .name = "Fastlane", .offset = 0x1000001, .dma_offset = 0x1000041, .zorro3 = 1 },
+	{ 0 }
+};
+
+static struct zorro_device_id zorro_esp_zorro_tbl[] = {
+	{
+		.id = ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM,
+		.driver_data = (unsigned long)&zorro_esp_driver_data[0],
+	},
+	{
+		.id = ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060,
+		.driver_data = (unsigned long)&zorro_esp_driver_data[0],
+	},
+	{
+		.id = ZORRO_PROD_PHASE5_CYBERSTORM_MK_II,
+		.driver_data = (unsigned long)&zorro_esp_driver_data[1],
+	},
+	{
+		.id = ZORRO_PROD_PHASE5_BLIZZARD_2060,
+		.driver_data = (unsigned long)&zorro_esp_driver_data[2],
+	},
+	{
+		.id = ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260,
+		.driver_data = (unsigned long)&zorro_esp_driver_data[3],
+	},
+	{
+		.id = ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060,
+		.driver_data = (unsigned long)&zorro_esp_driver_data[4],
+	},
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(zorro, zorro_esp_zorro_tbl);
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ2060_ESP_ADDR 0x1ff00
+#define BLZ2060_DMA_ADDR 0x1ffe0
+
+
+/* The Blizzard 2060 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ *  1) The data direction is controlled by the status of bit 31 (1 = write)
+ *  2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+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] */
+};
+
+#define BLZ2060_DMA_WRITE 0x80000000
+
+/* DMA control bits */
+#define BLZ2060_DMA_LED    0x02		/* HD led control 1 = off */
+
+
+/*
+ * m68k always assumes readl/writel operate on little endian
+ * mmio space; this is wrong at least for Sun3x, so we
+ * need to workaround this until a proper way is found
+ */
+#if 0
+#define dma_read32(REG) \
+	readl(esp->dma_regs + (REG))
+#define dma_write32(VAL, REG) \
+	writel((VAL), esp->dma_regs + (REG))
+#else
+#define dma_read32(REG) \
+	*(volatile u32 *)(esp->dma_regs + (REG))
+#define dma_write32(VAL, REG) \
+	do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0)
+#endif
+
+/*
+ * 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 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 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 zorro_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+				  u32 dma_count, int write, u8 cmd)
+{
+	struct blz2060_dma_registers *dregs = 
+		(struct blz2060_dma_registers *) (esp->dma_regs);
+
+	BUG_ON(!(cmd & ESP_CMD_DMA));
+	zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+	zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+
+	/* 
+	 * This will differ among Amiga ESP implementations - DMA setup!
+	 */
+
+	if (write)
+		cache_clear(addr, esp_count);
+	else
+		cache_push(addr, esp_count);
+
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ (from the ESP)!
+	 */
+	addr >>= 1;
+	if (write)
+		addr &= ~(BLZ2060_DMA_WRITE);
+	else
+		addr |= BLZ2060_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, cmd);
+}
+
+static int zorro_esp_dma_error(struct esp *esp)
+{
+	/* nothing to do here - there seems to be no way to check for DMA errors */
+	return 0;
+}
+
+static const 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,
+	.reset_dma	=	zorro_esp_reset_dma,
+	.dma_drain	=	zorro_esp_dma_drain,
+	.dma_invalidate	=	zorro_esp_dma_invalidate,
+	.send_dma_cmd	=	zorro_esp_send_dma_cmd,
+	.dma_error	=	zorro_esp_dma_error,
+};
+
+static int zorro_esp_init_one(struct zorro_dev *z,
+				       const struct zorro_device_id *ent)
+{
+	struct scsi_host_template *tpnt = &zorro_esp_scsi_driver_template;
+	struct Scsi_Host *host;
+	struct esp *esp;
+	struct zorro_driver_data *zdd;
+	unsigned long board, ioaddr, dmaaddr, esp_base;
+	int err = -ENOMEM;
+
+	board = zorro_resource_start(z);
+	zdd = (struct zorro_driver_data *)ent->driver_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)) {
+		printk(KERN_ERR "zorro_esp: cannot reserve region 0x%lx, abort\n",
+		       board);
+		return -EBUSY;
+	}
+
+	/* Fill in the required pieces of hostdata */
+	if (ioaddr > 0x01000000)
+		esp_base = ioremap(ioaddr, zorro_resource_len(z));
+	else
+		esp_base = (void __iomem *)ZTWO_VADDR(ioaddr);
+
+	zorro_esp_scsi_driver_template.name = zdd->name;
+
+	/* and register the chip */
+	host = scsi_host_alloc(tpnt, sizeof(struct esp));
+
+	if (!host) {
+		printk(KERN_ERR "zorro_esp: No host detected; "
+				"board configuration problem?\n");
+		goto out_free;
+	}
+
+	host->max_id = 8;
+	esp = shost_priv(host);
+
+	esp->host = host;
+	esp->dev = z;
+	esp->ops = &zorro_esp_ops;
+
+	esp->regs = ioremap_nocache(ioaddr, 0x20);
+	if (!esp->regs)
+		goto fail_unmap_regs;
+
+	esp->dma_regs = ioremap_nocache(dmaaddr, 0x20);
+
+	esp->command_block = dma_alloc_coherent(esp->dev, 32,
+						&esp->command_block_dma,
+						GFP_KERNEL);
+	if (!esp->command_block)
+		goto fail_unmap_regs_dma;
+
+	host->irq = IRQ_AMIGA_PORTS;
+	err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
+			  "Amiga Zorro ESP", esp);
+	if (err < 0)
+		goto fail_unmap_command_block;
+
+	esp->scsi_id = 7;
+	esp->host->this_id = esp->scsi_id;
+	esp->scsi_id_mask = (1 << esp->scsi_id);
+	esp->cfreq = 20000000;
+
+	dev_set_drvdata(&z->dev, esp);
+
+	err = scsi_esp_register(esp, &z->dev);
+	if (err)
+		goto fail_free_irq;
+
+	zorro_set_drvdata(z, host);
+	scsi_scan_host(host);
+
+	return 0;
+
+fail_free_irq:
+	free_irq(host->irq, esp);
+fail_unmap_command_block:
+	dma_free_coherent(esp->dev, 16,
+			  esp->command_block,
+			  esp->command_block_dma);
+fail_unmap_regs_dma:
+	iounmap(esp->dma_regs);
+fail_unmap_regs:
+	iounmap(esp->regs);
+	scsi_host_put(host);
+out_free:
+	if (ioaddr > 0x01000000)
+		iounmap(esp_base);
+out_release:
+	zorro_release_device(z);
+
+	return -ENODEV;
+}
+
+static void zorro_esp_remove_one(struct zorro_dev *z)
+{
+	struct Scsi_Host *host = zorro_get_drvdata(z);
+	struct esp *esp = dev_get_drvdata(&z->dev);
+	unsigned int irq = esp->host->irq;
+	u32 val;
+
+	scsi_esp_unregister(esp);
+
+	/* Disable interrupts. Perhaps use disable_irq instead ... */
+
+	free_irq(irq, esp);
+	dma_free_coherent(esp->dev, 16,
+			  esp->command_block,
+			  esp->command_block_dma);
+
+	scsi_host_put(esp->host);
+
+	zorro_release_device(z);
+}
+
+static struct zorro_driver zorro_esp_driver = {
+	.name	  = "zorro_esp-scsi",
+	.id_table = zorro_esp_zorro_tbl,
+	.probe	  = zorro_esp_init_one,
+	.remove	  = zorro_esp_remove_one,
+};
+
+static int __init zorro_esp_scsi_init(void)
+{
+	return zorro_register_driver(&zorro_esp_driver);
+}
+
+static void __exit zorro_esp_scsi_exit(void)
+{
+	zorro_unregister_driver(&zorro_esp_driver);
+}
+
+module_init(zorro_esp_scsi_init);
+module_exit(zorro_esp_scsi_exit);
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Video for Linux]     [Yosemite News]     [Linux S/390]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux