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