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