Commit 7d791df7 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.25: Add FCF priority failover functionality

This patch implements a new FCF failover policy for the lpfc driver. It
allows the driver to choose which FCF to failover to based on the FCF
priority. This patch also introduces a new sysfs parameter
(fcf_failover_policy) to allow the user to choose which FCF failover policy
to use.
Signed-off-by: default avatarAlex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent b76f2dc9
...@@ -680,6 +680,9 @@ struct lpfc_hba { ...@@ -680,6 +680,9 @@ struct lpfc_hba {
uint32_t cfg_enable_rrq; uint32_t cfg_enable_rrq;
uint32_t cfg_topology; uint32_t cfg_topology;
uint32_t cfg_link_speed; uint32_t cfg_link_speed;
#define LPFC_FCF_FOV 1 /* Fast fcf failover */
#define LPFC_FCF_PRIORITY 2 /* Priority fcf failover */
uint32_t cfg_fcf_failover_policy;
uint32_t cfg_cr_delay; uint32_t cfg_cr_delay;
uint32_t cfg_cr_count; uint32_t cfg_cr_count;
uint32_t cfg_multi_ring_support; uint32_t cfg_multi_ring_support;
......
...@@ -2193,6 +2193,9 @@ lpfc_param_show(enable_npiv); ...@@ -2193,6 +2193,9 @@ lpfc_param_show(enable_npiv);
lpfc_param_init(enable_npiv, 1, 0, 1); lpfc_param_init(enable_npiv, 1, 0, 1);
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL); static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
"FCF Fast failover=1 Priority failover=2");
int lpfc_enable_rrq; int lpfc_enable_rrq;
module_param(lpfc_enable_rrq, int, S_IRUGO); module_param(lpfc_enable_rrq, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality"); MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
...@@ -3775,6 +3778,7 @@ struct device_attribute *lpfc_hba_attrs[] = { ...@@ -3775,6 +3778,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_fdmi_on, &dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns, &dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv, &dev_attr_lpfc_enable_npiv,
&dev_attr_lpfc_fcf_failover_policy,
&dev_attr_lpfc_enable_rrq, &dev_attr_lpfc_enable_rrq,
&dev_attr_nport_evt_cnt, &dev_attr_nport_evt_cnt,
&dev_attr_board_mode, &dev_attr_board_mode,
...@@ -4995,6 +4999,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) ...@@ -4995,6 +4999,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_link_speed_init(phba, lpfc_link_speed); lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo); lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
lpfc_enable_npiv_init(phba, lpfc_enable_npiv); lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
lpfc_enable_rrq_init(phba, lpfc_enable_rrq); lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
lpfc_use_msi_init(phba, lpfc_use_msi); lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax); lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
......
...@@ -235,9 +235,11 @@ int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *); ...@@ -235,9 +235,11 @@ int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *);
void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *); void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *);
void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *); void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);
uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *); uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *);
void lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *, uint16_t);
int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t); int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);
void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t); void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);
int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t); int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);
int lpfc_mem_alloc(struct lpfc_hba *, int align); int lpfc_mem_alloc(struct lpfc_hba *, int align);
void lpfc_mem_free(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *);
......
...@@ -874,6 +874,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ...@@ -874,6 +874,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
phba->fcf.current_rec.fcf_indx, phba->fcf.current_rec.fcf_indx,
irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout); irsp->ulpTimeout);
lpfc_sli4_set_fcf_flogi_fail(phba,
phba->fcf.current_rec.fcf_indx);
fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index); rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);
if (rc) if (rc)
......
This diff is collapsed.
...@@ -3634,8 +3634,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, ...@@ -3634,8 +3634,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
lpfc_sli4_fcf_dead_failthrough(phba); lpfc_sli4_fcf_dead_failthrough(phba);
} else { } else {
/* Reset FCF roundrobin bmask for new discovery */ /* Reset FCF roundrobin bmask for new discovery */
memset(phba->fcf.fcf_rr_bmask, 0, lpfc_sli4_clear_fcf_rr_bmask(phba);
sizeof(*phba->fcf.fcf_rr_bmask));
/* /*
* Handling fast FCF failover to a DEAD FCF event is * Handling fast FCF failover to a DEAD FCF event is
* considered equalivant to receiving CVL to all vports. * considered equalivant to receiving CVL to all vports.
...@@ -3721,8 +3720,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, ...@@ -3721,8 +3720,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
* Reset FCF roundrobin bmask for new * Reset FCF roundrobin bmask for new
* discovery. * discovery.
*/ */
memset(phba->fcf.fcf_rr_bmask, 0, lpfc_sli4_clear_fcf_rr_bmask(phba);
sizeof(*phba->fcf.fcf_rr_bmask));
} }
break; break;
default: default:
...@@ -9046,6 +9044,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -9046,6 +9044,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
} }
INIT_LIST_HEAD(&phba->active_rrq_list); INIT_LIST_HEAD(&phba->active_rrq_list);
INIT_LIST_HEAD(&phba->fcf.fcf_pri_list);
/* Set up common device driver resources */ /* Set up common device driver resources */
error = lpfc_setup_driver_resource_phase2(phba); error = lpfc_setup_driver_resource_phase2(phba);
......
...@@ -14634,6 +14634,92 @@ lpfc_sli4_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) ...@@ -14634,6 +14634,92 @@ lpfc_sli4_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
return error; return error;
} }
/**
* lpfc_check_next_fcf_pri
* phba pointer to the lpfc_hba struct for this port.
* This routine is called from the lpfc_sli4_fcf_rr_next_index_get
* routine when the rr_bmask is empty. The FCF indecies are put into the
* rr_bmask based on their priority level. Starting from the highest priority
* to the lowest. The most likely FCF candidate will be in the highest
* priority group. When this routine is called it searches the fcf_pri list for
* next lowest priority group and repopulates the rr_bmask with only those
* fcf_indexes.
* returns:
* 1=success 0=failure
**/
int
lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba)
{
uint16_t next_fcf_pri;
uint16_t last_index;
struct lpfc_fcf_pri *fcf_pri;
int rc;
int ret = 0;
last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"3060 Last IDX %d\n", last_index);
if (list_empty(&phba->fcf.fcf_pri_list)) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
"3061 Last IDX %d\n", last_index);
return 0; /* Empty rr list */
}
next_fcf_pri = 0;
/*
* Clear the rr_bmask and set all of the bits that are at this
* priority.
*/
memset(phba->fcf.fcf_rr_bmask, 0,
sizeof(*phba->fcf.fcf_rr_bmask));
spin_lock_irq(&phba->hbalock);
list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
if (fcf_pri->fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)
continue;
/*
* the 1st priority that has not FLOGI failed
* will be the highest.
*/
if (!next_fcf_pri)
next_fcf_pri = fcf_pri->fcf_rec.priority;
spin_unlock_irq(&phba->hbalock);
if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
rc = lpfc_sli4_fcf_rr_index_set(phba,
fcf_pri->fcf_rec.fcf_index);
if (rc)
return 0;
}
spin_lock_irq(&phba->hbalock);
}
/*
* if next_fcf_pri was not set above and the list is not empty then
* we have failed flogis on all of them. So reset flogi failed
* and start at the begining.
*/
if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) {
list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
fcf_pri->fcf_rec.flag &= ~LPFC_FCF_FLOGI_FAILED;
/*
* the 1st priority that has not FLOGI failed
* will be the highest.
*/
if (!next_fcf_pri)
next_fcf_pri = fcf_pri->fcf_rec.priority;
spin_unlock_irq(&phba->hbalock);
if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
rc = lpfc_sli4_fcf_rr_index_set(phba,
fcf_pri->fcf_rec.fcf_index);
if (rc)
return 0;
}
spin_lock_irq(&phba->hbalock);
}
} else
ret = 1;
spin_unlock_irq(&phba->hbalock);
return ret;
}
/** /**
* lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index
* @phba: pointer to lpfc hba data structure. * @phba: pointer to lpfc hba data structure.
...@@ -14650,6 +14736,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) ...@@ -14650,6 +14736,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
uint16_t next_fcf_index; uint16_t next_fcf_index;
/* Search start from next bit of currently registered FCF index */ /* Search start from next bit of currently registered FCF index */
next_priority:
next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) % next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %
LPFC_SLI4_FCF_TBL_INDX_MAX; LPFC_SLI4_FCF_TBL_INDX_MAX;
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
...@@ -14657,16 +14744,45 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) ...@@ -14657,16 +14744,45 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
next_fcf_index); next_fcf_index);
/* Wrap around condition on phba->fcf.fcf_rr_bmask */ /* Wrap around condition on phba->fcf.fcf_rr_bmask */
if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
/*
* If we have wrapped then we need to clear the bits that
* have been tested so that we can detect when we should
* change the priority level.
*/
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX, 0); LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
}
/* Check roundrobin failover list empty condition */ /* Check roundrobin failover list empty condition */
if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX ||
next_fcf_index == phba->fcf.current_rec.fcf_indx) {
/*
* If next fcf index is not found check if there are lower
* Priority level fcf's in the fcf_priority list.
* Set up the rr_bmask with all of the avaiable fcf bits
* at that level and continue the selection process.
*/
if (lpfc_check_next_fcf_pri_level(phba))
goto next_priority;
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
"2844 No roundrobin failover FCF available\n"); "2844 No roundrobin failover FCF available\n");
if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
return LPFC_FCOE_FCF_NEXT_NONE; return LPFC_FCOE_FCF_NEXT_NONE;
else {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
"3063 Only FCF available idx %d, flag %x\n",
next_fcf_index,
phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag);
return next_fcf_index;
} }
}
if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
LPFC_FCF_FLOGI_FAILED)
goto next_priority;
lpfc_printf_log(phba, KERN_INFO, LOG_FIP, lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2845 Get next roundrobin failover FCF (x%x)\n", "2845 Get next roundrobin failover FCF (x%x)\n",
...@@ -14719,6 +14835,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index) ...@@ -14719,6 +14835,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
void void
lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
{ {
struct lpfc_fcf_pri *fcf_pri;
if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
lpfc_printf_log(phba, KERN_ERR, LOG_FIP, lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
"2762 FCF (x%x) reached driver's book " "2762 FCF (x%x) reached driver's book "
...@@ -14727,6 +14844,14 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) ...@@ -14727,6 +14844,14 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
return; return;
} }
/* Clear the eligible FCF record index bmask */ /* Clear the eligible FCF record index bmask */
spin_lock_irq(&phba->hbalock);
list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
if (fcf_pri->fcf_rec.fcf_index == fcf_index) {
list_del_init(&fcf_pri->list);
break;
}
}
spin_unlock_irq(&phba->hbalock);
clear_bit(fcf_index, phba->fcf.fcf_rr_bmask); clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP, lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
......
...@@ -159,6 +159,25 @@ struct lpfc_fcf_rec { ...@@ -159,6 +159,25 @@ struct lpfc_fcf_rec {
#define RECORD_VALID 0x02 #define RECORD_VALID 0x02
}; };
struct lpfc_fcf_pri_rec {
uint16_t fcf_index;
#define LPFC_FCF_ON_PRI_LIST 0x0001
#define LPFC_FCF_FLOGI_FAILED 0x0002
uint16_t flag;
uint32_t priority;
};
struct lpfc_fcf_pri {
struct list_head list;
struct lpfc_fcf_pri_rec fcf_rec;
};
/*
* Maximum FCF table index, it is for driver internal book keeping, it
* just needs to be no less than the supported HBA's FCF table size.
*/
#define LPFC_SLI4_FCF_TBL_INDX_MAX 32
struct lpfc_fcf { struct lpfc_fcf {
uint16_t fcfi; uint16_t fcfi;
uint32_t fcf_flag; uint32_t fcf_flag;
...@@ -178,15 +197,13 @@ struct lpfc_fcf { ...@@ -178,15 +197,13 @@ struct lpfc_fcf {
uint32_t eligible_fcf_cnt; uint32_t eligible_fcf_cnt;
struct lpfc_fcf_rec current_rec; struct lpfc_fcf_rec current_rec;
struct lpfc_fcf_rec failover_rec; struct lpfc_fcf_rec failover_rec;
struct list_head fcf_pri_list;
struct lpfc_fcf_pri fcf_pri[LPFC_SLI4_FCF_TBL_INDX_MAX];
uint32_t current_fcf_scan_pri;
struct timer_list redisc_wait; struct timer_list redisc_wait;
unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */ unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */
}; };
/*
* Maximum FCF table index, it is for driver internal book keeping, it
* just needs to be no less than the supported HBA's FCF table size.
*/
#define LPFC_SLI4_FCF_TBL_INDX_MAX 32
#define LPFC_REGION23_SIGNATURE "RG23" #define LPFC_REGION23_SIGNATURE "RG23"
#define LPFC_REGION23_VERSION 1 #define LPFC_REGION23_VERSION 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment