4.3BSD-Tahoe/usr/src/sys/vax/flp.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1982, 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)flp.c	7.1 (Berkeley) 6/5/86
 */

#if VAX780
#include "param.h"
#include "systm.h"
#include "conf.h"
#include "dir.h"
#include "user.h"
#include "buf.h"
#include "uio.h"

#include "cons.h"
#include "cpu.h"
#include "flp.h"
#include "mtpr.h"

struct {
	short	fl_state;		/* open and busy flags */
	short	fl_active;		/* driver state flag */
	struct	buf *fl_buf;		/* buffer we're using */
	unsigned char *fl_xaddr;	/* transfer address */
	short	fl_errcnt;
} fltab;

/*ARGSUSED*/
flopen(dev, flag)
	dev_t dev;
	int flag;
{
	struct buf *geteblk();

	if (cpu != VAX_780)
		return (ENXIO);
	if (fltab.fl_state != 0)
		return (ENXIO);
	fltab.fl_state = FL_OPEN;
	fltab.fl_buf = geteblk(512);
	fltab.fl_active = FL_IDLE;
	return (0);
}

/*ARGSUSED*/
flclose(dev, flag)
	dev_t dev;
	int flag;
{

	brelse(fltab.fl_buf);
	fltab.fl_state = 0;
}

floperation(rw, uio)
	enum uio_rw rw;
	struct uio *uio;
{
	register struct buf *bp;
	register int i;
	int error;

	/*
	 * Assume one block read/written for each call - 
	 * and enforce this by checking for block size of 128.
	 * Use the b_blkno field to address
	 * physical, 128-byte blocks (u.u_offset/128).
	 * This is checked for validity, and is further interpreted as:
	 *
	 *	track# * (sectors/track) + sector #
	 */
	if (uio->uio_resid == 0) 
		return (0);
	(void) spl4();
	while (fltab.fl_state & FL_BUSY)
		sleep((caddr_t)&fltab, PRIBIO);
	fltab.fl_state |= FL_BUSY;
	(void) spl0();

	bp = fltab.fl_buf;
	error = 0;
	while ((i = imin(RXBYSEC, uio->uio_resid)) > 0) {
		bp->b_blkno = uio->uio_offset>>7;
		if (bp->b_blkno >= MAXSEC || (uio->uio_offset & 0177) != 0) {
			error = ENXIO;
			break;
		}
		if (rw == UIO_WRITE) {
			error = uiomove(bp->b_un.b_addr, i, UIO_WRITE, uio);
			if (error)
				break;
		}
		bp->b_flags = rw == UIO_WRITE ? B_WRITE : B_READ;
		(void) spl4(); 
		flstart();
		while ((bp->b_flags & B_DONE) == 0)
			sleep((caddr_t)bp, PRIBIO);	
		(void) spl0();
		if (bp->b_flags & B_ERROR) {
			error = EIO;
			break;
		}
		if (rw == UIO_READ) {
			error = uiomove(bp->b_un.b_addr, i, UIO_READ, uio);
			if (error)
				break;
		}
	}
	fltab.fl_state &= ~FL_BUSY;
	wakeup((caddr_t)&fltab);
	return (error);
}

/*ARGSUSED*/
flread(dev, uio)
	dev_t dev;
	struct uio *uio;
{

	return (floperation(UIO_READ, uio));
}

/*ARGSUSED*/
flwrite(dev, uio)
	dev_t dev;
	struct uio *uio;
{

	return (floperation(UIO_WRITE, uio));
}

flstart()
{
	register struct buf *bp;

	bp = fltab.fl_buf;
	fltab.fl_active = FL_MAND;
	fltab.fl_errcnt = 0;
	fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
	bp->b_resid = 0;
	bp->b_bcount = RXBYSEC; /* always transfer a full sector */

	if ((mfpr(TXCS) & TXCS_RDY) == 0)
		/* not ready to receive order */
		return;
	/*
	 * Wake up floppy LSI software with command
	 */
	fltab.fl_active = FL_SEC;
	if ((bp->b_flags&B_READ) == B_READ)
		mtpr(TXDB, FL_RS);
	else
		mtpr(TXDB, FL_WS);
}

