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