summaryrefslogtreecommitdiffstats
path: root/sys/cam/cam_xpt.c
diff options
context:
space:
mode:
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 c123b5c..d13209e 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);
OpenPOWER on IntegriCloud