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