xref: /onnv-gate/usr/src/uts/sun4u/io/rmc_comm_dp.c (revision 1708:ea74d8598a3a)
1*1708Sstevel /*
2*1708Sstevel  * CDDL HEADER START
3*1708Sstevel  *
4*1708Sstevel  * The contents of this file are subject to the terms of the
5*1708Sstevel  * Common Development and Distribution License (the "License").
6*1708Sstevel  * You may not use this file except in compliance with the License.
7*1708Sstevel  *
8*1708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1708Sstevel  * or http://www.opensolaris.org/os/licensing.
10*1708Sstevel  * See the License for the specific language governing permissions
11*1708Sstevel  * and limitations under the License.
12*1708Sstevel  *
13*1708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
14*1708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
16*1708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
17*1708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1708Sstevel  *
19*1708Sstevel  * CDDL HEADER END
20*1708Sstevel  */
21*1708Sstevel 
22*1708Sstevel /*
23*1708Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*1708Sstevel  * Use is subject to license terms.
25*1708Sstevel  *
26*1708Sstevel  * implementation of the transport layer protocol (known as librsc protocol):
27*1708Sstevel  *
28*1708Sstevel  */
29*1708Sstevel 
30*1708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*1708Sstevel 
32*1708Sstevel /*
33*1708Sstevel  *  Header files
34*1708Sstevel  */
35*1708Sstevel 
36*1708Sstevel #include <sys/conf.h>
37*1708Sstevel #include <sys/cyclic.h>
38*1708Sstevel #include <sys/membar.h>
39*1708Sstevel #include <sys/modctl.h>
40*1708Sstevel #include <sys/strlog.h>
41*1708Sstevel #include <sys/sunddi.h>
42*1708Sstevel #include <sys/ddi.h>
43*1708Sstevel #include <sys/types.h>
44*1708Sstevel #include <sys/rmc_comm_dp.h>
45*1708Sstevel #include <sys/rmc_comm_dp_boot.h>
46*1708Sstevel #include <sys/rmc_comm_drvintf.h>
47*1708Sstevel #include <sys/rmc_comm.h>
48*1708Sstevel 
49*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
50*1708Sstevel 
51*1708Sstevel #define	ERRI_RX_SEQ_NUMBER	1
52*1708Sstevel #define	ERRI_ACK_MSG		2
53*1708Sstevel #define	ERRI_CRC_HEADER		3
54*1708Sstevel #define	ERRI_CRC_MSG		4
55*1708Sstevel #define	ERRI_SEND_CTL_STACK	5
56*1708Sstevel #define	ERRI_SEND_CTL_START	6
57*1708Sstevel 
58*1708Sstevel #define	ERRI_CTL_RX_SEQ_NUMBER	7
59*1708Sstevel #define	ERRI_CTL_CRC_HEADER	8
60*1708Sstevel 
61*1708Sstevel int	erri_test_number = 0;
62*1708Sstevel int	erri_test_intrvl = 0;
63*1708Sstevel int	erri_test_repeat = 0;
64*1708Sstevel int	erri_test_count = 0;
65*1708Sstevel 
66*1708Sstevel int erri_test_simulate_srec_sec(struct rmc_comm_state *, char *, int);
67*1708Sstevel 
68*1708Sstevel #endif
69*1708Sstevel 
70*1708Sstevel 
71*1708Sstevel /* static functions */
72*1708Sstevel 
73*1708Sstevel static void dp_link_setup_tohandler(void *);
74*1708Sstevel static void dp_delay_ack_tohandler(void *);
75*1708Sstevel static uint8_t *dp_get_buffer(struct rmc_comm_state *, uint8_t);
76*1708Sstevel static void dp_release_buffer(struct rmc_comm_state *, uint8_t);
77*1708Sstevel static void dp_init_buffers(struct rmc_comm_state *);
78*1708Sstevel static void dp_got_full_hdr(struct rmc_comm_state *, dp_packet_t *);
79*1708Sstevel static void dp_got_bp_msg(struct rmc_comm_state *, dp_packet_t *);
80*1708Sstevel static void dp_got_full_msg(struct rmc_comm_state *, dp_packet_t *);
81*1708Sstevel static void dp_tx_handle_ack(struct rmc_comm_state *, uint16_t);
82*1708Sstevel static void dp_tx_handle_nak(struct rmc_comm_state *, uint16_t);
83*1708Sstevel static void dp_send_packet(struct rmc_comm_state *, uchar_t *);
84*1708Sstevel static void dp_enable_data_link(struct rmc_comm_state *);
85*1708Sstevel static int dp_get_msglen(struct rmc_comm_state *, uint8_t *);
86*1708Sstevel static uint16_t dp_calc_crc16(uint8_t *, int);
87*1708Sstevel void dp_wake_up_waiter(struct rmc_comm_state *, uint8_t);
88*1708Sstevel void dp_reset(struct rmc_comm_state *, uint8_t, boolean_t, boolean_t);
89*1708Sstevel 
90*1708Sstevel /*
91*1708Sstevel  * utilities...
92*1708Sstevel  */
93*1708Sstevel 
94*1708Sstevel /*
95*1708Sstevel  *  init rx/tx buffer pool
96*1708Sstevel  */
97*1708Sstevel static void
98*1708Sstevel dp_init_buffers(struct rmc_comm_state *rcs)
99*1708Sstevel {
100*1708Sstevel 	int i;
101*1708Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
102*1708Sstevel 
103*1708Sstevel 	for (i = 0; i < DP_BUFFER_COUNT; i++)
104*1708Sstevel 		dbuf[i].in_use = 0;
105*1708Sstevel }
106*1708Sstevel 
107*1708Sstevel /*
108*1708Sstevel  *  get tx/rx buffer
109*1708Sstevel  */
110*1708Sstevel static uint8_t *
111*1708Sstevel dp_get_buffer(struct rmc_comm_state *rcs, uint8_t type)
112*1708Sstevel {
113*1708Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
114*1708Sstevel 
115*1708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
116*1708Sstevel 
117*1708Sstevel 	if ((type != DP_TX_BUFFER && type != DP_RX_BUFFER) ||
118*1708Sstevel 		dbuf[type].in_use) {
119*1708Sstevel 
120*1708Sstevel 		DPRINTF(rcs, DMEM,
121*1708Sstevel 			(CE_CONT, "get buffer err. type=%d, in_use=%d\n",
122*1708Sstevel 			type, dbuf[type].in_use));
123*1708Sstevel 
124*1708Sstevel 		return (NULL);
125*1708Sstevel 	}
126*1708Sstevel 
127*1708Sstevel 	DPRINTF(rcs, DMEM, (CE_CONT, "get buffer type=%d\n", type));
128*1708Sstevel 
129*1708Sstevel 	dbuf[type].in_use = 1;
130*1708Sstevel 
131*1708Sstevel 	return (dbuf[type].buf);
132*1708Sstevel }
133*1708Sstevel 
134*1708Sstevel /*
135*1708Sstevel  * release tx/rx buffer
136*1708Sstevel  */
137*1708Sstevel static void
138*1708Sstevel dp_release_buffer(struct rmc_comm_state *rcs, uint8_t type)
139*1708Sstevel {
140*1708Sstevel 	dp_buffer_t *dbuf = rcs->dp_state.dp_buffers;
141*1708Sstevel 
142*1708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
143*1708Sstevel 
144*1708Sstevel 	if (type != DP_TX_BUFFER && type != DP_RX_BUFFER) {
145*1708Sstevel 		DPRINTF(rcs, DMEM,
146*1708Sstevel 			(CE_CONT, "free buffer err. type=%d, in_use=%d\n",
147*1708Sstevel 			type, dbuf[type].in_use));
148*1708Sstevel 		return;
149*1708Sstevel 	}
150*1708Sstevel 	DPRINTF(rcs, DMEM, (CE_CONT, "free buffer type=%d\n", type));
151*1708Sstevel 
152*1708Sstevel 	dbuf[type].in_use = 0;
153*1708Sstevel }
154*1708Sstevel 
155*1708Sstevel /*
156*1708Sstevel  * setup data link timeout handler
157*1708Sstevel  * (called without having the dp_mutex)
158*1708Sstevel  */
159*1708Sstevel static void
160*1708Sstevel dp_link_setup_tohandler(void *arg)
161*1708Sstevel {
162*1708Sstevel 	struct rmc_comm_state *rcs = (struct rmc_comm_state *)arg;
163*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
164*1708Sstevel 
165*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "t/o setup data link\n"));
166*1708Sstevel 
167*1708Sstevel 	/*
168*1708Sstevel 	 * check if timer has actually been cancelled
169*1708Sstevel 	 */
170*1708Sstevel 	mutex_enter(dps->dp_mutex);
171*1708Sstevel 	if (dps->timer_link_setup != (timeout_id_t)0) {
172*1708Sstevel 
173*1708Sstevel 		/*
174*1708Sstevel 		 * send CTL:start to the remote side to set up the data link
175*1708Sstevel 		 */
176*1708Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
177*1708Sstevel 
178*1708Sstevel 		dps->timer_link_setup = timeout(dp_link_setup_tohandler,
179*1708Sstevel 		    (void *) rcs, drv_usectohz(RETRY_DP_SETUP * 1000));
180*1708Sstevel 	}
181*1708Sstevel 	mutex_exit(dps->dp_mutex);
182*1708Sstevel }
183*1708Sstevel 
184*1708Sstevel /*
185*1708Sstevel  * delay acknowledgment of a received message timeout handler
186*1708Sstevel  * (called without having the dp_mutex)
187*1708Sstevel  */
188*1708Sstevel static void
189*1708Sstevel dp_delay_ack_tohandler(void *arg)
190*1708Sstevel {
191*1708Sstevel 	struct rmc_comm_state *rcs = (struct rmc_comm_state *)arg;
192*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
193*1708Sstevel 
194*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
195*1708Sstevel 
196*1708Sstevel 	if (erri_test_number == ERRI_ACK_MSG &&
197*1708Sstevel 	    erri_test_repeat >= 0 &&
198*1708Sstevel 	    erri_test_count++ > 0 && !(erri_test_count % erri_test_intrvl)) {
199*1708Sstevel 
200*1708Sstevel 		/*
201*1708Sstevel 		 * DON'T ACK THE MESSAGE - BE SILENT!
202*1708Sstevel 		 */
203*1708Sstevel 
204*1708Sstevel 		if (erri_test_repeat == 0)
205*1708Sstevel 			erri_test_repeat--; /* will not repeat the test */
206*1708Sstevel 
207*1708Sstevel 		dps->timer_delay_ack = (timeout_id_t)0;
208*1708Sstevel 		return;
209*1708Sstevel 	}
210*1708Sstevel 
211*1708Sstevel #endif
212*1708Sstevel 
213*1708Sstevel 	/*
214*1708Sstevel 	 * check if timer has actually been cancelled
215*1708Sstevel 	 */
216*1708Sstevel 	mutex_enter(dps->dp_mutex);
217*1708Sstevel 	if (dps->timer_delay_ack != (timeout_id_t)0) {
218*1708Sstevel 		/*
219*1708Sstevel 		 * ACK the message
220*1708Sstevel 		 */
221*1708Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_ACK);
222*1708Sstevel 		dps->timer_delay_ack = (timeout_id_t)0;
223*1708Sstevel 	}
224*1708Sstevel 	mutex_exit(dps->dp_mutex);
225*1708Sstevel }
226*1708Sstevel 
227*1708Sstevel /*
228*1708Sstevel  * Enable data link protocol:
229*1708Sstevel  *  stop data link setup timer
230*1708Sstevel  *  set data_link_ok flag
231*1708Sstevel  * (must already have the dp_mutex)
232*1708Sstevel  */
233*1708Sstevel static void
234*1708Sstevel dp_enable_data_link(struct rmc_comm_state *rcs)
235*1708Sstevel {
236*1708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
237*1708Sstevel 	timeout_id_t		 timer_id;
238*1708Sstevel 
239*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
240*1708Sstevel 
241*1708Sstevel 	dps->data_link_ok = 1;
242*1708Sstevel 
243*1708Sstevel 	timer_id = dps->timer_link_setup;
244*1708Sstevel 	dps->timer_link_setup = (timeout_id_t)0;
245*1708Sstevel 	if (timer_id != (timeout_id_t)0) {
246*1708Sstevel 
247*1708Sstevel 		mutex_exit(dps->dp_mutex);
248*1708Sstevel 		(void) untimeout(timer_id);
249*1708Sstevel 		mutex_enter(dps->dp_mutex);
250*1708Sstevel 	}
251*1708Sstevel }
252*1708Sstevel 
253*1708Sstevel /*
254*1708Sstevel  * CRC calculation routine.
255*1708Sstevel  */
256*1708Sstevel static uint16_t
257*1708Sstevel dp_calc_crc16(uint8_t *buf, int len)
258*1708Sstevel {
259*1708Sstevel 	extern uint16_t crctab16[];
260*1708Sstevel 	uint16_t crc;
261*1708Sstevel 
262*1708Sstevel 	crc = 0;
263*1708Sstevel 	while (len--) {
264*1708Sstevel 		crc = (crc >> 8) ^ crctab16[(crc ^ *buf++) & 0xFF];
265*1708Sstevel 	}
266*1708Sstevel 	return (crc);
267*1708Sstevel }
268*1708Sstevel 
269*1708Sstevel /*
270*1708Sstevel  * Reset the data protocol
271*1708Sstevel  * (dp_mutex must be held)
272*1708Sstevel  */
273*1708Sstevel void
274*1708Sstevel dp_reset(struct rmc_comm_state *rcs, uint8_t rx_seqid,
275*1708Sstevel     boolean_t flush_tx, boolean_t restart_data_link)
276*1708Sstevel {
277*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
278*1708Sstevel 
279*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
280*1708Sstevel 
281*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT,
282*1708Sstevel 	    "reset proto: rxsid=%d, flushtx=%d, restartdp=%d\n",
283*1708Sstevel 	    rx_seqid, flush_tx, restart_data_link));
284*1708Sstevel 
285*1708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT,
286*1708Sstevel 	    "stats: reset=%d nak=%d start=%d stack=%d retries=%d crcerr=%d\n",
287*1708Sstevel 	    dps->reset_cnt, dps->nak_cnt, dps->start_cnt, dps->stack_cnt,
288*1708Sstevel 	    dps->retries_cnt, dps->crcerr_cnt));
289*1708Sstevel 
290*1708Sstevel 	dps->last_rx_seqid = rx_seqid;
291*1708Sstevel 	dps->reset_cnt++;
292*1708Sstevel 
293*1708Sstevel 	/*
294*1708Sstevel 	 * Flush pending tx message.
295*1708Sstevel 	 */
296*1708Sstevel 	if (flush_tx) {
297*1708Sstevel 		dps->last_tx_seqid = INITIAL_SEQID;
298*1708Sstevel 		dps->last_rx_ack = rx_seqid;
299*1708Sstevel 
300*1708Sstevel 		/*
301*1708Sstevel 		 * if there is any pending request/response session
302*1708Sstevel 		 * then just abort it.
303*1708Sstevel 		 */
304*1708Sstevel 		dp_wake_up_waiter(rcs, MSG_ERROR);
305*1708Sstevel 	}
306*1708Sstevel 
307*1708Sstevel 	/*
308*1708Sstevel 	 * restart data link, but only if the data link set up timer is
309*1708Sstevel 	 * not already running.
310*1708Sstevel 	 */
311*1708Sstevel 	if (restart_data_link && dps->timer_link_setup == (timeout_id_t)0) {
312*1708Sstevel 
313*1708Sstevel 		dps->data_link_ok = 0;
314*1708Sstevel 
315*1708Sstevel 		/*
316*1708Sstevel 		 * set up the data protocol link
317*1708Sstevel 		 */
318*1708Sstevel 		(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
319*1708Sstevel 		dps->timer_link_setup = timeout(dp_link_setup_tohandler,
320*1708Sstevel 		    (void *)rcs, drv_usectohz(RETRY_DP_SETUP * 1000));
321*1708Sstevel 	}
322*1708Sstevel }
323*1708Sstevel 
324*1708Sstevel /*
325*1708Sstevel  * Handles acknowledgment of a message previously sent OR a heartbeat command
326*1708Sstevel  * (CTL_RESPOND).
327*1708Sstevel  */
328*1708Sstevel static void
329*1708Sstevel dp_tx_handle_ack(struct rmc_comm_state *rcs, uint16_t rxnum)
330*1708Sstevel {
331*1708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
332*1708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
333*1708Sstevel 
334*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
335*1708Sstevel 
336*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "handle ACK, rxnum=%03d\n", rxnum));
337*1708Sstevel 
338*1708Sstevel 	dps->last_rx_ack = rxnum;
339*1708Sstevel 	if ((drr->flags & MSG_SENT) == 0) {
340*1708Sstevel 		/*
341*1708Sstevel 		 * no pending messages, so nothing to do
342*1708Sstevel 		 */
343*1708Sstevel 		return;
344*1708Sstevel 	}
345*1708Sstevel 
346*1708Sstevel 	if (rxnum == dps->last_tx_seqid) {
347*1708Sstevel 		/*
348*1708Sstevel 		 * message was sent and acknowledged successfully
349*1708Sstevel 		 * set flag and signal the waiting task if it is not
350*1708Sstevel 		 * expecting a reply back
351*1708Sstevel 		 */
352*1708Sstevel 		drr->flags |= MSG_ACKED;
353*1708Sstevel 		if (drr->response.msg_type == DP_NULL_MSG) {
354*1708Sstevel 			dp_wake_up_waiter(rcs, MSG_ACKED);
355*1708Sstevel 		}
356*1708Sstevel 	}
357*1708Sstevel }
358*1708Sstevel 
359*1708Sstevel /*
360*1708Sstevel  * Handles NAK
361*1708Sstevel  */
362*1708Sstevel static void
363*1708Sstevel dp_tx_handle_nak(struct rmc_comm_state *rcs, uint16_t rxnum)
364*1708Sstevel {
365*1708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
366*1708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
367*1708Sstevel 
368*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
369*1708Sstevel 
370*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "handle NAK, rxnum=%03d\n", rxnum));
371*1708Sstevel 
372*1708Sstevel 	if ((drr->flags & MSG_SENT) == 0) {
373*1708Sstevel 		/*
374*1708Sstevel 		 * no pending messages, so nothing to do
375*1708Sstevel 		 */
376*1708Sstevel 		return;
377*1708Sstevel 	}
378*1708Sstevel 
379*1708Sstevel 	/*
380*1708Sstevel 	 * since one message per time can be sent, it is assumed that the
381*1708Sstevel 	 * message being NAKed is just the one that has been sent.
382*1708Sstevel 	 */
383*1708Sstevel 	dps->nak_cnt++;
384*1708Sstevel 
385*1708Sstevel 	dp_wake_up_waiter(rcs, MSG_NAKED);
386*1708Sstevel }
387*1708Sstevel 
388*1708Sstevel /*
389*1708Sstevel  * Got a full header. Check header CRC and get the length of the packet
390*1708Sstevel  */
391*1708Sstevel static void
392*1708Sstevel dp_got_full_hdr(struct rmc_comm_state *rcs, dp_packet_t *pkt)
393*1708Sstevel {
394*1708Sstevel 	/*
395*1708Sstevel 	 * Got the full header.  Call up to the logical layer to see
396*1708Sstevel 	 * how big of a buffer I need for this message.  If the size
397*1708Sstevel 	 * is < sizeof (dp_msg_t), then there is something wrong with
398*1708Sstevel 	 * this message - drop it.  If the size is equal, then hand it
399*1708Sstevel 	 * up right now. If the size is too big - drop it. otherwise we must
400*1708Sstevel 	 * receive the body of the message.
401*1708Sstevel 	 */
402*1708Sstevel 
403*1708Sstevel 	pkt->full_length = dp_get_msglen(rcs, pkt->buf);
404*1708Sstevel 
405*1708Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "got header msglen=%d\n",
406*1708Sstevel 	    pkt->full_length));
407*1708Sstevel 
408*1708Sstevel 	if ((pkt->full_length < 0) ||
409*1708Sstevel 	    (pkt->full_length < sizeof (dp_header_t)) ||
410*1708Sstevel 	    (pkt->full_length > DP_BUFFER_SIZE)) {
411*1708Sstevel 		/*
412*1708Sstevel 		 * not a valid message: either message too big or too small
413*1708Sstevel 		 */
414*1708Sstevel 		dp_release_buffer(rcs, DP_RX_BUFFER);
415*1708Sstevel 		pkt->buf = NULL;
416*1708Sstevel 
417*1708Sstevel 		pkt->rx_state = WAITING_FOR_SYNC;
418*1708Sstevel 
419*1708Sstevel 	} else if (pkt->full_length == sizeof (dp_header_t)) {
420*1708Sstevel 		/*
421*1708Sstevel 		 * process message: it is basically a control message
422*1708Sstevel 		 * (no data being carried)
423*1708Sstevel 		 */
424*1708Sstevel 		rmc_comm_dp_mrecv(rcs, pkt->buf);
425*1708Sstevel 
426*1708Sstevel 		dp_release_buffer(rcs, DP_RX_BUFFER);
427*1708Sstevel 		pkt->buf = NULL;
428*1708Sstevel 
429*1708Sstevel 		pkt->rx_state = WAITING_FOR_SYNC;
430*1708Sstevel 	} else {
431*1708Sstevel 		pkt->rx_state = RECEIVING_BODY;
432*1708Sstevel 	}
433*1708Sstevel }
434*1708Sstevel 
435*1708Sstevel /*
436*1708Sstevel  * Got a BP (boot prom) message. Usually, BP messages are received when
437*1708Sstevel  * the firmware goes into boot monitor mode (where only BP protocol is used).
438*1708Sstevel  * This just happens during firmware download. There should not be any other
439*1708Sstevel  * case where a BP message is received.
440*1708Sstevel  */
441*1708Sstevel static void
442*1708Sstevel dp_got_bp_msg(struct rmc_comm_state *rcs, dp_packet_t *pkt)
443*1708Sstevel {
444*1708Sstevel 	bp_msg_t		*msgp = (bp_msg_t *)pkt->buf;
445*1708Sstevel 	rmc_comm_dp_state_t	*dps = &rcs->dp_state;
446*1708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
447*1708Sstevel 	int			datalen = sizeof (bp_msg_t);
448*1708Sstevel 
449*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
450*1708Sstevel 
451*1708Sstevel 	/*
452*1708Sstevel 	 * ignore BP message, if it is not expected
453*1708Sstevel 	 */
454*1708Sstevel 	if ((drr->flags & MSG_SENT_BP) != 0) {
455*1708Sstevel 
456*1708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "got bp msg: %02x %02x %02x\n",
457*1708Sstevel 		    msgp->cmd, msgp->dat1, msgp->dat2));
458*1708Sstevel 
459*1708Sstevel 		/*
460*1708Sstevel 		 * A boot prom (BP) msg has been sent. Here is the
461*1708Sstevel 		 * 'expected' reply
462*1708Sstevel 		 */
463*1708Sstevel 
464*1708Sstevel 		/*
465*1708Sstevel 		 * check that the recv buffer is big enough (just in case).
466*1708Sstevel 		 */
467*1708Sstevel 		if (datalen <= drr->response.msg_bufsiz) {
468*1708Sstevel 			bcopy(pkt->buf, drr->response.msg_buf, datalen);
469*1708Sstevel 			drr->response.msg_msglen = datalen;
470*1708Sstevel 			dp_wake_up_waiter(rcs, MSG_RXED_BP);
471*1708Sstevel 		} else {
472*1708Sstevel 			drr->response.msg_msglen = -1;
473*1708Sstevel 			dp_wake_up_waiter(rcs, MSG_RXED_BP);
474*1708Sstevel 		}
475*1708Sstevel 	}
476*1708Sstevel 
477*1708Sstevel 	/* Return the buffer to the pool and wait for the next msg. */
478*1708Sstevel 	dp_release_buffer(rcs, DP_RX_BUFFER);
479*1708Sstevel 	pkt->buf = NULL;
480*1708Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
481*1708Sstevel }
482*1708Sstevel 
483*1708Sstevel /*
484*1708Sstevel  * Got a complete message, check CRC and pass it on to the upper layer (message
485*1708Sstevel  * processing)
486*1708Sstevel  */
487*1708Sstevel static void
488*1708Sstevel dp_got_full_msg(struct rmc_comm_state *rcs, dp_packet_t *pkt)
489*1708Sstevel {
490*1708Sstevel 	uint16_t	 crc;
491*1708Sstevel 	int		 msglen;
492*1708Sstevel 
493*1708Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "got full msg\n"));
494*1708Sstevel 
495*1708Sstevel 	/*
496*1708Sstevel 	 * check message CRC
497*1708Sstevel 	 */
498*1708Sstevel 
499*1708Sstevel 	msglen = pkt->full_length - sizeof (dp_header_t) - sizeof (crc);
500*1708Sstevel 
501*1708Sstevel 	bcopy(pkt->buf + (pkt->full_length - sizeof (crc)), &crc, sizeof (crc));
502*1708Sstevel 
503*1708Sstevel 	if (crc == dp_calc_crc16(pkt->buf + sizeof (dp_header_t), msglen)) {
504*1708Sstevel 		/*
505*1708Sstevel 		 * CRC is ok, process this message
506*1708Sstevel 		 */
507*1708Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "got 'good' msg\n"));
508*1708Sstevel 
509*1708Sstevel 		rmc_comm_dp_mrecv(rcs, pkt->buf);
510*1708Sstevel 	} else {
511*1708Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "CRC error (msg)\n"));
512*1708Sstevel 		rcs->dp_state.crcerr_cnt++;
513*1708Sstevel 	}
514*1708Sstevel 
515*1708Sstevel 	dp_release_buffer(rcs, DP_RX_BUFFER);
516*1708Sstevel 	pkt->buf = NULL;
517*1708Sstevel 
518*1708Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
519*1708Sstevel }
520*1708Sstevel 
521*1708Sstevel /*
522*1708Sstevel  * Check the checksum of the header & return the length field.  If the
523*1708Sstevel  * checksum check fails, then return -1.
524*1708Sstevel  */
525*1708Sstevel static int
526*1708Sstevel dp_get_msglen(struct rmc_comm_state *rcs, uint8_t *buf)
527*1708Sstevel {
528*1708Sstevel 	dp_header_t 	*dp_msgp;
529*1708Sstevel 	uint16_t	 crc;
530*1708Sstevel 
531*1708Sstevel 	dp_msgp = (dp_header_t *)buf;
532*1708Sstevel 
533*1708Sstevel 	crc = dp_calc_crc16(buf + sizeof (dp_msgp->pad), sizeof (dp_header_t) -
534*1708Sstevel 	    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
535*1708Sstevel 
536*1708Sstevel 	if (dp_msgp->crc == crc) {
537*1708Sstevel 		return (dp_msgp->length + sizeof (dp_msgp->pad));
538*1708Sstevel 	} else {
539*1708Sstevel 		DPRINTF(rcs, DPKT, (CE_CONT, "CRC error (header)\n"));
540*1708Sstevel 		rcs->dp_state.crcerr_cnt++;
541*1708Sstevel 		return (-1);
542*1708Sstevel 	}
543*1708Sstevel }
544*1708Sstevel 
545*1708Sstevel /*
546*1708Sstevel  * to send a protocol packet to the remote side. it handles escaping SYNC
547*1708Sstevel  * and ESC chars
548*1708Sstevel  */
549*1708Sstevel static void
550*1708Sstevel dp_send_packet(struct rmc_comm_state *rcs, uchar_t *buf)
551*1708Sstevel {
552*1708Sstevel 	char syncbuf[2];
553*1708Sstevel 	dp_header_t *dp_msgp = (dp_header_t *)buf;
554*1708Sstevel 	int total, cur;
555*1708Sstevel 
556*1708Sstevel 	/* First, send out two SYNC characters. */
557*1708Sstevel 	syncbuf[0] = syncbuf[1] = SYNC_CHAR;
558*1708Sstevel 	rmc_comm_serdev_send(rcs, (char *)syncbuf, 2);
559*1708Sstevel 
560*1708Sstevel 	total = dp_msgp->length;
561*1708Sstevel 	buf = buf + sizeof (dp_msgp->pad);
562*1708Sstevel 
563*1708Sstevel 	while (total > 0) {
564*1708Sstevel 		cur = 0;
565*1708Sstevel 
566*1708Sstevel 		/* Count up characters that don't need ESC'ing. */
567*1708Sstevel 		while ((cur < total) &&
568*1708Sstevel 		    (buf[cur] != ESC_CHAR) &&
569*1708Sstevel 		    (buf[cur] != SYNC_CHAR)) {
570*1708Sstevel 			cur++;
571*1708Sstevel 		}
572*1708Sstevel 
573*1708Sstevel 		/* Send characters that don't need escaping, if any. */
574*1708Sstevel 		if (cur > 0) {
575*1708Sstevel 			rmc_comm_serdev_send(rcs, (char *)buf, cur);
576*1708Sstevel 			total -= cur;
577*1708Sstevel 			buf += cur;
578*1708Sstevel 		}
579*1708Sstevel 
580*1708Sstevel 		/*
581*1708Sstevel 		 * If total > 0 at this point, we need to send an
582*1708Sstevel 		 * ESC'd character.  Send as many as there are.
583*1708Sstevel 		 */
584*1708Sstevel 		while ((total > 0) &&
585*1708Sstevel 		    ((*buf == SYNC_CHAR) || (*buf == ESC_CHAR))) {
586*1708Sstevel 			syncbuf[0] = ESC_CHAR;
587*1708Sstevel 			syncbuf[1] = *buf;
588*1708Sstevel 			rmc_comm_serdev_send(rcs, (char *)syncbuf, 2);
589*1708Sstevel 			buf++;
590*1708Sstevel 			total--;
591*1708Sstevel 		}
592*1708Sstevel 	}
593*1708Sstevel }
594*1708Sstevel 
595*1708Sstevel /*
596*1708Sstevel  * to wake a thread waiting for a reply/ACK/error status for a request/response
597*1708Sstevel  * session.
598*1708Sstevel  */
599*1708Sstevel void
600*1708Sstevel dp_wake_up_waiter(struct rmc_comm_state *rcs, uint8_t flags)
601*1708Sstevel {
602*1708Sstevel 	dp_req_resp_t *drr = &rcs->dp_state.req_resp;
603*1708Sstevel 
604*1708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
605*1708Sstevel 
606*1708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "wake up? %x, set %x\n",
607*1708Sstevel 	    (drr->flags & (MSG_SENT | MSG_SENT_BP)) != 0, flags));
608*1708Sstevel 
609*1708Sstevel 	if ((drr->flags & (MSG_SENT | MSG_SENT_BP)) != 0) {
610*1708Sstevel 		drr->flags |= flags;
611*1708Sstevel 		cv_signal(drr->cv_wait_reply);
612*1708Sstevel 	}
613*1708Sstevel }
614*1708Sstevel 
615*1708Sstevel /*
616*1708Sstevel  * initialization of the data protocol (called from the attach routine)
617*1708Sstevel  */
618*1708Sstevel void
619*1708Sstevel rmc_comm_dp_init(struct rmc_comm_state *rcs)
620*1708Sstevel {
621*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
622*1708Sstevel 	dp_packet_t *pkt = &dps->dp_packet;
623*1708Sstevel 
624*1708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "rmc_comm_dp_init\n"));
625*1708Sstevel 
626*1708Sstevel 	/*
627*1708Sstevel 	 * initialize data structure:
628*1708Sstevel 	 */
629*1708Sstevel 	bzero((void *) dps, sizeof (rmc_comm_dp_state_t));
630*1708Sstevel 
631*1708Sstevel 	/*
632*1708Sstevel 	 * initialize packet receive handler state
633*1708Sstevel 	 */
634*1708Sstevel 
635*1708Sstevel 	pkt->rx_state = WAITING_FOR_SYNC;
636*1708Sstevel 
637*1708Sstevel 	/*
638*1708Sstevel 	 * cv variables initialization
639*1708Sstevel 	 * (dp_mutex has been already created during the serial device
640*1708Sstevel 	 * initialization)
641*1708Sstevel 	 */
642*1708Sstevel 	cv_init(dps->cv_ok_to_send, NULL, CV_DRIVER, NULL);
643*1708Sstevel 	cv_init(dps->req_resp.cv_wait_reply, NULL, CV_DRIVER, NULL);
644*1708Sstevel 
645*1708Sstevel 	mutex_enter(dps->dp_mutex);
646*1708Sstevel 
647*1708Sstevel 	dp_init_buffers(rcs);
648*1708Sstevel 
649*1708Sstevel 	/*
650*1708Sstevel 	 * initialize the data protocol (reset sequence numbers, etc.)
651*1708Sstevel 	 */
652*1708Sstevel 	dps->last_tx_seqid = INITIAL_SEQID;
653*1708Sstevel 	dps->last_rx_seqid = dps->last_rx_ack = INITIAL_SEQID;
654*1708Sstevel 
655*1708Sstevel 	/*
656*1708Sstevel 	 * start timer to 'delay' the set up of the data protocol link
657*1708Sstevel 	 */
658*1708Sstevel 	dps->timer_link_setup = timeout(dp_link_setup_tohandler,
659*1708Sstevel 	    (void *)rcs, drv_usectohz(DELAY_DP_SETUP * 1000));
660*1708Sstevel 
661*1708Sstevel 	mutex_exit(dps->dp_mutex);
662*1708Sstevel 
663*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
664*1708Sstevel 
665*1708Sstevel 	erri_test_number = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
666*1708Sstevel 	    DDI_PROP_DONTPASS, "test-no", 0);
667*1708Sstevel 	erri_test_intrvl = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
668*1708Sstevel 	    DDI_PROP_DONTPASS, "test-interval", 0);
669*1708Sstevel 	erri_test_repeat = ddi_prop_get_int(DDI_DEV_T_ANY, rcs->dip,
670*1708Sstevel 	    DDI_PROP_DONTPASS, "test-repeat", 0);
671*1708Sstevel 
672*1708Sstevel 	erri_test_count = 0;
673*1708Sstevel 
674*1708Sstevel 
675*1708Sstevel 	cmn_err(CE_CONT, "error injection test: no=%d, intrvl=%d, rep=%d\n",
676*1708Sstevel 	    erri_test_number, erri_test_intrvl, erri_test_repeat);
677*1708Sstevel #endif
678*1708Sstevel 
679*1708Sstevel }
680*1708Sstevel 
681*1708Sstevel /*
682*1708Sstevel  * termination of the data protocol (called from the detach routine)
683*1708Sstevel  */
684*1708Sstevel void
685*1708Sstevel rmc_comm_dp_fini(struct rmc_comm_state *rcs)
686*1708Sstevel {
687*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
688*1708Sstevel 	timeout_id_t	 tid_delay_ack;
689*1708Sstevel 	timeout_id_t	 tid_link_setup;
690*1708Sstevel 
691*1708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT,
692*1708Sstevel 	    "stats: reset=%d nak=%d start=%d stack=%d retries=%d crcerr=%d\n",
693*1708Sstevel 	    dps->reset_cnt, dps->nak_cnt, dps->start_cnt, dps->stack_cnt,
694*1708Sstevel 	    dps->retries_cnt, dps->crcerr_cnt));
695*1708Sstevel 
696*1708Sstevel 	/*
697*1708Sstevel 	 * if any timer is running, must be terminated here!
698*1708Sstevel 	 */
699*1708Sstevel 	mutex_enter(dps->dp_mutex);
700*1708Sstevel 	tid_delay_ack = dps->timer_link_setup;
701*1708Sstevel 	tid_link_setup = dps->timer_delay_ack;
702*1708Sstevel 	dps->timer_link_setup = (timeout_id_t)0;
703*1708Sstevel 	dps->timer_delay_ack = (timeout_id_t)0;
704*1708Sstevel 	mutex_exit(dps->dp_mutex);
705*1708Sstevel 
706*1708Sstevel 	if (tid_delay_ack)
707*1708Sstevel 		(void) untimeout(tid_delay_ack);
708*1708Sstevel 
709*1708Sstevel 	if (tid_link_setup)
710*1708Sstevel 		(void) untimeout(tid_link_setup);
711*1708Sstevel 
712*1708Sstevel 	/*
713*1708Sstevel 	 * cv variables termination
714*1708Sstevel 	 */
715*1708Sstevel 	cv_destroy(dps->cv_ok_to_send);
716*1708Sstevel 	cv_destroy(dps->req_resp.cv_wait_reply);
717*1708Sstevel }
718*1708Sstevel 
719*1708Sstevel /*
720*1708Sstevel  * This is the low-level receiver handler. It's job is to find a complete
721*1708Sstevel  * message from the incoming data stream, and once it finds one to pass it
722*1708Sstevel  * on to the upper layer (message processing).
723*1708Sstevel  * (it must have the dp_mutex)
724*1708Sstevel  */
725*1708Sstevel void
726*1708Sstevel rmc_comm_dp_drecv(struct rmc_comm_state *rcs, uint8_t *buf, int buflen)
727*1708Sstevel {
728*1708Sstevel 	rmc_comm_dp_state_t 	*dps = &rcs->dp_state;
729*1708Sstevel 	dp_packet_t 		*pkt = &dps->dp_packet;
730*1708Sstevel 	uint8_t			 quit;
731*1708Sstevel 	int			 count;
732*1708Sstevel 	int			 max;
733*1708Sstevel 
734*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
735*1708Sstevel 
736*1708Sstevel 	pkt->inbuf = buf;
737*1708Sstevel 	pkt->inbuflen = buflen;
738*1708Sstevel 
739*1708Sstevel 	DPRINTF(rcs, DPKT, (CE_CONT, "drecv len=%d\n", buflen));
740*1708Sstevel 
741*1708Sstevel 	while (pkt->inbuflen > 0) {
742*1708Sstevel 		switch (pkt->rx_state) {
743*1708Sstevel 
744*1708Sstevel 		case WAITING_FOR_SYNC:
745*1708Sstevel 			while ((pkt->inbuflen > 0) &&
746*1708Sstevel 			    (*pkt->inbuf != SYNC_CHAR) &&
747*1708Sstevel 			    (*pkt->inbuf != ESC_CHAR)) {
748*1708Sstevel 
749*1708Sstevel 				DPRINTF(rcs, DPKT,
750*1708Sstevel 				    (CE_CONT, "not SYNC: %02x\n",
751*1708Sstevel 				    (uchar_t)(*pkt->inbuf)));
752*1708Sstevel 
753*1708Sstevel 				pkt->inbuf++;
754*1708Sstevel 				pkt->inbuflen--;
755*1708Sstevel 			}
756*1708Sstevel 
757*1708Sstevel 			if (pkt->inbuflen > 0) {
758*1708Sstevel 				if (*pkt->inbuf == SYNC_CHAR)
759*1708Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
760*1708Sstevel 				else if (*pkt->inbuf == ESC_CHAR)
761*1708Sstevel 					pkt->rx_state = WAITING_FOR_SYNC_ESC;
762*1708Sstevel 			}
763*1708Sstevel 			break;
764*1708Sstevel 
765*1708Sstevel 		case WAITING_FOR_SYNC_ESC:
766*1708Sstevel 			pkt->inbuf++;
767*1708Sstevel 			pkt->inbuflen--;
768*1708Sstevel 			pkt->rx_state = WAITING_FOR_SYNC;
769*1708Sstevel 			break;
770*1708Sstevel 
771*1708Sstevel 		case WAITING_FOR_HDR:
772*1708Sstevel 			while ((pkt->inbuflen > 0) &&
773*1708Sstevel 			    (*pkt->inbuf == SYNC_CHAR)) {
774*1708Sstevel 				pkt->inbuf++;
775*1708Sstevel 				pkt->inbuflen--;
776*1708Sstevel 			}
777*1708Sstevel 
778*1708Sstevel 			if (pkt->inbuflen <= 0)
779*1708Sstevel 				break;
780*1708Sstevel 
781*1708Sstevel 			if (*pkt->inbuf == ESC_CHAR) {
782*1708Sstevel 				/*
783*1708Sstevel 				 * ESC as first char of header?
784*1708Sstevel 				 * Impossible - start over!
785*1708Sstevel 				 */
786*1708Sstevel 				pkt->rx_state = WAITING_FOR_SYNC;
787*1708Sstevel 				pkt->inbuf++;
788*1708Sstevel 				pkt->inbuflen--;
789*1708Sstevel 				break;
790*1708Sstevel 			}
791*1708Sstevel 
792*1708Sstevel 			/* Get a buffer for this message. */
793*1708Sstevel 			pkt->buf = dp_get_buffer(rcs, DP_RX_BUFFER);
794*1708Sstevel 			if (pkt->buf == NULL) {
795*1708Sstevel 				/* Out of buffers - drop this msg. */
796*1708Sstevel 				pkt->rx_state = WAITING_FOR_SYNC;
797*1708Sstevel 				break;
798*1708Sstevel 			}
799*1708Sstevel 			DPRINTF(rcs, DPKT, (CE_CONT, "drecv first char %x\n",
800*1708Sstevel 			    (uchar_t)*pkt->inbuf));
801*1708Sstevel 
802*1708Sstevel 			pkt->buf[1] = *pkt->inbuf;
803*1708Sstevel 			pkt->bufpos = 2;
804*1708Sstevel 			pkt->rx_state = RECEIVING_HDR;
805*1708Sstevel 
806*1708Sstevel 			pkt->inbuf++;
807*1708Sstevel 			pkt->inbuflen--;
808*1708Sstevel 			break;
809*1708Sstevel 
810*1708Sstevel 		case RECEIVING_HDR:
811*1708Sstevel 			quit = 0;
812*1708Sstevel 			while ((pkt->inbuflen > 0) &&
813*1708Sstevel 			    (*pkt->inbuf != SYNC_CHAR) &&
814*1708Sstevel 			    (*pkt->inbuf != ESC_CHAR)) {
815*1708Sstevel 				pkt->buf[pkt->bufpos++] = *pkt->inbuf;
816*1708Sstevel 				pkt->inbuf++;
817*1708Sstevel 				pkt->inbuflen--;
818*1708Sstevel 				if (pkt->bufpos >= sizeof (dp_header_t)) {
819*1708Sstevel 					dp_got_full_hdr(rcs, pkt);
820*1708Sstevel 					quit = 1;
821*1708Sstevel 					break;
822*1708Sstevel 				} else if ((pkt->bufpos >= sizeof (bp_msg_t)) &&
823*1708Sstevel 				    (IS_BOOT_MSG(pkt->buf[1]))) {
824*1708Sstevel 					dp_got_bp_msg(rcs, pkt);
825*1708Sstevel 					quit = 1;
826*1708Sstevel 					break;
827*1708Sstevel 				}
828*1708Sstevel 			}
829*1708Sstevel 
830*1708Sstevel 			if (quit)
831*1708Sstevel 				break;
832*1708Sstevel 
833*1708Sstevel 			if (pkt->inbuflen > 0) {
834*1708Sstevel 				/* Must have gotten an ESC_CHAR or SYNC_CHAR. */
835*1708Sstevel 				if (*pkt->inbuf == SYNC_CHAR) {
836*1708Sstevel 
837*1708Sstevel 					DPRINTF(rcs, DPKT,
838*1708Sstevel 						(CE_CONT, "drecv sync in hdr, "
839*1708Sstevel 						"bufpos=%d\n", pkt->bufpos));
840*1708Sstevel 
841*1708Sstevel 					dp_release_buffer(rcs, DP_RX_BUFFER);
842*1708Sstevel 					pkt->buf = NULL;
843*1708Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
844*1708Sstevel 				} else {
845*1708Sstevel 					pkt->rx_state = RECEIVING_HDR_ESC;
846*1708Sstevel 				}
847*1708Sstevel 				pkt->inbuf++;
848*1708Sstevel 				pkt->inbuflen--;
849*1708Sstevel 			}
850*1708Sstevel 			break;
851*1708Sstevel 
852*1708Sstevel 		case RECEIVING_HDR_ESC:
853*1708Sstevel 			pkt->buf[pkt->bufpos++] = *pkt->inbuf;
854*1708Sstevel 			pkt->inbuf++;
855*1708Sstevel 			pkt->inbuflen--;
856*1708Sstevel 			if (pkt->bufpos >= sizeof (dp_header_t)) {
857*1708Sstevel 				dp_got_full_hdr(rcs, pkt);
858*1708Sstevel 			} else if ((pkt->bufpos >= sizeof (bp_msg_t)) &&
859*1708Sstevel 			    (IS_BOOT_MSG(pkt->buf[1]))) {
860*1708Sstevel 				dp_got_bp_msg(rcs, pkt);
861*1708Sstevel 			} else {
862*1708Sstevel 				pkt->rx_state = RECEIVING_HDR;
863*1708Sstevel 			}
864*1708Sstevel 			break;
865*1708Sstevel 
866*1708Sstevel 		case RECEIVING_BODY:
867*1708Sstevel 			max = pkt->full_length - pkt->bufpos;
868*1708Sstevel 			if (max > pkt->inbuflen)
869*1708Sstevel 				max = pkt->inbuflen;
870*1708Sstevel 
871*1708Sstevel 			for (count = 0; count < max; count++)
872*1708Sstevel 				if ((pkt->inbuf[count] == SYNC_CHAR) ||
873*1708Sstevel 				    (pkt->inbuf[count] == ESC_CHAR))
874*1708Sstevel 					break;
875*1708Sstevel 
876*1708Sstevel 			if (count > 0) {
877*1708Sstevel 				bcopy(pkt->inbuf, pkt->buf + pkt->bufpos,
878*1708Sstevel 				    count);
879*1708Sstevel 				pkt->inbuf += count;
880*1708Sstevel 				pkt->inbuflen -= count;
881*1708Sstevel 				pkt->bufpos += count;
882*1708Sstevel 
883*1708Sstevel 				if (pkt->bufpos >= pkt->full_length) {
884*1708Sstevel 					dp_got_full_msg(rcs, pkt);
885*1708Sstevel 					break;
886*1708Sstevel 				}
887*1708Sstevel 			}
888*1708Sstevel 
889*1708Sstevel 			if (count < max) {
890*1708Sstevel 				/* Must have gotten an ESC_CHAR or SYNC_CHAR. */
891*1708Sstevel 				if (*pkt->inbuf == SYNC_CHAR) {
892*1708Sstevel 					dp_release_buffer(rcs, DP_RX_BUFFER);
893*1708Sstevel 					pkt->buf = NULL;
894*1708Sstevel 					pkt->rx_state = WAITING_FOR_HDR;
895*1708Sstevel 				} else {
896*1708Sstevel 					pkt->rx_state = RECEIVING_BODY_ESC;
897*1708Sstevel 				}
898*1708Sstevel 				pkt->inbuf++;
899*1708Sstevel 				pkt->inbuflen--;
900*1708Sstevel 			}
901*1708Sstevel 			break;
902*1708Sstevel 
903*1708Sstevel 		case RECEIVING_BODY_ESC:
904*1708Sstevel 			pkt->buf[pkt->bufpos] = *pkt->inbuf;
905*1708Sstevel 			pkt->inbuf++;
906*1708Sstevel 			pkt->inbuflen--;
907*1708Sstevel 			pkt->bufpos++;
908*1708Sstevel 			if (pkt->bufpos >= pkt->full_length) {
909*1708Sstevel 				dp_got_full_msg(rcs, pkt);
910*1708Sstevel 			} else {
911*1708Sstevel 				pkt->rx_state = RECEIVING_BODY;
912*1708Sstevel 			}
913*1708Sstevel 			break;
914*1708Sstevel 		}
915*1708Sstevel 	}
916*1708Sstevel }
917*1708Sstevel 
918*1708Sstevel /*
919*1708Sstevel  * Handle an incoming message. CRCs have been already checked so message
920*1708Sstevel  * is good. check if sequence numbers are ok.
921*1708Sstevel  * Handles: control message, asynchronous notification, reply to requests
922*1708Sstevel  * and notify the leaf driver of those events.
923*1708Sstevel  * (it must have the dp_mutex)
924*1708Sstevel  */
925*1708Sstevel void
926*1708Sstevel rmc_comm_dp_mrecv(struct rmc_comm_state *rcs, uint8_t *buf)
927*1708Sstevel {
928*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
929*1708Sstevel 	dp_header_t *dp_msgp;
930*1708Sstevel 	uint8_t *datap;
931*1708Sstevel 	int datalen;
932*1708Sstevel 	dp_msg_intr_t *dmi = &dps->msg_intr;
933*1708Sstevel 	dp_req_resp_t *drr = &dps->req_resp;
934*1708Sstevel 
935*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
936*1708Sstevel 
937*1708Sstevel 	dp_msgp = (dp_header_t *)buf;
938*1708Sstevel 
939*1708Sstevel 	datalen = dp_msgp->length -
940*1708Sstevel 	    (sizeof (dp_header_t) - sizeof (dp_msgp->pad));
941*1708Sstevel 
942*1708Sstevel 	if (datalen > 0) {
943*1708Sstevel 		datalen = datalen - sizeof (uint16_t); /* don't count msg CRC */
944*1708Sstevel 		datap = buf + sizeof (dp_header_t);
945*1708Sstevel 	} else {
946*1708Sstevel 		datap = NULL;
947*1708Sstevel 	}
948*1708Sstevel 
949*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT,
950*1708Sstevel 	    "[t%03dr%03d] mrecv msgtype: %02x, len=%d\n",
951*1708Sstevel 	    dp_msgp->txnum, dp_msgp->rxnum, dp_msgp->type, datalen));
952*1708Sstevel 
953*1708Sstevel 	/*
954*1708Sstevel 	 * Handle control messages first
955*1708Sstevel 	 */
956*1708Sstevel 	if (IS_UNNUMBERED_MSG(dp_msgp->type)) {
957*1708Sstevel 		switch (dp_msgp->type) {
958*1708Sstevel 		case DP_CTL_START:
959*1708Sstevel 			/*
960*1708Sstevel 			 * CTL:start
961*1708Sstevel 			 * Re-init protocol processing.
962*1708Sstevel 			 * Enable data link
963*1708Sstevel 			 * Stop data link setup timer if running
964*1708Sstevel 			 */
965*1708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT, "mrecv data link ok\n"));
966*1708Sstevel 
967*1708Sstevel 			dp_reset(rcs, dp_msgp->txnum, 1, 0);
968*1708Sstevel 
969*1708Sstevel 			dp_wake_up_waiter(rcs, 0);
970*1708Sstevel 
971*1708Sstevel 			/* Send CTL:stack message. */
972*1708Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_STACK);
973*1708Sstevel 
974*1708Sstevel 			dps->start_cnt++;
975*1708Sstevel 
976*1708Sstevel 			dp_enable_data_link(rcs);
977*1708Sstevel 
978*1708Sstevel 			break;
979*1708Sstevel 
980*1708Sstevel 		case DP_CTL_STACK:
981*1708Sstevel 			/*
982*1708Sstevel 			 * CTL:stack
983*1708Sstevel 			 * Enable data link
984*1708Sstevel 			 * Stop data link setup timer if running
985*1708Sstevel 			 */
986*1708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT, "mrecv data link ok\n"));
987*1708Sstevel 
988*1708Sstevel 			dp_reset(rcs, dp_msgp->txnum, 0, 0);
989*1708Sstevel 
990*1708Sstevel 			dp_wake_up_waiter(rcs, 0);
991*1708Sstevel 
992*1708Sstevel 			dps->stack_cnt++;
993*1708Sstevel 
994*1708Sstevel 			dp_enable_data_link(rcs);
995*1708Sstevel 			break;
996*1708Sstevel 
997*1708Sstevel 		case DP_CTL_RESPOND:
998*1708Sstevel 			/*
999*1708Sstevel 			 * CTL:respond (heartbeat)
1000*1708Sstevel 			 * Send a CTL:ack.
1001*1708Sstevel 			 */
1002*1708Sstevel 			if (dps->data_link_ok) {
1003*1708Sstevel 				(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_ACK);
1004*1708Sstevel 			}
1005*1708Sstevel 			break;
1006*1708Sstevel 
1007*1708Sstevel 		case DP_CTL_ACK:
1008*1708Sstevel 			/*
1009*1708Sstevel 			 * CTL:ack
1010*1708Sstevel 			 * Call a transmit-side routine to handle it.
1011*1708Sstevel 			 */
1012*1708Sstevel 			dp_tx_handle_ack(rcs, dp_msgp->rxnum);
1013*1708Sstevel 			break;
1014*1708Sstevel 
1015*1708Sstevel 		case DP_CTL_NAK:
1016*1708Sstevel 			/*
1017*1708Sstevel 			 * CTL:nak
1018*1708Sstevel 			 * Call a transmit-side routine to handle it.
1019*1708Sstevel 			 */
1020*1708Sstevel 			dp_tx_handle_nak(rcs, dp_msgp->rxnum);
1021*1708Sstevel 			break;
1022*1708Sstevel 
1023*1708Sstevel 		default:
1024*1708Sstevel 			/* Drop message. */
1025*1708Sstevel 			DPRINTF(rcs, DPRO,
1026*1708Sstevel 			    (CE_CONT, "mrecv unknown ctrlmsg\n"));
1027*1708Sstevel 			break;
1028*1708Sstevel 		}
1029*1708Sstevel 		return;
1030*1708Sstevel 	}
1031*1708Sstevel 
1032*1708Sstevel 	/*
1033*1708Sstevel 	 * Before processing the received message (NUMBERED), check that the
1034*1708Sstevel 	 * data link protocol is up. If not, ignore this message
1035*1708Sstevel 	 */
1036*1708Sstevel 	if (!dps->data_link_ok) {
1037*1708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "mrecv drop msg: no data link\n"));
1038*1708Sstevel 		return;
1039*1708Sstevel 	}
1040*1708Sstevel 
1041*1708Sstevel 	/*
1042*1708Sstevel 	 * we received a message (NUMBERED) and data link is ok.
1043*1708Sstevel 	 * First, instead of ACKing this message now, we delay it. The reason
1044*1708Sstevel 	 * why is that a message can be sent (from this side) in the meantime
1045*1708Sstevel 	 * and it can ACK the received message (it will spare us to send
1046*1708Sstevel 	 * the ACK message across the wire).
1047*1708Sstevel 	 */
1048*1708Sstevel 
1049*1708Sstevel 	/*
1050*1708Sstevel 	 * Handle acknowledgements even if this is a duplicate message.
1051*1708Sstevel 	 */
1052*1708Sstevel 	if (dps->timer_delay_ack == (timeout_id_t)0) {
1053*1708Sstevel 		dps->timer_delay_ack = timeout(dp_delay_ack_tohandler,
1054*1708Sstevel 		    (void *) rcs, drv_usectohz(TX_RETRY_TIME/2 * 1000));
1055*1708Sstevel 		DPRINTF(rcs, DGEN, (CE_CONT, "mrecv start ack t/o %p\n",
1056*1708Sstevel 		    dps->timer_delay_ack));
1057*1708Sstevel 	}
1058*1708Sstevel 	dp_tx_handle_ack(rcs, dp_msgp->rxnum);
1059*1708Sstevel 
1060*1708Sstevel 	if (dp_msgp->txnum != NEXT_SEQID(dps->last_rx_seqid)) {
1061*1708Sstevel 		/* Duplicate message - free it up & return. */
1062*1708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT, "mrecv dup msg txnum=%03d\n",
1063*1708Sstevel 		    dp_msgp->txnum));
1064*1708Sstevel 		return;
1065*1708Sstevel 	}
1066*1708Sstevel 	dps->last_rx_seqid = dp_msgp->txnum;
1067*1708Sstevel 
1068*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
1069*1708Sstevel 
1070*1708Sstevel 	if ((erri_test_number == ERRI_SEND_CTL_STACK ||
1071*1708Sstevel 	    erri_test_number == ERRI_SEND_CTL_START) &&
1072*1708Sstevel 	    erri_test_repeat >= 0 &&
1073*1708Sstevel 	    erri_test_count++ > 0 && !(erri_test_count % erri_test_intrvl)) {
1074*1708Sstevel 
1075*1708Sstevel 		if (erri_test_number == ERRI_SEND_CTL_STACK) {
1076*1708Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_STACK);
1077*1708Sstevel 
1078*1708Sstevel 		} else if (erri_test_number == ERRI_SEND_CTL_START) {
1079*1708Sstevel 			(void) rmc_comm_dp_ctlsend(rcs, DP_CTL_START);
1080*1708Sstevel 
1081*1708Sstevel 		}
1082*1708Sstevel 		if (erri_test_repeat == 0)
1083*1708Sstevel 			erri_test_repeat--; /* will not repeat the test */
1084*1708Sstevel 	}
1085*1708Sstevel 
1086*1708Sstevel #endif
1087*1708Sstevel 
1088*1708Sstevel 	/*
1089*1708Sstevel 	 * At this point, we know this is a good message.  We've
1090*1708Sstevel 	 * checked checksums, message types, and sequence id's.
1091*1708Sstevel 	 */
1092*1708Sstevel 
1093*1708Sstevel 	/*
1094*1708Sstevel 	 * First, check if a driver has register for this message
1095*1708Sstevel 	 * Second, check if this message is a reply to a request
1096*1708Sstevel 	 * Third, check to see if ALOM is telling us it doesn't
1097*1708Sstevel 	 * know about the command code.
1098*1708Sstevel 	 */
1099*1708Sstevel 
1100*1708Sstevel 	if (dmi->intr_handler != NULL &&
1101*1708Sstevel 	    dmi->intr_msg_type == dp_msgp->type) {
1102*1708Sstevel 
1103*1708Sstevel 		rmc_comm_msg_t 	*msgi = (rmc_comm_msg_t *)dmi->intr_arg;
1104*1708Sstevel 
1105*1708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT,
1106*1708Sstevel 		    "mrecv process async msg len=%d, max=%d\n",
1107*1708Sstevel 		    datalen, msgi->msg_len));
1108*1708Sstevel 		/*
1109*1708Sstevel 		 * process asynchronous notification only if the registered
1110*1708Sstevel 		 * driver is not currently processing any other notification
1111*1708Sstevel 		 */
1112*1708Sstevel 		mutex_enter(dmi->intr_lock);
1113*1708Sstevel 		if (dmi->intr_state == NULL ||
1114*1708Sstevel 		    (dmi->intr_state != NULL &&
1115*1708Sstevel 		    *(dmi->intr_state) == RMC_COMM_INTR_IDLE)) {
1116*1708Sstevel 			/*
1117*1708Sstevel 			 * check that the buffer is big enough. do not want to
1118*1708Sstevel 			 * cross boundaries here..
1119*1708Sstevel 			 */
1120*1708Sstevel 			if (datalen <= msgi->msg_len) {
1121*1708Sstevel 				bcopy(datap, msgi->msg_buf, datalen);
1122*1708Sstevel 				msgi->msg_bytes = datalen;
1123*1708Sstevel 
1124*1708Sstevel 			} else {
1125*1708Sstevel 				msgi->msg_bytes = -1;
1126*1708Sstevel 			}
1127*1708Sstevel 			/*
1128*1708Sstevel 			 * trigger soft intr. in any case.
1129*1708Sstevel 			 * if message is too big, at least, the leaf driver
1130*1708Sstevel 			 * will be notified (bytes returned will be -1)
1131*1708Sstevel 			 */
1132*1708Sstevel 			ddi_trigger_softintr(dmi->intr_id);
1133*1708Sstevel 		}
1134*1708Sstevel 		mutex_exit(dmi->intr_lock);
1135*1708Sstevel 
1136*1708Sstevel 	} else if ((drr->flags & MSG_SENT) != 0 &&
1137*1708Sstevel 	    drr->response.msg_type == dp_msgp->type) {
1138*1708Sstevel 
1139*1708Sstevel 		DPRINTF(rcs, DPRO, (CE_CONT,
1140*1708Sstevel 		    "mrecv process reply len=%d, max=%d\n",
1141*1708Sstevel 		    datalen, drr->response.msg_bufsiz));
1142*1708Sstevel 
1143*1708Sstevel 		/*
1144*1708Sstevel 		 * check that the recv buffer is big enough.
1145*1708Sstevel 		 */
1146*1708Sstevel 		if (datalen <= drr->response.msg_bufsiz) {
1147*1708Sstevel 			bcopy(datap, drr->response.msg_buf, datalen);
1148*1708Sstevel 			drr->response.msg_msglen = datalen;
1149*1708Sstevel 			dp_wake_up_waiter(rcs, MSG_REPLY_RXED);
1150*1708Sstevel 		} else {
1151*1708Sstevel 			drr->response.msg_msglen = -1;
1152*1708Sstevel 			dp_wake_up_waiter(rcs, MSG_REPLY_RXED);
1153*1708Sstevel 		}
1154*1708Sstevel 	} else if (dp_msgp->type == DP_INVCMD &&
1155*1708Sstevel 	    (drr->flags & MSG_SENT) != 0 &&
1156*1708Sstevel 	    ((dp_invcmd_t *)datap)->inv_type == drr->request.msg_type) {
1157*1708Sstevel 		drr->error_status = RCEINVCMD;
1158*1708Sstevel 		dp_wake_up_waiter(rcs, MSG_ERROR);
1159*1708Sstevel 	}
1160*1708Sstevel }
1161*1708Sstevel 
1162*1708Sstevel /*
1163*1708Sstevel  * to send a control message (unnumbered message)
1164*1708Sstevel  * (it must have the dp_mutex)
1165*1708Sstevel  */
1166*1708Sstevel int
1167*1708Sstevel rmc_comm_dp_ctlsend(struct rmc_comm_state *rcs, uint8_t type)
1168*1708Sstevel {
1169*1708Sstevel 	dp_message_t ctlmsg;
1170*1708Sstevel 	int err = RCNOERR;
1171*1708Sstevel 
1172*1708Sstevel 	ctlmsg.msg_type = type;
1173*1708Sstevel 	ctlmsg.msg_buf = NULL;
1174*1708Sstevel 	ctlmsg.msg_msglen = 0;
1175*1708Sstevel 
1176*1708Sstevel 	err = rmc_comm_dp_msend(rcs, &ctlmsg);
1177*1708Sstevel 
1178*1708Sstevel 	return (err);
1179*1708Sstevel }
1180*1708Sstevel 
1181*1708Sstevel /*
1182*1708Sstevel  * to send data to the remote party.
1183*1708Sstevel  *
1184*1708Sstevel  * NUMBERED messages carry payload data of variable size. A buffer is allocated
1185*1708Sstevel  * dynamically for the trasmission of data. NUMBERED message trasmission
1186*1708Sstevel  * data status is stored in the dp_state request_response data structure.
1187*1708Sstevel  * This because: data sent must be acknowledged, trasmission can be re-tried,
1188*1708Sstevel  * upper layer has to know the state/result of the trasmission. Upper layer has
1189*1708Sstevel  * to: initialize the data struct, send data (this function), read result,
1190*1708Sstevel  * clean up the data struct.
1191*1708Sstevel  *
1192*1708Sstevel  * UNUMBERED data are just only control command which do not carry any payload
1193*1708Sstevel  * A local buffer is used (ctlbuf) instead. UNNUMBERED message are transient
1194*1708Sstevel  * data which is sent once and not re-tried. It does not use the
1195*1708Sstevel  * request_response data structure
1196*1708Sstevel  *
1197*1708Sstevel  * (it must have the dp_mutex)
1198*1708Sstevel  */
1199*1708Sstevel int
1200*1708Sstevel rmc_comm_dp_msend(struct rmc_comm_state *rcs, dp_message_t *req)
1201*1708Sstevel {
1202*1708Sstevel 	rmc_comm_dp_state_t 	*dps = &rcs->dp_state;
1203*1708Sstevel 	dp_req_resp_t		*drr = &dps->req_resp;
1204*1708Sstevel 	dp_message_t		*pkt;
1205*1708Sstevel 	dp_header_t		*dp_msgp;
1206*1708Sstevel 	dp_message_t		 ctl;
1207*1708Sstevel 	dp_header_t		 ctlbuf;
1208*1708Sstevel 	uint16_t		 data_crc;
1209*1708Sstevel 	timeout_id_t		 timer_delay_ack = 0;
1210*1708Sstevel 	char			 first_time = 0;
1211*1708Sstevel 
1212*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
1213*1708Sstevel 
1214*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "msend msgtype=%02x\n", req->msg_type));
1215*1708Sstevel 
1216*1708Sstevel 	if (IS_NUMBERED_MSG(req->msg_type)) {
1217*1708Sstevel 		/*
1218*1708Sstevel 		 * if there was an error, just return the error.
1219*1708Sstevel 		 * Otherwise if the message was already acknowledged
1220*1708Sstevel 		 * (NUMBERED message) then, there is no need to (re)send it.
1221*1708Sstevel 		 * just wait for an expected reply (hence, do not return an
1222*1708Sstevel 		 * error)
1223*1708Sstevel 		 */
1224*1708Sstevel 		if ((drr->flags & MSG_ERROR) != 0) {
1225*1708Sstevel 
1226*1708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
1227*1708Sstevel 			    "msg send error flag=%02x\n", drr->flags));
1228*1708Sstevel 			return (RCEGENERIC);
1229*1708Sstevel 
1230*1708Sstevel 		} else if ((drr->flags & MSG_ACKED) != 0) {
1231*1708Sstevel 
1232*1708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
1233*1708Sstevel 			    "msg already ACKed flag=%02x\n", drr->flags));
1234*1708Sstevel 			return (RCNOERR);
1235*1708Sstevel 
1236*1708Sstevel 		} else if ((drr->flags & MSG_SENT) == 0) {
1237*1708Sstevel 
1238*1708Sstevel 			first_time = 1;
1239*1708Sstevel 		}
1240*1708Sstevel 
1241*1708Sstevel 		/*
1242*1708Sstevel 		 * everything is ok. Now check that the data protocol is up
1243*1708Sstevel 		 * and running: messages cannot be sent if the link is down.
1244*1708Sstevel 		 */
1245*1708Sstevel 		if (!dps->data_link_ok) {
1246*1708Sstevel 			DPRINTF(rcs, DPRO, (CE_CONT,
1247*1708Sstevel 			    "msend: can't send msg - no data link\n"));
1248*1708Sstevel 
1249*1708Sstevel 			/*
1250*1708Sstevel 			 * do not return error, since it can be retried
1251*1708Sstevel 			 * later (hoping that the data link will come
1252*1708Sstevel 			 * up, in the meantime)
1253*1708Sstevel 			 */
1254*1708Sstevel 			return (RCNOERR);
1255*1708Sstevel 
1256*1708Sstevel 		}
1257*1708Sstevel 	} else {
1258*1708Sstevel 		first_time = 1;
1259*1708Sstevel 	}
1260*1708Sstevel 
1261*1708Sstevel 	/*
1262*1708Sstevel 	 * if the message has never been sent (and, hence, it is the first
1263*1708Sstevel 	 * time), then prepare the protocol packet: allocate a buffer,
1264*1708Sstevel 	 * create the message header, copy the message body into the buffer and
1265*1708Sstevel 	 * calculate CRCs
1266*1708Sstevel 	 */
1267*1708Sstevel 	if (first_time) {
1268*1708Sstevel 
1269*1708Sstevel 		if (IS_NUMBERED_MSG(req->msg_type)) {
1270*1708Sstevel 
1271*1708Sstevel 			drr->retries_left = TX_RETRIES;
1272*1708Sstevel 
1273*1708Sstevel 			/*
1274*1708Sstevel 			 * Check length of the message.
1275*1708Sstevel 			 */
1276*1708Sstevel 			if (req->msg_msglen > DP_MAX_MSGLEN) {
1277*1708Sstevel 				DPRINTF(rcs, DPRO,
1278*1708Sstevel 				    (CE_CONT, "msend err: msg too big\n"));
1279*1708Sstevel 				return (RCEGENERIC);
1280*1708Sstevel 			}
1281*1708Sstevel 
1282*1708Sstevel 			pkt = &drr->request;
1283*1708Sstevel 
1284*1708Sstevel 			/*
1285*1708Sstevel 			 * check that the message buffer is not already
1286*1708Sstevel 			 * in use (race condition). If so, return error
1287*1708Sstevel 			 */
1288*1708Sstevel 			if (pkt->msg_buf != NULL) {
1289*1708Sstevel 				DPRINTF(rcs, DPRO, (CE_CONT,
1290*1708Sstevel 				    "msend err: buf already in use\n"));
1291*1708Sstevel 				return (RCENOMEM);
1292*1708Sstevel 			}
1293*1708Sstevel 
1294*1708Sstevel 			/*
1295*1708Sstevel 			 * allocate a buffer for the protocol packet
1296*1708Sstevel 			 */
1297*1708Sstevel 			if ((pkt->msg_buf = dp_get_buffer(rcs,
1298*1708Sstevel 			    DP_TX_BUFFER)) == NULL) {
1299*1708Sstevel 				DPRINTF(rcs, DPRO, (CE_CONT,
1300*1708Sstevel 				    "msend err: no mem\n"));
1301*1708Sstevel 				return (RCENOMEM);
1302*1708Sstevel 			}
1303*1708Sstevel 			pkt->msg_bufsiz = DP_BUFFER_SIZE;
1304*1708Sstevel 
1305*1708Sstevel 			/*
1306*1708Sstevel 			 * increment tx sequence number if sending a NUMBERED
1307*1708Sstevel 			 * message
1308*1708Sstevel 			 */
1309*1708Sstevel 			dps->last_tx_seqid = NEXT_SEQID(dps->last_tx_seqid);
1310*1708Sstevel 		} else {
1311*1708Sstevel 			/*
1312*1708Sstevel 			 * UNUMBERED messages (or control messages) do not
1313*1708Sstevel 			 * carry any data and, hence, have a 'small' fixed size
1314*1708Sstevel 			 * (the size of the header). In this case,
1315*1708Sstevel 			 * a 'local' buffer (ctlbuf) is used.
1316*1708Sstevel 			 */
1317*1708Sstevel 			pkt = &ctl;
1318*1708Sstevel 			pkt->msg_buf = (uint8_t *)&ctlbuf;
1319*1708Sstevel 			pkt->msg_bufsiz = sizeof (dp_header_t);
1320*1708Sstevel 		}
1321*1708Sstevel 
1322*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
1323*1708Sstevel 
1324*1708Sstevel 		if (((erri_test_number == ERRI_RX_SEQ_NUMBER &&
1325*1708Sstevel 		    IS_NUMBERED_MSG(req->msg_type)) ||
1326*1708Sstevel 		    (erri_test_number == ERRI_CTL_RX_SEQ_NUMBER &&
1327*1708Sstevel 		    IS_UNNUMBERED_MSG(req->msg_type))) &&
1328*1708Sstevel 		    erri_test_repeat >= 0 &&
1329*1708Sstevel 		    erri_test_count++ > 0 &&
1330*1708Sstevel 		    !(erri_test_count % erri_test_intrvl)) {
1331*1708Sstevel 
1332*1708Sstevel 			dps->last_rx_seqid--;
1333*1708Sstevel 
1334*1708Sstevel 			if (erri_test_repeat == 0)
1335*1708Sstevel 				erri_test_repeat--; /* will not repeat it */
1336*1708Sstevel 		}
1337*1708Sstevel #endif
1338*1708Sstevel 
1339*1708Sstevel 		/*
1340*1708Sstevel 		 * create the protocol packet
1341*1708Sstevel 		 */
1342*1708Sstevel 		pkt->msg_type = req->msg_type;
1343*1708Sstevel 
1344*1708Sstevel 		/*
1345*1708Sstevel 		 * length of the packet (including pad bytes)
1346*1708Sstevel 		 */
1347*1708Sstevel 		pkt->msg_msglen = req->msg_msglen + sizeof (dp_header_t);
1348*1708Sstevel 
1349*1708Sstevel 		/*
1350*1708Sstevel 		 * message header:
1351*1708Sstevel 		 *  set the message type
1352*1708Sstevel 		 *  set the length of the message (excluding pad bytes)
1353*1708Sstevel 		 *  set tx/rx sequence numbers
1354*1708Sstevel 		 *  calculate CRC
1355*1708Sstevel 		 */
1356*1708Sstevel 		dp_msgp = (dp_header_t *)pkt->msg_buf;
1357*1708Sstevel 		dp_msgp->type = pkt->msg_type;
1358*1708Sstevel 
1359*1708Sstevel 		if (req->msg_msglen == 0)
1360*1708Sstevel 			dp_msgp->length = pkt->msg_msglen -
1361*1708Sstevel 			    sizeof (dp_msgp->pad);
1362*1708Sstevel 		else
1363*1708Sstevel 			dp_msgp->length = sizeof (data_crc) +
1364*1708Sstevel 			    pkt->msg_msglen - sizeof (dp_msgp->pad);
1365*1708Sstevel 
1366*1708Sstevel 		dp_msgp->txnum = dps->last_tx_seqid;
1367*1708Sstevel 		dp_msgp->rxnum = dps->last_rx_seqid;
1368*1708Sstevel 
1369*1708Sstevel 		dp_msgp->crc = dp_calc_crc16(pkt->msg_buf +
1370*1708Sstevel 		    sizeof (dp_msgp->pad), sizeof (dp_header_t) -
1371*1708Sstevel 		    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
1372*1708Sstevel 
1373*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
1374*1708Sstevel 
1375*1708Sstevel 		if (((erri_test_number == ERRI_CRC_HEADER &&
1376*1708Sstevel 		    IS_NUMBERED_MSG(pkt->msg_type)) ||
1377*1708Sstevel 		    (erri_test_number == ERRI_CTL_CRC_HEADER &&
1378*1708Sstevel 		    IS_UNNUMBERED_MSG(pkt->msg_type))) &&
1379*1708Sstevel 		    erri_test_repeat >= 0 &&
1380*1708Sstevel 		    erri_test_count++ > 0 &&
1381*1708Sstevel 		    !(erri_test_count % erri_test_intrvl)) {
1382*1708Sstevel 
1383*1708Sstevel 			dp_msgp->crc = dp_msgp->crc/2;
1384*1708Sstevel 			if (erri_test_repeat == 0)
1385*1708Sstevel 				erri_test_repeat--; /* will not repeat it */
1386*1708Sstevel 		}
1387*1708Sstevel #endif
1388*1708Sstevel 
1389*1708Sstevel 		/*
1390*1708Sstevel 		 * copy message body (if present) into the buffer
1391*1708Sstevel 		 * and calculate message CRC
1392*1708Sstevel 		 */
1393*1708Sstevel 		if (req->msg_msglen > 0) {
1394*1708Sstevel 			bcopy(req->msg_buf, pkt->msg_buf + sizeof (dp_header_t),
1395*1708Sstevel 			    req->msg_msglen);
1396*1708Sstevel 			data_crc = dp_calc_crc16(pkt->msg_buf +
1397*1708Sstevel 			    sizeof (dp_header_t),
1398*1708Sstevel 			    req->msg_msglen);
1399*1708Sstevel 
1400*1708Sstevel #ifdef DEBUG_ERROR_INJECTION
1401*1708Sstevel 
1402*1708Sstevel 			if (erri_test_number == ERRI_CRC_MSG &&
1403*1708Sstevel 			    erri_test_repeat >= 0 &&
1404*1708Sstevel 			    erri_test_count++ > 0 &&
1405*1708Sstevel 			    !(erri_test_count % erri_test_intrvl)) {
1406*1708Sstevel 
1407*1708Sstevel 				data_crc = data_crc/2;
1408*1708Sstevel 				if (erri_test_repeat == 0)
1409*1708Sstevel 					erri_test_repeat--;
1410*1708Sstevel 			}
1411*1708Sstevel #endif
1412*1708Sstevel 			bcopy((void *) &data_crc,
1413*1708Sstevel 			    pkt->msg_buf + (sizeof (dp_header_t) +
1414*1708Sstevel 			    req->msg_msglen),
1415*1708Sstevel 			    sizeof (data_crc));
1416*1708Sstevel 		}
1417*1708Sstevel 	} else {
1418*1708Sstevel 		/*
1419*1708Sstevel 		 * message has already been sent (and packetized).
1420*1708Sstevel 		 * get the message packet from the request/response
1421*1708Sstevel 		 * data structure
1422*1708Sstevel 		 */
1423*1708Sstevel 		pkt = &drr->request;
1424*1708Sstevel 		dp_msgp = (dp_header_t *)pkt->msg_buf;
1425*1708Sstevel 		dps->retries_cnt++;
1426*1708Sstevel 	}
1427*1708Sstevel 
1428*1708Sstevel 	/*
1429*1708Sstevel 	 *  NUMBERED messages
1430*1708Sstevel 	 */
1431*1708Sstevel 	if (IS_NUMBERED_MSG(pkt->msg_type)) {
1432*1708Sstevel 
1433*1708Sstevel 		/*
1434*1708Sstevel 		 * check that we have not exceeded the maximum number of
1435*1708Sstevel 		 * retries
1436*1708Sstevel 		 */
1437*1708Sstevel 		if (drr->retries_left-- <= 0) {
1438*1708Sstevel 
1439*1708Sstevel 			drr->flags |= MSG_ERROR; /* set error flag */
1440*1708Sstevel 
1441*1708Sstevel 			/*
1442*1708Sstevel 			 * restart the data protocol link
1443*1708Sstevel 			 */
1444*1708Sstevel 			dp_reset(rcs, INITIAL_SEQID, 0, 1);
1445*1708Sstevel 
1446*1708Sstevel 			return (RCEMAXRETRIES);
1447*1708Sstevel 		}
1448*1708Sstevel 
1449*1708Sstevel 		if (dps->timer_delay_ack != (timeout_id_t)0) {
1450*1708Sstevel 			/*
1451*1708Sstevel 			 * Cancel any pending acknowledgements - we're
1452*1708Sstevel 			 * going to send a message which will include
1453*1708Sstevel 			 * an acknowledgement.
1454*1708Sstevel 			 */
1455*1708Sstevel 			timer_delay_ack = dps->timer_delay_ack;
1456*1708Sstevel 
1457*1708Sstevel 			/*
1458*1708Sstevel 			 * the timer is actually removed at the end of this
1459*1708Sstevel 			 * function since I need to release the dp_mutex.
1460*1708Sstevel 			 * Instead I clear the timer variable so that the
1461*1708Sstevel 			 * timeout callback will not do any processing in the
1462*1708Sstevel 			 * meantime.
1463*1708Sstevel 			 */
1464*1708Sstevel 			dps->timer_delay_ack = 0;
1465*1708Sstevel 		}
1466*1708Sstevel 
1467*1708Sstevel 		drr->flags |= MSG_SENT;
1468*1708Sstevel 	}
1469*1708Sstevel 
1470*1708Sstevel 	/*
1471*1708Sstevel 	 * set rx sequence number (as we might have received a message in the
1472*1708Sstevel 	 * meantime). tx sequence number to be the same (we can only send one
1473*1708Sstevel 	 * message per time)
1474*1708Sstevel 	 */
1475*1708Sstevel 	if (dp_msgp->rxnum != dps->last_rx_seqid) {
1476*1708Sstevel 
1477*1708Sstevel 		dp_msgp->rxnum = dps->last_rx_seqid;
1478*1708Sstevel 
1479*1708Sstevel 		/*
1480*1708Sstevel 		 * re-calculate CRC (header)
1481*1708Sstevel 		 */
1482*1708Sstevel 		dp_msgp->crc = dp_calc_crc16(pkt->msg_buf +
1483*1708Sstevel 		    sizeof (dp_msgp->pad), sizeof (dp_header_t) -
1484*1708Sstevel 		    sizeof (dp_msgp->crc) - sizeof (dp_msgp->pad));
1485*1708Sstevel 	}
1486*1708Sstevel 
1487*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "[t%03dr%03d] msend msgtype=%02x\n",
1488*1708Sstevel 	    dp_msgp->txnum, dp_msgp->rxnum, dp_msgp->type));
1489*1708Sstevel 
1490*1708Sstevel 	/*
1491*1708Sstevel 	 * send this message
1492*1708Sstevel 	 */
1493*1708Sstevel 
1494*1708Sstevel 	dp_send_packet(rcs, pkt->msg_buf);
1495*1708Sstevel 
1496*1708Sstevel 	/*
1497*1708Sstevel 	 * remove delay ack timer (if any is running)
1498*1708Sstevel 	 * Note that the dp_mutex must be released before calling
1499*1708Sstevel 	 * untimeout. Otherwise we may have a deadlock situation.
1500*1708Sstevel 	 */
1501*1708Sstevel 	if (timer_delay_ack != 0) {
1502*1708Sstevel 		DPRINTF(rcs, DGEN, (CE_CONT, "msend remove ack timer %p\n",
1503*1708Sstevel 		    timer_delay_ack));
1504*1708Sstevel 		mutex_exit(dps->dp_mutex);
1505*1708Sstevel 		(void) untimeout(timer_delay_ack);
1506*1708Sstevel 		mutex_enter(dps->dp_mutex);
1507*1708Sstevel 	}
1508*1708Sstevel 
1509*1708Sstevel 	return (RCNOERR);
1510*1708Sstevel }
1511*1708Sstevel 
1512*1708Sstevel /*
1513*1708Sstevel  * to send a boot protocol message
1514*1708Sstevel  * (this is to support the firmware download feature)
1515*1708Sstevel  */
1516*1708Sstevel void
1517*1708Sstevel rmc_comm_bp_msend(struct rmc_comm_state *rcs, bp_msg_t *bp_msg)
1518*1708Sstevel {
1519*1708Sstevel 	char syncbuf[2];
1520*1708Sstevel 
1521*1708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
1522*1708Sstevel 
1523*1708Sstevel 	DPRINTF(rcs, DPRO, (CE_CONT, "send bp msg: %02x %02x %02x\n",
1524*1708Sstevel 	    bp_msg->cmd, bp_msg->dat1, bp_msg->dat2));
1525*1708Sstevel 
1526*1708Sstevel 	rcs->dp_state.req_resp.flags |= MSG_SENT_BP;
1527*1708Sstevel 
1528*1708Sstevel 	/* First, send out two SYNC characters. */
1529*1708Sstevel 	syncbuf[0] = syncbuf[1] = SYNC_CHAR;
1530*1708Sstevel 	rmc_comm_serdev_send(rcs, (char *)syncbuf, 2);
1531*1708Sstevel 
1532*1708Sstevel 	/* Next, send the BP message. */
1533*1708Sstevel 	rmc_comm_serdev_send(rcs, (char *)&bp_msg->cmd,
1534*1708Sstevel 	    sizeof (bp_msg_t) - sizeof (bp_msg->pad));
1535*1708Sstevel }
1536*1708Sstevel 
1537*1708Sstevel /*
1538*1708Sstevel  * to send a fw s-record
1539*1708Sstevel  * (this is to support the firmware download feature)
1540*1708Sstevel  */
1541*1708Sstevel void
1542*1708Sstevel rmc_comm_bp_srecsend(struct rmc_comm_state *rcs, char *buf, int buflen)
1543*1708Sstevel {
1544*1708Sstevel 	ASSERT(MUTEX_HELD(rcs->dp_state.dp_mutex));
1545*1708Sstevel 
1546*1708Sstevel 	rcs->dp_state.req_resp.flags |= MSG_SENT_BP;
1547*1708Sstevel 
1548*1708Sstevel 	rmc_comm_serdev_send(rcs, buf, buflen);
1549*1708Sstevel }
1550*1708Sstevel 
1551*1708Sstevel /*
1552*1708Sstevel  * clean up a request/response session
1553*1708Sstevel  * (it must have the dp_mutex)
1554*1708Sstevel  */
1555*1708Sstevel 
1556*1708Sstevel void
1557*1708Sstevel rmc_comm_dp_mcleanup(struct rmc_comm_state *rcs)
1558*1708Sstevel {
1559*1708Sstevel 	rmc_comm_dp_state_t *dps = &rcs->dp_state;
1560*1708Sstevel 	dp_req_resp_t *drr = &dps->req_resp;
1561*1708Sstevel 	dp_message_t *req = &drr->request;
1562*1708Sstevel 	dp_message_t *resp = &drr->response;
1563*1708Sstevel 
1564*1708Sstevel 	ASSERT(MUTEX_HELD(dps->dp_mutex));
1565*1708Sstevel 
1566*1708Sstevel 	DPRINTF(rcs, DGEN, (CE_CONT, "msg cleanup\n"));
1567*1708Sstevel 
1568*1708Sstevel 	/*
1569*1708Sstevel 	 * 'release' memory
1570*1708Sstevel 	 * memory is only 'dynamically allocated for NUMBERED messages
1571*1708Sstevel 	 */
1572*1708Sstevel 	if (req->msg_buf != NULL)
1573*1708Sstevel 		dp_release_buffer(rcs, DP_TX_BUFFER);
1574*1708Sstevel 
1575*1708Sstevel 	drr->flags = 0;
1576*1708Sstevel 	drr->error_status = 0;
1577*1708Sstevel 
1578*1708Sstevel 	req->msg_type = DP_NULL_MSG;
1579*1708Sstevel 	req->msg_buf = NULL;
1580*1708Sstevel 	req->msg_msglen = 0;
1581*1708Sstevel 	req->msg_bufsiz = 0;
1582*1708Sstevel 	resp->msg_type = DP_NULL_MSG;
1583*1708Sstevel 	resp->msg_buf = NULL;
1584*1708Sstevel 	resp->msg_msglen = 0;
1585*1708Sstevel 	resp->msg_bufsiz = 0;
1586*1708Sstevel }
1587