diff mbox series

[1/2] scsi: mpi3mr: Add ATTO vendor support and disable firmware download

Message ID 20250613202941.62114-1-ssiwinski@atto.com
State New
Headers show
Series [1/2] scsi: mpi3mr: Add ATTO vendor support and disable firmware download | expand

Commit Message

Steve Siwinski June 13, 2025, 8:29 p.m. UTC
Add support for ATTO HBAs by defining the ATTO vendor ID and adding an
entry to the PCI device ID table for SAS4116-based ATTO devices.

Since ATTO HBAs use specialized firmware, block firmware downloads
to ATTO devices via the MPI3_FUNCTION_CI_DOWNLOAD command and return
an error.

Signed-off-by: Steve Siwinski <ssiwinski@atto.com>
---
 drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 1 +
 drivers/scsi/mpi3mr/mpi3mr_app.c     | 9 +++++++++
 drivers/scsi/mpi3mr/mpi3mr_os.c      | 4 ++++
 3 files changed, 14 insertions(+)

Comments

ALOK TIWARI June 14, 2025, 6:44 a.m. UTC | #1
On 14-06-2025 01:59, Steve Siwinski wrote:
> 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@atto.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

remove extra " " afetr :

> + * @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

it should be @sas_address: Pointer to store the 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");

typo manufacuring -> manufacturing

> +
> +out:
> +	kfree(sas_io_unit_pg0);
> +	kfree(man_pg5);
> +
> +	return 0;
> +}
> +
> +



Thanks
Alok
diff mbox series

Patch

diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
index 96401eb7e231..314eb058c12d 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
@@ -206,6 +206,7 @@  struct mpi3_config_page_header {
 #define MPI3_TEMP_SENSOR_LOCATION_OUTLET                (0x2)
 #define MPI3_TEMP_SENSOR_LOCATION_DRAM                  (0x3)
 #define MPI3_MFGPAGE_VENDORID_BROADCOM                  (0x1000)
+#define MPI3_MFGPAGE_VENDORID_ATTO                      (0x117C)
 #define MPI3_MFGPAGE_DEVID_SAS4116                      (0x00a5)
 #define MPI3_MFGPAGE_DEVID_SAS5116_MPI			(0x00b3)
 #define MPI3_MFGPAGE_DEVID_SAS5116_NVME			(0x00b4)
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
index f36663613950..7e2d23204e6c 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
@@ -2691,6 +2691,15 @@  static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
 		goto out;
 	}
 
+	if (mrioc->pdev->subsystem_vendor == MPI3_MFGPAGE_VENDORID_ATTO &&
+		mpi_header->function == MPI3_FUNCTION_CI_DOWNLOAD) {
+		dprint_bsg_err(mrioc, "%s: Firmware download not supported for ATTO HBA.\n",
+				__func__);
+		rval = -EPERM;
+		mutex_unlock(&mrioc->bsg_cmds.mutex);
+		goto out;
+	}
+
 	if (mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) {
 		nvme_fmt = mpi3mr_get_nvme_data_fmt(
 			(struct mpi3_nvme_encapsulated_request *)mpi_req);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index ce444efd859e..12914400660a 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -5931,6 +5931,10 @@  static const struct pci_device_id mpi3mr_pci_id_table[] = {
 		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
 		    MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT, PCI_ANY_ID, PCI_ANY_ID)
 	},
+	{
+		PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_ATTO,
+		    MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID)
+	},
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);