| 1 | /* |
| 2 | * Copyright (c) 1982 Regents of the University of California. |
| 3 | * All rights reserved. The Berkeley software License Agreement |
| 4 | * specifies the terms and conditions for redistribution. |
| 5 | * |
| 6 | * @(#)rl.c 6.2 (Berkeley) %G% |
| 7 | */ |
| 8 | |
| 9 | /* |
| 10 | * Standalone RL02 disk driver |
| 11 | */ |
| 12 | #include "../machine/pte.h" |
| 13 | |
| 14 | #include "../h/param.h" |
| 15 | #include "../h/inode.h" |
| 16 | #include "../h/fs.h" |
| 17 | |
| 18 | #include "../vaxuba/rlreg.h" |
| 19 | #include "../vaxuba/ubareg.h" |
| 20 | |
| 21 | #include "saio.h" |
| 22 | #include "savax.h" |
| 23 | |
| 24 | u_short rlstd[] = { 0774400 }; |
| 25 | short rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 }; |
| 26 | |
| 27 | /* struct to keep state info about the controller */ |
| 28 | struct rl_stat { |
| 29 | short rl_dn; /* drive number */ |
| 30 | short rl_cylnhd; /* cylinder and head */ |
| 31 | u_short rl_bleft; /* bytes left to transfer */ |
| 32 | u_short rl_bpart; /* bytes transferred */ |
| 33 | } rl_stat[] = { -1, 0, 0, 0}; |
| 34 | |
| 35 | rlopen(io) |
| 36 | register struct iob *io; |
| 37 | { |
| 38 | register struct rldevice *rladdr = |
| 39 | (struct rldevice *)ubamem(io->i_unit, rlstd[0]); |
| 40 | register struct rl_stat *st = &rl_stat[0]; |
| 41 | register int ctr = 0; |
| 42 | |
| 43 | if (rl_off[io->i_boff] == -1 || |
| 44 | io->i_boff < 0 || io->i_boff > 7) |
| 45 | _stop("rl bad unit"); |
| 46 | |
| 47 | /* |
| 48 | * DEC reports that: |
| 49 | * For some unknown reason the RL02 (seems to be only drive 1) |
| 50 | * does not return a valid drive status the first time that a |
| 51 | * GET STATUS request is issued for the drive, in fact it can |
| 52 | * take up to three or more GET STATUS requests to obtain the |
| 53 | * correct status. |
| 54 | * In order to overcome this, the driver has been modified to |
| 55 | * issue a GET STATUS request and validate the drive status |
| 56 | * returned. If a valid status is not returned after eight |
| 57 | * attempts, then an error message is printed. |
| 58 | */ |
| 59 | do { |
| 60 | rladdr->rlda.getstat = RL_RESET; |
| 61 | rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/ |
| 62 | rlwait(rladdr); |
| 63 | } while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 ); |
| 64 | |
| 65 | if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) |
| 66 | _stop("rl unit does not respond"); |
| 67 | |
| 68 | if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) /* NO RL01'S */ |
| 69 | _stop("rl01 unit not supported"); |
| 70 | |
| 71 | /* Determine disk posistion */ |
| 72 | rladdr->rlcs = (io->i_unit << 8) | RL_RHDR; |
| 73 | rlwait(rladdr); |
| 74 | |
| 75 | /* save disk drive posistion */ |
| 76 | st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; |
| 77 | st->rl_dn = io->i_unit; |
| 78 | |
| 79 | /* byte offset for cylinder desired */ |
| 80 | io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT; |
| 81 | } |
| 82 | |
| 83 | rlstrategy(io, func) |
| 84 | register struct iob *io; |
| 85 | { |
| 86 | register struct rldevice *rladdr = |
| 87 | (struct rldevice *)ubamem(io->i_unit, rlstd[0]); |
| 88 | register struct rl_stat *st = &rl_stat[0]; |
| 89 | int com; |
| 90 | daddr_t bn; |
| 91 | short cn, sn, head; |
| 92 | int diff, ubinfo, ubaddr, errcnt = 0; |
| 93 | |
| 94 | retry: |
| 95 | ubinfo = ubasetup(io, 1); |
| 96 | bn = io->i_bn; /* block number */ |
| 97 | cn = bn / 40; /* 40 512 byte blocks per cylinder */ |
| 98 | sn = (bn % 20) << 1; |
| 99 | head = (bn / 20) & 1; |
| 100 | st->rl_bleft = io->i_cc; /* total number of bytes to trans */ |
| 101 | ubaddr = ubinfo; |
| 102 | |
| 103 | stupid_rl: |
| 104 | /* find out how many cylinders to seek */ |
| 105 | diff = (st->rl_cylnhd >> 1) - cn; |
| 106 | if ( diff == 0 && (st->rl_cylnhd & 1) == head ) |
| 107 | goto noseek; |
| 108 | |
| 109 | /* first time or we switched drives */ |
| 110 | st->rl_dn = io->i_unit; /* drive number */ |
| 111 | |
| 112 | if ( diff < 0 ) |
| 113 | rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; |
| 114 | else |
| 115 | rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; |
| 116 | rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; |
| 117 | |
| 118 | /* reset position of drive */ |
| 119 | st->rl_cylnhd = (cn << 1) | head; |
| 120 | |
| 121 | noseek: |
| 122 | /* wait for controller and drive */ |
| 123 | while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) |
| 124 | continue; |
| 125 | |
| 126 | /* calculate the max number of bytes we can trans */ |
| 127 | st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); |
| 128 | if ( st->rl_bleft < st->rl_bpart ) |
| 129 | st->rl_bpart = st->rl_bleft; |
| 130 | |
| 131 | rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; |
| 132 | rladdr->rlmp.rw = -(st->rl_bpart >> 1); |
| 133 | rladdr->rlba = ubaddr; |
| 134 | |
| 135 | com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE); |
| 136 | |
| 137 | if (func == READ) |
| 138 | com |= RL_READ; |
| 139 | else |
| 140 | com |= RL_WRITE; |
| 141 | rladdr->rlcs = com; |
| 142 | |
| 143 | /* wait for controller and drive */ |
| 144 | while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) |
| 145 | continue; |
| 146 | |
| 147 | if (rladdr->rlcs & RL_ERR) { |
| 148 | int status; |
| 149 | |
| 150 | if ( rladdr->rlcs & RL_DE ) { |
| 151 | rladdr->rlda.getstat = RL_GSTAT; |
| 152 | rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; |
| 153 | rlwait(rladdr); |
| 154 | status = rladdr->rlmp.getstat; |
| 155 | rladdr->rlda.getstat = RL_RESET; |
| 156 | rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; |
| 157 | rlwait(rladdr); |
| 158 | } |
| 159 | printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", |
| 160 | cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, |
| 161 | status, RLER_BITS); |
| 162 | |
| 163 | /* Determine disk posistion */ |
| 164 | rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; |
| 165 | rlwait(rladdr); |
| 166 | |
| 167 | /* save disk drive posistion */ |
| 168 | st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; |
| 169 | |
| 170 | if (errcnt == 10) { |
| 171 | printf("rl: unrecovered error\n"); |
| 172 | return (-1); |
| 173 | } |
| 174 | errcnt++; |
| 175 | goto retry; |
| 176 | } |
| 177 | |
| 178 | /* do we have to finish off the rest of the transfer? */ |
| 179 | if ( (st->rl_bleft -= st->rl_bpart) > 0 ) { |
| 180 | /* increment head and/or cylinder */ |
| 181 | if ( ++head > 1 ) { |
| 182 | cn++; /* want next cyl, head 0 sector 0 */ |
| 183 | head = 0; |
| 184 | } |
| 185 | |
| 186 | /* we always want sector to be zero */ |
| 187 | sn = 0; |
| 188 | |
| 189 | /* |
| 190 | * standalone code for ubafree does what regular |
| 191 | * ubapurge does and we want to purge last transfer |
| 192 | */ |
| 193 | ubafree(io, ubinfo); |
| 194 | |
| 195 | ubaddr = ubinfo + io->i_cc - st->rl_bleft; |
| 196 | |
| 197 | goto stupid_rl; |
| 198 | } |
| 199 | |
| 200 | ubafree(io, ubinfo); |
| 201 | |
| 202 | if (errcnt) |
| 203 | printf("rl: recovered by retry\n"); |
| 204 | return (io->i_cc); |
| 205 | } |
| 206 | |
| 207 | rlwait(rladdr) |
| 208 | register struct rldevice *rladdr; |
| 209 | { |
| 210 | |
| 211 | while ((rladdr->rlcs & RL_CRDY) == 0) |
| 212 | continue; |
| 213 | } |
| 214 | |
| 215 | rlioctl(io, cmd, arg) |
| 216 | struct iob *io; |
| 217 | int cmd; |
| 218 | caddr_t arg; |
| 219 | { |
| 220 | |
| 221 | return (ECMD); |
| 222 | } |