Commit ee596b87 authored by Yihang Li's avatar Yihang Li Committed by Slim6882
Browse files

[Backport]scsi: hisi_sas: Add firmware information check

mainline inclusion
from mainline-v6.12-rc1
commit 2c335fa7e69c06d8932ae8bc0ec7145de2973cf5
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IBCN9K
CVE: NA
Reference: https://lore.kernel.org/r/20241008021822.2617339-4-liyihang9@huawei.com



------------------------------------------------------------------

For security purposes, after information is obtained through the FW,
check information to ensure data correctness.

 - In v1 and v2 hw, the maximum number of PHYs is 9, while in v3 it is 8.

 - In v2 and v3 hw, the maximum number of hardware queues is 16, while
   in v1 it is 32.

Also add some debug logs for failure.

Signed-off-by: default avatarYihang Li <liyihang9@huawei.com>
Link: https://lore.kernel.org/r/20241008021822.2617339-4-liyihang9@huawei.com


Reviewed-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarSlim6882 <yangjunshuo@huawei.com>
parent 65c39505
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -314,6 +314,7 @@ enum {

struct hisi_sas_hw {
	int (*hw_init)(struct hisi_hba *hisi_hba);
	int (*fw_info_check)(struct hisi_hba *hisi_hba);
	int (*interrupt_preinit)(struct hisi_hba *hisi_hba);
	void (*setup_itct)(struct hisi_hba *hisi_hba,
			   struct hisi_sas_device *device);
+5 −0
Original line number Diff line number Diff line
@@ -2760,6 +2760,11 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
	if (hisi_sas_get_fw_info(hisi_hba) < 0)
		goto err_out;

	if (hisi_hba->hw->fw_info_check) {
		if (hisi_hba->hw->fw_info_check(hisi_hba))
			goto err_out;
	}

	error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
	if (error)
		error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+18 −0
Original line number Diff line number Diff line
@@ -1751,6 +1751,23 @@ static struct device_attribute *host_attrs_v1_hw[] = {
	NULL
};

static int check_fw_info_v1_hw(struct hisi_hba *hisi_hba)
{
	struct device *dev = hisi_hba->dev;

	if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 9) {
		dev_err(dev, "invalid phy number from FW\n");
		return -EINVAL;
	}

	if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 32) {
		dev_err(dev, "invalid queue count from FW\n");
		return -EINVAL;
	}

	return 0;
}

static struct scsi_host_template sht_v1_hw = {
	.name			= DRV_NAME,
	.proc_name		= DRV_NAME,
@@ -1780,6 +1797,7 @@ static struct scsi_host_template sht_v1_hw = {

static const struct hisi_sas_hw hisi_sas_v1_hw = {
	.hw_init = hisi_sas_v1_init,
	.fw_info_check = check_fw_info_v1_hw,
	.setup_itct = setup_itct_v1_hw,
	.sl_notify_ssp = sl_notify_ssp_v1_hw,
	.clear_itct = clear_itct_v1_hw,
+18 −0
Original line number Diff line number Diff line
@@ -3567,6 +3567,23 @@ static int map_queues_v2_hw(struct Scsi_Host *shost)

}

static int check_fw_info_v2_hw(struct hisi_hba *hisi_hba)
{
	struct device *dev = hisi_hba->dev;

	if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 9) {
		dev_err(dev, "invalid phy number from FW\n");
		return -EINVAL;
	}

	if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 16) {
		dev_err(dev, "invalid queue count from FW\n");
		return -EINVAL;
	}

	return 0;
}

static struct scsi_host_template sht_v2_hw = {
	.name			= DRV_NAME,
	.proc_name		= DRV_NAME,
@@ -3598,6 +3615,7 @@ static struct scsi_host_template sht_v2_hw = {

static const struct hisi_sas_hw hisi_sas_v2_hw = {
	.hw_init = hisi_sas_v2_init,
	.fw_info_check = check_fw_info_v2_hw,
	.interrupt_preinit = hisi_sas_v2_interrupt_preinit,
	.setup_itct = setup_itct_v2_hw,
	.slot_index_alloc = slot_index_alloc_quirk_v2_hw,
+20 −0
Original line number Diff line number Diff line
@@ -3327,6 +3327,23 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
	.debugfs_snapshot_regs = debugfs_snapshot_regs_v3_hw,
};

static int check_fw_info_v3_hw(struct hisi_hba *hisi_hba)
{
	struct device *dev = hisi_hba->dev;

	if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 8) {
		dev_err(dev, "invalid phy number from FW\n");
		return -EINVAL;
	}

	if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 16) {
		dev_err(dev, "invalid queue count from FW\n");
		return -EINVAL;
	}

	return 0;
}

static struct Scsi_Host *
hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
{
@@ -3357,6 +3374,9 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
	if (hisi_sas_get_fw_info(hisi_hba) < 0)
		goto err_out;

	if (check_fw_info_v3_hw(hisi_hba) < 0)
		goto err_out;

	if (hisi_sas_alloc(hisi_hba)) {
		hisi_sas_free(hisi_hba);
		goto err_out;