rl.c revision 1.37 1 /* $NetBSD: rl.c,v 1.37 2007/10/19 12:01:09 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.37 2007/10/19 12:01:09 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 <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(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 disk_init(&rc->rc_disk, rc->rc_dev.dv_xname, &rldkdriver);
257 disk_attach(&rc->rc_disk);
258 dl = rc->rc_disk.dk_label;
259 dl->d_npartitions = 3;
260 strcpy(dl->d_typename, "RL01");
261 if (ra->type & RLMP_DT)
262 dl->d_typename[3] = '2';
263 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
264 dl->d_nsectors = RL_SPT/2;
265 dl->d_ntracks = RL_SPD;
266 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
267 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
268 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
269 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
270 dl->d_secperunit;
271 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
272 dl->d_interleave = dl->d_headswitch = 1;
273 dl->d_bbsize = BBSIZE;
274 dl->d_sbsize = SBLOCKSIZE;
275 dl->d_rpm = 2400;
276 dl->d_type = DTYPE_DEC;
277 printf(": %s, %s\n", dl->d_typename,
278 rlstate((struct rlc_softc *)parent, ra->hwid));
279
280 /*
281 * XXX We should try to discovery wedges here, but
282 * XXX that would mean loading up the pack and being
283 * XXX able to do I/O. Should use config_defer() here.
284 */
285 }
286
287 int
288 rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
289 {
290 int error, part, unit, mask;
291 struct disklabel *dl;
292 struct rlc_softc *sc;
293 struct rl_softc *rc;
294 const char *msg;
295
296 /*
297 * Make sure this is a reasonable open request.
298 */
299 unit = DISKUNIT(dev);
300 if (unit >= rl_cd.cd_ndevs)
301 return ENXIO;
302 rc = rl_cd.cd_devs[unit];
303 if (rc == 0)
304 return ENXIO;
305
306 part = DISKPART(dev);
307
308 mutex_enter(&rc->rc_disk.dk_openlock);
309
310 /*
311 * If there are wedges, and this is not RAW_PART, then we
312 * need to fail.
313 */
314 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
315 error = EBUSY;
316 goto bad1;
317 }
318
319 sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
320 /* Check that the disk actually is useable */
321 msg = rlstate(sc, rc->rc_hwid);
322 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
323 msg == rlstates[RLMP_SPUNDOWN]) {
324 error = ENXIO;
325 goto bad1;
326 }
327 /*
328 * If this is the first open; read in where on the disk we are.
329 */
330 dl = rc->rc_disk.dk_label;
331 if (rc->rc_state == DK_CLOSED) {
332 u_int16_t mp;
333 int maj;
334 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
335 waitcrdy(sc);
336 mp = RL_RREG(RL_MP);
337 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
338 rc->rc_cyl = (mp >> 7) & 0777;
339 rc->rc_state = DK_OPEN;
340 /* Get disk label */
341 printf("%s: ", rc->rc_dev.dv_xname);
342 maj = cdevsw_lookup_major(&rl_cdevsw);
343 if ((msg = readdisklabel(MAKEDISKDEV(maj,
344 device_unit(&rc->rc_dev), RAW_PART), rlstrategy, dl, NULL)))
345 printf("%s: ", msg);
346 printf("size %d sectors\n", dl->d_secperunit);
347 }
348 if (part >= dl->d_npartitions) {
349 error = ENXIO;
350 goto bad1;
351 }
352
353 mask = 1 << part;
354 switch (fmt) {
355 case S_IFCHR:
356 rc->rc_disk.dk_copenmask |= mask;
357 break;
358 case S_IFBLK:
359 rc->rc_disk.dk_bopenmask |= mask;
360 break;
361 }
362 rc->rc_disk.dk_openmask |= mask;
363 error = 0;
364 bad1:
365 mutex_exit(&rc->rc_disk.dk_openlock);
366 return (error);
367 }
368
369 int
370 rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
371 {
372 int unit = DISKUNIT(dev);
373 struct rl_softc *rc = rl_cd.cd_devs[unit];
374 int mask = (1 << DISKPART(dev));
375
376 mutex_enter(&rc->rc_disk.dk_openlock);
377
378 switch (fmt) {
379 case S_IFCHR:
380 rc->rc_disk.dk_copenmask &= ~mask;
381 break;
382 case S_IFBLK:
383 rc->rc_disk.dk_bopenmask &= ~mask;
384 break;
385 }
386 rc->rc_disk.dk_openmask =
387 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
388
389 if (rc->rc_disk.dk_openmask == 0)
390 rc->rc_state = DK_CLOSED; /* May change pack */
391 mutex_exit(&rc->rc_disk.dk_openlock);
392 return 0;
393 }
394
395 void
396 rlstrategy(struct buf *bp)
397 {
398 struct disklabel *lp;
399 struct rlc_softc *sc;
400 struct rl_softc *rc;
401 int unit, s, err;
402 /*
403 * Make sure this is a reasonable drive to use.
404 */
405 unit = DISKUNIT(bp->b_dev);
406 if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
407 bp->b_error = ENXIO;
408 goto done;
409 }
410 if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
411 panic("rlstrategy: state impossible");
412
413 lp = rc->rc_disk.dk_label;
414 if ((err = bounds_check_with_label(&rc->rc_disk, bp, 1)) <= 0)
415 goto done;
416
417 if (bp->b_bcount == 0)
418 goto done;
419
420 bp->b_rawblkno =
421 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
422 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
423 sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
424
425 s = splbio();
426 BUFQ_PUT(sc->sc_q, bp);
427 rlcstart(sc, 0);
428 splx(s);
429 return;
430
431 done: biodone(bp);
432 }
433
434 int
435 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
436 {
437 struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
438 struct disklabel *lp = rc->rc_disk.dk_label;
439 int err = 0;
440 #ifdef __HAVE_OLD_DISKLABEL
441 struct disklabel newlabel;
442 #endif
443
444 switch (cmd) {
445 case DIOCGDINFO:
446 bcopy(lp, addr, sizeof (struct disklabel));
447 break;
448
449 #ifdef __HAVE_OLD_DISKLABEL
450 case ODIOCGDINFO:
451 newlabel = *lp;
452 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
453 return ENOTTY;
454 bcopy(&newlabel, addr, sizeof (struct olddisklabel));
455 break;
456 #endif
457
458 case DIOCGPART:
459 ((struct partinfo *)addr)->disklab = lp;
460 ((struct partinfo *)addr)->part =
461 &lp->d_partitions[DISKPART(dev)];
462 break;
463
464 case DIOCSDINFO:
465 case DIOCWDINFO:
466 #ifdef __HAVE_OLD_DISKLABEL
467 case ODIOCWDINFO:
468 case ODIOCSDINFO:
469 #endif
470 {
471 struct disklabel *tp;
472
473 #ifdef __HAVE_OLD_DISKLABEL
474 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
475 memset(&newlabel, 0, sizeof newlabel);
476 memcpy(&newlabel, addr, sizeof (struct olddisklabel));
477 tp = &newlabel;
478 } else
479 #endif
480 tp = (struct disklabel *)addr;
481
482 if ((flag & FWRITE) == 0)
483 err = EBADF;
484 else {
485 mutex_enter(&rc->rc_disk.dk_openlock);
486 err = ((
487 #ifdef __HAVE_OLD_DISKLABEL
488 cmd == ODIOCSDINFO ||
489 #endif
490 cmd == DIOCSDINFO) ?
491 setdisklabel(lp, tp, 0, 0) :
492 writedisklabel(dev, rlstrategy, lp, 0));
493 mutex_exit(&rc->rc_disk.dk_openlock);
494 }
495 break;
496 }
497
498 case DIOCWLABEL:
499 if ((flag & FWRITE) == 0)
500 err = EBADF;
501 break;
502
503 case DIOCAWEDGE:
504 {
505 struct dkwedge_info *dkw = (void *) addr;
506
507 if ((flag & FWRITE) == 0)
508 return (EBADF);
509
510 /* If the ioctl happens here, the parent is us. */
511 strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
512 return (dkwedge_add(dkw));
513 }
514
515 case DIOCDWEDGE:
516 {
517 struct dkwedge_info *dkw = (void *) addr;
518
519 if ((flag & FWRITE) == 0)
520 return (EBADF);
521
522 /* If the ioctl happens here, the parent is us. */
523 strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
524 return (dkwedge_del(dkw));
525 }
526
527 case DIOCLWEDGES:
528 {
529 struct dkwedge_list *dkwl = (void *) addr;
530
531 return (dkwedge_list(&rc->rc_disk, dkwl, l));
532 }
533
534 default:
535 err = ENOTTY;
536 }
537 return err;
538 }
539
540 int
541 rlsize(dev_t dev)
542 {
543 struct disklabel *dl;
544 struct rl_softc *rc;
545 int size, unit = DISKUNIT(dev);
546
547 if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
548 return -1;
549 dl = rc->rc_disk.dk_label;
550 size = dl->d_partitions[DISKPART(dev)].p_size *
551 (dl->d_secsize / DEV_BSIZE);
552 return size;
553 }
554
555 int
556 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
557 {
558 /* Not likely... */
559 return 0;
560 }
561
562 int
563 rlread(dev_t dev, struct uio *uio, int ioflag)
564 {
565 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
566 }
567
568 int
569 rlwrite(dev_t dev, struct uio *uio, int ioflag)
570 {
571 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
572 }
573
574 static const char *rlerr[] = {
575 "no",
576 "operation incomplete",
577 "read data CRC",
578 "header CRC",
579 "data late",
580 "header not found",
581 "",
582 "",
583 "non-existent memory",
584 "memory parity error",
585 "",
586 "",
587 "",
588 "",
589 "",
590 "",
591 };
592
593 void
594 rlcintr(void *arg)
595 {
596 struct rlc_softc *sc = arg;
597 struct buf *bp;
598 u_int16_t cs;
599
600 bp = sc->sc_active;
601 if (bp == 0) {
602 printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
603 return;
604 }
605 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
606 sc->sc_active = 0;
607 cs = RL_RREG(RL_CS);
608 if (cs & RLCS_ERR) {
609 int error = (cs & RLCS_ERRMSK) >> 10;
610
611 printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
612 bp->b_error = EIO;
613 bp->b_resid = bp->b_bcount;
614 sc->sc_bytecnt = 0;
615 }
616 if (sc->sc_bytecnt == 0) /* Finished transfer */
617 biodone(bp);
618 rlcstart(sc, sc->sc_bytecnt ? bp : 0);
619 }
620
621 /*
622 * Start routine. First position the disk to the given position,
623 * then start reading/writing. An optimization would be to be able
624 * to handle overlapping seeks between disks.
625 */
626 void
627 rlcstart(struct rlc_softc *sc, struct buf *ob)
628 {
629 struct disklabel *lp;
630 struct rl_softc *rc;
631 struct buf *bp;
632 int bn, cn, sn, tn, blks, err;
633
634 if (sc->sc_active)
635 return; /* Already doing something */
636
637 if (ob == 0) {
638 bp = BUFQ_GET(sc->sc_q);
639 if (bp == NULL)
640 return; /* Nothing to do */
641 sc->sc_bufaddr = bp->b_data;
642 sc->sc_diskblk = bp->b_rawblkno;
643 sc->sc_bytecnt = bp->b_bcount;
644 bp->b_resid = 0;
645 } else
646 bp = ob;
647 sc->sc_active = bp;
648
649 rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
650 bn = sc->sc_diskblk;
651 lp = rc->rc_disk.dk_label;
652 if (bn) {
653 cn = bn / lp->d_secpercyl;
654 sn = bn % lp->d_secpercyl;
655 tn = sn / lp->d_nsectors;
656 sn = sn % lp->d_nsectors;
657 } else
658 cn = sn = tn = 0;
659
660 /*
661 * Check if we have to position disk first.
662 */
663 if (rc->rc_cyl != cn || rc->rc_head != tn) {
664 u_int16_t da = RLDA_SEEK;
665 if (cn > rc->rc_cyl)
666 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
667 else
668 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
669 if (tn)
670 da |= RLDA_HSSEEK;
671 waitcrdy(sc);
672 RL_WREG(RL_DA, da);
673 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
674 waitcrdy(sc);
675 rc->rc_cyl = cn;
676 rc->rc_head = tn;
677 }
678 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
679 blks = sc->sc_bytecnt/DEV_BSIZE;
680
681 if (sn + blks > RL_SPT/2)
682 blks = RL_SPT/2 - sn;
683 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
684 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
685 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
686 BUS_DMA_NOWAIT);
687 if (err)
688 panic("%s: bus_dmamap_load failed: %d",
689 sc->sc_dev.dv_xname, err);
690 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
691
692 /* Count up vars */
693 sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE);
694 sc->sc_diskblk += blks;
695 sc->sc_bytecnt -= (blks*DEV_BSIZE);
696
697 if (bp->b_flags & B_READ)
698 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
699 else
700 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
701 }
702
703 /*
704 * Called once per controller when an ubareset occurs.
705 * Retracts all disks and restarts active transfers.
706 */
707 void
708 rlcreset(struct device *dev)
709 {
710 struct rlc_softc *sc = (struct rlc_softc *)dev;
711 struct rl_softc *rc;
712 int i;
713 u_int16_t mp;
714
715 for (i = 0; i < rl_cd.cd_ndevs; i++) {
716 if ((rc = rl_cd.cd_devs[i]) == NULL)
717 continue;
718 if (rc->rc_state != DK_OPEN)
719 continue;
720
721 printf(" %s", rc->rc_dev.dv_xname);
722 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
723 waitcrdy(sc);
724 mp = RL_RREG(RL_MP);
725 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
726 rc->rc_cyl = (mp >> 7) & 0777;
727 }
728 if (sc->sc_active == 0)
729 return;
730
731 BUFQ_PUT(sc->sc_q, sc->sc_active);
732 sc->sc_active = 0;
733 rlcstart(sc, 0);
734 }
735