Blame view
drivers/scsi/a3000.c
6.96 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 |
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 switch wd33c93 to... |
176 177 |
.show_info = wd33c93_show_info, .write_info = wd33c93_write_info, |
c2a24a4ca 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 Linux-2.6.12-rc2 |
191 |
{ |
c2a24a4ca m68k: amiga - A30... |
192 |
struct resource *res; |
a8169e605 m68k/scsi: a3000 ... |
193 |
struct Scsi_Host *instance; |
c2a24a4ca m68k: amiga - A30... |
194 |
int error; |
c57c1cab7 m68k/scsi: a3000 ... |
195 |
struct a3000_scsiregs *regs; |
c2a24a4ca m68k: amiga - A30... |
196 |
wd33c93_regs wdregs; |
2b21d5e47 m68k/scsi: a3000 ... |
197 |
struct a3000_hostdata *hdata; |
213510134 [SCSI] a3000: Rei... |
198 |
|
c2a24a4ca m68k: amiga - A30... |
199 200 201 |
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; |
213510134 [SCSI] a3000: Rei... |
202 |
|
c2a24a4ca m68k: amiga - A30... |
203 204 |
if (!request_mem_region(res->start, resource_size(res), "wd33c93")) return -EBUSY; |
213510134 [SCSI] a3000: Rei... |
205 |
|
c2a24a4ca m68k: amiga - A30... |
206 |
instance = scsi_host_alloc(&amiga_a3000_scsi_template, |
2b21d5e47 m68k/scsi: a3000 ... |
207 |
sizeof(struct a3000_hostdata)); |
c2a24a4ca m68k: amiga - A30... |
208 209 210 211 |
if (!instance) { error = -ENOMEM; goto fail_alloc; } |
213510134 [SCSI] a3000: Rei... |
212 |
|
a8169e605 m68k/scsi: a3000 ... |
213 |
instance->irq = IRQ_AMIGA_PORTS; |
c2a24a4ca m68k: amiga - A30... |
214 |
|
6112ea086 zorro: ZTWO_VADDR... |
215 |
regs = ZTWO_VADDR(res->start); |
d753722ee m68k/scsi: a3000 ... |
216 |
regs->DAWR = DAWR_A3000; |
c2a24a4ca m68k: amiga - A30... |
217 |
|
d753722ee m68k/scsi: a3000 ... |
218 219 |
wdregs.SASR = ®s->SASR; wdregs.SCMD = ®s->SCMD; |
c2a24a4ca m68k: amiga - A30... |
220 |
|
a8169e605 m68k/scsi: a3000 ... |
221 |
hdata = shost_priv(instance); |
2b21d5e47 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 m68k: amiga - A30... |
226 |
|
a8169e605 m68k/scsi: a3000 ... |
227 |
wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); |
c2a24a4ca m68k: amiga - A30... |
228 229 230 |
error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", instance); if (error) |
213510134 [SCSI] a3000: Rei... |
231 |
goto fail_irq; |
c2a24a4ca m68k: amiga - A30... |
232 |
|
d753722ee m68k/scsi: a3000 ... |
233 |
regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
213510134 [SCSI] a3000: Rei... |
234 |
|
c2a24a4ca m68k: amiga - A30... |
235 236 237 |
error = scsi_add_host(instance, NULL); if (error) goto fail_host; |
1da177e4c Linux-2.6.12-rc2 |
238 |
|
c2a24a4ca m68k: amiga - A30... |
239 240 241 |
platform_set_drvdata(pdev, instance); scsi_scan_host(instance); |
213510134 [SCSI] a3000: Rei... |
242 |
return 0; |
c2a24a4ca 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 Linux-2.6.12-rc2 |
251 |
} |
c2a24a4ca m68k: amiga - A30... |
252 |
static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
253 |
{ |
c2a24a4ca m68k: amiga - A30... |
254 |
struct Scsi_Host *instance = platform_get_drvdata(pdev); |
2b21d5e47 m68k/scsi: a3000 ... |
255 |
struct a3000_hostdata *hdata = shost_priv(instance); |
c2a24a4ca m68k: amiga - A30... |
256 |
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
68b3aa7c9 [SCSI] allow slee... |
257 |
|
2b21d5e47 m68k/scsi: a3000 ... |
258 |
hdata->regs->CNTR = 0; |
c2a24a4ca 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 Linux-2.6.12-rc2 |
264 |
} |
c2a24a4ca 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 m68k: amiga - A30... |
269 |
}, |
1da177e4c Linux-2.6.12-rc2 |
270 |
}; |
a915b84a7 [SCSI] a3000: use... |
271 |
module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe); |
1da177e4c Linux-2.6.12-rc2 |
272 |
|
c2a24a4ca m68k: amiga - A30... |
273 |
MODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); |
1da177e4c Linux-2.6.12-rc2 |
274 |
MODULE_LICENSE("GPL"); |
c2a24a4ca m68k: amiga - A30... |
275 |
MODULE_ALIAS("platform:amiga-a3000-scsi"); |