diff options
author | Geert Uytterhoeven <geert@linux-m68k.org> | 2009-04-05 07:02:45 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2010-05-26 13:51:08 -0400 |
commit | c2a24a4ca1137473971842461612e56a654e7edb (patch) | |
tree | 0ed24e0553dc004d0729d22c7b4d9709f76e2621 /drivers/scsi/a3000.c | |
parent | cf2ed279f915f36c84ce21a5933ad4bba9f81de8 (diff) |
m68k: amiga - A3000 SCSI platform device conversion
Acked-by: James Bottomley <James.Bottomley@suse.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'drivers/scsi/a3000.c')
-rw-r--r-- | drivers/scsi/a3000.c | 164 |
1 files changed, 100 insertions, 64 deletions
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 79a4a3c97474..7f09d89100a1 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c | |||
@@ -1,28 +1,21 @@ | |||
1 | #include <linux/types.h> | 1 | #include <linux/types.h> |
2 | #include <linux/mm.h> | 2 | #include <linux/mm.h> |
3 | #include <linux/slab.h> | ||
4 | #include <linux/blkdev.h> | ||
5 | #include <linux/ioport.h> | 3 | #include <linux/ioport.h> |
6 | #include <linux/init.h> | 4 | #include <linux/init.h> |
5 | #include <linux/slab.h> | ||
7 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
8 | #include <linux/interrupt.h> | 7 | #include <linux/interrupt.h> |
8 | #include <linux/platform_device.h> | ||
9 | 9 | ||
10 | #include <asm/setup.h> | ||
11 | #include <asm/page.h> | 10 | #include <asm/page.h> |
12 | #include <asm/pgtable.h> | 11 | #include <asm/pgtable.h> |
13 | #include <asm/amigaints.h> | 12 | #include <asm/amigaints.h> |
14 | #include <asm/amigahw.h> | 13 | #include <asm/amigahw.h> |
15 | #include <asm/irq.h> | ||
16 | 14 | ||
17 | #include "scsi.h" | 15 | #include "scsi.h" |
18 | #include <scsi/scsi_host.h> | ||
19 | #include "wd33c93.h" | 16 | #include "wd33c93.h" |
20 | #include "a3000.h" | 17 | #include "a3000.h" |
21 | 18 | ||
22 | #include <linux/stat.h> | ||
23 | |||
24 | |||
25 | static int a3000_release(struct Scsi_Host *instance); | ||
26 | 19 | ||
27 | static irqreturn_t a3000_intr(int irq, void *data) | 20 | static irqreturn_t a3000_intr(int irq, void *data) |
28 | { | 21 | { |
@@ -39,7 +32,7 @@ static irqreturn_t a3000_intr(int irq, void *data) | |||
39 | spin_unlock_irqrestore(instance->host_lock, flags); | 32 | spin_unlock_irqrestore(instance->host_lock, flags); |
40 | return IRQ_HANDLED; | 33 | return IRQ_HANDLED; |
41 | } | 34 | } |
42 | printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); | 35 | pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); |
43 | return IRQ_NONE; | 36 | return IRQ_NONE; |
44 | } | 37 | } |
45 | 38 | ||
@@ -162,93 +155,136 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, | |||
162 | } | 155 | } |
163 | } | 156 | } |
164 | 157 | ||
165 | static int __init a3000_detect(struct scsi_host_template *tpnt) | 158 | static int a3000_bus_reset(struct scsi_cmnd *cmd) |
159 | { | ||
160 | struct Scsi_Host *instance = cmd->device->host; | ||
161 | |||
162 | /* FIXME perform bus-specific reset */ | ||
163 | |||
164 | /* FIXME 2: kill this entire function, which should | ||
165 | cause mid-layer to call wd33c93_host_reset anyway? */ | ||
166 | |||
167 | spin_lock_irq(instance->host_lock); | ||
168 | wd33c93_host_reset(cmd); | ||
169 | spin_unlock_irq(instance->host_lock); | ||
170 | |||
171 | return SUCCESS; | ||
172 | } | ||
173 | |||
174 | static struct scsi_host_template amiga_a3000_scsi_template = { | ||
175 | .module = THIS_MODULE, | ||
176 | .name = "Amiga 3000 built-in SCSI", | ||
177 | .proc_info = wd33c93_proc_info, | ||
178 | .proc_name = "A3000", | ||
179 | .queuecommand = wd33c93_queuecommand, | ||
180 | .eh_abort_handler = wd33c93_abort, | ||
181 | .eh_bus_reset_handler = a3000_bus_reset, | ||
182 | .eh_host_reset_handler = wd33c93_host_reset, | ||
183 | .can_queue = CAN_QUEUE, | ||
184 | .this_id = 7, | ||
185 | .sg_tablesize = SG_ALL, | ||
186 | .cmd_per_lun = CMD_PER_LUN, | ||
187 | .use_clustering = ENABLE_CLUSTERING | ||
188 | }; | ||
189 | |||
190 | static int __init amiga_a3000_scsi_probe(struct platform_device *pdev) | ||
166 | { | 191 | { |
192 | struct resource *res; | ||
167 | struct Scsi_Host *instance; | 193 | struct Scsi_Host *instance; |
168 | wd33c93_regs wdregs; | 194 | int error; |
169 | struct a3000_scsiregs *regs; | 195 | struct a3000_scsiregs *regs; |
196 | wd33c93_regs wdregs; | ||
170 | struct WD33C93_hostdata *hdata; | 197 | struct WD33C93_hostdata *hdata; |
171 | 198 | ||
172 | if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) | 199 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
173 | return 0; | 200 | if (!res) |
174 | if (!request_mem_region(0xDD0000, 256, "wd33c93")) | 201 | return -ENODEV; |
175 | return 0; | ||
176 | 202 | ||
177 | tpnt->proc_name = "A3000"; | 203 | if (!request_mem_region(res->start, resource_size(res), "wd33c93")) |
178 | tpnt->proc_info = &wd33c93_proc_info; | 204 | return -EBUSY; |
179 | 205 | ||
180 | instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); | 206 | instance = scsi_host_alloc(&amiga_a3000_scsi_template, |
181 | if (instance == NULL) | 207 | sizeof(struct WD33C93_hostdata)); |
182 | goto fail_register; | 208 | if (!instance) { |
209 | error = -ENOMEM; | ||
210 | goto fail_alloc; | ||
211 | } | ||
183 | 212 | ||
184 | instance->base = ZTWO_VADDR(0xDD0000); | 213 | instance->base = ZTWO_VADDR(res->start); |
185 | instance->irq = IRQ_AMIGA_PORTS; | 214 | instance->irq = IRQ_AMIGA_PORTS; |
215 | |||
186 | regs = (struct a3000_scsiregs *)(instance->base); | 216 | regs = (struct a3000_scsiregs *)(instance->base); |
187 | regs->DAWR = DAWR_A3000; | 217 | regs->DAWR = DAWR_A3000; |
218 | |||
188 | wdregs.SASR = ®s->SASR; | 219 | wdregs.SASR = ®s->SASR; |
189 | wdregs.SCMD = ®s->SCMD; | 220 | wdregs.SCMD = ®s->SCMD; |
221 | |||
190 | hdata = shost_priv(instance); | 222 | hdata = shost_priv(instance); |
191 | hdata->no_sync = 0xff; | 223 | hdata->no_sync = 0xff; |
192 | hdata->fast = 0; | 224 | hdata->fast = 0; |
193 | hdata->dma_mode = CTRL_DMA; | 225 | hdata->dma_mode = CTRL_DMA; |
226 | |||
194 | wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); | 227 | wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); |
195 | if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", | 228 | error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, |
196 | instance)) | 229 | "A3000 SCSI", instance); |
230 | if (error) | ||
197 | goto fail_irq; | 231 | goto fail_irq; |
232 | |||
198 | regs->CNTR = CNTR_PDMD | CNTR_INTEN; | 233 | regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
199 | 234 | ||
200 | return 1; | 235 | error = scsi_add_host(instance, NULL); |
236 | if (error) | ||
237 | goto fail_host; | ||
201 | 238 | ||
202 | fail_irq: | 239 | platform_set_drvdata(pdev, instance); |
203 | scsi_unregister(instance); | 240 | |
204 | fail_register: | 241 | scsi_scan_host(instance); |
205 | release_mem_region(0xDD0000, 256); | ||
206 | return 0; | 242 | return 0; |
243 | |||
244 | fail_host: | ||
245 | free_irq(IRQ_AMIGA_PORTS, instance); | ||
246 | fail_irq: | ||
247 | scsi_host_put(instance); | ||
248 | fail_alloc: | ||
249 | release_mem_region(res->start, resource_size(res)); | ||
250 | return error; | ||
207 | } | 251 | } |
208 | 252 | ||
209 | static int a3000_bus_reset(struct scsi_cmnd *cmd) | 253 | static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) |
210 | { | 254 | { |
211 | /* FIXME perform bus-specific reset */ | 255 | struct Scsi_Host *instance = platform_get_drvdata(pdev); |
212 | 256 | struct a3000_scsiregs *regs = (struct a3000_scsiregs *)(instance->base); | |
213 | /* FIXME 2: kill this entire function, which should | 257 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
214 | cause mid-layer to call wd33c93_host_reset anyway? */ | ||
215 | |||
216 | spin_lock_irq(cmd->device->host->host_lock); | ||
217 | wd33c93_host_reset(cmd); | ||
218 | spin_unlock_irq(cmd->device->host->host_lock); | ||
219 | 258 | ||
220 | return SUCCESS; | 259 | regs->CNTR = 0; |
260 | scsi_remove_host(instance); | ||
261 | free_irq(IRQ_AMIGA_PORTS, instance); | ||
262 | scsi_host_put(instance); | ||
263 | release_mem_region(res->start, resource_size(res)); | ||
264 | return 0; | ||
221 | } | 265 | } |
222 | 266 | ||
223 | #define HOSTS_C | 267 | static struct platform_driver amiga_a3000_scsi_driver = { |
224 | 268 | .remove = __exit_p(amiga_a3000_scsi_remove), | |
225 | static struct scsi_host_template driver_template = { | 269 | .driver = { |
226 | .proc_name = "A3000", | 270 | .name = "amiga-a3000-scsi", |
227 | .name = "Amiga 3000 built-in SCSI", | 271 | .owner = THIS_MODULE, |
228 | .detect = a3000_detect, | 272 | }, |
229 | .release = a3000_release, | ||
230 | .queuecommand = wd33c93_queuecommand, | ||
231 | .eh_abort_handler = wd33c93_abort, | ||
232 | .eh_bus_reset_handler = a3000_bus_reset, | ||
233 | .eh_host_reset_handler = wd33c93_host_reset, | ||
234 | .can_queue = CAN_QUEUE, | ||
235 | .this_id = 7, | ||
236 | .sg_tablesize = SG_ALL, | ||
237 | .cmd_per_lun = CMD_PER_LUN, | ||
238 | .use_clustering = ENABLE_CLUSTERING | ||
239 | }; | 273 | }; |
240 | 274 | ||
241 | 275 | static int __init amiga_a3000_scsi_init(void) | |
242 | #include "scsi_module.c" | ||
243 | |||
244 | static int a3000_release(struct Scsi_Host *instance) | ||
245 | { | 276 | { |
246 | struct a3000_scsiregs *regs = (struct a3000_scsiregs *)(instance->base); | 277 | return platform_driver_probe(&amiga_a3000_scsi_driver, |
278 | amiga_a3000_scsi_probe); | ||
279 | } | ||
280 | module_init(amiga_a3000_scsi_init); | ||
247 | 281 | ||
248 | regs->CNTR = 0; | 282 | static void __exit amiga_a3000_scsi_exit(void) |
249 | release_mem_region(0xDD0000, 256); | 283 | { |
250 | free_irq(IRQ_AMIGA_PORTS, a3000_intr); | 284 | platform_driver_unregister(&amiga_a3000_scsi_driver); |
251 | return 1; | ||
252 | } | 285 | } |
286 | module_exit(amiga_a3000_scsi_exit); | ||
253 | 287 | ||
288 | MODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); | ||
254 | MODULE_LICENSE("GPL"); | 289 | MODULE_LICENSE("GPL"); |
290 | MODULE_ALIAS("platform:amiga-a3000-scsi"); | ||