0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/interrupt.h>
0025 #include <linux/dma-direction.h>
0026
0027 #include <scsi/scsi_transport_fc.h>
0028
0029 #include "lpfc_hw4.h"
0030 #include "lpfc_hw.h"
0031 #include "lpfc_sli.h"
0032 #include "lpfc_sli4.h"
0033 #include "lpfc_nl.h"
0034 #include "lpfc_disc.h"
0035 #include "lpfc.h"
0036 #include "lpfc_crtn.h"
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport,
0048 u32 hash, u8 *buf)
0049 {
0050 struct lpfc_vmid *vmp;
0051
0052 hash_for_each_possible(vport->hash_table, vmp, hnode, hash) {
0053 if (memcmp(&vmp->host_vmid[0], buf, 16) == 0)
0054 return vmp;
0055 }
0056 return NULL;
0057 }
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 static void
0069 lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash,
0070 struct lpfc_vmid *vmp)
0071 {
0072 hash_add(vport->hash_table, &vmp->hnode, hash);
0073 }
0074
0075
0076
0077
0078
0079
0080
0081 int lpfc_vmid_hash_fn(const char *vmid, int len)
0082 {
0083 int c;
0084 int hash = 0;
0085
0086 if (len == 0)
0087 return 0;
0088 while (len--) {
0089 c = *vmid++;
0090 if (c >= 'A' && c <= 'Z')
0091 c += 'a' - 'A';
0092
0093 hash = (hash + (c << LPFC_VMID_HASH_SHIFT) +
0094 (c >> LPFC_VMID_HASH_SHIFT)) * 19;
0095 }
0096
0097 return hash & LPFC_VMID_HASH_MASK;
0098 }
0099
0100
0101
0102
0103
0104
0105
0106
0107 static void lpfc_vmid_update_entry(struct lpfc_vport *vport,
0108 enum dma_data_direction iodir,
0109 struct lpfc_vmid *vmp,
0110 union lpfc_vmid_io_tag *tag)
0111 {
0112 u64 *lta;
0113
0114 if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
0115 tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid;
0116 else if (vport->phba->cfg_vmid_app_header)
0117 tag->app_id = vmp->un.app_id;
0118
0119 if (iodir == DMA_TO_DEVICE)
0120 vmp->io_wr_cnt++;
0121 else if (iodir == DMA_FROM_DEVICE)
0122 vmp->io_rd_cnt++;
0123
0124
0125 lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id());
0126 *lta = jiffies;
0127 }
0128
0129 static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport,
0130 struct lpfc_vmid *vmid)
0131 {
0132 u32 hash;
0133 struct lpfc_vmid *pvmid;
0134
0135 if (vport->port_type == LPFC_PHYSICAL_PORT) {
0136 vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport);
0137 } else {
0138 hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len);
0139 pvmid =
0140 lpfc_get_vmid_from_hashtable(vport->phba->pport, hash,
0141 vmid->host_vmid);
0142 if (pvmid)
0143 vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid;
0144 else
0145 vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport);
0146 }
0147 }
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid,
0159 enum dma_data_direction iodir,
0160 union lpfc_vmid_io_tag *tag)
0161 {
0162 struct lpfc_vmid *vmp = NULL;
0163 int hash, len, rc = -EPERM, i;
0164
0165
0166 if (lpfc_vmid_is_type_priority_tag(vport) &&
0167 !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) &&
0168 (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) {
0169 vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
0170 return -EAGAIN;
0171 }
0172
0173
0174 len = strlen(uuid);
0175 hash = lpfc_vmid_hash_fn(uuid, len);
0176
0177
0178 read_lock(&vport->vmid_lock);
0179 vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid);
0180
0181
0182 if (vmp && vmp->flag & LPFC_VMID_REGISTERED) {
0183 read_unlock(&vport->vmid_lock);
0184 lpfc_vmid_update_entry(vport, iodir, vmp, tag);
0185 rc = 0;
0186 } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER ||
0187 vmp->flag & LPFC_VMID_DE_REGISTER)) {
0188
0189
0190 read_unlock(&vport->vmid_lock);
0191 rc = -EBUSY;
0192 } else {
0193
0194
0195 read_unlock(&vport->vmid_lock);
0196
0197
0198 write_lock(&vport->vmid_lock);
0199 vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid);
0200
0201
0202
0203 if (vmp && vmp->flag & LPFC_VMID_REGISTERED) {
0204 lpfc_vmid_update_entry(vport, iodir, vmp, tag);
0205 write_unlock(&vport->vmid_lock);
0206 return 0;
0207 } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) {
0208 write_unlock(&vport->vmid_lock);
0209 return -EBUSY;
0210 }
0211
0212
0213 if (vport->cur_vmid_cnt < vport->max_vmid) {
0214 for (i = 0; i < vport->max_vmid; i++) {
0215 vmp = vport->vmid + i;
0216 if (vmp->flag == LPFC_VMID_SLOT_FREE)
0217 break;
0218 }
0219 if (i == vport->max_vmid)
0220 vmp = NULL;
0221 } else {
0222 vmp = NULL;
0223 }
0224
0225 if (!vmp) {
0226 write_unlock(&vport->vmid_lock);
0227 return -ENOMEM;
0228 }
0229
0230
0231 lpfc_put_vmid_in_hashtable(vport, hash, vmp);
0232 vmp->vmid_len = len;
0233 memcpy(vmp->host_vmid, uuid, vmp->vmid_len);
0234 vmp->io_rd_cnt = 0;
0235 vmp->io_wr_cnt = 0;
0236 vmp->flag = LPFC_VMID_SLOT_USED;
0237
0238 vmp->delete_inactive =
0239 vport->vmid_inactivity_timeout ? 1 : 0;
0240
0241
0242 if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
0243 lpfc_vmid_assign_cs_ctl(vport, vmp);
0244
0245
0246
0247 if (!vmp->last_io_time)
0248 vmp->last_io_time = __alloc_percpu(sizeof(u64),
0249 __alignof__(struct
0250 lpfc_vmid));
0251 if (!vmp->last_io_time) {
0252 hash_del(&vmp->hnode);
0253 vmp->flag = LPFC_VMID_SLOT_FREE;
0254 write_unlock(&vport->vmid_lock);
0255 return -EIO;
0256 }
0257
0258 write_unlock(&vport->vmid_lock);
0259
0260
0261 if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
0262 rc = lpfc_vmid_uvem(vport, vmp, true);
0263 else if (vport->phba->cfg_vmid_app_header)
0264 rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp);
0265 if (!rc) {
0266 write_lock(&vport->vmid_lock);
0267 vport->cur_vmid_cnt++;
0268 vmp->flag |= LPFC_VMID_REQ_REGISTER;
0269 write_unlock(&vport->vmid_lock);
0270 } else {
0271 write_lock(&vport->vmid_lock);
0272 hash_del(&vmp->hnode);
0273 vmp->flag = LPFC_VMID_SLOT_FREE;
0274 free_percpu(vmp->last_io_time);
0275 write_unlock(&vport->vmid_lock);
0276 return -EIO;
0277 }
0278
0279
0280 if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) {
0281 mod_timer(&vport->phba->inactive_vmid_poll,
0282 jiffies +
0283 msecs_to_jiffies(1000 * LPFC_VMID_TIMER));
0284 vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD;
0285 }
0286 }
0287 return rc;
0288 }