scsi: mpt3sas: Add support for ATTO ExpressSAS H12xx GT devices
authorBradley Grove <bgrove@attotech.com>
Fri, 5 Aug 2022 17:46:08 +0000 (13:46 -0400)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 1 Sep 2022 03:39:57 +0000 (23:39 -0400)
Add ATTO's PCI IDs and modify the driver to handle the unique NVRAM
structure used by ATTO's devices.

Link: https://lore.kernel.org/r/20220805174609.14830-1-bgrove@attotech.com
Co-developed-by: Rob Crispo <rcrispo@attotech.com>
Signed-off-by: Rob Crispo <rcrispo@attotech.com>
Signed-off-by: Bradley Grove <bgrove@attotech.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_config.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c

index d00431f..4d0be5a 100644 (file)
@@ -534,6 +534,7 @@ typedef struct _MPI2_CONFIG_REPLY {
 ****************************************************************************/
 
 #define MPI2_MFGPAGE_VENDORID_LSI                   (0x1000)
+#define MPI2_MFGPAGE_VENDORID_ATTO                  (0x117C)
 
 /*MPI v2.0 SAS products */
 #define MPI2_MFGPAGE_DEVID_SAS2004                  (0x0070)
index 565339a..eeebe80 100644 (file)
@@ -5425,6 +5425,151 @@ out:
 }
 
 /**
+ * mpt3sas_atto_validate_nvram - validate the ATTO nvram read from mfg pg1
+ *
+ * @ioc : per adapter object
+ * @n   : ptr to the ATTO nvram structure
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+mpt3sas_atto_validate_nvram(struct MPT3SAS_ADAPTER *ioc,
+                           struct ATTO_SAS_NVRAM *n)
+{
+       int r = -EINVAL;
+       union ATTO_SAS_ADDRESS *s1;
+       u32 len;
+       u8 *pb;
+       u8 ckSum;
+
+       /* validate nvram checksum */
+       pb = (u8 *) n;
+       ckSum = ATTO_SASNVR_CKSUM_SEED;
+       len = sizeof(struct ATTO_SAS_NVRAM);
+
+       while (len--)
+               ckSum = ckSum + pb[len];
+
+       if (ckSum) {
+               ioc_err(ioc, "Invalid ATTO NVRAM checksum\n");
+               return r;
+       }
+
+       s1 = (union ATTO_SAS_ADDRESS *) n->SasAddr;
+
+       if (n->Signature[0] != 'E'
+       || n->Signature[1] != 'S'
+       || n->Signature[2] != 'A'
+       || n->Signature[3] != 'S')
+               ioc_err(ioc, "Invalid ATTO NVRAM signature\n");
+       else if (n->Version > ATTO_SASNVR_VERSION)
+               ioc_info(ioc, "Invalid ATTO NVRAM version");
+       else if ((n->SasAddr[7] & (ATTO_SAS_ADDR_ALIGN - 1))
+                       || s1->b[0] != 0x50
+                       || s1->b[1] != 0x01
+                       || s1->b[2] != 0x08
+                       || (s1->b[3] & 0xF0) != 0x60
+                       || ((s1->b[3] & 0x0F) | le32_to_cpu(s1->d[1])) == 0) {
+               ioc_err(ioc, "Invalid ATTO SAS address\n");
+       } else
+               r = 0;
+       return r;
+}
+
+/**
+ * mpt3sas_atto_get_sas_addr - get the ATTO SAS address from mfg page 1
+ *
+ * @ioc : per adapter object
+ * @*sas_addr : return sas address
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+mpt3sas_atto_get_sas_addr(struct MPT3SAS_ADAPTER *ioc, union ATTO_SAS_ADDRESS *sas_addr)
+{
+       Mpi2ManufacturingPage1_t mfg_pg1;
+       Mpi2ConfigReply_t mpi_reply;
+       struct ATTO_SAS_NVRAM *nvram;
+       int r;
+       __be64 addr;
+
+       r = mpt3sas_config_get_manufacturing_pg1(ioc, &mpi_reply, &mfg_pg1);
+       if (r) {
+               ioc_err(ioc, "Failed to read manufacturing page 1\n");
+               return r;
+       }
+
+       /* validate nvram */
+       nvram = (struct ATTO_SAS_NVRAM *) mfg_pg1.VPD;
+       r = mpt3sas_atto_validate_nvram(ioc, nvram);
+       if (r)
+               return r;
+
+       addr = *((__be64 *) nvram->SasAddr);
+       sas_addr->q = cpu_to_le64(be64_to_cpu(addr));
+       return r;
+}
+
+/**
+ * mpt3sas_atto_init - perform initializaion for ATTO branded
+ *                                     adapter.
+ * @ioc : per adapter object
+ *5
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+mpt3sas_atto_init(struct MPT3SAS_ADAPTER *ioc)
+{
+       int sz = 0;
+       Mpi2BiosPage4_t *bios_pg4 = NULL;
+       Mpi2ConfigReply_t mpi_reply;
+       int r;
+       int ix;
+       union ATTO_SAS_ADDRESS sas_addr;
+       union ATTO_SAS_ADDRESS temp;
+       union ATTO_SAS_ADDRESS bias;
+
+       r = mpt3sas_atto_get_sas_addr(ioc, &sas_addr);
+       if (r)
+               return r;
+
+       /* get header first to get size */
+       r = mpt3sas_config_get_bios_pg4(ioc, &mpi_reply, NULL, 0);
+       if (r) {
+               ioc_err(ioc, "Failed to read ATTO bios page 4 header.\n");
+               return r;
+       }
+
+       sz = mpi_reply.Header.PageLength * sizeof(u32);
+       bios_pg4 = kzalloc(sz, GFP_KERNEL);
+       if (!bios_pg4) {
+               ioc_err(ioc, "Failed to allocate memory for ATTO bios page.\n");
+               return -ENOMEM;
+       }
+
+       /* read bios page 4 */
+       r = mpt3sas_config_get_bios_pg4(ioc, &mpi_reply, bios_pg4, sz);
+       if (r) {
+               ioc_err(ioc, "Failed to read ATTO bios page 4\n");
+               goto out;
+       }
+
+       /* Update bios page 4 with the ATTO WWID */
+       bias.q = sas_addr.q;
+       bias.b[7] += ATTO_SAS_ADDR_DEVNAME_BIAS;
+
+       for (ix = 0; ix < bios_pg4->NumPhys; ix++) {
+               temp.q = sas_addr.q;
+               temp.b[7] += ix;
+               bios_pg4->Phy[ix].ReassignmentWWID = temp.q;
+               bios_pg4->Phy[ix].ReassignmentDeviceName = bias.q;
+       }
+       r = mpt3sas_config_set_bios_pg4(ioc, &mpi_reply, bios_pg4, sz);
+
+out:
+       kfree(bios_pg4);
+       return r;
+}
+
+/**
  * _base_static_config_pages - static start of day config pages
  * @ioc: per adapter object
  */
