static char     SCCS_ID [] = "@(#)udd.c	3.7";
/*
 * UDD disk driver - ITDC
 */

#include <sys/local.h>
#include <sys/param.h>
#include <sys/inode.h>
#include "../saio.h"

#define	ALTBSY	0x20
#define	UNS	0x10
#define UNREADY	0x08
#define	SINC	0x02
#define	OFFL	0x01

#define	DISABLE	0x80
#define ENABLE	0x40
#define	DISARM	0xc0
#define SETHEAD	0x20
#define	SETCYL	0x10
#define	SEEK	0x02
#define RELEASE	0xb0

#define CNTL_UNRCV      0xc1
#define CYL_OV          0x10
#define IDLE		0x02

#define CREAD            0x01
#define CWRITE           0x02
#define CRESET           0x08

#define	STOP	0x48
#define	GO	0x50
#define	READ_GO	0x70
#define SELCHBSY	0x08

#ifdef NORMAL
char    uddaddr[4]      = { 0xfc, 0xfd, 0xfe, 0xff };
char    uddcntl         = 0xfb;
char    uddselch        = 0xf0;
#else  NORMAL
char    uddaddr[4]      = { 0xec, 0xed, 0xee, 0xef };
char    uddcntl         = 0xeb;
char    uddselch        = 0xf1;
#endif NORMAL

static int      curcntl;        /* controller address for uddidle */

#define NSECTORS 2              /* number of physical sectors per 512 bytes */
#define SECSHIFT 1              /* shift for NSECTORS */
#define NBPT    59              /* 256-byte blocks per track */
#define NUMCYL	815		/* number of cylinders 0..814 */

#define UDD_ITDC        (59*5 ) /* 256-byte blocks per cylinder - ITDC  */

uddstrategy(io, func)
struct iob *io;
{
	return uddfstrategy (io, func, UDD_ITDC,0);
}

static
uddfstrategy(io, func, nbpc,headoffset)
register struct iob *io;
int     headoffset;
{
	register int drive, cntl, selch, stat;
	register offset;	/* number of bytes already finished */
	register int tn;        /* track */
	register int cn;        /* cylinder */
	register int sn;        /* sector */

	offset = 0;		/* offset initialy zero */
	if ((drive = io->i_deva) == 0) drive = uddaddr[io->i_unit];
	if ((cntl = io->i_cntl) == 0) cntl = uddcntl;
	if ((selch = io->i_selch) == 0) selch = uddselch;
	curcntl = cntl;
	io->i_bn *= 2;	/* block number in 256 byte blocks. */
	cn = io->i_bn / nbpc;
	{
		register off_t bn;        /* block number */
		bn = io->i_bn % nbpc;
		tn = bn / NBPT;
		sn = (bn % NBPT);
	}

findit:	uddidle();
       	while (ss(drive) & ALTBSY) ;
	wh(drive, cn);
	uddidle();
	oc(drive, SETCYL | DISARM) ;
	uddidle();
	oc(drive, SEEK);
	uddidle();
	while ((stat=ss(drive)) & UNREADY) ;
	if (stat & (UNS|SINC|OFFL|ALTBSY)) {
		printf("MSM seek error: cyl=%d track=%d sect=%d er=%x ad=%x\n",
		    cn, tn, sn, stat, drive);
		return(-1);
	}
	oc(selch, STOP);
	wdh(selch, &io->i_ma[offset]);
	wdh(selch, &io->i_ma[io->i_cc - 1]);
	wh(drive, tn | headoffset );
	oc(drive, SETHEAD);
	uddidle();
	wd(cntl, sn);
	wh(cntl, (tn<<10) | cn);
	wh(drive, tn);
	oc(drive, SETHEAD);
	if (func == READ) {
		oc(cntl, CREAD);
		oc(selch, READ_GO);
	} else {
		oc(cntl, CWRITE);
		oc(selch, GO);
	}
	while (ss(selch) & SELCHBSY) ;
	oc(selch, STOP);
	uddidle();

	/* check status */
	stat = ss(cntl);

	if (stat & (CNTL_UNRCV|CYL_OV)) {
		if(stat & CYL_OV)	/* cylinder overflow */
		{
			oc(cntl,CRESET);
			offset =  (rdh(selch) - io->i_ma +2) & 0x00FFFF00;
			sn = tn = 0;
			if(++cn < NUMCYL) goto findit;
		}
		printf("MSM %s error: cyl=%d track=%d sect=%d er=%x ad=%x\n",
		    func == READ ? "read" : "write",
		    cn, tn, sn, stat, cntl);
		return(-1);
	}
	return(io->i_cc);
}

uddidle()
{
	while (! (ss(curcntl) & IDLE) )
		continue;
}
