1 /* 2 * Copyright (c) 1982, 1986 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 * @(#)idc.c 7.3 (Berkeley) 05/06/88 7 */ 8 9 #include "rb.h" 10 #if NIDC > 0 11 int idcdebug = 0; 12 #define printd if(idcdebug)printf 13 int idctrb[1000]; 14 int *trp = idctrb; 15 #define trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;} 16 /* 17 * IDC (RB730) disk driver 18 * 19 * There can only ever be one IDC on a machine, 20 * and only on a VAX-11/730. We take advantage 21 * of that to simplify the driver. 22 * 23 * TODO: 24 * ecc 25 */ 26 #include "../machine/pte.h" 27 28 #include "param.h" 29 #include "systm.h" 30 #include "buf.h" 31 #include "conf.h" 32 #include "dir.h" 33 #include "user.h" 34 #include "map.h" 35 #include "vm.h" 36 #include "dkstat.h" 37 #include "cmap.h" 38 #include "dkbad.h" 39 #include "uio.h" 40 #include "kernel.h" 41 #include "syslog.h" 42 43 #include "../vax/cpu.h" 44 #include "ubareg.h" 45 #include "ubavar.h" 46 #include "idcreg.h" 47 48 struct idc_softc { 49 int sc_bcnt; /* number of bytes to transfer */ 50 int sc_resid; /* total number of bytes to transfer */ 51 int sc_ubaddr; /* Unibus address of data */ 52 short sc_unit; /* unit doing transfer */ 53 short sc_softas; /* software attention summary bits */ 54 union idc_dar { 55 long dar_l; 56 u_short dar_w[2]; 57 u_char dar_b[4]; 58 } sc_un; /* prototype disk address register */ 59 } idc_softc; 60 61 #define dar_dar dar_l /* the whole disk address */ 62 #define dar_cyl dar_w[1] /* cylinder address */ 63 #define dar_trk dar_b[1] /* track */ 64 #define dar_sect dar_b[0] /* sector */ 65 #define sc_dar sc_un.dar_dar 66 #define sc_cyl sc_un.dar_cyl 67 #define sc_trk sc_un.dar_trk 68 #define sc_sect sc_un.dar_sect 69 70 #define idcunit(dev) (minor(dev) >> 3) 71 72 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 73 struct size { 74 daddr_t nblocks; 75 int cyloff; 76 } rb02_sizes[8] ={ 77 15884, 0, /* A=cyl 0 thru 399 */ 78 4480, 400, /* B=cyl 400 thru 510 */ 79 20480, 0, /* C=cyl 0 thru 511 */ 80 0, 0, 81 0, 0, 82 0, 0, 83 0, 0, 84 0, 0, 85 }, rb80_sizes[8] ={ 86 15884, 0, /* A=cyl 0 thru 36 */ 87 33440, 37, /* B=cyl 37 thru 114 */ 88 242606, 0, /* C=cyl 0 thru 558 */ 89 0, 0, 90 0, 0, 91 0, 0, 92 82080, 115, /* G=cyl 115 thru 304 */ 93 110143, 305, /* H=cyl 305 thru 558 */ 94 }; 95 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 96 97 int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); 98 struct uba_ctlr *idcminfo[NIDC]; 99 struct uba_device *idcdinfo[NRB]; 100 101 u_short idcstd[] = { 0174400, 0}; 102 struct uba_driver idcdriver = 103 { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; 104 struct buf idcutab[NRB]; 105 union idc_dar idccyl[NRB]; 106 107 struct idcst { 108 short nbps; 109 short nsect; 110 short ntrak; 111 short nspc; 112 short ncyl; 113 struct size *sizes; 114 } idcst[] = { 115 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, 116 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, 117 }; 118 119 #define b_cylin b_resid 120 121 int idcwstart, idcwticks, idcwatch(); 122 123 /*ARGSUSED*/ 124 idcprobe(reg) 125 caddr_t reg; 126 { 127 register int br, cvec; 128 register struct idcdevice *idcaddr; 129 130 #ifdef lint 131 br = 0; cvec = br; br = cvec; 132 #endif 133 idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 134 idcaddr->idccsr = IDC_ATTN|IDC_IE; 135 while ((idcaddr->idccsr & IDC_CRDY) == 0) 136 ; 137 idcaddr->idccsr = IDC_ATTN|IDC_CRDY; 138 return (sizeof (struct idcdevice)); 139 } 140 141 /*ARGSUSED*/ 142 idcslave(ui, reg) 143 struct uba_device *ui; 144 caddr_t reg; 145 { 146 register struct idcdevice *idcaddr; 147 register int i; 148 149 idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 150 ui->ui_type = 0; 151 idcaddr->idcmpr = IDCGS_GETSTAT; 152 idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); 153 (void) idcwait(idcaddr, 0); 154 i = idcaddr->idcmpr; 155 idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); 156 (void) idcwait(idcaddr, 0); 157 /* read header to synchronize microcode */ 158 idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; 159 (void) idcwait(idcaddr, 0); 160 i = idcaddr->idcmpr; /* read header word 1 */ 161 i = idcaddr->idcmpr; /* read header word 2 */ 162 #ifdef lint 163 i = i; 164 #endif 165 if ((idcaddr->idccsr & (IDC_ERR|IDC_R80)) == IDC_R80) 166 ui->ui_type = 1; 167 else if ((idcaddr->idccsr & (IDC_DE|IDC_R80)) == 0) 168 /* 169 * RB02 may not have pack spun up, just look for drive error. 170 */ 171 ui->ui_type = 0; 172 else 173 return (0); 174 return (1); 175 } 176 177 idcattach(ui) 178 register struct uba_device *ui; 179 { 180 181 /* 182 * Fix all addresses to correspond 183 * to the "real" IDC address. 184 */ 185 ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; 186 ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; 187 if (idcwstart == 0) { 188 timeout(idcwatch, (caddr_t)0, hz); 189 idcwstart++; 190 } 191 if (ui->ui_dk >= 0) 192 if (ui->ui_type) 193 dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256); 194 else 195 dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128); 196 idccyl[ui->ui_unit].dar_dar = -1; 197 ui->ui_flags = 0; 198 } 199 200 idcopen(dev) 201 dev_t dev; 202 { 203 register int unit = idcunit(dev); 204 register struct uba_device *ui; 205 206 if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 207 return (ENXIO); 208 return (0); 209 } 210 211 idcstrategy(bp) 212 register struct buf *bp; 213 { 214 register struct uba_device *ui; 215 register struct idcst *st; 216 register int unit; 217 register struct buf *dp; 218 int xunit = minor(bp->b_dev) & 07; 219 long bn, sz; 220 221 sz = (bp->b_bcount+511) >> 9; 222 unit = idcunit(bp->b_dev); 223 if (unit >= NRB) { 224 bp->b_error = ENXIO; 225 goto bad; 226 } 227 ui = idcdinfo[unit]; 228 if (ui == 0 || ui->ui_alive == 0) { 229 bp->b_error = ENXIO; 230 goto bad; 231 } 232 st = &idcst[ui->ui_type]; 233 if (bp->b_blkno < 0 || 234 (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { 235 if (bp->b_blkno == st->sizes[xunit].nblocks) { 236 bp->b_resid = bp->b_bcount; 237 goto done; 238 } 239 bp->b_error = EINVAL; 240 goto bad; 241 } 242 if (ui->ui_type == 0) 243 bn *= 2; 244 bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 245 (void) spl5(); 246 trace("strt",bp); 247 dp = &idcutab[ui->ui_unit]; 248 disksort(dp, bp); 249 if (dp->b_active == 0) { 250 trace("!act",dp); 251 (void) idcustart(ui); 252 bp = &ui->ui_mi->um_tab; 253 if (bp->b_actf && bp->b_active == 0) 254 (void) idcstart(ui->ui_mi); 255 } 256 (void) spl0(); 257 return; 258 259 bad: 260 bp->b_flags |= B_ERROR; 261 done: 262 iodone(bp); 263 return; 264 } 265 266 idcustart(ui) 267 register struct uba_device *ui; 268 { 269 register struct buf *bp, *dp; 270 register struct uba_ctlr *um; 271 register struct idcdevice *idcaddr; 272 register struct idcst *st; 273 union idc_dar cyltrk; 274 daddr_t bn; 275 int unit; 276 277 if (ui == 0) 278 return (0); 279 dk_busy &= ~(1<<ui->ui_dk); 280 dp = &idcutab[ui->ui_unit]; 281 um = ui->ui_mi; 282 unit = ui->ui_slave; 283 trace("ust", dp); 284 idcaddr = (struct idcdevice *)um->um_addr; 285 if (um->um_tab.b_active) { 286 idc_softc.sc_softas |= 1<<unit; 287 trace("umac",idc_softc.sc_softas); 288 return (0); 289 } 290 if ((bp = dp->b_actf) == NULL) { 291 trace("!bp",0); 292 return (0); 293 } 294 if (dp->b_active) { 295 trace("dpac",dp->b_active); 296 goto done; 297 } 298 dp->b_active = 1; 299 /* CHECK DRIVE READY? */ 300 bn = bp->b_blkno; 301 trace("seek", bn); 302 if (ui->ui_type == 0) 303 bn *= 2; 304 st = &idcst[ui->ui_type]; 305 cyltrk.dar_cyl = bp->b_cylin; 306 cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; 307 cyltrk.dar_sect = 0; 308 printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); 309 /* 310 * If on cylinder, no need to seek. 311 */ 312 if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) 313 goto done; 314 /* 315 * RB80 can change heads (tracks) just by loading 316 * the disk address register, perform optimization 317 * here instead of doing a full seek. 318 */ 319 if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { 320 idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); 321 idcaddr->idcdar = cyltrk.dar_dar; 322 idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 323 goto done; 324 } 325 /* 326 * Need to do a full seek. Select the unit, clear 327 * its attention bit, set the command, load the 328 * disk address register, and then go. 329 */ 330 idcaddr->idccsr = 331 IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 332 idcaddr->idcdar = cyltrk.dar_dar; 333 idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 334 printd(" seek"); 335 idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); 336 if (ui->ui_dk >= 0) { 337 dk_busy |= 1<<ui->ui_dk; 338 dk_seek[ui->ui_dk]++; 339 } 340 /* 341 * RB80's initiate seeks very quickly. Wait for it 342 * to come ready rather than taking the interrupt. 343 */ 344 if (ui->ui_type) { 345 if (idcwait(idcaddr, 10) == 0) 346 return (1); 347 idcaddr->idccsr &= ~IDC_ATTN; 348 /* has the seek completed? */ 349 if (idcaddr->idccsr & IDC_DRDY) { 350 printd(", drdy"); 351 idcaddr->idccsr = 352 IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 353 goto done; 354 } 355 } 356 printd(", idccsr = 0x%x\n", idcaddr->idccsr); 357 return (1); 358 done: 359 if (dp->b_active != 2) { 360 trace("!=2",dp->b_active); 361 dp->b_forw = NULL; 362 if (um->um_tab.b_actf == NULL) 363 um->um_tab.b_actf = dp; 364 else { 365 trace("!NUL",um->um_tab.b_actl); 366 um->um_tab.b_actl->b_forw = dp; 367 } 368 um->um_tab.b_actl = dp; 369 dp->b_active = 2; 370 } 371 return (0); 372 } 373 374 idcstart(um) 375 register struct uba_ctlr *um; 376 { 377 register struct buf *bp, *dp; 378 register struct uba_device *ui; 379 register struct idcdevice *idcaddr; 380 register struct idc_softc *sc; 381 struct idcst *st; 382 daddr_t bn; 383 int sn, tn, cmd; 384 385 loop: 386 if ((dp = um->um_tab.b_actf) == NULL) { 387 trace("nodp",um); 388 return (0); 389 } 390 if ((bp = dp->b_actf) == NULL) { 391 trace("nobp", dp); 392 um->um_tab.b_actf = dp->b_forw; 393 goto loop; 394 } 395 um->um_tab.b_active = 1; 396 ui = idcdinfo[idcunit(bp->b_dev)]; 397 bn = bp->b_blkno; 398 trace("star",bp); 399 if (ui->ui_type == 0) 400 bn *= 2; 401 sc = &idc_softc; 402 st = &idcst[ui->ui_type]; 403 sn = bn%st->nspc; 404 tn = sn/st->nsect; 405 sn %= st->nsect; 406 sc->sc_sect = sn; 407 sc->sc_trk = tn; 408 sc->sc_cyl = bp->b_cylin; 409 idcaddr = (struct idcdevice *)ui->ui_addr; 410 printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); 411 if (bp->b_flags & B_READ) 412 cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); 413 else 414 cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); 415 idcaddr->idccsr = IDC_CRDY|cmd; 416 if ((idcaddr->idccsr&IDC_DRDY) == 0) { 417 printf("rb%d: not ready\n", idcunit(bp->b_dev)); 418 um->um_tab.b_active = 0; 419 um->um_tab.b_errcnt = 0; 420 dp->b_actf = bp->av_forw; 421 dp->b_active = 0; 422 bp->b_flags |= B_ERROR; 423 iodone(bp); 424 goto loop; 425 } 426 idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 427 idccyl[ui->ui_unit].dar_sect = 0; 428 sn = (st->nsect - sn) * st->nbps; 429 if (sn > bp->b_bcount) 430 sn = bp->b_bcount; 431 sc->sc_bcnt = sn; 432 sc->sc_resid = bp->b_bcount; 433 sc->sc_unit = ui->ui_slave; 434 printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); 435 um->um_cmd = cmd; 436 (void) ubago(ui); 437 return (1); 438 } 439 440 idcdgo(um) 441 register struct uba_ctlr *um; 442 { 443 register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 444 register struct idc_softc *sc = &idc_softc; 445 446 /* 447 * VERY IMPORTANT: must load registers in this order. 448 */ 449 idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff; 450 idcaddr->idcbcr = -sc->sc_bcnt; 451 idcaddr->idcdar = sc->sc_dar; 452 printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); 453 idcaddr->idccsr = um->um_cmd; 454 trace("go", um); 455 um->um_tab.b_active = 2; 456 /*** CLEAR SPURIOUS ATTN ON R80? ***/ 457 } 458 459 idcintr(idc) 460 int idc; 461 { 462 register struct uba_ctlr *um = idcminfo[idc]; 463 register struct uba_device *ui; 464 register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 465 register struct idc_softc *sc = &idc_softc; 466 register struct buf *bp, *dp; 467 struct idcst *st; 468 int unit, as, er, cmd, ds = 0; 469 470 printd("idcintr, idccsr 0x%x", idcaddr->idccsr); 471 top: 472 idcwticks = 0; 473 trace("intr", um->um_tab.b_active); 474 if (um->um_tab.b_active == 2) { 475 /* 476 * Process a data transfer complete interrupt. 477 */ 478 um->um_tab.b_active = 1; 479 dp = um->um_tab.b_actf; 480 bp = dp->b_actf; 481 ui = idcdinfo[idcunit(bp->b_dev)]; 482 unit = ui->ui_slave; 483 st = &idcst[ui->ui_type]; 484 idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 485 if ((er = idcaddr->idccsr) & IDC_ERR) { 486 if (er & IDC_DE) { 487 idcaddr->idcmpr = IDCGS_GETSTAT; 488 idcaddr->idccsr = IDC_GETSTAT|(unit<<8); 489 (void) idcwait(idcaddr, 0); 490 ds = idcaddr->idcmpr; 491 idcaddr->idccsr = 492 IDC_IE|IDC_CRDY|(1<<(unit+16)); 493 } 494 printd(", er 0x%x, ds 0x%x", er, ds); 495 if (ds & IDCDS_WL) { 496 printf("rb%d: write locked\n", 497 idcunit(bp->b_dev)); 498 bp->b_flags |= B_ERROR; 499 } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { 500 hard: 501 harderr(bp, "rb"); 502 printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds, 503 ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); 504 bp->b_flags |= B_ERROR; 505 } else if (er & IDC_DCK) { 506 switch ((int)(er & IDC_ECS)) { 507 case IDC_ECS_NONE: 508 break; 509 case IDC_ECS_SOFT: 510 idcecc(ui); 511 break; 512 case IDC_ECS_HARD: 513 default: 514 goto hard; 515 } 516 } else 517 /* recoverable error, set up for retry */ 518 goto seek; 519 } 520 if ((sc->sc_resid -= sc->sc_bcnt) != 0) { 521 sc->sc_ubaddr += sc->sc_bcnt; 522 /* 523 * Current transfer is complete, have 524 * we overflowed to the next track? 525 */ 526 if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { 527 sc->sc_sect = 0; 528 if (++sc->sc_trk == st->ntrak) { 529 sc->sc_trk = 0; 530 sc->sc_cyl++; 531 } else if (ui->ui_type) { 532 /* 533 * RB80 can change heads just by 534 * loading the disk address register. 535 */ 536 idcaddr->idccsr = IDC_SEEK|IDC_CRDY| 537 IDC_IE|(unit<<8); 538 printd(", change to track 0x%x", sc->sc_dar); 539 idcaddr->idcdar = sc->sc_dar; 540 idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 541 idccyl[ui->ui_unit].dar_sect = 0; 542 goto cont; 543 } 544 /* 545 * Changing tracks on RB02 or cylinders 546 * on RB80, start a seek. 547 */ 548 seek: 549 cmd = IDC_IE|IDC_SEEK|(unit<<8); 550 idcaddr->idccsr = cmd|IDC_CRDY; 551 idcaddr->idcdar = sc->sc_dar; 552 printd(", seek to 0x%x\n", sc->sc_dar); 553 idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 554 idccyl[ui->ui_unit].dar_sect = 0; 555 sc->sc_bcnt = 0; 556 idcaddr->idccsr = cmd; 557 if (ui->ui_type) { 558 if (idcwait(idcaddr, 10) == 0) 559 return; 560 idcaddr->idccsr &= ~IDC_ATTN; 561 if (idcaddr->idccsr & IDC_DRDY) 562 goto top; 563 } 564 } else { 565 /* 566 * Continue transfer on current track. 567 */ 568 cont: 569 sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; 570 if (sc->sc_bcnt > sc->sc_resid) 571 sc->sc_bcnt = sc->sc_resid; 572 if (bp->b_flags & B_READ) 573 cmd = IDC_IE|IDC_READ|(unit<<8); 574 else 575 cmd = IDC_IE|IDC_WRITE|(unit<<8); 576 idcaddr->idccsr = cmd|IDC_CRDY; 577 idcaddr->idcbar = sc->sc_ubaddr; 578 idcaddr->idcbcr = -sc->sc_bcnt; 579 idcaddr->idcdar = sc->sc_dar; 580 printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); 581 idcaddr->idccsr = cmd; 582 um->um_tab.b_active = 2; 583 } 584 return; 585 } 586 /* 587 * Entire transfer is done, clean up. 588 */ 589 ubadone(um); 590 dk_busy &= ~(1 << ui->ui_dk); 591 um->um_tab.b_active = 0; 592 um->um_tab.b_errcnt = 0; 593 um->um_tab.b_actf = dp->b_forw; 594 dp->b_active = 0; 595 dp->b_errcnt = 0; 596 dp->b_actf = bp->av_forw; 597 trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf); 598 bp->b_resid = sc->sc_resid; 599 printd(", iodone, resid 0x%x\n", bp->b_resid); 600 iodone(bp); 601 if (dp->b_actf) 602 if (idcustart(ui)) 603 return; 604 } else if (um->um_tab.b_active == 1) { 605 /* 606 * Got an interrupt while setting up for a command 607 * or doing a mid-transfer seek. Save any attentions 608 * for later and process a mid-transfer seek complete. 609 */ 610 as = idcaddr->idccsr; 611 idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 612 as = (as >> 16) & 0xf; 613 unit = sc->sc_unit; 614 sc->sc_softas |= as & ~(1<<unit); 615 if (as & (1<<unit)) { 616 printd(", seek1 complete"); 617 um->um_tab.b_active = 2; 618 goto top; 619 } 620 printd(", as1 %o\n", as); 621 return; 622 } 623 /* 624 * Process any seek initiated or complete interrupts. 625 */ 626 as = idcaddr->idccsr; 627 idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 628 as = ((as >> 16) & 0xf) | sc->sc_softas; 629 sc->sc_softas = 0; 630 trace("as", as); 631 printd(", as %o", as); 632 for (unit = 0; unit < NRB; unit++) 633 if (as & (1<<unit)) { 634 as &= ~(1<<unit); 635 idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 636 ui = idcdinfo[unit]; 637 if (ui) { 638 printd(", attn unit %d", unit); 639 if (idcaddr->idccsr & IDC_DRDY) 640 if (idcustart(ui)) { 641 sc->sc_softas = as; 642 return; 643 } 644 } else { 645 printd(", unsol. intr. unit %d", unit); 646 } 647 } 648 printd("\n"); 649 if (um->um_tab.b_actf && um->um_tab.b_active == 0) { 650 trace("stum",um->um_tab.b_actf); 651 (void) idcstart(um); 652 } 653 } 654 655 idcwait(addr, n) 656 register struct idcdevice *addr; 657 register int n; 658 { 659 register int i; 660 661 while (--n && (addr->idccsr & IDC_CRDY) == 0) 662 for (i = 10; i; i--) 663 ; 664 return (n); 665 } 666 667 idcecc(ui) 668 register struct uba_device *ui; 669 { 670 register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; 671 register struct buf *bp = idcutab[ui->ui_unit].b_actf; 672 register struct uba_ctlr *um = ui->ui_mi; 673 register struct idcst *st; 674 register int i; 675 struct uba_regs *ubp = ui->ui_hd->uh_uba; 676 int bit, byte, mask; 677 caddr_t addr; 678 int reg, npf, o; 679 int cn, tn, sn; 680 681 npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; 682 reg = btop(idc_softc.sc_ubaddr) + npf; 683 o = (int)bp->b_un.b_addr & PGOFSET; 684 st = &idcst[ui->ui_type]; 685 cn = idc_softc.sc_cyl; 686 tn = idc_softc.sc_trk; 687 sn = idc_softc.sc_sect; 688 um->um_tab.b_active = 1; /* Either complete or continuing... */ 689 log(LOG_WARNING, "rb%d%c: soft ecc sn%d\n", idcunit(bp->b_dev), 690 'a'+(minor(bp->b_dev)&07), 691 (cn*st->ntrak + tn) * st->nsect + sn + npf); 692 mask = idc->idceccpat; 693 i = idc->idceccpos - 1; /* -1 makes 0 origin */ 694 bit = i&07; 695 i = (i&~07)>>3; 696 byte = i + o; 697 while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { 698 /* 699 * should be: 700 * addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 701 * (byte & PGOFSET); 702 * but this generates an extzv which hangs the UNIBUS. 703 */ 704 addr = ptob(*(int *)&ubp->uba_map[reg+btop(byte)]&0x1fffff)+ 705 (byte & PGOFSET); 706 putmemc(addr, getmemc(addr)^(mask<<bit)); 707 byte++; 708 i++; 709 bit -= 8; 710 } 711 idc_softc.sc_bcnt += idc->idcbcr; 712 um->um_tab.b_errcnt = 0; /* error has been corrected */ 713 return; 714 } 715 716 idcreset(uban) 717 int uban; 718 { 719 register struct uba_ctlr *um; 720 register struct uba_device *ui; 721 register unit; 722 723 if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || 724 um->um_alive == 0) 725 return; 726 printf(" idc0"); 727 um->um_tab.b_active = 0; 728 um->um_tab.b_actf = um->um_tab.b_actl = 0; 729 if (um->um_ubinfo) { 730 printf("<%d>", (um->um_ubinfo>>28)&0xf); 731 um->um_ubinfo = 0; 732 } 733 for (unit = 0; unit < NRB; unit++) { 734 if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 735 continue; 736 idcutab[unit].b_active = 0; 737 (void) idcustart(ui); 738 } 739 (void) idcstart(um); 740 } 741 742 idcwatch() 743 { 744 register struct uba_ctlr *um; 745 register unit; 746 747 timeout(idcwatch, (caddr_t)0, hz); 748 um = idcminfo[0]; 749 if (um == 0 || um->um_alive == 0) 750 return; 751 if (um->um_tab.b_active == 0) { 752 for (unit = 0; unit < NRB; unit++) 753 if (idcutab[unit].b_active) 754 goto active; 755 idcwticks = 0; 756 return; 757 } 758 active: 759 idcwticks++; 760 if (idcwticks >= 20) { 761 idcwticks = 0; 762 printf("idc0: lost interrupt\n"); 763 idcintr(0); 764 } 765 } 766 767 /*ARGSUSED*/ 768 idcdump(dev) 769 dev_t dev; 770 { 771 struct idcdevice *idcaddr; 772 char *start; 773 int num, blk, unit; 774 struct size *sizes; 775 register struct uba_regs *uba; 776 register struct uba_device *ui; 777 struct idcst *st; 778 union idc_dar dar; 779 int nspg; 780 781 unit = idcunit(dev); 782 if (unit >= NRB) 783 return (ENXIO); 784 #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 785 ui = phys(struct uba_device *, idcdinfo[unit]); 786 if (ui->ui_alive == 0) 787 return (ENXIO); 788 uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 789 ubainit(uba); 790 idcaddr = (struct idcdevice *)ui->ui_physaddr; 791 if (idcwait(idcaddr, 100) == 0) 792 return (EFAULT); 793 /* 794 * Since we can only transfer one track at a time, and 795 * the rl02 has 256 byte sectors, all the calculations 796 * are done in terms of physical sectors (i.e. num and blk 797 * are in sectors not NBPG blocks. 798 */ 799 st = phys(struct idcst *, &idcst[ui->ui_type]); 800 sizes = phys(struct size *, st->sizes); 801 if (dumplo < 0) 802 return (EINVAL); 803 if (dumplo + maxfree >= sizes[minor(dev)&07].nblocks) 804 num = sizes[minor(dev)&07].nblocks - dumplo; 805 nspg = NBPG / st->nbps; 806 num = num * nspg; 807 start = 0; 808 809 while (num > 0) { 810 register struct pte *io; 811 register int i; 812 daddr_t bn; 813 814 bn = (dumplo + btop(start)) * nspg; 815 dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff; 816 bn %= st->nspc; 817 dar.dar_trk = bn / st->nsect; 818 dar.dar_sect = bn % st->nsect; 819 blk = st->nsect - dar.dar_sect; 820 if (num < blk) 821 blk = num; 822 823 io = uba->uba_map; 824 for (i = 0; i < (blk + nspg - 1) / nspg; i++) 825 *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 826 *(int *)io = 0; 827 828 idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8; 829 if ((idcaddr->idccsr&IDC_DRDY) == 0) 830 return (EFAULT); 831 idcaddr->idcdar = dar.dar_dar; 832 idcaddr->idccsr = IDC_SEEK | unit << 8; 833 while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) 834 != (IDC_CRDY|IDC_DRDY)) 835 ; 836 if (idcaddr->idccsr & IDC_ERR) { 837 printf("rb%d: seek, csr=%b\n", 838 unit, idcaddr->idccsr, IDCCSR_BITS); 839 return (EIO); 840 } 841 842 idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8; 843 if ((idcaddr->idccsr&IDC_DRDY) == 0) 844 return (EFAULT); 845 idcaddr->idcbar = 0; /* start addr 0 */ 846 idcaddr->idcbcr = - (blk * st->nbps); 847 idcaddr->idcdar = dar.dar_dar; 848 idcaddr->idccsr = IDC_WRITE | unit << 8; 849 while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) 850 != (IDC_CRDY|IDC_DRDY)) 851 ; 852 if (idcaddr->idccsr & IDC_ERR) { 853 printf("rb%d: write, csr=%b\n", 854 unit, idcaddr->idccsr, IDCCSR_BITS); 855 return (EIO); 856 } 857 858 start += blk * st->nbps; 859 num -= blk; 860 } 861 return (0); 862 } 863 864 idcsize(dev) 865 dev_t dev; 866 { 867 int unit = idcunit(dev); 868 struct uba_device *ui; 869 struct idcst *st; 870 871 if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 872 return (-1); 873 st = &idcst[ui->ui_type]; 874 return (st->sizes[minor(dev) & 07].nblocks); 875 } 876 #endif 877