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