2.9BSD/usr/net/sys/stand/libsa/rl.c
/*
* RL disk driver
*
* RL driver modified for the standalone shell.
* Armando P. Stettner Digital Equipment Corp. July, 1980
*/
#include <sys/param.h>
#include <sys/inode.h>
#include "../saio.h"
#define BLKRL1 10240 /* Number of UNIX blocks for an RL01 drive */
#define BLKRL2 20480 /* Number of UNIX blocks for an RL02 drive */
#define RLCYLSZ 10240 /* bytes per cylinder */
#define RLSECSZ 256 /* bytes per sector */
#define RESET 013
#define RL02TYP 0200 /* drive type bit */
#define STAT 03
#define GETSTAT 04
#define WCOM 012
#define RCOM 014
#define SEEK 06
#define SEEKHI 5
#define SEEKLO 1
#define RDHDR 010
#define IENABLE 0100
#define CRDY 0200
#define OPI 02000
#define CRCERR 04000
#define TIMOUT 010000
#define NXM 020000
#define DE 040000
struct device
{
int rlcs ,
rlba ,
rlda ,
rlmp ;
} ;
#define RLADDR ((struct device *)0174400)
#define RL_CNT 1
struct
{
int cn[4] ; /* location of heads for each drive */
int type[4] ; /* parameter dependent upon drive type (RL01/02) */
int com ; /* read or write command word */
int chn ; /* cylinder and head number */
unsigned int bleft ; /* bytes left to be transferred */
unsigned int bpart ; /* number of bytes transferred */
int sn ; /* sector number */
union {
int w[2] ;
long l ;
} addr ; /* address of memory for transfer */
} rl = {-1,-1,-1,-1, -1,-1,-1,-1} ; /* initialize cn[] and type[] */
rlstrategy(io, func)
register struct iob *io ;
int func ;
{
int nblocks ; /* number of UNIX blocks for the drive in question */
int drive ;
int dif ;
int head ;
int ctr ;
/*
* We must determine what type of drive we are talking to in order
* to determine how many blocks are on the device. The rl.type[]
* array has been initialized with -1's so that we may test first
* contact with a particular drive and do this determination only once.
* Sorry tjk for this hack.
*
* RL02 GET STATUS BAND-AID - Fred Canter 10/14/80
*
* For some unknown reason the RL02 (seems to be
* only drive 1) does not return a valid drive status
* the first time that a GET STATUS request is issued
* for the drive, in fact it can take up to three or more
* GET STATUS requests to obtain the correct status.
* In order to overcome this "HACK" the driver has been
* modified to issue a GET STATUS request, validate the
* drive status returned, and then use it to determine the
* drive type. If a valid status is not returned after eight
* attempts, then an error message is printed.
*/
drive = io->i_unit ;
if (rl.type[drive] < 0)
{
ctr = 0;
do {
RLADDR->rlda = RESET ; /* load this register; what a dumb controller */
RLADDR->rlcs = (drive << 8) | GETSTAT ; /* set up csr */
while ((RLADDR->rlcs & CRDY) == 0) /* wait for it */
;
} while (((RLADDR->rlmp & 0177477) != 035) && (++ctr < 8)) ;
if (ctr >= 8)
printf("\nCan't get status of RL unit %d\n",drive) ;
if (RLADDR->rlmp & RL02TYP)
rl.type[drive] = BLKRL2 ; /* drive is RL02 */
else
rl.type[drive] = BLKRL1 ; /* drive RL01 */
/*
* When the device is first touched, find out where the heads are.
*/
/* find where the heads are */
RLADDR->rlcs = (drive << 8) | RDHDR;
while ((RLADDR->rlcs&CRDY) == 0)
;
/*rl.cn[drive] = (RLADDR->rlmp&0177700) >> 6;*/
rl.cn[drive] = ((RLADDR->rlmp) >> 6) & 01777; /* fix sign bug */
}
nblocks = rl.type[drive] ; /* how many blocks on this drive */
if(io->i_bn >= nblocks)
return -1 ;
rl.chn = io->i_bn/20;
rl.sn = (io->i_bn%20) << 1;
rl.bleft = io->i_cc;
rl.addr.w[0] = segflag & 3;
rl.addr.w[1] = (int)io->i_ma ;
rl.com = (drive << 8) ;
if (func == READ)
rl.com |= RCOM;
else
rl.com |= WCOM;
reading:
/*
* One has to seek an RL head, relativily.
*/
dif =(rl.cn[drive] >> 1) - (rl.chn >>1);
head = (rl.chn & 1) << 4;
if (dif < 0)
RLADDR->rlda = (-dif <<7) | SEEKHI | head;
else
RLADDR->rlda = (dif << 7) | SEEKLO | head;
RLADDR->rlcs = (drive << 8) | SEEK;
rl.cn[drive] = rl.chn; /* keep current, our notion of where the heads are */
if (rl.bleft < (rl.bpart = RLCYLSZ - (rl.sn * RLSECSZ)))
rl.bpart = rl.bleft;
while ((RLADDR->rlcs&CRDY) == 0) ;
RLADDR->rlda = (rl.chn << 6) | rl.sn;
RLADDR->rlba = rl.addr.w[1];
RLADDR->rlmp = -(rl.bpart >> 1);
RLADDR->rlcs = rl.com | rl.addr.w[0] << 4;
while ((RLADDR->rlcs & CRDY) == 0) /* wait for completion */
;
if (RLADDR->rlcs < 0) /* check error bit */
{
if (RLADDR->rlcs & 040000) /* Drive error */
{
/*
* get status from drive
*/
RLADDR->rlda = STAT;
RLADDR->rlcs = (drive << 8) | GETSTAT;
while ((RLADDR->rlcs & CRDY) == 0) /* wait for controller */
;
}
printf("Rl disk error: cyl=%d, head=%d, sector=%d, rlcs=%o, rlmp=%o\n",
rl.chn>>01, rl.chn&01, rl.sn, RLADDR->rlcs, RLADDR->rlmp) ;
return -1 ;
}
/*
* Determine if there is more to read to satisfy this request.
* This is to compensate for the lacl of spiraling reads.
*/
if ((rl.bleft -= rl.bpart) > 0)
{
rl.addr.l += rl.bpart ;
rl.sn = 0 ;
rl.chn++ ;
goto reading ; /* read some more */
}
return io->i_cc ;
}