xref: /onnv-gate/usr/src/uts/sun4u/io/rmc_comm_dp.c (revision 3482:fb5fbb3c6c48)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*3482Sjfrank  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  *
261708Sstevel  * implementation of the transport layer protocol (known as librsc protocol):
271708Sstevel  *
281708Sstevel  */
291708Sstevel 
301708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
311708Sstevel 
321708Sstevel /*
331708Sstevel  *  Header files
341708Sstevel  */
351708Sstevel 
361708Sstevel #include <sys/conf.h>
371708Sstevel #include <sys/cyclic.h>
381708Sstevel #include <sys/membar.h>
391708Sstevel #include <sys/modctl.h>
401708Sstevel #include <sys/strlog.h>
411708Sstevel #include <sys/sunddi.h>
421708Sstevel #include <sys/ddi.h>
431708Sstevel #include <sys/types.h>
441708Sstevel #include <sys/rmc_comm_dp.h>
451708Sstevel #include <sys/rmc_comm_dp_boot.h>
461708Sstevel #include <sys/rmc_comm_drvintf.h>
471708Sstevel #include <sys/rmc_comm.h>
481708Sstevel 
491708Sstevel #ifdef DEBUG_ERROR_INJECTION
501708Sstevel 
511708Sstevel #define	ERRI_RX_SEQ_NUMBER	1
521708Sstevel #define	ERRI_ACK_MSG		2
531708Sstevel #define	ERRI_CRC_HEADER		3
541708Sstevel #define	ERRI_CRC_MSG		4
551708Sstevel #define	ERRI_SEND_CTL_STACK	5
561708Sstevel #define	ERRI_SEND_CTL_START	6
571708Sstevel 
581708Sstevel #define	ERRI_CTL_RX_SEQ_NUMBER	7
591708Sstevel #define	ERRI_CTL_CRC_HEADER	8
601708Sstevel 
611708Sstevel int	erri_test_number = 0;
621708Sstevel int	erri_test_intrvl = 0;
631708Sstevel int	erri_test_repeat = 0;
641708Sstevel int	erri_test_count = 0;
651708Sstevel 
661708Sstevel int erri_test_simulate_srec_sec(struct rmc_comm_state *, char *, int);
671708Sstevel 
681708Sstevel #endif
691708Sstevel 
701708Sstevel 
711708Sstevel /* static functions */
721708Sstevel 
731708Sstevel static void dp_link_setup_tohandler(void *);
741708Sstevel static void dp_delay_ack_tohandler(void *);
751708Sstevel static uint8_t *dp_get_buffer(struct rmc_comm_state *, uint8_t);
761708Sstevel static void dp_release_buffer(struct rmc_comm_state *, uint8_t);
771708Sstevel static void dp_init_buffers(struct rmc_comm_state *);
781708Sstevel static void dp_got_full_hdr(struct rmc_comm_state *, dp_packet_t *);
791708Sstevel static void dp_got_bp_msg(struct rmc_comm_state *, dp_packet_t *);
801708Sstevel static void dp_got_full_msg(struct rmc_comm_state *, dp_packet_t *);
811708Sstevel static void dp_tx_handle_ack(struct rmc_comm_state *, uint16_t);
821708Sstevel static void dp_tx_handle_nak(struct rmc_comm_state *, uint16_t);
831708Sstevel static void dp_send_packet(struct rmc_comm_state *, uchar_t *);
841708Sstevel static void dp_enable_data_link(struct rmc_comm_state *);
851708Sstevel static int dp_get_msglen(struct rmc_comm_state *, uint8_t *);
861708Sstevel static uint16_t dp_calc_crc16(uint8_t *, int);
871708Sstevel void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t);
881708Sstevel void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t);
891708Sstevel 
901708Sstevel /*
911708Sstevel  * utilities...
921708Sstevel  */
931708Sstevel 
941708Sstevel /*
951708Sstevel  *  init rx/tx buffer pool
961708Sstevel  */
971708Sstevel static void
dp_init_buffers(struct rmc_comm_state * rcs)981708Sstevel dp_init_buffers(struct rmc_comm_state *rcs)
991708Sstevel {
1001708Sstevel 	int i;
1011708Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
1021708Sstevel 
1031708Sstevel 	for (i = 0; i < DP_BUFFER_COUNT; i++)
1041708Sstevel 		dbuf[i].in_use = 0;
1051708Sstevel }
1061708Sstevel 
1071708Sstevel /*
1081708Sstevel  *  get tx/rx buffer
1091708Sstevel  */
1101708Sstevel static uint8_t *
dp_get_buffer(struct rmc_comm_state * rcs,uint8_t type)1111708Sstevel dp_get_buffer(struct rmc_comm_state *rcs, uint8_t type)
1121708Sstevel {
1131708Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
1141708Sstevel 
1151708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
1161708Sstevel 
1171708Sstevel 	if ((type != DP_TX_BUFFER && type != DP_RX_BUFFER) ||
1181708Sstevel 		dbuf[type].in_use) {
1191708Sstevel 
1201708Sstevel 		DPRINTF(rcs, DMEM,
1211708Sstevel 			(CE_CONT, "get buffer err. type=%d, in_use=%d\n",
1221708Sstevel 			type, dbuf[type].in_use));
1231708Sstevel 
1241708Sstevel 		return (NULL);
1251708Sstevel 	}
1261708Sstevel 
1271708Sstevel 	DPRINTF(rcs, DMEM, (CE_CONT, "get buffer type=%d\n", type));
1281708Sstevel 
1291708Sstevel 	dbuf[type].in_use = 1;
1301708Sstevel 
1311708Sstevel 	return (dbuf[type].buf);
1321708Sstevel }
1331708Sstevel 
1341708Sstevel /*
1351708Sstevel  * release tx/rx buffer
1361708Sstevel  */
1371708Sstevel static void
dp_release_buffer(struct rmc_comm_state * rcs,uint8_t type)1381708Sstevel dp_release_buffer(struct rmc_comm_state *rcs, uint8_t type)
1391708Sstevel {
1401708Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
1411708Sstevel 
1421708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
1431708Sstevel 
1441708Sstevel 	if (type != DP_TX_BUFFER && type != DP_RX_BUFFER) {
1451708Sstevel 		DPRINTF(rcs, DMEM,
1461708Sstevel 			(CE_CONT, "free buffer err. type=%d, in_use=%d\n",
1471708Sstevel 			type, dbuf[type].in_use));
1481708Sstevel 		return;
1491708Sstevel 	}
1501708Sstevel 	DPRINTF(rcs, DMEM, (CE_CONT, "free buffer type=%d\n", type));
1511708Sstevel 
1521708Sstevel 	dbuf[type].in_use = 0;
1531708Sstevel }
1541708Sstevel 
1551708Sstevel /*
1561708Sstevel  * setup data link timeout handler
1571708Sstevel  * (called without having the dp_mutex)
1581708Sstevel  */
1591708Sstevel static void
dp_link_setup_tohandler(void * arg)1601708Sstevel dp_link_setup_tohandler(void *arg)
1611708Sstevel {
1621708Sstevel 	struct rmc_comm_state *rcs = (struct rmc_comm_state *)arg;
1631708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
1641708Sstevel 
1651708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "t/o setup data link\n"));
1661708Sstevel 
1671708Sstevel 	/*
1681708Sstevel 	 * check if timer has actually been cancelled
1691708Sstevel 	 */
1701708Sstevel 	mutex_enter(dps->dp_mutex);
1711708Sstevel 	if (dps->timer_link_setup != (timeout_id_t)0) {
1721708Sstevel 
1731708Sstevel 		/*
1741708Sstevel 		 * send CTL:start to the remote side to set up the data link
1751708Sstevel 		 */
1761708Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
1771708Sstevel 
1781708Sstevel 		dps->timer_link_setup = timeout(dp_link_setup_tohandler,
1791708Sstevel 		    (void *) rcs, drv_usectohz(RETRY_DP_SETUP * 1000));
1801708Sstevel 	}
1811708Sstevel 	mutex_exit(dps->dp_mutex);
1821708Sstevel }
1831708Sstevel 
1841708Sstevel /*
1851708Sstevel  * delay acknowledgment of a received message timeout handler
1861708Sstevel  * (called without having the dp_mutex)
1871708Sstevel  */
1881708Sstevel static void
dp_delay_ack_tohandler(void * arg)1891708Sstevel dp_delay_ack_tohandler(void *arg)
1901708Sstevel {
1911708Sstevel 	struct rmc_comm_state *rcs = (struct rmc_comm_state *)arg;
1921708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
1931708Sstevel 
1941708Sstevel #ifdef DEBUG_ERROR_INJECTION
1951708Sstevel 
1961708Sstevel 	if (erri_test_number == ERRI_ACK_MSG &&
1971708Sstevel 	    erri_test_repeat >= 0 &&
1981708Sstevel 	    erri_test_count++ > 0 && !(erri_test_count % erri_test_intrvl)) {
1991708Sstevel 
2001708Sstevel 		/*
2011708Sstevel 		 * DON'T ACK THE MESSAGE - BE SILENT!
2021708Sstevel 		 */
2031708Sstevel 
2041708Sstevel 		if (erri_test_repeat == 0)
2051708Sstevel 			erri_test_repeat--; /* will not repeat the test */
2061708Sstevel 
2071708Sstevel 		dps->timer_delay_ack = (timeout_id_t)0;
2081708Sstevel 		return;
2091708Sstevel 	}
2101708Sstevel 
2111708Sstevel #endif
2121708Sstevel 
2131708Sstevel 	/*
2141708Sstevel 	 * check if timer has actually been cancelled
2151708Sstevel 	 */
2161708Sstevel 	mutex_enter(dps->dp_mutex);
2171708Sstevel 	if (dps->timer_delay_ack != (timeout_id_t)0) {
2181708Sstevel 		/*
2191708Sstevel 		 * ACK the message
2201708Sstevel 		 */
2211708Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_ACK);
2221708Sstevel 		dps->timer_delay_ack = (timeout_id_t)0;
2231708Sstevel 	}
2241708Sstevel 	mutex_exit(dps->dp_mutex);
2251708Sstevel }
2261708Sstevel 
2271708Sstevel /*
2281708Sstevel  * Enable data link protocol:
2291708Sstevel  *  stop data link setup timer
2301708Sstevel  *  set data_link_ok flag
2311708Sstevel  * (must already have the dp_mutex)
2321708Sstevel  */
2331708Sstevel static void
dp_enable_data_link(struct rmc_comm_state * rcs)2341708Sstevel dp_enable_data_link(struct rmc_comm_state *rcs)
2351708Sstevel {
2361708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
2371708Sstevel 	timeout_id_t		 timer_id;
2381708Sstevel 
2391708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
2401708Sstevel 
2411708Sstevel 	dps->data_link_ok = 1;
2421708Sstevel 
2431708Sstevel 	timer_id = dps->timer_link_setup;
2441708Sstevel 	dps->timer_link_setup = (timeout_id_t)0;
2451708Sstevel 	if (timer_id != (timeout_id_t)0) {
2461708Sstevel 
2471708Sstevel 		mutex_exit(dps->dp_mutex);
2481708Sstevel 		(void) untimeout(timer_id);
2491708Sstevel 		mutex_enter(dps->dp_mutex);
2501708Sstevel 	}
2511708Sstevel }
2521708Sstevel 
2531708Sstevel /*
2541708Sstevel  * CRC calculation routine.
2551708Sstevel  */
2561708Sstevel static uint16_t
dp_calc_crc16(uint8_t * buf,int len)2571708Sstevel dp_calc_crc16(uint8_t *buf, int len)
2581708Sstevel {
2591708Sstevel 	extern uint16_t crctab16[];
2601708Sstevel 	uint16_t crc;
2611708Sstevel 
2621708Sstevel 	crc = 0;
2631708Sstevel 	while (len--) {
2641708Sstevel 		crc = (crc >> 8) ^ crctab16[(crc ^ *buf++) & 0xFF];
2651708Sstevel 	}
2661708Sstevel 	return (crc);
2671708Sstevel }
2681708Sstevel 
2691708Sstevel /*
2701708Sstevel  * Reset the data protocol
2711708Sstevel  * (dp_mutex must be held)
2721708Sstevel  */
2731708Sstevel void
dp_reset(struct rmc_comm_state * rcs,uint8_t rx_seqid,boolean_t flush_tx,boolean_t restart_data_link)2741708Sstevel dp_reset(struct rmc_comm_state *rcs, uint8_t rx_seqid,
2751708Sstevel     boolean_t flush_tx, boolean_t restart_data_link)
2761708Sstevel {
2771708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
2781708Sstevel 
2791708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
2801708Sstevel 
2811708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT,
2821708Sstevel 	    "reset proto: rxsid=%d, flushtx=%d, restartdp=%d\n",
2831708Sstevel 	    rx_seqid, flush_tx, restart_data_link));
2841708Sstevel 
2851708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT,
2861708Sstevel 	    "stats: reset=%d nak=%d start=%d stack=%d retries=%d crcerr=%d\n",
2871708Sstevel 	    dps->reset_cnt, dps->nak_cnt, dps->start_cnt, dps->stack_cnt,
2881708Sstevel 	    dps->retries_cnt, dps->crcerr_cnt));
2891708Sstevel 
2901708Sstevel 	dps->last_rx_seqid = rx_seqid;
2911708Sstevel 	dps->reset_cnt++;
2921708Sstevel 
2931708Sstevel 	/*
2941708Sstevel 	 * Flush pending tx message.
2951708Sstevel 	 */
2961708Sstevel 	if (flush_tx) {
2971708Sstevel 		dps->last_tx_seqid = INITIAL_SEQID;
2981708Sstevel 		dps->last_rx_ack = rx_seqid;
2991708Sstevel 
3001708Sstevel 		/*
3011708Sstevel 		 * if there is any pending request/response session
3021708Sstevel 		 * then just abort it.
3031708Sstevel 		 */
3041708Sstevel 		dp_wake_up_waiter(rcs, MSG_ERROR);
3051708Sstevel 	}
3061708Sstevel 
3071708Sstevel 	/*
3081708Sstevel 	 * restart data link, but only if the data link set up timer is
3091708Sstevel 	 * not already running.
3101708Sstevel 	 */
3111708Sstevel 	if (restart_data_link && dps->timer_link_setup == (timeout_id_t)0) {
3121708Sstevel 
3131708Sstevel 		dps->data_link_ok = 0;
3141708Sstevel 
3151708Sstevel 		/*
3161708Sstevel 		 * set up the data protocol link
3171708Sstevel 		 */
3181708Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
3191708Sstevel 		dps->timer_link_setup = timeout(dp_link_setup_tohandler,
3201708Sstevel 		    (void *)rcs, drv_usectohz(RETRY_DP_SETUP * 1000));
3211708Sstevel 	}
3221708Sstevel }
3231708Sstevel 
3241708Sstevel /*
3251708Sstevel  * Handles acknowledgment of a message previously sent OR a heartbeat command
3261708Sstevel  * (CTL_RESPOND).
3271708Sstevel  */
3281708Sstevel static void
dp_tx_handle_ack(struct rmc_comm_state * rcs,uint16_t rxnum)3291708Sstevel dp_tx_handle_ack(struct rmc_comm_state *rcs, uint16_t rxnum)
3301708Sstevel {
3311708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
3321708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
3331708Sstevel 
3341708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
3351708Sstevel 
3361708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "handle ACK, rxnum=%03d\n", rxnum));
3371708Sstevel 
3381708Sstevel 	dps->last_rx_ack = rxnum;
3391708Sstevel 	if ((drr->flags & MSG_SENT) == 0) {
3401708Sstevel 		/*
3411708Sstevel 		 * no pending messages, so nothing to do
3421708Sstevel 		 */
3431708Sstevel 		return;
3441708Sstevel 	}
3451708Sstevel 
3461708Sstevel 	if (rxnum == dps->last_tx_seqid) {
3471708Sstevel 		/*
3481708Sstevel 		 * message was sent and acknowledged successfully
3491708Sstevel 		 * set flag and signal the waiting task if it is not
3501708Sstevel 		 * expecting a reply back
3511708Sstevel 		 */
3521708Sstevel 		drr->flags |= MSG_ACKED;
3531708Sstevel 		if (drr->response.msg_type == DP_NULL_MSG) {
3541708Sstevel 			dp_wake_up_waiter(rcs, MSG_ACKED);
3551708Sstevel 		}
3561708Sstevel 	}
3571708Sstevel }
3581708Sstevel 
3591708Sstevel /*
3601708Sstevel  * Handles NAK
3611708Sstevel  */
3621708Sstevel static void
dp_tx_handle_nak(struct rmc_comm_state * rcs,uint16_t rxnum)3631708Sstevel dp_tx_handle_nak(struct rmc_comm_state *rcs, uint16_t rxnum)
3641708Sstevel {
3651708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
3661708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
3671708Sstevel 
3681708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
3691708Sstevel 
3701708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "handle NAK, rxnum=%03d\n", rxnum));
3711708Sstevel 
3721708Sstevel 	if ((drr->flags & MSG_SENT) == 0) {
3731708Sstevel 		/*
3741708Sstevel 		 * no pending messages, so nothing to do
3751708Sstevel 		 */
3761708Sstevel 		return;
3771708Sstevel 	}
3781708Sstevel 
3791708Sstevel 	/*
3801708Sstevel 	 * since one message per time can be sent, it is assumed that the
3811708Sstevel 	 * message being NAKed is just the one that has been sent.
3821708Sstevel 	 */
3831708Sstevel 	dps->nak_cnt++;
3841708Sstevel 
3851708Sstevel 	dp_wake_up_waiter(rcs, MSG_NAKED);
3861708Sstevel }
3871708Sstevel 
3881708Sstevel /*
3891708Sstevel  * Got a full header. Check header CRC and get the length of the packet
3901708Sstevel  */
3911708Sstevel static void
dp_got_full_hdr(struct rmc_comm_state * rcs,dp_packet_t * pkt)3921708Sstevel dp_got_full_hdr(struct rmc_comm_state *rcs, dp_packet_t *pkt)
3931708Sstevel {
3941708Sstevel 	/*
3951708Sstevel 	 * Got the full header.  Call up to the logical layer to see
3961708Sstevel 	 * how big of a buffer I need for this message.  If the size
3971708Sstevel 	 * is < sizeof (dp_msg_t), then there is something wrong with
3981708Sstevel 	 * this message - drop it.  If the size is equal, then hand it
3991708Sstevel 	 * up right now. If the size is too big - drop it. otherwise we must
4001708Sstevel 	 * receive the body of the message.
4011708Sstevel 	 */
4021708Sstevel 
4031708Sstevel 	pkt->full_length = dp_get_msglen(rcs, pkt->buf);
4041708Sstevel 
4051708Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "got header msglen=%d\n",
4061708Sstevel 	    pkt->full_length));
4071708Sstevel 
4081708Sstevel 	if ((pkt->full_length < 0) ||
4091708Sstevel 	    (pkt->full_length < sizeof (dp_header_t)) ||
4101708Sstevel 	    (pkt->full_length > DP_BUFFER_SIZE)) {
4111708Sstevel 		/*
4121708Sstevel 		 * not a valid message: either message too big or too small
4131708Sstevel 		 */
4141708Sstevel 		dp_release_buffer(rcs, DP_RX_BUFFER);
4151708Sstevel 		pkt->buf = NULL;
4161708Sstevel 
4171708Sstevel 		pkt->rx_state = WAITING_FOR_SYNC;
4181708Sstevel 
4191708Sstevel 	} else if (pkt->full_length == sizeof (dp_header_t)) {
4201708Sstevel 		/*
4211708Sstevel 		 * process message: it is basically a control message
4221708Sstevel 		 * (no data being carried)
4231708Sstevel 		 */
4241708Sstevel 		rmc_comm_dp_mrecv(rcs, pkt->buf);
4251708Sstevel 
4261708Sstevel 		dp_release_buffer(rcs, DP_RX_BUFFER);
4271708Sstevel 		pkt->buf = NULL;
4281708Sstevel 
4291708Sstevel 		pkt->rx_state = WAITING_FOR_SYNC;
4301708Sstevel 	} else {
4311708Sstevel 		pkt->rx_state = RECEIVING_BODY;
4321708Sstevel 	}
4331708Sstevel }
4341708Sstevel 
4351708Sstevel /*
4361708Sstevel  * Got a BP (boot prom) message. Usually, BP messages are received when
4371708Sstevel  * the firmware goes into boot monitor mode (where only BP protocol is used).
4381708Sstevel  * This just happens during firmware download. There should not be any other
4391708Sstevel  * case where a BP message is received.
4401708Sstevel  */
4411708Sstevel static void
dp_got_bp_msg(struct rmc_comm_state * rcs,dp_packet_t * pkt)4421708Sstevel dp_got_bp_msg(struct rmc_comm_state *rcs, dp_packet_t *pkt)
4431708Sstevel {
4441708Sstevel 	bp_msg_t		*msgp = (bp_msg_t *)pkt->buf;
4451708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
4461708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
4471708Sstevel 	int			datalen = sizeof (bp_msg_t);
4481708Sstevel 
4491708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
4501708Sstevel 
4511708Sstevel 	/*
4521708Sstevel 	 * ignore BP message, if it is not expected
4531708Sstevel 	 */
4541708Sstevel 	if ((drr->flags & MSG_SENT_BP) != 0) {
4551708Sstevel 
4561708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "got bp msg: %02x %02x %02x\n",
4571708Sstevel 		    msgp->cmd, msgp->dat1, msgp->dat2));
4581708Sstevel 
4591708Sstevel 		/*
4601708Sstevel 		 * A boot prom (BP) msg has been sent. Here is the
4611708Sstevel 		 * 'expected' reply
4621708Sstevel 		 */
4631708Sstevel 
4641708Sstevel 		/*
4651708Sstevel 		 * check that the recv buffer is big enough (just in case).
4661708Sstevel 		 */
4671708Sstevel 		if (datalen <= drr->response.msg_bufsiz) {
4681708Sstevel 			bcopy(pkt->buf, drr->response.msg_buf, datalen);
4691708Sstevel 			drr->response.msg_msglen = datalen;
4701708Sstevel 			dp_wake_up_waiter(rcs, MSG_RXED_BP);
4711708Sstevel 		} else {
4721708Sstevel 			drr->response.msg_msglen = -1;
4731708Sstevel 			dp_wake_up_waiter(rcs, MSG_RXED_BP);
4741708Sstevel 		}
4751708Sstevel 	}
4761708Sstevel 
4771708Sstevel 	/* Return the buffer to the pool and wait for the next msg. */
4781708Sstevel 	dp_release_buffer(rcs, DP_RX_BUFFER);
4791708Sstevel 	pkt->buf = NULL;
4801708Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
4811708Sstevel }
4821708Sstevel 
4831708Sstevel /*
4841708Sstevel  * Got a complete message, check CRC and pass it on to the upper layer (message
4851708Sstevel  * processing)
4861708Sstevel  */
4871708Sstevel static void
dp_got_full_msg(struct rmc_comm_state * rcs,dp_packet_t * pkt)4881708Sstevel dp_got_full_msg(struct rmc_comm_state *rcs, dp_packet_t *pkt)
4891708Sstevel {
4901708Sstevel 	uint16_t	 crc;
4911708Sstevel 	int		 msglen;
4921708Sstevel 
4931708Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "got full msg\n"));
4941708Sstevel 
4951708Sstevel 	/*
4961708Sstevel 	 * check message CRC
4971708Sstevel 	 */
4981708Sstevel 
4991708Sstevel 	msglen = pkt->full_length - sizeof (dp_header_t) - sizeof (crc);
5001708Sstevel 
5011708Sstevel 	bcopy(pkt->buf + (pkt->full_length - sizeof (crc)), &crc, sizeof (crc));
5021708Sstevel 
5031708Sstevel 	if (crc == dp_calc_crc16(pkt->buf + sizeof (dp_header_t), msglen)) {
5041708Sstevel 		/*
5051708Sstevel 		 * CRC is ok, process this message
5061708Sstevel 		 */
5071708Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "got 'good' msg\n"));
5081708Sstevel 
5091708Sstevel 		rmc_comm_dp_mrecv(rcs, pkt->buf);
5101708Sstevel 	} else {
5111708Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "CRC error (msg)\n"));
5121708Sstevel 		rcs->dp_state.crcerr_cnt++;
5131708Sstevel 	}
5141708Sstevel 
5151708Sstevel 	dp_release_buffer(rcs, DP_RX_BUFFER);
5161708Sstevel 	pkt->buf = NULL;
5171708Sstevel 
5181708Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
5191708Sstevel }
5201708Sstevel 
5211708Sstevel /*
5221708Sstevel  * Check the checksum of the header & return the length field.  If the
5231708Sstevel  * checksum check fails, then return -1.
5241708Sstevel  */
5251708Sstevel static int
dp_get_msglen(struct rmc_comm_state * rcs,uint8_t * buf)5261708Sstevel dp_get_msglen(struct rmc_comm_state *rcs, uint8_t *buf)
5271708Sstevel {
5281708Sstevel 	dp_header_t 	*dp_msgp;
5291708Sstevel 	uint16_t	 crc;
5301708Sstevel 
5311708Sstevel 	dp_msgp = (dp_header_t *)buf;
5321708Sstevel 
5331708Sstevel 	crc = dp_calc_crc16(buf + sizeof (dp_msgp->pad), sizeof (dp_header_t) -
5341708Sstevel 	    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
5351708Sstevel 
5361708Sstevel 	if (dp_msgp->crc == crc) {
5371708Sstevel 		return (dp_msgp->length + sizeof (dp_msgp->pad));
5381708Sstevel 	} else {
5391708Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "CRC error (header)\n"));
5401708Sstevel 		rcs->dp_state.crcerr_cnt++;
5411708Sstevel 		return (-1);
5421708Sstevel 	}
5431708Sstevel }
5441708Sstevel 
5451708Sstevel /*
5461708Sstevel  * to send a protocol packet to the remote side. it handles escaping SYNC
5471708Sstevel  * and ESC chars
5481708Sstevel  */
5491708Sstevel static void
dp_send_packet(struct rmc_comm_state * rcs,uchar_t * buf)5501708Sstevel dp_send_packet(struct rmc_comm_state *rcs, uchar_t *buf)
5511708Sstevel {
5521708Sstevel 	char syncbuf[2];
5531708Sstevel 	dp_header_t *dp_msgp = (dp_header_t *)buf;
5541708Sstevel 	int total, cur;
5551708Sstevel 
5561708Sstevel 	/* First, send out two SYNC characters. */
5572840Scarlsonj 	syncbuf[0] = syncbuf[1] = (char)SYNC_CHAR;
5582840Scarlsonj 	rmc_comm_serdev_send(rcs, syncbuf, 2);
5591708Sstevel 
5601708Sstevel 	total = dp_msgp->length;
5611708Sstevel 	buf = buf + sizeof (dp_msgp->pad);
5621708Sstevel 
5631708Sstevel 	while (total > 0) {
5641708Sstevel 		cur = 0;
5651708Sstevel 
5661708Sstevel 		/* Count up characters that don't need ESC'ing. */
5671708Sstevel 		while ((cur < total) &&
5681708Sstevel 		    (buf[cur] != ESC_CHAR) &&
5691708Sstevel 		    (buf[cur] != SYNC_CHAR)) {
5701708Sstevel 			cur++;
5711708Sstevel 		}
5721708Sstevel 
5731708Sstevel 		/* Send characters that don't need escaping, if any. */
5741708Sstevel 		if (cur > 0) {
5751708Sstevel 			rmc_comm_serdev_send(rcs, (char *)buf, cur);
5761708Sstevel 			total -= cur;
5771708Sstevel 			buf += cur;
5781708Sstevel 		}
5791708Sstevel 
5801708Sstevel 		/*
5811708Sstevel 		 * If total > 0 at this point, we need to send an
5821708Sstevel 		 * ESC'd character.  Send as many as there are.
5831708Sstevel 		 */
5841708Sstevel 		while ((total > 0) &&
5851708Sstevel 		    ((*buf == SYNC_CHAR) || (*buf == ESC_CHAR))) {
5862840Scarlsonj 			syncbuf[0] = (char)ESC_CHAR;
5871708Sstevel 			syncbuf[1] = *buf;
5882840Scarlsonj 			rmc_comm_serdev_send(rcs, syncbuf, 2);
5891708Sstevel 			buf++;
5901708Sstevel 			total--;
5911708Sstevel 		}
5921708Sstevel 	}
5931708Sstevel }
5941708Sstevel 
5951708Sstevel /*
5961708Sstevel  * to wake a thread waiting for a reply/ACK/error status for a request/response
5971708Sstevel  * session.
5981708Sstevel  */
5991708Sstevel void
dp_wake_up_waiter(struct rmc_comm_state * rcs,uint8_t flags)6001708Sstevel dp_wake_up_waiter(struct rmc_comm_state *rcs, uint8_t flags)
6011708Sstevel {
6021708Sstevel 	dp_req_resp_t *drr = &rcs->dp_state.req_resp;
6031708Sstevel 
6041708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
6051708Sstevel 
6061708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "wake up? %x, set %x\n",
6071708Sstevel 	    (drr->flags & (MSG_SENT | MSG_SENT_BP)) != 0, flags));
6081708Sstevel 
6091708Sstevel 	if ((drr->flags & (MSG_SENT | MSG_SENT_BP)) != 0) {
6101708Sstevel 		drr->flags |= flags;
6111708Sstevel 		cv_signal(drr->cv_wait_reply);
6121708Sstevel 	}
6131708Sstevel }
6141708Sstevel 
6151708Sstevel /*
6161708Sstevel  * initialization of the data protocol (called from the attach routine)
6171708Sstevel  */
6181708Sstevel void
rmc_comm_dp_init(struct rmc_comm_state * rcs)6191708Sstevel rmc_comm_dp_init(struct rmc_comm_state *rcs)
6201708Sstevel {
6211708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
6221708Sstevel 	dp_packet_t *pkt = &dps->dp_packet;
6231708Sstevel 
6241708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_dp_init\n"));
6251708Sstevel 
6261708Sstevel 	/*
6271708Sstevel 	 * initialize data structure:
6281708Sstevel 	 */
6291708Sstevel 	bzero((void *) dps, sizeof (rmc_comm_dp_state_t));
6301708Sstevel 
6311708Sstevel 	/*
6321708Sstevel 	 * initialize packet receive handler state
6331708Sstevel 	 */
6341708Sstevel 
6351708Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
6361708Sstevel 
6371708Sstevel 	/*
6381708Sstevel 	 * cv variables initialization
6391708Sstevel 	 * (dp_mutex has been already created during the serial device
6401708Sstevel 	 * initialization)
6411708Sstevel 	 */
6421708Sstevel 	cv_init(dps->cv_ok_to_send, NULL, CV_DRIVER, NULL);
6431708Sstevel 	cv_init(dps->req_resp.cv_wait_reply, NULL, CV_DRIVER, NULL);
6441708Sstevel 
6451708Sstevel 	mutex_enter(dps->dp_mutex);
6461708Sstevel 
6471708Sstevel 	dp_init_buffers(rcs);
6481708Sstevel 
6491708Sstevel 	/*
6501708Sstevel 	 * initialize the data protocol (reset sequence numbers, etc.)
6511708Sstevel 	 */
6521708Sstevel 	dps->last_tx_seqid = INITIAL_SEQID;
6531708Sstevel 	dps->last_rx_seqid = dps->last_rx_ack = INITIAL_SEQID;
6541708Sstevel 
6551708Sstevel 	/*
6561708Sstevel 	 * start timer to 'delay' the set up of the data protocol link
6571708Sstevel 	 */
6581708Sstevel 	dps->timer_link_setup = timeout(dp_link_setup_tohandler,
6591708Sstevel 	    (void *)rcs, drv_usectohz(DELAY_DP_SETUP * 1000));
6601708Sstevel 
6611708Sstevel 	mutex_exit(dps->dp_mutex);
6621708Sstevel 
6631708Sstevel #ifdef DEBUG_ERROR_INJECTION
6641708Sstevel 
6651708Sstevel 	erri_test_number = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
6661708Sstevel 	    DDI_PROP_DONTPASS, "test-no", 0);
6671708Sstevel 	erri_test_intrvl = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
6681708Sstevel 	    DDI_PROP_DONTPASS, "test-interval", 0);
6691708Sstevel 	erri_test_repeat = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
6701708Sstevel 	    DDI_PROP_DONTPASS, "test-repeat", 0);
6711708Sstevel 
6721708Sstevel 	erri_test_count = 0;
6731708Sstevel 
6741708Sstevel 
6751708Sstevel 	cmn_err(CE_CONT, "error injection test: no=%d, intrvl=%d, rep=%d\n",
6761708Sstevel 	    erri_test_number, erri_test_intrvl, erri_test_repeat);
6771708Sstevel #endif
6781708Sstevel 
6791708Sstevel }
6801708Sstevel 
6811708Sstevel /*
6821708Sstevel  * termination of the data protocol (called from the detach routine)
6831708Sstevel  */
6841708Sstevel void
rmc_comm_dp_fini(struct rmc_comm_state * rcs)6851708Sstevel rmc_comm_dp_fini(struct rmc_comm_state *rcs)
6861708Sstevel {
6871708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
6881708Sstevel 	timeout_id_t	 tid_delay_ack;
6891708Sstevel 	timeout_id_t	 tid_link_setup;
6901708Sstevel 
6911708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT,
6921708Sstevel 	    "stats: reset=%d nak=%d start=%d stack=%d retries=%d crcerr=%d\n",
6931708Sstevel 	    dps->reset_cnt, dps->nak_cnt, dps->start_cnt, dps->stack_cnt,
6941708Sstevel 	    dps->retries_cnt, dps->crcerr_cnt));
6951708Sstevel 
6961708Sstevel 	/*
6971708Sstevel 	 * if any timer is running, must be terminated here!
6981708Sstevel 	 */
6991708Sstevel 	mutex_enter(dps->dp_mutex);
7001708Sstevel 	tid_delay_ack = dps->timer_link_setup;
7011708Sstevel 	tid_link_setup = dps->timer_delay_ack;
7021708Sstevel 	dps->timer_link_setup = (timeout_id_t)0;
7031708Sstevel 	dps->timer_delay_ack = (timeout_id_t)0;
7041708Sstevel 	mutex_exit(dps->dp_mutex);
7051708Sstevel 
7061708Sstevel 	if (tid_delay_ack)
7071708Sstevel 		(void) untimeout(tid_delay_ack);
7081708Sstevel 
7091708Sstevel 	if (tid_link_setup)
7101708Sstevel 		(void) untimeout(tid_link_setup);
7111708Sstevel 
7121708Sstevel 	/*
7131708Sstevel 	 * cv variables termination
7141708Sstevel 	 */
7151708Sstevel 	cv_destroy(dps->cv_ok_to_send);
7161708Sstevel 	cv_destroy(dps->req_resp.cv_wait_reply);
7171708Sstevel }
7181708Sstevel 
7191708Sstevel /*
7201708Sstevel  * This is the low-level receiver handler. It's job is to find a complete
7211708Sstevel  * message from the incoming data stream, and once it finds one to pass it
7221708Sstevel  * on to the upper layer (message processing).
7231708Sstevel  * (it must have the dp_mutex)
7241708Sstevel  */
7251708Sstevel void
rmc_comm_dp_drecv(struct rmc_comm_state * rcs,uint8_t * buf,int buflen)7261708Sstevel rmc_comm_dp_drecv(struct rmc_comm_state *rcs, uint8_t *buf, int buflen)
7271708Sstevel {
7281708Sstevel 	rmc_comm_dp_state_t 	*dps = &rcs->dp_state;
7291708Sstevel 	dp_packet_t 		*pkt = &dps->dp_packet;
7301708Sstevel 	uint8_t			 quit;
7311708Sstevel 	int			 count;
7321708Sstevel 	int			 max;
7331708Sstevel 
7341708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
7351708Sstevel 
7361708Sstevel 	pkt->inbuf = buf;
7371708Sstevel 	pkt->inbuflen = buflen;
7381708Sstevel 
7391708Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "drecv len=%d\n", buflen));
7401708Sstevel 
7411708Sstevel 	while (pkt->inbuflen > 0) {
7421708Sstevel 		switch (pkt->rx_state) {
7431708Sstevel 
7441708Sstevel 		case WAITING_FOR_SYNC:
7451708Sstevel 			while ((pkt->inbuflen > 0) &&
7461708Sstevel 			    (*pkt->inbuf != SYNC_CHAR) &&
7471708Sstevel 			    (*pkt->inbuf != ESC_CHAR)) {
7481708Sstevel 
7491708Sstevel 				DPRINTF(rcs, DPKT,
7501708Sstevel 				    (CE_CONT, "not SYNC: %02x\n",
7511708Sstevel 				    (uchar_t)(*pkt->inbuf)));
7521708Sstevel 
7531708Sstevel 				pkt->inbuf++;
7541708Sstevel 				pkt->inbuflen--;
7551708Sstevel 			}
7561708Sstevel 
7571708Sstevel 			if (pkt->inbuflen > 0) {
7581708Sstevel 				if (*pkt->inbuf == SYNC_CHAR)
7591708Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
7601708Sstevel 				else if (*pkt->inbuf == ESC_CHAR)
7611708Sstevel 					pkt->rx_state = WAITING_FOR_SYNC_ESC;
7621708Sstevel 			}
7631708Sstevel 			break;
7641708Sstevel 
7651708Sstevel 		case WAITING_FOR_SYNC_ESC:
7661708Sstevel 			pkt->inbuf++;
7671708Sstevel 			pkt->inbuflen--;
7681708Sstevel 			pkt->rx_state = WAITING_FOR_SYNC;
7691708Sstevel 			break;
7701708Sstevel 
7711708Sstevel 		case WAITING_FOR_HDR:
7721708Sstevel 			while ((pkt->inbuflen > 0) &&
7731708Sstevel 			    (*pkt->inbuf == SYNC_CHAR)) {
7741708Sstevel 				pkt->inbuf++;
7751708Sstevel 				pkt->inbuflen--;
7761708Sstevel 			}
7771708Sstevel 
7781708Sstevel 			if (pkt->inbuflen <= 0)
7791708Sstevel 				break;
7801708Sstevel 
7811708Sstevel 			if (*pkt->inbuf == ESC_CHAR) {
7821708Sstevel 				/*
7831708Sstevel 				 * ESC as first char of header?
7841708Sstevel 				 * Impossible - start over!
7851708Sstevel 				 */
7861708Sstevel 				pkt->rx_state = WAITING_FOR_SYNC;
7871708Sstevel 				pkt->inbuf++;
7881708Sstevel 				pkt->inbuflen--;
7891708Sstevel 				break;
7901708Sstevel 			}
7911708Sstevel 
7921708Sstevel 			/* Get a buffer for this message. */
7931708Sstevel 			pkt->buf = dp_get_buffer(rcs, DP_RX_BUFFER);
7941708Sstevel 			if (pkt->buf == NULL) {
7951708Sstevel 				/* Out of buffers - drop this msg. */
7961708Sstevel 				pkt->rx_state = WAITING_FOR_SYNC;
7971708Sstevel 				break;
7981708Sstevel 			}
7991708Sstevel 			DPRINTF(rcs, DPKT, (CE_CONT, "drecv first char %x\n",
8001708Sstevel 			    (uchar_t)*pkt->inbuf));
8011708Sstevel 
8021708Sstevel 			pkt->buf[1] = *pkt->inbuf;
8031708Sstevel 			pkt->bufpos = 2;
8041708Sstevel 			pkt->rx_state = RECEIVING_HDR;
8051708Sstevel 
8061708Sstevel 			pkt->inbuf++;
8071708Sstevel 			pkt->inbuflen--;
8081708Sstevel 			break;
8091708Sstevel 
8101708Sstevel 		case RECEIVING_HDR:
8111708Sstevel 			quit = 0;
8121708Sstevel 			while ((pkt->inbuflen > 0) &&
8131708Sstevel 			    (*pkt->inbuf != SYNC_CHAR) &&
8141708Sstevel 			    (*pkt->inbuf != ESC_CHAR)) {
8151708Sstevel 				pkt->buf[pkt->bufpos++] = *pkt->inbuf;
8161708Sstevel 				pkt->inbuf++;
8171708Sstevel 				pkt->inbuflen--;
8181708Sstevel 				if (pkt->bufpos >= sizeof (dp_header_t)) {
8191708Sstevel 					dp_got_full_hdr(rcs, pkt);
8201708Sstevel 					quit = 1;
8211708Sstevel 					break;
8221708Sstevel 				} else if ((pkt->bufpos >= sizeof (bp_msg_t)) &&
8231708Sstevel 				    (IS_BOOT_MSG(pkt->buf[1]))) {
8241708Sstevel 					dp_got_bp_msg(rcs, pkt);
8251708Sstevel 					quit = 1;
8261708Sstevel 					break;
8271708Sstevel 				}
8281708Sstevel 			}
8291708Sstevel 
8301708Sstevel 			if (quit)
8311708Sstevel 				break;
8321708Sstevel 
8331708Sstevel 			if (pkt->inbuflen > 0) {
8341708Sstevel 				/* Must have gotten an ESC_CHAR or SYNC_CHAR. */
8351708Sstevel 				if (*pkt->inbuf == SYNC_CHAR) {
8361708Sstevel 
8371708Sstevel 					DPRINTF(rcs, DPKT,
8381708Sstevel 						(CE_CONT, "drecv sync in hdr, "
8391708Sstevel 						"bufpos=%d\n", pkt->bufpos));
8401708Sstevel 
8411708Sstevel 					dp_release_buffer(rcs, DP_RX_BUFFER);
8421708Sstevel 					pkt->buf = NULL;
8431708Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
8441708Sstevel 				} else {
8451708Sstevel 					pkt->rx_state = RECEIVING_HDR_ESC;
8461708Sstevel 				}
8471708Sstevel 				pkt->inbuf++;
8481708Sstevel 				pkt->inbuflen--;
8491708Sstevel 			}
8501708Sstevel 			break;
8511708Sstevel 
8521708Sstevel 		case RECEIVING_HDR_ESC:
8531708Sstevel 			pkt->buf[pkt->bufpos++] = *pkt->inbuf;
8541708Sstevel 			pkt->inbuf++;
8551708Sstevel 			pkt->inbuflen--;
8561708Sstevel 			if (pkt->bufpos >= sizeof (dp_header_t)) {
8571708Sstevel 				dp_got_full_hdr(rcs, pkt);
8581708Sstevel 			} else if ((pkt->bufpos >= sizeof (bp_msg_t)) &&
8591708Sstevel 			    (IS_BOOT_MSG(pkt->buf[1]))) {
8601708Sstevel 				dp_got_bp_msg(rcs, pkt);
8611708Sstevel 			} else {
8621708Sstevel 				pkt->rx_state = RECEIVING_HDR;
8631708Sstevel 			}
8641708Sstevel 			break;
8651708Sstevel 
8661708Sstevel 		case RECEIVING_BODY:
8671708Sstevel 			max = pkt->full_length - pkt->bufpos;
8681708Sstevel 			if (max > pkt->inbuflen)
8691708Sstevel 				max = pkt->inbuflen;
8701708Sstevel 
8711708Sstevel 			for (count = 0; count < max; count++)
8721708Sstevel 				if ((pkt->inbuf[count] == SYNC_CHAR) ||
8731708Sstevel 				    (pkt->inbuf[count] == ESC_CHAR))
8741708Sstevel 					break;
8751708Sstevel 
8761708Sstevel 			if (count > 0) {
8771708Sstevel 				bcopy(pkt->inbuf, pkt->buf + pkt->bufpos,
8781708Sstevel 				    count);
8791708Sstevel 				pkt->inbuf += count;
8801708Sstevel 				pkt->inbuflen -= count;
8811708Sstevel 				pkt->bufpos += count;
8821708Sstevel 
8831708Sstevel 				if (pkt->bufpos >= pkt->full_length) {
8841708Sstevel 					dp_got_full_msg(rcs, pkt);
8851708Sstevel 					break;
8861708Sstevel 				}
8871708Sstevel 			}
8881708Sstevel 
8891708Sstevel 			if (count < max) {
8901708Sstevel 				/* Must have gotten an ESC_CHAR or SYNC_CHAR. */
8911708Sstevel 				if (*pkt->inbuf == SYNC_CHAR) {
8921708Sstevel 					dp_release_buffer(rcs, DP_RX_BUFFER);
8931708Sstevel 					pkt->buf = NULL;
8941708Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
8951708Sstevel 				} else {
8961708Sstevel 					pkt->rx_state = RECEIVING_BODY_ESC;
8971708Sstevel 				}
8981708Sstevel 				pkt->inbuf++;
8991708Sstevel 				pkt->inbuflen--;
9001708Sstevel 			}
9011708Sstevel 			break;
9021708Sstevel 
9031708Sstevel 		case RECEIVING_BODY_ESC:
9041708Sstevel 			pkt->buf[pkt->bufpos] = *pkt->inbuf;
9051708Sstevel 			pkt->inbuf++;
9061708Sstevel 			pkt->inbuflen--;
9071708Sstevel 			pkt->bufpos++;
9081708Sstevel 			if (pkt->bufpos >= pkt->full_length) {
9091708Sstevel 				dp_got_full_msg(rcs, pkt);
9101708Sstevel 			} else {
9111708Sstevel 				pkt->rx_state = RECEIVING_BODY;
9121708Sstevel 			}
9131708Sstevel 			break;
9141708Sstevel 		}
9151708Sstevel 	}
9161708Sstevel }
9171708Sstevel 
9181708Sstevel /*
9191708Sstevel  * Handle an incoming message. CRCs have been already checked so message
9201708Sstevel  * is good. check if sequence numbers are ok.
9211708Sstevel  * Handles: control message, asynchronous notification, reply to requests
9221708Sstevel  * and notify the leaf driver of those events.
9231708Sstevel  * (it must have the dp_mutex)
9241708Sstevel  */
9251708Sstevel void
rmc_comm_dp_mrecv(struct rmc_comm_state * rcs,uint8_t * buf)9261708Sstevel rmc_comm_dp_mrecv(struct rmc_comm_state *rcs, uint8_t *buf)
9271708Sstevel {
9281708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
9291708Sstevel 	dp_header_t *dp_msgp;
9301708Sstevel 	uint8_t *datap;
9311708Sstevel 	int datalen;
9321708Sstevel 	dp_msg_intr_t *dmi = &dps->msg_intr;
9331708Sstevel 	dp_req_resp_t *drr = &dps->req_resp;
9341708Sstevel 
9351708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
9361708Sstevel 
9371708Sstevel 	dp_msgp = (dp_header_t *)buf;
9381708Sstevel 
9391708Sstevel 	datalen = dp_msgp->length -
9401708Sstevel 	    (sizeof (dp_header_t) - sizeof (dp_msgp->pad));
9411708Sstevel 
9421708Sstevel 	if (datalen > 0) {
9431708Sstevel 		datalen = datalen - sizeof (uint16_t); /* don't count msg CRC */
9441708Sstevel 		datap = buf + sizeof (dp_header_t);
9451708Sstevel 	} else {
9461708Sstevel 		datap = NULL;
9471708Sstevel 	}
9481708Sstevel 
9491708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT,
9501708Sstevel 	    "[t%03dr%03d] mrecv msgtype: %02x, len=%d\n",
9511708Sstevel 	    dp_msgp->txnum, dp_msgp->rxnum, dp_msgp->type, datalen));
9521708Sstevel 
9531708Sstevel 	/*
9541708Sstevel 	 * Handle control messages first
9551708Sstevel 	 */
9561708Sstevel 	if (IS_UNNUMBERED_MSG(dp_msgp->type)) {
9571708Sstevel 		switch (dp_msgp->type) {
9581708Sstevel 		case DP_CTL_START:
9591708Sstevel 			/*
9601708Sstevel 			 * CTL:start
9611708Sstevel 			 * Re-init protocol processing.
9621708Sstevel 			 * Enable data link
9631708Sstevel 			 * Stop data link setup timer if running
9641708Sstevel 			 */
9651708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT, "mrecv data link ok\n"));
9661708Sstevel 
9671708Sstevel 			dp_reset(rcs, dp_msgp->txnum, 1, 0);
9681708Sstevel 
9691708Sstevel 			dp_wake_up_waiter(rcs, 0);
9701708Sstevel 
9711708Sstevel 			/* Send CTL:stack message. */
9721708Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_STACK);
9731708Sstevel 
9741708Sstevel 			dps->start_cnt++;
9751708Sstevel 
9761708Sstevel 			dp_enable_data_link(rcs);
9771708Sstevel 
9781708Sstevel 			break;
9791708Sstevel 
9801708Sstevel 		case DP_CTL_STACK:
9811708Sstevel 			/*
9821708Sstevel 			 * CTL:stack
9831708Sstevel 			 * Enable data link
9841708Sstevel 			 * Stop data link setup timer if running
9851708Sstevel 			 */
9861708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT, "mrecv data link ok\n"));
9871708Sstevel 
9881708Sstevel 			dp_reset(rcs, dp_msgp->txnum, 0, 0);
9891708Sstevel 
9901708Sstevel 			dp_wake_up_waiter(rcs, 0);
9911708Sstevel 
9921708Sstevel 			dps->stack_cnt++;
9931708Sstevel 
9941708Sstevel 			dp_enable_data_link(rcs);
9951708Sstevel 			break;
9961708Sstevel 
9971708Sstevel 		case DP_CTL_RESPOND:
9981708Sstevel 			/*
9991708Sstevel 			 * CTL:respond (heartbeat)
10001708Sstevel 			 * Send a CTL:ack.
10011708Sstevel 			 */
10021708Sstevel 			if (dps->data_link_ok) {
10031708Sstevel 				(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_ACK);
10041708Sstevel 			}
10051708Sstevel 			break;
10061708Sstevel 
10071708Sstevel 		case DP_CTL_ACK:
10081708Sstevel 			/*
10091708Sstevel 			 * CTL:ack
10101708Sstevel 			 * Call a transmit-side routine to handle it.
10111708Sstevel 			 */
10121708Sstevel 			dp_tx_handle_ack(rcs, dp_msgp->rxnum);
10131708Sstevel 			break;
10141708Sstevel 
10151708Sstevel 		case DP_CTL_NAK:
10161708Sstevel 			/*
10171708Sstevel 			 * CTL:nak
10181708Sstevel 			 * Call a transmit-side routine to handle it.
10191708Sstevel 			 */
10201708Sstevel 			dp_tx_handle_nak(rcs, dp_msgp->rxnum);
10211708Sstevel 			break;
10221708Sstevel 
10231708Sstevel 		default:
10241708Sstevel 			/* Drop message. */
10251708Sstevel 			DPRINTF(rcs, DPRO,
10261708Sstevel 			    (CE_CONT, "mrecv unknown ctrlmsg\n"));
10271708Sstevel 			break;
10281708Sstevel 		}
10291708Sstevel 		return;
10301708Sstevel 	}
10311708Sstevel 
10321708Sstevel 	/*
10331708Sstevel 	 * Before processing the received message (NUMBERED), check that the
10341708Sstevel 	 * data link protocol is up. If not, ignore this message
10351708Sstevel 	 */
10361708Sstevel 	if (!dps->data_link_ok) {
10371708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "mrecv drop msg: no data link\n"));
10381708Sstevel 		return;
10391708Sstevel 	}
10401708Sstevel 
10411708Sstevel 	/*
10421708Sstevel 	 * we received a message (NUMBERED) and data link is ok.
10431708Sstevel 	 * First, instead of ACKing this message now, we delay it. The reason
10441708Sstevel 	 * why is that a message can be sent (from this side) in the meantime
10451708Sstevel 	 * and it can ACK the received message (it will spare us to send
10461708Sstevel 	 * the ACK message across the wire).
10471708Sstevel 	 */
10481708Sstevel 
10491708Sstevel 	/*
10501708Sstevel 	 * Handle acknowledgements even if this is a duplicate message.
10511708Sstevel 	 */
10521708Sstevel 	if (dps->timer_delay_ack == (timeout_id_t)0) {
10531708Sstevel 		dps->timer_delay_ack = timeout(dp_delay_ack_tohandler,
10541708Sstevel 		    (void *) rcs, drv_usectohz(TX_RETRY_TIME/2 * 1000));
10551708Sstevel 		DPRINTF(rcs, DGEN, (CE_CONT, "mrecv start ack t/o %p\n",
10561708Sstevel 		    dps->timer_delay_ack));
10571708Sstevel 	}
10581708Sstevel 	dp_tx_handle_ack(rcs, dp_msgp->rxnum);
10591708Sstevel 
10601708Sstevel 	if (dp_msgp->txnum != NEXT_SEQID(dps->last_rx_seqid)) {
10611708Sstevel 		/* Duplicate message - free it up & return. */
10621708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "mrecv dup msg txnum=%03d\n",
10631708Sstevel 		    dp_msgp->txnum));
10641708Sstevel 		return;
10651708Sstevel 	}
10661708Sstevel 	dps->last_rx_seqid = dp_msgp->txnum;
10671708Sstevel 
10681708Sstevel #ifdef DEBUG_ERROR_INJECTION
10691708Sstevel 
10701708Sstevel 	if ((erri_test_number == ERRI_SEND_CTL_STACK ||
10711708Sstevel 	    erri_test_number == ERRI_SEND_CTL_START) &&
10721708Sstevel 	    erri_test_repeat >= 0 &&
10731708Sstevel 	    erri_test_count++ > 0 && !(erri_test_count % erri_test_intrvl)) {
10741708Sstevel 
10751708Sstevel 		if (erri_test_number == ERRI_SEND_CTL_STACK) {
10761708Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_STACK);
10771708Sstevel 
10781708Sstevel 		} else if (erri_test_number == ERRI_SEND_CTL_START) {
10791708Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
10801708Sstevel 
10811708Sstevel 		}
10821708Sstevel 		if (erri_test_repeat == 0)
10831708Sstevel 			erri_test_repeat--; /* will not repeat the test */
10841708Sstevel 	}
10851708Sstevel 
10861708Sstevel #endif
10871708Sstevel 
10881708Sstevel 	/*
10891708Sstevel 	 * At this point, we know this is a good message.  We've
10901708Sstevel 	 * checked checksums, message types, and sequence id's.
10911708Sstevel 	 */
10921708Sstevel 
10931708Sstevel 	/*
10941708Sstevel 	 * First, check if a driver has register for this message
10951708Sstevel 	 * Second, check if this message is a reply to a request
10961708Sstevel 	 * Third, check to see if ALOM is telling us it doesn't
10971708Sstevel 	 * know about the command code.
10981708Sstevel 	 */
10991708Sstevel 
11001708Sstevel 	if (dmi->intr_handler != NULL &&
11011708Sstevel 	    dmi->intr_msg_type == dp_msgp->type) {
11021708Sstevel 
11031708Sstevel 		rmc_comm_msg_t 	*msgi = (rmc_comm_msg_t *)dmi->intr_arg;
11041708Sstevel 
11051708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT,
11061708Sstevel 		    "mrecv process async msg len=%d, max=%d\n",
11071708Sstevel 		    datalen, msgi->msg_len));
11081708Sstevel 		/*
11091708Sstevel 		 * process asynchronous notification only if the registered
11101708Sstevel 		 * driver is not currently processing any other notification
11111708Sstevel 		 */
11121708Sstevel 		mutex_enter(dmi->intr_lock);
11131708Sstevel 		if (dmi->intr_state == NULL ||
11141708Sstevel 		    (dmi->intr_state != NULL &&
11151708Sstevel 		    *(dmi->intr_state) == RMC_COMM_INTR_IDLE)) {
11161708Sstevel 			/*
11171708Sstevel 			 * check that the buffer is big enough. do not want to
11181708Sstevel 			 * cross boundaries here..
11191708Sstevel 			 */
11201708Sstevel 			if (datalen <= msgi->msg_len) {
11211708Sstevel 				bcopy(datap, msgi->msg_buf, datalen);
11221708Sstevel 				msgi->msg_bytes = datalen;
11231708Sstevel 
11241708Sstevel 			} else {
11251708Sstevel 				msgi->msg_bytes = -1;
11261708Sstevel 			}
11271708Sstevel 			/*
11281708Sstevel 			 * trigger soft intr. in any case.
11291708Sstevel 			 * if message is too big, at least, the leaf driver
11301708Sstevel 			 * will be notified (bytes returned will be -1)
11311708Sstevel 			 */
11321708Sstevel 			ddi_trigger_softintr(dmi->intr_id);
11331708Sstevel 		}
11341708Sstevel 		mutex_exit(dmi->intr_lock);
11351708Sstevel 
11361708Sstevel 	} else if ((drr->flags & MSG_SENT) != 0 &&
11371708Sstevel 	    drr->response.msg_type == dp_msgp->type) {
11381708Sstevel 
11391708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT,
11401708Sstevel 		    "mrecv process reply len=%d, max=%d\n",
11411708Sstevel 		    datalen, drr->response.msg_bufsiz));
11421708Sstevel 
11431708Sstevel 		/*
11441708Sstevel 		 * check that the recv buffer is big enough.
11451708Sstevel 		 */
11461708Sstevel 		if (datalen <= drr->response.msg_bufsiz) {
11471708Sstevel 			bcopy(datap, drr->response.msg_buf, datalen);
11481708Sstevel 			drr->response.msg_msglen = datalen;
11491708Sstevel 			dp_wake_up_waiter(rcs, MSG_REPLY_RXED);
11501708Sstevel 		} else {
11511708Sstevel 			drr->response.msg_msglen = -1;
11521708Sstevel 			dp_wake_up_waiter(rcs, MSG_REPLY_RXED);
11531708Sstevel 		}
11541708Sstevel 	} else if (dp_msgp->type == DP_INVCMD &&
11551708Sstevel 	    (drr->flags & MSG_SENT) != 0 &&
11561708Sstevel 	    ((dp_invcmd_t *)datap)->inv_type == drr->request.msg_type) {
11571708Sstevel 		drr->error_status = RCEINVCMD;
11581708Sstevel 		dp_wake_up_waiter(rcs, MSG_ERROR);
11591708Sstevel 	}
11601708Sstevel }
11611708Sstevel 
11621708Sstevel /*
11631708Sstevel  * to send a control message (unnumbered message)
11641708Sstevel  * (it must have the dp_mutex)
11651708Sstevel  */
11661708Sstevel int
rmc_comm_dp_ctlsend(struct rmc_comm_state * rcs,uint8_t type)11671708Sstevel rmc_comm_dp_ctlsend(struct rmc_comm_state *rcs, uint8_t type)
11681708Sstevel {
11691708Sstevel 	dp_message_t ctlmsg;
11701708Sstevel 	int err = RCNOERR;
11711708Sstevel 
11721708Sstevel 	ctlmsg.msg_type = type;
11731708Sstevel 	ctlmsg.msg_buf = NULL;
11741708Sstevel 	ctlmsg.msg_msglen = 0;
11751708Sstevel 
11761708Sstevel 	err = rmc_comm_dp_msend(rcs, &ctlmsg);
11771708Sstevel 
11781708Sstevel 	return (err);
11791708Sstevel }
11801708Sstevel 
11811708Sstevel /*
11821708Sstevel  * to send data to the remote party.
11831708Sstevel  *
11841708Sstevel  * NUMBERED messages carry payload data of variable size. A buffer is allocated
11851708Sstevel  * dynamically for the trasmission of data. NUMBERED message trasmission
11861708Sstevel  * data status is stored in the dp_state request_response data structure.
11871708Sstevel  * This because: data sent must be acknowledged, trasmission can be re-tried,
11881708Sstevel  * upper layer has to know the state/result of the trasmission. Upper layer has
11891708Sstevel  * to: initialize the data struct, send data (this function), read result,
11901708Sstevel  * clean up the data struct.
11911708Sstevel  *
11921708Sstevel  * UNUMBERED data are just only control command which do not carry any payload
11931708Sstevel  * A local buffer is used (ctlbuf) instead. UNNUMBERED message are transient
11941708Sstevel  * data which is sent once and not re-tried. It does not use the
11951708Sstevel  * request_response data structure
11961708Sstevel  *
11971708Sstevel  * (it must have the dp_mutex)
11981708Sstevel  */
11991708Sstevel int
rmc_comm_dp_msend(struct rmc_comm_state * rcs,dp_message_t * req)12001708Sstevel rmc_comm_dp_msend(struct rmc_comm_state *rcs, dp_message_t *req)
12011708Sstevel {
12021708Sstevel 	rmc_comm_dp_state_t 	*dps = &rcs->dp_state;
12031708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
12041708Sstevel 	dp_message_t		*pkt;
12051708Sstevel 	dp_header_t		*dp_msgp;
12061708Sstevel 	dp_message_t		 ctl;
12071708Sstevel 	dp_header_t		 ctlbuf;
12081708Sstevel 	uint16_t		 data_crc;
12091708Sstevel 	timeout_id_t		 timer_delay_ack = 0;
12101708Sstevel 	char			 first_time = 0;
12111708Sstevel 
12121708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
12131708Sstevel 
12141708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "msend msgtype=%02x\n", req->msg_type));
12151708Sstevel 
12161708Sstevel 	if (IS_NUMBERED_MSG(req->msg_type)) {
12171708Sstevel 		/*
12181708Sstevel 		 * if there was an error, just return the error.
12191708Sstevel 		 * Otherwise if the message was already acknowledged
12201708Sstevel 		 * (NUMBERED message) then, there is no need to (re)send it.
12211708Sstevel 		 * just wait for an expected reply (hence, do not return an
12221708Sstevel 		 * error)
12231708Sstevel 		 */
12241708Sstevel 		if ((drr->flags & MSG_ERROR) != 0) {
12251708Sstevel 
12261708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
12271708Sstevel 			    "msg send error flag=%02x\n", drr->flags));
12281708Sstevel 			return (RCEGENERIC);
12291708Sstevel 
12301708Sstevel 		} else if ((drr->flags & MSG_ACKED) != 0) {
12311708Sstevel 
12321708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
12331708Sstevel 			    "msg already ACKed flag=%02x\n", drr->flags));
12341708Sstevel 			return (RCNOERR);
12351708Sstevel 
12361708Sstevel 		} else if ((drr->flags & MSG_SENT) == 0) {
12371708Sstevel 
12381708Sstevel 			first_time = 1;
12391708Sstevel 		}
12401708Sstevel 
12411708Sstevel 		/*
12421708Sstevel 		 * everything is ok. Now check that the data protocol is up
12431708Sstevel 		 * and running: messages cannot be sent if the link is down.
12441708Sstevel 		 */
12451708Sstevel 		if (!dps->data_link_ok) {
12461708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
12471708Sstevel 			    "msend: can't send msg - no data link\n"));
12481708Sstevel 
12491708Sstevel 			/*
12501708Sstevel 			 * do not return error, since it can be retried
12511708Sstevel 			 * later (hoping that the data link will come
12521708Sstevel 			 * up, in the meantime)
12531708Sstevel 			 */
12541708Sstevel 			return (RCNOERR);
12551708Sstevel 
12561708Sstevel 		}
12571708Sstevel 	} else {
12581708Sstevel 		first_time = 1;
12591708Sstevel 	}
12601708Sstevel 
12611708Sstevel 	/*
12621708Sstevel 	 * if the message has never been sent (and, hence, it is the first
12631708Sstevel 	 * time), then prepare the protocol packet: allocate a buffer,
12641708Sstevel 	 * create the message header, copy the message body into the buffer and
12651708Sstevel 	 * calculate CRCs
12661708Sstevel 	 */
12671708Sstevel 	if (first_time) {
12681708Sstevel 
12691708Sstevel 		if (IS_NUMBERED_MSG(req->msg_type)) {
12701708Sstevel 
12711708Sstevel 			drr->retries_left = TX_RETRIES;
12721708Sstevel 
12731708Sstevel 			/*
12741708Sstevel 			 * Check length of the message.
12751708Sstevel 			 */
12761708Sstevel 			if (req->msg_msglen > DP_MAX_MSGLEN) {
12771708Sstevel 				DPRINTF(rcs, DPRO,
12781708Sstevel 				    (CE_CONT, "msend err: msg too big\n"));
1279*3482Sjfrank 				return (RCEINVARG);
12801708Sstevel 			}
12811708Sstevel 
12821708Sstevel 			pkt = &drr->request;
12831708Sstevel 
12841708Sstevel 			/*
12851708Sstevel 			 * check that the message buffer is not already
12861708Sstevel 			 * in use (race condition). If so, return error
12871708Sstevel 			 */
12881708Sstevel 			if (pkt->msg_buf != NULL) {
12891708Sstevel 				DPRINTF(rcs, DPRO, (CE_CONT,
12901708Sstevel 				    "msend err: buf already in use\n"));
12911708Sstevel 				return (RCENOMEM);
12921708Sstevel 			}
12931708Sstevel 
12941708Sstevel 			/*
12951708Sstevel 			 * allocate a buffer for the protocol packet
12961708Sstevel 			 */
12971708Sstevel 			if ((pkt->msg_buf = dp_get_buffer(rcs,
12981708Sstevel 			    DP_TX_BUFFER)) == NULL) {
12991708Sstevel 				DPRINTF(rcs, DPRO, (CE_CONT,
13001708Sstevel 				    "msend err: no mem\n"));
13011708Sstevel 				return (RCENOMEM);
13021708Sstevel 			}
13031708Sstevel 			pkt->msg_bufsiz = DP_BUFFER_SIZE;
13041708Sstevel 
13051708Sstevel 			/*
13061708Sstevel 			 * increment tx sequence number if sending a NUMBERED
13071708Sstevel 			 * message
13081708Sstevel 			 */
13091708Sstevel 			dps->last_tx_seqid = NEXT_SEQID(dps->last_tx_seqid);
13101708Sstevel 		} else {
13111708Sstevel 			/*
13121708Sstevel 			 * UNUMBERED messages (or control messages) do not
13131708Sstevel 			 * carry any data and, hence, have a 'small' fixed size
13141708Sstevel 			 * (the size of the header). In this case,
13151708Sstevel 			 * a 'local' buffer (ctlbuf) is used.
13161708Sstevel 			 */
13171708Sstevel 			pkt = &ctl;
13181708Sstevel 			pkt->msg_buf = (uint8_t *)&ctlbuf;
13191708Sstevel 			pkt->msg_bufsiz = sizeof (dp_header_t);
13201708Sstevel 		}
13211708Sstevel 
13221708Sstevel #ifdef DEBUG_ERROR_INJECTION
13231708Sstevel 
13241708Sstevel 		if (((erri_test_number == ERRI_RX_SEQ_NUMBER &&
13251708Sstevel 		    IS_NUMBERED_MSG(req->msg_type)) ||
13261708Sstevel 		    (erri_test_number == ERRI_CTL_RX_SEQ_NUMBER &&
13271708Sstevel 		    IS_UNNUMBERED_MSG(req->msg_type))) &&
13281708Sstevel 		    erri_test_repeat >= 0 &&
13291708Sstevel 		    erri_test_count++ > 0 &&
13301708Sstevel 		    !(erri_test_count % erri_test_intrvl)) {
13311708Sstevel 
13321708Sstevel 			dps->last_rx_seqid--;
13331708Sstevel 
13341708Sstevel 			if (erri_test_repeat == 0)
13351708Sstevel 				erri_test_repeat--; /* will not repeat it */
13361708Sstevel 		}
13371708Sstevel #endif
13381708Sstevel 
13391708Sstevel 		/*
13401708Sstevel 		 * create the protocol packet
13411708Sstevel 		 */
13421708Sstevel 		pkt->msg_type = req->msg_type;
13431708Sstevel 
13441708Sstevel 		/*
13451708Sstevel 		 * length of the packet (including pad bytes)
13461708Sstevel 		 */
13471708Sstevel 		pkt->msg_msglen = req->msg_msglen + sizeof (dp_header_t);
13481708Sstevel 
13491708Sstevel 		/*
13501708Sstevel 		 * message header:
13511708Sstevel 		 *  set the message type
13521708Sstevel 		 *  set the length of the message (excluding pad bytes)
13531708Sstevel 		 *  set tx/rx sequence numbers
13541708Sstevel 		 *  calculate CRC
13551708Sstevel 		 */
13561708Sstevel 		dp_msgp = (dp_header_t *)pkt->msg_buf;
13571708Sstevel 		dp_msgp->type = pkt->msg_type;
13581708Sstevel 
13591708Sstevel 		if (req->msg_msglen == 0)
13601708Sstevel 			dp_msgp->length = pkt->msg_msglen -
13611708Sstevel 			    sizeof (dp_msgp->pad);
13621708Sstevel 		else
13631708Sstevel 			dp_msgp->length = sizeof (data_crc) +
13641708Sstevel 			    pkt->msg_msglen - sizeof (dp_msgp->pad);
13651708Sstevel 
13661708Sstevel 		dp_msgp->txnum = dps->last_tx_seqid;
13671708Sstevel 		dp_msgp->rxnum = dps->last_rx_seqid;
13681708Sstevel 
13691708Sstevel 		dp_msgp->crc = dp_calc_crc16(pkt->msg_buf +
13701708Sstevel 		    sizeof (dp_msgp->pad), sizeof (dp_header_t) -
13711708Sstevel 		    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
13721708Sstevel 
13731708Sstevel #ifdef DEBUG_ERROR_INJECTION
13741708Sstevel 
13751708Sstevel 		if (((erri_test_number == ERRI_CRC_HEADER &&
13761708Sstevel 		    IS_NUMBERED_MSG(pkt->msg_type)) ||
13771708Sstevel 		    (erri_test_number == ERRI_CTL_CRC_HEADER &&
13781708Sstevel 		    IS_UNNUMBERED_MSG(pkt->msg_type))) &&
13791708Sstevel 		    erri_test_repeat >= 0 &&
13801708Sstevel 		    erri_test_count++ > 0 &&
13811708Sstevel 		    !(erri_test_count % erri_test_intrvl)) {
13821708Sstevel 
13831708Sstevel 			dp_msgp->crc = dp_msgp->crc/2;
13841708Sstevel 			if (erri_test_repeat == 0)
13851708Sstevel 				erri_test_repeat--; /* will not repeat it */
13861708Sstevel 		}
13871708Sstevel #endif
13881708Sstevel 
13891708Sstevel 		/*
13901708Sstevel 		 * copy message body (if present) into the buffer
13911708Sstevel 		 * and calculate message CRC
13921708Sstevel 		 */
13931708Sstevel 		if (req->msg_msglen > 0) {
13941708Sstevel 			bcopy(req->msg_buf, pkt->msg_buf + sizeof (dp_header_t),
13951708Sstevel 			    req->msg_msglen);
13961708Sstevel 			data_crc = dp_calc_crc16(pkt->msg_buf +
13971708Sstevel 			    sizeof (dp_header_t),
13981708Sstevel 			    req->msg_msglen);
13991708Sstevel 
14001708Sstevel #ifdef DEBUG_ERROR_INJECTION
14011708Sstevel 
14021708Sstevel 			if (erri_test_number == ERRI_CRC_MSG &&
14031708Sstevel 			    erri_test_repeat >= 0 &&
14041708Sstevel 			    erri_test_count++ > 0 &&
14051708Sstevel 			    !(erri_test_count % erri_test_intrvl)) {
14061708Sstevel 
14071708Sstevel 				data_crc = data_crc/2;
14081708Sstevel 				if (erri_test_repeat == 0)
14091708Sstevel 					erri_test_repeat--;
14101708Sstevel 			}
14111708Sstevel #endif
14121708Sstevel 			bcopy((void *) &data_crc,
14131708Sstevel 			    pkt->msg_buf + (sizeof (dp_header_t) +
14141708Sstevel 			    req->msg_msglen),
14151708Sstevel 			    sizeof (data_crc));
14161708Sstevel 		}
14171708Sstevel 	} else {
14181708Sstevel 		/*
14191708Sstevel 		 * message has already been sent (and packetized).
14201708Sstevel 		 * get the message packet from the request/response
14211708Sstevel 		 * data structure
14221708Sstevel 		 */
14231708Sstevel 		pkt = &drr->request;
14241708Sstevel 		dp_msgp = (dp_header_t *)pkt->msg_buf;
14251708Sstevel 		dps->retries_cnt++;
14261708Sstevel 	}
14271708Sstevel 
14281708Sstevel 	/*
14291708Sstevel 	 *  NUMBERED messages
14301708Sstevel 	 */
14311708Sstevel 	if (IS_NUMBERED_MSG(pkt->msg_type)) {
14321708Sstevel 
14331708Sstevel 		/*
14341708Sstevel 		 * check that we have not exceeded the maximum number of
14351708Sstevel 		 * retries
14361708Sstevel 		 */
14371708Sstevel 		if (drr->retries_left-- <= 0) {
14381708Sstevel 
14391708Sstevel 			drr->flags |= MSG_ERROR; /* set error flag */
14401708Sstevel 
14411708Sstevel 			/*
14421708Sstevel 			 * restart the data protocol link
14431708Sstevel 			 */
14441708Sstevel 			dp_reset(rcs, INITIAL_SEQID, 0, 1);
14451708Sstevel 
14461708Sstevel 			return (RCEMAXRETRIES);
14471708Sstevel 		}
14481708Sstevel 
14491708Sstevel 		if (dps->timer_delay_ack != (timeout_id_t)0) {
14501708Sstevel 			/*
14511708Sstevel 			 * Cancel any pending acknowledgements - we're
14521708Sstevel 			 * going to send a message which will include
14531708Sstevel 			 * an acknowledgement.
14541708Sstevel 			 */
14551708Sstevel 			timer_delay_ack = dps->timer_delay_ack;
14561708Sstevel 
14571708Sstevel 			/*
14581708Sstevel 			 * the timer is actually removed at the end of this
14591708Sstevel 			 * function since I need to release the dp_mutex.
14601708Sstevel 			 * Instead I clear the timer variable so that the
14611708Sstevel 			 * timeout callback will not do any processing in the
14621708Sstevel 			 * meantime.
14631708Sstevel 			 */
14641708Sstevel 			dps->timer_delay_ack = 0;
14651708Sstevel 		}
14661708Sstevel 
14671708Sstevel 		drr->flags |= MSG_SENT;
14681708Sstevel 	}
14691708Sstevel 
14701708Sstevel 	/*
14711708Sstevel 	 * set rx sequence number (as we might have received a message in the
14721708Sstevel 	 * meantime). tx sequence number to be the same (we can only send one
14731708Sstevel 	 * message per time)
14741708Sstevel 	 */
14751708Sstevel 	if (dp_msgp->rxnum != dps->last_rx_seqid) {
14761708Sstevel 
14771708Sstevel 		dp_msgp->rxnum = dps->last_rx_seqid;
14781708Sstevel 
14791708Sstevel 		/*
14801708Sstevel 		 * re-calculate CRC (header)
14811708Sstevel 		 */
14821708Sstevel 		dp_msgp->crc = dp_calc_crc16(pkt->msg_buf +
14831708Sstevel 		    sizeof (dp_msgp->pad), sizeof (dp_header_t) -
14841708Sstevel 		    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
14851708Sstevel 	}
14861708Sstevel 
14871708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "[t%03dr%03d] msend msgtype=%02x\n",
14881708Sstevel 	    dp_msgp->txnum, dp_msgp->rxnum, dp_msgp->type));
14891708Sstevel 
14901708Sstevel 	/*
14911708Sstevel 	 * send this message
14921708Sstevel 	 */
14931708Sstevel 
14941708Sstevel 	dp_send_packet(rcs, pkt->msg_buf);
14951708Sstevel 
14961708Sstevel 	/*
14971708Sstevel 	 * remove delay ack timer (if any is running)
14981708Sstevel 	 * Note that the dp_mutex must be released before calling
14991708Sstevel 	 * untimeout. Otherwise we may have a deadlock situation.
15001708Sstevel 	 */
15011708Sstevel 	if (timer_delay_ack != 0) {
15021708Sstevel 		DPRINTF(rcs, DGEN, (CE_CONT, "msend remove ack timer %p\n",
15031708Sstevel 		    timer_delay_ack));
15041708Sstevel 		mutex_exit(dps->dp_mutex);
15051708Sstevel 		(void) untimeout(timer_delay_ack);
15061708Sstevel 		mutex_enter(dps->dp_mutex);
15071708Sstevel 	}
15081708Sstevel 
15091708Sstevel 	return (RCNOERR);
15101708Sstevel }
15111708Sstevel 
15121708Sstevel /*
15131708Sstevel  * to send a boot protocol message
15141708Sstevel  * (this is to support the firmware download feature)
15151708Sstevel  */
15161708Sstevel void
rmc_comm_bp_msend(struct rmc_comm_state * rcs,bp_msg_t * bp_msg)15171708Sstevel rmc_comm_bp_msend(struct rmc_comm_state *rcs, bp_msg_t *bp_msg)
15181708Sstevel {
15191708Sstevel 	char syncbuf[2];
15201708Sstevel 
15211708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
15221708Sstevel 
15231708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "send bp msg: %02x %02x %02x\n",
15241708Sstevel 	    bp_msg->cmd, bp_msg->dat1, bp_msg->dat2));
15251708Sstevel 
15261708Sstevel 	rcs->dp_state.req_resp.flags |= MSG_SENT_BP;
15271708Sstevel 
15281708Sstevel 	/* First, send out two SYNC characters. */
15292840Scarlsonj 	syncbuf[0] = syncbuf[1] = (char)SYNC_CHAR;
15302840Scarlsonj 	rmc_comm_serdev_send(rcs, syncbuf, 2);
15311708Sstevel 
15321708Sstevel 	/* Next, send the BP message. */
15331708Sstevel 	rmc_comm_serdev_send(rcs, (char *)&bp_msg->cmd,
15341708Sstevel 	    sizeof (bp_msg_t) - sizeof (bp_msg->pad));
15351708Sstevel }
15361708Sstevel 
15371708Sstevel /*
15381708Sstevel  * to send a fw s-record
15391708Sstevel  * (this is to support the firmware download feature)
15401708Sstevel  */
15411708Sstevel void
rmc_comm_bp_srecsend(struct rmc_comm_state * rcs,char * buf,int buflen)15421708Sstevel rmc_comm_bp_srecsend(struct rmc_comm_state *rcs, char *buf, int buflen)
15431708Sstevel {
15441708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
15451708Sstevel 
15461708Sstevel 	rcs->dp_state.req_resp.flags |= MSG_SENT_BP;
15471708Sstevel 
15481708Sstevel 	rmc_comm_serdev_send(rcs, buf, buflen);
15491708Sstevel }
15501708Sstevel 
15511708Sstevel /*
15521708Sstevel  * clean up a request/response session
15531708Sstevel  * (it must have the dp_mutex)
15541708Sstevel  */
15551708Sstevel 
15561708Sstevel void
rmc_comm_dp_mcleanup(struct rmc_comm_state * rcs)15571708Sstevel rmc_comm_dp_mcleanup(struct rmc_comm_state *rcs)
15581708Sstevel {
15591708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
15601708Sstevel 	dp_req_resp_t *drr = &dps->req_resp;
15611708Sstevel 	dp_message_t *req = &drr->request;
15621708Sstevel 	dp_message_t *resp = &drr->response;
15631708Sstevel 
15641708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
15651708Sstevel 
15661708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "msg cleanup\n"));
15671708Sstevel 
15681708Sstevel 	/*
15691708Sstevel 	 * 'release' memory
15701708Sstevel 	 * memory is only 'dynamically allocated for NUMBERED messages
15711708Sstevel 	 */
15721708Sstevel 	if (req->msg_buf != NULL)
15731708Sstevel 		dp_release_buffer(rcs, DP_TX_BUFFER);
15741708Sstevel 
15751708Sstevel 	drr->flags = 0;
15761708Sstevel 	drr->error_status = 0;
15771708Sstevel 
15781708Sstevel 	req->msg_type = DP_NULL_MSG;
15791708Sstevel 	req->msg_buf = NULL;
15801708Sstevel 	req->msg_msglen = 0;
15811708Sstevel 	req->msg_bufsiz = 0;
15821708Sstevel 	resp->msg_type = DP_NULL_MSG;
15831708Sstevel 	resp->msg_buf = NULL;
15841708Sstevel 	resp->msg_msglen = 0;
15851708Sstevel 	resp->msg_bufsiz = 0;
15861708Sstevel }
1587