1 /* hp.c 4.4 01/28/81 */ 2 3 #include "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 (HPDK_N + unit <= HPDK_NMAX) 168 dk_mspw[HPDK_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, ns; 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+HPDK_N <= HPDK_NMAX) 223 dk_busy &= ~(1<<(unit+HPDK_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 = DCLR|GO; 230 hpaddr->hpcs1 = PRESET|GO; 231 hpaddr->hpof = FMT22; 232 } 233 if(dp->b_active) 234 goto done; 235 dp->b_active++; 236 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 237 goto done; 238 239 #if NHP > 1 240 bn = dkblock(bp); 241 cn = bp->b_cylin; 242 switch (hp_type[unit]) { 243 244 case RM: 245 sn = bn%(NRMSECT*NRMTRAC); 246 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 247 ns = NRMSECT; 248 break; 249 case RM5: 250 sn = bn%(NRMSECT*NTRAC); 251 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 252 ns = NRMSECT; 253 break; 254 case RP: 255 sn = bn%(NSECT*NTRAC); 256 sn = (sn+NSECT-hpSDIST)%NSECT; 257 ns = NSECT; 258 break; 259 default: 260 panic("hpustart"); 261 } 262 263 if(cn - (hpaddr->hpdc & 0xffff)) 264 goto search; 265 else if (hpseek) 266 goto done; 267 csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 268 if(csn < 0) 269 csn += ns; 270 if(csn > ns-hpRDIST) 271 goto done; 272 273 search: 274 hpaddr->hpdc = cn; 275 if (hpseek) 276 hpaddr->hpcs1 = SEEK|GO; 277 else { 278 hpaddr->hpda = sn; 279 hpaddr->hpcs1 = SEARCH|GO; 280 } 281 unit += HPDK_N; 282 if (unit <= HPDK_NMAX) { 283 dk_busy |= 1<<unit; 284 dk_seek[unit]++; 285 } 286 return; 287 #endif 288 289 done: 290 dp->b_forw = NULL; 291 if(hptab.b_actf == NULL) 292 hptab.b_actf = dp; 293 else 294 hptab.b_actl->b_forw = dp; 295 hptab.b_actl = dp; 296 } 297 298 hpstart() 299 { 300 register struct buf *bp, *dp; 301 register unit; 302 register struct device *hpaddr; 303 daddr_t bn; 304 int dn, sn, tn, cn, nspc, ns; 305 306 loop: 307 if ((dp = hptab.b_actf) == NULL) 308 return; 309 if ((bp = dp->b_actf) == NULL) { 310 hptab.b_actf = dp->b_forw; 311 goto loop; 312 } 313 hptab.b_active++; 314 unit = minor(bp->b_dev) & 077; 315 dn = dkunit(bp); 316 bn = dkblock(bp); 317 switch (hp_type[dn]) { 318 case RM: 319 nspc = NRMSECT*NRMTRAC; 320 ns = NRMSECT; 321 cn = rm_sizes[unit&07].cyloff; 322 break; 323 case RM5: 324 nspc = NRMSECT*NTRAC; 325 ns = NRMSECT; 326 cn = rm5_sizes[unit&07].cyloff; 327 break; 328 case RP: 329 nspc = NSECT*NTRAC; 330 ns = NSECT; 331 cn = hp_sizes[unit&07].cyloff; 332 break; 333 default: 334 panic("hpstart"); 335 } 336 cn += bn/nspc; 337 sn = bn%nspc; 338 tn = sn/ns; 339 sn = sn%ns; 340 341 hpaddr = mbadev(HPMBA, dn); 342 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 343 hptab.b_active = 0; 344 hptab.b_errcnt = 0; 345 dp->b_actf = bp->av_forw; 346 bp->b_flags |= B_ERROR; 347 iodone(bp); 348 goto loop; 349 } 350 if(hptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 351 hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 352 HPMBA->mba_cr &= ~MBAIE; 353 hpaddr->hpcs1 = OFFSET|GO; 354 while(hpaddr->hpds & PIP) 355 ; 356 HPMBA->mba_cr |= MBAIE; 357 } 358 hpaddr->hpdc = cn; 359 hpaddr->hpda = (tn << 8) + sn; 360 mbastart(bp, (int *)hpaddr); 361 362 unit = dn+HPDK_N; 363 if (unit <= HPDK_NMAX) { 364 dk_busy |= 1<<unit; 365 dk_xfer[unit]++; 366 dk_wds[unit] += bp->b_bcount>>6; 367 } 368 } 369 370 hpintr(mbastat, as) 371 { 372 register struct buf *bp, *dp; 373 register unit; 374 register struct device *hpaddr; 375 376 if(hptab.b_active) { 377 dp = hptab.b_actf; 378 bp = dp->b_actf; 379 unit = dkunit(bp); 380 if (HPDK_N+unit <= HPDK_NMAX) 381 dk_busy &= ~(1<<(HPDK_N+unit)); 382 hpaddr = mbadev(HPMBA, unit); 383 if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 384 while((hpaddr->hpds & DRY) == 0) 385 ; 386 if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 387 bp->b_flags |= B_ERROR; 388 else 389 hptab.b_active = 0; 390 if(hptab.b_errcnt > 27) 391 deverror(bp, mbastat, hpaddr->hper1); 392 if ((hpaddr->hper1&0xffff) == DCK) { 393 if (hpecc(hpaddr, bp)) 394 return; 395 } 396 hpaddr->hpcs1 = DCLR|GO; 397 if((hptab.b_errcnt&07) == 4) { 398 HPMBA->mba_cr &= ~MBAIE; 399 hpaddr->hpcs1 = RECAL|GO; 400 while(hpaddr->hpds & PIP) 401 ; 402 HPMBA->mba_cr |= MBAIE; 403 } 404 } 405 if(hptab.b_active) { 406 if(hptab.b_errcnt) { 407 HPMBA->mba_cr &= ~MBAIE; 408 hpaddr->hpcs1 = RTC|GO; 409 while(hpaddr->hpds & PIP) 410 ; 411 HPMBA->mba_cr |= MBAIE; 412 } 413 hptab.b_active = 0; 414 hptab.b_errcnt = 0; 415 hptab.b_actf = dp->b_forw; 416 dp->b_active = 0; 417 dp->b_errcnt = 0; 418 dp->b_actf = bp->av_forw; 419 bp->b_resid = -HPMBA->mba_bcr & 0xffff; 420 iodone(bp); 421 if(dp->b_actf) 422 hpustart(unit); 423 } 424 as &= ~(1<<unit); 425 } else { 426 if(as == 0) 427 HPMBA->mba_cr |= MBAIE; 428 } 429 for(unit=0; unit<NHP; unit++) 430 if(as & (1<<unit)) 431 hpustart(unit); 432 hpstart(); 433 } 434 435 hpread(dev) 436 { 437 438 physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 439 } 440 441 hpwrite(dev) 442 { 443 444 physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 445 } 446 447 hpecc(rp, bp) 448 register struct device *rp; 449 register struct buf *bp; 450 { 451 struct mba_regs *mbp = HPMBA; 452 register int i; 453 caddr_t addr; 454 int reg, bit, byte, npf, mask, o; 455 int dn, bn, cn, tn, sn, ns, nt; 456 extern char buffers[NBUF][BSIZE]; 457 struct pte mpte; 458 int bcr; 459 460 /* 461 * Npf is the number of sectors transferred before the sector 462 * containing the ECC error, and reg is the MBA register 463 * mapping (the first part of)the transfer. 464 * O is offset within a memory page of the first byte transferred. 465 */ 466 bcr = mbp->mba_bcr & 0xffff; 467 if (bcr) 468 bcr |= 0xffff0000; /* sxt */ 469 npf = btop(bcr + bp->b_bcount) - 1; 470 reg = npf; 471 o = (int)bp->b_un.b_addr & PGOFSET; 472 printf("%D ", bp->b_blkno + npf); 473 prdev("ECC", bp->b_dev); 474 mask = rp->hpec2&0xffff; 475 if (mask == 0) { 476 rp->hpof = FMT22; 477 return (0); 478 } 479 480 /* 481 * Compute the byte and bit position of the error. 482 * The variable i is the byte offset in the transfer, 483 * the variable byte is the offset from a page boundary 484 * in main memory. 485 */ 486 i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 487 bit = i&07; 488 i = (i&~07)>>3; 489 byte = i + o; 490 /* 491 * Correct while possible bits remain of mask. Since mask 492 * contains 11 bits, we continue while the bit offset is > -11. 493 * Also watch out for end of this block and the end of the whole 494 * transfer. 495 */ 496 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 497 mpte = mbp->mba_map[reg+btop(byte)]; 498 addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 499 putmemc(addr, getmemc(addr)^(mask<<bit)); 500 byte++; 501 i++; 502 bit -= 8; 503 } 504 hptab.b_active++; /* Either complete or continuing */ 505 if (bcr == 0) 506 return (0); 507 /* 508 * Have to continue the transfer... clear the drive, 509 * and compute the position where the transfer is to continue. 510 * We have completed npf+1 sectores of the transfer already; 511 * restart at offset o of next sector (i.e. in MBA register reg+1). 512 */ 513 rp->hpcs1 = DCLR|GO; 514 dn = dkunit(bp); 515 bn = dkblock(bp); 516 switch (hp_type[dn]) { 517 518 case RM: 519 ns = NRMSECT; nt = NRMTRAC; break; 520 case RM5: 521 ns = NRMSECT; nt = NTRAC; break; 522 case RP: 523 ns = NSECT; nt = NTRAC; break; 524 default: 525 panic("hpecc"); 526 } 527 cn = bp->b_cylin; 528 sn = bn%(ns*nt) + npf + 1; 529 tn = sn/ns; 530 sn %= ns; 531 cn += tn/nt; 532 tn %= nt; 533 rp->hpdc = cn; 534 rp->hpda = (tn<<8) + sn; 535 mbp->mba_sr = -1; 536 mbp->mba_var = (int)ptob(reg+1) + o; 537 rp->hpcs1 = RCOM|GO; 538 return (1); 539 } 540 #endif 541