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 *
rlstate(struct rlc_softc * sc,int unit)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
waitcrdy(struct rlc_softc * sc)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
rlcprint(void * aux,const char * name)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
rlcmatch(device_t parent,cfdata_t cf,void * aux)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
rlcattach(device_t parent,device_t self,void * aux)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
rlmatch(device_t parent,cfdata_t cf,void * aux)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
rlattach(device_t parent,device_t self,void * aux)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
rlopen(dev_t dev,int flag,int fmt,struct lwp * l)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
rlclose(dev_t dev,int flag,int fmt,struct lwp * l)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
rlstrategy(struct buf * bp)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
rlioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)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
rlpsize(dev_t dev)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
rldump(dev_t dev,daddr_t blkno,void * va,size_t size)515 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
516 {
517           /* Not likely... */
518           return 0;
519 }
520 
521 int
rlread(dev_t dev,struct uio * uio,int ioflag)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
rlwrite(dev_t dev,struct uio * uio,int ioflag)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
rlcintr(void * arg)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
rlcstart(struct rlc_softc * sc,struct buf * ob)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
rlcreset(device_t dev)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 }
695