Blame view

drivers/scsi/a3000.c 7.18 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9

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

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

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

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

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

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
87
88
89
90
91
92
93
  	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
94

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

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
100
101
  	/* return success */
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  }
65396410a   Henrik Kretzschmar   [SCSI] wd33c93: S...
103
104
  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
  		     int status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
106
107
108
  	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...
109

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
110
111
  	/* disable SCSI interrupts */
  	unsigned short cntr = CNTR_PDMD;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
112
  	if (!wh->dma_dir)
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
113
  		cntr |= CNTR_DDIR;
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
114
  	regs->CNTR = cntr;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
115
116
117
  	mb();			/* make sure CNTR is updated before next IO */
  
  	/* flush if we were reading */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
118
  	if (wh->dma_dir) {
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
119
  		regs->FLUSH = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
120
  		mb();		/* don't allow prefetch */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
121
  		while (!(regs->ISTR & ISTR_FE_FLG))
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
122
123
124
125
126
127
128
129
  			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 ...
130
  	regs->CINT = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
131
132
  
  	/* stop DMA */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
133
  	regs->SP_DMA = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
134
135
136
  	mb();			/* make sure DMA is stopped before next IO */
  
  	/* restore the CONTROL bits (minus the direction flag) */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
137
  	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
138
139
140
  	mb();			/* make sure CNTR is updated before next IO */
  
  	/* copy from a bounce buffer, if necessary */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
141
  	if (status && wh->dma_bounce_buffer) {
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
142
  		if (SCpnt) {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
143
144
  			if (wh->dma_dir && SCpnt)
  				memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
145
  				       SCpnt->SCp.this_residual);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
146
147
148
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
149
  		} else {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
150
151
152
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
153
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  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",
  	.proc_info		= wd33c93_proc_info,
  	.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
189
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
190
  	struct resource *res;
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
191
  	struct Scsi_Host *instance;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
192
  	int error;
c57c1cab7   Geert Uytterhoeven   m68k/scsi: a3000 ...
193
  	struct a3000_scsiregs *regs;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
194
  	wd33c93_regs wdregs;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
195
  	struct a3000_hostdata *hdata;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
196

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

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

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

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

2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
213
  	regs = (struct a3000_scsiregs *)ZTWO_VADDR(res->start);
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
214
  	regs->DAWR = DAWR_A3000;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
215

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

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

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

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

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

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
237
238
239
  	platform_set_drvdata(pdev, instance);
  
  	scsi_scan_host(instance);
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
240
  	return 0;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
241
242
243
244
245
246
247
248
  
  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
249
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
250
  static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
252
  	struct Scsi_Host *instance = platform_get_drvdata(pdev);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
253
  	struct a3000_hostdata *hdata = shost_priv(instance);
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
254
  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
255

2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
256
  	hdata->regs->CNTR = 0;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
257
258
259
260
261
  	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
262
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
263
264
265
266
267
268
  static struct platform_driver amiga_a3000_scsi_driver = {
  	.remove = __exit_p(amiga_a3000_scsi_remove),
  	.driver   = {
  		.name	= "amiga-a3000-scsi",
  		.owner	= THIS_MODULE,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  };
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
270
  static int __init amiga_a3000_scsi_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
272
273
274
275
  	return platform_driver_probe(&amiga_a3000_scsi_driver,
  				     amiga_a3000_scsi_probe);
  }
  module_init(amiga_a3000_scsi_init);
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
276

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
277
278
279
  static void __exit amiga_a3000_scsi_exit(void)
  {
  	platform_driver_unregister(&amiga_a3000_scsi_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
281
  module_exit(amiga_a3000_scsi_exit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282

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