Commit 77ca20f2 authored by Jeff Garzik's avatar Jeff Garzik

[libata] don't probe from workqueue

Since we want the probe phase to call other workqueues, this is
required to eliminate future deadlocks.

Other methods would include starting a single-shot thread just for
probing, but overall, using a separate thread for probing is pointless
since we are already in process context when we probe.

So, we simply call ata_bus_probe directly.
parent 8b08e769
...@@ -65,37 +65,6 @@ MODULE_AUTHOR("Jeff Garzik"); ...@@ -65,37 +65,6 @@ MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_DESCRIPTION("Library module for ATA devices");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static const char * thr_state_name[] = {
"THR_UNKNOWN",
"THR_PORT_RESET",
"THR_AWAIT_DEATH",
"THR_PROBE_FAILED",
"THR_IDLE",
"THR_PROBE_SUCCESS",
"THR_PROBE_START",
};
/**
* ata_thr_state_name - convert thread state enum to string
* @thr_state: thread state to be converted to string
*
* Converts the specified thread state id to a constant C string.
*
* LOCKING:
* None.
*
* RETURNS:
* The THR_xxx-prefixed string naming the specified thread
* state id, or the string "<invalid THR_xxx state>".
*/
static const char *ata_thr_state_name(unsigned int thr_state)
{
if (thr_state < ARRAY_SIZE(thr_state_name))
return thr_state_name[thr_state];
return "<invalid THR_xxx state>";
}
/** /**
* ata_tf_load_pio - send taskfile registers to host controller * ata_tf_load_pio - send taskfile registers to host controller
* @ap: Port to which output is sent * @ap: Port to which output is sent
...@@ -1150,13 +1119,16 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device) ...@@ -1150,13 +1119,16 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device)
} }
/** /**
* ata_port_reset - * ata_bus_probe - Reset and probe ATA bus
* @ap: * @ap: Bus to probe
* *
* LOCKING: * LOCKING:
*
* RETURNS:
* Zero on success, non-zero on error.
*/ */
static void ata_port_reset(struct ata_port *ap) static int ata_bus_probe(struct ata_port *ap)
{ {
unsigned int i, found = 0; unsigned int i, found = 0;
...@@ -1180,14 +1152,12 @@ static void ata_port_reset(struct ata_port *ap) ...@@ -1180,14 +1152,12 @@ static void ata_port_reset(struct ata_port *ap)
if (ap->flags & ATA_FLAG_PORT_DISABLED) if (ap->flags & ATA_FLAG_PORT_DISABLED)
goto err_out_disable; goto err_out_disable;
ap->thr_state = THR_PROBE_SUCCESS; return 0;
return;
err_out_disable: err_out_disable:
ap->ops->port_disable(ap); ap->ops->port_disable(ap);
err_out: err_out:
ap->thr_state = THR_PROBE_FAILED; return -1;
} }
/** /**
...@@ -2718,62 +2688,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) ...@@ -2718,62 +2688,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
/**
* ata_thread_iter -
* @ap:
*
* LOCKING:
*
* RETURNS:
*
*/
static unsigned long ata_thread_iter(struct ata_port *ap)
{
long timeout = 0;
DPRINTK("ata%u: thr_state %s\n",
ap->id, ata_thr_state_name(ap->thr_state));
switch (ap->thr_state) {
case THR_UNKNOWN:
ap->thr_state = THR_PORT_RESET;
break;
case THR_PROBE_START:
ap->thr_state = THR_PORT_RESET;
break;
case THR_PORT_RESET:
ata_port_reset(ap);
break;
case THR_PROBE_SUCCESS:
up(&ap->probe_sem);
ap->thr_state = THR_IDLE;
break;
case THR_PROBE_FAILED:
up(&ap->probe_sem);
ap->thr_state = THR_AWAIT_DEATH;
break;
case THR_AWAIT_DEATH:
case THR_IDLE:
timeout = -1;
break;
default:
printk(KERN_DEBUG "ata%u: unknown thr state %s\n",
ap->id, ata_thr_state_name(ap->thr_state));
break;
}
DPRINTK("ata%u: new thr_state %s, returning %ld\n",
ap->id, ata_thr_state_name(ap->thr_state), timeout);
return timeout;
}
/** /**
* atapi_packet_task - Write CDB bytes to hardware * atapi_packet_task - Write CDB bytes to hardware
* @_data: Port to which ATAPI device is attached. * @_data: Port to which ATAPI device is attached.
...@@ -2855,21 +2769,6 @@ void ata_port_stop (struct ata_port *ap) ...@@ -2855,21 +2769,6 @@ void ata_port_stop (struct ata_port *ap)
pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
} }
static void ata_probe_task(void *_data)
{
struct ata_port *ap = _data;
long timeout;
timeout = ata_thread_iter(ap);
if (timeout < 0)
return;
if (timeout > 0)
queue_delayed_work(ata_wq, &ap->probe_task, timeout);
else
queue_work(ata_wq, &ap->probe_task);
}
/** /**
* ata_host_remove - Unregister SCSI host structure with upper layers * ata_host_remove - Unregister SCSI host structure with upper layers
* @ap: Port to unregister * @ap: Port to unregister
...@@ -2926,7 +2825,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ...@@ -2926,7 +2825,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
ap->udma_mask = ent->udma_mask; ap->udma_mask = ent->udma_mask;
ap->flags |= ent->host_flags; ap->flags |= ent->host_flags;
ap->ops = ent->port_ops; ap->ops = ent->port_ops;
ap->thr_state = THR_PROBE_START;
ap->cbl = ATA_CBL_NONE; ap->cbl = ATA_CBL_NONE;
ap->device[0].flags = ATA_DFLAG_MASTER; ap->device[0].flags = ATA_DFLAG_MASTER;
ap->active_tag = ATA_TAG_POISON; ap->active_tag = ATA_TAG_POISON;
...@@ -2934,13 +2832,10 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ...@@ -2934,13 +2832,10 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
INIT_WORK(&ap->packet_task, atapi_packet_task, ap); INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
INIT_WORK(&ap->pio_task, ata_pio_task, ap); INIT_WORK(&ap->pio_task, ata_pio_task, ap);
INIT_WORK(&ap->probe_task, ata_probe_task, ap);
for (i = 0; i < ATA_MAX_DEVICES; i++) for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].devno = i; ap->device[i].devno = i;
init_MUTEX_LOCKED(&ap->probe_sem);
#ifdef ATA_IRQ_TRAP #ifdef ATA_IRQ_TRAP
ap->stats.unhandled_irq = 1; ap->stats.unhandled_irq = 1;
ap->stats.idle_irq = 1; ap->stats.idle_irq = 1;
...@@ -3063,12 +2958,17 @@ int ata_device_add(struct ata_probe_ent *ent) ...@@ -3063,12 +2958,17 @@ int ata_device_add(struct ata_probe_ent *ent)
ap = host_set->ports[i]; ap = host_set->ports[i];
DPRINTK("ata%u: probe begin\n", ap->id); DPRINTK("ata%u: probe begin\n", ap->id);
queue_work(ata_wq, &ap->probe_task); /* start probe */ rc = ata_bus_probe(ap);
DPRINTK("ata%u: probe end\n", ap->id);
DPRINTK("ata%u: probe-wait begin\n", ap->id); if (rc) {
down(&ap->probe_sem); /* wait for end */ /* FIXME: do something useful here?
* Current libata behavior will
DPRINTK("ata%u: probe-wait end\n", ap->id); * tear down everything when
* the module is removed
* or the h/w is unplugged.
*/
}
rc = scsi_add_host(ap->host, &pdev->dev); rc = scsi_add_host(ap->host, &pdev->dev);
if (rc) { if (rc) {
......
...@@ -133,15 +133,6 @@ enum { ...@@ -133,15 +133,6 @@ enum {
BUS_IDENTIFY = 8, BUS_IDENTIFY = 8,
BUS_PACKET = 9, BUS_PACKET = 9,
/* thread states */
THR_UNKNOWN = 0,
THR_PORT_RESET = (THR_UNKNOWN + 1),
THR_AWAIT_DEATH = (THR_PORT_RESET + 1),
THR_PROBE_FAILED = (THR_AWAIT_DEATH + 1),
THR_IDLE = (THR_PROBE_FAILED + 1),
THR_PROBE_SUCCESS = (THR_IDLE + 1),
THR_PROBE_START = (THR_PROBE_SUCCESS + 1),
/* SATA port states */ /* SATA port states */
PORT_UNKNOWN = 0, PORT_UNKNOWN = 0,
PORT_ENABLED = 1, PORT_ENABLED = 1,
...@@ -294,18 +285,12 @@ struct ata_port { ...@@ -294,18 +285,12 @@ struct ata_port {
struct ata_host_stats stats; struct ata_host_stats stats;
struct ata_host_set *host_set; struct ata_host_set *host_set;
struct semaphore probe_sem;
unsigned int thr_state;
struct work_struct packet_task; struct work_struct packet_task;
struct work_struct pio_task; struct work_struct pio_task;
unsigned int pio_task_state; unsigned int pio_task_state;
unsigned long pio_task_timeout; unsigned long pio_task_timeout;
struct work_struct probe_task;
void *private_data; void *private_data;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment