/*	conf.c	6.1	83/07/29	*/


#include "../h/param.h"
#include "../h/inode.h"
#include "../h/fs.h"


#include "saio.h"

#ifdef	LATER

#define	NSABUFS	24
#define	lru(p)	\
		p->sab_next->sab_prev = p->sab_prev;\
		p->sab_prev->sab_next = p->sab_next;\
		sabhead.sab_prev->sab_next = p;\
		p->sab_prev = sabhead.sab_prev;\
		p->sab_next = (struct sabuf *) &sabhead;\
		sabhead.sab_prev = p;

struct	sabuf {
	struct sabuf	*sab_next,
			*sab_prev;
	daddr_t		sab_blkno;
	dev_t		sab_dev;
	char		sab_buf[MAXBSIZE];
} sabuf[NSABUFS];

struct	sa_bhead {
	struct sabuf	*sab_next,
			*sab_prev;
}sabhead;
#endif	LATER


/*
 * Devread -- read from the specified device.
 *
 * The device is specified as an index in the devsw[] array of device drivers.
 * The index is io->i_dev.  The io structure contains an address, a block
 * number and a character count, among other valuable data, used by the read
 * routine itself.
 *
 * Returns: a count of the bytes read. -1 on error. On error, io->i_error is
 * typically set by the driver routine for publication in the outside world.
 */
devread(io)
	register struct iob *io;
{
	int cc;

#ifdef	LATER
	register struct sabuf *sap;
	char	 *obuf;	
	int	occ;

	if (sabhead.sab_next == 0) { 	/* Initialize list */
		sabhead.sab_next = (struct sabuf *) &sabhead;
		sabhead.sab_prev = (struct sabuf *) &sabhead;
		for (cc = 0, sap = sabuf; cc < NSABUFS; cc++, sap++) {
			sap->sab_prev = sabhead.sab_prev;
			sap->sab_next = (struct sabuf *) &sabhead;
			sabhead.sab_prev->sab_next = sap;
			sabhead.sab_prev = sap;
		}
	}
	sap = sabhead.sab_next;
	if ((io->i_flgs & F_TAPE) == 0) {
		while (sap != (struct sabuf *) &sabhead) {
			if (sap->sab_dev == io->i_dev &&
			    sap->sab_blkno == io->i_bn) {
				bcopy (sap->sab_buf, io->i_ma, io->i_cc);
				lru (sap);
				return io->i_cc;
			}
			sap = sap->sab_next;
		}
		sap = sabhead.sab_next;
		obuf = io->i_ma;
		occ = io->i_cc;
		io->i_ma = sap->sab_buf;
		io->i_cc = MAXBSIZE;
	}
#endif	LATER
	io->i_flgs |= F_RDDATA;
	io->i_error = 0;
#ifndef INODE_LIVES_IN_IOB
	/*
	 * Don't use (possibly nonexistent) inode for device number.
	 */
	cc = (*devsw[io->i_dev].dv_strategy)(io, READ);
#else   INODE_LIVES_IN_IOB
	/*
	 * Inode contains device number.
	 */
	cc = (*devsw[io->i_ino->i_dev].dv_strategy)(io, READ);
#endif  INODE_LIVES_IN_IOB
	io->i_flgs &= ~F_TYPEMASK;
#ifdef	LATER
	if ((io->i_flgs & F_TAPE) == 0) {
		io->i_ma = obuf;
		io->i_cc = occ;
		bcopy (sap->sab_buf, io->i_ma, io->i_cc);
		sap->sab_blkno = io->i_bn;
		sap->sab_dev = io->i_dev;
		lru (sap);
	}
#endif	LATER
	return (cc);
}

/*
 * Devwrite -- write to the specified device.
 *
 * The device is specified as an index in the devsw[] array of device drivers.
 * The index is io->i_dev.  The io structure contains an address, a block
 * number and a character count, among other valuable data, used by the read
 * routine itself.
 *
 * Like UNIX, the drivers themselves contain, instead of a read and a write
 * routine, one single strategy routine to deal with reads and writes in the
 * same fashion.
 *
 * Returns: a count of the bytes written. -1 on error. On error, io->i_error is
 * typically set by the driver routine for publication in the outside world.
 */
