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