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