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