From b46dfeb2f31215fe56288a89d768b3167e823db9 Mon Sep 17 00:00:00 2001
From: Stuart Maybee <smaybee@tintri.com>
Date: Fri, 6 Oct 2023 12:03:54 -0400
Subject: [PATCH 1/2] xxxxx 38xx support for mpt_sas

---
 .../pkg/manifests/driver-storage-mpt_sas.p5m  |  4 +-
 .../common/io/scsi/adapters/mpt_sas/mptsas.c  | 87 +++++++++++++++----
 .../io/scsi/adapters/mpt_sas/mptsas_impl.c    | 44 +++++++---
 .../io/scsi/adapters/mpt_sas/mptsas_init.c    |  5 +-
 .../common/sys/scsi/adapters/mpi/mpi2_cnfg.h  |  3 +
 .../sys/scsi/adapters/mpt_sas/mptsas_var.h    | 16 +++-
 6 files changed, 126 insertions(+), 33 deletions(-)

diff --git a/usr/src/pkg/manifests/driver-storage-mpt_sas.p5m b/usr/src/pkg/manifests/driver-storage-mpt_sas.p5m
index b044e5f292..c1529c5894 100644
--- a/usr/src/pkg/manifests/driver-storage-mpt_sas.p5m
+++ b/usr/src/pkg/manifests/driver-storage-mpt_sas.p5m
@@ -93,7 +93,9 @@ driver name=mpt_sas class=scsi-self-identifying \
     alias=pciex1000,c9 \
     alias=pciex1000,d0 \
     alias=pciex1000,d1 \
-    alias=pciex1000,d2
+    alias=pciex1000,d2 \
+    alias=pciex1000,e5 \
+    alias=pciex1000,e6
 legacy pkg=SUNWmptsas desc="LSI MPT SAS 2.0/2.5 Controller HBA Driver" \
     name="LSI MPT SAS 2.0/2.5 Controller HBA Driver"
 license cr_Sun license=cr_Sun
diff --git a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c
index 3ff2251c90..14a5567cf8 100644
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c
@@ -1097,7 +1097,7 @@ mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 	char			doneq_thread_create = 0;
 	char			added_watchdog = 0;
 	scsi_hba_tran_t		*hba_tran;
-	uint_t			mem_bar = MEM_SPACE;
+	uint_t			mem_bar;
 	int			rval = DDI_FAILURE;
 
 	/* CONSTCOND */
@@ -1279,6 +1279,7 @@ mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 	}
 	config_setup++;
 
