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