Blame view

drivers/scsi/a2091.c 6.53 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  #include <linux/init.h>
  #include <linux/interrupt.h>
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
4
5
6
7
  #include <linux/mm.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/zorro.h>
acf3368ff   Paul Gortmaker   scsi: Fix up file...
8
  #include <linux/module.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 "a2091.h"
5880f486e   Adrian Bunk   [SCSI] a2091: mak...
18

65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
19
20
21
22
  struct a2091_hostdata {
  	struct WD33C93_hostdata wh;
  	struct a2091_scsiregs *regs;
  };
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
23
  static irqreturn_t a2091_intr(int irq, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  {
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
25
  	struct Scsi_Host *instance = data;
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
26
27
  	struct a2091_hostdata *hdata = shost_priv(instance);
  	unsigned int status = hdata->regs->ISTR;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
28
  	unsigned long flags;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
29

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
30
31
32
33
34
35
36
  	if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
  		return IRQ_NONE;
  
  	spin_lock_irqsave(instance->host_lock, flags);
  	wd33c93_intr(instance);
  	spin_unlock_irqrestore(instance->host_lock, flags);
  	return IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  }
65396410a   Henrik Kretzschmar   [SCSI] wd33c93: S...
38
  static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  {
6d1d5d43e   Geert Uytterhoeven   [SCSI] a2091: Use...
40
  	struct Scsi_Host *instance = cmd->device->host;
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
41
42
43
  	struct a2091_hostdata *hdata = shost_priv(instance);
  	struct WD33C93_hostdata *wh = &hdata->wh;
  	struct a2091_scsiregs *regs = hdata->regs;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
44
45
  	unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
  	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
47
  	/* don't allow DMA if the physical address is bad */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  	if (addr & A2091_XFER_MASK) {
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
49
50
51
  		wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
  		wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
  						GFP_KERNEL);
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
52
53
  
  		/* can't allocate memory; use PIO */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
54
55
  		if (!wh->dma_bounce_buffer) {
  			wh->dma_bounce_len = 0;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
56
57
58
59
  			return 1;
  		}
  
  		/* get the physical address of the bounce buffer */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
60
  		addr = virt_to_bus(wh->dma_bounce_buffer);
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
61
62
63
64
  
  		/* the bounce buffer may not be in the first 16M of physmem */
  		if (addr & A2091_XFER_MASK) {
  			/* we could use chipmem... maybe later */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
65
66
67
  			kfree(wh->dma_bounce_buffer);
  			wh->dma_bounce_buffer = NULL;
  			wh->dma_bounce_len = 0;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
68
69
70
71
72
  			return 1;
  		}
  
  		if (!dir_in) {
  			/* copy to bounce buffer for a write */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
73
  			memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
6d1d5d43e   Geert Uytterhoeven   [SCSI] a2091: Use...
74
  			       cmd->SCp.this_residual);
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
75
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
78
79
80
  	/* setup dma direction */
  	if (!dir_in)
  		cntr |= CNTR_DDIR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
82
  	/* remember direction */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
83
  	wh->dma_dir = dir_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
85
  	regs->CNTR = cntr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
87
  	/* setup DMA *physical* address */
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
88
  	regs->ACR = addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
90
91
92
93
94
95
96
97
  	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);
  	}
  	/* start DMA */
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
98
  	regs->ST_DMA = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
100
101
  	/* return success */
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  }
65396410a   Henrik Kretzschmar   [SCSI] wd33c93: S...
103
  static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
104
  		     int status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
106
107
108
  	struct a2091_hostdata *hdata = shost_priv(instance);
  	struct WD33C93_hostdata *wh = &hdata->wh;
  	struct a2091_scsiregs *regs = hdata->regs;
6d1d5d43e   Geert Uytterhoeven   [SCSI] a2091: Use...
109

09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
110
111
  	/* disable SCSI interrupts */
  	unsigned short cntr = CNTR_PDMD;
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
112
  	if (!wh->dma_dir)
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
113
114
115
  		cntr |= CNTR_DDIR;
  
  	/* disable SCSI interrupts */
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
116
  	regs->CNTR = cntr;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
117
118
  
  	/* flush if we were reading */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
119
  	if (wh->dma_dir) {
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
120
121
  		regs->FLUSH = 1;
  		while (!(regs->ISTR & ISTR_FE_FLG))
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
122
123
124
125
  			;
  	}
  
  	/* clear a possible interrupt */
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
126
  	regs->CINT = 1;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
127
128
  
  	/* stop DMA */
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
129
  	regs->SP_DMA = 1;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
130
131
  
  	/* restore the CONTROL bits (minus the direction flag) */
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
132
  	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
133
134
  
  	/* copy from a bounce buffer, if necessary */
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
135
136
137
  	if (status && wh->dma_bounce_buffer) {
  		if (wh->dma_dir)
  			memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
138
  			       SCpnt->SCp.this_residual);
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
139
140
141
  		kfree(wh->dma_bounce_buffer);
  		wh->dma_bounce_buffer = NULL;
  		wh->dma_bounce_len = 0;
