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