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