summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2007-02-23 05:47:36 +0000
committermjacob <mjacob@FreeBSD.org>2007-02-23 05:47:36 +0000
commit5688edd0032e2541fedeaa58a3f918aa0af73835 (patch)
tree50726cb63cfc4a82afc34c955a6de30d742f0611 /sys/cam
parent17f2e510e6ae66722eeb73d65b12574eca7a9f3c (diff)
downloadFreeBSD-src-5688edd0032e2541fedeaa58a3f918aa0af73835.zip
FreeBSD-src-5688edd0032e2541fedeaa58a3f918aa0af73835.tar.gz
Add an xpt_rescan function and a thread that will field
rescan requests. The purpose of this is to allow a SIM (or other entities) to request a bus rescan and have it then fielded in a different (process) context from the caller. There are probably better ways to accomplish this, but it's a very small change that helps solve a number of problems. Reviewed by: Justin, Ken and Scott. MFC after: 2 weeks
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_xpt.c53
-rw-r--r--sys/cam/cam_xpt.h1
2 files changed, 50 insertions, 4 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 2b1c8f4..ba6eefb 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/kthread.h>
#ifdef PC98
#include <pc98/pc98/pc98_machdep.h> /* geometry translation */
@@ -1412,10 +1413,50 @@ cam_module_event_handler(module_t mod, int what, void *arg)
return 0;
}
+/* thread to handle bus rescans */
+static TAILQ_HEAD(, ccb_hdr) ccb_scanq;
+static void
+xpt_scanner_thread(void *dummy)
+{
+ mtx_lock(&Giant);
+ 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);
+ 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);
+ }
+ }
+}
+
+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) {
+ if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) {
+ 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);
+}
+
/* Functions accessed by the peripheral drivers */
static void
-xpt_init(dummy)
- void *dummy;
+xpt_init(void *dummy)
{
struct cam_sim *xpt_sim;
struct cam_path *path;
@@ -1425,6 +1466,7 @@ xpt_init(dummy)
TAILQ_INIT(&xpt_busses);
TAILQ_INIT(&cam_bioq);
SLIST_INIT(&ccb_freeq);
+ TAILQ_INIT(&ccb_scanq);
STAILQ_INIT(&highpowerq);
mtx_init(&cam_bioq_lock, "CAM BIOQ lock", NULL, MTX_DEF);
@@ -1490,6 +1532,10 @@ xpt_init(dummy)
"- failing attach\n");
}
+ /* fire up rescan thread */
+ if (kthread_create(xpt_scanner_thread, NULL, NULL, 0, 0, "xpt_thrd")) {
+ 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);
}
@@ -4453,8 +4499,7 @@ xptnextfreepathid(void)
bus = TAILQ_FIRST(&xpt_busses);
retry:
/* Find an unoccupied pathid */
- while (bus != NULL
- && bus->path_id <= pathid) {
+ while (bus != NULL && bus->path_id <= pathid) {
if (bus->path_id == pathid)
pathid++;
bus = TAILQ_NEXT(bus, links);
diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h
index a84feae..f8557f9 100644
--- a/sys/cam/cam_xpt.h
+++ b/sys/cam/cam_xpt.h
@@ -72,6 +72,7 @@ struct cam_sim *xpt_path_sim(struct cam_path *path);
struct cam_periph *xpt_path_periph(struct cam_path *path);
void xpt_async(u_int32_t async_code, struct cam_path *path,
void *async_arg);
+void xpt_rescan(union ccb *ccb);
#endif /* _KERNEL */
#endif /* _CAM_CAM_XPT_H */
OpenPOWER on IntegriCloud