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), and a flag to tell NPIV VN_Ports from "real" N_Ports
Signed-off-by: Chris Leech <[email protected]> --- drivers/scsi/libfc/Makefile | 3 +- drivers/scsi/libfc/fc_exch.c | 25 +++++++++++++ drivers/scsi/libfc/fc_npiv.c | 79 ++++++++++++++++++++++++++++++++++++++++++ include/scsi/libfc.h | 19 ++++++++++ 4 files changed, 125 insertions(+), 1 deletions(-) create mode 100644 drivers/scsi/libfc/fc_npiv.c diff --git a/drivers/scsi/libfc/Makefile b/drivers/scsi/libfc/Makefile index 55f982d..d9704be 100644 --- a/drivers/scsi/libfc/Makefile +++ b/drivers/scsi/libfc/Makefile @@ -9,4 +9,5 @@ libfc-objs := \ fc_frame.o \ fc_lport.o \ fc_rport.o \ - fc_fcp.o + fc_fcp.o \ + fc_npiv.o diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index b51db15..0296f6f 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1114,6 +1114,15 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, u32 f_ctl; enum fc_pf_rjt_reason reject; + /* We can have the wrong fc_lport at this point with NPIV, which is a + * problem now that we know a new exchange needs to be allocated + */ + lp = fc_vport_id_lookup(lp, ntoh24(fh->fh_d_id)); + if (!lp) { + fc_frame_free(fp); + return; + } + fr_seq(fp) = NULL; reject = fc_seq_lookup_recip(lp, mp, fp); if (reject == FC_RJT_NONE) { @@ -1817,6 +1826,22 @@ void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema) } EXPORT_SYMBOL(fc_exch_mgr_del); +int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst) +{ + struct fc_exch_mgr_anchor *ema, *tmp; + + list_for_each_entry(ema, &src->ema_list, ema_list) { + if (!fc_exch_mgr_add(dst, ema->mp, ema->match)) + goto err; + } + return 0; +err: + list_for_each_entry_safe(ema, tmp, &dst->ema_list, ema_list) + fc_exch_mgr_del(ema); + return -ENOMEM; +} +EXPORT_SYMBOL(fc_exch_mgr_list_clone); + struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, enum fc_class class, u16 min_xid, u16 max_xid, diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c new file mode 100644 index 0000000..07cb5a6 --- /dev/null +++ b/drivers/scsi/libfc/fc_npiv.c @@ -0,0 +1,79 @@ +/* + * Copyright(c) 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Maintained at www.Open-FCoE.org + */ + +/* + * NPIV VN_Port helper functions for libfc + */ + +#include <scsi/libfc.h> + +/** + * fc_vport_create() - Create a new NPIV vport instance + * @vport: fc_vport structure from scsi_transport_fc + * @privsize: driver private data size to allocate along with the Scsi_Host + */ + +struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize) +{ + struct Scsi_Host *shost = vport_to_shost(vport); + struct fc_lport *n_port = shost_priv(shost); + struct fc_lport *vn_port; + + vn_port = libfc_host_alloc(shost->hostt, privsize); + if (!vn_port) + goto err_out; + vn_port->vn_port = 1; + if (fc_exch_mgr_list_clone(n_port, vn_port)) + goto err_put; + return vn_port; + +err_put: + scsi_host_put(vn_port->host); +err_out: + return NULL; +} +EXPORT_SYMBOL(libfc_vport_create); + +/** + * fc_vport_id_lookup() - find NPIV lport that matches a given fabric ID + * @n_port: Top level N_Port which may have multiple NPIV VN_Ports + * @port_id: Fabric ID to find a match for + * + * Returns: matching lport pointer or NULL if there is no match + */ +struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id) +{ + struct fc_lport *lport = NULL; + struct fc_lport *vn_port; + + if (fc_host_port_id(n_port->host) == port_id) + return n_port; + + mutex_lock(&n_port->lp_mutex); + list_for_each_entry(vn_port, &n_port->vports, list) { + if (fc_host_port_id(vn_port->host) == port_id) { + lport = vn_port; + break; + } + } + mutex_unlock(&n_port->lp_mutex); + + return lport; +} + diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 949f5d9..6047b4d 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -687,6 +687,7 @@ struct fc_lport { /* Associations */ struct Scsi_Host *host; struct list_head ema_list; + struct list_head vports; struct fc_rport *dns_rp; struct fc_rport *ptp_rp; void *scsi_priv; @@ -711,6 +712,8 @@ struct fc_lport { u32 seq_offload:1; /* seq offload supported */ u32 crc_offload:1; /* crc offload supported */ u32 lro_enabled:1; /* large receive offload */ + u32 does_npiv:1; /* supports multiple vports */ + u32 vn_port:1; /* is this a virtual port? */ u32 mfs; /* max FC payload size */ unsigned int service_params; unsigned int e_d_tov; @@ -801,6 +804,7 @@ libfc_host_alloc(struct scsi_host_template *sht, int priv_size) lport = shost_priv(shost); lport->host = shost; INIT_LIST_HEAD(&lport->ema_list); + INIT_LIST_HEAD(&lport->vports); return lport; } @@ -853,6 +857,15 @@ int fc_lport_reset(struct fc_lport *); */ int fc_set_mfs(struct fc_lport *lp, u32 mfs); +/* + * Allocate a new lport struct for an NPIV VN_Port + */ +struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize); + +/* + * Find an NPIV VN_Port by port ID + */ +struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id); /* * REMOTE PORT LAYER @@ -973,6 +986,12 @@ struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema); /* + * Clone an exchange manager list, getting reference holds for each EM. + * This is for use with NPIV and sharing the X_ID space between VN_Ports. + */ +int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst); + +/* * Allocates an Exchange Manager (EM). * * The EM manages exchanges for their allocation and _______________________________________________ devel mailing list [email protected] http://www.open-fcoe.org/mailman/listinfo/devel
