lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250613202941.62114-2-ssiwinski@atto.com>
Date: Fri, 13 Jun 2025 16:29:41 -0400
From: Steve Siwinski <stevensiwinski@...il.com>
To: mpi3mr-linuxdrv.pdl@...adcom.com
Cc: gustavoars@...nel.org,
	James.Bottomley@...senPartnership.com,
	kashyap.desai@...adcom.com,
	kees@...nel.org,
	linux-kernel@...r.kernel.org,
	linux-scsi@...r.kernel.org,
	martin.petersen@...cle.com,
	prayas.patel@...adcom.com,
	ranjan.kumar@...adcom.com,
	sathya.prakash@...adcom.com,
	sreekanth.reddy@...adcom.com,
	ssiwinski@...o.com,
	sumit.saxena@...adcom.com,
	bgrove@...o.com,
	tdoedline@...o.com
Subject: [PATCH 2/2] scsi: mpi3mr: Add initialization for ATTO 24Gb SAS HBAs

This patch adds initialization routines for ATTO 24Gb SAS HBAs.
It introduces the ATTO NVRAM structure and functions to validate
NVRAM contents.

The `mpi3mr_atto_init` function is added to handle ATTO-specific
controller initialization. This involves reading the ATTO SAS address
from Driver Page 2 and then assigning unique device names and WWIDs
to Manufacturing Page 5.

Signed-off-by: Steve Siwinski <ssiwinski@...o.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  35 ++++
 drivers/scsi/mpi3mr/mpi3mr_fw.c | 310 ++++++++++++++++++++++++++++++++
 2 files changed, 345 insertions(+)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 9bbc7cb98ca3..05583457ffaa 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -1438,6 +1438,35 @@ struct delayed_evt_ack_node {
 	u32 event_ctx;
 };
 
+/*
+ * struct ATTO_SAS_NVRAM - ATTO NVRAM settings
+ * @signature: ATTO NVRAM signature
+ * @version: ATTO NVRAM version
+ * @checksum: NVRAM checksum
+ * @sasaddr: ATTO SAS address
+ */
+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;
+};
+
 int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc);
 void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc);
 int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc);
@@ -1533,10 +1562,16 @@ int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz);
 int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz);
+int mpi3mr_cfg_get_man_pg5(struct mpi3mr_ioc *mrioc,
+	struct mpi3_man_page5 *man_pg5, u16 pg_sz);
+int mpi3mr_cfg_set_man_pg5(struct mpi3mr_ioc *mrioc,
+	struct mpi3_man_page5 *man_pg5, u16 pg_sz);
 int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
 	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz);
 int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
 	struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_type);
+int mpi3mr_cfg_get_page_size(struct mpi3mr_ioc *mrioc,
+	int page_type, int page_num);
 
 u8 mpi3mr_is_expander_device(u16 device_info);
 int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 1d7901a8f0e4..c0177ad3d200 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -4203,6 +4203,163 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
 	return retval;
 }
 
