vnet_gen.c revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f
* The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * See the License for the specific language governing permissions * and limitations under the License. * When distributing Covered Code, include this CDDL HEADER in each * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. #
pragma ident "%Z%%M% %I% %E% SMI" * Implementation of the mac functionality for vnet using the * generic(default) transport layer of sun4v Logical Domain Channels(LDC). /* vgen proxy entry points */ /* externs - functions provided by vnet to add/remove/modify entries in fdb */ /* vgen internal functions */ /* vgen handshake functions */ * The handshake process consists of 5 phases defined below, with VH_PHASE0 * being the pre-handshake phase and VH_DONE is the phase to indicate * successful completion of all phases. * Each phase may have one to several handshake states which are required * to complete successfully to move to the next phase. * Refer to the functions vgen_handshake() and vgen_handshake_done() for 0xff,
0xff,
0xff,
0xff,
0xff,
0xff /* versions supported - in decreasing order */ /* flags to simulate error conditions for debugging */ /* MD update matching structure */ /* template for matching a particular vnet instance */ * XXX: definitions below need to be in sync with those in vnet.c * DBG_LEVEL2: Info messages * DBG_LEVEL3: Warning messages * DBG_LEVEL4: Error messages /* simulate handshake error conditions for debug */ /* debug version negotiation, need to redefine VGEN_NUM_VER */ { {
5, 0}, {
3, 0}, {
2,
1}, {
1,
2}, {
1,
1} };
* vgen_init() is called by an instance of vnet driver to initialize the * corresponding generic proxy transport layer. The arguments passed by vnet * are - an opaque pointer to the vnet instance, pointers to dev_info_t and * mac_t of the vnet device, mac address of the vnet device, and a pointer to * the mac_t of the generic transport is returned in the last argument. /* allocate multicast table */ /* register with MD event generator */ /* register mac_t of this vgen_t with vnet */ * Called by vnet to undo the initializations done by vgen_init(). * The handle provided by generic transport during vgen_init() is the argument. /* unregister with MD event generator */ /* detach all ports from the device */ /* free multicast table */ /* vgen transmit function */ /* transmit packets over the given port */ * XXX - for now, we have a single channel. /* out of tx resources, see vgen_ldcsend() for details. */ /* channel transmit function */ /* drop the packet if handshake is not done or ldc is not up */ "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
DWARN((
vnetp,
"vgen_ldcsend: id(%lx) invalid size(%d)\n",
* The data buffer returned by allocb(9F) is 8byte aligned. * We allocate extra 8 bytes to ensure size is multiple of * 8 bytes for ldc_mem_bind_handle(). /* check if the channel is still up & running */ "vgen_ldcsend: id(%lx) status(%d), dropping packet\n",
* This cflag is disabled by default. This can be enabled if we * want to return failure to the mac layer when we run out of * descriptors and use mac_tx_update() to restart tx when * descriptors become available. However, stopping tx would * affect traffic going over other ports, as upper mac layer * has no concept of multiple ports within a device. * So currently, to avoid this, drop packets when we run out * of descrs and just return success. See the corresponding * code in vgen_portsend() and vgen_reclaim_dring(). * if num of pending transmits is more than hiwat, * reclaim now and also enable ack bit. * if the num of pending transmits is more than lowat * enable ack bit in the descr and reclaim in intr(). DWARN((
vnetp,
"vgen_ldcsend: id(%lx)ldc_mem_bind_handle failed" "vgen_ldcsend: id(%lx)ldc_mem_bind_handle returned" "vgen_ldcsend: ldc_mem_nextcookie" /* save the packet, free when the descr done flag is set */ /* initialize the corresponding public descriptor (txd) */ /* send dring datamsg to the peer */ /* vgen_send_dring_data() error: drop the packet */ "vgen_ldcsend: vgen_send_dring_data(): failed: " /* update next available tbuf in the ring */ /* update tx seqnum and index */ if (
bp)
/* free original pkt, copy is in bp */ * If handshake is done, send a msg to vsw to add/remove DWARN((
vnetp,
"vgen_mutlicst: vgen_sendmsg failed" /* set the flag to send a msg to vsw after handshake is done */ /* expand multicast table if necessary */ /* add address to the table */ /* delete address from the table */ * If there's more than one address in this * table, delete the unwanted one by moving * the last one in the list over top of it; * otherwise, just remove it. /* set or clear promiscuous mode on the device */ /* set the unicast mac address of the device */ /* get device statistics */ /* vgen internal functions */ /* detach all ports from the device */ "vgen_port_detach: enter: port_num(%d)\n",
port_num));
/* remove it from port list */ /* detach channels from this port */ "vgen_port_detach: exit: port_num(%d)\n",
port_num));
/* add a port to port list */ /* remove a port from port list */ /* lookup a port in the list based on port_num */ * Create fdb entry in vnet, corresponding to the mac * address of this port. Note that the port specified * is vsw-port. This is done so that vsw-port acts * as the route to reach this macaddr, until the * channel for this port comes up (LDC_UP) and * handshake is done successfully. * eg, if the peer is OBP-vnet, it may not bring the * channel up for this port and may communicate via * vsw to reach this port. * Later, when Solaris-vnet comes up at the other end * of the channel for this port and brings up the channel, * it is an indication that peer vnet is capable of * distributed switching, so the direct route through this * port is specified in fdb, using vnet_modify_fdb(macaddr); * create the default route entry in vnet's fdb. * This is the entry used by vnet to reach * unknown destinations, which basically goes * through vsw on domain0 and out through the * physical device bound to vsw. /* Bring up the channels of this port */ /* delete the entry in vnet's fdb for this port */ * if this is vsw-port, then delete the default * route entry in vnet's fdb. /* register with MD event generator */ * NOTE: The instance here refers to the value of "reg" property and * not the dev_info instance (ddi_get_instance()) of vnet. /* save parentp in vgen_t */ DERR((
vnetp,
"vgen_mdeg_reg: mdeg_register failed\n"));
/* save mdeg handle in vgen_t */ /* unregister with MD event generator */ /* callback function registered with MD event generator */ "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n",
* find vsw_port and add it first, because other ports need * this when adding fdb entry (see vgen_port_init()). * This port is connected to the "can't find vsw_port\n"));
/* add a new port to the device */ /* read "id" property to get the port number */ * Find the channel endpoint node(s) under this port node. "vgen_add_port: invalid number of nodes found (%d)",
/* allocate space for node list */ "vgen_add_port: prop(%s) not found\n",
"vgen_add_port: invalid address size (%d)\n",
addrsz));
/* This port is connected to the vsw on dom0 */ /* remove a port from the device */ /* read "id" property to get the port number */ "vgen_remove_port: prop(%s) not found\n",
id_propname));
/* attach a port to the device based on mdeg data */ /* link it into the list of ports */ /* This port is connected to the vsw on domain0 */ "vgen_port_attach_mdeg: exit: port_num(%d)\n",
portp->
port_num));
/* detach a port from the device based on mdeg data */ "vgen_port_detach_mdeg: enter: port_num(%d)\n",
portp->
port_num));
/* stop the port if needed */ "vgen_port_detach_mdeg: exit: port_num(%d)\n",
portp->
port_num));
/* attach the channel corresponding to the given ldc_id to the port */ "ldc_reg_callback failed, id (%lx) rv (%d)\n",
/* allocate transmit resources */ /* Setup kstats for the channel */ /* initialize vgen_versions supported */ /* link it into the list of channels for this port */ /* detach a channel from the port */ "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n",
/* free transmit resources */ /* unlink it from the list */ * This function allocates transmit resources for the channel. * The resources consist of a transmit descriptor ring and an associated /* allocate transmit buffer ring */ /* create transmit descriptor ring */ DWARN((
vnetp,
"vgen_alloc_tx_ring: ldc_mem_dring_create() " /* get the addr of descripror ring */ DWARN((
vnetp,
"vgen_alloc_tx_ring: ldc_mem_dring_info() " /* Free transmit resources for the channel */ /* free transmit descriptor ring */ /* free transmit buffer ring */ "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n",
"vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n",
"vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n",
/* Bind descriptor ring to the channel */ "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n",
DBG2((
vnetp,
"vgen_ldcinit: id(%lx) status(%d) is not UP\n",
/* initialize transmit watchdog timeout */ DWARN((
vnetp,
"vgen_ldc_uninit: id(%lx) CHANNEL_STARTED" /* disable further callbacks */ /* clear handshake done bit and wait for pending tx and cb to finish */ /* reset transmit watchdog timeout */ /* unbind tx descriptor ring from the channel */ DWARN((
vnetp,
"vgen_ldcuninit: ldc_mem_dring_unbind " DWARN((
vnetp,
"vgen_ldcuninit: ldc_close err id(%lx)\n",
/* Initialize the transmit buffer ring for the channel */ * for each tx buf (priv_desc), allocate a ldc mem_handle which is * required to map the data during transmit, set the flags * to free (available for use by transmit routine). /* reset tbuf walking pointers */ /* initialize tx seqnum and index */ /* Uninitialize transmit buffer ring for the channel */ /* for each tbuf (priv_desc), free ldc mem_handle */ /* clobber tx descriptor ring */ /* reset tbuf walking pointers */ /* reset tx seqnum and index */ "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n",
/* clobber receive descriptor ring */ /* initialize receive descriptor ring */ * sucessfully mapped, now try to * get info about the mapped dring * save ring address, number of descriptors. /* get channel statistics */ /* stats not relevant to ldc, return 0 */ /* Interrupt handler for the channel */ DWARN((
vnetp,
"vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n",
/* check ldc status change events first */ "vgen_ldc_cb: id(%lx) status(%d) is LDC_UP\n",
* modify fdb entry to use this port as the * channel is up, instead of going through the * vsw-port (see comments in vgen_port_init()) /* Initialize local session id */ /* clear peer session id */ /* Initiate Handshake process with peer ldc endpoint */ * modify fdb entry to use vsw-port as the * channel is reset and we don't have a direct * link to the destination (see comments "vgen_ldc_cb: id(%lx) status is (%d)\n",
"vgen_ldc_cb: id(%lx) istatus=(%d) status(%d) is" DBG1((
vnetp,
"vgen_ldc_cb: id(%lx) status(%d) is NOT LDC_UP\n",
/* if ldc_status is UP, receive all packets */ "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) " DBG2((
vnetp,
"vgen_ldc_cb: ldc_read id(%lx) NODATA",
DBG2((
vnetp,
"vgen_ldc_cb: ldc_read id(%lx): msglen(%d)",
* check sid only after we have received peer's sid * in the version negotiate msg. /* simulate bad sid condition */ * If sid mismatch is detected, /* build a chain of received packets */ "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n",
/* send up the received packets to MAC layer */ DBG2((
vnetp,
"vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n",
/* vgen handshake functions */ /* change the hphase for the channel to the next phase */ * Check whether the given version is supported or not and * return VGEN_SUCCESS if supported. * Given a version, return VGEN_SUCCESS if a lower version is supported. * if we support a lower minor version within the same major * version, or if we support a lower major version, * update the verp parameter with this lower version and * wrapper routine to send the given message over ldc using ldc_write(). "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)" /* send version negotiate message to the peer over ldc */ /* get version msg payload from ldcp->local */ DWARN((
vnetp,
"vgen_send_version_negotiate: vgen_sendmsg failed" "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n",
/* send attr info message to the peer over ldc */ /* get attr msg payload from ldcp->local */ DWARN((
vnetp,
"vgen_send_attr_info: vgen_sendmsg failed" DBG2((
vnetp,
"vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n",
/* send descriptor ring register message to the peer over ldc */ /* get dring info msg payload from ldcp->local */ * dring_ident is set to 0. After mapping the dring, peer sets this * value and sends it in the ack, which is saved in * vgen_handle_dring_reg(). DWARN((
vnetp,
"vgen_send_dring_reg: vgen_sendmsg failed" DBG2((
vnetp,
"vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n",
DWARN((
vnetp,
"vgen_send_rdx_info: vgen_sendmsg failed" DBG2((
vnetp,
"vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n",
/* send descriptor ring data message to the peer over ldc */ DWARN((
vnetp,
"vgen_send_dring_data: vgen_sendmsg failed" DBG2((
vnetp,
"vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n",
/* send multicast addr info message to vsw */ DWARN((
vnetp,
"vgen_send_mcast_info: vgen_sendmsg err" /* Initiate Phase 2 of handshake */ /* simulate out of state condition */ /* simulate timeout condition */ * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). * This can happen after a channel comes up (status: LDC_UP) or * when handshake gets terminated due to various conditions. /* reset hstate and hphase */ /* reset handshake watchdog timeout */ * Unmap drings, if dring_ready is set. /* do not unbind our dring */ * clear local handshake params and initialize. /* set version to the highest version supported */ /* set attr_info params */ * Note: dring is already created and bound. * dring_ident is set to 0. After mapping the dring, peer sets this * value and sends it in the ack, which is saved in * vgen_handle_dring_reg(). /* reset the channel if required */ "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n",
"vgen_reset_hphase: id (%lx), RESET Done,ldc_status(%x)\n",
/* wrapper function for vgen_reset_hphase */ * Initiate handshake with the peer by sending various messages * based on the handshake-phase that the channel is currently in. * start timer, for entire handshake process, turn this timer * off if all phases of handshake complete successfully and * hphase goes to VH_DONE(below) or * vgen_reset_hphase() gets called or * channel is reset due to errors or * vgen_ldc_uninit() is invoked(vgen_stop). /* Phase 1 involves negotiating the version */ /* reset handshake watchdog timeout */ DBG1((
vnetp,
"vgen_handshake: id(0x%lx) Handshake Done\n",
/* need to sync multicast table with vsw */ * Check if the current handshake phase has completed successfully and * Phase1 is done, if version negotiation * completed successfully. * Phase 2 is done, if attr info and dring info * have been exchanged successfully. /* Phase 3 is done, if rdx msg has been exchanged */ /* retry handshake on failure */ /* reset handshake phase */ * Handle a version info msg from the peer or an ACK/NACK from the peer * to a version info msg that we sent. DBG1((
vnetp,
"vgen_handle_version_negotiate: enter\n"));
/* Cache sid of peer if this is the first time */ "vgen_handle_version_negotiate: id (%lx) Caching" * If we are not already in VH_PHASE1, reset to * pre-handshake state, and initiate handshake /* save peer's requested values */ /* unsupported dev_class, send NACK */ /* send reply msg back to peer */ "vgen_handle_version_negotiate: Version" DBG2((
vnetp,
"vgen_handle_version_negotiate: VER_INFO_RCVD," /* nack with next lower version */ /* major version match - ACK version */ * lower minor version to the one this endpt /* no version match - send NACK */ /* send reply msg back to peer */ DBG2((
vnetp,
"vgen_handle_version_negotiate:" " VER_ACK_SENT, id (%lx) ver(%d,%d) \n",
" Version Negotiation Failed id (%lx)\n",
/* VER_ACK_SENT and VER_ACK_RCVD */ /* local and peer versions match? */ /* move to the next phase */ /* This should not happen. */ "vgen_handle_version_negotiate:" " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n",
/* SUCCESS - we have agreed on a version */ DBG2((
vnetp,
"vgen_handle_version_negotiate:" " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n",
/* VER_ACK_SENT and VER_ACK_RCVD */ /* local and peer versions match? */ /* move to the next phase */ /* This should not happen. */ "vgen_handle_version_negotiate:" " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n",
DBG2((
vnetp,
"vgen_handle_version_negotiate:" " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n",
/* check if version in NACK is zero */ * Version Negotiation has failed. " Version Negotiation Failed id (%lx)\n",
/* select next lower version */ /* major version match */ * Version Negotiation has failed. " Version Negotiation Failed id (%lx)\n",
DBG1((
vnetp,
"vgen_handle_version_negotiate: exit\n"));
/* Check if the attributes are supported */ * currently, we support these attr values: * mtu of ethernet, addr_type of mac, xfer_mode of * ldc shared memory, ack_freq of 0 (data is acked if * the ack bit is set in the descriptor) and the address should * match the address in the port node. cmn_err(
CE_CONT,
"vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n",
* Handle an attribute info msg from the peer or an ACK/NACK from the peer * to an attr info msg that we sent. DBG1((
vnetp,
"vgen_handle_attr_info: enter\n"));
"vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)" " subtype (%d), Invalid Phase(%u)\n",
ldcp->
ldc_id,
DBG2((
vnetp,
"vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n",
/* unsupported attr, send NACK */ /* send reply msg back to peer */ DBG2((
vnetp,
"vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n",
DBG2((
vnetp,
"vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n",
DBG1((
vnetp,
"vgen_handle_attr_info: exit\n"));
/* Check if the dring info msg is ok */ /* check if msg contents are ok */ * Handle a descriptor ring register msg from the peer or an ACK/NACK from * the peer to a dring register msg that we sent. DBG1((
vnetp,
"vgen_handle_dring_reg: enter\n"));
/* dring_info can be rcvd in any of the phases after Phase1 */ "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)" " Subtype (%d), Invalid Phase(%u)\n",
ldcp->
ldc_id,
DBG2((
vnetp,
"vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n",
* verified dring info msg to be ok, * now try to map the remote dring. /* now we can ack the peer */ /* save peer's dring_info values */ /* set dring_ident for the peer */ /* return the dring_ident in ack msg */ /* send reply msg back to peer */ DBG2((
vnetp,
"vgen_handle_dring_reg: DRING_ACK_SENT" DWARN((
vnetp,
"vgen_handle_dring_reg: DRING_NACK_SENT" DBG2((
vnetp,
"vgen_handle_dring_reg: DRING_ACK_RCVD" /* local dring is now ready */ /* save dring_ident acked by peer */ DBG2((
vnetp,
"vgen_handle_dring_reg: DRING_NACK_RCVD" DBG1((
vnetp,
"vgen_handle_dring_reg: exit\n"));
* Handle a rdx info msg from the peer or an ACK/NACK * from the peer to a rdx info msg that we sent. DBG1((
vnetp,
"vgen_handle_rdx_info: enter\n"));
"vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)" " Subtype (%d), Invalid Phase(%u)\n",
ldcp->
ldc_id,
DBG2((
vnetp,
"vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n",
/* send reply msg back to peer */ DBG2((
vnetp,
"vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n",
DBG2((
vnetp,
"vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n",
DBG2((
vnetp,
"vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n",
DBG1((
vnetp,
"vgen_handle_rdx_info: exit\n"));
/* Handle ACK/NACK from vsw to a set multicast msg that we sent */ DBG1((
vnetp,
"vgen_handle_mcast_info: enter\n"));
/* vnet shouldn't recv set mcast msg, only vsw handles it */ "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n",
"vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n",
"vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n",
/* multicast remove request failed */ /* multicast add request failed */ /* delete address from the table */ DBG1((
vnetp,
"vgen_handle_mcast_info: exit\n"));
/* handler for control messages received from the peer ldc end-point */ DBG1((
vnetp,
"vgen_handle_ctrlmsg: enter\n"));
DBG1((
vnetp,
"vgen_handle_ctrlmsg: exit\n"));
/* handler for data messages received from the peer ldc end-point */ DBG1((
vnetp,
"vgen_handle_datamsg: enter\n"));
DBG1((
vnetp,
"vgen_handle_datamsg: exit\n"));
DBG1((
vnetp,
"vgen_handle_dring_data: enter\n"));
* received a data msg, which contains the start and end * indeces of the descriptors within the rx ring holding data, * the seq_num of data packet corresponding to the start index, * We can now read the contents of each of these descriptors * and gather data from it. "vgen_handle_dring_data: INFO: start(%d), end(%d)\n",
/* validate rx start and end indeces */ /* drop the message if invalid index */ /* validate dring_ident */ /* invalid dring_ident, drop the msg */ /* drop this msg to simulate lost pkts for debugging */ /* receive start index doesn't match expected index */ "next_rxi(%d) != start(%d)\n",
/* calculate the number of pkts lost */ * Starting sequence number of the received packets * is less than the next sequence number that * drop the message and the corresponding packets. "dropping pkts, expected rxseq(0x%lx) " * sender?? drop this msg. * Starting sequence number of the received packets * is greater than the next expected sequence number * send a NACK back to the peer to indicate lost /* indicate the range of lost descriptors */ /* dring ident is left unchanged */ "vgen_handle_dring_data: id(%lx) " * stop further processing until peer * retransmits with the right index and seqnum. * and set the new expected values for next_rxi * and next_rxseq. continue(below) to process * from the new start index. * expected and starting seqnums match, but * the descriptor indeces don't? * restart handshake with peer. "vgen_handle_dring_data: id(%lx) " "next_rxseq(0x%lx) == seq_num(0x%lx)\n",
/* expected and start dring indeces match */ /* seqnums don't match */ "vgen_handle_dring_data: id(%lx) " "next_rxseq(0x%lx) != seq_num(0x%lx)\n",
#
endif /* VGEN_HANDLE_LOST_PKTS */ * Start processing the descriptor range, specified "id(%lx), ldc_mem_dring_acquire() failed\n",
/* recv packets from 'start' to 'end' */ * The data buffer returned by allocb(9F) is * 8byte aligned. We allocate extra 8 bytes to * ensure size is multiple of 8 bytes for * rxd_err or allocb() failure, * drop this packet, get next. /* set descriptor done bit */ * sender needs ack for this packet. * sync pkts upto this index and * send the ack to the peer. "vgen_handle_dring_data: " /* save new sync index start */ /* set done bit irrespective of rv of ldc_mem_copy() */ * sender needs ack for this packet. * sync pkts upto this index and * send the ack to the peer. "vgen_handle_dring_data: id(%lx) " "vgen_sendmsg failed stype: ACK\n",
/* save new sync index start */ /* if ldc_mem_copy() failed */ "vgen_handle_dring_data: id(%lx) " "vgen_handle_dring_data: id(%lx) " "ldc_mem_copy nread(%lx), nbytes(%lx)\n",
/* point to the actual end of data */ /* build a chain of received packets */ /* increment recv index */ /* sync remote descriptor range */ "vgen_handle_dring_data: not sending ACK\n"));
/* save new recv index */ /* try to reclaim transmit descrs also */ * received an ack corresponding to a specific descriptor for * which we had set the ACK bit in the descriptor (during * transmit). This enables us to reclaim descriptors. "vgen_handle_dring_data: ACK: start(%d), end(%d)\n",
/* validate start and end indeces in the tx ack msg */ /* drop the message if invalid index */ /* validate dring_ident */ /* invalid dring_ident, drop the msg */ * peer sent a NACK msg to indicate lost packets. * The start and end correspond to the range of descriptors * for which the peer didn't receive a dring data msg and so * didn't receive the corresponding data. "vgen_handle_dring_data: NACK: start(%d), end(%d)\n",
/* validate start and end indeces in the tx nack msg */ /* drop the message if invalid index */ /* validate dring_ident */ /* invalid dring_ident, drop the msg */ /* no busy descriptors, bogus nack ? */ /* send a new dring data msg including the lost descrs */ /* no need to increment ldcp->next_txseq as this is rexmit */ * vgen_send_dring_data() error: drop all packets "vgen_handle_dring_data: " "vgen_send_dring_data failed :" /* update next pointer */ "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n",
/* we just mark the descrs as done so they can be reclaimed */ DBG1((
vnetp,
"vgen_handle_dring_data: exit\n"));
return;
/* already in progress */ * transmit reclaim function. starting from the current reclaim index * look for descriptors marked DONE and reclaim the descriptor and the * corresponding buffers (tbuf). * Check if mac layer should be notified to restart transmissions /* return the number of pending transmits for the channel */ /* cur_tbufp > next_tbufp */ /* determine if the transmit descriptor ring is full */ /* determine if timeout condition has occured */ /* transmit watchdog timeout handler */ "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n",
/* tx timeout triggered for debugging */ /* based on mcopymsg() */ /* MIB II kstat variables */ /* handler for error messages received from the peer ldc end-point */ /* Check if the session id in the received message is valid */ "sid mismatch: expected(%x), rcvd(%x)\n",
/* convert mac address from string to uint64_t */ /* convert mac address from uint64_t to string */ "%x:%x:%x:%x:%x:%x", a[0], a[
1], a[
2], a[
3], a[
4], a[
5]);
/* Handshake watchdog timeout handler */ "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n",
"\tver_major: %d, ver_minor: %d, dev_class: %d\n",
"\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n",
"\tldc_addr: 0x%lx, ldc_size: %ld\n",
"\tldc_id: 0x%lx, ldc_status: 0x%x\n",
"\tlocal_sid: 0x%x, peer_sid: 0x%x\n",
"\thphase: 0x%x, hstate: 0x%x\n",