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