File:  [MW Coherent from dump] / coherent / d / PS2_KERNEL / io.286 / hld / ps.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* (-lgl
 * 	COHERENT Driver Kit Version 1.1.0
 * 	Copyright (c) 1982, 1990 by Mark Williams Company.
 * 	All rights reserved. May not be copied without permission.
 *
 * $Log: ps.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:39  root
 * coherent
 *
 * Revision 1.10  91/11/11  12:29:03  hal
 * Use n_atdr.
 * 
 * Revision 1.9  91/10/30  10:47:46  hal
 * Get psparms from tboot.
 *
 * Revision 1.8  91/10/24  12:36:25  hal
 * Bump PSSECS from 4 to 6.
 * Poll HF_REG (3F6) rather than CSR_REG (1F6).
 * COH 3.2.03.
 *
 * Revision 1.7  91/09/11  14:45:38  hal
 * Trial patch for Seagate 157A problems.
 *
 * Revision 1.6  91/09/11  13:23:12  hal
 * Explicit sys in include paths.  AT_MAJOR.
 *
 * Revision 1.5  91/05/22  15:06:59  hal
 * Don't force 8's bit of control byte.
 *
 * Revision 1.4	91/03/14  14:22:32	hal
 *
 -lgl) */
/*
 * This is a driver for the
 * hard disk on the PS.
 *
 * Reads drive characteristics from ROM (thru interrupt vector 0x41 and 0x46).
 * Reads partition information from disk.
 */
#include	<sys/coherent.h>
#include 	<sys/fdisk.h>
#include	<sys/hdioctl.h>
#include	<sys/buf.h>
#include	<sys/con.h>
#include	<sys/devices.h>
#include	<sys/stat.h>
#include	<sys/uproc.h>
#include	<sys/typed.h>
#include 	<sys/timeout.h>			/* TIM */
#include	<sys/sched.h>
#include	<errno.h>

extern	saddr_t	sds;		/* System Data Selector */
extern	short	n_atdr;		/* Number of "ps" drives */

/*
 * Configurable parameters
 */
#define	HDIRQ	14			/* Level 14 */
#define NDRIVE	2			/* only two drives supported */
#define	SOFTLIM	6			/*  (7) num of retrys before diag */
#define	HARDLIM	4			/* number of retrys before fail */
#define	BADLIM	100			/* num to stop recov if flagged bad */

#define	BIT(n)		(1 << (n))

#define	CMOSA	0x70			/* write cmos address to this port */
#define	CMOSD	0x71			/* read cmos data through this port */

/*
 * Driver configuration.
 */
void	psload();
void	psunload();
void	psopen();
void	psread();
void	pswrite();
int	psioctl();
void	pstimer();
void	psblock();
int	nulldev();
int	nonedev();

CON	pscon	= {
	DFBLK|DFCHR,			/* Flags */
	AT_MAJOR,			/* Major index */
	psopen,				/* Open */
	nulldev,			/* Close */
	psblock,			/* Block */
	psread,				/* Read */
	pswrite,			/* Write */
	psioctl,			/* Ioctl */
	nulldev,			/* Powerfail */
	pstimer,			/* Timeout */
	psload,				/* Load */
	psunload			/* Unload */
};

/*
 * Forward Referenced Functions.
 */
void	psreset();
int	psdequeue();
void	psstart();
void	psintr();
int	pserror();
void	psrecov();
void	psdone();
void	disk_function();
void	disk_functionb();

/*
 * Device States.
 */
#define	SIDLE	0			/* controller idle */
#define	SRETRY	1			/* seeking */
#define	SREAD	2			/* reading */
#define	SWRITE	3			/* writing */
#define SRESET  4			/* reseting */

char *smsg[] = { "SIDLE", "SRETRY", "SREAD", "SWRITE", "SRESET" };

