1 /* hp.c 3.9 07/29/80 */ 2 3 /* 4 * RP06/RM03 disk driver 5 */ 6 7 #include "../h/param.h" 8 #include "../h/systm.h" 9 #include "../h/dk.h" 10 #include "../h/buf.h" 11 #include "../h/conf.h" 12 #include "../h/dir.h" 13 #include "../h/user.h" 14 #include "../h/map.h" 15 #include "../h/pte.h" 16 #include "../h/mba.h" 17 #include "../h/mtpr.h" 18 #include "../h/vm.h" 19 20 #define DK_N 0 21 #define DK_NMAX 1 22 23 struct device 24 { 25 int hpcs1; /* control and Status register 1 */ 26 int hpds; /* Drive Status */ 27 int hper1; /* Error register 1 */ 28 int hpmr; /* Maintenance */ 29 int hpas; /* Attention Summary */ 30 int hpda; /* Desired address register */ 31 int hpdt; /* Drive type */ 32 int hpla; /* Look ahead */ 33 int hpsn; /* serial number */ 34 int hpof; /* Offset register */ 35 int hpdc; /* Desired Cylinder address register */ 36 int hpcc; /* Current Cylinder */ 37 int hper2; /* Error register 2 */ 38 int hper3; /* Error register 3 */ 39 int hpec1; /* Burst error bit position */ 40 int hpec2; /* Burst error bit pattern */ 41 }; 42 43 #define HPMBA MBA0 44 #define HPMBANUM 0 45 46 #define NHP 2 47 #define RP 022 48 #define RM 024 49 #define NSECT 22 50 #define NTRAC 19 51 #define NRMSECT 32 52 #define NRMTRAC 5 53 54 #define _hpSDIST 3 55 #define _hpRDIST 6 56 57 int hpSDIST = _hpSDIST; 58 int hpRDIST = _hpRDIST; 59 int hpseek; 60 61 struct size 62 { 63 daddr_t nblocks; 64 int cyloff; 65 } hp_sizes[8] = 66 { 67 15884, 0, /* cyl 0 thru 37 */ 68 33440, 38, /* cyl 38 thru 117 */ 69 8360, 98, /* cyl 98 thru 117 */ 70 #ifdef ERNIE 71 15884, 118, /* cyl 118 thru 155 */ 72 66880, 156, /* cyl 156 thru 315 */ 73 0, 0, 74 291346, 118, /* cyl 118 thru 814, (like distrib) */ 75 208582, 316, /* cyl 316 thru 814 */ 76 #else 77 0, 0, 78 0, 0, 79 0, 0, 80 291346, 118, /* cyl 118 thru 814 */ 81 0, 0, 82 #endif 83 }, rm_sizes[8] = { 84 15884, 0, /* cyl 0 thru 99 */ 85 33440, 100, /* cyl 100 thru 309 */ 86 0, 0, 87 0, 0, 88 0, 0, 89 0, 0, 90 82080, 310, /* cyl 310 thru 822 */ 91 0, 0, 92 }; 93 94 #define P400 020 95 #define M400 0220 96 #define P800 040 97 #define M800 0240 98 #define P1200 060 99 #define M1200 0260 100 int hp_offset[16] = 101 { 102 P400, M400, P400, M400, 103 P800, M800, P800, M800, 104 P1200, M1200, P1200, M1200, 105 0, 0, 0, 0, 106 }; 107 108 struct buf hptab; 109 struct buf rhpbuf; 110 struct buf hputab[NHP]; 111 char hp_type[NHP]; /* drive type */ 112 113 #define GO 01 114 #define PRESET 020 115 #define RTC 016 116 #define OFFSET 014 117 #define SEEK 04 118 #define SEARCH 030 119 #define RECAL 06 120 #define DCLR 010 121 #define WCOM 060 122 #define RCOM 070 123 124 #define IE 0100 125 #define PIP 020000 126 #define DRY 0200 127 #define ERR 040000 128 #define TRE 040000 129 #define DCK 0100000 130 #define WLE 04000 131 #define ECH 0100 132 #define VV 0100 133 #define DPR 0400 134 #define MOL 010000 135 #define FMT22 010000 136 137 #define b_cylin b_resid 138 139 #ifdef INTRLVE 140 daddr_t dkblock(); 141 #endif 142 143 hpstrategy(bp) 144 register struct buf *bp; 145 { 146 register struct buf *dp; 147 register unit, xunit, nspc; 148 long sz, bn; 149 struct size *sizes; 150 151 if ((mbaact&(1<<HPMBANUM)) == 0) 152 mbainit(HPMBANUM); 153 xunit = minor(bp->b_dev) & 077; 154 sz = bp->b_bcount; 155 sz = (sz+511) >> 9; 156 unit = dkunit(bp); 157 if (hp_type[unit] == 0) { 158 struct device *hpaddr; 159 160 /* determine device type */ 161 hpaddr = mbadev(HPMBA, unit); 162 hp_type[unit] = hpaddr->hpdt; 163 } 164 if (hp_type[unit] == RM) { 165 sizes = rm_sizes; 166 nspc = NRMSECT*NRMTRAC; 167 } else { 168 sizes = hp_sizes; 169 nspc = NSECT*NTRAC; 170 } 171 if (unit >= NHP || 172 bp->b_blkno < 0 || 173 (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 174 bp->b_flags |= B_ERROR; 175 iodone(bp); 176 return; 177 } 178 bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 179 dp = &hputab[unit]; 180 (void) spl5(); 181 disksort(dp, bp); 182 if (dp->b_active == 0) { 183 hpustart(unit); 184 if(hptab.b_active == 0) 185 hpstart(); 186 } 187 (void) spl0(); 188 } 189 190 hpustart(unit) 191 register unit; 192 { 193 register struct buf *bp, *dp; 194 register struct device *hpaddr; 195 daddr_t bn; 196 int sn, cn, csn; 197 198 ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; 199 hpaddr = mbadev(HPMBA, 0); 200 hpaddr->hpas = 1<<unit; 201 202 if(unit >= NHP) 203 return; 204 if (unit+DK_N <= DK_NMAX) 205 dk_busy &= ~(1<<(unit+DK_N)); 206 dp = &hputab[unit]; 207 if((bp=dp->b_actf) == NULL) 208 return; 209 hpaddr = mbadev(HPMBA, unit); 210 if((hpaddr->hpds & VV) == 0) { 211 hpaddr->hpcs1 = PRESET|GO; 212 hpaddr->hpof = FMT22; 213 } 214 if(dp->b_active) 215 goto done; 216 dp->b_active++; 217 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 218 goto done; 219 220 bn = dkblock(bp); 221 cn = bp->b_cylin; 222 if(hp_type[unit] == RM) { 223 sn = bn%(NRMSECT*NRMTRAC); 224 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 225 } else { 226 sn = bn%(NSECT*NTRAC); 227 sn = (sn+NSECT-hpSDIST)%NSECT; 228 } 229 230 if(cn - (hpaddr->hpdc & 0xffff)) 231 goto search; 232 else if (hpseek) 233 goto done; 234 csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 235 if(csn < 0) 236 csn += NSECT; 237 if(csn > NSECT-hpRDIST) 238 goto done; 239 240 search: 241 hpaddr->hpdc = cn; 242 if (hpseek) 243 hpaddr->hpcs1 = SEEK|GO; 244 else { 245 hpaddr->hpda = sn; 246 hpaddr->hpcs1 = SEARCH|GO; 247 } 248 unit += DK_N; 249 if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) { 250 dk_busy |= 1<<unit; 251 dk_numb[unit]++; 252 } 253 return; 254 255 done: 256 dp->b_forw = NULL; 257 if(hptab.b_actf == NULL) 258 hptab.b_actf = dp; 259 else 260 hptab.b_actl->b_forw = dp; 261 hptab.b_actl = dp; 262 } 263 264 hpstart() 265 { 266 register struct buf *bp, *dp; 267 register unit; 268 register struct device *hpaddr; 269 daddr_t bn; 270 int dn, sn, tn, cn, nspc, ns; 271 272 loop: 273 if ((dp = hptab.b_actf) == NULL) 274 return; 275 if ((bp = dp->b_actf) == NULL) { 276 hptab.b_actf = dp->b_forw; 277 goto loop; 278 } 279 hptab.b_active++; 280 unit = minor(bp->b_dev) & 077; 281 dn = dkunit(bp); 282 bn = dkblock(bp); 283 if (hp_type[dn] == RM) { 284 nspc = NRMSECT*NRMTRAC; 285 ns = NRMSECT; 286 cn = rm_sizes[unit&07].cyloff; 287 } else { 288 nspc = NSECT*NTRAC; 289 ns = NSECT; 290 cn = hp_sizes[unit&07].cyloff; 291 } 292 cn += bn/nspc; 293 sn = bn%nspc; 294 tn = sn/ns; 295 sn = sn%ns; 296 297 hpaddr = mbadev(HPMBA, dn); 298 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 299 hptab.b_active = 0; 300 hptab.b_errcnt = 0; 301 dp->b_actf = bp->av_forw; 302 bp->b_flags |= B_ERROR; 303 iodone(bp); 304 goto loop; 305 } 306 if(hptab.b_errcnt >= 16) { 307 hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 308 HPMBA->mba_cr &= ~MBAIE; 309 hpaddr->hpcs1 = OFFSET|GO; 310 while(hpaddr->hpds & PIP) 311 ; 312 HPMBA->mba_cr |= MBAIE; 313 } 314 hpaddr->hpdc = cn; 315 hpaddr->hpda = (tn << 8) + sn; 316 mbastart(bp, (int *)hpaddr); 317 318 unit = dn+DK_N; 319 if (NHP+DK_N == DK_NMAX) 320 unit = NHP+DK_N; 321 if (unit <= DK_NMAX) { 322 dk_busy |= 1<<unit; 323 dk_numb[unit]++; 324 dk_wds[unit] += bp->b_bcount>>6; 325 } 326 } 327 328 hpintr(mbastat, as) 329 { 330 register struct buf *bp, *dp; 331 register unit; 332 register struct device *hpaddr; 333 334 if(hptab.b_active) { 335 dp = hptab.b_actf; 336 bp = dp->b_actf; 337 unit = dkunit(bp); 338 if (DK_N+NHP == DK_NMAX) 339 dk_busy &= ~(1<<(DK_N+NHP)); 340 else if (DK_N+unit <= DK_NMAX) 341 dk_busy &= ~(1<<(DK_N+unit)); 342 hpaddr = mbadev(HPMBA, unit); 343 if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 344 while((hpaddr->hpds & DRY) == 0) 345 ; 346 if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 347 bp->b_flags |= B_ERROR; 348 else 349 hptab.b_active = 0; 350 if(hptab.b_errcnt > 27) 351 deverror(bp, mbastat, hpaddr->hper1); 352 if ((hpaddr->hper1&0xffff) == DCK) { 353 if (hpecc(hpaddr, bp)) 354 return; 355 } 356 hpaddr->hpcs1 = DCLR|GO; 357 if((hptab.b_errcnt&07) == 4) { 358 HPMBA->mba_cr &= ~MBAIE; 359 hpaddr->hpcs1 = RECAL|GO; 360 while(hpaddr->hpds & PIP) 361 ; 362 HPMBA->mba_cr |= MBAIE; 363 } 364 } 365 if(hptab.b_active) { 366 if(hptab.b_errcnt) { 367 HPMBA->mba_cr &= ~MBAIE; 368 hpaddr->hpcs1 = RTC|GO; 369 while(hpaddr->hpds & PIP) 370 ; 371 HPMBA->mba_cr |= MBAIE; 372 } 373 hptab.b_active = 0; 374 hptab.b_errcnt = 0; 375 hptab.b_actf = dp->b_forw; 376 dp->b_active = 0; 377 dp->b_errcnt = 0; 378 dp->b_actf = bp->av_forw; 379 bp->b_resid = -HPMBA->mba_bcr & 0xffff; 380 iodone(bp); 381 if(dp->b_actf) 382 hpustart(unit); 383 } 384 as &= ~(1<<unit); 385 } else { 386 if(as == 0) 387 HPMBA->mba_cr |= MBAIE; 388 } 389 for(unit=0; unit<NHP; unit++) 390 if(as & (1<<unit)) 391 hpustart(unit); 392 hpstart(); 393 } 394 395 hpread(dev) 396 { 397 398 physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 399 } 400 401 hpwrite(dev) 402 { 403 404 physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 405 } 406 407 hpecc(rp, bp) 408 register struct device *rp; 409 register struct buf *bp; 410 { 411 struct mba_regs *mbp = HPMBA; 412 register int i; 413 caddr_t addr; 414 int reg, bit, byte, npf, mask, o; 415 int dn, bn, cn, tn, sn, ns, nt; 416 extern char buffers[NBUF][BSIZE]; 417 struct pte mpte; 418 419 /* 420 * Npf is the number of sectors transferred before the sector 421 * containing the ECC error, and reg is the MBA register 422 * mapping (the first part of)the transfer. 423 * O is offset within a memory page of the first byte transferred. 424 */ 425 npf = btop((mbp->mba_bcr&0xffff) + bp->b_bcount) - 1; 426 if (bp->b_flags&B_PHYS) 427 reg = 128 + npf; 428 else 429 reg = btop(bp->b_un.b_addr - buffers[0]) + npf; 430 o = (int)bp->b_un.b_addr & PGOFSET; 431 printf("%D ", bp->b_blkno + npf); 432 prdev("ECC", bp->b_dev); 433 mask = rp->hpec2&0xffff; 434 if (mask == 0) { 435 rp->hpof = FMT22; 436 return (0); 437 } 438 439 /* 440 * Compute the byte and bit position of the error. 441 * The variable i is the byte offset in the transfer, 442 * the variable byte is the offset from a page boundary 443 * in main memory. 444 */ 445 i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 446 bit = i&017; 447 i = (i&~07)>>3; 448 byte = i + o; 449 /* 450 * Correct while possible bits remain of mask. Since mask 451 * contains 11 bits, we continue while the bit offset is > -11. 452 * Also watch out for end of this block and the end of the whole 453 * transfer. 454 */ 455 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 456 mpte = mbp->mba_map[reg+btop(byte)]; 457 addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 458 putmemc(addr, getmemc(addr)^(mask<<bit)); 459 byte++; 460 i++; 461 bit -= 8; 462 } 463 hptab.b_active++; /* Either complete or continuing */ 464 if (mbp->mba_bcr == 0) 465 return (0); 466 /* 467 * Have to continue the transfer... clear the drive, 468 * and compute the position where the transfer is to continue. 469 * We have completed npf+1 sectores of the transfer already; 470 * restart at offset o of next sector (i.e. in MBA register reg+1). 471 */ 472 rp->hpcs1 = DCLR|GO; 473 dn = dkunit(bp); 474 bn = dkblock(bp); 475 if (hp_type[dn] == RM) { 476 ns = NRMSECT; 477 nt = NRMTRAC; 478 } else { 479 ns = NSECT; 480 nt = NTRAC; 481 } 482 cn = bp->b_cylin; 483 sn = bn%(ns*nt) + npf + 1; 484 tn = sn/ns; 485 sn %= ns; 486 cn += tn/nt; 487 tn %= nt; 488 rp->hpdc = cn; 489 rp->hpda = (tn<<8) + sn; 490 mbp->mba_sr = -1; 491 mbp->mba_var = (int)ptob(reg+1) + o; 492 rp->hpcs1 = RCOM|GO; 493 return (1); 494 } 495