aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe
diff options
context:
space:
mode:
authorChris Leech <christopher.leech@intel.com>2009-11-03 14:46:40 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:00:59 -0500
commit9a05753b23c171b6a45e393ec2b9bc034d31bec8 (patch)
treeffef20c5d7e6ee5c25a0f18cedca0fff7dbb30e1 /drivers/scsi/fcoe
parente9084bb8b4414dc1cfb840ac5a86fac23fccd013 (diff)
[SCSI] fcoe: NPIV vport create/destroy
Add NPIV vport create and destroy handlers and register them with the FC transport. Signed-off-by: Chris Leech <christopher.leech@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r--drivers/scsi/fcoe/fcoe.c162
1 files changed, 139 insertions, 23 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index d37d5739799c..f23cdb38d5c3 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -93,6 +93,10 @@ static struct notifier_block fcoe_notifier = {
93static struct scsi_transport_template *fcoe_transport_template; 93static struct scsi_transport_template *fcoe_transport_template;
94static struct scsi_transport_template *fcoe_vport_transport_template; 94static struct scsi_transport_template *fcoe_vport_transport_template;
95 95
96static int fcoe_vport_destroy(struct fc_vport *vport);
97static int fcoe_vport_create(struct fc_vport *vport, bool disabled);
98static int fcoe_vport_disable(struct fc_vport *vport, bool disable);
99
96struct fc_function_template fcoe_transport_function = { 100struct fc_function_template fcoe_transport_function = {
97 .show_host_node_name = 1, 101 .show_host_node_name = 1,
98 .show_host_port_name = 1, 102 .show_host_port_name = 1,
@@ -124,6 +128,10 @@ struct fc_function_template fcoe_transport_function = {
124 .issue_fc_host_lip = fcoe_reset, 128 .issue_fc_host_lip = fcoe_reset,
125 129
126 .terminate_rport_io = fc_rport_terminate_io, 130 .terminate_rport_io = fc_rport_terminate_io,
131
132 .vport_create = fcoe_vport_create,
133 .vport_delete = fcoe_vport_destroy,
134 .vport_disable = fcoe_vport_disable,
127}; 135};
128 136
129struct fc_function_template fcoe_vport_transport_function = { 137struct fc_function_template fcoe_vport_transport_function = {
@@ -450,6 +458,7 @@ static int fcoe_lport_config(struct fc_lport *lp)
450 lp->r_a_tov = 2 * 2 * 1000; 458 lp->r_a_tov = 2 * 2 * 1000;
451 lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | 459 lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
452 FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); 460 FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
461 lp->does_npiv = 1;
453 462
454 fc_lport_init_stats(lp); 463 fc_lport_init_stats(lp);
455 464
@@ -536,11 +545,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
536 port->fcoe_pending_queue_active = 0; 545 port->fcoe_pending_queue_active = 0;
537 setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lp); 546 setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lp);
538 547
539 wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0); 548 if (!lp->vport) {
540 fc_set_wwnn(lp, wwnn); 549 wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0);
541 /* XXX - 3rd arg needs to be vlan id */ 550 fc_set_wwnn(lp, wwnn);
542 wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0); 551 /* XXX - 3rd arg needs to be vlan id */
543 fc_set_wwpn(lp, wwpn); 552 wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0);
553 fc_set_wwpn(lp, wwpn);
554 }
544 555
545 return 0; 556 return 0;
546} 557}
@@ -576,6 +587,10 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
576 "error on scsi_add_host\n"); 587 "error on scsi_add_host\n");
577 return rc; 588 return rc;
578 } 589 }
590
591 if (!lp->vport)
592 fc_host_max_npiv_vports(lp->host) = USHORT_MAX;
593
579 sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", 594 sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s",
580 FCOE_NAME, FCOE_VERSION, 595 FCOE_NAME, FCOE_VERSION,
581 fcoe_netdev(lp)->name); 596 fcoe_netdev(lp)->name);
@@ -776,24 +791,35 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
776 * fcoe_if_create() - this function creates the fcoe port 791 * fcoe_if_create() - this function creates the fcoe port
777 * @fcoe: fcoe_interface structure to create an fc_lport instance on 792 * @fcoe: fcoe_interface structure to create an fc_lport instance on
778 * @parent: device pointer to be the parent in sysfs for the SCSI host 793 * @parent: device pointer to be the parent in sysfs for the SCSI host
794 * @npiv: is this a vport?
779 * 795 *
780 * Creates fc_lport struct and scsi_host for lport, configures lport. 796 * Creates fc_lport struct and scsi_host for lport, configures lport.
781 * 797 *
782 * Returns : The allocated fc_lport or an error pointer 798 * Returns : The allocated fc_lport or an error pointer
783 */ 799 */
784static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, 800static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
785 struct device *parent) 801 struct device *parent, int npiv)
786{ 802{
787 int rc; 803 int rc;
788 struct fc_lport *lport = NULL; 804 struct fc_lport *lport = NULL;
789 struct fcoe_port *port; 805 struct fcoe_port *port;
790 struct Scsi_Host *shost; 806 struct Scsi_Host *shost;
791 struct net_device *netdev = fcoe->netdev; 807 struct net_device *netdev = fcoe->netdev;
808 /*
809 * parent is only a vport if npiv is 1,
810 * but we'll only use vport in that case so go ahead and set it
811 */
812 struct fc_vport *vport = dev_to_vport(parent);
792 813
793 FCOE_NETDEV_DBG(netdev, "Create Interface\n"); 814 FCOE_NETDEV_DBG(netdev, "Create Interface\n");
794 815
795 lport = libfc_host_alloc(&fcoe_shost_template, 816 if (!npiv) {
796 sizeof(struct fcoe_port)); 817 lport = libfc_host_alloc(&fcoe_shost_template,
818 sizeof(struct fcoe_port));
819 } else {
820 lport = libfc_vport_create(vport,
821 sizeof(struct fcoe_port));
822 }
797 if (!lport) { 823 if (!lport) {
798 FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); 824 FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n");
799 rc = -ENOMEM; 825 rc = -ENOMEM;
@@ -813,6 +839,13 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
813 goto out_host_put; 839 goto out_host_put;
814 } 840 }
815 841
842 if (npiv) {
843 FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n",
844 vport->node_name, vport->port_name);
845 fc_set_wwnn(lport, vport->node_name);
846 fc_set_wwpn(lport, vport->port_name);
847 }
848
816 /* configure lport network properties */ 849 /* configure lport network properties */
817 rc = fcoe_netdev_config(lport, netdev); 850 rc = fcoe_netdev_config(lport, netdev);
818 if (rc) { 851 if (rc) {
@@ -837,21 +870,24 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
837 goto out_lp_destroy; 870 goto out_lp_destroy;
838 } 871 }
839 872
840 /* 873 if (!npiv) {
841 * fcoe_em_alloc() and fcoe_hostlist_add() both 874 /*
842 * need to be atomic with respect to other changes to the hostlist 875 * fcoe_em_alloc() and fcoe_hostlist_add() both
843 * since fcoe_em_alloc() looks for an existing EM 876 * need to be atomic with respect to other changes to the
844 * instance on host list updated by fcoe_hostlist_add(). 877 * hostlist since fcoe_em_alloc() looks for an existing EM
845 * 878 * instance on host list updated by fcoe_hostlist_add().
846 * This is currently handled through the fcoe_config_mutex begin held. 879 *
847 */ 880 * This is currently handled through the fcoe_config_mutex
881 * begin held.
882 */
848 883
849 /* lport exch manager allocation */ 884 /* lport exch manager allocation */
850 rc = fcoe_em_config(lport); 885 rc = fcoe_em_config(lport);
851 if (rc) { 886 if (rc) {
852 FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " 887 FCOE_NETDEV_DBG(netdev, "Could not configure the EM "
853 "interface\n"); 888 "for the interface\n");
854 goto out_lp_destroy; 889 goto out_lp_destroy;
890 }
855 } 891 }
856 892
857 fcoe_interface_get(fcoe); 893 fcoe_interface_get(fcoe);
@@ -1806,7 +1842,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
1806 goto out_putdev; 1842 goto out_putdev;
1807 } 1843 }
1808 1844
1809 lport = fcoe_if_create(fcoe, &netdev->dev); 1845 lport = fcoe_if_create(fcoe, &netdev->dev, 0);
1810 if (IS_ERR(lport)) { 1846 if (IS_ERR(lport)) {
1811 printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", 1847 printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
1812 netdev->name); 1848 netdev->name);
@@ -2113,6 +2149,9 @@ static void __exit fcoe_exit(void)
2113 /* flush any asyncronous interface destroys, 2149 /* flush any asyncronous interface destroys,
2114 * this should happen after the netdev notifier is unregistered */ 2150 * this should happen after the netdev notifier is unregistered */
2115 flush_scheduled_work(); 2151 flush_scheduled_work();
2152 /* That will flush out all the N_Ports on the hostlist, but now we
2153 * may have NPIV VN_Ports scheduled for destruction */
2154 flush_scheduled_work();
2116 2155
2117 /* detach from scsi transport 2156 /* detach from scsi transport
2118 * must happen after all destroys are done, therefor after the flush */ 2157 * must happen after all destroys are done, therefor after the flush */
@@ -2210,3 +2249,80 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport,
2210 return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); 2249 return fc_elsct_send(lport, did, fp, op, resp, arg, timeout);
2211} 2250}
2212 2251
2252/**
2253 * fcoe_vport_create() - create an fc_host/scsi_host for a vport
2254 * @vport: fc_vport object to create a new fc_host for
2255 * @disabled: start the new fc_host in a disabled state by default?
2256 *
2257 * Returns: 0 for success
2258 */
2259static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
2260{
2261 struct Scsi_Host *shost = vport_to_shost(vport);
2262 struct fc_lport *n_port = shost_priv(shost);
2263 struct fcoe_port *port = lport_priv(n_port);
2264 struct fcoe_interface *fcoe = port->fcoe;
2265 struct net_device *netdev = fcoe->netdev;
2266 struct fc_lport *vn_port;
2267
2268 mutex_lock(&fcoe_config_mutex);
2269 vn_port = fcoe_if_create(fcoe, &vport->dev, 1);
2270 mutex_unlock(&fcoe_config_mutex);
2271
2272 if (IS_ERR(vn_port)) {
2273 printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n",
2274 netdev->name);
2275 return -EIO;
2276 }
2277
2278 if (disabled) {
2279 fc_vport_set_state(vport, FC_VPORT_DISABLED);
2280 } else {
2281 vn_port->boot_time = jiffies;
2282 fc_fabric_login(vn_port);
2283 fc_vport_setlink(vn_port);
2284 }
2285 return 0;
2286}
2287
2288/**
2289 * fcoe_vport_destroy() - destroy the fc_host/scsi_host for a vport
2290 * @vport: fc_vport object that is being destroyed
2291 *
2292 * Returns: 0 for success
2293 */
2294static int fcoe_vport_destroy(struct fc_vport *vport)
2295{
2296 struct Scsi_Host *shost = vport_to_shost(vport);
2297 struct fc_lport *n_port = shost_priv(shost);
2298 struct fc_lport *vn_port = vport->dd_data;
2299 struct fcoe_port *port = lport_priv(vn_port);
2300
2301 mutex_lock(&n_port->lp_mutex);
2302 list_del(&vn_port->list);
2303 mutex_unlock(&n_port->lp_mutex);
2304 schedule_work(&port->destroy_work);
2305 return 0;
2306}
2307
2308/**
2309 * fcoe_vport_disable() - change vport state
2310 * @vport: vport to bring online/offline
2311 * @disable: should the vport be disabled?
2312 */
2313static int fcoe_vport_disable(struct fc_vport *vport, bool disable)
2314{
2315 struct fc_lport *lport = vport->dd_data;
2316
2317 if (disable) {
2318 fc_vport_set_state(vport, FC_VPORT_DISABLED);
2319 fc_fabric_logoff(lport);
2320 } else {
2321 lport->boot_time = jiffies;
2322 fc_fabric_login(lport);
2323 fc_vport_setlink(lport);
2324 }
2325
2326 return 0;
2327}
2328