/*
 * Drive Parameters - copied from ROM.
 * If patched, use the given values instead of reading from the ROM.
 * NOTE: Exactly duplicates hdparm_s struct.
 */
struct dparm_s {
	unsigned short	d_ncyl;		/* number of cylinders */
	unsigned char	d_nhead;	/* number of heads */
	unsigned short	d_rwcc;		/* reduced write current cyl */
	unsigned short	d_wpcc;		/* write pre-compensation cyl */
	unsigned char	d_eccl;		/* max ecc data length */
	unsigned char	d_ctrl;		/* control byte */
	unsigned char	d_fill2[3];
	unsigned short	d_landc;	/* landing zone cylinder */
	unsigned char	d_nspt;		/* number of sectors per track */
	unsigned char	d_fill3;

}	psparm[ NDRIVE ] = {
	0				/* Initialized to allow patching */
};

/*
 * Partition Parameters - copied from disk.
 *
 *	There are NDRIVE * NPARTN positions for the user partitions,
 *	plus NDRIVE additional partitions to span each drive.
 *
 *	Aligning partitions on cylinder boundaries:
 *	Optimal partition size: 2 * 3 * 4 * 5 * 7 * 17 = 14280 blocks
 *	Acceptable partition size:  3 * 4 * 5 * 7 * 17 =  7140 blocks
 */
static
struct fdisk_s pparm[NDRIVE*NPARTN + NDRIVE];

/*
 * Per disk controller data.
 * Only one controller; no more, no less.
 */
static
struct	ps	{
	BUF		*ps_actf;	/* Link to first */
	BUF		*ps_actl;	/* Link to last */
	faddr_t		ps_faddr;	/* Source/Dest virtual address */
	daddr_t		ps_bno;		/* Block # on disk */
	unsigned	ps_nsec;	/* # of sectors on current transfer */
	unsigned	ps_drv;
	unsigned	ps_head;
	unsigned	ps_cyl;
	unsigned	ps_sec;
	unsigned	ps_partn;
	unsigned char	ps_dtype[ NDRIVE ];	/* drive type, 0 if unused */
	unsigned char	ps_tries;
	unsigned char	ps_state;
	unsigned char	ps_caching;		/* caching in progress */
	unsigned	ps_bad_drv;
	unsigned	ps_bad_head;
	unsigned	ps_bad_cyl;
}	ps;

static BUF	dbuf;			/* For raw I/O */


#include <sys/abios.h>
#include <sys/mmu.h>
#include <sys/types.h>
#include <stdio.h>

static request_block_hd rb;

char killbuf[1024]; /* don't forget to fix bio.c */
char l_com_data[0x80];
paddr_t com_data_p, dev1p, fcn1p, dev2p, fcn2p;
a_sys_parm sp;
a_init_table it0, it1, it2, it7, it15;


char fcn0[0x10], fcn1[0x50], fcn2[0x40], fcn7[0x50], fcn15[0x58];

extern int com_data,i0, i1, i2, i7, i15, end_table,
			fcn_trn0, fcn_trn1, fcn_trn2, fcn_trn7, fcn_trn15; 

#define cscolon(d)		((faddr_t)(0x600000L + (unsigned) (d)))
#define ftop(d)			((paddr_t)(FP_SEL(d)<<4L) + FP_OFF(d))
#define init_tab_cp(s,r)	fkcopy(cscolon(ffword(cscolon(s))), r, 24)

/*
 * Patchable variables.
 *	PSBSYW is a loop count for busy-waiting after issuing commands.
 *	PSSECS is number of seconds to wait for an expected interrupt.
 */
int	PSBSYW = 50;			/* patchable */
int	PSSECS = 6;			/* patchable */

/**
 *
 * void
 * psload()	- load routine.
 *
 *	Action:	The controller is reset and the interrupt vector is grabbed.
 *		The drive characteristics are set up ps this time.
 */
