Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Mar 2017 17:41:08 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314870 - in head/sys/cam: . ctl
Message-ID:  <201703071741.v27Hf8LD073505@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Tue Mar  7 17:41:08 2017
New Revision: 314870
URL: https://svnweb.freebsd.org/changeset/base/314870

Log:
  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.

Modified:
  head/sys/cam/cam_periph.c
  head/sys/cam/cam_periph.h
  head/sys/cam/ctl/scsi_ctl.c

Modified: head/sys/cam/cam_periph.c
==============================================================================
--- head/sys/cam/cam_periph.c	Tue Mar  7 17:38:52 2017	(r314869)
+++ head/sys/cam/cam_periph.c	Tue Mar  7 17:41:08 2017	(r314870)
@@ -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)
 {

Modified: head/sys/cam/cam_periph.h
==============================================================================
--- head/sys/cam/cam_periph.h	Tue Mar  7 17:38:52 2017	(r314869)
+++ head/sys/cam/cam_periph.h	Tue Mar  7 17:41:08 2017	(r314870)
@@ -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 {

Modified: head/sys/cam/ctl/scsi_ctl.c
==============================================================================
--- head/sys/cam/ctl/scsi_ctl.c	Tue Mar  7 17:38:52 2017	(r314869)
+++ head/sys/cam/ctl/scsi_ctl.c	Tue Mar  7 17:41:08 2017	(r314870)
@@ -172,6 +172,7 @@ MALLOC_DEFINE(M_CTLFE, "CAM CTL FE", "CA
 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 =
@@ -213,20 +215,24 @@ static struct ctl_frontend ctlfe_fronten
 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);
 }
 
@@ -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)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703071741.v27Hf8LD073505>