Blame view

drivers/scsi/a3000.c 6.96 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  #include <linux/types.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
  #include <linux/ioport.h>
  #include <linux/init.h>
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
5
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
8
  #include <linux/platform_device.h>
acf3368ff   Paul Gortmaker   scsi: Fix up file...
9
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
  #include <asm/page.h>
  #include <asm/pgtable.h>
  #include <asm/amigaints.h>
  #include <asm/amigahw.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  
  #include "scsi.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include "wd33c93.h"
  #include "a3000.h"
9387edbe6   Adrian Bunk   [SCSI] a3000: mak...
19

2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
20
21
22
23
  struct a3000_hostdata {
  	struct WD33C93_hostdata wh;
  	struct a3000_scsiregs *regs;
  };
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
24
  static irqreturn_t a3000_intr(int irq, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  {
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
26
  	struct Scsi_Host *instance = data;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
27
28
  	struct a3000_hostdata *hdata = shost_priv(instance);
  	unsigned int status = hdata->regs->ISTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
  
  	if (!(status & ISTR_INT_P))
  		return IRQ_NONE;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
33
  	if (status & ISTR_INTS) {
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
34
35
36
  		spin_lock_irqsave(instance->host_lock, flags);
  		wd33c93_intr(instance);
  		spin_unlock_irqrestore(instance->host_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
  		return IRQ_HANDLED;
  	}
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
39
40
  	pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  	return IRQ_NONE;
  }
65396410a   Henrik Kretzschmar   [SCSI] wd33c93: S...
43
  static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  {
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
45
  	struct Scsi_Host *instance = cmd->device->host;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
46
47
48
  	struct a3000_hostdata *hdata = shost_priv(instance);
  	struct WD33C93_hostdata *wh = &hdata->wh;
  	struct a3000_scsiregs *regs = hdata->regs;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
49
50
51
52
53
54
55
56
57
58
  	unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
  	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
  
  	/*
  	 * if the physical address has the wrong alignment, or if
  	 * physical address is bad, or if it is a write and at the
  	 * end of a physical memory chunk, then allocate a bounce
  	 * buffer
  	 */
  	if (addr & A3000_XFER_MASK) {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
59
60
61
  		wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
  		wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
  						GFP_KERNEL);
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
62
63
  
  		/* can't allocate memory; use PIO */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
64
65
  		if (!wh->dma_bounce_buffer) {
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
66
67
68
69
70
  			return 1;
  		}
  
  		if (!dir_in) {
  			/* copy to bounce buffer for a write */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
71
  			memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
afdbbc161   Geert Uytterhoeven   [SCSI] a3000: Use...
72
  			       cmd->SCp.this_residual);
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
73
  		}
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
74
  		addr = virt_to_bus(wh->dma_bounce_buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	}
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
76
77
78
  	/* setup dma direction */
  	if (!dir_in)
  		cntr |= CNTR_DDIR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
80
  	/* remember direction */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
81
  	wh->dma_dir = dir_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82

d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
83
  	regs->CNTR = cntr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
85
  	/* setup DMA *physical* address */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
86
  	regs->ACR = addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
88
89
90
91
92
93
94
  	if (dir_in) {
  		/* invalidate any cache */
  		cache_clear(addr, cmd->SCp.this_residual);
  	} else {
  		/* push any dirty cache */
  		cache_push(addr, cmd->SCp.this_residual);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
96
97
  	/* start DMA */
  	mb();			/* make sure setup is completed */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
98
  	regs->ST_DMA = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
99
  	mb();			/* make sure DMA has started before next IO */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
101
102
  	/* return success */
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  }
65396410a   Henrik Kretzschmar   [SCSI] wd33c93: S...
104
105
  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
  		     int status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
107
108
109
  	struct a3000_hostdata *hdata = shost_priv(instance);
  	struct WD33C93_hostdata *wh = &hdata->wh;
  	struct a3000_scsiregs *regs = hdata->regs;
afdbbc161   Geert Uytterhoeven   [SCSI] a3000: Use...
110

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
111
112
  	/* disable SCSI interrupts */
  	unsigned short cntr = CNTR_PDMD;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
113
  	if (!wh->dma_dir)
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
114
  		cntr |= CNTR_DDIR;
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
115
  	regs->CNTR = cntr;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
116
117
118
  	mb();			/* make sure CNTR is updated before next IO */
  
  	/* flush if we were reading */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
119
  	if (wh->dma_dir) {
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
120
  		regs->FLUSH = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
121
  		mb();		/* don't allow prefetch */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
122
  		while (!(regs->ISTR & ISTR_FE_FLG))
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
123
124
125
126
127
128
129
130
  			barrier();
  		mb();		/* no IO until FLUSH is done */
  	}
  
  	/* clear a possible interrupt */
  	/* I think that this CINT is only necessary if you are
  	 * using the terminal count features.   HM 7 Mar 1994
  	 */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
131
  	regs->CINT = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
132
133
  
  	/* stop DMA */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
134
  	regs->SP_DMA = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
135
136
137
  	mb();			/* make sure DMA is stopped before next IO */
  
  	/* restore the CONTROL bits (minus the direction flag) */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
138
  	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
139
140
141
  	mb();			/* make sure CNTR is updated before next IO */
  
  	/* copy from a bounce buffer, if necessary */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
142
  	if (status && wh->dma_bounce_buffer) {
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
143
  		if (SCpnt) {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
144
145
  			if (wh->dma_dir && SCpnt)
  				memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
146
  				       SCpnt->SCp.this_residual);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
147
148
149
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
150
  		} else {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
151
152
153
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
154
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  static int a3000_bus_reset(struct scsi_cmnd *cmd)
  {
  	struct Scsi_Host *instance = cmd->device->host;
  
  	/* FIXME perform bus-specific reset */
  
  	/* FIXME 2: kill this entire function, which should
  	   cause mid-layer to call wd33c93_host_reset anyway? */
  
  	spin_lock_irq(instance->host_lock);
  	wd33c93_host_reset(cmd);
  	spin_unlock_irq(instance->host_lock);
  
  	return SUCCESS;
  }
  
  static struct scsi_host_template amiga_a3000_scsi_template = {
  	.module			= THIS_MODULE,
  	.name			= "Amiga 3000 built-in SCSI",
408bb25ba   Al Viro   switch wd33c93 to...
176
177
  	.show_info		= wd33c93_show_info,
  	.write_info		= wd33c93_write_info,
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
178
179
180
181
182
183
184
185
186
187
188
189
190
  	.proc_name		= "A3000",
  	.queuecommand		= wd33c93_queuecommand,
  	.eh_abort_handler	= wd33c93_abort,
  	.eh_bus_reset_handler	= a3000_bus_reset,
  	.eh_host_reset_handler	= wd33c93_host_reset,
  	.can_queue		= CAN_QUEUE,
  	.this_id		= 7,
  	.sg_tablesize		= SG_ALL,
  	.cmd_per_lun		= CMD_PER_LUN,
  	.use_clustering		= ENABLE_CLUSTERING
  };
  
  static int __init amiga_a3000_scsi_probe(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
192
  	struct resource *res;
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
193
  	struct Scsi_Host *instance;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
194
  	int error;
c57c1cab7   Geert Uytterhoeven   m68k/scsi: a3000 ...
195
  	struct a3000_scsiregs *regs;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
196
  	wd33c93_regs wdregs;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
197
  	struct a3000_hostdata *hdata;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
198

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
199
200
201
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res)
  		return -ENODEV;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
202

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
203
204
  	if (!request_mem_region(res->start, resource_size(res), "wd33c93"))
  		return -EBUSY;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
205

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
206
  	instance = scsi_host_alloc(&amiga_a3000_scsi_template,
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
207
  				   sizeof(struct a3000_hostdata));
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
208
209
210
211
  	if (!instance) {
  		error = -ENOMEM;
  		goto fail_alloc;
  	}
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
212

a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
213
  	instance->irq = IRQ_AMIGA_PORTS;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
214

6112ea086   Geert Uytterhoeven   zorro: ZTWO_VADDR...
215
  	regs = ZTWO_VADDR(res->start);
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
216
  	regs->DAWR = DAWR_A3000;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
217

d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
218
219
  	wdregs.SASR = &regs->SASR;
  	wdregs.SCMD = &regs->SCMD;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
220

a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
221
  	hdata = shost_priv(instance);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
222
223
224
225
  	hdata->wh.no_sync = 0xff;
  	hdata->wh.fast = 0;
  	hdata->wh.dma_mode = CTRL_DMA;
  	hdata->regs = regs;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
226

a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
227
  	wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15);
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
228
229
230
  	error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED,
  			    "A3000 SCSI", instance);
  	if (error)
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
231
  		goto fail_irq;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
232

d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
233
  	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
234

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
235
236
237
  	error = scsi_add_host(instance, NULL);
  	if (error)
  		goto fail_host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
239
240
241
  	platform_set_drvdata(pdev, instance);
  
  	scsi_scan_host(instance);
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
242
  	return 0;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
243
244
245
246
247
248
249
250
  
  fail_host:
  	free_irq(IRQ_AMIGA_PORTS, instance);
  fail_irq:
  	scsi_host_put(instance);
  fail_alloc:
  	release_mem_region(res->start, resource_size(res));
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
252
  static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
254
  	struct Scsi_Host *instance = platform_get_drvdata(pdev);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
255
  	struct a3000_hostdata *hdata = shost_priv(instance);
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
256
  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
257

2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
258
  	hdata->regs->CNTR = 0;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
259
260
261
262
263
  	scsi_remove_host(instance);
  	free_irq(IRQ_AMIGA_PORTS, instance);
  	scsi_host_put(instance);
  	release_mem_region(res->start, resource_size(res));
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
265
266
267
268
  static struct platform_driver amiga_a3000_scsi_driver = {
  	.remove = __exit_p(amiga_a3000_scsi_remove),
  	.driver   = {
  		.name	= "amiga-a3000-scsi",
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
269
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  };
a915b84a7   Jingoo Han   [SCSI] a3000: use...
271
  module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
273
  MODULE_DESCRIPTION("Amiga 3000 built-in SCSI");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  MODULE_LICENSE("GPL");
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
275
  MODULE_ALIAS("platform:amiga-a3000-scsi");