diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e1466eec56b..362730b6dd8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1531,7 +1531,37 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) } /** - * lpfc_sli4_fcf_rec_mbox_parse - parse non-embedded fcf record mailbox command + * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record + * @phba: pointer to lpfc hba data structure. + * @fcf_cnt: number of eligible fcf record seen so far. + * + * This function makes an running random selection decision on FCF record to + * use through a sequence of @fcf_cnt eligible FCF records with equal + * probability. To perform integer manunipulation of random numbers with + * size unit32_t, the lower 16 bits of the 32-bit random number returned + * from random32() are taken as the random random number generated. + * + * Returns true when outcome is for the newly read FCF record should be + * chosen; otherwise, return false when outcome is for keeping the previously + * chosen FCF record. + **/ +static bool +lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) +{ + uint32_t rand_num; + + /* Get 16-bit uniform random number */ + rand_num = (0xFFFF & random32()); + + /* Decision with probability 1/fcf_cnt */ + if ((fcf_cnt * rand_num) < 0xFFFF) + return true; + else + return false; +} + +/** + * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox object. * @next_fcf_index: pointer to holder of next fcf index. @@ -1679,6 +1709,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) uint16_t fcf_index, next_fcf_index; struct lpfc_fcf_rec *fcf_rec = NULL; uint16_t vlan_id; + uint32_t seed; + bool select_new_fcf; int rc; /* If there is pending FCoE event restart FCF table scan */ @@ -1809,9 +1841,21 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) * than the driver FCF record, use the new record. */ if (new_fcf_record->fip_priority < fcf_rec->priority) { - /* Choose this FCF record */ + /* Choose the new FCF record with lower priority */ __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, addr_mode, vlan_id, 0); + /* Reset running random FCF selection count */ + phba->fcf.eligible_fcf_cnt = 1; + } else if (new_fcf_record->fip_priority == fcf_rec->priority) { + /* Update running random FCF selection count */ + phba->fcf.eligible_fcf_cnt++; + select_new_fcf = lpfc_sli4_new_fcf_random_select(phba, + phba->fcf.eligible_fcf_cnt); + if (select_new_fcf) + /* Choose the new FCF by random selection */ + __lpfc_update_fcf_record(phba, fcf_rec, + new_fcf_record, + addr_mode, vlan_id, 0); } spin_unlock_irq(&phba->hbalock); goto read_next_fcf; @@ -1825,6 +1869,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) addr_mode, vlan_id, (boot_flag ? BOOT_ENABLE : 0)); phba->fcf.fcf_flag |= FCF_AVAILABLE; + /* Setup initial running random FCF selection count */ + phba->fcf.eligible_fcf_cnt = 1; + /* Seeding the random number generator for random selection */ + seed = (uint32_t)(0xFFFFFFFF & jiffies); + srandom32(seed); } spin_unlock_irq(&phba->hbalock); goto read_next_fcf; |