Add NPIV vport create and destroy handlers and register them with the
FC transport.

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

 drivers/scsi/fcoe/fcoe.c |  160 +++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 137 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 66b7619..cfe3b87 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -90,6 +90,10 @@ static struct notifier_block fcoe_notifier = {
 static struct scsi_transport_template *fcoe_transport_template;
 static struct scsi_transport_template *fcoe_vport_template;
 
+static int fcoe_vport_destroy(struct fc_vport *vport);
+static int fcoe_vport_create(struct fc_vport *vport, bool disabled);
+static int fcoe_vport_disable(struct fc_vport *vport, bool disable);
+
 struct fc_function_template fcoe_transport_function = {
        .show_host_node_name = 1,
        .show_host_port_name = 1,
@@ -121,6 +125,10 @@ struct fc_function_template fcoe_transport_function = {
        .issue_fc_host_lip = fcoe_reset,
 
        .terminate_rport_io = fc_rport_terminate_io,
+
+       .vport_create = fcoe_vport_create,
+       .vport_delete = fcoe_vport_destroy,
+       .vport_disable = fcoe_vport_disable,
 };
 
 struct fc_function_template fcoe_vport_function = {
@@ -439,6 +447,7 @@ static int fcoe_lport_config(struct fc_lport *lp)
        lp->r_a_tov = 2 * 2 * 1000;
        lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
                              FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
+       lp->does_npiv = 1;
 
        fc_lport_init_stats(lp);
 
@@ -521,11 +530,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct 
net_device *netdev)
        port->fcoe_pending_queue_active = 0;
        setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lp);
 
-       wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0);
-       fc_set_wwnn(lp, wwnn);
-       /* XXX - 3rd arg needs to be vlan id */
-       wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0);
-       fc_set_wwpn(lp, wwpn);
+       if (!lp->vn_port) {
+               wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0);
+               fc_set_wwnn(lp, wwnn);
+               /* XXX - 3rd arg needs to be vlan id */
+               wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0);
+               fc_set_wwpn(lp, wwpn);
+       }
 
        return 0;
 }
@@ -561,6 +572,10 @@ static int fcoe_shost_config(struct fc_lport *lp, struct 
Scsi_Host *shost,
                                "error on scsi_add_host\n");
                return rc;
        }
+
+       if (!lp->vn_port)
+               fc_host_max_npiv_vports(lp->host) = 256;
+
        sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s",
                FCOE_NAME, FCOE_VERSION,
                fcoe_netdev(lp)->name);
