diff options
author | Chris Leech <christopher.leech@intel.com> | 2009-11-03 14:46:40 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:00:59 -0500 |
commit | 9a05753b23c171b6a45e393ec2b9bc034d31bec8 (patch) | |
tree | ffef20c5d7e6ee5c25a0f18cedca0fff7dbb30e1 /drivers | |
parent | e9084bb8b4414dc1cfb840ac5a86fac23fccd013 (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')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 162 |
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 = { | |||
93 | static struct scsi_transport_template *fcoe_transport_template; | 93 | static struct scsi_transport_template *fcoe_transport_template; |
94 | static struct scsi_transport_template *fcoe_vport_transport_template; | 94 | static struct scsi_transport_template *fcoe_vport_transport_template; |
95 | 95 | ||
96 | static int fcoe_vport_destroy(struct fc_vport *vport); | ||
97 | static int fcoe_vport_create(struct fc_vport *vport, bool disabled); | ||
98 | static int fcoe_vport_disable(struct fc_vport *vport, bool disable); | ||
99 | |||
96 | struct fc_function_template fcoe_transport_function = { | 100 | struct 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 | ||
129 | struct fc_function_template fcoe_vport_transport_function = { | 137 | struct 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 | */ |
784 | static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, | 800 | static 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 | */ | ||
2259 | static 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 | */ | ||
2294 | static 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 | */ | ||
2313 | static 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 | |||