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


/*
 *	Base of share memory for VDDC is at : 0x2000 (0x2X00)
 *		X is switch selectable. 
 */

#define	NOUNIT	20
#define	PGSHIFT	10

#include "pte.h"
#include "vddc.h"

/*	******************************
	parameters for FSD,SMD,XFD,XSD
	******************************
*/

struct DEVPAR devpar[NOUNIT] = {
	823,10,10,32,512,0,"fsd",	/* FSD */
	823,10,10,32,512,0,"fsd",	/* FSD */
	823,10,10,32,512,0,"fsd",   	/* FSD */
	823,10,10,32,512,0,"fsd",	/* FSD */
	0,0,0,0,0,0,"   ",
	823,19,19,32,512,0,"smd",	/* SMD */
	823,19,19,32,512,0,"smd",	/* SMD */
	823,19,19,32,512,0,"smd",	/* SMD */
	823,19,19,32,512,0,"smd",	/* SMD */
	0,0,0,0,0,0,"   ",
	711,24,24,32,512,0,"xfd",	/* XFD */
	711,24,24,32,512,0,"xfd",	/* XFD */
	711,24,24,32,512,0,"xfd",	/* XFD */
	711,24,24,32,512,0,"xfd",	/* XFD */
	0,0,0,0,0,0,"   ",
	711,24,24,48,512,0,"xsd",	/* XSD */
	711,24,24,48,512,0,"xsd",   	/* XSD */
	711,24,24,48,512,0,"xsd",   	/* XSD */
	711,24,24,48,512,0,"xsd",	/* XSD */
	0,0,0,0,0,0,"   "
};
/*	*****************************************
	Controller parameters for controllers 0-7
	*****************************************
*/
struct DA VDDCBASE[8] = {
	0xff2000,0xe0,0,	/* device address, int vect, online flg */
	0xff2100,0xe1,0,	/* device address, int vect, online flg */
	0xff2200,0xe2,0,	/* device address, int vect, online flg */
	0xff2300,0xe3,0,	/* device address, int vect, online flg */
	0xff2400,0xe4,0,	/* device address, int vect, online flg */
	0xff2500,0xe5,0,	/* device address, int vect, online flg */
	0xff2600,0xe6,0,	/* device address, int vect, online flg */
	0xff2700,0xe7,0		/* device address, int vect, online flg */
};
/* 	VDDC Master DCB packet 	*/

struct MDCB mdcb;

/* 	VDDC DCB 	*/

struct DCB dcb;

long VDDCbase;		/* Virtual address of VDDC */
long Vdone;		/* Flag polled for status packet */
long Format = 0;	/* If set, VDDC is formatting, wait longer ! */
long Probe = 0;		/* If set do not print error message */
extern long unused, iob0, Multi, Berr, IOinit;
int cont, type;

vddc()
{	register long r12;
	long oldvec;
	Probe = 0;

	/* output test header */ 

	writes("\n\n\t** VDDC Test **");

	cont = getcont();		/* Get controller number */
	type = gettype();		/* Get type of disk drives */

	/* Check if selected controller is installed */

	if(VDDCBASE[cont].online == 0) {
		writes("\n\nVDDC controller no. "); writed(cont);
		writes(" is not installed\n");
		return(0); }
	m_vddc();	/* Map VDDC */

	/* Set handler for VDDC interrupt */

	asm("movab vddchdlr,r12");
	set_handler(VDDCBASE[cont].intvect,&oldvec,r12);

	/* Reset UDC controller */ 
	vddc_reset();
	whonline();
	return(1);
}
chk_vdadr()
{	long curaddr, nvddc, vddcno;
	short len;
	len = 4;
	writes("\nProbing for VDDC controllers...");
	for(nvddc=vddcno=0; vddcno<8; vddcno++) {
		curaddr = VDDCBASE[vddcno].devaddr + IOBASE;
		if(badaddr(curaddr,len) == 0) {
			writes("\nVDDC controller no. "); writed(vddcno);
			writes(" at address ");
			curaddr -= IOBASE;
			writeh(curaddr);
			VDDCBASE[vddcno].online = 1;
			nvddc++; }
	}
	writes("\n"); writed(nvddc); writes(" VDDC controller(s) found");
	return(nvddc);
}
/*	Routine to map VDDC
*/
m_vddc()
{	long r12, phys_pg, pte, old_pte, which1;

	phys_pg = ((VDDCBASE[cont].devaddr + IOBASE) >> PGSHIFT) & 0x3fffff;

	/* 1st physical page of VDDC in IO space */
	pte = phys_pg | PG_KW | PG_V | PG_NC;
	fix_pte(SBR,unused,&old_pte,pte);

	/* Base Virtual addr of VDDC */
	VDDCbase = (unused << PGSHIFT) | (VDDCBASE[cont].devaddr & 0x3ff);

	asm("mfpr $SLR,r12");
	r12++;
	asm("mtpr r12,$SLR");
	unused++;		/* Next unused PTE in system map */
}
whonline()
{	register struct DEVPAR *dp;
	register long unit;
	*((long *)(VDDCbase + 0xc)) = 0xffffffff;
	if (*((long *)(VDDCbase + 0xc)) != 0xffffffff){
		writes("\n\nController ");writed(cont);writes(" is a VSMD");
		vddc_ctlr(INITIALIZE,unit);
		}
	else {
		writes("\n\nController ");writed(cont);writes(" is a VSMD-E");
		*((long *)(VDDCbase + 0x40)) = 0x33061;
		vddc_ctlr(INITIALIZE,unit);
		}
	for(unit=0;devpar[unit+type*5].nocyl != 0;unit++) {
		Probe = 1;
		devpar[unit+type*5].alive = 1;
		vddc_ctlr(CONFIG,unit);
		if (!vddc_op(R_DATA,unit,0,1,&iob0)){
			devpar[unit+type*5].alive = 0; }
		else {
			Probe = 0;
			}
	}
	Probe = 0;
}

