rl.c revision 1.47 1 /* $NetBSD: rl.c,v 1.47 2014/12/31 17:06:48 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.47 2014/12/31 17:06:48 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 = DTYPE_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 diklabel newlabel;
449 #endif
450
451 error = disk_ioctl(&rc->rc_disk, xfer, addr, flag, l);
452 if (error != EPASSTHROUGH)
453 return error;
454 else
455 error = 0;
456
457 switch (cmd) {
458 case DIOCGDINFO:
459 memcpy(addr, lp, sizeof (struct disklabel));
460 break;
461
462 #ifdef __HAVE_OLD_DISKLABEL
463 case ODIOCGDINFO:
464 newlabel = *lp;
465 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
466 return ENOTTY;
467 memcpy(addr, &newlabel, sizeof (struct olddisklabel));
468 break;
469 #endif
470
471 case DIOCGPART:
472 ((struct partinfo *)addr)->disklab = lp;
473 ((struct partinfo *)addr)->part =
474 &lp->d_partitions[DISKPART(dev)];
475 break;
476
477 case DIOCSDINFO:
478 case DIOCWDINFO:
479 #ifdef __HAVE_OLD_DISKLABEL
480 case ODIOCWDINFO:
481 case ODIOCSDINFO:
482 #endif
483 {
484 struct disklabel *tp;
485
486 #ifdef __HAVE_OLD_DISKLABEL
487 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
488 memset(&newlabel, 0, sizeof newlabel);
489 memcpy(&newlabel, addr, sizeof (struct olddisklabel));
490 tp = &newlabel;
491 } else
492 #endif
493 tp = (struct disklabel *)addr;
494
495 if ((flag & FWRITE) == 0)
496 error = EBADF;
497 else {
498 mutex_enter(&rc->rc_disk.dk_openlock);
499 error = ((
500 #ifdef __HAVE_OLD_DISKLABEL
501 cmd == ODIOCSDINFO ||
502 #endif
503 cmd == DIOCSDINFO) ?
504 setdisklabel(lp, tp, 0, 0) :
505 writedisklabel(dev, rlstrategy, lp, 0));
506 mutex_exit(&rc->rc_disk.dk_openlock);
507 }
508 break;
509 }
510
511 case DIOCWLABEL:
512 if ((flag & FWRITE) == 0)
513 error = EBADF;
514 break;
515
516 default:
517 error = ENOTTY;
518 break;
519 }
520 return error;
521 }
522
523 int
524 rlpsize(dev_t dev)
525 {
526 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
527 struct disklabel *dl;
528 int size;
529
530 if (rc == NULL)
531 return -1;
532 dl = rc->rc_disk.dk_label;
533 size = dl->d_partitions[DISKPART(dev)].p_size *
534 (dl->d_secsize / DEV_BSIZE);
535 return size;
536 }
537
538 int
539 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
540 {
541 /* Not likely... */
542 return 0;
543 }
544
545 int
546 rlread(dev_t dev, struct uio *uio, int ioflag)
547 {
548 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
549 }
550
551 int
552 rlwrite(dev_t dev, struct uio *uio, int ioflag)
553 {
554 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
555 }
556
557 static const char * const rlerr[] = {
558 "no",
559 "operation incomplete",
560 "read data CRC",
561 "header CRC",
562 "data late",
563 "header not found",
564 "",
565 "",
566 "non-existent memory",
567 "memory parity error",
568 "",
569 "",
570 "",
571 "",
572 "",
573 "",
574 };
575
576 void
577 rlcintr(void *arg)
578 {
579 struct rlc_softc *sc = arg;
580 struct buf *bp;
581 u_int16_t cs;
582
583 bp = sc->sc_active;
584 if (bp == 0) {
585 aprint_error_dev(sc->sc_dev, "strange interrupt\n");
586 return;
587 }
588 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
589 sc->sc_active = 0;
590 cs = RL_RREG(RL_CS);
591 if (cs & RLCS_ERR) {
592 int error = (cs & RLCS_ERRMSK) >> 10;
593
594 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]);
595 bp->b_error = EIO;
596 bp->b_resid = bp->b_bcount;
597 sc->sc_bytecnt = 0;
598 }
599 if (sc->sc_bytecnt == 0) /* Finished transfer */
600 biodone(bp);
601 rlcstart(sc, sc->sc_bytecnt ? bp : 0);
602 }
603
604 /*
605 * Start routine. First position the disk to the given position,
606 * then start reading/writing. An optimization would be to be able
607 * to handle overlapping seeks between disks.
608 */
609 void
610 rlcstart(struct rlc_softc *sc, struct buf *ob)
611 {
612 struct disklabel *lp;
613 struct rl_softc *rc;
614 struct buf *bp;
615 int bn, cn, sn, tn, blks, err;
616
617 if (sc->sc_active)
618 return; /* Already doing something */
619
620 if (ob == 0) {
621 bp = bufq_get(sc->sc_q);
622 if (bp == NULL)
623 return; /* Nothing to do */
624 sc->sc_bufaddr = bp->b_data;
625 sc->sc_diskblk = bp->b_rawblkno;
626 sc->sc_bytecnt = bp->b_bcount;
627 bp->b_resid = 0;
628 } else
629 bp = ob;
630 sc->sc_active = bp;
631
632 rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev));
633 bn = sc->sc_diskblk;
634 lp = rc->rc_disk.dk_label;
635 if (bn) {
636 cn = bn / lp->d_secpercyl;
637 sn = bn % lp->d_secpercyl;
638 tn = sn / lp->d_nsectors;
639 sn = sn % lp->d_nsectors;
640 } else
641 cn = sn = tn = 0;
642
643 /*
644 * Check if we have to position disk first.
645 */
646 if (rc->rc_cyl != cn || rc->rc_head != tn) {
647 u_int16_t da = RLDA_SEEK;
648 if (cn > rc->rc_cyl)
649 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
650 else
651 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
652 if (tn)
653 da |= RLDA_HSSEEK;
654 waitcrdy(sc);
655 RL_WREG(RL_DA, da);
656 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
657 waitcrdy(sc);
658 rc->rc_cyl = cn;
659 rc->rc_head = tn;
660 }
661 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
662 blks = sc->sc_bytecnt/DEV_BSIZE;
663
664 if (sn + blks > RL_SPT/2)
665 blks = RL_SPT/2 - sn;
666 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
667 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
668 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
669 BUS_DMA_NOWAIT);
670 if (err)
671 panic("%s: bus_dmamap_load failed: %d",
672 device_xname(sc->sc_dev), err);
673 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
674
675 /* Count up vars */
676 sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE);
677 sc->sc_diskblk += blks;
678 sc->sc_bytecnt -= (blks*DEV_BSIZE);
679
680 if (bp->b_flags & B_READ)
681 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
682 else
683 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
684 }
685
686 /*
687 * Called once per controller when an ubareset occurs.
688 * Retracts all disks and restarts active transfers.
689 */
690 void
691 rlcreset(device_t dev)
692 {
693 struct rlc_softc *sc = device_private(dev);
694 struct rl_softc *rc;
695 int i;
696 u_int16_t mp;
697
698 for (i = 0; i < rl_cd.cd_ndevs; i++) {
699 if ((rc = device_lookup_private(&rl_cd, i)) == NULL)
700 continue;
701 if (rc->rc_state != DK_OPEN)
702 continue;
703 if (rc->rc_rlc != sc)
704 continue;
705
706 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
707 waitcrdy(sc);
708 mp = RL_RREG(RL_MP);
709 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
710 rc->rc_cyl = (mp >> 7) & 0777;
711 }
712 if (sc->sc_active == 0)
713 return;
714
715 bufq_put(sc->sc_q, sc->sc_active);
716 sc->sc_active = 0;
717 rlcstart(sc, 0);
718 }
719