static void
psload()
{
	unsigned int u;
	register int	s;
	struct dparm_s * dp;

	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}
	{int i; for (i=0;i<1000; i++);}

	printf("loading ps\n");
	init_abios();

	n_atdr = 1;
/*	printf("n_atdr = %d\n", n_atdr); */

	if (n_atdr == 0)
		return;

	ps.ps_actf = NULL; /* Start up with this Null to avoid phony calls */

	/*
	 * Obtain (hardwire) Drive Types.
	 */
	ps.ps_dtype[0] = 1;		/* This just means that it exists */
	ps.ps_dtype[1] = 0;	 /* This just means that it doesn't exist */

	/*
	 * Obtain Drive Characteristics.
	 */

	for (u = 0, dp = &psparm[0]; u < n_atdr; ++dp, ++u) 
	{
		rb.length = 0x80;
		rb.logical_id = 6;
		rb.unit = 0;
		rb.function = 3;
		rb.reserved = 0L;
		rb.ret_code = 0xffff;
		rb.vars.f3.reserved = 0L;
		d2_func(&rb, START_P);
		if (rb.ret_code)
			printf("\nhard disk function 3 returned = %d\n", 
								rb.ret_code);
		dp->d_ncyl = rb.vars.f3.cylinders;
		dp->d_nhead = rb.vars.f3.heads;
		dp->d_nspt = rb.vars.f3.sectors_track;
		dp->d_wpcc = 0xffff;
		dp->d_landc = rb.vars.f3.cylinders;
		if (dp->d_nhead > 8)
			dp->d_ctrl |= 8;
 
#if 0

	printf(" drive %d parameters\n", u);
	printf(
	"ps%d: ncyl=%d nhead=%d wpcc=%d eccl=%d ctrl=%d landc=%d nspt=%d\n",
		u,
		dp->d_ncyl,
		dp->d_nhead,
		dp->d_wpcc,
		dp->d_eccl,
		dp->d_ctrl,
		dp->d_landc,
		dp->d_nspt);
	printf("\nhard disk function 3 returned = %d\n", rb.ret_code);
	printf("\nretries = %d", rb.vars.f3.retries);
	printf("\nblock_addresses = %lu", rb.vars.f3.block_addresses);
	printf("\nmax_blocks = %d\n", rb.vars.f3.max_blocks);

#endif
	}

	/*
	 * Initialize Drive Size.
	 */
	for (u = 0, dp = &psparm[0]; u < n_atdr; ++dp, ++u) {

		if (ps.ps_dtype[u] == 0)
			continue;

		pparm[NDRIVE*NPARTN + u].p_size =
			(long) dp->d_ncyl * dp->d_nhead * dp->d_nspt;
	}

/*	
	s = sphi(); 
	spl( s );
*/
	setivec(HDIRQ, psintr); 
	
	ps.ps_bad_drv = -1;

	/*
	 * Initialize Drive Controller.
	 */
	psreset();
}

paddr_t prot;

