File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / vba / vddc.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:30:10 2019 UTC (6 years, 11 months ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

#include "fsd.h"
#if NVD > 0


/*
**	VDDC Driver - Versabus to SMD direct interface version.
**		Written for TAHOE vmunix, CCI-WDC 9/1/83.		
*/

#include "../h/param.h"
#include "../h/buf.h"
#include "../h/cmap.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/dk.h"
#include "../h/map.h"
#include "../machine/mtpr.h"
#include "../machine/pte.h"
#include "../h/systm.h"
#include "../vba/vbavar.h"
#include "../h/user.h"
#include "../h/vmmac.h"
#include "../h/proc.h"
#include "../h/uio.h"
#define	VDGENDATA
#include "../vba/vddc.h"
#undef	VDGENDATA


#define	MAX_BLOCKSIZE	MAXBPTE * NBPG
#define	DUMPSIZE	64	/* Up to 64k at a time - controller limit */

/*
** Layout of minor number assignments for the VDDC devices.
**
** 	  
**	  7            3 2   0
**	 +--------------+-----+
**	 |  Unit number | FLS |
**	 +--------------+-----+
**	     	   |    |_____ File system # ( 0-7 )
**	      	   |__________ Unit # in the system
*/

#define VDUNIT(x)	(minor(x) >> 3)
#define FILSYS(x)	(minor(x) & 0x07)
#define PHYS(x)		(vtoph(0, (int)(x)))
#define TRUE		1
#define	FALSE		0
#define	NOERROR		0

#define CTLR_ERROR	1
#define DRIVE_ERROR	2
#define HARD_DATA_ERROR	3
#define SOFT_DATA_ERROR	4

#define b_cylin		b_resid
#define b_daddr		b_error

/*
**
*/

struct	vba_ctlr	*vdminfo[NVD];


/*
**
*/

struct  vba_device	*vddinfo[NFSD];


/*
**
*/

int	vdprobe();		/* See if VDDC is really there */
int	vdslave();		/* See if drive is really there */
int	vdattach();		/* Enter a drive in internal tables */
int	vddgo();		/* Old VAX function, not used. */



/*
**
*/

struct	vba_driver vddriver = {
	vdprobe, vdslave, vdattach, vddgo, vddcaddr, 
	"", vddinfo, "", vdminfo
};


/*
**
*/

typedef struct {
	struct buf	raw_q_element;
	short		sec_per_blk;
	short		sec_per_cyl;
	char		status;
	struct buf	xfer_queue;
	int		drive_type;
	fs_tab		info;
} unit_tab;

/*
**
*/

typedef struct {
	char		ctlr_type;		/*  */
	char		*map;			/*  */
	char		*utl;			/*  */
	unsigned	cur_slave : 8;		/* last active unit number */
	unsigned	int_expected : 1;	/* expect an interupt */
	unsigned	ctlr_started : 1;	/* start command was issued */
	unsigned	overlap_seeks : 1;	/* Should overlap seeks */
	unsigned	off_cylinder : 16;	/* Off cylinder bit map */
	unsigned	unit_type[16];		/* type of each slave */
	long		cur_cyl[16];		/* cylinder last selected */
	long		cur_trk[16];		/* track last selected */
	fmt_mdcb	ctlr_mdcb;		/* controller mdcb */
	fmt_dcb		ctlr_dcb;		/* R/W dcb */
	fmt_dcb		seek_dcb[4];		/* dcbs for overlapped seeks */
	char		rawbuf[MAX_BLOCKSIZE];	/* buffer for raw/swap i/o */
} ctlr_tab;


/*
**
*/

extern char	vd0utl[];
#if NVD > 1
extern char	vd1utl[];
#if NVD > 2
extern char	vd2utl[];
#if NVD > 3
extern char	vd3utl[];
#if NVD > 4
extern char	vd4utl[];
#if NVD > 5
extern char	vd5utl[];
#if NVD > 6
extern char	vd6utl[];
#if NVD > 7
extern char	vd7utl[];
#if NVD > 8
	error	Can only support up to 8 controllers
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif


/*
**
*/

ctlr_tab	vdctlr_info[NVD] = {
	 {UNKNOWN, (char *)VD0map, vd0utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 1
	,{UNKNOWN, (char *)VD1map, vd1utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 2
	,{UNKNOWN, (char *)VD2map, vd2utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 3
	,{UNKNOWN, (char *)VD3map, vd3utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 4
	,{UNKNOWN, (char *)VD4map, vd4utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 5
	,{UNKNOWN, (char *)VD5map, vd5utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 6
	,{UNKNOWN, (char *)VD6map, vd6utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 7
	,{UNKNOWN, (char *)VD7map, vd7utl, 0, FALSE, FALSE, TRUE, 0,
		{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
		 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#endif
#endif
#endif
#endif
#endif
#endif
#endif
};


/*
**
*/

unit_tab	vdunit_info[NFSD];


/*
**	See if the controller is really there. 
**  if TRUE - initialize the controller.
*/

vdprobe(ctlr_addr)
cdr	*ctlr_addr;
{
	if(!badaddr(ctlr_addr, 2)) {
		ctlr_addr->cdr_reset = 0xffffffff;
		DELAY(1000000);
		if(ctlr_addr->cdr_reset != 0xffffffff) {
			vddriver.ud_mname = "VSMD Controller #";
			DELAY(1000000);
		}
		else {
			vddriver.ud_mname = "SMD/E Controller #";
			ctlr_addr->cdr_reserved = 0x0;
			DELAY(3000000);
		}
		return TRUE;
	}
	return FALSE;				/* no controller */	
}


/*
** See if a drive is really there
** Try to Reset/Configure the drive, then test its status.
*/

vdslave(vba_dev_info, ctlr_addr)
register struct vba_device	*vba_dev_info;
register cdr			*ctlr_addr;
{
	register int		ctlr = vba_dev_info->ui_ctlr;
	register ctlr_tab	*c_info = &vdctlr_info[ctlr];
	register int		unit = vba_dev_info->ui_unit;
	register unit_tab	*u_info = &vdunit_info[unit];
	register int		slave = vba_dev_info->ui_slave;
	register int		type;
	register fmt_mdcb	*mdcb = &c_info->ctlr_mdcb;
	register fmt_dcb	*dcb = &c_info->ctlr_dcb;

	if(c_info->ctlr_type == UNKNOWN) {
		ctlr_addr->cdr_reset = 0xffffffff;
		DELAY(1000000);
		if(ctlr_addr->cdr_reset != 0xffffffff) {
			c_info->ctlr_type = SMDCTLR;
			c_info->overlap_seeks = FALSE;
			DELAY(1000000);
		}
		else {
			c_info->overlap_seeks = TRUE;
			c_info->ctlr_type = SMD_ECTLR;
			ctlr_addr->cdr_reserved = 0x0;
			DELAY(3000000);
			ctlr_addr->cdr_csr = 0;
			ctlr_addr->mdcb_tcf = AM_ENPDA;
			ctlr_addr->dcb_tcf = AM_ENPDA;
			ctlr_addr->trail_tcf = AM_ENPDA;
			ctlr_addr->data_tcf = AM_ENPDA;
			ctlr_addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
			    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
		}
		if(vdaccess_with_no_trailer(ctlr_addr,ctlr,slave,INIT,10) & 
		    HRDERR) {
			printf("\n  VDDC: Controller %d init error.\n", ctlr);
			return	FALSE;
		}
		if(vdaccess_with_no_trailer(ctlr_addr,ctlr,slave,DIAG,10) & 
		    HRDERR) {
			printf("\n  VDDC: Controller %d diagnostic error.\n",ctlr);
			return	FALSE;
		}
	}
	/*
	 * Seek on all drive types starting from the largest one.
	 * a successful seek to the last sector/cylinder/track verifies 
	 * the drive type connected to this port. 
	 */
	for (type = 0; type < nvddrv; type++) {	
		if((c_info->ctlr_type == SMDCTLR) && (vdst[type].nsec != 32))
			continue;
		if(vdconfigure_drive(ctlr_addr, ctlr, slave, type, 0)) {
			dcb->opcode = (short)RD;
			dcb->intflg = NOINT;
			dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
			dcb->operrsta  = 0;
			dcb->devselect = (char)slave;
			dcb->trailcnt = (char)(sizeof(trrw) / sizeof(long));
			dcb->trail.rwtrail.memadr=(char *)PHYS(c_info->rawbuf); 
			dcb->trail.rwtrail.wcount =
			    vdst[type].secsize/sizeof(short);
			dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
			dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
			dcb->trail.rwtrail.disk.sector=vdst[type].nsec - 1;
			mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
			mdcb->vddcstat = 0;
			VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(mdcb)),
			    c_info->ctlr_type);
			POLLTILLDONE(ctlr_addr, dcb, 60, c_info->ctlr_type);
			if(vdtimeout <= 0) {
				printf(" during probe operation.\n");
			}
			if(!(dcb->operrsta & HRDERR))
				break;
		}
		else
			return FALSE;
	}
	if (type >= nvddrv) {
		/*
		 *	If reached here, a drive which is not defined in the 
		 * 'vdst' tables is connected. Cannot set it's type.
		 */
		printf("VDDC: Could not identify controller %d, drive %d!\n",
		    ctlr, slave);
		return FALSE;
	}
	u_info->drive_type = type;
	u_info->info = vdst[type];
	u_info->sec_per_blk = DEV_BSIZE / u_info->info.secsize;
	vba_dev_info->ui_type = type;
 	vba_dev_info->ui_dk = TRUE;
	vddriver.ud_dname = u_info->info.type_name;
	return TRUE;
}



/*
**
*/

vdconfigure_drive(ctlr_addr, ctlr, slave, type, pass)
cdr		*ctlr_addr;
register int	ctlr, slave, type, pass;
{
	register ctlr_tab	*c_info = &vdctlr_info[ctlr];

	c_info->ctlr_dcb.opcode = RSTCFG;		/* command */
	c_info->ctlr_dcb.intflg = NOINT;
	c_info->ctlr_dcb.nxtdcb = (fmt_dcb *)0;	/* end of chain */
	c_info->ctlr_dcb.operrsta  = 0;
	c_info->ctlr_dcb.devselect = (char)slave;
	c_info->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
	c_info->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
	if(c_info->ctlr_type == SMD_ECTLR) {
		c_info->ctlr_dcb.trailcnt = (char)4;
		c_info->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
		c_info->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
	}
	else
		c_info->ctlr_dcb.trailcnt = (char)2;
	c_info->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&c_info->ctlr_dcb));
	c_info->ctlr_mdcb.vddcstat = 0;
	VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(&c_info->ctlr_mdcb)),
	    c_info->ctlr_type);
	POLLTILLDONE(ctlr_addr, &c_info->ctlr_dcb, 5, c_info->ctlr_type);
	if(vdtimeout <= 0) {
		printf(" during drive configuration.\n");
		return FALSE;
	}
	if(c_info->ctlr_dcb.operrsta & HRDERR) {
		if(!(c_info->ctlr_dcb.operrsta & (NOTCYLERR | DRVNRDY)))
			printf("\n  VDDC: Configuration error.\n");
		else if(pass == 0) {
			vdstart_drive(ctlr_addr, ctlr, slave);
			return vdconfigure_drive(ctlr_addr,ctlr,slave,type,1);
		}
		else if(pass == 2)
			return vdconfigure_drive(ctlr_addr,ctlr,slave,type,3);
		return FALSE;
	}
	return TRUE;
}


/*
**
*/

vdstart_drive(ctlr_addr, ctlr, slave)
cdr		*ctlr_addr;
register int	ctlr, slave;
{
	printf("\n  VDDC: Attempting to start drive %d.", slave);
	printf("  Please wait...");
	if(vdctlr_info[ctlr].ctlr_started) {
		DELAY(5500000);
		printf("\n");
		return TRUE;
	}
	vdctlr_info[ctlr].ctlr_started = TRUE;
	if(vdaccess_with_no_trailer(ctlr_addr, ctlr, 0, VDSTART, (slave*6)+62)
	    & HRDERR) {
		printf("\n");
		return	FALSE;
	}
	DELAY((slave * 5500000) + 62000000);
	printf("\n");
	return TRUE;
}


/*
**
*/

vdaccess_with_no_trailer(ctlr_addr, ctlr, unit, function, time)
register cdr		*ctlr_addr;
register int		ctlr, unit, function, time;
{
	fmt_mdcb	*mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
	fmt_dcb		*dcb = &vdctlr_info[ctlr].ctlr_dcb;

	dcb->opcode = function;		/* command */
	dcb->intflg = NOINT;
	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
	dcb->operrsta  = 0;
	dcb->devselect = (char)unit;
	dcb->trailcnt = (char)0;
	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
	mdcb->vddcstat = 0;
	VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(mdcb)),
	    vdctlr_info[ctlr].ctlr_type);
	POLLTILLDONE(ctlr_addr, dcb, time, vdctlr_info[ctlr].ctlr_type);
	if(vdtimeout <= 0) {
		printf(" during initialization operation.\n");
		return (DCBCMP | ANYERR | HRDERR | OPABRT);
	}
	return dcb->operrsta;
}


/*
**
*/

vdattach(vba_dev_info)
struct vba_device *vba_dev_info;
{
	register int		unit = vba_dev_info->ui_unit;
	register unit_tab	*u_info = &vdunit_info[unit];
	register ctlr_tab	*c_info = &vdctlr_info[vba_dev_info->ui_ctlr];
	register struct buf	*c_queue = &vba_dev_info->ui_mi->um_tab;
	register struct buf	*u_queue = c_queue->b_forw;
	register struct buf	*start_queue = u_queue;
	register int		type = vba_dev_info->ui_type;
	register fs_tab		*fs = &u_info->info;

	u_info->info = vdst[type];
	u_info->sec_per_blk = DEV_BSIZE / u_info->info.secsize;
	u_info->sec_per_cyl = u_info->info.nsec * u_info->info.ntrak;
	u_info->xfer_queue.b_dev = vba_dev_info->ui_slave;
	c_info->unit_type[vba_dev_info->ui_slave] = type;
	/* load unit into controller's active unit list */
	if(u_queue == NULL) {
		c_queue->b_forw = &u_info->xfer_queue;
		u_info->xfer_queue.b_forw = &u_info->xfer_queue;
		u_info->xfer_queue.b_back = &u_info->xfer_queue;
	}
	else {
		while(u_queue->b_forw != start_queue)
			u_queue = u_queue->b_forw;
		u_info->xfer_queue.b_forw = start_queue;
		u_info->xfer_queue.b_back = u_queue;
		u_queue->b_forw = &u_info->xfer_queue;
		start_queue->b_back = &u_info->xfer_queue;
	}
	/*
	**  (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
	*/
	dk_mspw[unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
}


/*
** Historic VAX routine.
*/

vddgo(um)
struct vba_ctlr *um;
{
}


/*
**	Variables used:
**  request		-> points to current transaction queue element.
**  unit		-> contains the system's logical unit number.
**  ctlr		-> contains the physical controller number.
**  slave		-> contains the physical unit number on ctlr.
**  vba_dev_info	-> unix's controller information tables.
**  par			-> contains the file system number (0-7)
**  u_info		-> points to internal unit_information table
**  c_info		-> points to internal controller information table.
**  blks		-> temporary variable holds number of blocks to xfer.
**  blks		-> temporary variable holds starting block number.
**  priority		-> temporary variable holds old cpu priority.
*/

vdstrategy(request)
register struct buf *request;
{
	register int			unit = VDUNIT(request->b_dev);
	register struct vba_device	*vba_dev_info = vddinfo[unit];
	register int			par = FILSYS(request->b_dev);
	register unit_tab		*u_info = &vdunit_info[unit];
	register ctlr_tab		*c_info;
	register fs_tab			*fs = &u_info->info;
	register int			blks, blk, priority, slave;

	if((request->b_bcount != 0) && (vba_dev_info != NULL) &&
	    (vba_dev_info->ui_alive != 0)&&(fs->partition[par].par_len != 0)) {
		slave = vba_dev_info->ui_slave;
		c_info = &vdctlr_info[vba_dev_info->ui_ctlr];
		blks = (request->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
		if(fs->partition[par].par_len < (request->b_blkno + blks)) {
			blks = fs->partition[par].par_len - request->b_blkno;
			if(blks > 0)
				request->b_bcount = blks * DEV_BSIZE;
			else
				goto error;
		}
		blk = request->b_blkno + fs->partition[par].par_start;
		blk *= u_info->sec_per_blk;
		request->b_daddr = (blk / fs->nsec) % fs->ntrak;
		request->b_cylin = blk / u_info->sec_per_cyl;
		buf_setup (request, u_info->info.secsize);
		priority = spl7();
		if(u_info->xfer_queue.av_forw == NULL)
			if((request->b_cylin != c_info->cur_cyl[slave]) ||
			    (request->b_daddr)!=(c_info->cur_trk[slave]))
				c_info->off_cylinder |= 1 << slave;
		request->b_daddr |= (blk % fs->nsec) << 8;
		disksort(&u_info->xfer_queue, request);
		if(!vddinfo[unit]->ui_mi->um_tab.b_active++) {
			splx(priority);
			vdstart(vddinfo[unit]->ui_mi);
			return;
		}
		splx(priority);
		return;
	}
	harderr(request, u_info->info.type_name);
	printf("- Strategy was passed bad information: " );
	printf("b_bcount=%d, dev_info=%x, alive=%x, and partition length=%d.\n",
	    request->b_bcount, vba_dev_info, vba_dev_info->ui_alive,
	    fs->partition[par].par_len);
error:	
	request->b_flags |= B_ERROR;
	request->b_error = ENXIO;
	request->b_resid = request->b_bcount;
	iodone(request);
}


/*
 * Start up a transfer on a drive.
 */
vdstart(controller_info)
register struct vba_ctlr *controller_info;
{
	register struct buf	*c_queue = &controller_info->um_tab;
	register struct buf	*u_queue = c_queue->b_forw;

	/* Search for next ready unit */
	c_queue->b_forw = c_queue->b_forw->b_forw;
	u_queue = c_queue->b_forw;
	do {
		if(u_queue->av_forw != NULL) {
			c_queue->b_forw = u_queue;
			vdexecute(controller_info, c_queue, u_queue);
			return;
		}
		u_queue = u_queue->b_forw;
	} while(u_queue != c_queue->b_forw);
}


vdload_seeks(c_info, u_queue)
register ctlr_tab	*c_info;
register struct buf	*u_queue;
{
	register int		unit, slave, seek_count = 0;
	register fmt_dcb	*dcb;
	register struct buf	*request;
	register int		new_cyl;
	register struct buf	*start_queue = u_queue;

	do {
		if((request = u_queue->av_forw) != NULL) {
			unit = VDUNIT(request->b_dev);
			slave = vddinfo[unit]->ui_slave;
			if(c_info->off_cylinder & (1 << slave)) {
				c_info->off_cylinder &= ~(1 << slave);
				if(c_info->cur_cyl[slave] != request->b_cylin) {
					c_info->cur_cyl[slave]=request->b_cylin;
					dk_seek[unit]++;
				}
				c_info->cur_trk[slave] = request->b_daddr&0xff;
				dcb = &c_info->seek_dcb[seek_count++];
				dcb->opcode = SEEK;
				dcb->intflg = NOINT | INT_PBA;
				dcb->operrsta  = 0;
				dcb->devselect = (char)slave;
				dcb->trailcnt = (char)1;
				dcb->trail.sktrail.skaddr.cylinder =
				    request->b_cylin;
				dcb->trail.sktrail.skaddr.track =
				    request->b_daddr & 0xff;
				dcb->trail.sktrail.skaddr.sector = 0;
			}
		}
		u_queue = u_queue->b_forw;
	} while((u_queue != start_queue) && (seek_count < 4));
	return seek_count;
}


/*
**
*/

vdexecute(controller_info, c_queue, u_queue)
register struct vba_ctlr *controller_info;
register struct buf	 *c_queue, *u_queue;
{
	extern			vd_int_timeout();
	register struct	buf	*request = u_queue->av_forw;
	register int		ctlr = controller_info->um_ctlr;
	register ctlr_tab	*c_info = &vdctlr_info[ctlr];
	register int		unit = VDUNIT(request->b_dev);
	register int		slave = vddinfo[unit]->ui_slave;
	register fs_tab		*fs = &vdunit_info[unit].info;
	register fmt_mdcb	*mdcb = &c_info->ctlr_mdcb; 
	register fmt_dcb	*dcb = &c_info->ctlr_dcb; 
	
	if((c_info->off_cylinder & ~(1<<slave)) && c_info->overlap_seeks) {
		register int	index;
		register int	seek_count = vdload_seeks(c_info, u_queue);

		mdcb->firstdcb = (fmt_dcb *)PHYS(&c_info->seek_dcb[0]);
		for(index = 1; index < seek_count; index++)
			c_info->seek_dcb[index-1].nxtdcb = 
			    (fmt_dcb *)PHYS(&c_info->seek_dcb[index]);
		c_info->seek_dcb[seek_count-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
	}
	else {
		if(request->b_cylin != c_info->cur_cyl[slave]) {
			c_info->cur_cyl[slave] = request->b_cylin;
			dk_seek[unit]++;
		}
		c_info->cur_trk[slave] = request->b_daddr & 0xff;
		c_info->off_cylinder = 0;
		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
	}
	dcb->opcode = (request->b_flags & B_READ) ? RD : WD;
	dcb->intflg = INTDONE;
	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
	dcb->operrsta  = 0;
	dcb->devselect = (char)slave;
	dcb->trailcnt = (char)(sizeof(trrw) / sizeof(long));
	dcb->trail.rwtrail.memadr = (char *)get_ioadr(request, c_info->rawbuf,
	    c_info->map, c_info->utl);
	dcb->trail.rwtrail.wcount=(short)((request->b_bcount+1)/sizeof(short));
	dcb->trail.rwtrail.disk.cylinder = request->b_cylin;
	dcb->trail.rwtrail.disk.track = request->b_daddr & 0xff;
	dcb->trail.rwtrail.disk.sector = request->b_daddr >> 8;
	mdcb->vddcstat = 0;
   	dk_wds[unit] += request->b_bcount / 32;
	c_info->int_expected = TRUE;
	timeout(vd_int_timeout, ctlr, 20*60);
  	dk_busy |= 1 << unit;
#ifdef VDDCPERF
	scope_out(1);
#endif
	VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),(fmt_mdcb *)(PHYS(mdcb)),
	    c_info->ctlr_type);
}


/*
**
*/

vd_int_timeout(ctlr)
register int	ctlr;
{
	register ctlr_tab	*c_info = &vdctlr_info[ctlr];
	register fmt_mdcb	*mdcb = &c_info->ctlr_mdcb;
	register fmt_dcb	*dcb = &c_info->ctlr_dcb;

	uncache(&dcb->operrsta);
	printf("\nVDDC: Controller %d didn't interupt!", ctlr);
	printf("  Status = %x", dcb->operrsta);
	if(c_info->ctlr_type == SMD_ECTLR) {
		uncache(&dcb->err_code);
		printf("  Error code = %x", dcb->err_code);
	}
	printf("\n");
	if(!(dcb->operrsta & DCBCMP)) { 
		VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), c_info->ctlr_type);
		dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
	}
	vdintr(ctlr);
}


/*
 * Handle a disk interrupt.
 */
vdintr(ctlr)
register int	ctlr;
{
	extern			vd_int_timeout();
	register ctlr_tab	*c_info = &vdctlr_info[ctlr];


	untimeout(vd_int_timeout, ctlr);
#ifdef VDDCPERF
	scope_out(2);
#endif
	if(c_info->int_expected) {
		register struct buf	*u_queue=vdminfo[ctlr]->um_tab.b_forw;
		register struct buf	*request = u_queue->av_forw;
		register int		slave = u_queue->b_dev;
		register int		unit = VDUNIT(request->b_dev);
		register unit_tab	*u_info = &vdunit_info[unit];
		register fmt_mdcb 	*mdcb = &c_info->ctlr_mdcb;
		register fmt_dcb 	*dcb = &c_info->ctlr_dcb;
		register int		priority;

   		dk_busy &= ~(1 << unit);
   		dk_xfer[unit]++;
		c_info->int_expected = FALSE;
		uncache(&mdcb->intdcb);
		uncache(&dcb->operrsta);
		if(c_info->ctlr_type == SMD_ECTLR)
			uncache(&dcb->err_code);
		switch(vddecode_error(request, dcb)) {
		case CTLR_ERROR :
			vdhard_error(c_info, request, dcb,
			    (vdminfo[ctlr]->um_tab.b_errcnt < 2),
			    "Disk controller");
			vdreset_ctlr(vdminfo[ctlr]->um_addr,ctlr);
			if(vdminfo[ctlr]->um_tab.b_errcnt++ < 2) {
				vdminfo[ctlr]->um_tab.b_forw = u_queue->b_back;
				vdstart(vdminfo[ctlr]);
				return;
			}
			request->b_resid = request->b_bcount;
			break;
		case DRIVE_ERROR :
			vdhard_error(c_info, request, dcb,
			    (vdminfo[ctlr]->um_tab.b_errcnt < 2), "Disk drive");
			reset_drive(vdminfo[ctlr]->um_addr, ctlr, slave, 2);
			if(vdminfo[ctlr]->um_tab.b_errcnt++ < 2) {
				vdminfo[ctlr]->um_tab.b_forw = u_queue->b_back;
				vdstart(vdminfo[ctlr]);
				return;
			}
			request->b_resid = request->b_bcount;
			break;
		case HARD_DATA_ERROR :
			vdhard_error(c_info, request, dcb,
			    (vdminfo[ctlr]->um_tab.b_errcnt < 3),
			    "Uncorrected data");
			reset_drive(vdminfo[ctlr]->um_addr, ctlr, slave, 2);
			if(vdminfo[ctlr]->um_tab.b_errcnt++ < 3) {
				vdminfo[ctlr]->um_tab.b_forw = u_queue->b_back;
				vdstart(vdminfo[ctlr]);
				return;
			}
			request->b_resid = 0;
			break;
		case SOFT_DATA_ERROR :
			vdsoft_error(c_info, request, dcb);
		default :
			if(vdminfo[ctlr]->um_tab.b_errcnt)
				printf("  VDDC: Retried successfully.\n");
			request->b_error = 0;
			request->b_resid = 0;
			break;
		}
		end_transfer(request, c_info->rawbuf, c_info->map, c_info->utl);
		priority = spl7();
		u_queue->av_forw = request->av_forw;
		if(u_queue->av_back == request)
			u_queue->av_back = NULL;
		else {
			register struct buf	*next;

			unit = VDUNIT(u_queue->av_forw->b_dev);
			slave = vddinfo[unit]->ui_slave;
			next = u_queue->av_forw;
			if((next->b_cylin != c_info->cur_cyl[slave]) ||
			    ((next->b_daddr & 0xff) != c_info->cur_trk[slave]))
				c_info->off_cylinder |= 1 << slave;
		}
		splx(priority);
		vdminfo[ctlr]->um_tab.b_errcnt = 0;
		vdminfo[ctlr]->um_tab.b_active--;
#ifdef VDDCPERF
		scope_out(3);
#endif
		if(request->b_flags & B_ERROR)
			request->b_error = EIO;
		iodone(request);
		vdstart(vdminfo[ctlr]);
		return;
	}
	printf("\nVDDC: Unexpected interupt from controller %d!\n", ctlr);
}


/*
**
*/

vddecode_error(request, dcb)
register struct buf	*request;
register fmt_dcb	*dcb;
{
	register int	 unit = VDUNIT(request->b_dev);

	if(dcb->operrsta & HRDERR) {
		if (dcb->operrsta & (HCMPERR | WPTERR | DSEEKERR |
		    NOTCYLERR | DRVNRDY | INVDADR))
			return DRIVE_ERROR;
		else if(dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
			return CTLR_ERROR;
		return HARD_DATA_ERROR;
	}
	if(dcb->operrsta & SFTERR)
		return SOFT_DATA_ERROR;
	return NOERROR;
}


/*
**
*/

vdhard_error(c_info, request, dcb, retry, type)
ctlr_tab	*c_info; 
struct buf	*request;
fmt_dcb		*dcb;
int		retry;
char		*type;
{
	vdreport(c_info, request, dcb, type);
	if(retry)
		printf("  VDDC: Retrying failed operation...\n");
	else {
		request->b_flags |= B_ERROR;
		printf("  VDDC: Retries failed to correct error!\n");
	}
}


/*
**
*/

vdsoft_error(c_info, request, dcb)
ctlr_tab	*c_info; 
struct buf	*request;
fmt_dcb		*dcb;
{
	vdreport(c_info, request, dcb, "Corrected data");
}


/*
*/

vdreport(c_info, request, dcb, type)
ctlr_tab		*c_info; 
register struct buf	*request;
register fmt_dcb	*dcb;
char			*type;
{
	register int		delta;
	register int		unit = VDUNIT(request->b_dev);
	register unit_tab	*u_info = &vdunit_info[unit];
	register int		blk = request->b_blkno * u_info->sec_per_blk;
	register int		par = FILSYS(request->b_dev);

	harderr(request, u_info->info.type_name);
	printf("- %s error.  Status = 0x%x", type, dcb->operrsta);
	if(c_info->ctlr_type == SMD_ECTLR)
		printf(", Error code = 0x%x", dcb->err_code);
	printf("\n");
	delta = (request->b_bcount - 1) / u_info->info.secsize;
	blk = request->b_blkno + u_info->info.partition[par].par_start;
	blk *= u_info->sec_per_blk;
	if(delta == 0)
		printf("  VDDC: Error occured on absolute sector %d.\n", blk);
	else {
		printf("  VDDC: Error occured between");
		printf(" absolute sectors %d and %d.\n", blk, (blk + delta));
	}
}


/*
**
*/

vdopen(dev, flag)
register dev_t dev;
int flag;
{
	register unit = VDUNIT(dev);
	register struct vba_device *vba_dev_info = vddinfo[unit];

	if((vba_dev_info == 0) ||
	    (vba_dev_info->ui_alive == 0) ||
	    (vba_dev_info->ui_type >= nvddrv))
		return ENXIO;
	if(vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
		return ENXIO;
	return NOERROR;
}


/*
**
*/

vdread(dev, uio)
dev_t dev;
struct uio *uio;
{
	extern			vdstrategy();
	register int		unit = VDUNIT(dev);
	register unit_tab	*u_info = &vdunit_info[unit];

	if (unit >= NFSD)
		return ENXIO;
	return physio(vdstrategy, &u_info->raw_q_element, dev, B_READ,
	    minphys, uio);
}


/*
**
*/

vdwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
	extern			vdstrategy();
	register int		unit = VDUNIT(dev);
	register unit_tab	*u_info = &vdunit_info[unit];

	if (unit >= NFSD)
		return ENXIO;
	return physio(vdstrategy, &u_info->raw_q_element, dev, B_WRITE,
	    minphys, uio);
}


/*
**
*/

extern int physmem;

vddump(dev)
dev_t	dev;
{
	register int		 unit = VDUNIT(dev);
	register unit_tab	 *u_info = &vdunit_info[unit];
	register fs_tab		 *fs = &u_info->info;
	register int		 ctlr = vddinfo[unit]->ui_ctlr;
	register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
	register int		 filsys = FILSYS(dev);
	register cdr		 *ctlr_addr = (cdr *)(vba_vdctlr_info->um_addr);
	register int		 cur_blk, blkcount, blocks;
	int			 dump_short = FALSE;
	int			 memaddr = 0x0;

	vdreset_ctlr(ctlr_addr, ctlr);
	blkcount = physmem;		/* In 1k byte pages */
	if ((dumplo + blkcount) > fs->partition[filsys].par_len) {
		blkcount = fs->partition[filsys].par_len - dumplo;
		printf("\nVDDC: Only dumping first %dmb of memory!\n",
		    blkcount / 1024);
		dump_short = TRUE;
	}
	cur_blk = fs->partition[filsys].par_start + dumplo;
	while (blkcount > 0) {
		blocks = MIN(blkcount, DUMPSIZE);
		if(!vdwrite_block(ctlr_addr,ctlr,unit,memaddr,cur_blk,blocks))
			return EIO;
		blkcount -= blocks;
		memaddr += blocks * NBPG;
		cur_blk += blocks;
	}
	return dump_short ? ENXIO : NOERROR;
}


/*
**
*/

vdwrite_block(ctlr_addr, ctlr, unit, addr, block, blocks)
register cdr	 *ctlr_addr;
register int	ctlr, unit;
register char	*addr;
register int	block, blocks;
{
	register fmt_mdcb	*mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
	register fmt_dcb	*dcb = &vdctlr_info[ctlr].ctlr_dcb;
	register unit_tab	*u_info = &vdunit_info[unit];
	register fs_tab		*fs = &u_info->info;

	block *= (int)u_info->sec_per_blk;
	blocks *= (int)u_info->sec_per_blk;
	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
	dcb->intflg = NOINT;
	dcb->opcode = WD;
	dcb->operrsta = 0;
	dcb->devselect = (char)(vddinfo[unit])->ui_slave;
	dcb->trailcnt = (char)(sizeof(trrw) / sizeof(long));
	dcb->trail.rwtrail.memadr = addr;
	dcb->trail.rwtrail.wcount = (short)((blocks*fs->secsize)/sizeof(short));
	dcb->trail.rwtrail.disk.cylinder= (short)(block / u_info->sec_per_cyl);
	dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
	dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
	VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(mdcb)),
	    vdctlr_info[ctlr].ctlr_type);
	POLLTILLDONE(ctlr_addr, dcb, 5, vdctlr_info[ctlr].ctlr_type);
	if(vdtimeout <= 0) {
		printf(" during dump operation!\n");
		return(FALSE);
	}
	if (dcb->operrsta & HRDERR) {
		printf("\nVDDC: Dump error.  Status = %x\n", dcb->operrsta);
		return(FALSE);
	}
	return	TRUE;
}



