1 /* rk.c 4.31 81/03/17 */ 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 ubadone(um); 339 dp = um->um_tab.b_actf; 340 bp = dp->b_actf; 341 ui = rkdinfo[dkunit(bp)]; 342 dk_busy &= ~(1 << ui->ui_dk); 343 if (rkaddr->rkcs1 & RK_CERR) { 344 int recal; 345 u_short ds = rkaddr->rkds; 346 u_short cs2 = rkaddr->rkcs2; 347 u_short er = rkaddr->rker; 348 if (rkdebug) { 349 printf("cs2=%b ds=%b er=%b\n", 350 cs2, RKCS2_BITS, ds, 351 RKDS_BITS, er, RKER_BITS); 352 } 353 if (er & RKER_WLE) { 354 printf("rk%d: write locked\n", dkunit(bp)); 355 bp->b_flags |= B_ERROR; 356 } else if (++um->um_tab.b_errcnt > 28 || 357 ds&RKDS_HARD || er&RKER_HARD || cs2&RKCS2_HARD) { 358 harderr(bp, "rk"); 359 printf("cs2=%b ds=%b er=%b\n", 360 cs2, RKCS2_BITS, ds, 361 RKDS_BITS, er, RKER_BITS); 362 bp->b_flags |= B_ERROR; 363 sc->sc_recal = 0; 364 } else 365 um->um_tab.b_active = 0; 366 if (cs2&RKCS2_MDS) { 367 rkaddr->rkcs2 = RKCS2_SCLR; 368 goto retry; 369 } 370 recal = 0; 371 if (ds&RKDS_DROT || er&(RKER_OPI|RKER_SKI|RKER_UNS) || 372 (um->um_tab.b_errcnt&07) == 4) 373 recal = 1; 374 if ((er & (RKER_DCK|RKER_ECH)) == RKER_DCK) 375 if (rkecc(ui)) 376 return; 377 rkaddr->rkcs1 = RK_CDT|RK_CCLR; 378 rkaddr->rkcs2 = ui->ui_slave; 379 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 380 rkwait(rkaddr); 381 if (recal && um->um_tab.b_active == 0) { 382 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_RECAL|RK_GO; 383 rkcyl[ui->ui_unit] = -1; 384 sc->sc_recal = 0; 385 goto nextrecal; 386 } 387 } 388 retry: 389 switch (sc->sc_recal) { 390 391 case 1: 392 rkaddr->rkcyl = bp->b_cylin; 393 rkcyl[ui->ui_unit] = bp->b_cylin; 394 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_SEEK|RK_GO; 395 goto nextrecal; 396 case 2: 397 if (um->um_tab.b_errcnt < 16 || 398 (bp->b_flags&B_READ) == 0) 399 goto donerecal; 400 rkaddr->rkatt = rk_offset[um->um_tab.b_errcnt & 017]; 401 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_OFFSET|RK_GO; 402 /* fall into ... */ 403 nextrecal: 404 sc->sc_recal++; 405 rkwait(rkaddr); 406 um->um_tab.b_active = 1; 407 return; 408 donerecal: 409 case 3: 410 sc->sc_recal = 0; 411 um->um_tab.b_active = 0; 412 break; 413 } 414 if (um->um_tab.b_active) { 415 um->um_tab.b_active = 0; 416 um->um_tab.b_errcnt = 0; 417 um->um_tab.b_actf = dp->b_forw; 418 dp->b_active = 0; 419 dp->b_errcnt = 0; 420 dp->b_actf = bp->av_forw; 421 bp->b_resid = -rkaddr->rkwc * sizeof(short); 422 iodone(bp); 423 if (dp->b_actf) 424 if (rkustart(ui)) 425 needie = 0; 426 } 427 as &= ~(1<<ui->ui_slave); 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 #if VAX780 624 if (cpu == VAX_780) 625 ubainit(uba); 626 #endif 627 rkaddr = (struct rkdevice *)ui->ui_physaddr; 628 num = maxfree; 629 start = 0; 630 rkaddr->rkcs1 = RK_CDT|RK_CERR; 631 rkaddr->rkcs2 = unit; 632 rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO; 633 rkwait(rkaddr); 634 if ((rkaddr->rkds & RKDS_VV) == 0) { 635 rkaddr->rkcs1 = RK_CDT|RK_IE|RK_PACK|RK_GO; 636 rkwait(rkaddr); 637 } 638 st = &rkst[ui->ui_type]; 639 sizes = phys(struct size *, st->sizes); 640 if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 641 return (EINVAL); 642 while (num > 0) { 643 register struct pte *io; 644 register int i; 645 int cn, sn, tn; 646 daddr_t bn; 647 648 blk = num > DBSIZE ? DBSIZE : num; 649 io = uba->uba_map; 650 for (i = 0; i < blk; i++) 651 *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 652 *(int *)io = 0; 653 bn = dumplo + btop(start); 654 cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 655 sn = bn%st->nspc; 656 tn = sn/st->nsect; 657 sn = sn%st->nsect; 658 rkaddr->rkcyl = cn; 659 rp = (short *) &rkaddr->rkda; 660 *rp = (tn << 8) + sn; 661 *--rp = 0; 662 *--rp = -blk*NBPG / sizeof (short); 663 *--rp = RK_CDT|RK_GO|RK_WRITE; 664 rkwait(rkaddr); 665 if (rkaddr->rkcs1 & RK_CERR) 666 return (EIO); 667 start += blk*NBPG; 668 num -= blk; 669 } 670 return (0); 671 } 672 #endif 673