fd.c revision 1.43 1 /* $NetBSD: fd.c,v 1.43 2002/09/06 13:18:43 gehenna 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 struct cfattach fdc_ca = {
179 sizeof(struct fdc_softc), fdcprobe, fdcattach
180 };
181
182 extern struct cfdriver fdc_cd;
183
184 /*
185 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
186 * we tell them apart.
187 */
188 struct fd_type {
189 int sectrac; /* sectors per track */
190 int heads; /* number of heads */
191 int seccyl; /* sectors per cylinder */
192 int secsize; /* size code for sectors */
193 int datalen; /* data len when secsize = 0 */
194 int steprate; /* step rate and head unload time */
195 int gap1; /* gap len between sectors */
196 int gap2; /* formatting gap */
197 int cyls; /* total num of cylinders */
198 int size; /* size of disk in sectors */
199 int step; /* steps per cylinder */
200 int rate; /* transfer speed code */
201 char *name;
202 };
203
204 /* The order of entries in the following table is important -- BEWARE! */
205 struct fd_type fd_types[] = {
206 { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]" }, /* 1.2 MB japanese format */
207 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB" }, /* 1.44MB diskette */
208 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
209 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
210 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
211 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
212 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
213 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
214 };
215
216 /* software state, per disk (with up to 4 disks per ctlr) */
217 struct fd_softc {
218 struct device sc_dev;
219 struct disk sc_dk;
220
221 struct fd_type *sc_deftype; /* default type descriptor */
222 struct fd_type *sc_type; /* current type descriptor */
223
224 struct callout sc_motoron_ch;
225 struct callout sc_motoroff_ch;
226
227 daddr_t sc_blkno; /* starting block number */
228 int sc_bcount; /* byte count left */
229 int sc_opts; /* user-set options */
230 int sc_skip; /* bytes already transferred */
231 int sc_nblks; /* number of blocks currently transferring */
232 int sc_nbytes; /* number of bytes currently transferring */
233
234 int sc_drive; /* physical unit number */
235 int sc_flags;
236 #define FD_BOPEN 0x01 /* it's open */
237 #define FD_COPEN 0x02 /* it's open */
238 #define FD_OPEN (FD_BOPEN|FD_COPEN) /* it's open */
239 #define FD_MOTOR 0x04 /* motor should be on */
240 #define FD_MOTOR_WAIT 0x08 /* motor coming up */
241 #define FD_ALIVE 0x10 /* alive */
242 int sc_cylin; /* where we think the head is */
243
244 TAILQ_ENTRY(fd_softc) sc_drivechain;
245 int sc_ops; /* I/O ops since last switch */
246 struct bufq_state sc_q; /* pending I/O requests */
247 int sc_active; /* number of active I/O operations */
248 u_char *sc_copybuf; /* for secsize >=3 */
249 u_char sc_part; /* for secsize >=3 */
250 #define SEC_P10 0x02 /* first part */
251 #define SEC_P01 0x01 /* second part */
252 #define SEC_P11 0x03 /* both part */
253
254 #if NRND > 0
255 rndsource_element_t rnd_source;
256 #endif
257 };
258
259 /* floppy driver configuration */
260 int fdprobe __P((struct device *, struct cfdata *, void *));
261 void fdattach __P((struct device *, struct device *, void *));
262
263 struct cfattach fd_ca = {
264 sizeof(struct fd_softc), fdprobe, fdattach
265 };
266
267 extern struct cfdriver fd_cd;
268
269 dev_type_open(fdopen);
270 dev_type_close(fdclose);
271 dev_type_read(fdread);
272 dev_type_write(fdwrite);
273 dev_type_ioctl(fdioctl);
274 dev_type_strategy(fdstrategy);
275
276 const struct bdevsw fd_bdevsw = {
277 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
278 };
279
280 const struct cdevsw fd_cdevsw = {
281 fdopen, fdclose, fdread, fdwrite, fdioctl,
282 nostop, notty, nopoll, nommap, D_DISK
283 };
284
285 void fdstart __P((struct fd_softc *fd));
286
287 struct dkdriver fddkdriver = { fdstrategy };
288
289 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
290 void fd_motor_off __P((void *arg));
291 void fd_motor_on __P((void *arg));
292 int fdcresult __P((struct fdc_softc *fdc));
293 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
294 void fdcstart __P((struct fdc_softc *fdc));
295 void fdcstatus __P((struct device *dv, int n, char *s));
296 void fdctimeout __P((void *arg));
297 void fdcpseudointr __P((void *arg));
298 void fdcretry __P((struct fdc_softc *fdc));
299 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
300 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
301 static int fdcpoll __P((struct fdc_softc *));
302 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
303 static void fd_do_eject __P((struct fdc_softc *, int));
304
305 void fd_mountroot_hook __P((struct device *));
306
307 /* dma transfer routines */
308 __inline static void fdc_dmastart __P((struct fdc_softc*, int,
309 caddr_t, vsize_t));
310 static int fdcdmaintr __P((void*));
311 static int fdcdmaerrintr __P((void*));
312
313 __inline static void
314 fdc_dmastart(fdc, read, addr, count)
315 struct fdc_softc *fdc;
316 int read;
317 caddr_t addr;
318 vsize_t count;
319 {
320 int error;
321
322 DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %ld\n",
323 read ? "read" : "write", (caddr_t) addr, count));
324
325 error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
326 0, BUS_DMA_NOWAIT);
327 if (error) {
328 panic ("fdc_dmastart: cannot load dmamap");
329 }
330
331 bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
332 read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
333
334 fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
335 fdc->sc_dmamap,
336 (read?
337 DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
338 (DMAC_SCR_MAC_COUNT_UP|
339 DMAC_SCR_DAC_NO_COUNT),
340 (u_int8_t*) (fdc->sc_addr +
341 fddata)); /* XXX */
342
343 dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
344 }
345
346 static int
347 fdcdmaintr(arg)
348 void *arg;
349 {
350 struct fdc_softc *fdc = arg;
351
352 bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
353
354 return 0;
355 }
356
357 static int
358 fdcdmaerrintr(dummy)
359 void *dummy;
360 {
361 DPRINTF(("fdcdmaerrintr\n"));
362
363 return 0;
364 }
365
366 /* ARGSUSED */
367 int
368 fdcprobe(parent, cf, aux)
369 struct device *parent;
370 struct cfdata *cf;
371 void *aux;
372 {
373 struct intio_attach_args *ia = aux;
374
375 if (strcmp(ia->ia_name, "fdc") != 0)
376 return 0;
377
378 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
379 ia->ia_addr = FDC_ADDR;
380 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
381 ia->ia_intr = FDC_INTR;
382 if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
383 ia->ia_dma = FDC_DMA;
384 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
385 ia->ia_dmaintr = FDC_DMAINTR;
386
387 if ((ia->ia_intr & 0x03) != 0)
388 return 0;
389
390 ia->ia_size = 0x2000;
391 if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
392 return 0;
393
394 /* builtin device; always there */
395 return 1;
396 }
397
398 /*
399 * Arguments passed between fdcattach and fdprobe.
400 */
401 struct fdc_attach_args {
402 int fa_drive;
403 struct fd_type *fa_deftype;
404 };
405
406 /*
407 * Print the location of a disk drive (called just before attaching the
408 * the drive). If `fdc' is not NULL, the drive was found but was not
409 * in the system config file; print the drive name as well.
410 * Return QUIET (config_find ignores this if the device was configured) to
411 * avoid printing `fdN not configured' messages.
412 */
413 int
414 fdprint(aux, fdc)
415 void *aux;
416 const char *fdc;
417 {
418 register struct fdc_attach_args *fa = aux;
419
420 if (!fdc)
421 printf(" drive %d", fa->fa_drive);
422 return QUIET;
423 }
424
425 void
426 fdcattach(parent, self, aux)
427 struct device *parent, *self;
428 void *aux;
429 {
430 struct fdc_softc *fdc = (void *)self;
431 bus_space_tag_t iot;
432 bus_space_handle_t ioh;
433 struct intio_attach_args *ia = aux;
434 struct fdc_attach_args fa;
435
436 iot = ia->ia_bst;
437
438 printf("\n");
439
440 callout_init(&fdc->sc_timo_ch);
441 callout_init(&fdc->sc_intr_ch);
442
443 /* Re-map the I/O space. */
444 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
445
446 fdc->sc_iot = iot;
447 fdc->sc_ioh = ioh;
448 fdc->sc_addr = (void*) ia->ia_addr;
449
450 fdc->sc_dmat = ia->ia_dmat;
451 fdc->sc_state = DEVIDLE;
452 TAILQ_INIT(&fdc->sc_drives);
453
454 /* Initialize DMAC channel */
455 fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
456 ia->ia_dmaintr, fdcdmaintr, fdc,
457 ia->ia_dmaintr+1, fdcdmaerrintr,
458 fdc);
459 if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
460 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
461 &fdc->sc_dmamap)) {
462 printf("%s: can't set up intio DMA map\n",
463 fdc->sc_dev.dv_xname);
464 return;
465 }
466
467 if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
468 panic ("Could not establish interrupt (duplicated vector?).");
469 intio_set_ivec(ia->ia_intr);
470
471 /* reset */
472 intio_disable_intr(SICILIAN_INTR_FDD);
473 intio_enable_intr(SICILIAN_INTR_FDC);
474 fdcresult(fdc);
475 fdcreset(fdc);
476
477 printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
478 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
479 out_fdc(iot, ioh, 0xd0);
480 out_fdc(iot, ioh, 0x10);
481
482 /* physical limit: four drives per controller. */
483 for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
484 (void)config_found(self, (void *)&fa, fdprint);
485 }
486
487 intio_enable_intr(SICILIAN_INTR_FDC);
488 }
489
490 void
491 fdcreset(fdc)
492 struct fdc_softc *fdc;
493 {
494 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
495 }
496
497 static int
498 fdcpoll(fdc)
499 struct fdc_softc *fdc;
500 {
501 int i = 25000, n;
502 while (--i > 0) {
503 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
504 out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
505 n = fdcresult(fdc);
506 break;
507 }
508 DELAY(100);
509 }
510 return i;
511 }
512
513 int
514 fdprobe(parent, cf, aux)
515 struct device *parent;
516 struct cfdata *cf;
517 void *aux;
518 {
519 struct fdc_softc *fdc = (void *)parent;
520 struct fd_type *type;
521 struct fdc_attach_args *fa = aux;
522 int drive = fa->fa_drive;
523 bus_space_tag_t iot = fdc->sc_iot;
524 bus_space_handle_t ioh = fdc->sc_ioh;
525 int n;
526 int found = 0;
527 int i;
528
529 if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
530 cf->cf_loc[FDCCF_UNIT] != drive)
531 return 0;
532
533 type = &fd_types[0]; /* XXX 1.2MB */
534
535 intio_disable_intr(SICILIAN_INTR_FDC);
536
537 /* select drive and turn on motor */
538 bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
539 fdc_force_ready(FDCRDY);
540 fdcpoll(fdc);
541
542 retry:
543 out_fdc(iot, ioh, NE7CMD_RECAL);
544 out_fdc(iot, ioh, drive);
545
546 i = 25000;
547 while (--i > 0) {
548 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
549 out_fdc(iot, ioh, NE7CMD_SENSEI);
550 n = fdcresult(fdc);
551 break;
552 }
553 DELAY(100);
554 }
555
556 #ifdef FDDEBUG
557 {
558 int i;
559 DPRINTF(("fdprobe: status"));
560 for (i = 0; i < n; i++)
561 DPRINTF((" %x", fdc->sc_status[i]));
562 DPRINTF(("\n"));
563 }
564 #endif
565
566 if (n == 2) {
567 if ((fdc->sc_status[0] & 0xf0) == 0x20) {
568 found = 1;
569 } else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
570 goto retry;
571 }
572 }
573
574 /* turn off motor */
575 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
576 fdctl, (type->rate << 4)| drive);
577 fdc_force_ready(FDCSTBY);
578 if (!found) {
579 intio_enable_intr(SICILIAN_INTR_FDC);
580 return 0;
581 }
582
583 return 1;
584 }
585
586 /*
587 * Controller is working, and drive responded. Attach it.
588 */
589 void
590 fdattach(parent, self, aux)
591 struct device *parent, *self;
592 void *aux;
593 {
594 struct fdc_softc *fdc = (void *)parent;
595 struct fd_softc *fd = (void *)self;
596 struct fdc_attach_args *fa = aux;
597 struct fd_type *type = &fd_types[0]; /* XXX 1.2MB */
598 int drive = fa->fa_drive;
599
600 callout_init(&fd->sc_motoron_ch);
601 callout_init(&fd->sc_motoroff_ch);
602
603 fd->sc_flags = 0;
604
605 if (type)
606 printf(": %s, %d cyl, %d head, %d sec\n", type->name,
607 type->cyls, type->heads, type->sectrac);
608 else
609 printf(": density unknown\n");
610
611 bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
612 fd->sc_cylin = -1;
613 fd->sc_drive = drive;
614 fd->sc_deftype = type;
615 fdc->sc_fd[drive] = fd;
616
617 fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
618 if (fd->sc_copybuf == 0)
619 printf("fdprobe: WARNING!! malloc() failed.\n");
620 fd->sc_flags |= FD_ALIVE;
621
622 /*
623 * Initialize and attach the disk structure.
624 */
625 fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
626 fd->sc_dk.dk_driver = &fddkdriver;
627 disk_attach(&fd->sc_dk);
628
629 /*
630 * Establish a mountroot_hook anyway in case we booted
631 * with RB_ASKNAME and get selected as the boot device.
632 */
633 mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
634
635 #if NRND > 0
636 rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
637 RND_TYPE_DISK, 0);
638 #endif
639 }
640
641 __inline struct fd_type *
642 fd_dev_to_type(fd, dev)
643 struct fd_softc *fd;
644 dev_t dev;
645 {
646 int type = FDTYPE(dev);
647
648 if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
649 return NULL;
650 return &fd_types[type];
651 }
652
653 void
654 fdstrategy(bp)
655 register struct buf *bp; /* IO operation to perform */
656 {
657 struct fd_softc *fd;
658 int unit = FDUNIT(bp->b_dev);
659 int sz;
660 int s;
661
662 if (unit >= fd_cd.cd_ndevs ||
663 (fd = fd_cd.cd_devs[unit]) == 0 ||
664 bp->b_blkno < 0 ||
665 (bp->b_bcount % FDC_BSIZE) != 0) {
666 DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%ld\n", unit,
667 bp->b_blkno, bp->b_bcount));
668 bp->b_error = EINVAL;
669 goto bad;
670 }
671
672 /* If it's a null transfer, return immediately. */
673 if (bp->b_bcount == 0)
674 goto done;
675
676 sz = howmany(bp->b_bcount, FDC_BSIZE);
677
678 if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
679 sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - 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 &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1134 break;
1135 }
1136 }
1137 fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1138 fd_set_motor(fdc, 0);
1139 fdc->sc_state = MOTORWAIT;
1140 /* allow .5s for motor to stabilize */
1141 callout_reset(&fd->sc_motoron_ch, hz / 2,
1142 fd_motor_on, fd);
1143 return 1;
1144 }
1145 /* Make sure the right drive is selected. */
1146 fd_set_motor(fdc, 0);
1147
1148 /* fall through */
1149 case DOSEEK:
1150 doseek:
1151 DPRINTF(("fdcintr: in DOSEEK\n"));
1152 if (fd->sc_cylin == bp->b_cylinder)
1153 goto doio;
1154
1155 out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1156 out_fdc(iot, ioh, 0xd0); /* XXX const */
1157 out_fdc(iot, ioh, 0x10);
1158
1159 out_fdc(iot, ioh, NE7CMD_SEEK); /* seek function */
1160 out_fdc(iot, ioh, fd->sc_drive); /* drive number */
1161 out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1162
1163 fd->sc_cylin = -1;
1164 fdc->sc_state = SEEKWAIT;
1165
1166 fd->sc_dk.dk_seek++;
1167 disk_busy(&fd->sc_dk);
1168
1169 callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1170 return 1;
1171
1172 case DOIO:
1173 doio:
1174 DPRINTF(("fdcintr: DOIO: "));
1175 type = fd->sc_type;
1176 sectrac = type->sectrac;
1177 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1178 sec = pos / (1 << (type->secsize - 2));
1179 if (type->secsize == 2) {
1180 fd->sc_part = SEC_P11;
1181 nblks = (sectrac - sec) << (type->secsize - 2);
1182 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1183 DPRINTF(("nblks(0)"));
1184 } else if ((fd->sc_blkno % 2) == 0) {
1185 if (fd->sc_bcount & 0x00000200) {
1186 if (fd->sc_bcount == FDC_BSIZE) {
1187 fd->sc_part = SEC_P10;
1188 nblks = 1;
1189 DPRINTF(("nblks(1)"));
1190 } else {
1191 fd->sc_part = SEC_P11;
1192 nblks = (sectrac - sec) * 2;
1193 nblks = min(nblks, fd->sc_bcount
1194 / FDC_BSIZE - 1);
1195 DPRINTF(("nblks(2)"));
1196 }
1197 } else {
1198 fd->sc_part = SEC_P11;
1199 nblks = (sectrac - sec)
1200 << (type->secsize - 2);
1201 nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1202 DPRINTF(("nblks(3)"));
1203 }
1204 } else {
1205 fd->sc_part = SEC_P01;
1206 nblks = 1;
1207 DPRINTF(("nblks(4)"));
1208 }
1209 nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1210 DPRINTF((" %d\n", nblks));
1211 fd->sc_nblks = nblks;
1212 fd->sc_nbytes = nblks * FDC_BSIZE;
1213 head = (fd->sc_blkno
1214 % (type->seccyl * (1 << (type->secsize - 2))))
1215 / (type->sectrac * (1 << (type->secsize - 2)));
1216
1217 #ifdef DIAGNOSTIC
1218 {int block;
1219 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
1220 + sec) * (1 << (type->secsize - 2));
1221 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1222 if (block != fd->sc_blkno) {
1223 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
1224 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
1225 #ifdef DDB
1226 Debugger();
1227 #endif
1228 }}
1229 #endif
1230 read = bp->b_flags & B_READ;
1231 DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
1232 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1233 head, sec, nblks, fd->sc_skip));
1234 DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
1235 type->secsize));
1236
1237 if (fd->sc_part != SEC_P11)
1238 goto docopy;
1239
1240 fdc_dmastart(fdc,
1241 read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
1242 if (read)
1243 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1244 else
1245 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1246 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1247 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1248 out_fdc(iot, ioh, head);
1249 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1250 out_fdc(iot, ioh, type->secsize); /* sector size */
1251 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1252 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1253 out_fdc(iot, ioh, type->datalen); /* data length */
1254 fdc->sc_state = IOCOMPLETE;
1255
1256 disk_busy(&fd->sc_dk);
1257
1258 /* allow 2 seconds for operation */
1259 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1260 return 1; /* will return later */
1261
1262 case DOCOPY:
1263 docopy:
1264 DPRINTF(("fdcintr: DOCOPY:\n"));
1265 fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
1266 out_fdc(iot, ioh, NE7CMD_READ); /* READ */
1267 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1268 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1269 out_fdc(iot, ioh, head);
1270 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1271 out_fdc(iot, ioh, type->secsize); /* sector size */
1272 out_fdc(iot, ioh, type->sectrac); /* sectors/track */
1273 out_fdc(iot, ioh, type->gap1); /* gap1 size */
1274 out_fdc(iot, ioh, type->datalen); /* data length */
1275 fdc->sc_state = COPYCOMPLETE;
1276 /* allow 2 seconds for operation */
1277 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1278 return 1; /* will return later */
1279
1280 case DOIOHALF:
1281 doiohalf:
1282 DPRINTF((" DOIOHALF:\n"));
1283
1284 #ifdef DIAGNOSTIC
1285 type = fd->sc_type;
1286 sectrac = type->sectrac;
1287 pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
1288 sec = pos / (1 << (type->secsize - 2));
1289 head = (fd->sc_blkno
1290 % (type->seccyl * (1 << (type->secsize - 2))))
1291 / (type->sectrac * (1 << (type->secsize - 2)));
1292 {int block;
1293 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
1294 * (1 << (type->secsize - 2));
1295 block += (fd->sc_part == SEC_P01) ? 1 : 0;
1296 if (block != fd->sc_blkno) {
1297 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
1298 #ifdef DDB
1299 Debugger();
1300 #endif
1301 }}
1302 #endif
1303 if ((read = bp->b_flags & B_READ)) {
1304 memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
1305 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1306 FDC_BSIZE);
1307 fdc->sc_state = IOCOMPLETE;
1308 goto iocomplete2;
1309 } else {
1310 memcpy(fd->sc_copybuf
1311 + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
1312 bp->b_data + fd->sc_skip, FDC_BSIZE);
1313 fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
1314 }
1315 out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1316 out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1317 out_fdc(iot, ioh, bp->b_cylinder); /* cylinder */
1318 out_fdc(iot, ioh, head);
1319 out_fdc(iot, ioh, sec + 1); /* sector +1 */
1320 out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
1321 out_fdc(iot, ioh, sectrac); /* sectors/track */
1322 out_fdc(iot, ioh, fd->sc_type->gap1); /* gap1 size */
1323 out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
1324 fdc->sc_state = IOCOMPLETE;
1325 /* allow 2 seconds for operation */
1326 callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1327 return 1; /* will return later */
1328
1329 case SEEKWAIT:
1330 callout_stop(&fdc->sc_timo_ch);
1331 fdc->sc_state = SEEKCOMPLETE;
1332 /* allow 1/50 second for heads to settle */
1333 #if 0
1334 callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1335 #endif
1336 return 1;
1337
1338 case SEEKCOMPLETE:
1339 /* Make sure seek really happened */
1340 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1341 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
1342 out_fdc(iot, ioh, NE7CMD_SENSEI);
1343 tmp = fdcresult(fdc);
1344 if ((st0 & 0xf8) == 0xc0) {
1345 DPRINTF(("fdcintr: first seek!\n"));
1346 fdc->sc_state = DORECAL;
1347 goto loop;
1348 } else if (tmp != 2 ||
1349 (st0 & 0xf8) != 0x20 ||
1350 cyl != bp->b_cylinder) {
1351 #ifdef FDDEBUG
1352 fdcstatus(&fd->sc_dev, 2, "seek failed");
1353 #endif
1354 fdcretry(fdc);
1355 goto loop;
1356 }
1357 fd->sc_cylin = bp->b_cylinder;
1358 goto doio;
1359
1360 case IOTIMEDOUT:
1361 #if 0
1362 isa_dmaabort(fdc->sc_drq);
1363 #endif
1364 case SEEKTIMEDOUT:
1365 case RECALTIMEDOUT:
1366 case RESETTIMEDOUT:
1367 fdcretry(fdc);
1368 goto loop;
1369
1370 case IOCOMPLETE: /* IO DONE, post-analyze */
1371 callout_stop(&fdc->sc_timo_ch);
1372 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1373 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1374 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1375 #if 0
1376 isa_dmaabort(fdc->sc_drq);
1377 #endif
1378 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1379 "read failed" : "write failed");
1380 printf("blkno %d nblks %d\n",
1381 fd->sc_blkno, fd->sc_nblks);
1382 fdcretry(fdc);
1383 goto loop;
1384 }
1385 #if 0
1386 isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
1387 nblks * FDC_BSIZE, fdc->sc_drq);
1388 #endif
1389 iocomplete2:
1390 if (fdc->sc_errors) {
1391 diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1392 fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1393 printf("\n");
1394 fdc->sc_errors = 0;
1395 }
1396 fd->sc_blkno += fd->sc_nblks;
1397 fd->sc_skip += fd->sc_nbytes;
1398 fd->sc_bcount -= fd->sc_nbytes;
1399 DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
1400 if (fd->sc_bcount > 0) {
1401 bp->b_cylinder = fd->sc_blkno
1402 / (fd->sc_type->seccyl
1403 * (1 << (fd->sc_type->secsize - 2)));
1404 goto doseek;
1405 }
1406 fdfinish(fd, bp);
1407 goto loop;
1408
1409 case COPYCOMPLETE: /* IO DONE, post-analyze */
1410 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1411 callout_stop(&fdc->sc_timo_ch);
1412 if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
1413 printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
1414 #if 0
1415 isa_dmaabort(fdc->sc_drq);
1416 #endif
1417 fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1418 "read failed" : "write failed");
1419 printf("blkno %d nblks %d\n",
1420 fd->sc_blkno, fd->sc_nblks);
1421 fdcretry(fdc);
1422 goto loop;
1423 }
1424 goto doiohalf;
1425
1426 case DORESET:
1427 DPRINTF(("fdcintr: in DORESET\n"));
1428 /* try a reset, keep motor on */
1429 fd_set_motor(fdc, 1);
1430 DELAY(100);
1431 fd_set_motor(fdc, 0);
1432 fdc->sc_state = RESETCOMPLETE;
1433 callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1434 return 1; /* will return later */
1435
1436 case RESETCOMPLETE:
1437 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1438 callout_stop(&fdc->sc_timo_ch);
1439 /* clear the controller output buffer */
1440 for (i = 0; i < 4; i++) {
1441 out_fdc(iot, ioh, NE7CMD_SENSEI);
1442 (void) fdcresult(fdc);
1443 }
1444
1445 /* fall through */
1446 case DORECAL:
1447 DPRINTF(("fdcintr: in DORECAL\n"));
1448 out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
1449 out_fdc(iot, ioh, fd->sc_drive);
1450 fdc->sc_state = RECALWAIT;
1451 callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1452 return 1; /* will return later */
1453
1454 case RECALWAIT:
1455 DPRINTF(("fdcintr: in RECALWAIT\n"));
1456 callout_stop(&fdc->sc_timo_ch);
1457 fdc->sc_state = RECALCOMPLETE;
1458 /* allow 1/30 second for heads to settle */
1459 #if 0
1460 callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1461 #endif
1462 return 1; /* will return later */
1463
1464 case RECALCOMPLETE:
1465 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1466 out_fdc(iot, ioh, NE7CMD_SENSEI);
1467 tmp = fdcresult(fdc);
1468 if ((st0 & 0xf8) == 0xc0) {
1469 DPRINTF(("fdcintr: first seek!\n"));
1470 fdc->sc_state = DORECAL;
1471 goto loop;
1472 } else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1473 #ifdef FDDEBUG
1474 fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1475 #endif
1476 fdcretry(fdc);
1477 goto loop;
1478 }
1479 fd->sc_cylin = 0;
1480 goto doseek;
1481
1482 case MOTORWAIT:
1483 if (fd->sc_flags & FD_MOTOR_WAIT)
1484 return 1; /* time's not up yet */
1485 goto doseek;
1486
1487 default:
1488 fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1489 return 1;
1490 }
1491 #ifdef DIAGNOSTIC
1492 panic("fdcintr: impossible");
1493 #endif
1494 #undef st0
1495 #undef cyl
1496 }
1497
1498 void
1499 fdcretry(fdc)
1500 struct fdc_softc *fdc;
1501 {
1502 struct fd_softc *fd;
1503 struct buf *bp;
1504 char bits[64];
1505
1506 DPRINTF(("fdcretry:\n"));
1507 fd = fdc->sc_drives.tqh_first;
1508 bp = BUFQ_PEEK(&fd->sc_q);
1509
1510 switch (fdc->sc_errors) {
1511 case 0:
1512 /* try again */
1513 fdc->sc_state = SEEKCOMPLETE;
1514 break;
1515
1516 case 1: case 2: case 3:
1517 /* didn't work; try recalibrating */
1518 fdc->sc_state = DORECAL;
1519 break;
1520
1521 case 4:
1522 /* still no go; reset the bastard */
1523 fdc->sc_state = DORESET;
1524 break;
1525
1526 default:
1527 diskerr(bp, "fd", "hard error", LOG_PRINTF,
1528 fd->sc_skip, (struct disklabel *)NULL);
1529 printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1530 NE7_ST0BITS, bits,
1531 sizeof(bits)));
1532 printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1533 NE7_ST1BITS, bits,
1534 sizeof(bits)));
1535 printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1536 NE7_ST2BITS, bits,
1537 sizeof(bits)));
1538 printf(" cyl %d head %d sec %d)\n",
1539 fdc->sc_status[3],
1540 fdc->sc_status[4],
1541 fdc->sc_status[5]);
1542
1543 bp->b_flags |= B_ERROR;
1544 bp->b_error = EIO;
1545 fdfinish(fd, bp);
1546 }
1547 fdc->sc_errors++;
1548 }
1549
1550 int
1551 fdioctl(dev, cmd, addr, flag, p)
1552 dev_t dev;
1553 u_long cmd;
1554 caddr_t addr;
1555 int flag;
1556 struct proc *p;
1557 {
1558 struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1559 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1560 int unit = FDUNIT(dev);
1561 int part = DISKPART(dev);
1562 struct disklabel buffer;
1563 int error;
1564
1565 DPRINTF(("fdioctl:\n"));
1566 switch (cmd) {
1567 case DIOCGDINFO:
1568 #if 1
1569 *(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1570 return(0);
1571 #else
1572 memset(&buffer, 0, sizeof(buffer));
1573
1574 buffer.d_secpercyl = fd->sc_type->seccyl;
1575 buffer.d_type = DTYPE_FLOPPY;
1576 buffer.d_secsize = 128 << fd->sc_type->secsize;
1577
1578 if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1579 return EINVAL;
1580
1581 *(struct disklabel *)addr = buffer;
1582 return 0;
1583 #endif
1584
1585 case DIOCGPART:
1586 ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
1587 ((struct partinfo *)addr)->part =
1588 &fd->sc_dk.dk_label->d_partitions[part];
1589 return(0);
1590
1591 case DIOCWLABEL:
1592 if ((flag & FWRITE) == 0)
1593 return EBADF;
1594 /* XXX do something */
1595 return 0;
1596
1597 case DIOCWDINFO:
1598 if ((flag & FWRITE) == 0)
1599 return EBADF;
1600
1601 error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1602 if (error)
1603 return error;
1604
1605 error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1606 return error;
1607
1608 case DIOCLOCK:
1609 /*
1610 * Nothing to do here, really.
1611 */
1612 return 0; /* XXX */
1613
1614 case DIOCEJECT:
1615 if (*(int *)addr == 0) {
1616 /*
1617 * Don't force eject: check that we are the only
1618 * partition open. If so, unlock it.
1619 */
1620 if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1621 fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1622 fd->sc_dk.dk_openmask) {
1623 return (EBUSY);
1624 }
1625 }
1626 /* FALLTHROUGH */
1627 case ODIOCEJECT:
1628 fd_do_eject(fdc, unit);
1629 return 0;
1630
1631 default:
1632 return ENOTTY;
1633 }
1634
1635 #ifdef DIAGNOSTIC
1636 panic("fdioctl: impossible");
1637 #endif
1638 }
1639
1640 void
1641 fd_do_eject(fdc, unit)
1642 struct fdc_softc *fdc;
1643 int unit;
1644 {
1645 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
1646 0x20 | ( 1 << unit));
1647 DELAY(1); /* XXX */
1648 bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
1649 }
1650
1651 /*
1652 * Build disk label. For now we only create a label from what we know
1653 * from 'sc'.
1654 */
1655 static int
1656 fdgetdisklabel(sc, dev)
1657 struct fd_softc *sc;
1658 dev_t dev;
1659 {
1660 struct disklabel *lp;
1661 int part;
1662
1663 DPRINTF(("fdgetdisklabel()\n"));
1664
1665 part = DISKPART(dev);
1666 lp = sc->sc_dk.dk_label;
1667 memset(lp, 0, sizeof(struct disklabel));
1668
1669 lp->d_secsize = 128 << sc->sc_type->secsize;
1670 lp->d_ntracks = sc->sc_type->heads;
1671 lp->d_nsectors = sc->sc_type->sectrac;
1672 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1673 lp->d_ncylinders = sc->sc_type->size / lp->d_secpercyl;
1674 lp->d_secperunit = sc->sc_type->size;
1675
1676 lp->d_type = DTYPE_FLOPPY;
1677 lp->d_rpm = 300; /* XXX */
1678 lp->d_interleave = 1; /* FIXME: is this OK? */
1679 lp->d_bbsize = 0;
1680 lp->d_sbsize = 0;
1681 lp->d_npartitions = part + 1;
1682 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1683 lp->d_trkseek = STEP_DELAY; /* XXX */
1684 lp->d_magic = DISKMAGIC;
1685 lp->d_magic2 = DISKMAGIC;
1686 lp->d_checksum = dkcksum(lp);
1687 lp->d_partitions[part].p_size = lp->d_secperunit;
1688 lp->d_partitions[part].p_fstype = FS_UNUSED;
1689 lp->d_partitions[part].p_fsize = 1024;
1690 lp->d_partitions[part].p_frag = 8;
1691
1692 return(0);
1693 }
1694
1695 #include <dev/cons.h>
1696
1697 /*
1698 * Mountroot hook: prompt the user to enter the root file system
1699 * floppy.
1700 */
1701 void
1702 fd_mountroot_hook(dev)
1703 struct device *dev;
1704 {
1705 struct fd_softc *fd = (void*) dev;
1706 struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
1707 int c;
1708
1709 fd_do_eject(fdc, dev->dv_unit);
1710 printf("Insert filesystem floppy and press return.");
1711 for (;;) {
1712 c = cngetc();
1713 if ((c == '\r') || (c == '\n')) {
1714 printf("\n");
1715 break;
1716 }
1717 }
1718 }
1719