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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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