/* 
	******************************************************
    		Routine to sent one of the following control
	command to VDDC : start drives, stop drives, 
	initialize controller, diagnose, Configure drive,
	status.
	op	 : one of the above opcode
	dev	 : device selected
	Returns 1 if command successfully completed.
	******************************************************
*/
vddc_ctlr(op,dev)
unsigned short op;
char dev;
{	long trailer[5];
	register long notrailer, noword;
	register struct DEVPAR *dp;
	unsigned short format_data[512];

	dp = &devpar[dev+type*5];
	notrailer = 0;
	switch	(op) {
		case START_DR :
			break;
		case STOP_DR :
			break;
		case CONFIG:
			trailer[0] = dp->nocyl;
			trailer[1] = dp->nohead;
			trailer[2] = dp->secs_trak;
			trailer[3] = 0;
			notrailer = 4;
			break;
		case STATUS:
			setup_dcb(&dcb,op,dev,notrailer,trailer);
			sento_vddc(&dcb);
			return(mdcb.ctlr_stat);
		case INITIALIZE:
			break;
		case DIAGNOSE:
			break;
	}
	setup_dcb(&dcb,op,dev,notrailer,trailer);
	return(sento_vddc(&dcb));	/* Return 1 if O.K */
}


/* 
	******************************************************
    		Routine to read/write N block from/to disk
	op	 : opcode, READ or WRITE
	dev	 : device selected
	blkno	 : Logical block no. (1024bytes/blk) to access
	no_blks	 : no. of blocks to access
	buf_adr	 : Memory address
	Returns 1 if command successfully completed.
	******************************************************
*/
vddc_op(op,dev,blkno,no_blks,buf_adr)
unsigned short op;
char *buf_adr;
long no_blks, blkno;
{	long trailer[3], nosec_cyl, secno;
	long cyl_no, trak_no, sector_no;
	char uf0,uf3;
	register struct DEVPAR *dp;
	uf0 = 0x0;
	uf3 = 0xc0;
	if (!devpar[dev+type*5].alive) {
		writes("\n...Unit "); writed(dev);
		writes(" is not online\n");
		return(0); }
	dp = &devpar[dev+type*5];
	/* Setup trailer words */
	nosec_cyl = dp->notraks * dp->secs_trak;	/* No of sectors/cyl */
	secno = blkno*(BLKSIZ/dp->sector_siz);   /* Abs. sector no. to access */

	if ( (cyl_no=secno/nosec_cyl)>dp->nocyl ) {
		if (!Probe) { writes("...Cylinder no "); writed(cyl_no);
				writes(", too large\n"); return(0); }
		}
	secno = secno%nosec_cyl;
	trak_no = secno/dp->secs_trak;
	sector_no = secno%dp->secs_trak;

	trailer[0] = (long)buf_adr;
	trailer[1] = no_blks * (BLKSIZ/2);	/* Unit is in word size */
	if (cyl_no > dp->nocyl-2) {
	   trailer[2]=(cyl_no&0xfff)|(sector_no<<16)|(trak_no<<24)|(uf3<<12);
 	}
	else {	
	   trailer[2]=(cyl_no&0xfff)|(sector_no<<16)|(trak_no<<24)|(uf0<<12);
	}
	setup_dcb(&dcb,op,dev,3,trailer);
	return(sento_vddc(&dcb));	/* Return 1 if O.K */
}
/*
	write or read to/from specific cylinder, track, sector
*/
vddc_op2(op,dev,cyl,trk,sec,no_blks,buf_adr)
unsigned short op;
char *buf_adr;
long no_blks, cyl, trk, sec;
{
	long trailer[3];
	char uf0;

	uf0 = 0x0;
	trailer[0] = (long)buf_adr;
	trailer[1] = no_blks * (BLKSIZ/2);
	trailer[2] = (cyl & 0xfff)|(sec << 16)|(trk << 24)|(uf0 << 12);
	setup_dcb(&dcb,op,dev,3,trailer);
	return(sento_vddc(&dcb));
}
/*
	seek to a specific cylinder, track, sector
*/
vddc_op3(op,dev,cyl,trk,sec)
unsigned short op;
long  cyl, trk, sec;
{
	long trailer[1];
	char uf0;

	uf0 = 0x0;
	trailer[0] = (cyl & 0xfff)|(sec << 16)|(trk << 24)|(uf0 << 12);
	setup_dcb(&dcb,op,dev,1,trailer);
	return(sento_vddc(&dcb));
}
/*	*********************
	Reset VDDC controller
	*********************
*/
vddc_reset()
{
	*((char *)(VDDCbase + 4)) = 1;	/* reset VDDC */
	DELAY(0x1f0000);		/* wait for 3 seconds */
	return(1);
}
vddc_init()
{
}
/*	Routine to fill DCB
*/
setup_dcb(dcb,opcode,devno,notrailer,trailer)
struct DCB *dcb;
unsigned short opcode;
char devno, notrailer;
long *trailer;
{	register long ix, *r12;
	dcb->nxt_dcb = NO_CHAIN;
	dcb->int_flags = (unsigned short)INT_DONE;
	dcb->opcode = opcode;
	dcb->dcb_stat = 0;			/* Clear DCB status */
	dcb->dev_sel = (char)devno & 0x3;	/* Device selected */
	dcb->trail_wcnt = notrailer;		/* No. of trailer words */
	r12 = (long *)dcb->trailer;
	for (ix=0;ix<notrailer;ix++) r12[ix] = trailer[ix];
}


