fd.c revision 1.25 1 /* $NetBSD: fd.c,v 1.25 1999/03/16 16:30:17 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, RND_TYPE_DISK);
618 #endif
619 }
620
621 __inline struct fd_type *
622 fd_dev_to_type(fd, dev)
623 struct fd_softc *fd;
624 dev_t dev;
625 {
626 int type = FDTYPE(dev);
627
628 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
629 return NULL;
630 return &fd_types[type];
631 }
632
633 void
634 fdstrategy(bp)
635 register struct buf *bp; /* IO operation to perform */
636 {
637 struct fd_softc *fd;
638 int unit = FDUNIT(bp->b_dev);
639 int sz;
640 int s;
641
642 if (unit >= fd_cd.cd_ndevs ||
643 (fd = fd_cd.cd_devs[unit]) == 0 ||
644 bp->b_blkno < 0 ||
645 (bp->b_bcount % FDC_BSIZE) != 0) {
646 DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
647 bp->b_blkno, bp->b_bcount));
648 bp->b_error = EINVAL;
649 goto bad;
650 }
651
652 /* If it's a null transfer, return immediately. */
653 if (bp->b_bcount == 0)
654 goto done;
655
656 sz = howmany(bp->b_bcount, FDC_BSIZE);
657
658 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
659 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
660 if (sz == 0) {
661 /* If exactly at end of disk, return EOF. */
662 bp->b_resid = bp->b_bcount;
663 goto done;
664 }
665 if (sz < 0) {
666 /* If past end of disk, return EINVAL. */
667 bp->b_error = EINVAL;
668 goto bad;
669 }
670 /* Otherwise, truncate request. */
671 bp->b_bcount = sz << DEV_BSHIFT;
672 }
673
674 bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
675 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
676
677 DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
678 bp->b_flags & B_READ ? "read" : "write",
679 bp->b_blkno, bp->b_bcount, bp->b_cylin));
680 /* Queue transfer on drive, activate drive and controller if idle. */
681 s = splbio();
682 disksort(&fd->sc_q, bp);
683 untimeout(fd_motor_off, fd); /* a good idea */
684 if (!fd->sc_q.b_active)
685 fdstart(fd);
686 #ifdef DIAGNOSTIC
687 else {
688 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
689 if (fdc->sc_state == DEVIDLE) {
690 printf("fdstrategy: controller inactive\n");
691 fdcstart(fdc);
692 }
693 }
694 #endif
695 splx(s);
696 return;
697
698 bad:
699 bp->b_flags |= B_ERROR;
700 done:
701 /* Toss transfer; we're done early. */
702 biodone(bp);
703 }
704
705 void
706 fdstart(fd)
707 struct fd_softc *fd;
708 {
709 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
710 int active = fdc->sc_drives.tqh_first != 0;
711
712 /* Link into controller queue. */
713 fd->sc_q.b_active = 1;
714 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
715
716 /* If controller not already active, start it. */
717 if (!active)
718 fdcstart(fdc);
719 }
720
721 void
722 fdfinish(fd, bp)
723 struct fd_softc *fd;
724 struct buf *bp;
725 {
726 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
727
728 /*
729 * Move this drive to the end of the queue to give others a `fair'
730 * chance. We only force a switch if N operations are completed while
731 * another drive is waiting to be serviced, since there is a long motor
732 * startup delay whenever we switch.
733 */
734 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
735 fd->sc_ops = 0;
736 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
737 if (bp->b_actf) {
738 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
739 } else
740 fd->sc_q.b_active = 0;
741 }
742 bp->b_resid = fd->sc_bcount;
743 fd->sc_skip = 0;
744 fd->sc_q.b_actf = bp->b_actf;
745
746 #if NRND > 0
747 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
748 #endif
749
750 biodone(bp);
751 /* turn off motor 5s from now */
752 timeout(fd_motor_off, fd, 5 * hz);
753 fdc->sc_state = DEVIDLE;
754 }
755
756 int
757 fdread(dev, uio, flags)
758 dev_t dev;
759 struct uio *uio;
760 int flags;
761 {
762
763 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
764 }
765
766 int
767 fdwrite(dev, uio, flags)
768 dev_t dev;
769 struct uio *uio;
770 int flags;
771 {
772
773 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
774 }
775
776 void
777 fd_set_motor(fdc, reset)
778 struct fdc_softc *fdc;
779 int reset;
780 {
781 struct fd_softc *fd;
782 int n;
783
784 DPRINTF(("fd_set_motor:\n"));
785 for (n = 0; n < 4; n++)
786 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
787 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
788 0x80 | (fd->sc_type->rate << 4)| n);
789 }
790 }
791
792 void
793 fd_motor_off(arg)
794 void *arg;
795 {
796 struct fd_softc *fd = arg;
797 struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
798 int s;
799
800 DPRINTF(("fd_motor_off:\n"));
801
802 s = splbio();
803 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
804 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
805 (fd->sc_type->rate << 4) | fd->sc_drive);
806 #if 0
807 fd_set_motor(fdc, 0); /* XXX */
808 #endif
809 splx(s);
810 }
811
812 void
813 fd_motor_on(arg)
814 void *arg;
815 {
816 struct fd_softc *fd = arg;
817 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
818 int s;
819
820 DPRINTF(("fd_motor_on:\n"));
821
822 s = splbio();
823 fd->sc_flags &= ~FD_MOTOR_WAIT;
824 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
825 (void) fdcintr(fdc);
826 splx(s);
827 }
828
829 int
830 fdcresult(fdc)
831 struct fdc_softc *fdc;
832 {
833 bus_space_tag_t iot = fdc->sc_iot;
834 bus_space_handle_t ioh = fdc->sc_ioh;
835 u_char i;
836 int j = 100000,
837 n = 0;
838
839 for (; j; j--) {
840 i = bus_space_read_1(iot, ioh, fdsts) &
841 (NE7_DIO | NE7_RQM | NE7_CB);
842
843 if (i == NE7_RQM)
844 return n;
845 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
846 if (n >= sizeof(fdc->sc_status)) {
847 log(LOG_ERR, "fdcresult: overrun\n");
848 return -1;
849 }
850 fdc->sc_status[n++] =
851 bus_space_read_1(iot, ioh, fddata);
852 }
853 delay(10);
854 }
855 log(LOG_ERR, "fdcresult: timeout\n");
856 return -1;
857 }
858
859 int
860 out_fdc(iot, ioh, x)
861 bus_space_tag_t iot;
862 bus_space_handle_t ioh;
863 u_char x;
864 {
865 int i = 100000;
866
867 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
868 if (i <= 0)
869 return -1;
870 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
871 if (i <= 0)
872 return -1;
873 bus_space_write_1(iot, ioh, fddata, x);
874 return 0;
875 }
876
877 int
878 fdopen(dev, flags, mode, p)
879 dev_t dev;
880 int flags, mode;
881 struct proc *p;
882 {
883 int unit;
884 struct fd_softc *fd;
885 struct fd_type *type;
886 struct fdc_softc *fdc;
887
888 unit = FDUNIT(dev);
889 if (unit >= fd_cd.cd_ndevs)
890 return ENXIO;
891 fd = fd_cd.cd_devs[unit];
892 if (fd == 0)
893 return ENXIO;
894 type = fd_dev_to_type(fd, dev);
895 if (type == NULL)
896 return ENXIO;
897
898 if ((fd->sc_flags & FD_OPEN) != 0 &&
899 fd->sc_type != type)
900 return EBUSY;
901
902 fdc = (void *)fd->sc_dev.dv_parent;
903 if ((fd->sc_flags & FD_OPEN) == 0) {
904 /* Lock eject button */
905 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
906 0x40 | ( 1 << unit));
907 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
908 }
909
910 fd->sc_type = type;
911 fd->sc_cylin = -1;
912
913 switch (mode) {
914 case S_IFCHR:
915 fd->sc_flags |= FD_COPEN;
916 break;
917 case S_IFBLK:
918 fd->sc_flags |= FD_BOPEN;
919 break;
920 }
921
922 fdgetdisklabel(fd, dev);
923
924 return 0;
925 }
926
927 int
928 fdclose(dev, flags, mode, p)
929 dev_t dev;
930 int flags, mode;
931 struct proc *p;
932 {
933 int unit = FDUNIT(dev);
934 struct fd_softc *fd = fd_cd.cd_devs[unit];
935 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
936
937 DPRINTF(("fdclose %d\n", unit));
938
939 switch (mode) {
940 case S_IFCHR:
941 fd->sc_flags &= ~FD_COPEN;
942 break;
943 case S_IFBLK:
944 fd->sc_flags &= ~FD_BOPEN;
945 break;
946 }
947
948 if ((fd->sc_flags & FD_OPEN) == 0) {
949 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
950 ( 1 << unit));
951 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
952 }
953 return 0;
954 }
955
956 void
957 fdcstart(fdc)
958 struct fdc_softc *fdc;
959 {
960
961 #ifdef DIAGNOSTIC
962 /* only got here if controller's drive queue was inactive; should
963 be in idle state */
964 if (fdc->sc_state != DEVIDLE) {
965 printf("fdcstart: not idle\n");
966 return;
967 }
968 #endif
969 (void) fdcintr(fdc);
970 }
971
972 void
973 fdcstatus(dv, n, s)
974 struct device *dv;
975 int n;
976 char *s;
977 {
978 struct fdc_softc *fdc = (void *)dv->dv_parent;
979 char bits[64];
980
981 if (n == 0) {
982 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
983 (void) fdcresult(fdc);
984 n = 2;
985 }
986
987 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
988
989 switch (n) {
990 case 0:
991 printf("\n");
992 break;
993 case 2:
994 printf(" (st0 %s cyl %d)\n",
995 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
996 bits, sizeof(bits)), fdc->sc_status[1]);
997 break;
998 case 7:
999 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1000 NE7_ST0BITS, bits, sizeof(bits)));
1001 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1002 NE7_ST1BITS, bits, sizeof(bits)));
1003 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1004 NE7_ST2BITS, bits, sizeof(bits)));
1005 printf(" cyl %d head %d sec %d)\n",
1006 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1007 break;
1008 #ifdef DIAGNOSTIC
1009 default:
1010 printf(" fdcstatus: weird size: %d\n", n);
1011 break;
1012 #endif
1013 }
1014 }
1015
1016 void
1017 fdctimeout(arg)
1018 void *arg;
1019 {
1020 struct fdc_softc *fdc = arg;
1021 struct fd_softc *fd = fdc->sc_drives.tqh_first;
1022 int s;
1023
1024 s = splbio();
1025 fdcstatus(&fd->sc_dev, 0, "timeout");
1026
1027 if (fd->sc_q.b_actf)
1028 fdc->sc_state++;
1029 else
1030 fdc->sc_state = DEVIDLE;
1031
1032 (void) fdcintr(fdc);
1033 splx(s);
1034 }
1035
1036 #if 0
1037 void
1038 fdcpseudointr(arg)
1039 void *arg;
1040 {
1041 int s;
1042 struct fdc_softc *fdc = arg;
1043
1044 /* just ensure it has the right spl */
1045 s = splbio();
1046 (void) fdcintr(fdc);
1047 splx(s);
1048 }
1049 #endif
1050
1051 int
1052 fdcintr(arg)
1053 void *arg;
1054 {
1055 struct fdc_softc *fdc = arg;
1056 #define st0 fdc->sc_status[0]
1057 #define cyl fdc->sc_status[1]
1058 struct fd_softc *fd;
1059 struct buf *bp;
1060 bus_space_tag_t iot = fdc->sc_iot;
1061 bus_space_handle_t ioh = fdc->sc_ioh;
1062 int read, head, sec, pos, i, sectrac, nblks;
1063 int tmp;
1064 struct fd_type *type;
1065
1066 loop:
1067 fd = fdc->sc_drives.tqh_first;
1068 if (fd == NULL) {
1069 DPRINTF(("fdcintr: set DEVIDLE\n"));
1070 if (fdc->sc_state == DEVIDLE) {
1071 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1072 out_fdc(iot, ioh, NE7CMD_SENSEI);
1073 if ((tmp = fdcresult(fdc)) != 2 ||
1074 (st0 & 0xf8) != 0x20) {
1075 goto loop;
1076 }
1077 }
1078 }
1079 /* no drives waiting; end */
1080 fdc->sc_state = DEVIDLE;
1081 return 1;
1082 }
1083
1084 /* Is there a transfer to this drive? If not, deactivate drive. */
1085 bp = fd->sc_q.b_actf;
1086 if (bp == NULL) {
1087 fd->sc_ops = 0;
1088 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1089 fd->sc_q.b_active = 0;
1090 goto loop;
1091 }
1092
1093 switch (fdc->sc_state) {
1094 case DEVIDLE:
1095 DPRINTF(("fdcintr: in DEVIDLE\n"));
1096 fdc->sc_errors = 0;
1097 fd->sc_skip = 0;
1098 fd->sc_bcount = bp->b_bcount;
1099 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1100 untimeout(fd_motor_off, fd);
1101 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1102 fdc->sc_state = MOTORWAIT;
1103 return 1;
1104 }
1105 if ((fd->sc_flags & FD_MOTOR) == 0) {
1106 /* Turn on the motor */
1107 /* being careful about other drives. */
1108 for (i = 0; i < 4; i++) {
1109 struct fd_softc *ofd = fdc->sc_fd[i];
1110 if (ofd && ofd->sc_flags & FD_MOTOR) {
1111 untimeout(fd_motor_off, ofd);
1112 ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1113 break;
1114 }
1115 }
1116 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1117 fd_set_motor(fdc, 0);
1118 fdc->sc_state = MOTORWAIT;
1119 /* allow .5s for motor to stabilize */
1120 timeout(fd_motor_on, fd, hz / 2);
1121 return 1;
1122 }
1123 /* Make sure the right drive is selected. */
1124 fd_set_motor(fdc, 0);
1125
1126 /* fall through */
1127 case DOSEEK:
1128 doseek:
1129 DPRINTF(("fdcintr: in DOSEEK\n"));
1130 if (fd->sc_cylin == bp->b_cylin)
1131 goto doio;
1132
1133 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1134 out_fdc(iot, ioh, 0xd0); /* XXX const */
1135 out_fdc(iot, ioh, 0x10);
1136
1137 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1138 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1139 out_fdc(iot, ioh, bp->b_cylin * fd->sc_type->step);
1140
1141 fd->sc_cylin = -1;
1142 fdc->sc_state = SEEKWAIT;
1143
1144 fd->sc_dk.dk_seek++;
1145 disk_busy(&fd->sc_dk);
1146
1147 timeout(fdctimeout, fdc, 4 * hz);
1148 return 1;
1149
1150 case DOIO:
1151 doio:
1152 DPRINTF(("fdcintr: DOIO: "));
1153 type = fd->sc_type;
1154 sectrac = type->sectrac;
1155 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1156 sec = pos / (1 << (type->secsize - 2));
1157 if (type->secsize == 2) {
1158 fd->sc_part = SEC_P11;
1159 nblks = (sectrac - sec) << (type->secsize - 2);
1160 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1161 DPRINTF(("nblks(0)"));
1162 } else if ((fd->sc_blkno % 2) == 0) {
1163 if (fd->sc_bcount & 0x00000200) {
1164 if (fd->sc_bcount == FDC_BSIZE) {
1165 fd->sc_part = SEC_P10;
1166 nblks = 1;
1167 DPRINTF(("nblks(1)"));
1168 } else {
1169 fd->sc_part = SEC_P11;
1170 nblks = (sectrac - sec) * 2;
1171 nblks = min(nblks, fd->sc_bcount
1172 / FDC_BSIZE - 1);
1173 DPRINTF(("nblks(2)"));
1174 }
1175 } else {
1176 fd->sc_part = SEC_P11;
1177 nblks = (sectrac - sec)
1178 << (type->secsize - 2);
1179 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1180 DPRINTF(("nblks(3)"));
1181 }
1182 } else {
1183 fd->sc_part = SEC_P01;
1184 nblks = 1;
1185 DPRINTF(("nblks(4)"));
1186 }
1187 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1188 DPRINTF((" %d\n", nblks));
1189 fd->sc_nblks = nblks;
1190 fd->sc_nbytes = nblks * FDC_BSIZE;
1191 head = (fd->sc_blkno
1192 % (type->seccyl * (1 << (type->secsize - 2))))
1193 / (type->sectrac * (1 << (type->secsize - 2)));
1194
1195 #ifdef DIAGNOSTIC
1196 {int block;
1197 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1198 + sec) * (1 << (type->secsize - 2));
1199 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1200 if (block != fd->sc_blkno) {
1201 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1202 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1203 #ifdef DDB
1204 Debugger();
1205 #endif
1206 }}
1207 #endif
1208 read = bp->b_flags & B_READ;
1209 DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1210 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1211 head, sec, nblks, fd->sc_skip));
1212 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1213 type->secsize));
1214
1215 if (fd->sc_part != SEC_P11)
1216 goto docopy;
1217
1218 fdc_dmastart(fdc,
1219 read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1220 if (read)
1221 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1222 else
1223 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1224 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1225 out_fdc(iot, ioh, bp->b_cylin); /* cylinder */
1226 out_fdc(iot, ioh, head);
1227 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1228 out_fdc(iot, ioh, type->secsize); /* sector size */
1229 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1230 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1231 out_fdc(iot, ioh, type->datalen); /* data length */
1232 fdc->sc_state = IOCOMPLETE;
1233
1234 disk_busy(&fd->sc_dk);
1235
1236 /* allow 2 seconds for operation */
1237 timeout(fdctimeout, fdc, 2 * hz);
1238 return 1; /* will return later */
1239
1240 case DOCOPY:
1241 docopy:
1242 DPRINTF(("fdcintr: DOCOPY:\n"));
1243 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1244 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1245 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1246 out_fdc(iot, ioh, bp->b_cylin); /* cylinder */
1247 out_fdc(iot, ioh, head);
1248 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1249 out_fdc(iot, ioh, type->secsize); /* sector size */
1250 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1251 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1252 out_fdc(iot, ioh, type->datalen); /* data length */
1253 fdc->sc_state = COPYCOMPLETE;
1254 /* allow 2 seconds for operation */
1255 timeout(fdctimeout, fdc, 2 * hz);
1256 return 1; /* will return later */
1257
1258 case DOIOHALF:
1259 doiohalf:
1260 DPRINTF((" DOIOHALF:\n"));
1261
1262 #ifdef DIAGNOSTIC
1263 type = fd->sc_type;
1264 sectrac = type->sectrac;
1265 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1266 sec = pos / (1 << (type->secsize - 2));
1267 head = (fd->sc_blkno
1268 % (type->seccyl * (1 << (type->secsize - 2))))
1269 / (type->sectrac * (1 << (type->secsize - 2)));
1270 {int block;
1271 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1272 * (1 << (type->secsize - 2));
1273 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1274 if (block != fd->sc_blkno) {
1275 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1276 #ifdef DDB
1277 Debugger();
1278 #endif
1279 }}
1280 #endif
1281 if (read = bp->b_flags & B_READ) {
1282 bcopy(fd->sc_copybuf
1283 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1284 bp->b_data + fd->sc_skip,
1285 FDC_BSIZE);
1286 fdc->sc_state = IOCOMPLETE;
1287 goto iocomplete2;
1288 } else {
1289 bcopy(bp->b_data + fd->sc_skip,
1290 fd->sc_copybuf
1291 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1292 FDC_BSIZE);
1293 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1294 }
1295 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1296 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1297 out_fdc(iot, ioh, bp->b_cylin); /* cylinder */
1298 out_fdc(iot, ioh, head);
1299 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1300 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1301 out_fdc(iot, ioh, sectrac); /* sectors/track */
1302 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1303 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1304 fdc->sc_state = IOCOMPLETE;
1305 /* allow 2 seconds for operation */
1306 timeout(fdctimeout, fdc, 2 * hz);
1307 return 1; /* will return later */
1308
1309 case SEEKWAIT:
1310 untimeout(fdctimeout, fdc);
1311 fdc->sc_state = SEEKCOMPLETE;
1312 /* allow 1/50 second for heads to settle */
1313 #if 0
1314 timeout(fdcpseudointr, fdc, hz / 50);
1315 #endif
1316 return 1;
1317
1318 case SEEKCOMPLETE:
1319 /* Make sure seek really happened */
1320 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1321 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1322 out_fdc(iot, ioh, NE7CMD_SENSEI);
1323 tmp = fdcresult(fdc);
1324 if ((st0 & 0xf8) == 0xc0) {
1325 DPRINTF(("fdcintr: first seek!\n"));
1326 fdc->sc_state = DORECAL;
1327 goto loop;
1328 } else if (tmp != 2 ||
1329 (st0 & 0xf8) != 0x20 ||
1330 cyl != bp->b_cylin) {
1331 #ifdef FDDEBUG
1332 fdcstatus(&fd->sc_dev, 2, "seek failed");
1333 #endif
1334 fdcretry(fdc);
1335 goto loop;
1336 }
1337 fd->sc_cylin = bp->b_cylin;
1338 goto doio;
1339
1340 case IOTIMEDOUT:
1341 #if 0
1342 isa_dmaabort(fdc->sc_drq);
1343 #endif
1344 case SEEKTIMEDOUT:
1345 case RECALTIMEDOUT:
1346 case RESETTIMEDOUT:
1347 fdcretry(fdc);
1348 goto loop;
1349
1350 case IOCOMPLETE: /* IO DONE, post-analyze */
1351 untimeout(fdctimeout, fdc);
1352 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1353 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1354 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1355 #if 0
1356 isa_dmaabort(fdc->sc_drq);
1357 #endif
1358 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1359 "read failed" : "write failed");
1360 printf("blkno %d nblks %d\n",
1361 fd->sc_blkno, fd->sc_nblks);
1362 fdcretry(fdc);
1363 goto loop;
1364 }
1365 #if 0
1366 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1367 nblks * FDC_BSIZE, fdc->sc_drq);
1368 #endif
1369 iocomplete2:
1370 if (fdc->sc_errors) {
1371 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1372 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1373 printf("\n");
1374 fdc->sc_errors = 0;
1375 }
1376 fd->sc_blkno += fd->sc_nblks;
1377 fd->sc_skip += fd->sc_nbytes;
1378 fd->sc_bcount -= fd->sc_nbytes;
1379 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1380 if (fd->sc_bcount > 0) {
1381 bp->b_cylin = fd->sc_blkno
1382 / (fd->sc_type->seccyl
1383 * (1 << (fd->sc_type->secsize - 2)));
1384 goto doseek;
1385 }
1386 fdfinish(fd, bp);
1387 goto loop;
1388
1389 case COPYCOMPLETE: /* IO DONE, post-analyze */
1390 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1391 untimeout(fdctimeout, fdc);
1392 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1393 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1394 #if 0
1395 isa_dmaabort(fdc->sc_drq);
1396 #endif
1397 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1398 "read failed" : "write failed");
1399 printf("blkno %d nblks %d\n",
1400 fd->sc_blkno, fd->sc_nblks);
1401 fdcretry(fdc);
1402 goto loop;
1403 }
1404 goto doiohalf;
1405
1406 case DORESET:
1407 DPRINTF(("fdcintr: in DORESET\n"));
1408 /* try a reset, keep motor on */
1409 fd_set_motor(fdc, 1);
1410 DELAY(100);
1411 fd_set_motor(fdc, 0);
1412 fdc->sc_state = RESETCOMPLETE;
1413 timeout(fdctimeout, fdc, hz / 2);
1414 return 1; /* will return later */
1415
1416 case RESETCOMPLETE:
1417 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1418 untimeout(fdctimeout, fdc);
1419 /* clear the controller output buffer */
1420 for (i = 0; i < 4; i++) {
1421 out_fdc(iot, ioh, NE7CMD_SENSEI);
1422 (void) fdcresult(fdc);
1423 }
1424
1425 /* fall through */
1426 case DORECAL:
1427 DPRINTF(("fdcintr: in DORECAL\n"));
1428 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1429 out_fdc(iot, ioh, fd->sc_drive);
1430 fdc->sc_state = RECALWAIT;
1431 timeout(fdctimeout, fdc, 5 * hz);
1432 return 1; /* will return later */
1433
1434 case RECALWAIT:
1435 DPRINTF(("fdcintr: in RECALWAIT\n"));
1436 untimeout(fdctimeout, fdc);
1437 fdc->sc_state = RECALCOMPLETE;
1438 /* allow 1/30 second for heads to settle */
1439 #if 0
1440 timeout(fdcpseudointr, fdc, hz / 30);
1441 #endif
1442 return 1; /* will return later */
1443
1444 case RECALCOMPLETE:
1445 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1446 out_fdc(iot, ioh, NE7CMD_SENSEI);
1447 tmp = fdcresult(fdc);
1448 if ((st0 & 0xf8) == 0xc0) {
1449 DPRINTF(("fdcintr: first seek!\n"));
1450 fdc->sc_state = DORECAL;
1451 goto loop;
1452 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1453 #ifdef FDDEBUG
1454 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1455 #endif
1456 fdcretry(fdc);
1457 goto loop;
1458 }
1459 fd->sc_cylin = 0;
1460 goto doseek;
1461
1462 case MOTORWAIT:
1463 if (fd->sc_flags & FD_MOTOR_WAIT)
1464 return 1; /* time's not up yet */
1465 goto doseek;
1466
1467 default:
1468 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1469 return 1;
1470 }
1471 #ifdef DIAGNOSTIC
1472 panic("fdcintr: impossible");
1473 #endif
1474 #undef st0
1475 #undef cyl
1476 }
1477
1478 void
1479 fdcretry(fdc)
1480 struct fdc_softc *fdc;
1481 {
1482 struct fd_softc *fd;
1483 struct buf *bp;
1484 char bits[64];
1485
1486 DPRINTF(("fdcretry:\n"));
1487 fd = fdc->sc_drives.tqh_first;
1488 bp = fd->sc_q.b_actf;
1489
1490 switch (fdc->sc_errors) {
1491 case 0:
1492 /* try again */
1493 fdc->sc_state = SEEKCOMPLETE;
1494 break;
1495
1496 case 1: case 2: case 3:
1497 /* didn't work; try recalibrating */
1498 fdc->sc_state = DORECAL;
1499 break;
1500
1501 case 4:
1502 /* still no go; reset the bastard */
1503 fdc->sc_state = DORESET;
1504 break;
1505
1506 default:
1507 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1508 fd->sc_skip, (struct disklabel *)NULL);
1509 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1510 NE7_ST0BITS, bits,
1511 sizeof(bits)));
1512 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1513 NE7_ST1BITS, bits,
1514 sizeof(bits)));
1515 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1516 NE7_ST2BITS, bits,
1517 sizeof(bits)));
1518 printf(" cyl %d head %d sec %d)\n",
1519 fdc->sc_status[3],
1520 fdc->sc_status[4],
1521 fdc->sc_status[5]);
1522
1523 bp->b_flags |= B_ERROR;
1524 bp->b_error = EIO;
1525 fdfinish(fd, bp);
1526 }
1527 fdc->sc_errors++;
1528 }
1529
1530 int
1531 fdsize(dev)
1532 dev_t dev;
1533 {
1534
1535 /* Swapping to floppies would not make sense. */
1536 return -1;
1537 }
1538
1539 int
1540 fddump(dev, blkno, va, size)
1541 dev_t dev;
1542 daddr_t blkno;
1543 caddr_t va;
1544 size_t size;
1545 {
1546
1547 /* Not implemented. */
1548 return ENXIO;
1549 }
1550
1551 int
1552 fdioctl(dev, cmd, addr, flag, p)
1553 dev_t dev;
1554 u_long cmd;
1555 caddr_t addr;
1556 int flag;
1557 struct proc *p;
1558 {
1559 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1560 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1561 int unit = FDUNIT(dev);
1562 int part = DISKPART(dev);
1563 struct disklabel buffer;
1564 int error;
1565
1566 DPRINTF(("fdioctl:\n"));
1567 switch (cmd) {
1568 case DIOCGDINFO:
1569 #if 1
1570 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1571 return(0);
1572 #else
1573 memset(&buffer, 0, sizeof(buffer));
1574
1575 buffer.d_secpercyl = fd->sc_type->seccyl;
1576 buffer.d_type = DTYPE_FLOPPY;
1577 buffer.d_secsize = 128 << fd->sc_type->secsize;
1578
1579 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1580 return EINVAL;
1581
1582 *(struct disklabel *)addr = buffer;
1583 return 0;
1584 #endif
1585
1586 case DIOCGPART:
1587 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1588 ((struct partinfo *)addr)->part =
1589 &fd->sc_dk.dk_label->d_partitions[part];
1590 return(0);
1591
1592 case DIOCWLABEL:
1593 if ((flag & FWRITE) == 0)
1594 return EBADF;
1595 /* XXX do something */
1596 return 0;
1597
1598 case DIOCWDINFO:
1599 if ((flag & FWRITE) == 0)
1600 return EBADF;
1601
1602 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1603 if (error)
1604 return error;
1605
1606 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1607 return error;
1608
1609 case DIOCLOCK:
1610 /*
1611 * Nothing to do here, really.
1612 */
1613 return 0; /* XXX */
1614
1615 case DIOCEJECT:
1616 if (*(int *)addr == 0) {
1617 /*
1618 * Don't force eject: check that we are the only
1619 * partition open. If so, unlock it.
1620 */
1621 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1622 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1623 fd->sc_dk.dk_openmask) {
1624 return (EBUSY);
1625 }
1626 }
1627 /* FALLTHROUGH */
1628 case ODIOCEJECT:
1629 fd_do_eject(fdc, unit);
1630 return 0;
1631
1632 default:
1633 return ENOTTY;
1634 }
1635
1636 #ifdef DIAGNOSTIC
1637 panic("fdioctl: impossible");
1638 #endif
1639 }
1640
1641 void
1642 fd_do_eject(fdc, unit)
1643 struct fdc_softc *fdc;
1644 int unit;
1645 {
1646 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1647 0x20 | ( 1 << unit));
1648 DELAY(1); /* XXX */
1649 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1650 }
1651
1652 /*
1653 * Build disk label. For now we only create a label from what we know
1654 * from 'sc'.
1655 */
1656 static int
1657 fdgetdisklabel(sc, dev)
1658 struct fd_softc *sc;
1659 dev_t dev;
1660 {
1661 struct disklabel *lp;
1662 int part;
1663
1664 DPRINTF(("fdgetdisklabel()\n"));
1665
1666 part = DISKPART(dev);
1667 lp = sc->sc_dk.dk_label;
1668 bzero(lp, sizeof(struct disklabel));
1669
1670 lp->d_secsize = 128 << sc->sc_type->secsize;
1671 lp->d_ntracks = sc->sc_type->heads;
1672 lp->d_nsectors = sc->sc_type->sectrac;
1673 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1674 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1675 lp->d_secperunit = sc->sc_type->size;
1676
1677 lp->d_type = DTYPE_FLOPPY;
1678 lp->d_rpm = 300; /* XXX */
1679 lp->d_interleave = 1; /* FIXME: is this OK? */
1680 lp->d_bbsize = 0;
1681 lp->d_sbsize = 0;
1682 lp->d_npartitions = part + 1;
1683 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1684 lp->d_trkseek = STEP_DELAY; /* XXX */
1685 lp->d_magic = DISKMAGIC;
1686 lp->d_magic2 = DISKMAGIC;
1687 lp->d_checksum = dkcksum(lp);
1688 lp->d_partitions[part].p_size = lp->d_secperunit;
1689 lp->d_partitions[part].p_fstype = FS_UNUSED;
1690 lp->d_partitions[part].p_fsize = 1024;
1691 lp->d_partitions[part].p_frag = 8;
1692
1693 return(0);
1694 }
1695
1696 /*
1697 * Mountroot hook: prompt the user to enter the root file system
1698 * floppy.
1699 */
1700 void
1701 fd_mountroot_hook(dev)
1702 struct device *dev;
1703 {
1704 struct fd_softc *fd = (void*) dev;
1705 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1706 int c;
1707
1708 fd_do_eject(fdc, dev->dv_unit);
1709 printf("Insert filesystem floppy and press return.");
1710 for (;;) {
1711 c = cngetc();
1712 if ((c == '\r') || (c == '\n')) {
1713 printf("\n");
1714 break;
1715 }
1716 }
1717 }
1718