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