@@ -761,24 +776,35 @@ static struct libfc_function_template 
fcoe_libfc_fcn_templ = {
  * fcoe_if_create() - this function creates the fcoe port
  * @fcoe: fcoe_interface structure to create an fc_lport instance on
  * @parent: device pointer to be the parent in sysfs for the SCSI host
+ * @npiv: is this a vport?
  *
  * Creates fc_lport struct and scsi_host for lport, configures lport.
  *
  * Returns : The allocated fc_lport or an error pointer
  */
 static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
-                                      struct device *parent)
+                                      struct device *parent, int npiv)
 {
        int rc;
        struct fc_lport *lport = NULL;
        struct fcoe_port *port;
        struct Scsi_Host *shost;
        struct net_device *netdev = fcoe->netdev;
+       /*
+        * parent is only a vport if npiv is 1,
+        * but we'll only use vport in that case so go ahead and set it
+        */
+       struct fc_vport *vport = dev_to_vport(parent);
 
        FCOE_NETDEV_DBG(netdev, "Create Interface\n");
 
-       lport = libfc_host_alloc(&fcoe_shost_template,
-                                sizeof(struct fcoe_port));
+       if (!npiv) {
+               lport = libfc_host_alloc(&fcoe_shost_template,
+                                        sizeof(struct fcoe_port));
+       } else  {
+               lport = libfc_vport_create(vport,
+                                          sizeof(struct fcoe_port));
+       }
        if (!lport) {
                FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n");
                rc = -ENOMEM;
@@ -798,6 +824,13 @@ static struct fc_lport *fcoe_if_create(struct 
fcoe_interface *fcoe,
                goto out_host_put;
        }
 
+       if (npiv) {
+               FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n",
+                       vport->node_name, vport->port_name);
+               fc_set_wwnn(lport, vport->node_name);
+               fc_set_wwpn(lport, vport->port_name);
+       }
+
        /* configure lport network properties */
        rc = fcoe_netdev_config(lport, netdev);
        if (rc) {
@@ -822,21 +855,24 @@ static struct fc_lport *fcoe_if_create(struct 
fcoe_interface *fcoe,
                goto out_lp_destroy;
        }
 
-       /*
-        * fcoe_em_alloc() and fcoe_hostlist_add() both
-        * need to be atomic with respect to other changes to the hostlist
-        * since fcoe_em_alloc() looks for an existing EM
-        * instance on host list updated by fcoe_hostlist_add().
-        *
-        * This is currently handled through the fcoe_config_mutex begin held.
-        */
+       if (!npiv) {
+               /*
+                * fcoe_em_alloc() and fcoe_hostlist_add() both
+                * need to be atomic with respect to other changes to the
+                * hostlist since fcoe_em_alloc() looks for an existing EM
+                * instance on host list updated by fcoe_hostlist_add().
+                *
+                * This is currently handled through the fcoe_config_mutex
+                * begin held.
+                */
 
-       /* lport exch manager allocation */
-       rc = fcoe_em_config(lport);
-       if (rc) {
-               FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
-                               "interface\n");
-               goto out_lp_destroy;
+               /* lport exch manager allocation */
+               rc = fcoe_em_config(lport);
+               if (rc) {
+                       FCOE_NETDEV_DBG(netdev, "Could not configure the EM "
+                                               "for the interface\n");
+                       goto out_lp_destroy;
+               }
        }
 
        port->flogi_oxid = FC_XID_UNKNOWN;
@@ -1779,7 +1815,7 @@ static int fcoe_create(const char *buffer, struct 
kernel_param *kp)
                goto out_putdev;
        }
 
-       lport = fcoe_if_create(fcoe, &netdev->dev);
+       lport = fcoe_if_create(fcoe, &netdev->dev, 0);
        if (IS_ERR(lport)) {
                printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
                       netdev->name);
@@ -2061,6 +2097,9 @@ static void __exit fcoe_exit(void)
        /* flush any asyncronous interface destroys,
         * this should happen after the netdev notifier is unregistered */
        flush_scheduled_work();
+       /* That will flush out all the N_Ports on the hostlist, but now we
+        * may have NPIV VN_Ports scheduled for destruction */
+       flush_scheduled_work();
 
        /* detach from scsi transport
         * must happen after all destroys are done, therefor after the flush */
@@ -2155,3 +2194,78 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport 
*lport,
        }
 }
 
+/**
+ * fcoe_vport_create()
+ * @vport: fc_vport object to create a new fc_host for
+ * @disabled: start the new fc_host in a disabled state by default?
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
+{
+       struct Scsi_Host *shost = vport_to_shost(vport);
+       struct fc_lport *n_port = shost_priv(shost);
+       struct fcoe_port *port = lport_priv(n_port);
+       struct fcoe_interface *fcoe = port->fcoe;
+       struct net_device *netdev = fcoe->netdev;
+       struct fc_lport *vn_port;
+
+       vn_port = fcoe_if_create(fcoe, &vport->dev, 1);
+       if (IS_ERR(vn_port)) {
+               printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n",
+                      netdev->name);
+               return -EIO;
+       }
+       vport->dd_data = vn_port;
+
+       vn_port->state = LPORT_ST_DISABLED;
+       vn_port->link_up = n_port->state == LPORT_ST_READY ? 1 : 0;
+
+       mutex_lock(&n_port->lp_mutex);
+       list_add_tail(&vn_port->list, &n_port->vports);
+       mutex_unlock(&n_port->lp_mutex);
+
+       if (!disabled) {
+               vn_port->boot_time = jiffies;
+               fc_fabric_login(vn_port);
+       }
+       return 0;
+}
+
+/**
+ * fcoe_vport_destroy() - handles the destroy from sysfs
+ * @vport:
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_vport_destroy(struct fc_vport *vport)
+{
+       struct fc_lport *lport = vport->dd_data;
+       struct fcoe_port *port = lport_priv(lport);
+
+       mutex_lock(&lport->lp_mutex);
+       list_del(&lport->list);
+       mutex_unlock(&lport->lp_mutex);
+       schedule_work(&port->destroy_work);
+       return 0;
+}
+
+/**
+ * fcoe_vport_disable()
+ * @vport
+ * @disable
+ */
+static int fcoe_vport_disable(struct fc_vport *vport, bool disable)
+{
+       struct fc_lport *lport = vport->dd_data;
+
+       if (disable) {
+               fc_fabric_login(lport);
+       } else {
+               lport->boot_time = jiffies;
+               fc_fabric_logoff(lport);
+       }
+
+       return 0;
+}
+

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

Reply via email to