devwrite(io)
	register struct iob *io;
{
	int cc;

#ifdef	LATER
	register struct sabuf *sap;
	
	if (sabhead.sab_next == 0) { 	/* Initialize list */
		sabhead.sab_next = (struct sabuf *) &sabhead;
		sabhead.sab_prev = (struct sabuf *) &sabhead;
		for (cc = 0, sap = sabuf; cc < NSABUFS; cc++, sap++) {
			sap->sab_prev = sabhead.sab_prev;
			sap->sab_next = (struct sabuf *) &sabhead;
			sabhead.sab_prev->sab_next = sap;
			sabhead.sab_prev = sap;
			sap->sab_blkno = 1;
		}
	}
	sap = sabhead.sab_next;
	if ((io->i_flgs & F_TAPE) == 0)
		while (sap != (struct sabuf *) &sabhead) {
			if (sap->sab_dev == io->i_dev &&
			    sap->sab_blkno == io->i_bn) {
				bcopy (io->i_ma, sap->sab_buf, MAXBSIZE);
				lru (sap);
				break;
			}
			sap = sap->sab_next;
		}
#endif	LATER
	io->i_flgs |= F_WRDATA;
	io->i_error = 0;
#ifndef INODE_LIVES_IN_IOB
	/*
	 * Inode may not exist yet -- use io->i_dev for device #.
	 */
	cc = (*devsw[io->i_dev].dv_strategy)(io, WRITE);
#else   INODE_LIVES_IN_IOB
	/*
	 * Inode is a part of the iob structure, and contains the device #.
	 */
	cc = (*devsw[io->i_ino->i_dev].dv_strategy)(io, WRITE);
#endif  INODE_LIVES_IN_IOB
	io->i_flgs &= ~F_TYPEMASK;
	return (cc);
}

/*
 * Devopen -- open the specified device.
 *
 * The device is, again, specified by io->i_dev.  The device driver open
 * routine called will perform whatever initializations are necessary to
 * prepare for subsequent reads and writes to and from the device.
 *
 * This routine returns caca.  Don't look at it;  instead, look at io->i_error,
 * which will probably be set in case of error, and cleared otherwise.
 */
devopen(io)
	register struct iob *io;
{

#ifndef INODE_LIVES_IN_IOB
	/*
	 * Inode may not exist yet -- use io itself for device #.
	 */
	(*devsw[io->i_dev].dv_open)(io);
#else   INODE_LIVES_IN_IOB
	/*
	 * Inode always exists and contains the device #.
	 */
	(*devsw[io->i_ino->i_dev].dv_open)(io);
#endif  INODE_LIVES_IN_IOB
}

/*
 * Devclose -- close the specified device.
 *
 * The device is, again, specified by io->i_dev.  The device driver close
 * routine called will perform whatever steps are deemed necessary to
 * clean up after possible previous reads and writes to and from the device.
 *
 * This routine returns caca.  Don't look at it;  instead, look at io->i_error,
 * which will probably be set in case of error.
 */
devclose(io)
	register struct iob *io;
{

#ifndef INODE_LIVES_IN_IOB
	/*
	 * Inode may not exist yet -- use io itself for device #.
	 */
	(*devsw[io->i_dev].dv_close)(io);
#else   INODE_LIVES_IN_IOB
	/*
	 * Inode always exists and contains the device #.
	 */
	(*devsw[io->i_ino->i_dev].dv_close)(io);
#endif  INODE_LIVES_IN_IOB
}

/*
 * Devioctl -- Perform weird acts upon the specified device.
 *
 * The device is specified by io->i_dev.  The device driver ioctl routine
 * will support a number of IO control calls which may vary from driver to
 * driver.  For instance, the disk drivers probably support getting and setting
 * drive label parameters, while the tape drive doesn't.  You can rewind the
 * tape, but not the disk.  And so on.
 *
 * This routine returns -1 on error, and 0 otherwise.
 */
devioctl(io, cmd, arg)
	register struct iob *io;
	int cmd;
	caddr_t arg;
{

#ifndef INODE_LIVES_IN_IOB
	/*
	 * Inode may not exist yet -- use io itself for device #.
	 */
	return ((*devsw[io->i_dev].dv_ioctl)(io, cmd, arg));
#else   INODE_LIVES_IN_IOB
	/*
	 * Inode always exists and contains the device #.
	 */
	return ((*devsw[io->i_ino->i_dev].dv_ioctl)(io, cmd, arg));
#endif  INODE_LIVES_IN_IOB
}

/* The following two routines are here to be stuck in devsw[] only. */

/*
 * Nullsys
 *
 * Handy-dandy stub routine for putting in tables of routines.
 * Doesn't particularly do anything (but see below).
 */
/*ARGSUSED*/
nullsys(io)
	struct iob *io;
{

	;
}

/*
 * Nullioctl
 *
 * Another handy dandy stub routine for putting in tables of routines.
 * This one always returns an error condition.
 */
/*ARGSUSED*/
nullioctl(io, cmd, arg)
	struct iob *io;
	int cmd;
	caddr_t arg;
{

	return (ECMD);
}

/* Routines used in devsw[] */

int	nullsys(), nullioctl();

int	rdstrategy(), rdopen(), rdioctl();
int	rtstrategy(), rtopen();
int	idstrategy(), idopen(), idioctl();
int	itstrategy(), itopen();

/*
 * Devsw is a table of read, write, open, close and ioctl routines,
 * indexed by device type and operation.  See "saio.h" for the structure
 * definition.
 */
struct devsw devsw[] = {
	{ "rd",	rdstrategy,	rdopen,		nullsys,	rdioctl },
	{ "id",	idstrategy,	idopen,		nullsys,	idioctl },
	{ "it",	itstrategy,	itopen,		nullsys,	nullioctl },
	{ "rt",	rtstrategy,	rtopen,		nullsys,	nullioctl },
	{ 0, 0, 0, 0, 0 },
};
