/*
 * 40MB disk driver
 */

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

#define NBPC    200             /* blocks per cylinder */
#define NBPT    10              /* blocks per track */
#define NTPC    20              /* tracks per cylinder */

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

#define	DISABLE	0x80
#define ENABLE	0x40
#define SETHEAD	0x20
#define	SETCYL	0x10
#define RSTGATN	0x08
#define RSTHEAD	0x04
#define	SEEK	0x02
#define	DISARM	0xc0

#define CNTL_UNRCV      0x61
#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

char    d40addr[4]      = { 0xfc, 0xfd, 0xfe, 0xff };
char    d40cntl         = 0xfb;
char    d40selch        = 0xf0;

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

d40strategy(io, func)
register struct iob *io;
{
	register drive, cntl, selch, stat;
	register bn, tn, cn, sn;

	if ((drive = io->i_deva) == 0) drive = d40addr[io->i_unit];
	if ((cntl = io->i_cntl) == 0) cntl = d40cntl;
	if ((selch = io->i_selch) == 0) selch = d40selch;
	curcntl = cntl;
	cn = io->i_bn / NBPC;
	bn = io->i_bn % NBPC;
	tn = bn / NBPT;
	sn = (bn % NBPT) << 1;
	d40idle();
	wh(drive, cn);
	d40idle();
	oc(drive, SETCYL | DISARM) ;
	d40idle();
	oc(drive, RSTGATN);
	d40idle();
	oc(drive, RSTHEAD);
	d40idle();
	wh(drive, tn);
	oc(drive, SETHEAD);
	d40idle();
	oc(drive, SEEK);
	d40idle();
	while ((stat=ss(drive)) & UNREADY) ;
	if (stat & (UNS|SINC|OFFL)) {
		printf("d40 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);
	wdh(selch, io->i_ma + io->i_cc - 1);
	wd(cntl, sn);
	wh(cntl, (tn<<10) | cn);
	if (func == READ) {
		oc(cntl, CREAD);
		oc(selch, READ_GO);
	} else {
		oc(cntl, CWRITE);
		oc(selch, GO);
	}
	while (ss(selch) & SELCHBSY) ;
	oc(selch, STOP);
	d40idle();
	if ((stat=ss(cntl)) & (CNTL_UNRCV|CYL_OV)) {
		printf("MSM error: cyl=%d track=%d sect=%d er=%x ad=%x\n",
		    cn, tn, sn, stat, cntl);
		return(-1);
	}
	return(io->i_cc);
}
d40idle()
{
	while (! (ss(curcntl) & IDLE) ) ;
}
