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