/*
 * $Id: netio1.c,v 1.3 1995/11/14 00:43:34 Rhialto Exp $
 * $Log: netio1.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 for the client only.
 * This version for PARNET.DEVICE.
 */

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

#include <string.h>

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

Prototype LONG SendRecv(void *sdata, ULONG slen, void *rdata, ULONG rlen);

LONG
SendRecv(Packet *sdata, ULONG slen, Packet *rdata, ULONG rlen)
{
    return SendRecv2(sdata, slen, NULL, 0, rdata, rlen, NULL, 0);
}

Prototype LONG Send2(Packet *sdata1, ULONG slen1, void *sdata2, ULONG slen2);

LONG
Send2(Packet *sdata1, ULONG slen1, void *sdata2, ULONG slen2)
{
    sdata1->p_Type = pt_Request;
    sdata1->p_Origin = MyAddr;

    ParReq->io_Command = CMD_WRITE;
    ParReq->io_Data    = sdata1;
    ParReq->io_Length  = slen1;
    ParReq->io_Data2   = sdata2;
    ParReq->io_Length2 = slen2;

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

Prototype LONG SendRecv2(Packet *sdata1, ULONG slen1, void *sdata2, ULONG slen2, Packet *rdata1, ULONG rlen1, void *rdata2, ULONG rlen2);

LONG
SendRecv2(Packet *sdata1, ULONG slen1, void *sdata2, ULONG slen2,
	  Packet *rdata1, ULONG rlen1, void *rdata2, ULONG rlen2)
{
    Packet	   *pkt;
    LONG	    ioerror = 0;
    struct IOParReq *io;

    debug(("Send %d %d, expect %d %d\n", slen1, slen2, rlen1, rlen2));
    if (ioerror = Send2(sdata1, slen1, sdata2, slen2)) {
	error = ERROR_NO_DISK;
	return ioerror;
    }

reread:
    WaitPort(RdPort);             /* XXX timeout & retry here */
    io = (struct IOParReq *)GetMsg(RdPort);
    pkt = io->io_Data;

    debug(("Receive %d\n", io->io_Actual));
    if (io->io_Error && (io->io_Error != PPERR_WARN_OVFLOW)) {
	debug(("parnet error = %d\n", io->io_Error));
	ioerror = io->io_Error;
	error = ERROR_NO_DISK;
	goto end;
    }

    switch (DoProtocol(io, pkt)) {
    case pt_Reply:
	/* This is what we want */
	memcpy(rdata1, pkt, rlen1);
	if (rlen2 && (slen2 = io->io_Actual - rlen1) > 0) {
	    memcpy(rdata2, (char *)pkt + rlen1, slen2);
	}
	break;
    case pt_Reset:
	ioerror = pt_Reset;	/* No use in retrying */
	break;
    default:
	/* Ignore bad packets, including mistaken pt_Requests */
	SendRead(io, pkt, PKTSIZE);
	debug(("Re-read a packet\n"));
	goto reread;
    }

end:
    SendRead(io, pkt, PKTSIZE);

    return ioerror;
}

Prototype void ClientDefaults(ULONG type, ULONG addrs);

void
ClientDefaults(ULONG type, ULONG addrs)
{
    debug(("ClientDefaults %x %x\n", type, addrs));

    switch (type) {
    case 0:
	/* Primary client/server */
	MyAddr = CLI_ADDR;
	PeerAddr = SRV_ADDR;
	NetFSPort = NETFS_PORT;
	break;
    case 1:
	/* Secondary server/client */
	MyAddr = SRV_ADDR;
	PeerAddr = CLI_ADDR;
	NetFSPort = NETFS_PORT + 1;
	break;
    case 2:
	/* Custom installation */
/*
 * Interleave = 0xppppsscc, where
 * pppp: the port number the server is using (in hex)
 * ss  : the parnet address of the server (in hex, 0x01 .. 0xFE)
 * cc  : the parnet address of this client (in hex, 0x01 .. 0xFE)
 */
	MyAddr =     addrs	  & 0x00FF;
	PeerAddr =  (addrs >>  8) & 0x00FF;
	NetFSPort = (addrs >> 16) & 0xFFFF;
	break;
    }
}
