|
|
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");
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.