a3000.c revision 900e8d6b871a986f5adfa0e71112b8b9face177e
1#include <linux/types.h>
2#include <linux/mm.h>
3#include <linux/slab.h>
4#include <linux/blkdev.h>
5#include <linux/ioport.h>
6#include <linux/init.h>
7#include <linux/spinlock.h>
8#include <linux/interrupt.h>
9
10#include <asm/setup.h>
11#include <asm/page.h>
12#include <asm/pgtable.h>
13#include <asm/amigaints.h>
14#include <asm/amigahw.h>
15#include <asm/irq.h>
16
17#include "scsi.h"
18#include <scsi/scsi_host.h>
19#include "wd33c93.h"
20#include "a3000.h"
21
22#include<linux/stat.h>
23
24#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
25#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
26
27static struct Scsi_Host *a3000_host = NULL;
28
29static int a3000_release(struct Scsi_Host *instance);
30
31static irqreturn_t a3000_intr (int irq, void *dummy)
32{
33	unsigned long flags;
34	unsigned int status = DMA(a3000_host)->ISTR;
35
36	if (!(status & ISTR_INT_P))
37		return IRQ_NONE;
38	if (status & ISTR_INTS)
39	{
40		spin_lock_irqsave(a3000_host->host_lock, flags);
41		wd33c93_intr (a3000_host);
42		spin_unlock_irqrestore(a3000_host->host_lock, flags);
43		return IRQ_HANDLED;
44	}
45	printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
46	return IRQ_NONE;
47}
48
49static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
50{
51    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
52    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
53
54    /*
55     * if the physical address has the wrong alignment, or if
56     * physical address is bad, or if it is a write and at the
57     * end of a physical memory chunk, then allocate a bounce
58     * buffer
59     */
60    if (addr & A3000_XFER_MASK)
61    {
62	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
63	    & ~0x1ff;
64	HDATA(a3000_host)->dma_bounce_buffer =
65	    kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
66
67	/* can't allocate memory; use PIO */
68	if (!HDATA(a3000_host)->dma_bounce_buffer) {
69	    HDATA(a3000_host)->dma_bounce_len = 0;
70	    return 1;
71	}
72
73	if (!dir_in) {
74	    /* copy to bounce buffer for a write */
75	    memcpy (HDATA(a3000_host)->dma_bounce_buffer,
76		cmd->SCp.ptr, cmd->SCp.this_residual);
77	}
78
79	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
80    }
81
82    /* setup dma direction */
83    if (!dir_in)
84	cntr |= CNTR_DDIR;
85
86    /* remember direction */
87    HDATA(a3000_host)->dma_dir = dir_in;
88
89    DMA(a3000_host)->CNTR = cntr;
90
91    /* setup DMA *physical* address */
92    DMA(a3000_host)->ACR = addr;
93
94    if (dir_in)
95  	/* invalidate any cache */
96	cache_clear (addr, cmd->SCp.this_residual);
97    else
98	/* push any dirty cache */
99	cache_push (addr, cmd->SCp.this_residual);
100
101    /* start DMA */
102    mb();			/* make sure setup is completed */
103    DMA(a3000_host)->ST_DMA = 1;
104    mb();			/* make sure DMA has started before next IO */
105
106    /* return success */
107    return 0;
108}
109
110static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
111		     int status)
112{
113    /* disable SCSI interrupts */
114    unsigned short cntr = CNTR_PDMD;
115
116    if (!HDATA(instance)->dma_dir)
117	cntr |= CNTR_DDIR;
118
119    DMA(instance)->CNTR = cntr;
120    mb();			/* make sure CNTR is updated before next IO */
121
122    /* flush if we were reading */
123    if (HDATA(instance)->dma_dir) {
124	DMA(instance)->FLUSH = 1;
125	mb();			/* don't allow prefetch */
126	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
127	    barrier();
128	mb();			/* no IO until FLUSH is done */
129    }
130
131    /* clear a possible interrupt */
132    /* I think that this CINT is only necessary if you are
133     * using the terminal count features.   HM 7 Mar 1994
134     */
135    DMA(instance)->CINT = 1;
136
137    /* stop DMA */
138    DMA(instance)->SP_DMA = 1;
139    mb();			/* make sure DMA is stopped before next IO */
140
141    /* restore the CONTROL bits (minus the direction flag) */
142    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
143    mb();			/* make sure CNTR is updated before next IO */
144
145    /* copy from a bounce buffer, if necessary */
146    if (status && HDATA(instance)->dma_bounce_buffer) {
147	if (SCpnt) {
148	    if (HDATA(instance)->dma_dir && SCpnt)
149		memcpy (SCpnt->SCp.ptr,
150			HDATA(instance)->dma_bounce_buffer,
151			SCpnt->SCp.this_residual);
152	    kfree (HDATA(instance)->dma_bounce_buffer);
153	    HDATA(instance)->dma_bounce_buffer = NULL;
154	    HDATA(instance)->dma_bounce_len = 0;
155	} else {
156	    kfree (HDATA(instance)->dma_bounce_buffer);
157	    HDATA(instance)->dma_bounce_buffer = NULL;
158	    HDATA(instance)->dma_bounce_len = 0;
159	}
160    }
161}
162
163static int __init a3000_detect(struct scsi_host_template *tpnt)
164{
165    wd33c93_regs regs;
166
167    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
168	return 0;
169    if (!request_mem_region(0xDD0000, 256, "wd33c93"))
170	return 0;
171
172    tpnt->proc_name = "A3000";
173    tpnt->proc_info = &wd33c93_proc_info;
174
175    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
176    if (a3000_host == NULL)
177	goto fail_register;
178
179    a3000_host->base = ZTWO_VADDR(0xDD0000);
180    a3000_host->irq = IRQ_AMIGA_PORTS;
181    DMA(a3000_host)->DAWR = DAWR_A3000;
182    regs.SASR = &(DMA(a3000_host)->SASR);
183    regs.SCMD = &(DMA(a3000_host)->SCMD);
184    HDATA(a3000_host)->no_sync = 0xff;
185    HDATA(a3000_host)->fast = 0;
186    HDATA(a3000_host)->dma_mode = CTRL_DMA;
187    wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
188    if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
189		    a3000_intr))
190        goto fail_irq;
191    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
192
193    return 1;
194
195fail_irq:
196    scsi_unregister(a3000_host);
197fail_register:
198    release_mem_region(0xDD0000, 256);
199    return 0;
200}
201
202static int a3000_bus_reset(struct scsi_cmnd *cmd)
203{
204	/* FIXME perform bus-specific reset */
205
206	/* FIXME 2: kill this entire function, which should
207	   cause mid-layer to call wd33c93_host_reset anyway? */
208
209	spin_lock_irq(cmd->device->host->host_lock);
210	wd33c93_host_reset(cmd);
211	spin_unlock_irq(cmd->device->host->host_lock);
212
213	return SUCCESS;
214}
215
216#define HOSTS_C
217
218static struct scsi_host_template driver_template = {
219	.proc_name		= "A3000",
220	.name			= "Amiga 3000 built-in SCSI",
221	.detect			= a3000_detect,
222	.release		= a3000_release,
223	.queuecommand		= wd33c93_queuecommand,
224	.eh_abort_handler	= wd33c93_abort,
225	.eh_bus_reset_handler	= a3000_bus_reset,
226	.eh_host_reset_handler	= wd33c93_host_reset,
227	.can_queue		= CAN_QUEUE,
228	.this_id		= 7,
229	.sg_tablesize		= SG_ALL,
230	.cmd_per_lun		= CMD_PER_LUN,
231	.use_clustering		= ENABLE_CLUSTERING
232};
233
234
235#include "scsi_module.c"
236
237static int a3000_release(struct Scsi_Host *instance)
238{
239    DMA(instance)->CNTR = 0;
240    release_mem_region(0xDD0000, 256);
241    free_irq(IRQ_AMIGA_PORTS, a3000_intr);
242    return 1;
243}
244
245MODULE_LICENSE("GPL");
246