1 /* $NetBSD: fd.c,v 1.91 2009/01/13 13:35:52 yamt Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and Minoura Makoto.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright (c) 1990 The Regents of the University of California.
34 * All rights reserved.
36 * This code is derived from software contributed to Berkeley by
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
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.
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
63 * @(#)fd.c 7.4 (Berkeley) 5/25/91
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.91 2009/01/13 13:35:52 yamt Exp $");
71 #include "opt_m680x0.h"
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/callout.h>
76 #include <sys/kernel.h>
80 #include <sys/ioctl.h>
81 #include <sys/malloc.h>
82 #include <sys/device.h>
83 #include <sys/disklabel.h>
88 #include <sys/syslog.h>
89 #include <sys/queue.h>
95 #include <uvm/uvm_extern.h>
99 #include <machine/bus.h>
100 #include <machine/cpu.h>
102 #include <arch/x68k/dev/intiovar.h>
103 #include <arch/x68k/dev/dmacvar.h>
104 #include <arch/x68k/dev/fdreg.h>
105 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
107 #include "locators.h"
110 #define DPRINTF(x) if (fddebug) printf x
116 #define FDUNIT(dev) (minor(dev) / 8)
117 #define FDTYPE(dev) (minor(dev) % 8)
141 /* software state, per controller */
143 bus_space_tag_t sc_iot
; /* intio i/o space identifier */
144 bus_space_handle_t sc_ioh
; /* intio io handle */
146 struct callout sc_timo_ch
; /* timeout callout */
147 struct callout sc_intr_ch
; /* pseudo-intr callout */
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 */
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 */
163 void fdcreset(struct fdc_softc
*);
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 *);
170 CFATTACH_DECL_NEW(fdc
, sizeof(struct fdc_softc
),
171 fdcprobe
, fdcattach
, NULL
, NULL
);
173 extern struct cfdriver fdc_cd
;
176 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
177 * we tell them apart.
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 */
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 */
207 /* software state, per disk (with up to 4 disks per ctlr) */
212 struct fd_type
*sc_deftype
; /* default type descriptor */
213 struct fd_type
*sc_type
; /* current type descriptor */
215 struct callout sc_motoron_ch
;
216 struct callout sc_motoroff_ch
;
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 */
225 int sc_drive
; /* physical unit number */
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 */
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 */
246 rndsource_element_t rnd_source
;
250 /* floppy driver configuration */
251 int fdprobe(device_t
, cfdata_t
, void *);
252 void fdattach(device_t
, device_t
, void *);
254 CFATTACH_DECL_NEW(fd
, sizeof(struct fd_softc
),
255 fdprobe
, fdattach
, NULL
, NULL
);
257 extern struct cfdriver fd_cd
;
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
);
266 const struct bdevsw fd_bdevsw
= {
267 fdopen
, fdclose
, fdstrategy
, fdioctl
, nodump
, nosize
, D_DISK
270 const struct cdevsw fd_cdevsw
= {
271 fdopen
, fdclose
, fdread
, fdwrite
, fdioctl
,
272 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
275 void fdstart(struct fd_softc
*);
277 struct dkdriver fddkdriver
= { fdstrategy
};
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);
295 void fd_mountroot_hook(device_t
);
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 *);
303 fdc_dmastart(struct fdc_softc
*fdc
, int read
, void *addr
, vsize_t count
)
307 DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
308 read
? "read" : "write", (void *) addr
, count
));
310 error
= bus_dmamap_load(fdc
->sc_dmat
, fdc
->sc_dmamap
, addr
, count
,
313 panic ("fdc_dmastart: cannot load dmamap");
316 bus_dmamap_sync(fdc
->sc_dmat
, fdc
->sc_dmamap
, 0, count
,
317 read
?BUS_DMASYNC_PREREAD
:BUS_DMASYNC_PREWRITE
);
319 fdc
->sc_xfer
= dmac_prepare_xfer(fdc
->sc_dmachan
, fdc
->sc_dmat
,
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
+
328 dmac_start_xfer(fdc
->sc_dmachan
->ch_softc
, fdc
->sc_xfer
);
332 fdcdmaintr(void *arg
)
334 struct fdc_softc
*fdc
= arg
;
336 bus_dmamap_unload(fdc
->sc_dmat
, fdc
->sc_dmamap
);
342 fdcdmaerrintr(void *dummy
)
344 DPRINTF(("fdcdmaerrintr\n"));
351 fdcprobe(device_t parent
, cfdata_t cf
, void *aux
)
353 struct intio_attach_args
*ia
= aux
;
355 if (strcmp(ia
->ia_name
, "fdc") != 0)
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
;
367 if ((ia
->ia_intr
& 0x03) != 0)
370 ia
->ia_size
= 0x2000;
371 if (intio_map_allocate_region (parent
, ia
, INTIO_MAP_TESTONLY
))
374 /* builtin device; always there */
379 * Arguments passed between fdcattach and fdprobe.
381 struct fdc_attach_args
{
383 struct fd_type
*fa_deftype
;
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.
394 fdprint(void *aux
, const char *fdc
)
396 struct fdc_attach_args
*fa
= aux
;
399 aprint_normal(" drive %d", fa
->fa_drive
);
404 fdcattach(device_t parent
, device_t self
, void *aux
)
406 struct fdc_softc
*fdc
= device_private(self
);
408 bus_space_handle_t ioh
;
409 struct intio_attach_args
*ia
= aux
;
410 struct fdc_attach_args fa
;
416 callout_init(&fdc
->sc_timo_ch
, 0);
417 callout_init(&fdc
->sc_intr_ch
, 0);
419 /* Re-map the I/O space. */
420 bus_space_map(iot
, ia
->ia_addr
, 0x2000, BUS_SPACE_MAP_SHIFTED
, &ioh
);
424 fdc
->sc_addr
= (void *)ia
->ia_addr
;
426 fdc
->sc_dmat
= ia
->ia_dmat
;
427 fdc
->sc_state
= DEVIDLE
;
428 TAILQ_INIT(&fdc
->sc_drives
);
430 /* Initialize DMAC channel */
431 fdc
->sc_dmachan
= dmac_alloc_channel(parent
, ia
->ia_dma
, "fdc",
432 ia
->ia_dmaintr
, fdcdmaintr
, fdc
,
433 ia
->ia_dmaintr
+1, fdcdmaerrintr
,
435 if (bus_dmamap_create(fdc
->sc_dmat
, FDC_MAXIOSIZE
, 1, DMAC_MAXSEGSZ
,
436 0, BUS_DMA_NOWAIT
|BUS_DMA_ALLOCNOW
,
438 aprint_error_dev(self
, "can't set up intio DMA map\n");
442 if (intio_intr_establish(ia
->ia_intr
, "fdc", fdcintr
, fdc
))
443 panic ("Could not establish interrupt (duplicated vector?).");
444 intio_set_ivec(ia
->ia_intr
);
447 intio_disable_intr(SICILIAN_INTR_FDD
);
448 intio_enable_intr(SICILIAN_INTR_FDC
);
452 aprint_normal_dev(self
, "uPD72065 FDC\n");
453 out_fdc(iot
, ioh
, NE7CMD_SPECIFY
);/* specify command */
454 out_fdc(iot
, ioh
, 0xd0);
455 out_fdc(iot
, ioh
, 0x10);
457 /* physical limit: four drives per controller. */
458 for (fa
.fa_drive
= 0; fa
.fa_drive
< 4; fa
.fa_drive
++) {
459 (void)config_found(self
, (void *)&fa
, fdprint
);
462 intio_enable_intr(SICILIAN_INTR_FDC
);
466 fdcreset(struct fdc_softc
*fdc
)
468 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdsts
, NE7CMD_RESET
);
472 fdcpoll(struct fdc_softc
*fdc
)
476 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC
)) {
477 out_fdc(fdc
->sc_iot
, fdc
->sc_ioh
, NE7CMD_SENSEI
);
487 fdprobe(device_t parent
, cfdata_t cf
, void *aux
)
489 struct fdc_softc
*fdc
= device_private(parent
);
490 struct fd_type
*type
;
491 struct fdc_attach_args
*fa
= aux
;
492 int drive
= fa
->fa_drive
;
493 bus_space_tag_t iot
= fdc
->sc_iot
;
494 bus_space_handle_t ioh
= fdc
->sc_ioh
;
499 if (cf
->cf_loc
[FDCCF_UNIT
] != FDCCF_UNIT_DEFAULT
&&
500 cf
->cf_loc
[FDCCF_UNIT
] != drive
)
503 type
= &fd_types
[0]; /* XXX 1.2MB */
505 intio_disable_intr(SICILIAN_INTR_FDC
);
507 /* select drive and turn on motor */
508 bus_space_write_1(iot
, ioh
, fdctl
, 0x80 | (type
->rate
<< 4)| drive
);
509 fdc_force_ready(FDCRDY
);
513 out_fdc(iot
, ioh
, NE7CMD_RECAL
);
514 out_fdc(iot
, ioh
, drive
);
518 if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC
)) {
519 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
529 DPRINTF(("fdprobe: status"));
530 for (_i
= 0; _i
< n
; _i
++)
531 DPRINTF((" %x", fdc
->sc_status
[_i
]));
537 if ((fdc
->sc_status
[0] & 0xf0) == 0x20)
539 else if ((fdc
->sc_status
[0] & 0xf0) == 0xc0)
544 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
,
545 fdctl
, (type
->rate
<< 4)| drive
);
546 fdc_force_ready(FDCSTBY
);
548 intio_enable_intr(SICILIAN_INTR_FDC
);
556 * Controller is working, and drive responded. Attach it.
559 fdattach(device_t parent
, device_t self
, void *aux
)
561 struct fdc_softc
*fdc
= device_private(parent
);
562 struct fd_softc
*fd
= device_private(self
);
563 struct fdc_attach_args
*fa
= aux
;
564 struct fd_type
*type
= &fd_types
[0]; /* XXX 1.2MB */
565 int drive
= fa
->fa_drive
;
567 callout_init(&fd
->sc_motoron_ch
, 0);
568 callout_init(&fd
->sc_motoroff_ch
, 0);
574 aprint_normal(": %s, %d cyl, %d head, %d sec\n", type
->name
,
575 type
->cyls
, type
->heads
, type
->sectrac
);
577 aprint_normal(": density unknown\n");
579 bufq_alloc(&fd
->sc_q
, "disksort", BUFQ_SORT_CYLINDER
);
581 fd
->sc_drive
= drive
;
582 fd
->sc_deftype
= type
;
583 fdc
->sc_fd
[drive
] = fd
;
585 fd
->sc_copybuf
= (u_char
*)malloc(PAGE_SIZE
, M_DEVBUF
, M_WAITOK
);
586 if (fd
->sc_copybuf
== 0)
587 aprint_error("%s: WARNING!! malloc() failed.\n", __func__
);
588 fd
->sc_flags
|= FD_ALIVE
;
591 * Initialize and attach the disk structure.
593 disk_init(&fd
->sc_dk
, device_xname(fd
->sc_dev
), &fddkdriver
);
594 disk_attach(&fd
->sc_dk
);
597 * Establish a mountroot_hook anyway in case we booted
598 * with RB_ASKNAME and get selected as the boot device.
600 mountroothook_establish(fd_mountroot_hook
, fd
->sc_dev
);
603 rnd_attach_source(&fd
->rnd_source
, device_xname(fd
->sc_dev
),
608 inline struct fd_type
*
609 fd_dev_to_type(struct fd_softc
*fd
, dev_t dev
)
611 int type
= FDTYPE(dev
);
613 if (type
> (sizeof(fd_types
) / sizeof(fd_types
[0])))
615 return &fd_types
[type
];
619 fdstrategy(struct buf
*bp
)
626 unit
= FDUNIT(bp
->b_dev
);
627 fd
= device_lookup_private(&fd_cd
, unit
);
629 bp
->b_error
= EINVAL
;
633 if (bp
->b_blkno
< 0 ||
634 (bp
->b_bcount
% FDC_BSIZE
) != 0) {
635 DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64
", "
637 bp
->b_blkno
, bp
->b_bcount
));
638 bp
->b_error
= EINVAL
;
642 /* If it's a null transfer, return immediately. */
643 if (bp
->b_bcount
== 0)
646 sz
= howmany(bp
->b_bcount
, FDC_BSIZE
);
648 if (bp
->b_blkno
+ sz
>
649 (fd
->sc_type
->size
<< (fd
->sc_type
->secsize
- 2))) {
650 sz
= (fd
->sc_type
->size
<< (fd
->sc_type
->secsize
- 2))
653 /* If exactly at end of disk, return EOF. */
654 bp
->b_resid
= bp
->b_bcount
;
658 /* If past end of disk, return EINVAL. */
659 bp
->b_error
= EINVAL
;
662 /* Otherwise, truncate request. */
663 bp
->b_bcount
= sz
<< DEV_BSHIFT
;
666 bp
->b_rawblkno
= bp
->b_blkno
;
667 bp
->b_cylinder
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
)
668 / (fd
->sc_type
->seccyl
* (1 << (fd
->sc_type
->secsize
- 2)));
670 DPRINTF(("fdstrategy: %s b_blkno %" PRId64
" b_bcount %d cylin %d\n",
671 bp
->b_flags
& B_READ
? "read" : "write",
672 bp
->b_blkno
, bp
->b_bcount
, bp
->b_cylinder
));
673 /* Queue transfer on drive, activate drive and controller if idle. */
675 bufq_put(fd
->sc_q
, bp
);
676 callout_stop(&fd
->sc_motoroff_ch
); /* a good idea */
677 if (fd
->sc_active
== 0)
681 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
682 if (fdc
->sc_state
== DEVIDLE
) {
683 printf("fdstrategy: controller inactive\n");
692 /* Toss transfer; we're done early. */
697 fdstart(struct fd_softc
*fd
)
699 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
700 int active
= !TAILQ_EMPTY(&fdc
->sc_drives
);
702 /* Link into controller queue. */
704 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
706 /* If controller not already active, start it. */
712 fdfinish(struct fd_softc
*fd
, struct buf
*bp
)
714 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
717 * Move this drive to the end of the queue to give others a `fair'
718 * chance. We only force a switch if N operations are completed while
719 * another drive is waiting to be serviced, since there is a long motor
720 * startup delay whenever we switch.
722 (void)bufq_get(fd
->sc_q
);
723 if (TAILQ_NEXT(fd
, sc_drivechain
) && ++fd
->sc_ops
>= 8) {
725 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
726 if (bufq_peek(fd
->sc_q
) != NULL
) {
727 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
731 bp
->b_resid
= fd
->sc_bcount
;
735 rnd_add_uint32(&fd
->rnd_source
, bp
->b_blkno
);
739 /* turn off motor 5s from now */
740 callout_reset(&fd
->sc_motoroff_ch
, 5 * hz
, fd_motor_off
, fd
);
741 fdc
->sc_state
= DEVIDLE
;
745 fdread(dev_t dev
, struct uio
*uio
, int flags
)
748 return (physio(fdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
752 fdwrite(dev_t dev
, struct uio
*uio
, int flags
)
755 return (physio(fdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
759 fd_set_motor(struct fdc_softc
*fdc
, int reset
)
764 DPRINTF(("fd_set_motor:\n"));
765 for (n
= 0; n
< 4; n
++)
766 if ((fd
= fdc
->sc_fd
[n
]) && (fd
->sc_flags
& FD_MOTOR
)) {
767 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdctl
,
768 0x80 | (fd
->sc_type
->rate
<< 4)| n
);
773 fd_motor_off(void *arg
)
775 struct fd_softc
*fd
= arg
;
776 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
779 DPRINTF(("fd_motor_off:\n"));
782 fd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
783 bus_space_write_1 (fdc
->sc_iot
, fdc
->sc_ioh
, fdctl
,
784 (fd
->sc_type
->rate
<< 4) | fd
->sc_drive
);
786 fd_set_motor(fdc
, 0); /* XXX */
792 fd_motor_on(void *arg
)
794 struct fd_softc
*fd
= arg
;
795 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
798 DPRINTF(("fd_motor_on:\n"));
801 fd
->sc_flags
&= ~FD_MOTOR_WAIT
;
802 if ((TAILQ_FIRST(&fdc
->sc_drives
) == fd
) && (fdc
->sc_state
== MOTORWAIT
))
808 fdcresult(struct fdc_softc
*fdc
)
810 bus_space_tag_t iot
= fdc
->sc_iot
;
811 bus_space_handle_t ioh
= fdc
->sc_ioh
;
817 i
= bus_space_read_1(iot
, ioh
, fdsts
) &
818 (NE7_DIO
| NE7_RQM
| NE7_CB
);
822 if (i
== (NE7_DIO
| NE7_RQM
| NE7_CB
)) {
823 if (n
>= sizeof(fdc
->sc_status
)) {
824 log(LOG_ERR
, "fdcresult: overrun\n");
827 fdc
->sc_status
[n
++] =
828 bus_space_read_1(iot
, ioh
, fddata
);
832 log(LOG_ERR
, "fdcresult: timeout\n");
837 out_fdc(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_char x
)
841 while ((bus_space_read_1(iot
, ioh
, fdsts
) & NE7_DIO
) && i
-- > 0);
844 while ((bus_space_read_1(iot
, ioh
, fdsts
) & NE7_RQM
) == 0 && i
-- > 0);
847 bus_space_write_1(iot
, ioh
, fddata
, x
);
852 fdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
856 struct fd_type
*type
;
857 struct fdc_softc
*fdc
;
860 fd
= device_lookup_private(&fd_cd
, unit
);
863 type
= fd_dev_to_type(fd
, dev
);
867 if ((fd
->sc_flags
& FD_OPEN
) != 0 &&
871 fdc
= device_private(device_parent(fd
->sc_dev
));
872 if ((fd
->sc_flags
& FD_OPEN
) == 0) {
873 /* Lock eject button */
874 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
,
875 0x40 | ( 1 << unit
));
876 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
, 0x40);
884 fd
->sc_flags
|= FD_COPEN
;
887 fd
->sc_flags
|= FD_BOPEN
;
891 fdgetdisklabel(fd
, dev
);
897 fdclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
899 int unit
= FDUNIT(dev
);
900 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, unit
);
901 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
903 DPRINTF(("fdclose %d\n", unit
));
907 fd
->sc_flags
&= ~FD_COPEN
;
910 fd
->sc_flags
&= ~FD_BOPEN
;
914 if ((fd
->sc_flags
& FD_OPEN
) == 0) {
915 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
,
917 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
, 0);
923 fdcstart(struct fdc_softc
*fdc
)
927 /* only got here if controller's drive queue was inactive; should
929 if (fdc
->sc_state
!= DEVIDLE
) {
930 printf("fdcstart: not idle\n");
939 fdcpstatus(int n
, struct fdc_softc
*fdc
)
948 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
949 printf(" (st0 %s cyl %d)\n", bits
, fdc
->sc_status
[1]);
952 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
953 printf(" (st0 %s", bits
);
954 snprintb(bits
, sizeof(bits
), NE7_ST1BITS
, fdc
->sc_status
[1]);
955 printf(" st1 %s", bits
);
956 snprintb(bits
, sizeof(bits
), NE7_ST2BITS
, fdc
->sc_status
[2]);
957 printf(" st2 %s", bits
);
958 printf(" cyl %d head %d sec %d)\n",
959 fdc
->sc_status
[3], fdc
->sc_status
[4], fdc
->sc_status
[5]);
963 printf("\nfdcstatus: weird size");
970 fdcstatus(device_t dv
, int n
, const char *s
)
972 struct fdc_softc
*fdc
= device_private(device_parent(dv
));
975 out_fdc(fdc
->sc_iot
, fdc
->sc_ioh
, NE7CMD_SENSEI
);
976 (void) fdcresult(fdc
);
980 printf("%s: %s: state %d", device_xname(dv
), s
, fdc
->sc_state
);
985 fdctimeout(void *arg
)
987 struct fdc_softc
*fdc
= arg
;
988 struct fd_softc
*fd
= TAILQ_FIRST(&fdc
->sc_drives
);
992 fdcstatus(fd
->sc_dev
, 0, "timeout");
994 if (bufq_peek(fd
->sc_q
) != NULL
)
997 fdc
->sc_state
= DEVIDLE
;
1005 fdcpseudointr(void *arg
)
1008 struct fdc_softc
*fdc
= arg
;
1010 /* just ensure it has the right spl */
1012 (void) fdcintr(fdc
);
1020 struct fdc_softc
*fdc
= arg
;
1021 #define st0 fdc->sc_status[0]
1022 #define cyl fdc->sc_status[1]
1023 struct fd_softc
*fd
;
1025 bus_space_tag_t iot
= fdc
->sc_iot
;
1026 bus_space_handle_t ioh
= fdc
->sc_ioh
;
1027 int read
, head
, sec
, pos
, i
, sectrac
, nblks
;
1029 struct fd_type
*type
;
1032 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1034 DPRINTF(("fdcintr: set DEVIDLE\n"));
1035 if (fdc
->sc_state
== DEVIDLE
) {
1036 if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC
) {
1037 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1038 if ((tmp
= fdcresult(fdc
)) != 2 ||
1039 (st0
& 0xf8) != 0x20) {
1044 /* no drives waiting; end */
1045 fdc
->sc_state
= DEVIDLE
;
1049 /* Is there a transfer to this drive? If not, deactivate drive. */
1050 bp
= bufq_peek(fd
->sc_q
);
1053 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
1058 switch (fdc
->sc_state
) {
1060 DPRINTF(("fdcintr: in DEVIDLE\n"));
1063 fd
->sc_bcount
= bp
->b_bcount
;
1064 fd
->sc_blkno
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
);
1065 callout_stop(&fd
->sc_motoroff_ch
);
1066 if ((fd
->sc_flags
& FD_MOTOR_WAIT
) != 0) {
1067 fdc
->sc_state
= MOTORWAIT
;
1070 if ((fd
->sc_flags
& FD_MOTOR
) == 0) {
1071 /* Turn on the motor */
1072 /* being careful about other drives. */
1073 for (i
= 0; i
< 4; i
++) {
1074 struct fd_softc
*ofd
= fdc
->sc_fd
[i
];
1075 if (ofd
&& ofd
->sc_flags
& FD_MOTOR
) {
1076 callout_stop(&ofd
->sc_motoroff_ch
);
1078 ~(FD_MOTOR
| FD_MOTOR_WAIT
);
1082 fd
->sc_flags
|= FD_MOTOR
| FD_MOTOR_WAIT
;
1083 fd_set_motor(fdc
, 0);
1084 fdc
->sc_state
= MOTORWAIT
;
1085 /* allow .5s for motor to stabilize */
1086 callout_reset(&fd
->sc_motoron_ch
, hz
/ 2,
1090 /* Make sure the right drive is selected. */
1091 fd_set_motor(fdc
, 0);
1096 DPRINTF(("fdcintr: in DOSEEK\n"));
1097 if (fd
->sc_cylin
== bp
->b_cylinder
)
1100 out_fdc(iot
, ioh
, NE7CMD_SPECIFY
);/* specify command */
1101 out_fdc(iot
, ioh
, 0xd0); /* XXX const */
1102 out_fdc(iot
, ioh
, 0x10);
1104 out_fdc(iot
, ioh
, NE7CMD_SEEK
); /* seek function */
1105 out_fdc(iot
, ioh
, fd
->sc_drive
); /* drive number */
1106 out_fdc(iot
, ioh
, bp
->b_cylinder
* fd
->sc_type
->step
);
1109 fdc
->sc_state
= SEEKWAIT
;
1111 iostat_seek(fd
->sc_dk
.dk_stats
);
1112 disk_busy(&fd
->sc_dk
);
1114 callout_reset(&fdc
->sc_timo_ch
, 4 * hz
, fdctimeout
, fdc
);
1119 DPRINTF(("fdcintr: DOIO: "));
1121 sectrac
= type
->sectrac
;
1122 pos
= fd
->sc_blkno
% (sectrac
* (1 << (type
->secsize
- 2)));
1123 sec
= pos
/ (1 << (type
->secsize
- 2));
1124 if (type
->secsize
== 2) {
1125 fd
->sc_part
= SEC_P11
;
1126 nblks
= (sectrac
- sec
) << (type
->secsize
- 2);
1127 nblks
= min(nblks
, fd
->sc_bcount
/ FDC_BSIZE
);
1128 DPRINTF(("nblks(0)"));
1129 } else if ((fd
->sc_blkno
% 2) == 0) {
1130 if (fd
->sc_bcount
& 0x00000200) {
1131 if (fd
->sc_bcount
== FDC_BSIZE
) {
1132 fd
->sc_part
= SEC_P10
;
1134 DPRINTF(("nblks(1)"));
1136 fd
->sc_part
= SEC_P11
;
1137 nblks
= (sectrac
- sec
) * 2;
1138 nblks
= min(nblks
, fd
->sc_bcount
1140 DPRINTF(("nblks(2)"));
1143 fd
->sc_part
= SEC_P11
;
1144 nblks
= (sectrac
- sec
)
1145 << (type
->secsize
- 2);
1146 nblks
= min(nblks
, fd
->sc_bcount
/ FDC_BSIZE
);
1147 DPRINTF(("nblks(3)"));
1150 fd
->sc_part
= SEC_P01
;
1152 DPRINTF(("nblks(4)"));
1154 nblks
= min(nblks
, FDC_MAXIOSIZE
/ FDC_BSIZE
);
1155 DPRINTF((" %d\n", nblks
));
1156 fd
->sc_nblks
= nblks
;
1157 fd
->sc_nbytes
= nblks
* FDC_BSIZE
;
1158 head
= (fd
->sc_blkno
1159 % (type
->seccyl
* (1 << (type
->secsize
- 2))))
1160 / (type
->sectrac
* (1 << (type
->secsize
- 2)));
1164 block
= ((fd
->sc_cylin
* type
->heads
+ head
) * type
->sectrac
1165 + sec
) * (1 << (type
->secsize
- 2));
1166 block
+= (fd
->sc_part
== SEC_P01
) ? 1 : 0;
1167 if (block
!= fd
->sc_blkno
) {
1168 printf("C H R N: %d %d %d %d\n",
1169 fd
->sc_cylin
, head
, sec
, type
->secsize
);
1170 printf("fdcintr: doio: block %d != blkno %" PRId64
"\n",
1171 block
, fd
->sc_blkno
);
1178 read
= bp
->b_flags
& B_READ
;
1179 DPRINTF(("fdcintr: %s drive %d track %d "
1180 "head %d sec %d nblks %d, skip %d\n",
1181 read
? "read" : "write", fd
->sc_drive
, fd
->sc_cylin
,
1182 head
, sec
, nblks
, fd
->sc_skip
));
1183 DPRINTF(("C H R N: %d %d %d %d\n", fd
->sc_cylin
, head
, sec
,
1186 if (fd
->sc_part
!= SEC_P11
)
1189 fdc_dmastart(fdc
, read
, (char *)bp
->b_data
+ fd
->sc_skip
,
1192 out_fdc(iot
, ioh
, NE7CMD_READ
); /* READ */
1194 out_fdc(iot
, ioh
, NE7CMD_WRITE
); /* WRITE */
1195 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1196 out_fdc(iot
, ioh
, bp
->b_cylinder
); /* cylinder */
1197 out_fdc(iot
, ioh
, head
);
1198 out_fdc(iot
, ioh
, sec
+ 1); /* sector +1 */
1199 out_fdc(iot
, ioh
, type
->secsize
); /* sector size */
1200 out_fdc(iot
, ioh
, type
->sectrac
); /* sectors/track */
1201 out_fdc(iot
, ioh
, type
->gap1
); /* gap1 size */
1202 out_fdc(iot
, ioh
, type
->datalen
); /* data length */
1203 fdc
->sc_state
= IOCOMPLETE
;
1205 disk_busy(&fd
->sc_dk
);
1207 /* allow 2 seconds for operation */
1208 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
1209 return 1; /* will return later */
1213 DPRINTF(("fdcintr: DOCOPY:\n"));
1215 head
= (fd
->sc_blkno
1216 % (type
->seccyl
* (1 << (type
->secsize
- 2))))
1217 / (type
->sectrac
* (1 << (type
->secsize
- 2)));
1218 pos
= fd
->sc_blkno
% (type
->sectrac
* (1 << (type
->secsize
- 2)));
1219 sec
= pos
/ (1 << (type
->secsize
- 2));
1220 fdc_dmastart(fdc
, B_READ
, fd
->sc_copybuf
, 1024);
1221 out_fdc(iot
, ioh
, NE7CMD_READ
); /* READ */
1222 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1223 out_fdc(iot
, ioh
, bp
->b_cylinder
); /* cylinder */
1224 out_fdc(iot
, ioh
, head
);
1225 out_fdc(iot
, ioh
, sec
+ 1); /* sector +1 */
1226 out_fdc(iot
, ioh
, type
->secsize
); /* sector size */
1227 out_fdc(iot
, ioh
, type
->sectrac
); /* sectors/track */
1228 out_fdc(iot
, ioh
, type
->gap1
); /* gap1 size */
1229 out_fdc(iot
, ioh
, type
->datalen
); /* data length */
1230 fdc
->sc_state
= COPYCOMPLETE
;
1231 /* allow 2 seconds for operation */
1232 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
1233 return 1; /* will return later */
1237 DPRINTF((" DOIOHALF:\n"));
1240 sectrac
= type
->sectrac
;
1241 pos
= fd
->sc_blkno
% (sectrac
* (1 << (type
->secsize
- 2)));
1242 sec
= pos
/ (1 << (type
->secsize
- 2));
1243 head
= (fd
->sc_blkno
1244 % (type
->seccyl
* (1 << (type
->secsize
- 2))))
1245 / (type
->sectrac
* (1 << (type
->secsize
- 2)));
1248 block
= ((fd
->sc_cylin
* type
->heads
+ head
) *
1249 type
->sectrac
+ sec
)
1250 * (1 << (type
->secsize
- 2));
1251 block
+= (fd
->sc_part
== SEC_P01
) ? 1 : 0;
1252 if (block
!= fd
->sc_blkno
) {
1253 printf("fdcintr: block %d != blkno %" PRId64
"\n",
1254 block
, fd
->sc_blkno
);
1261 if ((read
= bp
->b_flags
& B_READ
)) {
1262 memcpy((char *)bp
->b_data
+ fd
->sc_skip
, fd
->sc_copybuf
1263 + (fd
->sc_part
& SEC_P01
? FDC_BSIZE
: 0),
1265 fdc
->sc_state
= IOCOMPLETE
;
1268 memcpy((char *)fd
->sc_copybuf
1269 + (fd
->sc_part
& SEC_P01
? FDC_BSIZE
: 0),
1270 (char *)bp
->b_data
+ fd
->sc_skip
, FDC_BSIZE
);
1271 fdc_dmastart(fdc
, read
, fd
->sc_copybuf
, 1024);
1273 out_fdc(iot
, ioh
, NE7CMD_WRITE
); /* WRITE */
1274 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1275 out_fdc(iot
, ioh
, bp
->b_cylinder
); /* cylinder */
1276 out_fdc(iot
, ioh
, head
);
1277 out_fdc(iot
, ioh
, sec
+ 1); /* sector +1 */
1278 out_fdc(iot
, ioh
, fd
->sc_type
->secsize
); /* sector size */
1279 out_fdc(iot
, ioh
, sectrac
); /* sectors/track */
1280 out_fdc(iot
, ioh
, fd
->sc_type
->gap1
); /* gap1 size */
1281 out_fdc(iot
, ioh
, fd
->sc_type
->datalen
); /* data length */
1282 fdc
->sc_state
= IOCOMPLETE
;
1283 /* allow 2 seconds for operation */
1284 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
1285 return 1; /* will return later */
1288 callout_stop(&fdc
->sc_timo_ch
);
1289 fdc
->sc_state
= SEEKCOMPLETE
;
1290 /* allow 1/50 second for heads to settle */
1292 callout_reset(&fdc
->sc_intr_ch
, hz
/ 50, fdcpseudointr
, fdc
);
1297 /* Make sure seek really happened */
1298 DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
1299 bus_space_read_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdsts
)));
1300 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1301 tmp
= fdcresult(fdc
);
1302 if ((st0
& 0xf8) == 0xc0) {
1303 DPRINTF(("fdcintr: first seek!\n"));
1304 fdc
->sc_state
= DORECAL
;
1306 } else if (tmp
!= 2 ||
1307 (st0
& 0xf8) != 0x20 ||
1308 cyl
!= bp
->b_cylinder
) {
1310 fdcstatus(fd
->sc_dev
, 2, "seek failed");
1315 fd
->sc_cylin
= bp
->b_cylinder
;
1320 isa_dmaabort(fdc
->sc_drq
);
1328 case IOCOMPLETE
: /* IO DONE, post-analyze */
1329 callout_stop(&fdc
->sc_timo_ch
);
1330 DPRINTF(("fdcintr: in IOCOMPLETE\n"));
1331 if ((tmp
= fdcresult(fdc
)) != 7 || (st0
& 0xf8) != 0) {
1333 isa_dmaabort(fdc
->sc_drq
);
1335 fdcstatus(fd
->sc_dev
, tmp
, bp
->b_flags
& B_READ
?
1336 "read failed" : "write failed");
1337 printf("blkno %" PRId64
" nblks %d\n",
1338 fd
->sc_blkno
, fd
->sc_nblks
);
1343 isa_dmadone(bp
->b_flags
& B_READ
, bp
->b_data
+ fd
->sc_skip
,
1344 nblks
* FDC_BSIZE
, fdc
->sc_drq
);
1347 if (fdc
->sc_errors
) {
1348 diskerr(bp
, "fd", "soft error (corrected)", LOG_PRINTF
,
1349 fd
->sc_skip
/ FDC_BSIZE
, (struct disklabel
*)NULL
);
1353 fd
->sc_blkno
+= fd
->sc_nblks
;
1354 fd
->sc_skip
+= fd
->sc_nbytes
;
1355 fd
->sc_bcount
-= fd
->sc_nbytes
;
1356 DPRINTF(("fd->sc_bcount = %d\n", fd
->sc_bcount
));
1357 if (fd
->sc_bcount
> 0) {
1358 bp
->b_cylinder
= fd
->sc_blkno
1359 / (fd
->sc_type
->seccyl
1360 * (1 << (fd
->sc_type
->secsize
- 2)));
1366 case COPYCOMPLETE
: /* IO DONE, post-analyze */
1367 DPRINTF(("fdcintr: COPYCOMPLETE:"));
1368 callout_stop(&fdc
->sc_timo_ch
);
1369 if ((tmp
= fdcresult(fdc
)) != 7 || (st0
& 0xf8) != 0) {
1370 printf("fdcintr: resnum=%d, st0=%x\n", tmp
, st0
);
1372 isa_dmaabort(fdc
->sc_drq
);
1374 fdcstatus(fd
->sc_dev
, 7, bp
->b_flags
& B_READ
?
1375 "read failed" : "write failed");
1376 printf("blkno %" PRId64
" nblks %d\n",
1377 fd
->sc_blkno
, fd
->sc_nblks
);
1384 DPRINTF(("fdcintr: in DORESET\n"));
1385 /* try a reset, keep motor on */
1386 fd_set_motor(fdc
, 1);
1388 fd_set_motor(fdc
, 0);
1389 fdc
->sc_state
= RESETCOMPLETE
;
1390 callout_reset(&fdc
->sc_timo_ch
, hz
/ 2, fdctimeout
, fdc
);
1391 return 1; /* will return later */
1394 DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
1395 callout_stop(&fdc
->sc_timo_ch
);
1396 /* clear the controller output buffer */
1397 for (i
= 0; i
< 4; i
++) {
1398 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1399 (void) fdcresult(fdc
);
1404 DPRINTF(("fdcintr: in DORECAL\n"));
1405 out_fdc(iot
, ioh
, NE7CMD_RECAL
); /* recalibrate function */
1406 out_fdc(iot
, ioh
, fd
->sc_drive
);
1407 fdc
->sc_state
= RECALWAIT
;
1408 callout_reset(&fdc
->sc_timo_ch
, 5 * hz
, fdctimeout
, fdc
);
1409 return 1; /* will return later */
1412 DPRINTF(("fdcintr: in RECALWAIT\n"));
1413 callout_stop(&fdc
->sc_timo_ch
);
1414 fdc
->sc_state
= RECALCOMPLETE
;
1415 /* allow 1/30 second for heads to settle */
1417 callout_reset(&fdc
->sc_intr_ch
, hz
/ 30, fdcpseudointr
, fdc
);
1419 return 1; /* will return later */
1422 DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
1423 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1424 tmp
= fdcresult(fdc
);
1425 if ((st0
& 0xf8) == 0xc0) {
1426 DPRINTF(("fdcintr: first seek!\n"));
1427 fdc
->sc_state
= DORECAL
;
1429 } else if (tmp
!= 2 || (st0
& 0xf8) != 0x20 || cyl
!= 0) {
1431 fdcstatus(fd
->sc_dev
, 2, "recalibrate failed");
1440 if (fd
->sc_flags
& FD_MOTOR_WAIT
)
1441 return 1; /* time's not up yet */
1445 fdcstatus(fd
->sc_dev
, 0, "stray interrupt");
1449 panic("fdcintr: impossible");
1456 fdcretry(struct fdc_softc
*fdc
)
1458 struct fd_softc
*fd
;
1461 DPRINTF(("fdcretry:\n"));
1462 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1463 bp
= bufq_peek(fd
->sc_q
);
1465 switch (fdc
->sc_errors
) {
1468 fdc
->sc_state
= SEEKCOMPLETE
;
1471 case 1: case 2: case 3:
1472 /* didn't work; try recalibrating */
1473 fdc
->sc_state
= DORECAL
;
1477 /* still no go; reset the bastard */
1478 fdc
->sc_state
= DORESET
;
1482 diskerr(bp
, "fd", "hard error", LOG_PRINTF
,
1483 fd
->sc_skip
, (struct disklabel
*)NULL
);
1493 fdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
1495 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
1496 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
1497 int part
= DISKPART(dev
);
1498 struct disklabel buffer
;
1501 DPRINTF(("fdioctl:"));
1504 DPRINTF(("DIOCGDINFO\n"));
1506 *(struct disklabel
*)addr
= *(fd
->sc_dk
.dk_label
);
1509 memset(&buffer
, 0, sizeof(buffer
));
1511 buffer
.d_secpercyl
= fd
->sc_type
->seccyl
;
1512 buffer
.d_type
= DTYPE_FLOPPY
;
1513 buffer
.d_secsize
= 128 << fd
->sc_type
->secsize
;
1515 if (readdisklabel(dev
, fdstrategy
, &buffer
, NULL
) != NULL
)
1518 *(struct disklabel
*)addr
= buffer
;
1523 DPRINTF(("DIOCGPART\n"));
1524 ((struct partinfo
*)addr
)->disklab
= fd
->sc_dk
.dk_label
;
1525 ((struct partinfo
*)addr
)->part
=
1526 &fd
->sc_dk
.dk_label
->d_partitions
[part
];
1530 DPRINTF(("DIOCWLABEL\n"));
1531 if ((flag
& FWRITE
) == 0)
1533 /* XXX do something */
1537 DPRINTF(("DIOCWDINFO\n"));
1538 if ((flag
& FWRITE
) == 0)
1541 error
= setdisklabel(&buffer
, (struct disklabel
*)addr
,
1546 error
= writedisklabel(dev
, fdstrategy
, &buffer
, NULL
);
1551 * Nothing to do here, really.
1556 DPRINTF(("DIOCEJECT\n"));
1557 if (*(int *)addr
== 0) {
1559 * Don't force eject: check that we are the only
1560 * partition open. If so, unlock it.
1562 if ((fd
->sc_dk
.dk_openmask
& ~(1 << part
)) != 0 ||
1563 fd
->sc_dk
.dk_bopenmask
+ fd
->sc_dk
.dk_copenmask
!=
1564 fd
->sc_dk
.dk_openmask
) {
1570 DPRINTF(("ODIOCEJECT\n"));
1571 fd_do_eject(fdc
, FDUNIT(dev
));
1579 panic("fdioctl: impossible");
1584 fd_do_eject(struct fdc_softc
*fdc
, int unit
)
1586 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
,
1587 0x20 | ( 1 << unit
));
1589 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
, 0x20);
1593 * Build disk label. For now we only create a label from what we know
1597 fdgetdisklabel(struct fd_softc
*sc
, dev_t dev
)
1599 struct disklabel
*lp
;
1602 DPRINTF(("fdgetdisklabel()\n"));
1604 part
= DISKPART(dev
);
1605 lp
= sc
->sc_dk
.dk_label
;
1606 memset(lp
, 0, sizeof(struct disklabel
));
1608 lp
->d_secsize
= 128 << sc
->sc_type
->secsize
;
1609 lp
->d_ntracks
= sc
->sc_type
->heads
;
1610 lp
->d_nsectors
= sc
->sc_type
->sectrac
;
1611 lp
->d_secpercyl
= lp
->d_ntracks
* lp
->d_nsectors
;
1612 lp
->d_ncylinders
= sc
->sc_type
->size
/ lp
->d_secpercyl
;
1613 lp
->d_secperunit
= sc
->sc_type
->size
;
1615 lp
->d_type
= DTYPE_FLOPPY
;
1616 lp
->d_rpm
= 300; /* XXX */
1617 lp
->d_interleave
= 1; /* FIXME: is this OK? */
1620 lp
->d_npartitions
= part
+ 1;
1621 #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */
1622 lp
->d_trkseek
= STEP_DELAY
; /* XXX */
1623 lp
->d_magic
= DISKMAGIC
;
1624 lp
->d_magic2
= DISKMAGIC
;
1625 lp
->d_checksum
= dkcksum(lp
);
1626 lp
->d_partitions
[part
].p_size
= lp
->d_secperunit
;
1627 lp
->d_partitions
[part
].p_fstype
= FS_UNUSED
;
1628 lp
->d_partitions
[part
].p_fsize
= 1024;
1629 lp
->d_partitions
[part
].p_frag
= 8;
1635 * Mountroot hook: prompt the user to enter the root file system
1639 fd_mountroot_hook(device_t dev
)
1641 struct fd_softc
*fd
= device_private(dev
);
1642 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
1645 /* XXX device_unit() abuse */
1646 fd_do_eject(fdc
, device_unit(dev
));
1647 printf("Insert filesystem floppy and press return.");
1650 if ((c
== '\r') || (c
== '\n')) {