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