1 /* $NetBSD: rl.c,v 1.43 2014/03/16 05:20:29 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.43 2014/03/16 05:20:29 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_flag = D_DISK 106 }; 107 108 const struct cdevsw rl_cdevsw = { 109 .d_open = rlopen, 110 .d_close = rlclose, 111 .d_read = rlread, 112 .d_write = rlwrite, 113 .d_ioctl = rlioctl, 114 .d_stop = nostop, 115 .d_tty = notty, 116 .d_poll = nopoll, 117 .d_mmap = nommap, 118 .d_kqfilter = nokqfilter, 119 .d_flag = D_DISK 120 }; 121 122 #define MAXRLXFER (RL_BPS * RL_SPT) 123 124 #define RL_WREG(reg, val) \ 125 bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val)) 126 #define RL_RREG(reg) \ 127 bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg)) 128 129 static const char * const rlstates[] = { 130 "drive not loaded", 131 "drive spinning up", 132 "drive brushes out", 133 "drive loading heads", 134 "drive seeking", 135 "drive ready", 136 "drive unloading heads", 137 "drive spun down", 138 }; 139 140 static const struct dkdriver rldkdriver = { 141 rlstrategy, minphys 142 }; 143 144 static const char * 145 rlstate(struct rlc_softc *sc, int unit) 146 { 147 int i = 0; 148 149 do { 150 RL_WREG(RL_DA, RLDA_GS); 151 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT)); 152 waitcrdy(sc); 153 } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10); 154 if (i == 10) 155 return NULL; 156 i = RL_RREG(RL_MP) & RLMP_STATUS; 157 return rlstates[i]; 158 } 159 160 void 161 waitcrdy(struct rlc_softc *sc) 162 { 163 int i; 164 165 for (i = 0; i < 1000; i++) { 166 DELAY(10000); 167 if (RL_RREG(RL_CS) & RLCS_CRDY) 168 return; 169 } 170 aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */ 171 } 172 173 int 174 rlcprint(void *aux, const char *name) 175 { 176 struct rlc_attach_args *ra = aux; 177 178 if (name) 179 aprint_normal("RL0%d at %s", 180 ra->type & RLMP_DT ? '2' : '1', name); 181 aprint_normal(" drive %d", ra->hwid); 182 return UNCONF; 183 } 184 185 /* 186 * Force the controller to interrupt. 187 */ 188 int 189 rlcmatch(device_t parent, cfdata_t cf, void *aux) 190 { 191 struct uba_attach_args *ua = aux; 192 struct rlc_softc ssc, *sc = &ssc; 193 int i; 194 195 sc->sc_iot = ua->ua_iot; 196 sc->sc_ioh = ua->ua_ioh; 197 /* Force interrupt by issuing a "Get Status" command */ 198 RL_WREG(RL_DA, RLDA_GS); 199 RL_WREG(RL_CS, RLCS_GS|RLCS_IE); 200 201 for (i = 0; i < 100; i++) { 202 DELAY(100000); 203 if (RL_RREG(RL_CS) & RLCS_CRDY) 204 return 1; 205 } 206 return 0; 207 } 208 209 void 210 rlcattach(device_t parent, device_t self, void *aux) 211 { 212 struct rlc_softc *sc = device_private(self); 213 struct uba_attach_args *ua = aux; 214 struct rlc_attach_args ra; 215 int i, error; 216 217 sc->sc_dev = self; 218 sc->sc_uh = device_private(parent); 219 sc->sc_iot = ua->ua_iot; 220 sc->sc_ioh = ua->ua_ioh; 221 sc->sc_dmat = ua->ua_dmat; 222 uba_intr_establish(ua->ua_icookie, ua->ua_cvec, 223 rlcintr, sc, &sc->sc_intrcnt); 224 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt, 225 device_xname(sc->sc_dev), "intr"); 226 uba_reset_establish(rlcreset, self); 227 228 printf("\n"); 229 230 /* 231 * The RL11 can only have one transfer going at a time, 232 * and max transfer size is one track, so only one dmamap 233 * is needed. 234 */ 235 error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0, 236 BUS_DMA_ALLOCNOW, &sc->sc_dmam); 237 if (error) { 238 aprint_error(": Failed to allocate DMA map, error %d\n", error); 239 return; 240 } 241 bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER); 242 for (i = 0; i < RL_MAXDPC; i++) { 243 waitcrdy(sc); 244 RL_WREG(RL_DA, RLDA_GS|RLDA_RST); 245 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT)); 246 waitcrdy(sc); 247 ra.type = RL_RREG(RL_MP); 248 ra.hwid = i; 249 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0) 250 config_found(sc->sc_dev, &ra, rlcprint); 251 } 252 } 253 254 int 255 rlmatch(device_t parent, cfdata_t cf, void *aux) 256 { 257 struct rlc_attach_args *ra = aux; 258 259 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT && 260 cf->cf_loc[RLCCF_DRIVE] != ra->hwid) 261 return 0; 262 return 1; 263 } 264 265 void 266 rlattach(device_t parent, device_t self, void *aux) 267 { 268 struct rl_softc *rc = device_private(self); 269 struct rlc_attach_args *ra = aux; 270 struct disklabel *dl; 271 272 rc->rc_dev = self; 273 rc->rc_rlc = device_private(parent); 274 rc->rc_hwid = ra->hwid; 275 disk_init(&rc->rc_disk, device_xname(rc->rc_dev), &rldkdriver); 276 disk_attach(&rc->rc_disk); 277 dl = rc->rc_disk.dk_label; 278 dl->d_npartitions = 3; 279 strcpy(dl->d_typename, "RL01"); 280 if (ra->type & RLMP_DT) 281 dl->d_typename[3] = '2'; 282 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */ 283 dl->d_nsectors = RL_SPT/2; 284 dl->d_ntracks = RL_SPD; 285 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01; 286 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 287 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl; 288 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 289 dl->d_secperunit; 290 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 291 dl->d_interleave = dl->d_headswitch = 1; 292 dl->d_bbsize = BBSIZE; 293 dl->d_sbsize = SBLOCKSIZE; 294 dl->d_rpm = 2400; 295 dl->d_type = DTYPE_DEC; 296 printf(": %s, %s\n", dl->d_typename, rlstate(rc->rc_rlc, ra->hwid)); 297 298 /* 299 * XXX We should try to discovery wedges here, but 300 * XXX that would mean loading up the pack and being 301 * XXX able to do I/O. Should use config_defer() here. 302 */ 303 } 304 305 int 306 rlopen(dev_t dev, int flag, int fmt, struct lwp *l) 307 { 308 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 309 struct rlc_softc *sc; 310 int error, part, mask; 311 struct disklabel *dl; 312 const char *msg; 313 314 /* 315 * Make sure this is a reasonable open request. 316 */ 317 if (rc == NULL) 318 return ENXIO; 319 320 sc = rc->rc_rlc; 321 part = DISKPART(dev); 322 323 mutex_enter(&rc->rc_disk.dk_openlock); 324 325 /* 326 * If there are wedges, and this is not RAW_PART, then we 327 * need to fail. 328 */ 329 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) { 330 error = EBUSY; 331 goto bad1; 332 } 333 334 /* Check that the disk actually is useable */ 335 msg = rlstate(sc, rc->rc_hwid); 336 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] || 337 msg == rlstates[RLMP_SPUNDOWN]) { 338 error = ENXIO; 339 goto bad1; 340 } 341 /* 342 * If this is the first open; read in where on the disk we are. 343 */ 344 dl = rc->rc_disk.dk_label; 345 if (rc->rc_state == DK_CLOSED) { 346 u_int16_t mp; 347 int maj; 348 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 349 waitcrdy(sc); 350 mp = RL_RREG(RL_MP); 351 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 352 rc->rc_cyl = (mp >> 7) & 0777; 353 rc->rc_state = DK_OPEN; 354 /* Get disk label */ 355 maj = cdevsw_lookup_major(&rl_cdevsw); 356 if ((msg = readdisklabel(MAKEDISKDEV(maj, 357 device_unit(rc->rc_dev), RAW_PART), rlstrategy, dl, NULL))) 358 aprint_normal_dev(rc->rc_dev, "%s", msg); 359 aprint_normal_dev(rc->rc_dev, "size %d sectors\n", 360 dl->d_secperunit); 361 } 362 if (part >= dl->d_npartitions) { 363 error = ENXIO; 364 goto bad1; 365 } 366 367 mask = 1 << part; 368 switch (fmt) { 369 case S_IFCHR: 370 rc->rc_disk.dk_copenmask |= mask; 371 break; 372 case S_IFBLK: 373 rc->rc_disk.dk_bopenmask |= mask; 374 break; 375 } 376 rc->rc_disk.dk_openmask |= mask; 377 error = 0; 378 bad1: 379 mutex_exit(&rc->rc_disk.dk_openlock); 380 return (error); 381 } 382 383 int 384 rlclose(dev_t dev, int flag, int fmt, struct lwp *l) 385 { 386 int unit = DISKUNIT(dev); 387 struct rl_softc *rc = device_lookup_private(&rl_cd, unit); 388 int mask = (1 << DISKPART(dev)); 389 390 mutex_enter(&rc->rc_disk.dk_openlock); 391 392 switch (fmt) { 393 case S_IFCHR: 394 rc->rc_disk.dk_copenmask &= ~mask; 395 break; 396 case S_IFBLK: 397 rc->rc_disk.dk_bopenmask &= ~mask; 398 break; 399 } 400 rc->rc_disk.dk_openmask = 401 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask; 402 403 if (rc->rc_disk.dk_openmask == 0) 404 rc->rc_state = DK_CLOSED; /* May change pack */ 405 mutex_exit(&rc->rc_disk.dk_openlock); 406 return 0; 407 } 408 409 void 410 rlstrategy(struct buf *bp) 411 { 412 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 413 struct disklabel *lp; 414 int s; 415 416 if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */ 417 panic("rlstrategy: state impossible"); 418 419 lp = rc->rc_disk.dk_label; 420 if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0) 421 goto done; 422 423 if (bp->b_bcount == 0) 424 goto done; 425 426 bp->b_rawblkno = 427 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 428 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl; 429 430 s = splbio(); 431 bufq_put(rc->rc_rlc->sc_q, bp); 432 rlcstart(rc->rc_rlc, 0); 433 splx(s); 434 return; 435 436 done: biodone(bp); 437 } 438 439 int 440 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 441 { 442 struct rl_softc *rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 443 struct disklabel *lp = rc->rc_disk.dk_label; 444 int err = 0; 445 #ifdef __HAVE_OLD_DISKLABEL 446 struct disklabel newlabel; 447 #endif 448 449 switch (cmd) { 450 case DIOCGDINFO: 451 memcpy(addr, lp, sizeof (struct disklabel)); 452 break; 453 454 #ifdef __HAVE_OLD_DISKLABEL 455 case ODIOCGDINFO: 456 newlabel = *lp; 457 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 458 return ENOTTY; 459 memcpy(addr, &newlabel, sizeof (struct olddisklabel)); 460 break; 461 #endif 462 463 case DIOCGPART: 464 ((struct partinfo *)addr)->disklab = lp; 465 ((struct partinfo *)addr)->part = 466 &lp->d_partitions[DISKPART(dev)]; 467 break; 468 469 case DIOCSDINFO: 470 case DIOCWDINFO: 471 #ifdef __HAVE_OLD_DISKLABEL 472 case ODIOCWDINFO: 473 case ODIOCSDINFO: 474 #endif 475 { 476 struct disklabel *tp; 477 478 #ifdef __HAVE_OLD_DISKLABEL 479 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 480 memset(&newlabel, 0, sizeof newlabel); 481 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 482 tp = &newlabel; 483 } else 484 #endif 485 tp = (struct disklabel *)addr; 486 487 if ((flag & FWRITE) == 0) 488 err = EBADF; 489 else { 490 mutex_enter(&rc->rc_disk.dk_openlock); 491 err = (( 492 #ifdef __HAVE_OLD_DISKLABEL 493 cmd == ODIOCSDINFO || 494 #endif 495 cmd == DIOCSDINFO) ? 496 setdisklabel(lp, tp, 0, 0) : 497 writedisklabel(dev, rlstrategy, lp, 0)); 498 mutex_exit(&rc->rc_disk.dk_openlock); 499 } 500 break; 501 } 502 503 case DIOCWLABEL: 504 if ((flag & FWRITE) == 0) 505 err = EBADF; 506 break; 507 508 case DIOCAWEDGE: { 509 struct dkwedge_info *dkw = (void *) addr; 510 511 if ((flag & FWRITE) == 0) 512 return (EBADF); 513 514 /* If the ioctl happens here, the parent is us. */ 515 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev)); 516 return dkwedge_add(dkw); 517 } 518 519 case DIOCDWEDGE: { 520 struct dkwedge_info *dkw = (void *) addr; 521 522 if ((flag & FWRITE) == 0) 523 return (EBADF); 524 525 /* If the ioctl happens here, the parent is us. */ 526 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev)); 527 return dkwedge_del(dkw); 528 } 529 530 case DIOCLWEDGES: { 531 struct dkwedge_list *dkwl = (void *) addr; 532 533 return dkwedge_list(&rc->rc_disk, dkwl, l); 534 } 535 536 default: 537 err = ENOTTY; 538 break; 539 } 540 return err; 541 } 542 543 int 544 rlpsize(dev_t dev) 545 { 546 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 547 struct disklabel *dl; 548 int size; 549 550 if (rc == NULL) 551 return -1; 552 dl = rc->rc_disk.dk_label; 553 size = dl->d_partitions[DISKPART(dev)].p_size * 554 (dl->d_secsize / DEV_BSIZE); 555 return size; 556 } 557 558 int 559 rldump(dev_t dev, daddr_t blkno, void *va, size_t size) 560 { 561 /* Not likely... */ 562 return 0; 563 } 564 565 int 566 rlread(dev_t dev, struct uio *uio, int ioflag) 567 { 568 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 569 } 570 571 int 572 rlwrite(dev_t dev, struct uio *uio, int ioflag) 573 { 574 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 575 } 576 577 static const char * const rlerr[] = { 578 "no", 579 "operation incomplete", 580 "read data CRC", 581 "header CRC", 582 "data late", 583 "header not found", 584 "", 585 "", 586 "non-existent memory", 587 "memory parity error", 588 "", 589 "", 590 "", 591 "", 592 "", 593 "", 594 }; 595 596 void 597 rlcintr(void *arg) 598 { 599 struct rlc_softc *sc = arg; 600 struct buf *bp; 601 u_int16_t cs; 602 603 bp = sc->sc_active; 604 if (bp == 0) { 605 aprint_error_dev(sc->sc_dev, "strange interrupt\n"); 606 return; 607 } 608 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 609 sc->sc_active = 0; 610 cs = RL_RREG(RL_CS); 611 if (cs & RLCS_ERR) { 612 int error = (cs & RLCS_ERRMSK) >> 10; 613 614 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]); 615 bp->b_error = EIO; 616 bp->b_resid = bp->b_bcount; 617 sc->sc_bytecnt = 0; 618 } 619 if (sc->sc_bytecnt == 0) /* Finished transfer */ 620 biodone(bp); 621 rlcstart(sc, sc->sc_bytecnt ? bp : 0); 622 } 623 624 /* 625 * Start routine. First position the disk to the given position, 626 * then start reading/writing. An optimization would be to be able 627 * to handle overlapping seeks between disks. 628 */ 629 void 630 rlcstart(struct rlc_softc *sc, struct buf *ob) 631 { 632 struct disklabel *lp; 633 struct rl_softc *rc; 634 struct buf *bp; 635 int bn, cn, sn, tn, blks, err; 636 637 if (sc->sc_active) 638 return; /* Already doing something */ 639 640 if (ob == 0) { 641 bp = bufq_get(sc->sc_q); 642 if (bp == NULL) 643 return; /* Nothing to do */ 644 sc->sc_bufaddr = bp->b_data; 645 sc->sc_diskblk = bp->b_rawblkno; 646 sc->sc_bytecnt = bp->b_bcount; 647 bp->b_resid = 0; 648 } else 649 bp = ob; 650 sc->sc_active = bp; 651 652 rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 653 bn = sc->sc_diskblk; 654 lp = rc->rc_disk.dk_label; 655 if (bn) { 656 cn = bn / lp->d_secpercyl; 657 sn = bn % lp->d_secpercyl; 658 tn = sn / lp->d_nsectors; 659 sn = sn % lp->d_nsectors; 660 } else 661 cn = sn = tn = 0; 662 663 /* 664 * Check if we have to position disk first. 665 */ 666 if (rc->rc_cyl != cn || rc->rc_head != tn) { 667 u_int16_t da = RLDA_SEEK; 668 if (cn > rc->rc_cyl) 669 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 670 else 671 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 672 if (tn) 673 da |= RLDA_HSSEEK; 674 waitcrdy(sc); 675 RL_WREG(RL_DA, da); 676 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 677 waitcrdy(sc); 678 rc->rc_cyl = cn; 679 rc->rc_head = tn; 680 } 681 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 682 blks = sc->sc_bytecnt/DEV_BSIZE; 683 684 if (sn + blks > RL_SPT/2) 685 blks = RL_SPT/2 - sn; 686 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 687 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 688 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0), 689 BUS_DMA_NOWAIT); 690 if (err) 691 panic("%s: bus_dmamap_load failed: %d", 692 device_xname(sc->sc_dev), err); 693 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 694 695 /* Count up vars */ 696 sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE); 697 sc->sc_diskblk += blks; 698 sc->sc_bytecnt -= (blks*DEV_BSIZE); 699 700 if (bp->b_flags & B_READ) 701 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 702 else 703 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 704 } 705 706 /* 707 * Called once per controller when an ubareset occurs. 708 * Retracts all disks and restarts active transfers. 709 */ 710 void 711 rlcreset(device_t dev) 712 { 713 struct rlc_softc *sc = device_private(dev); 714 struct rl_softc *rc; 715 int i; 716 u_int16_t mp; 717 718 for (i = 0; i < rl_cd.cd_ndevs; i++) { 719 if ((rc = device_lookup_private(&rl_cd, i)) == NULL) 720 continue; 721 if (rc->rc_state != DK_OPEN) 722 continue; 723 if (rc->rc_rlc != sc) 724 continue; 725 726 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 727 waitcrdy(sc); 728 mp = RL_RREG(RL_MP); 729 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 730 rc->rc_cyl = (mp >> 7) & 0777; 731 } 732 if (sc->sc_active == 0) 733 return; 734 735 bufq_put(sc->sc_q, sc->sc_active); 736 sc->sc_active = 0; 737 rlcstart(sc, 0); 738 } 739