fd.c revision 1.55 1 /* $NetBSD: fd.c,v 1.55 2003/05/03 18:11:07 wiz 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, nokqfilter, 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 aprint_normal(" 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(PAGE_SIZE, 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 >
677 (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
678 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
679 - bp->b_blkno;
680 if (sz == 0) {
681 /* If exactly at end of disk, return EOF. */
682 bp->b_resid = bp->b_bcount;
683 goto done;
684 }
685 if (sz < 0) {
686 /* If past end of disk, return EINVAL. */
687 bp->b_error = EINVAL;
688 goto bad;
689 }
690 /* Otherwise, truncate request. */
691 bp->b_bcount = sz << DEV_BSHIFT;
692 }
693
694 bp->b_rawblkno = bp->b_blkno;
695 bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
696 / (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
697
698 DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
699 bp->b_flags & B_READ ? "read" : "write",
700 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
701 /* Queue transfer on drive, activate drive and controller if idle. */
702 s = splbio();
703 BUFQ_PUT(&fd->sc_q, bp);
704 callout_stop(&fd->sc_motoroff_ch); /* a good idea */
705 if (fd->sc_active == 0)
706 fdstart(fd);
707 #ifdef DIAGNOSTIC
708 else {
709 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
710 if (fdc->sc_state == DEVIDLE) {
711 printf("fdstrategy: controller inactive\n");
712 fdcstart(fdc);
713 }
714 }
715 #endif
716 splx(s);
717 return;
718
719 bad:
720 bp->b_flags |= B_ERROR;
721 done:
722 /* Toss transfer; we're done early. */
723 biodone(bp);
724 }
725
726 void
727 fdstart(fd)
728 struct fd_softc *fd;
729 {
730 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
731 int active = fdc->sc_drives.tqh_first != 0;
732
733 /* Link into controller queue. */
734 fd->sc_active = 1;
735 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
736
737 /* If controller not already active, start it. */
738 if (!active)
739 fdcstart(fdc);
740 }
741
742 void
743 fdfinish(fd, bp)
744 struct fd_softc *fd;
745 struct buf *bp;
746 {
747 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
748
749 /*
750 * Move this drive to the end of the queue to give others a `fair'
751 * chance. We only force a switch if N operations are completed while
752 * another drive is waiting to be serviced, since there is a long motor
753 * startup delay whenever we switch.
754 */
755 (void)BUFQ_GET(&fd->sc_q);
756 if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
757 fd->sc_ops = 0;
758 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
759 if (BUFQ_PEEK(&fd->sc_q) != NULL) {
760 TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
761 } else
762 fd->sc_active = 0;
763 }
764 bp->b_resid = fd->sc_bcount;
765 fd->sc_skip = 0;
766
767 #if NRND > 0
768 rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
769 #endif
770
771 biodone(bp);
772 /* turn off motor 5s from now */
773 callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
774 fdc->sc_state = DEVIDLE;
775 }
776
777 int
778 fdread(dev, uio, flags)
779 dev_t dev;
780 struct uio *uio;
781 int flags;
782 {
783
784 return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
785 }
786
787 int
788 fdwrite(dev, uio, flags)
789 dev_t dev;
790 struct uio *uio;
791 int flags;
792 {
793
794 return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
795 }
796
797 void
798 fd_set_motor(fdc, reset)
799 struct fdc_softc *fdc;
800 int reset;
801 {
802 struct fd_softc *fd;
803 int n;
804
805 DPRINTF(("fd_set_motor:\n"));
806 for (n = 0; n < 4; n++)
807 if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
808 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
809 0x80 | (fd->sc_type->rate << 4)| n);
810 }
811 }
812
813 void
814 fd_motor_off(arg)
815 void *arg;
816 {
817 struct fd_softc *fd = arg;
818 struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
819 int s;
820
821 DPRINTF(("fd_motor_off:\n"));
822
823 s = splbio();
824 fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
825 bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
826 (fd->sc_type->rate << 4) | fd->sc_drive);
827 #if 0
828 fd_set_motor(fdc, 0); /* XXX */
829 #endif
830 splx(s);
831 }
832
833 void
834 fd_motor_on(arg)
835 void *arg;
836 {
837 struct fd_softc *fd = arg;
838 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
839 int s;
840
841 DPRINTF(("fd_motor_on:\n"));
842
843 s = splbio();
844 fd->sc_flags &= ~FD_MOTOR_WAIT;
845 if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
846 (void) fdcintr(fdc);
847 splx(s);
848 }
849
850 int
851 fdcresult(fdc)
852 struct fdc_softc *fdc;
853 {
854 bus_space_tag_t iot = fdc->sc_iot;
855 bus_space_handle_t ioh = fdc->sc_ioh;
856 u_char i;
857 int j = 100000,
858 n = 0;
859
860 for (; j; j--) {
861 i = bus_space_read_1(iot, ioh, fdsts) &
862 (NE7_DIO | NE7_RQM | NE7_CB);
863
864 if (i == NE7_RQM)
865 return n;
866 if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
867 if (n >= sizeof(fdc->sc_status)) {
868 log(LOG_ERR, "fdcresult: overrun\n");
869 return -1;
870 }
871 fdc->sc_status[n++] =
872 bus_space_read_1(iot, ioh, fddata);
873 }
874 delay(10);
875 }
876 log(LOG_ERR, "fdcresult: timeout\n");
877 return -1;
878 }
879
880 int
881 out_fdc(iot, ioh, x)
882 bus_space_tag_t iot;
883 bus_space_handle_t ioh;
884 u_char x;
885 {
886 int i = 100000;
887
888 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
889 if (i <= 0)
890 return -1;
891 while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
892 if (i <= 0)
893 return -1;
894 bus_space_write_1(iot, ioh, fddata, x);
895 return 0;
896 }
897
898 int
899 fdopen(dev, flags, mode, p)
900 dev_t dev;
901 int flags, mode;
902 struct proc *p;
903 {
904 int unit;
905 struct fd_softc *fd;
906 struct fd_type *type;
907 struct fdc_softc *fdc;
908
909 unit = FDUNIT(dev);
910 if (unit >= fd_cd.cd_ndevs)
911 return ENXIO;
912 fd = fd_cd.cd_devs[unit];
913 if (fd == 0)
914 return ENXIO;
915 type = fd_dev_to_type(fd, dev);
916 if (type == NULL)
917 return ENXIO;
918
919 if ((fd->sc_flags & FD_OPEN) != 0 &&
920 fd->sc_type != type)
921 return EBUSY;
922
923 fdc = (void *)fd->sc_dev.dv_parent;
924 if ((fd->sc_flags & FD_OPEN) == 0) {
925 /* Lock eject button */
926 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
927 0x40 | ( 1 << unit));
928 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
929 }
930
931 fd->sc_type = type;
932 fd->sc_cylin = -1;
933
934 switch (mode) {
935 case S_IFCHR:
936 fd->sc_flags |= FD_COPEN;
937 break;
938 case S_IFBLK:
939 fd->sc_flags |= FD_BOPEN;
940 break;
941 }
942
943 fdgetdisklabel(fd, dev);
944
945 return 0;
946 }
947
948 int
949 fdclose(dev, flags, mode, p)
950 dev_t dev;
951 int flags, mode;
952 struct proc *p;
953 {
954 int unit = FDUNIT(dev);
955 struct fd_softc *fd = fd_cd.cd_devs[unit];
956 struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
957
958 DPRINTF(("fdclose %d\n", unit));
959
960 switch (mode) {
961 case S_IFCHR:
962 fd->sc_flags &= ~FD_COPEN;
963 break;
964 case S_IFBLK:
965 fd->sc_flags &= ~FD_BOPEN;
966 break;
967 }
968
969 if ((fd->sc_flags & FD_OPEN) == 0) {
970 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
971 ( 1 << unit));
972 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
973 }
974 return 0;
975 }
976
977 void
978 fdcstart(fdc)
979 struct fdc_softc *fdc;
980 {
981
982 #ifdef DIAGNOSTIC
983 /* only got here if controller's drive queue was inactive; should
984 be in idle state */
985 if (fdc->sc_state != DEVIDLE) {
986 printf("fdcstart: not idle\n");
987 return;
988 }
989 #endif
990 (void) fdcintr(fdc);
991 }
992
993 void
994 fdcstatus(dv, n, s)
995 struct device *dv;
996 int n;
997 char *s;
998 {
999 struct fdc_softc *fdc = (void *)dv->dv_parent;
1000 char bits[64];
1001
1002 if (n == 0) {
1003 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
1004 (void) fdcresult(fdc);
1005 n = 2;
1006 }
1007
1008 printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
1009
1010 switch (n) {
1011 case 0:
1012 printf("\n");
1013 break;
1014 case 2:
1015 printf(" (st0 %s cyl %d)\n",
1016 bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1017 bits, sizeof(bits)), fdc->sc_status[1]);
1018 break;
1019 case 7:
1020 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1021 NE7_ST0BITS, bits, sizeof(bits)));
1022 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1023 NE7_ST1BITS, bits, sizeof(bits)));
1024 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1025 NE7_ST2BITS, bits, sizeof(bits)));
1026 printf(" cyl %d head %d sec %d)\n",
1027 fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1028 break;
1029 #ifdef DIAGNOSTIC
1030 default:
1031 printf(" fdcstatus: weird size: %d\n", n);
1032 break;
1033 #endif
1034 }
1035 }
1036
1037 void
1038 fdctimeout(arg)
1039 void *arg;
1040 {
1041 struct fdc_softc *fdc = arg;
1042 struct fd_softc *fd = fdc->sc_drives.tqh_first;
1043 int s;
1044
1045 s = splbio();
1046 fdcstatus(&fd->sc_dev, 0, "timeout");
1047
1048 if (BUFQ_PEEK(&fd->sc_q) != NULL)
1049 fdc->sc_state++;
1050 else
1051 fdc->sc_state = DEVIDLE;
1052
1053 (void) fdcintr(fdc);
1054 splx(s);
1055 }
1056
1057 #if 0
1058 void
1059 fdcpseudointr(arg)
1060 void *arg;
1061 {
1062 int s;
1063 struct fdc_softc *fdc = arg;
1064
1065 /* just ensure it has the right spl */
1066 s = splbio();
1067 (void) fdcintr(fdc);
1068 splx(s);
1069 }
1070 #endif
1071
1072 int
1073 fdcintr(arg)
1074 void *arg;
1075 {
1076 struct fdc_softc *fdc = arg;
1077 #define st0 fdc->sc_status[0]
1078 #define cyl fdc->sc_status[1]
1079 struct fd_softc *fd;
1080 struct buf *bp;
1081 bus_space_tag_t iot = fdc->sc_iot;
1082 bus_space_handle_t ioh = fdc->sc_ioh;
1083 int read, head, sec, pos, i, sectrac, nblks;
1084 int tmp;
1085 struct fd_type *type;
1086
1087 loop:
1088 fd = fdc->sc_drives.tqh_first;
1089 if (fd == NULL) {
1090 DPRINTF(("fdcintr: set DEVIDLE\n"));
1091 if (fdc->sc_state == DEVIDLE) {
1092 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
1093 out_fdc(iot, ioh, NE7CMD_SENSEI);
1094 if ((tmp = fdcresult(fdc)) != 2 ||
1095 (st0 & 0xf8) != 0x20) {
1096 goto loop;
1097 }
1098 }
1099 }
1100 /* no drives waiting; end */
1101 fdc->sc_state = DEVIDLE;
1102 return 1;
1103 }
1104
1105 /* Is there a transfer to this drive? If not, deactivate drive. */
1106 bp = BUFQ_PEEK(&fd->sc_q);
1107 if (bp == NULL) {
1108 fd->sc_ops = 0;
1109 TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1110 fd->sc_active = 0;
1111 goto loop;
1112 }
1113
1114 switch (fdc->sc_state) {
1115 case DEVIDLE:
1116 DPRINTF(("fdcintr: in DEVIDLE\n"));
1117 fdc->sc_errors = 0;
1118 fd->sc_skip = 0;
1119 fd->sc_bcount = bp->b_bcount;
1120 fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1121 callout_stop(&fd->sc_motoroff_ch);
1122 if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1123 fdc->sc_state = MOTORWAIT;
1124 return 1;
1125 }
1126 if ((fd->sc_flags & FD_MOTOR) == 0) {
1127 /* Turn on the motor */
1128 /* being careful about other drives. */
1129 for (i = 0; i < 4; i++) {
1130 struct fd_softc *ofd = fdc->sc_fd[i];
1131 if (ofd && ofd->sc_flags & FD_MOTOR) {
1132 callout_stop(&ofd->sc_motoroff_ch);
1133 ofd->sc_flags &=
1134 ~(FD_MOTOR | FD_MOTOR_WAIT);
1135 break;
1136 }
1137 }
1138 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1139 fd_set_motor(fdc, 0);
1140 fdc->sc_state = MOTORWAIT;
1141 /* allow .5s for motor to stabilize */
1142 callout_reset(&fd->sc_motoron_ch, hz / 2,
1143 fd_motor_on, fd);
1144 return 1;
1145 }
1146 /* Make sure the right drive is selected. */
1147 fd_set_motor(fdc, 0);
1148
1149 /* fall through */
1150 case DOSEEK:
1151 doseek:
1152 DPRINTF(("fdcintr: in DOSEEK\n"));
1153 if (fd->sc_cylin == bp->b_cylinder)
1154 goto doio;
1155
1156 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1157 out_fdc(iot, ioh, 0xd0); /* XXX const */
1158 out_fdc(iot, ioh, 0x10);
1159
1160 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1161 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1162 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1163
1164 fd->sc_cylin = -1;
1165 fdc->sc_state = SEEKWAIT;
1166
1167 fd->sc_dk.dk_seek++;
1168 disk_busy(&fd->sc_dk);
1169
1170 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1171 return 1;
1172
1173 case DOIO:
1174 doio:
1175 DPRINTF(("fdcintr: DOIO: "));
1176 type = fd->sc_type;
1177 sectrac = type->sectrac;
1178 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1179 sec = pos / (1 << (type->secsize - 2));
1180 if (type->secsize == 2) {
1181 fd->sc_part = SEC_P11;
1182 nblks = (sectrac - sec) << (type->secsize - 2);
1183 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1184 DPRINTF(("nblks(0)"));
1185 } else if ((fd->sc_blkno % 2) == 0) {
1186 if (fd->sc_bcount & 0x00000200) {
1187 if (fd->sc_bcount == FDC_BSIZE) {
1188 fd->sc_part = SEC_P10;
1189 nblks = 1;
1190 DPRINTF(("nblks(1)"));
1191 } else {
1192 fd->sc_part = SEC_P11;
1193 nblks = (sectrac - sec) * 2;
1194 nblks = min(nblks, fd->sc_bcount
1195 / FDC_BSIZE - 1);
1196 DPRINTF(("nblks(2)"));
1197 }
1198 } else {
1199 fd->sc_part = SEC_P11;
1200 nblks = (sectrac - sec)
1201 << (type->secsize - 2);
1202 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1203 DPRINTF(("nblks(3)"));
1204 }
1205 } else {
1206 fd->sc_part = SEC_P01;
1207 nblks = 1;
1208 DPRINTF(("nblks(4)"));
1209 }
1210 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1211 DPRINTF((" %d\n", nblks));
1212 fd->sc_nblks = nblks;
1213 fd->sc_nbytes = nblks * FDC_BSIZE;
1214 head = (fd->sc_blkno
1215 % (type->seccyl * (1 << (type->secsize - 2))))
1216 / (type->sectrac * (1 << (type->secsize - 2)));
1217
1218 #ifdef DIAGNOSTIC
1219 {int block;
1220 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1221 + sec) * (1 << (type->secsize - 2));
1222 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1223 if (block != fd->sc_blkno) {
1224 printf("C H R N: %d %d %d %d\n",
1225 fd->sc_cylin, head, sec, type->secsize);
1226 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
1227 block, fd->sc_blkno);
1228 #ifdef DDB
1229 Debugger();
1230 #endif
1231 }
1232 }
1233 #endif
1234 read = bp->b_flags & B_READ;
1235 DPRINTF(("fdcintr: %s drive %d track %d "
1236 "head %d sec %d nblks %d, skip %d\n",
1237 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1238 head, sec, nblks, fd->sc_skip));
1239 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1240 type->secsize));
1241
1242 if (fd->sc_part != SEC_P11)
1243 goto docopy;
1244
1245 fdc_dmastart(fdc,
1246 read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1247 if (read)
1248 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1249 else
1250 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1251 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1252 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1253 out_fdc(iot, ioh, head);
1254 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1255 out_fdc(iot, ioh, type->secsize); /* sector size */
1256 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1257 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1258 out_fdc(iot, ioh, type->datalen); /* data length */
1259 fdc->sc_state = IOCOMPLETE;
1260
1261 disk_busy(&fd->sc_dk);
1262
1263 /* allow 2 seconds for operation */
1264 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1265 return 1; /* will return later */
1266
1267 case DOCOPY:
1268 docopy:
1269 DPRINTF(("fdcintr: DOCOPY:\n"));
1270 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1271 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1272 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1273 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1274 out_fdc(iot, ioh, head);
1275 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1276 out_fdc(iot, ioh, type->secsize); /* sector size */
1277 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1278 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1279 out_fdc(iot, ioh, type->datalen); /* data length */
1280 fdc->sc_state = COPYCOMPLETE;
1281 /* allow 2 seconds for operation */
1282 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1283 return 1; /* will return later */
1284
1285 case DOIOHALF:
1286 doiohalf:
1287 DPRINTF((" DOIOHALF:\n"));
1288
1289 #ifdef DIAGNOSTIC
1290 type = fd->sc_type;
1291 sectrac = type->sectrac;
1292 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1293 sec = pos / (1 << (type->secsize - 2));
1294 head = (fd->sc_blkno
1295 % (type->seccyl * (1 << (type->secsize - 2))))
1296 / (type->sectrac * (1 << (type->secsize - 2)));
1297 {int block;
1298 block = ((fd->sc_cylin * type->heads + head) *
1299 type->sectrac + sec)
1300 * (1 << (type->secsize - 2));
1301 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1302 if (block != fd->sc_blkno) {
1303 printf("fdcintr: block %d != blkno %" PRId64 "\n",
1304 block, fd->sc_blkno);
1305 #ifdef DDB
1306 Debugger();
1307 #endif
1308 }
1309 }
1310 #endif
1311 if ((read = bp->b_flags & B_READ)) {
1312 memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
1313 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1314 FDC_BSIZE);
1315 fdc->sc_state = IOCOMPLETE;
1316 goto iocomplete2;
1317 } else {
1318 memcpy(fd->sc_copybuf
1319 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1320 bp->b_data + fd->sc_skip, FDC_BSIZE);
1321 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1322 }
1323 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1324 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1325 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1326 out_fdc(iot, ioh, head);
1327 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1328 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1329 out_fdc(iot, ioh, sectrac); /* sectors/track */
1330 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1331 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1332 fdc->sc_state = IOCOMPLETE;
1333 /* allow 2 seconds for operation */
1334 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1335 return 1; /* will return later */
1336
1337 case SEEKWAIT:
1338 callout_stop(&fdc->sc_timo_ch);
1339 fdc->sc_state = SEEKCOMPLETE;
1340 /* allow 1/50 second for heads to settle */
1341 #if 0
1342 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1343 #endif
1344 return 1;
1345
1346 case SEEKCOMPLETE:
1347 /* Make sure seek really happened */
1348 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1349 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1350 out_fdc(iot, ioh, NE7CMD_SENSEI);
1351 tmp = fdcresult(fdc);
1352 if ((st0 & 0xf8) == 0xc0) {
1353 DPRINTF(("fdcintr: first seek!\n"));
1354 fdc->sc_state = DORECAL;
1355 goto loop;
1356 } else if (tmp != 2 ||
1357 (st0 & 0xf8) != 0x20 ||
1358 cyl != bp->b_cylinder) {
1359 #ifdef FDDEBUG
1360 fdcstatus(&fd->sc_dev, 2, "seek failed");
1361 #endif
1362 fdcretry(fdc);
1363 goto loop;
1364 }
1365 fd->sc_cylin = bp->b_cylinder;
1366 goto doio;
1367
1368 case IOTIMEDOUT:
1369 #if 0
1370 isa_dmaabort(fdc->sc_drq);
1371 #endif
1372 case SEEKTIMEDOUT:
1373 case RECALTIMEDOUT:
1374 case RESETTIMEDOUT:
1375 fdcretry(fdc);
1376 goto loop;
1377
1378 case IOCOMPLETE: /* IO DONE, post-analyze */
1379 callout_stop(&fdc->sc_timo_ch);
1380 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1381 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1382 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1383 #if 0
1384 isa_dmaabort(fdc->sc_drq);
1385 #endif
1386 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1387 "read failed" : "write failed");
1388 printf("blkno %" PRId64 " nblks %d\n",
1389 fd->sc_blkno, fd->sc_nblks);
1390 fdcretry(fdc);
1391 goto loop;
1392 }
1393 #if 0
1394 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1395 nblks * FDC_BSIZE, fdc->sc_drq);
1396 #endif
1397 iocomplete2:
1398 if (fdc->sc_errors) {
1399 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1400 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1401 printf("\n");
1402 fdc->sc_errors = 0;
1403 }
1404 fd->sc_blkno += fd->sc_nblks;
1405 fd->sc_skip += fd->sc_nbytes;
1406 fd->sc_bcount -= fd->sc_nbytes;
1407 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1408 if (fd->sc_bcount > 0) {
1409 bp->b_cylinder = fd->sc_blkno
1410 / (fd->sc_type->seccyl
1411 * (1 << (fd->sc_type->secsize - 2)));
1412 goto doseek;
1413 }
1414 fdfinish(fd, bp);
1415 goto loop;
1416
1417 case COPYCOMPLETE: /* IO DONE, post-analyze */
1418 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1419 callout_stop(&fdc->sc_timo_ch);
1420 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1421 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1422 #if 0
1423 isa_dmaabort(fdc->sc_drq);
1424 #endif
1425 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1426 "read failed" : "write failed");
1427 printf("blkno %" PRId64 " nblks %d\n",
1428 fd->sc_blkno, fd->sc_nblks);
1429 fdcretry(fdc);
1430 goto loop;
1431 }
1432 goto doiohalf;
1433
1434 case DORESET:
1435 DPRINTF(("fdcintr: in DORESET\n"));
1436 /* try a reset, keep motor on */
1437 fd_set_motor(fdc, 1);
1438 DELAY(100);
1439 fd_set_motor(fdc, 0);
1440 fdc->sc_state = RESETCOMPLETE;
1441 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1442 return 1; /* will return later */
1443
1444 case RESETCOMPLETE:
1445 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1446 callout_stop(&fdc->sc_timo_ch);
1447 /* clear the controller output buffer */
1448 for (i = 0; i < 4; i++) {
1449 out_fdc(iot, ioh, NE7CMD_SENSEI);
1450 (void) fdcresult(fdc);
1451 }
1452
1453 /* fall through */
1454 case DORECAL:
1455 DPRINTF(("fdcintr: in DORECAL\n"));
1456 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1457 out_fdc(iot, ioh, fd->sc_drive);
1458 fdc->sc_state = RECALWAIT;
1459 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1460 return 1; /* will return later */
1461
1462 case RECALWAIT:
1463 DPRINTF(("fdcintr: in RECALWAIT\n"));
1464 callout_stop(&fdc->sc_timo_ch);
1465 fdc->sc_state = RECALCOMPLETE;
1466 /* allow 1/30 second for heads to settle */
1467 #if 0
1468 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1469 #endif
1470 return 1; /* will return later */
1471
1472 case RECALCOMPLETE:
1473 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1474 out_fdc(iot, ioh, NE7CMD_SENSEI);
1475 tmp = fdcresult(fdc);
1476 if ((st0 & 0xf8) == 0xc0) {
1477 DPRINTF(("fdcintr: first seek!\n"));
1478 fdc->sc_state = DORECAL;
1479 goto loop;
1480 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1481 #ifdef FDDEBUG
1482 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1483 #endif
1484 fdcretry(fdc);
1485 goto loop;
1486 }
1487 fd->sc_cylin = 0;
1488 goto doseek;
1489
1490 case MOTORWAIT:
1491 if (fd->sc_flags & FD_MOTOR_WAIT)
1492 return 1; /* time's not up yet */
1493 goto doseek;
1494
1495 default:
1496 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1497 return 1;
1498 }
1499 #ifdef DIAGNOSTIC
1500 panic("fdcintr: impossible");
1501 #endif
1502 #undef st0
1503 #undef cyl
1504 }
1505
1506 void
1507 fdcretry(fdc)
1508 struct fdc_softc *fdc;
1509 {
1510 struct fd_softc *fd;
1511 struct buf *bp;
1512 char bits[64];
1513
1514 DPRINTF(("fdcretry:\n"));
1515 fd = fdc->sc_drives.tqh_first;
1516 bp = BUFQ_PEEK(&fd->sc_q);
1517
1518 switch (fdc->sc_errors) {
1519 case 0:
1520 /* try again */
1521 fdc->sc_state = SEEKCOMPLETE;
1522 break;
1523
1524 case 1: case 2: case 3:
1525 /* didn't work; try recalibrating */
1526 fdc->sc_state = DORECAL;
1527 break;
1528
1529 case 4:
1530 /* still no go; reset the bastard */
1531 fdc->sc_state = DORESET;
1532 break;
1533
1534 default:
1535 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1536 fd->sc_skip, (struct disklabel *)NULL);
1537 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1538 NE7_ST0BITS, bits,
1539 sizeof(bits)));
1540 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1541 NE7_ST1BITS, bits,
1542 sizeof(bits)));
1543 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1544 NE7_ST2BITS, bits,
1545 sizeof(bits)));
1546 printf(" cyl %d head %d sec %d)\n",
1547 fdc->sc_status[3],
1548 fdc->sc_status[4],
1549 fdc->sc_status[5]);
1550
1551 bp->b_flags |= B_ERROR;
1552 bp->b_error = EIO;
1553 fdfinish(fd, bp);
1554 }
1555 fdc->sc_errors++;
1556 }
1557
1558 int
1559 fdioctl(dev, cmd, addr, flag, p)
1560 dev_t dev;
1561 u_long cmd;
1562 caddr_t addr;
1563 int flag;
1564 struct proc *p;
1565 {
1566 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1567 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1568 int unit = FDUNIT(dev);
1569 int part = DISKPART(dev);
1570 struct disklabel buffer;
1571 int error;
1572
1573 DPRINTF(("fdioctl:\n"));
1574 switch (cmd) {
1575 case DIOCGDINFO:
1576 #if 1
1577 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1578 return(0);
1579 #else
1580 memset(&buffer, 0, sizeof(buffer));
1581
1582 buffer.d_secpercyl = fd->sc_type->seccyl;
1583 buffer.d_type = DTYPE_FLOPPY;
1584 buffer.d_secsize = 128 << fd->sc_type->secsize;
1585
1586 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1587 return EINVAL;
1588
1589 *(struct disklabel *)addr = buffer;
1590 return 0;
1591 #endif
1592
1593 case DIOCGPART:
1594 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1595 ((struct partinfo *)addr)->part =
1596 &fd->sc_dk.dk_label->d_partitions[part];
1597 return(0);
1598
1599 case DIOCWLABEL:
1600 if ((flag & FWRITE) == 0)
1601 return EBADF;
1602 /* XXX do something */
1603 return 0;
1604
1605 case DIOCWDINFO:
1606 if ((flag & FWRITE) == 0)
1607 return EBADF;
1608
1609 error = setdisklabel(&buffer, (struct disklabel *)addr,
1610 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