Blame view

drivers/scsi/a3000.c 6.55 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  #include <linux/types.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
  #include <linux/ioport.h>
  #include <linux/init.h>
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
6
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
9
  #include <linux/platform_device.h>
acf3368ff   Paul Gortmaker   scsi: Fix up file...
10
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11

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

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

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

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

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

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

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

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

213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
112
113
  	/* disable SCSI interrupts */
  	unsigned short cntr = CNTR_PDMD;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
114
  	if (!wh->dma_dir)
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
115
  		cntr |= CNTR_DDIR;
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
116
  	regs->CNTR = cntr;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
117
118
119
  	mb();			/* make sure CNTR is updated before next IO */
  
  	/* flush if we were reading */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
120
  	if (wh->dma_dir) {
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
121
  		regs->FLUSH = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
122
  		mb();		/* don't allow prefetch */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
123
  		while (!(regs->ISTR & ISTR_FE_FLG))
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
124
125
126
127
128
129
130
131
  			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 ...
132
  	regs->CINT = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
133
134
  
  	/* stop DMA */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
135
  	regs->SP_DMA = 1;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
136
137
138
  	mb();			/* make sure DMA is stopped before next IO */
  
  	/* restore the CONTROL bits (minus the direction flag) */
d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
139
  	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
140
141
142
  	mb();			/* make sure CNTR is updated before next IO */
  
  	/* copy from a bounce buffer, if necessary */
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
143
  	if (status && wh->dma_bounce_buffer) {
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
144
  		if (SCpnt) {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
145
146
  			if (wh->dma_dir && SCpnt)
  				memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
147
  				       SCpnt->SCp.this_residual);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
148
149
150
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
151
  		} else {
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
152
153
154
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
155
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
158
159
160
  static struct scsi_host_template amiga_a3000_scsi_template = {
  	.module			= THIS_MODULE,
  	.name			= "Amiga 3000 built-in SCSI",
408bb25ba   Al Viro   switch wd33c93 to...
161
162
  	.show_info		= wd33c93_show_info,
  	.write_info		= wd33c93_write_info,
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
163
164
165
  	.proc_name		= "A3000",
  	.queuecommand		= wd33c93_queuecommand,
  	.eh_abort_handler	= wd33c93_abort,
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
166
167
168
169
170
  	.eh_host_reset_handler	= wd33c93_host_reset,
  	.can_queue		= CAN_QUEUE,
  	.this_id		= 7,
  	.sg_tablesize		= SG_ALL,
  	.cmd_per_lun		= CMD_PER_LUN,
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
171
172
173
  };
  
  static int __init amiga_a3000_scsi_probe(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
175
  	struct resource *res;
a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
176
  	struct Scsi_Host *instance;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
177
  	int error;
c57c1cab7   Geert Uytterhoeven   m68k/scsi: a3000 ...
178
  	struct a3000_scsiregs *regs;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
179
  	wd33c93_regs wdregs;
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
180
  	struct a3000_hostdata *hdata;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
181

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
182
183
184
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res)
  		return -ENODEV;
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
185

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

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
189
  	instance = scsi_host_alloc(&amiga_a3000_scsi_template,
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
190
  				   sizeof(struct a3000_hostdata));
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
191
192
193
194
  	if (!instance) {
  		error = -ENOMEM;
  		goto fail_alloc;
  	}
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
195

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

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

d753722ee   Geert Uytterhoeven   m68k/scsi: a3000 ...
201
202
  	wdregs.SASR = &regs->SASR;
  	wdregs.SCMD = &regs->SCMD;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
203

a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
204
  	hdata = shost_priv(instance);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
205
206
207
208
  	hdata->wh.no_sync = 0xff;
  	hdata->wh.fast = 0;
  	hdata->wh.dma_mode = CTRL_DMA;
  	hdata->regs = regs;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
209

a8169e605   Geert Uytterhoeven   m68k/scsi: a3000 ...
210
  	wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15);
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
211
212
213
  	error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED,
  			    "A3000 SCSI", instance);
  	if (error)
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
214
  		goto fail_irq;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
215

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

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
218
219
220
  	error = scsi_add_host(instance, NULL);
  	if (error)
  		goto fail_host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
222
223
224
  	platform_set_drvdata(pdev, instance);
  
  	scsi_scan_host(instance);
213510134   Geert Uytterhoeven   [SCSI] a3000: Rei...
225
  	return 0;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
226
227
228
229
230
231
232
233
  
  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
234
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
235
  static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  {
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
237
  	struct Scsi_Host *instance = platform_get_drvdata(pdev);
2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
238
  	struct a3000_hostdata *hdata = shost_priv(instance);
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
239
  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
240

2b21d5e47   Geert Uytterhoeven   m68k/scsi: a3000 ...
241
  	hdata->regs->CNTR = 0;
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
242
243
244
245
246
  	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
247
  }
c2a24a4ca   Geert Uytterhoeven   m68k: amiga - A30...
248
249
250
251
  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...
252
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  };
a915b84a7   Jingoo Han   [SCSI] a3000: use...
254
  module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255

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