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