rl.c revision 1.22 1 /* $NetBSD: rl.c,v 1.22 2004/09/25 16:27:38 thorpej 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.22 2004/09/25 16:27:38 thorpej 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/stat.h>
56 #include <sys/dkio.h>
57 #include <sys/fcntl.h>
58 #include <sys/event.h>
59
60 #include <ufs/ufs/dinode.h>
61 #include <ufs/ffs/fs.h>
62
63 #include <machine/bus.h>
64
65 #include <dev/qbus/ubavar.h>
66 #include <dev/qbus/rlreg.h>
67 #include <dev/qbus/rlvar.h>
68
69 #include "ioconf.h"
70 #include "locators.h"
71
72 static int rlcmatch(struct device *, struct cfdata *, void *);
73 static void rlcattach(struct device *, struct device *, void *);
74 static int rlcprint(void *, const char *);
75 static void rlcintr(void *);
76 static int rlmatch(struct device *, struct cfdata *, void *);
77 static void rlattach(struct device *, struct device *, void *);
78 static void rlcstart(struct rlc_softc *, struct buf *);
79 static void waitcrdy(struct rlc_softc *);
80 static void rlcreset(struct device *);
81
82 CFATTACH_DECL(rlc, sizeof(struct rlc_softc),
83 rlcmatch, rlcattach, NULL, NULL);
84
85 CFATTACH_DECL(rl, sizeof(struct rl_softc),
86 rlmatch, rlattach, NULL, NULL);
87
88 dev_type_open(rlopen);
89 dev_type_close(rlclose);
90 dev_type_read(rlread);
91 dev_type_write(rlwrite);
92 dev_type_ioctl(rlioctl);
93 dev_type_strategy(rlstrategy);
94 dev_type_dump(rldump);
95 dev_type_size(rlsize);
96
97 const struct bdevsw rl_bdevsw = {
98 rlopen, rlclose, rlstrategy, rlioctl, rldump, rlsize, D_DISK
99 };
100
101 const struct cdevsw rl_cdevsw = {
102 rlopen, rlclose, rlread, rlwrite, rlioctl,
103 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
104 };
105
106 #define MAXRLXFER (RL_BPS * RL_SPT)
107
108 #define RL_WREG(reg, val) \
109 bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
110 #define RL_RREG(reg) \
111 bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
112
113 static char *rlstates[] = {
114 "drive not loaded",
115 "drive spinning up",
116 "drive brushes out",
117 "drive loading heads",
118 "drive seeking",
119 "drive ready",
120 "drive unloading heads",
121 "drive spun down",
122 };
123
124 static struct dkdriver rldkdriver = {
125 rlstrategy, minphys
126 };
127
128 static char *
129 rlstate(struct rlc_softc *sc, int unit)
130 {
131 int i = 0;
132
133 do {
134 RL_WREG(RL_DA, RLDA_GS);
135 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT));
136 waitcrdy(sc);
137 } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10);
138 if (i == 10)
139 return NULL;
140 i = RL_RREG(RL_MP) & RLMP_STATUS;
141 return rlstates[i];
142 }
143
144 void
145 waitcrdy(struct rlc_softc *sc)
146 {
147 int i;
148
149 for (i = 0; i < 1000; i++) {
150 DELAY(10000);
151 if (RL_RREG(RL_CS) & RLCS_CRDY)
152 return;
153 }
154 printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
155 }
156
157 int
158 rlcprint(void *aux, const char *name)
159 {
160 struct rlc_attach_args *ra = aux;
161
162 if (name)
163 aprint_normal("RL0%d at %s",
164 ra->type & RLMP_DT ? '2' : '1', name);
165 aprint_normal(" drive %d", ra->hwid);
166 return UNCONF;
167 }
168
169 /*
170 * Force the controller to interrupt.
171 */
172 int
173 rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
174 {
175 struct uba_attach_args *ua = aux;
176 struct rlc_softc ssc, *sc = &ssc;
177 int i;
178
179 sc->sc_iot = ua->ua_iot;
180 sc->sc_ioh = ua->ua_ioh;
181 /* Force interrupt by issuing a "Get Status" command */
182 RL_WREG(RL_DA, RLDA_GS);
183 RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
184
185 for (i = 0; i < 100; i++) {
186 DELAY(100000);
187 if (RL_RREG(RL_CS) & RLCS_CRDY)
188 return 1;
189 }
190 return 0;
191 }
192
193 void
194 rlcattach(struct device *parent, struct device *self, void *aux)
195 {
196 struct rlc_softc *sc = (struct rlc_softc *)self;
197 struct uba_attach_args *ua = aux;
198 struct rlc_attach_args ra;
199 int i, error;
200
201 sc->sc_iot = ua->ua_iot;
202 sc->sc_ioh = ua->ua_ioh;
203 sc->sc_dmat = ua->ua_dmat;
204 uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
205 rlcintr, sc, &sc->sc_intrcnt);
206 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
207 sc->sc_dev.dv_xname, "intr");
208 uba_reset_establish(rlcreset, self);
209
210 printf("\n");
211
212 /*
213 * The RL11 can only have one transfer going at a time,
214 * and max transfer size is one track, so only one dmamap
215 * is needed.
216 */
217 error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
218 BUS_DMA_ALLOCNOW, &sc->sc_dmam);
219 if (error) {
220 printf(": Failed to allocate DMA map, error %d\n", error);
221 return;
222 }
223 bufq_alloc(&sc->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
224 for (i = 0; i < RL_MAXDPC; i++) {
225 waitcrdy(sc);
226 RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
227 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
228 waitcrdy(sc);
229 ra.type = RL_RREG(RL_MP);
230 ra.hwid = i;
231 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
232 config_found(&sc->sc_dev, &ra, rlcprint);
233 }
234 }
235
236 int
237 rlmatch(struct device *parent, struct cfdata *cf, void *aux)
238 {
239 struct rlc_attach_args *ra = aux;
240
241 if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
242 cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
243 return 0;
244 return 1;
245 }
246
247 void
248 rlattach(struct device *parent, struct device *self, void *aux)
249 {
250 struct rl_softc *rc = (struct rl_softc *)self;
251 struct rlc_attach_args *ra = aux;
252 struct disklabel *dl;
253
254 rc->rc_hwid = ra->hwid;
255 rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
256 rc->rc_disk.dk_driver = &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 proc *p)
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 if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE,
309 NULL)) != 0)
310 return (error);
311
312 /*
313 * If there are wedges, and this is not RAW_PART, then we
314 * need to fail.
315 */
316 if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
317 error = EBUSY;
318 goto bad1;
319 }
320
321 sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
322 /* Check that the disk actually is useable */
323 msg = rlstate(sc, rc->rc_hwid);
324 if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
325 msg == rlstates[RLMP_SPUNDOWN]) {
326 error = ENXIO;
327 goto bad1;
328 }
329 /*
330 * If this is the first open; read in where on the disk we are.
331 */
332 dl = rc->rc_disk.dk_label;
333 if (rc->rc_state == DK_CLOSED) {
334 u_int16_t mp;
335 int maj;
336 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
337 waitcrdy(sc);
338 mp = RL_RREG(RL_MP);
339 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
340 rc->rc_cyl = (mp >> 7) & 0777;
341 rc->rc_state = DK_OPEN;
342 /* Get disk label */
343 printf("%s: ", rc->rc_dev.dv_xname);
344 maj = cdevsw_lookup_major(&rl_cdevsw);
345 if ((msg = readdisklabel(MAKEDISKDEV(maj,
346 rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL)))
347 printf("%s: ", msg);
348 printf("size %d sectors\n", dl->d_secperunit);
349 }
350 if (part >= dl->d_npartitions) {
351 error = ENXIO;
352 goto bad1;
353 }
354
355 mask = 1 << part;
356 switch (fmt) {
357 case S_IFCHR:
358 rc->rc_disk.dk_copenmask |= mask;
359 break;
360 case S_IFBLK:
361 rc->rc_disk.dk_bopenmask |= mask;
362 break;
363 }
364 rc->rc_disk.dk_openmask |= mask;
365 (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
366 return 0;
367
368 bad1:
369 (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
370 return (error);
371 }
372
373 int
374 rlclose(dev_t dev, int flag, int fmt, struct proc *p)
375 {
376 int error, unit = DISKUNIT(dev);
377 struct rl_softc *rc = rl_cd.cd_devs[unit];
378 int mask = (1 << DISKPART(dev));
379
380 if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE,
381 NULL)) != 0)
382 return (error);
383
384 switch (fmt) {
385 case S_IFCHR:
386 rc->rc_disk.dk_copenmask &= ~mask;
387 break;
388 case S_IFBLK:
389 rc->rc_disk.dk_bopenmask &= ~mask;
390 break;
391 }
392 rc->rc_disk.dk_openmask =
393 rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
394
395 if (rc->rc_disk.dk_openmask == 0)
396 rc->rc_state = DK_CLOSED; /* May change pack */
397 (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
398 return 0;
399 }
400
401 void
402 rlstrategy(struct buf *bp)
403 {
404 struct disklabel *lp;
405 struct rlc_softc *sc;
406 struct rl_softc *rc;
407 int unit, s, err;
408 /*
409 * Make sure this is a reasonable drive to use.
410 */
411 unit = DISKUNIT(bp->b_dev);
412 if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
413 bp->b_error = ENXIO;
414 bp->b_flags |= B_ERROR;
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 *)rc->rc_dev.dv_parent;
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, caddr_t addr, int flag, struct proc *p)
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, p));
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, caddr_t 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 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_flags |= B_ERROR;
623 bp->b_error = EIO;
624 bp->b_resid = bp->b_bcount;
625 sc->sc_bytecnt = 0;
626 }
627 if (sc->sc_bytecnt == 0) /* Finished transfer */
628 biodone(bp);
629 rlcstart(sc, sc->sc_bytecnt ? bp : 0);
630 }
631
632 /*
633 * Start routine. First position the disk to the given position,
634 * then start reading/writing. An optimization would be to be able
635 * to handle overlapping seeks between disks.
636 */
637 void
638 rlcstart(struct rlc_softc *sc, struct buf *ob)
639 {
640 struct disklabel *lp;
641 struct rl_softc *rc;
642 struct buf *bp;
643 int bn, cn, sn, tn, blks, err;
644
645 if (sc->sc_active)
646 return; /* Already doing something */
647
648 if (ob == 0) {
649 bp = BUFQ_GET(&sc->sc_q);
650 if (bp == NULL)
651 return; /* Nothing to do */
652 sc->sc_bufaddr = bp->b_data;
653 sc->sc_diskblk = bp->b_rawblkno;
654 sc->sc_bytecnt = bp->b_bcount;
655 bp->b_resid = 0;
656 } else
657 bp = ob;
658 sc->sc_active = bp;
659
660 rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
661 bn = sc->sc_diskblk;
662 lp = rc->rc_disk.dk_label;
663 if (bn) {
664 cn = bn / lp->d_secpercyl;
665 sn = bn % lp->d_secpercyl;
666 tn = sn / lp->d_nsectors;
667 sn = sn % lp->d_nsectors;
668 } else
669 cn = sn = tn = 0;
670
671 /*
672 * Check if we have to position disk first.
673 */
674 if (rc->rc_cyl != cn || rc->rc_head != tn) {
675 u_int16_t da = RLDA_SEEK;
676 if (cn > rc->rc_cyl)
677 da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
678 else
679 da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
680 if (tn)
681 da |= RLDA_HSSEEK;
682 waitcrdy(sc);
683 RL_WREG(RL_DA, da);
684 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
685 waitcrdy(sc);
686 rc->rc_cyl = cn;
687 rc->rc_head = tn;
688 }
689 RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
690 blks = sc->sc_bytecnt/DEV_BSIZE;
691
692 if (sn + blks > RL_SPT/2)
693 blks = RL_SPT/2 - sn;
694 RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
695 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
696 (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
697 BUS_DMA_NOWAIT);
698 if (err)
699 panic("%s: bus_dmamap_load failed: %d",
700 sc->sc_dev.dv_xname, err);
701 RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
702
703 /* Count up vars */
704 sc->sc_bufaddr += (blks*DEV_BSIZE);
705 sc->sc_diskblk += blks;
706 sc->sc_bytecnt -= (blks*DEV_BSIZE);
707
708 if (bp->b_flags & B_READ)
709 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
710 else
711 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
712 }
713
714 /*
715 * Called once per controller when an ubareset occurs.
716 * Retracts all disks and restarts active transfers.
717 */
718 void
719 rlcreset(struct device *dev)
720 {
721 struct rlc_softc *sc = (struct rlc_softc *)dev;
722 struct rl_softc *rc;
723 int i;
724 u_int16_t mp;
725
726 for (i = 0; i < rl_cd.cd_ndevs; i++) {
727 if ((rc = rl_cd.cd_devs[i]) == NULL)
728 continue;
729 if (rc->rc_state != DK_OPEN)
730 continue;
731
732 printf(" %s", rc->rc_dev.dv_xname);
733 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
734 waitcrdy(sc);
735 mp = RL_RREG(RL_MP);
736 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
737 rc->rc_cyl = (mp >> 7) & 0777;
738 }
739 if (sc->sc_active == 0)
740 return;
741
742 BUFQ_PUT(&sc->sc_q, sc->sc_active);
743 sc->sc_active = 0;
744 rlcstart(sc, 0);
745 }
746