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