09bc85b08   Geert Uytterhoeven   [SCSI] a2091: Rei...
142
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  }
65396410a   Henrik Kretzschmar   [SCSI] wd33c93: S...
144
  static int a2091_bus_reset(struct scsi_cmnd *cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  {
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
146
  	struct Scsi_Host *instance = cmd->device->host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	/* FIXME perform bus-specific reset */
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
148

df0ae2497   Jeff Garzik   [SCSI] allow slee...
149
150
  	/* FIXME 2: kill this function, and let midlayer fall back
  	   to the same action, calling wd33c93_host_reset() */
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
151
  	spin_lock_irq(instance->host_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	wd33c93_host_reset(cmd);
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
153
  	spin_unlock_irq(instance->host_lock);
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
154

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
  	return SUCCESS;
  }
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
157
158
  static struct scsi_host_template a2091_scsi_template = {
  	.module			= THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	.name			= "Commodore A2091/A590 SCSI",
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
160
161
  	.proc_info		= wd33c93_proc_info,
  	.proc_name		= "A2901",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
168
169
170
171
  	.queuecommand		= wd33c93_queuecommand,
  	.eh_abort_handler	= wd33c93_abort,
  	.eh_bus_reset_handler	= a2091_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		= DISABLE_CLUSTERING
  };
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
172
173
174
175
176
177
178
  static int __devinit a2091_probe(struct zorro_dev *z,
  				 const struct zorro_device_id *ent)
  {
  	struct Scsi_Host *instance;
  	int error;
  	struct a2091_scsiregs *regs;
  	wd33c93_regs wdregs;
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
179
  	struct a2091_hostdata *hdata;
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
180
181
182
183
184
  
  	if (!request_mem_region(z->resource.start, 256, "wd33c93"))
  		return -EBUSY;
  
  	instance = scsi_host_alloc(&a2091_scsi_template,
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
185
  				   sizeof(struct a2091_hostdata));
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
186
187
188
189
  	if (!instance) {
  		error = -ENOMEM;
  		goto fail_alloc;
  	}
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
190
191
  	instance->irq = IRQ_AMIGA_PORTS;
  	instance->unique_id = z->slotaddr;
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
192
  	regs = (struct a2091_scsiregs *)ZTWO_VADDR(z->resource.start);
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
193
194
195
196
  	regs->DAWR = DAWR_A2091;
  
  	wdregs.SASR = &regs->SASR;
  	wdregs.SCMD = &regs->SCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197

c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
198
  	hdata = shost_priv(instance);
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
199
200
201
202
  	hdata->wh.no_sync = 0xff;
  	hdata->wh.fast = 0;
  	hdata->wh.dma_mode = CTRL_DMA;
  	hdata->regs = regs;
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  
  	wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10);
  	error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
  			    "A2091 SCSI", instance);
  	if (error)
  		goto fail_irq;
  
  	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
  
  	error = scsi_add_host(instance, NULL);
  	if (error)
  		goto fail_host;
  
  	zorro_set_drvdata(z, instance);
  
  	scsi_scan_host(instance);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
221
222
223
224
225
226
227
228
229
230
  fail_host:
  	free_irq(IRQ_AMIGA_PORTS, instance);
  fail_irq:
  	scsi_host_put(instance);
  fail_alloc:
  	release_mem_region(z->resource.start, 256);
  	return error;
  }
  
  static void __devexit a2091_remove(struct zorro_dev *z)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
232
  	struct Scsi_Host *instance = zorro_get_drvdata(z);
65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
233
  	struct a2091_hostdata *hdata = shost_priv(instance);
b1de6ab79   Geert Uytterhoeven   [SCSI] a2091: Kil...
234

65c2784a2   Geert Uytterhoeven   m68k/scsi: a2091 ...
235
  	hdata->regs->CNTR = 0;
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
236
  	scsi_remove_host(instance);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  	free_irq(IRQ_AMIGA_PORTS, instance);
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  	scsi_host_put(instance);
  	release_mem_region(z->resource.start, 256);
  }
  
  static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = {
  	{ ZORRO_PROD_CBM_A590_A2091_1 },
  	{ ZORRO_PROD_CBM_A590_A2091_2 },
  	{ 0 }
  };
  MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl);
  
  static struct zorro_driver a2091_driver = {
  	.name		= "a2091",
  	.id_table	= a2091_zorro_tbl,
  	.probe		= a2091_probe,
  	.remove		= __devexit_p(a2091_remove),
  };
  
  static int __init a2091_init(void)
  {
  	return zorro_register_driver(&a2091_driver);
  }
  module_init(a2091_init);
  
  static void __exit a2091_exit(void)
  {
  	zorro_unregister_driver(&a2091_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  }
c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
266
  module_exit(a2091_exit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267

c737e22cd   Geert Uytterhoeven   m68k: amiga - A20...
268
  MODULE_DESCRIPTION("Commodore A2091/A590 SCSI");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  MODULE_LICENSE("GPL");