+/**
+ * mpi3mr_atto_validate_nvram - validate the ATTO nvram
+ *
+ * @mrioc:  Adapter instance reference
+ * @nvram: ptr to the ATTO nvram structure
+ * Return: 0 for success, non-zero for failure.
+ */
+static int mpi3mr_atto_validate_nvram(struct mpi3mr_ioc *mrioc, struct ATTO_SAS_NVRAM *nvram)
+{
+	int r = -EINVAL;
+	union ATTO_SAS_ADDRESS *sasaddr;
+	u32 len;
+	u8 *pb;
+	u8 cksum;
+
+	/* validate nvram checksum */
+	pb = (u8 *) nvram;
+	cksum = ATTO_SASNVR_CKSUM_SEED;
+	len = sizeof(struct ATTO_SAS_NVRAM);
+
+	while (len--)
+		cksum = cksum + pb[len];
+
+	if (cksum) {
+		ioc_err(mrioc, "Invalid ATTO NVRAM checksum\n");
+		return r;
+	}
+
+	sasaddr = (union ATTO_SAS_ADDRESS *) nvram->sasaddr;
+
+	if (nvram->signature[0] != 'E'
+	|| nvram->signature[1] != 'S'
+	|| nvram->signature[2] != 'A'
+	|| nvram->signature[3] != 'S')
+		ioc_err(mrioc, "Invalid ATTO NVRAM signature\n");
+	else if (nvram->version > ATTO_SASNVR_VERSION)
+		ioc_info(mrioc, "Invalid ATTO NVRAM version");
+	else if ((nvram->sasaddr[7] & (ATTO_SAS_ADDR_ALIGN - 1))
+			|| sasaddr->b[0] != 0x50
+			|| sasaddr->b[1] != 0x01
+			|| sasaddr->b[2] != 0x08
+			|| (sasaddr->b[3] & 0xF0) != 0x60
+			|| ((sasaddr->b[3] & 0x0F) | le32_to_cpu(sasaddr->d[1])) == 0) {
+		ioc_err(mrioc, "Invalid ATTO SAS address\n");
+	} else
+		r = 0;
+	return r;
+}
+
+/**
+ * mpi3mr_atto_get_sas_addr - get the ATTO SAS address from driver page 2
+ *
+ * @mrioc: Adapter instance reference
+ * @*sas_address: return sas address
+ * Return: 0 for success, non-zero for failure.
+ */
+static int mpi3mr_atto_get_sas_addr(struct mpi3mr_ioc *mrioc, union ATTO_SAS_ADDRESS *sas_address)
+{
+	struct mpi3_driver_page2 *driver_pg2 = NULL;
+	struct ATTO_SAS_NVRAM *nvram;
+	u16 sz;
+	int r;
+	__be64 addr;
+
+	sz = mpi3mr_cfg_get_page_size(mrioc, MPI3_CONFIG_PAGETYPE_DRIVER, 2);
+	driver_pg2 = kzalloc(sz, GFP_KERNEL);
+	if (!driver_pg2)
+		goto out;
+
+	r = mpi3mr_cfg_get_driver_pg2(mrioc, driver_pg2, sz, MPI3_CONFIG_ACTION_READ_PERSISTENT);
+	if (r)
+		goto out;
+
+	nvram = (struct ATTO_SAS_NVRAM *) &driver_pg2->trigger;
+
+	r = mpi3mr_atto_validate_nvram(mrioc, nvram);
+	if (r)
+		goto out;
+
+	addr = *((__be64 *) nvram->sasaddr);
+	sas_address->q = cpu_to_le64(be64_to_cpu(addr));
+
+out:
+	kfree(driver_pg2);
+	return r;
+}
+
+/**
+ * mpi3mr_atto_init - Initialize the controller
+ * @mrioc: Adapter instance reference
+ *
+ * This the ATTO controller initialization routine
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+static int mpi3mr_atto_init(struct mpi3mr_ioc *mrioc)
+{
+	int i, bias = 0;
+	u16 sz;
+	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
+	struct mpi3_man_page5 *man_pg5 = NULL;
+	union ATTO_SAS_ADDRESS base_address;
+	union ATTO_SAS_ADDRESS dev_address;
+	union ATTO_SAS_ADDRESS sas_address;
+
+	sz = mpi3mr_cfg_get_page_size(mrioc, MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT, 0);
+	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
+	if (!sas_io_unit_pg0)
+		goto out;
+
+	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		goto out;
+	}
+
+	sz = mpi3mr_cfg_get_page_size(mrioc, MPI3_CONFIG_PAGETYPE_MANUFACTURING, 5);
+	man_pg5 = kzalloc(sz, GFP_KERNEL);
+	if (!man_pg5)
+		goto out;
+
+	if (mpi3mr_cfg_get_man_pg5(mrioc, man_pg5, sz)) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		goto out;
+	}
+
+	mpi3mr_atto_get_sas_addr(mrioc, &base_address);
+
+	dev_address.q = base_address.q;
+	dev_address.b[0] += ATTO_SAS_ADDR_DEVNAME_BIAS;
+
+	for (i = 0; i < man_pg5->num_phys; i++) {
+		if (sas_io_unit_pg0->phy_data[i].phy_flags &
+			(MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
+			MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
+			continue;
+
+		sas_address.q = base_address.q;
+		sas_address.b[0] += bias++;
+
+		man_pg5->phy[i].device_name = dev_address.q;
+		man_pg5->phy[i].ioc_wwid = sas_address.q;
+		man_pg5->phy[i].sata_wwid = sas_address.q;
+	}
+
+	if (mpi3mr_cfg_set_man_pg5(mrioc, man_pg5, sz))
+		ioc_info(mrioc, "ATTO set manufacuring page 5 failed\n");
+
+out:
+	kfree(sas_io_unit_pg0);
+	kfree(man_pg5);
+
+	return 0;
+}
+
+
 /**
  * mpi3mr_init_ioc - Initialize the controller
  * @mrioc: Adapter instance reference
@@ -4376,6 +4533,9 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
 		goto out_failed;
 	}
 
+	if (mrioc->pdev->subsystem_vendor == MPI3_MFGPAGE_VENDORID_ATTO)
+		mpi3mr_atto_init(mrioc);
+
 	ioc_info(mrioc, "controller initialization completed successfully\n");
 	return retval;
 out_failed:
@@ -6293,6 +6453,118 @@ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
 	return -1;
 }
 
+/**
+ * mpi3mr_cfg_get_man_pg5 - Read manufacturing page 5
+ * @mrioc: Adapter instance reference
+ * @io_unit_pg5: Pointer to the manufacturing page 5 to read
+ * @pg_sz: Size of the memory allocated to the page pointer
+ *
+ * This is handler for config page read of manufacturing
+ * page 5.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_man_pg5(struct mpi3mr_ioc *mrioc,
+	struct mpi3_man_page5 *man_pg5, u16 pg_sz)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(man_pg5, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_MANUFACTURING;
+	cfg_req.page_number = 5;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "manufacturing page5 header read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "manufacturing page5 header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, man_pg5, pg_sz)) {
+		ioc_err(mrioc, "manufacturing page5 read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "manufacturing page5 read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_set_man_pg5 - Write manufacturing page 5
+ * @mrioc: Adapter instance reference
+ * @io_unit_pg5: Pointer to the manufacturing page 5 to write
+ * @pg_sz: Size of the memory allocated to the page pointer
+ *
+ * This is handler for config page write for manufacturing
+ * page 5. This will modify only the current page.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_set_man_pg5(struct mpi3mr_ioc *mrioc,
+	struct mpi3_man_page5 *man_pg5, u16 pg_sz)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_MANUFACTURING;
+	cfg_req.page_number = 5;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "manufacturing page5 header read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "manufacturing page5 header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+
+	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_CURRENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, man_pg5, pg_sz)) {
+		ioc_err(mrioc, "manufacturing page5 write failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "manufacturing page5 write failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+
+	return 0;
+out_failed:
+	return -1;
+}
+
 /**
  * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1
  * @mrioc: Adapter instance reference
@@ -6409,3 +6681,41 @@ int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
 	return -1;
 }
 
+/**
+ * mpi3mr_cfg_get_page_size - Get the size of requested page
+ * @mrioc: Adapter instance reference
+ * @page_type: Page type (MPI3_CONFIG_PAGETYPE_XXX)
+ * @page_num: Page number
+ *
+ * Return the specified config page size in bytes.
+ *
+ * Return: Page size in bytes, -1 on failure.
+ */
+int mpi3mr_cfg_get_page_size(struct mpi3mr_ioc *mrioc, int page_type, int page_num)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = page_type;
+	cfg_req.page_number = page_num;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "header read failed\n");
+		return -1;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		return -1;
+	}
+
+	return cfg_hdr.page_length * 4;
+}
-- 
2.43.5


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