Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] libfc: add some generic NPIV support routines to libfc

Adds a function to create a new VN_Port instances, which share the EM
list with the N_Port, VN_Port lookup by fabric ID when responding to a new
request (otherwise the exchange lookup from the N_Ports EM list is trusted to
return an exchange with a cached lport value for the correct VN_Port),
a pointer to a fc_vport structure for VN_Ports, and flags to indicate if an
N_Port supports NPIV and if the switch/fabric allows it.

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>

authored by

Chris Leech and committed by
James Bottomley
174e1ebf 86221969

+137 -1
+2 -1
drivers/scsi/libfc/Makefile
··· 10 10 fc_frame.o \ 11 11 fc_lport.o \ 12 12 fc_rport.o \ 13 - fc_fcp.o 13 + fc_fcp.o \ 14 + fc_npiv.o
+29
drivers/scsi/libfc/fc_exch.c
··· 1134 1134 u32 f_ctl; 1135 1135 enum fc_pf_rjt_reason reject; 1136 1136 1137 + /* We can have the wrong fc_lport at this point with NPIV, which is a 1138 + * problem now that we know a new exchange needs to be allocated 1139 + */ 1140 + lp = fc_vport_id_lookup(lp, ntoh24(fh->fh_d_id)); 1141 + if (!lp) { 1142 + fc_frame_free(fp); 1143 + return; 1144 + } 1145 + 1137 1146 fr_seq(fp) = NULL; 1138 1147 reject = fc_seq_lookup_recip(lp, mp, fp); 1139 1148 if (reject == FC_RJT_NONE) { ··· 1908 1899 kfree(ema); 1909 1900 } 1910 1901 EXPORT_SYMBOL(fc_exch_mgr_del); 1902 + 1903 + /** 1904 + * fc_exch_mgr_list_clone() - share all exchange manager objects 1905 + * @src: source lport to clone exchange managers from 1906 + * @dst: new lport that takes references to all the exchange managers 1907 + */ 1908 + int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst) 1909 + { 1910 + struct fc_exch_mgr_anchor *ema, *tmp; 1911 + 1912 + list_for_each_entry(ema, &src->ema_list, ema_list) { 1913 + if (!fc_exch_mgr_add(dst, ema->mp, ema->match)) 1914 + goto err; 1915 + } 1916 + return 0; 1917 + err: 1918 + list_for_each_entry_safe(ema, tmp, &dst->ema_list, ema_list) 1919 + fc_exch_mgr_del(ema); 1920 + return -ENOMEM; 1921 + } 1911 1922 1912 1923 struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, 1913 1924 enum fc_class class,
+86
drivers/scsi/libfc/fc_npiv.c
··· 1 + /* 2 + * Copyright(c) 2009 Intel Corporation. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along with 14 + * this program; if not, write to the Free Software Foundation, Inc., 15 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16 + * 17 + * Maintained at www.Open-FCoE.org 18 + */ 19 + 20 + /* 21 + * NPIV VN_Port helper functions for libfc 22 + */ 23 + 24 + #include <scsi/libfc.h> 25 + 26 + /** 27 + * fc_vport_create() - Create a new NPIV vport instance 28 + * @vport: fc_vport structure from scsi_transport_fc 29 + * @privsize: driver private data size to allocate along with the Scsi_Host 30 + */ 31 + 32 + struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize) 33 + { 34 + struct Scsi_Host *shost = vport_to_shost(vport); 35 + struct fc_lport *n_port = shost_priv(shost); 36 + struct fc_lport *vn_port; 37 + 38 + vn_port = libfc_host_alloc(shost->hostt, privsize); 39 + if (!vn_port) 40 + goto err_out; 41 + if (fc_exch_mgr_list_clone(n_port, vn_port)) 42 + goto err_put; 43 + 44 + vn_port->vport = vport; 45 + vport->dd_data = vn_port; 46 + 47 + mutex_lock(&n_port->lp_mutex); 48 + list_add_tail(&vn_port->list, &n_port->vports); 49 + mutex_unlock(&n_port->lp_mutex); 50 + 51 + return vn_port; 52 + 53 + err_put: 54 + scsi_host_put(vn_port->host); 55 + err_out: 56 + return NULL; 57 + } 58 + EXPORT_SYMBOL(libfc_vport_create); 59 + 60 + /** 61 + * fc_vport_id_lookup() - find NPIV lport that matches a given fabric ID 62 + * @n_port: Top level N_Port which may have multiple NPIV VN_Ports 63 + * @port_id: Fabric ID to find a match for 64 + * 65 + * Returns: matching lport pointer or NULL if there is no match 66 + */ 67 + struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id) 68 + { 69 + struct fc_lport *lport = NULL; 70 + struct fc_lport *vn_port; 71 + 72 + if (fc_host_port_id(n_port->host) == port_id) 73 + return n_port; 74 + 75 + mutex_lock(&n_port->lp_mutex); 76 + list_for_each_entry(vn_port, &n_port->vports, list) { 77 + if (fc_host_port_id(vn_port->host) == port_id) { 78 + lport = vn_port; 79 + break; 80 + } 81 + } 82 + mutex_unlock(&n_port->lp_mutex); 83 + 84 + return lport; 85 + } 86 +
+20
include/scsi/libfc.h
··· 640 640 /* Associations */ 641 641 struct Scsi_Host *host; 642 642 struct list_head ema_list; 643 + struct list_head vports; /* child vports if N_Port */ 644 + struct fc_vport *vport; /* parent vport if VN_Port */ 643 645 struct fc_rport_priv *dns_rp; 644 646 struct fc_rport_priv *ptp_rp; 645 647 void *scsi_priv; ··· 666 664 u32 seq_offload:1; /* seq offload supported */ 667 665 u32 crc_offload:1; /* crc offload supported */ 668 666 u32 lro_enabled:1; /* large receive offload */ 667 + u32 does_npiv:1; /* supports multiple vports */ 668 + u32 npiv_enabled:1; /* switch/fabric allows NPIV */ 669 669 u32 mfs; /* max FC payload size */ 670 670 unsigned int service_params; 671 671 unsigned int e_d_tov; ··· 757 753 lport = shost_priv(shost); 758 754 lport->host = shost; 759 755 INIT_LIST_HEAD(&lport->ema_list); 756 + INIT_LIST_HEAD(&lport->vports); 760 757 return lport; 761 758 } 762 759 ··· 810 805 */ 811 806 int fc_set_mfs(struct fc_lport *lp, u32 mfs); 812 807 808 + /* 809 + * Allocate a new lport struct for an NPIV VN_Port 810 + */ 811 + struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize); 812 + 813 + /* 814 + * Find an NPIV VN_Port by port ID 815 + */ 816 + struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id); 813 817 814 818 /* 815 819 * REMOTE PORT LAYER ··· 924 910 * then also destroys associated EM. 925 911 */ 926 912 void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema); 913 + 914 + /* 915 + * Clone an exchange manager list, getting reference holds for each EM. 916 + * This is for use with NPIV and sharing the X_ID space between VN_Ports. 917 + */ 918 + int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst); 927 919 928 920 /* 929 921 * Allocates an Exchange Manager (EM).