1 /* $NetBSD: fd.c,v 1.39 2009/01/13 13:35:51 yamt Exp $ */
2 /* $OpenBSD: fd.c,v 1.6 1998/10/03 21:18:57 millert Exp $ */
3 /* NetBSD: fd.c,v 1.78 1995/07/04 07:23:09 mycroft Exp */
6 * Copyright (c) 1998 The NetBSD Foundation, Inc.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Charles M. Hannum.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
35 * Copyright (c) 1990 The Regents of the University of California.
36 * All rights reserved.
38 * This code is derived from software contributed to Berkeley by
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * @(#)fd.c 7.4 (Berkeley) 5/25/91
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.39 2009/01/13 13:35:51 yamt Exp $");
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/callout.h>
74 #include <sys/kernel.h>
77 #include <sys/ioctl.h>
78 #include <sys/device.h>
79 #include <sys/disklabel.h>
84 #include <sys/syslog.h>
85 #include <sys/queue.h>
87 #include <uvm/uvm_extern.h>
91 #include <machine/bus.h>
92 #include <machine/cpu.h>
94 #include <arc/jazz/fdreg.h>
95 #include <arc/jazz/fdcvar.h>
100 #define FDUNIT(dev) DISKUNIT(dev)
101 #define FDTYPE(dev) DISKPART(dev)
103 /* controller driver configuration */
104 static int fdprint(void *, const char *);
107 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
108 * we tell them apart.
111 int sectrac
; /* sectors per track */
112 int heads
; /* number of heads */
113 int seccyl
; /* sectors per cylinder */
114 int secsize
; /* size code for sectors */
115 int datalen
; /* data len when secsize = 0 */
116 int steprate
; /* step rate and head unload time */
117 int gap1
; /* gap len between sectors */
118 int gap2
; /* formatting gap */
119 int cyls
; /* total num of cylinders */
120 int size
; /* size of disk in sectors */
121 int step
; /* steps per cylinder */
122 int rate
; /* transfer speed code */
126 /* The order of entries in the following table is important -- BEWARE! */
127 const static struct fd_type fd_types
[] = {
128 /* 1.44MB diskette */
129 { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS
,"1.44MB" },
130 /* 1.2 MB AT-diskettes */
131 { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS
, "1.2MB" },
132 /* 360kB in 1.2MB drive */
133 { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS
, "360KB/AT" },
134 /* 360kB PC diskettes */
135 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS
, "360KB/PC" },
136 /* 3.5" 720kB diskette */
137 { 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS
, "720KB" },
138 /* 720kB in 1.2MB drive */
139 { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS
, "720KB/x" },
140 /* 360kB in 720kB drive */
141 { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS
, "360KB/x" },
144 /* software state, per disk (with up to 4 disks per ctlr) */
149 const struct fd_type
*sc_deftype
; /* default type descriptor */
150 struct fd_type
*sc_type
; /* current type descriptor */
151 struct fd_type sc_type_copy
; /* copy for fiddling when formatting */
153 struct callout sc_motoron_ch
;
154 struct callout sc_motoroff_ch
;
156 daddr_t sc_blkno
; /* starting block number */
157 int sc_bcount
; /* byte count left */
158 int sc_opts
; /* user-set options */
159 int sc_skip
; /* bytes already transferred */
160 int sc_nblks
; /* number of blocks currently transferring */
161 int sc_nbytes
; /* number of bytes currently transferring */
163 int sc_drive
; /* physical unit number */
165 #define FD_OPEN 0x01 /* it's open */
166 #define FD_MOTOR 0x02 /* motor should be on */
167 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
168 int sc_cylin
; /* where we think the head is */
170 TAILQ_ENTRY(fd_softc
) sc_drivechain
;
171 int sc_ops
; /* I/O ops since last switch */
172 struct bufq_state
*sc_q
;/* pending I/O requests */
173 int sc_active
; /* number of active I/O operations */
176 /* floppy driver configuration */
177 static int fdprobe(device_t
, cfdata_t
, void *);
178 static void fdattach(device_t
, device_t
, void *);
180 CFATTACH_DECL_NEW(fd
, sizeof(struct fd_softc
), fdprobe
, fdattach
, NULL
, NULL
);
182 dev_type_open(fdopen
);
183 dev_type_close(fdclose
);
184 dev_type_read(fdread
);
185 dev_type_write(fdwrite
);
186 dev_type_ioctl(fdioctl
);
187 dev_type_strategy(fdstrategy
);
189 const struct bdevsw fd_bdevsw
= {
190 fdopen
, fdclose
, fdstrategy
, fdioctl
, nodump
, nosize
, D_DISK
193 const struct cdevsw fd_cdevsw
= {
194 fdopen
, fdclose
, fdread
, fdwrite
, fdioctl
,
195 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
198 static void fdstart(struct fd_softc
*);
200 struct dkdriver fddkdriver
= { fdstrategy
};
202 static bool fd_shutdown(device_t
, int);
204 static const struct fd_type
*fd_nvtotype(char *, int, int);
206 static void fd_set_motor(struct fdc_softc
*, int);
207 static void fd_motor_off(void *);
208 static void fd_motor_on(void *);
209 static int fdcresult(struct fdc_softc
*);
210 static void fdcstart(struct fdc_softc
*);
211 static void fdcstatus(device_t
, int, const char *);
212 static void fdctimeout(void *);
213 static void fdcpseudointr(void *);
214 static void fdcretry(struct fdc_softc
*);
215 static void fdfinish(struct fd_softc
*, struct buf
*);
216 static inline const struct fd_type
*fd_dev_to_type(struct fd_softc
*, dev_t
);
217 static void fd_mountroot_hook(device_t
);
220 * Arguments passed between fdcattach and fdprobe.
222 struct fdc_attach_args
{
224 const struct fd_type
*fa_deftype
;
228 * Print the location of a disk drive (called just before attaching the
229 * the drive). If `fdc' is not NULL, the drive was found but was not
230 * in the system config file; print the drive name as well.
231 * Return QUIET (config_find ignores this if the device was configured) to
232 * avoid printing `fdN not configured' messages.
235 fdprint(void *aux
, const char *fdc
)
237 struct fdc_attach_args
*fa
= aux
;
240 aprint_normal(" drive %d", fa
->fa_drive
);
245 fdcattach(struct fdc_softc
*fdc
)
247 struct fdc_attach_args fa
;
249 bus_space_handle_t ioh
;
254 callout_init(&fdc
->sc_timo_ch
, 0);
255 callout_init(&fdc
->sc_intr_ch
, 0);
257 fdc
->sc_state
= DEVIDLE
;
258 TAILQ_INIT(&fdc
->sc_drives
);
261 * No way yet to determine default disk types.
262 * we assume 1.44 3.5" type for the moment.
266 /* physical limit: two drives per controller. */
267 for (fa
.fa_drive
= 0; fa
.fa_drive
< 2; fa
.fa_drive
++) {
268 fa
.fa_deftype
= &fd_types
[type
];
269 (void)config_found(fdc
->sc_dev
, (void *)&fa
, fdprint
);
274 fdprobe(device_t parent
, cfdata_t cf
, void *aux
)
276 struct fdc_softc
*fdc
= device_private(parent
);
277 struct fdc_attach_args
*fa
= aux
;
278 int drive
= fa
->fa_drive
;
279 bus_space_tag_t iot
= fdc
->sc_iot
;
280 bus_space_handle_t ioh
= fdc
->sc_ioh
;
283 if (cf
->cf_loc
[FDCCF_DRIVE
] != FDCCF_DRIVE_DEFAULT
&&
284 cf
->cf_loc
[FDCCF_DRIVE
] != drive
)
287 /* select drive and turn on motor */
288 bus_space_write_1(iot
, ioh
, FDOUT
, drive
| FDO_FRST
| FDO_MOEN(drive
));
289 /* wait for motor to spin up */
291 out_fdc(iot
, ioh
, NE7CMD_RECAL
);
292 out_fdc(iot
, ioh
, drive
);
293 /* wait for recalibrate */
295 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
300 aprint_debug("%s: status", __func__
);
301 for (i
= 0; i
< n
; i
++)
302 aprint_debug(" %x", fdc
->sc_status
[i
]);
306 if (n
!= 2 || (fdc
->sc_status
[0] & 0xf8) != 0x20)
309 bus_space_write_1(iot
, ioh
, FDOUT
, FDO_FRST
);
315 * Controller is working, and drive responded. Attach it.
318 fdattach(device_t parent
, device_t self
, void *aux
)
320 struct fdc_softc
*fdc
= device_private(parent
);
321 struct fd_softc
*fd
= device_private(self
);
322 struct fdc_attach_args
*fa
= aux
;
323 const struct fd_type
*type
= fa
->fa_deftype
;
324 int drive
= fa
->fa_drive
;
328 callout_init(&fd
->sc_motoron_ch
, 0);
329 callout_init(&fd
->sc_motoroff_ch
, 0);
331 /* XXX Allow `flags' to override device type? */
334 printf(": %s, %d cyl, %d head, %d sec\n", type
->name
,
335 type
->cyls
, type
->heads
, type
->sectrac
);
337 printf(": density unknown\n");
339 bufq_alloc(&fd
->sc_q
, "disksort", BUFQ_SORT_CYLINDER
);
341 fd
->sc_drive
= drive
;
342 fd
->sc_deftype
= type
;
343 fdc
->sc_fd
[drive
] = fd
;
346 * Initialize and attach the disk structure.
348 disk_init(&fd
->sc_dk
, device_xname(fd
->sc_dev
), &fddkdriver
);
349 disk_attach(&fd
->sc_dk
);
351 /* Establish a mountroot hook. */
352 mountroothook_establish(fd_mountroot_hook
, fd
->sc_dev
);
354 /* Needed to power off if the motor is on when we halt. */
355 if (!pmf_device_register1(self
, NULL
, NULL
, fd_shutdown
))
356 aprint_error_dev(self
, "couldn't establish power handler\n");
360 fd_shutdown(device_t self
, int howto
)
364 fd
= device_private(self
);
372 * Translate nvram type into internal data structure. Return NULL for
373 * none/unknown/unusable.
375 static const struct fd_type
*
376 fd_nvtotype(char *fdc
, int nvraminfo
, int drive
)
380 type
= (drive
== 0 ? nvraminfo
: nvraminfo
<< 4) & 0xf0;
383 case NVRAM_DISKETTE_NONE
:
385 case NVRAM_DISKETTE_12M
:
387 case NVRAM_DISKETTE_TYPE5
:
388 case NVRAM_DISKETTE_TYPE6
:
389 /* XXX We really ought to handle 2.88MB format. */
390 case NVRAM_DISKETTE_144M
:
392 case NVRAM_DISKETTE_360K
:
394 case NVRAM_DISKETTE_720K
:
397 printf("%s: drive %d: unknown device type 0x%x\n",
402 return &fd_types
[0]; /* Use only 1.44 for now */
407 static inline const struct fd_type
*
408 fd_dev_to_type(struct fd_softc
*fd
, dev_t dev
)
410 int type
= FDTYPE(dev
);
412 if (type
> __arraycount(fd_types
))
414 return type
? &fd_types
[type
- 1] : fd
->sc_deftype
;
418 fdstrategy(struct buf
*bp
)
420 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(bp
->b_dev
));
424 /* Valid unit, controller, and request? */
425 if (bp
->b_blkno
< 0 ||
426 (bp
->b_bcount
% FDC_BSIZE
) != 0) {
427 bp
->b_error
= EINVAL
;
431 /* If it's a null transfer, return immediately. */
432 if (bp
->b_bcount
== 0)
435 sz
= howmany(bp
->b_bcount
, FDC_BSIZE
);
437 if (bp
->b_blkno
+ sz
> fd
->sc_type
->size
) {
438 sz
= fd
->sc_type
->size
- bp
->b_blkno
;
440 /* If exactly at end of disk, return EOF. */
444 /* If past end of disk, return EINVAL. */
445 bp
->b_error
= EINVAL
;
448 /* Otherwise, truncate request. */
449 bp
->b_bcount
= sz
<< DEV_BSHIFT
;
452 bp
->b_rawblkno
= bp
->b_blkno
;
454 bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
) / fd
->sc_type
->seccyl
;
457 printf("%s: b_blkno %" PRId64
" b_bcount %ld blkno %" PRId64
458 " cylin %ld sz %d\n", __func__
,
459 bp
->b_blkno
, bp
->b_bcount
, fd
->sc_blkno
, bp
->b_cylinder
, sz
);
462 /* Queue transfer on drive, activate drive and controller if idle. */
464 bufq_put(fd
->sc_q
, bp
);
465 callout_stop(&fd
->sc_motoroff_ch
); /* a good idea */
466 if (fd
->sc_active
== 0)
470 struct fdc_softc
*fdc
=
471 device_private(device_parent(fd
->sc_dev
));
472 if (fdc
->sc_state
== DEVIDLE
) {
473 printf("%s: controller inactive\n", __func__
);
482 /* Toss transfer; we're done early. */
483 bp
->b_resid
= bp
->b_bcount
;
488 fdstart(struct fd_softc
*fd
)
490 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
491 int active
= TAILQ_FIRST(&fdc
->sc_drives
) != 0;
493 /* Link into controller queue. */
495 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
497 /* If controller not already active, start it. */
503 fdfinish(struct fd_softc
*fd
, struct buf
*bp
)
505 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
508 * Move this drive to the end of the queue to give others a `fair'
509 * chance. We only force a switch if N operations are completed while
510 * another drive is waiting to be serviced, since there is a long motor
511 * startup delay whenever we switch.
513 (void)bufq_get(fd
->sc_q
);
514 if (TAILQ_NEXT(fd
, sc_drivechain
) && ++fd
->sc_ops
>= 8) {
516 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
517 if (bufq_peek(fd
->sc_q
) != NULL
)
518 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
522 bp
->b_resid
= fd
->sc_bcount
;
525 /* turn off motor 5s from now */
526 callout_reset(&fd
->sc_motoroff_ch
, 5 * hz
, fd_motor_off
, fd
);
527 fdc
->sc_state
= DEVIDLE
;
531 fdread(dev_t dev
, struct uio
*uio
, int flags
)
534 return physio(fdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
);
538 fdwrite(dev_t dev
, struct uio
*uio
, int flags
)
541 return physio(fdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
);
545 fd_set_motor(struct fdc_softc
*fdc
, int reset
)
551 if ((fd
= TAILQ_FIRST(&fdc
->sc_drives
)) != NULL
)
552 status
= fd
->sc_drive
;
556 status
|= FDO_FRST
| FDO_FDMAEN
;
557 for (n
= 0; n
< 4; n
++)
558 if ((fd
= fdc
->sc_fd
[n
]) && (fd
->sc_flags
& FD_MOTOR
))
559 status
|= FDO_MOEN(n
);
560 bus_space_write_1(fdc
->sc_iot
, fdc
->sc_ioh
, FDOUT
, status
);
564 fd_motor_off(void *arg
)
566 struct fd_softc
*fd
= arg
;
567 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
571 fd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
572 fd_set_motor(fdc
, 0);
577 fd_motor_on(void *arg
)
579 struct fd_softc
*fd
= arg
;
580 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dev
));
584 fd
->sc_flags
&= ~FD_MOTOR_WAIT
;
585 if ((TAILQ_FIRST(&fdc
->sc_drives
) == fd
) &&
586 (fdc
->sc_state
== MOTORWAIT
))
592 fdcresult(struct fdc_softc
*fdc
)
594 bus_space_tag_t iot
= fdc
->sc_iot
;
595 bus_space_handle_t ioh
= fdc
->sc_ioh
;
599 for (j
= 100000; j
; j
--) {
600 i
= bus_space_read_1(iot
, ioh
, FDSTS
) &
601 (NE7_DIO
| NE7_RQM
| NE7_CB
);
604 if (i
== (NE7_DIO
| NE7_RQM
| NE7_CB
)) {
605 if (n
>= sizeof(fdc
->sc_status
)) {
606 log(LOG_ERR
, "%s: overrun\n", __func__
);
609 fdc
->sc_status
[n
++] =
610 bus_space_read_1(iot
, ioh
, FDDATA
);
614 log(LOG_ERR
, "%s: timeout\n", __func__
);
619 out_fdc(bus_space_tag_t iot
, bus_space_handle_t ioh
, uint8_t x
)
623 while ((bus_space_read_1(iot
, ioh
, FDSTS
) & NE7_DIO
) && i
-- > 0);
626 while ((bus_space_read_1(iot
, ioh
, FDSTS
) & NE7_RQM
) == 0 && i
-- > 0);
629 bus_space_write_1(iot
, ioh
, FDDATA
, x
);
634 fdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
637 const struct fd_type
*type
;
639 fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
643 type
= fd_dev_to_type(fd
, dev
);
647 if ((fd
->sc_flags
& FD_OPEN
) != 0 &&
648 memcmp(fd
->sc_type
, type
, sizeof(*type
)))
651 fd
->sc_type_copy
= *type
;
652 fd
->sc_type
= &fd
->sc_type_copy
;
654 fd
->sc_flags
|= FD_OPEN
;
660 fdclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
662 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
664 fd
->sc_flags
&= ~FD_OPEN
;
669 fdcstart(struct fdc_softc
*fdc
)
673 /* only got here if controller's drive queue was inactive; should
675 if (fdc
->sc_state
!= DEVIDLE
) {
676 printf("%s: not idle\n", __func__
);
684 fdcpstatus(int n
, struct fdc_softc
*fdc
)
693 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
694 printf(" (st0 %s cyl %d)\n", bits
, fdc
->sc_status
[1]);
697 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
698 printf(" (st0 %s", bits
);
699 snprintb(bits
, sizeof(bits
), NE7_ST1BITS
, fdc
->sc_status
[1]);
700 printf(" st1 %s", bits
);
701 snprintb(bits
, sizeof(bits
), NE7_ST2BITS
, fdc
->sc_status
[2]);
702 printf(" st2 %s", bits
);
703 printf(" cyl %d head %d sec %d)\n",
704 fdc
->sc_status
[3], fdc
->sc_status
[4], fdc
->sc_status
[5]);
708 printf("\nfdcstatus: weird size");
715 fdcstatus(device_t dev
, int n
, const char *s
)
717 struct fdc_softc
*fdc
= device_private(device_parent(dev
));
720 out_fdc(fdc
->sc_iot
, fdc
->sc_ioh
, NE7CMD_SENSEI
);
721 (void)fdcresult(fdc
);
725 printf("%s: %s", device_xname(dev
), s
);
730 fdctimeout(void *arg
)
732 struct fdc_softc
*fdc
= arg
;
733 struct fd_softc
*fd
= TAILQ_FIRST(&fdc
->sc_drives
);
738 log(LOG_ERR
, "%s: state %d\n", __func__
, fdc
->sc_state
);
740 fdcstatus(fd
->sc_dev
, 0, "timeout");
742 if (bufq_peek(fd
->sc_q
) != NULL
)
745 fdc
->sc_state
= DEVIDLE
;
752 fdcpseudointr(void *arg
)
756 /* Just ensure it has the right spl. */
765 struct fdc_softc
*fdc
= arg
;
766 #define st0 fdc->sc_status[0]
767 #define cyl fdc->sc_status[1]
770 bus_space_tag_t iot
= fdc
->sc_iot
;
771 bus_space_handle_t ioh
= fdc
->sc_ioh
;
772 int read
, head
, sec
, i
, nblks
;
773 struct fd_type
*type
;
776 /* Is there a drive for the controller to do a transfer with? */
777 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
779 fdc
->sc_state
= DEVIDLE
;
783 /* Is there a transfer to this drive? If not, deactivate drive. */
784 bp
= bufq_peek(fd
->sc_q
);
787 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
792 switch (fdc
->sc_state
) {
796 fd
->sc_bcount
= bp
->b_bcount
;
797 fd
->sc_blkno
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
);
798 callout_stop(&fd
->sc_motoroff_ch
);
799 if ((fd
->sc_flags
& FD_MOTOR_WAIT
) != 0) {
800 fdc
->sc_state
= MOTORWAIT
;
803 if ((fd
->sc_flags
& FD_MOTOR
) == 0) {
804 /* Turn on the motor, being careful about pairing. */
805 struct fd_softc
*ofd
= fdc
->sc_fd
[fd
->sc_drive
^ 1];
806 if (ofd
&& ofd
->sc_flags
& FD_MOTOR
) {
807 callout_stop(&ofd
->sc_motoroff_ch
);
808 ofd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
810 fd
->sc_flags
|= FD_MOTOR
| FD_MOTOR_WAIT
;
811 fd_set_motor(fdc
, 0);
812 fdc
->sc_state
= MOTORWAIT
;
813 /* Allow .25s for motor to stabilize. */
814 callout_reset(&fd
->sc_motoron_ch
, hz
/ 4,
818 /* Make sure the right drive is selected. */
819 fd_set_motor(fdc
, 0);
824 if (fd
->sc_cylin
== bp
->b_cylinder
)
827 out_fdc(iot
, ioh
, NE7CMD_SPECIFY
);/* specify command */
828 out_fdc(iot
, ioh
, fd
->sc_type
->steprate
);
829 out_fdc(iot
, ioh
, 6); /* XXX head load time == 6ms */
831 out_fdc(iot
, ioh
, NE7CMD_SEEK
); /* seek function */
832 out_fdc(iot
, ioh
, fd
->sc_drive
); /* drive number */
833 out_fdc(iot
, ioh
, bp
->b_cylinder
* fd
->sc_type
->step
);
836 fdc
->sc_state
= SEEKWAIT
;
838 iostat_seek(fd
->sc_dk
.dk_stats
);
839 disk_busy(&fd
->sc_dk
);
841 callout_reset(&fdc
->sc_timo_ch
, 4 * hz
, fdctimeout
, fdc
);
847 sec
= fd
->sc_blkno
% type
->seccyl
;
848 nblks
= type
->seccyl
- sec
;
849 nblks
= min(nblks
, fd
->sc_bcount
/ FDC_BSIZE
);
850 nblks
= min(nblks
, fdc
->sc_maxiosize
/ FDC_BSIZE
);
851 fd
->sc_nblks
= nblks
;
852 fd
->sc_nbytes
= nblks
* FDC_BSIZE
;
853 head
= sec
/ type
->sectrac
;
854 sec
-= head
* type
->sectrac
;
858 block
= (fd
->sc_cylin
* type
->heads
+ head
) *
860 if (block
!= fd
->sc_blkno
) {
861 printf("%s: block %d != blkno %" PRId64
862 "\n", __func__
, block
, fd
->sc_blkno
);
869 read
= (bp
->b_flags
& B_READ
) != 0;
870 FDCDMA_START(fdc
, (uint8_t *)bp
->b_data
+ fd
->sc_skip
,
871 fd
->sc_nbytes
, read
);
872 bus_space_write_1(iot
, ioh
, FDCTL
, type
->rate
);
874 printf("%s: %s drive %d track %d head %d sec %d nblks %d\n",
875 __func__
, read
? "read" : "write", fd
->sc_drive
,
876 fd
->sc_cylin
, head
, sec
, nblks
);
879 out_fdc(iot
, ioh
, NE7CMD_READ
); /* READ */
881 out_fdc(iot
, ioh
, NE7CMD_WRITE
);/* WRITE */
882 out_fdc(iot
, ioh
, (head
<< 2) | fd
->sc_drive
);
883 out_fdc(iot
, ioh
, fd
->sc_cylin
); /* track */
884 out_fdc(iot
, ioh
, head
);
885 out_fdc(iot
, ioh
, sec
+ 1); /* sector + 1 */
886 out_fdc(iot
, ioh
, type
->secsize
); /* sector size */
887 out_fdc(iot
, ioh
, type
->sectrac
); /* sectors/track */
888 out_fdc(iot
, ioh
, type
->gap1
); /* gap1 size */
889 out_fdc(iot
, ioh
, type
->datalen
); /* data length */
890 fdc
->sc_state
= IOCOMPLETE
;
892 disk_busy(&fd
->sc_dk
);
894 /* allow 2 seconds for operation */
895 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
896 return 1; /* will return later */
899 callout_stop(&fdc
->sc_timo_ch
);
900 fdc
->sc_state
= SEEKCOMPLETE
;
901 /* allow 1/50 second for heads to settle */
902 callout_reset(&fdc
->sc_intr_ch
, hz
/ 50, fdcpseudointr
, fdc
);
906 disk_unbusy(&fd
->sc_dk
, 0, 0);
908 /* Make sure seek really happened. */
909 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
910 if (fdcresult(fdc
) != 2 || (st0
& 0xf8) != 0x20 ||
911 cyl
!= bp
->b_cylinder
* fd
->sc_type
->step
) {
913 fdcstatus(fd
->sc_dev
, 2, "seek failed");
918 fd
->sc_cylin
= bp
->b_cylinder
;
930 case IOCOMPLETE
: /* IO DONE, post-analyze */
931 callout_stop(&fdc
->sc_timo_ch
);
933 disk_unbusy(&fd
->sc_dk
, (bp
->b_bcount
- bp
->b_resid
),
934 (bp
->b_flags
& B_READ
));
937 if (i
!= 7 || (st0
& 0xf8) != 0) {
940 fdcstatus(fd
->sc_dev
, 7, bp
->b_flags
& B_READ
?
941 "read failed" : "write failed");
942 printf("blkno %" PRId64
" nblks %d\n",
943 fd
->sc_blkno
, fd
->sc_nblks
);
949 if (fdc
->sc_errors
) {
950 diskerr(bp
, "fd", "soft error (corrected)", LOG_PRINTF
,
951 fd
->sc_skip
/ FDC_BSIZE
, NULL
);
955 fd
->sc_blkno
+= fd
->sc_nblks
;
956 fd
->sc_skip
+= fd
->sc_nbytes
;
957 fd
->sc_bcount
-= fd
->sc_nbytes
;
958 if (fd
->sc_bcount
> 0) {
959 bp
->b_cylinder
= fd
->sc_blkno
/ fd
->sc_type
->seccyl
;
966 /* try a reset, keep motor on */
967 fd_set_motor(fdc
, 1);
969 fd_set_motor(fdc
, 0);
970 fdc
->sc_state
= RESETCOMPLETE
;
971 callout_reset(&fdc
->sc_timo_ch
, hz
/ 2, fdctimeout
, fdc
);
972 return 1; /* will return later */
975 callout_stop(&fdc
->sc_timo_ch
);
976 /* clear the controller output buffer */
977 for (i
= 0; i
< 4; i
++) {
978 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
979 (void)fdcresult(fdc
);
984 out_fdc(iot
, ioh
, NE7CMD_RECAL
); /* recalibrate function */
985 out_fdc(iot
, ioh
, fd
->sc_drive
);
986 fdc
->sc_state
= RECALWAIT
;
987 callout_reset(&fdc
->sc_timo_ch
, 5 * hz
, fdctimeout
, fdc
);
988 return 1; /* will return later */
991 callout_stop(&fdc
->sc_timo_ch
);
992 fdc
->sc_state
= RECALCOMPLETE
;
993 /* allow 1/30 second for heads to settle */
994 callout_reset(&fdc
->sc_intr_ch
, hz
/ 30, fdcpseudointr
, fdc
);
995 return 1; /* will return later */
998 out_fdc(iot
, ioh
, NE7CMD_SENSEI
);
999 if (fdcresult(fdc
) != 2 || (st0
& 0xf8) != 0x20 || cyl
!= 0) {
1001 fdcstatus(fd
->sc_dev
, 2, "recalibrate failed");
1010 if (fd
->sc_flags
& FD_MOTOR_WAIT
)
1011 return 1; /* time's not up yet */
1015 fdcstatus(fd
->sc_dev
, 0, "stray interrupt");
1019 panic("%s: impossible", __func__
);
1026 fdcretry(struct fdc_softc
*fdc
)
1028 struct fd_softc
*fd
;
1031 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1032 bp
= bufq_peek(fd
->sc_q
);
1034 switch (fdc
->sc_errors
) {
1037 fdc
->sc_state
= DOSEEK
;
1043 /* didn't work; try recalibrating */
1044 fdc
->sc_state
= DORECAL
;
1048 /* still no go; reset the bastard */
1049 fdc
->sc_state
= DORESET
;
1053 diskerr(bp
, "fd", "hard error", LOG_PRINTF
,
1054 fd
->sc_skip
/ FDC_BSIZE
, (struct disklabel
*)NULL
);
1064 fdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
1066 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
1067 struct disklabel buffer
;
1072 memset(&buffer
, 0, sizeof(buffer
));
1074 buffer
.d_secpercyl
= fd
->sc_type
->seccyl
;
1075 buffer
.d_type
= DTYPE_FLOPPY
;
1076 buffer
.d_secsize
= FDC_BSIZE
;
1078 if (readdisklabel(dev
, fdstrategy
, &buffer
, NULL
) != NULL
)
1081 *(struct disklabel
*)addr
= buffer
;
1085 if ((flag
& FWRITE
) == 0)
1087 /* XXX do something */
1091 if ((flag
& FWRITE
) == 0)
1094 error
= setdisklabel(&buffer
, (struct disklabel
*)addr
,
1099 error
= writedisklabel(dev
, fdstrategy
, &buffer
, NULL
);
1107 panic("%s: impossible", __func__
);
1112 * Mountroot hook: prompt the user to enter the root file system floppy.
1115 fd_mountroot_hook(device_t dev
)
1119 printf("Insert filesystem floppy and press return.");
1123 if ((c
== '\r') || (c
== '\n')) {