xref: /titanic_50/usr/src/uts/sun4u/io/rmc_comm_dp.c (revision 52f4394b704526bb3aa41e8729fd03e754732822)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*52f4394bSjfrank  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  *
2603831d35Sstevel  * implementation of the transport layer protocol (known as librsc protocol):
2703831d35Sstevel  *
2803831d35Sstevel  */
2903831d35Sstevel 
3003831d35Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
3103831d35Sstevel 
3203831d35Sstevel /*
3303831d35Sstevel  *  Header files
3403831d35Sstevel  */
3503831d35Sstevel 
3603831d35Sstevel #include <sys/conf.h>
3703831d35Sstevel #include <sys/cyclic.h>
3803831d35Sstevel #include <sys/membar.h>
3903831d35Sstevel #include <sys/modctl.h>
4003831d35Sstevel #include <sys/strlog.h>
4103831d35Sstevel #include <sys/sunddi.h>
4203831d35Sstevel #include <sys/ddi.h>
4303831d35Sstevel #include <sys/types.h>
4403831d35Sstevel #include <sys/rmc_comm_dp.h>
4503831d35Sstevel #include <sys/rmc_comm_dp_boot.h>
4603831d35Sstevel #include <sys/rmc_comm_drvintf.h>
4703831d35Sstevel #include <sys/rmc_comm.h>
4803831d35Sstevel 
4903831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
5003831d35Sstevel 
5103831d35Sstevel #define	ERRI_RX_SEQ_NUMBER	1
5203831d35Sstevel #define	ERRI_ACK_MSG		2
5303831d35Sstevel #define	ERRI_CRC_HEADER		3
5403831d35Sstevel #define	ERRI_CRC_MSG		4
5503831d35Sstevel #define	ERRI_SEND_CTL_STACK	5
5603831d35Sstevel #define	ERRI_SEND_CTL_START	6
5703831d35Sstevel 
5803831d35Sstevel #define	ERRI_CTL_RX_SEQ_NUMBER	7
5903831d35Sstevel #define	ERRI_CTL_CRC_HEADER	8
6003831d35Sstevel 
6103831d35Sstevel int	erri_test_number = 0;
6203831d35Sstevel int	erri_test_intrvl = 0;
6303831d35Sstevel int	erri_test_repeat = 0;
6403831d35Sstevel int	erri_test_count = 0;
6503831d35Sstevel 
6603831d35Sstevel int erri_test_simulate_srec_sec(struct rmc_comm_state *, char *, int);
6703831d35Sstevel 
6803831d35Sstevel #endif
6903831d35Sstevel 
7003831d35Sstevel 
7103831d35Sstevel /* static functions */
7203831d35Sstevel 
7303831d35Sstevel static void dp_link_setup_tohandler(void *);
7403831d35Sstevel static void dp_delay_ack_tohandler(void *);
7503831d35Sstevel static uint8_t *dp_get_buffer(struct rmc_comm_state *, uint8_t);
7603831d35Sstevel static void dp_release_buffer(struct rmc_comm_state *, uint8_t);
7703831d35Sstevel static void dp_init_buffers(struct rmc_comm_state *);
7803831d35Sstevel static void dp_got_full_hdr(struct rmc_comm_state *, dp_packet_t *);
7903831d35Sstevel static void dp_got_bp_msg(struct rmc_comm_state *, dp_packet_t *);
8003831d35Sstevel static void dp_got_full_msg(struct rmc_comm_state *, dp_packet_t *);
8103831d35Sstevel static void dp_tx_handle_ack(struct rmc_comm_state *, uint16_t);
8203831d35Sstevel static void dp_tx_handle_nak(struct rmc_comm_state *, uint16_t);
8303831d35Sstevel static void dp_send_packet(struct rmc_comm_state *, uchar_t *);
8403831d35Sstevel static void dp_enable_data_link(struct rmc_comm_state *);
8503831d35Sstevel static int dp_get_msglen(struct rmc_comm_state *, uint8_t *);
8603831d35Sstevel static uint16_t dp_calc_crc16(uint8_t *, int);
8703831d35Sstevel void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t);
8803831d35Sstevel void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t);
8903831d35Sstevel 
9003831d35Sstevel /*
9103831d35Sstevel  * utilities...
9203831d35Sstevel  */
9303831d35Sstevel 
9403831d35Sstevel /*
9503831d35Sstevel  *  init rx/tx buffer pool
9603831d35Sstevel  */
9703831d35Sstevel static void
dp_init_buffers(struct rmc_comm_state * rcs)9803831d35Sstevel dp_init_buffers(struct rmc_comm_state *rcs)
9903831d35Sstevel {
10003831d35Sstevel 	int i;
10103831d35Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
10203831d35Sstevel 
10303831d35Sstevel 	for (i = 0; i < DP_BUFFER_COUNT; i++)
10403831d35Sstevel 		dbuf[i].in_use = 0;
10503831d35Sstevel }
10603831d35Sstevel 
10703831d35Sstevel /*
10803831d35Sstevel  *  get tx/rx buffer
10903831d35Sstevel  */
11003831d35Sstevel static uint8_t *
dp_get_buffer(struct rmc_comm_state * rcs,uint8_t type)11103831d35Sstevel dp_get_buffer(struct rmc_comm_state *rcs, uint8_t type)
11203831d35Sstevel {
11303831d35Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
11403831d35Sstevel 
11503831d35Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
11603831d35Sstevel 
11703831d35Sstevel 	if ((type != DP_TX_BUFFER && type != DP_RX_BUFFER) ||
11803831d35Sstevel 		dbuf[type].in_use) {
11903831d35Sstevel 
12003831d35Sstevel 		DPRINTF(rcs, DMEM,
12103831d35Sstevel 			(CE_CONT, "get buffer err. type=%d, in_use=%d\n",
12203831d35Sstevel 			type, dbuf[type].in_use));
12303831d35Sstevel 
12403831d35Sstevel 		return (NULL);
12503831d35Sstevel 	}
12603831d35Sstevel 
12703831d35Sstevel 	DPRINTF(rcs, DMEM, (CE_CONT, "get buffer type=%d\n", type));
12803831d35Sstevel 
12903831d35Sstevel 	dbuf[type].in_use = 1;
13003831d35Sstevel 
13103831d35Sstevel 	return (dbuf[type].buf);
13203831d35Sstevel }
13303831d35Sstevel 
13403831d35Sstevel /*
13503831d35Sstevel  * release tx/rx buffer
13603831d35Sstevel  */
13703831d35Sstevel static void
dp_release_buffer(struct rmc_comm_state * rcs,uint8_t type)13803831d35Sstevel dp_release_buffer(struct rmc_comm_state *rcs, uint8_t type)
13903831d35Sstevel {
14003831d35Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
14103831d35Sstevel 
14203831d35Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
14303831d35Sstevel 
14403831d35Sstevel 	if (type != DP_TX_BUFFER && type != DP_RX_BUFFER) {
14503831d35Sstevel 		DPRINTF(rcs, DMEM,
14603831d35Sstevel 			(CE_CONT, "free buffer err. type=%d, in_use=%d\n",
14703831d35Sstevel 			type, dbuf[type].in_use));
14803831d35Sstevel 		return;
14903831d35Sstevel 	}
15003831d35Sstevel 	DPRINTF(rcs, DMEM, (CE_CONT, "free buffer type=%d\n", type));
15103831d35Sstevel 
15203831d35Sstevel 	dbuf[type].in_use = 0;
15303831d35Sstevel }
15403831d35Sstevel 
15503831d35Sstevel /*
15603831d35Sstevel  * setup data link timeout handler
15703831d35Sstevel  * (called without having the dp_mutex)
15803831d35Sstevel  */
15903831d35Sstevel static void
dp_link_setup_tohandler(void * arg)16003831d35Sstevel dp_link_setup_tohandler(void *arg)
16103831d35Sstevel {
16203831d35Sstevel 	struct rmc_comm_state *rcs = (struct rmc_comm_state *)arg;
16303831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
16403831d35Sstevel 
16503831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "t/o setup data link\n"));
16603831d35Sstevel 
16703831d35Sstevel 	/*
16803831d35Sstevel 	 * check if timer has actually been cancelled
16903831d35Sstevel 	 */
17003831d35Sstevel 	mutex_enter(dps->dp_mutex);
17103831d35Sstevel 	if (dps->timer_link_setup != (timeout_id_t)0) {
17203831d35Sstevel 
17303831d35Sstevel 		/*
17403831d35Sstevel 		 * send CTL:start to the remote side to set up the data link
17503831d35Sstevel 		 */
17603831d35Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
17703831d35Sstevel 
17803831d35Sstevel 		dps->timer_link_setup = timeout(dp_link_setup_tohandler,
17903831d35Sstevel 		    (void *) rcs, drv_usectohz(RETRY_DP_SETUP * 1000));
18003831d35Sstevel 	}
18103831d35Sstevel 	mutex_exit(dps->dp_mutex);
18203831d35Sstevel }
18303831d35Sstevel 
18403831d35Sstevel /*
18503831d35Sstevel  * delay acknowledgment of a received message timeout handler
18603831d35Sstevel  * (called without having the dp_mutex)
18703831d35Sstevel  */
18803831d35Sstevel static void
dp_delay_ack_tohandler(void * arg)18903831d35Sstevel dp_delay_ack_tohandler(void *arg)
19003831d35Sstevel {
19103831d35Sstevel 	struct rmc_comm_state *rcs = (struct rmc_comm_state *)arg;
19203831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
19303831d35Sstevel 
19403831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
19503831d35Sstevel 
19603831d35Sstevel 	if (erri_test_number == ERRI_ACK_MSG &&
19703831d35Sstevel 	    erri_test_repeat >= 0 &&
19803831d35Sstevel 	    erri_test_count++ > 0 && !(erri_test_count % erri_test_intrvl)) {
19903831d35Sstevel 
20003831d35Sstevel 		/*
20103831d35Sstevel 		 * DON'T ACK THE MESSAGE - BE SILENT!
20203831d35Sstevel 		 */
20303831d35Sstevel 
20403831d35Sstevel 		if (erri_test_repeat == 0)
20503831d35Sstevel 			erri_test_repeat--; /* will not repeat the test */
20603831d35Sstevel 
20703831d35Sstevel 		dps->timer_delay_ack = (timeout_id_t)0;
20803831d35Sstevel 		return;
20903831d35Sstevel 	}
21003831d35Sstevel 
21103831d35Sstevel #endif
21203831d35Sstevel 
21303831d35Sstevel 	/*
21403831d35Sstevel 	 * check if timer has actually been cancelled
21503831d35Sstevel 	 */
21603831d35Sstevel 	mutex_enter(dps->dp_mutex);
21703831d35Sstevel 	if (dps->timer_delay_ack != (timeout_id_t)0) {
21803831d35Sstevel 		/*
21903831d35Sstevel 		 * ACK the message
22003831d35Sstevel 		 */
22103831d35Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_ACK);
22203831d35Sstevel 		dps->timer_delay_ack = (timeout_id_t)0;
22303831d35Sstevel 	}
22403831d35Sstevel 	mutex_exit(dps->dp_mutex);
22503831d35Sstevel }
22603831d35Sstevel 
22703831d35Sstevel /*
22803831d35Sstevel  * Enable data link protocol:
22903831d35Sstevel  *  stop data link setup timer
23003831d35Sstevel  *  set data_link_ok flag
23103831d35Sstevel  * (must already have the dp_mutex)
23203831d35Sstevel  */
23303831d35Sstevel static void
dp_enable_data_link(struct rmc_comm_state * rcs)23403831d35Sstevel dp_enable_data_link(struct rmc_comm_state *rcs)
23503831d35Sstevel {
23603831d35Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
23703831d35Sstevel 	timeout_id_t		 timer_id;
23803831d35Sstevel 
23903831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
24003831d35Sstevel 
24103831d35Sstevel 	dps->data_link_ok = 1;
24203831d35Sstevel 
24303831d35Sstevel 	timer_id = dps->timer_link_setup;
24403831d35Sstevel 	dps->timer_link_setup = (timeout_id_t)0;
24503831d35Sstevel 	if (timer_id != (timeout_id_t)0) {
24603831d35Sstevel 
24703831d35Sstevel 		mutex_exit(dps->dp_mutex);
24803831d35Sstevel 		(void) untimeout(timer_id);
24903831d35Sstevel 		mutex_enter(dps->dp_mutex);
25003831d35Sstevel 	}
25103831d35Sstevel }
25203831d35Sstevel 
25303831d35Sstevel /*
25403831d35Sstevel  * CRC calculation routine.
25503831d35Sstevel  */
25603831d35Sstevel static uint16_t
dp_calc_crc16(uint8_t * buf,int len)25703831d35Sstevel dp_calc_crc16(uint8_t *buf, int len)
25803831d35Sstevel {
25903831d35Sstevel 	extern uint16_t crctab16[];
26003831d35Sstevel 	uint16_t crc;
26103831d35Sstevel 
26203831d35Sstevel 	crc = 0;
26303831d35Sstevel 	while (len--) {
26403831d35Sstevel 		crc = (crc >> 8) ^ crctab16[(crc ^ *buf++) & 0xFF];
26503831d35Sstevel 	}
26603831d35Sstevel 	return (crc);
26703831d35Sstevel }
26803831d35Sstevel 
26903831d35Sstevel /*
27003831d35Sstevel  * Reset the data protocol
27103831d35Sstevel  * (dp_mutex must be held)
27203831d35Sstevel  */
27303831d35Sstevel void
dp_reset(struct rmc_comm_state * rcs,uint8_t rx_seqid,boolean_t flush_tx,boolean_t restart_data_link)27403831d35Sstevel dp_reset(struct rmc_comm_state *rcs, uint8_t rx_seqid,
27503831d35Sstevel     boolean_t flush_tx, boolean_t restart_data_link)
27603831d35Sstevel {
27703831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
27803831d35Sstevel 
27903831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
28003831d35Sstevel 
28103831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT,
28203831d35Sstevel 	    "reset proto: rxsid=%d, flushtx=%d, restartdp=%d\n",
28303831d35Sstevel 	    rx_seqid, flush_tx, restart_data_link));
28403831d35Sstevel 
28503831d35Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT,
28603831d35Sstevel 	    "stats: reset=%d nak=%d start=%d stack=%d retries=%d crcerr=%d\n",
28703831d35Sstevel 	    dps->reset_cnt, dps->nak_cnt, dps->start_cnt, dps->stack_cnt,
28803831d35Sstevel 	    dps->retries_cnt, dps->crcerr_cnt));
28903831d35Sstevel 
29003831d35Sstevel 	dps->last_rx_seqid = rx_seqid;
29103831d35Sstevel 	dps->reset_cnt++;
29203831d35Sstevel 
29303831d35Sstevel 	/*
29403831d35Sstevel 	 * Flush pending tx message.
29503831d35Sstevel 	 */
29603831d35Sstevel 	if (flush_tx) {
29703831d35Sstevel 		dps->last_tx_seqid = INITIAL_SEQID;
29803831d35Sstevel 		dps->last_rx_ack = rx_seqid;
29903831d35Sstevel 
30003831d35Sstevel 		/*
30103831d35Sstevel 		 * if there is any pending request/response session
30203831d35Sstevel 		 * then just abort it.
30303831d35Sstevel 		 */
30403831d35Sstevel 		dp_wake_up_waiter(rcs, MSG_ERROR);
30503831d35Sstevel 	}
30603831d35Sstevel 
30703831d35Sstevel 	/*
30803831d35Sstevel 	 * restart data link, but only if the data link set up timer is
30903831d35Sstevel 	 * not already running.
31003831d35Sstevel 	 */
31103831d35Sstevel 	if (restart_data_link && dps->timer_link_setup == (timeout_id_t)0) {
31203831d35Sstevel 
31303831d35Sstevel 		dps->data_link_ok = 0;
31403831d35Sstevel 
31503831d35Sstevel 		/*
31603831d35Sstevel 		 * set up the data protocol link
31703831d35Sstevel 		 */
31803831d35Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
31903831d35Sstevel 		dps->timer_link_setup = timeout(dp_link_setup_tohandler,
32003831d35Sstevel 		    (void *)rcs, drv_usectohz(RETRY_DP_SETUP * 1000));
32103831d35Sstevel 	}
32203831d35Sstevel }
32303831d35Sstevel 
32403831d35Sstevel /*
32503831d35Sstevel  * Handles acknowledgment of a message previously sent OR a heartbeat command
32603831d35Sstevel  * (CTL_RESPOND).
32703831d35Sstevel  */
32803831d35Sstevel static void
dp_tx_handle_ack(struct rmc_comm_state * rcs,uint16_t rxnum)32903831d35Sstevel dp_tx_handle_ack(struct rmc_comm_state *rcs, uint16_t rxnum)
33003831d35Sstevel {
33103831d35Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
33203831d35Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
33303831d35Sstevel 
33403831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
33503831d35Sstevel 
33603831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "handle ACK, rxnum=%03d\n", rxnum));
33703831d35Sstevel 
33803831d35Sstevel 	dps->last_rx_ack = rxnum;
33903831d35Sstevel 	if ((drr->flags & MSG_SENT) == 0) {
34003831d35Sstevel 		/*
34103831d35Sstevel 		 * no pending messages, so nothing to do
34203831d35Sstevel 		 */
34303831d35Sstevel 		return;
34403831d35Sstevel 	}
34503831d35Sstevel 
34603831d35Sstevel 	if (rxnum == dps->last_tx_seqid) {
34703831d35Sstevel 		/*
34803831d35Sstevel 		 * message was sent and acknowledged successfully
34903831d35Sstevel 		 * set flag and signal the waiting task if it is not
35003831d35Sstevel 		 * expecting a reply back
35103831d35Sstevel 		 */
35203831d35Sstevel 		drr->flags |= MSG_ACKED;
35303831d35Sstevel 		if (drr->response.msg_type == DP_NULL_MSG) {
35403831d35Sstevel 			dp_wake_up_waiter(rcs, MSG_ACKED);
35503831d35Sstevel 		}
35603831d35Sstevel 	}
35703831d35Sstevel }
35803831d35Sstevel 
35903831d35Sstevel /*
36003831d35Sstevel  * Handles NAK
36103831d35Sstevel  */
36203831d35Sstevel static void
dp_tx_handle_nak(struct rmc_comm_state * rcs,uint16_t rxnum)36303831d35Sstevel dp_tx_handle_nak(struct rmc_comm_state *rcs, uint16_t rxnum)
36403831d35Sstevel {
36503831d35Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
36603831d35Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
36703831d35Sstevel 
36803831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
36903831d35Sstevel 
37003831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "handle NAK, rxnum=%03d\n", rxnum));
37103831d35Sstevel 
37203831d35Sstevel 	if ((drr->flags & MSG_SENT) == 0) {
37303831d35Sstevel 		/*
37403831d35Sstevel 		 * no pending messages, so nothing to do
37503831d35Sstevel 		 */
37603831d35Sstevel 		return;
37703831d35Sstevel 	}
37803831d35Sstevel 
37903831d35Sstevel 	/*
38003831d35Sstevel 	 * since one message per time can be sent, it is assumed that the
38103831d35Sstevel 	 * message being NAKed is just the one that has been sent.
38203831d35Sstevel 	 */
38303831d35Sstevel 	dps->nak_cnt++;
38403831d35Sstevel 
38503831d35Sstevel 	dp_wake_up_waiter(rcs, MSG_NAKED);
38603831d35Sstevel }
38703831d35Sstevel 
38803831d35Sstevel /*
38903831d35Sstevel  * Got a full header. Check header CRC and get the length of the packet
39003831d35Sstevel  */
39103831d35Sstevel static void
dp_got_full_hdr(struct rmc_comm_state * rcs,dp_packet_t * pkt)39203831d35Sstevel dp_got_full_hdr(struct rmc_comm_state *rcs, dp_packet_t *pkt)
39303831d35Sstevel {
39403831d35Sstevel 	/*
39503831d35Sstevel 	 * Got the full header.  Call up to the logical layer to see
39603831d35Sstevel 	 * how big of a buffer I need for this message.  If the size
39703831d35Sstevel 	 * is < sizeof (dp_msg_t), then there is something wrong with
39803831d35Sstevel 	 * this message - drop it.  If the size is equal, then hand it
39903831d35Sstevel 	 * up right now. If the size is too big - drop it. otherwise we must
40003831d35Sstevel 	 * receive the body of the message.
40103831d35Sstevel 	 */
40203831d35Sstevel 
40303831d35Sstevel 	pkt->full_length = dp_get_msglen(rcs, pkt->buf);
40403831d35Sstevel 
40503831d35Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "got header msglen=%d\n",
40603831d35Sstevel 	    pkt->full_length));
40703831d35Sstevel 
40803831d35Sstevel 	if ((pkt->full_length < 0) ||
40903831d35Sstevel 	    (pkt->full_length < sizeof (dp_header_t)) ||
41003831d35Sstevel 	    (pkt->full_length > DP_BUFFER_SIZE)) {
41103831d35Sstevel 		/*
41203831d35Sstevel 		 * not a valid message: either message too big or too small
41303831d35Sstevel 		 */
41403831d35Sstevel 		dp_release_buffer(rcs, DP_RX_BUFFER);
41503831d35Sstevel 		pkt->buf = NULL;
41603831d35Sstevel 
41703831d35Sstevel 		pkt->rx_state = WAITING_FOR_SYNC;
41803831d35Sstevel 
41903831d35Sstevel 	} else if (pkt->full_length == sizeof (dp_header_t)) {
42003831d35Sstevel 		/*
42103831d35Sstevel 		 * process message: it is basically a control message
42203831d35Sstevel 		 * (no data being carried)
42303831d35Sstevel 		 */
42403831d35Sstevel 		rmc_comm_dp_mrecv(rcs, pkt->buf);
42503831d35Sstevel 
42603831d35Sstevel 		dp_release_buffer(rcs, DP_RX_BUFFER);
42703831d35Sstevel 		pkt->buf = NULL;
42803831d35Sstevel 
42903831d35Sstevel 		pkt->rx_state = WAITING_FOR_SYNC;
43003831d35Sstevel 	} else {
43103831d35Sstevel 		pkt->rx_state = RECEIVING_BODY;
43203831d35Sstevel 	}
43303831d35Sstevel }
43403831d35Sstevel 
43503831d35Sstevel /*
43603831d35Sstevel  * Got a BP (boot prom) message. Usually, BP messages are received when
43703831d35Sstevel  * the firmware goes into boot monitor mode (where only BP protocol is used).
43803831d35Sstevel  * This just happens during firmware download. There should not be any other
43903831d35Sstevel  * case where a BP message is received.
44003831d35Sstevel  */
44103831d35Sstevel static void
dp_got_bp_msg(struct rmc_comm_state * rcs,dp_packet_t * pkt)44203831d35Sstevel dp_got_bp_msg(struct rmc_comm_state *rcs, dp_packet_t *pkt)
44303831d35Sstevel {
44403831d35Sstevel 	bp_msg_t		*msgp = (bp_msg_t *)pkt->buf;
44503831d35Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
44603831d35Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
44703831d35Sstevel 	int			datalen = sizeof (bp_msg_t);
44803831d35Sstevel 
44903831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
45003831d35Sstevel 
45103831d35Sstevel 	/*
45203831d35Sstevel 	 * ignore BP message, if it is not expected
45303831d35Sstevel 	 */
45403831d35Sstevel 	if ((drr->flags & MSG_SENT_BP) != 0) {
45503831d35Sstevel 
45603831d35Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "got bp msg: %02x %02x %02x\n",
45703831d35Sstevel 		    msgp->cmd, msgp->dat1, msgp->dat2));
45803831d35Sstevel 
45903831d35Sstevel 		/*
46003831d35Sstevel 		 * A boot prom (BP) msg has been sent. Here is the
46103831d35Sstevel 		 * 'expected' reply
46203831d35Sstevel 		 */
46303831d35Sstevel 
46403831d35Sstevel 		/*
46503831d35Sstevel 		 * check that the recv buffer is big enough (just in case).
46603831d35Sstevel 		 */
46703831d35Sstevel 		if (datalen <= drr->response.msg_bufsiz) {
46803831d35Sstevel 			bcopy(pkt->buf, drr->response.msg_buf, datalen);
46903831d35Sstevel 			drr->response.msg_msglen = datalen;
47003831d35Sstevel 			dp_wake_up_waiter(rcs, MSG_RXED_BP);
47103831d35Sstevel 		} else {
47203831d35Sstevel 			drr->response.msg_msglen = -1;
47303831d35Sstevel 			dp_wake_up_waiter(rcs, MSG_RXED_BP);
47403831d35Sstevel 		}
47503831d35Sstevel 	}
47603831d35Sstevel 
47703831d35Sstevel 	/* Return the buffer to the pool and wait for the next msg. */
47803831d35Sstevel 	dp_release_buffer(rcs, DP_RX_BUFFER);
47903831d35Sstevel 	pkt->buf = NULL;
48003831d35Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
48103831d35Sstevel }
48203831d35Sstevel 
48303831d35Sstevel /*
48403831d35Sstevel  * Got a complete message, check CRC and pass it on to the upper layer (message
48503831d35Sstevel  * processing)
48603831d35Sstevel  */
48703831d35Sstevel static void
dp_got_full_msg(struct rmc_comm_state * rcs,dp_packet_t * pkt)48803831d35Sstevel dp_got_full_msg(struct rmc_comm_state *rcs, dp_packet_t *pkt)
48903831d35Sstevel {
49003831d35Sstevel 	uint16_t	 crc;
49103831d35Sstevel 	int		 msglen;
49203831d35Sstevel 
49303831d35Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "got full msg\n"));
49403831d35Sstevel 
49503831d35Sstevel 	/*
49603831d35Sstevel 	 * check message CRC
49703831d35Sstevel 	 */
49803831d35Sstevel 
49903831d35Sstevel 	msglen = pkt->full_length - sizeof (dp_header_t) - sizeof (crc);
50003831d35Sstevel 
50103831d35Sstevel 	bcopy(pkt->buf + (pkt->full_length - sizeof (crc)), &crc, sizeof (crc));
50203831d35Sstevel 
50303831d35Sstevel 	if (crc == dp_calc_crc16(pkt->buf + sizeof (dp_header_t), msglen)) {
50403831d35Sstevel 		/*
50503831d35Sstevel 		 * CRC is ok, process this message
50603831d35Sstevel 		 */
50703831d35Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "got 'good' msg\n"));
50803831d35Sstevel 
50903831d35Sstevel 		rmc_comm_dp_mrecv(rcs, pkt->buf);
51003831d35Sstevel 	} else {
51103831d35Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "CRC error (msg)\n"));
51203831d35Sstevel 		rcs->dp_state.crcerr_cnt++;
51303831d35Sstevel 	}
51403831d35Sstevel 
51503831d35Sstevel 	dp_release_buffer(rcs, DP_RX_BUFFER);
51603831d35Sstevel 	pkt->buf = NULL;
51703831d35Sstevel 
51803831d35Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
51903831d35Sstevel }
52003831d35Sstevel 
52103831d35Sstevel /*
52203831d35Sstevel  * Check the checksum of the header & return the length field.  If the
52303831d35Sstevel  * checksum check fails, then return -1.
52403831d35Sstevel  */
52503831d35Sstevel static int
dp_get_msglen(struct rmc_comm_state * rcs,uint8_t * buf)52603831d35Sstevel dp_get_msglen(struct rmc_comm_state *rcs, uint8_t *buf)
52703831d35Sstevel {
52803831d35Sstevel 	dp_header_t 	*dp_msgp;
52903831d35Sstevel 	uint16_t	 crc;
53003831d35Sstevel 
53103831d35Sstevel 	dp_msgp = (dp_header_t *)buf;
53203831d35Sstevel 
53303831d35Sstevel 	crc = dp_calc_crc16(buf + sizeof (dp_msgp->pad), sizeof (dp_header_t) -
53403831d35Sstevel 	    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
53503831d35Sstevel 
53603831d35Sstevel 	if (dp_msgp->crc == crc) {
53703831d35Sstevel 		return (dp_msgp->length + sizeof (dp_msgp->pad));
53803831d35Sstevel 	} else {
53903831d35Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "CRC error (header)\n"));
54003831d35Sstevel 		rcs->dp_state.crcerr_cnt++;
54103831d35Sstevel 		return (-1);
54203831d35Sstevel 	}
54303831d35Sstevel }
54403831d35Sstevel 
54503831d35Sstevel /*
54603831d35Sstevel  * to send a protocol packet to the remote side. it handles escaping SYNC
54703831d35Sstevel  * and ESC chars
54803831d35Sstevel  */
54903831d35Sstevel static void
dp_send_packet(struct rmc_comm_state * rcs,uchar_t * buf)55003831d35Sstevel dp_send_packet(struct rmc_comm_state *rcs, uchar_t *buf)
55103831d35Sstevel {
55203831d35Sstevel 	char syncbuf[2];
55303831d35Sstevel 	dp_header_t *dp_msgp = (dp_header_t *)buf;
55403831d35Sstevel 	int total, cur;
55503831d35Sstevel 
55603831d35Sstevel 	/* First, send out two SYNC characters. */
557055d7c80Scarlsonj 	syncbuf[0] = syncbuf[1] = (char)SYNC_CHAR;
558055d7c80Scarlsonj 	rmc_comm_serdev_send(rcs, syncbuf, 2);
55903831d35Sstevel 
56003831d35Sstevel 	total = dp_msgp->length;
56103831d35Sstevel 	buf = buf + sizeof (dp_msgp->pad);
56203831d35Sstevel 
56303831d35Sstevel 	while (total > 0) {
56403831d35Sstevel 		cur = 0;
56503831d35Sstevel 
56603831d35Sstevel 		/* Count up characters that don't need ESC'ing. */
56703831d35Sstevel 		while ((cur < total) &&
56803831d35Sstevel 		    (buf[cur] != ESC_CHAR) &&
56903831d35Sstevel 		    (buf[cur] != SYNC_CHAR)) {
57003831d35Sstevel 			cur++;
57103831d35Sstevel 		}
57203831d35Sstevel 
57303831d35Sstevel 		/* Send characters that don't need escaping, if any. */
57403831d35Sstevel 		if (cur > 0) {
57503831d35Sstevel 			rmc_comm_serdev_send(rcs, (char *)buf, cur);
57603831d35Sstevel 			total -= cur;
57703831d35Sstevel 			buf += cur;
57803831d35Sstevel 		}
57903831d35Sstevel 
58003831d35Sstevel 		/*
58103831d35Sstevel 		 * If total > 0 at this point, we need to send an
58203831d35Sstevel 		 * ESC'd character.  Send as many as there are.
58303831d35Sstevel 		 */
58403831d35Sstevel 		while ((total > 0) &&
58503831d35Sstevel 		    ((*buf == SYNC_CHAR) || (*buf == ESC_CHAR))) {
586055d7c80Scarlsonj 			syncbuf[0] = (char)ESC_CHAR;
58703831d35Sstevel 			syncbuf[1] = *buf;
588055d7c80Scarlsonj 			rmc_comm_serdev_send(rcs, syncbuf, 2);
58903831d35Sstevel 			buf++;
59003831d35Sstevel 			total--;
59103831d35Sstevel 		}
59203831d35Sstevel 	}
59303831d35Sstevel }
59403831d35Sstevel 
59503831d35Sstevel /*
59603831d35Sstevel  * to wake a thread waiting for a reply/ACK/error status for a request/response
59703831d35Sstevel  * session.
59803831d35Sstevel  */
59903831d35Sstevel void
dp_wake_up_waiter(struct rmc_comm_state * rcs,uint8_t flags)60003831d35Sstevel dp_wake_up_waiter(struct rmc_comm_state *rcs, uint8_t flags)
60103831d35Sstevel {
60203831d35Sstevel 	dp_req_resp_t *drr = &rcs->dp_state.req_resp;
60303831d35Sstevel 
60403831d35Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
60503831d35Sstevel 
60603831d35Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "wake up? %x, set %x\n",
60703831d35Sstevel 	    (drr->flags & (MSG_SENT | MSG_SENT_BP)) != 0, flags));
60803831d35Sstevel 
60903831d35Sstevel 	if ((drr->flags & (MSG_SENT | MSG_SENT_BP)) != 0) {
61003831d35Sstevel 		drr->flags |= flags;
61103831d35Sstevel 		cv_signal(drr->cv_wait_reply);
61203831d35Sstevel 	}
61303831d35Sstevel }
61403831d35Sstevel 
61503831d35Sstevel /*
61603831d35Sstevel  * initialization of the data protocol (called from the attach routine)
61703831d35Sstevel  */
61803831d35Sstevel void
rmc_comm_dp_init(struct rmc_comm_state * rcs)61903831d35Sstevel rmc_comm_dp_init(struct rmc_comm_state *rcs)
62003831d35Sstevel {
62103831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
62203831d35Sstevel 	dp_packet_t *pkt = &dps->dp_packet;
62303831d35Sstevel 
62403831d35Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_dp_init\n"));
62503831d35Sstevel 
62603831d35Sstevel 	/*
62703831d35Sstevel 	 * initialize data structure:
62803831d35Sstevel 	 */
62903831d35Sstevel 	bzero((void *) dps, sizeof (rmc_comm_dp_state_t));
63003831d35Sstevel 
63103831d35Sstevel 	/*
63203831d35Sstevel 	 * initialize packet receive handler state
63303831d35Sstevel 	 */
63403831d35Sstevel 
63503831d35Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
63603831d35Sstevel 
63703831d35Sstevel 	/*
63803831d35Sstevel 	 * cv variables initialization
63903831d35Sstevel 	 * (dp_mutex has been already created during the serial device
64003831d35Sstevel 	 * initialization)
64103831d35Sstevel 	 */
64203831d35Sstevel 	cv_init(dps->cv_ok_to_send, NULL, CV_DRIVER, NULL);
64303831d35Sstevel 	cv_init(dps->req_resp.cv_wait_reply, NULL, CV_DRIVER, NULL);
64403831d35Sstevel 
64503831d35Sstevel 	mutex_enter(dps->dp_mutex);
64603831d35Sstevel 
64703831d35Sstevel 	dp_init_buffers(rcs);
64803831d35Sstevel 
64903831d35Sstevel 	/*
65003831d35Sstevel 	 * initialize the data protocol (reset sequence numbers, etc.)
65103831d35Sstevel 	 */
65203831d35Sstevel 	dps->last_tx_seqid = INITIAL_SEQID;
65303831d35Sstevel 	dps->last_rx_seqid = dps->last_rx_ack = INITIAL_SEQID;
65403831d35Sstevel 
65503831d35Sstevel 	/*
65603831d35Sstevel 	 * start timer to 'delay' the set up of the data protocol link
65703831d35Sstevel 	 */
65803831d35Sstevel 	dps->timer_link_setup = timeout(dp_link_setup_tohandler,
65903831d35Sstevel 	    (void *)rcs, drv_usectohz(DELAY_DP_SETUP * 1000));
66003831d35Sstevel 
66103831d35Sstevel 	mutex_exit(dps->dp_mutex);
66203831d35Sstevel 
66303831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
66403831d35Sstevel 
66503831d35Sstevel 	erri_test_number = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
66603831d35Sstevel 	    DDI_PROP_DONTPASS, "test-no", 0);
66703831d35Sstevel 	erri_test_intrvl = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
66803831d35Sstevel 	    DDI_PROP_DONTPASS, "test-interval", 0);
66903831d35Sstevel 	erri_test_repeat = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
67003831d35Sstevel 	    DDI_PROP_DONTPASS, "test-repeat", 0);
67103831d35Sstevel 
67203831d35Sstevel 	erri_test_count = 0;
67303831d35Sstevel 
67403831d35Sstevel 
67503831d35Sstevel 	cmn_err(CE_CONT, "error injection test: no=%d, intrvl=%d, rep=%d\n",
67603831d35Sstevel 	    erri_test_number, erri_test_intrvl, erri_test_repeat);
67703831d35Sstevel #endif
67803831d35Sstevel 
67903831d35Sstevel }
68003831d35Sstevel 
68103831d35Sstevel /*
68203831d35Sstevel  * termination of the data protocol (called from the detach routine)
68303831d35Sstevel  */
68403831d35Sstevel void
rmc_comm_dp_fini(struct rmc_comm_state * rcs)68503831d35Sstevel rmc_comm_dp_fini(struct rmc_comm_state *rcs)
68603831d35Sstevel {
68703831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
68803831d35Sstevel 	timeout_id_t	 tid_delay_ack;
68903831d35Sstevel 	timeout_id_t	 tid_link_setup;
69003831d35Sstevel 
69103831d35Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT,
69203831d35Sstevel 	    "stats: reset=%d nak=%d start=%d stack=%d retries=%d crcerr=%d\n",
69303831d35Sstevel 	    dps->reset_cnt, dps->nak_cnt, dps->start_cnt, dps->stack_cnt,
69403831d35Sstevel 	    dps->retries_cnt, dps->crcerr_cnt));
69503831d35Sstevel 
69603831d35Sstevel 	/*
69703831d35Sstevel 	 * if any timer is running, must be terminated here!
69803831d35Sstevel 	 */
69903831d35Sstevel 	mutex_enter(dps->dp_mutex);
70003831d35Sstevel 	tid_delay_ack = dps->timer_link_setup;
70103831d35Sstevel 	tid_link_setup = dps->timer_delay_ack;
70203831d35Sstevel 	dps->timer_link_setup = (timeout_id_t)0;
70303831d35Sstevel 	dps->timer_delay_ack = (timeout_id_t)0;
70403831d35Sstevel 	mutex_exit(dps->dp_mutex);
70503831d35Sstevel 
70603831d35Sstevel 	if (tid_delay_ack)
70703831d35Sstevel 		(void) untimeout(tid_delay_ack);
70803831d35Sstevel 
70903831d35Sstevel 	if (tid_link_setup)
71003831d35Sstevel 		(void) untimeout(tid_link_setup);
71103831d35Sstevel 
71203831d35Sstevel 	/*
71303831d35Sstevel 	 * cv variables termination
71403831d35Sstevel 	 */
71503831d35Sstevel 	cv_destroy(dps->cv_ok_to_send);
71603831d35Sstevel 	cv_destroy(dps->req_resp.cv_wait_reply);
71703831d35Sstevel }
71803831d35Sstevel 
71903831d35Sstevel /*
72003831d35Sstevel  * This is the low-level receiver handler. It's job is to find a complete
72103831d35Sstevel  * message from the incoming data stream, and once it finds one to pass it
72203831d35Sstevel  * on to the upper layer (message processing).
72303831d35Sstevel  * (it must have the dp_mutex)
72403831d35Sstevel  */
72503831d35Sstevel void
rmc_comm_dp_drecv(struct rmc_comm_state * rcs,uint8_t * buf,int buflen)72603831d35Sstevel rmc_comm_dp_drecv(struct rmc_comm_state *rcs, uint8_t *buf, int buflen)
72703831d35Sstevel {
72803831d35Sstevel 	rmc_comm_dp_state_t 	*dps = &rcs->dp_state;
72903831d35Sstevel 	dp_packet_t 		*pkt = &dps->dp_packet;
73003831d35Sstevel 	uint8_t			 quit;
73103831d35Sstevel 	int			 count;
73203831d35Sstevel 	int			 max;
73303831d35Sstevel 
73403831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
73503831d35Sstevel 
73603831d35Sstevel 	pkt->inbuf = buf;
73703831d35Sstevel 	pkt->inbuflen = buflen;
73803831d35Sstevel 
73903831d35Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "drecv len=%d\n", buflen));
74003831d35Sstevel 
74103831d35Sstevel 	while (pkt->inbuflen > 0) {
74203831d35Sstevel 		switch (pkt->rx_state) {
74303831d35Sstevel 
74403831d35Sstevel 		case WAITING_FOR_SYNC:
74503831d35Sstevel 			while ((pkt->inbuflen > 0) &&
74603831d35Sstevel 			    (*pkt->inbuf != SYNC_CHAR) &&
74703831d35Sstevel 			    (*pkt->inbuf != ESC_CHAR)) {
74803831d35Sstevel 
74903831d35Sstevel 				DPRINTF(rcs, DPKT,
75003831d35Sstevel 				    (CE_CONT, "not SYNC: %02x\n",
75103831d35Sstevel 				    (uchar_t)(*pkt->inbuf)));
75203831d35Sstevel 
75303831d35Sstevel 				pkt->inbuf++;
75403831d35Sstevel 				pkt->inbuflen--;
75503831d35Sstevel 			}
75603831d35Sstevel 
75703831d35Sstevel 			if (pkt->inbuflen > 0) {
75803831d35Sstevel 				if (*pkt->inbuf == SYNC_CHAR)
75903831d35Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
76003831d35Sstevel 				else if (*pkt->inbuf == ESC_CHAR)
76103831d35Sstevel 					pkt->rx_state = WAITING_FOR_SYNC_ESC;
76203831d35Sstevel 			}
76303831d35Sstevel 			break;
76403831d35Sstevel 
76503831d35Sstevel 		case WAITING_FOR_SYNC_ESC:
76603831d35Sstevel 			pkt->inbuf++;
76703831d35Sstevel 			pkt->inbuflen--;
76803831d35Sstevel 			pkt->rx_state = WAITING_FOR_SYNC;
76903831d35Sstevel 			break;
77003831d35Sstevel 
77103831d35Sstevel 		case WAITING_FOR_HDR:
77203831d35Sstevel 			while ((pkt->inbuflen > 0) &&
77303831d35Sstevel 			    (*pkt->inbuf == SYNC_CHAR)) {
77403831d35Sstevel 				pkt->inbuf++;
77503831d35Sstevel 				pkt->inbuflen--;
77603831d35Sstevel 			}
77703831d35Sstevel 
77803831d35Sstevel 			if (pkt->inbuflen <= 0)
77903831d35Sstevel 				break;
78003831d35Sstevel 
78103831d35Sstevel 			if (*pkt->inbuf == ESC_CHAR) {
78203831d35Sstevel 				/*
78303831d35Sstevel 				 * ESC as first char of header?
78403831d35Sstevel 				 * Impossible - start over!
78503831d35Sstevel 				 */
78603831d35Sstevel 				pkt->rx_state = WAITING_FOR_SYNC;
78703831d35Sstevel 				pkt->inbuf++;
78803831d35Sstevel 				pkt->inbuflen--;
78903831d35Sstevel 				break;
79003831d35Sstevel 			}
79103831d35Sstevel 
79203831d35Sstevel 			/* Get a buffer for this message. */
79303831d35Sstevel 			pkt->buf = dp_get_buffer(rcs, DP_RX_BUFFER);
79403831d35Sstevel 			if (pkt->buf == NULL) {
79503831d35Sstevel 				/* Out of buffers - drop this msg. */
79603831d35Sstevel 				pkt->rx_state = WAITING_FOR_SYNC;
79703831d35Sstevel 				break;
79803831d35Sstevel 			}
79903831d35Sstevel 			DPRINTF(rcs, DPKT, (CE_CONT, "drecv first char %x\n",
80003831d35Sstevel 			    (uchar_t)*pkt->inbuf));
80103831d35Sstevel 
80203831d35Sstevel 			pkt->buf[1] = *pkt->inbuf;
80303831d35Sstevel 			pkt->bufpos = 2;
80403831d35Sstevel 			pkt->rx_state = RECEIVING_HDR;
80503831d35Sstevel 
80603831d35Sstevel 			pkt->inbuf++;
80703831d35Sstevel 			pkt->inbuflen--;
80803831d35Sstevel 			break;
80903831d35Sstevel 
81003831d35Sstevel 		case RECEIVING_HDR:
81103831d35Sstevel 			quit = 0;
81203831d35Sstevel 			while ((pkt->inbuflen > 0) &&
81303831d35Sstevel 			    (*pkt->inbuf != SYNC_CHAR) &&
81403831d35Sstevel 			    (*pkt->inbuf != ESC_CHAR)) {
81503831d35Sstevel 				pkt->buf[pkt->bufpos++] = *pkt->inbuf;
81603831d35Sstevel 				pkt->inbuf++;
81703831d35Sstevel 				pkt->inbuflen--;
81803831d35Sstevel 				if (pkt->bufpos >= sizeof (dp_header_t)) {
81903831d35Sstevel 					dp_got_full_hdr(rcs, pkt);
82003831d35Sstevel 					quit = 1;
82103831d35Sstevel 					break;
82203831d35Sstevel 				} else if ((pkt->bufpos >= sizeof (bp_msg_t)) &&
82303831d35Sstevel 				    (IS_BOOT_MSG(pkt->buf[1]))) {
82403831d35Sstevel 					dp_got_bp_msg(rcs, pkt);
82503831d35Sstevel 					quit = 1;
82603831d35Sstevel 					break;
82703831d35Sstevel 				}
82803831d35Sstevel 			}
82903831d35Sstevel 
83003831d35Sstevel 			if (quit)
83103831d35Sstevel 				break;
83203831d35Sstevel 
83303831d35Sstevel 			if (pkt->inbuflen > 0) {
83403831d35Sstevel 				/* Must have gotten an ESC_CHAR or SYNC_CHAR. */
83503831d35Sstevel 				if (*pkt->inbuf == SYNC_CHAR) {
83603831d35Sstevel 
83703831d35Sstevel 					DPRINTF(rcs, DPKT,
83803831d35Sstevel 						(CE_CONT, "drecv sync in hdr, "
83903831d35Sstevel 						"bufpos=%d\n", pkt->bufpos));
84003831d35Sstevel 
84103831d35Sstevel 					dp_release_buffer(rcs, DP_RX_BUFFER);
84203831d35Sstevel 					pkt->buf = NULL;
84303831d35Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
84403831d35Sstevel 				} else {
84503831d35Sstevel 					pkt->rx_state = RECEIVING_HDR_ESC;
84603831d35Sstevel 				}
84703831d35Sstevel 				pkt->inbuf++;
84803831d35Sstevel 				pkt->inbuflen--;
84903831d35Sstevel 			}
85003831d35Sstevel 			break;
85103831d35Sstevel 
85203831d35Sstevel 		case RECEIVING_HDR_ESC:
85303831d35Sstevel 			pkt->buf[pkt->bufpos++] = *pkt->inbuf;
85403831d35Sstevel 			pkt->inbuf++;
85503831d35Sstevel 			pkt->inbuflen--;
85603831d35Sstevel 			if (pkt->bufpos >= sizeof (dp_header_t)) {
85703831d35Sstevel 				dp_got_full_hdr(rcs, pkt);
85803831d35Sstevel 			} else if ((pkt->bufpos >= sizeof (bp_msg_t)) &&
85903831d35Sstevel 			    (IS_BOOT_MSG(pkt->buf[1]))) {
86003831d35Sstevel 				dp_got_bp_msg(rcs, pkt);
86103831d35Sstevel 			} else {
86203831d35Sstevel 				pkt->rx_state = RECEIVING_HDR;
86303831d35Sstevel 			}
86403831d35Sstevel 			break;
86503831d35Sstevel 
86603831d35Sstevel 		case RECEIVING_BODY:
86703831d35Sstevel 			max = pkt->full_length - pkt->bufpos;
86803831d35Sstevel 			if (max > pkt->inbuflen)
86903831d35Sstevel 				max = pkt->inbuflen;
87003831d35Sstevel 
87103831d35Sstevel 			for (count = 0; count < max; count++)
87203831d35Sstevel 				if ((pkt->inbuf[count] == SYNC_CHAR) ||
87303831d35Sstevel 				    (pkt->inbuf[count] == ESC_CHAR))
87403831d35Sstevel 					break;
87503831d35Sstevel 
87603831d35Sstevel 			if (count > 0) {
87703831d35Sstevel 				bcopy(pkt->inbuf, pkt->buf + pkt->bufpos,
87803831d35Sstevel 				    count);
87903831d35Sstevel 				pkt->inbuf += count;
88003831d35Sstevel 				pkt->inbuflen -= count;
88103831d35Sstevel 				pkt->bufpos += count;
88203831d35Sstevel 
88303831d35Sstevel 				if (pkt->bufpos >= pkt->full_length) {
88403831d35Sstevel 					dp_got_full_msg(rcs, pkt);
88503831d35Sstevel 					break;
88603831d35Sstevel 				}
88703831d35Sstevel 			}
88803831d35Sstevel 
88903831d35Sstevel 			if (count < max) {
89003831d35Sstevel 				/* Must have gotten an ESC_CHAR or SYNC_CHAR. */
89103831d35Sstevel 				if (*pkt->inbuf == SYNC_CHAR) {
89203831d35Sstevel 					dp_release_buffer(rcs, DP_RX_BUFFER);
89303831d35Sstevel 					pkt->buf = NULL;
89403831d35Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
89503831d35Sstevel 				} else {
89603831d35Sstevel 					pkt->rx_state = RECEIVING_BODY_ESC;
89703831d35Sstevel 				}
89803831d35Sstevel 				pkt->inbuf++;
89903831d35Sstevel 				pkt->inbuflen--;
90003831d35Sstevel 			}
90103831d35Sstevel 			break;
90203831d35Sstevel 
90303831d35Sstevel 		case RECEIVING_BODY_ESC:
90403831d35Sstevel 			pkt->buf[pkt->bufpos] = *pkt->inbuf;
90503831d35Sstevel 			pkt->inbuf++;
90603831d35Sstevel 			pkt->inbuflen--;
90703831d35Sstevel 			pkt->bufpos++;
90803831d35Sstevel 			if (pkt->bufpos >= pkt->full_length) {
90903831d35Sstevel 				dp_got_full_msg(rcs, pkt);
91003831d35Sstevel 			} else {
91103831d35Sstevel 				pkt->rx_state = RECEIVING_BODY;
91203831d35Sstevel 			}
91303831d35Sstevel 			break;
91403831d35Sstevel 		}
91503831d35Sstevel 	}
91603831d35Sstevel }
91703831d35Sstevel 
91803831d35Sstevel /*
91903831d35Sstevel  * Handle an incoming message. CRCs have been already checked so message
92003831d35Sstevel  * is good. check if sequence numbers are ok.
92103831d35Sstevel  * Handles: control message, asynchronous notification, reply to requests
92203831d35Sstevel  * and notify the leaf driver of those events.
92303831d35Sstevel  * (it must have the dp_mutex)
92403831d35Sstevel  */
92503831d35Sstevel void
rmc_comm_dp_mrecv(struct rmc_comm_state * rcs,uint8_t * buf)92603831d35Sstevel rmc_comm_dp_mrecv(struct rmc_comm_state *rcs, uint8_t *buf)
92703831d35Sstevel {
92803831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
92903831d35Sstevel 	dp_header_t *dp_msgp;
93003831d35Sstevel 	uint8_t *datap;
93103831d35Sstevel 	int datalen;
93203831d35Sstevel 	dp_msg_intr_t *dmi = &dps->msg_intr;
93303831d35Sstevel 	dp_req_resp_t *drr = &dps->req_resp;
93403831d35Sstevel 
93503831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
93603831d35Sstevel 
93703831d35Sstevel 	dp_msgp = (dp_header_t *)buf;
93803831d35Sstevel 
93903831d35Sstevel 	datalen = dp_msgp->length -
94003831d35Sstevel 	    (sizeof (dp_header_t) - sizeof (dp_msgp->pad));
94103831d35Sstevel 
94203831d35Sstevel 	if (datalen > 0) {
94303831d35Sstevel 		datalen = datalen - sizeof (uint16_t); /* don't count msg CRC */
94403831d35Sstevel 		datap = buf + sizeof (dp_header_t);
94503831d35Sstevel 	} else {
94603831d35Sstevel 		datap = NULL;
94703831d35Sstevel 	}
94803831d35Sstevel 
94903831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT,
95003831d35Sstevel 	    "[t%03dr%03d] mrecv msgtype: %02x, len=%d\n",
95103831d35Sstevel 	    dp_msgp->txnum, dp_msgp->rxnum, dp_msgp->type, datalen));
95203831d35Sstevel 
95303831d35Sstevel 	/*
95403831d35Sstevel 	 * Handle control messages first
95503831d35Sstevel 	 */
95603831d35Sstevel 	if (IS_UNNUMBERED_MSG(dp_msgp->type)) {
95703831d35Sstevel 		switch (dp_msgp->type) {
95803831d35Sstevel 		case DP_CTL_START:
95903831d35Sstevel 			/*
96003831d35Sstevel 			 * CTL:start
96103831d35Sstevel 			 * Re-init protocol processing.
96203831d35Sstevel 			 * Enable data link
96303831d35Sstevel 			 * Stop data link setup timer if running
96403831d35Sstevel 			 */
96503831d35Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT, "mrecv data link ok\n"));
96603831d35Sstevel 
96703831d35Sstevel 			dp_reset(rcs, dp_msgp->txnum, 1, 0);
96803831d35Sstevel 
96903831d35Sstevel 			dp_wake_up_waiter(rcs, 0);
97003831d35Sstevel 
97103831d35Sstevel 			/* Send CTL:stack message. */
97203831d35Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_STACK);
97303831d35Sstevel 
97403831d35Sstevel 			dps->start_cnt++;
97503831d35Sstevel 
97603831d35Sstevel 			dp_enable_data_link(rcs);
97703831d35Sstevel 
97803831d35Sstevel 			break;
97903831d35Sstevel 
98003831d35Sstevel 		case DP_CTL_STACK:
98103831d35Sstevel 			/*
98203831d35Sstevel 			 * CTL:stack
98303831d35Sstevel 			 * Enable data link
98403831d35Sstevel 			 * Stop data link setup timer if running
98503831d35Sstevel 			 */
98603831d35Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT, "mrecv data link ok\n"));
98703831d35Sstevel 
98803831d35Sstevel 			dp_reset(rcs, dp_msgp->txnum, 0, 0);
98903831d35Sstevel 
99003831d35Sstevel 			dp_wake_up_waiter(rcs, 0);
99103831d35Sstevel 
99203831d35Sstevel 			dps->stack_cnt++;
99303831d35Sstevel 
99403831d35Sstevel 			dp_enable_data_link(rcs);
99503831d35Sstevel 			break;
99603831d35Sstevel 
99703831d35Sstevel 		case DP_CTL_RESPOND:
99803831d35Sstevel 			/*
99903831d35Sstevel 			 * CTL:respond (heartbeat)
100003831d35Sstevel 			 * Send a CTL:ack.
100103831d35Sstevel 			 */
100203831d35Sstevel 			if (dps->data_link_ok) {
100303831d35Sstevel 				(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_ACK);
100403831d35Sstevel 			}
100503831d35Sstevel 			break;
100603831d35Sstevel 
100703831d35Sstevel 		case DP_CTL_ACK:
100803831d35Sstevel 			/*
100903831d35Sstevel 			 * CTL:ack
101003831d35Sstevel 			 * Call a transmit-side routine to handle it.
101103831d35Sstevel 			 */
101203831d35Sstevel 			dp_tx_handle_ack(rcs, dp_msgp->rxnum);
101303831d35Sstevel 			break;
101403831d35Sstevel 
101503831d35Sstevel 		case DP_CTL_NAK:
101603831d35Sstevel 			/*
101703831d35Sstevel 			 * CTL:nak
101803831d35Sstevel 			 * Call a transmit-side routine to handle it.
101903831d35Sstevel 			 */
102003831d35Sstevel 			dp_tx_handle_nak(rcs, dp_msgp->rxnum);
102103831d35Sstevel 			break;
102203831d35Sstevel 
102303831d35Sstevel 		default:
102403831d35Sstevel 			/* Drop message. */
102503831d35Sstevel 			DPRINTF(rcs, DPRO,
102603831d35Sstevel 			    (CE_CONT, "mrecv unknown ctrlmsg\n"));
102703831d35Sstevel 			break;
102803831d35Sstevel 		}
102903831d35Sstevel 		return;
103003831d35Sstevel 	}
103103831d35Sstevel 
103203831d35Sstevel 	/*
103303831d35Sstevel 	 * Before processing the received message (NUMBERED), check that the
103403831d35Sstevel 	 * data link protocol is up. If not, ignore this message
103503831d35Sstevel 	 */
103603831d35Sstevel 	if (!dps->data_link_ok) {
103703831d35Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "mrecv drop msg: no data link\n"));
103803831d35Sstevel 		return;
103903831d35Sstevel 	}
104003831d35Sstevel 
104103831d35Sstevel 	/*
104203831d35Sstevel 	 * we received a message (NUMBERED) and data link is ok.
104303831d35Sstevel 	 * First, instead of ACKing this message now, we delay it. The reason
104403831d35Sstevel 	 * why is that a message can be sent (from this side) in the meantime
104503831d35Sstevel 	 * and it can ACK the received message (it will spare us to send
104603831d35Sstevel 	 * the ACK message across the wire).
104703831d35Sstevel 	 */
104803831d35Sstevel 
104903831d35Sstevel 	/*
105003831d35Sstevel 	 * Handle acknowledgements even if this is a duplicate message.
105103831d35Sstevel 	 */
105203831d35Sstevel 	if (dps->timer_delay_ack == (timeout_id_t)0) {
105303831d35Sstevel 		dps->timer_delay_ack = timeout(dp_delay_ack_tohandler,
105403831d35Sstevel 		    (void *) rcs, drv_usectohz(TX_RETRY_TIME/2 * 1000));
105503831d35Sstevel 		DPRINTF(rcs, DGEN, (CE_CONT, "mrecv start ack t/o %p\n",
105603831d35Sstevel 		    dps->timer_delay_ack));
105703831d35Sstevel 	}
105803831d35Sstevel 	dp_tx_handle_ack(rcs, dp_msgp->rxnum);
105903831d35Sstevel 
106003831d35Sstevel 	if (dp_msgp->txnum != NEXT_SEQID(dps->last_rx_seqid)) {
106103831d35Sstevel 		/* Duplicate message - free it up & return. */
106203831d35Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "mrecv dup msg txnum=%03d\n",
106303831d35Sstevel 		    dp_msgp->txnum));
106403831d35Sstevel 		return;
106503831d35Sstevel 	}
106603831d35Sstevel 	dps->last_rx_seqid = dp_msgp->txnum;
106703831d35Sstevel 
106803831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
106903831d35Sstevel 
107003831d35Sstevel 	if ((erri_test_number == ERRI_SEND_CTL_STACK ||
107103831d35Sstevel 	    erri_test_number == ERRI_SEND_CTL_START) &&
107203831d35Sstevel 	    erri_test_repeat >= 0 &&
107303831d35Sstevel 	    erri_test_count++ > 0 && !(erri_test_count % erri_test_intrvl)) {
107403831d35Sstevel 
107503831d35Sstevel 		if (erri_test_number == ERRI_SEND_CTL_STACK) {
107603831d35Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_STACK);
107703831d35Sstevel 
107803831d35Sstevel 		} else if (erri_test_number == ERRI_SEND_CTL_START) {
107903831d35Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
108003831d35Sstevel 
108103831d35Sstevel 		}
108203831d35Sstevel 		if (erri_test_repeat == 0)
108303831d35Sstevel 			erri_test_repeat--; /* will not repeat the test */
108403831d35Sstevel 	}
108503831d35Sstevel 
108603831d35Sstevel #endif
108703831d35Sstevel 
108803831d35Sstevel 	/*
108903831d35Sstevel 	 * At this point, we know this is a good message.  We've
109003831d35Sstevel 	 * checked checksums, message types, and sequence id's.
109103831d35Sstevel 	 */
109203831d35Sstevel 
109303831d35Sstevel 	/*
109403831d35Sstevel 	 * First, check if a driver has register for this message
109503831d35Sstevel 	 * Second, check if this message is a reply to a request
109603831d35Sstevel 	 * Third, check to see if ALOM is telling us it doesn't
109703831d35Sstevel 	 * know about the command code.
109803831d35Sstevel 	 */
109903831d35Sstevel 
110003831d35Sstevel 	if (dmi->intr_handler != NULL &&
110103831d35Sstevel 	    dmi->intr_msg_type == dp_msgp->type) {
110203831d35Sstevel 
110303831d35Sstevel 		rmc_comm_msg_t 	*msgi = (rmc_comm_msg_t *)dmi->intr_arg;
110403831d35Sstevel 
110503831d35Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT,
110603831d35Sstevel 		    "mrecv process async msg len=%d, max=%d\n",
110703831d35Sstevel 		    datalen, msgi->msg_len));
110803831d35Sstevel 		/*
110903831d35Sstevel 		 * process asynchronous notification only if the registered
111003831d35Sstevel 		 * driver is not currently processing any other notification
111103831d35Sstevel 		 */
111203831d35Sstevel 		mutex_enter(dmi->intr_lock);
111303831d35Sstevel 		if (dmi->intr_state == NULL ||
111403831d35Sstevel 		    (dmi->intr_state != NULL &&
111503831d35Sstevel 		    *(dmi->intr_state) == RMC_COMM_INTR_IDLE)) {
111603831d35Sstevel 			/*
111703831d35Sstevel 			 * check that the buffer is big enough. do not want to
111803831d35Sstevel 			 * cross boundaries here..
111903831d35Sstevel 			 */
112003831d35Sstevel 			if (datalen <= msgi->msg_len) {
112103831d35Sstevel 				bcopy(datap, msgi->msg_buf, datalen);
112203831d35Sstevel 				msgi->msg_bytes = datalen;
112303831d35Sstevel 
112403831d35Sstevel 			} else {
112503831d35Sstevel 				msgi->msg_bytes = -1;
112603831d35Sstevel 			}
112703831d35Sstevel 			/*
112803831d35Sstevel 			 * trigger soft intr. in any case.
112903831d35Sstevel 			 * if message is too big, at least, the leaf driver
113003831d35Sstevel 			 * will be notified (bytes returned will be -1)
113103831d35Sstevel 			 */
113203831d35Sstevel 			ddi_trigger_softintr(dmi->intr_id);
113303831d35Sstevel 		}
113403831d35Sstevel 		mutex_exit(dmi->intr_lock);
113503831d35Sstevel 
113603831d35Sstevel 	} else if ((drr->flags & MSG_SENT) != 0 &&
113703831d35Sstevel 	    drr->response.msg_type == dp_msgp->type) {
113803831d35Sstevel 
113903831d35Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT,
114003831d35Sstevel 		    "mrecv process reply len=%d, max=%d\n",
114103831d35Sstevel 		    datalen, drr->response.msg_bufsiz));
114203831d35Sstevel 
114303831d35Sstevel 		/*
114403831d35Sstevel 		 * check that the recv buffer is big enough.
114503831d35Sstevel 		 */
114603831d35Sstevel 		if (datalen <= drr->response.msg_bufsiz) {
114703831d35Sstevel 			bcopy(datap, drr->response.msg_buf, datalen);
114803831d35Sstevel 			drr->response.msg_msglen = datalen;
114903831d35Sstevel 			dp_wake_up_waiter(rcs, MSG_REPLY_RXED);
115003831d35Sstevel 		} else {
115103831d35Sstevel 			drr->response.msg_msglen = -1;
115203831d35Sstevel 			dp_wake_up_waiter(rcs, MSG_REPLY_RXED);
115303831d35Sstevel 		}
115403831d35Sstevel 	} else if (dp_msgp->type == DP_INVCMD &&
115503831d35Sstevel 	    (drr->flags & MSG_SENT) != 0 &&
115603831d35Sstevel 	    ((dp_invcmd_t *)datap)->inv_type == drr->request.msg_type) {
115703831d35Sstevel 		drr->error_status = RCEINVCMD;
115803831d35Sstevel 		dp_wake_up_waiter(rcs, MSG_ERROR);
115903831d35Sstevel 	}
116003831d35Sstevel }
116103831d35Sstevel 
116203831d35Sstevel /*
116303831d35Sstevel  * to send a control message (unnumbered message)
116403831d35Sstevel  * (it must have the dp_mutex)
116503831d35Sstevel  */
116603831d35Sstevel int
rmc_comm_dp_ctlsend(struct rmc_comm_state * rcs,uint8_t type)116703831d35Sstevel rmc_comm_dp_ctlsend(struct rmc_comm_state *rcs, uint8_t type)
116803831d35Sstevel {
116903831d35Sstevel 	dp_message_t ctlmsg;
117003831d35Sstevel 	int err = RCNOERR;
117103831d35Sstevel 
117203831d35Sstevel 	ctlmsg.msg_type = type;
117303831d35Sstevel 	ctlmsg.msg_buf = NULL;
117403831d35Sstevel 	ctlmsg.msg_msglen = 0;
117503831d35Sstevel 
117603831d35Sstevel 	err = rmc_comm_dp_msend(rcs, &ctlmsg);
117703831d35Sstevel 
117803831d35Sstevel 	return (err);
117903831d35Sstevel }
118003831d35Sstevel 
118103831d35Sstevel /*
118203831d35Sstevel  * to send data to the remote party.
118303831d35Sstevel  *
118403831d35Sstevel  * NUMBERED messages carry payload data of variable size. A buffer is allocated
118503831d35Sstevel  * dynamically for the trasmission of data. NUMBERED message trasmission
118603831d35Sstevel  * data status is stored in the dp_state request_response data structure.
118703831d35Sstevel  * This because: data sent must be acknowledged, trasmission can be re-tried,
118803831d35Sstevel  * upper layer has to know the state/result of the trasmission. Upper layer has
118903831d35Sstevel  * to: initialize the data struct, send data (this function), read result,
119003831d35Sstevel  * clean up the data struct.
119103831d35Sstevel  *
119203831d35Sstevel  * UNUMBERED data are just only control command which do not carry any payload
119303831d35Sstevel  * A local buffer is used (ctlbuf) instead. UNNUMBERED message are transient
119403831d35Sstevel  * data which is sent once and not re-tried. It does not use the
119503831d35Sstevel  * request_response data structure
119603831d35Sstevel  *
119703831d35Sstevel  * (it must have the dp_mutex)
119803831d35Sstevel  */
119903831d35Sstevel int
rmc_comm_dp_msend(struct rmc_comm_state * rcs,dp_message_t * req)120003831d35Sstevel rmc_comm_dp_msend(struct rmc_comm_state *rcs, dp_message_t *req)
120103831d35Sstevel {
120203831d35Sstevel 	rmc_comm_dp_state_t 	*dps = &rcs->dp_state;
120303831d35Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
120403831d35Sstevel 	dp_message_t		*pkt;
120503831d35Sstevel 	dp_header_t		*dp_msgp;
120603831d35Sstevel 	dp_message_t		 ctl;
120703831d35Sstevel 	dp_header_t		 ctlbuf;
120803831d35Sstevel 	uint16_t		 data_crc;
120903831d35Sstevel 	timeout_id_t		 timer_delay_ack = 0;
121003831d35Sstevel 	char			 first_time = 0;
121103831d35Sstevel 
121203831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
121303831d35Sstevel 
121403831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "msend msgtype=%02x\n", req->msg_type));
121503831d35Sstevel 
121603831d35Sstevel 	if (IS_NUMBERED_MSG(req->msg_type)) {
121703831d35Sstevel 		/*
121803831d35Sstevel 		 * if there was an error, just return the error.
121903831d35Sstevel 		 * Otherwise if the message was already acknowledged
122003831d35Sstevel 		 * (NUMBERED message) then, there is no need to (re)send it.
122103831d35Sstevel 		 * just wait for an expected reply (hence, do not return an
122203831d35Sstevel 		 * error)
122303831d35Sstevel 		 */
122403831d35Sstevel 		if ((drr->flags & MSG_ERROR) != 0) {
122503831d35Sstevel 
122603831d35Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
122703831d35Sstevel 			    "msg send error flag=%02x\n", drr->flags));
122803831d35Sstevel 			return (RCEGENERIC);
122903831d35Sstevel 
123003831d35Sstevel 		} else if ((drr->flags & MSG_ACKED) != 0) {
123103831d35Sstevel 
123203831d35Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
123303831d35Sstevel 			    "msg already ACKed flag=%02x\n", drr->flags));
123403831d35Sstevel 			return (RCNOERR);
123503831d35Sstevel 
123603831d35Sstevel 		} else if ((drr->flags & MSG_SENT) == 0) {
123703831d35Sstevel 
123803831d35Sstevel 			first_time = 1;
123903831d35Sstevel 		}
124003831d35Sstevel 
124103831d35Sstevel 		/*
124203831d35Sstevel 		 * everything is ok. Now check that the data protocol is up
124303831d35Sstevel 		 * and running: messages cannot be sent if the link is down.
124403831d35Sstevel 		 */
124503831d35Sstevel 		if (!dps->data_link_ok) {
124603831d35Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
124703831d35Sstevel 			    "msend: can't send msg - no data link\n"));
124803831d35Sstevel 
124903831d35Sstevel 			/*
125003831d35Sstevel 			 * do not return error, since it can be retried
125103831d35Sstevel 			 * later (hoping that the data link will come
125203831d35Sstevel 			 * up, in the meantime)
125303831d35Sstevel 			 */
125403831d35Sstevel 			return (RCNOERR);
125503831d35Sstevel 
125603831d35Sstevel 		}
125703831d35Sstevel 	} else {
125803831d35Sstevel 		first_time = 1;
125903831d35Sstevel 	}
126003831d35Sstevel 
126103831d35Sstevel 	/*
126203831d35Sstevel 	 * if the message has never been sent (and, hence, it is the first
126303831d35Sstevel 	 * time), then prepare the protocol packet: allocate a buffer,
126403831d35Sstevel 	 * create the message header, copy the message body into the buffer and
126503831d35Sstevel 	 * calculate CRCs
126603831d35Sstevel 	 */
126703831d35Sstevel 	if (first_time) {
126803831d35Sstevel 
126903831d35Sstevel 		if (IS_NUMBERED_MSG(req->msg_type)) {
127003831d35Sstevel 
127103831d35Sstevel 			drr->retries_left = TX_RETRIES;
127203831d35Sstevel 
127303831d35Sstevel 			/*
127403831d35Sstevel 			 * Check length of the message.
127503831d35Sstevel 			 */
127603831d35Sstevel 			if (req->msg_msglen > DP_MAX_MSGLEN) {
127703831d35Sstevel 				DPRINTF(rcs, DPRO,
127803831d35Sstevel 				    (CE_CONT, "msend err: msg too big\n"));
1279*52f4394bSjfrank 				return (RCEINVARG);
128003831d35Sstevel 			}
128103831d35Sstevel 
128203831d35Sstevel 			pkt = &drr->request;
128303831d35Sstevel 
128403831d35Sstevel 			/*
128503831d35Sstevel 			 * check that the message buffer is not already
128603831d35Sstevel 			 * in use (race condition). If so, return error
128703831d35Sstevel 			 */
128803831d35Sstevel 			if (pkt->msg_buf != NULL) {
128903831d35Sstevel 				DPRINTF(rcs, DPRO, (CE_CONT,
129003831d35Sstevel 				    "msend err: buf already in use\n"));
129103831d35Sstevel 				return (RCENOMEM);
129203831d35Sstevel 			}
129303831d35Sstevel 
129403831d35Sstevel 			/*
129503831d35Sstevel 			 * allocate a buffer for the protocol packet
129603831d35Sstevel 			 */
129703831d35Sstevel 			if ((pkt->msg_buf = dp_get_buffer(rcs,
129803831d35Sstevel 			    DP_TX_BUFFER)) == NULL) {
129903831d35Sstevel 				DPRINTF(rcs, DPRO, (CE_CONT,
130003831d35Sstevel 				    "msend err: no mem\n"));
130103831d35Sstevel 				return (RCENOMEM);
130203831d35Sstevel 			}
130303831d35Sstevel 			pkt->msg_bufsiz = DP_BUFFER_SIZE;
130403831d35Sstevel 
130503831d35Sstevel 			/*
130603831d35Sstevel 			 * increment tx sequence number if sending a NUMBERED
130703831d35Sstevel 			 * message
130803831d35Sstevel 			 */
130903831d35Sstevel 			dps->last_tx_seqid = NEXT_SEQID(dps->last_tx_seqid);
131003831d35Sstevel 		} else {
131103831d35Sstevel 			/*
131203831d35Sstevel 			 * UNUMBERED messages (or control messages) do not
131303831d35Sstevel 			 * carry any data and, hence, have a 'small' fixed size
131403831d35Sstevel 			 * (the size of the header). In this case,
131503831d35Sstevel 			 * a 'local' buffer (ctlbuf) is used.
131603831d35Sstevel 			 */
131703831d35Sstevel 			pkt = &ctl;
131803831d35Sstevel 			pkt->msg_buf = (uint8_t *)&ctlbuf;
131903831d35Sstevel 			pkt->msg_bufsiz = sizeof (dp_header_t);
132003831d35Sstevel 		}
132103831d35Sstevel 
132203831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
132303831d35Sstevel 
132403831d35Sstevel 		if (((erri_test_number == ERRI_RX_SEQ_NUMBER &&
132503831d35Sstevel 		    IS_NUMBERED_MSG(req->msg_type)) ||
132603831d35Sstevel 		    (erri_test_number == ERRI_CTL_RX_SEQ_NUMBER &&
132703831d35Sstevel 		    IS_UNNUMBERED_MSG(req->msg_type))) &&
132803831d35Sstevel 		    erri_test_repeat >= 0 &&
132903831d35Sstevel 		    erri_test_count++ > 0 &&
133003831d35Sstevel 		    !(erri_test_count % erri_test_intrvl)) {
133103831d35Sstevel 
133203831d35Sstevel 			dps->last_rx_seqid--;
133303831d35Sstevel 
133403831d35Sstevel 			if (erri_test_repeat == 0)
133503831d35Sstevel 				erri_test_repeat--; /* will not repeat it */
133603831d35Sstevel 		}
133703831d35Sstevel #endif
133803831d35Sstevel 
133903831d35Sstevel 		/*
134003831d35Sstevel 		 * create the protocol packet
134103831d35Sstevel 		 */
134203831d35Sstevel 		pkt->msg_type = req->msg_type;
134303831d35Sstevel 
134403831d35Sstevel 		/*
134503831d35Sstevel 		 * length of the packet (including pad bytes)
134603831d35Sstevel 		 */
134703831d35Sstevel 		pkt->msg_msglen = req->msg_msglen + sizeof (dp_header_t);
134803831d35Sstevel 
134903831d35Sstevel 		/*
135003831d35Sstevel 		 * message header:
135103831d35Sstevel 		 *  set the message type
135203831d35Sstevel 		 *  set the length of the message (excluding pad bytes)
135303831d35Sstevel 		 *  set tx/rx sequence numbers
135403831d35Sstevel 		 *  calculate CRC
135503831d35Sstevel 		 */
135603831d35Sstevel 		dp_msgp = (dp_header_t *)pkt->msg_buf;
135703831d35Sstevel 		dp_msgp->type = pkt->msg_type;
135803831d35Sstevel 
135903831d35Sstevel 		if (req->msg_msglen == 0)
136003831d35Sstevel 			dp_msgp->length = pkt->msg_msglen -
136103831d35Sstevel 			    sizeof (dp_msgp->pad);
136203831d35Sstevel 		else
136303831d35Sstevel 			dp_msgp->length = sizeof (data_crc) +
136403831d35Sstevel 			    pkt->msg_msglen - sizeof (dp_msgp->pad);
136503831d35Sstevel 
136603831d35Sstevel 		dp_msgp->txnum = dps->last_tx_seqid;
136703831d35Sstevel 		dp_msgp->rxnum = dps->last_rx_seqid;
136803831d35Sstevel 
136903831d35Sstevel 		dp_msgp->crc = dp_calc_crc16(pkt->msg_buf +
137003831d35Sstevel 		    sizeof (dp_msgp->pad), sizeof (dp_header_t) -
137103831d35Sstevel 		    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
137203831d35Sstevel 
137303831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
137403831d35Sstevel 
137503831d35Sstevel 		if (((erri_test_number == ERRI_CRC_HEADER &&
137603831d35Sstevel 		    IS_NUMBERED_MSG(pkt->msg_type)) ||
137703831d35Sstevel 		    (erri_test_number == ERRI_CTL_CRC_HEADER &&
137803831d35Sstevel 		    IS_UNNUMBERED_MSG(pkt->msg_type))) &&
137903831d35Sstevel 		    erri_test_repeat >= 0 &&
138003831d35Sstevel 		    erri_test_count++ > 0 &&
138103831d35Sstevel 		    !(erri_test_count % erri_test_intrvl)) {
138203831d35Sstevel 
138303831d35Sstevel 			dp_msgp->crc = dp_msgp->crc/2;
138403831d35Sstevel 			if (erri_test_repeat == 0)
138503831d35Sstevel 				erri_test_repeat--; /* will not repeat it */
138603831d35Sstevel 		}
138703831d35Sstevel #endif
138803831d35Sstevel 
138903831d35Sstevel 		/*
139003831d35Sstevel 		 * copy message body (if present) into the buffer
139103831d35Sstevel 		 * and calculate message CRC
139203831d35Sstevel 		 */
139303831d35Sstevel 		if (req->msg_msglen > 0) {
139403831d35Sstevel 			bcopy(req->msg_buf, pkt->msg_buf + sizeof (dp_header_t),
139503831d35Sstevel 			    req->msg_msglen);
139603831d35Sstevel 			data_crc = dp_calc_crc16(pkt->msg_buf +
139703831d35Sstevel 			    sizeof (dp_header_t),
139803831d35Sstevel 			    req->msg_msglen);
139903831d35Sstevel 
140003831d35Sstevel #ifdef DEBUG_ERROR_INJECTION
140103831d35Sstevel 
140203831d35Sstevel 			if (erri_test_number == ERRI_CRC_MSG &&
140303831d35Sstevel 			    erri_test_repeat >= 0 &&
140403831d35Sstevel 			    erri_test_count++ > 0 &&
140503831d35Sstevel 			    !(erri_test_count % erri_test_intrvl)) {
140603831d35Sstevel 
140703831d35Sstevel 				data_crc = data_crc/2;
140803831d35Sstevel 				if (erri_test_repeat == 0)
140903831d35Sstevel 					erri_test_repeat--;
141003831d35Sstevel 			}
141103831d35Sstevel #endif
141203831d35Sstevel 			bcopy((void *) &data_crc,
141303831d35Sstevel 			    pkt->msg_buf + (sizeof (dp_header_t) +
141403831d35Sstevel 			    req->msg_msglen),
141503831d35Sstevel 			    sizeof (data_crc));
141603831d35Sstevel 		}
141703831d35Sstevel 	} else {
141803831d35Sstevel 		/*
141903831d35Sstevel 		 * message has already been sent (and packetized).
142003831d35Sstevel 		 * get the message packet from the request/response
142103831d35Sstevel 		 * data structure
142203831d35Sstevel 		 */
142303831d35Sstevel 		pkt = &drr->request;
142403831d35Sstevel 		dp_msgp = (dp_header_t *)pkt->msg_buf;
142503831d35Sstevel 		dps->retries_cnt++;
142603831d35Sstevel 	}
142703831d35Sstevel 
142803831d35Sstevel 	/*
142903831d35Sstevel 	 *  NUMBERED messages
143003831d35Sstevel 	 */
143103831d35Sstevel 	if (IS_NUMBERED_MSG(pkt->msg_type)) {
143203831d35Sstevel 
143303831d35Sstevel 		/*
143403831d35Sstevel 		 * check that we have not exceeded the maximum number of
143503831d35Sstevel 		 * retries
143603831d35Sstevel 		 */
143703831d35Sstevel 		if (drr->retries_left-- <= 0) {
143803831d35Sstevel 
143903831d35Sstevel 			drr->flags |= MSG_ERROR; /* set error flag */
144003831d35Sstevel 
144103831d35Sstevel 			/*
144203831d35Sstevel 			 * restart the data protocol link
144303831d35Sstevel 			 */
144403831d35Sstevel 			dp_reset(rcs, INITIAL_SEQID, 0, 1);
144503831d35Sstevel 
144603831d35Sstevel 			return (RCEMAXRETRIES);
144703831d35Sstevel 		}
144803831d35Sstevel 
144903831d35Sstevel 		if (dps->timer_delay_ack != (timeout_id_t)0) {
145003831d35Sstevel 			/*
145103831d35Sstevel 			 * Cancel any pending acknowledgements - we're
145203831d35Sstevel 			 * going to send a message which will include
145303831d35Sstevel 			 * an acknowledgement.
145403831d35Sstevel 			 */
145503831d35Sstevel 			timer_delay_ack = dps->timer_delay_ack;
145603831d35Sstevel 
145703831d35Sstevel 			/*
145803831d35Sstevel 			 * the timer is actually removed at the end of this
145903831d35Sstevel 			 * function since I need to release the dp_mutex.
146003831d35Sstevel 			 * Instead I clear the timer variable so that the
146103831d35Sstevel 			 * timeout callback will not do any processing in the
146203831d35Sstevel 			 * meantime.
146303831d35Sstevel 			 */
146403831d35Sstevel 			dps->timer_delay_ack = 0;
146503831d35Sstevel 		}
146603831d35Sstevel 
146703831d35Sstevel 		drr->flags |= MSG_SENT;
146803831d35Sstevel 	}
146903831d35Sstevel 
147003831d35Sstevel 	/*
147103831d35Sstevel 	 * set rx sequence number (as we might have received a message in the
147203831d35Sstevel 	 * meantime). tx sequence number to be the same (we can only send one
147303831d35Sstevel 	 * message per time)
147403831d35Sstevel 	 */
147503831d35Sstevel 	if (dp_msgp->rxnum != dps->last_rx_seqid) {
147603831d35Sstevel 
147703831d35Sstevel 		dp_msgp->rxnum = dps->last_rx_seqid;
147803831d35Sstevel 
147903831d35Sstevel 		/*
148003831d35Sstevel 		 * re-calculate CRC (header)
148103831d35Sstevel 		 */
148203831d35Sstevel 		dp_msgp->crc = dp_calc_crc16(pkt->msg_buf +
148303831d35Sstevel 		    sizeof (dp_msgp->pad), sizeof (dp_header_t) -
148403831d35Sstevel 		    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
148503831d35Sstevel 	}
148603831d35Sstevel 
148703831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "[t%03dr%03d] msend msgtype=%02x\n",
148803831d35Sstevel 	    dp_msgp->txnum, dp_msgp->rxnum, dp_msgp->type));
148903831d35Sstevel 
149003831d35Sstevel 	/*
149103831d35Sstevel 	 * send this message
149203831d35Sstevel 	 */
149303831d35Sstevel 
149403831d35Sstevel 	dp_send_packet(rcs, pkt->msg_buf);
149503831d35Sstevel 
149603831d35Sstevel 	/*
149703831d35Sstevel 	 * remove delay ack timer (if any is running)
149803831d35Sstevel 	 * Note that the dp_mutex must be released before calling
149903831d35Sstevel 	 * untimeout. Otherwise we may have a deadlock situation.
150003831d35Sstevel 	 */
150103831d35Sstevel 	if (timer_delay_ack != 0) {
150203831d35Sstevel 		DPRINTF(rcs, DGEN, (CE_CONT, "msend remove ack timer %p\n",
150303831d35Sstevel 		    timer_delay_ack));
150403831d35Sstevel 		mutex_exit(dps->dp_mutex);
150503831d35Sstevel 		(void) untimeout(timer_delay_ack);
150603831d35Sstevel 		mutex_enter(dps->dp_mutex);
150703831d35Sstevel 	}
150803831d35Sstevel 
150903831d35Sstevel 	return (RCNOERR);
151003831d35Sstevel }
151103831d35Sstevel 
151203831d35Sstevel /*
151303831d35Sstevel  * to send a boot protocol message
151403831d35Sstevel  * (this is to support the firmware download feature)
151503831d35Sstevel  */
151603831d35Sstevel void
rmc_comm_bp_msend(struct rmc_comm_state * rcs,bp_msg_t * bp_msg)151703831d35Sstevel rmc_comm_bp_msend(struct rmc_comm_state *rcs, bp_msg_t *bp_msg)
151803831d35Sstevel {
151903831d35Sstevel 	char syncbuf[2];
152003831d35Sstevel 
152103831d35Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
152203831d35Sstevel 
152303831d35Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "send bp msg: %02x %02x %02x\n",
152403831d35Sstevel 	    bp_msg->cmd, bp_msg->dat1, bp_msg->dat2));
152503831d35Sstevel 
152603831d35Sstevel 	rcs->dp_state.req_resp.flags |= MSG_SENT_BP;
152703831d35Sstevel 
152803831d35Sstevel 	/* First, send out two SYNC characters. */
1529055d7c80Scarlsonj 	syncbuf[0] = syncbuf[1] = (char)SYNC_CHAR;
1530055d7c80Scarlsonj 	rmc_comm_serdev_send(rcs, syncbuf, 2);
153103831d35Sstevel 
153203831d35Sstevel 	/* Next, send the BP message. */
153303831d35Sstevel 	rmc_comm_serdev_send(rcs, (char *)&bp_msg->cmd,
153403831d35Sstevel 	    sizeof (bp_msg_t) - sizeof (bp_msg->pad));
153503831d35Sstevel }
153603831d35Sstevel 
153703831d35Sstevel /*
153803831d35Sstevel  * to send a fw s-record
153903831d35Sstevel  * (this is to support the firmware download feature)
154003831d35Sstevel  */
154103831d35Sstevel void
rmc_comm_bp_srecsend(struct rmc_comm_state * rcs,char * buf,int buflen)154203831d35Sstevel rmc_comm_bp_srecsend(struct rmc_comm_state *rcs, char *buf, int buflen)
154303831d35Sstevel {
154403831d35Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
154503831d35Sstevel 
154603831d35Sstevel 	rcs->dp_state.req_resp.flags |= MSG_SENT_BP;
154703831d35Sstevel 
154803831d35Sstevel 	rmc_comm_serdev_send(rcs, buf, buflen);
154903831d35Sstevel }
155003831d35Sstevel 
155103831d35Sstevel /*
155203831d35Sstevel  * clean up a request/response session
155303831d35Sstevel  * (it must have the dp_mutex)
155403831d35Sstevel  */
155503831d35Sstevel 
155603831d35Sstevel void
rmc_comm_dp_mcleanup(struct rmc_comm_state * rcs)155703831d35Sstevel rmc_comm_dp_mcleanup(struct rmc_comm_state *rcs)
155803831d35Sstevel {
155903831d35Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
156003831d35Sstevel 	dp_req_resp_t *drr = &dps->req_resp;
156103831d35Sstevel 	dp_message_t *req = &drr->request;
156203831d35Sstevel 	dp_message_t *resp = &drr->response;
156303831d35Sstevel 
156403831d35Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
156503831d35Sstevel 
156603831d35Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "msg cleanup\n"));
156703831d35Sstevel 
156803831d35Sstevel 	/*
156903831d35Sstevel 	 * 'release' memory
157003831d35Sstevel 	 * memory is only 'dynamically allocated for NUMBERED messages
157103831d35Sstevel 	 */
157203831d35Sstevel 	if (req->msg_buf != NULL)
157303831d35Sstevel 		dp_release_buffer(rcs, DP_TX_BUFFER);
157403831d35Sstevel 
157503831d35Sstevel 	drr->flags = 0;
157603831d35Sstevel 	drr->error_status = 0;
157703831d35Sstevel 
157803831d35Sstevel 	req->msg_type = DP_NULL_MSG;
157903831d35Sstevel 	req->msg_buf = NULL;
158003831d35Sstevel 	req->msg_msglen = 0;
158103831d35Sstevel 	req->msg_bufsiz = 0;
158203831d35Sstevel 	resp->msg_type = DP_NULL_MSG;
158303831d35Sstevel 	resp->msg_buf = NULL;
158403831d35Sstevel 	resp->msg_msglen = 0;
158503831d35Sstevel 	resp->msg_bufsiz = 0;
158603831d35Sstevel }
1587