/* This is the protected mode part of the abios initialization */
init_abios()
{
	unsigned int i, count, *tmp1;
	paddr_t codeseg;
	paddr_t *tmp;
	static short done = 0;

	if (done)		/* Make sure we don't call this twice */
		return;

	done++;

	printf("init_abios_a() = %x\n", iresult());

	/* First create the virtual pointer to the comm area */
	com_data_p = ptov(vtop(l_com_data, sds), 0x80L);

	/* Now copy the common data table into local space */
	fkcopy(cscolon((unsigned)(&com_data) & 0xfff0), l_com_data, 0x80);

	/* Now copy the initialization tables into local space */
	init_tab_cp(&i0,  &it0);
	init_tab_cp(&i1,  &it1);
	init_tab_cp(&i7,  &it7);
	init_tab_cp(&i15, &it15);
	init_tab_cp(&i2,  &it2);
/*
	fkcopy(cscolon(ffword(cscolon(&i0))), &it0, 24);
	fkcopy(cscolon(ffword(cscolon(&i1))), &it1, 24);
	fkcopy(cscolon(ffword(cscolon(&i1))), &it7, 24);
	fkcopy(cscolon(ffword(cscolon(&i15))), &it15, 24);
	fkcopy(cscolon(ffword(cscolon(&i2))), &it2, 24);
*/
	/* Now convert each real mode device block pointer into a protected 
	 * mode device block pointer .
	 */

	tmp = tmp1 = l_com_data;      /* Make thing easier on the compiler */

	codeseg = ptov(0x0600L,&end_table);/* Set up an r/w alias to the cs */

					/* Fix the segments in the CDA */
					/* the offsets are still ok */
	tmp1[9] = tmp1[13] = tmp1[17] = tmp1[21] = tmp1[25] = FP_SEL(codeseg);

	dev1p = tmp[6];
	dev2p = tmp[12];	/* Set this up so calls are easier later */
	
	/* Now fix each function transfer table pointer in the cda so that 
         * it points to the proper spot in the ds
	 */
	
					/* Fix the segments in the CDA */
	tmp1[11] = tmp1[15] = tmp1[19] = tmp1[23] = tmp1[27] = sds;

	tmp1[10] = (unsigned)fcn0;	/* Now fix the offsets */	
	tmp1[14] = (unsigned)fcn1;
	tmp1[18] = (unsigned)fcn7;
	tmp1[22] = (unsigned)fcn15;
	tmp1[26] = (unsigned)fcn2;

	fcn1p = tmp[7];
	fcn2p = tmp[13];	/* Set this up so calls are easier later */

	/* Now convert the pointers in the ftts to protected mode pointers */
				      /* This is the location of the Abios */
	prot = ptovx((paddr_t)(0xE0000L)); 
				    /* Take out this hardwired number later */

				  /* First do the system level functions */
	cnvt_ptrs(&fcn_trn0, fcn0, it0.ftt_length);
					/* Now do the diskette functions */
	cnvt_ptrs(&fcn_trn1, fcn1, it1.ftt_length);
					   /* Now do the timer functions */
	cnvt_ptrs(&fcn_trn7, fcn7, it7.ftt_length);
				   	     /* Now do the DMA functions */
	cnvt_ptrs(&fcn_trn15, fcn15, it15.ftt_length);
			 /* Finish up with the hard disk functions table */
	cnvt_ptrs(&fcn_trn2, fcn2, it2.ftt_length);

	/* Finally,  Convert the data pointers */

	i = *(int *)l_com_data;	/* i is now a pointer to the first pointer */
	count = *(int *)(l_com_data+i+6);/* count is the # of data pointers*/
	while (count--)		/* Any more data pointers? */
	{			/* Redo the pointer using the saved size */
		tmp = l_com_data + i + 2;
		*tmp = ptov(ftop(*tmp),(long)*(unsigned *)(tmp-2));
		i -= 6;			/* Now point to the next pointer */
	}

	printf("abios inited\n");
}


cnvt_ptrs(cs_src, fcn_dest, length)
int cs_src, length;
char *fcn_dest;
{
	paddr_t *tmp;
	int count, i;

	/* First copy the tables into the data space */
	fkcopy(cscolon(cs_src), fcn_dest, length);

	/* First do the system level functions */

	tmp = fcn_dest;

 	FP_SEL(tmp[0]) = FP_SEL(prot);  /* First the start routine */
 	FP_SEL(tmp[1]) = FP_SEL(prot); 	/* Next the interrupt routine */
 	FP_SEL(tmp[2]) = FP_SEL(prot);	/* Next the time-out ruutine */

	/* Then do the individual functions */

	count = *((int *)(fcn_dest+0x0c));	/* how many functions */
	for (i=0; i < count; i++)		/* convert each function */
		if (FP_OFF(tmp[i+4]))
			FP_SEL(tmp[i+4]) = FP_SEL(prot); 
}


