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