* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)rl.c 7.6 (Berkeley) %G%
* Standalone RL02 disk driver
#include "../vaxuba/rlreg.h"
#include "../vaxuba/ubareg.h"
#define MAXCTLR 1 /* all addresses must be specified */
u_short rlstd
[MAXCTLR
] = { 0774400 };
short rl_off
[] = { 0, 361, 0, -1, -1, -1, -1, -1 };
/* struct to keep state info about the controller */
short rl_dn
; /* drive number */
short rl_cylnhd
; /* cylinder and head */
u_short rl_bleft
; /* bytes left to transfer */
u_short rl_bpart
; /* bytes transferred */
} rl_stat
[MAXCTLR
] = { -1, 0, 0, 0 };
register struct rldevice
*rladdr
;
register struct rl_stat
*st
;
if ((u_int
)io
->i_adapt
>= nuba
)
if ((u_int
)io
->i_ctlr
>= MAXCTLR
)
rladdr
= (struct rldevice
*)ubamem(io
->i_adapt
, rlstd
[io
->i_ctlr
]);
if (badaddr((char *)rladdr
, sizeof(short)))
if ((u_int
)io
->i_part
>= MAXPART
|| rl_off
[io
->i_part
] == -1)
* 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
* In order to overcome this, the driver has been modified to
* issue a GET STATUS request and validate the drive status
* returned. If a valid status is not returned after eight
* attempts, then an error message is printed.
rladdr
->rlda
.getstat
= RL_RESET
;
rladdr
->rlcs
= (io
->i_unit
<<8) | RL_GETSTAT
; /* Get status*/
} while ((rladdr
->rlmp
.getstat
&RLMP_STATUS
) != RLMP_STATOK
&& ++ctr
<8);
if ((rladdr
->rlcs
& RL_DE
) || (ctr
>= 8)) {
printf("rl: unit does not respond\n");
if ((rladdr
->rlmp
.getstat
& RLMP_DT
) == 0) { /* NO RL01'S */
printf("rl01 unit not supported\n");
/* Determine disk posistion */
rladdr
->rlcs
= (io
->i_unit
<< 8) | RL_RHDR
;
/* save disk drive posistion */
st
= &rl_stat
[io
->i_ctlr
];
st
->rl_cylnhd
= (rladdr
->rlmp
.readhdr
& 0177700) >> 6;
/* byte offset for cylinder desired */
io
->i_boff
= rl_off
[io
->i_part
] * NRLBPSC
* NRLTRKS
* NRLSECT
;
register struct rldevice
*rladdr
;
register struct rl_stat
*st
;
int diff
, ubinfo
, ubaaddr
, errcnt
= 0;
rladdr
= (struct rldevice
*)ubamem(io
->i_adapt
, rlstd
[io
->i_ctlr
]);
st
= &rl_stat
[io
->i_ctlr
];
ubinfo
= ubasetup(io
, 1);
bn
= io
->i_bn
; /* block number */
cn
= bn
/ 40; /* 40 512 byte blocks per cylinder */
st
->rl_bleft
= io
->i_cc
; /* total number of bytes to trans */
/* find out how many cylinders to seek */
diff
= (st
->rl_cylnhd
>> 1) - cn
;
if (diff
== 0 && (st
->rl_cylnhd
& 1) == head
)
/* first time or we switched drives */
st
->rl_dn
= io
->i_unit
; /* drive number */
rladdr
->rlda
.seek
= -diff
<<7 | RLDA_HGH
| head
<< 4;
rladdr
->rlda
.seek
= diff
<<7 | RLDA_LOW
| head
<< 4;
rladdr
->rlcs
= (st
->rl_dn
<< 8) | RL_SEEK
;
/* reset position of drive */
st
->rl_cylnhd
= (cn
<< 1) | head
;
/* wait for controller and drive */
while( (rladdr
->rlcs
& RL_DCRDY
) != RL_DCRDY
)
/* calculate the max number of bytes we can trans */
st
->rl_bpart
= NRLSECT
* NRLBPSC
- (sn
* NRLBPSC
);
if (st
->rl_bleft
< st
->rl_bpart
)
st
->rl_bpart
= st
->rl_bleft
;
rladdr
->rlda
.rw
= (st
->rl_cylnhd
<< 6) | sn
;
rladdr
->rlmp
.rw
= -(st
->rl_bpart
>> 1);
com
= (st
->rl_dn
<< 8) | ((ubaaddr
>>12)&RL_BAE
);
/* wait for controller and drive */
while( (rladdr
->rlcs
& RL_DCRDY
) != RL_DCRDY
)
if (rladdr
->rlcs
& RL_ERR
) {
if (rladdr
->rlcs
& RL_DE
) {
rladdr
->rlda
.getstat
= RL_GSTAT
;
rladdr
->rlcs
= (st
->rl_dn
<< 8) | RL_GETSTAT
;
status
= rladdr
->rlmp
.getstat
;
rladdr
->rlda
.getstat
= RL_RESET
;
rladdr
->rlcs
= (st
->rl_dn
<<8) | RL_GETSTAT
;
printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n",
cn
, head
, sn
, rladdr
->rlcs
& 0xffff, RLCS_BITS
,
/* Determine disk posistion */
rladdr
->rlcs
= (st
->rl_dn
<< 8) | RL_RHDR
;
/* save disk drive posistion */
st
->rl_cylnhd
= (rladdr
->rlmp
.readhdr
& 0177700) >> 6;
printf("rl: unrecovered error\n");
/* do we have to finish off the rest of the transfer? */
if ((st
->rl_bleft
-= st
->rl_bpart
) > 0) {
/* increment head and/or cylinder */
cn
++; /* want next cyl, head 0 sector 0 */
/* we always want sector to be zero */
* standalone code for ubafree does what regular
* ubapurge does and we want to purge last transfer
ubaaddr
= ubinfo
+ io
->i_cc
- st
->rl_bleft
;
printf("rl: recovered by retry\n");
register struct rldevice
*rladdr
;
while ((rladdr
->rlcs
& RL_CRDY
) == 0);