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