1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-01 12:19:28 +00:00

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.
This commit is contained in:
Alexander Motin 2017-03-07 17:41:08 +00:00
parent 61471674c4
commit 94173c3c9b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=314870
3 changed files with 74 additions and 19 deletions

View File

@ -139,6 +139,38 @@ periphdriver_register(void *data)
(*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)
{

View File

@ -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 {

View File

@ -172,6 +172,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;
@ -200,7 +201,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 =
@ -212,14 +214,6 @@ static struct ctl_frontend ctlfe_frontend =
};
CTL_FRONTEND_DECLARE(ctlfe, ctlfe_frontend);
static int
ctlfeshutdown(void)
{
/* CAM does not support periph driver unregister now. */
return (EBUSY);
}
static int
ctlfeinitialize(void)
{
@ -230,6 +224,18 @@ ctlfeinitialize(void)
return (0);
}
static int
ctlfeshutdown(void)
{
int error;
error = periphdriver_unregister(&ctlfe_driver);
if (error != 0)
return (error);
mtx_destroy(&ctlfe_list_mtx);
return (0);
}
static void
ctlfeperiphinit(void)
{
@ -243,6 +249,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)
{