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