/*	
	Routine to initiate a command to VDDC after DCB is set up
	Input : vdcb = pointer to DCB structure
*/
TO_VDDC(vdcb)
struct DCB *vdcb;
{
	mdcb.fdcb_adr = (long)vdcb;		/* Set 1st DCB address */
	mdcb.dcb_active = mdcb.dcb_int = mdcb.ctlr_stat = 0;
	INT_VDDC();
}
INT_VDDC()
{
	register long r12, r11, r10;
	r12 = (((long)&mdcb) >> 16) & 0xffff; 
	r11 = ((long)&mdcb) & 0xffff;
	r10 = VDDCbase;
	asm("movow r12,(r10)");
	asm("movow r11,2(r10)");
}
/* 
	**********************************************************
    	Routine to set up, sent command packet to UDC and check
	status packet received from UDC. Return 0 if error occured
	**********************************************************
*/
sento_vddc(vdcb)
struct DCB *vdcb;
{
	Vdone = 0;
	TO_VDDC(vdcb);		/* Sent command to vddc */
	if (Multi) return(1);
	if (!vddc_wait()) return(0);
	return(chk_vddcstat(vdcb));
}


/*	**************************************************
	Routine to poll for completion interrupt from VDDC
	**************************************************
*/
vddc_wait()
{	register long cnt;
	cnt = 0xfff00;
	while (!Vdone) {	/* Wait for completion interrupt */
		if (--cnt <= 0) {
			if (!Probe) 
			 writes("\n...time out, lost completion interrupt..\n");
			return(0); }
		}
	return(1);
}


/*	*****************************************************
	Routine to check completion status returned from VDDC
	return 1 : status OK; command completed
	       0 : Command did not completed
	*****************************************************
*/
chk_vddcstat(vdcb)
struct DCB *vdcb;
{
	if (mdcb.dcb_int != (long)vdcb) {
		writes("\n...Unsolicited DCB address, expected ");
		writeh((long)vdcb); writes(", actual ");
		writeh(mdcb.dcb_int); writes("\n"); 
		return(0); }
	if (((vdcb->dcb_stat&0xf0000000) != DCB_DONE) ||
		(vdcb->dcb_stat&ANY_ERROR)) {
		prt_vddcstat(vdcb->dcb_stat);
		if (vdcb->dcb_stat&HARD_ERROR) return(0);
		}
	return(1);
}

/*	***********************
	Routine to print status 
	***********************
*/
prt_vddcstat(stat)
long stat;
{
	if (Probe) return;
	if (stat&SOFT_ERROR) {
		writes("\n...soft error ");
		writeh(stat&SOFTERR_MASK);
		}
	    else {
		if (stat&HARD_ERROR) {
			writes("\n...hard error ");
			writeh(stat&HARDERR_MASK); }
		    else 
			if (stat&DATA_CORRECT) {
			    writes("\n...Controller performed data correction");
				writeh(stat&HARDERR_MASK); }
	    }
	writec('\n');
}
/*	VDDC interrupt handler 
*/
vddc_hdlr()
{
	Vdone = 1;    /* Command done, received interrupt */
}
Vddchdlr()
{	asm(".align 2");
	asm(".globl vddchdlr");
asm("vddchdlr:");
	asm("svpctx");   
	vddc_hdlr();		/* VDDC handler */
	asm("ldpctx");   
	asm("rei");
}

unix.superglobalmegacorp.com

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