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