1 /* $NetBSD: rl.c,v 1.45 2014/07/25 08:10:38 dholland 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.45 2014/07/25 08:10:38 dholland 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 = DTYPE_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 err = 0; 447 #ifdef __HAVE_OLD_DISKLABEL 448 struct disklabel newlabel; 449 #endif 450 451 switch (cmd) { 452 case DIOCGDINFO: 453 memcpy(addr, lp, sizeof (struct disklabel)); 454 break; 455 456 #ifdef __HAVE_OLD_DISKLABEL 457 case ODIOCGDINFO: 458 newlabel = *lp; 459 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 460 return ENOTTY; 461 memcpy(addr, &newlabel, sizeof (struct olddisklabel)); 462 break; 463 #endif 464 465 case DIOCGPART: 466 ((struct partinfo *)addr)->disklab = lp; 467 ((struct partinfo *)addr)->part = 468 &lp->d_partitions[DISKPART(dev)]; 469 break; 470 471 case DIOCSDINFO: 472 case DIOCWDINFO: 473 #ifdef __HAVE_OLD_DISKLABEL 474 case ODIOCWDINFO: 475 case ODIOCSDINFO: 476 #endif 477 { 478 struct disklabel *tp; 479 480 #ifdef __HAVE_OLD_DISKLABEL 481 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 482 memset(&newlabel, 0, sizeof newlabel); 483 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 484 tp = &newlabel; 485 } else 486 #endif 487 tp = (struct disklabel *)addr; 488 489 if ((flag & FWRITE) == 0) 490 err = EBADF; 491 else { 492 mutex_enter(&rc->rc_disk.dk_openlock); 493 err = (( 494 #ifdef __HAVE_OLD_DISKLABEL 495 cmd == ODIOCSDINFO || 496 #endif 497 cmd == DIOCSDINFO) ? 498 setdisklabel(lp, tp, 0, 0) : 499 writedisklabel(dev, rlstrategy, lp, 0)); 500 mutex_exit(&rc->rc_disk.dk_openlock); 501 } 502 break; 503 } 504 505 case DIOCWLABEL: 506 if ((flag & FWRITE) == 0) 507 err = EBADF; 508 break; 509 510 case DIOCAWEDGE: { 511 struct dkwedge_info *dkw = (void *) addr; 512 513 if ((flag & FWRITE) == 0) 514 return (EBADF); 515 516 /* If the ioctl happens here, the parent is us. */ 517 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev)); 518 return dkwedge_add(dkw); 519 } 520 521 case DIOCDWEDGE: { 522 struct dkwedge_info *dkw = (void *) addr; 523 524 if ((flag & FWRITE) == 0) 525 return (EBADF); 526 527 /* If the ioctl happens here, the parent is us. */ 528 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev)); 529 return dkwedge_del(dkw); 530 } 531 532 case DIOCLWEDGES: { 533 struct dkwedge_list *dkwl = (void *) addr; 534 535 return dkwedge_list(&rc->rc_disk, dkwl, l); 536 } 537 538 default: 539 err = ENOTTY; 540 break; 541 } 542 return err; 543 } 544 545 int 546 rlpsize(dev_t dev) 547 { 548 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 549 struct disklabel *dl; 550 int size; 551 552 if (rc == NULL) 553 return -1; 554 dl = rc->rc_disk.dk_label; 555 size = dl->d_partitions[DISKPART(dev)].p_size * 556 (dl->d_secsize / DEV_BSIZE); 557 return size; 558 } 559 560 int 561 rldump(dev_t dev, daddr_t blkno, void *va, size_t size) 562 { 563 /* Not likely... */ 564 return 0; 565 } 566 567 int 568 rlread(dev_t dev, struct uio *uio, int ioflag) 569 { 570 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 571 } 572 573 int 574 rlwrite(dev_t dev, struct uio *uio, int ioflag) 575 { 576 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 577 } 578 579 static const char * const rlerr[] = { 580 "no", 581 "operation incomplete", 582 "read data CRC", 583 "header CRC", 584 "data late", 585 "header not found", 586 "", 587 "", 588 "non-existent memory", 589 "memory parity error", 590 "", 591 "", 592 "", 593 "", 594 "", 595 "", 596 }; 597 598 void 599 rlcintr(void *arg) 600 { 601 struct rlc_softc *sc = arg; 602 struct buf *bp; 603 u_int16_t cs; 604 605 bp = sc->sc_active; 606 if (bp == 0) { 607 aprint_error_dev(sc->sc_dev, "strange interrupt\n"); 608 return; 609 } 610 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 611 sc->sc_active = 0; 612 cs = RL_RREG(RL_CS); 613 if (cs & RLCS_ERR) { 614 int error = (cs & RLCS_ERRMSK) >> 10; 615 616 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]); 617 bp->b_error = EIO; 618 bp->b_resid = bp->b_bcount; 619 sc->sc_bytecnt = 0; 620 } 621 if (sc->sc_bytecnt == 0) /* Finished transfer */ 622 biodone(bp); 623 rlcstart(sc, sc->sc_bytecnt ? bp : 0); 624 } 625 626 /* 627 * Start routine. First position the disk to the given position, 628 * then start reading/writing. An optimization would be to be able 629 * to handle overlapping seeks between disks. 630 */ 631 void 632 rlcstart(struct rlc_softc *sc, struct buf *ob) 633 { 634 struct disklabel *lp; 635 struct rl_softc *rc; 636 struct buf *bp; 637 int bn, cn, sn, tn, blks, err; 638 639 if (sc->sc_active) 640 return; /* Already doing something */ 641 642 if (ob == 0) { 643 bp = bufq_get(sc->sc_q); 644 if (bp == NULL) 645 return; /* Nothing to do */ 646 sc->sc_bufaddr = bp->b_data; 647 sc->sc_diskblk = bp->b_rawblkno; 648 sc->sc_bytecnt = bp->b_bcount; 649 bp->b_resid = 0; 650 } else 651 bp = ob; 652 sc->sc_active = bp; 653 654 rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 655 bn = sc->sc_diskblk; 656 lp = rc->rc_disk.dk_label; 657 if (bn) { 658 cn = bn / lp->d_secpercyl; 659 sn = bn % lp->d_secpercyl; 660 tn = sn / lp->d_nsectors; 661 sn = sn % lp->d_nsectors; 662 } else 663 cn = sn = tn = 0; 664 665 /* 666 * Check if we have to position disk first. 667 */ 668 if (rc->rc_cyl != cn || rc->rc_head != tn) { 669 u_int16_t da = RLDA_SEEK; 670 if (cn > rc->rc_cyl) 671 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 672 else 673 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 674 if (tn) 675 da |= RLDA_HSSEEK; 676 waitcrdy(sc); 677 RL_WREG(RL_DA, da); 678 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 679 waitcrdy(sc); 680 rc->rc_cyl = cn; 681 rc->rc_head = tn; 682 } 683 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 684 blks = sc->sc_bytecnt/DEV_BSIZE; 685 686 if (sn + blks > RL_SPT/2) 687 blks = RL_SPT/2 - sn; 688 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 689 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 690 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0), 691 BUS_DMA_NOWAIT); 692 if (err) 693 panic("%s: bus_dmamap_load failed: %d", 694 device_xname(sc->sc_dev), err); 695 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 696 697 /* Count up vars */ 698 sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE); 699 sc->sc_diskblk += blks; 700 sc->sc_bytecnt -= (blks*DEV_BSIZE); 701 702 if (bp->b_flags & B_READ) 703 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 704 else 705 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 706 } 707 708 /* 709 * Called once per controller when an ubareset occurs. 710 * Retracts all disks and restarts active transfers. 711 */ 712 void 713 rlcreset(device_t dev) 714 { 715 struct rlc_softc *sc = device_private(dev); 716 struct rl_softc *rc; 717 int i; 718 u_int16_t mp; 719 720 for (i = 0; i < rl_cd.cd_ndevs; i++) { 721 if ((rc = device_lookup_private(&rl_cd, i)) == NULL) 722 continue; 723 if (rc->rc_state != DK_OPEN) 724 continue; 725 if (rc->rc_rlc != sc) 726 continue; 727 728 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 729 waitcrdy(sc); 730 mp = RL_RREG(RL_MP); 731 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 732 rc->rc_cyl = (mp >> 7) & 0777; 733 } 734 if (sc->sc_active == 0) 735 return; 736 737 bufq_put(sc->sc_q, sc->sc_active); 738 sc->sc_active = 0; 739 rlcstart(sc, 0); 740 } 741