aboutsummaryrefslogtreecommitdiff
path: root/sys/cam/cam_xpt.c
diff options
context:
space:
mode:
authorScott Long <scottl@FreeBSD.org>2007-04-15 08:49:19 +0000
committerScott Long <scottl@FreeBSD.org>2007-04-15 08:49:19 +0000
commit2b83592fdcb9e7c201677f3605b9e8738a6b0737 (patch)
tree010146772b36d16e6f98671b4bed7ce094acd633 /sys/cam/cam_xpt.c
parent4f450d951a7b14cda1b359646ec580a82b4f012e (diff)
downloadsrc-2b83592fdcb9e7c201677f3605b9e8738a6b0737.tar.gz
src-2b83592fdcb9e7c201677f3605b9e8738a6b0737.zip
Remove Giant from CAM. Drivers (SIMs) now register a mutex that CAM will
use to synchornize and protect all data objects that are used for that SIM. Drivers that are not yet MPSAFE register Giant and operate as usual. RIght now, no drivers are MPSAFE, though a few will be changed in the coming week as this work settles down. The driver API has changed, so all CAM drivers will need to be recompiled. The userland API has not changed, so tools like camcontrol do not need to be recompiled.
Notes
Notes: svn path=/head/; revision=168752
Diffstat (limited to 'sys/cam/cam_xpt.c')
-rw-r--r--sys/cam/cam_xpt.c766
1 files changed, 447 insertions, 319 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index c123b5cfcd07..d13209e199d2 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/md5.h>
#include <sys/interrupt.h>
#include <sys/sbuf.h>
+#include <sys/taskqueue.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -70,6 +71,12 @@ __FBSDID("$FreeBSD$");
/* Datastructures internal to the xpt layer */
MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers");
+/* Object for defering XPT actions to a taskqueue */
+struct xpt_task {
+ struct task task;
+ void *data;
+};
+
/*
* Definition of an async handler callback block. These are used to add
* SIMs and peripherals to the async callback lists.
@@ -84,7 +91,6 @@ struct async_node {
SLIST_HEAD(async_list, async_node);
SLIST_HEAD(periph_list, cam_periph);
-static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq;
/*
* This is the maximum number of high powered commands (e.g. start unit)
@@ -94,9 +100,6 @@ static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq;
#define CAM_MAX_HIGHPOWER 4
#endif
-/* number of high powered commands that can go through right now */
-static int num_highpower = CAM_MAX_HIGHPOWER;
-
/*
* Structure for queueing a device in a run queue.
* There is one run queue for allocating new ccbs,
@@ -117,6 +120,7 @@ struct cam_ed {
struct cam_ed_qinfo alloc_ccb_entry;
struct cam_ed_qinfo send_ccb_entry;
struct cam_et *target;
+ struct cam_sim *sim;
lun_id_t lun_id;
struct camq drvq; /*
* Queue of type drivers wanting to do
@@ -158,7 +162,7 @@ struct cam_ed {
#define CAM_TAG_DELAY_COUNT 5
u_int32_t tag_saved_openings;
u_int32_t refcount;
- struct callout_handle c_handle;
+ struct callout callout;
};
/*
@@ -242,8 +246,24 @@ typedef enum {
} xpt_flags;
struct xpt_softc {
- xpt_flags flags;
- u_int32_t generation;
+ xpt_flags flags;
+ u_int32_t xpt_generation;
+
+ /* number of high powered commands that can go through right now */
+ STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq;
+ int num_highpower;
+
+ /* queue for handling async rescan requests. */
+ TAILQ_HEAD(, ccb_hdr) ccb_scanq;
+
+ /* Registered busses */
+ TAILQ_HEAD(,cam_eb) xpt_busses;
+ u_int bus_generation;
+
+ struct intr_config_hook *xpt_config_hook;
+
+ struct mtx xpt_topo_lock;
+ struct mtx xpt_lock;
};
static const char quantum[] = "QUANTUM";
@@ -647,14 +667,8 @@ typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t;
static cam_isrq_t cam_bioq;
static struct mtx cam_bioq_lock;
-/* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */
-static SLIST_HEAD(,ccb_hdr) ccb_freeq;
-static u_int xpt_max_ccbs; /*
- * Maximum size of ccb pool. Modified as
- * devices are added/removed or have their
- * opening counts changed.
- */
-static u_int xpt_ccb_count; /* Current count of allocated ccbs */
+/* Pointers to software interrupt handlers */
+static void *cambio_ih;
struct cam_periph *xpt_periph;
@@ -684,14 +698,13 @@ static d_ioctl_t xptioctl;
static struct cdevsw xpt_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
+ .d_flags = 0,
.d_open = xptopen,
.d_close = xptclose,
.d_ioctl = xptioctl,
.d_name = "xpt",
};
-static struct intr_config_hook *xpt_config_hook;
static void dead_sim_action(struct cam_sim *sim, union ccb *ccb);
static void dead_sim_poll(struct cam_sim *sim);
@@ -705,9 +718,6 @@ static struct cam_sim cam_dead_sim = {
#define SIM_DEAD(sim) ((sim) == &cam_dead_sim)
-/* Registered busses */
-static TAILQ_HEAD(,cam_eb) xpt_busses;
-static u_int bus_generation;
/* Storage for debugging datastructures */
#ifdef CAMDEBUG
@@ -716,9 +726,6 @@ u_int32_t cam_dflags;
u_int32_t cam_debug_delay;
#endif
-/* Pointers to software interrupt handlers */
-static void *cambio_ih;
-
#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG)
#error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS"
#endif
@@ -750,7 +757,7 @@ static moduledata_t cam_moduledata = {
NULL
};
-static void xpt_init(void *);
+static int xpt_init(void *);
DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND);
MODULE_VERSION(cam, 1);
@@ -781,7 +788,7 @@ static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo,
static void xpt_run_dev_allocq(struct cam_eb *bus);
static void xpt_run_dev_sendq(struct cam_eb *bus);
static timeout_t xpt_release_devq_timeout;
-static timeout_t xpt_release_simq_timeout;
+static void xpt_release_simq_timeout(void *arg) __unused;
static void xpt_release_bus(struct cam_eb *bus);
static void xpt_release_devq_device(struct cam_ed *dev, u_int count,
int run_queue);
@@ -813,11 +820,6 @@ static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb);
static void xptaction(struct cam_sim *sim, union ccb *work_ccb);
static void xptpoll(struct cam_sim *sim);
static void camisr(void *);
-#if 0
-static void xptstart(struct cam_periph *periph, union ccb *work_ccb);
-static void xptasync(struct cam_periph *periph,
- u_int32_t code, cam_path *path);
-#endif
static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns,
u_int num_patterns, struct cam_eb *bus);
static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns,
@@ -856,16 +858,8 @@ static xpt_targetfunc_t xptdeftargetfunc;
static xpt_devicefunc_t xptdefdevicefunc;
static xpt_periphfunc_t xptdefperiphfunc;
static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg);
-#ifdef notusedyet
-static int xpt_for_all_targets(xpt_targetfunc_t *tr_func,
- void *arg);
-#endif
static int xpt_for_all_devices(xpt_devicefunc_t *tr_func,
void *arg);
-#ifdef notusedyet
-static int xpt_for_all_periphs(xpt_periphfunc_t *tr_func,
- void *arg);
-#endif
static xpt_devicefunc_t xptsetasyncfunc;
static xpt_busfunc_t xptsetasyncbusfunc;
static cam_status xptregister(struct cam_periph *periph,
@@ -996,9 +990,6 @@ xptdone(struct cam_periph *periph, union ccb *done_ccb)
static int
xptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
{
- int unit;
-
- unit = minor(dev) & 0xff;
/*
* Only allow read-write access.
@@ -1010,22 +1001,14 @@ xptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
* We don't allow nonblocking access.
*/
if ((flags & O_NONBLOCK) != 0) {
- printf("xpt%d: can't do nonblocking access\n", unit);
+ printf("%s: can't do nonblocking access\n", devtoname(dev));
return(ENODEV);
}
- /*
- * We only have one transport layer right now. If someone accesses
- * us via something other than minor number 1, point out their
- * mistake.
- */
- if (unit != 0) {
- printf("xptopen: got invalid xpt unit %d\n", unit);
- return(ENXIO);
- }
-
/* Mark ourselves open */
+ mtx_lock(&xsoftc.xpt_lock);
xsoftc.flags |= XPT_FLAG_OPEN;
+ mtx_unlock(&xsoftc.xpt_lock);
return(0);
}
@@ -1033,43 +1016,27 @@ xptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
static int
xptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
{
- int unit;
-
- unit = minor(dev) & 0xff;
-
- /*
- * We only have one transport layer right now. If someone accesses
- * us via something other than minor number 1, point out their
- * mistake.
- */
- if (unit != 0) {
- printf("xptclose: got invalid xpt unit %d\n", unit);
- return(ENXIO);
- }
/* Mark ourselves closed */
+ mtx_lock(&xsoftc.xpt_lock);
xsoftc.flags &= ~XPT_FLAG_OPEN;
+ mtx_unlock(&xsoftc.xpt_lock);
return(0);
}
+/*
+ * Don't automatically grab the xpt softc lock here even though this is going
+ * through the xpt device. The xpt device is really just a back door for
+ * accessing other devices and SIMs, so the right thing to do is to grab
+ * the appropriate SIM lock once the bus/SIM is located.
+ */
static int
xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
- int unit, error;
+ int error;
error = 0;
- unit = minor(dev) & 0xff;
-
- /*
- * We only have one transport layer right now. If someone accesses
- * us via something other than minor number 1, point out their
- * mistake.
- */
- if (unit != 0) {
- printf("xptioctl: got invalid xpt unit %d\n", unit);
- return(ENXIO);
- }
switch(cmd) {
/*
@@ -1081,9 +1048,16 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
case CAMIOCOMMAND: {
union ccb *ccb;
union ccb *inccb;
+ struct cam_eb *bus;
inccb = (union ccb *)addr;
+ bus = xpt_find_bus(inccb->ccb_h.path_id);
+ if (bus == NULL) {
+ error = EINVAL;
+ break;
+ }
+
switch(inccb->ccb_h.func_code) {
case XPT_SCAN_BUS:
case XPT_RESET_BUS:
@@ -1097,7 +1071,9 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
case XPT_ENG_INQ:
case XPT_SCAN_LUN:
- ccb = xpt_alloc_ccb();
+ ccb = xpt_alloc_ccb(bus->sim);
+
+ CAM_SIM_LOCK(bus->sim);
/*
* Create a path using the bus, target, and lun the
@@ -1109,6 +1085,7 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
inccb->ccb_h.target_lun) !=
CAM_REQ_CMP){
error = EINVAL;
+ CAM_SIM_UNLOCK(bus->sim);
xpt_free_ccb(ccb);
break;
}
@@ -1121,6 +1098,7 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
bcopy(ccb, inccb, sizeof(union ccb));
xpt_free_path(ccb->ccb_h.path);
xpt_free_ccb(ccb);
+ CAM_SIM_UNLOCK(bus->sim);
break;
case XPT_DEBUG: {
@@ -1131,6 +1109,8 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
* allocate it on the stack.
*/
+ CAM_SIM_LOCK(bus->sim);
+
/*
* Create a path using the bus, target, and lun the
* user passed in.
@@ -1149,6 +1129,7 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
xpt_merge_ccb(&ccb, inccb);
ccb.ccb_h.cbfcnp = xptdone;
xpt_action(&ccb);
+ CAM_SIM_UNLOCK(bus->sim);
bcopy(&ccb, inccb, sizeof(union ccb));
xpt_free_path(ccb.ccb_h.path);
break;
@@ -1268,7 +1249,7 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
/* Keep the list from changing while we traverse it */
s = splcam();
ptstartover:
- cur_generation = xsoftc.generation;
+ cur_generation = xsoftc.xpt_generation;
/* first find our driver in the list of drivers */
for (p_drv = periph_drivers; *p_drv != NULL; p_drv++)
@@ -1301,7 +1282,7 @@ ptstartover:
splx(s);
s = splcam();
splbreaknum = 100;
- if (cur_generation != xsoftc.generation)
+ if (cur_generation != xsoftc.xpt_generation)
goto ptstartover;
}
}
@@ -1402,11 +1383,16 @@ ptstartover:
static int
cam_module_event_handler(module_t mod, int what, void *arg)
{
- if (what == MOD_LOAD) {
- xpt_init(NULL);
- } else if (what == MOD_UNLOAD) {
+ int error;
+
+ switch (what) {
+ case MOD_LOAD:
+ if ((error = xpt_init(NULL)) != 0)
+ return (error);
+ break;
+ case MOD_UNLOAD:
return EBUSY;
- } else {
+ default:
return EOPNOTSUPP;
}
@@ -1414,22 +1400,40 @@ cam_module_event_handler(module_t mod, int what, void *arg)
}
/* thread to handle bus rescans */
-static TAILQ_HEAD(, ccb_hdr) ccb_scanq;
static void
xpt_scanner_thread(void *dummy)
{
- mtx_lock(&Giant);
+ cam_isrq_t queue;
+ union ccb *ccb;
+ struct cam_sim *sim;
+
for (;;) {
- union ccb *ccb;
- tsleep(&ccb_scanq, PRIBIO, "ccb_scanq", 0);
- while ((ccb = (union ccb *)TAILQ_FIRST(&ccb_scanq)) != NULL) {
- TAILQ_REMOVE(&ccb_scanq, &ccb->ccb_h, sim_links.tqe);
+ /*
+ * Wait for a rescan request to come in. When it does, splice
+ * it onto a queue from local storage so that the xpt lock
+ * doesn't need to be held while the requests are being
+ * processed.
+ */
+ xpt_lock_buses();
+ msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO,
+ "ccb_scanq", 0);
+ TAILQ_INIT(&queue);
+ TAILQ_CONCAT(&queue, &xsoftc.ccb_scanq, sim_links.tqe);
+ xpt_unlock_buses();
+
+ while ((ccb = (union ccb *)TAILQ_FIRST(&queue)) != NULL) {
+ TAILQ_REMOVE(&queue, &ccb->ccb_h, sim_links.tqe);
+
+ sim = ccb->ccb_h.path->bus->sim;
+ mtx_lock(sim->mtx);
+
ccb->ccb_h.func_code = XPT_SCAN_BUS;
ccb->ccb_h.cbfcnp = xptdone;
xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5);
cam_periph_runccb(ccb, NULL, 0, 0, NULL);
xpt_free_path(ccb->ccb_h.path);
xpt_free_ccb(ccb);
+ mtx_unlock(sim->mtx);
}
}
}
@@ -1438,24 +1442,27 @@ void
xpt_rescan(union ccb *ccb)
{
struct ccb_hdr *hdr;
- GIANT_REQUIRED;
+
/*
* Don't make duplicate entries for the same paths.
*/
- TAILQ_FOREACH(hdr, &ccb_scanq, sim_links.tqe) {
+ xpt_lock_buses();
+ TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) {
if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) {
+ xpt_unlock_buses();
xpt_print(ccb->ccb_h.path, "rescan already queued\n");
xpt_free_path(ccb->ccb_h.path);
xpt_free_ccb(ccb);
return;
}
}
- TAILQ_INSERT_TAIL(&ccb_scanq, &ccb->ccb_h, sim_links.tqe);
- wakeup(&ccb_scanq);
+ TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe);
+ wakeup(&xsoftc.ccb_scanq);
+ xpt_unlock_buses();
}
/* Functions accessed by the peripheral drivers */
-static void
+static int
xpt_init(void *dummy)
{
struct cam_sim *xpt_sim;
@@ -1463,13 +1470,15 @@ xpt_init(void *dummy)
struct cam_devq *devq;
cam_status status;
- TAILQ_INIT(&xpt_busses);
+ TAILQ_INIT(&xsoftc.xpt_busses);
TAILQ_INIT(&cam_bioq);
- SLIST_INIT(&ccb_freeq);
- TAILQ_INIT(&ccb_scanq);
- STAILQ_INIT(&highpowerq);
+ TAILQ_INIT(&xsoftc.ccb_scanq);
+ STAILQ_INIT(&xsoftc.highpowerq);
+ xsoftc.num_highpower = CAM_MAX_HIGHPOWER;
mtx_init(&cam_bioq_lock, "CAM BIOQ lock", NULL, MTX_DEF);
+ mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF);
+ mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF);
/*
* The xpt layer is, itself, the equivelent of a SIM.
@@ -1483,15 +1492,20 @@ xpt_init(void *dummy)
"xpt",
/*softc*/NULL,
/*unit*/0,
+ /*mtx*/&xsoftc.xpt_lock,
/*max_dev_transactions*/0,
/*max_tagged_dev_transactions*/0,
devq);
- xpt_max_ccbs = 16;
-
+ if (xpt_sim == NULL)
+ return (ENOMEM);
+
+ xpt_sim->max_ccbs = 16;
+
+ mtx_lock(&xsoftc.xpt_lock);
if ((status = xpt_bus_register(xpt_sim, /*bus #*/0)) != CAM_SUCCESS) {
printf("xpt_init: xpt_bus_register failed with status %#x,"
" failing attach\n", status);
- return;
+ return (EINVAL);
}
/*
@@ -1504,30 +1518,29 @@ xpt_init(void *dummy)
CAM_LUN_WILDCARD)) != CAM_REQ_CMP) {
printf("xpt_init: xpt_create_path failed with status %#x,"
" failing attach\n", status);
- return;
+ return (EINVAL);
}
cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO,
- path, NULL, 0, NULL);
+ path, NULL, 0, xpt_sim);
xpt_free_path(path);
-
- xpt_sim->softc = xpt_periph;
+ mtx_unlock(&xsoftc.xpt_lock);
/*
* Register a callback for when interrupts are enabled.
*/
- xpt_config_hook =
+ xsoftc.xpt_config_hook =
(struct intr_config_hook *)malloc(sizeof(struct intr_config_hook),
M_TEMP, M_NOWAIT | M_ZERO);
- if (xpt_config_hook == NULL) {
+ if (xsoftc.xpt_config_hook == NULL) {
printf("xpt_init: Cannot malloc config hook "
"- failing attach\n");
- return;
+ return (ENOMEM);
}
- xpt_config_hook->ich_func = xpt_config;
- if (config_intrhook_establish(xpt_config_hook) != 0) {
- free (xpt_config_hook, M_TEMP);
+ xsoftc.xpt_config_hook->ich_func = xpt_config;
+ if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) {
+ free (xsoftc.xpt_config_hook, M_TEMP);
printf("xpt_init: config_intrhook_establish failed "
"- failing attach\n");
}
@@ -1537,20 +1550,25 @@ xpt_init(void *dummy)
printf("xpt_init: failed to create rescan thread\n");
}
/* Install our software interrupt handlers */
- swi_add(NULL, "cambio", camisr, &cam_bioq, SWI_CAMBIO, 0, &cambio_ih);
+ swi_add(NULL, "cambio", camisr, &cam_bioq, SWI_CAMBIO, INTR_MPSAFE, &cambio_ih);
+
+ return (0);
}
static cam_status
xptregister(struct cam_periph *periph, void *arg)
{
+ struct cam_sim *xpt_sim;
+
if (periph == NULL) {
printf("xptregister: periph was NULL!!\n");
return(CAM_REQ_CMP_ERR);
}
- periph->softc = NULL;
-
+ xpt_sim = (struct cam_sim *)arg;
+ xpt_sim->softc = periph;
xpt_periph = periph;
+ periph->softc = NULL;
return(CAM_REQ_CMP);
}
@@ -1562,7 +1580,7 @@ xpt_add_periph(struct cam_periph *periph)
int32_t status;
struct periph_list *periph_head;
- GIANT_REQUIRED;
+ mtx_assert(periph->sim->mtx, MA_OWNED);
device = periph->path->device;
@@ -1589,7 +1607,7 @@ xpt_add_periph(struct cam_periph *periph)
splx(s);
}
- xsoftc.generation++;
+ atomic_add_int(&xsoftc.xpt_generation, 1);
return (status);
}
@@ -1599,7 +1617,7 @@ xpt_remove_periph(struct cam_periph *periph)
{
struct cam_ed *device;
- GIANT_REQUIRED;
+ mtx_assert(periph->sim->mtx, MA_OWNED);
device = periph->path->device;
@@ -1620,7 +1638,7 @@ xpt_remove_periph(struct cam_periph *periph)
splx(s);
}
- xsoftc.generation++;
+ atomic_add_int(&xsoftc.xpt_generation, 1);
}
@@ -1636,7 +1654,7 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string)
u_int mb;
int s;
- GIANT_REQUIRED;
+ mtx_assert(periph->sim->mtx, MA_OWNED);
path = periph->path;
/*
@@ -2147,7 +2165,7 @@ xptedtbusfunc(struct cam_eb *bus, void *arg)
cdm->pos.cookie.bus = bus;
cdm->pos.generations[CAM_BUS_GENERATION]=
- bus_generation;
+ xsoftc.bus_generation;
cdm->status = CAM_DEV_MATCH_MORE;
return(0);
}
@@ -2279,7 +2297,7 @@ xptedtdevicefunc(struct cam_ed *device, void *arg)
cdm->pos.cookie.bus = device->target->bus;
cdm->pos.generations[CAM_BUS_GENERATION]=
- bus_generation;
+ xsoftc.bus_generation;
cdm->pos.cookie.target = device->target;
cdm->pos.generations[CAM_TARGET_GENERATION] =
device->target->bus->generation;
@@ -2389,7 +2407,7 @@ xptedtperiphfunc(struct cam_periph *periph, void *arg)
cdm->pos.cookie.bus = periph->path->bus;
cdm->pos.generations[CAM_BUS_GENERATION]=
- bus_generation;
+ xsoftc.bus_generation;
cdm->pos.cookie.target = periph->path->target;
cdm->pos.generations[CAM_TARGET_GENERATION] =
periph->path->bus->generation;
@@ -2434,7 +2452,7 @@ xptedtmatch(struct ccb_dev_match *cdm)
*/
if ((cdm->pos.position_type & CAM_DEV_POS_BUS)
&& (cdm->pos.generations[CAM_BUS_GENERATION] != 0)
- && (cdm->pos.generations[CAM_BUS_GENERATION] != bus_generation)) {
+ && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) {
cdm->status = CAM_DEV_MATCH_LIST_CHANGED;
return(0);
}
@@ -2633,15 +2651,21 @@ xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg)
retval = 1;
- for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xpt_busses));
+ mtx_lock(&xsoftc.xpt_topo_lock);
+ for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xsoftc.xpt_busses));
bus != NULL;
bus = next_bus) {
next_bus = TAILQ_NEXT(bus, links);
+ mtx_unlock(&xsoftc.xpt_topo_lock);
+ mtx_lock(bus->sim->mtx);
retval = tr_func(bus, arg);
+ mtx_unlock(bus->sim->mtx);
if (retval == 0)
return(retval);
+ mtx_lock(&xsoftc.xpt_topo_lock);
}
+ mtx_unlock(&xsoftc.xpt_topo_lock);
return(retval);
}
@@ -2852,23 +2876,6 @@ xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg)
return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
}
-#ifdef notusedyet
-/*
- * Execute the given function for every target in the EDT.
- */
-static int
-xpt_for_all_targets(xpt_targetfunc_t *tr_func, void *arg)
-{
- struct xpt_traverse_config tr_config;
-
- tr_config.depth = XPT_DEPTH_TARGET;
- tr_config.tr_func = tr_func;
- tr_config.tr_arg = arg;
-
- return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
-}
-#endif /* notusedyet */
-
/*
* Execute the given function for every device in the EDT.
*/
@@ -2884,23 +2891,6 @@ xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg)
return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
}
-#ifdef notusedyet
-/*
- * Execute the given function for every peripheral in the EDT.
- */
-static int
-xpt_for_all_periphs(xpt_periphfunc_t *tr_func, void *arg)
-{
- struct xpt_traverse_config tr_config;
-
- tr_config.depth = XPT_DEPTH_PERIPH;
- tr_config.tr_func = tr_func;
- tr_config.tr_arg = arg;
-
- return(xptbustraverse(NULL, xptdefbusfunc, &tr_config));
-}
-#endif /* notusedyet */
-
static int
xptsetasyncfunc(struct cam_ed *device, void *arg)
{
@@ -2959,13 +2949,93 @@ xptsetasyncbusfunc(struct cam_eb *bus, void *arg)
return(1);
}
+static void
+xpt_action_sasync_cb(void *context, int pending)
+{
+ union ccb *start_ccb;
+ struct xpt_task *task;
+ struct ccb_setasync *csa;
+ struct async_node *cur_entry;
+ struct async_list *async_head;
+ u_int32_t added;
+ int s;
+
+ task = (struct xpt_task *)context;
+ start_ccb = (union ccb *)task->data;
+ csa = &start_ccb->csa;
+ added = csa->event_enable;
+ async_head = &csa->ccb_h.path->device->asyncs;
+
+ /*
+ * If there is already an entry for us, simply
+ * update it.
+ */
+ s = splcam();
+ mtx_lock(csa->ccb_h.path->bus->sim->mtx);
+ cur_entry = SLIST_FIRST(async_head);
+ while (cur_entry != NULL) {
+ if ((cur_entry->callback_arg == csa->callback_arg)
+ && (cur_entry->callback == csa->callback))
+ break;
+ cur_entry = SLIST_NEXT(cur_entry, links);
+ }
+
+ if (cur_entry != NULL) {
+ /*
+ * If the request has no flags set,
+ * remove the entry.
+ */
+ added &= ~cur_entry->event_enable;
+ if (csa->event_enable == 0) {
+ SLIST_REMOVE(async_head, cur_entry,
+ async_node, links);
+ csa->ccb_h.path->device->refcount--;
+ free(cur_entry, M_CAMXPT);
+ } else {
+ cur_entry->event_enable = csa->event_enable;
+ }
+ } else {
+ cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT,
+ M_NOWAIT);
+ if (cur_entry == NULL) {
+ splx(s);
+ goto out;
+ }
+ cur_entry->event_enable = csa->event_enable;
+ cur_entry->callback_arg = csa->callback_arg;
+ cur_entry->callback = csa->callback;
+ SLIST_INSERT_HEAD(async_head, cur_entry, links);
+ csa->ccb_h.path->device->refcount++;
+ }
+ mtx_unlock(csa->ccb_h.path->bus->sim->mtx);
+
+ if ((added & AC_FOUND_DEVICE) != 0) {
+ /*
+ * Get this peripheral up to date with all
+ * the currently existing devices.
+ */
+ xpt_for_all_devices(xptsetasyncfunc, cur_entry);
+ }
+ if ((added & AC_PATH_REGISTERED) != 0) {
+ /*
+ * Get this peripheral up to date with all
+ * the currently existing busses.
+ */
+ xpt_for_all_busses(xptsetasyncbusfunc, cur_entry);
+ }
+ splx(s);
+
+out:
+ xpt_free_path(start_ccb->ccb_h.path);
+ xpt_free_ccb(start_ccb);
+ free(task, M_CAMXPT);
+}
+
void
xpt_action(union ccb *start_ccb)
{
int iopl;
- GIANT_REQUIRED;
-
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n"));
start_ccb->ccb_h.status = CAM_REQ_INPROG;
@@ -3363,73 +3433,42 @@ xpt_action(union ccb *start_ccb)
}
case XPT_SASYNC_CB:
{
- struct ccb_setasync *csa;
- struct async_node *cur_entry;
- struct async_list *async_head;
- u_int32_t added;
- int s;
-
- csa = &start_ccb->csa;
- added = csa->event_enable;
- async_head = &csa->ccb_h.path->device->asyncs;
+ union ccb *task_ccb;
+ struct xpt_task *task;
/*
- * If there is already an entry for us, simply
- * update it.
+ * Need to decouple this operation via a taqskqueue so that
+ * the locking doesn't become a mess. Clone the ccb so that
+ * we own the memory and can free it later.
*/
- s = splcam();
- cur_entry = SLIST_FIRST(async_head);
- while (cur_entry != NULL) {
- if ((cur_entry->callback_arg == csa->callback_arg)
- && (cur_entry->callback == csa->callback))
- break;
- cur_entry = SLIST_NEXT(cur_entry, links);
+ task_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
+ if (task_ccb == NULL) {
+ start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ break;
}
-
- if (cur_entry != NULL) {
- /*
- * If the request has no flags set,
- * remove the entry.
- */
- added &= ~cur_entry->event_enable;
- if (csa->event_enable == 0) {
- SLIST_REMOVE(async_head, cur_entry,
- async_node, links);
- csa->ccb_h.path->device->refcount--;
- free(cur_entry, M_CAMXPT);
- } else {
- cur_entry->event_enable = csa->event_enable;
- }
- } else {
- cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT,
- M_NOWAIT);
- if (cur_entry == NULL) {
- splx(s);
- csa->ccb_h.status = CAM_RESRC_UNAVAIL;
- break;
- }
- cur_entry->event_enable = csa->event_enable;
- cur_entry->callback_arg = csa->callback_arg;
- cur_entry->callback = csa->callback;
- SLIST_INSERT_HEAD(async_head, cur_entry, links);
- csa->ccb_h.path->device->refcount++;
+ bcopy(start_ccb, task_ccb, sizeof(union ccb));
+ if (xpt_create_path(&task_ccb->ccb_h.path, NULL,
+ start_ccb->ccb_h.path_id,
+ start_ccb->ccb_h.target_id,
+ start_ccb->ccb_h.target_lun) !=
+ CAM_REQ_CMP) {
+ start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_free_ccb(task_ccb);
+ break;
}
- if ((added & AC_FOUND_DEVICE) != 0) {
- /*
- * Get this peripheral up to date with all
- * the currently existing devices.
- */
- xpt_for_all_devices(xptsetasyncfunc, cur_entry);
- }
- if ((added & AC_PATH_REGISTERED) != 0) {
- /*
- * Get this peripheral up to date with all
- * the currently existing busses.
- */
- xpt_for_all_busses(xptsetasyncbusfunc, cur_entry);
+ task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT);
+ if (task == NULL) {
+ start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+ xpt_free_path(task_ccb->ccb_h.path);
+ xpt_free_ccb(task_ccb);
+ break;
}
- splx(s);
+
+ TASK_INIT(&task->task, 0, xpt_action_sasync_cb, task);
+ task->data = task_ccb;
+ taskqueue_enqueue(taskqueue_thread, &task->task);
+
start_ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
@@ -3476,17 +3515,15 @@ xpt_action(union ccb *start_ccb)
* is sufficient for releasing the queue.
*/
start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE;
- untimeout(xpt_release_devq_timeout,
- dev, dev->c_handle);
+ callout_stop(&dev->callout);
} else {
start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
}
- dev->c_handle =
- timeout(xpt_release_devq_timeout,
- dev,
- (crs->release_timeout * hz) / 1000);
+ callout_reset(&dev->callout,
+ (crs->release_timeout * hz) / 1000,
+ xpt_release_devq_timeout, dev);
dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING;
@@ -3601,13 +3638,13 @@ xpt_polled_action(union ccb *start_ccb)
struct cam_devq *devq;
struct cam_ed *dev;
- GIANT_REQUIRED;
timeout = start_ccb->ccb_h.timeout;
sim = start_ccb->ccb_h.path->bus->sim;
devq = sim->devq;
dev = start_ccb->ccb_h.path->device;
+ mtx_assert(sim->mtx, MA_OWNED);
s = splcam();
/*
@@ -3664,7 +3701,7 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority)
int s;
int runq;
- GIANT_REQUIRED;
+ mtx_assert(perph->sim->mtx, MA_OWNED);
CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n"));
device = perph->path->device;
@@ -3885,7 +3922,8 @@ xpt_run_dev_sendq(struct cam_eb *bus)
if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) {
- if (num_highpower <= 0) {
+ mtx_lock(&xsoftc.xpt_lock);
+ if (xsoftc.num_highpower <= 0) {
/*
* We got a high power command, but we
* don't have any available slots. Freeze
@@ -3893,7 +3931,7 @@ xpt_run_dev_sendq(struct cam_eb *bus)
* available.
*/
device->qfrozen_cnt++;
- STAILQ_INSERT_TAIL(&highpowerq,
+ STAILQ_INSERT_TAIL(&xsoftc.highpowerq,
&work_ccb->ccb_h,
xpt_links.stqe);
@@ -3904,8 +3942,9 @@ xpt_run_dev_sendq(struct cam_eb *bus)
* Consume a high power slot while
* this ccb runs.
*/
- num_highpower--;
+ xsoftc.num_highpower--;
}
+ mtx_unlock(&xsoftc.xpt_lock);
}
devq->active_dev = device;
cam_ccbq_remove_ccb(&device->ccbq, work_ccb);
@@ -3972,7 +4011,6 @@ xpt_run_dev_sendq(struct cam_eb *bus)
void
xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb)
{
- GIANT_REQUIRED;
/*
* Pull fields that are valid for peripheral drivers to set
@@ -3989,7 +4027,6 @@ xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb)
void
xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority)
{
- GIANT_REQUIRED;
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n"));
ccb_h->pinfo.priority = priority;
@@ -4017,8 +4054,6 @@ xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph,
struct cam_path *path;
cam_status status;
- GIANT_REQUIRED;
-
path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_NOWAIT);
if (path == NULL) {
@@ -4034,6 +4069,36 @@ xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph,
return (status);
}
+cam_status
+xpt_create_path_unlocked(struct cam_path **new_path_ptr,
+ struct cam_periph *periph, path_id_t path_id,
+ target_id_t target_id, lun_id_t lun_id)
+{
+ struct cam_path *path;
+ struct cam_eb *bus = NULL;
+ cam_status status;
+ int need_unlock = 0;
+
+ path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_WAITOK);
+
+ if (path_id != CAM_BUS_WILDCARD) {
+ bus = xpt_find_bus(path_id);
+ if (bus != NULL) {
+ need_unlock = 1;
+ mtx_lock(bus->sim->mtx);
+ }
+ }
+ status = xpt_compile_path(path, periph, path_id, target_id, lun_id);
+ if (need_unlock)
+ mtx_unlock(bus->sim->mtx);
+ if (status != CAM_REQ_CMP) {
+ free(path, M_CAMXPT);
+ path = NULL;
+ }
+ *new_path_ptr = path;
+ return (status);
+}
+
static cam_status
xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph,
path_id_t path_id, target_id_t target_id, lun_id_t lun_id)
@@ -4129,7 +4194,6 @@ xpt_release_path(struct cam_path *path)
void
xpt_free_path(struct cam_path *path)
{
- GIANT_REQUIRED;
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n"));
xpt_release_path(path);
@@ -4144,8 +4208,6 @@ xpt_free_path(struct cam_path *path)
int
xpt_path_comp(struct cam_path *path1, struct cam_path *path2)
{
- GIANT_REQUIRED;
-
int retval = 0;
if (path1->bus != path2->bus) {
@@ -4180,7 +4242,7 @@ xpt_path_comp(struct cam_path *path1, struct cam_path *path2)
void
xpt_print_path(struct cam_path *path)
{
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
if (path == NULL)
printf("(nopath): ");
@@ -4225,7 +4287,7 @@ xpt_path_string(struct cam_path *path, char *str, size_t str_len)
{
struct sbuf sb;
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
sbuf_new(&sb, str, str_len, 0);
@@ -4263,7 +4325,7 @@ xpt_path_string(struct cam_path *path, char *str, size_t str_len)
path_id_t
xpt_path_path_id(struct cam_path *path)
{
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
return(path->bus->path_id);
}
@@ -4271,7 +4333,7 @@ xpt_path_path_id(struct cam_path *path)
target_id_t
xpt_path_target_id(struct cam_path *path)
{
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
if (path->target != NULL)
return (path->target->target_id);
@@ -4282,7 +4344,7 @@ xpt_path_target_id(struct cam_path *path)
lun_id_t
xpt_path_lun_id(struct cam_path *path)
{
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
if (path->device != NULL)
return (path->device->lun_id);
@@ -4293,7 +4355,6 @@ xpt_path_lun_id(struct cam_path *path)
struct cam_sim *
xpt_path_sim(struct cam_path *path)
{
- GIANT_REQUIRED;
return (path->bus->sim);
}
@@ -4301,7 +4362,7 @@ xpt_path_sim(struct cam_path *path)
struct cam_periph*
xpt_path_periph(struct cam_path *path)
{
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
return (path->periph);
}
@@ -4319,34 +4380,38 @@ xpt_release_ccb(union ccb *free_ccb)
struct cam_path *path;
struct cam_ed *device;
struct cam_eb *bus;
-
- GIANT_REQUIRED;
+ struct cam_sim *sim;
CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n"));
path = free_ccb->ccb_h.path;
device = path->device;
bus = path->bus;
+ sim = bus->sim;
s = splsoftcam();
+
+ mtx_assert(sim->mtx, MA_OWNED);
+
cam_ccbq_release_opening(&device->ccbq);
- if (xpt_ccb_count > xpt_max_ccbs) {
+ if (sim->ccb_count > sim->max_ccbs) {
xpt_free_ccb(free_ccb);
- xpt_ccb_count--;
+ sim->ccb_count--;
} else {
- SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle);
+ SLIST_INSERT_HEAD(&sim->ccb_freeq, &free_ccb->ccb_h,
+ xpt_links.sle);
}
- if (bus->sim->devq == NULL) {
+ if (sim->devq == NULL) {
splx(s);
return;
}
- bus->sim->devq->alloc_openings++;
- bus->sim->devq->alloc_active--;
+ sim->devq->alloc_openings++;
+ sim->devq->alloc_active--;
/* XXX Turn this into an inline function - xpt_run_device?? */
if ((device_is_alloc_queued(device) == 0)
&& (device->drvq.entries > 0)) {
xpt_schedule_dev_allocq(bus, device);
}
splx(s);
- if (dev_allocq_is_runnable(bus->sim->devq))
+ if (dev_allocq_is_runnable(sim->devq))
xpt_run_dev_allocq(bus);
}
@@ -4369,7 +4434,7 @@ xpt_bus_register(struct cam_sim *sim, u_int32_t bus)
struct ccb_pathinq cpi;
int s;
- GIANT_REQUIRED;
+ mtx_assert(sim->mtx, MA_OWNED);
sim->bus_id = bus;
new_bus = (struct cam_eb *)malloc(sizeof(*new_bus),
@@ -4393,15 +4458,17 @@ xpt_bus_register(struct cam_sim *sim, u_int32_t bus)
new_bus->refcount = 1; /* Held until a bus_deregister event */
new_bus->generation = 0;
s = splcam();
- old_bus = TAILQ_FIRST(&xpt_busses);
+ mtx_lock(&xsoftc.xpt_topo_lock);
+ old_bus = TAILQ_FIRST(&xsoftc.xpt_busses);
while (old_bus != NULL
&& old_bus->path_id < new_bus->path_id)
old_bus = TAILQ_NEXT(old_bus, links);
if (old_bus != NULL)
TAILQ_INSERT_BEFORE(old_bus, new_bus, links);
else
- TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links);
- bus_generation++;
+ TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links);
+ xsoftc.bus_generation++;
+ mtx_unlock(&xsoftc.xpt_topo_lock);
splx(s);
/* Notify interested parties */
@@ -4431,7 +4498,6 @@ xpt_bus_deregister(path_id_t pathid)
union ccb *work_ccb;
cam_status status;
- GIANT_REQUIRED;
status = xpt_compile_path(&bus_path, NULL, pathid,
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
@@ -4496,7 +4562,8 @@ xptnextfreepathid(void)
const char *strval;
pathid = 0;
- bus = TAILQ_FIRST(&xpt_busses);
+ mtx_lock(&xsoftc.xpt_topo_lock);
+ bus = TAILQ_FIRST(&xsoftc.xpt_busses);
retry:
/* Find an unoccupied pathid */
while (bus != NULL && bus->path_id <= pathid) {
@@ -4504,6 +4571,7 @@ retry:
pathid++;
bus = TAILQ_NEXT(bus, links);
}
+ mtx_unlock(&xsoftc.xpt_topo_lock);
/*
* Ensure that this pathid is not reserved for
@@ -4512,6 +4580,7 @@ retry:
if (resource_string_value("scbus", pathid, "at", &strval) == 0) {
++pathid;
/* Start the search over */
+ mtx_lock(&xsoftc.xpt_topo_lock);
goto retry;
}
return (pathid);
@@ -4568,7 +4637,7 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg)
struct cam_ed *device, *next_device;
int s;
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n"));
@@ -4735,7 +4804,7 @@ xpt_freeze_devq(struct cam_path *path, u_int count)
int s;
struct ccb_hdr *ccbh;
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
s = splcam();
path->device->qfrozen_cnt += count;
@@ -4763,7 +4832,7 @@ xpt_freeze_devq(struct cam_path *path, u_int count)
u_int32_t
xpt_freeze_simq(struct cam_sim *sim, u_int count)
{
- GIANT_REQUIRED;
+ mtx_assert(sim->mtx, MA_OWNED);
sim->devq->send_queue.qfrozen_cnt += count;
if (sim->devq->active_dev != NULL) {
@@ -4790,7 +4859,7 @@ xpt_release_devq_timeout(void *arg)
void
xpt_release_devq(struct cam_path *path, u_int count, int run_queue)
{
- GIANT_REQUIRED;
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
xpt_release_devq_device(path->device, count, run_queue);
}
@@ -4821,8 +4890,7 @@ xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue)
* to release this queue.
*/
if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) {
- untimeout(xpt_release_devq_timeout, dev,
- dev->c_handle);
+ callout_stop(&dev->callout);
dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING;
}
@@ -4850,7 +4918,7 @@ xpt_release_simq(struct cam_sim *sim, int run_queue)
int s;
struct camq *sendq;
- GIANT_REQUIRED;
+ mtx_assert(sim->mtx, MA_OWNED);
sendq = &(sim->devq->send_queue);
s = splcam();
@@ -4866,8 +4934,7 @@ xpt_release_simq(struct cam_sim *sim, int run_queue)
* already at 0.
*/
if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){
- untimeout(xpt_release_simq_timeout, sim,
- sim->c_handle);
+ callout_stop(&sim->callout);
sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING;
}
bus = xpt_find_bus(sim->path_id);
@@ -4886,6 +4953,9 @@ xpt_release_simq(struct cam_sim *sim, int run_queue)
splx(s);
}
+/*
+ * XXX Appears to be unused.
+ */
static void
xpt_release_simq_timeout(void *arg)
{
@@ -4915,7 +4985,9 @@ xpt_done(union ccb *done_ccb)
sim_links.tqe);
done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX;
mtx_unlock(&cam_bioq_lock);
- swi_sched(cambio_ih, 0);
+ if ((done_ccb->ccb_h.path->periph->flags &
+ CAM_PERIPH_POLLED) == 0)
+ swi_sched(cambio_ih, 0);
break;
default:
panic("unknown periph type %d",
@@ -4926,24 +4998,26 @@ xpt_done(union ccb *done_ccb)
}
union ccb *
-xpt_alloc_ccb()
+xpt_alloc_ccb(struct cam_sim *sim)
{
union ccb *new_ccb;
- GIANT_REQUIRED;
-
new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_WAITOK);
+ if ((sim != NULL) && ((sim->flags & CAM_SIM_MPSAFE) == 0)) {
+ callout_handle_init(&new_ccb->ccb_h.timeout_ch);
+ }
return (new_ccb);
}
union ccb *
-xpt_alloc_ccb_nowait()
+xpt_alloc_ccb_nowait(struct cam_sim *sim)
{
union ccb *new_ccb;
- GIANT_REQUIRED;
-
new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_NOWAIT);
+ if ((sim != NULL) && ((sim->flags & CAM_SIM_MPSAFE) == 0)) {
+ callout_handle_init(&new_ccb->ccb_h.timeout_ch);
+ }
return (new_ccb);
}
@@ -4968,22 +5042,23 @@ static union ccb *
xpt_get_ccb(struct cam_ed *device)
{
union ccb *new_ccb;
+ struct cam_sim *sim;
int s;
s = splsoftcam();
- if ((new_ccb = (union ccb *)SLIST_FIRST(&ccb_freeq)) == NULL) {
- new_ccb = xpt_alloc_ccb_nowait();
+ sim = device->sim;
+ if ((new_ccb = (union ccb *)SLIST_FIRST(&sim->ccb_freeq)) == NULL) {
+ new_ccb = xpt_alloc_ccb_nowait(sim);
if (new_ccb == NULL) {
splx(s);
return (NULL);
}
- callout_handle_init(&new_ccb->ccb_h.timeout_ch);
- SLIST_INSERT_HEAD(&ccb_freeq, &new_ccb->ccb_h,
+ SLIST_INSERT_HEAD(&sim->ccb_freeq, &new_ccb->ccb_h,
xpt_links.sle);
- xpt_ccb_count++;
+ sim->ccb_count++;
}
cam_ccbq_take_opening(&device->ccbq);
- SLIST_REMOVE_HEAD(&ccb_freeq, xpt_links.sle);
+ SLIST_REMOVE_HEAD(&sim->ccb_freeq, xpt_links.sle);
splx(s);
return (new_ccb);
}
@@ -4996,8 +5071,10 @@ xpt_release_bus(struct cam_eb *bus)
s = splcam();
if ((--bus->refcount == 0)
&& (TAILQ_FIRST(&bus->et_entries) == NULL)) {
- TAILQ_REMOVE(&xpt_busses, bus, links);
- bus_generation++;
+ mtx_lock(&xsoftc.xpt_topo_lock);
+ TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links);
+ xsoftc.bus_generation++;
+ mtx_unlock(&xsoftc.xpt_topo_lock);
splx(s);
free(bus, M_CAMXPT);
} else
@@ -5088,6 +5165,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
device->send_ccb_entry.device = device;
device->target = target;
device->lun_id = lun_id;
+ device->sim = bus->sim;
/* Initialize our queues */
if (camq_init(&device->drvq, 0) != 0) {
free(device, M_CAMXPT);
@@ -5118,7 +5196,10 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
device->tag_delay_count = 0;
device->tag_saved_openings = 0;
device->refcount = 1;
- callout_handle_init(&device->c_handle);
+ if (bus->sim->flags & CAM_SIM_MPSAFE)
+ callout_init_mtx(&device->callout, bus->sim->mtx, 0);
+ else
+ callout_init_mtx(&device->callout, &Giant, 0);
/*
* Hold a reference to our parent target so it
@@ -5130,7 +5211,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
* XXX should be limited by number of CCBs this bus can
* do.
*/
- xpt_max_ccbs += device->ccbq.devq_openings;
+ bus->sim->max_ccbs += device->ccbq.devq_openings;
/* Insertion sort into our target's device list */
cur_device = TAILQ_FIRST(&target->ed_entries);
while (cur_device != NULL && cur_device->lun_id < lun_id)
@@ -5170,12 +5251,11 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target,
panic("Removing device while still queued for ccbs");
if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0)
- untimeout(xpt_release_devq_timeout, device,
- device->c_handle);
+ callout_stop(&device->callout);
TAILQ_REMOVE(&target->ed_entries, device,links);
target->generation++;
- xpt_max_ccbs -= device->ccbq.devq_openings;
+ bus->sim->max_ccbs -= device->ccbq.devq_openings;
if (!SIM_DEAD(bus->sim)) {
/* Release our slot in the devq */
devq = bus->sim->devq;
@@ -5210,7 +5290,7 @@ xpt_dev_ccbq_resize(struct cam_path *path, int newopenings)
|| (dev->inq_flags & SID_CmdQue) != 0)
dev->tag_saved_openings = newopenings;
/* Adjust the global limit */
- xpt_max_ccbs += diff;
+ dev->sim->max_ccbs += diff;
splx(s);
return (result);
}
@@ -5220,7 +5300,8 @@ xpt_find_bus(path_id_t path_id)
{
struct cam_eb *bus;
- for (bus = TAILQ_FIRST(&xpt_busses);
+ mtx_lock(&xsoftc.xpt_topo_lock);
+ for (bus = TAILQ_FIRST(&xsoftc.xpt_busses);
bus != NULL;
bus = TAILQ_NEXT(bus, links)) {
if (bus->path_id == path_id) {
@@ -5228,6 +5309,7 @@ xpt_find_bus(path_id_t path_id)
break;
}
}
+ mtx_unlock(&xsoftc.xpt_topo_lock);
return (bus);
}
@@ -5290,7 +5372,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
u_int initiator_id;
/* Find out the characteristics of the bus */
- work_ccb = xpt_alloc_ccb();
+ work_ccb = xpt_alloc_ccb_nowait(periph->sim);
xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
request_ccb->ccb_h.pinfo.priority);
work_ccb->ccb_h.func_code = XPT_PATH_INQ;
@@ -5315,7 +5397,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
/* Save some state for use while we probe for devices */
scan_info = (xpt_scan_bus_info *)
- malloc(sizeof(xpt_scan_bus_info), M_TEMP, M_WAITOK);
+ malloc(sizeof(xpt_scan_bus_info), M_TEMP, M_NOWAIT);
scan_info->request_ccb = request_ccb;
scan_info->cpi = &work_ccb->cpi;
@@ -5355,7 +5437,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
xpt_done(request_ccb);
break;
}
- work_ccb = xpt_alloc_ccb();
+ work_ccb = xpt_alloc_ccb_nowait(periph->sim);
xpt_setup_ccb(&work_ccb->ccb_h, path,
request_ccb->ccb_h.pinfo.priority);
work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
@@ -6870,6 +6952,9 @@ static int busses_to_reset;
static int
xptconfigbuscountfunc(struct cam_eb *bus, void *arg)
{
+
+ mtx_assert(bus->sim->mtx, MA_OWNED);
+
if (bus->path_id != CAM_XPT_PATH_ID) {
struct cam_path path;
struct ccb_pathinq cpi;
@@ -6898,11 +6983,13 @@ xptconfigfunc(struct cam_eb *bus, void *arg)
struct cam_path *path;
union ccb *work_ccb;
+ mtx_assert(bus->sim->mtx, MA_OWNED);
+
if (bus->path_id != CAM_XPT_PATH_ID) {
cam_status status;
int can_negotiate;
- work_ccb = xpt_alloc_ccb();
+ work_ccb = xpt_alloc_ccb_nowait(bus->sim);
if ((status = xpt_create_path(&path, xpt_periph, bus->path_id,
CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){
@@ -6962,6 +7049,11 @@ xpt_config(void *arg)
#endif /* CAM_DEBUG_FLAGS */
#ifdef CAM_DEBUG_BUS
if (cam_dflags != CAM_DEBUG_NONE) {
+ /*
+ * Locking is specifically omitted here. No SIMs have
+ * registered yet, so xpt_create_path will only be searching
+ * empty lists of targets and devices.
+ */
if (xpt_create_path(&cam_dpath, xpt_periph,
CAM_DEBUG_BUS, CAM_DEBUG_TARGET,
CAM_DEBUG_LUN) != CAM_REQ_CMP) {
@@ -7017,11 +7109,40 @@ xptpassannouncefunc(struct cam_ed *device, void *arg)
}
static void
-xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb)
+xpt_finishconfig_task(void *context, int pending)
{
struct periph_driver **p_drv;
int i;
+ if (busses_to_config == 0) {
+ /* Register all the peripheral drivers */
+ /* XXX This will have to change when we have loadable modules */
+ p_drv = periph_drivers;
+ for (i = 0; p_drv[i] != NULL; i++) {
+ (*p_drv[i]->init)();
+ }
+
+ /*
+ * Check for devices with no "standard" peripheral driver
+ * attached. For any devices like that, announce the
+ * passthrough driver so the user will see something.
+ */
+ xpt_for_all_devices(xptpassannouncefunc, NULL);
+
+ /* Release our hook so that the boot can continue. */
+ config_intrhook_disestablish(xsoftc.xpt_config_hook);
+ free(xsoftc.xpt_config_hook, M_TEMP);
+ xsoftc.xpt_config_hook = NULL;
+ }
+
+ free(context, M_CAMXPT);
+}
+
+static void
+xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb)
+{
+ struct xpt_task *task;
+
if (done_ccb != NULL) {
CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE,
("xpt_finishconfig\n"));
@@ -7043,26 +7164,12 @@ xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb)
}
}
- if (busses_to_config == 0) {
- /* Register all the peripheral drivers */
- /* XXX This will have to change when we have loadable modules */
- p_drv = periph_drivers;
- for (i = 0; p_drv[i] != NULL; i++) {
- (*p_drv[i]->init)();
- }
-
- /*
- * Check for devices with no "standard" peripheral driver
- * attached. For any devices like that, announce the
- * passthrough driver so the user will see something.
- */
- xpt_for_all_devices(xptpassannouncefunc, NULL);
-
- /* Release our hook so that the boot can continue. */
- config_intrhook_disestablish(xpt_config_hook);
- free(xpt_config_hook, M_TEMP);
- xpt_config_hook = NULL;
+ task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT);
+ if (task != NULL) {
+ TASK_INIT(&task->task, 0, xpt_finishconfig_task, task);
+ taskqueue_enqueue(taskqueue_thread, &task->task);
}
+
if (done_ccb != NULL)
xpt_free_ccb(done_ccb);
}
@@ -7117,6 +7224,18 @@ xptpoll(struct cam_sim *sim)
{
}
+void
+xpt_lock_buses(void)
+{
+ mtx_lock(&xsoftc.xpt_topo_lock);
+}
+
+void
+xpt_unlock_buses(void)
+{
+ mtx_unlock(&xsoftc.xpt_topo_lock);
+}
+
static void
camisr(void *V_queue)
{
@@ -7124,6 +7243,7 @@ camisr(void *V_queue)
cam_isrq_t queue;
int s;
struct ccb_hdr *ccb_h;
+ struct cam_sim *sim;
/*
* Transfer the ccb_bioq list to a temporary list so we can operate
@@ -7152,14 +7272,15 @@ camisr(void *V_queue)
struct highpowerlist *hphead;
union ccb *send_ccb;
- hphead = &highpowerq;
+ mtx_lock(&xsoftc.xpt_lock);
+ hphead = &xsoftc.highpowerq;
send_ccb = (union ccb *)STAILQ_FIRST(hphead);
/*
* Increment the count since this command is done.
*/
- num_highpower++;
+ xsoftc.num_highpower++;
/*
* Any high powered commands queued up?
@@ -7167,11 +7288,17 @@ camisr(void *V_queue)
if (send_ccb != NULL) {
STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe);
+ mtx_unlock(&xsoftc.xpt_lock);
xpt_release_devq(send_ccb->ccb_h.path,
/*count*/1, /*runqueue*/TRUE);
- }
+ } else
+ mtx_unlock(&xsoftc.xpt_lock);
}
+
+ sim = ccb_h->path->bus->sim;
+ mtx_lock(sim->mtx);
+
if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) {
struct cam_ed *dev;
@@ -7227,6 +7354,7 @@ camisr(void *V_queue)
(*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h);
/* Raise IPL for while test */
+ mtx_unlock(sim->mtx);
s = splcam();
}
splx(s);