forked from Minki/linux
[SCSI] lpfc 8.3.26: Fix SYSFS interface issues
Fix SYSFS interface issues. - In the lpfc_sli4_pdev_status_reg_wait() routine, after initial 100ms delay following write to PHYSDEV_CONTROL register for the firmware reaction, check the RN bit and ERR bit of the SLIPORT_STATUS register. If none of them became 1, the previous PHYSDEV_CONTROL register should be considered failed due to lack of privilege and error for no permission should be returned immediately without getting into the wait for RDY bits on the SLIPORT_STATUS register. - Remove the driver check on dev->is_physfn before proceed to perform the PHYSDEV_CONTROL register write, and let the PCI function's privilege setting and driver handling of PHYSDEV_CONTROL register write failure to handle the reset-ability through the SLI port. - Added key to ctlreg_write to prevent unauthorized or unexpected write to the control register. - Change return to EACCES for sysfs access that are failed because hba_reset is disabled. Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com> Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
079b5c916d
commit
f7a919b4cd
@ -52,6 +52,13 @@
|
|||||||
#define LPFC_MIN_DEVLOSS_TMO 1
|
#define LPFC_MIN_DEVLOSS_TMO 1
|
||||||
#define LPFC_MAX_DEVLOSS_TMO 255
|
#define LPFC_MAX_DEVLOSS_TMO 255
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write key size should be multiple of 4. If write key is changed
|
||||||
|
* make sure that library write key is also changed.
|
||||||
|
*/
|
||||||
|
#define LPFC_REG_WRITE_KEY_SIZE 4
|
||||||
|
#define LPFC_REG_WRITE_KEY "EMLX"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules
|
* lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules
|
||||||
* @incr: integer to convert.
|
* @incr: integer to convert.
|
||||||
@ -693,7 +700,7 @@ lpfc_selective_reset(struct lpfc_hba *phba)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!phba->cfg_enable_hba_reset)
|
if (!phba->cfg_enable_hba_reset)
|
||||||
return -EIO;
|
return -EACCES;
|
||||||
|
|
||||||
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
|
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
|
||||||
|
|
||||||
@ -768,13 +775,18 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr,
|
|||||||
static int
|
static int
|
||||||
lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
|
lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
|
||||||
{
|
{
|
||||||
struct lpfc_register portstat_reg;
|
struct lpfc_register portstat_reg = {0};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
msleep(100);
|
||||||
lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
|
lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
|
||||||
&portstat_reg.word0);
|
&portstat_reg.word0);
|
||||||
|
|
||||||
|
/* verify if privilaged for the request operation */
|
||||||
|
if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) &&
|
||||||
|
!bf_get(lpfc_sliport_status_err, &portstat_reg))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
/* wait for the SLI port firmware ready after firmware reset */
|
/* wait for the SLI port firmware ready after firmware reset */
|
||||||
for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
|
for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
|
||||||
msleep(10);
|
msleep(10);
|
||||||
@ -816,16 +828,13 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!phba->cfg_enable_hba_reset)
|
if (!phba->cfg_enable_hba_reset)
|
||||||
return -EIO;
|
return -EACCES;
|
||||||
|
|
||||||
if ((phba->sli_rev < LPFC_SLI_REV4) ||
|
if ((phba->sli_rev < LPFC_SLI_REV4) ||
|
||||||
(bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
|
(bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
|
||||||
LPFC_SLI_INTF_IF_TYPE_2))
|
LPFC_SLI_INTF_IF_TYPE_2))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (!pdev->is_physfn)
|
|
||||||
return -EPERM;
|
|
||||||
|
|
||||||
/* Disable SR-IOV virtual functions if enabled */
|
/* Disable SR-IOV virtual functions if enabled */
|
||||||
if (phba->cfg_sriov_nr_virtfn) {
|
if (phba->cfg_sriov_nr_virtfn) {
|
||||||
pci_disable_sriov(pdev);
|
pci_disable_sriov(pdev);
|
||||||
@ -858,7 +867,7 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
|
|||||||
rc = lpfc_sli4_pdev_status_reg_wait(phba);
|
rc = lpfc_sli4_pdev_status_reg_wait(phba);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return -EIO;
|
return rc;
|
||||||
|
|
||||||
init_completion(&online_compl);
|
init_completion(&online_compl);
|
||||||
rc = lpfc_workq_post_event(phba, &status, &online_compl,
|
rc = lpfc_workq_post_event(phba, &status, &online_compl,
|
||||||
@ -984,7 +993,7 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
|
|||||||
if (!status)
|
if (!status)
|
||||||
return strlen(buf);
|
return strlen(buf);
|
||||||
else
|
else
|
||||||
return -EIO;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3885,18 +3894,23 @@ sysfs_ctlreg_write(struct file *filp, struct kobject *kobj,
|
|||||||
if ((off + count) > FF_REG_AREA_SIZE)
|
if ((off + count) > FF_REG_AREA_SIZE)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
if (count == 0) return 0;
|
if (count <= LPFC_REG_WRITE_KEY_SIZE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (off % 4 || count % 4 || (unsigned long)buf % 4)
|
if (off % 4 || count % 4 || (unsigned long)buf % 4)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
|
/* This is to protect HBA registers from accidental writes. */
|
||||||
|
if (memcmp(buf, LPFC_REG_WRITE_KEY, LPFC_REG_WRITE_KEY_SIZE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!(vport->fc_flag & FC_OFFLINE_MODE))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irq(&phba->hbalock);
|
spin_lock_irq(&phba->hbalock);
|
||||||
for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t))
|
for (buf_off = 0; buf_off < count - LPFC_REG_WRITE_KEY_SIZE;
|
||||||
writel(*((uint32_t *)(buf + buf_off)),
|
buf_off += sizeof(uint32_t))
|
||||||
|
writel(*((uint32_t *)(buf + buf_off + LPFC_REG_WRITE_KEY_SIZE)),
|
||||||
phba->ctrl_regs_memmap_p + off + buf_off);
|
phba->ctrl_regs_memmap_p + off + buf_off);
|
||||||
|
|
||||||
spin_unlock_irq(&phba->hbalock);
|
spin_unlock_irq(&phba->hbalock);
|
||||||
|
@ -4056,9 +4056,6 @@ lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba)
|
|||||||
uint16_t nr_virtfn;
|
uint16_t nr_virtfn;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
if (!pdev->is_physfn)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
|
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
|
||||||
if (pos == 0)
|
if (pos == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user