You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1546 lines
47 KiB
1546 lines
47 KiB
/*--------------------------------------------------------------------------
|
|
| port.c - common port code
|
|
Change History:
|
|
4-27-98 - adjust for scanrate addition.
|
|
3-23-98 - add in broadcast for boxes if not found(had put in V1.12) but
|
|
the changes did not make it into source-safe. kpb.
|
|
3-20-98 - Change scheme to track remote tx-buffer level, all changes
|
|
ifdef'ed by NEW_Q in port.h, turned off for now. - kpb.
|
|
3-16-98 - VS recovery fix, reset flags in port_resync_all() to force update.
|
|
If RAS lost box, it would continue to see active connections, then on
|
|
recovery, DSR,CD,CTS input signals would not be updated immediately.
|
|
11-05-97 - Add Backup Server feature. DCS
|
|
6-17-97 - start using index field assigned to box to id rx-messages.
|
|
6-17-97 - change link-integrity check code.
|
|
|--------------------------------------------------------------------------*/
|
|
#include "precomp.h"
|
|
|
|
int check_ack_code(PortMan *pm, BYTE *pkt);
|
|
int send_code(PortMan *pm);
|
|
int send_go(PortMan *pm);
|
|
|
|
int port_handle_outpkt(PortMan *pm, BYTE **buf, int *tx_used, int *port_set);
|
|
BYTE *port_setup_outpkt(PortMan *pm, int *tx_used);
|
|
void port_query_reply(PortMan *pm, BYTE *pkt);
|
|
void port_load_pkt(PortMan *pm, BYTE *pkt);
|
|
ULONG port_event_proc(PVOID context, int message_id, ULONG message_data);
|
|
int port_resync_all(PortMan *pm);
|
|
int port_connect_reply(Hdlc *hd);
|
|
int port_connect_ask(Hdlc *hd);
|
|
int port_packet(PortMan *pm, BYTE *buf);
|
|
|
|
#define DISABLE()
|
|
#define ENABLE()
|
|
|
|
#define TraceErr3(s, p1, p2, p3) GTrace3(D_Error, sz_modid, s, p1, p2, p3)
|
|
#define TraceErr2(s, p1, p2) GTrace2(D_Error, sz_modid, s, p1, p2)
|
|
#define TraceErr1(s, p1) GTrace1(D_Error, sz_modid, s, p1)
|
|
#define Trace2(s, p1, p2) GTrace2(D_Port, sz_modid, s, p1, p2)
|
|
#define Trace1(s, p1) GTrace1(D_Port, sz_modid, s, p1)
|
|
#define TraceStr(s) GTrace(D_Port, sz_modid, s)
|
|
#define TraceErr(s) GTrace(D_Error, sz_modid_err, s)
|
|
#define TraceAssert(l,s)
|
|
static char *sz_modid = {"Port"};
|
|
static char *sz_modid_err = {"Error,Port"};
|
|
|
|
// following for trace or dump messages, make public for other mods as well.
|
|
char *port_state_str[] = {"Init", "InitOwn", "SendCode", "Connect", "Active", "."};
|
|
|
|
|
|
#ifdef NEW_Q
|
|
/*--------------------------------------------------------------------------
|
|
PortGetTxCntRemote -
|
|
|--------------------------------------------------------------------------*/
|
|
WORD PortGetTxCntRemote(SerPort *p)
|
|
{
|
|
WORD Get, Put;
|
|
|
|
Get = p->nGetRemote;
|
|
Put = p->nPutRemote;
|
|
|
|
if (Put >= Get)
|
|
return (Put - Get);
|
|
else
|
|
return (Put + (~Get) + 1);
|
|
}
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------------
|
|
PortFlushTx -
|
|
|--------------------------------------------------------------------------*/
|
|
void PortFlushTx(SerPort *p)
|
|
{
|
|
if (!q_empty(&p->QOut)) // flush local side
|
|
{
|
|
q_put_flush(&p->QOut);
|
|
}
|
|
pFlushOutput(p); // flush remote
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
PortFlushRx -
|
|
|--------------------------------------------------------------------------*/
|
|
void PortFlushRx(SerPort *p)
|
|
{
|
|
if (!q_empty(&p->QIn)) // flush local side
|
|
{
|
|
#ifdef NEW_Q
|
|
p->nGetLocal += q_count(&p->QIn);
|
|
#endif
|
|
q_get_flush(&p->QIn);
|
|
p->Status |= S_UPDATE_ROOM;
|
|
}
|
|
pFlushInput(p); // flush remote
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_resync_all - total-resync, this routine is called to reset port
|
|
users, to inform them of a re-sync operation and adjust operation
|
|
accordingly.
|
|
If our case, since remote q is critical to maintain between both sides,
|
|
we clear out all buffer data and start with all empty buffers.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_resync_all(PortMan *pm)
|
|
{
|
|
int i;
|
|
SerPort *Port;
|
|
|
|
TraceStr( "ReSync");
|
|
|
|
for (i=0; i<pm->num_ports; i++)
|
|
{
|
|
Port = pm->sp[i];
|
|
if (Port != NULL)
|
|
{
|
|
Port->QOut.QSize = OUT_BUF_SIZE;
|
|
Port->QOut.QGet = 0;
|
|
Port->QOut.QPut = 0;
|
|
|
|
#ifdef NEW_Q
|
|
Port->nPutRemote = 0;
|
|
Port->nGetRemote = 0;
|
|
Port->nGetLocal = 0;
|
|
#else
|
|
Port->QInRemote.QSize= OUT_BUF_SIZE; // for now assume same sizes
|
|
Port->QInRemote.QGet = 0;
|
|
Port->QInRemote.QPut = 0;
|
|
#endif
|
|
|
|
//Port->LanIndex = i;
|
|
Port->QIn.QSize = IN_BUF_SIZE;
|
|
Port->QIn.QGet = 0;
|
|
Port->QIn.QPut = 0;
|
|
|
|
Port->change_flags |= (CHG_BAUDRATE | CHG_SP_CHARS);
|
|
Port->old_baudrate = 0; // force baud rate update
|
|
|
|
Port->old_control_settings = ~Port->control_settings; // force update
|
|
Port->old_mcr_value = ~Port->mcr_value; // force update
|
|
// reset this
|
|
memset(&Port->last_sp_chars, 0, sizeof(Port->last_sp_chars));
|
|
|
|
Port->msr_value = 0; // back to initial state.
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
Callback routine that hdlc(l2) protocol calls on events.
|
|
We are upper layer(3).
|
|
|--------------------------------------------------------------------------*/
|
|
ULONG port_event_proc(PVOID context, int message_id, ULONG message_data)
|
|
{
|
|
TraceStr("L3Event");
|
|
switch(message_id)
|
|
{
|
|
case EV_L2_CHECK_LINK: // hdlc wants us to check link
|
|
TraceStr("Chk Link");
|
|
// request that the portman do a link message check
|
|
((PortMan *) context)->Status |= S_CHECK_LINK;
|
|
break;
|
|
|
|
case EV_L2_ADMIN_REPLY: // got a query-id reply ADMIN packet
|
|
TraceStr("ID PKT");
|
|
port_query_reply((PortMan *) context, (BYTE *) message_data);
|
|
break;
|
|
|
|
case EV_L2_BOOT_REPLY: // got a boot loader ADMIN packet
|
|
TraceStr("LOAD PKT");
|
|
port_load_pkt((PortMan *) context, (BYTE *) message_data);
|
|
break;
|
|
|
|
case EV_L2_RESYNC:
|
|
// this happens on RK_CONNECT reply
|
|
port_resync_all((PortMan *) context);
|
|
break;
|
|
|
|
case EV_L2_RELOAD:
|
|
// this only happens when alive timer times out,
|
|
// (hdlc-level detects a bad connection),
|
|
// so lets assume box needs to be brought up from ground zero.
|
|
port_resync_all((PortMan *) context);
|
|
((PortMan *) context)->state = ST_INIT;
|
|
((PortMan *) context)->load_timer = 0;
|
|
++((PortMan *) context)->reload_errors;
|
|
TraceErr("Reload device");
|
|
break;
|
|
|
|
case EV_L2_RX_PACKET:
|
|
port_packet((PortMan *) context, ((BYTE *) message_data) );
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_set_new_mac_addr -
|
|
|--------------------------------------------------------------------------*/
|
|
int port_set_new_mac_addr(PortMan *pm, BYTE *box_addr)
|
|
{
|
|
// Hdlc *hd;
|
|
// int i;
|
|
|
|
// copy over the new mac-address
|
|
memcpy(pm->hd->dest_addr, box_addr, 6);
|
|
|
|
// force a complete update of the box
|
|
pm->reload_errors = 0;
|
|
pm->state = 0;
|
|
pm->Status |= S_NEED_CODE_UPDATE;
|
|
pm->Status |= S_SERVER; // yes we are server(not box)
|
|
|
|
port_resync_all(pm);
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
portman_init - init the Box(PortMAn) struct, and the associated hdlc hd object.
|
|
At this point the Nic object is already open.
|
|
|--------------------------------------------------------------------------*/
|
|
int portman_init(Hdlc *hd,
|
|
PortMan *pm,
|
|
int num_ports,
|
|
int unique_id,
|
|
int backup_server,
|
|
int backup_timer,
|
|
BYTE *box_addr)
|
|
{
|
|
int i, stat;
|
|
|
|
MyKdPrint(D_Init, ("portman_init\n"))
|
|
|
|
TraceStr( "PortInit");
|
|
stat = 0;
|
|
|
|
// allocate serial-port structures.
|
|
for (i=0; i<num_ports; i++)
|
|
{
|
|
if (pm->sp[i] == NULL)
|
|
{
|
|
pm->sp[i] = (SerPort *)our_locked_alloc(sizeof(SerPort), "Dsp");
|
|
port_init(pm->sp[i]); // let port create and init some stuff
|
|
}
|
|
}
|
|
pm->num_ports = num_ports;
|
|
pm->backup_server = backup_server;
|
|
pm->backup_timer = backup_timer;
|
|
pm->unique_id = unique_id;
|
|
pm->load_timer = 0;
|
|
|
|
// default to the first nic card slot, port state handling and nic
|
|
// packet reception handling dynamically figures this out.
|
|
// we should probably set it to null, but I'm afraid of this right now
|
|
#ifdef BREAK_NIC_STUFF
|
|
pm->nic =NULL;
|
|
#else
|
|
pm->nic = &Driver.nics[0];
|
|
#endif
|
|
pm->nic_index = 0;
|
|
|
|
pm->hd = hd;
|
|
pm->reload_errors = 0;
|
|
pm->state = 0;
|
|
pm->state_timer = 0;
|
|
pm->Status |= S_NEED_CODE_UPDATE;
|
|
pm->Status |= S_SERVER; // yes we are server(not box)
|
|
|
|
pm->hd = hd;
|
|
stat = hdlc_open(pm->hd, box_addr);
|
|
hd->context = pm; // put our handle here, so hdlc sends this along
|
|
// with any upper_layer messages
|
|
|
|
if (stat)
|
|
{
|
|
if (Driver.VerboseLog)
|
|
Eprintf("Hdlc open fail:%d",stat);
|
|
|
|
TraceStr("Err-Hdlc Open!");
|
|
return 3;
|
|
}
|
|
|
|
// set HDLC's callback RX-proc to point to our routine
|
|
hd->upper_layer_proc = port_event_proc;
|
|
|
|
port_resync_all(pm);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
portman_close - close down the port manager.
|
|
|--------------------------------------------------------------------------*/
|
|
int portman_close(PortMan *pm)
|
|
{
|
|
int i;
|
|
|
|
pm->state = 0;
|
|
|
|
// deallocate any Port things
|
|
for (i=0; i<pm->num_ports; i++)
|
|
{
|
|
if (pm->sp[i] != NULL)
|
|
{
|
|
port_close(pm->sp[i]);
|
|
our_free(pm->sp[i], "Dsp");
|
|
pm->sp[i] = NULL;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_init - init a SerPort thing.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_init(SerPort *sp)
|
|
{
|
|
TraceStr("SPort_Init");
|
|
|
|
if (sp->QOut.QBase == NULL)
|
|
{
|
|
sp->QOut.QBase = our_locked_alloc(OUT_BUF_SIZE+2,"pmQO");
|
|
if (sp->QOut.QBase == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (sp->QIn.QBase == NULL)
|
|
{
|
|
sp->QIn.QBase = our_locked_alloc(IN_BUF_SIZE+2, "pmQI");
|
|
if (sp->QIn.QBase == NULL)
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
sp->Status |= S_OPENED;
|
|
sp->mcr_value = 0;
|
|
//sp->mcr_value = MCR_RTS_SET_ON | MCR_DTR_SET_ON;
|
|
sp->old_mcr_value = sp->mcr_value;
|
|
|
|
sp->sp_chars.tx_xon = 0x11;
|
|
sp->sp_chars.tx_xoff = 0x13;
|
|
sp->sp_chars.rx_xon = 0x11;
|
|
sp->sp_chars.rx_xoff = 0x13;
|
|
sp->last_sp_chars = sp->sp_chars; // copy struct to old
|
|
sp->change_flags = 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_close -
|
|
|--------------------------------------------------------------------------*/
|
|
int port_close(SerPort *sp)
|
|
{
|
|
int i;
|
|
|
|
if (sp == NULL)
|
|
return 0;
|
|
|
|
if (sp->QIn.QBase != NULL)
|
|
{
|
|
our_free(sp->QIn.QBase,"pmQI");
|
|
sp->QIn.QBase = NULL;
|
|
}
|
|
|
|
if (sp->QOut.QBase != NULL)
|
|
{
|
|
our_free(sp->QOut.QBase,"pmQO");
|
|
sp->QOut.QBase = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_packet - got an incoming packet, do something with it.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_packet(PortMan *pm, BYTE *buf)
|
|
{
|
|
SerPort *Port;
|
|
int port_num;
|
|
int done, len;
|
|
int QInRoom;
|
|
|
|
TraceStr( "GotPkt");
|
|
|
|
Port = pm->sp[0]; // default to point to first port
|
|
|
|
//----- process all the sub-packets in the lan-packet, process
|
|
// until we hit a zero header field, or some header we don't know
|
|
// about(default: case).
|
|
done = 0;
|
|
if (*(buf) == 0)
|
|
{
|
|
// bugbug: this is a problem, we get a bunch of these during
|
|
// normal operation, for now just show in debug version, as
|
|
// they are a nuciance in peer error tracing.
|
|
#if DBG
|
|
TraceErr("Empty pkt!");
|
|
#endif
|
|
}
|
|
while (!done)
|
|
{
|
|
switch(*buf++)
|
|
{
|
|
case RK_CONNECT_CHECK: // check link
|
|
TraceStr( "Rk_Conn_Chk_reply");
|
|
|
|
// do nothing on the server, on box send back a iframe reply
|
|
break;
|
|
|
|
case RK_CONNECT_REPLY: // reply from our request to bring up connection
|
|
TraceStr( "Rk_reply");
|
|
if (pm->Status & S_SERVER)
|
|
{
|
|
if (pm->state == ST_CONNECT) // should happen at this time
|
|
{
|
|
pm->state = ST_ACTIVE; // fire up a connection
|
|
}
|
|
else // got it when not expecting it.
|
|
{
|
|
TraceStr("Err-Recover!");
|
|
// client recovering, need resyc.
|
|
port_resync_all(pm);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RK_CONNECT_ASK: // packet from server
|
|
TraceStr( "Rk_Ask");
|
|
// should not see this on server
|
|
break;
|
|
|
|
case RK_PORT_SET: // set the port num to work with
|
|
TraceStr( "Rk_Port");
|
|
if (*buf >= pm->num_ports)
|
|
{
|
|
TraceErr( "PortI!");
|
|
port_num = *buf++;
|
|
break;
|
|
}
|
|
port_num = *buf++;
|
|
Port = pm->sp[port_num];
|
|
break;
|
|
|
|
#ifdef COMMENT_OUT // not on server
|
|
case RK_BAUD_SET: // set the baud rate
|
|
Port->baudrate = *((DWORD *)(buf)); // Remotes QIn.QGet value
|
|
buf += 4;
|
|
//sSetBaudRate(ChP, Port->baudrate, 1);
|
|
break;
|
|
|
|
case RK_CONTROL_SET: // set the baud rate
|
|
w1 = *((WORD *)(buf)); // control settings
|
|
buf += 2;
|
|
control_set(port_num, w1);
|
|
break;
|
|
|
|
case RK_MCR_SET: // modem control reg pkt
|
|
w1 = *((WORD *)(buf)); // control settings
|
|
buf += 2;
|
|
mcr_set(port_num, w1);
|
|
break;
|
|
#endif
|
|
|
|
case RK_MSR_SET: // modem status reg pkt
|
|
Port->msr_value = *((WORD *)(buf));
|
|
Trace1("Rk_MSR:%xH", Port->msr_value);
|
|
buf += 2;
|
|
break;
|
|
|
|
case RK_ACTION_ACK: // modem status reg pkt
|
|
// NT does not use this one, novell driver does to
|
|
// help dump all data in transit during a flush.
|
|
//Port->action_resp = *((WORD *)(buf));
|
|
Trace1("Rk_Act_Ack:%xH", *((WORD *)(buf)));
|
|
buf += 2;
|
|
break;
|
|
|
|
case RK_ESR_SET: // error status reg pkt
|
|
Port->esr_reg = *((WORD *)(buf));
|
|
Trace1("Rk_ESR:%xH", Port->esr_reg);
|
|
buf += 2;
|
|
break;
|
|
|
|
case RK_QIN_STATUS: // qin status report
|
|
TraceStr( "Rk_QStat");
|
|
#ifdef NEW_Q
|
|
Port->nGetRemote = *((WORD *)(buf)); // track remote output buffer space
|
|
#else
|
|
Port->QInRemote.QGet = *((short *)(buf)); // Remotes QIn.QGet value
|
|
#endif
|
|
buf += 2;
|
|
break;
|
|
|
|
case RK_DATA_BLK: // data block to put in buffer queue
|
|
TraceStr( "Rk_Data");
|
|
#ifdef NEW_Q
|
|
//old(does not belong here!):Port->Status |= S_UPDATE_ROOM;
|
|
#else
|
|
Port->Status |= S_UPDATE_ROOM;
|
|
#endif
|
|
len = *((WORD *)(buf));
|
|
buf += 2;
|
|
|
|
QInRoom = q_room(&Port->QIn);
|
|
TraceAssert((QInRoom < Port->QIn.QSize), "Err1B!!!");
|
|
TraceAssert((QInRoom >= 0), "Err1B!!!");
|
|
if (len > QInRoom) // Overflow
|
|
{
|
|
TraceErr("Err-Port Overflow!");
|
|
len = 0;
|
|
}
|
|
q_put(&Port->QIn, buf, len);
|
|
buf += len;
|
|
break;
|
|
|
|
default:
|
|
done = 1;
|
|
if (*(buf-1) != 0)
|
|
{
|
|
TraceErr("Bad Sub pkt hdr!");
|
|
GTrace1(D_Error,sz_modid," HDR:%xH",*(buf-1));
|
|
}
|
|
break;
|
|
} // case per sub-packet
|
|
} // while not done with sub-packets
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_poll - check to see if we need to send any packets over. If we have
|
|
new data in or need to send status packets over.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_poll(PortMan *pm)
|
|
{
|
|
#define MAX_TX_SPACE 1460
|
|
int i, tx_used;
|
|
SerPort *Port;
|
|
unsigned char *buf;
|
|
int ToMove, ThisMove;
|
|
int QOutCount;
|
|
int QLanRoom;
|
|
#ifdef NEW_Q
|
|
WORD tmp_word;
|
|
#endif
|
|
int port_set; // flag it as not setup.
|
|
|
|
|
|
// this logic is in isr.c service routine now
|
|
// if (pm->state != ST_ACTIVE)
|
|
// {
|
|
// port_state_handler(pm);
|
|
// return 0;
|
|
// }
|
|
|
|
tx_used = MAX_TX_SPACE+1000; // indicate no pkt allocated
|
|
#if DBG
|
|
if (pm == NULL)
|
|
{
|
|
MyKdPrint(D_Error, ("!!!!!pm null\n"))
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// handle box things, send out a query to check-connection if
|
|
// hdlc saw inactivity.
|
|
if (pm->Status & S_CHECK_LINK)
|
|
{
|
|
if (tx_used > (MAX_TX_SPACE-50)) // if our tx-pkt is near full or null
|
|
{
|
|
buf = port_setup_outpkt(pm, &tx_used);
|
|
if (buf == NULL)
|
|
return 0; // no more output packet space available, so all done
|
|
buf[tx_used++] = RK_CONNECT_CHECK;
|
|
// at this point we queued our iframe to query other side(to ensure
|
|
// link-integrity.
|
|
pm->Status &= ~S_CHECK_LINK; // reset our request to send this
|
|
TraceStr("Check sent");
|
|
}
|
|
}
|
|
|
|
for (i=0; i<pm->num_ports; i++)
|
|
{
|
|
Port = pm->sp[pm->last_round_robin];
|
|
|
|
//----- see if flag set to tell other side how much room in Port Rx buf
|
|
if (Port->Status & S_UPDATE_ROOM)
|
|
{
|
|
TraceStr("Update needed");
|
|
if (tx_used > (MAX_TX_SPACE-50)) // if our tx-pkt is near full or null
|
|
{
|
|
buf = port_setup_outpkt(pm, &tx_used);
|
|
if (buf == NULL)
|
|
return 0; // no more output packet space available, so all done
|
|
port_set = 0xff; // flag it as not setup.
|
|
}
|
|
if (port_set != pm->last_round_robin) // our port index not setup
|
|
{
|
|
buf[tx_used++] = RK_PORT_SET;
|
|
buf[tx_used++] = (BYTE) pm->last_round_robin;
|
|
port_set = pm->last_round_robin;
|
|
}
|
|
|
|
// take away status reminder flag
|
|
Port->Status &= ~S_UPDATE_ROOM;
|
|
|
|
// form the sub-packet in our output packet buffer
|
|
buf[tx_used++] = RK_QIN_STATUS;
|
|
// report our actual QGet index to other side.
|
|
#ifdef NEW_Q
|
|
*((WORD *)(&buf[tx_used])) = Port->nGetLocal;
|
|
#else
|
|
*((short *)(&buf[tx_used])) = Port->QIn.QGet;
|
|
#endif
|
|
tx_used += 2;
|
|
}
|
|
|
|
//----- do action items
|
|
if (Port->action_reg != 0)
|
|
{
|
|
if (port_handle_outpkt(pm, &buf, &tx_used, &port_set) != 0) // no pkt space avail
|
|
return 0; // no more output packet space available, so all done
|
|
|
|
TraceStr("act pkt");
|
|
buf[tx_used++] = RK_ACTION_SET;
|
|
*((WORD *)(&buf[tx_used])) = Port->action_reg;
|
|
Port->action_reg = 0; // its a one-shot deal, so we reset this now
|
|
tx_used += 2;
|
|
}
|
|
|
|
//----- do updates for control settings, mcr, etc
|
|
if (Port->old_control_settings != Port->control_settings)
|
|
{
|
|
if (port_handle_outpkt(pm, &buf, &tx_used, &port_set) != 0) // no pkt space avail
|
|
return 0; // no more output packet space available, so all done
|
|
|
|
Port->old_control_settings = Port->control_settings;
|
|
TraceStr("ctr chg");
|
|
buf[tx_used++] = RK_CONTROL_SET;
|
|
*((WORD *)(&buf[tx_used])) = Port->control_settings;
|
|
tx_used += 2;
|
|
}
|
|
|
|
//----- do updates for mcr
|
|
if (Port->old_mcr_value != Port->mcr_value)
|
|
{
|
|
if (port_handle_outpkt(pm, &buf, &tx_used, &port_set) != 0) // no pkt space avail
|
|
return 0; // no more output packet space available, so all done
|
|
|
|
TraceStr("mcr chg");
|
|
Port->old_mcr_value = Port->mcr_value;
|
|
buf[tx_used++] = RK_MCR_SET;
|
|
*((WORD *)(&buf[tx_used])) = Port->mcr_value;
|
|
tx_used += 2;
|
|
}
|
|
|
|
//----- do updates for special chars, etc
|
|
if (Port->change_flags)
|
|
{
|
|
if (Port->change_flags & CHG_BAUDRATE)
|
|
{
|
|
//----- do updates for baud rate settings
|
|
if (Port->old_baudrate != Port->baudrate)
|
|
{
|
|
if (port_handle_outpkt(pm, &buf, &tx_used, &port_set) != 0) // no pkt space avail
|
|
return 0; // no more output packet space available, so all done
|
|
|
|
Port->old_baudrate = Port->baudrate;
|
|
Trace1("baud:%lu", Port->baudrate);
|
|
buf[tx_used++] = RK_BAUD_SET;
|
|
*((DWORD *)(&buf[tx_used])) = Port->baudrate;
|
|
tx_used += 4;
|
|
}
|
|
}
|
|
|
|
if (Port->change_flags & CHG_SP_CHARS)
|
|
{
|
|
if (memcmp(&Port->last_sp_chars, &Port->sp_chars, 6) != 0) // compare structs for chg
|
|
{
|
|
Port->last_sp_chars = Port->sp_chars; // remember last set values
|
|
if (port_handle_outpkt(pm, &buf, &tx_used, &port_set) != 0) // no pkt space avail
|
|
return 0; // no more output packet space available, so all done
|
|
|
|
TraceStr("sp_chars");
|
|
buf[tx_used++] = RK_SPECIAL_CHAR_SET;
|
|
|
|
Trace1(" rx_xon:%x", Port->sp_chars.rx_xon);
|
|
Trace1(" rx_xoff:%x", Port->sp_chars.rx_xoff);
|
|
Trace1(" tx_xon:%x", Port->sp_chars.tx_xon);
|
|
Trace1(" tx_xoff:%x", Port->sp_chars.tx_xoff);
|
|
Trace1(" error:%x", Port->sp_chars.error);
|
|
Trace1(" event:%x", Port->sp_chars.event);
|
|
|
|
buf[tx_used++] = Port->sp_chars.rx_xon;
|
|
buf[tx_used++] = Port->sp_chars.rx_xoff;
|
|
buf[tx_used++] = Port->sp_chars.tx_xon;
|
|
buf[tx_used++] = Port->sp_chars.tx_xoff;
|
|
buf[tx_used++] = Port->sp_chars.error;
|
|
buf[tx_used++] = Port->sp_chars.event;
|
|
}
|
|
}
|
|
Port->change_flags = 0; // reset all
|
|
}
|
|
|
|
//----- send any outgoing data if other side has room.
|
|
QOutCount = q_count(&Port->QOut);
|
|
#ifdef NEW_Q
|
|
// calculate our remote tx-buffer space based on WORD modulo arithmetic
|
|
tmp_word = PortGetTxCntRemote(Port);
|
|
|
|
// right now this var is equal to how much tx-data is in remote buffer.
|
|
if (tmp_word < REMOTE_IN_BUF_SIZE)
|
|
QLanRoom = REMOTE_IN_BUF_SIZE - tmp_word;
|
|
else QLanRoom = 0;
|
|
// now it is how much room we have in the remote tx-buffer.
|
|
#else
|
|
QLanRoom = q_room(&Port->QInRemote); // other sides port queue room
|
|
#endif
|
|
if ((QOutCount > 0) && (QLanRoom > 50)) // have data, other side has room
|
|
{
|
|
TraceStr("Data to Send");
|
|
if (QOutCount > QLanRoom) // more data than room
|
|
ToMove = QLanRoom; // limit
|
|
else ToMove = QOutCount;
|
|
|
|
do
|
|
{
|
|
if (tx_used > (MAX_TX_SPACE-50)) // if our tx-pkt is near full or null
|
|
{
|
|
buf = port_setup_outpkt(pm, &tx_used); // allocate a new one
|
|
if (buf == NULL)
|
|
return 0; // no more output packet space available, so all done
|
|
port_set = 0xff; // flag it as not setup.
|
|
}
|
|
if (port_set != pm->last_round_robin) // our port index not setup
|
|
{
|
|
buf[tx_used++] = RK_PORT_SET;
|
|
buf[tx_used++] = (BYTE) pm->last_round_robin;
|
|
port_set = pm->last_round_robin;
|
|
}
|
|
|
|
// make sure we have emough room for data, limit if we don't
|
|
if (ToMove > ((MAX_TX_SPACE-1) - tx_used) )
|
|
{
|
|
ThisMove = (MAX_TX_SPACE-1) - tx_used;
|
|
ToMove -= ThisMove;
|
|
}
|
|
else
|
|
{
|
|
ThisMove = ToMove;
|
|
ToMove = 0;
|
|
}
|
|
buf[tx_used++] = RK_DATA_BLK; // set header sub-type
|
|
*((WORD *)(&buf[tx_used])) = ThisMove; // set header data size
|
|
tx_used += 2;
|
|
q_get(&Port->QOut, &buf[tx_used], ThisMove);
|
|
tx_used += ThisMove;
|
|
|
|
// keep our own copy of remote qin indexes
|
|
#ifdef NEW_Q
|
|
// bump our tx-buffer count based on WORD modulo arithmetic
|
|
Port->nPutRemote += ((WORD)ThisMove);
|
|
#else
|
|
q_putted(&Port->QInRemote, ((short)ThisMove));
|
|
#endif
|
|
} while (ToMove > 0); // keep using packets if more to send
|
|
} // if data sent
|
|
|
|
++pm->last_round_robin;
|
|
if (pm->last_round_robin >= pm->num_ports)
|
|
pm->last_round_robin = 0;
|
|
}
|
|
|
|
|
|
if (tx_used < (MAX_TX_SPACE+1000)) // then we allocated a packet prior
|
|
{ // and need to send it
|
|
if (hdlc_send_outpkt(pm->hd, tx_used, pm->hd->dest_addr)) // send it out!
|
|
{
|
|
TraceErr("Err-hdlc_send1");
|
|
}
|
|
}
|
|
|
|
//TraceStr( "EndPoll");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_state_handler - handle states other than normal data flowage.
|
|
Called at scanrate(1-20ms) times per second from service routine.
|
|
|--------------------------------------------------------------------------*/
|
|
void port_state_handler(PortMan *pm)
|
|
{
|
|
int inic;
|
|
|
|
if (pm->old_state != pm->state)
|
|
{
|
|
pm->old_state = pm->state;
|
|
pm->state_timer = 0;
|
|
}
|
|
|
|
pm->timer_base += ((WORD) Driver.Tick100usBase); // 100us base units(typical:100)
|
|
if (pm->timer_base < 98) // less than 9.8ms
|
|
{
|
|
// we want to run roughly 100 ticks per second
|
|
return;
|
|
}
|
|
pm->timer_base = 0;
|
|
|
|
switch(pm->state)
|
|
{
|
|
case ST_INIT:
|
|
// if we are server, then wait for query back.
|
|
|
|
//pm->state_timer = 0;
|
|
//break;
|
|
|
|
if (pm->Status & S_SERVER)
|
|
{
|
|
if (pm->state_timer == 600) // 6 seconds
|
|
{
|
|
pm->ownership_timer = 0;
|
|
TraceStr( "Send Query");
|
|
// find box out on network, use ADMIN pkt
|
|
// do the query on all nic-segments
|
|
for (inic=0; inic<VS1000_MAX_NICS; inic++)
|
|
{
|
|
if (Driver.nics[inic].Open) // if nic-card open for use
|
|
{
|
|
// send a passive query(don't try to assume ownership
|
|
if (admin_send_query_id(&Driver.nics[inic], pm->hd->dest_addr,
|
|
0, 0) != 0)
|
|
{
|
|
TraceErr( "Err1E");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pm->state_timer == 1800) // 18 seconds
|
|
{
|
|
// try a broadcast to cut through switches.
|
|
TraceStr( "Send Br.Query");
|
|
// find box out on network, use ADMIN pkt
|
|
// do the query on all nic-segments
|
|
for (inic=0; inic<VS1000_MAX_NICS; inic++)
|
|
{
|
|
if (Driver.nics[inic].Open) // if nic-card open for use
|
|
{
|
|
// send a passive query(don't try to assume ownership
|
|
if (admin_send_query_id(&Driver.nics[inic], broadcast_addr,
|
|
0, 0) != 0)
|
|
{
|
|
TraceErr( "Err1E");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pm->state_timer > 2400) // 24 sec, give up start over
|
|
pm->state_timer = 0;
|
|
}
|
|
break;
|
|
|
|
case ST_GET_OWNERSHIP:
|
|
// if we are server, then wait for query back.
|
|
if (pm->Status & S_SERVER)
|
|
{
|
|
// Increment when in ST_GET_OWNERSHIP state for backup server.
|
|
++pm->load_timer;
|
|
if (pm->state_timer == 10) // 100ms
|
|
{
|
|
TraceStr( "Send Query Owner");
|
|
// find box out on network, use ADMIN pkt
|
|
// do the query on all nic-segments
|
|
for (inic=0; inic<VS1000_MAX_NICS; inic++)
|
|
{
|
|
if (Driver.nics[inic].Open) // if nic-card open for use
|
|
{
|
|
// BUGFIX(8-26-98), this was only sending it out on
|
|
// the nic card assigned to pm.
|
|
//)if (admin_send_query_id(pm->nic, pm->hd->dest_addr,
|
|
if (admin_send_query_id(&Driver.nics[inic], pm->hd->dest_addr,
|
|
1, (BYTE) pm->unique_id) != 0)
|
|
{
|
|
TraceErr( "Err1G");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pm->state_timer > 600) // 6 seconds
|
|
{
|
|
// SAFE GUARD ADDED DUE to SCREWED UP OWNERSHIP STATE MACHINE
|
|
// kpb, 8-25-98, make sure we don't spend forever in this state.
|
|
pm->ownership_timer += 6;
|
|
if (pm->ownership_timer > (60 * 15)) // 15 minutes
|
|
{
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
}
|
|
pm->state_timer = 0;
|
|
}
|
|
// 8-26-98
|
|
// NOTICE, we are not reseting state to INIT after a while,
|
|
// this is a problem!
|
|
}
|
|
break;
|
|
|
|
case ST_SENDCODE: // download main driver code to box
|
|
if (pm->state_timer == 0)
|
|
{
|
|
++pm->total_loads;
|
|
pm->code_cnt = 0; // start upload
|
|
send_code(pm);
|
|
}
|
|
else if (pm->state_timer == 1000) // 10 seconds since init
|
|
{
|
|
TraceErr("Upload Retry");
|
|
++pm->total_loads;
|
|
pm->code_cnt = 0; // start upload
|
|
send_code(pm);
|
|
}
|
|
else if (pm->state_timer == 2000) // 20 seconds since init
|
|
{
|
|
TraceErr("Upload Retry");
|
|
++pm->total_loads;
|
|
pm->code_cnt = 0; // start upload
|
|
send_code(pm);
|
|
}
|
|
else if (pm->state_timer == 3000) // fail it out, start over with init
|
|
{
|
|
TraceErr("Upload Fail");
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
}
|
|
else if (pm->code_state == 1) // signal port poll code to send next chunk
|
|
{
|
|
TraceStr("Upload, next chk.");
|
|
if (pm->code_cnt < Driver.MicroCodeSize)
|
|
{
|
|
if (send_code(pm) == 0) // success
|
|
pm->code_state = 0;
|
|
}
|
|
else // all done
|
|
{
|
|
TraceStr("Code Upload Done.");
|
|
if (send_go(pm) == 0)
|
|
{
|
|
++pm->good_loads;
|
|
pm->code_cnt = 0;
|
|
pm->state = ST_GET_OWNERSHIP;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ST_CONNECT:
|
|
if (pm->state_timer == 0)
|
|
port_connect_ask(pm->hd);
|
|
else if (pm->state_timer == 1000) // 10 seconds
|
|
port_connect_ask(pm->hd);
|
|
else if (pm->state_timer == 2000) // 20 seconds
|
|
{
|
|
pm->state = ST_INIT; // fall back
|
|
pm->load_timer = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TraceErr("Err-PState!");
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
break;
|
|
}
|
|
++pm->state_timer;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_handle_outpkt - check if we have at least 50 bytes in outpkt, if
|
|
not get a new one. If no new one avail, return non-zero.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_handle_outpkt(PortMan *pm, BYTE **buf, int *tx_used, int *port_set)
|
|
{
|
|
if (*tx_used > (MAX_TX_SPACE-50)) // if our tx-pkt is near full or null
|
|
{
|
|
*buf = port_setup_outpkt(pm, tx_used);
|
|
if (*buf == NULL)
|
|
return 1; // no more output packet space available, so all done
|
|
*port_set = 0xff;
|
|
}
|
|
if (*port_set != pm->last_round_robin)
|
|
{
|
|
// since we have a new pkt, we need to
|
|
(*buf)[(*tx_used)++] = RK_PORT_SET;
|
|
(*buf)[(*tx_used)++] = (BYTE) pm->last_round_robin;
|
|
*port_set = pm->last_round_robin;
|
|
}
|
|
return 0; // current pkt has plenty of room(at least 50 bytes)
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_setup_outpkt - setup an outgoing packet if one is available, if previously
|
|
filled one out then we ship it off out the nic card.
|
|
|--------------------------------------------------------------------------*/
|
|
BYTE *port_setup_outpkt(PortMan *pm, int *tx_used)
|
|
{
|
|
BYTE *buf;
|
|
|
|
if (*tx_used != (MAX_TX_SPACE+1000)) // then we allocated a packet prior
|
|
{ // and need to send it
|
|
if (hdlc_send_outpkt(pm->hd, *tx_used, pm->hd->dest_addr)) // send it out!
|
|
{
|
|
TraceErr("send err");
|
|
}
|
|
}
|
|
if (hdlc_get_outpkt(pm->hd, &buf) == 0) // no error, got a output packet
|
|
{
|
|
TraceStr("NPkt2");
|
|
*tx_used = 0; // have a new empty output packet allocated
|
|
return buf; // all done
|
|
}
|
|
else
|
|
{
|
|
TraceStr("NPktDone2");
|
|
*tx_used = MAX_TX_SPACE+1000; // indicate no pkt allocated
|
|
return NULL; // all done
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_load_pkt - got a admin boot load packet: ACK back from code download pkt.
|
|
|--------------------------------------------------------------------------*/
|
|
void port_load_pkt(PortMan *pm, BYTE *pkt)
|
|
{
|
|
if (pm->state != ST_SENDCODE) // not expected at this time, lets reset it.
|
|
{
|
|
TraceErr("BootLoad not at SENDCODE!");
|
|
Tprintf("state=%d", pm->state);
|
|
// other details????
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
//pm->hd->state = ST_HDLC_INIT;
|
|
return;
|
|
}
|
|
|
|
if (Driver.MicroCodeSize == 0)
|
|
{
|
|
TraceErr("Bad MC");
|
|
return;
|
|
}
|
|
|
|
if (check_ack_code(pm,pkt) != 0)
|
|
{
|
|
TraceErr("Bad Ack");
|
|
return;
|
|
}
|
|
TraceStr("Good Ack!");
|
|
|
|
// send more data
|
|
if (pm->code_cnt < Driver.MicroCodeSize)
|
|
pm->code_cnt += 1000;
|
|
pm->code_state = 1; // signal port poll code to send next chunk
|
|
}
|
|
|
|
#if NEW_QUERY_HANDLER
|
|
/*--------------------------------------------------------------------------
|
|
port_query_reply - got a ADMIN query reply back, server sends out
|
|
query-id request on init and when setup is entered, box sends back
|
|
id(which tells us if code is loaded.) A query reply is ignored in
|
|
states other that ST_INIT and ST_GET_OWNERSHIP
|
|
|--------------------------------------------------------------------------*/
|
|
void port_query_reply(PortMan *pm, BYTE *pkt)
|
|
{
|
|
int unit_available = 0;
|
|
int unit_needs_code = 0;
|
|
int unit_needs_reset = 0;
|
|
|
|
if (!mac_match(pkt, pm->hd->dest_addr))
|
|
{
|
|
TraceErr("Reply MAC bad!");
|
|
return;
|
|
}
|
|
|
|
// ignore if not ST_INIT or ST_GET_OWNERSHIP
|
|
if ((pm->state != ST_INIT) && (pm->state != ST_GET_OWNERSHIP))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pkt[7] >= VS1000_MAX_NICS) // if invalid nic-index
|
|
{
|
|
TraceErr("Nic Index Reply!");
|
|
return;
|
|
}
|
|
|
|
// when we get the query packet, we stash the nic-card index
|
|
// into part of the receive buffer that is unused(pkt[7]).
|
|
// see if this matches what our port-manager nic_index is,
|
|
// if not, then we switched nic cards and need to update some
|
|
// things.
|
|
if (pm->nic_index != (int)(pkt[7])) // changed nic cards
|
|
{
|
|
TraceErr("Nic Changed!");
|
|
pm->nic_index = (int)(pkt[7]); // set nic_index
|
|
pm->nic = &Driver.nics[pm->nic_index]; // changed nic cards
|
|
pm->hd->nic = pm->nic; // update the hdlc nic ptr
|
|
}
|
|
#define Q_DRIVER_RUNNING 1
|
|
#define Q_NOT_OWNER 2
|
|
#define Q_ABANDONED 4
|
|
|
|
// we are NOT owner(2H), and main app-driver running(1H), be careful
|
|
if ((pkt[6] & Q_DRIVER_RUNNING) && (pkt[6] & Q_NOT_OWNER))
|
|
{
|
|
// if not owner timeout, (4H=ABANDONED) then leave alone!
|
|
// some other server is actively using it.
|
|
if ((pkt[6] & Q_ABANDONED) == 0)
|
|
{
|
|
Trace1("ReplyID, Not Ours. [%x]", pkt[6]);
|
|
pm->load_timer = 0;
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
return;
|
|
}
|
|
// else its abandoned, so we can take ownership.
|
|
unit_available = 1;
|
|
unit_needs_reset = 1;
|
|
}
|
|
else
|
|
{
|
|
// we are owner or main-driver not running yet
|
|
unit_available = 1;
|
|
}
|
|
if ((pkt[6] & Q_DRIVER_RUNNING) == 0)
|
|
{
|
|
unit_needs_code = 1;
|
|
}
|
|
|
|
if (pm->Status & S_NEED_CODE_UPDATE)
|
|
{
|
|
unit_needs_reset = 1;
|
|
unit_needs_code = 1;
|
|
}
|
|
|
|
// ok to take ownership(no owner)
|
|
TraceStr("ReplyID, Unit Available");
|
|
if (pm->state == ST_INIT)
|
|
{
|
|
if ((pm->backup_server == 0) ||
|
|
(pm->load_timer >= (pm->backup_timer*6000)) )
|
|
{
|
|
if (pm->backup_server == 0)
|
|
{ TraceStr("Pri. make owner"); }
|
|
else
|
|
{ TraceStr("2nd. make owner"); }
|
|
pm->state = ST_GET_OWNERSHIP;
|
|
// this will cause the state machine to issue a query trying to
|
|
// obtain ownership
|
|
unit_needs_reset = 1;
|
|
}
|
|
else
|
|
{
|
|
if (pm->load_timer >= (pm->backup_timer*6000))
|
|
{
|
|
TraceStr("2nd, make owner");
|
|
pm->state = ST_GET_OWNERSHIP;
|
|
// this will cause the state machine to issue a query trying to
|
|
// obtain ownership
|
|
}
|
|
}
|
|
}
|
|
else if (pm->state == ST_GET_OWNERSHIP)
|
|
{
|
|
TraceStr("ReplyID in GET_OWNERSHIP");
|
|
|
|
// Is this the primary server or has the backup timer expired?
|
|
if ((pm->backup_server == 0) && (pm->load_timer >= (pm->backup_timer*6000))
|
|
{
|
|
// we are NOT owner(2H), and main app-driver running(1H), be careful
|
|
if ((pkt[6] & 3) == 3)
|
|
{
|
|
if (pkt[6] & 4) // Owner has timed out - force reload
|
|
{
|
|
// force a reset of box on driver-load(this bit is set in
|
|
// port_init) so we load up some fresh microcode.
|
|
admin_send_reset(pm->nic, pm->hd->dest_addr);
|
|
TraceStr("Abandoned, ReSet");
|
|
}
|
|
}
|
|
else if ((pkt[6] & 1) == 0) // code is not downloaded, so download it.
|
|
{
|
|
// Make sure that we are the owner?
|
|
if (pkt[6] & 2) // 2h=not owner bit
|
|
{
|
|
TraceStr("GET_OWNERSHIP: No App - Not Owner!");
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
return;
|
|
}
|
|
TraceStr("GET_OWNERSHIP: Download");
|
|
pm->Status &= ~S_NEED_CODE_UPDATE;
|
|
pm->state = ST_SENDCODE;
|
|
}
|
|
else // code is downloaded - we are the owner
|
|
{
|
|
if (pm->Status & S_NEED_CODE_UPDATE)
|
|
{
|
|
// force a reset of box on driver-load(this bit is set in
|
|
// port_init) and set S_NEED_CODE_UPDATE so we load up some
|
|
// fresh microcode.
|
|
admin_send_reset(pm->nic, pm->hd->dest_addr);
|
|
TraceStr("ReplyID, ReLoad");
|
|
pm->Status &= ~S_NEED_CODE_UPDATE;
|
|
}
|
|
else
|
|
{
|
|
TraceStr("ReplyID, GoToConnect");
|
|
port_resync_all(pm);
|
|
//pm->state = ST_ACTIVE;
|
|
pm->state = ST_CONNECT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
|
|
/*--------------------------------------------------------------------------
|
|
port_query_reply - got a ADMIN query reply back, server sends out
|
|
query-id request on init and when setup is entered, box sends back
|
|
id(which tells us if code is loaded.) A query reply is ignored in
|
|
states other that ST_INIT and ST_GET_OWNERSHIP
|
|
|--------------------------------------------------------------------------*/
|
|
void port_query_reply(PortMan *pm, BYTE *pkt)
|
|
{
|
|
if (!mac_match(pkt, pm->hd->dest_addr))
|
|
{
|
|
TraceErr("Reply MAC bad!");
|
|
return;
|
|
}
|
|
|
|
// ignore if not ST_INIT or ST_GET_OWNERSHIP
|
|
if ((pm->state != ST_INIT) && (pm->state != ST_GET_OWNERSHIP))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pkt[7] >= VS1000_MAX_NICS) // if invalid nic-index
|
|
{
|
|
TraceErr("Nic Index Reply!");
|
|
return;
|
|
}
|
|
|
|
// when we get the query packet, we stash the nic-card index
|
|
// into part of the receive buffer that is unused(pkt[7]).
|
|
// see if this matches what our port-manager nic_index is,
|
|
// if not, then we switched nic cards and need to update some
|
|
// things.
|
|
if (pm->nic_index != (int)(pkt[7])) // changed nic cards
|
|
{
|
|
TraceErr("Nic Changed!");
|
|
pm->nic_index = (int)(pkt[7]); // set nic_index
|
|
pm->nic = &Driver.nics[pm->nic_index]; // changed nic cards
|
|
pm->hd->nic = pm->nic; // update the hdlc nic ptr
|
|
}
|
|
|
|
// we are NOT owner(2H), and main app-driver running(1H), be careful
|
|
if ((pkt[6] & 3) == 3)
|
|
{
|
|
// if not owner timeout, (4H=ABANDONED) then leave alone!
|
|
// some other server is actively using it.
|
|
if ((pkt[6] & 4) == 0)
|
|
{
|
|
Trace1("ReplyID, Not Ours. [%x]", pkt[6]);
|
|
pm->load_timer = 0;
|
|
pm->state = ST_INIT;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (pm->state == ST_INIT)
|
|
{
|
|
// ok to take ownership(no owner)
|
|
pm->state = ST_GET_OWNERSHIP;
|
|
if(pm->backup_server == 0)
|
|
{
|
|
Trace1("ReplyID, Primary Server - Unit Available [%x]", pkt[6]);
|
|
}
|
|
else
|
|
{
|
|
Trace1("ReplyID, Backup Server - Unit Available [%x]", pkt[6]);
|
|
}
|
|
}
|
|
else if (pm->state == ST_GET_OWNERSHIP)
|
|
{
|
|
Trace1("ReplyID, GET_OWNERSHIP [%x]", pkt[6]);
|
|
// Is this the primary server or has the backup timer expired?
|
|
if((pm->backup_server == 0) ||
|
|
(pm->load_timer >= (pm->backup_timer*6000)))
|
|
{
|
|
// we are NOT owner(2H), and main app-driver running(1H), be careful
|
|
if ((pkt[6] & 3) == 3)
|
|
{
|
|
if (pkt[6] & 4) // Owner has timed out - force reload
|
|
{
|
|
// force a reset of box on driver-load(this bit is set in
|
|
// port_init) so we load up some fresh microcode.
|
|
admin_send_reset(pm->nic, pm->hd->dest_addr);
|
|
TraceStr("ReplyID, ReLoad");
|
|
}
|
|
else
|
|
{
|
|
TraceStr("GET_OWNERSHIP: App Running - Not Owner!");
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
return;
|
|
}
|
|
}
|
|
else if ((pkt[6] & 1) == 0) // code is not downloaded, so download it.
|
|
{
|
|
// Make sure that we are the owner?
|
|
if (pkt[6] & 2) // 2h=not owner bit
|
|
{
|
|
TraceStr("GET_OWNERSHIP: No App - Not Owner!");
|
|
pm->state = ST_INIT;
|
|
pm->load_timer = 0;
|
|
return;
|
|
}
|
|
TraceStr("GET_OWNERSHIP: Download");
|
|
pm->Status &= ~S_NEED_CODE_UPDATE;
|
|
pm->state = ST_SENDCODE;
|
|
}
|
|
else // code is downloaded - we are the owner
|
|
{
|
|
if (pm->Status & S_NEED_CODE_UPDATE)
|
|
{
|
|
// force a reset of box on driver-load(this bit is set in
|
|
// port_init) and set S_NEED_CODE_UPDATE so we load up some
|
|
// fresh microcode.
|
|
admin_send_reset(pm->nic, pm->hd->dest_addr);
|
|
TraceStr("ReplyID, ReLoad");
|
|
pm->Status &= ~S_NEED_CODE_UPDATE;
|
|
}
|
|
else
|
|
{
|
|
TraceStr("ReplyID, GoToConnect");
|
|
port_resync_all(pm);
|
|
//pm->state = ST_ACTIVE;
|
|
pm->state = ST_CONNECT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| port_connect_reply - Reply to server connection request, we return our
|
|
MAC address, and do a re-sync operation.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_connect_reply(Hdlc *hd)
|
|
{
|
|
BYTE rkt_header[8];
|
|
|
|
TraceStr( "Connect Reply");
|
|
rkt_header[0] = RK_CONNECT_REPLY;
|
|
memcpy(&rkt_header[1], hd->nic->address,6);
|
|
hdlc_send_control(hd, rkt_header, 7,
|
|
NULL, 0, // ptr to data to send
|
|
hd->dest_addr); // MAC address to send to
|
|
hdlc_resync(hd);
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
| port_connect_ask - Ask box to initiate a connection. We send out our
|
|
MAC address, and do a resync.
|
|
|--------------------------------------------------------------------------*/
|
|
int port_connect_ask(Hdlc *hd)
|
|
{
|
|
BYTE rkt_header[8];
|
|
|
|
TraceStr( "Connect Ask");
|
|
rkt_header[0] = RK_CONNECT_ASK;
|
|
memcpy(&rkt_header[1], hd->nic->address,6);
|
|
|
|
hdlc_send_control(hd, rkt_header, 7,
|
|
NULL, 0, // ptr to data to send
|
|
hd->dest_addr); // MAC address to send to
|
|
hdlc_resync(hd);
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
PortSetBaudRate - Set the desired baud rate. Return non-zero on error.
|
|
|-------------------------------------------------------------------*/
|
|
int PortSetBaudRate(SerPort *p,
|
|
ULONG desired_baud,
|
|
USHORT SetHardware,
|
|
DWORD clock_freq,
|
|
DWORD clk_prescaler)
|
|
{
|
|
ULONG diff;
|
|
ULONG act_baud;
|
|
ULONG percent_error;
|
|
ULONG div;
|
|
ULONG base_clock_rate;
|
|
|
|
base_clock_rate = ((clock_freq/16) / ((clk_prescaler & 0xf)+1));
|
|
|
|
// calculate the divisor for our hardware register.
|
|
// this is really just div = clk/desired_baud -1. but we do some
|
|
// work to minimize round-off error.
|
|
if (desired_baud <= 0) desired_baud = 1; // guard against div 0
|
|
|
|
div = ((base_clock_rate+(desired_baud>>1)) / desired_baud) - 1;
|
|
if (div > 8191) // overflow hardware divide register
|
|
div = 8191;
|
|
|
|
// this is really just (clk) / (div+1) but we do some
|
|
// work to minimize round-off error.
|
|
act_baud = (base_clock_rate+((div+1)>>1)) / (div+1);
|
|
|
|
if (desired_baud > act_baud)
|
|
diff = desired_baud - act_baud;
|
|
else
|
|
diff = act_baud - desired_baud;
|
|
|
|
percent_error = (diff * 100) / desired_baud;
|
|
if (percent_error > 5)
|
|
return (int) percent_error;
|
|
|
|
if (SetHardware)
|
|
{
|
|
p->change_flags |= CHG_BAUDRATE;
|
|
//---- OLD p->out_flags |= SC_BAUDRATE_CHANGE; // tells what needs changing to remote
|
|
p->baudrate = desired_baud;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
| check_ack_code - upload code, given ack packet, check for good status.
|
|
|---------------------------------------------------------------------------*/
|
|
int check_ack_code(PortMan *pm, BYTE *pkt)
|
|
{
|
|
int stat;
|
|
int snd;
|
|
|
|
TraceStr("CodeChk");
|
|
stat = eth_device_reply(UPLOAD_COMMAND,
|
|
0x00010000L + pm->code_cnt,
|
|
&snd,
|
|
NULL,
|
|
pkt);
|
|
return stat;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
| send_go - send boot loader command to start execution of uploaded driver
|
|
at 1000:0 in memory.
|
|
|---------------------------------------------------------------------------*/
|
|
int send_go(PortMan *pm)
|
|
{
|
|
int stat;
|
|
BYTE *buf;
|
|
WORD io[4];
|
|
BYTE *tx_base;
|
|
|
|
TraceStr("GoSend");
|
|
|
|
hdlc_get_ctl_outpkt(pm->hd, &buf);
|
|
if (buf == NULL)
|
|
return 1;
|
|
tx_base = buf - 20; // backup to start of pkt
|
|
|
|
io[0] = 0x1000; // segment to go at
|
|
io[1] = 0; // offset to go at
|
|
|
|
// send more code, loading at 10000H location in mem.
|
|
// first just transfer data to an outgoing packet buffer
|
|
stat = ioctl_device(IOCTL_COMMAND,
|
|
(BYTE *) io,
|
|
buf,
|
|
12, // 12 = go command
|
|
4); // num bytes of data
|
|
// setup header
|
|
tx_base[14] = ASYNC_PRODUCT_HEADER_ID; // comtrol packet type = driver management, any product.
|
|
tx_base[15] = 0; // conc. index field
|
|
tx_base[16] = 1; // admin
|
|
*((WORD *)&tx_base[17]) = 40;
|
|
tx_base[19] = 1; // ADMIN packet type, 1=boot-loader, 3=id-reply
|
|
|
|
// send it.
|
|
stat = hdlc_send_raw(pm->hd, 60, NULL);
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
| send_code - upload code.
|
|
|---------------------------------------------------------------------------*/
|
|
int send_code(PortMan *pm)
|
|
{
|
|
int stat;
|
|
BYTE *buf;
|
|
BYTE *tx_base;
|
|
long snd;
|
|
|
|
TraceStr("CodeSend");
|
|
|
|
// send more data
|
|
if (pm->code_cnt < Driver.MicroCodeSize)
|
|
{
|
|
if ((Driver.MicroCodeSize - pm->code_cnt) > 1000)
|
|
snd = 1000;
|
|
else
|
|
snd = Driver.MicroCodeSize - pm->code_cnt;
|
|
|
|
hdlc_get_ctl_outpkt(pm->hd, &buf);
|
|
if (buf == NULL)
|
|
{
|
|
TraceErr("CodeSend Err1A");
|
|
return 1;
|
|
}
|
|
tx_base = buf - 20; // backup to start of pkt
|
|
|
|
// send more code, loading at 10000H location in mem.
|
|
// first just transfer data to an outgoing packet buffer
|
|
stat = ioctl_device(UPLOAD_COMMAND,
|
|
&Driver.MicroCodeImage[pm->code_cnt],
|
|
buf,
|
|
0x00010000L + pm->code_cnt, // offset into memory
|
|
snd);
|
|
// setup header
|
|
tx_base[14] = ASYNC_PRODUCT_HEADER_ID; // comtrol packet type = driver management, any product.
|
|
tx_base[15] = 0; // conc. index field
|
|
tx_base[16] = 1; // admin
|
|
*((WORD *)&tx_base[17]) = snd+20;
|
|
tx_base[19] = 1; // ADMIN packet type, 1=boot-loader, 3=id-reply
|
|
|
|
// send it.
|
|
stat = hdlc_send_raw(pm->hd, snd+40, NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|