NPIV vports are managed in libfc by changing their virtual link state
when the parent N_Ports internal state changes.  The vport link is only
online when the N_Port is in a read state (logged into the fabric).

Signed-off-by: Chris Leech <[email protected]>
---

 drivers/scsi/libfc/fc_lport.c |   53 ++++++++++++++++++++++++++++++-----------
 drivers/scsi/libfc/fc_npiv.c  |   45 +++++++++++++++++++++++++++++++++++
 include/scsi/libfc.h          |    8 ++++++
 3 files changed, 92 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index a430335..df555a3 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -561,40 +561,62 @@ int fc_fabric_login(struct fc_lport *lport)
 EXPORT_SYMBOL(fc_fabric_login);
 
 /**
- * fc_linkup() - Handler for transport linkup events
+ * __fc_linkup() - Handler for transport linkup events
  * @lport: The lport whose link is up
+ *
+ * Locking: must be called with the lp_mutex held
  */
-void fc_linkup(struct fc_lport *lport)
+void __fc_linkup(struct fc_lport *lport)
 {
-       printk(KERN_INFO "libfc: Link up on port (%6x)\n",
-              fc_host_port_id(lport->host));
-
-       mutex_lock(&lport->lp_mutex);
        if (!lport->link_up) {
                lport->link_up = 1;
 
                if (lport->state == LPORT_ST_RESET)
                        fc_lport_enter_flogi(lport);
        }
+}
+
+/**
+ * fc_linkup() - Handler for transport linkup events
+ * @lport: The lport whose link is up
+ */
+void fc_linkup(struct fc_lport *lport)
+{
+       printk(KERN_INFO "libfc: Link up on port (%6x)\n",
+              fc_host_port_id(lport->host));
+
+       mutex_lock(&lport->lp_mutex);
+       __fc_linkup(lport);
        mutex_unlock(&lport->lp_mutex);
 }
 EXPORT_SYMBOL(fc_linkup);
 
 /**
- * fc_linkdown() - Handler for transport linkdown events
+ * __fc_linkdown() - Handler for transport linkdown events
  * @lport: The lport whose link is down
+ *
+ * Locking: must be called with the lp_mutex held
  */
-void fc_linkdown(struct fc_lport *lport)
+void __fc_linkdown(struct fc_lport *lport)
 {
-       mutex_lock(&lport->lp_mutex);
-       printk(KERN_INFO "libfc: Link down on port (%6x)\n",
-              fc_host_port_id(lport->host));
-
        if (lport->link_up) {
                lport->link_up = 0;
                fc_lport_enter_reset(lport);
                lport->tt.fcp_cleanup(lport);
        }
+}
+
+/**
+ * fc_linkdown() - Handler for transport linkdown events
+ * @lport: The lport whose link is down
+ */
+void fc_linkdown(struct fc_lport *lport)
+{
+       printk(KERN_INFO "libfc: Link down on port (%6x)\n",
+              fc_host_port_id(lport->host));
+
+       mutex_lock(&lport->lp_mutex);
+       __fc_linkdown(lport);
        mutex_unlock(&lport->lp_mutex);
 }
 EXPORT_SYMBOL(fc_linkdown);
@@ -722,7 +744,7 @@ static void fc_lport_enter_ready(struct fc_lport *lport)
                     fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_READY);
-
+       fc_vports_linkup(lport);
        lport->tt.disc_start(fc_lport_disc_callback, lport);
 }
 
@@ -971,8 +993,10 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
 
        fc_lport_state_enter(lport, LPORT_ST_RESET);
        fc_lport_reset_locked(lport);
-       if (lport->link_up)
+       if (lport->link_up) {
+               fc_vports_linkdown(lport);
                fc_lport_enter_flogi(lport);
+       }
 }
 
 /**
@@ -1438,6 +1462,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
                     fc_lport_state(lport));
 
        fc_lport_state_enter(lport, LPORT_ST_LOGO);
+       fc_vports_linkdown(lport);
 
        fp = fc_frame_alloc(lport, sizeof(*logo));
        if (!fp) {
diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c
index 07cb5a6..e51c5ef 100644
--- a/drivers/scsi/libfc/fc_npiv.c
+++ b/drivers/scsi/libfc/fc_npiv.c
@@ -77,3 +77,48 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, 
u32 port_id)
        return lport;
 }
 
+/*
+ * When setting the link state of vports during an lport state change, it's
+ * necessary to hold the lp_mutex of both the N_Port and the VN_Port.
+ * This tells the lockdep engine to treat the nested locking of the VN_Port
+ * as a different lock class.
+ */
+enum libfc_lport_mutex_class {
+       LPORT_MUTEX_NORMAL = 0,
+       LPORT_MUTEX_VN_PORT = 1,
+};
+
+/**
+ * fc_vports_linkup() - change the link state of all vports to up
+ * @n_port: Parent N_Port that is now in a ready state
+ *
+ * Locking: called with the n_port lp_mutex held
+ */
+void fc_vports_linkup(struct fc_lport *n_port)
+{
+       struct fc_lport *vn_port;
+
+       list_for_each_entry(vn_port, &n_port->vports, list) {
+               mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT);
+               __fc_linkup(vn_port);
+               mutex_unlock(&vn_port->lp_mutex);
+       }
+}
+
+/**
+ * fc_vports_linkdown() - change the link state of all vports to down
+ * @n_port: Parent N_Port
+ *
+ * Locking: called with the n_port lp_mutex held
+ */
+void fc_vports_linkdown(struct fc_lport *n_port)
+{
+       struct fc_lport *vn_port;
+
+       list_for_each_entry(vn_port, &n_port->vports, list) {
+               mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT);
+               __fc_linkdown(vn_port);
+               mutex_unlock(&vn_port->lp_mutex);
+       }
+}
+
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 6047b4d..1686aba 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -835,11 +835,13 @@ int fc_fabric_login(struct fc_lport *lp);
 /*
  * The link is up for the given local port.
  */
+void __fc_linkup(struct fc_lport *);
 void fc_linkup(struct fc_lport *);
 
 /*
  * Link is down for the given local port.
  */
+void __fc_linkdown(struct fc_lport *);
 void fc_linkdown(struct fc_lport *);
 
 /*
@@ -868,6 +870,12 @@ struct fc_lport *libfc_vport_create(struct fc_vport 
*vport, int privsize);
 struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id);
 
 /*
+ * NPIV VN_Port link state management
+ */
+void fc_vports_linkup(struct fc_lport *n_port);
+void fc_vports_linkdown(struct fc_lport *n_port);
+
+/*
  * REMOTE PORT LAYER
  *****************************/
 int fc_rport_init(struct fc_lport *lp);

_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel

Reply via email to