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