/**
 *
 * void
 * psunload()	- unload routine.
 */
static void
psunload()
{
	clrivec(HDIRQ);
}

static	TIM	psrstlck;

/**
 *
 * void
 * psreset()	-- reset hard disk controller, define drive characteristics.
 */
static void
psreset()
{
	register int s;

	ps.ps_state = SRESET;
	rb.length = 0x80;
	rb.logical_id = 6;
	rb.unit = 0;
	rb.function = 5;
	rb.reserved = 0L;
	rb.ret_code = 0xffff;
	rb.vars.f5.reserved = 0;

	d2_func(&rb, START_P);

	while (rb.ret_code == 2)	/* Wait for time */
	{
		unsigned long i;

		for(i=0L; i < rb.vars.f8.wait_time; i+=8)
			;
		d2_func(&rb, INTERRUPT_P); 
	}

	ps.ps_state = SIDLE;
	if (rb.ret_code != 0)
		printf("PS: reset failed - %x\n", rb.ret_code);
	return;
#if 0
	disk_function(START_P); 

	s = sphi();
	while ((rb.ret_code == 1) || (rb.ret_code == 2))
		sleep(&psrstlck, CVWAIT, IVWAIT, SVWAIT);
	spl( s );

	ps.ps_state = SIDLE;
	if (rb.ret_code != 0)
		printf("PS: reset failed - %u\n", rb.ret_code);
	return;
#endif
}

/**
 *
 * void
 * psopen(dev, mode)
 * dev_t dev;
 * int mode;
 *
 *	Input:	dev = disk device to be opened.
 *		mode = access mode [IPR,IPW, IPR+IPW].
 *
 *	Action:	Validate the minor device.
 *		Update the paritition table if necessary.
 */
static void
psopen(dev, mode)
register dev_t	dev;
{
	register int d;		/* drive */
	register int p;		/* partition */

	p = minor(dev) % (NDRIVE*NPARTN);

	if (minor(dev) & SDEV) {
		d = minor(dev) % NDRIVE;
		p += NDRIVE * NPARTN;
	}
	else
		d = minor(dev) / NPARTN;

	if ((d >= NDRIVE) || (ps.ps_dtype[d] == 0)) {
		u.u_error = ENXIO;
		return;
	}

	if (minor(dev) & SDEV)
		return;

	/*
	 * If partition not defined read partition characteristics.
	 */
	if (pparm[p].p_size == 0)
		fdisk(makedev(major(dev), SDEV + d), &pparm[ d * NPARTN ]);
	/*
	 * Ensure partition lies within drive boundaries and is non-zero size.
	 */
	if ((pparm[p].p_base+pparm[p].p_size) > pparm[d+NDRIVE*NPARTN].p_size)
		u.u_error = EBADFMT;
	else if (pparm[p].p_size == 0)
		u.u_error = ENODEV;
}

/**
 *
 * void
 * psread(dev, iop)	- read a block from the raw disk
 * dev_t dev;
 * IO * iop;
 *
 *	Input:	dev = disk device to be written to.
 *		iop = pointer to source I/O structure.
 *
 *	Action:	Invoke the common raw I/O processing code.
 */
static void
psread(dev, iop)
dev_t	dev;
IO	*iop;
{
	ioreq(&dbuf, iop, dev, BREAD, BFRAW|BFBLK|BFIOC);
}

/**
 *
 * void
 * pswrite(dev, iop)	- write a block to the raw disk
 * dev_t dev;
 * IO * iop;
 *
 *	Input:	dev = disk device to be written to.
 *		iop = pointer to source I/O structure.
 *
 *	Action:	Invoke the common raw I/O processing code.
 */
static void
pswrite(dev, iop)
dev_t	dev;
IO	*iop;
{
	ioreq(&dbuf, iop, dev, BWRITE, BFRAW|BFBLK|BFIOC);
}

