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