fd.c revision 1.27 1 /* $NetBSD: fd.c,v 1.27 1999/03/24 05:51:17 mrg 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 #define b_cylin b_resid
126
127 enum fdc_state {
128 DEVIDLE = 0,
129 MOTORWAIT,
130 DOSEEK,
131 SEEKWAIT,
132 SEEKTIMEDOUT,
133 SEEKCOMPLETE,
134 DOIO,
135 IOCOMPLETE,
136 IOTIMEDOUT,
137 DORESET,
138 RESETCOMPLETE,
139 RESETTIMEDOUT,
140 DORECAL,
141 RECALWAIT,
142 RECALTIMEDOUT,
143 RECALCOMPLETE,
144 DOCOPY,
145 DOIOHALF,
146 COPYCOMPLETE,
147 };
148
149 /* software state, per controller */
150 struct fdc_softc {
151 struct device sc_dev; /* boilerplate */
152
153 bus_space_tag_t sc_iot; /* intio i/o space identifier */
154 bus_space_handle_t sc_ioh; /* intio io handle */
155 bus_dma_tag_t sc_dmat; /* intio dma tag */
156 bus_dmamap_t sc_dmamap; /* dma map */
157 u_int8_t *sc_addr; /* physical address */
158 struct dmac_channel_stat *sc_dmachan; /* intio dma channel */
159 struct dmac_dma_xfer *sc_xfer; /* dma transfer */
160
161 struct fd_softc *sc_fd[4]; /* pointers to children */
162 TAILQ_HEAD(drivehead, fd_softc) sc_drives;
163 enum fdc_state sc_state;
164 int sc_errors; /* number of retries so far */
165 u_char sc_status[7]; /* copy of registers */
166 } fdc_softc;
167
168 bdev_decl(fd);
169 cdev_decl(fd);
170
171 int fdcintr __P((void*));
172 void fdcreset __P((struct fdc_softc *));
173
174 /* controller driver configuration */
175 int fdcprobe __P((struct device *, struct cfdata *, void *));
176 void fdcattach __P((struct device *, struct device *, void *));
177 int fdprint __P((void *, const char *));
178
179 struct cfattach fdc_ca = {
180 sizeof(struct fdc_softc), fdcprobe, fdcattach
181 };
182
183 extern struct cfdriver fdc_cd;
184
185 /*
186 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
187 * we tell them apart.
188 */
189 struct fd_type {
190 int sectrac; /* sectors per track */
191 int heads; /* number of heads */
192 int seccyl; /* sectors per cylinder */
193 int secsize; /* size code for sectors */
194 int datalen; /* data len when secsize = 0 */
195 int steprate; /* step rate and head unload time */
196 int gap1; /* gap len between sectors */
197 int gap2; /* formatting gap */
198 int cyls; /* total num of cylinders */
199 int size; /* size of disk in sectors */
200 int step; /* steps per cylinder */
201 int rate; /* transfer speed code */
202 char *name;
203 };
204
205 /* The order of entries in the following table is important -- BEWARE! */
206 struct fd_type fd_types[] = {
207 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
208 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
209 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
210 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
211 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
212 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
213 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
214 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
215 };
216
217 /* software state, per disk (with up to 4 disks per ctlr) */
218 struct fd_softc {
219 struct device sc_dev;
220 struct disk sc_dk;
221
222 struct fd_type *sc_deftype; /* default type descriptor */
223 struct fd_type *sc_type; /* current type descriptor */
224
225 daddr_t sc_blkno; /* starting block number */
226 int sc_bcount; /* byte count left */
227 int sc_opts; /* user-set options */
228 int sc_skip; /* bytes already transferred */
229 int sc_nblks; /* number of blocks currently tranferring */
230 int sc_nbytes; /* number of bytes currently tranferring */
231
232 int sc_drive; /* physical unit number */
233 int sc_flags;
234 #define FD_BOPEN 0x01 /* it's open */
235 #define FD_COPEN 0x02 /* it's open */
236 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
237 #define FD_MOTOR 0x04 /* motor should be on */
238 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
239 #define FD_ALIVE 0x10 /* alive */
240 int sc_cylin; /* where we think the head is */
241
242 TAILQ_ENTRY(fd_softc) sc_drivechain;
243 int sc_ops; /* I/O ops since last switch */
244 struct buf sc_q; /* head of buf chain */
245 u_char *sc_copybuf; /* for secsize >=3 */
246 u_char sc_part; /* for secsize >=3 */
247 #define SEC_P10 0x02 /* first part */
248 #define SEC_P01 0x01 /* second part */
249 #define SEC_P11 0x03 /* both part */
250
251 #if NRND > 0
252 rndsource_element_t rnd_source;
253 #endif
254 };
255
256 /* floppy driver configuration */
257 int fdprobe __P((struct device *, struct cfdata *, void *));
258 void fdattach __P((struct device *, struct device *, void *));
259
260 struct cfattach fd_ca = {
261 sizeof(struct fd_softc), fdprobe, fdattach
262 };
263
264 extern struct cfdriver fd_cd;
265
266 void fdstrategy __P((struct buf *));
267 void fdstart __P((struct fd_softc *fd));
268
269 struct dkdriver fddkdriver = { fdstrategy };
270
271 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
272 void fd_motor_off __P((void *arg));
273 void fd_motor_on __P((void *arg));
274 int fdcresult __P((struct fdc_softc *fdc));
275 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
276 void fdcstart __P((struct fdc_softc *fdc));
277 void fdcstatus __P((struct device *dv, int n, char *s));
278 void fdctimeout __P((void *arg));
279 void fdcpseudointr __P((void *arg));
280 void fdcretry __P((struct fdc_softc *fdc));
281 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
282 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
283 static int fdcpoll __P((struct fdc_softc *));
284 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
285 static void fd_do_eject __P((struct fdc_softc *, int));
286
287 void fd_mountroot_hook __P((struct device *));
288
289 /* dma transfer routines */
290 __inline static void fdc_dmastart __P((struct fdc_softc*, int,
291 caddr_t, vsize_t));
292 static int fdcdmaintr __P((void*));
293 static int fdcdmaerrintr __P((void*));
294
295 __inline static void
296 fdc_dmastart(fdc, read, addr, count)
297 struct fdc_softc *fdc;
298 int read;
299 caddr_t addr;
300 vsize_t count;
301 {
302 int error;
303
304 DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %d\n",
305 read ? "read" : "write", (caddr_t) addr, count));
306
307 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
308 0, BUS_DMA_NOWAIT);
309 if (error) {
310 panic ("fdc_dmastart: cannot load dmamap");
311 }
312
313 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
314 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
315
316 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
317 fdc->sc_dmamap,
318 (read?
319 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
320 (DMAC_SCR_MAC_COUNT_UP|
321 DMAC_SCR_DAC_NO_COUNT),
322 (u_int8_t*) (fdc->sc_addr +
323 fddata)); /* XXX */
324 #if defined(M68040) || defined(M68060)
325 if (mmutype == MMU_68040)
326 dma_cachectl(addr, count);
327 #endif
328
329 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
330 }
331
332 static int
333 fdcdmaintr(arg)
334 void *arg;
335 {
336 struct fdc_softc *fdc = arg;
337
338 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
339
340 return 0;
341 }
342
343 static int
344 fdcdmaerrintr(dummy)
345 void *dummy;
346 {
347 DPRINTF(("fdcdmaerrintr\n"));
348
349 return 0;
350 }
351
352 /* ARGSUSED */
353 int
354 fdcprobe(parent, cf, aux)
355 struct device *parent;
356 struct cfdata *cf;
357 void *aux;
358 {
359 struct intio_attach_args *ia = aux;
360
361 if (strcmp(ia->ia_name, "fdc") != 0)
362 return 0;
363
364 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
365 ia->ia_addr = FDC_ADDR;
366 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
367 ia->ia_intr = FDC_INTR;
368 if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
369 ia->ia_dma = FDC_DMA;
370 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
371 ia->ia_dmaintr = FDC_DMAINTR;
372
373 if (ia->ia_intr & 0x03 != 0)
374 return 0;
375
376 ia->ia_size = 0x2000;
377 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
378 return 0;
379
380 /* builtin device; always there */
381 return 1;
382 }
383
384 /*
385 * Arguments passed between fdcattach and fdprobe.
386 */
387 struct fdc_attach_args {
388 int fa_drive;
389 struct fd_type *fa_deftype;
390 };
391
392 /*
393 * Print the location of a disk drive (called just before attaching the
394 * the drive). If `fdc' is not NULL, the drive was found but was not
395 * in the system config file; print the drive name as well.
396 * Return QUIET (config_find ignores this if the device was configured) to
397 * avoid printing `fdN not configured' messages.
398 */
399 int
400 fdprint(aux, fdc)
401 void *aux;
402 const char *fdc;
403 {
404 register struct fdc_attach_args *fa = aux;
405
406 if (!fdc)
407 printf(" drive %d", fa->fa_drive);
408 return QUIET;
409 }
410
411 void
412 fdcattach(parent, self, aux)
413 struct device *parent, *self;
414 void *aux;
415 {
416 struct fdc_softc *fdc = (void *)self;
417 bus_space_tag_t iot;
418 bus_space_handle_t ioh;
419 struct intio_attach_args *ia = aux;
420 struct fdc_attach_args fa;
421
422 iot = ia->ia_bst;
423
424 printf("\n");
425
426 /* Re-map the I/O space. */
427 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
428
429 fdc->sc_iot = iot;
430 fdc->sc_ioh = ioh;
431 fdc->sc_addr = (void*) ia->ia_addr;
432
433 fdc->sc_dmat = ia->ia_dmat;
434 fdc->sc_state = DEVIDLE;
435 TAILQ_INIT(&fdc->sc_drives);
436
437 /* Initialize DMAC channel */
438 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
439 ia->ia_dmaintr, fdcdmaintr, fdc,
440 ia->ia_dmaintr+1, fdcdmaerrintr,
441 fdc);
442 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 16, 0xf000, 0,
443 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
444 &fdc->sc_dmamap)) {
445 printf("%s: can't set up intio DMA map\n",
446 fdc->sc_dev.dv_xname);
447 return;
448 }
449
450 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
451 panic ("Could not establish interrupt (duplicated vector?).");
452 intio_set_ivec(ia->ia_intr);
453
454 /* reset */
455 intio_disable_intr(SICILIAN_INTR_FDD);
456 intio_enable_intr(SICILIAN_INTR_FDC);
457 fdcresult(fdc);
458 fdcreset(fdc);
459
460 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
461 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
462 out_fdc(iot, ioh, 0xd0);
463 out_fdc(iot, ioh, 0x10);
464
465 /* physical limit: four drives per controller. */
466 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
467 (void)config_found(self, (void *)&fa, fdprint);
468 }
469
470 intio_enable_intr(SICILIAN_INTR_FDC);
471 }
472
473 void
474 fdcreset(fdc)
475 struct fdc_softc *fdc;
476 {
477 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
478 }
479
480 static int
481 fdcpoll(fdc)
482 struct fdc_softc *fdc;
483 {
484 int i = 25000, n;
485 while (--i > 0) {
486 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
487 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
488 n = fdcresult(fdc);
489 break;
490 }
491 DELAY(100);
492 }
493 return i;
494 }
495
496 int
497 fdprobe(parent, cf, aux)
498 struct device *parent;
499 struct cfdata *cf;
500 void *aux;
501 {
502 struct fdc_softc *fdc = (void *)parent;
503 struct fd_type *type;
504 struct fdc_attach_args *fa = aux;
505 int drive = fa->fa_drive;
506 bus_space_tag_t iot = fdc->sc_iot;
507 bus_space_handle_t ioh = fdc->sc_ioh;
508 int n;
509 int found = 0;
510 int i;
511
512 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
513 cf->cf_loc[FDCCF_UNIT] != drive)
514 return 0;
515
516 type = &fd_types[0]; /* XXX 1.2MB */
517
518 intio_disable_intr(SICILIAN_INTR_FDC);
519
520 /* select drive and turn on motor */
521 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
522 fdc_force_ready(FDCRDY);
523 fdcpoll(fdc);
524
525 retry:
526 out_fdc(iot, ioh, NE7CMD_RECAL);
527 out_fdc(iot, ioh, drive);
528
529 i = 25000;
530 while (--i > 0) {
531 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
532 out_fdc(iot, ioh, NE7CMD_SENSEI);
533 n = fdcresult(fdc);
534 break;
535 }
536 DELAY(100);
537 }
538
539 #ifdef FDDEBUG
540 {
541 int i;
542 DPRINTF(("fdprobe: status"));
543 for (i = 0; i < n; i++)
544 DPRINTF((" %x", fdc->sc_status[i]));
545 DPRINTF(("\n"));
546 }
547 #endif
548
549 if (n == 2) {
550 if ((fdc->sc_status[0] & 0xf0) == 0x20) {
551 found = 1;
552 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
553 goto retry;
554 }
555 }
556
557 /* turn off motor */
558 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
559 fdctl, (type->rate << 4)| drive);
560 fdc_force_ready(FDCSTBY);
561 if (!found) {
562 intio_enable_intr(SICILIAN_INTR_FDC);
563 return 0;
564 }
565
566 return 1;
567 }
568
569 /*
570 * Controller is working, and drive responded. Attach it.
571 */
572 void
573 fdattach(parent, self, aux)
574 struct device *parent, *self;
575 void *aux;
576 {
577 struct fdc_softc *fdc = (void *)parent;
578 struct fd_softc *fd = (void *)self;
579 struct fdc_attach_args *fa = aux;
580 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
581 int drive = fa->fa_drive;
582
583 fd->sc_flags = 0;
584
585 if (type)
586 printf(": %s, %d cyl, %d head, %d sec\n", type->name,
587 type->cyls, type->heads, type->sectrac);
588 else
589 printf(": density unknown\n");
590
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_cylin = 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_cylin));
679 /* Queue transfer on drive, activate drive and controller if idle. */
680 s = splbio();
681 disksort(&fd->sc_q, bp);
682 untimeout(fd_motor_off, fd); /* a good idea */
683 if (!fd->sc_q.b_active)
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_q.b_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 (bp->b_actf) {
737 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
738 } else
739 fd->sc_q.b_active = 0;
740 }
741 bp->b_resid = fd->sc_bcount;
742 fd->sc_skip = 0;
743 fd->sc_q.b_actf = bp->b_actf;
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 (fd->sc_q.b_actf)
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 = fd->sc_q.b_actf;
1085 if (bp == NULL) {
1086 fd->sc_ops = 0;
1087 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1088 fd->sc_q.b_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_cylin)
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_cylin * 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_cylin); /* 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_cylin); /* 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_cylin); /* 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_cylin) {
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_cylin;
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_cylin = 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 = fd->sc_q.b_actf;
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 /*
1696 * Mountroot hook: prompt the user to enter the root file system
1697 * floppy.
1698 */
1699 void
1700 fd_mountroot_hook(dev)
1701 struct device *dev;
1702 {
1703 struct fd_softc *fd = (void*) dev;
1704 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1705 int c;
1706
1707 fd_do_eject(fdc, dev->dv_unit);
1708 printf("Insert filesystem floppy and press return.");
1709 for (;;) {
1710 c = cngetc();
1711 if ((c == '\r') || (c == '\n')) {
1712 printf("\n");
1713 break;
1714 }
1715 }
1716 }
1717