@@ -5447,6 +5592,13 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
                if (rc)
                        return rc;
        }
+
+       if (ioc->pdev->vendor == MPI2_MFGPAGE_VENDORID_ATTO) {
+               rc = mpt3sas_atto_init(ioc);
+               if (rc)
+                       return rc;
+       }
+
        /*
         * Ensure correct T10 PI operation if vendor left EEDPTagMode
         * flag unset in NVDATA.
@@ -5496,12 +5648,21 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
        rc = _base_assign_fw_reported_qd(ioc);
        if (rc)
                return rc;
-       rc = mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
-       if (rc)
-               return rc;
-       rc = mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
-       if (rc)
-               return rc;
+
+       /*
+        * ATTO doesn't use bios page 2 and 3 for bios settings.
+        */
+       if (ioc->pdev->vendor ==  MPI2_MFGPAGE_VENDORID_ATTO)
+               ioc->bios_pg3.BiosVersion = 0;
+       else {
+               rc = mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
+               if (rc)
+                       return rc;
+               rc = mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
+               if (rc)
+                       return rc;
+       }
+
        rc = mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
        if (rc)
                return rc;
index e584cf0..542fb74 100644 (file)
@@ -1652,6 +1652,32 @@ struct mpt3sas_debugfs_buffer {
 typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
        u32 reply);
 
