fd.c revision 1.46 1 1.46 cegger /* $NetBSD: fd.c,v 1.46 2009/05/12 07:07:44 cegger Exp $ */
2 1.1 reinoud
3 1.1 reinoud /*-
4 1.1 reinoud * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 1.1 reinoud * All rights reserved.
6 1.1 reinoud *
7 1.1 reinoud * This code is derived from software contributed to The NetBSD Foundation
8 1.1 reinoud * by Charles M. Hannum.
9 1.1 reinoud *
10 1.1 reinoud * Redistribution and use in source and binary forms, with or without
11 1.1 reinoud * modification, are permitted provided that the following conditions
12 1.1 reinoud * are met:
13 1.1 reinoud * 1. Redistributions of source code must retain the above copyright
14 1.1 reinoud * notice, this list of conditions and the following disclaimer.
15 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 reinoud * notice, this list of conditions and the following disclaimer in the
17 1.1 reinoud * documentation and/or other materials provided with the distribution.
18 1.1 reinoud *
19 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 reinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 reinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 reinoud * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 reinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 reinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 reinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 reinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 reinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 reinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 reinoud * POSSIBILITY OF SUCH DAMAGE.
30 1.1 reinoud */
31 1.1 reinoud
32 1.1 reinoud /*-
33 1.1 reinoud * Copyright (c) 1990 The Regents of the University of California.
34 1.1 reinoud * All rights reserved.
35 1.1 reinoud *
36 1.1 reinoud * This code is derived from software contributed to Berkeley by
37 1.1 reinoud * Don Ahn.
38 1.1 reinoud *
39 1.1 reinoud * Redistribution and use in source and binary forms, with or without
40 1.1 reinoud * modification, are permitted provided that the following conditions
41 1.1 reinoud * are met:
42 1.1 reinoud * 1. Redistributions of source code must retain the above copyright
43 1.1 reinoud * notice, this list of conditions and the following disclaimer.
44 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright
45 1.1 reinoud * notice, this list of conditions and the following disclaimer in the
46 1.1 reinoud * documentation and/or other materials provided with the distribution.
47 1.18 agc * 3. Neither the name of the University nor the names of its contributors
48 1.1 reinoud * may be used to endorse or promote products derived from this software
49 1.1 reinoud * without specific prior written permission.
50 1.1 reinoud *
51 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 1.1 reinoud * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 1.1 reinoud * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 1.1 reinoud * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 1.1 reinoud * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 1.1 reinoud * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 1.1 reinoud * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 1.1 reinoud * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 1.1 reinoud * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 1.1 reinoud * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 1.1 reinoud * SUCH DAMAGE.
62 1.1 reinoud *
63 1.1 reinoud * @(#)fd.c 7.4 (Berkeley) 5/25/91
64 1.1 reinoud * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
65 1.1 reinoud */
66 1.1 reinoud
67 1.1 reinoud /*
68 1.1 reinoud * Floppy formatting facilities merged from FreeBSD fd.c driver:
69 1.1 reinoud * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
70 1.1 reinoud * which carries the same copyright/redistribution notice as shown above with
71 1.1 reinoud * the addition of the following statement before the "Redistribution and
72 1.1 reinoud * use ..." clause:
73 1.1 reinoud *
74 1.1 reinoud * Copyright (c) 1993, 1994 by
75 1.1 reinoud * jc (at) irbs.UUCP (John Capo)
76 1.1 reinoud * vak (at) zebub.msk.su (Serge Vakulenko)
77 1.1 reinoud * ache (at) astral.msk.su (Andrew A. Chernov)
78 1.1 reinoud *
79 1.1 reinoud * Copyright (c) 1993, 1994, 1995 by
80 1.1 reinoud * joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
81 1.1 reinoud * dufault (at) hda.com (Peter Dufault)
82 1.1 reinoud */
83 1.17 lukem
84 1.17 lukem #include <sys/cdefs.h>
85 1.46 cegger __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.46 2009/05/12 07:07:44 cegger Exp $");
86 1.1 reinoud
87 1.1 reinoud #include "opt_ddb.h"
88 1.1 reinoud
89 1.1 reinoud #include <sys/param.h>
90 1.1 reinoud #include <sys/systm.h>
91 1.1 reinoud #include <sys/callout.h>
92 1.1 reinoud #include <sys/kernel.h>
93 1.1 reinoud #include <sys/file.h>
94 1.1 reinoud #include <sys/ioctl.h>
95 1.1 reinoud #include <sys/device.h>
96 1.1 reinoud #include <sys/disklabel.h>
97 1.1 reinoud #include <sys/disk.h>
98 1.1 reinoud #include <sys/buf.h>
99 1.19 yamt #include <sys/bufq.h>
100 1.1 reinoud #include <sys/malloc.h>
101 1.1 reinoud #include <sys/uio.h>
102 1.1 reinoud #include <sys/syslog.h>
103 1.1 reinoud #include <sys/queue.h>
104 1.1 reinoud #include <sys/proc.h>
105 1.1 reinoud #include <sys/fdio.h>
106 1.6 gehenna #include <sys/conf.h>
107 1.1 reinoud
108 1.1 reinoud #include <uvm/uvm_extern.h>
109 1.1 reinoud
110 1.4 thorpej #include <arm/fiq.h>
111 1.4 thorpej
112 1.1 reinoud #include <machine/cpu.h>
113 1.3 thorpej #include <machine/intr.h>
114 1.1 reinoud #include <machine/io.h>
115 1.2 thorpej #include <arm/arm32/katelib.h>
116 1.1 reinoud #include <machine/bus.h>
117 1.4 thorpej
118 1.1 reinoud #include <arm/iomd/iomdreg.h>
119 1.4 thorpej #include <arm/iomd/iomdvar.h>
120 1.4 thorpej
121 1.1 reinoud #include <acorn32/mainbus/piocvar.h>
122 1.1 reinoud #include <acorn32/mainbus/fdreg.h>
123 1.1 reinoud
124 1.1 reinoud #include "locators.h"
125 1.1 reinoud
126 1.1 reinoud #define NE7CMD_CONFIGURE 0x13
127 1.1 reinoud
128 1.1 reinoud #define FDUNIT(dev) (minor(dev) / 8)
129 1.1 reinoud #define FDTYPE(dev) (minor(dev) % 8)
130 1.1 reinoud
131 1.27 reinoud /* (mis)use device use flag to identify format operation */
132 1.27 reinoud #define B_FORMAT B_DEVPRIVATE
133 1.1 reinoud
134 1.1 reinoud enum fdc_state {
135 1.1 reinoud DEVIDLE = 0,
136 1.1 reinoud MOTORWAIT,
137 1.1 reinoud DOSEEK,
138 1.1 reinoud SEEKWAIT,
139 1.1 reinoud SEEKTIMEDOUT,
140 1.1 reinoud SEEKCOMPLETE,
141 1.1 reinoud DOIO,
142 1.1 reinoud IOCOMPLETE,
143 1.1 reinoud IOTIMEDOUT,
144 1.1 reinoud DORESET,
145 1.1 reinoud RESETCOMPLETE,
146 1.1 reinoud RESETTIMEDOUT,
147 1.1 reinoud DORECAL,
148 1.1 reinoud RECALWAIT,
149 1.1 reinoud RECALTIMEDOUT,
150 1.1 reinoud RECALCOMPLETE,
151 1.1 reinoud };
152 1.1 reinoud
153 1.1 reinoud /* software state, per controller */
154 1.1 reinoud struct fdc_softc {
155 1.1 reinoud struct device sc_dev; /* boilerplate */
156 1.1 reinoud void *sc_ih;
157 1.1 reinoud
158 1.1 reinoud bus_space_tag_t sc_iot; /* ISA i/o space identifier */
159 1.1 reinoud bus_space_handle_t sc_ioh; /* ISA io handle */
160 1.1 reinoud
161 1.1 reinoud struct callout sc_timo_ch; /* timeout callout */
162 1.1 reinoud struct callout sc_intr_ch; /* pseudo-intr callout */
163 1.1 reinoud
164 1.4 thorpej /* ...for pseudo-DMA... */
165 1.4 thorpej struct fiqhandler sc_fh; /* FIQ handler descriptor */
166 1.4 thorpej struct fiqregs sc_fr; /* FIQ handler reg context */
167 1.1 reinoud int sc_drq;
168 1.1 reinoud
169 1.1 reinoud struct fd_softc *sc_fd[4]; /* pointers to children */
170 1.1 reinoud TAILQ_HEAD(drivehead, fd_softc) sc_drives;
171 1.1 reinoud enum fdc_state sc_state;
172 1.1 reinoud int sc_errors; /* number of retries so far */
173 1.1 reinoud u_char sc_status[7]; /* copy of registers */
174 1.1 reinoud };
175 1.1 reinoud
176 1.1 reinoud /* controller driver configuration */
177 1.43 dsl int fdcprobe(struct device *, struct cfdata *, void *);
178 1.43 dsl int fdprint(void *, const char *);
179 1.43 dsl void fdcattach(struct device *, struct device *, void *);
180 1.1 reinoud
181 1.9 thorpej CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
182 1.10 thorpej fdcprobe, fdcattach, NULL, NULL);
183 1.1 reinoud
184 1.1 reinoud /*
185 1.1 reinoud * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
186 1.1 reinoud * we tell them apart.
187 1.1 reinoud */
188 1.1 reinoud struct fd_type {
189 1.1 reinoud int sectrac; /* sectors per track */
190 1.1 reinoud int heads; /* number of heads */
191 1.1 reinoud int seccyl; /* sectors per cylinder */
192 1.1 reinoud int secsize; /* size code for sectors */
193 1.1 reinoud int datalen; /* data len when secsize = 0 */
194 1.1 reinoud int steprate; /* step rate and head unload time */
195 1.1 reinoud int gap1; /* gap len between sectors */
196 1.1 reinoud int gap2; /* formatting gap */
197 1.1 reinoud int cyls; /* total num of cylinders */
198 1.1 reinoud int size; /* size of disk in sectors */
199 1.1 reinoud int step; /* steps per cylinder */
200 1.1 reinoud int rate; /* transfer speed code */
201 1.1 reinoud u_char fillbyte; /* format fill byte */
202 1.1 reinoud u_char interleave; /* interleave factor (formatting) */
203 1.20 he const char *name;
204 1.1 reinoud };
205 1.1 reinoud
206 1.1 reinoud /* The order of entries in the following table is important -- BEWARE! */
207 1.1 reinoud struct fd_type fd_types[] = {
208 1.1 reinoud { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
209 1.1 reinoud { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
210 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
211 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
212 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */
213 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
214 1.1 reinoud { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
215 1.1 reinoud };
216 1.1 reinoud
217 1.1 reinoud /* software state, per disk (with up to 4 disks per ctlr) */
218 1.1 reinoud struct fd_softc {
219 1.1 reinoud struct device sc_dev;
220 1.1 reinoud struct disk sc_dk;
221 1.1 reinoud
222 1.1 reinoud struct fd_type *sc_deftype; /* default type descriptor */
223 1.1 reinoud struct fd_type *sc_type; /* current type descriptor */
224 1.1 reinoud struct fd_type sc_type_copy; /* copy for fiddling when formatting */
225 1.1 reinoud
226 1.1 reinoud struct callout sc_motoron_ch;
227 1.1 reinoud struct callout sc_motoroff_ch;
228 1.1 reinoud
229 1.1 reinoud daddr_t sc_blkno; /* starting block number */
230 1.1 reinoud int sc_bcount; /* byte count left */
231 1.1 reinoud int sc_opts; /* user-set options */
232 1.1 reinoud int sc_skip; /* bytes already transferred */
233 1.1 reinoud int sc_nblks; /* number of blocks currently transferring */
234 1.1 reinoud int sc_nbytes; /* number of bytes currently transferring */
235 1.1 reinoud
236 1.1 reinoud int sc_drive; /* physical unit number */
237 1.1 reinoud int sc_flags;
238 1.1 reinoud #define FD_OPEN 0x01 /* it's open */
239 1.1 reinoud #define FD_MOTOR 0x02 /* motor should be on */
240 1.1 reinoud #define FD_MOTOR_WAIT 0x04 /* motor coming up */
241 1.1 reinoud int sc_cylin; /* where we think the head is */
242 1.1 reinoud
243 1.1 reinoud void *sc_sdhook; /* saved shutdown hook for drive. */
244 1.1 reinoud
245 1.1 reinoud TAILQ_ENTRY(fd_softc) sc_drivechain;
246 1.1 reinoud int sc_ops; /* I/O ops since last switch */
247 1.21 yamt struct bufq_state *sc_q;/* pending I/O requests */
248 1.1 reinoud int sc_active; /* number of active I/O operations */
249 1.1 reinoud };
250 1.1 reinoud
251 1.1 reinoud /* floppy driver configuration */
252 1.43 dsl int fdprobe(struct device *, struct cfdata *, void *);
253 1.43 dsl void fdattach(struct device *, struct device *, void *);
254 1.1 reinoud
255 1.4 thorpej extern char floppy_read_fiq[], floppy_read_fiq_end[];
256 1.4 thorpej extern char floppy_write_fiq[], floppy_write_fiq_end[];
257 1.1 reinoud
258 1.9 thorpej CFATTACH_DECL(fd, sizeof(struct fd_softc),
259 1.10 thorpej fdprobe, fdattach, NULL, NULL);
260 1.1 reinoud
261 1.1 reinoud extern struct cfdriver fd_cd;
262 1.1 reinoud
263 1.6 gehenna dev_type_open(fdopen);
264 1.6 gehenna dev_type_close(fdclose);
265 1.6 gehenna dev_type_read(fdread);
266 1.6 gehenna dev_type_write(fdwrite);
267 1.6 gehenna dev_type_ioctl(fdioctl);
268 1.6 gehenna dev_type_strategy(fdstrategy);
269 1.6 gehenna
270 1.6 gehenna const struct bdevsw fd_bdevsw = {
271 1.6 gehenna fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
272 1.6 gehenna };
273 1.6 gehenna
274 1.6 gehenna const struct cdevsw fd_cdevsw = {
275 1.6 gehenna fdopen, fdclose, fdread, fdwrite, fdioctl,
276 1.11 jdolecek nostop, notty, nopoll, nommap, nokqfilter, D_DISK
277 1.6 gehenna };
278 1.6 gehenna
279 1.43 dsl void fdgetdisklabel(struct fd_softc *);
280 1.43 dsl int fd_get_parms(struct fd_softc *);
281 1.43 dsl void fdstart(struct fd_softc *);
282 1.1 reinoud
283 1.1 reinoud struct dkdriver fddkdriver = { fdstrategy };
284 1.1 reinoud
285 1.46 cegger struct fd_type *fd_nvtotype(const char *, int, int);
286 1.43 dsl void fd_set_motor(struct fdc_softc *fdc, int reset);
287 1.43 dsl void fd_motor_off(void *arg);
288 1.43 dsl void fd_motor_on(void *arg);
289 1.43 dsl int fdcresult(struct fdc_softc *fdc);
290 1.43 dsl int out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x);
291 1.43 dsl void fdcstart(struct fdc_softc *fdc);
292 1.43 dsl void fdcstatus(struct device *dv, int n, const char *s);
293 1.43 dsl void fdctimeout(void *arg);
294 1.43 dsl void fdcpseudointr(void *arg);
295 1.43 dsl int fdcintr(void *);
296 1.43 dsl void fdcretry(struct fdc_softc *fdc);
297 1.43 dsl void fdfinish(struct fd_softc *fd, struct buf *bp);
298 1.43 dsl inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
299 1.43 dsl int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
300 1.1 reinoud
301 1.1 reinoud int
302 1.44 dsl fdcprobe(struct device *parent, struct cfdata *cf, void *aux)
303 1.1 reinoud {
304 1.1 reinoud struct pioc_attach_args *pa = aux;
305 1.1 reinoud bus_space_tag_t iot;
306 1.1 reinoud bus_space_handle_t ioh;
307 1.1 reinoud int rv;
308 1.1 reinoud
309 1.1 reinoud if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
310 1.1 reinoud return(0);
311 1.1 reinoud
312 1.1 reinoud iot = pa->pa_iot;
313 1.1 reinoud rv = 0;
314 1.1 reinoud
315 1.1 reinoud /* Map the i/o space. */
316 1.1 reinoud if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
317 1.1 reinoud return 0;
318 1.1 reinoud
319 1.1 reinoud /* reset */
320 1.1 reinoud bus_space_write_2(iot, ioh, fdout, 0);
321 1.1 reinoud delay(100);
322 1.1 reinoud bus_space_write_2(iot, ioh, fdout, FDO_FRST);
323 1.1 reinoud
324 1.1 reinoud /* see if it can handle a command */
325 1.1 reinoud if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
326 1.1 reinoud goto out;
327 1.1 reinoud out_fdc(iot, ioh, 0xdf);
328 1.1 reinoud out_fdc(iot, ioh, 2);
329 1.1 reinoud
330 1.1 reinoud rv = 1;
331 1.1 reinoud pa->pa_iosize = FDC_NPORT;
332 1.1 reinoud
333 1.1 reinoud out:
334 1.1 reinoud bus_space_unmap(iot, ioh, FDC_NPORT);
335 1.1 reinoud return rv;
336 1.1 reinoud }
337 1.1 reinoud
338 1.1 reinoud /*
339 1.1 reinoud * Arguments passed between fdcattach and fdprobe.
340 1.1 reinoud */
341 1.1 reinoud struct fdc_attach_args {
342 1.1 reinoud int fa_drive;
343 1.1 reinoud struct fd_type *fa_deftype;
344 1.1 reinoud };
345 1.1 reinoud
346 1.1 reinoud /*
347 1.1 reinoud * Print the location of a disk drive (called just before attaching the
348 1.1 reinoud * the drive). If `fdc' is not NULL, the drive was found but was not
349 1.1 reinoud * in the system config file; print the drive name as well.
350 1.1 reinoud * Return QUIET (config_find ignores this if the device was configured) to
351 1.1 reinoud * avoid printing `fdN not configured' messages.
352 1.1 reinoud */
353 1.1 reinoud int
354 1.44 dsl fdprint(void *aux, const char *fdc)
355 1.1 reinoud {
356 1.1 reinoud register struct fdc_attach_args *fa = aux;
357 1.1 reinoud
358 1.1 reinoud if (!fdc)
359 1.13 thorpej aprint_normal(" drive %d", fa->fa_drive);
360 1.1 reinoud return QUIET;
361 1.1 reinoud }
362 1.1 reinoud
363 1.1 reinoud void
364 1.45 dsl fdcattach(struct device *parent, struct device *self, void *aux)
365 1.1 reinoud {
366 1.1 reinoud struct fdc_softc *fdc = (void *)self;
367 1.1 reinoud bus_space_tag_t iot;
368 1.1 reinoud bus_space_handle_t ioh;
369 1.1 reinoud struct pioc_attach_args *pa = aux;
370 1.1 reinoud struct fdc_attach_args fa;
371 1.1 reinoud int type;
372 1.1 reinoud
373 1.1 reinoud iot = pa->pa_iot;
374 1.1 reinoud
375 1.1 reinoud /* Re-map the I/O space. */
376 1.1 reinoud if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
377 1.1 reinoud panic("fdcattach: couldn't map I/O ports");
378 1.1 reinoud
379 1.1 reinoud fdc->sc_iot = iot;
380 1.1 reinoud fdc->sc_ioh = ioh;
381 1.1 reinoud
382 1.1 reinoud fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
383 1.1 reinoud fdc->sc_state = DEVIDLE;
384 1.1 reinoud TAILQ_INIT(&fdc->sc_drives);
385 1.1 reinoud
386 1.1 reinoud printf("\n");
387 1.1 reinoud
388 1.29 ad callout_init(&fdc->sc_timo_ch, 0);
389 1.29 ad callout_init(&fdc->sc_intr_ch, 0);
390 1.1 reinoud
391 1.1 reinoud fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc",
392 1.1 reinoud fdcintr, fdc);
393 1.1 reinoud if (!fdc->sc_ih)
394 1.7 provos panic("%s: Cannot claim IRQ %d", self->dv_xname, pa->pa_irq);
395 1.1 reinoud
396 1.1 reinoud #if 0
397 1.1 reinoud /*
398 1.1 reinoud * The NVRAM info only tells us about the first two disks on the
399 1.1 reinoud * `primary' floppy controller.
400 1.1 reinoud */
401 1.25 thorpej if (device_unit(&fdc->sc_dev) == 0)
402 1.1 reinoud type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
403 1.1 reinoud else
404 1.1 reinoud type = -1;
405 1.1 reinoud #endif
406 1.1 reinoud type = 0x10; /* XXX - hardcoded for 1 floppy */
407 1.1 reinoud
408 1.1 reinoud /* physical limit: four drives per controller. */
409 1.1 reinoud for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
410 1.1 reinoud if (type >= 0 && fa.fa_drive < 2)
411 1.46 cegger fa.fa_deftype = fd_nvtotype(device_xname(&fdc->sc_dev),
412 1.1 reinoud type, fa.fa_drive);
413 1.1 reinoud else
414 1.1 reinoud fa.fa_deftype = NULL; /* unknown */
415 1.1 reinoud (void)config_found(self, (void *)&fa, fdprint);
416 1.1 reinoud }
417 1.1 reinoud }
418 1.1 reinoud
419 1.1 reinoud int
420 1.44 dsl fdprobe(struct device *parent, struct cfdata *cf, void *aux)
421 1.1 reinoud {
422 1.1 reinoud struct fdc_softc *fdc = (void *)parent;
423 1.1 reinoud struct fdc_attach_args *fa = aux;
424 1.1 reinoud int drive = fa->fa_drive;
425 1.1 reinoud bus_space_tag_t iot = fdc->sc_iot;
426 1.1 reinoud bus_space_handle_t ioh = fdc->sc_ioh;
427 1.1 reinoud int n;
428 1.1 reinoud
429 1.1 reinoud if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
430 1.1 reinoud && cf->cf_loc[FDCCF_DRIVE] != drive)
431 1.1 reinoud return 0;
432 1.1 reinoud /*
433 1.1 reinoud * XXX
434 1.1 reinoud * This is to work around some odd interactions between this driver
435 1.1 reinoud * and SMC Ethernet cards.
436 1.1 reinoud */
437 1.1 reinoud
438 1.1 reinoud /* Don't need this for arm32 port but leave for the time being (it won't hurt) */
439 1.1 reinoud
440 1.1 reinoud if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
441 1.1 reinoud return 0;
442 1.1 reinoud
443 1.1 reinoud /* select drive and turn on motor */
444 1.1 reinoud bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
445 1.1 reinoud /* wait for motor to spin up */
446 1.1 reinoud delay(250000);
447 1.1 reinoud out_fdc(iot, ioh, NE7CMD_RECAL);
448 1.1 reinoud out_fdc(iot, ioh, drive);
449 1.1 reinoud /* wait for recalibrate */
450 1.1 reinoud delay(2000000);
451 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI);
452 1.1 reinoud n = fdcresult(fdc);
453 1.1 reinoud #ifdef FD_DEBUG
454 1.1 reinoud {
455 1.1 reinoud int i;
456 1.1 reinoud printf("fdprobe: status");
457 1.1 reinoud for (i = 0; i < n; i++)
458 1.1 reinoud printf(" %x", fdc->sc_status[i]);
459 1.1 reinoud printf("\n");
460 1.1 reinoud }
461 1.1 reinoud #endif
462 1.1 reinoud /* turn off motor */
463 1.1 reinoud bus_space_write_1(iot, ioh, fdout, FDO_FRST);
464 1.1 reinoud
465 1.1 reinoud if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
466 1.1 reinoud return 0;
467 1.1 reinoud
468 1.1 reinoud return 1;
469 1.1 reinoud }
470 1.1 reinoud
471 1.1 reinoud /*
472 1.1 reinoud * Controller is working, and drive responded. Attach it.
473 1.1 reinoud */
474 1.1 reinoud void
475 1.45 dsl fdattach(struct device *parent, struct device *self, void *aux)
476 1.1 reinoud {
477 1.1 reinoud struct fdc_softc *fdc = (void *)parent;
478 1.1 reinoud struct fd_softc *fd = (void *)self;
479 1.1 reinoud struct fdc_attach_args *fa = aux;
480 1.1 reinoud struct fd_type *type = fa->fa_deftype;
481 1.1 reinoud int drive = fa->fa_drive;
482 1.1 reinoud
483 1.29 ad callout_init(&fd->sc_motoron_ch, 0);
484 1.29 ad callout_init(&fd->sc_motoroff_ch, 0);
485 1.1 reinoud
486 1.1 reinoud /* XXX Allow `flags' to override device type? */
487 1.1 reinoud
488 1.1 reinoud if (type)
489 1.1 reinoud printf(": %s %d cyl, %d head, %d sec\n", type->name,
490 1.1 reinoud type->cyls, type->heads, type->sectrac);
491 1.1 reinoud else
492 1.1 reinoud printf(": density unknown\n");
493 1.1 reinoud
494 1.21 yamt bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
495 1.1 reinoud fd->sc_cylin = -1;
496 1.1 reinoud fd->sc_drive = drive;
497 1.1 reinoud fd->sc_deftype = type;
498 1.1 reinoud fdc->sc_fd[drive] = fd;
499 1.1 reinoud
500 1.1 reinoud /*
501 1.1 reinoud * Initialize and attach the disk structure.
502 1.1 reinoud */
503 1.46 cegger disk_init(&fd->sc_dk, device_xname(&fd->sc_dev), &fddkdriver);
504 1.1 reinoud disk_attach(&fd->sc_dk);
505 1.1 reinoud
506 1.1 reinoud /* Needed to power off if the motor is on when we halt. */
507 1.1 reinoud
508 1.1 reinoud }
509 1.1 reinoud
510 1.1 reinoud /*
511 1.1 reinoud * Translate nvram type into internal data structure. Return NULL for
512 1.1 reinoud * none/unknown/unusable.
513 1.1 reinoud */
514 1.1 reinoud struct fd_type *
515 1.46 cegger fd_nvtotype(const char *fdc, int nvraminfo, int drive)
516 1.1 reinoud {
517 1.1 reinoud int type;
518 1.1 reinoud
519 1.1 reinoud type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
520 1.1 reinoud switch (type) {
521 1.1 reinoud #ifndef RC7500
522 1.1 reinoud case 0x00 :
523 1.1 reinoud return NULL;
524 1.1 reinoud #else
525 1.1 reinoud case 0x00 :
526 1.1 reinoud #endif /* !RC7500 */
527 1.1 reinoud case 0x10 :
528 1.1 reinoud return &fd_types[0];
529 1.1 reinoud default:
530 1.1 reinoud printf("%s: drive %d: unknown device type 0x%x\n",
531 1.1 reinoud fdc, drive, type);
532 1.1 reinoud return NULL;
533 1.1 reinoud }
534 1.1 reinoud }
535 1.1 reinoud
536 1.23 perry inline struct fd_type *
537 1.44 dsl fd_dev_to_type(struct fd_softc *fd, dev_t dev)
538 1.1 reinoud {
539 1.1 reinoud int type = FDTYPE(dev);
540 1.1 reinoud
541 1.1 reinoud if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
542 1.1 reinoud return NULL;
543 1.1 reinoud return type ? &fd_types[type - 1] : fd->sc_deftype;
544 1.1 reinoud }
545 1.1 reinoud
546 1.1 reinoud void
547 1.39 cegger fdstrategy(struct buf *bp)
548 1.1 reinoud {
549 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(bp->b_dev));
550 1.1 reinoud int sz;
551 1.1 reinoud int s;
552 1.1 reinoud
553 1.1 reinoud /* Valid unit, controller, and request? */
554 1.1 reinoud if (bp->b_blkno < 0 ||
555 1.1 reinoud ((bp->b_bcount % FDC_BSIZE) != 0 &&
556 1.1 reinoud (bp->b_flags & B_FORMAT) == 0)) {
557 1.1 reinoud bp->b_error = EINVAL;
558 1.30 ad goto done;
559 1.1 reinoud }
560 1.1 reinoud
561 1.1 reinoud /* If it's a null transfer, return immediately. */
562 1.1 reinoud if (bp->b_bcount == 0)
563 1.1 reinoud goto done;
564 1.1 reinoud
565 1.1 reinoud sz = howmany(bp->b_bcount, FDC_BSIZE);
566 1.1 reinoud
567 1.1 reinoud if (bp->b_blkno + sz > fd->sc_type->size) {
568 1.1 reinoud sz = fd->sc_type->size - bp->b_blkno;
569 1.1 reinoud if (sz == 0) {
570 1.1 reinoud /* If exactly at end of disk, return EOF. */
571 1.1 reinoud goto done;
572 1.1 reinoud }
573 1.1 reinoud if (sz < 0) {
574 1.1 reinoud /* If past end of disk, return EINVAL. */
575 1.1 reinoud bp->b_error = EINVAL;
576 1.30 ad goto done;
577 1.1 reinoud }
578 1.1 reinoud /* Otherwise, truncate request. */
579 1.1 reinoud bp->b_bcount = sz << DEV_BSHIFT;
580 1.1 reinoud }
581 1.1 reinoud
582 1.1 reinoud bp->b_rawblkno = bp->b_blkno;
583 1.1 reinoud bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
584 1.1 reinoud
585 1.1 reinoud #ifdef FD_DEBUG
586 1.1 reinoud printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
587 1.1 reinoud bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
588 1.1 reinoud #endif
589 1.1 reinoud
590 1.1 reinoud /* Queue transfer on drive, activate drive and controller if idle. */
591 1.1 reinoud s = splbio();
592 1.41 yamt bufq_put(fd->sc_q, bp);
593 1.1 reinoud callout_stop(&fd->sc_motoroff_ch); /* a good idea */
594 1.1 reinoud if (fd->sc_active == 0)
595 1.1 reinoud fdstart(fd);
596 1.1 reinoud #ifdef DIAGNOSTIC
597 1.1 reinoud else {
598 1.24 thorpej struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
599 1.1 reinoud if (fdc->sc_state == DEVIDLE) {
600 1.1 reinoud printf("fdstrategy: controller inactive\n");
601 1.1 reinoud fdcstart(fdc);
602 1.1 reinoud }
603 1.1 reinoud }
604 1.1 reinoud #endif
605 1.1 reinoud splx(s);
606 1.1 reinoud return;
607 1.1 reinoud
608 1.1 reinoud done:
609 1.1 reinoud /* Toss transfer; we're done early. */
610 1.1 reinoud bp->b_resid = bp->b_bcount;
611 1.1 reinoud biodone(bp);
612 1.1 reinoud }
613 1.1 reinoud
614 1.1 reinoud void
615 1.44 dsl fdstart(struct fd_softc *fd)
616 1.1 reinoud {
617 1.24 thorpej struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
618 1.1 reinoud int active = fdc->sc_drives.tqh_first != 0;
619 1.1 reinoud
620 1.1 reinoud /* Link into controller queue. */
621 1.1 reinoud fd->sc_active = 1;
622 1.1 reinoud TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
623 1.1 reinoud
624 1.1 reinoud /* If controller not already active, start it. */
625 1.1 reinoud if (!active)
626 1.1 reinoud fdcstart(fdc);
627 1.1 reinoud }
628 1.1 reinoud
629 1.1 reinoud void
630 1.44 dsl fdfinish(struct fd_softc *fd, struct buf *bp)
631 1.1 reinoud {
632 1.24 thorpej struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
633 1.1 reinoud
634 1.1 reinoud /*
635 1.1 reinoud * Move this drive to the end of the queue to give others a `fair'
636 1.1 reinoud * chance. We only force a switch if N operations are completed while
637 1.1 reinoud * another drive is waiting to be serviced, since there is a long motor
638 1.1 reinoud * startup delay whenever we switch.
639 1.1 reinoud */
640 1.41 yamt (void)bufq_get(fd->sc_q);
641 1.1 reinoud if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
642 1.1 reinoud fd->sc_ops = 0;
643 1.1 reinoud TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
644 1.41 yamt if (bufq_peek(fd->sc_q) != NULL)
645 1.1 reinoud TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
646 1.1 reinoud else
647 1.1 reinoud fd->sc_active = 0;
648 1.1 reinoud }
649 1.1 reinoud bp->b_resid = fd->sc_bcount;
650 1.1 reinoud fd->sc_skip = 0;
651 1.1 reinoud
652 1.1 reinoud biodone(bp);
653 1.1 reinoud /* turn off motor 5s from now */
654 1.1 reinoud callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
655 1.1 reinoud fdc->sc_state = DEVIDLE;
656 1.1 reinoud }
657 1.1 reinoud
658 1.1 reinoud int
659 1.44 dsl fdread(dev_t dev, struct uio *uio, int flags)
660 1.1 reinoud {
661 1.1 reinoud
662 1.1 reinoud return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
663 1.1 reinoud }
664 1.1 reinoud
665 1.1 reinoud int
666 1.44 dsl fdwrite(dev_t dev, struct uio *uio, int flags)
667 1.1 reinoud {
668 1.1 reinoud
669 1.1 reinoud return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
670 1.1 reinoud }
671 1.1 reinoud
672 1.1 reinoud void
673 1.44 dsl fd_set_motor(struct fdc_softc *fdc, int reset)
674 1.1 reinoud {
675 1.1 reinoud struct fd_softc *fd;
676 1.1 reinoud u_char status;
677 1.1 reinoud int n;
678 1.1 reinoud
679 1.1 reinoud if ((fd = fdc->sc_drives.tqh_first) != NULL)
680 1.1 reinoud status = fd->sc_drive;
681 1.1 reinoud else
682 1.1 reinoud status = 0;
683 1.1 reinoud if (!reset)
684 1.1 reinoud status |= FDO_FRST | FDO_FDMAEN;
685 1.1 reinoud for (n = 0; n < 4; n++)
686 1.1 reinoud if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
687 1.1 reinoud status |= FDO_MOEN(n);
688 1.1 reinoud bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
689 1.1 reinoud }
690 1.1 reinoud
691 1.1 reinoud void
692 1.44 dsl fd_motor_off(void *arg)
693 1.1 reinoud {
694 1.1 reinoud struct fd_softc *fd = arg;
695 1.1 reinoud int s;
696 1.1 reinoud
697 1.1 reinoud s = splbio();
698 1.1 reinoud fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
699 1.24 thorpej fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
700 1.1 reinoud splx(s);
701 1.1 reinoud }
702 1.1 reinoud
703 1.1 reinoud void
704 1.44 dsl fd_motor_on(void *arg)
705 1.1 reinoud {
706 1.1 reinoud struct fd_softc *fd = arg;
707 1.24 thorpej struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
708 1.1 reinoud int s;
709 1.1 reinoud
710 1.1 reinoud s = splbio();
711 1.1 reinoud fd->sc_flags &= ~FD_MOTOR_WAIT;
712 1.1 reinoud if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
713 1.1 reinoud (void) fdcintr(fdc);
714 1.1 reinoud splx(s);
715 1.1 reinoud }
716 1.1 reinoud
717 1.1 reinoud int
718 1.44 dsl fdcresult(struct fdc_softc *fdc)
719 1.1 reinoud {
720 1.1 reinoud bus_space_tag_t iot = fdc->sc_iot;
721 1.1 reinoud bus_space_handle_t ioh = fdc->sc_ioh;
722 1.1 reinoud u_char i;
723 1.1 reinoud int j = 100000,
724 1.1 reinoud n = 0;
725 1.1 reinoud
726 1.1 reinoud for (; j; j--) {
727 1.1 reinoud i = bus_space_read_1(iot, ioh, fdsts) &
728 1.1 reinoud (NE7_DIO | NE7_RQM | NE7_CB);
729 1.1 reinoud if (i == NE7_RQM)
730 1.1 reinoud return n;
731 1.1 reinoud if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
732 1.1 reinoud if (n >= sizeof(fdc->sc_status)) {
733 1.1 reinoud log(LOG_ERR, "fdcresult: overrun\n");
734 1.1 reinoud return -1;
735 1.1 reinoud }
736 1.1 reinoud fdc->sc_status[n++] =
737 1.1 reinoud bus_space_read_1(iot, ioh, fddata);
738 1.1 reinoud }
739 1.1 reinoud delay(10);
740 1.1 reinoud }
741 1.1 reinoud log(LOG_ERR, "fdcresult: timeout\n");
742 1.1 reinoud return -1;
743 1.1 reinoud }
744 1.1 reinoud
745 1.1 reinoud int
746 1.44 dsl out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
747 1.1 reinoud {
748 1.1 reinoud int i = 100000;
749 1.1 reinoud
750 1.1 reinoud while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
751 1.1 reinoud if (i <= 0)
752 1.1 reinoud return -1;
753 1.1 reinoud while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
754 1.1 reinoud if (i <= 0)
755 1.1 reinoud return -1;
756 1.1 reinoud bus_space_write_2(iot, ioh, fddata, x);
757 1.1 reinoud return 0;
758 1.1 reinoud }
759 1.1 reinoud
760 1.1 reinoud int
761 1.39 cegger fdopen(dev_t dev, int flags, int mode, struct lwp *l)
762 1.1 reinoud {
763 1.1 reinoud struct fd_softc *fd;
764 1.1 reinoud struct fd_type *type;
765 1.1 reinoud
766 1.39 cegger fd = device_lookup_private(&fd_cd, FDUNIT(dev));
767 1.39 cegger if (fd == NULL)
768 1.1 reinoud return ENXIO;
769 1.1 reinoud type = fd_dev_to_type(fd, dev);
770 1.1 reinoud if (type == NULL)
771 1.1 reinoud return ENXIO;
772 1.1 reinoud
773 1.1 reinoud if ((fd->sc_flags & FD_OPEN) != 0 &&
774 1.1 reinoud memcmp(fd->sc_type, type, sizeof(*type)))
775 1.1 reinoud return EBUSY;
776 1.1 reinoud
777 1.1 reinoud fd->sc_type_copy = *type;
778 1.1 reinoud fd->sc_type = &fd->sc_type_copy;
779 1.1 reinoud fd->sc_cylin = -1;
780 1.1 reinoud fd->sc_flags |= FD_OPEN;
781 1.1 reinoud
782 1.1 reinoud return 0;
783 1.1 reinoud }
784 1.1 reinoud
785 1.1 reinoud int
786 1.39 cegger fdclose(dev_t dev, int flags, int mode, struct lwp *l)
787 1.1 reinoud {
788 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
789 1.1 reinoud
790 1.1 reinoud fd->sc_flags &= ~FD_OPEN;
791 1.1 reinoud fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
792 1.1 reinoud return 0;
793 1.1 reinoud }
794 1.1 reinoud
795 1.1 reinoud void
796 1.44 dsl fdcstart(struct fdc_softc *fdc)
797 1.1 reinoud {
798 1.1 reinoud
799 1.1 reinoud #ifdef DIAGNOSTIC
800 1.1 reinoud /* only got here if controller's drive queue was inactive; should
801 1.1 reinoud be in idle state */
802 1.1 reinoud if (fdc->sc_state != DEVIDLE) {
803 1.1 reinoud printf("fdcstart: not idle\n");
804 1.1 reinoud return;
805 1.1 reinoud }
806 1.1 reinoud #endif
807 1.1 reinoud (void) fdcintr(fdc);
808 1.1 reinoud }
809 1.1 reinoud
810 1.40 christos static void
811 1.40 christos fdcpstatus(int n, struct fdc_softc *fdc)
812 1.1 reinoud {
813 1.1 reinoud char bits[64];
814 1.1 reinoud
815 1.1 reinoud switch (n) {
816 1.1 reinoud case 0:
817 1.1 reinoud printf("\n");
818 1.1 reinoud break;
819 1.1 reinoud case 2:
820 1.40 christos snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
821 1.40 christos printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
822 1.1 reinoud break;
823 1.1 reinoud case 7:
824 1.40 christos snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
825 1.40 christos printf(" (st0 %s", bits);
826 1.40 christos snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
827 1.40 christos printf(" st1 %s", bits);
828 1.40 christos snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
829 1.40 christos printf(" st2 %s", bits);
830 1.1 reinoud printf(" cyl %d head %d sec %d)\n",
831 1.1 reinoud fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
832 1.1 reinoud break;
833 1.1 reinoud #ifdef DIAGNOSTIC
834 1.1 reinoud default:
835 1.1 reinoud printf("\nfdcstatus: weird size");
836 1.1 reinoud break;
837 1.1 reinoud #endif
838 1.1 reinoud }
839 1.1 reinoud }
840 1.1 reinoud
841 1.1 reinoud void
842 1.44 dsl fdcstatus(struct device *dv, int n, const char *s)
843 1.40 christos {
844 1.40 christos struct fdc_softc *fdc = (void *) device_parent(dv);
845 1.40 christos
846 1.40 christos if (n == 0) {
847 1.40 christos out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
848 1.40 christos (void) fdcresult(fdc);
849 1.40 christos n = 2;
850 1.40 christos }
851 1.40 christos
852 1.46 cegger printf("%s: %s", device_xname(dv), s);
853 1.40 christos fdcpstatus(n, fdc);
854 1.40 christos }
855 1.40 christos
856 1.40 christos void
857 1.44 dsl fdctimeout(void *arg)
858 1.1 reinoud {
859 1.1 reinoud struct fdc_softc *fdc = arg;
860 1.1 reinoud struct fd_softc *fd = fdc->sc_drives.tqh_first;
861 1.1 reinoud int s;
862 1.1 reinoud
863 1.1 reinoud s = splbio();
864 1.1 reinoud #ifdef DEBUG
865 1.1 reinoud log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
866 1.1 reinoud #endif
867 1.1 reinoud fdcstatus(&fd->sc_dev, 0, "timeout");
868 1.1 reinoud
869 1.41 yamt if (bufq_peek(fd->sc_q) != NULL)
870 1.1 reinoud fdc->sc_state++;
871 1.1 reinoud else
872 1.1 reinoud fdc->sc_state = DEVIDLE;
873 1.1 reinoud
874 1.1 reinoud (void) fdcintr(fdc);
875 1.1 reinoud splx(s);
876 1.1 reinoud }
877 1.1 reinoud
878 1.1 reinoud void
879 1.44 dsl fdcpseudointr(void *arg)
880 1.1 reinoud {
881 1.1 reinoud int s;
882 1.1 reinoud
883 1.1 reinoud /* Just ensure it has the right spl. */
884 1.1 reinoud s = splbio();
885 1.1 reinoud (void) fdcintr(arg);
886 1.1 reinoud splx(s);
887 1.1 reinoud }
888 1.1 reinoud
889 1.1 reinoud int
890 1.44 dsl fdcintr(void *arg)
891 1.1 reinoud {
892 1.1 reinoud struct fdc_softc *fdc = arg;
893 1.1 reinoud #define st0 fdc->sc_status[0]
894 1.1 reinoud #define cyl fdc->sc_status[1]
895 1.1 reinoud struct fd_softc *fd;
896 1.1 reinoud struct buf *bp;
897 1.1 reinoud bus_space_tag_t iot = fdc->sc_iot;
898 1.1 reinoud bus_space_handle_t ioh = fdc->sc_ioh;
899 1.1 reinoud int read, head, sec, i, nblks;
900 1.1 reinoud struct fd_type *type;
901 1.1 reinoud struct ne7_fd_formb *finfo = NULL;
902 1.1 reinoud
903 1.1 reinoud loop:
904 1.1 reinoud /* Is there a drive for the controller to do a transfer with? */
905 1.1 reinoud fd = fdc->sc_drives.tqh_first;
906 1.1 reinoud if (fd == NULL) {
907 1.1 reinoud fdc->sc_state = DEVIDLE;
908 1.1 reinoud return 1;
909 1.1 reinoud }
910 1.1 reinoud
911 1.1 reinoud /* Is there a transfer to this drive? If not, deactivate drive. */
912 1.41 yamt bp = bufq_peek(fd->sc_q);
913 1.1 reinoud if (bp == NULL) {
914 1.1 reinoud fd->sc_ops = 0;
915 1.1 reinoud TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
916 1.1 reinoud fd->sc_active = 0;
917 1.1 reinoud goto loop;
918 1.1 reinoud }
919 1.1 reinoud
920 1.1 reinoud if (bp->b_flags & B_FORMAT)
921 1.1 reinoud finfo = (struct ne7_fd_formb *)bp->b_data;
922 1.1 reinoud
923 1.1 reinoud switch (fdc->sc_state) {
924 1.1 reinoud case DEVIDLE:
925 1.1 reinoud fdc->sc_errors = 0;
926 1.1 reinoud fd->sc_skip = 0;
927 1.1 reinoud fd->sc_bcount = bp->b_bcount;
928 1.1 reinoud fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
929 1.1 reinoud callout_stop(&fd->sc_motoroff_ch);
930 1.1 reinoud if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
931 1.1 reinoud fdc->sc_state = MOTORWAIT;
932 1.1 reinoud return 1;
933 1.1 reinoud }
934 1.1 reinoud if ((fd->sc_flags & FD_MOTOR) == 0) {
935 1.1 reinoud /* Turn on the motor, being careful about pairing. */
936 1.1 reinoud struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
937 1.1 reinoud if (ofd && ofd->sc_flags & FD_MOTOR) {
938 1.1 reinoud callout_stop(&ofd->sc_motoroff_ch);
939 1.1 reinoud ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
940 1.1 reinoud }
941 1.1 reinoud fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
942 1.1 reinoud fd_set_motor(fdc, 0);
943 1.1 reinoud fdc->sc_state = MOTORWAIT;
944 1.1 reinoud /* Allow .25s for motor to stabilize. */
945 1.1 reinoud callout_reset(&fd->sc_motoron_ch, hz / 4,
946 1.1 reinoud fd_motor_on, fd);
947 1.1 reinoud return 1;
948 1.1 reinoud }
949 1.1 reinoud /* Make sure the right drive is selected. */
950 1.1 reinoud fd_set_motor(fdc, 0);
951 1.1 reinoud
952 1.1 reinoud /* fall through */
953 1.1 reinoud case DOSEEK:
954 1.1 reinoud doseek:
955 1.1 reinoud if (fd->sc_cylin == bp->b_cylinder)
956 1.1 reinoud goto doio;
957 1.1 reinoud
958 1.1 reinoud #if 1
959 1.1 reinoud out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
960 1.1 reinoud out_fdc(iot, ioh, 0);
961 1.1 reinoud out_fdc(iot, ioh, 0x18);
962 1.1 reinoud out_fdc(iot, ioh, 0);
963 1.1 reinoud #endif
964 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
965 1.1 reinoud out_fdc(iot, ioh, fd->sc_type->steprate);
966 1.1 reinoud out_fdc(iot, ioh, 6); /* XXX head load time == 6ms */
967 1.1 reinoud
968 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
969 1.1 reinoud out_fdc(iot, ioh, fd->sc_drive); /* drive number */
970 1.1 reinoud out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
971 1.1 reinoud
972 1.1 reinoud fd->sc_cylin = -1;
973 1.1 reinoud fdc->sc_state = SEEKWAIT;
974 1.1 reinoud
975 1.26 blymn iostat_seek(fd->sc_dk.dk_stats);
976 1.1 reinoud disk_busy(&fd->sc_dk);
977 1.1 reinoud
978 1.1 reinoud callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
979 1.1 reinoud return 1;
980 1.1 reinoud
981 1.1 reinoud case DOIO:
982 1.1 reinoud doio:
983 1.1 reinoud type = fd->sc_type;
984 1.1 reinoud if (finfo)
985 1.1 reinoud fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
986 1.1 reinoud (char *)finfo;
987 1.1 reinoud sec = fd->sc_blkno % type->seccyl;
988 1.1 reinoud nblks = type->seccyl - sec;
989 1.1 reinoud nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
990 1.1 reinoud nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
991 1.1 reinoud fd->sc_nblks = nblks;
992 1.1 reinoud fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
993 1.1 reinoud head = sec / type->sectrac;
994 1.1 reinoud sec -= head * type->sectrac;
995 1.1 reinoud #ifdef DIAGNOSTIC
996 1.14 thorpej {daddr_t block;
997 1.1 reinoud block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
998 1.1 reinoud if (block != fd->sc_blkno) {
999 1.14 thorpej printf("fdcintr: block %" PRId64
1000 1.14 thorpej " != blkno %" PRId64 "\n",
1001 1.1 reinoud block, fd->sc_blkno);
1002 1.1 reinoud #ifdef DDB
1003 1.1 reinoud Debugger();
1004 1.1 reinoud #endif
1005 1.1 reinoud }}
1006 1.1 reinoud #endif
1007 1.1 reinoud read = bp->b_flags & B_READ;
1008 1.4 thorpej if (read) {
1009 1.4 thorpej fdc->sc_fh.fh_func = floppy_read_fiq;
1010 1.4 thorpej fdc->sc_fh.fh_size = floppy_read_fiq_end -
1011 1.4 thorpej floppy_read_fiq;
1012 1.4 thorpej } else {
1013 1.4 thorpej fdc->sc_fh.fh_func = floppy_write_fiq;
1014 1.4 thorpej fdc->sc_fh.fh_size = floppy_read_fiq_end -
1015 1.4 thorpej floppy_read_fiq;
1016 1.4 thorpej }
1017 1.4 thorpej fdc->sc_fh.fh_flags = 0;
1018 1.4 thorpej fdc->sc_fh.fh_regs = &fdc->sc_fr;
1019 1.4 thorpej fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
1020 1.4 thorpej fdc->sc_fr.fr_r10 = fd->sc_nbytes;
1021 1.34 yamt fdc->sc_fr.fr_r11 =
1022 1.34 yamt (u_int)((uintptr_t)bp->b_data + fd->sc_skip);
1023 1.4 thorpej fdc->sc_fr.fr_r12 = fdc->sc_drq;
1024 1.1 reinoud #ifdef FD_DEBUG
1025 1.4 thorpej printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1026 1.4 thorpej fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
1027 1.4 thorpej fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
1028 1.1 reinoud #endif
1029 1.4 thorpej if (fiq_claim(&fdc->sc_fh) == -1)
1030 1.7 provos panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
1031 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1032 1.1 reinoud bus_space_write_2(iot, ioh, fdctl, type->rate);
1033 1.1 reinoud #ifdef FD_DEBUG
1034 1.1 reinoud printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1035 1.1 reinoud read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1036 1.1 reinoud head, sec, nblks);
1037 1.1 reinoud #endif
1038 1.1 reinoud if (finfo) {
1039 1.1 reinoud /* formatting */
1040 1.1 reinoud if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1041 1.1 reinoud fdc->sc_errors = 4;
1042 1.1 reinoud fdcretry(fdc);
1043 1.1 reinoud goto loop;
1044 1.1 reinoud }
1045 1.1 reinoud out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1046 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_secshift);
1047 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1048 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1049 1.1 reinoud out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1050 1.1 reinoud } else {
1051 1.1 reinoud if (read)
1052 1.1 reinoud out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1053 1.1 reinoud else
1054 1.1 reinoud out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1055 1.1 reinoud out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1056 1.1 reinoud out_fdc(iot, ioh, fd->sc_cylin); /* track */
1057 1.1 reinoud out_fdc(iot, ioh, head);
1058 1.1 reinoud out_fdc(iot, ioh, sec + 1); /* sector +1 */
1059 1.1 reinoud out_fdc(iot, ioh, type->secsize);/* sector size */
1060 1.1 reinoud out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1061 1.1 reinoud out_fdc(iot, ioh, type->gap1); /* gap1 size */
1062 1.1 reinoud out_fdc(iot, ioh, type->datalen);/* data length */
1063 1.1 reinoud }
1064 1.1 reinoud fdc->sc_state = IOCOMPLETE;
1065 1.1 reinoud
1066 1.1 reinoud disk_busy(&fd->sc_dk);
1067 1.1 reinoud
1068 1.1 reinoud /* allow 2 seconds for operation */
1069 1.1 reinoud callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1070 1.1 reinoud return 1; /* will return later */
1071 1.1 reinoud
1072 1.1 reinoud case SEEKWAIT:
1073 1.1 reinoud callout_stop(&fdc->sc_timo_ch);
1074 1.1 reinoud fdc->sc_state = SEEKCOMPLETE;
1075 1.1 reinoud /* allow 1/50 second for heads to settle */
1076 1.1 reinoud #if 0
1077 1.1 reinoud callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1078 1.1 reinoud #endif
1079 1.1 reinoud return 1;
1080 1.1 reinoud
1081 1.1 reinoud case SEEKCOMPLETE:
1082 1.12 mrg /* no data on seek */
1083 1.12 mrg disk_unbusy(&fd->sc_dk, 0, 0);
1084 1.1 reinoud
1085 1.1 reinoud /* Make sure seek really happened. */
1086 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI);
1087 1.1 reinoud if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1088 1.1 reinoud cyl != bp->b_cylinder * fd->sc_type->step) {
1089 1.1 reinoud #ifdef FD_DEBUG
1090 1.1 reinoud fdcstatus(&fd->sc_dev, 2, "seek failed");
1091 1.1 reinoud #endif
1092 1.1 reinoud fdcretry(fdc);
1093 1.1 reinoud goto loop;
1094 1.1 reinoud }
1095 1.1 reinoud fd->sc_cylin = bp->b_cylinder;
1096 1.1 reinoud goto doio;
1097 1.1 reinoud
1098 1.1 reinoud case IOTIMEDOUT:
1099 1.4 thorpej fiq_release(&fdc->sc_fh);
1100 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1101 1.1 reinoud case SEEKTIMEDOUT:
1102 1.1 reinoud case RECALTIMEDOUT:
1103 1.1 reinoud case RESETTIMEDOUT:
1104 1.1 reinoud fdcretry(fdc);
1105 1.1 reinoud goto loop;
1106 1.1 reinoud
1107 1.1 reinoud case IOCOMPLETE: /* IO DONE, post-analyze */
1108 1.1 reinoud callout_stop(&fdc->sc_timo_ch);
1109 1.1 reinoud
1110 1.12 mrg disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1111 1.12 mrg (bp->b_flags & B_READ));
1112 1.1 reinoud
1113 1.1 reinoud if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1114 1.4 thorpej fiq_release(&fdc->sc_fh);
1115 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1116 1.1 reinoud #ifdef FD_DEBUG
1117 1.1 reinoud fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1118 1.1 reinoud "read failed" : "write failed");
1119 1.1 reinoud printf("blkno %d nblks %d\n",
1120 1.1 reinoud fd->sc_blkno, fd->sc_nblks);
1121 1.1 reinoud #endif
1122 1.1 reinoud fdcretry(fdc);
1123 1.1 reinoud goto loop;
1124 1.1 reinoud }
1125 1.4 thorpej fiq_release(&fdc->sc_fh);
1126 1.4 thorpej IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1127 1.1 reinoud if (fdc->sc_errors) {
1128 1.1 reinoud #if 0
1129 1.1 reinoud diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1130 1.1 reinoud fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1131 1.1 reinoud printf("\n");
1132 1.1 reinoud #endif
1133 1.1 reinoud fdc->sc_errors = 0;
1134 1.1 reinoud }
1135 1.1 reinoud fd->sc_blkno += fd->sc_nblks;
1136 1.1 reinoud fd->sc_skip += fd->sc_nbytes;
1137 1.1 reinoud fd->sc_bcount -= fd->sc_nbytes;
1138 1.1 reinoud if (!finfo && fd->sc_bcount > 0) {
1139 1.1 reinoud bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1140 1.1 reinoud goto doseek;
1141 1.1 reinoud }
1142 1.1 reinoud fdfinish(fd, bp);
1143 1.1 reinoud goto loop;
1144 1.1 reinoud
1145 1.1 reinoud case DORESET:
1146 1.1 reinoud /* try a reset, keep motor on */
1147 1.1 reinoud fd_set_motor(fdc, 1);
1148 1.1 reinoud delay(100);
1149 1.1 reinoud fd_set_motor(fdc, 0);
1150 1.1 reinoud fdc->sc_state = RESETCOMPLETE;
1151 1.1 reinoud callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1152 1.1 reinoud return 1; /* will return later */
1153 1.1 reinoud
1154 1.1 reinoud case RESETCOMPLETE:
1155 1.1 reinoud callout_stop(&fdc->sc_timo_ch);
1156 1.1 reinoud /* clear the controller output buffer */
1157 1.1 reinoud for (i = 0; i < 4; i++) {
1158 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI);
1159 1.1 reinoud (void) fdcresult(fdc);
1160 1.1 reinoud }
1161 1.1 reinoud
1162 1.1 reinoud /* fall through */
1163 1.1 reinoud case DORECAL:
1164 1.1 reinoud out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1165 1.1 reinoud out_fdc(iot, ioh, fd->sc_drive);
1166 1.1 reinoud fdc->sc_state = RECALWAIT;
1167 1.1 reinoud callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1168 1.1 reinoud return 1; /* will return later */
1169 1.1 reinoud
1170 1.1 reinoud case RECALWAIT:
1171 1.1 reinoud callout_stop(&fdc->sc_timo_ch);
1172 1.1 reinoud fdc->sc_state = RECALCOMPLETE;
1173 1.1 reinoud /* allow 1/30 second for heads to settle */
1174 1.1 reinoud #if 0
1175 1.1 reinoud callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1176 1.1 reinoud #endif
1177 1.1 reinoud return 1; /* will return later */
1178 1.1 reinoud
1179 1.1 reinoud case RECALCOMPLETE:
1180 1.1 reinoud out_fdc(iot, ioh, NE7CMD_SENSEI);
1181 1.1 reinoud if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1182 1.1 reinoud #ifdef FD_DEBUG
1183 1.1 reinoud fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1184 1.1 reinoud #endif
1185 1.1 reinoud fdcretry(fdc);
1186 1.1 reinoud goto loop;
1187 1.1 reinoud }
1188 1.1 reinoud fd->sc_cylin = 0;
1189 1.1 reinoud goto doseek;
1190 1.1 reinoud
1191 1.1 reinoud case MOTORWAIT:
1192 1.1 reinoud if (fd->sc_flags & FD_MOTOR_WAIT)
1193 1.1 reinoud return 1; /* time's not up yet */
1194 1.1 reinoud goto doseek;
1195 1.1 reinoud
1196 1.1 reinoud default:
1197 1.1 reinoud fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1198 1.1 reinoud return 1;
1199 1.1 reinoud }
1200 1.1 reinoud #ifdef DIAGNOSTIC
1201 1.1 reinoud panic("fdcintr: impossible");
1202 1.1 reinoud #endif
1203 1.1 reinoud #undef st0
1204 1.1 reinoud #undef cyl
1205 1.1 reinoud }
1206 1.1 reinoud
1207 1.1 reinoud void
1208 1.44 dsl fdcretry(struct fdc_softc *fdc)
1209 1.1 reinoud {
1210 1.1 reinoud struct fd_softc *fd;
1211 1.1 reinoud struct buf *bp;
1212 1.1 reinoud
1213 1.1 reinoud fd = fdc->sc_drives.tqh_first;
1214 1.41 yamt bp = bufq_peek(fd->sc_q);
1215 1.1 reinoud
1216 1.1 reinoud if (fd->sc_opts & FDOPT_NORETRY)
1217 1.1 reinoud goto fail;
1218 1.1 reinoud switch (fdc->sc_errors) {
1219 1.1 reinoud case 0:
1220 1.1 reinoud /* try again */
1221 1.1 reinoud fdc->sc_state = DOSEEK;
1222 1.1 reinoud break;
1223 1.1 reinoud
1224 1.1 reinoud case 1: case 2: case 3:
1225 1.1 reinoud /* didn't work; try recalibrating */
1226 1.1 reinoud fdc->sc_state = DORECAL;
1227 1.1 reinoud break;
1228 1.1 reinoud
1229 1.1 reinoud case 4:
1230 1.1 reinoud /* still no go; reset the bastard */
1231 1.1 reinoud fdc->sc_state = DORESET;
1232 1.1 reinoud break;
1233 1.1 reinoud
1234 1.1 reinoud default:
1235 1.1 reinoud fail:
1236 1.1 reinoud if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1237 1.1 reinoud diskerr(bp, "fd", "hard error", LOG_PRINTF,
1238 1.1 reinoud fd->sc_skip / FDC_BSIZE,
1239 1.1 reinoud (struct disklabel *)NULL);
1240 1.40 christos fdcpstatus(7, fdc);
1241 1.1 reinoud }
1242 1.1 reinoud
1243 1.1 reinoud bp->b_error = EIO;
1244 1.1 reinoud fdfinish(fd, bp);
1245 1.1 reinoud }
1246 1.1 reinoud fdc->sc_errors++;
1247 1.1 reinoud }
1248 1.1 reinoud
1249 1.1 reinoud int
1250 1.39 cegger fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1251 1.1 reinoud {
1252 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1253 1.1 reinoud struct fdformat_parms *form_parms;
1254 1.1 reinoud struct fdformat_cmd *form_cmd;
1255 1.1 reinoud struct ne7_fd_formb *fd_formb;
1256 1.1 reinoud struct disklabel buffer;
1257 1.1 reinoud int error;
1258 1.1 reinoud unsigned int scratch;
1259 1.1 reinoud int il[FD_MAX_NSEC + 1];
1260 1.1 reinoud register int i, j;
1261 1.1 reinoud
1262 1.1 reinoud switch (cmd) {
1263 1.1 reinoud case DIOCGDINFO:
1264 1.1 reinoud memset(&buffer, 0, sizeof(buffer));
1265 1.1 reinoud
1266 1.1 reinoud buffer.d_secpercyl = fd->sc_type->seccyl;
1267 1.1 reinoud buffer.d_type = DTYPE_FLOPPY;
1268 1.1 reinoud buffer.d_secsize = FDC_BSIZE;
1269 1.1 reinoud
1270 1.1 reinoud if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1271 1.1 reinoud return EINVAL;
1272 1.1 reinoud
1273 1.1 reinoud *(struct disklabel *)addr = buffer;
1274 1.1 reinoud return 0;
1275 1.1 reinoud
1276 1.1 reinoud case DIOCWLABEL:
1277 1.1 reinoud if ((flag & FWRITE) == 0)
1278 1.1 reinoud return EBADF;
1279 1.1 reinoud /* XXX do something */
1280 1.1 reinoud return 0;
1281 1.1 reinoud
1282 1.1 reinoud case DIOCWDINFO:
1283 1.1 reinoud if ((flag & FWRITE) == 0)
1284 1.1 reinoud return EBADF;
1285 1.1 reinoud
1286 1.1 reinoud error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1287 1.1 reinoud if (error)
1288 1.1 reinoud return error;
1289 1.1 reinoud
1290 1.1 reinoud error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1291 1.1 reinoud return error;
1292 1.1 reinoud
1293 1.1 reinoud case FDIOCGETFORMAT:
1294 1.1 reinoud form_parms = (struct fdformat_parms *)addr;
1295 1.1 reinoud form_parms->fdformat_version = FDFORMAT_VERSION;
1296 1.1 reinoud form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1297 1.1 reinoud form_parms->ncyl = fd->sc_type->cyls;
1298 1.1 reinoud form_parms->nspt = fd->sc_type->sectrac;
1299 1.1 reinoud form_parms->ntrk = fd->sc_type->heads;
1300 1.1 reinoud form_parms->stepspercyl = fd->sc_type->step;
1301 1.1 reinoud form_parms->gaplen = fd->sc_type->gap2;
1302 1.1 reinoud form_parms->fillbyte = fd->sc_type->fillbyte;
1303 1.1 reinoud form_parms->interleave = fd->sc_type->interleave;
1304 1.1 reinoud switch (fd->sc_type->rate) {
1305 1.1 reinoud case FDC_500KBPS:
1306 1.1 reinoud form_parms->xfer_rate = 500 * 1024;
1307 1.1 reinoud break;
1308 1.1 reinoud case FDC_300KBPS:
1309 1.1 reinoud form_parms->xfer_rate = 300 * 1024;
1310 1.1 reinoud break;
1311 1.1 reinoud case FDC_250KBPS:
1312 1.1 reinoud form_parms->xfer_rate = 250 * 1024;
1313 1.1 reinoud break;
1314 1.1 reinoud default:
1315 1.1 reinoud return EINVAL;
1316 1.1 reinoud }
1317 1.1 reinoud return 0;
1318 1.1 reinoud
1319 1.1 reinoud case FDIOCSETFORMAT:
1320 1.1 reinoud if((flag & FWRITE) == 0)
1321 1.1 reinoud return EBADF; /* must be opened for writing */
1322 1.1 reinoud form_parms = (struct fdformat_parms *)addr;
1323 1.1 reinoud if (form_parms->fdformat_version != FDFORMAT_VERSION)
1324 1.1 reinoud return EINVAL; /* wrong version of formatting prog */
1325 1.1 reinoud
1326 1.1 reinoud scratch = form_parms->nbps >> 7;
1327 1.1 reinoud if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1328 1.1 reinoud scratch & ~(1 << (ffs(scratch)-1)))
1329 1.1 reinoud /* not a power-of-two multiple of 128 */
1330 1.1 reinoud return EINVAL;
1331 1.1 reinoud
1332 1.1 reinoud switch (form_parms->xfer_rate) {
1333 1.1 reinoud case 500 * 1024:
1334 1.1 reinoud fd->sc_type->rate = FDC_500KBPS;
1335 1.1 reinoud break;
1336 1.1 reinoud case 300 * 1024:
1337 1.1 reinoud fd->sc_type->rate = FDC_300KBPS;
1338 1.1 reinoud break;
1339 1.1 reinoud case 250 * 1024:
1340 1.1 reinoud fd->sc_type->rate = FDC_250KBPS;
1341 1.1 reinoud break;
1342 1.1 reinoud default:
1343 1.1 reinoud return EINVAL;
1344 1.1 reinoud }
1345 1.1 reinoud
1346 1.1 reinoud if (form_parms->nspt > FD_MAX_NSEC ||
1347 1.1 reinoud form_parms->fillbyte > 0xff ||
1348 1.1 reinoud form_parms->interleave > 0xff)
1349 1.1 reinoud return EINVAL;
1350 1.1 reinoud fd->sc_type->sectrac = form_parms->nspt;
1351 1.1 reinoud if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1352 1.1 reinoud return EINVAL;
1353 1.1 reinoud fd->sc_type->heads = form_parms->ntrk;
1354 1.1 reinoud fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1355 1.1 reinoud fd->sc_type->secsize = ffs(scratch)-1;
1356 1.1 reinoud fd->sc_type->gap2 = form_parms->gaplen;
1357 1.1 reinoud fd->sc_type->cyls = form_parms->ncyl;
1358 1.1 reinoud fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1359 1.1 reinoud form_parms->nbps / DEV_BSIZE;
1360 1.1 reinoud fd->sc_type->step = form_parms->stepspercyl;
1361 1.1 reinoud fd->sc_type->fillbyte = form_parms->fillbyte;
1362 1.1 reinoud fd->sc_type->interleave = form_parms->interleave;
1363 1.1 reinoud return 0;
1364 1.1 reinoud
1365 1.1 reinoud case FDIOCFORMAT_TRACK:
1366 1.1 reinoud if((flag & FWRITE) == 0)
1367 1.1 reinoud return EBADF; /* must be opened for writing */
1368 1.1 reinoud form_cmd = (struct fdformat_cmd *)addr;
1369 1.1 reinoud if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1370 1.1 reinoud return EINVAL; /* wrong version of formatting prog */
1371 1.1 reinoud
1372 1.1 reinoud if (form_cmd->head >= fd->sc_type->heads ||
1373 1.1 reinoud form_cmd->cylinder >= fd->sc_type->cyls) {
1374 1.1 reinoud return EINVAL;
1375 1.1 reinoud }
1376 1.1 reinoud
1377 1.1 reinoud fd_formb = malloc(sizeof(struct ne7_fd_formb),
1378 1.1 reinoud M_TEMP, M_NOWAIT);
1379 1.1 reinoud if(fd_formb == 0)
1380 1.1 reinoud return ENOMEM;
1381 1.1 reinoud
1382 1.1 reinoud
1383 1.1 reinoud fd_formb->head = form_cmd->head;
1384 1.1 reinoud fd_formb->cyl = form_cmd->cylinder;
1385 1.1 reinoud fd_formb->transfer_rate = fd->sc_type->rate;
1386 1.1 reinoud fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1387 1.1 reinoud fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1388 1.1 reinoud fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1389 1.1 reinoud fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1390 1.1 reinoud
1391 1.1 reinoud memset(il, 0, sizeof il);
1392 1.1 reinoud for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1393 1.1 reinoud while (il[(j%fd_formb->fd_formb_nsecs)+1])
1394 1.1 reinoud j++;
1395 1.1 reinoud il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1396 1.1 reinoud j += fd->sc_type->interleave;
1397 1.1 reinoud }
1398 1.1 reinoud for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1399 1.1 reinoud fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1400 1.1 reinoud fd_formb->fd_formb_headno(i) = form_cmd->head;
1401 1.1 reinoud fd_formb->fd_formb_secno(i) = il[i+1];
1402 1.1 reinoud fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1403 1.1 reinoud }
1404 1.1 reinoud
1405 1.22 christos error = fdformat(dev, fd_formb, l);
1406 1.1 reinoud free(fd_formb, M_TEMP);
1407 1.1 reinoud return error;
1408 1.1 reinoud
1409 1.1 reinoud case FDIOCGETOPTS: /* get drive options */
1410 1.1 reinoud *(int *)addr = fd->sc_opts;
1411 1.1 reinoud return 0;
1412 1.1 reinoud
1413 1.1 reinoud case FDIOCSETOPTS: /* set drive options */
1414 1.1 reinoud fd->sc_opts = *(int *)addr;
1415 1.1 reinoud return 0;
1416 1.1 reinoud
1417 1.1 reinoud default:
1418 1.1 reinoud return ENOTTY;
1419 1.1 reinoud }
1420 1.1 reinoud
1421 1.1 reinoud #ifdef DIAGNOSTIC
1422 1.1 reinoud panic("fdioctl: impossible");
1423 1.1 reinoud #endif
1424 1.1 reinoud }
1425 1.1 reinoud
1426 1.1 reinoud int
1427 1.39 cegger fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1428 1.1 reinoud {
1429 1.37 matt int rv = 0;
1430 1.39 cegger struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
1431 1.1 reinoud struct fd_type *type = fd->sc_type;
1432 1.1 reinoud struct buf *bp;
1433 1.1 reinoud
1434 1.1 reinoud /* set up a buffer header for fdstrategy() */
1435 1.35 ad bp = getiobuf(NULL, false);
1436 1.1 reinoud if(bp == 0)
1437 1.1 reinoud return ENOBUFS;
1438 1.35 ad bp->b_flags = B_PHYS | B_FORMAT;
1439 1.35 ad bp->b_cflags |= BC_BUSY;
1440 1.22 christos bp->b_proc = l->l_proc;
1441 1.1 reinoud bp->b_dev = dev;
1442 1.1 reinoud
1443 1.1 reinoud /*
1444 1.1 reinoud * calculate a fake blkno, so fdstrategy() would initiate a
1445 1.1 reinoud * seek to the requested cylinder
1446 1.1 reinoud */
1447 1.1 reinoud bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1448 1.1 reinoud + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1449 1.1 reinoud
1450 1.1 reinoud bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1451 1.28 christos bp->b_data = (void *)finfo;
1452 1.1 reinoud
1453 1.1 reinoud #ifdef DEBUG
1454 1.15 bjh21 printf("fdformat: blkno %llx count %lx\n",
1455 1.15 bjh21 (unsigned long long)bp->b_blkno, bp->b_bcount);
1456 1.1 reinoud #endif
1457 1.1 reinoud
1458 1.1 reinoud /* now do the format */
1459 1.1 reinoud fdstrategy(bp);
1460 1.1 reinoud
1461 1.1 reinoud /* ...and wait for it to complete */
1462 1.35 ad /* XXX very dodgy */
1463 1.35 ad mutex_enter(bp->b_objlock);
1464 1.35 ad while (!(bp->b_oflags & BO_DONE)) {
1465 1.36 ad rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
1466 1.1 reinoud if (rv == EWOULDBLOCK)
1467 1.1 reinoud break;
1468 1.1 reinoud }
1469 1.35 ad mutex_exit(bp->b_objlock);
1470 1.35 ad
1471 1.1 reinoud if (rv == EWOULDBLOCK) {
1472 1.1 reinoud /* timed out */
1473 1.1 reinoud rv = EIO;
1474 1.1 reinoud biodone(bp);
1475 1.30 ad } else if (bp->b_error != 0)
1476 1.1 reinoud rv = bp->b_error;
1477 1.35 ad putiobuf(bp);
1478 1.1 reinoud return rv;
1479 1.1 reinoud }
1480 1.1 reinoud
1481 1.1 reinoud #include "md.h"
1482 1.1 reinoud #if NMD > 0
1483 1.1 reinoud
1484 1.1 reinoud #include <dev/md.h>
1485 1.1 reinoud
1486 1.43 dsl int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev);
1487 1.1 reinoud
1488 1.1 reinoud int
1489 1.44 dsl load_memory_disc_from_floppy(struct md_conf *md, dev_t dev)
1490 1.1 reinoud {
1491 1.1 reinoud struct buf *bp;
1492 1.1 reinoud int loop;
1493 1.1 reinoud int s;
1494 1.1 reinoud int type;
1495 1.1 reinoud int floppysize;
1496 1.1 reinoud
1497 1.6 gehenna if (bdevsw_lookup(dev) != &fd_bdevsw)
1498 1.1 reinoud return(EINVAL);
1499 1.1 reinoud
1500 1.1 reinoud if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1501 1.1 reinoud return(EBUSY);
1502 1.1 reinoud
1503 1.1 reinoud type = FDTYPE(dev) - 1;
1504 1.1 reinoud if (type < 0) type = 0;
1505 1.1 reinoud floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1506 1.1 reinoud
1507 1.1 reinoud if (md->md_size < floppysize) {
1508 1.1 reinoud printf("Memory disc is not big enough for floppy image\n");
1509 1.1 reinoud return(EINVAL);
1510 1.1 reinoud }
1511 1.1 reinoud
1512 1.1 reinoud /* We have the memory disk ! */
1513 1.1 reinoud
1514 1.1 reinoud printf("Loading memory disc : %4dK ", 0);
1515 1.1 reinoud
1516 1.1 reinoud /* obtain a buffer */
1517 1.1 reinoud
1518 1.1 reinoud bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1519 1.1 reinoud
1520 1.1 reinoud /* request no partition relocation by driver on I/O operations */
1521 1.1 reinoud
1522 1.1 reinoud bp->b_dev = dev;
1523 1.1 reinoud
1524 1.42 cegger s = splbio();
1525 1.1 reinoud
1526 1.22 christos if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
1527 1.32 ad brelse(bp, 0);
1528 1.1 reinoud printf("Cannot open floppy device\n");
1529 1.1 reinoud return(EINVAL);
1530 1.1 reinoud }
1531 1.1 reinoud
1532 1.1 reinoud for (loop = 0;
1533 1.1 reinoud loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1534 1.1 reinoud ++loop) {
1535 1.1 reinoud printf("\x08\x08\x08\x08\x08\x08%4dK ",
1536 1.1 reinoud loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1537 1.1 reinoud bp->b_blkno = loop * fd_types[type].sectrac;
1538 1.1 reinoud bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1539 1.1 reinoud bp->b_flags |= B_READ;
1540 1.1 reinoud bp->b_error = 0;
1541 1.1 reinoud bp->b_resid = 0;
1542 1.1 reinoud fdstrategy(bp);
1543 1.1 reinoud
1544 1.1 reinoud if (biowait(bp))
1545 1.7 provos panic("Cannot load floppy image");
1546 1.1 reinoud
1547 1.34 yamt memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
1548 1.28 christos * DEV_BSIZE, (void *)bp->b_data,
1549 1.1 reinoud fd_types[type].sectrac * DEV_BSIZE);
1550 1.1 reinoud }
1551 1.1 reinoud printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1552 1.1 reinoud loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1553 1.1 reinoud
1554 1.22 christos fdclose(bp->b_dev, 0, 0, curlwp);
1555 1.1 reinoud
1556 1.32 ad brelse(bp, 0);
1557 1.1 reinoud
1558 1.1 reinoud splx(s);
1559 1.1 reinoud return(0);
1560 1.1 reinoud }
1561 1.1 reinoud
1562 1.1 reinoud #endif
1563