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