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 | |
| 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>
| -rw-r--r-- | arch/m68k/amiga/platform.c | 11 | ||||
| -rw-r--r-- | drivers/scsi/a3000.c | 164 |
2 files changed, 111 insertions, 64 deletions
diff --git a/arch/m68k/amiga/platform.c b/arch/m68k/amiga/platform.c index 38f18bf14737..df1fae3c3729 100644 --- a/arch/m68k/amiga/platform.c +++ b/arch/m68k/amiga/platform.c | |||
| @@ -58,6 +58,13 @@ subsys_initcall(amiga_init_bus); | |||
| 58 | #endif /* CONFIG_ZORRO */ | 58 | #endif /* CONFIG_ZORRO */ |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | static const struct resource a3000_scsi_resource __initconst = { | ||
| 62 | .start = 0xdd0000, | ||
| 63 | .end = 0xdd00ff, | ||
| 64 | .flags = IORESOURCE_MEM, | ||
| 65 | }; | ||
| 66 | |||
| 67 | |||
| 61 | static int __init amiga_init_devices(void) | 68 | static int __init amiga_init_devices(void) |
| 62 | { | 69 | { |
| 63 | if (!MACH_IS_AMIGA) | 70 | if (!MACH_IS_AMIGA) |
| @@ -77,6 +84,10 @@ static int __init amiga_init_devices(void) | |||
| 77 | if (AMIGAHW_PRESENT(AMI_FLOPPY)) | 84 | if (AMIGAHW_PRESENT(AMI_FLOPPY)) |
| 78 | platform_device_register_simple("amiga-floppy", -1, NULL, 0); | 85 | platform_device_register_simple("amiga-floppy", -1, NULL, 0); |
| 79 | 86 | ||
| 87 | if (AMIGAHW_PRESENT(A3000_SCSI)) | ||
| 88 | platform_device_register_simple("amiga-a3000-scsi", -1, | ||
| 89 | &a3000_scsi_resource, 1); | ||
| 90 | |||
| 80 | return 0; | 91 | return 0; |
| 81 | } | 92 | } |
| 82 | 93 | ||
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"); | ||
