Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | // SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2009 Intel Corporation. All rights reserved. * * Maintained at www.Open-FCoE.org */ /* * NPIV VN_Port helper functions for libfc */ #include <scsi/libfc.h> #include <linux/export.h> /** * libfc_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) return vn_port; vn_port->vport = vport; vport->dd_data = vn_port; mutex_lock(&n_port->lp_mutex); list_add_tail(&vn_port->list, &n_port->vports); mutex_unlock(&n_port->lp_mutex); return vn_port; } 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 (n_port->port_id == port_id) return n_port; if (port_id == FC_FID_FLOGI) return n_port; /* for point-to-point */ mutex_lock(&n_port->lp_mutex); list_for_each_entry(vn_port, &n_port->vports, list) { if (vn_port->port_id == port_id) { lport = vn_port; break; } } mutex_unlock(&n_port->lp_mutex); return lport; } EXPORT_SYMBOL(fc_vport_id_lookup); /* * When setting the link state of vports during an lport state change, it's * necessary to hold the lp_mutex of both the N_Port and the VN_Port. * This tells the lockdep engine to treat the nested locking of the VN_Port * as a different lock class. */ enum libfc_lport_mutex_class { LPORT_MUTEX_NORMAL = 0, LPORT_MUTEX_VN_PORT = 1, }; /** * __fc_vport_setlink() - update link and status on a VN_Port * @n_port: parent N_Port * @vn_port: VN_Port to update * * Locking: must be called with both the N_Port and VN_Port lp_mutex held */ static void __fc_vport_setlink(struct fc_lport *n_port, struct fc_lport *vn_port) { struct fc_vport *vport = vn_port->vport; if (vn_port->state == LPORT_ST_DISABLED) return; if (n_port->state == LPORT_ST_READY) { if (n_port->npiv_enabled) { fc_vport_set_state(vport, FC_VPORT_INITIALIZING); __fc_linkup(vn_port); } else { fc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); __fc_linkdown(vn_port); } } else { fc_vport_set_state(vport, FC_VPORT_LINKDOWN); __fc_linkdown(vn_port); } } /** * fc_vport_setlink() - update link and status on a VN_Port * @vn_port: virtual port to update */ void fc_vport_setlink(struct fc_lport *vn_port) { struct fc_vport *vport = vn_port->vport; struct Scsi_Host *shost = vport_to_shost(vport); struct fc_lport *n_port = shost_priv(shost); mutex_lock(&n_port->lp_mutex); mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT); __fc_vport_setlink(n_port, vn_port); mutex_unlock(&vn_port->lp_mutex); mutex_unlock(&n_port->lp_mutex); } EXPORT_SYMBOL(fc_vport_setlink); /** * fc_vports_linkchange() - change the link state of all vports * @n_port: Parent N_Port that has changed state * * Locking: called with the n_port lp_mutex held */ void fc_vports_linkchange(struct fc_lport *n_port) { struct fc_lport *vn_port; list_for_each_entry(vn_port, &n_port->vports, list) { mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT); __fc_vport_setlink(n_port, vn_port); mutex_unlock(&vn_port->lp_mutex); } } |