Files
Zorro-LAN-IDE/Driver/baxnet/server.c
T

862 lines
21 KiB
C

/*
server.c
(C) 2018 Henryk Richter <henryk.richter@gmx.net>
Main Dispatcher
TODO: sort multicast addresses and ranges
*/
#include <proto/exec.h>
#include <proto/utility.h>
#include <proto/dos.h>
#include <proto/timer.h>
#include <dos/dostags.h>
#include <devices/timer.h>
#include "device.h"
#include "hw.h"
#include "macros.h"
#include "server.h"
/* (avoid external link libraries) this call is not time critical */
static void MemSet( void *a, ULONG val, ULONG size )
{
UBYTE *p = (UBYTE*)a;
while( size-- )
*p++ = (UBYTE)val;
}
static void server_AbortList( DEVBASEP, struct List*list )
{
struct IOSana2Req *ioreq;
while( (ioreq = (struct IOSana2Req *)GetHead( list )) )
{
Remove( (struct Node*)ioreq );
ioreq->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ioreq->ios2_WireError = S2WERR_UNIT_OFFLINE;
svTermIO( db, ioreq );
}
}
/* cancel all pending requests */
static void server_Offline_CancelRequests( DEVBASEP , ULONG unit )
{
struct SanaReadType *type;
struct SanaReader *rd;
D(("server_Offline_CancelRequests for unit %ld\n",unit));
ObtainSemaphore( &db->db_Units[unit].du_Sem );
/* start with the read list -> types -> readers -> reqlist */
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
while( type )
{
rd = (struct SanaReader *)GetHead( &type->srt_Readers );
while( rd )
{
server_AbortList( db, &rd->snr_Requests );
rd = GetSucc( rd );
}
type = GetSucc( type );
}
server_AbortList( db, (struct List*)&db->db_Units[unit].du_WriteQueue );
server_AbortList( db, (struct List*)&db->db_Units[unit].du_EventQueue );
server_AbortList( db, (struct List*)&db->db_Units[unit].du_ReadOrphans );
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
/* clear Multicast list, TODO: subroutine */
{
struct MCastEntry *entry;
while(1)
{
entry = (struct MCastEntry *)db->db_svdat.sv_mclist.lh_Head;
if( !entry->mce_Node.mln_Succ )
break;
REMOVE(entry);
FreeMem(entry,sizeof(struct MCastEntry));
}
}
D(("server_Offline_CancelRequests done\n"));
}
static LONG server_setOnline( DEVBASEP , ULONG unit, ULONG evt )
{
D(("Unit %ld online command\n",unit));
if( db->db_Units[unit].du_Flags & DUF_ONLINE )
{
D(("Was Online already\n"));
return SERR_OK;
}
if( !hw_Attach( db, unit ) )
{
D(("Hardware hw_attach Fail\n"));
return SERR_ERROR;
}
D(("hw_attach success\n"));
{ /* track last opening time */
struct timerequest timereq;
struct Library *TimerBase;
MemSet( &timereq, 0, sizeof(struct timerequest));
OpenDevice("timer.device", 0, (struct IORequest*)&timereq, 0);
TimerBase = (struct Library *)timereq.tr_node.io_Device;
GetSysTime( &db->db_Units[unit].du_DevStats.LastStart );
CloseDevice( (struct IORequest*)&timereq);
}
db->db_Units[unit].du_Flags |= DUF_ONLINE;
if( evt )
{
ObtainSemaphore( &db->db_Units[unit].du_Sem );
server_SendEvent(db, unit, S2EVENT_ONLINE );
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
}
D(("Unit %ld online\n",unit));
return SERR_OK;
}
static void server_setOffline( DEVBASEP , ULONG unit, ULONG evt )
{
D(("Unit %ld offline command\n",unit));
if( !(db->db_Units[unit].du_Flags & DUF_ONLINE ))
return;
hw_Detach( db,unit );
db->db_Units[unit].du_Flags &= ~(DUF_ONLINE);
if( evt )
{
ObtainSemaphore( &db->db_Units[unit].du_Sem );
server_SendEvent(db, unit, S2EVENT_OFFLINE );
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
}
D(("Unit %ld offline\n",unit));
}
/* check for online status following closeDevice */
static void server_CloseDevice_offline( DEVBASEP )
{
LONG unit;
unit=0;BOARDLOOP( ( ; unit < db->db_NBoards ; unit++ ) )
{
/* bring unit offline if no opener left */
if( !db->db_Units[unit].du_OpenCount )
{
if( db->db_Units[unit].du_Flags & DUF_ONLINE )
{
server_setOffline( db, unit, 0 );
server_Offline_CancelRequests( db, unit );
}
}
}
}
/* IMPORTANT: base pointer is unavailable here until
retrieved from incoming message */
static struct ServerMsg *server_startup(void)
{
struct ServerMsg *msg;
struct Process *self;
struct { struct Library *db_SysBase; } *db = (void*)0x4;
self = (struct Process*)FindTask(NULL);
D(("Waiting for Message from Device\n"));
WaitPort( &self->pr_MsgPort);
msg = (struct ServerMsg *)GetMsg( &self->pr_MsgPort );
return msg;
}
/* real init, now with active device base */
static LONG server_init( DEVBASEP )
{
LONG ret = SERR_ERROR;
NEWLIST( &db->db_svdat.sv_mclist ); /* list of multicast addresses to accept on RX */
db->db_ServerPort = CreateMsgPort(); /* forwarded IO Requests */
if( db->db_ServerPort )
{
if( hw_Setup( db ) ) /* management stuff for hardware: interrupts, timers, memory etc. */
{
db->db_svdat.sv_framesize = ETH_MTU+18+8; /* 1514 = RAW IEE802.2, 1518 = with VLAN TAG, +8 for safety */
db->db_svdat.sv_frame = AllocMem( db->db_svdat.sv_framesize, MEMF_PUBLIC );
if( db->db_svdat.sv_frame )
ret = SERR_OK;
}
}
return ret;
}
static void server_up( DEVBASEP , struct ServerMsg *msg, LONG updown )
{
msg->sm_result = updown;
ReplyMsg( &msg->sm_msg );
D(("Replied to Startup Message with %ld\n",updown));
}
static LONG server_shutdown( DEVBASEP )
{
hw_Shutdown( db );
if( (db->db_svdat.sv_framesize) && (db->db_svdat.sv_frame) )
FreeMem( db->db_svdat.sv_frame, db->db_svdat.sv_framesize );
db->db_svdat.sv_frame = (0);
if( db->db_ServerPort )
DeleteMsgPort(db->db_ServerPort);
db->db_ServerPort = (0);
return SERR_OK;
}
/* read config file (if present) and reconfigure HW parameters */
const BYTE configtemplate[] = COMMON_TEMPLATE HW_CONFIGTEMPLATE;
static LONG server_Config( DEVBASEP )
{
BPTR cfgfile;
LONG i;
hw_ConfigInit( db ); /* hw defaults */
if((cfgfile = Open(HW_CONFIGFILE, MODE_OLDFILE))) /* see hwprivate.h for CONFIGFILE */
{
struct HWConfig args; /* see hwprivate.h */
struct RDArgs *readargs;
cfgfile = SelectInput(cfgfile); /* get default Input */
MemSet( &args, 0, sizeof( args ) );
readargs = ReadArgs( (BYTE*)configtemplate, (LONG *)&args, NULL);
Close( SelectInput( cfgfile ) ); /* restore default input and retrieve cfgfile */
if( readargs )
{
/* copy common variables */
if(args.common.priority)
SetTaskPri((struct Task*)db->db_ServerProc,BOUNDS(*args.common.priority, MINPRIORITY, MAXPRIORITY));
i=0;BOARDLOOP( ( ; i < db->db_NBoards ; i++ ) )
{
if( args.common.bps )
db->db_Units[i].du_BitPerSec = *args.common.bps;
if( args.common.mtu )
db->db_Units[i].du_MTU = *args.common.mtu;
}
#if 0 /* ignored for now but kept in template for compatibility with old codebase */
if(args.common.nospecialstats)
#endif
hw_ConfigUpdate( db, &args );
FreeArgs( readargs );
}
}
return SERR_OK;
}
static LONG CMPeqMAC( BYTE *a, BYTE *b )
{
LONG i;
for( i=0 ; i<6 ; i++ )
{
if( a[i] != b[i] )
return 0;
}
return 1;
}
static LONG server_changeMulticast( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, ULONG add_del )
{
/* step 1: find start address in active list */
struct MCastEntry *entry;
LONG ret = 1;
entry = (struct MCastEntry *)db->db_svdat.sv_mclist.lh_Head;
while( entry->mce_Node.mln_Succ )
{
if( CMPeqMAC( entry->mce_start, ioreq->ios2_SrcAddr ) )
break;
entry = (struct MCastEntry *)entry->mce_Node.mln_Succ;
}
/* did we have a prior entry ? */
if( entry->mce_Node.mln_Succ )
{
if( add_del )
{
entry->mce_refcount++;
goto apply;
}
else
{
if( entry->mce_refcount > 1 )
{
entry->mce_refcount--;
goto apply;
}
else
{
REMOVE(entry);
FreeMem( entry, sizeof( struct MCastEntry ) );
goto apply;
}
}
}
/* prior not found */
if( !add_del )
{
ret = 0; /* ERROR: CAN`T DELETE NONEXISTENT ENTRY */
goto donothing;
}
/* add new entry */
entry = (struct MCastEntry*)AllocMem( sizeof( struct MCastEntry ), MEMF_PUBLIC|MEMF_CLEAR );
if( !entry )
{
ret = 0;
goto donothing;
}
entry->mce_refcount = 1;
COPYMAC( entry->mce_start, ioreq->ios2_SrcAddr );
COPYMAC( entry->mce_stop, ioreq->ios2_SrcAddr );
ADDTAIL( &db->db_svdat.sv_mclist, entry );
apply:
hw_change_multicast( db, unit, &db->db_svdat.sv_mclist );
donothing:
return ret;
}
/* forwarded commands (online/offline etc.) */
static LONG server_HandleS2Commands( DEVBASEP )
{
ULONG unit;
struct IOSana2Req *ioreq;
while( (ioreq = (struct IOSana2Req *)GetMsg(db->db_ServerPort)) )
{
unit = (ULONG)ioreq->ios2_Req.io_Unit;
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
switch( ioreq->ios2_Req.io_Command)
{
case S2_ONLINE:
if( server_setOnline(db,unit,1 ) != SERR_OK )
{
ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
}
break;
case S2_OFFLINE:
server_setOffline( db, unit, 1 ); /* ,1: send event to opener */
server_Offline_CancelRequests( db, unit );
break;
case S2_CONFIGINTERFACE:
COPYMAC( db->db_Units[unit].du_CFGAddr, ioreq->ios2_SrcAddr );
if( db->db_Units[unit].du_Flags & DUF_ONLINE )
server_setOffline( db, unit,0 );
server_setOnline( db, unit,0 );
break;
case S2_ADDMULTICASTADDRESS:
if( server_changeMulticast( db, unit, ioreq, 1 ) )
{
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
}
else
{
ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
}
break;
case S2_DELMULTICASTADDRESS:
if( server_changeMulticast( db, unit, ioreq, 0 ) )
{
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
}
else
{
ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
}
break;
default: /* shouldn't happen */
ioreq->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
break;
}
svTermIO( db, ioreq );
}
return SERR_OK;
}
/* error conditions sent via EventQueue */
static LONG server_SendEvent( DEVBASEP, ULONG unit, ULONG evtmask )
{
struct IOSana2Req *ioreq;
/* Semaphore is locked outside */
/* ObtainSemaphore( &db->db_Units[unit].du_Sem ); */
for( ioreq = (struct IOSana2Req *)db->db_Units[unit].du_EventQueue.lh_Head;
(ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
ioreq = (struct IOSana2Req *)ioreq->ios2_Req.io_Message.mn_Node.ln_Succ )
{
if( ioreq->ios2_WireError & evtmask )
{
Remove( (struct Node*)ioreq );
svTermIO( db, ioreq );
break;
}
}
/* ReleaseSemaphore( &db->db_Units[unit].du_Sem ); */
return SERR_OK;
}
/* handle write errors */
LONG server_writeerror( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, LONG code )
{
if (code == SERR_BUFFER_ERROR) /* no buffer management callback or copy error */
{
D(("buffer error (TX)\n"));
server_SendEvent(db, unit, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
/* db->db_SpecialStats[S2SS_TXERRORS].Count++; */
ioreq->ios2_Req.io_Error = S2ERR_SOFTWARE;
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
}
else /* if (code != SERR_OK) */
{
D(("TX error\n"));
server_SendEvent(db, unit, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
/* db->db_SpecialStats[S2SS_TXERRORS].Count++; */
ioreq->ios2_Req.io_Error = S2ERR_TX_FAILURE;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
}
Remove((struct Node*)ioreq);
svTermIO( db, ioreq ); /* SANA2IOF_QUICK is off for write queue, just ReplyMsg */
return 0;
}
#ifndef EXTERNAL_WRITE_FRAME
/* note: entering here with locked semaphore */
static LONG write_frame( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq )
{
LONG ret = SERR_OK;
UBYTE *copy_ptr,*frame;
ULONG framesize;
struct db_BufferManagement *dbm;
D(("write: type %08lx, size %ld\n",ioreq->ios2_PacketType,
ioreq->ios2_DataLength));
frame = db->db_svdat.sv_frame;
framesize = ioreq->ios2_DataLength;
copy_ptr = frame;
/* copy raw frame: simply overwrite ethernet frame part of plip packet */
if( !(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) )
{
COPYMAC( frame, ioreq->ios2_DstAddr ); /* macro in server.h */
COPYMAC( frame+6, db->db_Units[unit].du_CFGAddr );
*( (USHORT*)(frame+12)) = ioreq->ios2_PacketType;
copy_ptr += 14;
framesize += 14;
}
dbm = (struct db_BufferManagement *)ioreq->ios2_BufferManagement;
/* copy32 is valid ptr, even if the stack offers only regular CopyFromBuffer */
if( (*dbm->dbm_CopyFromBuffer32)(copy_ptr,ioreq->ios2_Data, ioreq->ios2_DataLength) )
{
send:
D(("+hw_send\n"));
ret = hw_send_frame(db, unit, frame, framesize) ? SERR_OK : SERR_ERROR;
D(("-hw_send\n"));
}
else
{
/* if copy32 fails, try regular call */
if( (*dbm->dbm_CopyFromBuffer)(copy_ptr,ioreq->ios2_Data, ioreq->ios2_DataLength) )
goto send;
else
ret = SERR_BUFFER_ERROR;
}
return ret;
}
#endif
static LONG server_writequeue( DEVBASEP, ULONG unit )
{
LONG code;
struct IOSana2Req *ioreq,*nextio;
ObtainSemaphore( &db->db_Units[unit].du_Sem );
#if 1
/* whole queue per call */
for( ioreq = (struct IOSana2Req *)db->db_Units[unit].du_WriteQueue.lh_Head;
(nextio= (struct IOSana2Req *)ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
ioreq = nextio )
#else
/* single write per call */
ioreq = (struct IOSana2Req *)db->db_Units[unit].du_WriteQueue.lh_Head;
if( ioreq->ios2_Req.io_Message.mn_Node.ln_Succ )
#endif
{
code = write_frame( db, unit, ioreq );
if( code >= 0 )
{
/* statistics ? */
if( db->db_Units[unit].du_Flags & DUF_TYPETRACK )
{
struct SanaReadType *type;
type = (struct SanaReadType *)GetHead( &db->db_Units[unit].du_ReadTypes );
while( type )
{
if( type->srt_Type == ioreq->ios2_PacketType )
{
type->srt_Sana2PacketTypeStats.PacketsSent++;
type->srt_Sana2PacketTypeStats.BytesSent += ioreq->ios2_DataLength;
break;
}
type = GetSucc( type );
}
}
db->db_Units[unit].du_DevStats.PacketsSent++;
ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
REMOVE( (struct Node*)ioreq );
svTermIO( db, ioreq ); /* SANA2IOF_QUICK is off for write queue, just ReplyMsg */
}
else
{
/* error handling */
server_writeerror( db, unit, ioreq, code );
}
}
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
return SERR_OK;
}
/* note: entering here with locked semaphore */
static void server_read_frame( DEVBASEP, ULONG unit, struct IOSana2Req *ioreq, UBYTE *frame, ULONG framesize )
{
struct db_BufferManagement *dbm;
ULONG bcflag = 0;
COPYMAC( ioreq->ios2_DstAddr, frame ); /* macro in server.h */
COPYMAC( ioreq->ios2_SrcAddr, frame+6 );
if( *frame & 1 ) /* just check Ethernet MULTICAST flag */
{
ULONG mac = *((ULONG*)frame );
bcflag = SANA2IOF_MCAST;
if( mac == 0xffffffff ) /* evil: ignore the lower 16 bit... */
bcflag = SANA2IOF_BCAST; /* special case of multicast, actually */
#if 0
mac >>= 8;
if( mac == 0x0001005e ) /* IPv4 MCAST */
bcflag = SANA2IOF_MCAST;
#endif
}
if( !(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) )
{
frame += 14; /* skip DST,SRC,Type */
framesize -= 18; /* also remove CRC */
D(("plain mode: frame flags %ld\n",bcflag));
}
ioreq->ios2_Req.io_Flags &= SANA2IOF_RAW; /* ignore all other flags */
ioreq->ios2_Req.io_Flags |= bcflag;
ioreq->ios2_Req.io_Error = 0;
ioreq->ios2_WireError = 0;
dbm = (struct db_BufferManagement *)ioreq->ios2_BufferManagement;
D(("ReadFrm IO %lx, DBM %lx frm %lx frmsz %ld\n",(ULONG)ioreq,(ULONG)dbm,(ULONG)frame,framesize));
if(!(*dbm->dbm_CopyToBuffer32)(ioreq->ios2_Data, frame, framesize ))
{
if(!(*dbm->dbm_CopyToBuffer)(ioreq->ios2_Data, frame, framesize ))
{
ioreq->ios2_Req.io_Error = S2ERR_SOFTWARE;
ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
}
}
D(("Copied io_Error %ld\n",(LONG)ioreq->ios2_Req.io_Error));
Remove( (struct Node*)ioreq );
svTermIO( db, ioreq );
}
/* it is assumed that hw_recv_pending() was called before entering here */
static LONG server_readqueue( DEVBASEP, ULONG unit )
{
struct SanaReadType *type;
struct SanaReader *rd;
struct IOSana2Req *ioreq;
UBYTE *frame = db->db_svdat.sv_frame;
LONG framesize;
LONG frametype;
LONG dropflag;
while(1)
{
if( (framesize = hw_recv_frame(db, unit, frame) ) > 0 )
{
/* TODO: devstats */
frametype = *( (USHORT*)(frame+12) );
D(("Have Frame size %ld type %ld\n",framesize,frametype));
ObtainSemaphore( &db->db_Units[unit].du_Sem );
type = (struct SanaReadType *)db->db_Units[unit].du_ReadTypes.lh_Head;
while( (type->srt_Node.mln_Succ) )
{
if( type->srt_Type == frametype )
goto havetype;
type = (struct SanaReadType *)type->srt_Node.mln_Succ;
}
/* desired type not found, get orphan list */
db->db_Units[unit].du_DevStats.UnknownTypesReceived++;
orphan:
ioreq = (struct IOSana2Req *)GetHead( (struct List*)&db->db_Units[unit].du_ReadOrphans );
if( ioreq )
{
D(("Orphaned Frame\n"));
ioreq->ios2_PacketType = frametype;
server_read_frame( db, unit, ioreq, frame, framesize );
}
else
{
D(("No ioreq for orphaned frame\n"));
}
goto nextframe;
havetype:
/* push frame to all readers */
/*if( type->srt_Flags & SRTF_TRACKTYPE )*/ /* stats ? */
{
/* type->srt_Sana2PacketTypeStats.PacketsSent++; */
/* type->srt_Sana2PacketTypeStats.BytesSent++; */
/* type->srt_Sana2PacketTypeStats.PacketsDropped++; */
type->srt_Sana2PacketTypeStats.PacketsReceived++;
type->srt_Sana2PacketTypeStats.BytesReceived += framesize;
}
db->db_Units[unit].du_DevStats.PacketsReceived++;
rd = (struct SanaReader *)type->srt_Readers.lh_Head;
dropflag = 1;
while( rd->snr_Node.mln_Succ )
{
ioreq = (struct IOSana2Req *)rd->snr_Requests.lh_Head;
if( ioreq->ios2_Req.io_Message.mn_Node.ln_Succ )
{
server_read_frame( db, unit, ioreq, frame, framesize );
dropflag = 0;
}
rd = (struct SanaReader *)rd->snr_Node.mln_Succ;
}
if( dropflag )
{
db->db_Units[unit].du_DevStats.Overruns++;
type->srt_Sana2PacketTypeStats.PacketsDropped++;
D(("No Reader for frame\n"));
goto orphan; /* does it help if we give the frame to the orphan list? */
}
nextframe:
ReleaseSemaphore( &db->db_Units[unit].du_Sem );
}
else
{
/* TODO: check for error, send S2EVENT_HARDWARE|S2EVENT_ERROR|S2EVENT_RX along with stats db_DevStats.BadData */
goto end;
}
}
end:
return SERR_OK;
}
VOID SAVEDS ServerTask(void)
{
struct ServerMsg *msg;
ULONG wmask,gotmask,spcmask,portsigmask,recvmask,i=0,action;
struct IOSana2Req*wr;
struct DevUnit *curunit;
DEVBASEP = (0); /* Don`t call Libraries until server_startup() succeeds! */
msg = server_startup();
if( !msg )
goto QuitServer; /* unlikely */
db = msg->sm_devbase;
if( !server_init( db ) )
{
server_up( db, msg, 0 );
goto QuitServer;
}
server_Config( db ); /* load config (if present) */
server_up( db, msg, 1 ); /* init done, server is active */
/*----------------------------------------------------------------------*/
/*-------------------------- MAIN LOOP --------------------------------*/
/*----------------------------------------------------------------------*/
portsigmask = 1<<db->db_ServerPort->mp_SigBit;
recvmask = hw_recv_sigmask( db );
wmask = SIGBREAKF_CTRL_F|SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|portsigmask|recvmask;
spcmask= SIGBREAKF_CTRL_C|portsigmask|SIGBREAKF_CTRL_D;
D(("Portsigmask %ld RecvMask %ld wmask %ld\n",portsigmask,recvmask,wmask));
action = 0;
gotmask = 0;
while(1)
{
if( !action ) /* queues quiet ? -> sleep */
{
i=0;BOARDLOOP( ( ; i < db->db_NBoards ; i++ ) )
{ /* housekeeping -> check for link change on idle, re-enable interrupts etc. */
hw_check_link_change(db,i);
}
gotmask = Wait(wmask);
}
action = 0; /* any action on the queues ? */
curunit = &db->db_Units[0];
i=0;BOARDLOOP( (; i < db->db_NBoards ; i++ ) ) /* skip the for() when just a single device is supported */
{
if( curunit->du_Flags & DUF_ONLINE )
{
/* D(("BoardLoop %ld\n",i)); */
wr = (struct IOSana2Req *)curunit->du_WriteQueue.lh_Head; /* don't bother with semaphore, lh_Head is always !=0 */
if( wr->ios2_Req.io_Message.mn_Node.ln_Succ ) /* quick check for write reqs */
{
server_writequeue( db, i );
action = 1;
}
if( hw_recv_pending(db,i) )
{
D(("Read on unit %ld start\n",i));
server_readqueue( db, i );
D(("Read on unit %ld stop\n",i));
action = 1;
}
}
curunit++;
}
if( gotmask & spcmask ) /* rare flags */
{
if( gotmask & portsigmask )
{
D(("SANA-II request handling commencing\n"));
server_HandleS2Commands( db );
gotmask &= ~portsigmask;
}
if( gotmask & SIGBREAKF_CTRL_D )
{
D(("Got CTRL-D in Server. Checking Online status\n"));
gotmask &= ~SIGBREAKF_CTRL_D;
server_CloseDevice_offline( db );
}
if( gotmask & SIGBREAKF_CTRL_C )
{
D(("Got CTRL-C in Server. leaving.\n"));
break;
}
}
}
server_shutdown( db );
QuitServer:
if( db )
db->db_ServerProc = (0);
{ /* revert to "real" execbase, in case that we never got the startup msg */
struct { struct Library *db_SysBase; } *db = (void*)0x4;
D(("Server exiting"));
Forbid();
}
}