Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright(c) 2009 Intel Corporation. All rights reserved.
0004  *
0005  * Maintained at www.Open-FCoE.org
0006  */
0007 
0008 /*
0009  * NPIV VN_Port helper functions for libfc
0010  */
0011 
0012 #include <scsi/libfc.h>
0013 #include <linux/export.h>
0014 
0015 /**
0016  * libfc_vport_create() - Create a new NPIV vport instance
0017  * @vport: fc_vport structure from scsi_transport_fc
0018  * @privsize: driver private data size to allocate along with the Scsi_Host
0019  */
0020 
0021 struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize)
0022 {
0023     struct Scsi_Host *shost = vport_to_shost(vport);
0024     struct fc_lport *n_port = shost_priv(shost);
0025     struct fc_lport *vn_port;
0026 
0027     vn_port = libfc_host_alloc(shost->hostt, privsize);
0028     if (!vn_port)
0029         return vn_port;
0030 
0031     vn_port->vport = vport;
0032     vport->dd_data = vn_port;
0033 
0034     mutex_lock(&n_port->lp_mutex);
0035     list_add_tail(&vn_port->list, &n_port->vports);
0036     mutex_unlock(&n_port->lp_mutex);
0037 
0038     return vn_port;
0039 }
0040 EXPORT_SYMBOL(libfc_vport_create);
0041 
0042 /**
0043  * fc_vport_id_lookup() - find NPIV lport that matches a given fabric ID
0044  * @n_port: Top level N_Port which may have multiple NPIV VN_Ports
0045  * @port_id: Fabric ID to find a match for
0046  *
0047  * Returns: matching lport pointer or NULL if there is no match
0048  */
0049 struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)
0050 {
0051     struct fc_lport *lport = NULL;
0052     struct fc_lport *vn_port;
0053 
0054     if (n_port->port_id == port_id)
0055         return n_port;
0056 
0057     if (port_id == FC_FID_FLOGI)
0058         return n_port;      /* for point-to-point */
0059 
0060     mutex_lock(&n_port->lp_mutex);
0061     list_for_each_entry(vn_port, &n_port->vports, list) {
0062         if (vn_port->port_id == port_id) {
0063             lport = vn_port;
0064             break;
0065         }
0066     }
0067     mutex_unlock(&n_port->lp_mutex);
0068 
0069     return lport;
0070 }
0071 EXPORT_SYMBOL(fc_vport_id_lookup);
0072 
0073 /*
0074  * When setting the link state of vports during an lport state change, it's
0075  * necessary to hold the lp_mutex of both the N_Port and the VN_Port.
0076  * This tells the lockdep engine to treat the nested locking of the VN_Port
0077  * as a different lock class.
0078  */
0079 enum libfc_lport_mutex_class {
0080     LPORT_MUTEX_NORMAL = 0,
0081     LPORT_MUTEX_VN_PORT = 1,
0082 };
0083 
0084 /**
0085  * __fc_vport_setlink() - update link and status on a VN_Port
0086  * @n_port: parent N_Port
0087  * @vn_port: VN_Port to update
0088  *
0089  * Locking: must be called with both the N_Port and VN_Port lp_mutex held
0090  */
0091 static void __fc_vport_setlink(struct fc_lport *n_port,
0092                    struct fc_lport *vn_port)
0093 {
0094     struct fc_vport *vport = vn_port->vport;
0095 
0096     if (vn_port->state == LPORT_ST_DISABLED)
0097         return;
0098 
0099     if (n_port->state == LPORT_ST_READY) {
0100         if (n_port->npiv_enabled) {
0101             fc_vport_set_state(vport, FC_VPORT_INITIALIZING);
0102             __fc_linkup(vn_port);
0103         } else {
0104             fc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
0105             __fc_linkdown(vn_port);
0106         }
0107     } else {
0108         fc_vport_set_state(vport, FC_VPORT_LINKDOWN);
0109         __fc_linkdown(vn_port);
0110     }
0111 }
0112 
0113 /**
0114  * fc_vport_setlink() - update link and status on a VN_Port
0115  * @vn_port: virtual port to update
0116  */
0117 void fc_vport_setlink(struct fc_lport *vn_port)
0118 {
0119     struct fc_vport *vport = vn_port->vport;
0120     struct Scsi_Host *shost = vport_to_shost(vport);
0121     struct fc_lport *n_port = shost_priv(shost);
0122 
0123     mutex_lock(&n_port->lp_mutex);
0124     mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT);
0125     __fc_vport_setlink(n_port, vn_port);
0126     mutex_unlock(&vn_port->lp_mutex);
0127     mutex_unlock(&n_port->lp_mutex);
0128 }
0129 EXPORT_SYMBOL(fc_vport_setlink);
0130 
0131 /**
0132  * fc_vports_linkchange() - change the link state of all vports
0133  * @n_port: Parent N_Port that has changed state
0134  *
0135  * Locking: called with the n_port lp_mutex held
0136  */
0137 void fc_vports_linkchange(struct fc_lport *n_port)
0138 {
0139     struct fc_lport *vn_port;
0140 
0141     list_for_each_entry(vn_port, &n_port->vports, list) {
0142         mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT);
0143         __fc_vport_setlink(n_port, vn_port);
0144         mutex_unlock(&vn_port->lp_mutex);
0145     }
0146 }
0147