/**
 *
 * int
 * psioctl(dev, cmd, arg)
 * dev_t dev;
 * int cmd;
 * char * vec;
 *
 *	Input:	dev = disk device to be operated on.
 *		cmd = input/output request to be performed.
 *		vec = (pointer to) optional argument.
 *
 *	Action:	Validate the minor device.
 *		Update the paritition table if necessary.
 */
static int
psioctl(dev, cmd, vec)
register dev_t	dev;
int cmd;
char * vec;
{
	int d;

	/*
	 * Identify drive number.
	 */
	if (minor(dev) & SDEV)
		d = minor(dev) % NDRIVE;
	else
		d = minor(dev) / NPARTN;

	/*
	 * Identify input/output request.
	 */
	switch (cmd) {

	case HDGETA:
		/*
		 * Get hard disk attributes.
		 */
		kucopy(&psparm[d], vec, sizeof(psparm[0]));
		return(0);

	case HDSETA:
		return 0;	/* For now, do not allow this */
		/* Set hard disk pstributes. */
		ukcopy(vec, &psparm[d], sizeof(psparm[0]));
		ps.ps_dtype[d] = 1;		/* set drive type nonzero */
		pparm[NDRIVE * NPARTN + d].p_size = (long) psparm[d].d_ncyl 
				* psparm[d].d_nhead * psparm[d].d_nspt;
		psreset();
		return 0;

	default:
		u.u_error = EINVAL;
		return(-1);
	}
}

/**
 *
 * void
 * pstimer()		- wait for timeout
 *
 *	Action:	If drvl[AT_MAJOR] is greater than zero, decrement it.
 *		If it decrements to zero, call the abios again
 */
static void
pstimer()
{
	register int s;
	
	s = sphi();
	if (--drvl[AT_MAJOR].d_time > 0) {
		spl(s);
		return;
	}
	disk_function(INTERRUPT_P); 
	spl(s);
}

/**
 *
 * void
 * psblock(bp)	- queue a block to the disk
 *
 *	Input:	bp = pointer to block to be queued.
 *
 *	Action:	Queue a block to the disk.
 *		Make sure that the transfer is within the disk partition.
 */
static void
psblock(bp)
register BUF	*bp;
{
	register struct fdisk_s *pp;
	int partn = minor(bp->b_dev) % (NDRIVE*NPARTN);

	if (minor(bp->b_dev) & SDEV)
		partn += NDRIVE * NPARTN;

	pp = &pparm[ partn ];

	/*
	 * Check for read at end of partition.
	 */
	if ((bp->b_req == BREAD) && (bp->b_bno == pp->p_size)) {
		bdone(bp);
		return;
	}

	/*
	 * Range check disk region.
	 */
	if (((bp->b_bno + (bp->b_count/BSIZE)) > pp->p_size)
	|| (bp->b_count % BSIZE) || bp->b_count == 0) {
		bp->b_flag |= BFERR;
		bdone(bp);
		return;
	}

	bp->b_actf = NULL;
	if (ps.ps_actf == NULL)
		ps.ps_actf = bp;
	else
		ps.ps_actl->b_actf = bp;
	ps.ps_actl = bp;
	if (ps.ps_state == SIDLE)
		if (psdequeue())
			psstart();
}

/**
 *
 * int
 * psdequeue()		- obtain next disk read/write operation
 *
 *	Action:	Pull some work from the disk queue.
 *
 *	Return:	0 = no work.
 *		* = work to do.
 */