/*
**
*/

vdsize(dev)
register dev_t dev;
{
	register unit = VDUNIT(dev);
	register struct vba_device *vba_dev_info = vddinfo[unit];

	if((vba_dev_info == 0) || 
	    (vba_dev_info->ui_alive == 0) ||
	    (vba_dev_info->ui_type >= nvddrv))
		return -1;
	return vdunit_info[unit].info.partition[FILSYS(dev)].par_len;
}


/*
**
*/

vdreset_ctlr(ctlr_addr, ctlr)
register cdr	*ctlr_addr;
register int	ctlr;
{
	register struct buf	*c_queue = &vdminfo[ctlr]->um_tab;
	register struct buf	*u_queue = c_queue->b_forw;
	register ctlr_tab	*c_info = &vdctlr_info[ctlr];
	register int		type, priority;
	
	printf("\n  VDDC: Resetting controller %d.  Please wait...\n", ctlr);
	VDDC_RESET(ctlr_addr, type);
	c_info->ctlr_started = FALSE;
	if(c_info->ctlr_type == SMD_ECTLR) {
		ctlr_addr->cdr_csr = 0;
		ctlr_addr->mdcb_tcf = AM_ENPDA;
		ctlr_addr->dcb_tcf = AM_ENPDA;
		ctlr_addr->trail_tcf = AM_ENPDA;
		ctlr_addr->data_tcf = AM_ENPDA;
		ctlr_addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
	}
	if(vdaccess_with_no_trailer(ctlr_addr,ctlr,0,INIT,10) & HRDERR) {
		printf("\n  VDDC: Controller %d failed to initialize!\n",ctlr);
		return	FALSE;
	}
	if(vdaccess_with_no_trailer(ctlr_addr,ctlr,0,DIAG,10) & HRDERR) {
		printf("\n  VDDC: Controller %d diagnostic error!\n",ctlr);
		return	FALSE;
	}
	/*  reset all units attached to controller */
	u_queue = c_queue->b_forw;
	do {
		reset_drive(ctlr_addr, ctlr, u_queue->b_dev, 0);
		u_queue = u_queue->b_forw;
	} while(u_queue != c_queue->b_forw);
	printf("  VDDC: Controller %d was reset successfully.\n", ctlr);
	return TRUE;
}


