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