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