File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / d / ioex / vddc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b


/*
 *	Base of share memory for VDDC is at : 0x2000 (0x2X00)
 *		X is switch selectable. 
 *	The following configuration is assumed on VDDC :
 *		FSD0          : device 0
 *		FSD1          : device 1
 *		SMD0 	      : device 2
 *		SMD1 	      : device 3
 */

#define  SBR		0
#define  PGSHIFT	10
#include "pte.h"
#include "vddc.h"

/*	**********************
	parameters for FSD,SMD
	**********************
*/
#define	NOUNIT		4
struct DEVPAR devpar[NOUNIT+1] = {
	823,10,10,32,512,0,"FSD",	/* FSD */
	823,10,10,32,512,0,"FSD",	/* FSD */
	823,19,19,32,512,0,"SMD",	/* SMD */
	823,19,19,32,512,0,"SMD",	/* SMD */
	0,0,0,0,0,0,"   "
};

/* 	VDDC Master DCB packet 	*/
struct MDCB mdcb;

/* 	VDDC DCB 	*/
struct DCB dcb;

long VDDCbase;		/* Virtual addrss 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, IOinit;

vddc()
{	register long r12;
	long oldvec;

	Probe = 0;
	m_vddc();		/* Map VDDC */

	/* Set handler for VDDC interrupt */
	asm("movab vddchdlr,r12");
	set_handler(VDDCVEC,&oldvec,r12);

	/* Reset UDC controller */
	if ( vddc_reset()==0 )  {
		writes("\n** Cannot reset VDDC controller \n");
		return(0);
		}
	writes("\nVDDC controller is at "); writeh(VDDCBASE);
	whonline();
	return(1);
}


/*	Routine to map VDDC
*/
m_vddc()
{	long r12, phys_pg, pte, old_pte, which1;

	phys_pg = ((VDDCBASE+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);

	asm("mfpr $SLR,r12");
	r12++;
	asm("mtpr r12,$SLR");
	unused++;		/* Next unused PTE in system map */
}

whonline()
{	register struct DEVPAR *dp;
	register long unit;
	for(unit=0;devpar[unit].nocyl != 0;unit++) {
		Probe = 1;
		devpar[unit].alive = 1;
		if (!vddc_op(RD_DATA,unit,0,1,&iob0)) devpar[unit].alive = 0; 
			else {	/* Unit is on line */
				/* Execute configure command */
				Probe = 0;
				vddc_ctlr(CONFIG,unit);
				writes("\n\t"); writes(devpar[unit].name);
				writes(" is on unit "); writed(unit);
				writec('\n');
				} 
	}
	Probe = 0;
}

/* 
	******************************************************
    		Routine to sent one of the following control
	command to VDDC : Format, 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];
	notrailer = 0;
	switch	(op) {
		case FORMAT :
			for (noword=0;noword<512;noword++)
				format_data[noword] = 0xabababab;
			trailer[0] = (long)format_data;
			trailer[1] = dp->nocyl*dp->nohead*dp->secs_trak;
			trailer[2] = 0;		/* Start from log. sector 0 */
			trailer[3] = 0;
			notrailer = 4;
			Format = 1;
			setup_dcb(&dcb,op,dev,notrailer,trailer);
			noword=sento_vddc(&dcb);	/* Return 1 if O.K */
			Format = 0;
			return(noword);
			break;
		case START_DR :
			break;
		case STOP_DR :
			break;
		case CONFIG:
			trailer[0] = dp->nocyl;
			trailer[1] = dp->nohead;
			notrailer = 2;
			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 dev, *buf_adr;
long no_blks, blkno;
{	long trailer[3], nosec_cyl, secno;
	long cyl_no, trak_no, sector_no;
	register struct DEVPAR *dp;

	if (!devpar[dev].alive) {
		writes("\nUnit "); writed(dev);
		writes(" is not online..\n");
		return(0); }
	dp = &devpar[dev];
	/* 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 */
	trailer[2] = (cyl_no&0xfff)|(sector_no<<16)|(trak_no<<24);
	if (!IOinit) {
		if (op==(unsigned short)RD_DATA) writec('R');
	 		else writec('W'); 
		/* writeh(blkno); writec('/'); writeh(no_blks); writec('/');
		writeh(trailer[2]); */
		}
	setup_dcb(&dcb,op,dev,3,trailer);
	return(sento_vddc(&dcb));	/* Return 1 if O.K */
}


/*	*********************
   	Reset VDDC controller.
	*********************
*/
vddc_reset()
{	register long cnt;

	*((char *)(VDDCbase + 4)) = 1;		/* Reset VDDC */
	DELAY(0x1f0000);			/* Wait for 3 seconds */
	return(1);
}


/*	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_SUCCESS;
	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();				/* Interrupt 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;

	if (Format)  { cnt = 0xfffffff0;
			writes("\nVDDC formatting..."); }
		else cnt = 0xfff00;
	while (!Vdone) {	/* Wait for completion interrupt */
		if (Format) writec('f');
		if (--cnt <= 0) {
			if (!Probe)
			    writes("\ntime 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("\nUnsolicited 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);
		return(0);
		}
	return(1);
}

/*	***********************
	Routine to print status 
	***********************
*/
prt_vddcstat(stat)
long stat;
{
	if (Probe) return;
	if (stat&SOFT_ERROR) {
		writes("\nsoft error ");
		writeh((stat&SOFTERR_MASK)>>8);
		}
	    else {
		if (stat&HARD_ERROR) {
			writes("\nhard error ");
			writeh(stat&HARDERR_MASK); }
		    else 
			if (stat&DATA_CORRECT) {
			       writes("\nController performed data correction");
				writeh(stat&HARDERR_MASK); }
	    }
	writec('\n');
}



/*	VDDC interrupt handler 
*/
vddc_hdlr()
{
	Vdone = 1;    /* Command done, received interrupt */
}

Vddchdlr()
{	long dummy;
	asm(".align 2");
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.