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