Message ID | 20220510200028.37399-3-jsmart2021@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add VMID support to nvme-fc transport and lpfc driver | expand |
On 5/10/22 22:00, James Smart wrote: > Remove VMID code from its scsi-specific location and move to a new > file solely for VMID code. > > Signed-off-by: Gaurav Srivastava <gaurav.srivastava@broadcom.com> > Signed-off-by: James Smart <jsmart2021@gmail.com> > --- > drivers/scsi/lpfc/Makefile | 2 +- > drivers/scsi/lpfc/lpfc_crtn.h | 2 + > drivers/scsi/lpfc/lpfc_scsi.c | 256 ------------------------------ > drivers/scsi/lpfc/lpfc_vmid.c | 288 ++++++++++++++++++++++++++++++++++ > 4 files changed, 291 insertions(+), 257 deletions(-) > create mode 100644 drivers/scsi/lpfc/lpfc_vmid.c > Reviewed-by: Hannes Reinecke <hare@suse.de> Cheers, Hannes
> On May 10, 2022, at 1:00 PM, James Smart <jsmart2021@gmail.com> wrote: > > Remove VMID code from its scsi-specific location and move to a new > file solely for VMID code. > > Signed-off-by: Gaurav Srivastava <gaurav.srivastava@broadcom.com> > Signed-off-by: James Smart <jsmart2021@gmail.com> > --- > drivers/scsi/lpfc/Makefile | 2 +- > drivers/scsi/lpfc/lpfc_crtn.h | 2 + > drivers/scsi/lpfc/lpfc_scsi.c | 256 ------------------------------ > drivers/scsi/lpfc/lpfc_vmid.c | 288 ++++++++++++++++++++++++++++++++++ > 4 files changed, 291 insertions(+), 257 deletions(-) > create mode 100644 drivers/scsi/lpfc/lpfc_vmid.c > > diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile > index 092a971d066b..bbd1faf41e80 100644 > --- a/drivers/scsi/lpfc/Makefile > +++ b/drivers/scsi/lpfc/Makefile > @@ -33,4 +33,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o > lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o \ > lpfc_hbadisc.o lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o \ > lpfc_scsi.o lpfc_attr.o lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o \ > - lpfc_nvme.o lpfc_nvmet.o > + lpfc_nvme.o lpfc_nvmet.o lpfc_vmid.o > diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h > index b0775be31d5c..913844f01bf5 100644 > --- a/drivers/scsi/lpfc/lpfc_crtn.h > +++ b/drivers/scsi/lpfc/lpfc_crtn.h > @@ -671,6 +671,8 @@ int lpfc_vmid_cmd(struct lpfc_vport *vport, > int lpfc_vmid_hash_fn(const char *vmid, int len); > struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, > uint32_t hash, uint8_t *buf); > +int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct > + scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag); > void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport); > int lpfc_issue_els_qfpa(struct lpfc_vport *vport); > > diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c > index 1d134a01ff3e..70d0a4d3d92e 100644 > --- a/drivers/scsi/lpfc/lpfc_scsi.c > +++ b/drivers/scsi/lpfc/lpfc_scsi.c > @@ -87,14 +87,6 @@ static void > lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb); > static int > lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc); > -static void > -lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, > - struct lpfc_vmid *vmp); > -static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd > - *cmd, struct lpfc_vmid *vmp, > - union lpfc_vmid_io_tag *tag); > -static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, > - struct lpfc_vmid *vmid); > > /** > * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. > @@ -5270,254 +5262,6 @@ void lpfc_poll_timeout(struct timer_list *t) > } > } > > -/* > - * lpfc_get_vmid_from_hashtable - search the UUID in the hash table > - * @vport: The virtual port for which this call is being executed. > - * @hash: calculated hash value > - * @buf: uuid associated with the VE > - * Return the VMID entry associated with the UUID > - * Make sure to acquire the appropriate lock before invoking this routine. > - */ > -struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, > - u32 hash, u8 *buf) > -{ > - struct lpfc_vmid *vmp; > - > - hash_for_each_possible(vport->hash_table, vmp, hnode, hash) { > - if (memcmp(&vmp->host_vmid[0], buf, 16) == 0) > - return vmp; > - } > - return NULL; > -} > - > -/* > - * lpfc_put_vmid_in_hashtable - put the VMID in the hash table > - * @vport: The virtual port for which this call is being executed. > - * @hash - calculated hash value > - * @vmp: Pointer to a VMID entry representing a VM sending I/O > - * > - * This routine will insert the newly acquired VMID entity in the hash table. > - * Make sure to acquire the appropriate lock before invoking this routine. > - */ > -static void > -lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, > - struct lpfc_vmid *vmp) > -{ > - hash_add(vport->hash_table, &vmp->hnode, hash); > -} > - > -/* > - * lpfc_vmid_hash_fn - create a hash value of the UUID > - * @vmid: uuid associated with the VE > - * @len: length of the VMID string > - * Returns the calculated hash value > - */ > -int lpfc_vmid_hash_fn(const char *vmid, int len) > -{ > - int c; > - int hash = 0; > - > - if (len == 0) > - return 0; > - while (len--) { > - c = *vmid++; > - if (c >= 'A' && c <= 'Z') > - c += 'a' - 'A'; > - > - hash = (hash + (c << LPFC_VMID_HASH_SHIFT) + > - (c >> LPFC_VMID_HASH_SHIFT)) * 19; > - } > - > - return hash & LPFC_VMID_HASH_MASK; > -} > - > -/* > - * lpfc_vmid_update_entry - update the vmid entry in the hash table > - * @vport: The virtual port for which this call is being executed. > - * @cmd: address of scsi cmd descriptor > - * @vmp: Pointer to a VMID entry representing a VM sending I/O > - * @tag: VMID tag > - */ > -static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd > - *cmd, struct lpfc_vmid *vmp, > - union lpfc_vmid_io_tag *tag) > -{ > - u64 *lta; > - > - if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) > - tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid; > - else if (vport->phba->cfg_vmid_app_header) > - tag->app_id = vmp->un.app_id; > - > - if (cmd->sc_data_direction == DMA_TO_DEVICE) > - vmp->io_wr_cnt++; > - else > - vmp->io_rd_cnt++; > - > - /* update the last access timestamp in the table */ > - lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id()); > - *lta = jiffies; > -} > - > -static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, > - struct lpfc_vmid *vmid) > -{ > - u32 hash; > - struct lpfc_vmid *pvmid; > - > - if (vport->port_type == LPFC_PHYSICAL_PORT) { > - vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); > - } else { > - hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len); > - pvmid = > - lpfc_get_vmid_from_hashtable(vport->phba->pport, hash, > - vmid->host_vmid); > - if (pvmid) > - vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid; > - else > - vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); > - } > -} > - > -/* > - * lpfc_vmid_get_appid - get the VMID associated with the UUID > - * @vport: The virtual port for which this call is being executed. > - * @uuid: UUID associated with the VE > - * @cmd: address of scsi_cmd descriptor > - * @tag: VMID tag > - * Returns status of the function > - */ > -static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct > - scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag) > -{ > - struct lpfc_vmid *vmp = NULL; > - int hash, len, rc = -EPERM, i; > - > - /* check if QFPA is complete */ > - if (lpfc_vmid_is_type_priority_tag(vport) && > - !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) && > - (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) { > - vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA; > - return -EAGAIN; > - } > - > - /* search if the UUID has already been mapped to the VMID */ > - len = strlen(uuid); > - hash = lpfc_vmid_hash_fn(uuid, len); > - > - /* search for the VMID in the table */ > - read_lock(&vport->vmid_lock); > - vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); > - > - /* if found, check if its already registered */ > - if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { > - read_unlock(&vport->vmid_lock); > - lpfc_vmid_update_entry(vport, cmd, vmp, tag); > - rc = 0; > - } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER || > - vmp->flag & LPFC_VMID_DE_REGISTER)) { > - /* else if register or dereg request has already been sent */ > - /* Hence VMID tag will not be added for this I/O */ > - read_unlock(&vport->vmid_lock); > - rc = -EBUSY; > - } else { > - /* The VMID was not found in the hashtable. At this point, */ > - /* drop the read lock first before proceeding further */ > - read_unlock(&vport->vmid_lock); > - /* start the process to obtain one as per the */ > - /* type of the VMID indicated */ > - write_lock(&vport->vmid_lock); > - vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); > - > - /* while the read lock was released, in case the entry was */ > - /* added by other context or is in process of being added */ > - if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { > - lpfc_vmid_update_entry(vport, cmd, vmp, tag); > - write_unlock(&vport->vmid_lock); > - return 0; > - } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) { > - write_unlock(&vport->vmid_lock); > - return -EBUSY; > - } > - > - /* else search and allocate a free slot in the hash table */ > - if (vport->cur_vmid_cnt < vport->max_vmid) { > - for (i = 0; i < vport->max_vmid; i++) { > - vmp = vport->vmid + i; > - if (vmp->flag == LPFC_VMID_SLOT_FREE) > - break; > - } > - if (i == vport->max_vmid) > - vmp = NULL; > - } else { > - vmp = NULL; > - } > - > - if (!vmp) { > - write_unlock(&vport->vmid_lock); > - return -ENOMEM; > - } > - > - /* Add the vmid and register */ > - lpfc_put_vmid_in_hashtable(vport, hash, vmp); > - vmp->vmid_len = len; > - memcpy(vmp->host_vmid, uuid, vmp->vmid_len); > - vmp->io_rd_cnt = 0; > - vmp->io_wr_cnt = 0; > - vmp->flag = LPFC_VMID_SLOT_USED; > - > - vmp->delete_inactive = > - vport->vmid_inactivity_timeout ? 1 : 0; > - > - /* if type priority tag, get next available VMID */ > - if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) > - lpfc_vmid_assign_cs_ctl(vport, vmp); > - > - /* allocate the per cpu variable for holding */ > - /* the last access time stamp only if VMID is enabled */ > - if (!vmp->last_io_time) > - vmp->last_io_time = __alloc_percpu(sizeof(u64), > - __alignof__(struct > - lpfc_vmid)); > - if (!vmp->last_io_time) { > - hash_del(&vmp->hnode); > - vmp->flag = LPFC_VMID_SLOT_FREE; > - write_unlock(&vport->vmid_lock); > - return -EIO; > - } > - > - write_unlock(&vport->vmid_lock); > - > - /* complete transaction with switch */ > - if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) > - rc = lpfc_vmid_uvem(vport, vmp, true); > - else if (vport->phba->cfg_vmid_app_header) > - rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp); > - if (!rc) { > - write_lock(&vport->vmid_lock); > - vport->cur_vmid_cnt++; > - vmp->flag |= LPFC_VMID_REQ_REGISTER; > - write_unlock(&vport->vmid_lock); > - } else { > - write_lock(&vport->vmid_lock); > - hash_del(&vmp->hnode); > - vmp->flag = LPFC_VMID_SLOT_FREE; > - free_percpu(vmp->last_io_time); > - write_unlock(&vport->vmid_lock); > - return -EIO; > - } > - > - /* finally, enable the idle timer once */ > - if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) { > - mod_timer(&vport->phba->inactive_vmid_poll, > - jiffies + > - msecs_to_jiffies(1000 * LPFC_VMID_TIMER)); > - vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD; > - } > - } > - return rc; > -} > - > /* > * lpfc_is_command_vm_io - get the UUID from blk cgroup > * @cmd: Pointer to scsi_cmnd data structure > diff --git a/drivers/scsi/lpfc/lpfc_vmid.c b/drivers/scsi/lpfc/lpfc_vmid.c > new file mode 100644 > index 000000000000..f64ced04b912 > --- /dev/null > +++ b/drivers/scsi/lpfc/lpfc_vmid.c > @@ -0,0 +1,288 @@ > +/******************************************************************* > + * This file is part of the Emulex Linux Device Driver for * > + * Fibre Channel Host Bus Adapters. * > + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * > + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * > + * Copyright (C) 2004-2016 Emulex. All rights reserved. * > + * EMULEX and SLI are trademarks of Emulex. * > + * www.broadcom.com * > + * Portions Copyright (C) 2004-2005 Christoph Hellwig * > + * * > + * This program is free software; you can redistribute it and/or * > + * modify it under the terms of version 2 of the GNU General * > + * Public License as published by the Free Software Foundation. * > + * This program is distributed in the hope that it will be useful. * > + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * > + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * > + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * > + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * > + * TO BE LEGALLY INVALID. See the GNU General Public License for * > + * more details, a copy of which can be found in the file COPYING * > + * included with this package. * > + *******************************************************************/ > + > +#include <linux/interrupt.h> > +#include <linux/dma-direction.h> > + > +#include <scsi/scsi_transport_fc.h> > + > +#include "lpfc_hw4.h" > +#include "lpfc_hw.h" > +#include "lpfc_sli.h" > +#include "lpfc_sli4.h" > +#include "lpfc_nl.h" > +#include "lpfc_disc.h" > +#include "lpfc.h" > +#include "lpfc_crtn.h" > + > + > +/* > + * lpfc_get_vmid_from_hashtable - search the UUID in the hash table > + * @vport: The virtual port for which this call is being executed. > + * @hash: calculated hash value > + * @buf: uuid associated with the VE > + * Return the VMID entry associated with the UUID > + * Make sure to acquire the appropriate lock before invoking this routine. > + */ > +struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, > + u32 hash, u8 *buf) > +{ > + struct lpfc_vmid *vmp; > + > + hash_for_each_possible(vport->hash_table, vmp, hnode, hash) { > + if (memcmp(&vmp->host_vmid[0], buf, 16) == 0) > + return vmp; > + } > + return NULL; > +} > + > +/* > + * lpfc_put_vmid_in_hashtable - put the VMID in the hash table > + * @vport: The virtual port for which this call is being executed. > + * @hash - calculated hash value > + * @vmp: Pointer to a VMID entry representing a VM sending I/O > + * > + * This routine will insert the newly acquired VMID entity in the hash table. > + * Make sure to acquire the appropriate lock before invoking this routine. > + */ > +static void > +lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, > + struct lpfc_vmid *vmp) > +{ > + hash_add(vport->hash_table, &vmp->hnode, hash); > +} > + > +/* > + * lpfc_vmid_hash_fn - create a hash value of the UUID > + * @vmid: uuid associated with the VE > + * @len: length of the VMID string > + * Returns the calculated hash value > + */ > +int lpfc_vmid_hash_fn(const char *vmid, int len) > +{ > + int c; > + int hash = 0; > + > + if (len == 0) > + return 0; > + while (len--) { > + c = *vmid++; > + if (c >= 'A' && c <= 'Z') > + c += 'a' - 'A'; > + > + hash = (hash + (c << LPFC_VMID_HASH_SHIFT) + > + (c >> LPFC_VMID_HASH_SHIFT)) * 19; > + } > + > + return hash & LPFC_VMID_HASH_MASK; > +} > + > +/* > + * lpfc_vmid_update_entry - update the vmid entry in the hash table > + * @vport: The virtual port for which this call is being executed. > + * @iodir: io direction > + * @vmp: Pointer to a VMID entry representing a VM sending I/O > + * @tag: VMID tag > + */ > +static void lpfc_vmid_update_entry(struct lpfc_vport *vport, > + enum dma_data_direction iodir, > + struct lpfc_vmid *vmp, > + union lpfc_vmid_io_tag *tag) > +{ > + u64 *lta; > + > + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) > + tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid; > + else if (vport->phba->cfg_vmid_app_header) > + tag->app_id = vmp->un.app_id; > + > + if (iodir == DMA_TO_DEVICE) > + vmp->io_wr_cnt++; > + else if (iodir == DMA_FROM_DEVICE) > + vmp->io_rd_cnt++; > + > + /* update the last access timestamp in the table */ > + lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id()); > + *lta = jiffies; > +} > + > +static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, > + struct lpfc_vmid *vmid) > +{ > + u32 hash; > + struct lpfc_vmid *pvmid; > + > + if (vport->port_type == LPFC_PHYSICAL_PORT) { > + vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); > + } else { > + hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len); > + pvmid = > + lpfc_get_vmid_from_hashtable(vport->phba->pport, hash, > + vmid->host_vmid); > + if (pvmid) > + vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid; > + else > + vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); > + } > +} > + > +/* > + * lpfc_vmid_get_appid - get the VMID associated with the UUID > + * @vport: The virtual port for which this call is being executed. > + * @uuid: UUID associated with the VE > + * @cmd: address of scsi_cmd descriptor > + * @iodir: io direction > + * @tag: VMID tag > + * Returns status of the function > + */ > +int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, > + enum dma_data_direction iodir, > + union lpfc_vmid_io_tag *tag) > +{ > + struct lpfc_vmid *vmp = NULL; > + int hash, len, rc = -EPERM, i; > + > + /* check if QFPA is complete */ > + if (lpfc_vmid_is_type_priority_tag(vport) && > + !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) && > + (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) { > + vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA; > + return -EAGAIN; > + } > + > + /* search if the UUID has already been mapped to the VMID */ > + len = strlen(uuid); > + hash = lpfc_vmid_hash_fn(uuid, len); > + > + /* search for the VMID in the table */ > + read_lock(&vport->vmid_lock); > + vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); > + > + /* if found, check if its already registered */ > + if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { > + read_unlock(&vport->vmid_lock); > + lpfc_vmid_update_entry(vport, iodir, vmp, tag); > + rc = 0; > + } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER || > + vmp->flag & LPFC_VMID_DE_REGISTER)) { > + /* else if register or dereg request has already been sent */ > + /* Hence VMID tag will not be added for this I/O */ > + read_unlock(&vport->vmid_lock); > + rc = -EBUSY; > + } else { > + /* The VMID was not found in the hashtable. At this point, */ > + /* drop the read lock first before proceeding further */ > + read_unlock(&vport->vmid_lock); > + /* start the process to obtain one as per the */ > + /* type of the VMID indicated */ > + write_lock(&vport->vmid_lock); > + vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); > + > + /* while the read lock was released, in case the entry was */ > + /* added by other context or is in process of being added */ > + if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { > + lpfc_vmid_update_entry(vport, iodir, vmp, tag); > + write_unlock(&vport->vmid_lock); > + return 0; > + } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) { > + write_unlock(&vport->vmid_lock); > + return -EBUSY; > + } > + > + /* else search and allocate a free slot in the hash table */ > + if (vport->cur_vmid_cnt < vport->max_vmid) { > + for (i = 0; i < vport->max_vmid; i++) { > + vmp = vport->vmid + i; > + if (vmp->flag == LPFC_VMID_SLOT_FREE) > + break; > + } > + if (i == vport->max_vmid) > + vmp = NULL; > + } else { > + vmp = NULL; > + } > + > + if (!vmp) { > + write_unlock(&vport->vmid_lock); > + return -ENOMEM; > + } > + > + /* Add the vmid and register */ > + lpfc_put_vmid_in_hashtable(vport, hash, vmp); > + vmp->vmid_len = len; > + memcpy(vmp->host_vmid, uuid, vmp->vmid_len); > + vmp->io_rd_cnt = 0; > + vmp->io_wr_cnt = 0; > + vmp->flag = LPFC_VMID_SLOT_USED; > + > + vmp->delete_inactive = > + vport->vmid_inactivity_timeout ? 1 : 0; > + > + /* if type priority tag, get next available VMID */ > + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) > + lpfc_vmid_assign_cs_ctl(vport, vmp); > + > + /* allocate the per cpu variable for holding */ > + /* the last access time stamp only if VMID is enabled */ > + if (!vmp->last_io_time) > + vmp->last_io_time = __alloc_percpu(sizeof(u64), > + __alignof__(struct > + lpfc_vmid)); > + if (!vmp->last_io_time) { > + hash_del(&vmp->hnode); > + vmp->flag = LPFC_VMID_SLOT_FREE; > + write_unlock(&vport->vmid_lock); > + return -EIO; > + } > + > + write_unlock(&vport->vmid_lock); > + > + /* complete transaction with switch */ > + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) > + rc = lpfc_vmid_uvem(vport, vmp, true); > + else if (vport->phba->cfg_vmid_app_header) > + rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp); > + if (!rc) { > + write_lock(&vport->vmid_lock); > + vport->cur_vmid_cnt++; > + vmp->flag |= LPFC_VMID_REQ_REGISTER; > + write_unlock(&vport->vmid_lock); > + } else { > + write_lock(&vport->vmid_lock); > + hash_del(&vmp->hnode); > + vmp->flag = LPFC_VMID_SLOT_FREE; > + free_percpu(vmp->last_io_time); > + write_unlock(&vport->vmid_lock); > + return -EIO; > + } > + > + /* finally, enable the idle timer once */ > + if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) { > + mod_timer(&vport->phba->inactive_vmid_poll, > + jiffies + > + msecs_to_jiffies(1000 * LPFC_VMID_TIMER)); > + vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD; > + } > + } > + return rc; > +} > -- > 2.26.2 > Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> -- Himanshu Madhani Oracle Linux Engineering
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 092a971d066b..bbd1faf41e80 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -33,4 +33,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o \ lpfc_hbadisc.o lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o \ lpfc_scsi.o lpfc_attr.o lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o \ - lpfc_nvme.o lpfc_nvmet.o + lpfc_nvme.o lpfc_nvmet.o lpfc_vmid.o diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index b0775be31d5c..913844f01bf5 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -671,6 +671,8 @@ int lpfc_vmid_cmd(struct lpfc_vport *vport, int lpfc_vmid_hash_fn(const char *vmid, int len); struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, uint32_t hash, uint8_t *buf); +int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct + scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag); void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport); int lpfc_issue_els_qfpa(struct lpfc_vport *vport); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 1d134a01ff3e..70d0a4d3d92e 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -87,14 +87,6 @@ static void lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb); static int lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc); -static void -lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, - struct lpfc_vmid *vmp); -static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd - *cmd, struct lpfc_vmid *vmp, - union lpfc_vmid_io_tag *tag); -static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, - struct lpfc_vmid *vmid); /** * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. @@ -5270,254 +5262,6 @@ void lpfc_poll_timeout(struct timer_list *t) } } -/* - * lpfc_get_vmid_from_hashtable - search the UUID in the hash table - * @vport: The virtual port for which this call is being executed. - * @hash: calculated hash value - * @buf: uuid associated with the VE - * Return the VMID entry associated with the UUID - * Make sure to acquire the appropriate lock before invoking this routine. - */ -struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, - u32 hash, u8 *buf) -{ - struct lpfc_vmid *vmp; - - hash_for_each_possible(vport->hash_table, vmp, hnode, hash) { - if (memcmp(&vmp->host_vmid[0], buf, 16) == 0) - return vmp; - } - return NULL; -} - -/* - * lpfc_put_vmid_in_hashtable - put the VMID in the hash table - * @vport: The virtual port for which this call is being executed. - * @hash - calculated hash value - * @vmp: Pointer to a VMID entry representing a VM sending I/O - * - * This routine will insert the newly acquired VMID entity in the hash table. - * Make sure to acquire the appropriate lock before invoking this routine. - */ -static void -lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, - struct lpfc_vmid *vmp) -{ - hash_add(vport->hash_table, &vmp->hnode, hash); -} - -/* - * lpfc_vmid_hash_fn - create a hash value of the UUID - * @vmid: uuid associated with the VE - * @len: length of the VMID string - * Returns the calculated hash value - */ -int lpfc_vmid_hash_fn(const char *vmid, int len) -{ - int c; - int hash = 0; - - if (len == 0) - return 0; - while (len--) { - c = *vmid++; - if (c >= 'A' && c <= 'Z') - c += 'a' - 'A'; - - hash = (hash + (c << LPFC_VMID_HASH_SHIFT) + - (c >> LPFC_VMID_HASH_SHIFT)) * 19; - } - - return hash & LPFC_VMID_HASH_MASK; -} - -/* - * lpfc_vmid_update_entry - update the vmid entry in the hash table - * @vport: The virtual port for which this call is being executed. - * @cmd: address of scsi cmd descriptor - * @vmp: Pointer to a VMID entry representing a VM sending I/O - * @tag: VMID tag - */ -static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd - *cmd, struct lpfc_vmid *vmp, - union lpfc_vmid_io_tag *tag) -{ - u64 *lta; - - if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) - tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid; - else if (vport->phba->cfg_vmid_app_header) - tag->app_id = vmp->un.app_id; - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - vmp->io_wr_cnt++; - else - vmp->io_rd_cnt++; - - /* update the last access timestamp in the table */ - lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id()); - *lta = jiffies; -} - -static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, - struct lpfc_vmid *vmid) -{ - u32 hash; - struct lpfc_vmid *pvmid; - - if (vport->port_type == LPFC_PHYSICAL_PORT) { - vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); - } else { - hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len); - pvmid = - lpfc_get_vmid_from_hashtable(vport->phba->pport, hash, - vmid->host_vmid); - if (pvmid) - vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid; - else - vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); - } -} - -/* - * lpfc_vmid_get_appid - get the VMID associated with the UUID - * @vport: The virtual port for which this call is being executed. - * @uuid: UUID associated with the VE - * @cmd: address of scsi_cmd descriptor - * @tag: VMID tag - * Returns status of the function - */ -static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct - scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag) -{ - struct lpfc_vmid *vmp = NULL; - int hash, len, rc = -EPERM, i; - - /* check if QFPA is complete */ - if (lpfc_vmid_is_type_priority_tag(vport) && - !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) && - (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) { - vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA; - return -EAGAIN; - } - - /* search if the UUID has already been mapped to the VMID */ - len = strlen(uuid); - hash = lpfc_vmid_hash_fn(uuid, len); - - /* search for the VMID in the table */ - read_lock(&vport->vmid_lock); - vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); - - /* if found, check if its already registered */ - if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { - read_unlock(&vport->vmid_lock); - lpfc_vmid_update_entry(vport, cmd, vmp, tag); - rc = 0; - } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER || - vmp->flag & LPFC_VMID_DE_REGISTER)) { - /* else if register or dereg request has already been sent */ - /* Hence VMID tag will not be added for this I/O */ - read_unlock(&vport->vmid_lock); - rc = -EBUSY; - } else { - /* The VMID was not found in the hashtable. At this point, */ - /* drop the read lock first before proceeding further */ - read_unlock(&vport->vmid_lock); - /* start the process to obtain one as per the */ - /* type of the VMID indicated */ - write_lock(&vport->vmid_lock); - vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); - - /* while the read lock was released, in case the entry was */ - /* added by other context or is in process of being added */ - if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { - lpfc_vmid_update_entry(vport, cmd, vmp, tag); - write_unlock(&vport->vmid_lock); - return 0; - } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) { - write_unlock(&vport->vmid_lock); - return -EBUSY; - } - - /* else search and allocate a free slot in the hash table */ - if (vport->cur_vmid_cnt < vport->max_vmid) { - for (i = 0; i < vport->max_vmid; i++) { - vmp = vport->vmid + i; - if (vmp->flag == LPFC_VMID_SLOT_FREE) - break; - } - if (i == vport->max_vmid) - vmp = NULL; - } else { - vmp = NULL; - } - - if (!vmp) { - write_unlock(&vport->vmid_lock); - return -ENOMEM; - } - - /* Add the vmid and register */ - lpfc_put_vmid_in_hashtable(vport, hash, vmp); - vmp->vmid_len = len; - memcpy(vmp->host_vmid, uuid, vmp->vmid_len); - vmp->io_rd_cnt = 0; - vmp->io_wr_cnt = 0; - vmp->flag = LPFC_VMID_SLOT_USED; - - vmp->delete_inactive = - vport->vmid_inactivity_timeout ? 1 : 0; - - /* if type priority tag, get next available VMID */ - if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) - lpfc_vmid_assign_cs_ctl(vport, vmp); - - /* allocate the per cpu variable for holding */ - /* the last access time stamp only if VMID is enabled */ - if (!vmp->last_io_time) - vmp->last_io_time = __alloc_percpu(sizeof(u64), - __alignof__(struct - lpfc_vmid)); - if (!vmp->last_io_time) { - hash_del(&vmp->hnode); - vmp->flag = LPFC_VMID_SLOT_FREE; - write_unlock(&vport->vmid_lock); - return -EIO; - } - - write_unlock(&vport->vmid_lock); - - /* complete transaction with switch */ - if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) - rc = lpfc_vmid_uvem(vport, vmp, true); - else if (vport->phba->cfg_vmid_app_header) - rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp); - if (!rc) { - write_lock(&vport->vmid_lock); - vport->cur_vmid_cnt++; - vmp->flag |= LPFC_VMID_REQ_REGISTER; - write_unlock(&vport->vmid_lock); - } else { - write_lock(&vport->vmid_lock); - hash_del(&vmp->hnode); - vmp->flag = LPFC_VMID_SLOT_FREE; - free_percpu(vmp->last_io_time); - write_unlock(&vport->vmid_lock); - return -EIO; - } - - /* finally, enable the idle timer once */ - if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) { - mod_timer(&vport->phba->inactive_vmid_poll, - jiffies + - msecs_to_jiffies(1000 * LPFC_VMID_TIMER)); - vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD; - } - } - return rc; -} - /* * lpfc_is_command_vm_io - get the UUID from blk cgroup * @cmd: Pointer to scsi_cmnd data structure diff --git a/drivers/scsi/lpfc/lpfc_vmid.c b/drivers/scsi/lpfc/lpfc_vmid.c new file mode 100644 index 000000000000..f64ced04b912 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_vmid.c @@ -0,0 +1,288 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2004-2016 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.broadcom.com * + * Portions Copyright (C) 2004-2005 Christoph Hellwig * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ + +#include <linux/interrupt.h> +#include <linux/dma-direction.h> + +#include <scsi/scsi_transport_fc.h> + +#include "lpfc_hw4.h" +#include "lpfc_hw.h" +#include "lpfc_sli.h" +#include "lpfc_sli4.h" +#include "lpfc_nl.h" +#include "lpfc_disc.h" +#include "lpfc.h" +#include "lpfc_crtn.h" + + +/* + * lpfc_get_vmid_from_hashtable - search the UUID in the hash table + * @vport: The virtual port for which this call is being executed. + * @hash: calculated hash value + * @buf: uuid associated with the VE + * Return the VMID entry associated with the UUID + * Make sure to acquire the appropriate lock before invoking this routine. + */ +struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, + u32 hash, u8 *buf) +{ + struct lpfc_vmid *vmp; + + hash_for_each_possible(vport->hash_table, vmp, hnode, hash) { + if (memcmp(&vmp->host_vmid[0], buf, 16) == 0) + return vmp; + } + return NULL; +} + +/* + * lpfc_put_vmid_in_hashtable - put the VMID in the hash table + * @vport: The virtual port for which this call is being executed. + * @hash - calculated hash value + * @vmp: Pointer to a VMID entry representing a VM sending I/O + * + * This routine will insert the newly acquired VMID entity in the hash table. + * Make sure to acquire the appropriate lock before invoking this routine. + */ +static void +lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, + struct lpfc_vmid *vmp) +{ + hash_add(vport->hash_table, &vmp->hnode, hash); +} + +/* + * lpfc_vmid_hash_fn - create a hash value of the UUID + * @vmid: uuid associated with the VE + * @len: length of the VMID string + * Returns the calculated hash value + */ +int lpfc_vmid_hash_fn(const char *vmid, int len) +{ + int c; + int hash = 0; + + if (len == 0) + return 0; + while (len--) { + c = *vmid++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + + hash = (hash + (c << LPFC_VMID_HASH_SHIFT) + + (c >> LPFC_VMID_HASH_SHIFT)) * 19; + } + + return hash & LPFC_VMID_HASH_MASK; +} + +/* + * lpfc_vmid_update_entry - update the vmid entry in the hash table + * @vport: The virtual port for which this call is being executed. + * @iodir: io direction + * @vmp: Pointer to a VMID entry representing a VM sending I/O + * @tag: VMID tag + */ +static void lpfc_vmid_update_entry(struct lpfc_vport *vport, + enum dma_data_direction iodir, + struct lpfc_vmid *vmp, + union lpfc_vmid_io_tag *tag) +{ + u64 *lta; + + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid; + else if (vport->phba->cfg_vmid_app_header) + tag->app_id = vmp->un.app_id; + + if (iodir == DMA_TO_DEVICE) + vmp->io_wr_cnt++; + else if (iodir == DMA_FROM_DEVICE) + vmp->io_rd_cnt++; + + /* update the last access timestamp in the table */ + lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id()); + *lta = jiffies; +} + +static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, + struct lpfc_vmid *vmid) +{ + u32 hash; + struct lpfc_vmid *pvmid; + + if (vport->port_type == LPFC_PHYSICAL_PORT) { + vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); + } else { + hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len); + pvmid = + lpfc_get_vmid_from_hashtable(vport->phba->pport, hash, + vmid->host_vmid); + if (pvmid) + vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid; + else + vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); + } +} + +/* + * lpfc_vmid_get_appid - get the VMID associated with the UUID + * @vport: The virtual port for which this call is being executed. + * @uuid: UUID associated with the VE + * @cmd: address of scsi_cmd descriptor + * @iodir: io direction + * @tag: VMID tag + * Returns status of the function + */ +int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, + enum dma_data_direction iodir, + union lpfc_vmid_io_tag *tag) +{ + struct lpfc_vmid *vmp = NULL; + int hash, len, rc = -EPERM, i; + + /* check if QFPA is complete */ + if (lpfc_vmid_is_type_priority_tag(vport) && + !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) && + (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) { + vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA; + return -EAGAIN; + } + + /* search if the UUID has already been mapped to the VMID */ + len = strlen(uuid); + hash = lpfc_vmid_hash_fn(uuid, len); + + /* search for the VMID in the table */ + read_lock(&vport->vmid_lock); + vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); + + /* if found, check if its already registered */ + if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { + read_unlock(&vport->vmid_lock); + lpfc_vmid_update_entry(vport, iodir, vmp, tag); + rc = 0; + } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER || + vmp->flag & LPFC_VMID_DE_REGISTER)) { + /* else if register or dereg request has already been sent */ + /* Hence VMID tag will not be added for this I/O */ + read_unlock(&vport->vmid_lock); + rc = -EBUSY; + } else { + /* The VMID was not found in the hashtable. At this point, */ + /* drop the read lock first before proceeding further */ + read_unlock(&vport->vmid_lock); + /* start the process to obtain one as per the */ + /* type of the VMID indicated */ + write_lock(&vport->vmid_lock); + vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); + + /* while the read lock was released, in case the entry was */ + /* added by other context or is in process of being added */ + if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { + lpfc_vmid_update_entry(vport, iodir, vmp, tag); + write_unlock(&vport->vmid_lock); + return 0; + } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) { + write_unlock(&vport->vmid_lock); + return -EBUSY; + } + + /* else search and allocate a free slot in the hash table */ + if (vport->cur_vmid_cnt < vport->max_vmid) { + for (i = 0; i < vport->max_vmid; i++) { + vmp = vport->vmid + i; + if (vmp->flag == LPFC_VMID_SLOT_FREE) + break; + } + if (i == vport->max_vmid) + vmp = NULL; + } else { + vmp = NULL; + } + + if (!vmp) { + write_unlock(&vport->vmid_lock); + return -ENOMEM; + } + + /* Add the vmid and register */ + lpfc_put_vmid_in_hashtable(vport, hash, vmp); + vmp->vmid_len = len; + memcpy(vmp->host_vmid, uuid, vmp->vmid_len); + vmp->io_rd_cnt = 0; + vmp->io_wr_cnt = 0; + vmp->flag = LPFC_VMID_SLOT_USED; + + vmp->delete_inactive = + vport->vmid_inactivity_timeout ? 1 : 0; + + /* if type priority tag, get next available VMID */ + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + lpfc_vmid_assign_cs_ctl(vport, vmp); + + /* allocate the per cpu variable for holding */ + /* the last access time stamp only if VMID is enabled */ + if (!vmp->last_io_time) + vmp->last_io_time = __alloc_percpu(sizeof(u64), + __alignof__(struct + lpfc_vmid)); + if (!vmp->last_io_time) { + hash_del(&vmp->hnode); + vmp->flag = LPFC_VMID_SLOT_FREE; + write_unlock(&vport->vmid_lock); + return -EIO; + } + + write_unlock(&vport->vmid_lock); + + /* complete transaction with switch */ + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + rc = lpfc_vmid_uvem(vport, vmp, true); + else if (vport->phba->cfg_vmid_app_header) + rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp); + if (!rc) { + write_lock(&vport->vmid_lock); + vport->cur_vmid_cnt++; + vmp->flag |= LPFC_VMID_REQ_REGISTER; + write_unlock(&vport->vmid_lock); + } else { + write_lock(&vport->vmid_lock); + hash_del(&vmp->hnode); + vmp->flag = LPFC_VMID_SLOT_FREE; + free_percpu(vmp->last_io_time); + write_unlock(&vport->vmid_lock); + return -EIO; + } + + /* finally, enable the idle timer once */ + if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) { + mod_timer(&vport->phba->inactive_vmid_poll, + jiffies + + msecs_to_jiffies(1000 * LPFC_VMID_TIMER)); + vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD; + } + } + return rc; +}