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