Commit 91cf186a authored by Bradley Grove's avatar Bradley Grove Committed by Martin K. Petersen
Browse files

scsi: mpt3sas: Add support for ATTO ExpressSAS H12xx GT devices

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: default avatarRob Crispo <rcrispo@attotech.com>
Signed-off-by: default avatarRob Crispo <rcrispo@attotech.com>
Signed-off-by: default avatarBradley Grove <bgrove@attotech.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7f90bc70
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+167 −6
Original line number Diff line number Diff line
@@ -5424,6 +5424,151 @@ static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc)
	return rc;
}

/**
 * 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;

	/*
	 * 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;
+35 −0
Original line number Diff line number Diff line
@@ -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,
+124 −0
Original line number Diff line number Diff line
@@ -540,6 +540,42 @@ mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc,
	return r;
}

/**
 * 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
@@ -757,6 +793,94 @@ 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;
}
+6 −0
Original line number Diff line number Diff line
@@ -12732,6 +12732,12 @@ 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 },

	/*
	 * 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
	 */