/*
**
*/

reset_drive(ctlr_addr, ctlr, slave, start)
register cdr	*ctlr_addr;
register int	ctlr, slave, start;
{
	register int	type = vdctlr_info[ctlr].unit_type[slave];

	if(type != UNKNOWN)
		if(!vdconfigure_drive(ctlr_addr, ctlr, slave, type, start)) {
			printf("\n  VDDC: Could not reset");
			printf(" unit %d, controller %d!\n", slave, ctlr);
		}
}

/*
	Print_dcb() dumps the mdcb and DCB for diagnostic purposes.  This
 routine is called whenever a fatal error is encountered.
*/

vdprintdcb(ptr)
register long	*ptr;
{
	register long	i, j=0;
	register long	trailer_count;

	ptr = (long *)(*ptr | 0xc0000000);
	while(ptr != (long *)NULL) {
		ptr = (long *)((long)ptr | 0xc0000000);
		printf(" Dump of DCB 0x%x,%d:", ptr, j++);
		trailer_count = *(ptr+3) & 0xff;
		for(i=0; i<7+trailer_count; i++)
			printf("  %lx", *(ptr+i));
		ptr = (long *)(*ptr);
		printf("\n");
	}
	printf("\n");
	for(i=0; i<5000000; i++) ;
}

#endif NVD > 0


unix.superglobalmegacorp.com

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