/*
 * See if we want to transmit something
 * to the floppy - and do it
 */
conxfl()
{
	register int databyte;
	register struct buf *bp;

	bp = fltab.fl_buf;
	switch (fltab.fl_active) {

	case FL_MAND:		/* send command */
		if ((bp->b_flags&B_READ) == B_READ)
			mtpr(TXDB,FL_RS);
		else
			mtpr(TXDB,  FL_WS);
		fltab.fl_active = FL_SEC;
		break;

	case FL_SEC:		/* send sector address */
		databyte = (int)bp->b_blkno % RXSTRK + 1;
		mtpr(TXDB, FL_DATA | databyte);
		fltab.fl_active = FL_TRACK;
		break;

	case FL_TRACK:		/* send track address */
		databyte = (int)bp->b_blkno / RXSTRK;
		mtpr(TXDB , FL_DATA | databyte);
		if ((bp->b_flags&B_READ) == B_READ)
			/* prepare to receive complete */
			fltab.fl_active = FL_COM;
		else
			/* prepare to send data */
			fltab.fl_active = FL_DAX;
		break;

	case FL_DAX:
		databyte = *(fltab.fl_xaddr++);
		mtpr(TXDB, FL_DATA | databyte);
		if (--bp->b_bcount == 0)
			fltab.fl_active = FL_COM;
		break;

	case FL_CAN:		/* give cancel order */
		mtpr(TXDB, FL_CANCEL);
		if (++fltab.fl_errcnt <= FLERRS) {
			/* If error count permits, retry order */
			fltab.fl_active = FL_MAND;
			bp->b_bcount = RXBYSEC;
			fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr;
		} else {
			/*
			 * We're really stupid today - call it an
			 * error and give up
			 */
			bp->b_flags |= B_ERROR | B_DONE;
			bp->b_resid = -RXBYSEC;
			fltab.fl_active = FL_IDLE;
			wakeup((caddr_t)bp);
		}
	}
}

cnrfl(c)
	int c;
{
	register int datum;
	register struct buf *bp;

	datum = c;
	bp = fltab.fl_buf;
	if (datum == FL_PERR) {
		/*
		 * Got a protocol error - cancel the
		 * current function and try again if error count isn't
		 * too great.  First, though, make sure that an actual
		 * transaction is in progress (so a spurious error from
		 * the LSI won't screw us up too much!
		 */
		if (fltab.fl_active != FL_IDLE)
			fltab.fl_active = FL_CAN;
	} else switch(fltab.fl_active ) {

	case FL_DAR:		/* expecting a datum */
		if ((c&RXDB_ID) != FL_DATA)
			goto error;
		*(fltab.fl_xaddr++) = (c & RXDB_DATA);
		if (--bp->b_bcount==0) {
			fltab.fl_active = FL_IDLE;
			bp->b_flags |= B_DONE;
			wakeup((caddr_t)bp);
		}
		break;

	case FL_COM:		/* expecting a "function complete" */
		if ((c&RXDB_ID)!= FL_FFC || (c&FL_ERR) == FL_ERR){
error:
			bp->b_flags |= B_ERROR | B_DONE;
			bp->b_resid = -bp->b_bcount;
			fltab.fl_active = FL_IDLE;
			wakeup((caddr_t)bp);
		} else if ((bp->b_flags&B_READ) == B_READ)
			/* got function complete, now get data */
			fltab.fl_active = FL_DAR;
		else {
			/* got function complete on write - finish up */
			fltab.fl_active = FL_IDLE;
			bp->b_flags |= B_DONE;
				wakeup((caddr_t)bp);
		}
		break;
	}
}
#endif