11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mvme147hw.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi.h"
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "wd33c93.h"
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mvme147.h"
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven#include <linux/stat.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
194616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoevenstatic irqreturn_t mvme147_intr(int irq, void *data)
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
214616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	struct Scsi_Host *instance = data;
224616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven
23be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	if (irq == MVME147_IRQ_SCSI_PORT)
244616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven		wd33c93_intr(instance);
25be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	else
26be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */
27be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	return IRQ_HANDLED;
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3065396410af63db90d6428c678ff84aa652c3c1ecHenrik Kretzschmarstatic int dma_setup(struct scsi_cmnd *cmd, int dir_in)
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
324616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	struct Scsi_Host *instance = cmd->device->host;
334616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	struct WD33C93_hostdata *hdata = shost_priv(instance);
34be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	unsigned char flags = 0x01;
35be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
36be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
37be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	/* setup dma direction */
38be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	if (!dir_in)
39be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		flags |= 0x04;
40be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
41be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	/* remember direction */
42ce195662bbc063c29294c11a57aa2db182a837eaGeert Uytterhoeven	hdata->dma_dir = dir_in;
43be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
44be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	if (dir_in) {
45be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		/* invalidate any cache */
46be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		cache_clear(addr, cmd->SCp.this_residual);
47be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	} else {
48be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		/* push any dirty cache */
49be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		cache_push(addr, cmd->SCp.this_residual);
50be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	}
51be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
52be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	/* start DMA */
53be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->dma_bcr = cmd->SCp.this_residual | (1 << 24);
54be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->dma_dadr = addr;
55be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->dma_cntrl = flags;
56be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
57be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	/* return success */
58be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	return 0;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6165396410af63db90d6428c678ff84aa652c3c1ecHenrik Kretzschmarstatic void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
62be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		     int status)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
64be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->dma_cntrl = 0;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67d0be4a7d29ad0bd3ce2209dd9e46d410b632db59Christoph Hellwigint mvme147_detect(struct scsi_host_template *tpnt)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	static unsigned char called = 0;
704616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	struct Scsi_Host *instance;
71be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	wd33c93_regs regs;
72ce195662bbc063c29294c11a57aa2db182a837eaGeert Uytterhoeven	struct WD33C93_hostdata *hdata;
73be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
74be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	if (!MACH_IS_MVME147 || called)
75be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		return 0;
76be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	called++;
77be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
78be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	tpnt->proc_name = "MVME147";
79be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	tpnt->proc_info = &wd33c93_proc_info;
80be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
814616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
824616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	if (!instance)
83be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		goto err_out;
84be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
854616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	instance->base = 0xfffe4000;
864616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	instance->irq = MVME147_IRQ_SCSI_PORT;
87be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	regs.SASR = (volatile unsigned char *)0xfffe4000;
88be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	regs.SCMD = (volatile unsigned char *)0xfffe4001;
894616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	hdata = shost_priv(instance);
90ce195662bbc063c29294c11a57aa2db182a837eaGeert Uytterhoeven	hdata->no_sync = 0xff;
91ce195662bbc063c29294c11a57aa2db182a837eaGeert Uytterhoeven	hdata->fast = 0;
92ce195662bbc063c29294c11a57aa2db182a837eaGeert Uytterhoeven	hdata->dma_mode = CTRL_DMA;
934616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
94be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven
95be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
964616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven			"MVME147 SCSI PORT", instance))
97be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		goto err_unregister;
98be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
994616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven			"MVME147 SCSI DMA", instance))
100be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven		goto err_free_irq;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0	/* Disabled; causes problems booting */
102be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->scsi_interrupt = 0x10;	/* Assert SCSI bus reset */
103be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	udelay(100);
104be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->scsi_interrupt = 0x00;	/* Negate SCSI bus reset */
105be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	udelay(2000);
106be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->scsi_interrupt = 0x40;	/* Clear bus reset interrupt */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
108be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->scsi_interrupt = 0x09;	/* Enable interrupt */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
110be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->dma_cntrl = 0x00;	/* ensure DMA is stopped */
111be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
113be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	return 1;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
115be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoevenerr_free_irq:
116be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
117be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoevenerr_unregister:
1184616ac7e84c58660a11b991460cf2611552faa76Geert Uytterhoeven	scsi_unregister(instance);
119be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoevenerr_out:
120be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	return 0;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12365396410af63db90d6428c678ff84aa652c3c1ecHenrik Kretzschmarstatic int mvme147_bus_reset(struct scsi_cmnd *cmd)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME perform bus-specific reset */
12668b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik
127be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	/* FIXME 2: kill this function, and let midlayer fallback to
128df0ae2497ddefd72a87f3a3b34ff32455d7d4ae0Jeff Garzik	   the same result, calling wd33c93_host_reset() */
129df0ae2497ddefd72a87f3a3b34ff32455d7d4ae0Jeff Garzik
13068b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	spin_lock_irq(cmd->device->host->host_lock);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wd33c93_host_reset(cmd);
13268b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	spin_unlock_irq(cmd->device->host->host_lock);
13368b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SUCCESS;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
138d0be4a7d29ad0bd3ce2209dd9e46d410b632db59Christoph Hellwigstatic struct scsi_host_template driver_template = {
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_name		= "MVME147",
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name			= "MVME147 built-in SCSI",
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.detect			= mvme147_detect,
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release		= mvme147_release,
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queuecommand		= wd33c93_queuecommand,
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_abort_handler	= wd33c93_abort,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_bus_reset_handler	= mvme147_bus_reset,
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_host_reset_handler	= wd33c93_host_reset,
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.can_queue		= CAN_QUEUE,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.this_id		= 7,
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sg_tablesize		= SG_ALL,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmd_per_lun		= CMD_PER_LUN,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.use_clustering		= ENABLE_CLUSTERING
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi_module.c"
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint mvme147_release(struct Scsi_Host *instance)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
160be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	/* XXX Make sure DMA is stopped! */
161be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
162be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
164be4540db062975ce557daf0119153fb17ecd6693Geert Uytterhoeven	return 1;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
166