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