1 /* rk.c 4.33 81/04/02 */ 2 3 #include "rk.h" 4 #if NHK > 0 5 int rkpip; /* DEBUG */ 6 int rknosval; /* DEBUG */ 7 int rkdebug; 8 /* 9 * RK611/RK0[67] disk driver 10 * 11 * This driver mimics up.c; see it for an explanation of common code. 12 * 13 * TODO: 14 * Learn why we lose an interrupt sometime when spinning drives down 15 * Support rk06 16 */ 17 #include "../h/param.h" 18 #include "../h/systm.h" 19 #include "../h/buf.h" 20 #include "../h/conf.h" 21 #include "../h/dir.h" 22 #include "../h/user.h" 23 #include "../h/pte.h" 24 #include "../h/map.h" 25 #include "../h/vm.h" 26 #include "../h/ubareg.h" 27 #include "../h/ubavar.h" 28 #include "../h/dk.h" 29 #include "../h/cpu.h" 30 #include "../h/cmap.h" 31 32 #include "../h/rkreg.h" 33 34 struct rk_softc { 35 int sc_softas; 36 int sc_ndrive; 37 int sc_wticks; 38 int sc_recal; 39 } rk_softc[NHK]; 40 41 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 42 struct size { 43 daddr_t nblocks; 44 int cyloff; 45 } rk7_sizes[] ={ 46 15884, 0, /* A=cyl 0 thru 240 */ 47 10032, 241, /* B=cyl 241 thru 392 */ 48 53790, 0, /* C=cyl 0 thru 814 */ 49 0, 0, 50 0, 0, 51 0, 0, 52 27786, 393, /* G=cyl 393 thru 813 */ 53 0, 0, 54 }; 55 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 56 57 int rkprobe(), rkslave(), rkattach(), rkdgo(), rkintr(); 58 struct uba_ctlr *rkminfo[NHK]; 59 struct uba_device *rkdinfo[NRK]; 60 struct uba_device *rkip[NHK][4]; 61 62 u_short rkstd[] = { 0777440, 0 }; 63 struct uba_driver hkdriver = 64 { rkprobe, rkslave, rkattach, rkdgo, rkstd, "rk", rkdinfo, "hk", rkminfo, 1 }; 65 struct buf rkutab[NRK]; 66 short rkcyl[NRK]; 67 68 struct rkst { 69 short nsect; 70 short ntrak; 71 short nspc; 72 short ncyl; 73 struct size *sizes; 74 } rkst[] = { 75 NRKSECT, NRKTRK, NRKSECT*NRKTRK, NRK7CYL, rk7_sizes, 76 }; 77 78 u_char rk_offset[16] = 79 { RKAS_P400,RKAS_M400,RKAS_P400,RKAS_M400,RKAS_P800,RKAS_M800,RKAS_P800, 80 RKAS_M800,RKAS_P1200,RKAS_M1200,RKAS_P1200,RKAS_M1200,0,0,0,0 81 }; 82 83 struct buf rrkbuf[NRK]; 84 85 #define b_cylin b_resid 86 87 #ifdef INTRLVE 88 daddr_t dkblock(); 89 #endif 90 91 int rkwstart, rkwatch(); 92 93 rkprobe(reg) 94 caddr_t reg; 95 { 96 register int br, cvec; 97 98 #ifdef lint 99 br = 0; cvec = br; br = cvec; 100 #endif 101 ((struct rkdevice *)reg)->rkcs1 = RK_CDT|RK_IE|RK_CRDY; 102 DELAY(10); 103 ((struct rkdevice *)reg)->rkcs1 = RK_CDT; 104 return (1); 105 } 106 107 rkslave(ui, reg) 108 struct uba_device *ui; 109 caddr_t reg; 110 { 111 register struct rkdevice *rkaddr = (struct rkdevice *)reg; 112 113 rkaddr->rkcs1 = RK_CDT|RK_CCLR; 114 rkaddr->rkcs2 = ui->ui_slave; 115 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 116 rkwait(rkaddr); 117 DELAY(50); 118 if (rkaddr->rkcs2&RKCS2_NED || (rkaddr->rkds&RKDS_SVAL) == 0) { 119 rkaddr->rkcs1 = RK_CDT|RK_CCLR; 120 return (0); 121 } 122 return (1); 123 } 124 125 rkattach(ui) 126 register struct uba_device *ui; 127 { 128 129 if (rkwstart == 0) { 130 timeout(rkwatch, (caddr_t)0, hz); 131 rkwstart++; 132 } 133 if (ui->ui_dk >= 0) 134 dk_mspw[ui->ui_dk] = 1.0 / (60 * NRKSECT * 256); 135 rkip[ui->ui_ctlr][ui->ui_slave] = ui; 136 rk_softc[ui->ui_ctlr].sc_ndrive++; 137 rkcyl[ui->ui_unit] = -1; 138 } 139 140 rkstrategy(bp) 141 register struct buf *bp; 142 { 143 register struct uba_device *ui; 144 register struct rkst *st; 145 register int unit; 146 register struct buf *dp; 147 int xunit = minor(bp->b_dev) & 07; 148 long bn, sz; 149 150 sz = (bp->b_bcount+511) >> 9; 151 unit = dkunit(bp); 152 if (unit >= NRK) 153 goto bad; 154 ui = rkdinfo[unit]; 155 if (ui == 0 || ui->ui_alive == 0) 156 goto bad; 157 st = &rkst[ui->ui_type]; 158 if (bp->b_blkno < 0 || 159 (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 160 goto bad; 161 bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 162 (void) spl5(); 163 dp = &rkutab[ui->ui_unit]; 164 disksort(dp, bp); 165 if (dp->b_active == 0) { 166 (void) rkustart(ui); 167 bp = &ui->ui_mi->um_tab; 168 if (bp->b_actf && bp->b_active == 0) 169 (void) rkstart(ui->ui_mi); 170 } 171 (void) spl0(); 172 return; 173 174 bad: 175 bp->b_flags |= B_ERROR; 176 iodone(bp); 177 return; 178 } 179 180 rkustart(ui) 181 register struct uba_device *ui; 182 { 183 register struct buf *bp, *dp; 184 register struct uba_ctlr *um; 185 register struct rkdevice *rkaddr; 186 int didie = 0; 187 188 if (ui == 0) 189 return (0); 190 dk_busy &= ~(1<<ui->ui_dk); 191 dp = &rkutab[ui->ui_unit]; 192 um = ui->ui_mi; 193 rkaddr = (struct rkdevice *)um->um_addr; 194 if (um->um_tab.b_active) { 195 rk_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 196 return (0); 197 } 198 rkaddr->rkcs1 = RK_CDT|RK_CERR; 199 rkaddr->rkcs2 = ui->ui_slave; 200 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 201 rkwait(rkaddr); 202 if ((bp = dp->b_actf) == NULL) { 203 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 204 rkwait(rkaddr); 205 return (0); 206 } 207 if ((rkaddr->rkds & RKDS_VV) == 0) { 208 /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 209 rkaddr->rkcs1 = RK_CDT|RK_PACK|RK_GO; 210 rkwait(rkaddr); 211 } 212 if (dp->b_active) 213 goto done; 214 dp->b_active = 1; 215 if ((rkaddr->rkds & RKDS_DREADY) != RKDS_DREADY) 216 goto done; 217 if (rk_softc[um->um_ctlr].sc_ndrive == 1) 218 goto done; 219 if (bp->b_cylin == rkcyl[ui->ui_unit]) 220 goto done; 221 rkaddr->rkcyl = bp->b_cylin; 222 rkcyl[ui->ui_unit] = bp->b_cylin; 223 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_SEEK|RK_GO; 224 didie = 1; 225 if (ui->ui_dk >= 0) { 226 dk_busy |= 1<<ui->ui_dk; 227 dk_seek[ui->ui_dk]++; 228 } 229 goto out; 230 done: 231 if (dp->b_active != 2) { 232 dp->b_forw = NULL; 233 if (um->um_tab.b_actf == NULL) 234 um->um_tab.b_actf = dp; 235 else 236 um->um_tab.b_actl->b_forw = dp; 237 um->um_tab.b_actl = dp; 238 dp->b_active = 2; 239 } 240 out: 241 return (didie); 242 } 243 244 rkstart(um) 245 register struct uba_ctlr *um; 246 { 247 register struct buf *bp, *dp; 248 register struct uba_device *ui; 249 register struct rkdevice *rkaddr; 250 struct rkst *st; 251 daddr_t bn; 252 int sn, tn, cmd; 253 254 loop: 255 if ((dp = um->um_tab.b_actf) == NULL) 256 return (0); 257 if ((bp = dp->b_actf) == NULL) { 258 um->um_tab.b_actf = dp->b_forw; 259 goto loop; 260 } 261 um->um_tab.b_active++; 262 ui = rkdinfo[dkunit(bp)]; 263 bn = dkblock(bp); 264 st = &rkst[ui->ui_type]; 265 sn = bn%st->nspc; 266 tn = sn/st->nsect; 267 sn %= st->nsect; 268 rkaddr = (struct rkdevice *)ui->ui_addr; 269 retry: 270 rkaddr->rkcs1 = RK_CDT|RK_CERR; 271 rkaddr->rkcs2 = ui->ui_slave; 272 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 273 rkwait(rkaddr); 274 if ((rkaddr->rkds&RKDS_SVAL) == 0) { 275 rknosval++; 276 goto nosval; 277 } 278 if (rkaddr->rkds&RKDS_PIP) { 279 rkpip++; 280 goto retry; 281 } 282 if ((rkaddr->rkds&RKDS_DREADY) != RKDS_DREADY) { 283 printf("rk%d: not ready", dkunit(bp)); 284 if ((rkaddr->rkds&RKDS_DREADY) != RKDS_DREADY) { 285 printf("\n"); 286 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 287 rkwait(rkaddr); 288 rkaddr->rkcs1 = RK_CDT|RK_CERR; 289 rkwait(rkaddr); 290 um->um_tab.b_active = 0; 291 um->um_tab.b_errcnt = 0; 292 dp->b_actf = bp->av_forw; 293 dp->b_active = 0; 294 bp->b_flags |= B_ERROR; 295 iodone(bp); 296 goto loop; 297 } 298 printf(" (came back!)\n"); 299 } 300 nosval: 301 rkaddr->rkcyl = bp->b_cylin; 302 rkcyl[ui->ui_unit] = bp->b_cylin; 303 rkaddr->rkda = (tn << 8) + sn; 304 rkaddr->rkwc = -bp->b_bcount / sizeof (short); 305 if (bp->b_flags & B_READ) 306 cmd = RK_CDT|RK_IE|RK_READ|RK_GO; 307 else 308 cmd = RK_CDT|RK_IE|RK_WRITE|RK_GO; 309 um->um_cmd = cmd; 310 (void) ubago(ui); 311 return (1); 312 } 313 314 rkdgo(um) 315 register struct uba_ctlr *um; 316 { 317 register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr; 318 319 rkaddr->rkba = um->um_ubinfo; 320 rkaddr->rkcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 321 } 322 323 rkintr(rk11) 324 int rk11; 325 { 326 register struct uba_ctlr *um = rkminfo[rk11]; 327 register struct uba_device *ui; 328 register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr; 329 register struct buf *bp, *dp; 330 int unit; 331 struct rk_softc *sc = &rk_softc[um->um_ctlr]; 332 int as = (rkaddr->rkatt >> 8) | sc->sc_softas; 333 int needie = 1; 334 335 sc->sc_wticks = 0; 336 sc->sc_softas = 0; 337 if (um->um_tab.b_active) { 338 dp = um->um_tab.b_actf; 339 bp = dp->b_actf; 340 ui = rkdinfo[dkunit(bp)]; 341 dk_busy &= ~(1 << ui->ui_dk); 342 if (rkaddr->rkcs1 & RK_CERR) { 343 int recal; 344 u_short ds = rkaddr->rkds; 345 u_short cs2 = rkaddr->rkcs2; 346 u_short er = rkaddr->rker; 347 if (rkdebug) { 348 printf("cs2=%b ds=%b er=%b\n", 349 cs2, RKCS2_BITS, ds, 350 RKDS_BITS, er, RKER_BITS); 351 } 352 if (er & RKER_WLE) { 353 printf("rk%d: write locked\n", dkunit(bp)); 354 bp->b_flags |= B_ERROR; 355 } else if (++um->um_tab.b_errcnt > 28 || 356 ds&RKDS_HARD || er&RKER_HARD || cs2&RKCS2_HARD) { 357 harderr(bp, "rk"); 358 printf("cs2=%b ds=%b er=%b\n", 359 cs2, RKCS2_BITS, ds, 360 RKDS_BITS, er, RKER_BITS); 361 bp->b_flags |= B_ERROR; 362 sc->sc_recal = 0; 363 } else 364 um->um_tab.b_active = 0; 365 if (cs2&RKCS2_MDS) { 366 rkaddr->rkcs2 = RKCS2_SCLR; 367 goto retry; 368 } 369 recal = 0; 370 if (ds&RKDS_DROT || er&(RKER_OPI|RKER_SKI|RKER_UNS) || 371 (um->um_tab.b_errcnt&07) == 4) 372 recal = 1; 373 if ((er & (RKER_DCK|RKER_ECH)) == RKER_DCK) 374 if (rkecc(ui)) 375 return; 376 rkaddr->rkcs1 = RK_CDT|RK_CCLR; 377 rkaddr->rkcs2 = ui->ui_slave; 378 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 379 rkwait(rkaddr); 380 if (recal && um->um_tab.b_active == 0) { 381 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_RECAL|RK_GO; 382 rkcyl[ui->ui_unit] = -1; 383 sc->sc_recal = 0; 384 goto nextrecal; 385 } 386 } 387 retry: 388 switch (sc->sc_recal) { 389 390 case 1: 391 rkaddr->rkcyl = bp->b_cylin; 392 rkcyl[ui->ui_unit] = bp->b_cylin; 393 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_SEEK|RK_GO; 394 goto nextrecal; 395 case 2: 396 if (um->um_tab.b_errcnt < 16 || 397 (bp->b_flags&B_READ) == 0) 398 goto donerecal; 399 rkaddr->rkatt = rk_offset[um->um_tab.b_errcnt & 017]; 400 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_OFFSET|RK_GO; 401 /* fall into ... */ 402 nextrecal: 403 sc->sc_recal++; 404 rkwait(rkaddr); 405 um->um_tab.b_active = 1; 406 return; 407 donerecal: 408 case 3: 409 sc->sc_recal = 0; 410 um->um_tab.b_active = 0; 411 break; 412 } 413 if (um->um_tab.b_active) { 414 um->um_tab.b_active = 0; 415 um->um_tab.b_errcnt = 0; 416 um->um_tab.b_actf = dp->b_forw; 417 dp->b_active = 0; 418 dp->b_errcnt = 0; 419 dp->b_actf = bp->av_forw; 420 bp->b_resid = -rkaddr->rkwc * sizeof(short); 421 iodone(bp); 422 if (dp->b_actf) 423 if (rkustart(ui)) 424 needie = 0; 425 } 426 as &= ~(1<<ui->ui_slave); 427 ubadone(um); 428 } 429 for (unit = 0; as; as >>= 1, unit++) 430 if (as & 1) { 431 ui = rkip[rk11][unit]; 432 if (ui) { 433 if (rkustart(rkip[rk11][unit])) 434 needie = 0; 435 } else { 436 rkaddr->rkcs1 = RK_CERR|RK_CDT; 437 rkaddr->rkcs2 = unit; 438 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 439 rkwait(rkaddr); 440 } 441 } 442 if (um->um_tab.b_actf && um->um_tab.b_active == 0) 443 if (rkstart(um)) 444 needie = 0; 445 if (needie) 446 rkaddr->rkcs1 = RK_CDT|RK_IE; 447 } 448 449 rkwait(addr) 450 register struct rkdevice *addr; 451 { 452 453 while ((addr->rkcs1 & RK_CRDY) == 0) 454 ; 455 } 456 457 rkread(dev) 458 dev_t dev; 459 { 460 register int unit = minor(dev) >> 3; 461 462 if (unit >= NRK) 463 u.u_error = ENXIO; 464 else 465 physio(rkstrategy, &rrkbuf[unit], dev, B_READ, minphys); 466 } 467 468 rkwrite(dev) 469 dev_t dev; 470 { 471 register int unit = minor(dev) >> 3; 472 473 if (unit >= NRK) 474 u.u_error = ENXIO; 475 else 476 physio(rkstrategy, &rrkbuf[unit], dev, B_WRITE, minphys); 477 } 478 479 rkecc(ui) 480 register struct uba_device *ui; 481 { 482 register struct rkdevice *rk = (struct rkdevice *)ui->ui_addr; 483 register struct buf *bp = rkutab[ui->ui_unit].b_actf; 484 register struct uba_ctlr *um = ui->ui_mi; 485 register struct rkst *st; 486 struct uba_regs *ubp = ui->ui_hd->uh_uba; 487 register int i; 488 caddr_t addr; 489 int reg, bit, byte, npf, mask, o, cmd, ubaddr; 490 int bn, cn, tn, sn; 491 492 npf = btop((rk->rkwc * sizeof(short)) + bp->b_bcount) - 1; 493 reg = btop(um->um_ubinfo&0x3ffff) + npf; 494 o = (int)bp->b_un.b_addr & PGOFSET; 495 printf("rk%d%c: soft ecc sn%d\n", dkunit(bp), 496 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 497 mask = rk->rkec2; 498 ubapurge(um); 499 i = rk->rkec1 - 1; /* -1 makes 0 origin */ 500 bit = i&07; 501 i = (i&~07)>>3; 502 byte = i + o; 503 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 504 addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 505 (byte & PGOFSET); 506 putmemc(addr, getmemc(addr)^(mask<<bit)); 507 byte++; 508 i++; 509 bit -= 8; 510 } 511 um->um_tab.b_active++; /* Either complete or continuing... */ 512 if (rk->rkwc == 0) 513 return (0); 514 #ifdef notdef 515 rk->rkcs1 |= RK_GO; 516 #else 517 rk->rkcs1 = RK_CDT|RK_CCLR; 518 rk->rkcs2 = ui->ui_slave; 519 rk->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 520 rkwait(rk); 521 bn = dkblock(bp); 522 st = &rkst[ui->ui_type]; 523 cn = bp->b_cylin; 524 sn = bn%st->nspc + npf + 1; 525 tn = sn/st->nsect; 526 sn %= st->nsect; 527 cn += tn/st->ntrak; 528 tn %= st->ntrak; 529 rk->rkcyl = cn; 530 rk->rkda = (tn << 8) | sn; 531 ubaddr = (int)ptob(reg+1) + o; 532 rk->rkba = ubaddr; 533 cmd = (ubaddr >> 8) & 0x300; 534 cmd |= RK_CDT|RK_IE|RK_GO|RK_READ; 535 rk->rkcs1 = cmd; 536 #endif 537 return (1); 538 } 539 540 rkreset(uban) 541 int uban; 542 { 543 register struct uba_ctlr *um; 544 register struct uba_device *ui; 545 register rk11, unit; 546 547 for (rk11 = 0; rk11 < NHK; rk11++) { 548 if ((um = rkminfo[rk11]) == 0 || um->um_ubanum != uban || 549 um->um_alive == 0) 550 continue; 551 printf(" hk%d", rk11); 552 um->um_tab.b_active = 0; 553 um->um_tab.b_actf = um->um_tab.b_actl = 0; 554 rk_softc[um->um_ctlr].sc_recal = 0; 555 if (um->um_ubinfo) { 556 printf("<%d>", (um->um_ubinfo>>28)&0xf); 557 ubadone(um); 558 } 559 for (unit = 0; unit < NHK; unit++) { 560 if ((ui = rkdinfo[unit]) == 0) 561 continue; 562 if (ui->ui_alive == 0) 563 continue; 564 rkutab[unit].b_active = 0; 565 (void) rkustart(ui); 566 } 567 (void) rkstart(um); 568 } 569 } 570 571 rkwatch() 572 { 573 register struct uba_ctlr *um; 574 register rk11, unit; 575 register struct rk_softc *sc; 576 577 timeout(rkwatch, (caddr_t)0, hz); 578 for (rk11 = 0; rk11 < NHK; rk11++) { 579 um = rkminfo[rk11]; 580 if (um == 0 || um->um_alive == 0) 581 continue; 582 sc = &rk_softc[rk11]; 583 if (um->um_tab.b_active == 0) { 584 for (unit = 0; unit < NRK; unit++) 585 if (rkutab[unit].b_active && 586 rkdinfo[unit]->ui_mi == um) 587 goto active; 588 sc->sc_wticks = 0; 589 continue; 590 } 591 active: 592 sc->sc_wticks++; 593 if (sc->sc_wticks >= 20) { 594 sc->sc_wticks = 0; 595 printf("hk%d: lost interrupt\n", rk11); 596 ubareset(um->um_ubanum); 597 } 598 } 599 } 600 601 #define DBSIZE 20 602 603 rkdump(dev) 604 dev_t dev; 605 { 606 struct rkdevice *rkaddr; 607 char *start; 608 int num, blk, unit; 609 struct size *sizes; 610 register struct uba_regs *uba; 611 register struct uba_device *ui; 612 register short *rp; 613 struct rkst *st; 614 615 unit = minor(dev) >> 3; 616 if (unit >= NRK) 617 return (ENXIO); 618 #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 619 ui = phys(struct uba_device *, rkdinfo[unit]); 620 if (ui->ui_alive == 0) 621 return (ENXIO); 622 uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 623 ubainit(uba); 624 rkaddr = (struct rkdevice *)ui->ui_physaddr; 625 num = maxfree; 626 start = 0; 627 rkaddr->rkcs1 = RK_CDT|RK_CERR; 628 rkaddr->rkcs2 = unit; 629 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 630 rkwait(rkaddr); 631 if ((rkaddr->rkds & RKDS_VV) == 0) { 632 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_PACK|RK_GO; 633 rkwait(rkaddr); 634 } 635 st = &rkst[ui->ui_type]; 636 sizes = phys(struct size *, st->sizes); 637 if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 638 return (EINVAL); 639 while (num > 0) { 640 register struct pte *io; 641 register int i; 642 int cn, sn, tn; 643 daddr_t bn; 644 645 blk = num > DBSIZE ? DBSIZE : num; 646 io = uba->uba_map; 647 for (i = 0; i < blk; i++) 648 *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 649 *(int *)io = 0; 650 bn = dumplo + btop(start); 651 cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 652 sn = bn%st->nspc; 653 tn = sn/st->nsect; 654 sn = sn%st->nsect; 655 rkaddr->rkcyl = cn; 656 rp = (short *) &rkaddr->rkda; 657 *rp = (tn << 8) + sn; 658 *--rp = 0; 659 *--rp = -blk*NBPG / sizeof (short); 660 *--rp = RK_CDT|RK_GO|RK_WRITE; 661 rkwait(rkaddr); 662 if (rkaddr->rkcs1 & RK_CERR) 663 return (EIO); 664 start += blk*NBPG; 665 num -= blk; 666 } 667 return (0); 668 } 669 #endif 670