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