diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2007-02-05 19:28:29 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-02-09 11:23:17 -0500 |
commit | 4df4db5c6c6daeb10a8693d09ce872bce8cd84e6 (patch) | |
tree | 7ec7632d88253f41c4b4a2faf0f404f661ed6f50 /drivers/scsi/dec_esp.c | |
parent | 335dc50cec2891026bd51e46769fc12365b6e475 (diff) |
[TC] dec_esp: Driver model for the PMAZ-A
This is a set of changes that converts the PMAZ-A support to the driver model.
The use of the driver model required switching to the hotplug SCSI
initialization model, which in turn required a change to the core NCR53C9x
driver. I decided not to break all the frontend drivers and introduced an
additional parameter for esp_allocate() to select between the old and the new
model. I hope this is OK, but I would be fine with converting NCR53C9x to the
new model unconditionally as long as I do not have to fix all the other
frontends (OK, perhaps I could do some of them ;-) ).
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/scsi/dec_esp.c')
-rw-r--r-- | drivers/scsi/dec_esp.c | 355 |
1 files changed, 232 insertions, 123 deletions
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index c29ccbc44693..d42ad663ffee 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * 20001005 - Initialization fixes for 2.4.0-test9 | 18 | * 20001005 - Initialization fixes for 2.4.0-test9 |
19 | * Florian Lohoff <flo@rfc822.org> | 19 | * Florian Lohoff <flo@rfc822.org> |
20 | * | 20 | * |
21 | * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki | 21 | * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/proc_fs.h> | 30 | #include <linux/proc_fs.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <linux/stat.h> | 32 | #include <linux/stat.h> |
33 | #include <linux/tc.h> | ||
33 | 34 | ||
34 | #include <asm/dma.h> | 35 | #include <asm/dma.h> |
35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
@@ -42,7 +43,6 @@ | |||
42 | #include <asm/dec/ioasic_ints.h> | 43 | #include <asm/dec/ioasic_ints.h> |
43 | #include <asm/dec/machtype.h> | 44 | #include <asm/dec/machtype.h> |
44 | #include <asm/dec/system.h> | 45 | #include <asm/dec/system.h> |
45 | #include <asm/dec/tc.h> | ||
46 | 46 | ||
47 | #define DEC_SCSI_SREG 0 | 47 | #define DEC_SCSI_SREG 0 |
48 | #define DEC_SCSI_DMAREG 0x40000 | 48 | #define DEC_SCSI_DMAREG 0x40000 |
@@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int, void *); | |||
98 | static irqreturn_t scsi_dma_err_int(int, void *); | 98 | static irqreturn_t scsi_dma_err_int(int, void *); |
99 | static irqreturn_t scsi_dma_int(int, void *); | 99 | static irqreturn_t scsi_dma_int(int, void *); |
100 | 100 | ||
101 | static int dec_esp_detect(struct scsi_host_template * tpnt); | 101 | static struct scsi_host_template dec_esp_template = { |
102 | 102 | .module = THIS_MODULE, | |
103 | static int dec_esp_release(struct Scsi_Host *shost) | ||
104 | { | ||
105 | if (shost->irq) | ||
106 | free_irq(shost->irq, NULL); | ||
107 | if (shost->io_port && shost->n_io_port) | ||
108 | release_region(shost->io_port, shost->n_io_port); | ||
109 | scsi_unregister(shost); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static struct scsi_host_template driver_template = { | ||
114 | .proc_name = "dec_esp", | ||
115 | .proc_info = esp_proc_info, | ||
116 | .name = "NCR53C94", | 103 | .name = "NCR53C94", |
117 | .detect = dec_esp_detect, | ||
118 | .slave_alloc = esp_slave_alloc, | ||
119 | .slave_destroy = esp_slave_destroy, | ||
120 | .release = dec_esp_release, | ||
121 | .info = esp_info, | 104 | .info = esp_info, |
122 | .queuecommand = esp_queue, | 105 | .queuecommand = esp_queue, |
123 | .eh_abort_handler = esp_abort, | 106 | .eh_abort_handler = esp_abort, |
124 | .eh_bus_reset_handler = esp_reset, | 107 | .eh_bus_reset_handler = esp_reset, |
108 | .slave_alloc = esp_slave_alloc, | ||
109 | .slave_destroy = esp_slave_destroy, | ||
110 | .proc_info = esp_proc_info, | ||
111 | .proc_name = "dec_esp", | ||
125 | .can_queue = 7, | 112 | .can_queue = 7, |
126 | .this_id = 7, | ||
127 | .sg_tablesize = SG_ALL, | 113 | .sg_tablesize = SG_ALL, |
128 | .cmd_per_lun = 1, | 114 | .cmd_per_lun = 1, |
129 | .use_clustering = DISABLE_CLUSTERING, | 115 | .use_clustering = DISABLE_CLUSTERING, |
130 | }; | 116 | }; |
131 | 117 | ||
132 | 118 | static struct NCR_ESP *dec_esp_platform; | |
133 | #include "scsi_module.c" | ||
134 | 119 | ||
135 | /***************************************************************** Detection */ | 120 | /***************************************************************** Detection */ |
136 | static int dec_esp_detect(struct scsi_host_template * tpnt) | 121 | static int dec_esp_platform_probe(void) |
137 | { | 122 | { |
138 | struct NCR_ESP *esp; | 123 | struct NCR_ESP *esp; |
139 | struct ConfigDev *esp_dev; | 124 | int err = 0; |
140 | int slot; | ||
141 | unsigned long mem_start; | ||
142 | 125 | ||
143 | if (IOASIC) { | 126 | if (IOASIC) { |
144 | esp_dev = 0; | 127 | esp = esp_allocate(&dec_esp_template, NULL, 1); |
145 | esp = esp_allocate(tpnt, (void *) esp_dev); | ||
146 | 128 | ||
147 | /* Do command transfer with programmed I/O */ | 129 | /* Do command transfer with programmed I/O */ |
148 | esp->do_pio_cmds = 1; | 130 | esp->do_pio_cmds = 1; |
@@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt) | |||
200 | /* Check for differential SCSI-bus */ | 182 | /* Check for differential SCSI-bus */ |
201 | esp->diff = 0; | 183 | esp->diff = 0; |
202 | 184 | ||
185 | err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, | ||
186 | "ncr53c94", esp->ehost); | ||
187 | if (err) | ||
188 | goto err_alloc; | ||
189 | err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], | ||
190 | scsi_dma_merr_int, IRQF_DISABLED, | ||
191 | "ncr53c94 error", esp->ehost); | ||
192 | if (err) | ||
193 | goto err_irq; | ||
194 | err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], | ||
195 | scsi_dma_err_int, IRQF_DISABLED, | ||
196 | "ncr53c94 overrun", esp->ehost); | ||
197 | if (err) | ||
198 | goto err_irq_merr; | ||
199 | err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, | ||
200 | IRQF_DISABLED, "ncr53c94 dma", esp->ehost); | ||
201 | if (err) | ||
202 | goto err_irq_err; | ||
203 | |||
203 | esp_initialize(esp); | 204 | esp_initialize(esp); |
204 | 205 | ||
205 | if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, | 206 | err = scsi_add_host(esp->ehost, NULL); |
206 | "ncr53c94", esp->ehost)) | 207 | if (err) { |
207 | goto err_dealloc; | 208 | printk(KERN_ERR "ESP: Unable to register adapter\n"); |
208 | if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], | 209 | goto err_irq_dma; |
209 | scsi_dma_merr_int, IRQF_DISABLED, | 210 | } |
210 | "ncr53c94 error", esp->ehost)) | 211 | |
211 | goto err_free_irq; | 212 | scsi_scan_host(esp->ehost); |
212 | if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], | ||
213 | scsi_dma_err_int, IRQF_DISABLED, | ||
214 | "ncr53c94 overrun", esp->ehost)) | ||
215 | goto err_free_irq_merr; | ||
216 | if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], | ||
217 | scsi_dma_int, IRQF_DISABLED, | ||
218 | "ncr53c94 dma", esp->ehost)) | ||
219 | goto err_free_irq_err; | ||
220 | 213 | ||
214 | dec_esp_platform = esp; | ||
221 | } | 215 | } |
222 | 216 | ||
223 | if (TURBOCHANNEL) { | 217 | return 0; |
224 | while ((slot = search_tc_card("PMAZ-AA")) >= 0) { | 218 | |
225 | claim_tc_card(slot); | 219 | err_irq_dma: |
226 | 220 | free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); | |
227 | esp_dev = 0; | 221 | err_irq_err: |
228 | esp = esp_allocate(tpnt, (void *) esp_dev); | 222 | free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); |
229 | 223 | err_irq_merr: | |
230 | mem_start = get_tc_base_addr(slot); | 224 | free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); |
231 | 225 | err_irq: | |
232 | /* Store base addr into esp struct */ | 226 | free_irq(esp->irq, esp->ehost); |
233 | esp->slot = CPHYSADDR(mem_start); | 227 | err_alloc: |
234 | 228 | esp_deallocate(esp); | |
235 | esp->dregs = 0; | 229 | scsi_host_put(esp->ehost); |
236 | esp->eregs = (void *)CKSEG1ADDR(mem_start + | 230 | return err; |
237 | DEC_SCSI_SREG); | 231 | } |
238 | esp->do_pio_cmds = 1; | 232 | |
239 | 233 | static int __init dec_esp_probe(struct device *dev) | |
240 | /* Set the command buffer */ | 234 | { |
241 | esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer; | 235 | struct NCR_ESP *esp; |
242 | 236 | resource_size_t start, len; | |
243 | /* get virtual dma address for command buffer */ | 237 | int err; |
244 | esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); | 238 | |
245 | 239 | esp = esp_allocate(&dec_esp_template, NULL, 1); | |
246 | esp->cfreq = get_tc_speed(); | 240 | |
247 | 241 | dev_set_drvdata(dev, esp); | |
248 | esp->irq = get_tc_irq_nr(slot); | 242 | |
249 | 243 | start = to_tc_dev(dev)->resource.start; | |
250 | /* Required functions */ | 244 | len = to_tc_dev(dev)->resource.end - start + 1; |
251 | esp->dma_bytes_sent = &dma_bytes_sent; | 245 | |
252 | esp->dma_can_transfer = &dma_can_transfer; | 246 | if (!request_mem_region(start, len, dev->bus_id)) { |
253 | esp->dma_dump_state = &dma_dump_state; | 247 | printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", |
254 | esp->dma_init_read = &pmaz_dma_init_read; | 248 | dev->bus_id); |
255 | esp->dma_init_write = &pmaz_dma_init_write; | 249 | err = -EBUSY; |
256 | esp->dma_ints_off = &pmaz_dma_ints_off; | 250 | goto err_alloc; |
257 | esp->dma_ints_on = &pmaz_dma_ints_on; | ||
258 | esp->dma_irq_p = &dma_irq_p; | ||
259 | esp->dma_ports_p = &dma_ports_p; | ||
260 | esp->dma_setup = &pmaz_dma_setup; | ||
261 | |||
262 | /* Optional functions */ | ||
263 | esp->dma_barrier = 0; | ||
264 | esp->dma_drain = &pmaz_dma_drain; | ||
265 | esp->dma_invalidate = 0; | ||
266 | esp->dma_irq_entry = 0; | ||
267 | esp->dma_irq_exit = 0; | ||
268 | esp->dma_poll = 0; | ||
269 | esp->dma_reset = 0; | ||
270 | esp->dma_led_off = 0; | ||
271 | esp->dma_led_on = 0; | ||
272 | |||
273 | esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; | ||
274 | esp->dma_mmu_get_scsi_sgl = 0; | ||
275 | esp->dma_mmu_release_scsi_one = 0; | ||
276 | esp->dma_mmu_release_scsi_sgl = 0; | ||
277 | esp->dma_advance_sg = 0; | ||
278 | |||
279 | if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, | ||
280 | "PMAZ_AA", esp->ehost)) { | ||
281 | esp_deallocate(esp); | ||
282 | release_tc_card(slot); | ||
283 | continue; | ||
284 | } | ||
285 | esp->scsi_id = 7; | ||
286 | esp->diff = 0; | ||
287 | esp_initialize(esp); | ||
288 | } | ||
289 | } | 251 | } |
290 | 252 | ||
291 | if(nesps) { | 253 | /* Store base addr into esp struct. */ |
292 | printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); | 254 | esp->slot = start; |
293 | esps_running = esps_in_use; | 255 | |
294 | return esps_in_use; | 256 | esp->dregs = 0; |
257 | esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); | ||
258 | esp->do_pio_cmds = 1; | ||
259 | |||
260 | /* Set the command buffer. */ | ||
261 | esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; | ||
262 | |||
263 | /* Get virtual dma address for command buffer. */ | ||
264 | esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); | ||
265 | |||
266 | esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); | ||
267 | |||
268 | esp->irq = to_tc_dev(dev)->interrupt; | ||
269 | |||
270 | /* Required functions. */ | ||
271 | esp->dma_bytes_sent = &dma_bytes_sent; | ||
272 | esp->dma_can_transfer = &dma_can_transfer; | ||
273 | esp->dma_dump_state = &dma_dump_state; | ||
274 | esp->dma_init_read = &pmaz_dma_init_read; | ||
275 | esp->dma_init_write = &pmaz_dma_init_write; | ||
276 | esp->dma_ints_off = &pmaz_dma_ints_off; | ||
277 | esp->dma_ints_on = &pmaz_dma_ints_on; | ||
278 | esp->dma_irq_p = &dma_irq_p; | ||
279 | esp->dma_ports_p = &dma_ports_p; | ||
280 | esp->dma_setup = &pmaz_dma_setup; | ||
281 | |||
282 | /* Optional functions. */ | ||
283 | esp->dma_barrier = 0; | ||
284 | esp->dma_drain = &pmaz_dma_drain; | ||
285 | esp->dma_invalidate = 0; | ||
286 | esp->dma_irq_entry = 0; | ||
287 | esp->dma_irq_exit = 0; | ||
288 | esp->dma_poll = 0; | ||
289 | esp->dma_reset = 0; | ||
290 | esp->dma_led_off = 0; | ||
291 | esp->dma_led_on = 0; | ||
292 | |||
293 | esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; | ||
294 | esp->dma_mmu_get_scsi_sgl = 0; | ||
295 | esp->dma_mmu_release_scsi_one = 0; | ||
296 | esp->dma_mmu_release_scsi_sgl = 0; | ||
297 | esp->dma_advance_sg = 0; | ||
298 | |||
299 | err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", | ||
300 | esp->ehost); | ||
301 | if (err) { | ||
302 | printk(KERN_ERR "%s: Unable to get IRQ %d\n", | ||
303 | dev->bus_id, esp->irq); | ||
304 | goto err_resource; | ||
305 | } | ||
306 | |||
307 | esp->scsi_id = 7; | ||
308 | esp->diff = 0; | ||
309 | esp_initialize(esp); | ||
310 | |||
311 | err = scsi_add_host(esp->ehost, dev); | ||
312 | if (err) { | ||
313 | printk(KERN_ERR "%s: Unable to register adapter\n", | ||
314 | dev->bus_id); | ||
315 | goto err_irq; | ||
295 | } | 316 | } |
317 | |||
318 | scsi_scan_host(esp->ehost); | ||
319 | |||
296 | return 0; | 320 | return 0; |
297 | 321 | ||
298 | err_free_irq_err: | 322 | err_irq: |
299 | free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int); | 323 | free_irq(esp->irq, esp->ehost); |
300 | err_free_irq_merr: | 324 | |
301 | free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int); | 325 | err_resource: |
302 | err_free_irq: | 326 | release_mem_region(start, len); |
303 | free_irq(esp->irq, esp_intr); | 327 | |
304 | err_dealloc: | 328 | err_alloc: |
305 | esp_deallocate(esp); | 329 | esp_deallocate(esp); |
306 | return 0; | 330 | scsi_host_put(esp->ehost); |
331 | return err; | ||
332 | } | ||
333 | |||
334 | static void __exit dec_esp_platform_remove(void) | ||
335 | { | ||
336 | struct NCR_ESP *esp = dec_esp_platform; | ||
337 | |||
338 | free_irq(esp->irq, esp->ehost); | ||
339 | esp_deallocate(esp); | ||
340 | scsi_host_put(esp->ehost); | ||
341 | dec_esp_platform = NULL; | ||
307 | } | 342 | } |
308 | 343 | ||
344 | static void __exit dec_esp_remove(struct device *dev) | ||
345 | { | ||
346 | struct NCR_ESP *esp = dev_get_drvdata(dev); | ||
347 | |||
348 | free_irq(esp->irq, esp->ehost); | ||
349 | esp_deallocate(esp); | ||
350 | scsi_host_put(esp->ehost); | ||
351 | } | ||
352 | |||
353 | |||
309 | /************************************************************* DMA Functions */ | 354 | /************************************************************* DMA Functions */ |
310 | static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) | 355 | static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) |
311 | { | 356 | { |
@@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp | |||
576 | { | 621 | { |
577 | sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); | 622 | sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); |
578 | } | 623 | } |
624 | |||
625 | |||
626 | #ifdef CONFIG_TC | ||
627 | static int __init dec_esp_tc_probe(struct device *dev); | ||
628 | static int __exit dec_esp_tc_remove(struct device *dev); | ||
629 | |||
630 | static const struct tc_device_id dec_esp_tc_table[] = { | ||
631 | { "DEC ", "PMAZ-AA " }, | ||
632 | { } | ||
633 | }; | ||
634 | MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); | ||
635 | |||
636 | static struct tc_driver dec_esp_tc_driver = { | ||
637 | .id_table = dec_esp_tc_table, | ||
638 | .driver = { | ||
639 | .name = "dec_esp", | ||
640 | .bus = &tc_bus_type, | ||
641 | .probe = dec_esp_tc_probe, | ||
642 | .remove = __exit_p(dec_esp_tc_remove), | ||
643 | }, | ||
644 | }; | ||
645 | |||
646 | static int __init dec_esp_tc_probe(struct device *dev) | ||
647 | { | ||
648 | int status = dec_esp_probe(dev); | ||
649 | if (!status) | ||
650 | get_device(dev); | ||
651 | return status; | ||
652 | } | ||
653 | |||
654 | static int __exit dec_esp_tc_remove(struct device *dev) | ||
655 | { | ||
656 | put_device(dev); | ||
657 | dec_esp_remove(dev); | ||
658 | return 0; | ||
659 | } | ||
660 | #endif | ||
661 | |||
662 | static int __init dec_esp_init(void) | ||
663 | { | ||
664 | int status; | ||
665 | |||
666 | status = tc_register_driver(&dec_esp_tc_driver); | ||
667 | if (!status) | ||
668 | dec_esp_platform_probe(); | ||
669 | |||
670 | if (nesps) { | ||
671 | pr_info("ESP: Total of %d ESP hosts found, " | ||
672 | "%d actually in use.\n", nesps, esps_in_use); | ||
673 | esps_running = esps_in_use; | ||
674 | } | ||
675 | |||
676 | return status; | ||
677 | } | ||
678 | |||
679 | static void __exit dec_esp_exit(void) | ||
680 | { | ||
681 | dec_esp_platform_remove(); | ||
682 | tc_unregister_driver(&dec_esp_tc_driver); | ||
683 | } | ||
684 | |||
685 | |||
686 | module_init(dec_esp_init); | ||
687 | module_exit(dec_esp_exit); | ||