1 /* $NetBSD: rl.c,v 1.23 2004/10/28 07:07:41 yamt 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.23 2004/10/28 07:07:41 yamt 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 <machine/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 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 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 = (struct rlc_softc *)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, BUFQ_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 = (struct rl_softc *)self; 252 struct rlc_attach_args *ra = aux; 253 struct disklabel *dl; 254 255 rc->rc_hwid = ra->hwid; 256 rc->rc_disk.dk_name = rc->rc_dev.dv_xname; 257 rc->rc_disk.dk_driver = &rldkdriver; 258 disk_attach(&rc->rc_disk); 259 dl = rc->rc_disk.dk_label; 260 dl->d_npartitions = 3; 261 strcpy(dl->d_typename, "RL01"); 262 if (ra->type & RLMP_DT) 263 dl->d_typename[3] = '2'; 264 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */ 265 dl->d_nsectors = RL_SPT/2; 266 dl->d_ntracks = RL_SPD; 267 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01; 268 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 269 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl; 270 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 271 dl->d_secperunit; 272 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 273 dl->d_interleave = dl->d_headswitch = 1; 274 dl->d_bbsize = BBSIZE; 275 dl->d_sbsize = SBLOCKSIZE; 276 dl->d_rpm = 2400; 277 dl->d_type = DTYPE_DEC; 278 printf(": %s, %s\n", dl->d_typename, 279 rlstate((struct rlc_softc *)parent, ra->hwid)); 280 281 /* 282 * XXX We should try to discovery wedges here, but 283 * XXX that would mean loading up the pack and being 284 * XXX able to do I/O. Should use config_defer() here. 285 */ 286 } 287 288 int 289 rlopen(dev_t dev, int flag, int fmt, struct proc *p) 290 { 291 int error, part, unit, mask; 292 struct disklabel *dl; 293 struct rlc_softc *sc; 294 struct rl_softc *rc; 295 const char *msg; 296 297 /* 298 * Make sure this is a reasonable open request. 299 */ 300 unit = DISKUNIT(dev); 301 if (unit >= rl_cd.cd_ndevs) 302 return ENXIO; 303 rc = rl_cd.cd_devs[unit]; 304 if (rc == 0) 305 return ENXIO; 306 307 part = DISKPART(dev); 308 309 if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE, 310 NULL)) != 0) 311 return (error); 312 313 /* 314 * If there are wedges, and this is not RAW_PART, then we 315 * need to fail. 316 */ 317 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) { 318 error = EBUSY; 319 goto bad1; 320 } 321 322 sc = (struct rlc_softc *)rc->rc_dev.dv_parent; 323 /* Check that the disk actually is useable */ 324 msg = rlstate(sc, rc->rc_hwid); 325 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] || 326 msg == rlstates[RLMP_SPUNDOWN]) { 327 error = ENXIO; 328 goto bad1; 329 } 330 /* 331 * If this is the first open; read in where on the disk we are. 332 */ 333 dl = rc->rc_disk.dk_label; 334 if (rc->rc_state == DK_CLOSED) { 335 u_int16_t mp; 336 int maj; 337 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 338 waitcrdy(sc); 339 mp = RL_RREG(RL_MP); 340 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 341 rc->rc_cyl = (mp >> 7) & 0777; 342 rc->rc_state = DK_OPEN; 343 /* Get disk label */ 344 printf("%s: ", rc->rc_dev.dv_xname); 345 maj = cdevsw_lookup_major(&rl_cdevsw); 346 if ((msg = readdisklabel(MAKEDISKDEV(maj, 347 rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL))) 348 printf("%s: ", msg); 349 printf("size %d sectors\n", dl->d_secperunit); 350 } 351 if (part >= dl->d_npartitions) { 352 error = ENXIO; 353 goto bad1; 354 } 355 356 mask = 1 << part; 357 switch (fmt) { 358 case S_IFCHR: 359 rc->rc_disk.dk_copenmask |= mask; 360 break; 361 case S_IFBLK: 362 rc->rc_disk.dk_bopenmask |= mask; 363 break; 364 } 365 rc->rc_disk.dk_openmask |= mask; 366 (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL); 367 return 0; 368 369 bad1: 370 (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL); 371 return (error); 372 } 373 374 int 375 rlclose(dev_t dev, int flag, int fmt, struct proc *p) 376 { 377 int error, unit = DISKUNIT(dev); 378 struct rl_softc *rc = rl_cd.cd_devs[unit]; 379 int mask = (1 << DISKPART(dev)); 380 381 if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE, 382 NULL)) != 0) 383 return (error); 384 385 switch (fmt) { 386 case S_IFCHR: 387 rc->rc_disk.dk_copenmask &= ~mask; 388 break; 389 case S_IFBLK: 390 rc->rc_disk.dk_bopenmask &= ~mask; 391 break; 392 } 393 rc->rc_disk.dk_openmask = 394 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask; 395 396 if (rc->rc_disk.dk_openmask == 0) 397 rc->rc_state = DK_CLOSED; /* May change pack */ 398 (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL); 399 return 0; 400 } 401 402 void 403 rlstrategy(struct buf *bp) 404 { 405 struct disklabel *lp; 406 struct rlc_softc *sc; 407 struct rl_softc *rc; 408 int unit, s, err; 409 /* 410 * Make sure this is a reasonable drive to use. 411 */ 412 unit = DISKUNIT(bp->b_dev); 413 if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) { 414 bp->b_error = ENXIO; 415 bp->b_flags |= B_ERROR; 416 goto done; 417 } 418 if (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 ((err = 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 sc = (struct rlc_softc *)rc->rc_dev.dv_parent; 432 433 s = splbio(); 434 BUFQ_PUT(&sc->sc_q, bp); 435 rlcstart(sc, 0); 436 splx(s); 437 return; 438 439 done: biodone(bp); 440 } 441 442 int 443 rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 444 { 445 struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)]; 446 struct disklabel *lp = rc->rc_disk.dk_label; 447 int err = 0; 448 #ifdef __HAVE_OLD_DISKLABEL 449 struct disklabel newlabel; 450 #endif 451 452 switch (cmd) { 453 case DIOCGDINFO: 454 bcopy(lp, addr, sizeof (struct disklabel)); 455 break; 456 457 #ifdef __HAVE_OLD_DISKLABEL 458 case ODIOCGDINFO: 459 newlabel = *lp; 460 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 461 return ENOTTY; 462 bcopy(&newlabel, addr, sizeof (struct olddisklabel)); 463 break; 464 #endif 465 466 case DIOCGPART: 467 ((struct partinfo *)addr)->disklab = lp; 468 ((struct partinfo *)addr)->part = 469 &lp->d_partitions[DISKPART(dev)]; 470 break; 471 472 case DIOCSDINFO: 473 case DIOCWDINFO: 474 #ifdef __HAVE_OLD_DISKLABEL 475 case ODIOCWDINFO: 476 case ODIOCSDINFO: 477 #endif 478 { 479 struct disklabel *tp; 480 481 #ifdef __HAVE_OLD_DISKLABEL 482 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 483 memset(&newlabel, 0, sizeof newlabel); 484 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 485 tp = &newlabel; 486 } else 487 #endif 488 tp = (struct disklabel *)addr; 489 490 if ((flag & FWRITE) == 0) 491 err = EBADF; 492 else { 493 if ((err = lockmgr(&rc->rc_disk.dk_openlock, 494 LK_EXCLUSIVE, NULL)) != 0) 495 break; 496 err = (( 497 #ifdef __HAVE_OLD_DISKLABEL 498 cmd == ODIOCSDINFO || 499 #endif 500 cmd == DIOCSDINFO) ? 501 setdisklabel(lp, tp, 0, 0) : 502 writedisklabel(dev, rlstrategy, lp, 0)); 503 (void) lockmgr(&rc->rc_disk.dk_openlock, 504 LK_RELEASE, NULL); 505 } 506 break; 507 } 508 509 case DIOCWLABEL: 510 if ((flag & FWRITE) == 0) 511 err = EBADF; 512 break; 513 514 case DIOCAWEDGE: 515 { 516 struct dkwedge_info *dkw = (void *) addr; 517 518 if ((flag & FWRITE) == 0) 519 return (EBADF); 520 521 /* If the ioctl happens here, the parent is us. */ 522 strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname); 523 return (dkwedge_add(dkw)); 524 } 525 526 case DIOCDWEDGE: 527 { 528 struct dkwedge_info *dkw = (void *) addr; 529 530 if ((flag & FWRITE) == 0) 531 return (EBADF); 532 533 /* If the ioctl happens here, the parent is us. */ 534 strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname); 535 return (dkwedge_del(dkw)); 536 } 537 538 case DIOCLWEDGES: 539 { 540 struct dkwedge_list *dkwl = (void *) addr; 541 542 return (dkwedge_list(&rc->rc_disk, dkwl, p)); 543 } 544 545 default: 546 err = ENOTTY; 547 } 548 return err; 549 } 550 551 int 552 rlsize(dev_t dev) 553 { 554 struct disklabel *dl; 555 struct rl_softc *rc; 556 int size, unit = DISKUNIT(dev); 557 558 if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0)) 559 return -1; 560 dl = rc->rc_disk.dk_label; 561 size = dl->d_partitions[DISKPART(dev)].p_size * 562 (dl->d_secsize / DEV_BSIZE); 563 return size; 564 } 565 566 int 567 rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 568 { 569 /* Not likely... */ 570 return 0; 571 } 572 573 int 574 rlread(dev_t dev, struct uio *uio, int ioflag) 575 { 576 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 577 } 578 579 int 580 rlwrite(dev_t dev, struct uio *uio, int ioflag) 581 { 582 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 583 } 584 585 static char *rlerr[] = { 586 "no", 587 "operation incomplete", 588 "read data CRC", 589 "header CRC", 590 "data late", 591 "header not found", 592 "", 593 "", 594 "non-existent memory", 595 "memory parity error", 596 "", 597 "", 598 "", 599 "", 600 "", 601 "", 602 }; 603 604 void 605 rlcintr(void *arg) 606 { 607 struct rlc_softc *sc = arg; 608 struct buf *bp; 609 u_int16_t cs; 610 611 bp = sc->sc_active; 612 if (bp == 0) { 613 printf("%s: strange interrupt\n", sc->sc_dev.dv_xname); 614 return; 615 } 616 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 617 sc->sc_active = 0; 618 cs = RL_RREG(RL_CS); 619 if (cs & RLCS_ERR) { 620 int error = (cs & RLCS_ERRMSK) >> 10; 621 622 printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]); 623 bp->b_flags |= B_ERROR; 624 bp->b_error = EIO; 625 bp->b_resid = bp->b_bcount; 626 sc->sc_bytecnt = 0; 627 } 628 if (sc->sc_bytecnt == 0) /* Finished transfer */ 629 biodone(bp); 630 rlcstart(sc, sc->sc_bytecnt ? bp : 0); 631 } 632 633 /* 634 * Start routine. First position the disk to the given position, 635 * then start reading/writing. An optimization would be to be able 636 * to handle overlapping seeks between disks. 637 */ 638 void 639 rlcstart(struct rlc_softc *sc, struct buf *ob) 640 { 641 struct disklabel *lp; 642 struct rl_softc *rc; 643 struct buf *bp; 644 int bn, cn, sn, tn, blks, err; 645 646 if (sc->sc_active) 647 return; /* Already doing something */ 648 649 if (ob == 0) { 650 bp = BUFQ_GET(&sc->sc_q); 651 if (bp == NULL) 652 return; /* Nothing to do */ 653 sc->sc_bufaddr = bp->b_data; 654 sc->sc_diskblk = bp->b_rawblkno; 655 sc->sc_bytecnt = bp->b_bcount; 656 bp->b_resid = 0; 657 } else 658 bp = ob; 659 sc->sc_active = bp; 660 661 rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)]; 662 bn = sc->sc_diskblk; 663 lp = rc->rc_disk.dk_label; 664 if (bn) { 665 cn = bn / lp->d_secpercyl; 666 sn = bn % lp->d_secpercyl; 667 tn = sn / lp->d_nsectors; 668 sn = sn % lp->d_nsectors; 669 } else 670 cn = sn = tn = 0; 671 672 /* 673 * Check if we have to position disk first. 674 */ 675 if (rc->rc_cyl != cn || rc->rc_head != tn) { 676 u_int16_t da = RLDA_SEEK; 677 if (cn > rc->rc_cyl) 678 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 679 else 680 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 681 if (tn) 682 da |= RLDA_HSSEEK; 683 waitcrdy(sc); 684 RL_WREG(RL_DA, da); 685 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 686 waitcrdy(sc); 687 rc->rc_cyl = cn; 688 rc->rc_head = tn; 689 } 690 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 691 blks = sc->sc_bytecnt/DEV_BSIZE; 692 693 if (sn + blks > RL_SPT/2) 694 blks = RL_SPT/2 - sn; 695 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 696 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 697 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0), 698 BUS_DMA_NOWAIT); 699 if (err) 700 panic("%s: bus_dmamap_load failed: %d", 701 sc->sc_dev.dv_xname, err); 702 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 703 704 /* Count up vars */ 705 sc->sc_bufaddr += (blks*DEV_BSIZE); 706 sc->sc_diskblk += blks; 707 sc->sc_bytecnt -= (blks*DEV_BSIZE); 708 709 if (bp->b_flags & B_READ) 710 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 711 else 712 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 713 } 714 715 /* 716 * Called once per controller when an ubareset occurs. 717 * Retracts all disks and restarts active transfers. 718 */ 719 void 720 rlcreset(struct device *dev) 721 { 722 struct rlc_softc *sc = (struct rlc_softc *)dev; 723 struct rl_softc *rc; 724 int i; 725 u_int16_t mp; 726 727 for (i = 0; i < rl_cd.cd_ndevs; i++) { 728 if ((rc = rl_cd.cd_devs[i]) == NULL) 729 continue; 730 if (rc->rc_state != DK_OPEN) 731 continue; 732 733 printf(" %s", rc->rc_dev.dv_xname); 734 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 735 waitcrdy(sc); 736 mp = RL_RREG(RL_MP); 737 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 738 rc->rc_cyl = (mp >> 7) & 0777; 739 } 740 if (sc->sc_active == 0) 741 return; 742 743 BUFQ_PUT(&sc->sc_q, sc->sc_active); 744 sc->sc_active = 0; 745 rlcstart(sc, 0); 746 } 747