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