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