git: e30fceb89b7e - main - mps: Use 64-bit chain structures

From: Warner Losh <imp_at_FreeBSD.org>
Date: Thu, 03 Feb 2022 05:35:44 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=e30fceb89b7eb51825bdd65f9cc4fbadf107d763

commit e30fceb89b7eb51825bdd65f9cc4fbadf107d763
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2022-02-02 21:36:49 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2022-02-03 05:35:33 +0000

    mps: Use 64-bit chain structures
    
    According to Broadcom, mixing 64-bit SGEs with 32-bit chain entries can
    lead to IOC Fault code 0x40000d04. This fault code has been observed to
    suddenly increase on certain machines when the OCA firmware images are
    deployed. The hardware interprets all elements of a 64-bit SGE, even
    ones marked as 32-bit. Depending on the other bits, this will just work,
    but sometimes generate the above fault. Broadcom recommends this
    practice, and the Linux and NetBSD drivers follow it.
    
    Rework the chaining code to use MPI2_SGE_CHAIN64 instead of
    MPI2_SGE_CHAIN32. Adjust MPS_SGC_SIZE from 8 to 12 to match the size of
    the new structure. Flag the structure as being 64-bits now. Since
    MPS_SGE64_SIZE and MPS_SGC_SIZE are the same now, mps_push_sge could be
    simplified (after the same fashion of mpr). The different number of
    cases collapse to whether or not there's room for the segments and if
    not we need a chain, however these changes haven't been made yet as the
    current code handles those cases properly with the new defines.
    
    Made chain_busaddr 64-bits, even though we ask for all allocations to be
    below 4GB for this tag. Use it to set both parts of the CHAIN64 address
    rather than baking the 4GB assumption. Add asserts around the allocation
    to detect and BUSDMA bugs in allocation.
    
    Remove asserts and associated comment in mpi_pre_fw_download and
    mpi_pre_fw_upload. The code does not, it seems, depend on this
    invariant. The mpr driver has similar code, no asserts and also doesn't
    depend on this.
    
    Adjust comments to reflect the updated size.
    
    Sponsored by:           Netflix
    Reviewed by:            scottl, mav
    Differential Revision:  https://reviews.freebsd.org/D34016
---
 sys/dev/mps/mps.c      | 16 ++++++++++------
 sys/dev/mps/mps_user.c | 12 ------------
 sys/dev/mps/mpsvar.h   |  4 ++--
 3 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c
index 956a0301e70a..5021acf930a3 100644
--- a/sys/dev/mps/mps.c
+++ b/sys/dev/mps/mps.c
@@ -1382,6 +1382,9 @@ mps_load_chains_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 		return;
 
 	for (i = 0, o = 0, s = 0; s < nsegs; s++) {
+		KASSERT(segs[s].ds_addr + segs[s].ds_len - 1 <= BUS_SPACE_MAXADDR_32BIT,
+		    ("mps: Bad segment address %#jx len %#jx\n", (uintmax_t)segs[s].ds_addr,
+			(uintmax_t)segs[s].ds_len));
 		for (bo = 0; bo + sc->reqframesz <= segs[s].ds_len;
 		    bo += sc->reqframesz) {
 			chain = &sc->chains[i++];
@@ -2696,7 +2699,7 @@ mps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle)
 static int
 mps_add_chain(struct mps_command *cm)
 {
-	MPI2_SGE_CHAIN32 *sgc;
+	MPI2_SGE_CHAIN64 *sgc;
 	struct mps_chain *chain;
 	u_int space;
 
@@ -2715,17 +2718,18 @@ mps_add_chain(struct mps_command *cm)
 	 */
 	TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link);
 
-	sgc = (MPI2_SGE_CHAIN32 *)&cm->cm_sge->MpiChain;
+	sgc = (MPI2_SGE_CHAIN64 *)&cm->cm_sge->MpiChain;
 	sgc->Length = htole16(space);
 	sgc->NextChainOffset = 0;
 	/* TODO Looks like bug in Setting sgc->Flags. 
 	 *	sgc->Flags = ( MPI2_SGE_FLAGS_CHAIN_ELEMENT | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
 	 *	            MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT
 	 *	This is fine.. because we are not using simple element. In case of 
-	 *	MPI2_SGE_CHAIN32, we have separate Length and Flags feild.
+	 *	MPI2_SGE_CHAIN64, we have separate Length and Flags feild.
  	 */
-	sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT;
-	sgc->Address = htole32(chain->chain_busaddr);
+	sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT | MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
+	sgc->Address.High = htole32(chain->chain_busaddr >> 32);
+	sgc->Address.Low = htole32(chain->chain_busaddr);
 
 	cm->cm_sge = (MPI2_SGE_IO_UNION *)&chain->chain->MpiSimple;
 	cm->cm_sglsize = space;
@@ -2757,7 +2761,7 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
 		}
 		break;
 	case MPI2_SGE_FLAGS_CHAIN_ELEMENT:
-		/* Driver only uses 32-bit chain elements */
+		/* Driver only uses 64-bit chain elements */
 		if (len != MPS_SGC_SIZE)
 			panic("CHAIN %p length %u or %zu?", sgep,
 			    MPS_SGC_SIZE, len);
diff --git a/sys/dev/mps/mps_user.c b/sys/dev/mps/mps_user.c
index 9d4aab54562f..4b09b486b0dd 100644
--- a/sys/dev/mps/mps_user.c
+++ b/sys/dev/mps/mps_user.c
@@ -468,12 +468,6 @@ mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
 	MPI2_FW_DOWNLOAD_TCSGE tc;
 	int error;
 
-	/*
-	 * This code assumes there is room in the request's SGL for
-	 * the TransactionContext plus at least a SGL chain element.
-	 */
-	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
-
 	if (cmd->req_len != sizeof *req)
 		return (EINVAL);
 	if (cmd->rpl_len != sizeof *rpl)
@@ -521,12 +515,6 @@ mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
 	MPI2_FW_UPLOAD_REPLY *rpl;
 	MPI2_FW_UPLOAD_TCSGE tc;
 
-	/*
-	 * This code assumes there is room in the request's SGL for
-	 * the TransactionContext plus at least a SGL chain element.
-	 */
-	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
-
 	if (cmd->req_len != sizeof *req)
 		return (EINVAL);
 	if (cmd->rpl_len != sizeof *rpl)
diff --git a/sys/dev/mps/mpsvar.h b/sys/dev/mps/mpsvar.h
index 9cffd0f730d5..8e3d324215fe 100644
--- a/sys/dev/mps/mpsvar.h
+++ b/sys/dev/mps/mpsvar.h
@@ -53,7 +53,7 @@
 #define MPS_MSIX_MAX		16
 #define MPS_SGE64_SIZE		12
 #define MPS_SGE32_SIZE		8
-#define MPS_SGC_SIZE		8
+#define MPS_SGC_SIZE		12
 
 #define	 CAN_SLEEP			1
 #define  NO_SLEEP			0
@@ -199,7 +199,7 @@ typedef void mps_command_callback_t(struct mps_softc *, struct mps_command *cm);
 struct mps_chain {
 	TAILQ_ENTRY(mps_chain)		chain_link;
 	MPI2_SGE_IO_UNION		*chain;
-	uint32_t			chain_busaddr;
+	uint64_t			chain_busaddr;
 };
 
 /*