1 /* $NetBSD: fd.c,v 1.93 2009/06/05 21:52:31 haad Exp $ */
4 * Copyright (c) 1998, 2003, 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
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
67 * Floppy formatting facilities merged from FreeBSD fd.c driver:
68 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
69 * which carries the same copyright/redistribution notice as shown above with
70 * the addition of the following statement before the "Redistribution and
73 * Copyright (c) 1993, 1994 by
74 * jc@irbs.UUCP (John Capo)
75 * vak@zebub.msk.su (Serge Vakulenko)
76 * ache@astral.msk.su (Andrew A. Chernov)
78 * Copyright (c) 1993, 1994, 1995 by
79 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
80 * dufault@hda.com (Peter Dufault)
83 #include <sys/cdefs.h>
84 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.93 2009/06/05 21:52:31 haad Exp $");
90 * XXX This driver should be properly MI'd some day, but this allows us
91 * XXX to eliminate a lot of code duplication for now.
93 #if !defined(alpha) && !defined(algor) && !defined(atari) && \
94 !defined(bebox) && !defined(evbmips) && !defined(i386) && \
95 !defined(prep) && !defined(sandpoint) && !defined(x86_64) && \
97 #error platform not supported by this driver, yet
100 #include <sys/param.h>
101 #include <sys/systm.h>
102 #include <sys/callout.h>
103 #include <sys/kernel.h>
104 #include <sys/file.h>
105 #include <sys/ioctl.h>
106 #include <sys/device.h>
107 #include <sys/disklabel.h>
108 #include <sys/disk.h>
110 #include <sys/bufq.h>
111 #include <sys/malloc.h>
113 #include <sys/syslog.h>
114 #include <sys/queue.h>
115 #include <sys/proc.h>
116 #include <sys/fdio.h>
117 #include <sys/conf.h>
118 #include <sys/vnode.h>
123 #include <prop/proplib.h>
125 #include <uvm/uvm_extern.h>
127 #include <dev/cons.h>
132 #include "locators.h"
136 * On the atari, it is configured as fdcisa
138 #define FDCCF_DRIVE FDCISACF_DRIVE
139 #define FDCCF_DRIVE_DEFAULT FDCISACF_DRIVE_DEFAULT
141 #define fd_cd fdisa_cd
144 #include <sys/intr.h>
146 #include <dev/isa/isavar.h>
147 #include <dev/isa/isadmavar.h>
149 #include <dev/isa/fdreg.h>
150 #include <dev/isa/fdcvar.h>
152 #if defined(i386) || defined(x86_64)
154 #include <dev/ic/mc146818reg.h> /* for NVRAM access */
155 #include <i386/isa/nvram.h>
160 #include <machine/mca_machdep.h> /* for MCA_system */
164 #endif /* i386 || x86_64 */
166 #include <dev/isa/fdvar.h>
168 #define FDUNIT(dev) (minor(dev) / 8)
169 #define FDTYPE(dev) (minor(dev) % 8)
171 /* (mis)use device use flag to identify format operation */
172 #define B_FORMAT B_DEVPRIVATE
174 /* controller driver configuration */
175 int fdprint(void *, const char *);
178 /* MCA - specific entries */
179 const struct fd_type mca_fd_types
[] = {
180 { 18,2,36,2,0xff,0x0f,0x1b,0x6c,80,2880,1,FDC_500KBPS
,0xf6,1, "1.44MB" }, /* 1.44MB diskette - XXX try 16ms step rate */
181 { 9,2,18,2,0xff,0x4f,0x2a,0x50,80,1440,1,FDC_250KBPS
,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette - XXX try 24ms step rate */
183 #endif /* NMCA > 0 */
185 /* The order of entries in the following table is important -- BEWARE! */
188 const struct fd_type fd_types
[] = {
189 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS
,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
190 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS
,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette */
191 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS
,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
194 const struct fd_type fd_types
[] = {
195 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS
,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
196 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS
,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
197 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS
,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
198 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS
,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
199 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS
,0xf6,1, "720KB" }, /* 3.5 inch 720kB diskette */
200 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS
,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
201 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS
,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
203 #endif /* defined(atari) */
205 void fdcfinishattach(device_t
);
206 int fdprobe(device_t
, cfdata_t
, void *);
207 void fdattach(device_t
, device_t
, void *);
208 static int fddetach(device_t
, int);
209 static int fdcintr1(struct fdc_softc
*);
210 static void fdcintrcb(void *);
211 static bool fdcsuspend(device_t
, pmf_qual_t
);
212 static bool fdcresume(device_t
, pmf_qual_t
);
214 extern struct cfdriver fd_cd
;
217 CFATTACH_DECL_NEW(fdisa
, sizeof(struct fd_softc
),
218 fdprobe
, fdattach
, fddetach
, NULL
);
220 CFATTACH_DECL_NEW(fd
, sizeof(struct fd_softc
),
221 fdprobe
, fdattach
, fddetach
, NULL
);
224 dev_type_open(fdopen
);
225 dev_type_close(fdclose
);
226 dev_type_read(fdread
);
227 dev_type_write(fdwrite
);
228 dev_type_ioctl(fdioctl
);
229 dev_type_strategy(fdstrategy
);
231 const struct bdevsw fd_bdevsw
= {
232 fdopen
, fdclose
, fdstrategy
, fdioctl
, nodump
, nosize
, D_DISK
235 const struct cdevsw fd_cdevsw
= {
236 fdopen
, fdclose
, fdread
, fdwrite
, fdioctl
,
237 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
240 void fdgetdisklabel(struct fd_softc
*);
241 int fd_get_parms(struct fd_softc
*);
242 void fdstart(struct fd_softc
*);
244 struct dkdriver fddkdriver
= { fdstrategy
, NULL
};
246 #if defined(i386) || defined(x86_64)
247 const struct fd_type
*fd_nvtotype(const char *, int, int);
248 #endif /* i386 || x86_64 */
249 void fd_set_motor(struct fdc_softc
*fdc
, int reset
);
250 void fd_motor_off(void *arg
);
251 void fd_motor_on(void *arg
);
252 int fdcresult(struct fdc_softc
*fdc
);
253 void fdcstart(struct fdc_softc
*fdc
);
254 void fdcstatus(device_t
, int, const char *);
255 void fdctimeout(void *arg
);
256 void fdcretry(struct fdc_softc
*fdc
);
257 void fdfinish(struct fd_softc
*fd
, struct buf
*bp
);
258 static const struct fd_type
*fd_dev_to_type(struct fd_softc
*, dev_t
);
259 int fdformat(dev_t
, struct ne7_fd_formb
*, struct lwp
*);
260 static void fd_set_properties(struct fd_softc
*fd
);
262 void fd_mountroot_hook(device_t
);
265 * Arguments passed between fdcattach and fdprobe.
267 struct fdc_attach_args
{
269 const struct fd_type
*fa_deftype
;
273 * Print the location of a disk drive (called just before attaching the
274 * the drive). If `fdc' is not NULL, the drive was found but was not
275 * in the system config file; print the drive name as well.
276 * Return QUIET (config_find ignores this if the device was configured) to
277 * avoid printing `fdN not configured' messages.
280 fdprint(void *aux
, const char *fdc
)
282 struct fdc_attach_args
*fa
= aux
;
285 aprint_normal(" drive %d", fa
->fa_drive
);
290 fdcresume(device_t self
, pmf_qual_t qual
)
292 struct fdc_softc
*fdc
= device_private(self
);
294 mutex_enter(&fdc
->sc_mtx
);
296 mutex_exit(&fdc
->sc_mtx
);
301 fdcsuspend(device_t self
, pmf_qual_t qual
)
303 struct fdc_softc
*fdc
= device_private(self
);
307 mutex_enter(&fdc
->sc_mtx
);
308 while (fdc
->sc_state
!= DEVIDLE
)
309 cv_wait(&fdc
->sc_cv
, &fdc
->sc_mtx
);
310 for (drive
= 0; drive
< 4; drive
++) {
311 if ((fd
= fdc
->sc_fd
[drive
]) == NULL
)
313 fd
->sc_flags
&= ~(FD_MOTOR
|FD_MOTOR_WAIT
);
315 fd_set_motor(fdc
, 0);
316 mutex_exit(&fdc
->sc_mtx
);
321 fdc_childdet(device_t self
, device_t child
)
323 struct fdc_softc
*fdc
= device_private(self
);
324 struct fd_softc
*fd
= device_private(child
);
325 int drive
= fd
->sc_drive
;
327 KASSERT(fdc
->sc_fd
[drive
] == fd
); /* but the kid is not my son */
328 fdc
->sc_fd
[drive
] = NULL
;
332 fdcdetach(device_t self
, int flags
)
335 struct fdc_softc
*fdc
= device_private(self
);
337 if ((rc
= config_detach_children(self
, flags
)) != 0)
340 pmf_device_deregister(self
);
342 isa_dmamap_destroy(fdc
->sc_ic
, fdc
->sc_drq
);
343 isa_drq_free(fdc
->sc_ic
, fdc
->sc_drq
);
345 callout_destroy(&fdc
->sc_intr_ch
);
346 callout_destroy(&fdc
->sc_timo_ch
);
348 cv_destroy(&fdc
->sc_cv
);
349 mutex_destroy(&fdc
->sc_mtx
);
355 fdcattach(struct fdc_softc
*fdc
)
357 mutex_init(&fdc
->sc_mtx
, MUTEX_DEFAULT
, IPL_BIO
);
358 cv_init(&fdc
->sc_cv
, "fdcwakeup");
359 callout_init(&fdc
->sc_timo_ch
, 0);
360 callout_init(&fdc
->sc_intr_ch
, 0);
362 fdc
->sc_state
= DEVIDLE
;
363 TAILQ_INIT(&fdc
->sc_drives
);
365 fdc
->sc_maxiosize
= isa_dmamaxsize(fdc
->sc_ic
, fdc
->sc_drq
);
367 if (isa_drq_alloc(fdc
->sc_ic
, fdc
->sc_drq
) != 0) {
368 aprint_normal_dev(fdc
->sc_dev
, "can't reserve drq %d\n",
373 if (isa_dmamap_create(fdc
->sc_ic
, fdc
->sc_drq
, fdc
->sc_maxiosize
,
374 BUS_DMA_NOWAIT
|BUS_DMA_ALLOCNOW
)) {
375 aprint_normal_dev(fdc
->sc_dev
, "can't set up ISA DMA map\n");
379 config_interrupts(fdc
->sc_dev
, fdcfinishattach
);
381 if (!pmf_device_register(fdc
->sc_dev
, fdcsuspend
, fdcresume
)) {
382 aprint_error_dev(fdc
->sc_dev
,
383 "cannot set power mgmt handler\n");
388 fdcfinishattach(device_t self
)
390 struct fdc_softc
*fdc
= device_private(self
);
391 bus_space_tag_t iot
= fdc
->sc_iot
;
392 bus_space_handle_t ioh
= fdc
->sc_ioh
;
393 struct fdc_attach_args fa
;
396 * Reset the controller to get it into a known state. Not all
397 * probes necessarily need do this to discover the controller up
398 * front, so don't assume anything.
401 bus_space_write_1(iot
, ioh
, fdout
, 0);
403 bus_space_write_1(iot
, ioh
, fdout
, FDO_FRST
);
405 /* see if it can handle a command */
406 if (out_fdc(iot
, ioh
, NE7CMD_SPECIFY
) < 0) {
407 aprint_normal_dev(fdc
->sc_dev
, "can't reset controller\n");
410 out_fdc(iot
, ioh
, 0xdf);
411 out_fdc(iot
, ioh
, 2);
413 #if defined(i386) || defined(x86_64)
415 * The NVRAM info only tells us about the first two disks on the
416 * `primary' floppy controller.
418 /* XXX device_unit() abuse */
419 if (device_unit(fdc
->sc_dev
) == 0) {
420 int type
= mc146818_read(NULL
, NVRAM_DISKETTE
); /* XXX softc */
422 fdc
->sc_knownfds
[0] = fd_nvtotype(device_xname(fdc
->sc_dev
),
424 if (fdc
->sc_knownfds
[0] != NULL
)
425 fdc
->sc_present
|= 1;
426 fdc
->sc_knownfds
[1] = fd_nvtotype(device_xname(fdc
->sc_dev
),
428 if (fdc
->sc_knownfds
[1] != NULL
)
429 fdc
->sc_present
|= 2;
431 #endif /* i386 || x86_64 */
433 /* physical limit: four drives per controller. */
434 fdc
->sc_state
= PROBING
;
435 for (fa
.fa_drive
= 0; fa
.fa_drive
< 4; fa
.fa_drive
++) {
437 if (fdc
->sc_present
& (1 << fa
.fa_drive
)) {
438 fa
.fa_deftype
= fdc
->sc_knownfds
[fa
.fa_drive
];
439 config_found(fdc
->sc_dev
, (void *)&fa
,
445 * Atari has a different ordening, defaults to 1.44
447 fa
.fa_deftype
= &fd_types
[2];
450 * Default to 1.44MB on Alpha and BeBox. How do we tell
451 * on these platforms?
453 fa
.fa_deftype
= &fd_types
[0];
455 (void)config_found_ia(fdc
->sc_dev
, "fdc", (void *)&fa
, fdprint
);
458 fdc
->sc_state
= DEVIDLE
;
462 fdprobe(device_t parent
, cfdata_t match
, void *aux
)
464 struct fdc_softc
*fdc
= device_private(parent
);
466 struct fdc_attach_args
*fa
= aux
;
467 int drive
= fa
->fa_drive
;
468 bus_space_tag_t iot
= fdc
->sc_iot
;
469 bus_space_handle_t ioh
= fdc
->sc_ioh
;
472 if (cf
->cf_loc
[FDCCF_DRIVE
] != FDCCF_DRIVE_DEFAULT
&&
473 cf
->cf_loc
[FDCCF_DRIVE
] != drive
)
477 * This is to work around some odd interactions between this driver
478 * and SMC Ethernet cards.
480 if (cf
->cf_loc
[FDCCF_DRIVE
] == FDCCF_DRIVE_DEFAULT
&& drive
>= 2)
483 /* Use PNP information if available */
487 mutex_enter(&fdc
->sc_mtx
);
488 /* toss any interrupt status */
489 for (n
= 0; n
< 4; n
++) {
490 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
491 (void) fdcresult(fdc
);
493 /* select drive and turn on motor */
494 bus_space_write_1(iot
, ioh
, fdout
, drive
| FDO_FRST
| FDO_MOEN(drive
));
495 /* wait for motor to spin up */
496 /* XXX check sc_probe */
497 (void) cv_timedwait(&fdc
->sc_cv
, &fdc
->sc_mtx
, hz
/ 4);
498 out_fdc(iot
, ioh
, NE7CMD_RECAL
);
499 out_fdc(iot
, ioh
, drive
);
500 /* wait for recalibrate, up to 2s */
501 /* XXX check sc_probe */
502 if (cv_timedwait(&fdc
->sc_cv
, &fdc
->sc_mtx
, 2 * hz
) != EWOULDBLOCK
){
505 printf("fdprobe: got intr\n");
508 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
513 printf("fdprobe: status");
514 for (i
= 0; i
< n
; i
++)
515 printf(" %x", fdc
->sc_status
[i
]);
520 bus_space_write_1(iot
, ioh
, fdout
, FDO_FRST
);
521 mutex_exit(&fdc
->sc_mtx
);
523 #if defined(bebox) /* XXX What is this about? --thorpej@NetBSD.org */
524 if (n
!= 2 || (fdc
->sc_status
[1] != 0))
527 if (n
!= 2 || (fdc
->sc_status
[0] & 0xf8) != 0x20)
535 * Controller is working, and drive responded. Attach it.
538 fdattach(device_t parent
, device_t self
, void *aux
)
540 struct fdc_softc
*fdc
= device_private(parent
);
541 struct fd_softc
*fd
= device_private(self
);
542 struct fdc_attach_args
*fa
= aux
;
543 const struct fd_type
*type
= fa
->fa_deftype
;
544 int drive
= fa
->fa_drive
;
548 callout_init(&fd
->sc_motoron_ch
, 0);
549 callout_init(&fd
->sc_motoroff_ch
, 0);
551 /* XXX Allow `flags' to override device type? */
554 aprint_normal(": %s, %d cyl, %d head, %d sec\n", type
->name
,
555 type
->cyls
, type
->heads
, type
->sectrac
);
557 aprint_normal(": density unknown\n");
559 bufq_alloc(&fd
->sc_q
, "disksort", BUFQ_SORT_CYLINDER
);
561 fd
->sc_drive
= drive
;
562 fd
->sc_deftype
= type
;
563 fdc
->sc_fd
[drive
] = fd
;
566 * Initialize and attach the disk structure.
568 disk_init(&fd
->sc_dk
, device_xname(fd
->sc_dev
), &fddkdriver
);
569 disk_attach(&fd
->sc_dk
);
572 * Establish a mountroot hook.
575 mountroothook_establish(fd_mountroot_hook
, fd
->sc_dev
);
578 rnd_attach_source(&fd
->rnd_source
, device_xname(fd
->sc_dev
),
582 fd_set_properties(fd
);
584 if (!pmf_device_register(self
, NULL
, NULL
))
585 aprint_error_dev(self
, "cannot set power mgmt handler\n");
589 fddetach(device_t self
, int flags
)
591 struct fd_softc
*fd
= device_private(self
);
592 int bmaj
, cmaj
, i
, mn
;
596 /* locate the major number */
597 bmaj
= bdevsw_lookup_major(&fd_bdevsw
);
598 cmaj
= cdevsw_lookup_major(&fd_cdevsw
);
600 /* Nuke the vnodes for any open instances. */
601 for (i
= 0; i
< MAXPARTITIONS
; i
++) {
602 mn
= DISKMINOR(device_unit(self
), i
);
603 vdevgone(bmaj
, mn
, mn
, VBLK
);
604 vdevgone(cmaj
, mn
, mn
, VCHR
);
607 pmf_device_deregister(self
);
609 #if 0 /* XXX need to undo at detach? */
610 fd_set_properties(fd
);
613 rnd_detach_source(&fd
->rnd_source
);
616 disk_detach(&fd
->sc_dk
);
617 disk_destroy(&fd
->sc_dk
);
619 /* Kill off any queued buffers. */
620 bufq_drain(fd
->sc_q
);
624 callout_destroy(&fd
->sc_motoroff_ch
);
625 callout_destroy(&fd
->sc_motoron_ch
);
630 #if defined(i386) || defined(x86_64)
632 * Translate nvram type into internal data structure. Return NULL for
633 * none/unknown/unusable.
635 const struct fd_type
*
636 fd_nvtotype(const char *fdc
, int nvraminfo
, int drive
)
640 type
= (drive
== 0 ? nvraminfo
: nvraminfo
<< 4) & 0xf0;
642 case NVRAM_DISKETTE_NONE
:
644 case NVRAM_DISKETTE_12M
:
646 case NVRAM_DISKETTE_TYPE5
:
647 case NVRAM_DISKETTE_TYPE6
:
648 /* XXX We really ought to handle 2.88MB format. */
649 case NVRAM_DISKETTE_144M
:
652 return &mca_fd_types
[0];
654 #endif /* NMCA > 0 */
656 case NVRAM_DISKETTE_360K
:
658 case NVRAM_DISKETTE_720K
:
661 return &mca_fd_types
[1];
663 #endif /* NMCA > 0 */
666 printf("%s: drive %d: unknown device type 0x%x\n",
671 #endif /* i386 || x86_64 */
673 static const struct fd_type
*
674 fd_dev_to_type(struct fd_softc
*fd
, dev_t dev
)
676 u_int type
= FDTYPE(dev
);
678 if (type
> __arraycount(fd_types
))
680 return type
? &fd_types
[type
- 1] : fd
->sc_deftype
;
684 fdstrategy(struct buf
*bp
)
686 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(bp
->b_dev
));
687 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
690 /* Valid unit, controller, and request? */
691 if (bp
->b_blkno
< 0 ||
692 ((bp
->b_bcount
% FDC_BSIZE
) != 0 &&
693 (bp
->b_flags
& B_FORMAT
) == 0)) {
694 bp
->b_error
= EINVAL
;
698 /* If it's a null transfer, return immediately. */
699 if (bp
->b_bcount
== 0)
702 sz
= howmany(bp
->b_bcount
, FDC_BSIZE
);
704 if (bp
->b_blkno
+ sz
> fd
->sc_type
->size
) {
705 sz
= fd
->sc_type
->size
- bp
->b_blkno
;
707 /* If exactly at end of disk, return EOF. */
711 /* If past end of disk, return EINVAL. */
712 bp
->b_error
= EINVAL
;
715 /* Otherwise, truncate request. */
716 bp
->b_bcount
= sz
<< DEV_BSHIFT
;
719 bp
->b_rawblkno
= bp
->b_blkno
;
721 bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
) / fd
->sc_type
->seccyl
;
724 printf("fdstrategy: b_blkno %llu b_bcount %d blkno %llu cylin %d "
725 "sz %d\n", (unsigned long long)bp
->b_blkno
, bp
->b_bcount
,
726 (unsigned long long)fd
->sc_blkno
, bp
->b_cylinder
, sz
);
729 /* Queue transfer on drive, activate drive and controller if idle. */
730 mutex_enter(&fdc
->sc_mtx
);
731 bufq_put(fd
->sc_q
, bp
);
732 callout_stop(&fd
->sc_motoroff_ch
); /* a good idea */
733 if (fd
->sc_active
== 0)
737 if (fdc
->sc_state
== DEVIDLE
) {
738 printf("fdstrategy: controller inactive\n");
743 mutex_exit(&fdc
->sc_mtx
);
747 /* Toss transfer; we're done early. */
748 bp
->b_resid
= bp
->b_bcount
;
753 fdstart(struct fd_softc
*fd
)
755 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
756 int active
= !TAILQ_EMPTY(&fdc
->sc_drives
);
758 KASSERT(mutex_owned(&fdc
->sc_mtx
));
759 /* Link into controller queue. */
761 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
763 /* If controller not already active, start it. */
769 fdfinish(struct fd_softc
*fd
, struct buf
*bp
)
771 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
774 * Move this drive to the end of the queue to give others a `fair'
775 * chance. We only force a switch if N operations are completed while
776 * another drive is waiting to be serviced, since there is a long motor
777 * startup delay whenever we switch.
779 (void)bufq_get(fd
->sc_q
);
780 if (TAILQ_NEXT(fd
, sc_drivechain
) && ++fd
->sc_ops
>= 8) {
782 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
783 if (bufq_peek(fd
->sc_q
) != NULL
)
784 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
788 bp
->b_resid
= fd
->sc_bcount
;
792 rnd_add_uint32(&fd
->rnd_source
, bp
->b_blkno
);
796 /* turn off motor 5s from now */
797 callout_reset(&fd
->sc_motoroff_ch
, 5 * hz
, fd_motor_off
, fd
);
798 fdc
->sc_state
= DEVIDLE
;
802 fdread(dev_t dev
, struct uio
*uio
, int flags
)
805 return (physio(fdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
809 fdwrite(dev_t dev
, struct uio
*uio
, int flags
)
812 return (physio(fdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
816 fd_set_motor(struct fdc_softc
*fdc
, int reset
)
822 if ((fd
= TAILQ_FIRST(&fdc
->sc_drives
)) != NULL
)
823 status
= fd
->sc_drive
;
827 status
|= FDO_FRST
| FDO_FDMAEN
;
828 for (n
= 0; n
< 4; n
++)
829 if ((fd
= fdc
->sc_fd
[n
]) && (fd
->sc_flags
& FD_MOTOR
))
830 status
|= FDO_MOEN(n
);
831 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
, status
);
835 fd_motor_off(void *arg
)
837 struct fd_softc
*fd
= arg
;
838 struct fdc_softc
*fdc
;
840 fdc
= device_private(device_parent(fd
->sc_dev
));
842 mutex_enter(&fdc
->sc_mtx
);
843 fd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
844 fd_set_motor(fdc
, 0);
845 mutex_exit(&fdc
->sc_mtx
);
849 fd_motor_on(void *arg
)
851 struct fd_softc
*fd
= arg
;
852 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
854 mutex_enter(&fdc
->sc_mtx
);
855 fd
->sc_flags
&= ~FD_MOTOR_WAIT
;
856 if (TAILQ_FIRST(&fdc
->sc_drives
) == fd
&& fdc
->sc_state
== MOTORWAIT
)
858 mutex_exit(&fdc
->sc_mtx
);
862 fdcresult(struct fdc_softc
*fdc
)
864 bus_space_tag_t iot
= fdc
->sc_iot
;
865 bus_space_handle_t ioh
= fdc
->sc_ioh
;
871 i
= bus_space_read_1(iot
, ioh
, fdsts
) &
872 (NE7_DIO
| NE7_RQM
| NE7_CB
);
875 if (i
== (NE7_DIO
| NE7_RQM
| NE7_CB
)) {
876 if (n
>= sizeof(fdc
->sc_status
)) {
877 log(LOG_ERR
, "fdcresult: overrun\n");
880 fdc
->sc_status
[n
++] =
881 bus_space_read_1(iot
, ioh
, fddata
);
885 log(LOG_ERR
, "fdcresult: timeout\n");
890 out_fdc(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_char x
)
896 i
= bus_space_read_1(iot
, ioh
, fdsts
) &
899 bus_space_write_1(iot
, ioh
, fddata
, x
);
908 fdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
911 const struct fd_type
*type
;
913 fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
917 type
= fd_dev_to_type(fd
, dev
);
921 if ((fd
->sc_flags
& FD_OPEN
) != 0 &&
922 memcmp(fd
->sc_type
, type
, sizeof(*type
)))
925 fd
->sc_type_copy
= *type
;
926 fd
->sc_type
= &fd
->sc_type_copy
;
928 fd
->sc_flags
|= FD_OPEN
;
930 fd_set_properties(fd
);
936 fdclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
938 struct fd_softc
*fd
=
939 device_lookup_private(&fd_cd
, FDUNIT(dev
));
941 fd
->sc_flags
&= ~FD_OPEN
;
942 fd
->sc_opts
&= ~(FDOPT_NORETRY
|FDOPT_SILENT
);
947 fdcstart(struct fdc_softc
*fdc
)
950 KASSERT(mutex_owned(&fdc
->sc_mtx
));
952 if (!device_is_active(fdc
->sc_dev
))
956 /* only got here if controller's drive queue was inactive; should
958 if (fdc
->sc_state
!= DEVIDLE
) {
959 printf("fdcstart: not idle\n");
967 fdcpstatus(int n
, struct fdc_softc
*fdc
)
976 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
977 printf(" (st0 %s cyl %d)\n", bits
, fdc
->sc_status
[1]);
980 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
981 printf(" (st0 %s", bits
);
982 snprintb(bits
, sizeof(bits
), NE7_ST1BITS
, fdc
->sc_status
[1]);
983 printf(" st1 %s", bits
);
984 snprintb(bits
, sizeof(bits
), NE7_ST2BITS
, fdc
->sc_status
[2]);
985 printf(" st2 %s", bits
);
986 printf(" cyl %d head %d sec %d)\n",
987 fdc
->sc_status
[3], fdc
->sc_status
[4], fdc
->sc_status
[5]);
991 printf("\nfdcstatus: weird size");
998 fdcstatus(device_t dv
, int n
, const char *s
)
1000 struct fdc_softc
*fdc
= device_private(device_parent(dv
));
1003 out_fdc(fdc
->sc_iot
, fdc
->sc_ioh
, NE7CMD_SENSEI
);
1004 (void) fdcresult(fdc
);
1009 aprint_normal_dev(dv
, "%s", s
);
1014 fdctimeout(void *arg
)
1016 struct fdc_softc
*fdc
= arg
;
1017 struct fd_softc
*fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1019 mutex_enter(&fdc
->sc_mtx
);
1021 log(LOG_ERR
, "fdctimeout: state %d\n", fdc
->sc_state
);
1023 fdcstatus(fd
->sc_dev
, 0, "timeout");
1025 if (bufq_peek(fd
->sc_q
) != NULL
)
1028 fdc
->sc_state
= DEVIDLE
;
1030 (void)fdcintr1(fdc
);
1031 mutex_exit(&fdc
->sc_mtx
);
1035 fdcintr1(struct fdc_softc
*fdc
)
1037 #define st0 fdc->sc_status[0]
1038 #define cyl fdc->sc_status[1]
1039 struct fd_softc
*fd
;
1041 bus_space_tag_t iot
= fdc
->sc_iot
;
1042 bus_space_handle_t ioh
= fdc
->sc_ioh
;
1043 int read
, head
, sec
, i
, nblks
;
1044 struct fd_type
*type
;
1045 struct ne7_fd_formb
*finfo
= NULL
;
1047 KASSERT(mutex_owned(&fdc
->sc_mtx
));
1048 if (fdc
->sc_state
== PROBING
) {
1050 printf("fdcintr: got probe interrupt\n");
1057 /* Is there a drive for the controller to do a transfer with? */
1058 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1060 fdc
->sc_state
= DEVIDLE
;
1064 /* Is there a transfer to this drive? If not, deactivate drive. */
1065 bp
= bufq_peek(fd
->sc_q
);
1068 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
1073 if (bp
->b_flags
& B_FORMAT
)
1074 finfo
= (struct ne7_fd_formb
*)bp
->b_data
;
1076 switch (fdc
->sc_state
) {
1080 fd
->sc_bcount
= bp
->b_bcount
;
1081 fd
->sc_blkno
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
);
1082 callout_stop(&fd
->sc_motoroff_ch
);
1083 if ((fd
->sc_flags
& FD_MOTOR_WAIT
) != 0) {
1084 fdc
->sc_state
= MOTORWAIT
;
1087 if ((fd
->sc_flags
& FD_MOTOR
) == 0) {
1088 /* Turn on the motor, being careful about pairing. */
1089 struct fd_softc
*ofd
= fdc
->sc_fd
[fd
->sc_drive
^ 1];
1090 if (ofd
&& ofd
->sc_flags
& FD_MOTOR
) {
1091 callout_stop(&ofd
->sc_motoroff_ch
);
1092 ofd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
1094 fd
->sc_flags
|= FD_MOTOR
| FD_MOTOR_WAIT
;
1095 fd_set_motor(fdc
, 0);
1096 fdc
->sc_state
= MOTORWAIT
;
1097 /* Allow .25s for motor to stabilize. */
1098 callout_reset(&fd
->sc_motoron_ch
, hz
/ 4,
1102 /* Make sure the right drive is selected. */
1103 fd_set_motor(fdc
, 0);
1108 if (fd
->sc_cylin
== bp
->b_cylinder
)
1111 out_fdc(iot
, ioh
, NE7CMD_SPECIFY
);/* specify command */
1112 out_fdc(iot
, ioh
, fd
->sc_type
->steprate
);
1113 out_fdc(iot
, ioh
, 6); /* XXX head load time == 6ms */
1115 out_fdc(iot
, ioh
, NE7CMD_SEEK
); /* seek function */
1116 out_fdc(iot
, ioh
, fd
->sc_drive
); /* drive number */
1117 out_fdc(iot
, ioh
, bp
->b_cylinder
* fd
->sc_type
->step
);
1120 fdc
->sc_state
= SEEKWAIT
;
1122 iostat_seek(fd
->sc_dk
.dk_stats
);
1123 disk_busy(&fd
->sc_dk
);
1125 callout_reset(&fdc
->sc_timo_ch
, 4 * hz
, fdctimeout
, fdc
);
1132 fd
->sc_skip
= (char *)&(finfo
->fd_formb_cylno(0)) -
1134 sec
= fd
->sc_blkno
% type
->seccyl
;
1135 nblks
= type
->seccyl
- sec
;
1136 nblks
= min(nblks
, fd
->sc_bcount
/ FDC_BSIZE
);
1137 nblks
= min(nblks
, fdc
->sc_maxiosize
/ FDC_BSIZE
);
1138 fd
->sc_nblks
= nblks
;
1139 fd
->sc_nbytes
= finfo
? bp
->b_bcount
: nblks
* FDC_BSIZE
;
1140 head
= sec
/ type
->sectrac
;
1141 sec
-= head
* type
->sectrac
;
1145 block
= (fd
->sc_cylin
* type
->heads
+ head
)
1146 * type
->sectrac
+ sec
;
1147 if (block
!= fd
->sc_blkno
) {
1148 printf("fdcintr: block %d != blkno "
1149 "%" PRId64
"\n", block
, fd
->sc_blkno
);
1156 read
= bp
->b_flags
& B_READ
? DMAMODE_READ
: DMAMODE_WRITE
;
1157 isa_dmastart(fdc
->sc_ic
, fdc
->sc_drq
,
1158 (char *)bp
->b_data
+ fd
->sc_skip
, fd
->sc_nbytes
,
1159 NULL
, read
| DMAMODE_DEMAND
, BUS_DMA_NOWAIT
);
1160 bus_space_write_1(iot
, fdc
->sc_fdctlioh
, 0, type
->rate
);
1162 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1163 read
? "read" : "write", fd
->sc_drive
, fd
->sc_cylin
,
1168 if (out_fdc(iot
, ioh
, NE7CMD_FORMAT
) < 0) {
1173 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1174 out_fdc(iot
, ioh
, finfo
->fd_formb_secshift
);
1175 out_fdc(iot
, ioh
, finfo
->fd_formb_nsecs
);
1176 out_fdc(iot
, ioh
, finfo
->fd_formb_gaplen
);
1177 out_fdc(iot
, ioh
, finfo
->fd_formb_fillbyte
);
1180 out_fdc(iot
, ioh
, NE7CMD_READ
); /* READ */
1182 out_fdc(iot
, ioh
, NE7CMD_WRITE
); /* WRITE */
1183 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1184 out_fdc(iot
, ioh
, fd
->sc_cylin
); /* track */
1185 out_fdc(iot
, ioh
, head
);
1186 out_fdc(iot
, ioh
, sec
+ 1); /* sector +1 */
1187 out_fdc(iot
, ioh
, type
->secsize
);/* sector size */
1188 out_fdc(iot
, ioh
, type
->sectrac
);/* sectors/track */
1189 out_fdc(iot
, ioh
, type
->gap1
); /* gap1 size */
1190 out_fdc(iot
, ioh
, type
->datalen
);/* data length */
1192 fdc
->sc_state
= IOCOMPLETE
;
1194 disk_busy(&fd
->sc_dk
);
1196 /* allow 2 seconds for operation */
1197 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
1198 return 1; /* will return later */
1201 callout_stop(&fdc
->sc_timo_ch
);
1202 fdc
->sc_state
= SEEKCOMPLETE
;
1203 /* allow 1/50 second for heads to settle */
1204 callout_reset(&fdc
->sc_intr_ch
, hz
/ 50, fdcintrcb
, fdc
);
1208 /* no data on seek */
1209 disk_unbusy(&fd
->sc_dk
, 0, 0);
1211 /* Make sure seek really happened. */
1212 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1213 if (fdcresult(fdc
) != 2 || (st0
& 0xf8) != 0x20 ||
1214 cyl
!= bp
->b_cylinder
* fd
->sc_type
->step
) {
1216 fdcstatus(fd
->sc_dev
, 2, "seek failed");
1221 fd
->sc_cylin
= bp
->b_cylinder
;
1225 isa_dmaabort(fdc
->sc_ic
, fdc
->sc_drq
);
1232 case IOCOMPLETE
: /* IO DONE, post-analyze */
1233 callout_stop(&fdc
->sc_timo_ch
);
1235 disk_unbusy(&fd
->sc_dk
, (bp
->b_bcount
- bp
->b_resid
),
1236 (bp
->b_flags
& B_READ
));
1238 if (fdcresult(fdc
) != 7 || (st0
& 0xf8) != 0) {
1239 isa_dmaabort(fdc
->sc_ic
, fdc
->sc_drq
);
1241 fdcstatus(fd
->sc_dev
, 7, bp
->b_flags
& B_READ
?
1242 "read failed" : "write failed");
1243 printf("blkno %llu nblks %d\n",
1244 (unsigned long long)fd
->sc_blkno
, fd
->sc_nblks
);
1249 isa_dmadone(fdc
->sc_ic
, fdc
->sc_drq
);
1250 if (fdc
->sc_errors
) {
1251 diskerr(bp
, "fd", "soft error (corrected)", LOG_PRINTF
,
1252 fd
->sc_skip
/ FDC_BSIZE
, NULL
);
1256 fd
->sc_blkno
+= fd
->sc_nblks
;
1257 fd
->sc_skip
+= fd
->sc_nbytes
;
1258 fd
->sc_bcount
-= fd
->sc_nbytes
;
1259 if (!finfo
&& fd
->sc_bcount
> 0) {
1260 bp
->b_cylinder
= fd
->sc_blkno
/ fd
->sc_type
->seccyl
;
1267 /* try a reset, keep motor on */
1268 fd_set_motor(fdc
, 1);
1270 fd_set_motor(fdc
, 0);
1271 fdc
->sc_state
= RESETCOMPLETE
;
1272 callout_reset(&fdc
->sc_timo_ch
, hz
/ 2, fdctimeout
, fdc
);
1273 return 1; /* will return later */
1276 callout_stop(&fdc
->sc_timo_ch
);
1277 /* clear the controller output buffer */
1278 for (i
= 0; i
< 4; i
++) {
1279 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1280 (void) fdcresult(fdc
);
1285 out_fdc(iot
, ioh
, NE7CMD_RECAL
); /* recalibrate function */
1286 out_fdc(iot
, ioh
, fd
->sc_drive
);
1287 fdc
->sc_state
= RECALWAIT
;
1288 callout_reset(&fdc
->sc_timo_ch
, 5 * hz
, fdctimeout
, fdc
);
1289 return 1; /* will return later */
1292 callout_stop(&fdc
->sc_timo_ch
);
1293 fdc
->sc_state
= RECALCOMPLETE
;
1294 /* allow 1/30 second for heads to settle */
1295 callout_reset(&fdc
->sc_intr_ch
, hz
/ 30, fdcintrcb
, fdc
);
1296 return 1; /* will return later */
1299 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1300 if (fdcresult(fdc
) != 2 || (st0
& 0xf8) != 0x20 || cyl
!= 0) {
1302 fdcstatus(fd
->sc_dev
, 2, "recalibrate failed");
1311 if (fd
->sc_flags
& FD_MOTOR_WAIT
)
1312 return 1; /* time's not up yet */
1316 fdcstatus(fd
->sc_dev
, 0, "stray interrupt");
1323 cv_signal(&fdc
->sc_cv
);
1328 fdcintrcb(void *arg
)
1337 struct fdc_softc
*fdc
= arg
;
1339 mutex_enter(&fdc
->sc_mtx
);
1341 mutex_exit(&fdc
->sc_mtx
);
1346 fdcretry(struct fdc_softc
*fdc
)
1348 struct fd_softc
*fd
;
1351 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1352 bp
= bufq_peek(fd
->sc_q
);
1354 if (fd
->sc_opts
& FDOPT_NORETRY
)
1356 switch (fdc
->sc_errors
) {
1359 fdc
->sc_state
= DOSEEK
;
1362 case 1: case 2: case 3:
1363 /* didn't work; try recalibrating */
1364 fdc
->sc_state
= DORECAL
;
1368 /* still no go; reset the bastard */
1369 fdc
->sc_state
= DORESET
;
1374 if ((fd
->sc_opts
& FDOPT_SILENT
) == 0) {
1375 diskerr(bp
, "fd", "hard error", LOG_PRINTF
,
1376 fd
->sc_skip
/ FDC_BSIZE
, NULL
);
1387 fdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
1389 struct fd_softc
*fd
=
1390 device_lookup_private(&fd_cd
, FDUNIT(dev
));
1391 struct fdformat_parms
*form_parms
;
1392 struct fdformat_cmd
*form_cmd
;
1393 struct ne7_fd_formb
*fd_formb
;
1394 struct disklabel buffer
;
1396 unsigned int scratch
;
1397 int il
[FD_MAX_NSEC
+ 1];
1399 #ifdef __HAVE_OLD_DISKLABEL
1400 struct disklabel newlabel
;
1403 error
= disk_ioctl(&fd
->sc_dk
, cmd
, addr
, flag
, l
);
1404 if (error
!= EPASSTHROUGH
)
1409 #ifdef __HAVE_OLD_DISKLABEL
1412 memset(&buffer
, 0, sizeof(buffer
));
1414 buffer
.d_type
= DTYPE_FLOPPY
;
1415 buffer
.d_secsize
= FDC_BSIZE
;
1416 buffer
.d_nsectors
= fd
->sc_type
->sectrac
;
1417 buffer
.d_ntracks
= fd
->sc_type
->heads
;
1418 buffer
.d_ncylinders
= fd
->sc_type
->cyls
;
1419 buffer
.d_secpercyl
= fd
->sc_type
->seccyl
;
1420 buffer
.d_secperunit
= fd
->sc_type
->size
;
1422 if (readdisklabel(dev
, fdstrategy
, &buffer
, NULL
) != NULL
)
1425 #ifdef __HAVE_OLD_DISKLABEL
1426 if (cmd
== ODIOCGDINFO
) {
1427 if (buffer
.d_npartitions
> OLDMAXPARTITIONS
)
1429 memcpy(addr
, &buffer
, sizeof (struct olddisklabel
));
1432 *(struct disklabel
*)addr
= buffer
;
1436 if ((flag
& FWRITE
) == 0)
1438 /* XXX do something */
1442 #ifdef __HAVE_OLD_DISKLABEL
1446 struct disklabel
*lp
;
1448 if ((flag
& FWRITE
) == 0)
1450 #ifdef __HAVE_OLD_DISKLABEL
1451 if (cmd
== ODIOCWDINFO
) {
1452 memset(&newlabel
, 0, sizeof newlabel
);
1453 memcpy(&newlabel
, addr
, sizeof (struct olddisklabel
));
1457 lp
= (struct disklabel
*)addr
;
1459 error
= setdisklabel(&buffer
, lp
, 0, NULL
);
1463 error
= writedisklabel(dev
, fdstrategy
, &buffer
, NULL
);
1467 case FDIOCGETFORMAT
:
1468 form_parms
= (struct fdformat_parms
*)addr
;
1469 form_parms
->fdformat_version
= FDFORMAT_VERSION
;
1470 form_parms
->nbps
= 128 * (1 << fd
->sc_type
->secsize
);
1471 form_parms
->ncyl
= fd
->sc_type
->cyls
;
1472 form_parms
->nspt
= fd
->sc_type
->sectrac
;
1473 form_parms
->ntrk
= fd
->sc_type
->heads
;
1474 form_parms
->stepspercyl
= fd
->sc_type
->step
;
1475 form_parms
->gaplen
= fd
->sc_type
->gap2
;
1476 form_parms
->fillbyte
= fd
->sc_type
->fillbyte
;
1477 form_parms
->interleave
= fd
->sc_type
->interleave
;
1478 switch (fd
->sc_type
->rate
) {
1480 form_parms
->xfer_rate
= 500 * 1024;
1483 form_parms
->xfer_rate
= 300 * 1024;
1486 form_parms
->xfer_rate
= 250 * 1024;
1493 case FDIOCSETFORMAT
:
1494 if((flag
& FWRITE
) == 0)
1495 return EBADF
; /* must be opened for writing */
1496 form_parms
= (struct fdformat_parms
*)addr
;
1497 if (form_parms
->fdformat_version
!= FDFORMAT_VERSION
)
1498 return EINVAL
; /* wrong version of formatting prog */
1500 scratch
= form_parms
->nbps
>> 7;
1501 if ((form_parms
->nbps
& 0x7f) || ffs(scratch
) == 0 ||
1502 scratch
& ~(1 << (ffs(scratch
)-1)))
1503 /* not a power-of-two multiple of 128 */
1506 switch (form_parms
->xfer_rate
) {
1508 fd
->sc_type
->rate
= FDC_500KBPS
;
1511 fd
->sc_type
->rate
= FDC_300KBPS
;
1514 fd
->sc_type
->rate
= FDC_250KBPS
;
1520 if (form_parms
->nspt
> FD_MAX_NSEC
||
1521 form_parms
->fillbyte
> 0xff ||
1522 form_parms
->interleave
> 0xff)
1524 fd
->sc_type
->sectrac
= form_parms
->nspt
;
1525 if (form_parms
->ntrk
!= 2 && form_parms
->ntrk
!= 1)
1527 fd
->sc_type
->heads
= form_parms
->ntrk
;
1528 fd
->sc_type
->seccyl
= form_parms
->nspt
* form_parms
->ntrk
;
1529 fd
->sc_type
->secsize
= ffs(scratch
)-1;
1530 fd
->sc_type
->gap2
= form_parms
->gaplen
;
1531 fd
->sc_type
->cyls
= form_parms
->ncyl
;
1532 fd
->sc_type
->size
= fd
->sc_type
->seccyl
* form_parms
->ncyl
*
1533 form_parms
->nbps
/ DEV_BSIZE
;
1534 fd
->sc_type
->step
= form_parms
->stepspercyl
;
1535 fd
->sc_type
->fillbyte
= form_parms
->fillbyte
;
1536 fd
->sc_type
->interleave
= form_parms
->interleave
;
1539 case FDIOCFORMAT_TRACK
:
1540 if((flag
& FWRITE
) == 0)
1541 return EBADF
; /* must be opened for writing */
1542 form_cmd
= (struct fdformat_cmd
*)addr
;
1543 if (form_cmd
->formatcmd_version
!= FDFORMAT_VERSION
)
1544 return EINVAL
; /* wrong version of formatting prog */
1546 if (form_cmd
->head
>= fd
->sc_type
->heads
||
1547 form_cmd
->cylinder
>= fd
->sc_type
->cyls
) {
1551 fd_formb
= malloc(sizeof(struct ne7_fd_formb
),
1556 fd_formb
->head
= form_cmd
->head
;
1557 fd_formb
->cyl
= form_cmd
->cylinder
;
1558 fd_formb
->transfer_rate
= fd
->sc_type
->rate
;
1559 fd_formb
->fd_formb_secshift
= fd
->sc_type
->secsize
;
1560 fd_formb
->fd_formb_nsecs
= fd
->sc_type
->sectrac
;
1561 fd_formb
->fd_formb_gaplen
= fd
->sc_type
->gap2
;
1562 fd_formb
->fd_formb_fillbyte
= fd
->sc_type
->fillbyte
;
1564 memset(il
, 0, sizeof il
);
1565 for (j
= 0, i
= 1; i
<= fd_formb
->fd_formb_nsecs
; i
++) {
1566 while (il
[(j
%fd_formb
->fd_formb_nsecs
)+1])
1568 il
[(j
%fd_formb
->fd_formb_nsecs
)+1] = i
;
1569 j
+= fd
->sc_type
->interleave
;
1571 for (i
= 0; i
< fd_formb
->fd_formb_nsecs
; i
++) {
1572 fd_formb
->fd_formb_cylno(i
) = form_cmd
->cylinder
;
1573 fd_formb
->fd_formb_headno(i
) = form_cmd
->head
;
1574 fd_formb
->fd_formb_secno(i
) = il
[i
+1];
1575 fd_formb
->fd_formb_secsize(i
) = fd
->sc_type
->secsize
;
1578 error
= fdformat(dev
, fd_formb
, l
);
1579 free(fd_formb
, M_TEMP
);
1582 case FDIOCGETOPTS
: /* get drive options */
1583 *(int *)addr
= fd
->sc_opts
;
1586 case FDIOCSETOPTS
: /* set drive options */
1587 fd
->sc_opts
= *(int *)addr
;
1595 panic("fdioctl: impossible");
1600 fdformat(dev_t dev
, struct ne7_fd_formb
*finfo
, struct lwp
*l
)
1603 struct fd_softc
*fd
=
1604 device_lookup_private(&fd_cd
, FDUNIT(dev
));
1605 struct fd_type
*type
= fd
->sc_type
;
1608 /* set up a buffer header for fdstrategy() */
1609 bp
= getiobuf(NULL
, false);
1613 bp
->b_cflags
= BC_BUSY
;
1614 bp
->b_flags
= B_PHYS
| B_FORMAT
;
1615 bp
->b_proc
= l
->l_proc
;
1619 * calculate a fake blkno, so fdstrategy() would initiate a
1620 * seek to the requested cylinder
1622 bp
->b_blkno
= (finfo
->cyl
* (type
->sectrac
* type
->heads
)
1623 + finfo
->head
* type
->sectrac
) * FDC_BSIZE
/ DEV_BSIZE
;
1625 bp
->b_bcount
= sizeof(struct fd_idfield_data
) * finfo
->fd_formb_nsecs
;
1626 bp
->b_data
= (void *)finfo
;
1629 printf("fdformat: blkno %" PRIx64
" count %x\n",
1630 bp
->b_blkno
, bp
->b_bcount
);
1633 /* now do the format */
1636 /* ...and wait for it to complete */
1643 * Mountroot hook: prompt the user to enter the root file system
1647 fd_mountroot_hook(device_t dev
)
1651 printf("Insert filesystem floppy and press return.");
1655 if ((c
== '\r') || (c
== '\n')) {
1664 fd_set_properties(struct fd_softc
*fd
)
1666 prop_dictionary_t disk_info
, odisk_info
, geom
;
1667 const struct fd_type
*fdt
;
1672 fdt
= fd
->sc_deftype
;
1677 disk_info
= prop_dictionary_create();
1679 geom
= prop_dictionary_create();
1681 prop_dictionary_set_uint64(geom
, "sectors-per-unit",
1684 switch (fdt
->secsize
) {
1695 prop_dictionary_set_uint32(geom
, "sector-size",
1698 prop_dictionary_set_uint16(geom
, "sectors-per-track",
1701 prop_dictionary_set_uint16(geom
, "tracks-per-cylinder",
1704 prop_dictionary_set_uint64(geom
, "cylinders-per-unit",
1707 prop_dictionary_set(disk_info
, "geometry", geom
);
1708 prop_object_release(geom
);
1710 prop_dictionary_set(device_properties(fd
->sc_dev
),
1711 "disk-info", disk_info
);
1714 * Don't release disk_info here; we keep a reference to it.
1715 * disk_detach() will release it when we go away.
1718 odisk_info
= fd
->sc_dk
.dk_info
;
1719 fd
->sc_dk
.dk_info
= disk_info
;
1721 prop_object_release(odisk_info
);