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