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