+/*
+ * struct ATTO_SAS_NVRAM - ATTO NVRAM settings stored
+ *                             in Manufacturing page 1 used to get
+ *                             ATTO SasAddr.
+ */
+struct ATTO_SAS_NVRAM {
+       u8              Signature[4];
+       u8              Version;
+#define ATTO_SASNVR_VERSION            0
+
+       u8              Checksum;
+#define ATTO_SASNVR_CKSUM_SEED 0x5A
+       u8              Pad[10];
+       u8              SasAddr[8];
+#define ATTO_SAS_ADDR_ALIGN            64
+       u8              Reserved[232];
+};
+
+#define ATTO_SAS_ADDR_DEVNAME_BIAS             63
+
+union ATTO_SAS_ADDRESS {
+       U8              b[8];
+       U16             w[4];
+       U32             d[2];
+       U64             q;
+};
 
 /* base shared API */
 extern struct list_head mpt3sas_ioc_list;
@@ -1828,6 +1854,9 @@ int mpt3sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc,
        u8 *num_phys);
 int mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc,
        Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
+int mpt3sas_config_get_manufacturing_pg1(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage1_t *config_page);
+
 int mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc,
        Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page,
        u16 sz);
@@ -1846,6 +1875,12 @@ int mpt3sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        *mpi_reply, Mpi2BiosPage2_t *config_page);
 int mpt3sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        *mpi_reply, Mpi2BiosPage3_t *config_page);
+int mpt3sas_config_set_bios_pg4(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage4_t *config_page,
+       int sz_config_page);
+int mpt3sas_config_get_bios_pg4(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage4_t *config_page,
+       int sz_config_page);
 int mpt3sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        *mpi_reply, Mpi2IOUnitPage0_t *config_page);
 int mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc,
index a8dd14c..d114ef3 100644 (file)
@@ -541,6 +541,42 @@ mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc,
 }
 
 /**
+ * mpt3sas_config_get_manufacturing_pg1 - obtain manufacturing page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_manufacturing_pg1(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage1_t *config_page)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
+       mpi_request.Header.PageNumber = 1;
+       mpi_request.Header.PageVersion = MPI2_MANUFACTURING1_PAGEVERSION;
+       ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+               MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+               MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+               sizeof(*config_page));
+ out:
+       return r;
+}
+
+/**
  * mpt3sas_config_get_manufacturing_pg7 - obtain manufacturing page 7
  * @ioc: per adapter object
  * @mpi_reply: reply mf payload returned from firmware
@@ -757,11 +793,99 @@ mpt3sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
        r = _config_request(ioc, &mpi_request, mpi_reply,
            MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
            sizeof(*config_page));
+
  out:
        return r;
 }
 
 /**
+ * mpt3sas_config_set_bios_pg4 - write out bios page 4
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz_config_pg: sizeof the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_set_bios_pg4(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage4_t *config_page,
+       int sz_config_pg)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+       mpi_request.Header.PageNumber = 4;
+       mpi_request.Header.PageVersion = MPI2_BIOSPAGE4_PAGEVERSION;
+
+       ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+               MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+               MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+               sz_config_pg);
+ out:
+       return r;
+}
+
+/**
+ * mpt3sas_config_get_bios_pg4 - read bios page 4
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz_config_pg: sizeof the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_bios_pg4(struct MPT3SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage4_t *config_page,
+       int sz_config_pg)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+       mpi_request.Header.PageNumber = 4;
+       mpi_request.Header.PageVersion =  MPI2_BIOSPAGE4_PAGEVERSION;
+       ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+               MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+       if (r)
+               goto out;
+
+       /*
+        * The sizeof the page is variable. Allow for just the
+        * size to be returned
+        */
+       if (config_page && sz_config_pg) {
+               mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               r = _config_request(ioc, &mpi_request, mpi_reply,
+                       MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+                       sz_config_pg);
+       }
+
+out:
+       return r;
+}
+
+/**
  * mpt3sas_config_get_iounit_pg0 - obtain iounit page 0
  * @ioc: per adapter object
  * @mpi_reply: reply mf payload returned from firmware
index def37a7..3507e2a 100644 (file)
@@ -12733,6 +12733,12 @@ static const struct pci_device_id mpt3sas_pci_table[] = {
                PCI_ANY_ID, PCI_ANY_ID },
 
        /*
+        * ATTO Branded ExpressSAS H12xx GT
+        */
+       { MPI2_MFGPAGE_VENDORID_ATTO, 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,