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