ahc/ahd locking
Peter Avalos
pavalos at theshell.com
Tue Jan 1 18:21:06 PST 2008
Here's my latest patch. The difference from the last is that I interlocked
the tsleeps and asserted that the serializer is held in the interrupt
handler.
1. Do the tsleep interlocks look right?
2. Did I use lwkt_serialize_handler_enable/disable properly?
3. Generally, does this patch look right?
Thanks,
Peter
http://www.theshell.com/~pavalos/wip/aic7xxx-locking3.patch
diff --git a/sys/dev/disk/aic7xxx/aic7770.c b/sys/dev/disk/aic7xxx/aic7770.c
index fcef375..ad91898 100644
--- a/sys/dev/disk/aic7xxx/aic7770.c
+++ b/sys/dev/disk/aic7xxx/aic7770.c
@@ -254,6 +254,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
if (error != 0)
return (error);
+ ahc_lock(ahc);
/*
* Link this softc in with all other ahc instances.
*/
@@ -264,6 +265,8 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
*/
ahc_outb(ahc, BCTL, ENABLE);
+ ahc_unlock(ahc);
+
return (0);
}
diff --git a/sys/dev/disk/aic7xxx/aic79xx.c b/sys/dev/disk/aic7xxx/aic79xx.c
index 834fcf4..47f3565 100644
--- a/sys/dev/disk/aic7xxx/aic79xx.c
+++ b/sys/dev/disk/aic7xxx/aic79xx.c
@@ -5251,6 +5251,7 @@ ahd_alloc(void *platform_arg, char *name)
ahd_free(ahd);
ahd = NULL;
}
+ ahd_lockinit(ahd);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MEMORY) != 0) {
kprintf("%s: scb size = 0x%x, hscb size = 0x%x\n",
@@ -5322,22 +5323,6 @@ ahd_softc_insert(struct ahd_softc *ahd)
ahd->init_level++;
}
-/*
- * Verify that the passed in softc pointer is for a
- * controller that is still configured.
- */
-struct ahd_softc *
-ahd_find_softc(struct ahd_softc *ahd)
-{
- struct ahd_softc *list_ahd;
-
- TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
- if (list_ahd == ahd)
- return (ahd);
- }
- return (NULL);
-}
-
void
ahd_set_unit(struct ahd_softc *ahd, int unit)
{
@@ -6179,6 +6164,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag);
if (next_scb->col_scb != NULL)
next_scb->col_scb->col_scb = next_scb;
+ aic_timer_init(&next_scb->io_timer);
ahd_free_scb(ahd, next_scb);
hscb++;
hscb_busaddr += sizeof(*hscb);
@@ -7019,6 +7005,9 @@ ahd_intr_enable(struct ahd_softc *ahd, int enable)
{
u_int hcntrl;
+ if (enable)
+ lwkt_serialize_handler_enable(&ahd->platform_data->serializer);
+
hcntrl = ahd_inb(ahd, HCNTRL);
hcntrl &= ~INTEN;
ahd->pause &= ~INTEN;
@@ -7029,6 +7018,8 @@ ahd_intr_enable(struct ahd_softc *ahd, int enable)
ahd->unpause |= INTEN;
}
ahd_outb(ahd, HCNTRL, hcntrl);
+ if (!enable)
+ lwkt_serialize_handler_disable(&ahd->platform_data->serializer);
}
void
@@ -8024,15 +8015,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
static void
ahd_reset_poll(void *arg)
{
- struct ahd_softc *ahd;
+ struct ahd_softc *ahd = (struct ahd_softc *)arg;
u_int scsiseq1;
- ahd = ahd_find_softc((struct ahd_softc *)arg);
- if (ahd == NULL) {
- kprintf("ahd_reset_poll: Instance %p no longer exists\n", arg);
- return;
- }
- ahd_lock();
+ ahd_lock(ahd);
ahd_pause(ahd);
ahd_update_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
@@ -8041,7 +8027,7 @@ ahd_reset_poll(void *arg)
aic_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_MS,
ahd_reset_poll, ahd);
ahd_unpause(ahd);
- ahd_unlock();
+ ahd_unlock(ahd);
return;
}
@@ -8051,24 +8037,18 @@ ahd_reset_poll(void *arg)
ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP));
ahd_unpause(ahd);
ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
- ahd_unlock();
aic_release_simq(ahd);
+ ahd_unlock(ahd);
}
/**************************** Statistics Processing ***************************/
static void
ahd_stat_timer(void *arg)
{
- struct ahd_softc *ahd;
+ struct ahd_softc *ahd = (struct ahd_softc *)arg;
int enint_coal;
- ahd = ahd_find_softc((struct ahd_softc *)arg);
- if (ahd == NULL) {
- kprintf("ahd_stat_timer: Instance %p no longer exists\n", arg);
- return;
- }
- ahd_lock();
-
+ ahd_lock(ahd);
enint_coal = ahd->hs_mailbox & ENINT_COALESCE;
if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold)
enint_coal |= ENINT_COALESCE;
@@ -8092,7 +8072,7 @@ ahd_stat_timer(void *arg)
ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0;
aic_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_MS,
ahd_stat_timer, ahd);
- ahd_unlock();
+ ahd_unlock(ahd);
}
/****************************** Status Processing *****************************/
@@ -9255,8 +9235,6 @@ ahd_recover_commands(struct ahd_softc *ahd)
u_int active_scbptr;
u_int last_phase;
- ahd_lock();
-
/*
* Pause the controller and manually flush any
* commands that have just completed but that our
@@ -9282,7 +9260,6 @@ ahd_recover_commands(struct ahd_softc *ahd)
kprintf("%s: Timedout SCBs already complete. "
"Interrupts may not be functioning.\n", ahd_name(ahd));
ahd_unpause(ahd);
- ahd_unlock();
return;
}
@@ -9473,7 +9450,6 @@ bus_reset:
}
ahd_unpause(ahd);
- ahd_unlock();
}
/*
@@ -9889,13 +9865,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
*/
if ((ahd->flags & AHD_TARGETROLE) == 0
&& ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
- u_long s;
-
kprintf("Configuring Target Mode\n");
- ahd_lock();
if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
ccb->ccb_h.status = CAM_BUSY;
- ahd_unlock();
return;
}
ahd->flags |= AHD_TARGETROLE;
@@ -9904,7 +9876,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
ahd_pause(ahd);
ahd_loadseq(ahd);
ahd_restart(ahd);
- ahd_unlock();
}
cel = &ccb->cel;
target = ccb->ccb_h.target_id;
@@ -9963,7 +9934,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
}
SLIST_INIT(&lstate->accept_tios);
SLIST_INIT(&lstate->immed_notifies);
- ahd_lock();
ahd_pause(ahd);
if (target != CAM_TARGET_WILDCARD) {
tstate->enabled_luns[lun] = lstate;
@@ -10022,7 +9992,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
ahd_outb(ahd, SCSISEQ1, scsiseq1);
}
ahd_unpause(ahd);
- ahd_unlock();
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print_path(ccb->ccb_h.path);
kprintf("Lun now enabled for target mode\n");
@@ -10035,8 +10004,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
return;
}
- ahd_lock();
-
ccb->ccb_h.status = CAM_REQ_CMP;
LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
struct ccb_hdr *ccbh;
@@ -10046,7 +10013,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
&& !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
kprintf("CTIO pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
- ahd_unlock();
return;
}
}
@@ -10062,7 +10028,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
}
if (ccb->ccb_h.status != CAM_REQ_CMP) {
- ahd_unlock();
return;
}
@@ -10129,7 +10094,6 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
}
}
ahd_unpause(ahd);
- ahd_unlock();
}
#endif
}
diff --git a/sys/dev/disk/aic7xxx/aic79xx.h b/sys/dev/disk/aic7xxx/aic79xx.h
index f4e5bf3..847ae9d 100644
--- a/sys/dev/disk/aic7xxx/aic79xx.h
+++ b/sys/dev/disk/aic7xxx/aic79xx.h
@@ -640,6 +640,7 @@ struct scb {
u_int sg_count;/* How full ahd_dma_seg is */
#define AHD_MAX_LQ_CRC_ERRORS 5
u_int crc_retry_count;
+ aic_timer_t io_timer;
};
TAILQ_HEAD(scb_tailq, scb);
@@ -1395,7 +1396,6 @@ void ahd_pause_and_flushwork(struct ahd_softc *ahd);
int ahd_suspend(struct ahd_softc *ahd);
int ahd_resume(struct ahd_softc *ahd);
void ahd_softc_insert(struct ahd_softc *);
-struct ahd_softc *ahd_find_softc(struct ahd_softc *ahd);
void ahd_set_unit(struct ahd_softc *, int);
void ahd_set_name(struct ahd_softc *, char *);
struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
diff --git a/sys/dev/disk/aic7xxx/aic79xx_osm.c b/sys/dev/disk/aic7xxx/aic79xx_osm.c
index 360dea5..3c38a89 100644
--- a/sys/dev/disk/aic7xxx/aic79xx_osm.c
+++ b/sys/dev/disk/aic7xxx/aic79xx_osm.c
@@ -94,9 +94,9 @@ ahd_map_int(struct ahd_softc *ahd)
int error;
/* Hook up our interrupt handler */
- error = bus_setup_intr(ahd->dev_softc, ahd->platform_data->irq,
- 0, ahd_platform_intr, ahd,
- &ahd->platform_data->ih, NULL);
+ error = bus_setup_intr(ahd->dev_softc, ahd->platform_data->irq, 0,
+ ahd_platform_intr, ahd, &ahd->platform_data->ih,
+ &ahd->platform_data->serializer);
if (error != 0)
device_printf(ahd->dev_softc, "bus_setup_intr() failed: %d\n",
error);
@@ -126,7 +126,7 @@ ahd_attach(struct ahd_softc *ahd)
ahd_controller_info(ahd, ahd_info);
kprintf("%s\n", ahd_info);
- ahd_lock();
+ ahd_lock(ahd);
/*
* Construct our SIM entry
@@ -163,6 +163,7 @@ ahd_attach(struct ahd_softc *ahd)
fail:
ahd->platform_data->sim = sim;
ahd->platform_data->path = path;
+ ahd_unlock(ahd);
if (count != 0) {
/* We have to wait until after any system dumps... */
ahd->platform_data->eh =
@@ -171,8 +172,6 @@ fail:
ahd_intr_enable(ahd, TRUE);
}
- ahd_unlock();
-
return (count);
}
@@ -185,6 +184,7 @@ ahd_platform_intr(void *arg)
struct ahd_softc *ahd;
ahd = (struct ahd_softc *)arg;
+ ASSERT_SERIALIZED(&ahd->platform_data->serializer);
ahd_intr(ahd);
}
@@ -206,7 +206,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
if ((scb->flags & SCB_TIMEDOUT) != 0)
LIST_REMOVE(scb, timedout_links);
- callout_stop(&ccb->ccb_h.timeout_ch);
+ callout_stop(&scb->io_timer);
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
bus_dmasync_op_t op;
@@ -369,13 +369,11 @@ ahd_action(struct cam_sim *sim, union ccb *ccb)
}
if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
- ahd_lock();
SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
sim_links.sle);
ccb->ccb_h.status = CAM_REQ_INPROG;
if ((ahd->flags & AHD_TQINFIFO_BLOCKED) != 0)
ahd_run_tqinfifo(ahd, /*paused*/FALSE);
- ahd_unlock();
break;
}
@@ -409,7 +407,6 @@ ahd_action(struct cam_sim *sim, union ccb *ccb)
/*
* get an scb to use.
*/
- ahd_lock();
tinfo = ahd_fetch_transinfo(ahd, 'A', our_id,
target_id, &tstate);
if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0
@@ -424,12 +421,10 @@ ahd_action(struct cam_sim *sim, union ccb *ccb)
xpt_freeze_simq(sim, /*count*/1);
ahd->flags |= AHD_RESOURCE_SHORTAGE;
- ahd_unlock();
ccb->ccb_h.status = CAM_REQUEUE_REQ;
xpt_done(ccb);
return;
}
- ahd_unlock();
hscb = scb->hscb;
@@ -517,20 +512,16 @@ ahd_action(struct cam_sim *sim, union ccb *ccb)
}
case XPT_SET_TRAN_SETTINGS:
{
- ahd_lock();
ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim),
SIM_CHANNEL(ahd, sim), &ccb->cts);
- ahd_unlock();
xpt_done(ccb);
break;
}
case XPT_GET_TRAN_SETTINGS:
/* Get default/user set transfer settings for the target */
{
- ahd_lock();
ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim),
SIM_CHANNEL(ahd, sim), &ccb->cts);
- ahd_unlock();
xpt_done(ccb);
break;
}
@@ -544,10 +535,8 @@ ahd_action(struct cam_sim *sim, union ccb *ccb)
{
int found;
- ahd_lock();
found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim),
/*initiate reset*/TRUE);
- ahd_unlock();
if (bootverbose) {
xpt_print_path(SIM_PATH(ahd, sim));
kprintf("SCSI bus reset delivered. "
@@ -976,13 +965,11 @@ ahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
* Revert to async/narrow transfers
* for the next device.
*/
- ahd_lock();
ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE);
ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0,
/*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR,
/*paused*/FALSE);
- ahd_unlock();
break;
}
default:
@@ -1012,9 +999,7 @@ ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
aic_set_transaction_status(scb, CAM_REQ_CMP_ERR);
if (nsegments != 0)
bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap);
- ahd_lock();
ahd_free_scb(ahd, scb);
- ahd_unlock();
xpt_done(ccb);
return;
}
@@ -1052,8 +1037,6 @@ ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
}
}
- ahd_lock();
-
/*
* Last time we need to check if this SCB needs to
* be aborted.
@@ -1063,7 +1046,6 @@ ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
bus_dmamap_unload(ahd->buffer_dmat,
scb->dmamap);
ahd_free_scb(ahd, scb);
- ahd_unlock();
xpt_done(ccb);
return;
}
@@ -1112,8 +1094,6 @@ ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
} else {
ahd_queue_scb(ahd, scb);
}
-
- ahd_unlock();
}
static void
@@ -1140,6 +1120,7 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
if (hscb->cdb_len > MAX_CDB_LEN
&& (ccb_h->flags & CAM_CDB_PHYS) == 0) {
+
/*
* Should CAM start to support CDB sizes
* greater than 16 bytes, we could use
@@ -1147,9 +1128,7 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
*/
aic_set_transaction_status(scb,
CAM_REQ_INVALID);
- ahd_lock();
ahd_free_scb(ahd, scb);
- ahd_unlock();
xpt_done((union ccb *)csio);
return;
}
@@ -1166,11 +1145,10 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
}
} else {
if (hscb->cdb_len > MAX_CDB_LEN) {
+
aic_set_transaction_status(scb,
CAM_REQ_INVALID);
- ahd_lock();
ahd_free_scb(ahd, scb);
- ahd_unlock();
xpt_done((union ccb *)csio);
return;
}
@@ -1448,16 +1426,11 @@ ahd_detach(device_t dev)
device_printf(dev, "detaching device\n");
ahd = device_get_softc(dev);
- ahd = ahd_find_softc(ahd);
- if (ahd == NULL) {
- device_printf(dev, "aic7xxx already detached\n");
- return (ENOENT);
- }
+ ahd_lock(ahd);
TAILQ_REMOVE(&ahd_tailq, ahd, links);
- ahd_lock();
ahd_intr_enable(ahd, FALSE);
bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih);
- ahd_unlock();
+ ahd_unlock(ahd);
ahd_free(ahd);
return (0);
}
@@ -1494,6 +1467,7 @@ static int
ahd_modevent(module_t mod, int type, void *data)
{
/* XXX Deal with busy status on unload. */
+ /* XXX Deal with unknown events */
return 0;
}
diff --git a/sys/dev/disk/aic7xxx/aic79xx_osm.h b/sys/dev/disk/aic7xxx/aic79xx_osm.h
index 1e4b4fe..994a616 100644
--- a/sys/dev/disk/aic7xxx/aic79xx_osm.h
+++ b/sys/dev/disk/aic7xxx/aic79xx_osm.h
@@ -116,6 +116,17 @@
#define AHD_TARGET_MODE 1
#endif
+/***************************** Core Includes **********************************/
+#ifdef AHD_REG_PRETTY_PRINT
+#define AIC_DEBUG_REGISTERS 1
+#else
+#define AIC_DEBUG_REGISTERS 0
+#endif
+#define AIC_CORE_INCLUDE "aic79xx.h"
+#define AIC_LIB_PREFIX ahd
+#define AIC_CONST_PREFIX AHD
+#include "aic_osm_lib.h"
+
/************************** Softc/SCB Platform Data ***************************/
struct ahd_platform_data {
/*
@@ -132,22 +143,12 @@ struct ahd_platform_data {
void *ih;
eventhandler_tag eh;
struct thread *recovery_thread;
+ struct lwkt_serialize serializer;
};
struct scb_platform_data {
};
-/***************************** Core Includes **********************************/
-#ifdef AHD_REG_PRETTY_PRINT
-#define AIC_DEBUG_REGISTERS 1
-#else
-#define AIC_DEBUG_REGISTERS 0
-#endif
-#define AIC_CORE_INCLUDE "aic79xx.h"
-#define AIC_LIB_PREFIX ahd
-#define AIC_CONST_PREFIX AHD
-#include "aic_osm_lib.h"
-
/*************************** Device Access ************************************/
#define ahd_inb(ahd, port) \
bus_space_read_1((ahd)->tags[(port) >> 8], \
@@ -187,19 +188,26 @@ ahd_flush_device_writes(struct ahd_softc *ahd)
/**************************** Locking Primitives ******************************/
/* Lock protecting internal data structures */
-static __inline void ahd_lock(void);
-static __inline void ahd_unlock(void);
+static __inline void ahd_lockinit(struct ahd_softc *);
+static __inline void ahd_lock(struct ahd_softc *);
+static __inline void ahd_unlock(struct ahd_softc *);
+
+static __inline void
+ahd_lockinit(struct ahd_softc *ahd)
+{
+ lwkt_serialize_init(&ahd->platform_data->serializer);
+}
static __inline void
-ahd_lock(void)
+ahd_lock(struct ahd_softc *ahd)
{
- crit_enter();
+ lwkt_serialize_enter(&ahd->platform_data->serializer);
}
static __inline void
-ahd_unlock(void)
+ahd_unlock(struct ahd_softc *ahd)
{
- crit_exit();
+ lwkt_serialize_exit(&ahd->platform_data->serializer);
}
/********************************** PCI ***************************************/
diff --git a/sys/dev/disk/aic7xxx/aic79xx_pci.c b/sys/dev/disk/aic7xxx/aic79xx_pci.c
index 07e27cf..ee67102 100644
--- a/sys/dev/disk/aic7xxx/aic79xx_pci.c
+++ b/sys/dev/disk/aic7xxx/aic79xx_pci.c
@@ -416,10 +416,12 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
if (error != 0)
return (error);
+ ahd_lock(ahd);
/*
* Link this softc in with all other ahd instances.
*/
ahd_softc_insert(ahd);
+ ahd_unlock(ahd);
return (0);
}
diff --git a/sys/dev/disk/aic7xxx/aic7xxx.c b/sys/dev/disk/aic7xxx/aic7xxx.c
index add0b68..febc516 100644
--- a/sys/dev/disk/aic7xxx/aic7xxx.c
+++ b/sys/dev/disk/aic7xxx/aic7xxx.c
@@ -3928,6 +3928,7 @@ ahc_alloc(void *platform_arg, char *name)
ahc_free(ahc);
ahc = NULL;
}
+ ahc_lockinit(ahc);
return (ahc);
}
@@ -4006,22 +4007,6 @@ ahc_softc_insert(struct ahc_softc *ahc)
ahc->init_level++;
}
-/*
- * Verify that the passed in softc pointer is for a
- * controller that is still configured.
- */
-struct ahc_softc *
-ahc_find_softc(struct ahc_softc *ahc)
-{
- struct ahc_softc *list_ahc;
-
- TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
- if (list_ahc == ahc)
- return (ahc);
- }
- return (NULL);
-}
-
void
ahc_set_unit(struct ahc_softc *ahc, int unit)
{
@@ -4574,6 +4559,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
#endif
next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
next_scb->hscb->tag = ahc->scb_data->numscbs;
+ aic_timer_init(&next_scb->io_timer);
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
next_scb, links.sle);
segs += AHC_NSEG;
@@ -5147,6 +5133,9 @@ ahc_intr_enable(struct ahc_softc *ahc, int enable)
{
u_int hcntrl;
+ if (enable)
+ lwkt_serialize_handler_enable(&ahc->platform_data->serializer);
+
hcntrl = ahc_inb(ahc, HCNTRL);
hcntrl &= ~INTEN;
ahc->pause &= ~INTEN;
@@ -5157,6 +5146,8 @@ ahc_intr_enable(struct ahc_softc *ahc, int enable)
ahc->unpause |= INTEN;
}
ahc_outb(ahc, HCNTRL, hcntrl);
+ if (!enable)
+ lwkt_serialize_handler_disable(&ahc->platform_data->serializer);
}
/*
@@ -6988,8 +6979,6 @@ ahc_recover_commands(struct ahc_softc *ahc)
int restart_needed;
u_int last_phase;
- ahc_lock();
-
/*
* Pause the controller and manually flush any
* commands that have just completed but that our
@@ -7009,7 +6998,6 @@ ahc_recover_commands(struct ahc_softc *ahc)
kprintf("%s: Timedout SCBs already complete. "
"Interrupts may not be functioning.\n", ahc_name(ahc));
ahc_unpause(ahc);
- ahc_unlock();
return;
}
@@ -7262,7 +7250,6 @@ bus_reset:
ahc_restart(ahc);
else
ahc_unpause(ahc);
- ahc_unlock();
}
/************************* Target Mode ****************************************/
@@ -7399,10 +7386,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc_flag saved_flags;
kprintf("Configuring Target Mode\n");
- ahc_lock();
if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
ccb->ccb_h.status = CAM_BUSY;
- ahc_unlock();
return;
}
saved_flags = ahc->flags;
@@ -7423,12 +7408,10 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc->flags = saved_flags;
(void)ahc_loadseq(ahc);
ahc_restart(ahc);
- ahc_unlock();
ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
return;
}
ahc_restart(ahc);
- ahc_unlock();
}
cel = &ccb->cel;
target = ccb->ccb_h.target_id;
@@ -7487,7 +7470,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
}
SLIST_INIT(&lstate->accept_tios);
SLIST_INIT(&lstate->immed_notifies);
- ahc_lock();
ahc_pause(ahc);
if (target != CAM_TARGET_WILDCARD) {
tstate->enabled_luns[lun] = lstate;
@@ -7553,7 +7535,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc_outb(ahc, SCSISEQ, scsiseq);
}
ahc_unpause(ahc);
- ahc_unlock();
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print_path(ccb->ccb_h.path);
kprintf("Lun now enabled for target mode\n");
@@ -7566,8 +7547,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
return;
}
- ahc_lock();
-
ccb->ccb_h.status = CAM_REQ_CMP;
LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
struct ccb_hdr *ccbh;
@@ -7577,7 +7556,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
&& !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
kprintf("CTIO pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
- ahc_unlock();
return;
}
}
@@ -7593,7 +7571,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
}
if (ccb->ccb_h.status != CAM_REQ_CMP) {
- ahc_unlock();
return;
}
@@ -7668,7 +7645,6 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
}
}
ahc_unpause(ahc);
- ahc_unlock();
}
}
diff --git a/sys/dev/disk/aic7xxx/aic7xxx.h b/sys/dev/disk/aic7xxx/aic7xxx.h
index 77cce33..65a1cb0 100644
--- a/sys/dev/disk/aic7xxx/aic7xxx.h
+++ b/sys/dev/disk/aic7xxx/aic7xxx.h
@@ -598,6 +598,7 @@ struct scb {
struct ahc_dma_seg *sg_list;
bus_addr_t sg_list_phys;
u_int sg_count;/* How full ahc_dma_seg is */
+ aic_timer_t io_timer;
};
struct scb_data {
@@ -1225,7 +1226,6 @@ void ahc_pause_and_flushwork(struct ahc_softc *ahc);
int ahc_suspend(struct ahc_softc *ahc);
int ahc_resume(struct ahc_softc *ahc);
void ahc_softc_insert(struct ahc_softc *);
-struct ahc_softc *ahc_find_softc(struct ahc_softc *ahc);
void ahc_set_unit(struct ahc_softc *, int);
void ahc_set_name(struct ahc_softc *, char *);
int ahc_alloc_scbs(struct ahc_softc *ahc);
diff --git a/sys/dev/disk/aic7xxx/aic7xxx_osm.c b/sys/dev/disk/aic7xxx/aic7xxx_osm.c
index 8181836..0b66a6d 100644
--- a/sys/dev/disk/aic7xxx/aic7xxx_osm.c
+++ b/sys/dev/disk/aic7xxx/aic7xxx_osm.c
@@ -106,9 +106,9 @@ ahc_map_int(struct ahc_softc *ahc)
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
/* Hook up our interrupt handler */
- error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq,
- 0, ahc_platform_intr, ahc,
- &ahc->platform_data->ih, NULL);
+ error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq, 0,
+ ahc_platform_intr, ahc, &ahc->platform_data->ih,
+ &ahc->platform_data->serializer);
if (error != 0)
device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n",
@@ -167,7 +167,7 @@ ahc_attach(struct ahc_softc *ahc)
ahc_controller_info(ahc, ahc_info);
kprintf("%s\n", ahc_info);
- ahc_lock();
+ ahc_lock(ahc);
/*
* Attach secondary channel first if the user has
@@ -267,6 +267,7 @@ fail:
ahc->platform_data->sim_b = sim2;
ahc->platform_data->path_b = path2;
}
+ ahc_unlock(ahc);
if (count != 0) {
/* We have to wait until after any system dumps... */
@@ -276,7 +277,6 @@ fail:
ahc_intr_enable(ahc, TRUE);
}
- ahc_unlock();
return (count);
}
@@ -289,6 +289,7 @@ ahc_platform_intr(void *arg)
struct ahc_softc *ahc;
ahc = (struct ahc_softc *)arg;
+ ASSERT_SERIALIZED(&ahc->platform_data->serializer);
ahc_intr(ahc);
}
@@ -320,7 +321,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
ahc_run_untagged_queue(ahc, untagged_q);
}
- callout_stop(&ccb->ccb_h.timeout_ch);
+ callout_stop(&scb->io_timer);
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
bus_dmasync_op_t op;
@@ -384,8 +385,8 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
* so reinstate the timeouts for all other pending
* commands.
*/
- LIST_FOREACH(list_scb, &ahc->pending_scbs,
- pending_links) {
+ LIST_FOREACH(list_scb, &ahc->pending_scbs,
+ pending_links) {
aic_scb_timer_reset(list_scb,
aic_get_timeout(scb));
@@ -462,13 +463,11 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
}
if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
- ahc_lock();
SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
sim_links.sle);
ccb->ccb_h.status = CAM_REQ_INPROG;
if ((ahc->flags & AHC_TQINFIFO_BLOCKED) != 0)
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
- ahc_unlock();
break;
}
@@ -498,17 +497,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
/*
* get an scb to use.
*/
- ahc_lock();
if ((scb = ahc_get_scb(ahc)) == NULL) {
xpt_freeze_simq(sim, /*count*/1);
ahc->flags |= AHC_RESOURCE_SHORTAGE;
- ahc_unlock();
ccb->ccb_h.status = CAM_REQUEUE_REQ;
xpt_done(ccb);
return;
}
- ahc_unlock();
hscb = scb->hscb;
@@ -639,8 +635,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
break;
}
- ahc_lock();
-
if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
*discenable |= devinfo.target_mask;
@@ -716,7 +710,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
/*paused*/FALSE);
}
- ahc_unlock();
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
#else
@@ -752,8 +745,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
break;
}
- ahc_lock();
-
if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
*discenable |= devinfo.target_mask;
@@ -834,7 +825,6 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
ppr_options, update_type,
/*paused*/FALSE);
}
- ahc_unlock();
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
#endif
@@ -844,10 +834,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
/* Get default/user set transfer settings for the target */
{
- ahc_lock();
ahc_get_tran_settings(ahc, SIM_SCSI_ID(ahc, sim),
SIM_CHANNEL(ahc, sim), &ccb->cts);
- ahc_unlock();
xpt_done(ccb);
break;
}
@@ -866,10 +854,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb)
{
int found;
- ahc_lock();
found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim),
/*initiate reset*/TRUE);
- ahc_unlock();
if (bootverbose) {
xpt_print_path(SIM_PATH(ahc, sim));
kprintf("SCSI bus reset delivered. "
@@ -1077,14 +1063,12 @@ ahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
* Revert to async/narrow transfers
* for the next device.
*/
- ahc_lock();
ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE);
ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL,
/*period*/0, /*offset*/0, /*ppr_options*/0,
AHC_TRANS_GOAL|AHC_TRANS_CUR,
/*paused*/FALSE);
- ahc_unlock();
break;
}
default:
@@ -1114,9 +1098,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
aic_set_transaction_status(scb, CAM_REQ_CMP_ERR);
if (nsegments != 0)
bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
- ahc_lock();
ahc_free_scb(ahc, scb);
- ahc_unlock();
xpt_done(ccb);
return;
}
@@ -1189,9 +1171,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
CAM_REQ_TOO_BIG);
bus_dmamap_unload(ahc->buffer_dmat,
scb->dmamap);
- ahc_lock();
ahc_free_scb(ahc, scb);
- ahc_unlock();
xpt_done(ccb);
return;
}
@@ -1214,8 +1194,6 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
scb->sg_count = nsegments;
- ahc_lock();
-
/*
* Last time we need to check if this SCB needs to
* be aborted.
@@ -1224,7 +1202,6 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
if (nsegments != 0)
bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
ahc_free_scb(ahc, scb);
- ahc_unlock();
xpt_done(ccb);
return;
}
@@ -1275,7 +1252,6 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
scb->flags |= SCB_UNTAGGEDQ;
if (TAILQ_FIRST(untagged_q) != scb) {
- ahc_unlock();
return;
}
}
@@ -1297,8 +1273,6 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
} else {
ahc_queue_scb(ahc, scb);
}
-
- ahc_unlock();
}
static void
@@ -1330,9 +1304,7 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
|| (ccb_h->flags & CAM_CDB_PHYS) != 0) {
aic_set_transaction_status(scb,
CAM_REQ_INVALID);
- ahc_lock();
ahc_free_scb(ahc, scb);
- ahc_unlock();
xpt_done((union ccb *)csio);
return;
}
@@ -1628,16 +1600,11 @@ ahc_detach(device_t dev)
device_printf(dev, "detaching device\n");
ahc = device_get_softc(dev);
- ahc = ahc_find_softc(ahc);
- if (ahc == NULL) {
- device_printf(dev, "aic7xxx already detached\n");
- return (ENOENT);
- }
+ ahc_lock(ahc);
TAILQ_REMOVE(&ahc_tailq, ahc, links);
- ahc_lock();
ahc_intr_enable(ahc, FALSE);
bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih);
- ahc_unlock();
+ ahc_unlock(ahc);
ahc_free(ahc);
return (0);
}
@@ -1674,6 +1641,7 @@ static int
ahc_modevent(module_t mod, int type, void *data)
{
/* XXX Deal with busy status on unload. */
+ /* XXX Deal with unknown events */
return 0;
}
diff --git a/sys/dev/disk/aic7xxx/aic7xxx_osm.h b/sys/dev/disk/aic7xxx/aic7xxx_osm.h
index 193bef0..a73fc7a 100644
--- a/sys/dev/disk/aic7xxx/aic7xxx_osm.h
+++ b/sys/dev/disk/aic7xxx/aic7xxx_osm.h
@@ -126,6 +126,17 @@ extern devclass_t ahc_devclass;
/* This driver supports target mode */
#define AHC_TARGET_MODE 1
+/***************************** Core Includes **********************************/
+#ifdef AHC_REG_PRETTY_PRINT
+#define AIC_DEBUG_REGISTERS 1
+#else
+#define AIC_DEBUG_REGISTERS 0
+#endif
+#define AIC_CORE_INCLUDE "aic7xxx.h"
+#define AIC_LIB_PREFIX ahc
+#define AIC_CONST_PREFIX AHC
+#include "aic_osm_lib.h"
+
/************************** Softc/SCB Platform Data ***************************/
struct ahc_platform_data {
/*
@@ -144,22 +155,12 @@ struct ahc_platform_data {
void *ih;
eventhandler_tag eh;
struct thread *recovery_thread;
+ struct lwkt_serialize serializer;
};
struct scb_platform_data {
};
-/***************************** Core Includes **********************************/
-#ifdef AHC_REG_PRETTY_PRINT
-#define AIC_DEBUG_REGISTERS 1
-#else
-#define AIC_DEBUG_REGISTERS 0
-#endif
-#define AIC_CORE_INCLUDE "aic7xxx.h"
-#define AIC_LIB_PREFIX ahc
-#define AIC_CONST_PREFIX AHC
-#include "aic_osm_lib.h"
-
/*************************** Device Access ************************************/
#define ahc_inb(ahc, port) \
bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
@@ -184,19 +185,26 @@ ahc_flush_device_writes(struct ahc_softc *ahc)
/**************************** Locking Primitives ******************************/
/* Lock protecting internal data structures */
-static __inline void ahc_lock(void);
-static __inline void ahc_unlock(void);
+static __inline void ahc_lockinit(struct ahc_softc *);
+static __inline void ahc_lock(struct ahc_softc *);
+static __inline void ahc_unlock(struct ahc_softc *);
+
+static __inline void
+ahc_lockinit(struct ahc_softc *ahc)
+{
+ lwkt_serialize_init(&ahc->platform_data->serializer);
+}
static __inline void
-ahc_lock(void)
+ahc_lock(struct ahc_softc *ahc)
{
- crit_enter_id("ahc");
+ lwkt_serialize_enter(&ahc->platform_data->serializer);
}
static __inline void
-ahc_unlock(void)
+ahc_unlock(struct ahc_softc *ahc)
{
- crit_exit_id("ahc");
+ lwkt_serialize_exit(&ahc->platform_data->serializer);
}
/************************* Initialization/Teardown ****************************/
diff --git a/sys/dev/disk/aic7xxx/aic7xxx_pci.c b/sys/dev/disk/aic7xxx/aic7xxx_pci.c
index c4caf62..2129843 100644
--- a/sys/dev/disk/aic7xxx/aic7xxx_pci.c
+++ b/sys/dev/disk/aic7xxx/aic7xxx_pci.c
@@ -1045,10 +1045,12 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
if (error != 0)
return (error);
+ ahc_lock(ahc);
/*
* Link this softc in with all other ahc instances.
*/
ahc_softc_insert(ahc);
+ ahc_unlock(ahc);
return (0);
}
diff --git a/sys/dev/disk/aic7xxx/aic_osm_lib.c b/sys/dev/disk/aic7xxx/aic_osm_lib.c
index ff2568d..35ff4ae 100644
--- a/sys/dev/disk/aic7xxx/aic_osm_lib.c
+++ b/sys/dev/disk/aic7xxx/aic_osm_lib.c
@@ -57,7 +57,7 @@ aic_set_recoveryscb(struct aic_softc *aic, struct scb *scb)
union ccb *ccb;
ccb = list_scb->io_ctx;
- callout_stop(&ccb->ccb_h.timeout_ch);
+ callout_stop(&scb->io_timer);
}
}
}
@@ -68,9 +68,9 @@ aic_platform_timeout(void *arg)
struct scb *scb;
scb = (struct scb *)arg;
- aic_lock();
+ aic_lock(scb->aic_softc);
aic_timeout(scb);
- aic_unlock();
+ aic_unlock(scb->aic_softc);
}
int
@@ -92,9 +92,7 @@ void
aic_terminate_recovery_thread(struct aic_softc *aic)
{
- aic_lock();
if (aic->platform_data->recovery_thread == NULL) {
- aic_unlock();
return;
}
aic->flags |= AIC_SHUTDOWN_RECOVERY;
@@ -103,8 +101,12 @@ aic_terminate_recovery_thread(struct aic_softc *aic)
* Sleep on a slightly different location
* for this interlock just for added safety.
*/
+ crit_enter();
+ aic_lock(aic);
+ tsleep_interlock(aic->platform_data);
+ aic_unlock(aic);
tsleep(aic->platform_data, 0, "thtrm", 0);
- aic_unlock();
+ crit_exit();
}
static void
@@ -112,29 +114,27 @@ aic_recovery_thread(void *arg)
{
struct aic_softc *aic;
-#if __FreeBSD_version >= 500000
- mtx_lock(&Giant);
-#endif
aic = (struct aic_softc *)arg;
- aic_lock();
+ aic_lock(aic);
for (;;) {
if (LIST_EMPTY(&aic->timedout_scbs) != 0
- && (aic->flags & AIC_SHUTDOWN_RECOVERY) == 0)
+ && (aic->flags & AIC_SHUTDOWN_RECOVERY) == 0) {
+ crit_enter();
+ tsleep_interlock(aic);
+ aic_unlock(aic);
tsleep(aic, 0, "idle", 0);
+ crit_exit();
+ aic_lock(aic);
+ }
if ((aic->flags & AIC_SHUTDOWN_RECOVERY) != 0)
break;
- aic_unlock();
aic_recover_commands(aic);
- aic_lock();
}
aic->platform_data->recovery_thread = NULL;
wakeup(aic->platform_data);
- aic_unlock();
-#if __FreeBSD_version >= 500000
- mtx_unlock(&Giant);
-#endif
+ aic_unlock(aic);
kthread_exit();
}
diff --git a/sys/dev/disk/aic7xxx/aic_osm_lib.h b/sys/dev/disk/aic7xxx/aic_osm_lib.h
index e402ba1..ce4e153 100644
--- a/sys/dev/disk/aic7xxx/aic_osm_lib.h
+++ b/sys/dev/disk/aic7xxx/aic_osm_lib.h
@@ -39,6 +39,8 @@
/******************************** OS Includes *********************************/
#if __FreeBSD_version >= 500000
#include <sys/mutex.h>
+#else
+#include <sys/serialize.h>
#endif
/*************************** Library Symbol Mapping ***************************/
@@ -223,8 +225,7 @@ aic_scb_timer_reset(struct scb *scb, u_int msec)
time = msec;
time *= hz;
time /= 1000;
- callout_reset(&scb->io_ctx->ccb_h.timeout_ch, time,
- aic_platform_timeout, scb);
+ callout_reset(&scb->io_timer, time, aic_platform_timeout, scb);
}
static __inline void
@@ -233,13 +234,7 @@ aic_scb_timer_start(struct scb *scb)
if (AIC_SCB_DATA(scb->aic_softc)->recovery_scbs == 0
&& scb->io_ctx->ccb_h.timeout != CAM_TIME_INFINITY) {
- uint64_t time;
-
- time = scb->io_ctx->ccb_h.timeout;
- time *= hz;
- time /= 1000;
- callout_reset(&scb->io_ctx->ccb_h.timeout_ch, time,
- aic_platform_timeout, scb);
+ aic_scb_timer_reset(scb, scb->io_ctx->ccb_h.timeout);
}
}
Attachment:
pgp00001.pgp
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pgp00001.pgp
Type: application/octet-stream
Size: 189 bytes
Desc: "Description: PGP signature"
URL: <http://lists.dragonflybsd.org/pipermail/kernel/attachments/20080101/2238ba73/attachment-0020.obj>
More information about the Kernel
mailing list