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