diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2542f1f8bf86..13215cd396aa 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -52,6 +52,13 @@ #define LPFC_MIN_DEVLOSS_TMO 1 #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 * @incr: integer to convert. @@ -693,7 +700,7 @@ lpfc_selective_reset(struct lpfc_hba *phba) int rc; if (!phba->cfg_enable_hba_reset) - return -EIO; + return -EACCES; status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); @@ -768,13 +775,18 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, static int lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) { - struct lpfc_register portstat_reg; + struct lpfc_register portstat_reg = {0}; int i; - + msleep(100); lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, &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 */ for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) { msleep(10); @@ -816,16 +828,13 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) int rc; if (!phba->cfg_enable_hba_reset) - return -EIO; + return -EACCES; if ((phba->sli_rev < LPFC_SLI_REV4) || (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_2)) return -EPERM; - if (!pdev->is_physfn) - return -EPERM; - /* Disable SR-IOV virtual functions if enabled */ if (phba->cfg_sriov_nr_virtfn) { 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); if (rc) - return -EIO; + return rc; init_completion(&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) return strlen(buf); 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) 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) 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; - } spin_lock_irq(&phba->hbalock); - for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) - writel(*((uint32_t *)(buf + buf_off)), + for (buf_off = 0; buf_off < count - LPFC_REG_WRITE_KEY_SIZE; + buf_off += sizeof(uint32_t)) + writel(*((uint32_t *)(buf + buf_off + LPFC_REG_WRITE_KEY_SIZE)), phba->ctrl_regs_memmap_p + off + buf_off); spin_unlock_irq(&phba->hbalock); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b9ff38fa7c26..d8ac7694854e 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4056,9 +4056,6 @@ lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba) uint16_t nr_virtfn; int pos; - if (!pdev->is_physfn) - return 0; - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); if (pos == 0) return 0;