rl.c revision 1.3 1 1.3 thorpej /* $NetBSD: rl.c,v 1.3 2000/05/19 18:54:30 thorpej Exp $ */
2 1.1 ragge
3 1.1 ragge /*
4 1.1 ragge * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
5 1.1 ragge *
6 1.1 ragge * Redistribution and use in source and binary forms, with or without
7 1.1 ragge * modification, are permitted provided that the following conditions
8 1.1 ragge * are met:
9 1.1 ragge * 1. Redistributions of source code must retain the above copyright
10 1.1 ragge * notice, this list of conditions and the following disclaimer.
11 1.1 ragge * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 ragge * notice, this list of conditions and the following disclaimer in the
13 1.1 ragge * documentation and/or other materials provided with the distribution.
14 1.1 ragge * 3. All advertising materials mentioning features or use of this software
15 1.1 ragge * must display the following acknowledgement:
16 1.1 ragge * This product includes software developed at Ludd, University of
17 1.1 ragge * Lule}, Sweden and its contributors.
18 1.1 ragge * 4. The name of the author may not be used to endorse or promote products
19 1.1 ragge * derived from this software without specific prior written permission
20 1.1 ragge *
21 1.1 ragge * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 1.1 ragge * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 1.1 ragge * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 1.1 ragge * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 1.1 ragge * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 1.1 ragge * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 1.1 ragge * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 1.1 ragge * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 1.1 ragge * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 1.1 ragge * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 1.1 ragge */
32 1.1 ragge
33 1.1 ragge /*
34 1.1 ragge * RL11/RLV11/RLV12 disk controller driver and
35 1.1 ragge * RL01/RL02 disk device driver.
36 1.1 ragge *
37 1.1 ragge * TODO:
38 1.1 ragge * Handle disk errors more gracefully
39 1.1 ragge * Do overlapping seeks on multiple drives
40 1.1 ragge *
41 1.1 ragge * Implementation comments:
42 1.1 ragge *
43 1.1 ragge */
44 1.1 ragge
45 1.1 ragge #include <sys/param.h>
46 1.1 ragge #include <sys/device.h>
47 1.1 ragge #include <sys/systm.h>
48 1.1 ragge #include <sys/conf.h>
49 1.1 ragge #include <sys/disk.h>
50 1.1 ragge #include <sys/disklabel.h>
51 1.1 ragge #include <sys/buf.h>
52 1.1 ragge #include <sys/stat.h>
53 1.1 ragge #include <sys/dkio.h>
54 1.1 ragge #include <sys/fcntl.h>
55 1.1 ragge
56 1.1 ragge #include <ufs/ufs/dinode.h>
57 1.1 ragge #include <ufs/ffs/fs.h>
58 1.1 ragge
59 1.1 ragge #include <machine/bus.h>
60 1.1 ragge
61 1.1 ragge #include <dev/qbus/ubavar.h>
62 1.1 ragge #include <dev/qbus/rlreg.h>
63 1.1 ragge
64 1.1 ragge #include "ioconf.h"
65 1.1 ragge #include "locators.h"
66 1.1 ragge
67 1.1 ragge struct rlc_softc {
68 1.1 ragge struct device sc_dev;
69 1.1 ragge bus_space_tag_t sc_iot;
70 1.1 ragge bus_space_handle_t sc_ioh;
71 1.1 ragge bus_dma_tag_t sc_dmat;
72 1.1 ragge bus_dmamap_t sc_dmam;
73 1.1 ragge struct buf_queue sc_q; /* Queue of waiting bufs */
74 1.1 ragge struct buf *sc_active; /* Currently active buf */
75 1.1 ragge caddr_t sc_bufaddr; /* Current in-core address */
76 1.1 ragge int sc_diskblk; /* Current block on disk */
77 1.1 ragge int sc_bytecnt; /* How much left to transfer */
78 1.1 ragge };
79 1.1 ragge
80 1.1 ragge struct rl_softc {
81 1.1 ragge struct device rc_dev;
82 1.1 ragge struct disk rc_disk;
83 1.1 ragge int rc_state;
84 1.1 ragge int rc_head;
85 1.1 ragge int rc_cyl;
86 1.1 ragge int rc_hwid;
87 1.1 ragge };
88 1.1 ragge
89 1.1 ragge static int rlcmatch(struct device *, struct cfdata *, void *);
90 1.1 ragge static void rlcattach(struct device *, struct device *, void *);
91 1.1 ragge static int rlcprint(void *, const char *);
92 1.1 ragge static void rlcintr(void *);
93 1.1 ragge static int rlmatch(struct device *, struct cfdata *, void *);
94 1.1 ragge static void rlattach(struct device *, struct device *, void *);
95 1.1 ragge static void rlcstart(struct rlc_softc *, struct buf *);
96 1.1 ragge static void waitcrdy(struct rlc_softc *);
97 1.2 ragge static void rlreset(struct device *);
98 1.1 ragge cdev_decl(rl);
99 1.1 ragge bdev_decl(rl);
100 1.1 ragge
101 1.1 ragge struct cfattach rlc_ca = {
102 1.1 ragge sizeof(struct rlc_softc), rlcmatch, rlcattach
103 1.1 ragge };
104 1.1 ragge
105 1.1 ragge struct cfattach rl_ca = {
106 1.1 ragge sizeof(struct rl_softc), rlmatch, rlattach
107 1.1 ragge };
108 1.1 ragge
109 1.1 ragge struct rlc_attach_args {
110 1.1 ragge u_int16_t type;
111 1.1 ragge int hwid;
112 1.1 ragge };
113 1.1 ragge
114 1.1 ragge #define MAXRLXFER (RL_BPS * RL_SPT)
115 1.1 ragge #define RLMAJOR 14
116 1.1 ragge
117 1.1 ragge #define RL_WREG(reg, val) \
118 1.1 ragge bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
119 1.1 ragge #define RL_RREG(reg) \
120 1.1 ragge bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
121 1.1 ragge
122 1.1 ragge void
123 1.1 ragge waitcrdy(struct rlc_softc *sc)
124 1.1 ragge {
125 1.1 ragge int i;
126 1.1 ragge
127 1.1 ragge for (i = 0; i < 1000; i++) {
128 1.1 ragge DELAY(10000);
129 1.1 ragge if (RL_RREG(RL_CS) & RLCS_CRDY)
130 1.1 ragge return;
131 1.1 ragge }
132 1.1 ragge printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
133 1.1 ragge }
134 1.1 ragge
135 1.1 ragge int
136 1.1 ragge rlcprint(void *aux, const char *name)
137 1.1 ragge {
138 1.1 ragge struct rlc_attach_args *ra = aux;
139 1.1 ragge
140 1.1 ragge if (name)
141 1.1 ragge printf("RL0%d at %s", ra->type & RLMP_DT ? '2' : '1', name);
142 1.1 ragge printf(" drive %d", ra->hwid);
143 1.1 ragge return UNCONF;
144 1.1 ragge }
145 1.1 ragge
146 1.1 ragge /*
147 1.1 ragge * Force the controller to interrupt.
148 1.1 ragge */
149 1.1 ragge int
150 1.1 ragge rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
151 1.1 ragge {
152 1.1 ragge struct uba_attach_args *ua = aux;
153 1.1 ragge struct rlc_softc ssc, *sc = &ssc;
154 1.1 ragge int i;
155 1.1 ragge
156 1.1 ragge sc->sc_iot = ua->ua_iot;
157 1.1 ragge sc->sc_ioh = ua->ua_ioh;
158 1.1 ragge /* Force interrupt by issuing a "Get Status" command */
159 1.1 ragge RL_WREG(RL_DA, RLDA_GS);
160 1.1 ragge RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
161 1.1 ragge
162 1.1 ragge for (i = 0; i < 100; i++) {
163 1.1 ragge DELAY(100000);
164 1.1 ragge if (RL_RREG(RL_CS) & RLCS_CRDY)
165 1.1 ragge return 1;
166 1.1 ragge }
167 1.1 ragge return 0;
168 1.1 ragge }
169 1.1 ragge
170 1.1 ragge void
171 1.1 ragge rlcattach(struct device *parent, struct device *self, void *aux)
172 1.1 ragge {
173 1.1 ragge struct rlc_softc *sc = (struct rlc_softc *)self;
174 1.1 ragge struct uba_attach_args *ua = aux;
175 1.1 ragge struct rlc_attach_args ra;
176 1.1 ragge int i, error;
177 1.1 ragge
178 1.1 ragge sc->sc_iot = ua->ua_iot;
179 1.1 ragge sc->sc_ioh = ua->ua_ioh;
180 1.1 ragge sc->sc_dmat = ua->ua_dmat;
181 1.1 ragge uba_intr_establish(ua->ua_icookie, ua->ua_cvec, rlcintr, sc);
182 1.1 ragge printf("\n");
183 1.1 ragge
184 1.1 ragge /*
185 1.1 ragge * The RL11 can only have one transfer going at a time,
186 1.1 ragge * and max transfer size is one track, so only one dmamap
187 1.1 ragge * is needed.
188 1.1 ragge */
189 1.1 ragge error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
190 1.1 ragge BUS_DMA_ALLOCNOW, &sc->sc_dmam);
191 1.1 ragge if (error) {
192 1.1 ragge printf(": Failed to allocate DMA map, error %d\n", error);
193 1.1 ragge return;
194 1.1 ragge }
195 1.1 ragge BUFQ_INIT(&sc->sc_q);
196 1.1 ragge for (i = 0; i < RL_MAXDPC; i++) {
197 1.1 ragge waitcrdy(sc);
198 1.1 ragge RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
199 1.1 ragge RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
200 1.1 ragge waitcrdy(sc);
201 1.1 ragge ra.type = RL_RREG(RL_MP);
202 1.1 ragge ra.hwid = i;
203 1.1 ragge if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
204 1.1 ragge config_found(&sc->sc_dev, &ra, rlcprint);
205 1.1 ragge }
206 1.1 ragge }
207 1.1 ragge
208 1.1 ragge int
209 1.1 ragge rlmatch(struct device *parent, struct cfdata *cf, void *aux)
210 1.1 ragge {
211 1.1 ragge struct rlc_attach_args *ra = aux;
212 1.1 ragge
213 1.1 ragge if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
214 1.1 ragge cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
215 1.1 ragge return 0;
216 1.1 ragge return 1;
217 1.1 ragge }
218 1.1 ragge
219 1.1 ragge void
220 1.1 ragge rlattach(struct device *parent, struct device *self, void *aux)
221 1.1 ragge {
222 1.1 ragge struct rl_softc *rc = (struct rl_softc *)self;
223 1.1 ragge struct rlc_attach_args *ra = aux;
224 1.1 ragge struct disklabel *dl;
225 1.1 ragge
226 1.2 ragge uba_reset_establish(rlreset, self);
227 1.2 ragge
228 1.1 ragge rc->rc_hwid = ra->hwid;
229 1.1 ragge rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
230 1.1 ragge disk_attach(&rc->rc_disk);
231 1.1 ragge dl = rc->rc_disk.dk_label;
232 1.1 ragge dl->d_npartitions = 3;
233 1.1 ragge strcpy(dl->d_typename, "RL01");
234 1.1 ragge if (ra->type & RLMP_DT)
235 1.1 ragge dl->d_typename[3] = '2';
236 1.1 ragge dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
237 1.1 ragge dl->d_nsectors = RL_SPT/2;
238 1.1 ragge dl->d_ntracks = RL_SPD;
239 1.1 ragge dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
240 1.1 ragge dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
241 1.1 ragge dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
242 1.1 ragge dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
243 1.1 ragge dl->d_secperunit;
244 1.1 ragge dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
245 1.1 ragge dl->d_interleave = dl->d_headswitch = 1;
246 1.1 ragge dl->d_bbsize = BBSIZE;
247 1.1 ragge dl->d_sbsize = SBSIZE;
248 1.1 ragge dl->d_rpm = 2400;
249 1.1 ragge dl->d_type = DTYPE_DEC;
250 1.1 ragge printf(": %s\n", dl->d_typename);
251 1.1 ragge }
252 1.1 ragge
253 1.1 ragge int
254 1.1 ragge rlopen(dev_t dev, int flag, int fmt, struct proc *p)
255 1.1 ragge {
256 1.1 ragge int part, unit, mask;
257 1.1 ragge struct disklabel *dl;
258 1.1 ragge struct rlc_softc *sc;
259 1.1 ragge struct rl_softc *rc;
260 1.1 ragge char *msg;
261 1.1 ragge /*
262 1.1 ragge * Make sure this is a reasonable open request.
263 1.1 ragge */
264 1.1 ragge unit = DISKUNIT(dev);
265 1.1 ragge if (unit >= rl_cd.cd_ndevs)
266 1.1 ragge return ENXIO;
267 1.1 ragge rc = rl_cd.cd_devs[unit];
268 1.1 ragge if (rc == 0)
269 1.1 ragge return ENXIO;
270 1.1 ragge
271 1.1 ragge sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
272 1.1 ragge /* XXX - check that the disk actually is useable */
273 1.1 ragge /*
274 1.1 ragge * If this is the first open; read in where on the disk we are.
275 1.1 ragge */
276 1.1 ragge dl = rc->rc_disk.dk_label;
277 1.1 ragge if (rc->rc_state == DK_CLOSED) {
278 1.1 ragge u_int16_t mp;
279 1.1 ragge RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
280 1.1 ragge waitcrdy(sc);
281 1.1 ragge mp = RL_RREG(RL_MP);
282 1.1 ragge rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
283 1.1 ragge rc->rc_cyl = (mp >> 7) & 0777;
284 1.1 ragge rc->rc_state = DK_OPEN;
285 1.1 ragge /* Get disk label */
286 1.1 ragge printf("%s: ", rc->rc_dev.dv_xname);
287 1.1 ragge if ((msg = readdisklabel(MAKEDISKDEV(RLMAJOR,
288 1.1 ragge rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL)))
289 1.1 ragge printf("%s: ", msg);
290 1.1 ragge printf("size %d sectors\n", dl->d_secperunit);
291 1.1 ragge }
292 1.1 ragge part = DISKPART(dev);
293 1.1 ragge if (part >= dl->d_npartitions)
294 1.1 ragge return ENXIO;
295 1.1 ragge
296 1.1 ragge mask = 1 << part;
297 1.1 ragge switch (fmt) {
298 1.1 ragge case S_IFCHR:
299 1.1 ragge rc->rc_disk.dk_copenmask |= mask;
300 1.1 ragge break;
301 1.1 ragge case S_IFBLK:
302 1.1 ragge rc->rc_disk.dk_bopenmask |= mask;
303 1.1 ragge break;
304 1.1 ragge }
305 1.1 ragge rc->rc_disk.dk_openmask |= mask;
306 1.1 ragge return 0;
307 1.1 ragge }
308 1.1 ragge
309 1.1 ragge int
310 1.1 ragge rlclose(dev_t dev, int flag, int fmt, struct proc *p)
311 1.1 ragge {
312 1.1 ragge int unit = DISKUNIT(dev);
313 1.1 ragge struct rl_softc *rc = rl_cd.cd_devs[unit];
314 1.1 ragge int mask = (1 << DISKPART(dev));
315 1.1 ragge
316 1.1 ragge switch (fmt) {
317 1.1 ragge case S_IFCHR:
318 1.1 ragge rc->rc_disk.dk_copenmask &= ~mask;
319 1.1 ragge break;
320 1.1 ragge case S_IFBLK:
321 1.1 ragge rc->rc_disk.dk_bopenmask &= ~mask;
322 1.1 ragge break;
323 1.1 ragge }
324 1.1 ragge rc->rc_disk.dk_openmask =
325 1.1 ragge rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
326 1.1 ragge
327 1.1 ragge if (rc->rc_disk.dk_openmask == 0)
328 1.1 ragge rc->rc_state = DK_CLOSED; /* May change pack */
329 1.1 ragge return 0;
330 1.1 ragge }
331 1.1 ragge
332 1.1 ragge void
333 1.1 ragge rlstrategy(struct buf *bp)
334 1.1 ragge {
335 1.1 ragge struct disklabel *lp;
336 1.1 ragge struct rlc_softc *sc;
337 1.1 ragge struct rl_softc *rc;
338 1.1 ragge int unit, s, err;
339 1.1 ragge /*
340 1.1 ragge * Make sure this is a reasonable drive to use.
341 1.1 ragge */
342 1.1 ragge unit = DISKUNIT(bp->b_dev);
343 1.1 ragge if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
344 1.1 ragge bp->b_error = ENXIO;
345 1.1 ragge bp->b_flags |= B_ERROR;
346 1.1 ragge goto done;
347 1.1 ragge }
348 1.1 ragge if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
349 1.1 ragge panic("rlstrategy: state impossible");
350 1.1 ragge
351 1.1 ragge lp = rc->rc_disk.dk_label;
352 1.1 ragge if ((err = bounds_check_with_label(bp, lp, 1)) <= 0)
353 1.1 ragge goto done;
354 1.1 ragge
355 1.1 ragge if (bp->b_bcount == 0)
356 1.1 ragge goto done;
357 1.1 ragge
358 1.1 ragge bp->b_rawblkno =
359 1.1 ragge bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
360 1.1 ragge bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
361 1.1 ragge sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
362 1.1 ragge
363 1.1 ragge s = splimp();
364 1.1 ragge disksort_cylinder(&sc->sc_q, bp);
365 1.1 ragge rlcstart(sc, 0);
366 1.1 ragge splx(s);
367 1.1 ragge return;
368 1.1 ragge
369 1.1 ragge done: biodone(bp);
370 1.1 ragge }
371 1.1 ragge
372 1.1 ragge int
373 1.1 ragge rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
374 1.1 ragge {
375 1.1 ragge struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
376 1.1 ragge struct disklabel *lp = rc->rc_disk.dk_label;
377 1.1 ragge int err = 0;
378 1.1 ragge
379 1.1 ragge switch (cmd) {
380 1.1 ragge case DIOCGDINFO:
381 1.1 ragge bcopy(lp, addr, sizeof (struct disklabel));
382 1.1 ragge break;
383 1.1 ragge
384 1.1 ragge case DIOCGPART:
385 1.1 ragge ((struct partinfo *)addr)->disklab = lp;
386 1.1 ragge ((struct partinfo *)addr)->part =
387 1.1 ragge &lp->d_partitions[DISKPART(dev)];
388 1.1 ragge break;
389 1.1 ragge
390 1.1 ragge case DIOCSDINFO:
391 1.1 ragge case DIOCWDINFO:
392 1.1 ragge if ((flag & FWRITE) == 0)
393 1.1 ragge err = EBADF;
394 1.1 ragge else
395 1.1 ragge err = (cmd == DIOCSDINFO ?
396 1.1 ragge setdisklabel(lp, (struct disklabel *)addr, 0, 0) :
397 1.1 ragge writedisklabel(dev, rlstrategy, lp, 0));
398 1.1 ragge break;
399 1.1 ragge
400 1.1 ragge case DIOCWLABEL:
401 1.1 ragge if ((flag & FWRITE) == 0)
402 1.1 ragge err = EBADF;
403 1.1 ragge break;
404 1.1 ragge
405 1.1 ragge default:
406 1.1 ragge err = ENOTTY;
407 1.1 ragge }
408 1.1 ragge return err;
409 1.1 ragge }
410 1.1 ragge
411 1.1 ragge int
412 1.1 ragge rlsize(dev_t dev)
413 1.1 ragge {
414 1.1 ragge struct disklabel *dl;
415 1.1 ragge struct rl_softc *rc;
416 1.1 ragge int size, unit = DISKUNIT(dev);
417 1.1 ragge
418 1.1 ragge if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
419 1.1 ragge return -1;
420 1.1 ragge dl = rc->rc_disk.dk_label;
421 1.1 ragge size = dl->d_partitions[DISKPART(dev)].p_size *
422 1.1 ragge (dl->d_secsize / DEV_BSIZE);
423 1.1 ragge return size;
424 1.1 ragge }
425 1.1 ragge
426 1.1 ragge int
427 1.1 ragge rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
428 1.1 ragge {
429 1.1 ragge /* Not likely... */
430 1.1 ragge return 0;
431 1.1 ragge }
432 1.1 ragge
433 1.1 ragge int
434 1.1 ragge rlread(dev_t dev, struct uio *uio, int ioflag)
435 1.1 ragge {
436 1.1 ragge return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
437 1.1 ragge }
438 1.1 ragge
439 1.1 ragge int
440 1.1 ragge rlwrite(dev_t dev, struct uio *uio, int ioflag)
441 1.1 ragge {
442 1.1 ragge return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
443 1.1 ragge }
444 1.1 ragge
445 1.1 ragge static char *rlerr[] = {
446 1.1 ragge "no",
447 1.1 ragge "operation incomplete",
448 1.1 ragge "read data CRC",
449 1.1 ragge "header CRC",
450 1.1 ragge "data late",
451 1.1 ragge "header not found",
452 1.1 ragge "",
453 1.1 ragge "",
454 1.1 ragge "non-existant memory",
455 1.1 ragge "memory parity error",
456 1.1 ragge "",
457 1.1 ragge "",
458 1.1 ragge "",
459 1.1 ragge "",
460 1.1 ragge "",
461 1.1 ragge "",
462 1.1 ragge };
463 1.1 ragge
464 1.1 ragge void
465 1.1 ragge rlcintr(void *arg)
466 1.1 ragge {
467 1.1 ragge struct rlc_softc *sc = arg;
468 1.1 ragge struct buf *bp;
469 1.1 ragge u_int16_t cs;
470 1.1 ragge
471 1.1 ragge bp = sc->sc_active;
472 1.1 ragge if (bp == 0) {
473 1.1 ragge printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
474 1.1 ragge return;
475 1.1 ragge }
476 1.1 ragge bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
477 1.1 ragge sc->sc_active = 0;
478 1.1 ragge cs = RL_RREG(RL_CS);
479 1.1 ragge if (cs & RLCS_ERR) {
480 1.1 ragge int error = (cs & RLCS_ERRMSK) >> 10;
481 1.1 ragge
482 1.1 ragge printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
483 1.1 ragge bp->b_flags |= B_ERROR;
484 1.1 ragge bp->b_error = EIO;
485 1.1 ragge bp->b_resid = bp->b_bcount;
486 1.1 ragge sc->sc_bytecnt = 0;
487 1.1 ragge }
488 1.1 ragge if (sc->sc_bytecnt == 0) /* Finished transfer */
489 1.1 ragge biodone(bp);
490 1.1 ragge rlcstart(sc, sc->sc_bytecnt ? bp : 0);
491 1.1 ragge }
492 1.1 ragge
493 1.1 ragge /*
494 1.1 ragge * Start routine. First position the disk to the given position,
495 1.1 ragge * then start reading/writing. An optimization would be to be able
496 1.1 ragge * to handle overlapping seeks between disks.
497 1.1 ragge */
498 1.1 ragge void
499 1.1 ragge rlcstart(struct rlc_softc *sc, struct buf *ob)
500 1.1 ragge {
501 1.1 ragge struct disklabel *lp;
502 1.1 ragge struct rl_softc *rc;
503 1.1 ragge struct buf *bp;
504 1.1 ragge int bn, cn, sn, tn, blks, err;
505 1.1 ragge
506 1.1 ragge if (sc->sc_active)
507 1.1 ragge return; /* Already doing something */
508 1.1 ragge
509 1.1 ragge if (ob == 0) {
510 1.1 ragge bp = BUFQ_FIRST(&sc->sc_q);
511 1.1 ragge if (bp == NULL)
512 1.1 ragge return; /* Nothing to do */
513 1.1 ragge BUFQ_REMOVE(&sc->sc_q, bp);
514 1.3 thorpej sc->sc_bufaddr = bp->b_data;
515 1.1 ragge sc->sc_diskblk = bp->b_rawblkno;
516 1.1 ragge sc->sc_bytecnt = bp->b_bcount;
517 1.1 ragge bp->b_resid = 0;
518 1.1 ragge } else
519 1.1 ragge bp = ob;
520 1.1 ragge sc->sc_active = bp;
521 1.1 ragge
522 1.1 ragge rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
523 1.1 ragge bn = sc->sc_diskblk;
524 1.1 ragge lp = rc->rc_disk.dk_label;
525 1.1 ragge if (bn) {
526 1.1 ragge cn = bn / lp->d_secpercyl;
527 1.1 ragge sn = bn % lp->d_secpercyl;
528 1.1 ragge tn = sn / lp->d_nsectors;
529 1.1 ragge sn = sn % lp->d_nsectors;
530 1.1 ragge } else
531 1.1 ragge cn = sn = tn = 0;
532 1.1 ragge
533 1.1 ragge /*
534 1.1 ragge * Check if we have to position disk first.
535 1.1 ragge */
536 1.1 ragge if (rc->rc_cyl != cn || rc->rc_head != tn) {
537 1.1 ragge u_int16_t da = RLDA_SEEK;
538 1.1 ragge if (cn > rc->rc_cyl)
539 1.1 ragge da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
540 1.1 ragge else
541 1.1 ragge da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
542 1.1 ragge if (tn)
543 1.1 ragge da |= RLDA_HSSEEK;
544 1.1 ragge waitcrdy(sc);
545 1.1 ragge RL_WREG(RL_DA, da);
546 1.1 ragge RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
547 1.1 ragge waitcrdy(sc);
548 1.1 ragge rc->rc_cyl = cn;
549 1.1 ragge rc->rc_head = tn;
550 1.1 ragge }
551 1.1 ragge RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
552 1.1 ragge blks = sc->sc_bytecnt/DEV_BSIZE;
553 1.1 ragge
554 1.1 ragge if (sn + blks > RL_SPT/2)
555 1.1 ragge blks = RL_SPT/2 - sn;
556 1.1 ragge RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
557 1.1 ragge err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
558 1.1 ragge (blks*DEV_BSIZE), bp->b_proc, BUS_DMA_NOWAIT);
559 1.1 ragge if (err)
560 1.1 ragge panic("%s: bus_dmamap_load failed: %d",
561 1.1 ragge sc->sc_dev.dv_xname, err);
562 1.1 ragge RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
563 1.1 ragge
564 1.1 ragge /* Count up vars */
565 1.1 ragge sc->sc_bufaddr += (blks*DEV_BSIZE);
566 1.1 ragge sc->sc_diskblk += blks;
567 1.1 ragge sc->sc_bytecnt -= (blks*DEV_BSIZE);
568 1.1 ragge
569 1.1 ragge if (bp->b_flags & B_READ)
570 1.1 ragge RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
571 1.1 ragge else
572 1.1 ragge RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
573 1.2 ragge }
574 1.2 ragge
575 1.2 ragge void
576 1.2 ragge rlreset(struct device *dev)
577 1.2 ragge {
578 1.2 ragge struct rl_softc *rc = (struct rl_softc *)dev;
579 1.2 ragge struct rlc_softc *sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
580 1.2 ragge u_int16_t mp;
581 1.2 ragge
582 1.2 ragge if (rc->rc_state != DK_OPEN)
583 1.2 ragge return;
584 1.2 ragge RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
585 1.2 ragge waitcrdy(sc);
586 1.2 ragge mp = RL_RREG(RL_MP);
587 1.2 ragge rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
588 1.2 ragge rc->rc_cyl = (mp >> 7) & 0777;
589 1.2 ragge if (sc->sc_active == 0)
590 1.2 ragge return;
591 1.2 ragge
592 1.2 ragge BUFQ_INSERT_HEAD(&sc->sc_q, sc->sc_active);
593 1.2 ragge sc->sc_active = 0;
594 1.2 ragge rlcstart(sc, 0);
595 1.1 ragge }
596