summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2017-03-29 15:25:34 +0000
committermav <mav@FreeBSD.org>2017-03-29 15:25:34 +0000
commit33f724af2a41d2718665f79e6133da912144d740 (patch)
treef94f91a6efb6819a1df9dfa17bca41ec297ea004 /sys/cam
parent3a5e9f39444fa3592e2d25989db2813566141a24 (diff)
downloadFreeBSD-src-33f724af2a41d2718665f79e6133da912144d740.zip
FreeBSD-src-33f724af2a41d2718665f79e6133da912144d740.tar.gz
MFC r314870: Add mechanism to unload CAM periph drivers.
For now it allows to unload CTL kernel module if there are no target-capable SIMs in CAM. As next step full teardown of CAM targets can be implemented.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_periph.c32
-rw-r--r--sys/cam/cam_periph.h26
-rw-r--r--sys/cam/ctl/scsi_ctl.c33
3 files changed, 73 insertions, 18 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 78b5541..cd096a4 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -139,6 +139,38 @@ again:
(*drv->init)();
}
+int
+periphdriver_unregister(void *data)
+{
+ struct periph_driver *drv = (struct periph_driver *)data;
+ int error, n;
+
+ /* If driver marked as early or it is late now, deinitialize it. */
+ if (((drv->flags & CAM_PERIPH_DRV_EARLY) != 0 && initialized > 0) ||
+ initialized > 1) {
+ if (drv->deinit == NULL) {
+ printf("CAM periph driver '%s' doesn't have deinit.\n",
+ drv->driver_name);
+ return (EOPNOTSUPP);
+ }
+ error = drv->deinit();
+ if (error != 0)
+ return (error);
+ }
+
+ xpt_lock_buses();
+ for (n = 0; n < nperiph_drivers && periph_drivers[n] != drv; n++)
+ ;
+ KASSERT(n < nperiph_drivers,
+ ("Periph driver '%s' was not registered", drv->driver_name));
+ for (; n + 1 < nperiph_drivers; n++)
+ periph_drivers[n] = periph_drivers[n + 1];
+ periph_drivers[n + 1] = NULL;
+ nperiph_drivers--;
+ xpt_unlock_buses();
+ return (0);
+}
+
void
periphdriver_init(int level)
{
diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h
index d5a74a5..87f153c 100644
--- a/sys/cam/cam_periph.h
+++ b/sys/cam/cam_periph.h
@@ -45,6 +45,7 @@ extern struct cam_periph *xpt_periph;
extern struct periph_driver **periph_drivers;
void periphdriver_register(void *);
+int periphdriver_unregister(void *);
void periphdriver_init(int level);
#include <sys/module.h>
@@ -56,8 +57,7 @@ void periphdriver_init(int level);
periphdriver_register(data); \
break; \
case MOD_UNLOAD: \
- printf(#name " module unload - not possible for this module type\n"); \
- return EINVAL; \
+ return (periphdriver_unregister(data)); \
default: \
return EOPNOTSUPP; \
} \
@@ -71,20 +71,26 @@ void periphdriver_init(int level);
DECLARE_MODULE(name, name ## _mod, SI_SUB_DRIVERS, SI_ORDER_ANY); \
MODULE_DEPEND(name, cam, 1, 1, 1)
-typedef void (periph_init_t)(void); /*
- * Callback informing the peripheral driver
- * it can perform it's initialization since
- * the XPT is now fully initialized.
- */
-typedef periph_init_t *periph_init_func_t;
+/*
+ * Callback informing the peripheral driver it can perform it's
+ * initialization since the XPT is now fully initialized.
+ */
+typedef void (periph_init_t)(void);
+
+/*
+ * Callback requesting the peripheral driver to remove its instances
+ * and shutdown, if possible.
+ */
+typedef int (periph_deinit_t)(void);
struct periph_driver {
- periph_init_func_t init;
- char *driver_name;
+ periph_init_t *init;
+ char *driver_name;
TAILQ_HEAD(,cam_periph) units;
u_int generation;
u_int flags;
#define CAM_PERIPH_DRV_EARLY 0x01
+ periph_deinit_t *deinit;
};
typedef enum {
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c
index 95d4c7c..8400af2 100644
--- a/sys/cam/ctl/scsi_ctl.c
+++ b/sys/cam/ctl/scsi_ctl.c
@@ -174,6 +174,7 @@ MALLOC_DEFINE(M_CTLFE, "CAM CTL FE", "CAM CTL FE interface");
static int ctlfeinitialize(void);
static int ctlfeshutdown(void);
static periph_init_t ctlfeperiphinit;
+static periph_deinit_t ctlfeperiphdeinit;
static void ctlfeasync(void *callback_arg, uint32_t code,
struct cam_path *path, void *arg);
static periph_ctor_t ctlferegister;
@@ -202,7 +203,8 @@ static struct periph_driver ctlfe_driver =
{
ctlfeperiphinit, "ctl",
TAILQ_HEAD_INITIALIZER(ctlfe_driver.units), /*generation*/ 0,
- CAM_PERIPH_DRV_EARLY
+ CAM_PERIPH_DRV_EARLY,
+ ctlfeperiphdeinit
};
static struct ctl_frontend ctlfe_frontend =
@@ -215,20 +217,24 @@ static struct ctl_frontend ctlfe_frontend =
CTL_FRONTEND_DECLARE(ctlfe, ctlfe_frontend);
static int
-ctlfeshutdown(void)
+ctlfeinitialize(void)
{
- /* CAM does not support periph driver unregister now. */
- return (EBUSY);
+ STAILQ_INIT(&ctlfe_softc_list);
+ mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF);
+ periphdriver_register(&ctlfe_driver);
+ return (0);
}
static int
-ctlfeinitialize(void)
+ctlfeshutdown(void)
{
+ int error;
- STAILQ_INIT(&ctlfe_softc_list);
- mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF);
- periphdriver_register(&ctlfe_driver);
+ error = periphdriver_unregister(&ctlfe_driver);
+ if (error != 0)
+ return (error);
+ mtx_destroy(&ctlfe_list_mtx);
return (0);
}
@@ -245,6 +251,17 @@ ctlfeperiphinit(void)
}
}
+static int
+ctlfeperiphdeinit(void)
+{
+
+ /* XXX: It would be good to tear down active ports here. */
+ if (!TAILQ_EMPTY(&ctlfe_driver.units))
+ return (EBUSY);
+ xpt_register_async(0, ctlfeasync, NULL, NULL);
+ return (0);
+}
+
static void
ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
{
OpenPOWER on IntegriCloud