scsi: hisi_sas: Add firmware information check
authorYihang Li <liyihang9@huawei.com>
Tue, 8 Oct 2024 02:18:12 +0000 (10:18 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 16 Oct 2024 02:33:34 +0000 (22:33 -0400)
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: Yihang Li <liyihang9@huawei.com>
Link: https://lore.kernel.org/r/20241008021822.2617339-4-liyihang9@huawei.com
Reviewed-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index d223f48..a44768b 100644 (file)
@@ -307,6 +307,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);
index d3dcc49..275d45a 100644 (file)
@@ -2450,6 +2450,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) {
                dev_err(dev, "No usable DMA addressing method\n");
index 71b5008..70bba55 100644 (file)
@@ -1734,6 +1734,23 @@ static struct attribute *host_v1_hw_attrs[] = {
 
 ATTRIBUTE_GROUPS(host_v1_hw);
 
+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 const struct scsi_host_template sht_v1_hw = {
        LIBSAS_SHT_BASE_NO_SLAVE_INIT
        .device_configure       = hisi_sas_device_configure,
@@ -1747,6 +1764,7 @@ static const 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,
index 342d75f..ab6668d 100644 (file)
@@ -3566,6 +3566,23 @@ static void 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 const struct scsi_host_template sht_v2_hw = {
        LIBSAS_SHT_BASE_NO_SLAVE_INIT
        .device_configure       = hisi_sas_device_configure,
@@ -3582,6 +3599,7 @@ static const 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,
index 980f28d..d48777f 100644 (file)
@@ -3371,6 +3371,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)
 {
@@ -3401,6 +3418,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 (experimental_iopoll_q_cnt < 0 ||
                experimental_iopoll_q_cnt >= hisi_hba->queue_count)
                dev_err(dev, "iopoll queue count %d cannot exceed or equal 16, using default 0\n",