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