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