static int
psdequeue()
{
	register BUF * bp = ps.ps_actf;
	register struct fdisk_s * pp;
	unsigned int nspt;

	ps.ps_caching = 0;
	ps.ps_tries   = 0;

	if (bp == NULL)
		return (0);

	ps.ps_partn = minor(bp->b_dev) % (NDRIVE*NPARTN);

	if (minor(bp->b_dev) & SDEV) {
		ps.ps_partn += (NDRIVE*NPARTN);
		ps.ps_drv  = minor(bp->b_dev) % NDRIVE;
	}
	else
		ps.ps_drv = minor(bp->b_dev) / NPARTN;
	nspt = psparm[ps.ps_drv].d_nspt;

	pp = &pparm[ ps.ps_partn ];
	ps.ps_bno   = pp->p_base + bp->b_bno;
	ps.ps_nsec  = bp->b_count / BSIZE;
	ps.ps_faddr = bp->b_faddr;
	return (1);
}


/**
 *
 * void
 * psstart()	- start or restart next disk read/write operation.
 *
 *	Action:	Initiate disk read/write operation.
 */
static void
psstart()
{
	register struct dparm_s *dp;

	dp = &psparm[ ps.ps_drv ];
#if 0
	ps.ps_cyl  = (ps.ps_bno / dp->d_nspt) / dp->d_nhead;
	ps.ps_head = (ps.ps_bno / dp->d_nspt) % dp->d_nhead;
	ps.ps_sec  = (ps.ps_bno % dp->d_nspt) + 1;

	/*
	 * Check for repeated access to most recently identified bad track.
	 */
	if ((ps.ps_drv  == ps.ps_bad_drv)
	  && (ps.ps_cyl  == ps.ps_bad_cyl)
	  && (ps.ps_head == ps.ps_bad_head)) {
	  	BUF * bp = ps.ps_actf;
		printf("ps%d%c: bno=%U head=%u cyl=%u <Track Flagged Bad>\n",
			ps.ps_drv,
			(bp->b_dev & SDEV) ? 'x' : ps.ps_partn % NPARTN + 'a',
			bp->b_bno,
			ps.ps_head,
			ps.ps_cyl);
		bp->b_flag |= BFERR;
		psdone();
		return;
	}
#endif
	rb.length = 0x80;
	rb.logical_id = 6;
	rb.unit = 0;
	rb.reserved = 0L;
	rb.ret_code = 0xffff;

	/* Note that the items below are set up the same way for a
	 * read or a write. */
	rb.vars.f8.reserved = 0;
	rb.vars.f8.reserved1 = 0;
	rb.vars.f8.dptr = vtop(ps.ps_faddr);
	rb.vars.f8.reserved2 = 0;
	rb.vars.f8.rb_address = ps.ps_bno;
	rb.vars.f8.reserved3 = 0;
	rb.vars.f8.blocks_read = ps.ps_nsec;
	rb.vars.f8.caching = 0;
	if (ps.ps_actf->b_req == BWRITE) {
		rb.function = 9;
		ps.ps_state = SWRITE;
	}
	else {
		rb.function = 8;
		ps.ps_state = SREAD;

	}
	disk_function(START_P);
}

/**
 *
 * void
 * psintr()	- Interrupt routine.
 *
 */
static void
psintr()
{
	d2_func(&rb, INTERRUPT_P);
	defer(disk_functionb, 0); 
}

/**
 *
 * int
 * pserror()
 *
 *	Action:	Check for drive error.
 *		If found, increment error count and report it.
 *
 *	Return: 0 = No error found.
 *		1 = Error occurred.
 */
