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