FreeBSD/sys/dev/mps/mps.c
/* Step through the synchronous command state machine, i.e. "Doorbell mode" */
Step through the synchronous command state machine, i.e. "Doorbell mode"
Step through the synchronous command state machine i . e . " Doorbell mode "
static int
mps_request_sync(struct mps_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply,
    int req_sz, int reply_sz, int timeout)
{
	uint32_t *data32;
	uint16_t *data16;
	int i, count, ioc_sz, residual;
	int sleep_flags = CAN_SLEEP;
	if (curthread->td_no_sleeping != 0)
		sleep_flags = NO_SLEEP;
	mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	if (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED)
		return (EBUSY);
	count = (req_sz + 3) / 4;
	mps_regwrite(sc, MPI2_DOORBELL_OFFSET,
	    (MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
	    (count << MPI2_DOORBELL_ADD_DWORDS_SHIFT));
	if (mps_wait_db_int(sc) ||
	    (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) == 0) {
		mps_dprint(sc, MPS_FAULT, "Doorbell failed to activate\n");
		return (ENXIO);
	}
	mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	if (mps_wait_db_ack(sc, 5, sleep_flags) != 0) {
		mps_dprint(sc, MPS_FAULT, "Doorbell handshake failed\n");
		return (ENXIO);
	}
	data32 = (uint32_t *)req;
	for (i = 0; i < count; i++) {
		mps_regwrite(sc, MPI2_DOORBELL_OFFSET, htole32(data32[i]));
		if (mps_wait_db_ack(sc, 5, sleep_flags) != 0) {
			mps_dprint(sc, MPS_FAULT,
			    "Timeout while writing doorbell\n");
			return (ENXIO);
		}
	}
	data16 = (uint16_t *)reply;
	if (mps_wait_db_int(sc) != 0) {
		mps_dprint(sc, MPS_FAULT, "Timeout reading doorbell 0\n");
		return (ENXIO);
	}
	data16[0] =
	    mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK;
	mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	if (mps_wait_db_int(sc) != 0) {
		mps_dprint(sc, MPS_FAULT, "Timeout reading doorbell 1\n");
		return (ENXIO);
	}
	data16[1] =
	    mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK;
	mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	ioc_sz = reply->MsgLength;
	residual = 0;
	count = MIN((reply_sz / 4), ioc_sz) * 2;
	if (count < ioc_sz * 2) {
		residual = ioc_sz * 2 - count;
		mps_dprint(sc, MPS_ERROR, "Driver error, throwing away %d "
		    "residual message words\n", residual);
	}
	for (i = 2; i < count; i++) {
		if (mps_wait_db_int(sc) != 0) {
			mps_dprint(sc, MPS_FAULT,
			    "Timeout reading doorbell %d\n", i);
			return (ENXIO);
		}
		data16[i] = mps_regread(sc, MPI2_DOORBELL_OFFSET) &
		    MPI2_DOORBELL_DATA_MASK;
		mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	}
	while (residual--) {
		if (mps_wait_db_int(sc) != 0) {
			mps_dprint(sc, MPS_FAULT,
			    "Timeout reading doorbell\n");
			return (ENXIO);
		}
		(void)mps_regread(sc, MPI2_DOORBELL_OFFSET);
		mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	}
	if (mps_wait_db_int(sc) != 0) {
		mps_dprint(sc, MPS_FAULT, "Timeout waiting to exit doorbell\n");
		return (ENXIO);
	}
	if (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED)
		mps_dprint(sc, MPS_FAULT, "Warning, doorbell still active\n");
	mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0);
	return (0);
}
static int mps_request_sync ( struct mps_softc * sc , void * req , MPI2_DEFAULT_REPLY * reply , int req_sz , int reply_sz , int timeout ) { uint32_t * data32 ; uint16_t * data16 ; int i , count , ioc_sz , residual ; int sleep_flags = CAN_SLEEP ; if ( curthread -> td_no_sleeping != 0 ) sleep_flags = NO_SLEEP ; mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; if ( mps_regread ( sc , MPI2_DOORBELL_OFFSET ) & MPI2_DOORBELL_USED ) return ( EBUSY ) ; count = ( req_sz + 3 ) / 4 ; mps_regwrite ( sc , MPI2_DOORBELL_OFFSET , ( MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT ) | ( count << MPI2_DOORBELL_ADD_DWORDS_SHIFT ) ) ; if ( mps_wait_db_int ( sc ) || ( mps_regread ( sc , MPI2_DOORBELL_OFFSET ) & MPI2_DOORBELL_USED ) == 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; if ( mps_wait_db_ack ( sc , 5 , sleep_flags ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } data32 = ( uint32_t * ) req ; for ( i = 0 ; i < count ; i ++ ) { mps_regwrite ( sc , MPI2_DOORBELL_OFFSET , htole32 ( data32 [ i ] ) ) ; if ( mps_wait_db_ack ( sc , 5 , sleep_flags ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } } data16 = ( uint16_t * ) reply ; if ( mps_wait_db_int ( sc ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } data16 [ 0 ] = mps_regread ( sc , MPI2_DOORBELL_OFFSET ) & MPI2_DOORBELL_DATA_MASK ; mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; if ( mps_wait_db_int ( sc ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } data16 [ 1 ] = mps_regread ( sc , MPI2_DOORBELL_OFFSET ) & MPI2_DOORBELL_DATA_MASK ; mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; ioc_sz = reply -> MsgLength ; residual = 0 ; count = MIN ( ( reply_sz / 4 ) , ioc_sz ) * 2 ; if ( count < ioc_sz * 2 ) { residual = ioc_sz * 2 - count ; mps_dprint ( sc , MPS_ERROR , " " " \n " , residual ) ; } for ( i = 2 ; i < count ; i ++ ) { if ( mps_wait_db_int ( sc ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " , i ) ; return ( ENXIO ) ; } data16 [ i ] = mps_regread ( sc , MPI2_DOORBELL_OFFSET ) & MPI2_DOORBELL_DATA_MASK ; mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; } while ( residual -- ) { if ( mps_wait_db_int ( sc ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } ( void ) mps_regread ( sc , MPI2_DOORBELL_OFFSET ) ; mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; } if ( mps_wait_db_int ( sc ) != 0 ) { mps_dprint ( sc , MPS_FAULT , " \n " ) ; return ( ENXIO ) ; } if ( mps_regread ( sc , MPI2_DOORBELL_OFFSET ) & MPI2_DOORBELL_USED ) mps_dprint ( sc , MPS_FAULT , " \n " ) ; mps_regwrite ( sc , MPI2_HOST_INTERRUPT_STATUS_OFFSET , 0x0 ) ; return ( 0 ) ; }
Step through the synchronous command state machine, i.e.
Step through the synchronous command state machine i . e .
/* Step 1 */ /* Step 2 */ /* Step 3
	 * Announce that a message is coming through the doorbell.  Messages
	 * are pushed at 32bit words, so round up if needed.
	 */ /* Step 4 */ /* Step 5 */ /* Clock out the message data synchronously in 32-bit dwords*/ /* Step 6 */ /* Clock in the reply in 16-bit words.  The total length of the
	 * message is always in the 4th byte, so clock out the first 2 words
	 * manually, then loop the rest.
	 */ /* Number of 32bit words in the message */ /*
	 * Figure out how many 16bit words to clock in without overrunning.
	 * The precision loss with dividing reply_sz can safely be
	 * ignored because the messages can only be multiples of 32bits.
	 */ /*
	 * Pull out residual words that won't fit into the provided buffer.
	 * This keeps the chip from hanging due to a driver programming
	 * error.
	 */ /* Step 7 */