fd.c revision 1.23.6.1 1 /* $NetBSD: fd.c,v 1.23.6.1 1999/02/02 23:47:11 minoura 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 and Minoura Makoto.
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 #include "opt_uvm.h"
97
98 #include <sys/param.h>
99 #include <sys/systm.h>
100 #include <sys/kernel.h>
101 #include <sys/conf.h>
102 #include <sys/file.h>
103 #include <sys/stat.h>
104 #include <sys/ioctl.h>
105 #include <sys/malloc.h>
106 #include <sys/device.h>
107 #include <sys/disklabel.h>
108 #include <sys/dkstat.h>
109 #include <sys/disk.h>
110 #include <sys/buf.h>
111 #include <sys/uio.h>
112 #include <sys/syslog.h>
113 #include <sys/queue.h>
114 #include <sys/fdio.h>
115 #if NRND > 0
116 #include <sys/rnd.h>
117 #endif
118
119 #if defined(UVM)
120 #include <vm/vm.h>
121 #include <uvm/uvm_extern.h>
122 #endif
123
124 #include <machine/bus.h>
125 #include <machine/cpu.h>
126
127 #include <arch/x68k/dev/intiovar.h>
128 #include <arch/x68k/dev/dmacvar.h>
129 #include <arch/x68k/dev/fdreg.h>
130 #include <arch/x68k/dev/opmreg.h> /* for CT1 access */
131
132 #include "locators.h"
133
134 #define FDDEBUG
135 #ifdef FDDEBUG
136 #define DPRINTF(x) if (fddebug) printf x
137 int fddebug = 0;
138 #else
139 #define DPRINTF(x)
140 #endif
141
142 #define FDUNIT(dev) (minor(dev) / 8)
143 #define FDTYPE(dev) (minor(dev) % 8)
144
145 /* XXX misuse a flag to identify format operation */
146 #define B_FORMAT B_XXX
147
148 #define b_cylin b_resid
149
150 enum fdc_state {
151 DEVIDLE = 0,
152 MOTORWAIT,
153 DOSEEK,
154 SEEKWAIT,
155 SEEKTIMEDOUT,
156 SEEKCOMPLETE,
157 DOIO,
158 IOCOMPLETE,
159 IOTIMEDOUT,
160 DORESET,
161 RESETCOMPLETE,
162 RESETTIMEDOUT,
163 DORECAL,
164 RECALWAIT,
165 RECALTIMEDOUT,
166 RECALCOMPLETE,
167 DOCOPY,
168 DOIOHALF,
169 COPYCOMPLETE,
170 };
171
172 /* software state, per controller */
173 struct fdc_softc {
174 struct device sc_dev; /* boilerplate */
175 u_char sc_flags;
176
177 bus_space_tag_t sc_bst; /* intio i/o space identifier */
178 bus_space_handle_t sc_bht; /* intio io handle */
179 bus_dma_tag_t sc_dmat; /* intio dma tag */
180 bus_dmamap_t sc_dmamap; /* dma map */
181 u_int8_t *sc_addr; /* physical address */
182 struct dmac_channel_stat *sc_dmachan; /* intio dma channel */
183 struct dmac_dma_xfer *sc_xfer; /* dma transfer */
184
185 struct fd_softc *sc_fd[4]; /* pointers to children */
186 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
187 enum fdc_state sc_state;
188 int sc_errors; /* number of retries so far */
189 u_char sc_status[7]; /* copy of registers */
190 } fdc_softc;
191
192 bdev_decl(fd);
193 cdev_decl(fd);
194
195 int fdcintr __P((void*));
196 void fdcreset __P((struct fdc_softc *));
197
198 /* controller driver configuration */
199 int fdcprobe __P((struct device *, struct cfdata *, void *));
200 void fdcattach __P((struct device *, struct device *, void *));
201 int fdprint __P((void *, const char *));
202
203 struct cfattach fdc_ca = {
204 sizeof(struct fdc_softc), fdcprobe, fdcattach
205 };
206
207 extern struct cfdriver fdc_cd;
208
209 /*
210 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
211 * we tell them apart.
212 */
213 struct fd_type {
214 int sectrac; /* sectors per track */
215 int heads; /* number of heads */
216 int seccyl; /* sectors per cylinder */
217 int secsize; /* size code for sectors */
218 int datalen; /* data len when secsize = 0 */
219 int steprate; /* step rate and head unload time */
220 int gap1; /* gap len between sectors */
221 int gap2; /* formatting gap */
222 int tracks; /* total num of tracks */
223 int size; /* size of disk in sectors */
224 int step; /* steps per cylinder */
225 int rate; /* transfer speed code */
226 char *name;
227 };
228
229 /* The order of entries in the following table is important -- BEWARE! */
230 struct fd_type fd_types[] = {
231 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
232 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
233 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
234 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
235 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
236 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
237 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
238 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
239 };
240
241 /* software state, per disk (with up to 4 disks per ctlr) */
242 struct fd_softc {
243 struct device sc_dev;
244 struct disk sc_dk;
245
246 struct fd_type *sc_deftype; /* default type descriptor */
247 struct fd_type *sc_type; /* current type descriptor */
248 struct fd_type sc_type_copy; /* copy for fiddling when formatting */
249
250 daddr_t sc_blkno; /* starting block number */
251 int sc_bcount; /* byte count left */
252 int sc_opts; /* user-set options */
253 int sc_skip; /* bytes already transferred */
254 int sc_nblks; /* number of blocks currently tranferring */
255 int sc_nbytes; /* number of bytes currently tranferring */
256
257 int sc_drive; /* physical unit number */
258 int sc_flags;
259 #define FD_BOPEN 0x01 /* it's open */
260 #define FD_COPEN 0x02 /* it's open */
261 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
262 #define FD_MOTOR 0x04 /* motor should be on */
263 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
264 #define FD_ALIVE 0x10 /* alive */
265 int sc_cylin; /* where we think the head is */
266
267 TAILQ_ENTRY(fd_softc) sc_drivechain;
268 int sc_ops; /* I/O ops since last switch */
269 struct buf sc_q; /* head of buf chain */
270 u_char *sc_copybuf; /* for secsize >=3 */
271 u_char sc_part; /* for secsize >=3 */
272 #define SEC_P10 0x02 /* first part */
273 #define SEC_P01 0x01 /* second part */
274 #define SEC_P11 0x03 /* both part */
275
276 #if NRND > 0
277 rndsource_element_t rnd_source;
278 #endif
279 };
280
281 /* floppy driver configuration */
282 int fdprobe __P((struct device *, struct cfdata *, void *));
283 void fdattach __P((struct device *, struct device *, void *));
284
285 struct cfattach fd_ca = {
286 sizeof(struct fd_softc), fdprobe, fdattach
287 };
288
289 extern struct cfdriver fd_cd;
290
291 void fdstrategy __P((struct buf *));
292 void fdstart __P((struct fd_softc *fd));
293
294 struct dkdriver fddkdriver = { fdstrategy };
295
296 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
297 void fd_motor_off __P((void *arg));
298 void fd_motor_on __P((void *arg));
299 int fdcresult __P((struct fdc_softc *fdc));
300 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
301 void fdcstart __P((struct fdc_softc *fdc));
302 void fdcstatus __P((struct device *dv, int n, char *s));
303 void fdctimeout __P((void *arg));
304 void fdcpseudointr __P((void *arg));
305 void fdcretry __P((struct fdc_softc *fdc));
306 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
307 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
308 static int fdcpoll __P((struct fdc_softc *));
309 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
310 static void fd_do_eject __P((struct fdc_softc *, int));
311
312 void fd_mountroot_hook __P((struct device *));
313
314 /* dma transfer routines */
315 __inline static void fdc_dmastart __P((struct fdc_softc*, int,
316 caddr_t, vsize_t));
317 static int fdcdmaintr __P((void*));
318 static int fdcdmaerrintr __P((void*));
319
320 __inline static void
321 fdc_dmastart(fdc, read, addr, count)
322 struct fdc_softc *fdc;
323 int read;
324 caddr_t addr;
325 vsize_t count;
326 {
327 int error;
328
329 DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %d\n",
330 read ? "read" : "write", (caddr_t) addr, count));
331
332 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
333 0, BUS_DMA_NOWAIT);
334 if (error) {
335 panic ("fdc_dmastart: cannot load dmamap");
336 }
337
338 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
339 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
340
341 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
342 fdc->sc_dmamap,
343 (read?
344 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
345 (DMAC_SCR_MAC_COUNT_UP|
346 DMAC_SCR_DAC_NO_COUNT),
347 (u_int8_t*) (fdc->sc_addr +
348 fddata)); /* XXX */
349
350 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
351 }
352
353 static int
354 fdcdmaintr(arg)
355 void *arg;
356 {
357 struct fdc_softc *fdc = arg;
358
359 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
360
361 return 0;
362 }
363
364 static int
365 fdcdmaerrintr(dummy)
366 void *dummy;
367 {
368 DPRINTF(("fdcdmaerrintr\n"));
369
370 return 0;
371 }
372
373 /* ARGSUSED */
374 int
375 fdcprobe(parent, cf, aux)
376 struct device *parent;
377 struct cfdata *cf;
378 void *aux;
379 {
380 struct intio_attach_args *ia = aux;
381
382 if (strcmp(ia->ia_name, "fdc") != 0)
383 return 0;
384
385 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
386 ia->ia_addr = FDC_ADDR;
387
388 if (ia->ia_intr & 0x03 != 0)
389 return 0;
390
391 ia->ia_size = 0x2000;
392 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
393 return 0;
394
395 /* builtin device; always there */
396 return 1;
397 }
398
399 /*
400 * Arguments passed between fdcattach and fdprobe.
401 */
402 struct fdc_attach_args {
403 int fa_drive;
404 struct fd_type *fa_deftype;
405 };
406
407 /*
408 * Print the location of a disk drive (called just before attaching the
409 * the drive). If `fdc' is not NULL, the drive was found but was not
410 * in the system config file; print the drive name as well.
411 * Return QUIET (config_find ignores this if the device was configured) to
412 * avoid printing `fdN not configured' messages.
413 */
414 int
415 fdprint(aux, fdc)
416 void *aux;
417 const char *fdc;
418 {
419 register struct fdc_attach_args *fa = aux;
420
421 if (!fdc)
422 printf(" drive %d", fa->fa_drive);
423 return QUIET;
424 }
425
426 void
427 fdcattach(parent, self, aux)
428 struct device *parent, *self;
429 void *aux;
430 {
431 struct fdc_softc *fdc = (void *)self;
432 bus_space_tag_t iot;
433 bus_space_handle_t ioh;
434 struct intio_attach_args *ia = aux;
435 struct fdc_attach_args fa;
436
437 iot = ia->ia_bst;
438
439 printf("\n");
440
441 /* Re-map the I/O space. */
442 bus_space_map(iot, ia->ia_addr, 0x2000, 0, &ioh);
443
444 fdc->sc_bst = iot;
445 fdc->sc_bht = ioh;
446 fdc->sc_addr = (void*) ia->ia_addr;
447
448 fdc->sc_dmat = ia->ia_dmat;
449 fdc->sc_state = DEVIDLE;
450 TAILQ_INIT(&fdc->sc_drives);
451 fdc->sc_flags = 0;
452
453 /* Initialize DMAC channel */
454 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
455 ia->ia_dmaintr, fdcdmaintr, fdc,
456 ia->ia_dmaintr+1, fdcdmaerrintr,
457 fdc);
458 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 16, 0xf000, 0,
459 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
460 &fdc->sc_dmamap)) {
461 printf("%s: can't set up intio DMA map\n",
462 fdc->sc_dev.dv_xname);
463 return;
464 }
465
466 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
467 panic ("Could not establish interrupt (duplicated vector?).");
468 intio_set_ivec(ia->ia_intr);
469
470 /* reset */
471 intio_disable_intr(SICILIAN_INTR_FDD);
472 intio_enable_intr(SICILIAN_INTR_FDC);
473 fdcresult(fdc);
474 fdcreset(fdc);
475
476 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
477 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
478 out_fdc(iot, ioh, 0xd0);
479 out_fdc(iot, ioh, 0x10);
480
481 /* physical limit: four drives per controller. */
482 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
483 (void)config_found(self, (void *)&fa, fdprint);
484 }
485
486 intio_enable_intr(SICILIAN_INTR_FDC);
487 }
488
489 void
490 fdcreset(fdc)
491 struct fdc_softc *fdc;
492 {
493 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fdstat, NE7CMD_RESET);
494 }
495
496 static int
497 fdcpoll(fdc)
498 struct fdc_softc *fdc;
499 {
500 int i = 25000, n;
501 while (--i > 0) {
502 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
503 out_fdc(fdc->sc_bst, fdc->sc_bht, NE7CMD_SENSEI);
504 n = fdcresult(fdc);
505 break;
506 }
507 DELAY(100);
508 }
509 return i;
510 }
511
512 int
513 fdprobe(parent, cf, aux)
514 struct device *parent;
515 struct cfdata *cf;
516 void *aux;
517 {
518 struct fdc_softc *fdc = (void *)parent;
519 struct fd_type *type;
520 struct fdc_attach_args *fa = aux;
521 int drive = fa->fa_drive;
522 bus_space_tag_t iot = fdc->sc_bst;
523 bus_space_handle_t ioh = fdc->sc_bht;
524 int n;
525 int found = 0;
526 int i;
527
528 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
529 cf->cf_loc[FDCCF_UNIT] != drive)
530 return 0;
531
532 type = &fd_types[0]; /* XXX 1.2MB */
533
534 intio_disable_intr(SICILIAN_INTR_FDC);
535
536 /* select drive and turn on motor */
537 bus_space_write_1(iot, ioh, fdselect, 0x80 | (type->rate << 4)| drive);
538 fdc_force_ready(FDCRDY);
539 fdcpoll(fdc);
540
541 retry:
542 out_fdc(iot, ioh, NE7CMD_RECAL);
543 out_fdc(iot, ioh, drive);
544
545 i = 25000;
546 while (--i > 0) {
547 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
548 out_fdc(iot, ioh, NE7CMD_SENSEI);
549 n = fdcresult(fdc);
550 break;
551 }
552 DELAY(100);
553 }
554
555 #ifdef FDDEBUG
556 {
557 int i;
558 DPRINTF(("fdprobe: status"));
559 for (i = 0; i < n; i++)
560 DPRINTF((" %x", fdc->sc_status[i]));
561 DPRINTF(("\n"));
562 }
563 #endif
564
565 if (n == 2) {
566 if ((fdc->sc_status[0] & 0xf0) == 0x20) {
567 found = 1;
568 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
569 goto retry;
570 }
571 }
572
573 /* turn off motor */
574 bus_space_write_1(fdc->sc_bst, fdc->sc_bht,
575 fdselect, (type->rate << 4)| drive);
576 fdc_force_ready(FDCSTBY);
577 if (!found) {
578 intio_enable_intr(SICILIAN_INTR_FDC);
579 return 0;
580 }
581
582 return 1;
583 }
584
585 /*
586 * Controller is working, and drive responded. Attach it.
587 */
588 void
589 fdattach(parent, self, aux)
590 struct device *parent, *self;
591 void *aux;
592 {
593 struct fdc_softc *fdc = (void *)parent;
594 struct fd_softc *fd = (void *)self;
595 struct fdc_attach_args *fa = aux;
596 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
597 int drive = fa->fa_drive;
598
599 fd->sc_flags = 0;
600
601 if (type)
602 printf(": %s, %d cyl, %d head, %d sec\n", type->name,
603 type->tracks, type->heads, type->sectrac);
604 else
605 printf(": density unknown\n");
606
607 fd->sc_cylin = -1;
608 fd->sc_drive = drive;
609 fd->sc_deftype = type;
610 fdc->sc_fd[drive] = fd;
611
612 fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
613 if (fd->sc_copybuf == 0)
614 printf("fdprobe: WARNING!! malloc() failed.\n");
615 fd->sc_flags |= FD_ALIVE;
616
617 /*
618 * Initialize and attach the disk structure.
619 */
620 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
621 fd->sc_dk.dk_driver = &fddkdriver;
622 disk_attach(&fd->sc_dk);
623
624 /*
625 * Establish a mountroot_hook anyway in case we booted
626 * with RB_ASKNAME and get selected as the boot device.
627 */
628 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
629
630 #if NRND > 0
631 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname, RND_TYPE_DISK);
632 #endif
633 }
634
635 __inline struct fd_type *
636 fd_dev_to_type(fd, dev)
637 struct fd_softc *fd;
638 dev_t dev;
639 {
640 int type = FDTYPE(dev);
641
642 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
643 return NULL;
644 return &fd_types[type];
645 }
646
647 void
648 fdstrategy(bp)
649 register struct buf *bp; /* IO operation to perform */
650 {
651 struct fd_softc *fd;
652 int unit = FDUNIT(bp->b_dev);
653 int sz;
654 int s;
655
656 if (unit >= fd_cd.cd_ndevs ||
657 (fd = fd_cd.cd_devs[unit]) == 0 ||
658 bp->b_blkno < 0 ||
659 (bp->b_bcount % FDC_BSIZE) != 0) {
660 DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
661 bp->b_blkno, bp->b_bcount));
662 bp->b_error = EINVAL;
663 goto bad;
664 }
665
666 /* If it's a null transfer, return immediately. */
667 if (bp->b_bcount == 0)
668 goto done;
669
670 sz = howmany(bp->b_bcount, FDC_BSIZE);
671
672 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
673 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
674 if (sz == 0) {
675 /* If exactly at end of disk, return EOF. */
676 bp->b_resid = bp->b_bcount;
677 goto done;
678 }
679 if (sz < 0) {
680 /* If past end of disk, return EINVAL. */
681 bp->b_error = EINVAL;
682 goto bad;
683 }
684 /* Otherwise, truncate request. */
685 bp->b_bcount = sz << DEV_BSHIFT;
686 }
687
688 bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
689 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
690
691 DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
692 bp->b_flags & B_READ ? "read" : "write",
693 bp->b_blkno, bp->b_bcount, bp->b_cylin));
694 /* Queue transfer on drive, activate drive and controller if idle. */
695 s = splbio();
696 disksort(&fd->sc_q, bp);
697 untimeout(fd_motor_off, fd); /* a good idea */
698 if (!fd->sc_q.b_active)
699 fdstart(fd);
700 #ifdef DIAGNOSTIC
701 else {
702 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
703 if (fdc->sc_state == DEVIDLE) {
704 printf("fdstrategy: controller inactive\n");
705 fdcstart(fdc);
706 }
707 }
708 #endif
709 splx(s);
710 return;
711
712 bad:
713 bp->b_flags |= B_ERROR;
714 done:
715 /* Toss transfer; we're done early. */
716 biodone(bp);
717 }
718
719 void
720 fdstart(fd)
721 struct fd_softc *fd;
722 {
723 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
724 int active = fdc->sc_drives.tqh_first != 0;
725
726 /* Link into controller queue. */
727 fd->sc_q.b_active = 1;
728 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
729
730 /* If controller not already active, start it. */
731 if (!active)
732 fdcstart(fdc);
733 }
734
735 void
736 fdfinish(fd, bp)
737 struct fd_softc *fd;
738 struct buf *bp;
739 {
740 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
741
742 /*
743 * Move this drive to the end of the queue to give others a `fair'
744 * chance. We only force a switch if N operations are completed while
745 * another drive is waiting to be serviced, since there is a long motor
746 * startup delay whenever we switch.
747 */
748 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
749 fd->sc_ops = 0;
750 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
751 if (bp->b_actf) {
752 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
753 } else
754 fd->sc_q.b_active = 0;
755 }
756 bp->b_resid = fd->sc_bcount;
757 fd->sc_skip = 0;
758 fd->sc_q.b_actf = bp->b_actf;
759
760 #if NRND > 0
761 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
762 #endif
763
764 biodone(bp);
765 /* turn off motor 5s from now */
766 timeout(fd_motor_off, fd, 5 * hz);
767 fdc->sc_state = DEVIDLE;
768 }
769
770 int
771 fdread(dev, uio, flags)
772 dev_t dev;
773 struct uio *uio;
774 int flags;
775 {
776
777 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
778 }
779
780 int
781 fdwrite(dev, uio, flags)
782 dev_t dev;
783 struct uio *uio;
784 int flags;
785 {
786
787 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
788 }
789
790 void
791 fd_set_motor(fdc, reset)
792 struct fdc_softc *fdc;
793 int reset;
794 {
795 struct fd_softc *fd;
796 int n;
797
798 DPRINTF(("fd_set_motor:\n"));
799 for (n = 0; n < 4; n++)
800 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
801 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fdselect,
802 0x80 | (fd->sc_type->rate << 4)| n);
803 }
804 }
805
806 void
807 fd_motor_off(arg)
808 void *arg;
809 {
810 struct fd_softc *fd = arg;
811 struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
812 int s;
813
814 DPRINTF(("fd_motor_off:\n"));
815
816 s = splbio();
817 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
818 bus_space_write_1 (fdc->sc_bst, fdc->sc_bht, fdselect,
819 (fd->sc_type->rate << 4) | fd->sc_drive);
820 #if 0
821 fd_set_motor(fdc, 0); /* XXX */
822 #endif
823 splx(s);
824 }
825
826 void
827 fd_motor_on(arg)
828 void *arg;
829 {
830 struct fd_softc *fd = arg;
831 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
832 int s;
833
834 DPRINTF(("fd_motor_on:\n"));
835
836 s = splbio();
837 fd->sc_flags &= ~FD_MOTOR_WAIT;
838 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
839 (void) fdcintr(fdc);
840 splx(s);
841 }
842
843 int
844 fdcresult(fdc)
845 struct fdc_softc *fdc;
846 {
847 bus_space_tag_t iot = fdc->sc_bst;
848 bus_space_handle_t ioh = fdc->sc_bht;
849 u_char i;
850 int j = 100000,
851 n = 0;
852
853 for (; j; j--) {
854 i = bus_space_read_1(iot, ioh, fdstat) &
855 (NE7_DIO | NE7_RQM | NE7_CB);
856
857 if (i == NE7_RQM)
858 return n;
859 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
860 if (n >= sizeof(fdc->sc_status)) {
861 log(LOG_ERR, "fdcresult: overrun\n");
862 return -1;
863 }
864 fdc->sc_status[n++] =
865 bus_space_read_1(iot, ioh, fddata);
866 }
867 delay(10);
868 }
869 log(LOG_ERR, "fdcresult: timeout\n");
870 return -1;
871 }
872
873 int
874 out_fdc(iot, ioh, x)
875 bus_space_tag_t iot;
876 bus_space_handle_t ioh;
877 u_char x;
878 {
879 int i = 100000;
880
881 while ((bus_space_read_1(iot, ioh, fdstat) & NE7_DIO) && i-- > 0);
882 if (i <= 0)
883 return -1;
884 while ((bus_space_read_1(iot, ioh, fdstat) & NE7_RQM) == 0 && i-- > 0);
885 if (i <= 0)
886 return -1;
887 bus_space_write_1(iot, ioh, fddata, x);
888 return 0;
889 }
890
891 int
892 fdopen(dev, flags, mode, p)
893 dev_t dev;
894 int flags, mode;
895 struct proc *p;
896 {
897 int unit;
898 struct fd_softc *fd;
899 struct fd_type *type;
900 struct fdc_softc *fdc;
901
902 unit = FDUNIT(dev);
903 if (unit >= fd_cd.cd_ndevs)
904 return ENXIO;
905 fd = fd_cd.cd_devs[unit];
906 if (fd == 0)
907 return ENXIO;
908 type = fd_dev_to_type(fd, dev);
909 if (type == NULL)
910 return ENXIO;
911
912 if ((fd->sc_flags & FD_OPEN) != 0 &&
913 fd->sc_type != type)
914 return EBUSY;
915
916 fdc = (void *)fd->sc_dev.dv_parent;
917 if ((fd->sc_flags & FD_OPEN) == 0) {
918 /* Lock eject button */
919 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fddrvstat,
920 0x40 | ( 1 << unit));
921 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fddrvstat, 0x40);
922 }
923
924 fd->sc_type = type;
925 fd->sc_cylin = -1;
926
927 switch (mode) {
928 case S_IFCHR:
929 fd->sc_flags |= FD_COPEN;
930 break;
931 case S_IFBLK:
932 fd->sc_flags |= FD_BOPEN;
933 break;
934 }
935
936 fdgetdisklabel(fd, dev);
937
938 return 0;
939 }
940
941 int
942 fdclose(dev, flags, mode, p)
943 dev_t dev;
944 int flags, mode;
945 struct proc *p;
946 {
947 int unit = FDUNIT(dev);
948 struct fd_softc *fd = fd_cd.cd_devs[unit];
949 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
950
951 DPRINTF(("fdclose %d\n", unit));
952
953 switch (mode) {
954 case S_IFCHR:
955 fd->sc_flags &= ~FD_COPEN;
956 break;
957 case S_IFBLK:
958 fd->sc_flags &= ~FD_BOPEN;
959 break;
960 }
961
962 if ((fd->sc_flags & FD_OPEN) == 0) {
963 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fddrvstat,
964 ( 1 << unit));
965 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fddrvstat, 0);
966 }
967 return 0;
968 }
969
970 void
971 fdcstart(fdc)
972 struct fdc_softc *fdc;
973 {
974
975 #ifdef DIAGNOSTIC
976 /* only got here if controller's drive queue was inactive; should
977 be in idle state */
978 if (fdc->sc_state != DEVIDLE) {
979 printf("fdcstart: not idle\n");
980 return;
981 }
982 #endif
983 (void) fdcintr(fdc);
984 }
985
986 void
987 fdcstatus(dv, n, s)
988 struct device *dv;
989 int n;
990 char *s;
991 {
992 struct fdc_softc *fdc = (void *)dv->dv_parent;
993 char bits[64];
994
995 if (n == 0) {
996 out_fdc(fdc->sc_bst, fdc->sc_bht, NE7CMD_SENSEI);
997 (void) fdcresult(fdc);
998 n = 2;
999 }
1000
1001 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
1002
1003 switch (n) {
1004 case 0:
1005 printf("\n");
1006 break;
1007 case 2:
1008 printf(" (st0 %s cyl %d)\n",
1009 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1010 bits, sizeof(bits)), fdc->sc_status[1]);
1011 break;
1012 case 7:
1013 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1014 NE7_ST0BITS, bits, sizeof(bits)));
1015 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1016 NE7_ST1BITS, bits, sizeof(bits)));
1017 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1018 NE7_ST2BITS, bits, sizeof(bits)));
1019 printf(" cyl %d head %d sec %d)\n",
1020 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1021 break;
1022 #ifdef DIAGNOSTIC
1023 default:
1024 printf(" fdcstatus: weird size: %d\n", n);
1025 break;
1026 #endif
1027 }
1028 }
1029
1030 void
1031 fdctimeout(arg)
1032 void *arg;
1033 {
1034 struct fdc_softc *fdc = arg;
1035 struct fd_softc *fd = fdc->sc_drives.tqh_first;
1036 int s;
1037
1038 s = splbio();
1039 fdcstatus(&fd->sc_dev, 0, "timeout");
1040
1041 if (fd->sc_q.b_actf)
1042 fdc->sc_state++;
1043 else
1044 fdc->sc_state = DEVIDLE;
1045
1046 (void) fdcintr(fdc);
1047 splx(s);
1048 }
1049
1050 #if 0
1051 void
1052 fdcpseudointr(arg)
1053 void *arg;
1054 {
1055 int s;
1056 struct fdc_softc *fdc = arg;
1057
1058 /* just ensure it has the right spl */
1059 s = splbio();
1060 (void) fdcintr(fdc);
1061 splx(s);
1062 }
1063 #endif
1064
1065 int
1066 fdcintr(arg)
1067 void *arg;
1068 {
1069 struct fdc_softc *fdc = arg;
1070 #define st0 fdc->sc_status[0]
1071 #define cyl fdc->sc_status[1]
1072 struct fd_softc *fd;
1073 struct buf *bp;
1074 bus_space_tag_t iot = fdc->sc_bst;
1075 bus_space_handle_t ioh = fdc->sc_bht;
1076 int read, head, sec, pos, i, sectrac, nblks;
1077 int tmp;
1078 struct fd_type *type;
1079
1080 loop:
1081 fd = fdc->sc_drives.tqh_first;
1082 if (fd == NULL) {
1083 DPRINTF(("fdcintr: set DEVIDLE\n"));
1084 if (fdc->sc_state == DEVIDLE) {
1085 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1086 out_fdc(iot, ioh, NE7CMD_SENSEI);
1087 if ((tmp = fdcresult(fdc)) != 2 ||
1088 (st0 & 0xf8) != 0x20) {
1089 goto loop;
1090 }
1091 }
1092 }
1093 /* no drives waiting; end */
1094 fdc->sc_state = DEVIDLE;
1095 return 1;
1096 }
1097
1098 /* Is there a transfer to this drive? If not, deactivate drive. */
1099 bp = fd->sc_q.b_actf;
1100 if (bp == NULL) {
1101 fd->sc_ops = 0;
1102 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1103 fd->sc_q.b_active = 0;
1104 goto loop;
1105 }
1106
1107 switch (fdc->sc_state) {
1108 case DEVIDLE:
1109 DPRINTF(("fdcintr: in DEVIDLE\n"));
1110 fdc->sc_errors = 0;
1111 fd->sc_skip = 0;
1112 fd->sc_bcount = bp->b_bcount;
1113 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1114 untimeout(fd_motor_off, fd);
1115 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1116 fdc->sc_state = MOTORWAIT;
1117 return 1;
1118 }
1119 if ((fd->sc_flags & FD_MOTOR) == 0) {
1120 /* Turn on the motor */
1121 /* being careful about other drives. */
1122 for (i = 0; i < 4; i++) {
1123 struct fd_softc *ofd = fdc->sc_fd[i];
1124 if (ofd && ofd->sc_flags & FD_MOTOR) {
1125 untimeout(fd_motor_off, ofd);
1126 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1127 break;
1128 }
1129 }
1130 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1131 fd_set_motor(fdc, 0);
1132 fdc->sc_state = MOTORWAIT;
1133 /* allow .5s for motor to stabilize */
1134 timeout(fd_motor_on, fd, hz / 2);
1135 return 1;
1136 }
1137 /* Make sure the right drive is selected. */
1138 fd_set_motor(fdc, 0);
1139
1140 /* fall through */
1141 case DOSEEK:
1142 doseek:
1143 DPRINTF(("fdcintr: in DOSEEK\n"));
1144 if (fd->sc_cylin == bp->b_cylin)
1145 goto doio;
1146
1147 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1148 out_fdc(iot, ioh, 0xd0); /* XXX const */
1149 out_fdc(iot, ioh, 0x10);
1150
1151 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1152 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1153 out_fdc(iot, ioh, bp->b_cylin * fd->sc_type->step);
1154
1155 fd->sc_cylin = -1;
1156 fdc->sc_state = SEEKWAIT;
1157
1158 fd->sc_dk.dk_seek++;
1159 disk_busy(&fd->sc_dk);
1160
1161 timeout(fdctimeout, fdc, 4 * hz);
1162 return 1;
1163
1164 case DOIO:
1165 doio:
1166 DPRINTF(("fdcintr: DOIO: "));
1167 type = fd->sc_type;
1168 sectrac = type->sectrac;
1169 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1170 sec = pos / (1 << (type->secsize - 2));
1171 if (type->secsize == 2) {
1172 fd->sc_part = SEC_P11;
1173 nblks = (sectrac - sec) << (type->secsize - 2);
1174 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1175 DPRINTF(("nblks(0)"));
1176 } else if ((fd->sc_blkno % 2) == 0) {
1177 if (fd->sc_bcount & 0x00000200) {
1178 if (fd->sc_bcount == FDC_BSIZE) {
1179 fd->sc_part = SEC_P10;
1180 nblks = 1;
1181 DPRINTF(("nblks(1)"));
1182 } else {
1183 fd->sc_part = SEC_P11;
1184 nblks = (sectrac - sec) * 2;
1185 nblks = min(nblks, fd->sc_bcount
1186 / FDC_BSIZE - 1);
1187 DPRINTF(("nblks(2)"));
1188 }
1189 } else {
1190 fd->sc_part = SEC_P11;
1191 nblks = (sectrac - sec)
1192 << (type->secsize - 2);
1193 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1194 DPRINTF(("nblks(3)"));
1195 }
1196 } else {
1197 fd->sc_part = SEC_P01;
1198 nblks = 1;
1199 DPRINTF(("nblks(4)"));
1200 }
1201 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1202 DPRINTF((" %d\n", nblks));
1203 fd->sc_nblks = nblks;
1204 fd->sc_nbytes = nblks * FDC_BSIZE;
1205 head = (fd->sc_blkno
1206 % (type->seccyl * (1 << (type->secsize - 2))))
1207 / (type->sectrac * (1 << (type->secsize - 2)));
1208
1209 #ifdef DIAGNOSTIC
1210 {int block;
1211 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1212 + sec) * (1 << (type->secsize - 2));
1213 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1214 if (block != fd->sc_blkno) {
1215 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1216 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1217 #ifdef DDB
1218 Debugger();
1219 #endif
1220 }}
1221 #endif
1222 read = bp->b_flags & B_READ;
1223 DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1224 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1225 head, sec, nblks, fd->sc_skip));
1226 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1227 type->secsize));
1228
1229 if (fd->sc_part != SEC_P11)
1230 goto docopy;
1231
1232 fdc_dmastart(fdc,
1233 read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1234 if (read)
1235 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1236 else
1237 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1238 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1239 out_fdc(iot, ioh, bp->b_cylin); /* cylinder */
1240 out_fdc(iot, ioh, head);
1241 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1242 out_fdc(iot, ioh, type->secsize); /* sector size */
1243 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1244 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1245 out_fdc(iot, ioh, type->datalen); /* data length */
1246 fdc->sc_state = IOCOMPLETE;
1247
1248 disk_busy(&fd->sc_dk);
1249
1250 /* allow 2 seconds for operation */
1251 timeout(fdctimeout, fdc, 2 * hz);
1252 return 1; /* will return later */
1253
1254 case DOCOPY:
1255 docopy:
1256 DPRINTF(("fdcintr: DOCOPY:\n"));
1257 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1258 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1259 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1260 out_fdc(iot, ioh, bp->b_cylin); /* cylinder */
1261 out_fdc(iot, ioh, head);
1262 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1263 out_fdc(iot, ioh, type->secsize); /* sector size */
1264 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1265 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1266 out_fdc(iot, ioh, type->datalen); /* data length */
1267 fdc->sc_state = COPYCOMPLETE;
1268 /* allow 2 seconds for operation */
1269 timeout(fdctimeout, fdc, 2 * hz);
1270 return 1; /* will return later */
1271
1272 case DOIOHALF:
1273 doiohalf:
1274 DPRINTF((" DOIOHALF:\n"));
1275
1276 #ifdef DIAGNOSTIC
1277 type = fd->sc_type;
1278 sectrac = type->sectrac;
1279 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1280 sec = pos / (1 << (type->secsize - 2));
1281 head = (fd->sc_blkno
1282 % (type->seccyl * (1 << (type->secsize - 2))))
1283 / (type->sectrac * (1 << (type->secsize - 2)));
1284 {int block;
1285 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1286 * (1 << (type->secsize - 2));
1287 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1288 if (block != fd->sc_blkno) {
1289 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1290 #ifdef DDB
1291 Debugger();
1292 #endif
1293 }}
1294 #endif
1295 if (read = bp->b_flags & B_READ) {
1296 bcopy(fd->sc_copybuf
1297 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1298 bp->b_data + fd->sc_skip,
1299 FDC_BSIZE);
1300 fdc->sc_state = IOCOMPLETE;
1301 goto iocomplete2;
1302 } else {
1303 bcopy(bp->b_data + fd->sc_skip,
1304 fd->sc_copybuf
1305 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1306 FDC_BSIZE);
1307 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1308 }
1309 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1310 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1311 out_fdc(iot, ioh, bp->b_cylin); /* cylinder */
1312 out_fdc(iot, ioh, head);
1313 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1314 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1315 out_fdc(iot, ioh, sectrac); /* sectors/track */
1316 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1317 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1318 fdc->sc_state = IOCOMPLETE;
1319 /* allow 2 seconds for operation */
1320 timeout(fdctimeout, fdc, 2 * hz);
1321 return 1; /* will return later */
1322
1323 case SEEKWAIT:
1324 untimeout(fdctimeout, fdc);
1325 fdc->sc_state = SEEKCOMPLETE;
1326 /* allow 1/50 second for heads to settle */
1327 /* timeout(fdcpseudointr, fdc, hz / 50);*/
1328 return 1;
1329
1330 case SEEKCOMPLETE:
1331 /* Make sure seek really happened */
1332 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1333 bus_space_read_1(fdc->sc_bst, fdc->sc_bht, fdstat)));
1334 out_fdc(iot, ioh, NE7CMD_SENSEI);
1335 tmp = fdcresult(fdc);
1336 if ((st0 & 0xf8) == 0xc0) {
1337 DPRINTF(("fdcintr: first seek!\n"));
1338 fdc->sc_state = DORECAL;
1339 goto loop;
1340 } else if (tmp != 2 ||
1341 (st0 & 0xf8) != 0x20 ||
1342 cyl != bp->b_cylin) {
1343 #ifdef FDDEBUG
1344 fdcstatus(&fd->sc_dev, 2, "seek failed");
1345 #endif
1346 fdcretry(fdc);
1347 goto loop;
1348 }
1349 fd->sc_cylin = bp->b_cylin;
1350 goto doio;
1351
1352 case IOTIMEDOUT:
1353 #if 0
1354 isa_dmaabort(fdc->sc_drq);
1355 #endif
1356 case SEEKTIMEDOUT:
1357 case RECALTIMEDOUT:
1358 case RESETTIMEDOUT:
1359 fdcretry(fdc);
1360 goto loop;
1361
1362 case IOCOMPLETE: /* IO DONE, post-analyze */
1363 untimeout(fdctimeout, fdc);
1364 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1365 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1366 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1367 #if 0
1368 isa_dmaabort(fdc->sc_drq);
1369 #endif
1370 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1371 "read failed" : "write failed");
1372 printf("blkno %d nblks %d\n",
1373 fd->sc_blkno, fd->sc_nblks);
1374 fdcretry(fdc);
1375 goto loop;
1376 }
1377 #if 0
1378 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1379 nblks * FDC_BSIZE, fdc->sc_drq);
1380 #endif
1381 iocomplete2:
1382 if (fdc->sc_errors) {
1383 diskerr(bp, "fd", "soft error", LOG_PRINTF,
1384 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1385 printf("\n");
1386 fdc->sc_errors = 0;
1387 }
1388 fd->sc_blkno += fd->sc_nblks;
1389 fd->sc_skip += fd->sc_nbytes;
1390 fd->sc_bcount -= fd->sc_nbytes;
1391 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1392 if (fd->sc_bcount > 0) {
1393 bp->b_cylin = fd->sc_blkno
1394 / (fd->sc_type->seccyl
1395 * (1 << (fd->sc_type->secsize - 2)));
1396 goto doseek;
1397 }
1398 fdfinish(fd, bp);
1399 goto loop;
1400
1401 case COPYCOMPLETE: /* IO DONE, post-analyze */
1402 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1403 untimeout(fdctimeout, fdc);
1404 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1405 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1406 #if 0
1407 isa_dmaabort(fdc->sc_drq);
1408 #endif
1409 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1410 "read failed" : "write failed");
1411 printf("blkno %d nblks %d\n",
1412 fd->sc_blkno, fd->sc_nblks);
1413 fdcretry(fdc);
1414 goto loop;
1415 }
1416 goto doiohalf;
1417
1418 case DORESET:
1419 DPRINTF(("fdcintr: in DORESET\n"));
1420 /* try a reset, keep motor on */
1421 fd_set_motor(fdc, 1);
1422 DELAY(100);
1423 fd_set_motor(fdc, 0);
1424 fdc->sc_state = RESETCOMPLETE;
1425 timeout(fdctimeout, fdc, hz / 2);
1426 return 1; /* will return later */
1427
1428 case RESETCOMPLETE:
1429 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1430 untimeout(fdctimeout, fdc);
1431 /* clear the controller output buffer */
1432 for (i = 0; i < 4; i++) {
1433 out_fdc(iot, ioh, NE7CMD_SENSEI);
1434 (void) fdcresult(fdc);
1435 }
1436
1437 /* fall through */
1438 case DORECAL:
1439 DPRINTF(("fdcintr: in DORECAL\n"));
1440 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1441 out_fdc(iot, ioh, fd->sc_drive);
1442 fdc->sc_state = RECALWAIT;
1443 timeout(fdctimeout, fdc, 5 * hz);
1444 return 1; /* will return later */
1445
1446 case RECALWAIT:
1447 DPRINTF(("fdcintr: in RECALWAIT\n"));
1448 untimeout(fdctimeout, fdc);
1449 fdc->sc_state = RECALCOMPLETE;
1450 /* allow 1/30 second for heads to settle */
1451 /* timeout(fdcpseudointr, fdc, hz / 30);*/
1452 return 1; /* will return later */
1453
1454 case RECALCOMPLETE:
1455 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1456 out_fdc(iot, ioh, NE7CMD_SENSEI);
1457 tmp = fdcresult(fdc);
1458 if ((st0 & 0xf8) == 0xc0) {
1459 DPRINTF(("fdcintr: first seek!\n"));
1460 fdc->sc_state = DORECAL;
1461 goto loop;
1462 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1463 #ifdef FDDEBUG
1464 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1465 #endif
1466 fdcretry(fdc);
1467 goto loop;
1468 }
1469 fd->sc_cylin = 0;
1470 goto doseek;
1471
1472 case MOTORWAIT:
1473 if (fd->sc_flags & FD_MOTOR_WAIT)
1474 return 1; /* time's not up yet */
1475 goto doseek;
1476
1477 default:
1478 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1479 return 1;
1480 }
1481 #ifdef DIAGNOSTIC
1482 panic("fdcintr: impossible");
1483 #endif
1484 #undef st0
1485 #undef cyl
1486 }
1487
1488 void
1489 fdcretry(fdc)
1490 struct fdc_softc *fdc;
1491 {
1492 struct fd_softc *fd;
1493 struct buf *bp;
1494 char bits[64];
1495
1496 DPRINTF(("fdcretry:\n"));
1497 fd = fdc->sc_drives.tqh_first;
1498 bp = fd->sc_q.b_actf;
1499
1500 switch (fdc->sc_errors) {
1501 case 0:
1502 /* try again */
1503 fdc->sc_state = SEEKCOMPLETE;
1504 break;
1505
1506 case 1: case 2: case 3:
1507 /* didn't work; try recalibrating */
1508 fdc->sc_state = DORECAL;
1509 break;
1510
1511 case 4:
1512 /* still no go; reset the bastard */
1513 fdc->sc_state = DORESET;
1514 break;
1515
1516 default:
1517 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1518 fd->sc_skip, (struct disklabel *)NULL);
1519 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1520 NE7_ST0BITS, bits,
1521 sizeof(bits)));
1522 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1523 NE7_ST1BITS, bits,
1524 sizeof(bits)));
1525 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1526 NE7_ST2BITS, bits,
1527 sizeof(bits)));
1528 printf(" cyl %d head %d sec %d)\n",
1529 fdc->sc_status[3],
1530 fdc->sc_status[4],
1531 fdc->sc_status[5]);
1532
1533 bp->b_flags |= B_ERROR;
1534 bp->b_error = EIO;
1535 fdfinish(fd, bp);
1536 }
1537 fdc->sc_errors++;
1538 }
1539
1540 int
1541 fdsize(dev)
1542 dev_t dev;
1543 {
1544
1545 /* Swapping to floppies would not make sense. */
1546 return -1;
1547 }
1548
1549 int
1550 fddump(dev, blkno, va, size)
1551 dev_t dev;
1552 daddr_t blkno;
1553 caddr_t va;
1554 size_t size;
1555 {
1556
1557 /* Not implemented. */
1558 return ENXIO;
1559 }
1560
1561 int
1562 fdioctl(dev, cmd, addr, flag, p)
1563 dev_t dev;
1564 u_long cmd;
1565 caddr_t addr;
1566 int flag;
1567 struct proc *p;
1568 {
1569 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1570 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1571 int unit = FDUNIT(dev);
1572 struct disklabel buffer;
1573 int error;
1574
1575 DPRINTF(("fdioctl:\n"));
1576 switch (cmd) {
1577 case DIOCGDINFO:
1578 #if 1
1579 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1580 return(0);
1581 #else
1582 bzero(&buffer, sizeof(buffer));
1583
1584 buffer.d_secpercyl = fd->sc_type->seccyl;
1585 buffer.d_type = DTYPE_FLOPPY;
1586 buffer.d_secsize = 128 << fd->sc_type->secsize;
1587
1588 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1589 return EINVAL;
1590
1591 *(struct disklabel *)addr = buffer;
1592 return 0;
1593 #endif
1594
1595 case DIOCGPART:
1596 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1597 ((struct partinfo *)addr)->part =
1598 &fd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
1599 return(0);
1600
1601 case DIOCWLABEL:
1602 if ((flag & FWRITE) == 0)
1603 return EBADF;
1604 /* XXX do something */
1605 return 0;
1606
1607 case DIOCWDINFO:
1608 if ((flag & FWRITE) == 0)
1609 return EBADF;
1610
1611 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1612 if (error)
1613 return error;
1614
1615 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1616 return error;
1617
1618 case DIOCLOCK:
1619 /*
1620 * Nothing to do here, really.
1621 */
1622 return 0; /* XXX */
1623
1624 case DIOCEJECT:
1625 fd_do_eject(fdc, unit);
1626 return 0;
1627
1628 default:
1629 return ENOTTY;
1630 }
1631
1632 #ifdef DIAGNOSTIC
1633 panic("fdioctl: impossible");
1634 #endif
1635 }
1636
1637 void
1638 fd_do_eject(fdc, unit)
1639 struct fdc_softc *fdc;
1640 int unit;
1641 {
1642 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fddrvstat,
1643 0x20 | ( 1 << unit));
1644 DELAY(1); /* XXX */
1645 bus_space_write_1(fdc->sc_bst, fdc->sc_bht, fddrvstat, 0x20);
1646 }
1647
1648 /*
1649 * Build disk label. For now we only create a label from what we know
1650 * from 'sc'.
1651 */
1652 static int
1653 fdgetdisklabel(sc, dev)
1654 struct fd_softc *sc;
1655 dev_t dev;
1656 {
1657 struct disklabel *lp;
1658 int part;
1659
1660 DPRINTF(("fdgetdisklabel()\n"));
1661
1662 part = DISKPART(dev);
1663 lp = sc->sc_dk.dk_label;
1664 bzero(lp, sizeof(struct disklabel));
1665
1666 lp->d_secsize = 128 << sc->sc_type->secsize;
1667 lp->d_ntracks = sc->sc_type->heads;
1668 lp->d_nsectors = sc->sc_type->sectrac;
1669 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1670 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1671 lp->d_secperunit = sc->sc_type->size;
1672
1673 lp->d_type = DTYPE_FLOPPY;
1674 lp->d_rpm = 300; /* XXX */
1675 lp->d_interleave = 1; /* FIXME: is this OK? */
1676 lp->d_bbsize = 0;
1677 lp->d_sbsize = 0;
1678 lp->d_npartitions = part + 1;
1679 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1680 lp->d_trkseek = STEP_DELAY; /* XXX */
1681 lp->d_magic = DISKMAGIC;
1682 lp->d_magic2 = DISKMAGIC;
1683 lp->d_checksum = dkcksum(lp);
1684 lp->d_partitions[part].p_size = lp->d_secperunit;
1685 lp->d_partitions[part].p_fstype = FS_UNUSED;
1686 lp->d_partitions[part].p_fsize = 1024;
1687 lp->d_partitions[part].p_frag = 8;
1688
1689 return(0);
1690 }
1691
1692 /*
1693 * Mountroot hook: prompt the user to enter the root file system
1694 * floppy.
1695 */
1696 void
1697 fd_mountroot_hook(dev)
1698 struct device *dev;
1699 {
1700 struct fd_softc *fd = (void*) dev;
1701 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1702 int c;
1703
1704 fd_do_eject(fdc, dev->dv_unit);
1705 printf("Insert filesystem floppy and press return.");
1706 for (;;) {
1707 c = cngetc();
1708 if ((c == '\r') || (c == '\n')) {
1709 printf("\n");
1710 break;
1711 }
1712 }
1713 }
1714