Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / qbus / rl.c
blob1d86bad3b25e1d4c7ae0fdf4472f9b77653ddcab
1 /* $NetBSD: rl.c,v 1.41 2009/03/18 17:06:50 cegger Exp $ */
3 /*
4 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
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
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.
34 * RL11/RLV11/RLV12 disk controller driver and
35 * RL01/RL02 disk device driver.
37 * TODO:
38 * Handle disk errors more gracefully
39 * Do overlapping seeks on multiple drives
41 * Implementation comments:
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: rl.c,v 1.41 2009/03/18 17:06:50 cegger Exp $");
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>
61 #include <ufs/ufs/dinode.h>
62 #include <ufs/ffs/fs.h>
64 #include <sys/bus.h>
66 #include <dev/qbus/ubavar.h>
67 #include <dev/qbus/rlreg.h>
68 #include <dev/qbus/rlvar.h>
70 #include "ioconf.h"
71 #include "locators.h"
73 static int rlcmatch(device_t, cfdata_t, void *);
74 static void rlcattach(device_t, device_t, void *);
75 static int rlcprint(void *, const char *);
76 static void rlcintr(void *);
77 static int rlmatch(device_t, cfdata_t, void *);
78 static void rlattach(device_t, device_t, void *);
79 static void rlcstart(struct rlc_softc *, struct buf *);
80 static void waitcrdy(struct rlc_softc *);
81 static void rlcreset(device_t);
83 CFATTACH_DECL_NEW(rlc, sizeof(struct rlc_softc),
84 rlcmatch, rlcattach, NULL, NULL);
86 CFATTACH_DECL_NEW(rl, sizeof(struct rl_softc),
87 rlmatch, rlattach, NULL, NULL);
89 static dev_type_open(rlopen);
90 static dev_type_close(rlclose);
91 static dev_type_read(rlread);
92 static dev_type_write(rlwrite);
93 static dev_type_ioctl(rlioctl);
94 static dev_type_strategy(rlstrategy);
95 static dev_type_dump(rldump);
96 static dev_type_size(rlpsize);
98 const struct bdevsw rl_bdevsw = {
99 rlopen, rlclose, rlstrategy, rlioctl, rldump, rlpsize, D_DISK
102 const struct cdevsw rl_cdevsw = {
103 rlopen, rlclose, rlread, rlwrite, rlioctl,
104 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
107 #define MAXRLXFER (RL_BPS * RL_SPT)
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))
114 static 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",
125 static const struct dkdriver rldkdriver = {
126 rlstrategy, minphys
129 static const char *
130 rlstate(struct rlc_softc *sc, int unit)
132 int i = 0;
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];
145 void
146 waitcrdy(struct rlc_softc *sc)
148 int i;
150 for (i = 0; i < 1000; i++) {
151 DELAY(10000);
152 if (RL_RREG(RL_CS) & RLCS_CRDY)
153 return;
155 aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */
159 rlcprint(void *aux, const char *name)
161 struct rlc_attach_args *ra = aux;
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;
171 * Force the controller to interrupt.
174 rlcmatch(device_t parent, cfdata_t cf, void *aux)
176 struct uba_attach_args *ua = aux;
177 struct rlc_softc ssc, *sc = &ssc;
178 int i;
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);
186 for (i = 0; i < 100; i++) {
187 DELAY(100000);
188 if (RL_RREG(RL_CS) & RLCS_CRDY)
189 return 1;
191 return 0;
194 void
195 rlcattach(device_t parent, device_t self, void *aux)
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;
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);
213 printf("\n");
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.
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;
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);
240 rlmatch(device_t parent, cfdata_t cf, void *aux)
242 struct rlc_attach_args *ra = aux;
244 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
245 cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
246 return 0;
247 return 1;
250 void
251 rlattach(device_t parent, device_t self, void *aux)
253 struct rl_softc *rc = device_private(self);
254 struct rlc_attach_args *ra = aux;
255 struct disklabel *dl;
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));
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.
291 rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
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;
300 * Make sure this is a reasonable open request.
302 if (rc == NULL)
303 return ENXIO;
305 sc = rc->rc_rlc;
306 part = DISKPART(dev);
308 mutex_enter(&rc->rc_disk.dk_openlock);
311 * If there are wedges, and this is not RAW_PART, then we
312 * need to fail.
314 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
315 error = EBUSY;
316 goto bad1;
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;
327 * If this is the first open; read in where on the disk we are.
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);
347 if (part >= dl->d_npartitions) {
348 error = ENXIO;
349 goto bad1;
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;
361 rc->rc_disk.dk_openmask |= mask;
362 error = 0;
363 bad1:
364 mutex_exit(&rc->rc_disk.dk_openlock);
365 return (error);
369 rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
371 int unit = DISKUNIT(dev);
372 struct rl_softc *rc = device_lookup_private(&rl_cd, unit);
373 int mask = (1 << DISKPART(dev));
375 mutex_enter(&rc->rc_disk.dk_openlock);
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;
385 rc->rc_disk.dk_openmask =
386 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
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;
394 void
395 rlstrategy(struct buf *bp)
397 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev));
398 struct disklabel *lp;
399 int s;
401 if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */
402 panic("rlstrategy: state impossible");
404 lp = rc->rc_disk.dk_label;
405 if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0)
406 goto done;
408 if (bp->b_bcount == 0)
409 goto done;
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;
415 s = splbio();
416 bufq_put(rc->rc_rlc->sc_q, bp);
417 rlcstart(rc->rc_rlc, 0);
418 splx(s);
419 return;
421 done: biodone(bp);
425 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
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
434 switch (cmd) {
435 case DIOCGDINFO:
436 memcpy(addr, lp, sizeof (struct disklabel));
437 break;
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
448 case DIOCGPART:
449 ((struct partinfo *)addr)->disklab = lp;
450 ((struct partinfo *)addr)->part =
451 &lp->d_partitions[DISKPART(dev)];
452 break;
454 case DIOCSDINFO:
455 case DIOCWDINFO:
456 #ifdef __HAVE_OLD_DISKLABEL
457 case ODIOCWDINFO:
458 case ODIOCSDINFO:
459 #endif
461 struct disklabel *tp;
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;
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);
485 break;
488 case DIOCWLABEL:
489 if ((flag & FWRITE) == 0)
490 err = EBADF;
491 break;
493 case DIOCAWEDGE: {
494 struct dkwedge_info *dkw = (void *) addr;
496 if ((flag & FWRITE) == 0)
497 return (EBADF);
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);
504 case DIOCDWEDGE: {
505 struct dkwedge_info *dkw = (void *) addr;
507 if ((flag & FWRITE) == 0)
508 return (EBADF);
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);
515 case DIOCLWEDGES: {
516 struct dkwedge_list *dkwl = (void *) addr;
518 return dkwedge_list(&rc->rc_disk, dkwl, l);
521 default:
522 err = ENOTTY;
523 break;
525 return err;
529 rlpsize(dev_t dev)
531 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
532 struct disklabel *dl;
533 int size;
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;
544 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
546 /* Not likely... */
547 return 0;
551 rlread(dev_t dev, struct uio *uio, int ioflag)
553 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
557 rlwrite(dev_t dev, struct uio *uio, int ioflag)
559 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
562 static const char * const rlerr[] = {
563 "no",
564 "operation incomplete",
565 "read data CRC",
566 "header CRC",
567 "data late",
568 "header not found",
571 "non-existent memory",
572 "memory parity error",
581 void
582 rlcintr(void *arg)
584 struct rlc_softc *sc = arg;
585 struct buf *bp;
586 u_int16_t cs;
588 bp = sc->sc_active;
589 if (bp == 0) {
590 aprint_error_dev(sc->sc_dev, "strange interrupt\n");
591 return;
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;
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;
604 if (sc->sc_bytecnt == 0) /* Finished transfer */
605 biodone(bp);
606 rlcstart(sc, sc->sc_bytecnt ? bp : 0);
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.
614 void
615 rlcstart(struct rlc_softc *sc, struct buf *ob)
617 struct disklabel *lp;
618 struct rl_softc *rc;
619 struct buf *bp;
620 int bn, cn, sn, tn, blks, err;
622 if (sc->sc_active)
623 return; /* Already doing something */
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;
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;
649 * Check if we have to position disk first.
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;
666 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
667 blks = sc->sc_bytecnt/DEV_BSIZE;
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));
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);
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));
692 * Called once per controller when an ubareset occurs.
693 * Retracts all disks and restarts active transfers.
695 void
696 rlcreset(device_t dev)
698 struct rlc_softc *sc = device_private(dev);
699 struct rl_softc *rc;
700 int i;
701 u_int16_t mp;
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;
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;
717 if (sc->sc_active == 0)
718 return;
720 bufq_put(sc->sc_q, sc->sc_active);
721 sc->sc_active = 0;
722 rlcstart(sc, 0);