FreeBSD/Linux Kernel Cross Reference
sys/dev/qbus/rl.c
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 }
Cache object: 09a4f1490a327ac9afc0f3736215fa0f
|