1 /* $NetBSD: fd.c,v 1.45 2009/03/14 21:04:01 dsl 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.
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
64 * from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
68 * Floppy formatting facilities merged from FreeBSD fd.c driver:
69 * Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
70 * which carries the same copyright/redistribution notice as shown above with
71 * the addition of the following statement before the "Redistribution and
74 * Copyright (c) 1993, 1994 by
75 * jc@irbs.UUCP (John Capo)
76 * vak@zebub.msk.su (Serge Vakulenko)
77 * ache@astral.msk.su (Andrew A. Chernov)
79 * Copyright (c) 1993, 1994, 1995 by
80 * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
81 * dufault@hda.com (Peter Dufault)
84 #include <sys/cdefs.h>
85 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.45 2009/03/14 21:04:01 dsl Exp $");
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/callout.h>
92 #include <sys/kernel.h>
94 #include <sys/ioctl.h>
95 #include <sys/device.h>
96 #include <sys/disklabel.h>
100 #include <sys/malloc.h>
102 #include <sys/syslog.h>
103 #include <sys/queue.h>
104 #include <sys/proc.h>
105 #include <sys/fdio.h>
106 #include <sys/conf.h>
108 #include <uvm/uvm_extern.h>
112 #include <machine/cpu.h>
113 #include <machine/intr.h>
114 #include <machine/io.h>
115 #include <arm/arm32/katelib.h>
116 #include <machine/bus.h>
118 #include <arm/iomd/iomdreg.h>
119 #include <arm/iomd/iomdvar.h>
121 #include <acorn32/mainbus/piocvar.h>
122 #include <acorn32/mainbus/fdreg.h>
124 #include "locators.h"
126 #define NE7CMD_CONFIGURE 0x13
128 #define FDUNIT(dev) (minor(dev) / 8)
129 #define FDTYPE(dev) (minor(dev) % 8)
131 /* (mis)use device use flag to identify format operation */
132 #define B_FORMAT B_DEVPRIVATE
153 /* software state, per controller */
155 struct device sc_dev
; /* boilerplate */
158 bus_space_tag_t sc_iot
; /* ISA i/o space identifier */
159 bus_space_handle_t sc_ioh
; /* ISA io handle */
161 struct callout sc_timo_ch
; /* timeout callout */
162 struct callout sc_intr_ch
; /* pseudo-intr callout */
164 /* ...for pseudo-DMA... */
165 struct fiqhandler sc_fh
; /* FIQ handler descriptor */
166 struct fiqregs sc_fr
; /* FIQ handler reg context */
169 struct fd_softc
*sc_fd
[4]; /* pointers to children */
170 TAILQ_HEAD(drivehead
, fd_softc
) sc_drives
;
171 enum fdc_state sc_state
;
172 int sc_errors
; /* number of retries so far */
173 u_char sc_status
[7]; /* copy of registers */
176 /* controller driver configuration */
177 int fdcprobe(struct device
*, struct cfdata
*, void *);
178 int fdprint(void *, const char *);
179 void fdcattach(struct device
*, struct device
*, void *);
181 CFATTACH_DECL(fdc
, sizeof(struct fdc_softc
),
182 fdcprobe
, fdcattach
, NULL
, NULL
);
185 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
186 * we tell them apart.
189 int sectrac
; /* sectors per track */
190 int heads
; /* number of heads */
191 int seccyl
; /* sectors per cylinder */
192 int secsize
; /* size code for sectors */
193 int datalen
; /* data len when secsize = 0 */
194 int steprate
; /* step rate and head unload time */
195 int gap1
; /* gap len between sectors */
196 int gap2
; /* formatting gap */
197 int cyls
; /* total num of cylinders */
198 int size
; /* size of disk in sectors */
199 int step
; /* steps per cylinder */
200 int rate
; /* transfer speed code */
201 u_char fillbyte
; /* format fill byte */
202 u_char interleave
; /* interleave factor (formatting) */
206 /* The order of entries in the following table is important -- BEWARE! */
207 struct fd_type fd_types
[] = {
208 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS
,0xf6,1, "1.44MB" }, /* 1.44MB diskette */
209 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS
,0xf6,1, "1.2MB" }, /* 1.2 MB AT-diskettes */
210 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS
,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
211 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS
,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
212 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS
,0xf6,1, "720KB" }, /* 3.5" 720kB diskette */
213 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS
,0xf6,1, "720KB/x" }, /* 720kB in 1.2MB drive */
214 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS
,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
217 /* software state, per disk (with up to 4 disks per ctlr) */
219 struct device sc_dev
;
222 struct fd_type
*sc_deftype
; /* default type descriptor */
223 struct fd_type
*sc_type
; /* current type descriptor */
224 struct fd_type sc_type_copy
; /* copy for fiddling when formatting */
226 struct callout sc_motoron_ch
;
227 struct callout sc_motoroff_ch
;
229 daddr_t sc_blkno
; /* starting block number */
230 int sc_bcount
; /* byte count left */
231 int sc_opts
; /* user-set options */
232 int sc_skip
; /* bytes already transferred */
233 int sc_nblks
; /* number of blocks currently transferring */
234 int sc_nbytes
; /* number of bytes currently transferring */
236 int sc_drive
; /* physical unit number */
238 #define FD_OPEN 0x01 /* it's open */
239 #define FD_MOTOR 0x02 /* motor should be on */
240 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
241 int sc_cylin
; /* where we think the head is */
243 void *sc_sdhook
; /* saved shutdown hook for drive. */
245 TAILQ_ENTRY(fd_softc
) sc_drivechain
;
246 int sc_ops
; /* I/O ops since last switch */
247 struct bufq_state
*sc_q
;/* pending I/O requests */
248 int sc_active
; /* number of active I/O operations */
251 /* floppy driver configuration */
252 int fdprobe(struct device
*, struct cfdata
*, void *);
253 void fdattach(struct device
*, struct device
*, void *);
255 extern char floppy_read_fiq
[], floppy_read_fiq_end
[];
256 extern char floppy_write_fiq
[], floppy_write_fiq_end
[];
258 CFATTACH_DECL(fd
, sizeof(struct fd_softc
),
259 fdprobe
, fdattach
, NULL
, NULL
);
261 extern struct cfdriver fd_cd
;
263 dev_type_open(fdopen
);
264 dev_type_close(fdclose
);
265 dev_type_read(fdread
);
266 dev_type_write(fdwrite
);
267 dev_type_ioctl(fdioctl
);
268 dev_type_strategy(fdstrategy
);
270 const struct bdevsw fd_bdevsw
= {
271 fdopen
, fdclose
, fdstrategy
, fdioctl
, nodump
, nosize
, D_DISK
274 const struct cdevsw fd_cdevsw
= {
275 fdopen
, fdclose
, fdread
, fdwrite
, fdioctl
,
276 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
279 void fdgetdisklabel(struct fd_softc
*);
280 int fd_get_parms(struct fd_softc
*);
281 void fdstart(struct fd_softc
*);
283 struct dkdriver fddkdriver
= { fdstrategy
};
285 struct fd_type
*fd_nvtotype(const char *, int, int);
286 void fd_set_motor(struct fdc_softc
*fdc
, int reset
);
287 void fd_motor_off(void *arg
);
288 void fd_motor_on(void *arg
);
289 int fdcresult(struct fdc_softc
*fdc
);
290 int out_fdc(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_char x
);
291 void fdcstart(struct fdc_softc
*fdc
);
292 void fdcstatus(struct device
*dv
, int n
, const char *s
);
293 void fdctimeout(void *arg
);
294 void fdcpseudointr(void *arg
);
296 void fdcretry(struct fdc_softc
*fdc
);
297 void fdfinish(struct fd_softc
*fd
, struct buf
*bp
);
298 inline struct fd_type
*fd_dev_to_type(struct fd_softc
*, dev_t
);
299 int fdformat(dev_t
, struct ne7_fd_formb
*, struct lwp
*);
302 fdcprobe(struct device
*parent
, struct cfdata
*cf
, void *aux
)
304 struct pioc_attach_args
*pa
= aux
;
306 bus_space_handle_t ioh
;
309 if (pa
->pa_name
&& strcmp(pa
->pa_name
, "fdc") != 0)
315 /* Map the i/o space. */
316 if (bus_space_map(iot
, pa
->pa_iobase
+ pa
->pa_offset
, FDC_NPORT
, 0, &ioh
))
320 bus_space_write_2(iot
, ioh
, fdout
, 0);
322 bus_space_write_2(iot
, ioh
, fdout
, FDO_FRST
);
324 /* see if it can handle a command */
325 if (out_fdc(iot
, ioh
, NE7CMD_SPECIFY
) < 0)
327 out_fdc(iot
, ioh
, 0xdf);
328 out_fdc(iot
, ioh
, 2);
331 pa
->pa_iosize
= FDC_NPORT
;
334 bus_space_unmap(iot
, ioh
, FDC_NPORT
);
339 * Arguments passed between fdcattach and fdprobe.
341 struct fdc_attach_args
{
343 struct fd_type
*fa_deftype
;
347 * Print the location of a disk drive (called just before attaching the
348 * the drive). If `fdc' is not NULL, the drive was found but was not
349 * in the system config file; print the drive name as well.
350 * Return QUIET (config_find ignores this if the device was configured) to
351 * avoid printing `fdN not configured' messages.
354 fdprint(void *aux
, const char *fdc
)
356 register struct fdc_attach_args
*fa
= aux
;
359 aprint_normal(" drive %d", fa
->fa_drive
);
364 fdcattach(struct device
*parent
, struct device
*self
, void *aux
)
366 struct fdc_softc
*fdc
= (void *)self
;
368 bus_space_handle_t ioh
;
369 struct pioc_attach_args
*pa
= aux
;
370 struct fdc_attach_args fa
;
375 /* Re-map the I/O space. */
376 if (bus_space_map(iot
, pa
->pa_iobase
+ pa
->pa_offset
, FDC_NPORT
, 0, &ioh
))
377 panic("fdcattach: couldn't map I/O ports");
382 fdc
->sc_drq
= pa
->pa_iobase
+ pa
->pa_offset
+ pa
->pa_drq
;
383 fdc
->sc_state
= DEVIDLE
;
384 TAILQ_INIT(&fdc
->sc_drives
);
388 callout_init(&fdc
->sc_timo_ch
, 0);
389 callout_init(&fdc
->sc_intr_ch
, 0);
391 fdc
->sc_ih
= intr_claim(pa
->pa_irq
, IPL_BIO
, "fdc",
394 panic("%s: Cannot claim IRQ %d", self
->dv_xname
, pa
->pa_irq
);
398 * The NVRAM info only tells us about the first two disks on the
399 * `primary' floppy controller.
401 if (device_unit(&fdc
->sc_dev
) == 0)
402 type
= mc146818_read(NULL
, NVRAM_DISKETTE
); /* XXX softc */
406 type
= 0x10; /* XXX - hardcoded for 1 floppy */
408 /* physical limit: four drives per controller. */
409 for (fa
.fa_drive
= 0; fa
.fa_drive
< 4; fa
.fa_drive
++) {
410 if (type
>= 0 && fa
.fa_drive
< 2)
411 fa
.fa_deftype
= fd_nvtotype(device_xname(&fdc
->sc_dev
),
414 fa
.fa_deftype
= NULL
; /* unknown */
415 (void)config_found(self
, (void *)&fa
, fdprint
);
420 fdprobe(struct device
*parent
, struct cfdata
*cf
, void *aux
)
422 struct fdc_softc
*fdc
= (void *)parent
;
423 struct fdc_attach_args
*fa
= aux
;
424 int drive
= fa
->fa_drive
;
425 bus_space_tag_t iot
= fdc
->sc_iot
;
426 bus_space_handle_t ioh
= fdc
->sc_ioh
;
429 if (cf
->cf_loc
[FDCCF_DRIVE
] != FDCCF_DRIVE_DEFAULT
430 && cf
->cf_loc
[FDCCF_DRIVE
] != drive
)
434 * This is to work around some odd interactions between this driver
435 * and SMC Ethernet cards.
438 /* Don't need this for arm32 port but leave for the time being (it won't hurt) */
440 if (cf
->cf_loc
[FDCCF_DRIVE
] == FDCCF_DRIVE_DEFAULT
&& drive
>= 2)
443 /* select drive and turn on motor */
444 bus_space_write_2(iot
, ioh
, fdout
, drive
| FDO_FRST
| FDO_MOEN(drive
));
445 /* wait for motor to spin up */
447 out_fdc(iot
, ioh
, NE7CMD_RECAL
);
448 out_fdc(iot
, ioh
, drive
);
449 /* wait for recalibrate */
451 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
456 printf("fdprobe: status");
457 for (i
= 0; i
< n
; i
++)
458 printf(" %x", fdc
->sc_status
[i
]);
463 bus_space_write_1(iot
, ioh
, fdout
, FDO_FRST
);
465 if (n
!= 2 || (fdc
->sc_status
[0] & 0xf8) != 0x20)
472 * Controller is working, and drive responded. Attach it.
475 fdattach(struct device
*parent
, struct device
*self
, void *aux
)
477 struct fdc_softc
*fdc
= (void *)parent
;
478 struct fd_softc
*fd
= (void *)self
;
479 struct fdc_attach_args
*fa
= aux
;
480 struct fd_type
*type
= fa
->fa_deftype
;
481 int drive
= fa
->fa_drive
;
483 callout_init(&fd
->sc_motoron_ch
, 0);
484 callout_init(&fd
->sc_motoroff_ch
, 0);
486 /* XXX Allow `flags' to override device type? */
489 printf(": %s %d cyl, %d head, %d sec\n", type
->name
,
490 type
->cyls
, type
->heads
, type
->sectrac
);
492 printf(": density unknown\n");
494 bufq_alloc(&fd
->sc_q
, "disksort", BUFQ_SORT_CYLINDER
);
496 fd
->sc_drive
= drive
;
497 fd
->sc_deftype
= type
;
498 fdc
->sc_fd
[drive
] = fd
;
501 * Initialize and attach the disk structure.
503 disk_init(&fd
->sc_dk
, device_xname(&fd
->sc_dev
), &fddkdriver
);
504 disk_attach(&fd
->sc_dk
);
506 /* Needed to power off if the motor is on when we halt. */
511 * Translate nvram type into internal data structure. Return NULL for
512 * none/unknown/unusable.
515 fd_nvtotype(const char *fdc
, int nvraminfo
, int drive
)
519 type
= (drive
== 0 ? nvraminfo
: nvraminfo
<< 4) & 0xf0;
530 printf("%s: drive %d: unknown device type 0x%x\n",
536 inline struct fd_type
*
537 fd_dev_to_type(struct fd_softc
*fd
, dev_t dev
)
539 int type
= FDTYPE(dev
);
541 if (type
> (sizeof(fd_types
) / sizeof(fd_types
[0])))
543 return type
? &fd_types
[type
- 1] : fd
->sc_deftype
;
547 fdstrategy(struct buf
*bp
)
549 struct fd_softc
*fd
= device_lookup_private(&fd_cd
,FDUNIT(bp
->b_dev
));
553 /* Valid unit, controller, and request? */
554 if (bp
->b_blkno
< 0 ||
555 ((bp
->b_bcount
% FDC_BSIZE
) != 0 &&
556 (bp
->b_flags
& B_FORMAT
) == 0)) {
557 bp
->b_error
= EINVAL
;
561 /* If it's a null transfer, return immediately. */
562 if (bp
->b_bcount
== 0)
565 sz
= howmany(bp
->b_bcount
, FDC_BSIZE
);
567 if (bp
->b_blkno
+ sz
> fd
->sc_type
->size
) {
568 sz
= fd
->sc_type
->size
- bp
->b_blkno
;
570 /* If exactly at end of disk, return EOF. */
574 /* If past end of disk, return EINVAL. */
575 bp
->b_error
= EINVAL
;
578 /* Otherwise, truncate request. */
579 bp
->b_bcount
= sz
<< DEV_BSHIFT
;
582 bp
->b_rawblkno
= bp
->b_blkno
;
583 bp
->b_cylinder
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
) / fd
->sc_type
->seccyl
;
586 printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
587 bp
->b_blkno
, bp
->b_bcount
, fd
->sc_blkno
, bp
->b_cylinder
, sz
);
590 /* Queue transfer on drive, activate drive and controller if idle. */
592 bufq_put(fd
->sc_q
, bp
);
593 callout_stop(&fd
->sc_motoroff_ch
); /* a good idea */
594 if (fd
->sc_active
== 0)
598 struct fdc_softc
*fdc
= (void *) device_parent(&fd
->sc_dev
);
599 if (fdc
->sc_state
== DEVIDLE
) {
600 printf("fdstrategy: controller inactive\n");
609 /* Toss transfer; we're done early. */
610 bp
->b_resid
= bp
->b_bcount
;
615 fdstart(struct fd_softc
*fd
)
617 struct fdc_softc
*fdc
= (void *) device_parent(&fd
->sc_dev
);
618 int active
= fdc
->sc_drives
.tqh_first
!= 0;
620 /* Link into controller queue. */
622 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
624 /* If controller not already active, start it. */
630 fdfinish(struct fd_softc
*fd
, struct buf
*bp
)
632 struct fdc_softc
*fdc
= (void *) device_parent(&fd
->sc_dev
);
635 * Move this drive to the end of the queue to give others a `fair'
636 * chance. We only force a switch if N operations are completed while
637 * another drive is waiting to be serviced, since there is a long motor
638 * startup delay whenever we switch.
640 (void)bufq_get(fd
->sc_q
);
641 if (fd
->sc_drivechain
.tqe_next
&& ++fd
->sc_ops
>= 8) {
643 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
644 if (bufq_peek(fd
->sc_q
) != NULL
)
645 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
649 bp
->b_resid
= fd
->sc_bcount
;
653 /* turn off motor 5s from now */
654 callout_reset(&fd
->sc_motoroff_ch
, 5 * hz
, fd_motor_off
, fd
);
655 fdc
->sc_state
= DEVIDLE
;
659 fdread(dev_t dev
, struct uio
*uio
, int flags
)
662 return (physio(fdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
666 fdwrite(dev_t dev
, struct uio
*uio
, int flags
)
669 return (physio(fdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
673 fd_set_motor(struct fdc_softc
*fdc
, int reset
)
679 if ((fd
= fdc
->sc_drives
.tqh_first
) != NULL
)
680 status
= fd
->sc_drive
;
684 status
|= FDO_FRST
| FDO_FDMAEN
;
685 for (n
= 0; n
< 4; n
++)
686 if ((fd
= fdc
->sc_fd
[n
]) && (fd
->sc_flags
& FD_MOTOR
))
687 status
|= FDO_MOEN(n
);
688 bus_space_write_2(fdc
->sc_iot
, fdc
->sc_ioh
, fdout
, status
);
692 fd_motor_off(void *arg
)
694 struct fd_softc
*fd
= arg
;
698 fd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
699 fd_set_motor((struct fdc_softc
*) device_parent(&fd
->sc_dev
), 0);
704 fd_motor_on(void *arg
)
706 struct fd_softc
*fd
= arg
;
707 struct fdc_softc
*fdc
= (void *) device_parent(&fd
->sc_dev
);
711 fd
->sc_flags
&= ~FD_MOTOR_WAIT
;
712 if ((fdc
->sc_drives
.tqh_first
== fd
) && (fdc
->sc_state
== MOTORWAIT
))
718 fdcresult(struct fdc_softc
*fdc
)
720 bus_space_tag_t iot
= fdc
->sc_iot
;
721 bus_space_handle_t ioh
= fdc
->sc_ioh
;
727 i
= bus_space_read_1(iot
, ioh
, fdsts
) &
728 (NE7_DIO
| NE7_RQM
| NE7_CB
);
731 if (i
== (NE7_DIO
| NE7_RQM
| NE7_CB
)) {
732 if (n
>= sizeof(fdc
->sc_status
)) {
733 log(LOG_ERR
, "fdcresult: overrun\n");
736 fdc
->sc_status
[n
++] =
737 bus_space_read_1(iot
, ioh
, fddata
);
741 log(LOG_ERR
, "fdcresult: timeout\n");
746 out_fdc(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_char x
)
750 while ((bus_space_read_1(iot
, ioh
, fdsts
) & NE7_DIO
) && i
-- > 0);
753 while ((bus_space_read_1(iot
, ioh
, fdsts
) & NE7_RQM
) == 0 && i
-- > 0);
756 bus_space_write_2(iot
, ioh
, fddata
, x
);
761 fdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
764 struct fd_type
*type
;
766 fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
769 type
= fd_dev_to_type(fd
, dev
);
773 if ((fd
->sc_flags
& FD_OPEN
) != 0 &&
774 memcmp(fd
->sc_type
, type
, sizeof(*type
)))
777 fd
->sc_type_copy
= *type
;
778 fd
->sc_type
= &fd
->sc_type_copy
;
780 fd
->sc_flags
|= FD_OPEN
;
786 fdclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
788 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
790 fd
->sc_flags
&= ~FD_OPEN
;
791 fd
->sc_opts
&= ~(FDOPT_NORETRY
|FDOPT_SILENT
);
796 fdcstart(struct fdc_softc
*fdc
)
800 /* only got here if controller's drive queue was inactive; should
802 if (fdc
->sc_state
!= DEVIDLE
) {
803 printf("fdcstart: not idle\n");
811 fdcpstatus(int n
, struct fdc_softc
*fdc
)
820 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
821 printf(" (st0 %s cyl %d)\n", bits
, fdc
->sc_status
[1]);
824 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
825 printf(" (st0 %s", bits
);
826 snprintb(bits
, sizeof(bits
), NE7_ST1BITS
, fdc
->sc_status
[1]);
827 printf(" st1 %s", bits
);
828 snprintb(bits
, sizeof(bits
), NE7_ST2BITS
, fdc
->sc_status
[2]);
829 printf(" st2 %s", bits
);
830 printf(" cyl %d head %d sec %d)\n",
831 fdc
->sc_status
[3], fdc
->sc_status
[4], fdc
->sc_status
[5]);
835 printf("\nfdcstatus: weird size");
842 fdcstatus(struct device
*dv
, int n
, const char *s
)
844 struct fdc_softc
*fdc
= (void *) device_parent(dv
);
847 out_fdc(fdc
->sc_iot
, fdc
->sc_ioh
, NE7CMD_SENSEI
);
848 (void) fdcresult(fdc
);
852 printf("%s: %s", device_xname(dv
), s
);
857 fdctimeout(void *arg
)
859 struct fdc_softc
*fdc
= arg
;
860 struct fd_softc
*fd
= fdc
->sc_drives
.tqh_first
;
865 log(LOG_ERR
,"fdctimeout: state %d\n", fdc
->sc_state
);
867 fdcstatus(&fd
->sc_dev
, 0, "timeout");
869 if (bufq_peek(fd
->sc_q
) != NULL
)
872 fdc
->sc_state
= DEVIDLE
;
879 fdcpseudointr(void *arg
)
883 /* Just ensure it has the right spl. */
892 struct fdc_softc
*fdc
= arg
;
893 #define st0 fdc->sc_status[0]
894 #define cyl fdc->sc_status[1]
897 bus_space_tag_t iot
= fdc
->sc_iot
;
898 bus_space_handle_t ioh
= fdc
->sc_ioh
;
899 int read
, head
, sec
, i
, nblks
;
900 struct fd_type
*type
;
901 struct ne7_fd_formb
*finfo
= NULL
;
904 /* Is there a drive for the controller to do a transfer with? */
905 fd
= fdc
->sc_drives
.tqh_first
;
907 fdc
->sc_state
= DEVIDLE
;
911 /* Is there a transfer to this drive? If not, deactivate drive. */
912 bp
= bufq_peek(fd
->sc_q
);
915 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
920 if (bp
->b_flags
& B_FORMAT
)
921 finfo
= (struct ne7_fd_formb
*)bp
->b_data
;
923 switch (fdc
->sc_state
) {
927 fd
->sc_bcount
= bp
->b_bcount
;
928 fd
->sc_blkno
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
);
929 callout_stop(&fd
->sc_motoroff_ch
);
930 if ((fd
->sc_flags
& FD_MOTOR_WAIT
) != 0) {
931 fdc
->sc_state
= MOTORWAIT
;
934 if ((fd
->sc_flags
& FD_MOTOR
) == 0) {
935 /* Turn on the motor, being careful about pairing. */
936 struct fd_softc
*ofd
= fdc
->sc_fd
[fd
->sc_drive
^ 1];
937 if (ofd
&& ofd
->sc_flags
& FD_MOTOR
) {
938 callout_stop(&ofd
->sc_motoroff_ch
);
939 ofd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
941 fd
->sc_flags
|= FD_MOTOR
| FD_MOTOR_WAIT
;
942 fd_set_motor(fdc
, 0);
943 fdc
->sc_state
= MOTORWAIT
;
944 /* Allow .25s for motor to stabilize. */
945 callout_reset(&fd
->sc_motoron_ch
, hz
/ 4,
949 /* Make sure the right drive is selected. */
950 fd_set_motor(fdc
, 0);
955 if (fd
->sc_cylin
== bp
->b_cylinder
)
959 out_fdc(iot
, ioh
, NE7CMD_CONFIGURE
);/* configure command */
960 out_fdc(iot
, ioh
, 0);
961 out_fdc(iot
, ioh
, 0x18);
962 out_fdc(iot
, ioh
, 0);
964 out_fdc(iot
, ioh
, NE7CMD_SPECIFY
);/* specify command */
965 out_fdc(iot
, ioh
, fd
->sc_type
->steprate
);
966 out_fdc(iot
, ioh
, 6); /* XXX head load time == 6ms */
968 out_fdc(iot
, ioh
, NE7CMD_SEEK
); /* seek function */
969 out_fdc(iot
, ioh
, fd
->sc_drive
); /* drive number */
970 out_fdc(iot
, ioh
, bp
->b_cylinder
* fd
->sc_type
->step
);
973 fdc
->sc_state
= SEEKWAIT
;
975 iostat_seek(fd
->sc_dk
.dk_stats
);
976 disk_busy(&fd
->sc_dk
);
978 callout_reset(&fdc
->sc_timo_ch
, 4 * hz
, fdctimeout
, fdc
);
985 fd
->sc_skip
= (char *)&(finfo
->fd_formb_cylno(0)) -
987 sec
= fd
->sc_blkno
% type
->seccyl
;
988 nblks
= type
->seccyl
- sec
;
989 nblks
= min(nblks
, fd
->sc_bcount
/ FDC_BSIZE
);
990 nblks
= min(nblks
, FDC_MAXIOSIZE
/ FDC_BSIZE
);
991 fd
->sc_nblks
= nblks
;
992 fd
->sc_nbytes
= finfo
? bp
->b_bcount
: nblks
* FDC_BSIZE
;
993 head
= sec
/ type
->sectrac
;
994 sec
-= head
* type
->sectrac
;
997 block
= (fd
->sc_cylin
* type
->heads
+ head
) * type
->sectrac
+ sec
;
998 if (block
!= fd
->sc_blkno
) {
999 printf("fdcintr: block %" PRId64
1000 " != blkno %" PRId64
"\n",
1001 block
, fd
->sc_blkno
);
1007 read
= bp
->b_flags
& B_READ
;
1009 fdc
->sc_fh
.fh_func
= floppy_read_fiq
;
1010 fdc
->sc_fh
.fh_size
= floppy_read_fiq_end
-
1013 fdc
->sc_fh
.fh_func
= floppy_write_fiq
;
1014 fdc
->sc_fh
.fh_size
= floppy_read_fiq_end
-
1017 fdc
->sc_fh
.fh_flags
= 0;
1018 fdc
->sc_fh
.fh_regs
= &fdc
->sc_fr
;
1019 fdc
->sc_fr
.fr_r9
= IOMD_BASE
+ (IOMD_FIQRQ
<< 2);
1020 fdc
->sc_fr
.fr_r10
= fd
->sc_nbytes
;
1022 (u_int
)((uintptr_t)bp
->b_data
+ fd
->sc_skip
);
1023 fdc
->sc_fr
.fr_r12
= fdc
->sc_drq
;
1025 printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1026 fdc
->sc_fr
.fr_r9
, fdc
->sc_fr
.fh_r10
, fdc
->sc_fr
.fh_r11
,
1027 fdc
->sc_fr
.fh_r12
, (u_int
)bp
->b_data
, fd
->sc_skip
);
1029 if (fiq_claim(&fdc
->sc_fh
) == -1)
1030 panic("%s: Cannot claim FIQ vector", fdc
->sc_dev
.dv_xname
);
1031 IOMD_WRITE_BYTE(IOMD_FIQMSK
, 0x01);
1032 bus_space_write_2(iot
, ioh
, fdctl
, type
->rate
);
1034 printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1035 read
? "read" : "write", fd
->sc_drive
, fd
->sc_cylin
,
1040 if (out_fdc(iot
, ioh
, NE7CMD_FORMAT
) < 0) {
1045 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1046 out_fdc(iot
, ioh
, finfo
->fd_formb_secshift
);
1047 out_fdc(iot
, ioh
, finfo
->fd_formb_nsecs
);
1048 out_fdc(iot
, ioh
, finfo
->fd_formb_gaplen
);
1049 out_fdc(iot
, ioh
, finfo
->fd_formb_fillbyte
);
1052 out_fdc(iot
, ioh
, NE7CMD_READ
); /* READ */
1054 out_fdc(iot
, ioh
, NE7CMD_WRITE
); /* WRITE */
1055 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
1056 out_fdc(iot
, ioh
, fd
->sc_cylin
); /* track */
1057 out_fdc(iot
, ioh
, head
);
1058 out_fdc(iot
, ioh
, sec
+ 1); /* sector +1 */
1059 out_fdc(iot
, ioh
, type
->secsize
);/* sector size */
1060 out_fdc(iot
, ioh
, type
->sectrac
);/* sectors/track */
1061 out_fdc(iot
, ioh
, type
->gap1
); /* gap1 size */
1062 out_fdc(iot
, ioh
, type
->datalen
);/* data length */
1064 fdc
->sc_state
= IOCOMPLETE
;
1066 disk_busy(&fd
->sc_dk
);
1068 /* allow 2 seconds for operation */
1069 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
1070 return 1; /* will return later */
1073 callout_stop(&fdc
->sc_timo_ch
);
1074 fdc
->sc_state
= SEEKCOMPLETE
;
1075 /* allow 1/50 second for heads to settle */
1077 callout_reset(&fdc
->sc_intr_ch
, hz
/ 50, fdcpseudointr
, fdc
);
1082 /* no data on seek */
1083 disk_unbusy(&fd
->sc_dk
, 0, 0);
1085 /* Make sure seek really happened. */
1086 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1087 if (fdcresult(fdc
) != 2 || (st0
& 0xf8) != 0x20 ||
1088 cyl
!= bp
->b_cylinder
* fd
->sc_type
->step
) {
1090 fdcstatus(&fd
->sc_dev
, 2, "seek failed");
1095 fd
->sc_cylin
= bp
->b_cylinder
;
1099 fiq_release(&fdc
->sc_fh
);
1100 IOMD_WRITE_BYTE(IOMD_FIQMSK
, 0x00);
1107 case IOCOMPLETE
: /* IO DONE, post-analyze */
1108 callout_stop(&fdc
->sc_timo_ch
);
1110 disk_unbusy(&fd
->sc_dk
, (bp
->b_bcount
- bp
->b_resid
),
1111 (bp
->b_flags
& B_READ
));
1113 if (fdcresult(fdc
) != 7 || (st0
& 0xf8) != 0) {
1114 fiq_release(&fdc
->sc_fh
);
1115 IOMD_WRITE_BYTE(IOMD_FIQMSK
, 0x00);
1117 fdcstatus(&fd
->sc_dev
, 7, bp
->b_flags
& B_READ
?
1118 "read failed" : "write failed");
1119 printf("blkno %d nblks %d\n",
1120 fd
->sc_blkno
, fd
->sc_nblks
);
1125 fiq_release(&fdc
->sc_fh
);
1126 IOMD_WRITE_BYTE(IOMD_FIQMSK
, 0x00);
1127 if (fdc
->sc_errors
) {
1129 diskerr(bp
, "fd", "soft error (corrected)", LOG_PRINTF
,
1130 fd
->sc_skip
/ FDC_BSIZE
, (struct disklabel
*)NULL
);
1135 fd
->sc_blkno
+= fd
->sc_nblks
;
1136 fd
->sc_skip
+= fd
->sc_nbytes
;
1137 fd
->sc_bcount
-= fd
->sc_nbytes
;
1138 if (!finfo
&& fd
->sc_bcount
> 0) {
1139 bp
->b_cylinder
= fd
->sc_blkno
/ fd
->sc_type
->seccyl
;
1146 /* try a reset, keep motor on */
1147 fd_set_motor(fdc
, 1);
1149 fd_set_motor(fdc
, 0);
1150 fdc
->sc_state
= RESETCOMPLETE
;
1151 callout_reset(&fdc
->sc_timo_ch
, hz
/ 2, fdctimeout
, fdc
);
1152 return 1; /* will return later */
1155 callout_stop(&fdc
->sc_timo_ch
);
1156 /* clear the controller output buffer */
1157 for (i
= 0; i
< 4; i
++) {
1158 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1159 (void) fdcresult(fdc
);
1164 out_fdc(iot
, ioh
, NE7CMD_RECAL
); /* recalibrate function */
1165 out_fdc(iot
, ioh
, fd
->sc_drive
);
1166 fdc
->sc_state
= RECALWAIT
;
1167 callout_reset(&fdc
->sc_timo_ch
, 5 * hz
, fdctimeout
, fdc
);
1168 return 1; /* will return later */
1171 callout_stop(&fdc
->sc_timo_ch
);
1172 fdc
->sc_state
= RECALCOMPLETE
;
1173 /* allow 1/30 second for heads to settle */
1175 callout_reset(&fdc
->sc_intr_ch
, hz
/ 30, fdcpseudointr
, fdc
);
1177 return 1; /* will return later */
1180 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
1181 if (fdcresult(fdc
) != 2 || (st0
& 0xf8) != 0x20 || cyl
!= 0) {
1183 fdcstatus(&fd
->sc_dev
, 2, "recalibrate failed");
1192 if (fd
->sc_flags
& FD_MOTOR_WAIT
)
1193 return 1; /* time's not up yet */
1197 fdcstatus(&fd
->sc_dev
, 0, "stray interrupt");
1201 panic("fdcintr: impossible");
1208 fdcretry(struct fdc_softc
*fdc
)
1210 struct fd_softc
*fd
;
1213 fd
= fdc
->sc_drives
.tqh_first
;
1214 bp
= bufq_peek(fd
->sc_q
);
1216 if (fd
->sc_opts
& FDOPT_NORETRY
)
1218 switch (fdc
->sc_errors
) {
1221 fdc
->sc_state
= DOSEEK
;
1224 case 1: case 2: case 3:
1225 /* didn't work; try recalibrating */
1226 fdc
->sc_state
= DORECAL
;
1230 /* still no go; reset the bastard */
1231 fdc
->sc_state
= DORESET
;
1236 if ((fd
->sc_opts
& FDOPT_SILENT
) == 0) {
1237 diskerr(bp
, "fd", "hard error", LOG_PRINTF
,
1238 fd
->sc_skip
/ FDC_BSIZE
,
1239 (struct disklabel
*)NULL
);
1250 fdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
1252 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
1253 struct fdformat_parms
*form_parms
;
1254 struct fdformat_cmd
*form_cmd
;
1255 struct ne7_fd_formb
*fd_formb
;
1256 struct disklabel buffer
;
1258 unsigned int scratch
;
1259 int il
[FD_MAX_NSEC
+ 1];
1264 memset(&buffer
, 0, sizeof(buffer
));
1266 buffer
.d_secpercyl
= fd
->sc_type
->seccyl
;
1267 buffer
.d_type
= DTYPE_FLOPPY
;
1268 buffer
.d_secsize
= FDC_BSIZE
;
1270 if (readdisklabel(dev
, fdstrategy
, &buffer
, NULL
) != NULL
)
1273 *(struct disklabel
*)addr
= buffer
;
1277 if ((flag
& FWRITE
) == 0)
1279 /* XXX do something */
1283 if ((flag
& FWRITE
) == 0)
1286 error
= setdisklabel(&buffer
, (struct disklabel
*)addr
, 0, NULL
);
1290 error
= writedisklabel(dev
, fdstrategy
, &buffer
, NULL
);
1293 case FDIOCGETFORMAT
:
1294 form_parms
= (struct fdformat_parms
*)addr
;
1295 form_parms
->fdformat_version
= FDFORMAT_VERSION
;
1296 form_parms
->nbps
= 128 * (1 << fd
->sc_type
->secsize
);
1297 form_parms
->ncyl
= fd
->sc_type
->cyls
;
1298 form_parms
->nspt
= fd
->sc_type
->sectrac
;
1299 form_parms
->ntrk
= fd
->sc_type
->heads
;
1300 form_parms
->stepspercyl
= fd
->sc_type
->step
;
1301 form_parms
->gaplen
= fd
->sc_type
->gap2
;
1302 form_parms
->fillbyte
= fd
->sc_type
->fillbyte
;
1303 form_parms
->interleave
= fd
->sc_type
->interleave
;
1304 switch (fd
->sc_type
->rate
) {
1306 form_parms
->xfer_rate
= 500 * 1024;
1309 form_parms
->xfer_rate
= 300 * 1024;
1312 form_parms
->xfer_rate
= 250 * 1024;
1319 case FDIOCSETFORMAT
:
1320 if((flag
& FWRITE
) == 0)
1321 return EBADF
; /* must be opened for writing */
1322 form_parms
= (struct fdformat_parms
*)addr
;
1323 if (form_parms
->fdformat_version
!= FDFORMAT_VERSION
)
1324 return EINVAL
; /* wrong version of formatting prog */
1326 scratch
= form_parms
->nbps
>> 7;
1327 if ((form_parms
->nbps
& 0x7f) || ffs(scratch
) == 0 ||
1328 scratch
& ~(1 << (ffs(scratch
)-1)))
1329 /* not a power-of-two multiple of 128 */
1332 switch (form_parms
->xfer_rate
) {
1334 fd
->sc_type
->rate
= FDC_500KBPS
;
1337 fd
->sc_type
->rate
= FDC_300KBPS
;
1340 fd
->sc_type
->rate
= FDC_250KBPS
;
1346 if (form_parms
->nspt
> FD_MAX_NSEC
||
1347 form_parms
->fillbyte
> 0xff ||
1348 form_parms
->interleave
> 0xff)
1350 fd
->sc_type
->sectrac
= form_parms
->nspt
;
1351 if (form_parms
->ntrk
!= 2 && form_parms
->ntrk
!= 1)
1353 fd
->sc_type
->heads
= form_parms
->ntrk
;
1354 fd
->sc_type
->seccyl
= form_parms
->nspt
* form_parms
->ntrk
;
1355 fd
->sc_type
->secsize
= ffs(scratch
)-1;
1356 fd
->sc_type
->gap2
= form_parms
->gaplen
;
1357 fd
->sc_type
->cyls
= form_parms
->ncyl
;
1358 fd
->sc_type
->size
= fd
->sc_type
->seccyl
* form_parms
->ncyl
*
1359 form_parms
->nbps
/ DEV_BSIZE
;
1360 fd
->sc_type
->step
= form_parms
->stepspercyl
;
1361 fd
->sc_type
->fillbyte
= form_parms
->fillbyte
;
1362 fd
->sc_type
->interleave
= form_parms
->interleave
;
1365 case FDIOCFORMAT_TRACK
:
1366 if((flag
& FWRITE
) == 0)
1367 return EBADF
; /* must be opened for writing */
1368 form_cmd
= (struct fdformat_cmd
*)addr
;
1369 if (form_cmd
->formatcmd_version
!= FDFORMAT_VERSION
)
1370 return EINVAL
; /* wrong version of formatting prog */
1372 if (form_cmd
->head
>= fd
->sc_type
->heads
||
1373 form_cmd
->cylinder
>= fd
->sc_type
->cyls
) {
1377 fd_formb
= malloc(sizeof(struct ne7_fd_formb
),
1383 fd_formb
->head
= form_cmd
->head
;
1384 fd_formb
->cyl
= form_cmd
->cylinder
;
1385 fd_formb
->transfer_rate
= fd
->sc_type
->rate
;
1386 fd_formb
->fd_formb_secshift
= fd
->sc_type
->secsize
;
1387 fd_formb
->fd_formb_nsecs
= fd
->sc_type
->sectrac
;
1388 fd_formb
->fd_formb_gaplen
= fd
->sc_type
->gap2
;
1389 fd_formb
->fd_formb_fillbyte
= fd
->sc_type
->fillbyte
;
1391 memset(il
, 0, sizeof il
);
1392 for (j
= 0, i
= 1; i
<= fd_formb
->fd_formb_nsecs
; i
++) {
1393 while (il
[(j
%fd_formb
->fd_formb_nsecs
)+1])
1395 il
[(j
%fd_formb
->fd_formb_nsecs
)+1] = i
;
1396 j
+= fd
->sc_type
->interleave
;
1398 for (i
= 0; i
< fd_formb
->fd_formb_nsecs
; i
++) {
1399 fd_formb
->fd_formb_cylno(i
) = form_cmd
->cylinder
;
1400 fd_formb
->fd_formb_headno(i
) = form_cmd
->head
;
1401 fd_formb
->fd_formb_secno(i
) = il
[i
+1];
1402 fd_formb
->fd_formb_secsize(i
) = fd
->sc_type
->secsize
;
1405 error
= fdformat(dev
, fd_formb
, l
);
1406 free(fd_formb
, M_TEMP
);
1409 case FDIOCGETOPTS
: /* get drive options */
1410 *(int *)addr
= fd
->sc_opts
;
1413 case FDIOCSETOPTS
: /* set drive options */
1414 fd
->sc_opts
= *(int *)addr
;
1422 panic("fdioctl: impossible");
1427 fdformat(dev_t dev
, struct ne7_fd_formb
*finfo
, struct lwp
*l
)
1430 struct fd_softc
*fd
= device_lookup_private(&fd_cd
,FDUNIT(dev
));
1431 struct fd_type
*type
= fd
->sc_type
;
1434 /* set up a buffer header for fdstrategy() */
1435 bp
= getiobuf(NULL
, false);
1438 bp
->b_flags
= B_PHYS
| B_FORMAT
;
1439 bp
->b_cflags
|= BC_BUSY
;
1440 bp
->b_proc
= l
->l_proc
;
1444 * calculate a fake blkno, so fdstrategy() would initiate a
1445 * seek to the requested cylinder
1447 bp
->b_blkno
= (finfo
->cyl
* (type
->sectrac
* type
->heads
)
1448 + finfo
->head
* type
->sectrac
) * FDC_BSIZE
/ DEV_BSIZE
;
1450 bp
->b_bcount
= sizeof(struct fd_idfield_data
) * finfo
->fd_formb_nsecs
;
1451 bp
->b_data
= (void *)finfo
;
1454 printf("fdformat: blkno %llx count %lx\n",
1455 (unsigned long long)bp
->b_blkno
, bp
->b_bcount
);
1458 /* now do the format */
1461 /* ...and wait for it to complete */
1462 /* XXX very dodgy */
1463 mutex_enter(bp
->b_objlock
);
1464 while (!(bp
->b_oflags
& BO_DONE
)) {
1465 rv
= cv_timedwait(&bp
->b_done
, bp
->b_objlock
, 20 * hz
);
1466 if (rv
== EWOULDBLOCK
)
1469 mutex_exit(bp
->b_objlock
);
1471 if (rv
== EWOULDBLOCK
) {
1475 } else if (bp
->b_error
!= 0)
1486 int load_memory_disc_from_floppy(struct md_conf
*md
, dev_t dev
);
1489 load_memory_disc_from_floppy(struct md_conf
*md
, dev_t dev
)
1497 if (bdevsw_lookup(dev
) != &fd_bdevsw
)
1500 if (md
->md_type
== MD_UNCONFIGURED
|| md
->md_addr
== 0)
1503 type
= FDTYPE(dev
) - 1;
1504 if (type
< 0) type
= 0;
1505 floppysize
= fd_types
[type
].size
<< (fd_types
[type
].secsize
+ 7);
1507 if (md
->md_size
< floppysize
) {
1508 printf("Memory disc is not big enough for floppy image\n");
1512 /* We have the memory disk ! */
1514 printf("Loading memory disc : %4dK ", 0);
1516 /* obtain a buffer */
1518 bp
= geteblk(fd_types
[type
].sectrac
* DEV_BSIZE
);
1520 /* request no partition relocation by driver on I/O operations */
1526 if (fdopen(bp
->b_dev
, 0, 0, curlwp
) != 0) {
1528 printf("Cannot open floppy device\n");
1533 loop
< (floppysize
/ DEV_BSIZE
/ fd_types
[type
].sectrac
);
1535 printf("\x08\x08\x08\x08\x08\x08%4dK ",
1536 loop
* fd_types
[type
].sectrac
* DEV_BSIZE
/ 1024);
1537 bp
->b_blkno
= loop
* fd_types
[type
].sectrac
;
1538 bp
->b_bcount
= fd_types
[type
].sectrac
* DEV_BSIZE
;
1539 bp
->b_flags
|= B_READ
;
1545 panic("Cannot load floppy image");
1547 memcpy((char *)md
->md_addr
+ loop
* fd_types
[type
].sectrac
1548 * DEV_BSIZE
, (void *)bp
->b_data
,
1549 fd_types
[type
].sectrac
* DEV_BSIZE
);
1551 printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1552 loop
* fd_types
[type
].sectrac
* DEV_BSIZE
/ 1024);
1554 fdclose(bp
->b_dev
, 0, 0, curlwp
);