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)
 {
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to