static int
pserror()
{
	register BUF * bp = ps.ps_actf;

	if (rb.ret_code <= 2)
		return 0;	/* For now, do nothing */
	else 
	{
		printf("ps%d%c: bno=%U head=%u cyl=%u error=%x",
			ps.ps_drv,
			(bp->b_dev & SDEV) ? 'x' : ps.ps_partn % NPARTN + 'a',
			(bp->b_count/BSIZE) + bp->b_bno
				+ ps.ps_caching - ps.ps_nsec,
			ps.ps_head, ps.ps_cyl, rb.ret_code);
		return rb.ret_code;
	}
		
#if 0
	if ((csr = inb(HF_REG)) & (ERR_ST|WFLT_ST)) {

		aux = inb(AUX_REG);

		if (aux & BAD_ERR) {
			ps.ps_tries	= BADLIM;
			ps.ps_bad_drv	= ps.ps_drv;
			ps.ps_bad_head	= ps.ps_head;
			ps.ps_bad_cyl	= ps.ps_cyl;
		}
		else if (++ps.ps_tries < SOFTLIM)
			return 1;

		printf("ps%d%c: bno=%U head=%u cyl=%u",
			ps.ps_drv,
			(bp->b_dev & SDEV) ? 'x' : ps.ps_partn % NPARTN + 'a',
			(bp->b_count/BSIZE) + bp->b_bno
				+ ps.ps_caching - ps.ps_nsec,
			ps.ps_head, ps.ps_cyl);

#if VERBOSE > 0
		if ((csr & RDY_ST) == 0)
			printf(" <Drive Not Ready>");
		if (csr & WFLT_ST)
			printf(" <Write Fault>");

		if (aux & DAM_ERR)
			printf(" <No Data Addr Mark>");
		if (aux & TR0_ERR)
			printf(" <Track 0 Not Found>");
		if (aux & ID_ERR)
			printf(" <ID Not Found>");
		if (aux & ECC_ERR)
			printf(" <Bad Data Checksum>");
		if (aux & ABT_ERR)
			printf(" <Command Aborted>");
#else
		if ((csr & (RDY_ST|WFLT_ST)) != RDY_ST)
			printf(" csr=%x", csr);
		if (aux & (DAM_ERR|TR0_ERR|ID_ERR|ECC_ERR|ABT_ERR))
			printf(" aux=%x", aux);
#endif
		if (aux & BAD_ERR)
			printf(" <Block Flagged Bad>");

		if (ps.ps_tries < HARDLIM)
			printf(" retrying...");
		printf("\n");
		return 1;
	}
	return 0;
#endif
}

/**
 *
 * void
 * psrecov()
 *
 *	Action:	Attempt recovery.
 */
static void
psrecov()
{
	register BUF *bp = ps.ps_actf;
	if (ps.ps_tries < HARDLIM) {
		ps.ps_tries++;
		psdequeue();
		psstart();
	}

	/*
	 * Give up on block.
	 */
	else {
		bp->b_flag |= BFERR;
		psdone();
	}
}

/**
 *
 * void
 * psdone()
 *
 *	Action:	Release current i/o buffer to the O/S.
 */
static void
psdone()
{
	register BUF * bp = ps.ps_actf;

	drvl[AT_MAJOR].d_time = 0;
	ps.ps_state = SIDLE;
	bdone(bp);

	ps.ps_actf = bp->b_actf;

	if (psdequeue())
		psstart();
}


void disk_function(type)
int type;
{
	d2_func(&rb, type);
	disk_functionb();
}

static TIM pstim;

void disk_functionb()
{
static int test=0;
	while (rb.ret_code == 2)	/* Wait for time */
	{
test++;
if (test > 1) printf("%");
/*		timeout(&pstim, 1, wakeup, (int)&pstim);
		sleep((char *)&pstim, CVTTOUT, IVTTOUT, SVTTOUT);
*/
{
long i;
	for(i=0L; i < rb.vars.f8.wait_time; i+=64)
		;
}
		d2_func(&rb, INTERRUPT_P);
	}
test=0;
	if (rb.ret_code == 0)		/* Finished */
	{
		if (ps.ps_state != SRESET) 
		{
			ps.ps_actf->b_resid = 0;
			psdone();
		}
		else
			wakeup(&psrstlck);
	}
	else if (rb.ret_code == 1)	/* Wat for int */
 	{
		/*ps.ps_state = SINT; */
	}
	else
	{
		printf("PS: error %x in %s.\n", rb.ret_code, 
					smsg[ps.ps_state]);
		psrecov();
	}

}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.