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