提交 0ad0eff9 编写于 作者: F Finn Thain 提交者: Martin K. Petersen

ncr5380: Introduce unbound workqueue

Allocate a work queue that will permit busy waiting and sleeping. This
means NCR5380_init() can potentially fail, so add this error path.
Signed-off-by: NFinn Thain <fthain@telegraphics.com.au>
Reviewed-by: NHannes Reinecke <hare@suse.com>
Tested-by: NOndrej Zary <linux@rainbow-software.org>
Tested-by: NMichael Schmitz <schmitzmic@gmail.com>
Signed-off-by: NMartin K. Petersen <martin.petersen@oracle.com>
上级 e52bbd5c
...@@ -514,7 +514,7 @@ static int should_disconnect(unsigned char cmd) ...@@ -514,7 +514,7 @@ static int should_disconnect(unsigned char cmd)
static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout) static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout)
{ {
hostdata->time_expires = jiffies + timeout; hostdata->time_expires = jiffies + timeout;
schedule_delayed_work(&hostdata->coroutine, timeout); queue_delayed_work(hostdata->work_q, &hostdata->coroutine, timeout);
} }
...@@ -791,7 +791,12 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags) ...@@ -791,7 +791,12 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
hostdata->disconnected_queue = NULL; hostdata->disconnected_queue = NULL;
INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main); INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
hostdata->work_q = alloc_workqueue("ncr5380_%d",
WQ_UNBOUND | WQ_MEM_RECLAIM,
1, instance->host_no);
if (!hostdata->work_q)
return -ENOMEM;
/* The CHECK code seems to break the 53C400. Will check it later maybe */ /* The CHECK code seems to break the 53C400. Will check it later maybe */
if (flags & FLAG_NCR53C400) if (flags & FLAG_NCR53C400)
hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags; hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
...@@ -872,6 +877,7 @@ static void NCR5380_exit(struct Scsi_Host *instance) ...@@ -872,6 +877,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
cancel_delayed_work_sync(&hostdata->coroutine); cancel_delayed_work_sync(&hostdata->coroutine);
destroy_workqueue(hostdata->work_q);
} }
/** /**
...@@ -932,7 +938,7 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct ...@@ -932,7 +938,7 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct
/* Run the coroutine if it isn't already running. */ /* Run the coroutine if it isn't already running. */
/* Kick off command processing */ /* Kick off command processing */
schedule_delayed_work(&hostdata->coroutine, 0); queue_delayed_work(hostdata->work_q, &hostdata->coroutine, 0);
return 0; return 0;
} }
...@@ -1128,7 +1134,8 @@ static irqreturn_t NCR5380_intr(int dummy, void *dev_id) ...@@ -1128,7 +1134,8 @@ static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
} /* if BASR_IRQ */ } /* if BASR_IRQ */
spin_unlock_irqrestore(instance->host_lock, flags); spin_unlock_irqrestore(instance->host_lock, flags);
if(!done) if(!done)
schedule_delayed_work(&hostdata->coroutine, 0); queue_delayed_work(hostdata->work_q,
&hostdata->coroutine, 0);
} while (!done); } while (!done);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -284,6 +284,7 @@ struct NCR5380_hostdata { ...@@ -284,6 +284,7 @@ struct NCR5380_hostdata {
unsigned spin_max_r; unsigned spin_max_r;
unsigned spin_max_w; unsigned spin_max_w;
#endif #endif
struct workqueue_struct *work_q;
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
......
...@@ -238,7 +238,9 @@ static int cumanascsi1_probe(struct expansion_card *ec, ...@@ -238,7 +238,9 @@ static int cumanascsi1_probe(struct expansion_card *ec,
host->irq = ec->irq; host->irq = ec->irq;
NCR5380_init(host, 0); ret = NCR5380_init(host, 0);
if (ret)
goto out_unmap;
NCR5380_maybe_reset_bus(host); NCR5380_maybe_reset_bus(host);
...@@ -250,7 +252,7 @@ static int cumanascsi1_probe(struct expansion_card *ec, ...@@ -250,7 +252,7 @@ static int cumanascsi1_probe(struct expansion_card *ec,
if (ret) { if (ret) {
printk("scsi%d: IRQ%d not free: %d\n", printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, host->irq, ret); host->host_no, host->irq, ret);
goto out_unmap; goto out_exit;
} }
ret = scsi_add_host(host, &ec->dev); ret = scsi_add_host(host, &ec->dev);
...@@ -262,6 +264,8 @@ static int cumanascsi1_probe(struct expansion_card *ec, ...@@ -262,6 +264,8 @@ static int cumanascsi1_probe(struct expansion_card *ec,
out_free_irq: out_free_irq:
free_irq(host->irq, host); free_irq(host->irq, host);
out_exit:
NCR5380_exit(host);
out_unmap: out_unmap:
iounmap(priv(host)->base); iounmap(priv(host)->base);
iounmap(priv(host)->dma); iounmap(priv(host)->dma);
......
...@@ -143,17 +143,21 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) ...@@ -143,17 +143,21 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
host->irq = NO_IRQ; host->irq = NO_IRQ;
host->n_io_port = 255; host->n_io_port = 255;
NCR5380_init(host, 0); ret = NCR5380_init(host, 0);
if (ret)
goto out_unmap;
NCR5380_maybe_reset_bus(host); NCR5380_maybe_reset_bus(host);
ret = scsi_add_host(host, &ec->dev); ret = scsi_add_host(host, &ec->dev);
if (ret) if (ret)
goto out_unmap; goto out_exit;
scsi_scan_host(host); scsi_scan_host(host);
goto out; goto out;
out_exit:
NCR5380_exit(host);
out_unmap: out_unmap:
iounmap(priv(host)->base); iounmap(priv(host)->base);
unreg: unreg:
......
...@@ -643,7 +643,7 @@ static inline void queue_main(struct NCR5380_hostdata *hostdata) ...@@ -643,7 +643,7 @@ static inline void queue_main(struct NCR5380_hostdata *hostdata)
queue it on the 'immediate' task queue, to be processed queue it on the 'immediate' task queue, to be processed
immediately after the current interrupt processing has immediately after the current interrupt processing has
finished. */ finished. */
schedule_work(&hostdata->main_task); queue_work(hostdata->work_q, &hostdata->main_task);
} }
/* else: nothing to do: the running NCR5380_main() will pick up /* else: nothing to do: the running NCR5380_main() will pick up
any newly queued command. */ any newly queued command. */
...@@ -832,6 +832,11 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) ...@@ -832,6 +832,11 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
hostdata->flags = flags; hostdata->flags = flags;
INIT_WORK(&hostdata->main_task, NCR5380_main); INIT_WORK(&hostdata->main_task, NCR5380_main);
hostdata->work_q = alloc_workqueue("ncr5380_%d",
WQ_UNBOUND | WQ_MEM_RECLAIM,
1, instance->host_no);
if (!hostdata->work_q)
return -ENOMEM;
prepare_info(instance); prepare_info(instance);
...@@ -907,6 +912,7 @@ static void NCR5380_exit(struct Scsi_Host *instance) ...@@ -907,6 +912,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = shost_priv(instance); struct NCR5380_hostdata *hostdata = shost_priv(instance);
cancel_work_sync(&hostdata->main_task); cancel_work_sync(&hostdata->main_task);
destroy_workqueue(hostdata->work_q);
} }
/** /**
......
...@@ -885,7 +885,9 @@ static int __init atari_scsi_probe(struct platform_device *pdev) ...@@ -885,7 +885,9 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
#endif #endif
host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0; host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
NCR5380_init(instance, host_flags); error = NCR5380_init(instance, host_flags);
if (error)
goto fail_init;
if (IS_A_TT()) { if (IS_A_TT()) {
error = request_irq(instance->irq, scsi_tt_intr, 0, error = request_irq(instance->irq, scsi_tt_intr, 0,
...@@ -947,6 +949,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev) ...@@ -947,6 +949,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
free_irq(instance->irq, instance); free_irq(instance->irq, instance);
fail_irq: fail_irq:
NCR5380_exit(instance); NCR5380_exit(instance);
fail_init:
scsi_host_put(instance); scsi_host_put(instance);
fail_alloc: fail_alloc:
if (atari_dma_buffer) if (atari_dma_buffer)
......
...@@ -95,7 +95,9 @@ static int dmx3191d_probe_one(struct pci_dev *pdev, ...@@ -95,7 +95,9 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
*/ */
shost->irq = NO_IRQ; shost->irq = NO_IRQ;
NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E); error = NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
if (error)
goto out_host_put;
NCR5380_maybe_reset_bus(shost); NCR5380_maybe_reset_bus(shost);
...@@ -103,11 +105,15 @@ static int dmx3191d_probe_one(struct pci_dev *pdev, ...@@ -103,11 +105,15 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
error = scsi_add_host(shost, &pdev->dev); error = scsi_add_host(shost, &pdev->dev);
if (error) if (error)
goto out_release_region; goto out_exit;
scsi_scan_host(shost); scsi_scan_host(shost);
return 0; return 0;
out_exit:
NCR5380_exit(shost);
out_host_put:
scsi_host_put(shost);
out_release_region: out_release_region:
release_region(io, DMX3191D_REGION_LEN); release_region(io, DMX3191D_REGION_LEN);
out_disable_device: out_disable_device:
...@@ -119,15 +125,14 @@ static int dmx3191d_probe_one(struct pci_dev *pdev, ...@@ -119,15 +125,14 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
static void dmx3191d_remove_one(struct pci_dev *pdev) static void dmx3191d_remove_one(struct pci_dev *pdev)
{ {
struct Scsi_Host *shost = pci_get_drvdata(pdev); struct Scsi_Host *shost = pci_get_drvdata(pdev);
unsigned long io = shost->io_port;
scsi_remove_host(shost); scsi_remove_host(shost);
NCR5380_exit(shost); NCR5380_exit(shost);
release_region(shost->io_port, DMX3191D_REGION_LEN);
pci_disable_device(pdev);
scsi_host_put(shost); scsi_host_put(shost);
release_region(io, DMX3191D_REGION_LEN);
pci_disable_device(pdev);
} }
static struct pci_device_id dmx3191d_pci_tbl[] = { static struct pci_device_id dmx3191d_pci_tbl[] = {
......
...@@ -230,12 +230,13 @@ static int __init dtc_detect(struct scsi_host_template * tpnt) ...@@ -230,12 +230,13 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
found: found:
instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
if (instance == NULL) if (instance == NULL)
break; goto out_unmap;
instance->base = addr; instance->base = addr;
((struct NCR5380_hostdata *)(instance)->hostdata)->base = base; ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
NCR5380_init(instance, 0); if (NCR5380_init(instance, 0))
goto out_unregister;
NCR5380_maybe_reset_bus(instance); NCR5380_maybe_reset_bus(instance);
...@@ -275,6 +276,12 @@ static int __init dtc_detect(struct scsi_host_template * tpnt) ...@@ -275,6 +276,12 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
++count; ++count;
} }
return count; return count;
out_unregister:
scsi_unregister(instance);
out_unmap:
iounmap(base);
return count;
} }
/* /*
......
...@@ -239,9 +239,6 @@ static int __init do_DTC3181E_setup(char *str) ...@@ -239,9 +239,6 @@ static int __init do_DTC3181E_setup(char *str)
* and DTC436(ISAPnP) controllers. If overrides have been set we use * and DTC436(ISAPnP) controllers. If overrides have been set we use
* them. * them.
* *
* The caller supplied NCR5380_init function is invoked from here, before
* the interrupt line is taken.
*
* Locks: none * Locks: none
*/ */
...@@ -402,15 +399,8 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) ...@@ -402,15 +399,8 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
} }
#endif #endif
instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
if (instance == NULL) { if (instance == NULL)
#ifndef SCSI_G_NCR5380_MEM goto out_release;
release_region(overrides[current_override].NCR5380_map_name, region_size);
#else
iounmap(iomem);
release_mem_region(base, NCR5380_region_size);
#endif
continue;
}
#ifndef SCSI_G_NCR5380_MEM #ifndef SCSI_G_NCR5380_MEM
instance->io_port = overrides[current_override].NCR5380_map_name; instance->io_port = overrides[current_override].NCR5380_map_name;
...@@ -427,7 +417,8 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) ...@@ -427,7 +417,8 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem; ((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem;
#endif #endif
NCR5380_init(instance, flags); if (NCR5380_init(instance, flags))
goto out_unregister;
if (overrides[current_override].board == BOARD_NCR53C400) if (overrides[current_override].board == BOARD_NCR53C400)
NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
...@@ -459,6 +450,17 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) ...@@ -459,6 +450,17 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
++count; ++count;
} }
return count; return count;
out_unregister:
scsi_unregister(instance);
out_release:
#ifndef SCSI_G_NCR5380_MEM
release_region(overrides[current_override].NCR5380_map_name, region_size);
#else
iounmap(iomem);
release_mem_region(base, NCR5380_region_size);
#endif
return count;
} }
/** /**
...@@ -475,15 +477,12 @@ static int generic_NCR5380_release_resources(struct Scsi_Host *instance) ...@@ -475,15 +477,12 @@ static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
if (instance->irq != NO_IRQ) if (instance->irq != NO_IRQ)
free_irq(instance->irq, instance); free_irq(instance->irq, instance);
NCR5380_exit(instance); NCR5380_exit(instance);
#ifndef SCSI_G_NCR5380_MEM #ifndef SCSI_G_NCR5380_MEM
release_region(instance->io_port, instance->n_io_port); release_region(instance->io_port, instance->n_io_port);
#else #else
iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem); iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem);
release_mem_region(instance->base, NCR5380_region_size); release_mem_region(instance->base, NCR5380_region_size);
#endif #endif
return 0; return 0;
} }
......
...@@ -382,7 +382,9 @@ static int __init mac_scsi_probe(struct platform_device *pdev) ...@@ -382,7 +382,9 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
#endif #endif
host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0; host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
NCR5380_init(instance, host_flags); error = NCR5380_init(instance, host_flags);
if (error)
goto fail_init;
if (instance->irq != NO_IRQ) { if (instance->irq != NO_IRQ) {
error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED, error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
...@@ -407,6 +409,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev) ...@@ -407,6 +409,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
free_irq(instance->irq, instance); free_irq(instance->irq, instance);
fail_irq: fail_irq:
NCR5380_exit(instance); NCR5380_exit(instance);
fail_init:
scsi_host_put(instance); scsi_host_put(instance);
return error; return error;
} }
......
...@@ -378,11 +378,12 @@ static int __init pas16_detect(struct scsi_host_template *tpnt) ...@@ -378,11 +378,12 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if(instance == NULL) if(instance == NULL)
break; goto out;
instance->io_port = io_port; instance->io_port = io_port;
NCR5380_init(instance, 0); if (NCR5380_init(instance, 0))
goto out_unregister;
NCR5380_maybe_reset_bus(instance); NCR5380_maybe_reset_bus(instance);
...@@ -418,6 +419,11 @@ static int __init pas16_detect(struct scsi_host_template *tpnt) ...@@ -418,6 +419,11 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
++count; ++count;
} }
return count; return count;
out_unregister:
scsi_unregister(instance);
out:
return count;
} }
/* /*
......
...@@ -557,7 +557,9 @@ static int __init sun3_scsi_probe(struct platform_device *pdev) ...@@ -557,7 +557,9 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0; host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif #endif
NCR5380_init(instance, host_flags); error = NCR5380_init(instance, host_flags);
if (error)
goto fail_init;
error = request_irq(instance->irq, scsi_sun3_intr, 0, error = request_irq(instance->irq, scsi_sun3_intr, 0,
"NCR5380", instance); "NCR5380", instance);
...@@ -604,6 +606,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev) ...@@ -604,6 +606,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
free_irq(instance->irq, instance); free_irq(instance->irq, instance);
fail_irq: fail_irq:
NCR5380_exit(instance); NCR5380_exit(instance);
fail_init:
scsi_host_put(instance); scsi_host_put(instance);
fail_alloc: fail_alloc:
if (udc_regs) if (udc_regs)
......
...@@ -208,12 +208,13 @@ static int __init t128_detect(struct scsi_host_template *tpnt) ...@@ -208,12 +208,13 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
found: found:
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if(instance == NULL) if(instance == NULL)
break; goto out_unmap;
instance->base = base; instance->base = base;
((struct NCR5380_hostdata *)instance->hostdata)->base = p; ((struct NCR5380_hostdata *)instance->hostdata)->base = p;
NCR5380_init(instance, 0); if (NCR5380_init(instance, 0))
goto out_unregister;
NCR5380_maybe_reset_bus(instance); NCR5380_maybe_reset_bus(instance);
...@@ -246,6 +247,12 @@ static int __init t128_detect(struct scsi_host_template *tpnt) ...@@ -246,6 +247,12 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
++count; ++count;
} }
return count; return count;
out_unregister:
scsi_unregister(instance);
out_unmap:
iounmap(p);
return count;
} }
static int t128_release(struct Scsi_Host *shost) static int t128_release(struct Scsi_Host *shost)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册