1 /* $NetBSD: rl.c,v 1.51 2017/05/22 17:22:29 ragge 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* 28 * RL11/RLV11/RLV12 disk controller driver and 29 * RL01/RL02 disk device driver. 30 * 31 * TODO: 32 * Handle disk errors more gracefully 33 * Do overlapping seeks on multiple drives 34 * 35 * Implementation comments: 36 * 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: rl.c,v 1.51 2017/05/22 17:22:29 ragge Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/device.h> 44 #include <sys/systm.h> 45 #include <sys/conf.h> 46 #include <sys/disk.h> 47 #include <sys/disklabel.h> 48 #include <sys/buf.h> 49 #include <sys/bufq.h> 50 #include <sys/stat.h> 51 #include <sys/dkio.h> 52 #include <sys/fcntl.h> 53 #include <sys/event.h> 54 55 #include <ufs/ufs/dinode.h> 56 #include <ufs/ffs/fs.h> 57 58 #include <sys/bus.h> 59 60 #include <dev/qbus/ubavar.h> 61 #include <dev/qbus/rlreg.h> 62 #include <dev/qbus/rlvar.h> 63 64 #include "ioconf.h" 65 #include "locators.h" 66 67 static int rlcmatch(device_t, cfdata_t, void *); 68 static void rlcattach(device_t, device_t, void *); 69 static int rlcprint(void *, const char *); 70 static void rlcintr(void *); 71 static int rlmatch(device_t, cfdata_t, void *); 72 static void rlattach(device_t, device_t, void *); 73 static void rlcstart(struct rlc_softc *, struct buf *); 74 static void waitcrdy(struct rlc_softc *); 75 static void rlcreset(device_t); 76 77 CFATTACH_DECL_NEW(rlc, sizeof(struct rlc_softc), 78 rlcmatch, rlcattach, NULL, NULL); 79 80 CFATTACH_DECL_NEW(rl, sizeof(struct rl_softc), 81 rlmatch, rlattach, NULL, NULL); 82 83 static dev_type_open(rlopen); 84 static dev_type_close(rlclose); 85 static dev_type_read(rlread); 86 static dev_type_write(rlwrite); 87 static dev_type_ioctl(rlioctl); 88 static dev_type_strategy(rlstrategy); 89 static dev_type_dump(rldump); 90 static dev_type_size(rlpsize); 91 92 const struct bdevsw rl_bdevsw = { 93 .d_open = rlopen, 94 .d_close = rlclose, 95 .d_strategy = rlstrategy, 96 .d_ioctl = rlioctl, 97 .d_dump = rldump, 98 .d_psize = rlpsize, 99 .d_discard = nodiscard, 100 .d_flag = D_DISK 101 }; 102 103 const struct cdevsw rl_cdevsw = { 104 .d_open = rlopen, 105 .d_close = rlclose, 106 .d_read = rlread, 107 .d_write = rlwrite, 108 .d_ioctl = rlioctl, 109 .d_stop = nostop, 110 .d_tty = notty, 111 .d_poll = nopoll, 112 .d_mmap = nommap, 113 .d_kqfilter = nokqfilter, 114 .d_discard = nodiscard, 115 .d_flag = D_DISK 116 }; 117 118 #define MAXRLXFER (RL_BPS * RL_SPT) 119 120 #define RL_WREG(reg, val) \ 121 bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val)) 122 #define RL_RREG(reg) \ 123 bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg)) 124 125 static const char * const rlstates[] = { 126 "drive not loaded", 127 "drive spinning up", 128 "drive brushes out", 129 "drive loading heads", 130 "drive seeking", 131 "drive ready", 132 "drive unloading heads", 133 "drive spun down", 134 }; 135 136 static const struct dkdriver rldkdriver = { 137 .d_strategy = rlstrategy, 138 .d_minphys = minphys 139 }; 140 141 static const char * 142 rlstate(struct rlc_softc *sc, int unit) 143 { 144 int i = 0; 145 146 do { 147 RL_WREG(RL_DA, RLDA_GS); 148 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT)); 149 waitcrdy(sc); 150 } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10); 151 if (i == 10) 152 return NULL; 153 i = RL_RREG(RL_MP) & RLMP_STATUS; 154 return rlstates[i]; 155 } 156 157 void 158 waitcrdy(struct rlc_softc *sc) 159 { 160 int i; 161 162 for (i = 0; i < 1000; i++) { 163 DELAY(10000); 164 if (RL_RREG(RL_CS) & RLCS_CRDY) 165 return; 166 } 167 aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */ 168 } 169 170 int 171 rlcprint(void *aux, const char *name) 172 { 173 struct rlc_attach_args *ra = aux; 174 175 if (name) 176 aprint_normal("RL0%d at %s", 177 ra->type & RLMP_DT ? '2' : '1', name); 178 aprint_normal(" drive %d", ra->hwid); 179 return UNCONF; 180 } 181 182 /* 183 * Force the controller to interrupt. 184 */ 185 int 186 rlcmatch(device_t parent, cfdata_t cf, void *aux) 187 { 188 struct uba_attach_args *ua = aux; 189 struct rlc_softc ssc, *sc = &ssc; 190 int i; 191 192 sc->sc_iot = ua->ua_iot; 193 sc->sc_ioh = ua->ua_ioh; 194 /* Force interrupt by issuing a "Get Status" command */ 195 RL_WREG(RL_DA, RLDA_GS); 196 RL_WREG(RL_CS, RLCS_GS|RLCS_IE); 197 198 for (i = 0; i < 100; i++) { 199 DELAY(100000); 200 if (RL_RREG(RL_CS) & RLCS_CRDY) 201 return 1; 202 } 203 return 0; 204 } 205 206 void 207 rlcattach(device_t parent, device_t self, void *aux) 208 { 209 struct rlc_softc *sc = device_private(self); 210 struct uba_attach_args *ua = aux; 211 struct rlc_attach_args ra; 212 int i, error; 213 214 sc->sc_dev = self; 215 sc->sc_uh = device_private(parent); 216 sc->sc_iot = ua->ua_iot; 217 sc->sc_ioh = ua->ua_ioh; 218 sc->sc_dmat = ua->ua_dmat; 219 uba_intr_establish(ua->ua_icookie, ua->ua_cvec, 220 rlcintr, sc, &sc->sc_intrcnt); 221 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt, 222 device_xname(sc->sc_dev), "intr"); 223 uba_reset_establish(rlcreset, self); 224 225 printf("\n"); 226 227 /* 228 * The RL11 can only have one transfer going at a time, 229 * and max transfer size is one track, so only one dmamap 230 * is needed. 231 */ 232 error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0, 233 BUS_DMA_ALLOCNOW, &sc->sc_dmam); 234 if (error) { 235 aprint_error(": Failed to allocate DMA map, error %d\n", error); 236 return; 237 } 238 bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER); 239 for (i = 0; i < RL_MAXDPC; i++) { 240 waitcrdy(sc); 241 RL_WREG(RL_DA, RLDA_GS|RLDA_RST); 242 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT)); 243 waitcrdy(sc); 244 ra.type = RL_RREG(RL_MP); 245 ra.hwid = i; 246 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0) 247 config_found(sc->sc_dev, &ra, rlcprint); 248 } 249 } 250 251 int 252 rlmatch(device_t parent, cfdata_t cf, void *aux) 253 { 254 struct rlc_attach_args *ra = aux; 255 256 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT && 257 cf->cf_loc[RLCCF_DRIVE] != ra->hwid) 258 return 0; 259 return 1; 260 } 261 262 void 263 rlattach(device_t parent, device_t self, void *aux) 264 { 265 struct rl_softc *rc = device_private(self); 266 struct rlc_attach_args *ra = aux; 267 struct disklabel *dl; 268 269 rc->rc_dev = self; 270 rc->rc_rlc = device_private(parent); 271 rc->rc_hwid = ra->hwid; 272 disk_init(&rc->rc_disk, device_xname(rc->rc_dev), &rldkdriver); 273 disk_attach(&rc->rc_disk); 274 dl = rc->rc_disk.dk_label; 275 dl->d_npartitions = 3; 276 strcpy(dl->d_typename, "RL01"); 277 if (ra->type & RLMP_DT) 278 dl->d_typename[3] = '2'; 279 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */ 280 dl->d_nsectors = RL_SPT/2; 281 dl->d_ntracks = RL_SPD; 282 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01; 283 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 284 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl; 285 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 286 dl->d_secperunit; 287 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 288 dl->d_interleave = dl->d_headswitch = 1; 289 dl->d_bbsize = BBSIZE; 290 dl->d_sbsize = SBLOCKSIZE; 291 dl->d_rpm = 2400; 292 dl->d_type = DKTYPE_DEC; 293 printf(": %s, %s\n", dl->d_typename, rlstate(rc->rc_rlc, ra->hwid)); 294 295 /* 296 * XXX We should try to discovery wedges here, but 297 * XXX that would mean loading up the pack and being 298 * XXX able to do I/O. Should use config_defer() here. 299 */ 300 } 301 302 int 303 rlopen(dev_t dev, int flag, int fmt, struct lwp *l) 304 { 305 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 306 struct rlc_softc *sc; 307 int error, part, mask; 308 struct disklabel *dl; 309 const char *msg; 310 311 /* 312 * Make sure this is a reasonable open request. 313 */ 314 if (rc == NULL) 315 return ENXIO; 316 317 sc = rc->rc_rlc; 318 part = DISKPART(dev); 319 320 mutex_enter(&rc->rc_disk.dk_openlock); 321 322 /* 323 * If there are wedges, and this is not RAW_PART, then we 324 * need to fail. 325 */ 326 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) { 327 error = EBUSY; 328 goto bad1; 329 } 330 331 /* Check that the disk actually is useable */ 332 msg = rlstate(sc, rc->rc_hwid); 333 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] || 334 msg == rlstates[RLMP_SPUNDOWN]) { 335 error = ENXIO; 336 goto bad1; 337 } 338 /* 339 * If this is the first open; read in where on the disk we are. 340 */ 341 dl = rc->rc_disk.dk_label; 342 if (rc->rc_state == DK_CLOSED) { 343 u_int16_t mp; 344 int maj; 345 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 346 waitcrdy(sc); 347 mp = RL_RREG(RL_MP); 348 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 349 rc->rc_cyl = (mp >> 7) & 0777; 350 rc->rc_state = DK_OPEN; 351 /* Get disk label */ 352 maj = cdevsw_lookup_major(&rl_cdevsw); 353 if ((msg = readdisklabel(MAKEDISKDEV(maj, 354 device_unit(rc->rc_dev), RAW_PART), rlstrategy, dl, NULL))) 355 aprint_normal_dev(rc->rc_dev, "%s", msg); 356 aprint_normal_dev(rc->rc_dev, "size %d sectors\n", 357 dl->d_secperunit); 358 } 359 if (part >= dl->d_npartitions) { 360 error = ENXIO; 361 goto bad1; 362 } 363 364 mask = 1 << part; 365 switch (fmt) { 366 case S_IFCHR: 367 rc->rc_disk.dk_copenmask |= mask; 368 break; 369 case S_IFBLK: 370 rc->rc_disk.dk_bopenmask |= mask; 371 break; 372 } 373 rc->rc_disk.dk_openmask |= mask; 374 error = 0; 375 bad1: 376 mutex_exit(&rc->rc_disk.dk_openlock); 377 return (error); 378 } 379 380 int 381 rlclose(dev_t dev, int flag, int fmt, struct lwp *l) 382 { 383 int unit = DISKUNIT(dev); 384 struct rl_softc *rc = device_lookup_private(&rl_cd, unit); 385 int mask = (1 << DISKPART(dev)); 386 387 mutex_enter(&rc->rc_disk.dk_openlock); 388 389 switch (fmt) { 390 case S_IFCHR: 391 rc->rc_disk.dk_copenmask &= ~mask; 392 break; 393 case S_IFBLK: 394 rc->rc_disk.dk_bopenmask &= ~mask; 395 break; 396 } 397 rc->rc_disk.dk_openmask = 398 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask; 399 400 if (rc->rc_disk.dk_openmask == 0) 401 rc->rc_state = DK_CLOSED; /* May change pack */ 402 mutex_exit(&rc->rc_disk.dk_openlock); 403 return 0; 404 } 405 406 void 407 rlstrategy(struct buf *bp) 408 { 409 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 410 struct disklabel *lp; 411 int s; 412 413 if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */ 414 panic("rlstrategy: state impossible"); 415 416 lp = rc->rc_disk.dk_label; 417 if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0) 418 goto done; 419 420 if (bp->b_bcount == 0) 421 goto done; 422 423 bp->b_rawblkno = 424 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 425 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl; 426 427 s = splbio(); 428 bufq_put(rc->rc_rlc->sc_q, bp); 429 rlcstart(rc->rc_rlc, 0); 430 splx(s); 431 return; 432 433 done: biodone(bp); 434 } 435 436 int 437 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 438 { 439 struct rl_softc *rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 440 struct disklabel *lp = rc->rc_disk.dk_label; 441 int error; 442 #ifdef __HAVE_OLD_DISKLABEL 443 struct disklabel newlabel; 444 #endif 445 446 error = disk_ioctl(&rc->rc_disk, dev, cmd, addr, flag, l); 447 if (error != EPASSTHROUGH) 448 return error; 449 else 450 error = 0; 451 452 switch (cmd) { 453 case DIOCSDINFO: 454 case DIOCWDINFO: 455 #ifdef __HAVE_OLD_DISKLABEL 456 case ODIOCWDINFO: 457 case ODIOCSDINFO: 458 #endif 459 { 460 struct disklabel *tp; 461 462 #ifdef __HAVE_OLD_DISKLABEL 463 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 464 memset(&newlabel, 0, sizeof newlabel); 465 memcpy(&newlabel, addr, sizeof (struct olddisklabel)); 466 tp = &newlabel; 467 } else 468 #endif 469 tp = (struct disklabel *)addr; 470 471 if ((flag & FWRITE) == 0) 472 error = EBADF; 473 else { 474 mutex_enter(&rc->rc_disk.dk_openlock); 475 error = (( 476 #ifdef __HAVE_OLD_DISKLABEL 477 cmd == ODIOCSDINFO || 478 #endif 479 cmd == DIOCSDINFO) ? 480 setdisklabel(lp, tp, 0, 0) : 481 writedisklabel(dev, rlstrategy, lp, 0)); 482 mutex_exit(&rc->rc_disk.dk_openlock); 483 } 484 break; 485 } 486 487 case DIOCWLABEL: 488 if ((flag & FWRITE) == 0) 489 error = EBADF; 490 break; 491 492 default: 493 error = ENOTTY; 494 break; 495 } 496 return error; 497 } 498 499 int 500 rlpsize(dev_t dev) 501 { 502 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev)); 503 struct disklabel *dl; 504 int size; 505 506 if (rc == NULL) 507 return -1; 508 dl = rc->rc_disk.dk_label; 509 size = dl->d_partitions[DISKPART(dev)].p_size * 510 (dl->d_secsize / DEV_BSIZE); 511 return size; 512 } 513 514 int 515 rldump(dev_t dev, daddr_t blkno, void *va, size_t size) 516 { 517 /* Not likely... */ 518 return 0; 519 } 520 521 int 522 rlread(dev_t dev, struct uio *uio, int ioflag) 523 { 524 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio)); 525 } 526 527 int 528 rlwrite(dev_t dev, struct uio *uio, int ioflag) 529 { 530 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio)); 531 } 532 533 static const char * const rlerr[] = { 534 "no", 535 "operation incomplete", 536 "read data CRC", 537 "header CRC", 538 "data late", 539 "header not found", 540 "", 541 "", 542 "non-existent memory", 543 "memory parity error", 544 "", 545 "", 546 "", 547 "", 548 "", 549 "", 550 }; 551 552 void 553 rlcintr(void *arg) 554 { 555 struct rlc_softc *sc = arg; 556 struct buf *bp; 557 u_int16_t cs; 558 559 bp = sc->sc_active; 560 if (bp == 0) { 561 aprint_error_dev(sc->sc_dev, "strange interrupt\n"); 562 return; 563 } 564 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam); 565 sc->sc_active = 0; 566 cs = RL_RREG(RL_CS); 567 if (cs & RLCS_ERR) { 568 int error = (cs & RLCS_ERRMSK) >> 10; 569 570 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]); 571 bp->b_error = EIO; 572 bp->b_resid = bp->b_bcount; 573 sc->sc_bytecnt = 0; 574 } 575 if (sc->sc_bytecnt == 0) /* Finished transfer */ 576 biodone(bp); 577 rlcstart(sc, sc->sc_bytecnt ? bp : 0); 578 } 579 580 /* 581 * Start routine. First position the disk to the given position, 582 * then start reading/writing. An optimization would be to be able 583 * to handle overlapping seeks between disks. 584 */ 585 void 586 rlcstart(struct rlc_softc *sc, struct buf *ob) 587 { 588 struct disklabel *lp; 589 struct rl_softc *rc; 590 struct buf *bp; 591 int bn, cn, sn, tn, blks, err; 592 593 if (sc->sc_active) 594 return; /* Already doing something */ 595 596 if (ob == 0) { 597 bp = bufq_get(sc->sc_q); 598 if (bp == NULL) 599 return; /* Nothing to do */ 600 sc->sc_bufaddr = bp->b_data; 601 sc->sc_diskblk = bp->b_rawblkno; 602 sc->sc_bytecnt = bp->b_bcount; 603 bp->b_resid = 0; 604 } else 605 bp = ob; 606 sc->sc_active = bp; 607 608 rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev)); 609 bn = sc->sc_diskblk; 610 lp = rc->rc_disk.dk_label; 611 if (bn) { 612 cn = bn / lp->d_secpercyl; 613 sn = bn % lp->d_secpercyl; 614 tn = sn / lp->d_nsectors; 615 sn = sn % lp->d_nsectors; 616 } else 617 cn = sn = tn = 0; 618 619 /* 620 * Check if we have to position disk first. 621 */ 622 if (rc->rc_cyl != cn || rc->rc_head != tn) { 623 u_int16_t da = RLDA_SEEK; 624 if (cn > rc->rc_cyl) 625 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR; 626 else 627 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT); 628 if (tn) 629 da |= RLDA_HSSEEK; 630 waitcrdy(sc); 631 RL_WREG(RL_DA, da); 632 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT)); 633 waitcrdy(sc); 634 rc->rc_cyl = cn; 635 rc->rc_head = tn; 636 } 637 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1)); 638 blks = sc->sc_bytecnt/DEV_BSIZE; 639 640 if (sn + blks > RL_SPT/2) 641 blks = RL_SPT/2 - sn; 642 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2); 643 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr, 644 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0), 645 BUS_DMA_NOWAIT); 646 if (err) 647 panic("%s: bus_dmamap_load failed: %d", 648 device_xname(sc->sc_dev), err); 649 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff)); 650 651 /* Count up vars */ 652 sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE); 653 sc->sc_diskblk += blks; 654 sc->sc_bytecnt -= (blks*DEV_BSIZE); 655 656 if (bp->b_flags & B_READ) 657 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT)); 658 else 659 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT)); 660 } 661 662 /* 663 * Called once per controller when an ubareset occurs. 664 * Retracts all disks and restarts active transfers. 665 */ 666 void 667 rlcreset(device_t dev) 668 { 669 struct rlc_softc *sc = device_private(dev); 670 struct rl_softc *rc; 671 int i; 672 u_int16_t mp; 673 674 for (i = 0; i < rl_cd.cd_ndevs; i++) { 675 if ((rc = device_lookup_private(&rl_cd, i)) == NULL) 676 continue; 677 if (rc->rc_state != DK_OPEN) 678 continue; 679 if (rc->rc_rlc != sc) 680 continue; 681 682 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT)); 683 waitcrdy(sc); 684 mp = RL_RREG(RL_MP); 685 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS); 686 rc->rc_cyl = (mp >> 7) & 0777; 687 } 688 if (sc->sc_active == 0) 689 return; 690 691 bufq_put(sc->sc_q, sc->sc_active); 692 sc->sc_active = 0; 693 rlcstart(sc, 0); 694 } 695