+	mem_bar = mpt->m_mem_bar;
 	if (ddi_regs_map_setup(dip, mem_bar, (caddr_t *)&mpt->m_reg,
 	    0, 0, &mpt->m_reg_acc_attr, &mpt->m_datap) != DDI_SUCCESS) {
 		mptsas_log(mpt, CE_WARN, "map setup failed");
@@ -2476,7 +2477,7 @@ mptsas_power(dev_info_t *dip, int component, int level)
 		/*
 		 * Wait up to 30 seconds for IOC to come out of reset.
 		 */
-		while (((ioc_status = ddi_get32(mpt->m_datap,
+		while (((ioc_status = mptsas_hirrd(mpt,
 		    &mpt->m_reg->Doorbell)) &
 		    MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_RESET) {
 			if (polls++ > 3000) {
@@ -2513,6 +2514,60 @@ mptsas_power(dev_info_t *dip, int component, int level)
 	return (rval);
 }
 
+/*
+ * Check for newer v2.6 SAS chips.
+ */
+static void
+mptsas_ioc_check_rev(mptsas_t *mpt)
+{
+	switch (mpt->m_devid) {
+	case MPI26_MFGPAGE_DEVID_SAS3816:
+	case MPI26_MFGPAGE_DEVID_SAS3816_1:
+		mpt->m_is_sea_ioc = 1;
+		mptsas_log(mpt, CE_NOTE, "!mptsas3%d: SAS3816 IOC Detected",
+		    mpt->m_instance);
+		/* fallthrough */
+	case MPI26_MFGPAGE_DEVID_SAS3616:
+	case MPI26_MFGPAGE_DEVID_SAS3708:
+	case MPI26_MFGPAGE_DEVID_SAS3716:
+		mptsas_log(mpt, CE_NOTE, "!mptsas3%d: gen3.5 IOC Detected",
+		    mpt->m_instance);
+		mpt->m_is_gen35_ioc = 1;
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Search through the reg property for the first memory BAR.
+ */
+static void
+mptsas_find_mem_bar(mptsas_t *mpt)
+{
+	int		i, rcount;
+	pci_regspec_t	*reg_data;
+	int		reglen;
+
+	mpt->m_mem_bar = MEM_SPACE; /* old default */
+	/*
+	 * Lookup the 'reg' property.
+	 */
+	if (ddi_getlongprop(DDI_DEV_T_ANY, mpt->m_dip,
+	   DDI_PROP_DONTPASS, "reg", (caddr_t)&reg_data, &reglen) ==
+	   DDI_PROP_SUCCESS) {
+		rcount = reglen / sizeof (pci_regspec_t);
+		for (i = 0; i < rcount; i++) {
+			if (PCI_REG_ADDR_G(reg_data[i].pci_phys_hi) ==
+			    PCI_REG_ADDR_G(PCI_ADDR_MEM64)) {
+				mpt->m_mem_bar = i;
+				break;
+			}
+		}
+	}
+}
+
+
 /*
  * Initialize configuration space and figure out which
  * chip and revison of the chip the mpt driver is using.
@@ -2568,6 +2623,8 @@ mptsas_config_space_init(mptsas_t *mpt)
 	pci_config_put8(mpt->m_config_handle, PCI_CONF_LATENCY_TIMER,
 	    MPTSAS_LATENCY_TIMER);
 
+	mptsas_ioc_check_rev(mpt);
+	mptsas_find_mem_bar(mpt);
 	(void) mptsas_get_pci_cap(mpt);
 	return (TRUE);
 }
@@ -5197,7 +5254,7 @@ mptsas_wait_intr(mptsas_t *mpt, int polltime)
 	 * Get the current interrupt mask and disable interrupts.  When
 	 * re-enabling ints, set mask to saved value.
 	 */
-	int_mask = ddi_get32(mpt->m_datap, &mpt->m_reg->HostInterruptMask);
+	int_mask = mptsas_hirrd(mpt, &mpt->m_reg->HostInterruptMask);
 	MPTSAS_DISABLE_INTR(mpt);
 
 	/*
@@ -10165,7 +10222,7 @@ mptsas_watch(void *arg)
 		/*
 		 * Check if controller is in a FAULT state. If so, reset it.
 		 */
-		doorbell = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
+		doorbell = mptsas_hirrd(mpt, &mpt->m_reg->Doorbell);
 		if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
 			doorbell &= MPI2_DOORBELL_DATA_MASK;
 			mptsas_log(mpt, CE_WARN, "MPT Firmware Fault, "
@@ -12655,7 +12712,7 @@ mptsas_reg_access(mptsas_t *mpt, mptsas_reg_access_t *data, int mode)
 				break;
 
 			case REG_MEM_READ:
-				driverdata.RegData = ddi_get32(mpt->m_datap,
+				driverdata.RegData = mptsas_hirrd(mpt,
 				    (uint32_t *)(void *)mpt->m_reg +
 				    driverdata.RegOffset);
 				if (ddi_copyout(&driverdata.RegData,
@@ -13183,10 +13240,19 @@ mptsas_init_chip(mptsas_t *mpt, int first_time)
 	uint32_t		i;
 	int			rval;
 
+	/*
+	 * Setup configuration space
+	 */
+	if (mptsas_config_space_init(mpt) == FALSE) {
+		mptsas_log(mpt, CE_WARN, "mptsas_config_space_init "
+		    "failed!");
+		goto fail;
+	}
+
 	/*
 	 * Check to see if the firmware image is valid
 	 */
-	if (ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic) &
+	if (mptsas_hirrd(mpt, &mpt->m_reg->HostDiagnostic) &
 	    MPI2_DIAG_FLASH_BAD_SIG) {
 		mptsas_log(mpt, CE_WARN, "mptsas bad flash signature!");
 		goto fail;
@@ -13204,15 +13270,6 @@ mptsas_init_chip(mptsas_t *mpt, int first_time)
 	if ((rval == MPTSAS_SUCCESS_MUR) && (!first_time)) {
 		goto mur;
 	}
-	/*
-	 * Setup configuration space
-	 */
-	if (mptsas_config_space_init(mpt) == FALSE) {
-		mptsas_log(mpt, CE_WARN, "mptsas_config_space_init "
-		    "failed!");
-		goto fail;
-	}
-
 	/*
 	 * IOC facts can change after a diag reset so all buffers that are
 	 * based on these numbers must be de-allocated and re-allocated.  Get
diff --git a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
index fdf79e2d27..9124685977 100644
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
@@ -100,6 +100,26 @@ static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
     struct mptsas_cmd *cmd);
 
+/*
+ * Use to read Host interface registers.  May read up to 3 times for
+ * certain IOC's due to chip bug where zero can be erroneously returned
+ * when under high i/o load.
+ */
+uint32_t
+mptsas_hirrd(mptsas_t *mpt, uint32_t *regaddr)
+{
+	int i, ntries;
+	uint32_t ret;
+
+	ntries = (mpt->m_is_sea_ioc == 1) ? 3 : 1;
+	for (i = 0; i < ntries; i++) {
+		if ((ret = ddi_get32(mpt->m_datap, regaddr)) != 0)
+			break;
+	}
+	return (ret);
+}
+
+
 /*
  * add ioc evnet cmd into the queue
  */
@@ -694,7 +714,7 @@ mptsas_ioc_wait_for_response(mptsas_t *mpt)
 {
 	int	polls = 0;
 
-	while ((ddi_get32(mpt->m_datap,
+	while ((mptsas_hirrd(mpt,
 	    &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
 		drv_usecwait(1000);
 		if (polls++ > 60000) {
@@ -709,7 +729,7 @@ mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
 {
 	int	polls = 0;
 
-	while ((ddi_get32(mpt->m_datap,
+	while ((mptsas_hirrd(mpt,
 	    &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
 		drv_usecwait(1000);
 		if (polls++ > 300000) {
@@ -791,7 +811,7 @@ mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
 	 * data we will be getting
 	 */
 	for (i = 0; i < 2; i++, memp += 2) {
-		val = (ddi_get32(mpt->m_datap,
+		val = (mptsas_hirrd(mpt,
 		    &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
 		ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 		if (mptsas_ioc_wait_for_doorbell(mpt)) {
@@ -820,7 +840,7 @@ mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
 	 * Get the rest of the data
 	 */
 	for (i = 0; i < bytesleft; i++, memp += 2) {
-		val = (ddi_get32(mpt->m_datap,
+		val = (mptsas_hirrd(mpt,
 		    &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
 		ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
 		if (mptsas_ioc_wait_for_doorbell(mpt)) {
@@ -839,8 +859,7 @@ mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
 	 */
 	if (totalbytes > (numbytes / 2)) {
 		for (i = (numbytes / 2); i < totalbytes; i++) {
-			val = (ddi_get32(mpt->m_datap,
-			    &mpt->m_reg->Doorbell) &
+			val = (mptsas_hirrd(mpt, &mpt->m_reg->Doorbell) &
 			    MPI2_DOORBELL_DATA_MASK);
 			ddi_put32(mpt->m_datap,
 			    &mpt->m_reg->HostInterruptStatus, 0);
@@ -878,8 +897,8 @@ mptsas_kick_start(mptsas_t *mpt)
 	/*
 	 * Read the current Diag Reg and save the Host Controlled Boot size.
 	 */
-	diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
-	saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
+	diag_reg = mptsas_hirrd(mpt, &mpt->m_reg->HostDiagnostic);
+	saved_HCB_size = mptsas_hirrd(mpt, &mpt->m_reg->HCBSize);
 
 	/*
 	 * Set Reset Adapter bit and wait 50 mSeconds.
@@ -894,8 +913,7 @@ mptsas_kick_start(mptsas_t *mpt)
 	 * If no more adapter (all FF's), just return failure.
 	 */
 	for (polls = 0; polls < 600000; polls++) {
-		diag_reg = ddi_get32(mpt->m_datap,
-		    &mpt->m_reg->HostDiagnostic);
+		diag_reg = mptsas_hirrd(mpt, &mpt->m_reg->HostDiagnostic);
 		if (diag_reg == 0xFFFFFFFF) {
 			mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 			ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
@@ -945,7 +963,7 @@ mptsas_kick_start(mptsas_t *mpt)
 	 * Wait 60 seconds max for FW to come to ready state.
 	 */
 	for (polls = 0; polls < 60000; polls++) {
-		ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
+		ioc_state = mptsas_hirrd(mpt, &mpt->m_reg->Doorbell);
 		if (ioc_state == 0xFFFFFFFF) {
 			mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 			ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
@@ -978,7 +996,7 @@ mptsas_ioc_reset(mptsas_t *mpt, int first_time)
 	uint32_t	reset_msg;
 	uint32_t	ioc_state;
 
-	ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
+	ioc_state = mptsas_hirrd(mpt, &mpt->m_reg->Doorbell);
 	/*
 	 * If chip is already in ready state then there is nothing to do.
 	 */
@@ -1014,7 +1032,7 @@ mptsas_ioc_reset(mptsas_t *mpt, int first_time)
 			 * Wait no more than 60 seconds for chip to become
 			 * ready.
 			 */
-			while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
+			while ((mptsas_hirrd(mpt, &mpt->m_reg->Doorbell) &
 			    MPI2_IOC_STATE_READY) == 0x0) {
 				drv_usecwait(1000);
 				if (polls++ > 60000) {
diff --git a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c
index d8d9d5cdab..d81286f749 100644
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c
@@ -166,6 +166,9 @@ mptsas_devid_type_string(mptsas_t *mpt)
 		return ("SAS3708");
 	case MPI26_MFGPAGE_DEVID_SAS3716:
 		return ("SAS3716");
+	case MPI26_MFGPAGE_DEVID_SAS3816:
+	case MPI26_MFGPAGE_DEVID_SAS3816_1:
+		return ("SAS3816");
 	case MPI26_MFGPAGE_DEVID_SAS4008:
 		return ("SAS4008");
 	default:
@@ -759,7 +762,7 @@ mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
 		return (DDI_FAILURE);
 	}
 
-	if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) &
+	if ((mptsas_hirrd(mpt, &mpt->m_reg->Doorbell)) &
 	    MPI2_IOC_STATE_OPERATIONAL) {
 		mptsas_log(mpt, CE_NOTE,
 		    "?mpt%d: IOC Operational.\n", mpt->m_instance);
diff --git a/usr/src/uts/common/sys/scsi/adapters/mpi/mpi2_cnfg.h b/usr/src/uts/common/sys/scsi/adapters/mpi/mpi2_cnfg.h
index 73b063015e..c8173899f7 100644
--- a/usr/src/uts/common/sys/scsi/adapters/mpi/mpi2_cnfg.h
+++ b/usr/src/uts/common/sys/scsi/adapters/mpi/mpi2_cnfg.h
@@ -593,6 +593,9 @@ typedef struct _MPI2_CONFIG_REPLY
 #define MPI26_MFGPAGE_DEVID_SAS3616                 (0x00D1)
 #define MPI26_MFGPAGE_DEVID_SAS3708                 (0x00D2)
 
+#define MPI26_MFGPAGE_DEVID_SAS3816                 (0x00E5)
+#define MPI26_MFGPAGE_DEVID_SAS3816_1               (0x00E6)
+
 #define MPI26_MFGPAGE_DEVID_SAS4008                 (0x00A1)
 
 
diff --git a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
index b4498c3bed..da39decd11 100644
--- a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
@@ -933,6 +933,10 @@ typedef struct mptsas {
 	mptsas_fw_diagnostic_buffer_t
 		m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_COUNT];
 
+	/* IOC type flags */
+	uint8_t			m_is_sea_ioc;
+	uint8_t			m_is_gen35_ioc;
+
 	/* GEN3 support */
 	uint8_t			m_MPI25;
 
@@ -951,6 +955,11 @@ typedef struct mptsas {
 	 */
 	uint8_t			m_in_reset;
 
+	/*
+	 * index for the pci memory BAR
+	 */
+	uint8_t			m_mem_bar;
+
 	/*
 	 * per instance cmd data structures for task management cmds
 	 */
@@ -1135,7 +1144,7 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_instance))
 #define	MPTSAS_QUIESCE_TIMEOUT	1		/* 1 sec */
 #define	MPTSAS_PM_IDLE_TIMEOUT	60		/* 60 seconds */
 
-#define	MPTSAS_GET_ISTAT(mpt)  (ddi_get32((mpt)->m_datap, \
+#define	MPTSAS_GET_ISTAT(mpt)  (mptsas_hirrd((mpt), \
 			&(mpt)->m_reg->HostInterruptStatus))
 
 #define	MPTSAS_SET_SIGP(P) \
@@ -1144,7 +1153,7 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_instance))
 #define	MPTSAS_RESET_SIGP(P) (void) ddi_get8(mpt->m_datap, \
 			(uint8_t *)(mpt->m_devaddr + NREG_CTEST2))
 
-#define	MPTSAS_GET_INTCODE(P) (ddi_get32(mpt->m_datap, \
+#define	MPTSAS_GET_INTCODE(P) (mptsas_hirrd(mpt, \
 			(uint32_t *)(mpt->m_devaddr + NREG_DSPS)))
 
 
@@ -1179,7 +1188,7 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_instance))
 
 #define	ClrSetBits32(hdl, reg, clr, set) \
 	ddi_put32(hdl, (reg), \
-	    ((ddi_get32(mpt->m_datap, (reg)) & ~(clr)) | (set)))
+	    ((mptsas_hirrd(mpt, (reg)) & ~(clr)) | (set)))
 
 #define	ClrSetBits(reg, clr, set) \
 	ddi_put8(mpt->m_datap, (uint8_t *)(reg), \
@@ -1312,6 +1321,7 @@ int mptsas_dma_addr_create(mptsas_t *mpt, ddi_dma_attr_t dma_attr,
     ddi_dma_handle_t *dma_hdp, ddi_acc_handle_t *acc_hdp, caddr_t *dma_memp,
     uint32_t alloc_size, ddi_dma_cookie_t *cookiep);
 void mptsas_dma_addr_destroy(ddi_dma_handle_t *, ddi_acc_handle_t *);
+uint32_t mptsas_hirrd(mptsas_t *mpt, uint32_t *regaddr);
 
 /*
  * impl functions
-- 
2.34.1

