/*
 * $Id: netio.c,v 1.3 1995/11/14 00:43:34 Rhialto Exp $
 * $Log: netio.c,v $
 * Revision 1.3  1995/11/14  00:43:34  Rhialto
 * More casts for yet stricter DICE type checking...
 *
 * Revision 1.2  1995/11/14  00:08:15  Rhialto
 * #ifdef -> #if.
 *
 * Revision 1.1  1993/12/02  20:45:46  Rhialto
 * Initial revision
 *
 *
 * Network file system: network I/O. This version for PARNET.DEVICE.
 */

#include "netfs.h"
#include "devices/parnet.h"

#if DEBUG
#   include "syslog.h"
#else
#   define	debug(x)
#endif

Prototype struct MsgPort *Port;
Prototype struct MsgPort *RdPort;
Prototype struct IOParReq *ParReq;
Prototype struct IOParReq *RdParReq[PENDREADS];
Prototype Packet	 *RdPkt[PENDREADS];
Prototype int		  MyAddr;
Prototype int		  PeerAddr;
Prototype int		  NetFSPort;

struct MsgPort *Port;
struct MsgPort *RdPort;
struct IOParReq *ParReq;
struct IOParReq *RdParReq[PENDREADS];
Packet	       *RdPkt[PENDREADS];
int		MyAddr;
int		PeerAddr;
int		NetFSPort;

Prototype void SendRead(struct IOParReq *io, Packet *pkt, ULONG size);

void
SendRead(struct IOParReq *io, Packet *pkt, ULONG size)
{
    io->io_Command = CMD_READ;
    io->io_Data    = pkt;
    io->io_Length  = size;
    io->io_Data2   = NULL;
    io->io_Length2 = 0;

    SendIO((struct IORequest *)io);
}

Prototype LONG DoReset(struct IOParReq *io);

LONG
DoReset(struct IOParReq *io)
{
    char	    pkt[STDREPLY];
    Packet	   *p = (Packet *)pkt;
    struct	    DateStamp ds;

    p->p_Type = pt_Reset;
    p->p_Origin = MyAddr;

    DateStamp(&ds);

    if (MyValidation == 0)
	MyValidation = (ds.ds_Days * 24*60 +
			ds.ds_Minute) * 60 +
		       ds.ds_Tick / TICKS_PER_SECOND;
    p->p_Validation = MyValidation;

    debug(("DoReset %d\n", MyValidation));

    io->io_Command = CMD_WRITE;
    io->io_Data    = pkt;
    io->io_Length  = sizeof(pkt);
    io->io_Data2   = NULL;
    io->io_Length2 = 0;

    return DoIO((struct IORequest *)io);
}

Prototype LONG DoResetReply(struct IOParReq *io);

LONG
DoResetReply(struct IOParReq *io)
{
    char	    pkt[STDREPLY];
    Packet	   *p = (Packet *)pkt;

    p->p_Type = pt_ResetReply;
    p->p_Origin = MyAddr;

    p->p_Validation = MyValidation;

    debug(("DoResetReply %d\n", MyValidation));

    io->io_Command = CMD_WRITE;
    io->io_Data    = pkt;
    io->io_Length  = sizeof(pkt);
    io->io_Data2   = NULL;
    io->io_Length2 = 0;

    return DoIO((struct IORequest *)io);
}

Prototype LONG DoProtocol(struct IOParReq *io, Packet *pkt);

LONG
DoProtocol(struct IOParReq *io, Packet *pkt)
{
    switch (pkt->p_Type) {
    case pt_Reply:
	return pt_Reply;
    case pt_Request:
	return pt_Request;
    case pt_AsyncReply:
	DoAsyncReply(pkt);      /* Different in client and server */
	return pt_Retry;
	break;
    case pt_Reset:
	/* Oops! Server reset! */
	Validation = pkt->p_Validation;
	DoResetReply(io);
	return pt_Reset;	/* No use in retrying */
    case pt_ResetReply:
	Validation = pkt->p_Validation;
	debug(("got ResetReply %d\n", Validation));
	/* fall through */
    default:
	/* Ignore bad packets, including mistaken pt_Requests */
	debug(("Must re-read a packet\n"));
	return pt_Retry;
    }
}

Prototype LONG InitReads(void);

LONG
InitReads(void)
{
    int 	    i;

    for (i = 0; i < PENDREADS; i++) {
	if ((RdPkt[i] = AllocMem(PKTSIZE, MEMF_PUBLIC)) == NULL)
	    return 4;
    }

    for (i = 0; i < PENDREADS; i++) {
	SendRead(RdParReq[i], RdPkt[i], PKTSIZE);
    }

    return 0;
}

Prototype ULONG OpenNetwork(void);

ULONG
OpenNetwork(void)
{
    ULONG	    error;
    int 	    i;

    Port = CreatePort("Net:NetIO", -1);
    if (Port == NULL)
	return 1;
    RdPort = CreatePort("Net:RdNetIO", -1);
    if (RdPort == NULL)
	return 1;
    ParReq = (struct IOParReq *)CreateExtIO(Port, sizeof(*ParReq));
    if (ParReq == 0)
	return 2;

    ParReq->io_Port = NetFSPort;
    ParReq->io_Flags = PRO_DGRAM;
    ParReq->io_Addr = PeerAddr;

    debug(("MyAddr %d PeerAddr %d Port %d\n", MyAddr, PeerAddr, NetFSPort));

    error = OpenDevice(DevName, 0, (struct IORequest *)ParReq, 0);
    if (error)
	return error;

    ParReq->io_Command = PPD_SETADDR;
    ParReq->io_Addr = MyAddr;
    DoIO((struct IORequest *)ParReq);

    ParReq->io_Addr = PeerAddr;

    if ((RdParReq[0] = (struct IOParReq *)CreateExtIO(RdPort, sizeof(*ParReq)))
	== NULL)
	return 3;

    RdParReq[0]->io_Device = ParReq->io_Device;
    RdParReq[0]->io_Unit   = ParReq->io_Unit;
    RdParReq[0]->io_Port   = NetFSPort;     /* not needed, just tidy */
    RdParReq[0]->io_Flags  = IOF_QUICK;

    for (i = 1; i < PENDREADS; i++) {
	if ((RdParReq[i] = (struct IOParReq *)CreateExtIO(RdPort,
	                                                  sizeof(*ParReq)))
	    == NULL)
	    return 4;
	*RdParReq[i] = *RdParReq[0];
    }

    InitReads();
    DoReset(ParReq);

    return 0;
}

Prototype ULONG CloseNetwork(void);

ULONG
CloseNetwork(void)
{
    int 	    i;

    if (ParReq) {
	if (ParReq->io_Device) {
	    CloseDevice((struct IORequest *)ParReq);
	}
	DeleteExtIO((struct IORequest *)ParReq);
	ParReq = NULL;
    }
    for (i = 0; i < PENDREADS; i++) {
	if (RdParReq[i]) {
	    AbortIO((struct IORequest *)RdParReq[i]);
	    WaitIO((struct IORequest *)RdParReq[i]);
	    DeleteExtIO((struct IORequest *)RdParReq[i]);
	}
	RdParReq[i] = NULL;
    }
    if (RdPort) {
	DeletePort(RdPort);
	RdPort = NULL;
    }
    if (Port) {
	DeletePort(Port);
	Port = NULL;
    }
    return 0;
}

