|
@@ -1109,6 +1109,28 @@ out:
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * lpfc_sli4_clear_fcf_rr_bmask
|
|
|
+ * @phba pointer to the struct lpfc_hba for this port.
|
|
|
+ * This fucnction resets the round robin bit mask and clears the
|
|
|
+ * fcf priority list. The list deletions are done while holding the
|
|
|
+ * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared
|
|
|
+ * from the lpfc_fcf_pri record.
|
|
|
+ **/
|
|
|
+void
|
|
|
+lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba)
|
|
|
+{
|
|
|
+ struct lpfc_fcf_pri *fcf_pri;
|
|
|
+ struct lpfc_fcf_pri *next_fcf_pri;
|
|
|
+ memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ list_for_each_entry_safe(fcf_pri, next_fcf_pri,
|
|
|
+ &phba->fcf.fcf_pri_list, list) {
|
|
|
+ list_del_init(&fcf_pri->list);
|
|
|
+ fcf_pri->fcf_rec.flag = 0;
|
|
|
+ }
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+}
|
|
|
static void
|
|
|
lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|
|
{
|
|
@@ -1130,7 +1152,8 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|
|
spin_unlock_irq(&phba->hbalock);
|
|
|
|
|
|
/* If there is a pending FCoE event, restart FCF table scan. */
|
|
|
- if (lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
|
|
|
+ if ((!(phba->hba_flag & FCF_RR_INPROG)) &&
|
|
|
+ lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
|
|
|
goto fail_out;
|
|
|
|
|
|
/* Mark successful completion of FCF table scan */
|
|
@@ -1249,6 +1272,30 @@ lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id)
|
|
|
return (curr_vlan_id == new_vlan_id);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * lpfc_update_fcf_record - Update driver fcf record
|
|
|
+ * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record.
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
+ * @fcf_index: Index for the lpfc_fcf_record.
|
|
|
+ * @new_fcf_record: pointer to hba fcf record.
|
|
|
+ *
|
|
|
+ * This routine updates the driver FCF priority record from the new HBA FCF
|
|
|
+ * record. This routine is called with the host lock held.
|
|
|
+ **/
|
|
|
+static void
|
|
|
+__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index,
|
|
|
+ struct fcf_record *new_fcf_record
|
|
|
+ )
|
|
|
+{
|
|
|
+ struct lpfc_fcf_pri *fcf_pri;
|
|
|
+
|
|
|
+ fcf_pri = &phba->fcf.fcf_pri[fcf_index];
|
|
|
+ fcf_pri->fcf_rec.fcf_index = fcf_index;
|
|
|
+ /* FCF record priority */
|
|
|
+ fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
|
|
|
* @fcf: pointer to driver fcf record.
|
|
@@ -1332,6 +1379,9 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
|
|
|
fcf_rec->addr_mode = addr_mode;
|
|
|
fcf_rec->vlan_id = vlan_id;
|
|
|
fcf_rec->flag |= (flag | RECORD_VALID);
|
|
|
+ __lpfc_update_fcf_record_pri(phba,
|
|
|
+ bf_get(lpfc_fcf_record_fcf_index, new_fcf_record),
|
|
|
+ new_fcf_record);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1834,6 +1884,8 @@ lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
|
|
|
return false;
|
|
|
if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
|
|
|
return false;
|
|
|
+ if (fcf_rec->priority != new_fcf_record->fip_priority)
|
|
|
+ return false;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -1896,6 +1948,152 @@ stop_flogi_current_fcf:
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * lpfc_sli4_fcf_pri_list_del
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
+ * @fcf_index the index of the fcf record to delete
|
|
|
+ * This routine checks the on list flag of the fcf_index to be deleted.
|
|
|
+ * If it is one the list then it is removed from the list, and the flag
|
|
|
+ * is cleared. This routine grab the hbalock before removing the fcf
|
|
|
+ * record from the list.
|
|
|
+ **/
|
|
|
+static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba,
|
|
|
+ uint16_t fcf_index)
|
|
|
+{
|
|
|
+ struct lpfc_fcf_pri *new_fcf_pri;
|
|
|
+
|
|
|
+ new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
|
|
|
+ "3058 deleting idx x%x pri x%x flg x%x\n",
|
|
|
+ fcf_index, new_fcf_pri->fcf_rec.priority,
|
|
|
+ new_fcf_pri->fcf_rec.flag);
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) {
|
|
|
+ if (phba->fcf.current_rec.priority ==
|
|
|
+ new_fcf_pri->fcf_rec.priority)
|
|
|
+ phba->fcf.eligible_fcf_cnt--;
|
|
|
+ list_del_init(&new_fcf_pri->list);
|
|
|
+ new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST;
|
|
|
+ }
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * lpfc_sli4_set_fcf_flogi_fail
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
+ * @fcf_index the index of the fcf record to update
|
|
|
+ * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED
|
|
|
+ * flag so the the round robin slection for the particular priority level
|
|
|
+ * will try a different fcf record that does not have this bit set.
|
|
|
+ * If the fcf record is re-read for any reason this flag is cleared brfore
|
|
|
+ * adding it to the priority list.
|
|
|
+ **/
|
|
|
+void
|
|
|
+lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index)
|
|
|
+{
|
|
|
+ struct lpfc_fcf_pri *new_fcf_pri;
|
|
|
+ new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * lpfc_sli4_fcf_pri_list_add
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
+ * @fcf_index the index of the fcf record to add
|
|
|
+ * This routine checks the priority of the fcf_index to be added.
|
|
|
+ * If it is a lower priority than the current head of the fcf_pri list
|
|
|
+ * then it is added to the list in the right order.
|
|
|
+ * If it is the same priority as the current head of the list then it
|
|
|
+ * is added to the head of the list and its bit in the rr_bmask is set.
|
|
|
+ * If the fcf_index to be added is of a higher priority than the current
|
|
|
+ * head of the list then the rr_bmask is cleared, its bit is set in the
|
|
|
+ * rr_bmask and it is added to the head of the list.
|
|
|
+ * returns:
|
|
|
+ * 0=success 1=failure
|
|
|
+ **/
|
|
|
+int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, uint16_t fcf_index,
|
|
|
+ struct fcf_record *new_fcf_record)
|
|
|
+{
|
|
|
+ uint16_t current_fcf_pri;
|
|
|
+ uint16_t last_index;
|
|
|
+ struct lpfc_fcf_pri *fcf_pri;
|
|
|
+ struct lpfc_fcf_pri *next_fcf_pri;
|
|
|
+ struct lpfc_fcf_pri *new_fcf_pri;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
|
|
|
+ "3059 adding idx x%x pri x%x flg x%x\n",
|
|
|
+ fcf_index, new_fcf_record->fip_priority,
|
|
|
+ new_fcf_pri->fcf_rec.flag);
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST)
|
|
|
+ list_del_init(&new_fcf_pri->list);
|
|
|
+ new_fcf_pri->fcf_rec.fcf_index = fcf_index;
|
|
|
+ new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
|
|
|
+ if (list_empty(&phba->fcf.fcf_pri_list)) {
|
|
|
+ list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
|
|
|
+ ret = lpfc_sli4_fcf_rr_index_set(phba,
|
|
|
+ new_fcf_pri->fcf_rec.fcf_index);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
|
|
|
+ LPFC_SLI4_FCF_TBL_INDX_MAX);
|
|
|
+ if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
|
|
|
+ ret = 0; /* Empty rr list */
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority;
|
|
|
+ if (new_fcf_pri->fcf_rec.priority <= current_fcf_pri) {
|
|
|
+ list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
|
|
|
+ if (new_fcf_pri->fcf_rec.priority < current_fcf_pri) {
|
|
|
+ memset(phba->fcf.fcf_rr_bmask, 0,
|
|
|
+ sizeof(*phba->fcf.fcf_rr_bmask));
|
|
|
+ /* fcfs_at_this_priority_level = 1; */
|
|
|
+ phba->fcf.eligible_fcf_cnt = 1;
|
|
|
+ } else
|
|
|
+ /* fcfs_at_this_priority_level++; */
|
|
|
+ phba->fcf.eligible_fcf_cnt++;
|
|
|
+ ret = lpfc_sli4_fcf_rr_index_set(phba,
|
|
|
+ new_fcf_pri->fcf_rec.fcf_index);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ list_for_each_entry_safe(fcf_pri, next_fcf_pri,
|
|
|
+ &phba->fcf.fcf_pri_list, list) {
|
|
|
+ if (new_fcf_pri->fcf_rec.priority <=
|
|
|
+ fcf_pri->fcf_rec.priority) {
|
|
|
+ if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list)
|
|
|
+ list_add(&new_fcf_pri->list,
|
|
|
+ &phba->fcf.fcf_pri_list);
|
|
|
+ else
|
|
|
+ list_add(&new_fcf_pri->list,
|
|
|
+ &((struct lpfc_fcf_pri *)
|
|
|
+ fcf_pri->list.prev)->list);
|
|
|
+ ret = 0;
|
|
|
+ goto out;
|
|
|
+ } else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list
|
|
|
+ || new_fcf_pri->fcf_rec.priority <
|
|
|
+ next_fcf_pri->fcf_rec.priority) {
|
|
|
+ list_add(&new_fcf_pri->list, &fcf_pri->list);
|
|
|
+ ret = 0;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+ ret = 1;
|
|
|
+out:
|
|
|
+ /* we use = instead of |= to clear the FLOGI_FAILED flag. */
|
|
|
+ new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
|
|
|
* @phba: pointer to lpfc hba data structure.
|
|
@@ -1958,6 +2156,9 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|
|
* record for roundrobin FCF failover.
|
|
|
*/
|
|
|
if (!rc) {
|
|
|
+ lpfc_sli4_fcf_pri_list_del(phba,
|
|
|
+ bf_get(lpfc_fcf_record_fcf_index,
|
|
|
+ new_fcf_record));
|
|
|
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
|
|
|
"2781 FCF (x%x) failed connection "
|
|
|
"list check: (x%x/x%x)\n",
|
|
@@ -2005,7 +2206,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|
|
goto read_next_fcf;
|
|
|
} else {
|
|
|
fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
|
|
|
- rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
|
|
|
+ rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index,
|
|
|
+ new_fcf_record);
|
|
|
if (rc)
|
|
|
goto read_next_fcf;
|
|
|
}
|
|
@@ -2018,7 +2220,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|
|
*/
|
|
|
spin_lock_irq(&phba->hbalock);
|
|
|
if (phba->fcf.fcf_flag & FCF_IN_USE) {
|
|
|
- if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
|
|
|
+ if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
|
|
|
+ lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
|
|
|
new_fcf_record, vlan_id)) {
|
|
|
if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==
|
|
|
phba->fcf.current_rec.fcf_indx) {
|
|
@@ -2232,7 +2435,8 @@ read_next_fcf:
|
|
|
(phba->fcf.fcf_flag & FCF_REDISC_PEND))
|
|
|
return;
|
|
|
|
|
|
- if (phba->fcf.fcf_flag & FCF_IN_USE) {
|
|
|
+ if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
|
|
|
+ phba->fcf.fcf_flag & FCF_IN_USE) {
|
|
|
/*
|
|
|
* In case the current in-use FCF record no
|
|
|
* longer existed during FCF discovery that
|
|
@@ -2423,7 +2627,8 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|
|
|
|
|
/* Update the eligible FCF record index bmask */
|
|
|
fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
|
|
|
- rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
|
|
|
+
|
|
|
+ rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record);
|
|
|
|
|
|
out:
|
|
|
lpfc_sli4_mbox_cmd_free(phba, mboxq);
|
|
@@ -2893,8 +3098,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
|
|
|
goto out;
|
|
|
}
|
|
|
/* Reset FCF roundrobin bmask for new discovery */
|
|
|
- memset(phba->fcf.fcf_rr_bmask, 0,
|
|
|
- sizeof(*phba->fcf.fcf_rr_bmask));
|
|
|
+ lpfc_sli4_clear_fcf_rr_bmask(phba);
|
|
|
}
|
|
|
|
|
|
return;
|
|
@@ -5592,7 +5796,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
|
|
|
spin_unlock_irq(&phba->hbalock);
|
|
|
|
|
|
/* Reset FCF roundrobin bmask for new discovery */
|
|
|
- memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
|
|
|
+ lpfc_sli4_clear_fcf_rr_bmask(phba);
|
|
|
|
|
|
rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
|
|
|
|