FreeBSD/sys/dev/mps/mps.c
/*
 * Add one scatter-gather element (chain, simple, transaction context)
 * to the scatter-gather list for a command.  Maintain cm_sglsize and
 * cm_sge as the remaining size and pointer to the next SGE to fill
 * in, respectively.
 */
Add one scatter-gather element (chain, simple, transaction context)
to the scatter-gather list for a command.  Maintain cm_sglsize and
cm_sge as the remaining size and pointer to the next SGE to fill
in, respectively.
Add one scatter - gather element ( chain simple transaction context ) to the scatter - gather list for a command . Maintain cm_sglsize and cm_sge as the remaining size and pointer to the next SGE to fill in respectively .
int
mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
{
	MPI2_SGE_TRANSACTION_UNION *tc = sgep;
	MPI2_SGE_SIMPLE64 *sge = sgep;
	int error, type;
	uint32_t saved_buf_len, saved_address_low, saved_address_high;
	type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK);
#ifdef INVARIANTS
	switch (type) {
	case MPI2_SGE_FLAGS_TRANSACTION_ELEMENT: {
		if (len != tc->DetailsLength + 4)
			panic("TC %p length %u or %zu?", tc,
			    tc->DetailsLength + 4, len);
		}
		break;
	case MPI2_SGE_FLAGS_CHAIN_ELEMENT:
		if (len != MPS_SGC_SIZE)
			panic("CHAIN %p length %u or %zu?", sgep,
			    MPS_SGC_SIZE, len);
		break;
	case MPI2_SGE_FLAGS_SIMPLE_ELEMENT:
		if (len != MPS_SGE64_SIZE)
			panic("SGE simple %p length %u or %zu?", sge,
			    MPS_SGE64_SIZE, len);
		if (((le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT) &
		    MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0)
			panic("SGE simple %p not marked 64-bit?", sge);
		break;
	default:
		panic("Unexpected SGE %p, flags %02x", tc, tc->Flags);
	}
#endif
	if (cm->cm_sglsize < MPS_SGC_SIZE)
		panic("MPS: Need SGE Error Code\n");
	if (segsleft >= 2 &&
	    cm->cm_sglsize < len + MPS_SGC_SIZE + MPS_SGE64_SIZE) {
		if (type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
			sge->FlagsLength |= htole32(
			    MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT);
		}
		cm->cm_sglsize -= len;
		bcopy(sgep, cm->cm_sge, len);
		cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
		return (mps_add_chain(cm));
	}
	if (segsleft >= 1 && cm->cm_sglsize < len + MPS_SGC_SIZE) {
		if ((error = mps_add_chain(cm)) != 0)
			return (error);
	}
#ifdef INVARIANTS
	if (segsleft == 1 && cm->cm_sglsize < len)
		panic("1 seg left and no room? %u versus %zu",
		    cm->cm_sglsize, len);
	if (segsleft == 2 && cm->cm_sglsize < len + MPS_SGE64_SIZE)
		panic("2 segs left and no room? %u versus %zu",
		    cm->cm_sglsize, len);
#endif
	if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
		saved_buf_len = le32toh(sge->FlagsLength) & 0x00FFFFFF;
		saved_address_low = sge->Address.Low;
		saved_address_high = sge->Address.High;
		if (cm->cm_out_len) {
			sge->FlagsLength = htole32(cm->cm_out_len |
			    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
			    MPI2_SGE_FLAGS_END_OF_BUFFER |
			    MPI2_SGE_FLAGS_HOST_TO_IOC |
			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
			    MPI2_SGE_FLAGS_SHIFT));
			cm->cm_sglsize -= len;
			bcopy(sgep, cm->cm_sge, len);
			cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge
			    + len);
		}
		saved_buf_len |=
		    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
		    MPI2_SGE_FLAGS_END_OF_BUFFER |
		    MPI2_SGE_FLAGS_LAST_ELEMENT |
		    MPI2_SGE_FLAGS_END_OF_LIST |
		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
		    MPI2_SGE_FLAGS_SHIFT);
		if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
			saved_buf_len |=
			    ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
			    MPI2_SGE_FLAGS_SHIFT);
		} else {
			saved_buf_len |=
			    ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
			    MPI2_SGE_FLAGS_SHIFT);
		}
		sge->FlagsLength = htole32(saved_buf_len);
		sge->Address.Low = saved_address_low;
		sge->Address.High = saved_address_high;
	}
	cm->cm_sglsize -= len;
	bcopy(sgep, cm->cm_sge, len);
	cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
	return (0);
}
int mps_push_sge ( struct mps_command * cm , void * sgep , size_t len , int segsleft ) { MPI2_SGE_TRANSACTION_UNION * tc = sgep ; MPI2_SGE_SIMPLE64 * sge = sgep ; int error , type ; uint32_t saved_buf_len , saved_address_low , saved_address_high ; type = ( tc -> Flags & MPI2_SGE_FLAGS_ELEMENT_MASK ) ; #ifdef INVARIANTS switch ( type ) { case MPI2_SGE_FLAGS_TRANSACTION_ELEMENT : { if ( len != tc -> DetailsLength + 4 ) panic ( " " , tc , tc -> DetailsLength + 4 , len ) ; } break ; case MPI2_SGE_FLAGS_CHAIN_ELEMENT : if ( len != MPS_SGC_SIZE ) panic ( " " , sgep , MPS_SGC_SIZE , len ) ; break ; case MPI2_SGE_FLAGS_SIMPLE_ELEMENT : if ( len != MPS_SGE64_SIZE ) panic ( " " , sge , MPS_SGE64_SIZE , len ) ; if ( ( ( le32toh ( sge -> FlagsLength ) >> MPI2_SGE_FLAGS_SHIFT ) & MPI2_SGE_FLAGS_ADDRESS_SIZE ) == 0 ) panic ( " " , sge ) ; break ; default : panic ( " " , tc , tc -> Flags ) ; } #endif if ( cm -> cm_sglsize < MPS_SGC_SIZE ) panic ( " \n " ) ; if ( segsleft >= 2 && cm -> cm_sglsize < len + MPS_SGC_SIZE + MPS_SGE64_SIZE ) { if ( type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT ) { sge -> FlagsLength |= htole32 ( MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT ) ; } cm -> cm_sglsize -= len ; bcopy ( sgep , cm -> cm_sge , len ) ; cm -> cm_sge = ( MPI2_SGE_IO_UNION * ) ( ( uintptr_t ) cm -> cm_sge + len ) ; return ( mps_add_chain ( cm ) ) ; } if ( segsleft >= 1 && cm -> cm_sglsize < len + MPS_SGC_SIZE ) { if ( ( error = mps_add_chain ( cm ) ) != 0 ) return ( error ) ; } #ifdef INVARIANTS if ( segsleft == 1 && cm -> cm_sglsize < len ) panic ( " " , cm -> cm_sglsize , len ) ; if ( segsleft == 2 && cm -> cm_sglsize < len + MPS_SGE64_SIZE ) panic ( " " , cm -> cm_sglsize , len ) ; #endif if ( segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT ) { saved_buf_len = le32toh ( sge -> FlagsLength ) & 0x00FFFFFF ; saved_address_low = sge -> Address . Low ; saved_address_high = sge -> Address . High ; if ( cm -> cm_out_len ) { sge -> FlagsLength = htole32 ( cm -> cm_out_len | ( ( uint32_t ) ( MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC | MPI2_SGE_FLAGS_64_BIT_ADDRESSING ) << MPI2_SGE_FLAGS_SHIFT ) ) ; cm -> cm_sglsize -= len ; bcopy ( sgep , cm -> cm_sge , len ) ; cm -> cm_sge = ( MPI2_SGE_IO_UNION * ) ( ( uintptr_t ) cm -> cm_sge + len ) ; } saved_buf_len |= ( ( uint32_t ) ( MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_64_BIT_ADDRESSING ) << MPI2_SGE_FLAGS_SHIFT ) ; if ( cm -> cm_flags & MPS_CM_FLAGS_DATAIN ) { saved_buf_len |= ( ( uint32_t ) ( MPI2_SGE_FLAGS_IOC_TO_HOST ) << MPI2_SGE_FLAGS_SHIFT ) ; } else { saved_buf_len |= ( ( uint32_t ) ( MPI2_SGE_FLAGS_HOST_TO_IOC ) << MPI2_SGE_FLAGS_SHIFT ) ; } sge -> FlagsLength = htole32 ( saved_buf_len ) ; sge -> Address . Low = saved_address_low ; sge -> Address . High = saved_address_high ; } cm -> cm_sglsize -= len ; bcopy ( sgep , cm -> cm_sge , len ) ; cm -> cm_sge = ( MPI2_SGE_IO_UNION * ) ( ( uintptr_t ) cm -> cm_sge + len ) ; return ( 0 ) ; }
Add one scatter-gather element (chain, simple, transaction context)
 to the scatter-gather list for a command.
Add one scatter - gather element ( chain simple transaction context ) to the scatter - gather list for a command .
/* Driver only uses 32-bit chain elements */ /* Driver only uses 64-bit SGE simple elements */ /*
	 * case 1: 1 more segment, enough room for it
	 * case 2: 2 more segments, enough room for both
	 * case 3: >=2 more segments, only enough room for 1 and a chain
	 * case 4: >=1 more segment, enough room for only a chain
	 * case 5: >=1 more segment, no room for anything (error)
         */ /*
	 * There should be room for at least a chain element, or this
	 * code is buggy.  Case (5).
	 */ /*
		 * There are 2 or more segments left to add, and only
		 * enough room for 1 and a chain.  Case (3).
		 *
		 * Mark as last element in this chain if necessary.
		 */ /*
		 * Add the item then a chain.  Do the chain now,
		 * rather than on the next iteration, to simplify
		 * understanding the code.
		 */ /*
		 * 1 or more segment, enough room for only a chain.
		 * Hope the previous element wasn't a Simple entry
		 * that needed to be marked with
		 * MPI2_SGE_FLAGS_LAST_ELEMENT.  Case (4).
		 */ /* Case 1: 1 more segment, enough room for it. */ /* Case 2: 2 more segments, enough room for both */ /*
		 * If this is a bi-directional request, need to account for that
		 * here.  Save the pre-filled sge values.  These will be used
		 * either for the 2nd SGL or for a single direction SGL.  If
		 * cm_out_len is non-zero, this is a bi-directional request, so
		 * fill in the OUT SGL first, then the IN SGL, otherwise just
		 * fill in the IN SGL.  Note that at this time, when filling in
		 * 2 SGL's for a bi-directional request, they both use the same
		 * DMA buffer (same cm command).
		 */