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