rl.c revision 1.43 1 /* $NetBSD: rl.c,v 1.43 2014/03/16 05:20:29 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.43 2014/03/16 05:20:29 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_flag = D_DISK
106 };
107
108 const struct cdevsw rl_cdevsw = {
109 .d_open = rlopen,
110 .d_close = rlclose,
111 .d_read = rlread,
112 .d_write = rlwrite,
113 .d_ioctl = rlioctl,
114 .d_stop = nostop,
115 .d_tty = notty,
116 .d_poll = nopoll,
117 .d_mmap = nommap,
118 .d_kqfilter = nokqfilter,
119 .d_flag = D_DISK
120 };
121
122 #define MAXRLXFER (RL_BPS * RL_SPT)
123
124 #define RL_WREG(reg, val) \
125 bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
126 #define RL_RREG(reg) \
127 bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
128
129 static const char * const rlstates[] = {
130 "drive not loaded",
131 "drive spinning up",
132 "drive brushes out",
133 "drive loading heads",
134 "drive seeking",
135 "drive ready",
136 "drive unloading heads",
137 "drive spun down",
138 };
139
140 static const struct dkdriver rldkdriver = {
141 rlstrategy, minphys
142 };
143
144 static const char *
145 rlstate(struct rlc_softc *sc, int unit)
146 {
147 int i = 0;
148
149 do {
150 RL_WREG(RL_DA, RLDA_GS);
151 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT));
152 waitcrdy(sc);
153 } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10);
154 if (i == 10)
155 return NULL;
156 i = RL_RREG(RL_MP) & RLMP_STATUS;
157 return rlstates[i];
158 }
159
160 void
161 waitcrdy(struct rlc_softc *sc)
162 {
163 int i;
164
165 for (i = 0; i < 1000; i++) {
166 DELAY(10000);
167 if (RL_RREG(RL_CS) & RLCS_CRDY)
168 return;
169 }
170 aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */
171 }
172
173 int
174 rlcprint(void *aux, const char *name)
175 {
176 struct rlc_attach_args *ra = aux;
177
178 if (name)
179 aprint_normal("RL0%d at %s",
180 ra->type & RLMP_DT ? '2' : '1', name);
181 aprint_normal(" drive %d", ra->hwid);
182 return UNCONF;
183 }
184
185 /*
186 * Force the controller to interrupt.
187 */
188 int
189 rlcmatch(device_t parent, cfdata_t cf, void *aux)
190 {
191 struct uba_attach_args *ua = aux;
192 struct rlc_softc ssc, *sc = &ssc;
193 int i;
194
195 sc->sc_iot = ua->ua_iot;
196 sc->sc_ioh = ua->ua_ioh;
197 /* Force interrupt by issuing a "Get Status" command */
198 RL_WREG(RL_DA, RLDA_GS);
199 RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
200
201 for (i = 0; i < 100; i++) {
202 DELAY(100000);
203 if (RL_RREG(RL_CS) & RLCS_CRDY)
204 return 1;
205 }
206 return 0;
207 }
208
209 void
210 rlcattach(device_t parent, device_t self, void *aux)
211 {
212 struct rlc_softc *sc = device_private(self);
213 struct uba_attach_args *ua = aux;
214 struct rlc_attach_args ra;
215 int i, error;
216
217 sc->sc_dev = self;
218 sc->sc_uh = device_private(parent);
219 sc->sc_iot = ua->ua_iot;
220 sc->sc_ioh = ua->ua_ioh;
221 sc->sc_dmat = ua->ua_dmat;
222 uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
223 rlcintr, sc, &sc->sc_intrcnt);
224 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
225 device_xname(sc->sc_dev), "intr");
226 uba_reset_establish(rlcreset, self);
227
228 printf("\n");
229
230 /*
231 * The RL11 can only have one transfer going at a time,
232 * and max transfer size is one track, so only one dmamap
233 * is needed.
234 */
235 error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
236 BUS_DMA_ALLOCNOW, &sc->sc_dmam);
237 if (error) {
238 aprint_error(": Failed to allocate DMA map, error %d\n", error);
239 return;
240 }
241 bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER);
242 for (i = 0; i < RL_MAXDPC; i++) {
243 waitcrdy(sc);
244 RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
245 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
246 waitcrdy(sc);
247 ra.type = RL_RREG(RL_MP);
248 ra.hwid = i;
249 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
250 config_found(sc->sc_dev, &ra, rlcprint);
251 }
252 }
253
254 int
255 rlmatch(device_t parent, cfdata_t cf, void *aux)
256 {
257 struct rlc_attach_args *ra = aux;
258
259 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
260 cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
261 return 0;
262 return 1;
263 }
264
265 void
266 rlattach(device_t parent, device_t self, void *aux)
267 {
268 struct rl_softc *rc = device_private(self);
269 struct rlc_attach_args *ra = aux;
270 struct disklabel *dl;
271
272 rc->rc_dev = self;
273 rc->rc_rlc = device_private(parent);
274 rc->rc_hwid = ra->hwid;
275 disk_init(&rc->rc_disk, device_xname(rc->rc_dev), &rldkdriver);
276 disk_attach(&rc->rc_disk);
277 dl = rc->rc_disk.dk_label;
278 dl->d_npartitions = 3;
279 strcpy(dl->d_typename, "RL01");
280 if (ra->type & RLMP_DT)
281 dl->d_typename[3] = '2';
282 dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
283 dl->d_nsectors = RL_SPT/2;
284 dl->d_ntracks = RL_SPD;
285 dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
286 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
287 dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
288 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
289 dl->d_secperunit;
290 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
291 dl->d_interleave = dl->d_headswitch = 1;
292 dl->d_bbsize = BBSIZE;
293 dl->d_sbsize = SBLOCKSIZE;
294 dl->d_rpm = 2400;
295 dl->d_type = DTYPE_DEC;
296 printf(": %s, %s\n", dl->d_typename, rlstate(rc->rc_rlc, ra->hwid));
297
298 /*
299 * XXX We should try to discovery wedges here, but
300 * XXX that would mean loading up the pack and being
301 * XXX able to do I/O. Should use config_defer() here.
302 */
303 }
304
305 int
306 rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
307 {
308 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
309 struct rlc_softc *sc;
310 int error, part, mask;
311 struct disklabel *dl;
312 const char *msg;
313
314 /*
315 * Make sure this is a reasonable open request.
316 */
317 if (rc == NULL)
318 return ENXIO;
319
320 sc = rc->rc_rlc;
321 part = DISKPART(dev);
322
323 mutex_enter(&rc->rc_disk.dk_openlock);
324
325 /*
326 * If there are wedges, and this is not RAW_PART, then we
327 * need to fail.
328 */
329 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
330 error = EBUSY;
331 goto bad1;
332 }
333
334 /* Check that the disk actually is useable */
335 msg = rlstate(sc, rc->rc_hwid);
336 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
337 msg == rlstates[RLMP_SPUNDOWN]) {
338 error = ENXIO;
339 goto bad1;
340 }
341 /*
342 * If this is the first open; read in where on the disk we are.
343 */
344 dl = rc->rc_disk.dk_label;
345 if (rc->rc_state == DK_CLOSED) {
346 u_int16_t mp;
347 int maj;
348 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
349 waitcrdy(sc);
350 mp = RL_RREG(RL_MP);
351 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
352 rc->rc_cyl = (mp >> 7) & 0777;
353 rc->rc_state = DK_OPEN;
354 /* Get disk label */
355 maj = cdevsw_lookup_major(&rl_cdevsw);
356 if ((msg = readdisklabel(MAKEDISKDEV(maj,
357 device_unit(rc->rc_dev), RAW_PART), rlstrategy, dl, NULL)))
358 aprint_normal_dev(rc->rc_dev, "%s", msg);
359 aprint_normal_dev(rc->rc_dev, "size %d sectors\n",
360 dl->d_secperunit);
361 }
362 if (part >= dl->d_npartitions) {
363 error = ENXIO;
364 goto bad1;
365 }
366
367 mask = 1 << part;
368 switch (fmt) {
369 case S_IFCHR:
370 rc->rc_disk.dk_copenmask |= mask;
371 break;
372 case S_IFBLK:
373 rc->rc_disk.dk_bopenmask |= mask;
374 break;
375 }
376 rc->rc_disk.dk_openmask |= mask;
377 error = 0;
378 bad1:
379 mutex_exit(&rc->rc_disk.dk_openlock);
380 return (error);
381 }
382
383 int
384 rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
385 {
386 int unit = DISKUNIT(dev);
387 struct rl_softc *rc = device_lookup_private(&rl_cd, unit);
388 int mask = (1 << DISKPART(dev));
389
390 mutex_enter(&rc->rc_disk.dk_openlock);
391
392 switch (fmt) {
393 case S_IFCHR:
394 rc->rc_disk.dk_copenmask &= ~mask;
395 break;
396 case S_IFBLK:
397 rc->rc_disk.dk_bopenmask &= ~mask;
398 break;
399 }
400 rc->rc_disk.dk_openmask =
401 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
402
403 if (rc->rc_disk.dk_openmask == 0)
404 rc->rc_state = DK_CLOSED; /* May change pack */
405 mutex_exit(&rc->rc_disk.dk_openlock);
406 return 0;
407 }
408
409 void
410 rlstrategy(struct buf *bp)
411 {
412 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev));
413 struct disklabel *lp;
414 int s;
415
416 if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */
417 panic("rlstrategy: state impossible");
418
419 lp = rc->rc_disk.dk_label;
420 if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0)
421 goto done;
422
423 if (bp->b_bcount == 0)
424 goto done;
425
426 bp->b_rawblkno =
427 bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
428 bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
429
430 s = splbio();
431 bufq_put(rc->rc_rlc->sc_q, bp);
432 rlcstart(rc->rc_rlc, 0);
433 splx(s);
434 return;
435
436 done: biodone(bp);
437 }
438
439 int
440 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
441 {
442 struct rl_softc *rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
443 struct disklabel *lp = rc->rc_disk.dk_label;
444 int err = 0;
445 #ifdef __HAVE_OLD_DISKLABEL
446 struct disklabel newlabel;
447 #endif
448
449 switch (cmd) {
450 case DIOCGDINFO:
451 memcpy(addr, lp, sizeof (struct disklabel));
452 break;
453
454 #ifdef __HAVE_OLD_DISKLABEL
455 case ODIOCGDINFO:
456 newlabel = *lp;
457 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
458 return ENOTTY;
459 memcpy(addr, &newlabel, sizeof (struct olddisklabel));
460 break;
461 #endif
462
463 case DIOCGPART:
464 ((struct partinfo *)addr)->disklab = lp;
465 ((struct partinfo *)addr)->part =
466 &lp->d_partitions[DISKPART(dev)];
467 break;
468
469 case DIOCSDINFO:
470 case DIOCWDINFO:
471 #ifdef __HAVE_OLD_DISKLABEL
472 case ODIOCWDINFO:
473 case ODIOCSDINFO:
474 #endif
475 {
476 struct disklabel *tp;
477
478 #ifdef __HAVE_OLD_DISKLABEL
479 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
480 memset(&newlabel, 0, sizeof newlabel);
481 memcpy(&newlabel, addr, sizeof (struct olddisklabel));
482 tp = &newlabel;
483 } else
484 #endif
485 tp = (struct disklabel *)addr;
486
487 if ((flag & FWRITE) == 0)
488 err = EBADF;
489 else {
490 mutex_enter(&rc->rc_disk.dk_openlock);
491 err = ((
492 #ifdef __HAVE_OLD_DISKLABEL
493 cmd == ODIOCSDINFO ||
494 #endif
495 cmd == DIOCSDINFO) ?
496 setdisklabel(lp, tp, 0, 0) :
497 writedisklabel(dev, rlstrategy, lp, 0));
498 mutex_exit(&rc->rc_disk.dk_openlock);
499 }
500 break;
501 }
502
503 case DIOCWLABEL:
504 if ((flag & FWRITE) == 0)
505 err = EBADF;
506 break;
507
508 case DIOCAWEDGE: {
509 struct dkwedge_info *dkw = (void *) addr;
510
511 if ((flag & FWRITE) == 0)
512 return (EBADF);
513
514 /* If the ioctl happens here, the parent is us. */
515 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev));
516 return dkwedge_add(dkw);
517 }
518
519 case DIOCDWEDGE: {
520 struct dkwedge_info *dkw = (void *) addr;
521
522 if ((flag & FWRITE) == 0)
523 return (EBADF);
524
525 /* If the ioctl happens here, the parent is us. */
526 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev));
527 return dkwedge_del(dkw);
528 }
529
530 case DIOCLWEDGES: {
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 break;
539 }
540 return err;
541 }
542
543 int
544 rlpsize(dev_t dev)
545 {
546 struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
547 struct disklabel *dl;
548 int size;
549
550 if (rc == NULL)
551 return -1;
552 dl = rc->rc_disk.dk_label;
553 size = dl->d_partitions[DISKPART(dev)].p_size *
554 (dl->d_secsize / DEV_BSIZE);
555 return size;
556 }
557
558 int
559 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
560 {
561 /* Not likely... */
562 return 0;
563 }
564
565 int
566 rlread(dev_t dev, struct uio *uio, int ioflag)
567 {
568 return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
569 }
570
571 int
572 rlwrite(dev_t dev, struct uio *uio, int ioflag)
573 {
574 return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
575 }
576
577 static const char * const rlerr[] = {
578 "no",
579 "operation incomplete",
580 "read data CRC",
581 "header CRC",
582 "data late",
583 "header not found",
584 "",
585 "",
586 "non-existent memory",
587 "memory parity error",
588 "",
589 "",
590 "",
591 "",
592 "",
593 "",
594 };
595
596 void
597 rlcintr(void *arg)
598 {
599 struct rlc_softc *sc = arg;
600 struct buf *bp;
601 u_int16_t cs;
602
603 bp = sc->sc_active;
604 if (bp == 0) {
605 aprint_error_dev(sc->sc_dev, "strange interrupt\n");
606 return;
607 }
608 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
609 sc->sc_active = 0;
610 cs = RL_RREG(RL_CS);
611 if (cs & RLCS_ERR) {
612 int error = (cs & RLCS_ERRMSK) >> 10;
613
614 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[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 = device_lookup_private(&rl_cd, 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 device_xname(sc->sc_dev), 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(device_t dev)
712 {
713 struct rlc_softc *sc = device_private(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 = device_lookup_private(&rl_cd, i)) == NULL)
720 continue;
721 if (rc->rc_state != DK_OPEN)
722 continue;
723 if (rc->rc_rlc != sc)
724 continue;
725
726 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
727 waitcrdy(sc);
728 mp = RL_RREG(RL_MP);
729 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
730 rc->rc_cyl = (mp >> 7) & 0777;
731 }
732 if (sc->sc_active == 0)
733 return;
734
735 bufq_put(sc->sc_q, sc->sc_active);
736 sc->sc_active = 0;
737 rlcstart(sc, 0);
738 }
739