Blame view
drivers/scsi/a3000.c
7.21 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 |
#include <linux/types.h> #include <linux/mm.h> |
1da177e4c Linux-2.6.12-rc2 |
3 4 |
#include <linux/ioport.h> #include <linux/init.h> |
c2a24a4ca m68k: amiga - A30... |
5 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
6 7 |
#include <linux/spinlock.h> #include <linux/interrupt.h> |
c2a24a4ca m68k: amiga - A30... |
8 |
#include <linux/platform_device.h> |
acf3368ff scsi: Fix up file... |
9 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
10 |
|
1da177e4c 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 Linux-2.6.12-rc2 |
15 16 |
#include "scsi.h" |
1da177e4c Linux-2.6.12-rc2 |
17 18 |
#include "wd33c93.h" #include "a3000.h" |
9387edbe6 [SCSI] a3000: mak... |
19 |
|
2b21d5e47 m68k/scsi: a3000 ... |
20 21 22 23 |
struct a3000_hostdata { struct WD33C93_hostdata wh; struct a3000_scsiregs *regs; }; |
a8169e605 m68k/scsi: a3000 ... |
24 |
static irqreturn_t a3000_intr(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
25 |
{ |
a8169e605 m68k/scsi: a3000 ... |
26 |
struct Scsi_Host *instance = data; |
2b21d5e47 m68k/scsi: a3000 ... |
27 28 |
struct a3000_hostdata *hdata = shost_priv(instance); unsigned int status = hdata->regs->ISTR; |
1da177e4c Linux-2.6.12-rc2 |
29 |
unsigned long flags; |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 |
if (!(status & ISTR_INT_P)) return IRQ_NONE; |
213510134 [SCSI] a3000: Rei... |
33 |
if (status & ISTR_INTS) { |
a8169e605 m68k/scsi: a3000 ... |
34 35 36 |
spin_lock_irqsave(instance->host_lock, flags); wd33c93_intr(instance); spin_unlock_irqrestore(instance->host_lock, flags); |
1da177e4c Linux-2.6.12-rc2 |
37 38 |
return IRQ_HANDLED; } |
c2a24a4ca m68k: amiga - A30... |
39 40 |
pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x ", status); |
1da177e4c Linux-2.6.12-rc2 |
41 42 |
return IRQ_NONE; } |
65396410a [SCSI] wd33c93: S... |
43 |
static int dma_setup(struct scsi_cmnd *cmd, int dir_in) |
1da177e4c Linux-2.6.12-rc2 |
44 |
{ |
a8169e605 m68k/scsi: a3000 ... |
45 |
struct Scsi_Host *instance = cmd->device->host; |
2b21d5e47 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 [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 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 [SCSI] a3000: Rei... |
62 63 |
/* can't allocate memory; use PIO */ |
2b21d5e47 m68k/scsi: a3000 ... |
64 65 |
if (!wh->dma_bounce_buffer) { wh->dma_bounce_len = 0; |
213510134 [SCSI] a3000: Rei... |
66 67 68 69 70 |
return 1; } if (!dir_in) { /* copy to bounce buffer for a write */ |
2b21d5e47 m68k/scsi: a3000 ... |
71 |
memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, |
afdbbc161 [SCSI] a3000: Use... |
72 |
cmd->SCp.this_residual); |
213510134 [SCSI] a3000: Rei... |
73 |
} |
2b21d5e47 m68k/scsi: a3000 ... |
74 |
addr = virt_to_bus(wh->dma_bounce_buffer); |
1da177e4c Linux-2.6.12-rc2 |
75 |
} |
213510134 [SCSI] a3000: Rei... |
76 77 78 |
/* setup dma direction */ if (!dir_in) cntr |= CNTR_DDIR; |
1da177e4c Linux-2.6.12-rc2 |
79 |
|
213510134 [SCSI] a3000: Rei... |
80 |
/* remember direction */ |
2b21d5e47 m68k/scsi: a3000 ... |
81 |
wh->dma_dir = dir_in; |
1da177e4c Linux-2.6.12-rc2 |
82 |
|
d753722ee m68k/scsi: a3000 ... |
83 |
regs->CNTR = cntr; |
1da177e4c Linux-2.6.12-rc2 |
84 |
|
213510134 [SCSI] a3000: Rei... |
85 |
/* setup DMA *physical* address */ |
d753722ee m68k/scsi: a3000 ... |
86 |
regs->ACR = addr; |
1da177e4c Linux-2.6.12-rc2 |
87 |
|
213510134 [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 Linux-2.6.12-rc2 |
95 |
|
213510134 [SCSI] a3000: Rei... |
96 97 |
/* start DMA */ mb(); /* make sure setup is completed */ |
d753722ee m68k/scsi: a3000 ... |
98 |
regs->ST_DMA = 1; |
213510134 [SCSI] a3000: Rei... |
99 |
mb(); /* make sure DMA has started before next IO */ |
1da177e4c Linux-2.6.12-rc2 |
100 |
|
213510134 [SCSI] a3000: Rei... |
101 102 |
/* return success */ return 0; |
1da177e4c Linux-2.6.12-rc2 |
103 |
} |
65396410a [SCSI] wd33c93: S... |
104 105 |
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, int status) |
1da177e4c Linux-2.6.12-rc2 |
106 |
{ |
2b21d5e47 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 [SCSI] a3000: Use... |
110 |
|
213510134 [SCSI] a3000: Rei... |
111 112 |
/* disable SCSI interrupts */ unsigned short cntr = CNTR_PDMD; |
2b21d5e47 m68k/scsi: a3000 ... |
113 |
if (!wh->dma_dir) |
213510134 [SCSI] a3000: Rei... |
114 |
cntr |= CNTR_DDIR; |
d753722ee m68k/scsi: a3000 ... |
115 |
regs->CNTR = cntr; |
213510134 [SCSI] a3000: Rei... |
116 117 118 |
mb(); /* make sure CNTR is updated before next IO */ /* flush if we were reading */ |
2b21d5e47 m68k/scsi: a3000 ... |
119 |
if (wh->dma_dir) { |
d753722ee m68k/scsi: a3000 ... |
120 |
regs->FLUSH = 1; |
213510134 [SCSI] a3000: Rei... |
121 |
mb(); /* don't allow prefetch */ |
d753722ee m68k/scsi: a3000 ... |
122 |
while (!(regs->ISTR & ISTR_FE_FLG)) |
213510134 [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 m68k/scsi: a3000 ... |
131 |
regs->CINT = 1; |
213510134 [SCSI] a3000: Rei... |
132 133 |
/* stop DMA */ |
d753722ee m68k/scsi: a3000 ... |
134 |
regs->SP_DMA = 1; |
213510134 [SCSI] a3000: Rei... |
135 136 137 |
mb(); /* make sure DMA is stopped before next IO */ /* restore the CONTROL bits (minus the direction flag) */ |
d753722ee m68k/scsi: a3000 ... |
138 |
regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
213510134 [SCSI] a3000: Rei... |
139 140 141 |
mb(); /* make sure CNTR is updated before next IO */ /* copy from a bounce buffer, if necessary */ |
2b21d5e47 m68k/scsi: a3000 ... |
142 |
if (status && wh->dma_bounce_buffer) { |
213510134 [SCSI] a3000: Rei... |
143 |
if (SCpnt) { |
2b21d5e47 m68k/scsi: a3000 ... |
144 145 |
if (wh->dma_dir && SCpnt) memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, |
213510134 [SCSI] a3000: Rei... |
146 |
SCpnt->SCp.this_residual); |
2b21d5e47 m68k/scsi: a3000 ... |
147 148 149 |
kfree(wh->dma_bounce_buffer); wh->dma_bounce_buffer = NULL; wh->dma_bounce_len = 0; |
213510134 [SCSI] a3000: Rei... |
150 |
} else { |
2b21d5e47 m68k/scsi: a3000 ... |
151 152 153 |
kfree(wh->dma_bounce_buffer); wh->dma_bounce_buffer = NULL; wh->dma_bounce_len = 0; |
213510134 [SCSI] a3000: Rei... |
154 |
} |
1da177e4c Linux-2.6.12-rc2 |
155 |
} |
1da177e4c Linux-2.6.12-rc2 |
156 |
} |
c2a24a4ca m68k: amiga - A30... |
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 189 |
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 Linux-2.6.12-rc2 |
190 |
{ |
c2a24a4ca m68k: amiga - A30... |
191 |
struct resource *res; |
a8169e605 m68k/scsi: a3000 ... |
192 |
struct Scsi_Host *instance; |
c2a24a4ca m68k: amiga - A30... |
193 |
int error; |
c57c1cab7 m68k/scsi: a3000 ... |
194 |
struct a3000_scsiregs *regs; |
c2a24a4ca m68k: amiga - A30... |
195 |
wd33c93_regs wdregs; |
2b21d5e47 m68k/scsi: a3000 ... |
196 |
struct a3000_hostdata *hdata; |
213510134 [SCSI] a3000: Rei... |
197 |
|
c2a24a4ca m68k: amiga - A30... |
198 199 200 |
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; |
213510134 [SCSI] a3000: Rei... |
201 |
|
c2a24a4ca m68k: amiga - A30... |
202 203 |
if (!request_mem_region(res->start, resource_size(res), "wd33c93")) return -EBUSY; |
213510134 [SCSI] a3000: Rei... |
204 |
|
c2a24a4ca m68k: amiga - A30... |
205 |
instance = scsi_host_alloc(&amiga_a3000_scsi_template, |
2b21d5e47 m68k/scsi: a3000 ... |
206 |
sizeof(struct a3000_hostdata)); |
c2a24a4ca m68k: amiga - A30... |
207 208 209 210 |
if (!instance) { error = -ENOMEM; goto fail_alloc; } |
213510134 [SCSI] a3000: Rei... |
211 |
|
a8169e605 m68k/scsi: a3000 ... |
212 |
instance->irq = IRQ_AMIGA_PORTS; |
c2a24a4ca m68k: amiga - A30... |
213 |
|
2b21d5e47 m68k/scsi: a3000 ... |
214 |
regs = (struct a3000_scsiregs *)ZTWO_VADDR(res->start); |
d753722ee m68k/scsi: a3000 ... |
215 |
regs->DAWR = DAWR_A3000; |
c2a24a4ca m68k: amiga - A30... |
216 |
|
d753722ee m68k/scsi: a3000 ... |
217 218 |
wdregs.SASR = ®s->SASR; wdregs.SCMD = ®s->SCMD; |
c2a24a4ca m68k: amiga - A30... |
219 |
|
a8169e605 m68k/scsi: a3000 ... |
220 |
hdata = shost_priv(instance); |
2b21d5e47 m68k/scsi: a3000 ... |
221 222 223 224 |
hdata->wh.no_sync = 0xff; hdata->wh.fast = 0; hdata->wh.dma_mode = CTRL_DMA; hdata->regs = regs; |
c2a24a4ca m68k: amiga - A30... |
225 |
|
a8169e605 m68k/scsi: a3000 ... |
226 |
wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); |
c2a24a4ca m68k: amiga - A30... |
227 228 229 |
error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", instance); if (error) |
213510134 [SCSI] a3000: Rei... |
230 |
goto fail_irq; |
c2a24a4ca m68k: amiga - A30... |
231 |
|
d753722ee m68k/scsi: a3000 ... |
232 |
regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
213510134 [SCSI] a3000: Rei... |
233 |
|
c2a24a4ca m68k: amiga - A30... |
234 235 236 |
error = scsi_add_host(instance, NULL); if (error) goto fail_host; |
1da177e4c Linux-2.6.12-rc2 |
237 |
|
c2a24a4ca m68k: amiga - A30... |
238 239 240 |
platform_set_drvdata(pdev, instance); scsi_scan_host(instance); |
213510134 [SCSI] a3000: Rei... |
241 |
return 0; |
c2a24a4ca m68k: amiga - A30... |
242 243 244 245 246 247 248 249 |
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 Linux-2.6.12-rc2 |
250 |
} |
c2a24a4ca m68k: amiga - A30... |
251 |
static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
252 |
{ |
c2a24a4ca m68k: amiga - A30... |
253 |
struct Scsi_Host *instance = platform_get_drvdata(pdev); |
2b21d5e47 m68k/scsi: a3000 ... |
254 |
struct a3000_hostdata *hdata = shost_priv(instance); |
c2a24a4ca m68k: amiga - A30... |
255 |
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
68b3aa7c9 [SCSI] allow slee... |
256 |
|
2b21d5e47 m68k/scsi: a3000 ... |
257 |
hdata->regs->CNTR = 0; |
c2a24a4ca m68k: amiga - A30... |
258 259 260 261 262 |
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 Linux-2.6.12-rc2 |
263 |
} |
c2a24a4ca m68k: amiga - A30... |
264 265 266 267 268 269 |
static struct platform_driver amiga_a3000_scsi_driver = { .remove = __exit_p(amiga_a3000_scsi_remove), .driver = { .name = "amiga-a3000-scsi", .owner = THIS_MODULE, }, |
1da177e4c Linux-2.6.12-rc2 |
270 |
}; |
c2a24a4ca m68k: amiga - A30... |
271 |
static int __init amiga_a3000_scsi_init(void) |
1da177e4c Linux-2.6.12-rc2 |
272 |
{ |
c2a24a4ca m68k: amiga - A30... |
273 274 275 276 |
return platform_driver_probe(&amiga_a3000_scsi_driver, amiga_a3000_scsi_probe); } module_init(amiga_a3000_scsi_init); |
d753722ee m68k/scsi: a3000 ... |
277 |
|
c2a24a4ca m68k: amiga - A30... |
278 279 280 |
static void __exit amiga_a3000_scsi_exit(void) { platform_driver_unregister(&amiga_a3000_scsi_driver); |
1da177e4c Linux-2.6.12-rc2 |
281 |
} |
c2a24a4ca m68k: amiga - A30... |
282 |
module_exit(amiga_a3000_scsi_exit); |
1da177e4c Linux-2.6.12-rc2 |
283 |
|
c2a24a4ca m68k: amiga - A30... |
284 |
MODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); |
1da177e4c Linux-2.6.12-rc2 |
285 |
MODULE_LICENSE("GPL"); |
c2a24a4ca m68k: amiga - A30... |
286 |
MODULE_ALIAS("platform:amiga-a3000-scsi"); |