scsi: mpt3sas: Detect tampered Aero and Sea adapters
authorSreekanth Reddy <sreekanth.reddy@broadcom.com>
Fri, 14 Aug 2020 13:04:26 +0000 (13:04 +0000)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 15 Sep 2020 22:23:18 +0000 (18:23 -0400)
The driver will throw an error message when a tampered type controller
is detected. The intent is to avoid interacting with any firmware
which is not secured/signed by Broadcom. Any tampering on firmware
component will be detected by hardware and it will be communicated to
the driver to avoid any further interaction with that component.

[mkp: switched back to dev_err]

Link: https://lore.kernel.org/r/20200814130426.2741171-1-sreekanth.reddy@broadcom.com
Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpt3sas/mpt3sas_scsih.c

index 6fe931b..db9c816 100644 (file)
@@ -10091,6 +10091,34 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
        mutex_unlock(&ioc->scsih_cmds.mutex);
 }
 
+/**
+ * _scsih_get_shost_and_ioc - get shost and ioc
+ *                     and verify whether they are NULL or not
+ * @pdev: PCI device struct
+ * @shost: address of scsi host pointer
+ * @ioc: address of HBA adapter pointer
+ *
+ * Return zero if *shost and *ioc are not NULL otherwise return error number.
+ */
+static int
+_scsih_get_shost_and_ioc(struct pci_dev *pdev,
+       struct Scsi_Host **shost, struct MPT3SAS_ADAPTER **ioc)
+{
+       *shost = pci_get_drvdata(pdev);
+       if (*shost == NULL) {
+               dev_err(&pdev->dev, "pdev's driver data is null\n");
+               return -ENXIO;
+       }
+
+       *ioc = shost_priv(*shost);
+       if (*ioc == NULL) {
+               dev_err(&pdev->dev, "shost's private data is null\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
 /**
  * scsih_remove - detach and remove add host
  * @pdev: PCI device struct
@@ -10099,8 +10127,8 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
  */
 static void scsih_remove(struct pci_dev *pdev)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
        struct _sas_port *mpt3sas_port, *next_port;
        struct _raid_device *raid_device, *next;
        struct MPT3SAS_TARGET *sas_target_priv_data;
@@ -10109,6 +10137,9 @@ static void scsih_remove(struct pci_dev *pdev)
        unsigned long flags;
        Mpi2ConfigReply_t mpi_reply;
 
+       if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc))
+               return;
+
        ioc->remove_host = 1;
 
        if (!pci_device_is_present(pdev))
@@ -10188,12 +10219,15 @@ static void scsih_remove(struct pci_dev *pdev)
 static void
 scsih_shutdown(struct pci_dev *pdev)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
        struct workqueue_struct *wq;
        unsigned long flags;
        Mpi2ConfigReply_t mpi_reply;
 
+       if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc))
+               return;
+
        ioc->remove_host = 1;
 
        if (!pci_device_is_present(pdev))
@@ -10763,6 +10797,10 @@ _scsih_determine_hba_mpi_version(struct pci_dev *pdev)
        case MPI26_MFGPAGE_DEVID_HARD_SEC_3916:
        case MPI26_MFGPAGE_DEVID_CFG_SEC_3816:
        case MPI26_MFGPAGE_DEVID_HARD_SEC_3816:
+       case MPI26_MFGPAGE_DEVID_INVALID0_3916:
+       case MPI26_MFGPAGE_DEVID_INVALID1_3916:
+       case MPI26_MFGPAGE_DEVID_INVALID0_3816:
+       case MPI26_MFGPAGE_DEVID_INVALID1_3816:
                return MPI26_VERSION;
        }
        return 0;
@@ -10852,6 +10890,20 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                case MPI26_ATLAS_PCIe_SWITCH_DEVID:
                        ioc->is_gen35_ioc = 1;
                        break;
