fd.c revision 1.30 1 /* $NetBSD: fd.c,v 1.30 2000/02/07 20:16:54 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum 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
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/kernel.h>
83 #include <sys/conf.h>
84 #include <sys/file.h>
85 #include <sys/stat.h>
86 #include <sys/ioctl.h>
87 #include <sys/malloc.h>
88 #include <sys/device.h>
89 #include <sys/disklabel.h>
90 #include <sys/dkstat.h>
91 #include <sys/disk.h>
92 #include <sys/buf.h>
93 #include <sys/uio.h>
94 #include <sys/syslog.h>
95 #include <sys/queue.h>
96 #include <sys/fdio.h>
97 #if NRND > 0
98 #include <sys/rnd.h>
99 #endif
100
101 #include <vm/vm.h>
102
103 #include <uvm/uvm_extern.h>
104
105 #include <machine/bus.h>
106 #include <machine/cpu.h>
107
108 #include <arch/x68k/dev/intiovar.h>
109 #include <arch/x68k/dev/dmacvar.h>
110 #include <arch/x68k/dev/fdreg.h>
111 #include <arch/x68k/dev/opmreg.h> /* for CT1 access */
112
113 #include "locators.h"
114
115 #ifdef FDDEBUG
116 #define DPRINTF(x) if (fddebug) printf x
117 int fddebug = 0;
118 #else
119 #define DPRINTF(x)
120 #endif
121
122 #define FDUNIT(dev) (minor(dev) / 8)
123 #define FDTYPE(dev) (minor(dev) % 8)
124
125 enum fdc_state {
126 DEVIDLE = 0,
127 MOTORWAIT,
128 DOSEEK,
129 SEEKWAIT,
130 SEEKTIMEDOUT,
131 SEEKCOMPLETE,
132 DOIO,
133 IOCOMPLETE,
134 IOTIMEDOUT,
135 DORESET,
136 RESETCOMPLETE,
137 RESETTIMEDOUT,
138 DORECAL,
139 RECALWAIT,
140 RECALTIMEDOUT,
141 RECALCOMPLETE,
142 DOCOPY,
143 DOIOHALF,
144 COPYCOMPLETE,
145 };
146
147 /* software state, per controller */
148 struct fdc_softc {
149 struct device sc_dev; /* boilerplate */
150
151 bus_space_tag_t sc_iot; /* intio i/o space identifier */
152 bus_space_handle_t sc_ioh; /* intio io handle */
153 bus_dma_tag_t sc_dmat; /* intio dma tag */
154 bus_dmamap_t sc_dmamap; /* dma map */
155 u_int8_t *sc_addr; /* physical address */
156 struct dmac_channel_stat *sc_dmachan; /* intio dma channel */
157 struct dmac_dma_xfer *sc_xfer; /* dma transfer */
158
159 struct fd_softc *sc_fd[4]; /* pointers to children */
160 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
161 enum fdc_state sc_state;
162 int sc_errors; /* number of retries so far */
163 u_char sc_status[7]; /* copy of registers */
164 } fdc_softc;
165
166 bdev_decl(fd);
167 cdev_decl(fd);
168
169 int fdcintr __P((void*));
170 void fdcreset __P((struct fdc_softc *));
171
172 /* controller driver configuration */
173 int fdcprobe __P((struct device *, struct cfdata *, void *));
174 void fdcattach __P((struct device *, struct device *, void *));
175 int fdprint __P((void *, const char *));
176
177 struct cfattach fdc_ca = {
178 sizeof(struct fdc_softc), fdcprobe, fdcattach
179 };
180
181 extern struct cfdriver fdc_cd;
182
183 /*
184 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
185 * we tell them apart.
186 */
187 struct fd_type {
188 int sectrac; /* sectors per track */
189 int heads; /* number of heads */
190 int seccyl; /* sectors per cylinder */
191 int secsize; /* size code for sectors */
192 int datalen; /* data len when secsize = 0 */
193 int steprate; /* step rate and head unload time */
194 int gap1; /* gap len between sectors */
195 int gap2; /* formatting gap */
196 int cyls; /* total num of cylinders */
197 int size; /* size of disk in sectors */
198 int step; /* steps per cylinder */
199 int rate; /* transfer speed code */
200 char *name;
201 };
202
203 /* The order of entries in the following table is important -- BEWARE! */
204 struct fd_type fd_types[] = {
205 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
206 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
207 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
208 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
209 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
210 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
211 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
212 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
213 };
214
215 /* software state, per disk (with up to 4 disks per ctlr) */
216 struct fd_softc {
217 struct device sc_dev;
218 struct disk sc_dk;
219
220 struct fd_type *sc_deftype; /* default type descriptor */
221 struct fd_type *sc_type; /* current type descriptor */
222
223 daddr_t sc_blkno; /* starting block number */
224 int sc_bcount; /* byte count left */
225 int sc_opts; /* user-set options */
226 int sc_skip; /* bytes already transferred */
227 int sc_nblks; /* number of blocks currently tranferring */
228 int sc_nbytes; /* number of bytes currently tranferring */
229
230 int sc_drive; /* physical unit number */
231 int sc_flags;
232 #define FD_BOPEN 0x01 /* it's open */
233 #define FD_COPEN 0x02 /* it's open */
234 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
235 #define FD_MOTOR 0x04 /* motor should be on */
236 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
237 #define FD_ALIVE 0x10 /* alive */
238 int sc_cylin; /* where we think the head is */
239
240 TAILQ_ENTRY(fd_softc) sc_drivechain;
241 int sc_ops; /* I/O ops since last switch */
242 struct buf_queue sc_q; /* pending I/O requests */
243 int sc_active; /* number of active I/O operations */
244 u_char *sc_copybuf; /* for secsize >=3 */
245 u_char sc_part; /* for secsize >=3 */
246 #define SEC_P10 0x02 /* first part */
247 #define SEC_P01 0x01 /* second part */
248 #define SEC_P11 0x03 /* both part */
249
250 #if NRND > 0
251 rndsource_element_t rnd_source;
252 #endif
253 };
254
255 /* floppy driver configuration */
256 int fdprobe __P((struct device *, struct cfdata *, void *));
257 void fdattach __P((struct device *, struct device *, void *));
258
259 struct cfattach fd_ca = {
260 sizeof(struct fd_softc), fdprobe, fdattach
261 };
262
263 extern struct cfdriver fd_cd;
264
265 void fdstrategy __P((struct buf *));
266 void fdstart __P((struct fd_softc *fd));
267
268 struct dkdriver fddkdriver = { fdstrategy };
269
270 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
271 void fd_motor_off __P((void *arg));
272 void fd_motor_on __P((void *arg));
273 int fdcresult __P((struct fdc_softc *fdc));
274 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
275 void fdcstart __P((struct fdc_softc *fdc));
276 void fdcstatus __P((struct device *dv, int n, char *s));
277 void fdctimeout __P((void *arg));
278 void fdcpseudointr __P((void *arg));
279 void fdcretry __P((struct fdc_softc *fdc));
280 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
281 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
282 static int fdcpoll __P((struct fdc_softc *));
283 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
284 static void fd_do_eject __P((struct fdc_softc *, int));
285
286 void fd_mountroot_hook __P((struct device *));
287
288 /* dma transfer routines */
289 __inline static void fdc_dmastart __P((struct fdc_softc*, int,
290 caddr_t, vsize_t));
291 static int fdcdmaintr __P((void*));
292 static int fdcdmaerrintr __P((void*));
293
294 __inline static void
295 fdc_dmastart(fdc, read, addr, count)
296 struct fdc_softc *fdc;
297 int read;
298 caddr_t addr;
299 vsize_t count;
300 {
301 int error;
302
303 DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %d\n",
304 read ? "read" : "write", (caddr_t) addr, count));
305
306 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
307 0, BUS_DMA_NOWAIT);
308 if (error) {
309 panic ("fdc_dmastart: cannot load dmamap");
310 }
311
312 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
313 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
314
315 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
316 fdc->sc_dmamap,
317 (read?
318 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
319 (DMAC_SCR_MAC_COUNT_UP|
320 DMAC_SCR_DAC_NO_COUNT),
321 (u_int8_t*) (fdc->sc_addr +
322 fddata)); /* XXX */
323 #if defined(M68040) || defined(M68060)
324 if (mmutype == MMU_68040)
325 dma_cachectl(addr, count);
326 #endif
327
328 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
329 }
330
331 static int
332 fdcdmaintr(arg)
333 void *arg;
334 {
335 struct fdc_softc *fdc = arg;
336
337 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
338
339 return 0;
340 }
341
342 static int
343 fdcdmaerrintr(dummy)
344 void *dummy;
345 {
346 DPRINTF(("fdcdmaerrintr\n"));
347
348 return 0;
349 }
350
351 /* ARGSUSED */
352 int
353 fdcprobe(parent, cf, aux)
354 struct device *parent;
355 struct cfdata *cf;
356 void *aux;
357 {
358 struct intio_attach_args *ia = aux;
359
360 if (strcmp(ia->ia_name, "fdc") != 0)
361 return 0;
362
363 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
364 ia->ia_addr = FDC_ADDR;
365 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
366 ia->ia_intr = FDC_INTR;
367 if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
368 ia->ia_dma = FDC_DMA;
369 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
370 ia->ia_dmaintr = FDC_DMAINTR;
371
372 if ((ia->ia_intr & 0x03) != 0)
373 return 0;
374
375 ia->ia_size = 0x2000;
376 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
377 return 0;
378
379 /* builtin device; always there */
380 return 1;
381 }
382
383 /*
384 * Arguments passed between fdcattach and fdprobe.
385 */
386 struct fdc_attach_args {
387 int fa_drive;
388 struct fd_type *fa_deftype;
389 };
390
391 /*
392 * Print the location of a disk drive (called just before attaching the
393 * the drive). If `fdc' is not NULL, the drive was found but was not
394 * in the system config file; print the drive name as well.
395 * Return QUIET (config_find ignores this if the device was configured) to
396 * avoid printing `fdN not configured' messages.
397 */
398 int
399 fdprint(aux, fdc)
400 void *aux;
401 const char *fdc;
402 {
403 register struct fdc_attach_args *fa = aux;
404
405 if (!fdc)
406 printf(" drive %d", fa->fa_drive);
407 return QUIET;
408 }
409
410 void
411 fdcattach(parent, self, aux)
412 struct device *parent, *self;
413 void *aux;
414 {
415 struct fdc_softc *fdc = (void *)self;
416 bus_space_tag_t iot;
417 bus_space_handle_t ioh;
418 struct intio_attach_args *ia = aux;
419 struct fdc_attach_args fa;
420
421 iot = ia->ia_bst;
422
423 printf("\n");
424
425 /* Re-map the I/O space. */
426 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
427
428 fdc->sc_iot = iot;
429 fdc->sc_ioh = ioh;
430 fdc->sc_addr = (void*) ia->ia_addr;
431
432 fdc->sc_dmat = ia->ia_dmat;
433 fdc->sc_state = DEVIDLE;
434 TAILQ_INIT(&fdc->sc_drives);
435
436 /* Initialize DMAC channel */
437 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
438 ia->ia_dmaintr, fdcdmaintr, fdc,
439 ia->ia_dmaintr+1, fdcdmaerrintr,
440 fdc);
441 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 16, 0xf000, 0,
442 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
443 &fdc->sc_dmamap)) {
444 printf("%s: can't set up intio DMA map\n",
445 fdc->sc_dev.dv_xname);
446 return;
447 }
448
449 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
450 panic ("Could not establish interrupt (duplicated vector?).");
451 intio_set_ivec(ia->ia_intr);
452
453 /* reset */
454 intio_disable_intr(SICILIAN_INTR_FDD);
455 intio_enable_intr(SICILIAN_INTR_FDC);
456 fdcresult(fdc);
457 fdcreset(fdc);
458
459 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
460 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
461 out_fdc(iot, ioh, 0xd0);
462 out_fdc(iot, ioh, 0x10);
463
464 /* physical limit: four drives per controller. */
465 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
466 (void)config_found(self, (void *)&fa, fdprint);
467 }
468
469 intio_enable_intr(SICILIAN_INTR_FDC);
470 }
471
472 void
473 fdcreset(fdc)
474 struct fdc_softc *fdc;
475 {
476 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
477 }
478
479 static int
480 fdcpoll(fdc)
481 struct fdc_softc *fdc;
482 {
483 int i = 25000, n;
484 while (--i > 0) {
485 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
486 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
487 n = fdcresult(fdc);
488 break;
489 }
490 DELAY(100);
491 }
492 return i;
493 }
494
495 int
496 fdprobe(parent, cf, aux)
497 struct device *parent;
498 struct cfdata *cf;
499 void *aux;
500 {
501 struct fdc_softc *fdc = (void *)parent;
502 struct fd_type *type;
503 struct fdc_attach_args *fa = aux;
504 int drive = fa->fa_drive;
505 bus_space_tag_t iot = fdc->sc_iot;
506 bus_space_handle_t ioh = fdc->sc_ioh;
507 int n;
508 int found = 0;
509 int i;
510
511 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
512 cf->cf_loc[FDCCF_UNIT] != drive)
513 return 0;
514
515 type = &fd_types[0]; /* XXX 1.2MB */
516
517 intio_disable_intr(SICILIAN_INTR_FDC);
518
519 /* select drive and turn on motor */
520 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
521 fdc_force_ready(FDCRDY);
522 fdcpoll(fdc);
523
524 retry:
525 out_fdc(iot, ioh, NE7CMD_RECAL);
526 out_fdc(iot, ioh, drive);
527
528 i = 25000;
529 while (--i > 0) {
530 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
531 out_fdc(iot, ioh, NE7CMD_SENSEI);
532 n = fdcresult(fdc);
533 break;
534 }
535 DELAY(100);
536 }
537
538 #ifdef FDDEBUG
539 {
540 int i;
541 DPRINTF(("fdprobe: status"));
542 for (i = 0; i < n; i++)
543 DPRINTF((" %x", fdc->sc_status[i]));
544 DPRINTF(("\n"));
545 }
546 #endif
547
548 if (n == 2) {
549 if ((fdc->sc_status[0] & 0xf0) == 0x20) {
550 found = 1;
551 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
552 goto retry;
553 }
554 }
555
556 /* turn off motor */
557 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
558 fdctl, (type->rate << 4)| drive);
559 fdc_force_ready(FDCSTBY);
560 if (!found) {
561 intio_enable_intr(SICILIAN_INTR_FDC);
562 return 0;
563 }
564
565 return 1;
566 }
567
568 /*
569 * Controller is working, and drive responded. Attach it.
570 */
571 void
572 fdattach(parent, self, aux)
573 struct device *parent, *self;
574 void *aux;
575 {
576 struct fdc_softc *fdc = (void *)parent;
577 struct fd_softc *fd = (void *)self;
578 struct fdc_attach_args *fa = aux;
579 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
580 int drive = fa->fa_drive;
581
582 fd->sc_flags = 0;
583
584 if (type)
585 printf(": %s, %d cyl, %d head, %d sec\n", type->name,
586 type->cyls, type->heads, type->sectrac);
587 else
588 printf(": density unknown\n");
589
590 BUFQ_INIT(&fd->sc_q);
591 fd->sc_cylin = -1;
592 fd->sc_drive = drive;
593 fd->sc_deftype = type;
594 fdc->sc_fd[drive] = fd;
595
596 fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
597 if (fd->sc_copybuf == 0)
598 printf("fdprobe: WARNING!! malloc() failed.\n");
599 fd->sc_flags |= FD_ALIVE;
600
601 /*
602 * Initialize and attach the disk structure.
603 */
604 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
605 fd->sc_dk.dk_driver = &fddkdriver;
606 disk_attach(&fd->sc_dk);
607
608 /*
609 * Establish a mountroot_hook anyway in case we booted
610 * with RB_ASKNAME and get selected as the boot device.
611 */
612 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
613
614 #if NRND > 0
615 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
616 RND_TYPE_DISK, 0);
617 #endif
618 }
619
620 __inline struct fd_type *
621 fd_dev_to_type(fd, dev)
622 struct fd_softc *fd;
623 dev_t dev;
624 {
625 int type = FDTYPE(dev);
626
627 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
628 return NULL;
629 return &fd_types[type];
630 }
631
632 void
633 fdstrategy(bp)
634 register struct buf *bp; /* IO operation to perform */
635 {
636 struct fd_softc *fd;
637 int unit = FDUNIT(bp->b_dev);
638 int sz;
639 int s;
640
641 if (unit >= fd_cd.cd_ndevs ||
642 (fd = fd_cd.cd_devs[unit]) == 0 ||
643 bp->b_blkno < 0 ||
644 (bp->b_bcount % FDC_BSIZE) != 0) {
645 DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
646 bp->b_blkno, bp->b_bcount));
647 bp->b_error = EINVAL;
648 goto bad;
649 }
650
651 /* If it's a null transfer, return immediately. */
652 if (bp->b_bcount == 0)
653 goto done;
654
655 sz = howmany(bp->b_bcount, FDC_BSIZE);
656
657 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
658 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
659 if (sz == 0) {
660 /* If exactly at end of disk, return EOF. */
661 bp->b_resid = bp->b_bcount;
662 goto done;
663 }
664 if (sz < 0) {
665 /* If past end of disk, return EINVAL. */
666 bp->b_error = EINVAL;
667 goto bad;
668 }
669 /* Otherwise, truncate request. */
670 bp->b_bcount = sz << DEV_BSHIFT;
671 }
672
673 bp->b_rawblkno = bp->b_blkno;
674 bp->b_cylinder = 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_cylinder));
680 /* Queue transfer on drive, activate drive and controller if idle. */
681 s = splbio();
682 disksort_cylinder(&fd->sc_q, bp);
683 untimeout(fd_motor_off, fd); /* a good idea */
684 if (fd->sc_active == 0)
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_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 (BUFQ_NEXT(bp) != NULL) {
738 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
739 } else
740 fd->sc_active = 0;
741 }
742 bp->b_resid = fd->sc_bcount;
743 fd->sc_skip = 0;
744 BUFQ_REMOVE(&fd->sc_q, bp);
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 (BUFQ_FIRST(&fd->sc_q) != NULL)
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 = BUFQ_FIRST(&fd->sc_q);
1086 if (bp == NULL) {
1087 fd->sc_ops = 0;
1088 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1089 fd->sc_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_cylinder)
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_cylinder * 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_cylinder); /* 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_cylinder); /* 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_cylinder); /* 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_cylinder) {
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_cylinder;
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_cylinder = 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 = BUFQ_FIRST(&fd->sc_q);
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 #include <dev/cons.h>
1697
1698 /*
1699 * Mountroot hook: prompt the user to enter the root file system
1700 * floppy.
1701 */
1702 void
1703 fd_mountroot_hook(dev)
1704 struct device *dev;
1705 {
1706 struct fd_softc *fd = (void*) dev;
1707 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1708 int c;
1709
1710 fd_do_eject(fdc, dev->dv_unit);
1711 printf("Insert filesystem floppy and press return.");
1712 for (;;) {
1713 c = cngetc();
1714 if ((c == '\r') || (c == '\n')) {
1715 printf("\n");
1716 break;
1717 }
1718 }
1719 }
1720