Skip to content

Commit

Permalink
scsi: lpfc: vmid: Timeout implementation for VMID
Browse files Browse the repository at this point in the history
Implement timeout functionality for the VMID. After the set time period of
inactivity, the VMID is deregistered from the switch.

Link: https://lore.kernel.org/r/20210608043556.274139-12-muneendra.kumar@broadcom.com
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Gaurav Srivastava <gaurav.srivastava@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Muneendra Kumar <muneendra.kumar@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Gaurav Srivastava authored and Martin K. Petersen committed Jun 10, 2021
1 parent f56e86a commit 2039717
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
105 changes: 105 additions & 0 deletions drivers/scsi/lpfc/lpfc_hbadisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static void lpfc_disc_flush_list(struct lpfc_vport *vport);
static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
static int lpfc_fcf_inuse(struct lpfc_hba *);
static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
static void lpfc_check_inactive_vmid(struct lpfc_hba *phba);

static int
lpfc_valid_xpt_node(struct lpfc_nodelist *ndlp)
Expand Down Expand Up @@ -234,6 +235,110 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
return;
}

/**
* lpfc_check_inactive_vmid_one - VMID inactivity checker for a vport
* @vport: Pointer to vport context object.
*
* This function checks for idle VMID entries related to a particular vport. If
* found unused/idle, free them accordingly.
**/
static void lpfc_check_inactive_vmid_one(struct lpfc_vport *vport)
{
u16 keep;
u32 difftime = 0, r, bucket;
u64 *lta;
int cpu;
struct lpfc_vmid *vmp;

write_lock(&vport->vmid_lock);

if (!vport->cur_vmid_cnt)
goto out;

/* iterate through the table */
hash_for_each(vport->hash_table, bucket, vmp, hnode) {
keep = 0;
if (vmp->flag & LPFC_VMID_REGISTERED) {
/* check if the particular VMID is in use */
/* for all available per cpu variable */
for_each_possible_cpu(cpu) {
/* if last access time is less than timeout */
lta = per_cpu_ptr(vmp->last_io_time, cpu);
if (!lta)
continue;
difftime = (jiffies) - (*lta);
if ((vport->vmid_inactivity_timeout *
JIFFIES_PER_HR) > difftime) {
keep = 1;
break;
}
}

/* if none of the cpus have been used by the vm, */
/* remove the entry if already registered */
if (!keep) {
/* mark the entry for deregistration */
vmp->flag = LPFC_VMID_DE_REGISTER;
write_unlock(&vport->vmid_lock);
if (vport->vmid_priority_tagging)
r = lpfc_vmid_uvem(vport, vmp, false);
else
r = lpfc_vmid_cmd(vport,
SLI_CTAS_DAPP_IDENT,
vmp);

/* decrement number of active vms and mark */
/* entry in slot as free */
write_lock(&vport->vmid_lock);
if (!r) {
struct lpfc_vmid *ht = vmp;

vport->cur_vmid_cnt--;
ht->flag = LPFC_VMID_SLOT_FREE;
free_percpu(ht->last_io_time);
ht->last_io_time = NULL;
hash_del(&ht->hnode);
}
}
}
}
out:
write_unlock(&vport->vmid_lock);
}

/**
* lpfc_check_inactive_vmid - VMID inactivity checker
* @phba: Pointer to hba context object.
*
* This function is called from the worker thread to determine if an entry in
* the VMID table can be released since there was no I/O activity seen from that
* particular VM for the specified time. When this happens, the entry in the
* table is released and also the resources on the switch cleared.
**/

static void lpfc_check_inactive_vmid(struct lpfc_hba *phba)
{
struct lpfc_vport *vport;
struct lpfc_vport **vports;
int i;

vports = lpfc_create_vport_work_array(phba);
if (!vports)
return;

for (i = 0; i <= phba->max_vports; i++) {
if ((!vports[i]) && (i == 0))
vport = phba->pport;
else
vport = vports[i];
if (!vport)
break;

lpfc_check_inactive_vmid_one(vport);
}
lpfc_destroy_vport_work_array(phba, vports);
}

/**
* lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
* @ndlp: Pointer to remote node object.
Expand Down
40 changes: 40 additions & 0 deletions drivers/scsi/lpfc/lpfc_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -4843,6 +4843,42 @@ lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t)
lpfc_worker_wake_up(phba);
}

/**
* lpfc_vmid_poll - VMID timeout detection
* @ptr: Map to lpfc_hba data structure pointer.
*
* This routine is invoked when there is no I/O on by a VM for the specified
* amount of time. When this situation is detected, the VMID has to be
* deregistered from the switch and all the local resources freed. The VMID
* will be reassigned to the VM once the I/O begins.
**/
static void
lpfc_vmid_poll(struct timer_list *t)
{
struct lpfc_hba *phba = from_timer(phba, t, inactive_vmid_poll);
u32 wake_up = 0;

/* check if there is a need to issue QFPA */
if (phba->pport->vmid_priority_tagging) {
wake_up = 1;
phba->pport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
}

/* Is the vmid inactivity timer enabled */
if (phba->pport->vmid_inactivity_timeout ||
phba->pport->load_flag & FC_DEREGISTER_ALL_APP_ID) {
wake_up = 1;
phba->pport->work_port_events |= WORKER_CHECK_INACTIVE_VMID;
}

if (wake_up)
lpfc_worker_wake_up(phba);

/* restart the timer for the next iteration */
mod_timer(&phba->inactive_vmid_poll, jiffies + msecs_to_jiffies(1000 *
LPFC_VMID_TIMER));
}

/**
* lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
* @phba: pointer to lpfc hba data structure.
Expand Down Expand Up @@ -6691,6 +6727,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc;
phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free;

/* for VMID idle timeout if VMID is enabled */
if (lpfc_is_vmid_enabled(phba))
timer_setup(&phba->inactive_vmid_poll, lpfc_vmid_poll, 0);

/*
* Initialize the SLI Layer to run with lpfc SLI4 HBAs.
*/
Expand Down

0 comments on commit 2039717

Please sign in to comment.