summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-07-12 12:16:11 +0000
committermav <mav@FreeBSD.org>2010-07-12 12:16:11 +0000
commit60fbea5ce04159a53b23ed74153bd7a8e9e25a54 (patch)
tree7185df50c44e668a750f864cd6902763113418ee /sys/dev/ata
parentbb2d216b9a3031ec25d74c586cba760bd9f0f2e7 (diff)
downloadFreeBSD-src-60fbea5ce04159a53b23ed74153bd7a8e9e25a54.zip
FreeBSD-src-60fbea5ce04159a53b23ed74153bd7a8e9e25a54.tar.gz
Revert and remake r209883:
Do not grab lock while setting up interrupt, as it causes LOR with allocation code. Instead make interrupt handler check that CAM bus initialization completed before touching it. While there, slightly improve attach errors handling. Reported by: kib
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-all.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index ac94e8e..3f7f1a9 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -185,29 +185,28 @@ ata_attach(device_t dev)
if (ch->dma.alloc)
ch->dma.alloc(dev);
- mtx_lock(&ch->state_mtx);
/* setup interrupt delivery */
rid = ATA_IRQ_RID;
ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_SHAREABLE | RF_ACTIVE);
if (!ch->r_irq) {
device_printf(dev, "unable to allocate interrupt\n");
- mtx_unlock(&ch->state_mtx);
return ENXIO;
}
if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL,
ata_interrupt, ch, &ch->ih))) {
+ bus_release_resource(dev, SYS_RES_IRQ, rid, ch->r_irq);
device_printf(dev, "unable to setup interrupt\n");
- goto err1;
+ return error;
}
#ifndef ATA_CAM
- mtx_unlock(&ch->state_mtx);
/* probe and attach devices on this channel unless we are in early boot */
if (!ata_delayed_attach)
ata_identify(dev);
return (0);
#else
+ mtx_lock(&ch->state_mtx);
/* Create the device queue for our SIM. */
devq = cam_simq_alloc(1);
if (devq == NULL) {
@@ -220,8 +219,9 @@ ata_attach(device_t dev)
device_get_unit(dev), &ch->state_mtx, 1, 0, devq);
if (ch->sim == NULL) {
device_printf(dev, "unable to allocate sim\n");
+ cam_simq_free(devq);
error = ENOMEM;
- goto err2;
+ goto err1;
}
if (xpt_bus_register(ch->sim, dev, 0) != CAM_SUCCESS) {
device_printf(dev, "unable to register xpt bus\n");
@@ -241,11 +241,12 @@ err3:
xpt_bus_deregister(cam_sim_path(ch->sim));
err2:
cam_sim_free(ch->sim, /*free_devq*/TRUE);
-#endif
+ ch->sim = NULL;
err1:
- bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
+ bus_release_resource(dev, SYS_RES_IRQ, rid, ch->r_irq);
mtx_unlock(&ch->state_mtx);
return (error);
+#endif
}
int
@@ -283,6 +284,7 @@ ata_detach(device_t dev)
xpt_free_path(ch->path);
xpt_bus_deregister(cam_sim_path(ch->sim));
cam_sim_free(ch->sim, /*free_devq*/TRUE);
+ ch->sim = NULL;
mtx_unlock(&ch->state_mtx);
#endif
@@ -309,9 +311,12 @@ ata_conn_event(void *context, int dummy)
union ccb *ccb;
mtx_lock(&ch->state_mtx);
+ if (ch->sim == NULL) {
+ mtx_unlock(&ch->state_mtx);
+ return;
+ }
ata_reinit(dev);
- mtx_unlock(&ch->state_mtx);
- if ((ccb = xpt_alloc_ccb()) == NULL)
+ if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
return;
if (xpt_create_path(&ccb->ccb_h.path, NULL,
cam_sim_path(ch->sim),
@@ -320,6 +325,7 @@ ata_conn_event(void *context, int dummy)
return;
}
xpt_rescan(ccb);
+ mtx_unlock(&ch->state_mtx);
#else
ata_reinit(dev);
#endif
OpenPOWER on IntegriCloud