1 /* $NetBSD: rl.c,v 1.49 2015/01/02 19:42:07 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of 17 * Lule}, Sweden and its contributors. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * RL11/RLV11/RLV12 disk controller driver and 35 * RL01/RL02 disk device driver. 36 * 37 * TODO: 38 * Handle disk errors more gracefully 39 * Do overlapping seeks on multiple drives 40 * 41 * Implementation comments: 42 * 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: rl.c,v 1.49 2015/01/02 19:42:07 christos Exp $"); 47 48 #include <sys/param.h> 49 #include <sys/device.h> 50 #include <sys/systm.h> 51 #include <sys/conf.h> 52 #include <sys/disk.h> 53 #include <sys/disklabel.h> 54 #include <sys/buf.h> 55 #include <sys/bufq.h> 56 #include <sys/stat.h> 57 #include <sys/dkio.h> 58 #include <sys/fcntl.h> 59 #include <sys/event.h> 60 61 #include <ufs/ufs/dinode.h> 62 #include <ufs/ffs/fs.h> 63 64 #include <sys/bus.h> 65 66 #include <dev/qbus/ubavar.h> 67 #include <dev/qbus/rlreg.h> 68 #include <dev/qbus/rlvar.h> 69 70 #include "ioconf.h" 71 #include "locators.h" 72 73 static int rlcmatch(device_t, cfdata_t, void *); 74 static void rlcattach(device_t, device_t, void *); 75 static int rlcprint(void *, const char *); 76 static void rlcintr(void *); 77 static int rlmatch(device_t, cfdata_t, void *); 78 static void rlattach(device_t, device_t, void *); 79 static void rlcstart(struct rlc_softc *, struct buf *); 80 static void waitcrdy(struct rlc_softc *); 81 static void rlcreset(device_t); 82 83 CFATTACH_DECL_NEW(rlc, sizeof(struct rlc_softc), 84 rlcmatch, rlcattach, NULL, NULL); 85 86 CFATTACH_DECL_NEW(rl, sizeof(struct rl_softc), 87 rlmatch, rlattach, NULL, NULL); 88 89 static dev_type_open(rlopen); 90 static dev_type_close(rlclose); 91 static dev_type_read(rlread); 92 static dev_type_write(rlwrite); 93 static dev_type_ioctl(rlioctl); 94 static dev_type_strategy(rlstrategy); 95 static dev_type_dump(rldump); 96 static dev_type_size(rlpsize); 97 98 const struct bdevsw rl_bdevsw = { 99 .d_open = rlopen, 100 .d_close = rlclose, 101 .d_strategy = rlstrategy, 102 .d_ioctl = rlioctl, 103 .d_dump = rldump, 104 .d_psize = rlpsize, 105 .d_discard = nodiscard, 106 .d_flag = D_DISK 107 }; 108 109 const struct cdevsw rl_cdevsw = { 110 .d_open = rlopen, 111 .d_close = rlclose, 112 .d_read = rlread, 113 .d_write = rlwrite, 114 .d_ioctl = rlioctl, 115 .d_stop = nostop, 116 .d_tty = notty, 117 .d_poll = nopoll, 118 .d_mmap = nommap, 119 .d_kqfilter = nokqfilter, 120 .d_discard = nodiscard, 121 .d_flag = D_DISK 122 }; 123 124 #define MAXRLXFER (RL_BPS * RL_SPT) 125 126 #define RL_WREG(reg, val) \ 127 bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val)) 128 #define RL_RREG(reg) \ 129 bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg)) 130 131 static const char * const rlstates[] = { 132 "drive not loaded", 133 "drive spinning up", 134 "drive brushes out", 135 "drive loading heads", 136 "drive seeking", 137 "drive ready", 138 "drive unloading heads", 139 "drive spun down", 140 }; 141 142 static const struct dkdriver rldkdriver = { 143 rlstrategy, minphys 144 }; 145 146 static const char * 147 rlstate(struct rlc_softc *sc, int unit) 148 { 149 int i = 0; 150 151 do { 152 RL_WREG(RL_DA, RLDA_GS); 153 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT)); 154 waitcrdy(sc); 155 } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10); 156 if (i == 10) 157 return NULL; 158 i = RL_RREG(RL_MP) & RLMP_STATUS; 159 return rlstates[i]; 160 } 161 162 void 163 waitcrdy(struct rlc_softc *sc) 164 { 165 int i; 166 167 for (i = 0; i < 1000; i++) { 168 DELAY(10000); 169 if (RL_RREG(RL_CS) & RLCS_CRDY) 170 return; 171 } 172 aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */ 173 } 174 175 int 176 rlcprint(void *aux, const char *name) 177 { 178 struct rlc_attach_args *ra = aux; 179 180 if (name) 181 aprint_normal("RL0%d at %s", 182 ra->type & RLMP_DT ? '2' : '1', name); 183 aprint_normal(" drive %d", ra->hwid); 184 return UNCONF; 185 } 186 187 /* 188 * Force the controller to interrupt. 189 */ 190 int 191 rlcmatch(device_t parent, cfdata_t cf, void *aux) 192 { 193 struct uba_attach_args *ua = aux; 194 struct rlc_softc ssc, *sc = &ssc; 195 int i; 196 197 sc->sc_iot = ua->ua_iot; 198 sc->sc_ioh = ua->ua_ioh; 199 /* Force interrupt by issuing a "Get Status" command */ 200 RL_WREG(RL_DA, RLDA_GS); 201 RL_WREG(RL_CS, RLCS_GS|RLCS_IE); 202 203 for (i = 0; i < 100; i++) { 204 DELAY(100000); 205 if (RL_RREG(RL_CS) & RLCS_CRDY) 206 return 1; 207 } 208 return 0; 209 } 210 211 void 212 rlcattach(device_t parent, device_t self, void *aux) 213 { 214 struct rlc_softc *sc = device_private(self); 215 struct uba_attach_args *ua = aux; 216 struct rlc_attach_args ra; 217 int i, error; 218 219 sc->sc_dev = self; 220 sc->sc_uh = device_private(parent); 221 sc->sc_iot = ua->ua_iot; 222 sc->sc_ioh = ua->ua_ioh; 223 sc->sc_dmat = ua->ua_dmat; 224 uba_intr_establish(ua->ua_icookie, ua->ua_cvec, 225 rlcintr, sc, &sc->sc_intrcnt); 226 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt, 227 device_xname(sc->sc_dev), "intr"); 228 uba_reset_establish(rlcreset, self); 229 230 printf("\n"); 231 232 /* 233 * The RL11 can only have one transfer going at a time, 234 * and max transfer size is one track, so only one dmamap 235 * is needed. 236 */ 237 error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0, 238 BUS_DMA_ALLOCNOW, &sc->sc_dmam); 239 if (error) { 240 aprint_error(": Failed to allocate DMA map, error %d\n", error); 241 return; 242 } 243 bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER); 244 for (i = 0; i < RL_MAXDPC; i++) { 245 waitcrdy(sc); 246 RL_WREG(RL_DA, RLDA_GS|RLDA_RST); 247 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT)); 248 waitcrdy(sc); 249 ra.type = RL_RREG(RL_MP); 250 ra.hwid = i; 251 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0) 252 config_found(sc->sc_dev, &ra, rlcprint); 253 } 254 } 255 256 int 257 rlmatch(device_t parent, cfdata_t cf, void *aux) 258 { 259 struct rlc_attach_args *ra = aux; 260 261 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT && 262 cf->cf_loc[RLCCF_DRIVE] != ra->hwid) 263 return 0; 264 return 1; 265 } 266 267 void 268 rlattach(device_t parent, device_t self, void *aux) 269 { 270 struct rl_softc *rc = device_private(self); 271 struct rlc_attach_args *ra = aux; 272 struct disklabel *dl; 273 274 rc->rc_dev = self; 275 rc->rc_rlc = device_private(parent); 276 rc->rc_hwid = ra->hwid; 277 disk_init(&rc->rc_disk, device_xname(rc->rc_dev), &rldkdriver); 278 disk_attach(&rc->rc_disk); 279 dl = rc->rc_disk.dk_label; 280 dl->d_npartitions = 3; 281 strcpy(dl->d_typename, "RL01"); 282 if (ra->type & RLMP_DT) 283 dl->d_typename[3] = '2'; 284 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */ 285 dl->d_nsectors = RL_SPT/2; 286 dl->d_ntracks = RL_SPD; 287 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01; 288 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 289 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl; 290 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 291 dl->d_secperunit; 292 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 293 dl->d_interleave = dl->d_headswitch = 1; 294 dl->d_bbsize = BBSIZE; 295 dl->d_sbsize = SBLOCKSIZE; 296 dl->d_rpm = 2400; 297 dl->d_type = DKTYPE_DEC; 298 printf(": %s, %s\n", dl->d_typename, rlstate(rc->rc_rlc, ra->hwid)); 299 300 /* 301 * XXX We should try to discovery wedges here, but 302 * XXX that would mean loading up the pack and being 303 * XXX able to do I/O. Should use config_defer() here. 304 */ 305 } 306 307 int 308 rlopen(dev_t dev, int flag, int fmt, struct lwp *l) 309 { 310 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 311 struct rlc_softc *sc; 312 int error, part, mask; 313 struct disklabel *dl; 314 const char *msg; 315 316 /* 317 * Make sure this is a reasonable open request. 318 */ 319 if (rc == NULL) 320 return ENXIO; 321 322 sc = rc->rc_rlc; 323 part = DISKPART(dev); 324 325 mutex_enter(&rc->rc_disk.dk_openlock); 326 327 /* 328 * If there are wedges, and this is not RAW_PART, then we 329 * need to fail. 330 */ 331 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) { 332 error = EBUSY; 333 goto bad1; 334 } 335 336 /* Check that the disk actually is useable */ 337 msg = rlstate(sc, rc->rc_hwid); 338 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] || 339 msg == rlstates[RLMP_SPUNDOWN]) { 340 error = ENXIO; 341 goto bad1; 342 } 343 /* 344 * If this is the first open; read in where on the disk we are. 345 */ 346 dl = rc->rc_disk.dk_label; 347 if (rc->rc_state == DK_CLOSED) { 348 u_int16_t mp; 349 int maj; 350 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 351 waitcrdy(sc); 352 mp = RL_RREG(RL_MP); 353 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 354 rc->rc_cyl = (mp >> 7) & 0777; 355 rc->rc_state = DK_OPEN; 356 /* Get disk label */ 357 maj = cdevsw_lookup_major(&rl_cdevsw); 358 if ((msg = readdisklabel(MAKEDISKDEV(maj, 359 device_unit(rc->rc_dev), RAW_PART), rlstrategy, dl, NULL))) 360 aprint_normal_dev(rc->rc_dev, "%s", msg); 361 aprint_normal_dev(rc->rc_dev, "size %d sectors\n", 362 dl->d_secperunit); 363 } 364 if (part >= dl->d_npartitions) { 365 error = ENXIO; 366 goto bad1; 367 } 368 369 mask = 1 << part; 370 switch (fmt) { 371 case S_IFCHR: 372 rc->rc_disk.dk_copenmask |= mask; 373 break; 374 case S_IFBLK: 375 rc->rc_disk.dk_bopenmask |= mask; 376 break; 377 } 378 rc->rc_disk.dk_openmask |= mask; 379 error = 0; 380 bad1: 381 mutex_exit(&rc->rc_disk.dk_openlock); 382 return (error); 383 } 384 385 int 386 rlclose(dev_t dev, int flag, int fmt, struct lwp *l) 387 { 388 int unit = DISKUNIT(dev); 389 struct rl_softc *rc = device_lookup_private(&rl_cd, unit); 390 int mask = (1 << DISKPART(dev)); 391 392 mutex_enter(&rc->rc_disk.dk_openlock); 393 394 switch (fmt) { 395 case S_IFCHR: 396 rc->rc_disk.dk_copenmask &= ~mask; 397 break; 398 case S_IFBLK: 399 rc->rc_disk.dk_bopenmask &= ~mask; 400 break; 401 } 402 rc->rc_disk.dk_openmask = 403 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask; 404 405 if (rc->rc_disk.dk_openmask == 0) 406 rc->rc_state = DK_CLOSED; /* May change pack */ 407 mutex_exit(&rc->rc_disk.dk_openlock); 408 return 0; 409 } 410 411 void 412 rlstrategy(struct buf *bp) 413 { 414 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 415 struct disklabel *lp; 416 int s; 417 418 if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */ 419 panic("rlstrategy: state impossible"); 420 421 lp = rc->rc_disk.dk_label; 422 if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0) 423 goto done; 424 425 if (bp->b_bcount == 0) 426 goto done; 427 428 bp->b_rawblkno = 429 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 430 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl; 431 432 s = splbio(); 433 bufq_put(rc->rc_rlc->sc_q, bp); 434 rlcstart(rc->rc_rlc, 0); 435 splx(s); 436 return; 437 438 done: biodone(bp); 439 } 440 441 int 442 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 443 { 444 struct rl_softc *rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 445 struct disklabel *lp = rc->rc_disk.dk_label; 446 int error; 447 #ifdef __HAVE_OLD_DISKLABEL 448 struct disklabel newlabel; 449 #endif 450 451 error = disk_ioctl(&rc->rc_disk, dev, cmd, addr, flag, l); 452 if (error != EPASSTHROUGH) 453 return error; 454 else 455 error = 0; 456 457 switch (cmd) { 458 case DIOCSDINFO: 459 case DIOCWDINFO: 460 #ifdef __HAVE_OLD_DISKLABEL 461 case ODIOCWDINFO: 462 case ODIOCSDINFO: 463 #endif 464 { 465 struct disklabel *tp; 466 467 #ifdef __HAVE_OLD_DISKLABEL 468 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 469 memset(&newlabel, 0, sizeof newlabel); 470 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 471 tp = &newlabel; 472 } else 473 #endif 474 tp = (struct disklabel *)addr; 475 476 if ((flag & FWRITE) == 0) 477 error = EBADF; 478 else { 479 mutex_enter(&rc->rc_disk.dk_openlock); 480 error = (( 481 #ifdef __HAVE_OLD_DISKLABEL 482 cmd == ODIOCSDINFO || 483 #endif 484 cmd == DIOCSDINFO) ? 485 setdisklabel(lp, tp, 0, 0) : 486 writedisklabel(dev, rlstrategy, lp, 0)); 487 mutex_exit(&rc->rc_disk.dk_openlock); 488 } 489 break; 490 } 491 492 case DIOCWLABEL: 493 if ((flag & FWRITE) == 0) 494 error = EBADF; 495 break; 496 497 default: 498 error = ENOTTY; 499 break; 500 } 501 return error; 502 } 503 504 int 505 rlpsize(dev_t dev) 506 { 507 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 508 struct disklabel *dl; 509 int size; 510 511 if (rc == NULL) 512 return -1; 513 dl = rc->rc_disk.dk_label; 514 size = dl->d_partitions[DISKPART(dev)].p_size * 515 (dl->d_secsize / DEV_BSIZE); 516 return size; 517 } 518 519 int 520 rldump(dev_t dev, daddr_t blkno, void *va, size_t size) 521 { 522 /* Not likely... */ 523 return 0; 524 } 525 526 int 527 rlread(dev_t dev, struct uio *uio, int ioflag) 528 { 529 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 530 } 531 532 int 533 rlwrite(dev_t dev, struct uio *uio, int ioflag) 534 { 535 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 536 } 537 538 static const char * const rlerr[] = { 539 "no", 540 "operation incomplete", 541 "read data CRC", 542 "header CRC", 543 "data late", 544 "header not found", 545 "", 546 "", 547 "non-existent memory", 548 "memory parity error", 549 "", 550 "", 551 "", 552 "", 553 "", 554 "", 555 }; 556 557 void 558 rlcintr(void *arg) 559 { 560 struct rlc_softc *sc = arg; 561 struct buf *bp; 562 u_int16_t cs; 563 564 bp = sc->sc_active; 565 if (bp == 0) { 566 aprint_error_dev(sc->sc_dev, "strange interrupt\n"); 567 return; 568 } 569 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 570 sc->sc_active = 0; 571 cs = RL_RREG(RL_CS); 572 if (cs & RLCS_ERR) { 573 int error = (cs & RLCS_ERRMSK) >> 10; 574 575 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]); 576 bp->b_error = EIO; 577 bp->b_resid = bp->b_bcount; 578 sc->sc_bytecnt = 0; 579 } 580 if (sc->sc_bytecnt == 0) /* Finished transfer */ 581 biodone(bp); 582 rlcstart(sc, sc->sc_bytecnt ? bp : 0); 583 } 584 585 /* 586 * Start routine. First position the disk to the given position, 587 * then start reading/writing. An optimization would be to be able 588 * to handle overlapping seeks between disks. 589 */ 590 void 591 rlcstart(struct rlc_softc *sc, struct buf *ob) 592 { 593 struct disklabel *lp; 594 struct rl_softc *rc; 595 struct buf *bp; 596 int bn, cn, sn, tn, blks, err; 597 598 if (sc->sc_active) 599 return; /* Already doing something */ 600 601 if (ob == 0) { 602 bp = bufq_get(sc->sc_q); 603 if (bp == NULL) 604 return; /* Nothing to do */ 605 sc->sc_bufaddr = bp->b_data; 606 sc->sc_diskblk = bp->b_rawblkno; 607 sc->sc_bytecnt = bp->b_bcount; 608 bp->b_resid = 0; 609 } else 610 bp = ob; 611 sc->sc_active = bp; 612 613 rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 614 bn = sc->sc_diskblk; 615 lp = rc->rc_disk.dk_label; 616 if (bn) { 617 cn = bn / lp->d_secpercyl; 618 sn = bn % lp->d_secpercyl; 619 tn = sn / lp->d_nsectors; 620 sn = sn % lp->d_nsectors; 621 } else 622 cn = sn = tn = 0; 623 624 /* 625 * Check if we have to position disk first. 626 */ 627 if (rc->rc_cyl != cn || rc->rc_head != tn) { 628 u_int16_t da = RLDA_SEEK; 629 if (cn > rc->rc_cyl) 630 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 631 else 632 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 633 if (tn) 634 da |= RLDA_HSSEEK; 635 waitcrdy(sc); 636 RL_WREG(RL_DA, da); 637 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 638 waitcrdy(sc); 639 rc->rc_cyl = cn; 640 rc->rc_head = tn; 641 } 642 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 643 blks = sc->sc_bytecnt/DEV_BSIZE; 644 645 if (sn + blks > RL_SPT/2) 646 blks = RL_SPT/2 - sn; 647 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 648 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 649 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0), 650 BUS_DMA_NOWAIT); 651 if (err) 652 panic("%s: bus_dmamap_load failed: %d", 653 device_xname(sc->sc_dev), err); 654 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 655 656 /* Count up vars */ 657 sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE); 658 sc->sc_diskblk += blks; 659 sc->sc_bytecnt -= (blks*DEV_BSIZE); 660 661 if (bp->b_flags & B_READ) 662 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 663 else 664 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 665 } 666 667 /* 668 * Called once per controller when an ubareset occurs. 669 * Retracts all disks and restarts active transfers. 670 */ 671 void 672 rlcreset(device_t dev) 673 { 674 struct rlc_softc *sc = device_private(dev); 675 struct rl_softc *rc; 676 int i; 677 u_int16_t mp; 678 679 for (i = 0; i < rl_cd.cd_ndevs; i++) { 680 if ((rc = device_lookup_private(&rl_cd, i)) == NULL) 681 continue; 682 if (rc->rc_state != DK_OPEN) 683 continue; 684 if (rc->rc_rlc != sc) 685 continue; 686 687 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 688 waitcrdy(sc); 689 mp = RL_RREG(RL_MP); 690 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 691 rc->rc_cyl = (mp >> 7) & 0777; 692 } 693 if (sc->sc_active == 0) 694 return; 695 696 bufq_put(sc->sc_q, sc->sc_active); 697 sc->sc_active = 0; 698 rlcstart(sc, 0); 699 } 700