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