diff options
author | mav <mav@FreeBSD.org> | 2017-03-29 15:25:34 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2017-03-29 15:25:34 +0000 |
commit | 33f724af2a41d2718665f79e6133da912144d740 (patch) | |
tree | f94f91a6efb6819a1df9dfa17bca41ec297ea004 /sys/cam | |
parent | 3a5e9f39444fa3592e2d25989db2813566141a24 (diff) | |
download | FreeBSD-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.c | 32 | ||||
-rw-r--r-- | sys/cam/cam_periph.h | 26 | ||||
-rw-r--r-- | sys/cam/ctl/scsi_ctl.c | 33 |
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) { |