+               case MPI26_MFGPAGE_DEVID_INVALID0_3816:
+               case MPI26_MFGPAGE_DEVID_INVALID0_3916:
+                       dev_err(&pdev->dev,
+                           "HBA with DeviceId 0x%04x, sub VendorId 0x%04x, sub DeviceId 0x%04x is Invalid",
+                           pdev->device, pdev->subsystem_vendor,
+                           pdev->subsystem_device);
+                       return 1;
+               case MPI26_MFGPAGE_DEVID_INVALID1_3816:
+               case MPI26_MFGPAGE_DEVID_INVALID1_3916:
+                       dev_err(&pdev->dev,
+                           "HBA with DeviceId 0x%04x, sub VendorId 0x%04x, sub DeviceId 0x%04x is Tampered",
+                           pdev->device, pdev->subsystem_vendor,
+                           pdev->subsystem_device);
+                       return 1;
                case MPI26_MFGPAGE_DEVID_CFG_SEC_3816:
                case MPI26_MFGPAGE_DEVID_CFG_SEC_3916:
                        dev_info(&pdev->dev,
@@ -11043,9 +11095,14 @@ out_add_shost_fail:
 static int
 scsih_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
        pci_power_t device_state;
+       int rc;
+
+       rc = _scsih_get_shost_and_ioc(pdev, &shost, &ioc);
+       if (rc)
+               return rc;
 
        mpt3sas_base_stop_watchdog(ioc);
        flush_scheduled_work();
@@ -11070,11 +11127,15 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state)
 static int
 scsih_resume(struct pci_dev *pdev)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
        pci_power_t device_state = pdev->current_state;
        int r;
 
+       r = _scsih_get_shost_and_ioc(pdev, &shost, &ioc);
+       if (r)
+               return r;
+
        ioc_info(ioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",
                 pdev, pci_name(pdev), device_state);
 
@@ -11105,8 +11166,11 @@ scsih_resume(struct pci_dev *pdev)
 static pci_ers_result_t
 scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
+
+       if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc))
+               return PCI_ERS_RESULT_DISCONNECT;
 
        ioc_info(ioc, "PCI error: detected callback, state(%d)!!\n", state);
 
@@ -11141,10 +11205,13 @@ scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 static pci_ers_result_t
 scsih_pci_slot_reset(struct pci_dev *pdev)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
        int rc;
 
+       if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc))
+               return PCI_ERS_RESULT_DISCONNECT;
+
        ioc_info(ioc, "PCI error: slot reset callback!!\n");
 
        ioc->pci_error_recovery = 0;
@@ -11177,8 +11244,11 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
 static void
 scsih_pci_resume(struct pci_dev *pdev)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
+
+       if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc))
+               return;
 
        ioc_info(ioc, "PCI error: resume callback!!\n");
 
@@ -11193,8 +11263,11 @@ scsih_pci_resume(struct pci_dev *pdev)
 static pci_ers_result_t
 scsih_pci_mmio_enabled(struct pci_dev *pdev)
 {
-       struct Scsi_Host *shost = pci_get_drvdata(pdev);
-       struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+       struct Scsi_Host *shost;
+       struct MPT3SAS_ADAPTER *ioc;
+
+       if (_scsih_get_shost_and_ioc(pdev, &shost, &ioc))
+               return PCI_ERS_RESULT_DISCONNECT;
 
        ioc_info(ioc, "PCI error: mmio enabled callback!!\n");
 
@@ -11342,6 +11415,14 @@ static const struct pci_device_id mpt3sas_pci_table[] = {
        { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_HARD_SEC_3916,
                PCI_ANY_ID, PCI_ANY_ID },
 
+       /*
+        *  Aero SI –> 0x00E0 Invalid, 0x00E3 Tampered
+        */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_INVALID0_3916,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_INVALID1_3916,
+               PCI_ANY_ID, PCI_ANY_ID },
+
        /* Atlas PCIe Switch Management Port */
        { MPI2_MFGPAGE_VENDORID_LSI, MPI26_ATLAS_PCIe_SWITCH_DEVID,
                PCI_ANY_ID, PCI_ANY_ID },
@@ -11354,6 +11435,14 @@ static const struct pci_device_id mpt3sas_pci_table[] = {
        { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_HARD_SEC_3816,
                PCI_ANY_ID, PCI_ANY_ID },
 
+       /*
+        *  Sea SI –> 0x00E4 Invalid, 0x00E7 Tampered
+        */
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_INVALID0_3816,
+               PCI_ANY_ID, PCI_ANY_ID },
+       { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_INVALID1_3816,
+               PCI_ANY_ID, PCI_ANY_ID },
+
        {0}     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);