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