1 /* $NetBSD: fd.c,v 1.70 2009/09/26 16:03:45 tsutsui Exp $ */
4 * Copyright (c) 1990 The Regents of the University of California.
7 * This code is derived from software contributed to Berkeley by
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.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)fd.c 7.4 (Berkeley) 5/25/91
38 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.
40 * This code is derived from software contributed to Berkeley by
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * @(#)fd.c 7.4 (Berkeley) 5/25/91
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.70 2009/09/26 16:03:45 tsutsui Exp $");
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/callout.h>
82 #include <sys/kernel.h>
84 #include <sys/ioctl.h>
85 #include <sys/device.h>
86 #include <sys/disklabel.h>
91 #include <sys/malloc.h>
95 #include <sys/syslog.h>
96 #include <sys/queue.h>
101 #include <uvm/uvm_extern.h>
103 #include <machine/cpu.h>
104 #include <machine/autoconf.h>
106 #include <sun3/dev/fdreg.h>
107 #include <sun3/dev/fdvar.h>
112 * Print a complaint when no fd children were specified
113 * in the config file. Better than a link error...
115 * XXX: Some folks say this driver should be split in two,
116 * but that seems pointless with ONLY one type of child.
117 * (Thankfully, no 3/80 boxes have floppy tapes!:)
121 #error "fdc but no fd?"
124 #define FDUNIT(dev) (minor(dev) / 8)
125 #define FDTYPE(dev) (minor(dev) % 8)
127 /* (mis)use device use flag to identify format operation */
128 #define B_FORMAT B_DEVPRIVATE
153 /* software state, per controller */
155 device_t sc_dev
; /* boilerplate */
158 struct callout sc_timo_ch
; /* timeout callout */
159 struct callout sc_intr_ch
; /* pseudo-intr callout */
161 struct fd_softc
*sc_fd
[4]; /* pointers to children */
162 TAILQ_HEAD(drivehead
, fd_softc
) sc_drives
;
163 enum fdc_state sc_state
;
165 #define FDC_82077 0x01
166 #define FDC_NEEDHEADSETTLE 0x02
168 int sc_errors
; /* number of retries so far */
169 int sc_overruns
; /* number of DMA overruns */
170 int sc_cfg
; /* current configuration */
171 int sc_fcr
; /* current image of floppy ctrlr reg. */
173 #define sc_reg_msr sc_io.fdcio_reg_msr
174 #define sc_reg_fifo sc_io.fdcio_reg_fifo
175 #define sc_reg_fcr sc_io.fdcio_reg_fcr
176 #define sc_reg_fvr sc_io.fdcio_reg_fvr
177 #define sc_reg_drs sc_io.fdcio_reg_msr
178 #define sc_istate sc_io.fdcio_istate
179 #define sc_data sc_io.fdcio_data
180 #define sc_tc sc_io.fdcio_tc
181 #define sc_nstat sc_io.fdcio_nstat
182 #define sc_status sc_io.fdcio_status
183 #define sc_intrcnt sc_io.fdcio_intrcnt
184 void *sc_si
; /* softintr cookie */
187 /* controller driver configuration */
188 static int fdcmatch(device_t
, cfdata_t
, void *);
189 static void fdcattach(device_t
, device_t
, void *);
191 CFATTACH_DECL_NEW(fdc
, sizeof(struct fdc_softc
),
192 fdcmatch
, fdcattach
, NULL
, NULL
);
194 static inline struct fd_type
*fd_dev_to_type(struct fd_softc
*, dev_t
);
197 * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
198 * we tell them apart.
201 int sectrac
; /* sectors per track */
202 int heads
; /* number of heads */
203 int seccyl
; /* sectors per cylinder */
204 int secsize
; /* size code for sectors */
205 int datalen
; /* data len when secsize = 0 */
206 int steprate
; /* step rate and head unload time */
207 int gap1
; /* gap len between sectors */
208 int gap2
; /* formatting gap */
209 int tracks
; /* total num of tracks */
210 int size
; /* size of disk in sectors */
211 int step
; /* steps per cylinder */
212 int rate
; /* transfer speed code */
213 int fillbyte
; /* format fill byte */
214 int interleave
; /* interleave factor (formatting) */
218 /* The order of entries in the following table is important -- BEWARE! */
219 static struct fd_type fd_types
[] = {
220 { 18, 2, 36, 2, 0xff, 0xcf, 0x18, 0x50, 80, 2880, 1,
221 FDC_500KBPS
, 0xf6, 1, "1.44MB" }, /* 1.44MB diskette */
222 { 15, 2, 30, 2, 0xff, 0xdf, 0x1b, 0x54, 80, 2400, 1,
223 FDC_500KBPS
, 0xf6, 1, "1.2MB" }, /* 1.2 MB AT-diskettes */
224 { 9, 2, 18, 2, 0xff, 0xdf, 0x23, 0x50, 40, 720, 2,
225 FDC_300KBPS
, 0xf6, 1, "360KB/AT" }, /* 360kB in 1.2MB drive */
226 { 9, 2, 18, 2, 0xff, 0xdf, 0x2a, 0x50, 40, 720, 1,
227 FDC_250KBPS
, 0xf6, 1, "360KB/PC" }, /* 360kB PC diskettes */
228 { 9, 2, 18, 2, 0xff, 0xdf, 0x2a, 0x50, 80, 1440, 1,
229 FDC_250KBPS
, 0xf6, 1, "720KB" }, /* 3.5" 720kB diskette */
230 { 9, 2, 18, 2, 0xff, 0xdf, 0x23, 0x50, 80, 1440, 1,
231 FDC_300KBPS
, 0xf6, 1, "720KB/x" }, /* 720kB in 1.2MB drive */
232 { 9, 2, 18, 2, 0xff, 0xdf, 0x2a, 0x50, 40, 720, 2,
233 FDC_250KBPS
,0xf6,1, "360KB/x" }, /* 360kB in 720kB drive */
236 /* software state, per disk (with up to 4 disks per ctlr) */
238 device_t sc_dv
; /* generic device info */
239 struct disk sc_dk
; /* generic disk info */
241 struct fd_type
*sc_deftype
; /* default type descriptor */
242 struct fd_type
*sc_type
; /* current type descriptor */
244 struct callout sc_motoron_ch
;
245 struct callout sc_motoroff_ch
;
247 daddr_t sc_blkno
; /* starting block number */
248 int sc_bcount
; /* byte count left */
249 int sc_skip
; /* bytes already transferred */
250 int sc_nblks
; /* number of blocks currently transferring */
251 int sc_nbytes
; /* number of bytes currently transferring */
253 int sc_drive
; /* physical unit number */
255 #define FD_OPEN 0x01 /* it's open */
256 #define FD_MOTOR 0x02 /* motor should be on */
257 #define FD_MOTOR_WAIT 0x04 /* motor coming up */
258 int sc_cylin
; /* where we think the head is */
259 int sc_opts
; /* user-set options */
261 TAILQ_ENTRY(fd_softc
) sc_drivechain
;
262 int sc_ops
; /* I/O ops since last switch */
263 struct bufq_state
*sc_q
;/* pending I/O requests */
264 int sc_active
; /* number of active I/O operations */
267 /* floppy driver configuration */
268 static int fdmatch(device_t
, cfdata_t
, void *);
269 static void fdattach(device_t
, device_t
, void *);
271 CFATTACH_DECL_NEW(fd
, sizeof(struct fd_softc
),
272 fdmatch
, fdattach
, NULL
, NULL
);
274 dev_type_open(fdopen
);
275 dev_type_close(fdclose
);
276 dev_type_read(fdread
);
277 dev_type_write(fdwrite
);
278 dev_type_ioctl(fdioctl
);
279 dev_type_strategy(fdstrategy
);
281 const struct bdevsw fd_bdevsw
= {
282 fdopen
, fdclose
, fdstrategy
, fdioctl
, nodump
, nosize
, D_DISK
285 const struct cdevsw fd_cdevsw
= {
286 fdopen
, fdclose
, fdread
, fdwrite
, fdioctl
,
287 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
290 static bool fd_shutdown(device_t
, int);
291 static void fdgetdisklabel(dev_t
);
292 static void fdstart(struct fd_softc
*);
293 static int fdprint(void *, const char *);
295 struct dkdriver fddkdriver
= { fdstrategy
};
297 static void fd_set_motor(struct fdc_softc
*);
298 static void fd_motor_off(void *);
299 static void fd_motor_on(void *);
300 static int fdcresult(struct fdc_softc
*);
301 static int out_fdc(struct fdc_softc
*, u_char
);
302 static void fdcstart(struct fdc_softc
*);
303 static void fdcstatus(device_t
, int, const char *);
304 static void fdc_reset(struct fdc_softc
*);
305 static void fdctimeout(void *);
306 static void fdcpseudointr(void *);
307 static int fdchwintr(void *);
308 static void fdcswintr(void *);
309 static int fdcstate(struct fdc_softc
*);
310 static void fdcretry(struct fdc_softc
*);
311 static void fdfinish(struct fd_softc
*, struct buf
*);
312 static int fdformat(dev_t
, struct ne7_fd_formb
*, struct proc
*);
313 static void fd_do_eject(struct fdc_softc
*, int);
314 static void fd_mountroot_hook(device_t
);
315 static void fdconf(struct fdc_softc
*);
317 #define IPL_SOFTFD IPL_BIO
318 #define FDC_SOFTPRI 2
319 #define FD_SET_SWINTR() softint_schedule(fdc->sc_si);
322 * The Floppy Control Register on the sun3x, not to be confused with the
323 * Floppy ControllER Registers that this driver mostly insterfaces with,
324 * controls some of the auxillary functions of the floppy drive. These
325 * include asserting the floppy eject and terminal data count (or TC) pins
326 * of the floppy drive and controller chip respectively.
328 * Often it is necessary to toggle individual bits within this register
329 * while keeping the others untouched. However, the register does not
330 * present its latched data to the processor when read. This prevents the
331 * use of a read-modify-write cycle that would normally be used to modify
332 * individual bits. To get around this we must keep a copy of register's
333 * current value and always insure that when we wish to modify the register,
334 * we actually modify the copy and synchronize the register to it.
336 #define FCR_REG_SYNC() (*fdc->sc_reg_fcr = fdc->sc_fcr)
339 fdcmatch(device_t parent
, cfdata_t cf
, void *aux
)
341 struct confargs
*ca
= aux
;
343 if (bus_peek(ca
->ca_bustype
, ca
->ca_paddr
, sizeof(uint8_t)) == -1)
350 * Arguments passed between fdcattach and fdprobe.
352 struct fdc_attach_args
{
354 struct bootpath
*fa_bootpath
;
355 struct fd_type
*fa_deftype
;
359 * Print the location of a disk drive (called just before attaching the
360 * the drive). If `fdc' is not NULL, the drive was found but was not
361 * in the system config file; print the drive name as well.
362 * Return QUIET (config_find ignores this if the device was configured) to
363 * avoid printing `fdN not configured' messages.
366 fdprint(void *aux
, const char *fdc
)
368 struct fdc_attach_args
*fa
= aux
;
371 aprint_normal(" drive %d", fa
->fa_drive
);
376 fdconf(struct fdc_softc
*fdc
)
380 if (out_fdc(fdc
, NE7CMD_DUMPREG
) || fdcresult(fdc
) != 10)
384 * dumpreg[7] seems to be a motor-off timeout; set it to whatever
385 * the PROM thinks is appropriate.
387 if ((vroom
= fdc
->sc_status
[7]) == 0)
390 /* Configure controller to use FIFO and Implied Seek */
391 out_fdc(fdc
, NE7CMD_CFG
);
393 out_fdc(fdc
, fdc
->sc_cfg
);
394 out_fdc(fdc
, 0); /* PRETRK */
395 /* No result phase */
399 fdcattach(struct device
*parent
, struct device
*self
, void *aux
)
401 struct confargs
*ca
= aux
;
402 struct fdc_softc
*fdc
= device_private(self
);
403 struct fdc_attach_args fa
;
409 fdc
->sc_reg
= (void *)bus_mapin(ca
->ca_bustype
, ca
->ca_paddr
,
410 sizeof(union fdreg
));
412 callout_init(&fdc
->sc_timo_ch
, 0);
413 callout_init(&fdc
->sc_intr_ch
, 0);
415 fdc
->sc_state
= DEVIDLE
;
416 fdc
->sc_istate
= ISTATE_IDLE
;
417 fdc
->sc_flags
|= FDC_EIS
;
418 TAILQ_INIT(&fdc
->sc_drives
);
424 panic("no 82077 fdc in this kernel");
427 fdc
->sc_reg_msr
= &((struct fdreg_72
*)fdc
->sc_reg
)->fd_msr
;
428 fdc
->sc_reg_fifo
= &((struct fdreg_72
*)fdc
->sc_reg
)->fd_fifo
;
430 fdc
->sc_reg_fcr
= ((volatile uint8_t *)fdc
->sc_reg
)
432 fdc
->sc_reg_fvr
= ((volatile uint8_t *)fdc
->sc_reg
)
439 /* Tell the FDC to fake an autovector. */
440 vec
= 0x18 + pri
; /* XXX */
441 isr_add_autovect(fdchwintr
, fdc
, pri
);
443 /* An OBIO bus with vectors? Weird exception. */
444 isr_add_vectored(fdchwintr
, fdc
, pri
, vec
);
446 *fdc
->sc_reg_fvr
= vec
; /* Program controller w/ interrupt vector */
448 fdc
->sc_si
= softint_establish(SOFTINT_BIO
, fdcswintr
, fdc
);
450 aprint_normal(": (softpri %d) chip 8207%c\n", FDC_SOFTPRI
, code
);
452 aprint_normal(": chip 8207%c\n", code
);
456 if (out_fdc(fdc
, NE7CMD_VERSION
) == 0 &&
457 fdcresult(fdc
) == 1 && fdc
->sc_status
[0] == 0x90) {
459 aprint_debug("[version cmd]");
465 * Configure controller; enable FIFO, Implied seek, no POLL mode?.
466 * Note: CFG_EFIFO is active-low, initial threshold value: 8
468 fdc
->sc_cfg
= CFG_EIS
|/*CFG_EFIFO|*/CFG_POLL
|(8 & CFG_THRHLD_MASK
);
471 evcnt_attach_dynamic(&fdc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
472 device_xname(self
), "intr");
474 /* physical limit: four drives per controller. */
475 for (fa
.fa_drive
= 0; fa
.fa_drive
< 4; fa
.fa_drive
++) {
476 fa
.fa_deftype
= NULL
; /* unknown */
477 fa
.fa_deftype
= &fd_types
[0]; /* XXX */
478 (void)config_found(self
, (void *)&fa
, fdprint
);
483 fdmatch(device_t parent
, cfdata_t cf
, void *aux
)
485 struct fdc_softc
*fdc
= device_private(parent
);
486 struct fdc_attach_args
*fa
= aux
;
487 int drive
= fa
->fa_drive
;
491 /* XXX - for now, punt > 1 drives */
494 /* select drive and turn on motor */
495 fdc
->sc_fcr
|= FCR_DSEL(drive
) | FCR_MTRON
;
497 /* wait for motor to spin up */
501 out_fdc(fdc
, NE7CMD_RECAL
);
503 /* wait for recalibrate */
504 for (n
= 0; n
< 10000; n
++) {
506 if ((*fdc
->sc_reg_msr
& (NE7_RQM
|NE7_DIO
|NE7_CB
)) == NE7_RQM
) {
507 /* wait a bit longer till device *really* is ready */
509 if (out_fdc(fdc
, NE7CMD_SENSEI
))
511 if (fdcresult(fdc
) == 1 && fdc
->sc_status
[0] == 0x80)
513 * Got `invalid command'; we interpret it
514 * to mean that the re-calibrate hasn't in
525 aprint_debug("%s: %d stati:", __func__
, n
);
526 for (i
= 0; i
< n
; i
++)
527 aprint_debug(" %x", fdc
->sc_status
[i
]);
531 ok
= (n
== 2 && (fdc
->sc_status
[0] & 0xf8) == 0x20) ? 1 : 0;
534 fdc
->sc_fcr
&= ~(FCR_DSEL(drive
)|FCR_MTRON
);
541 * Controller is working, and drive responded. Attach it.
544 fdattach(device_t parent
, device_t self
, void *aux
)
546 struct fdc_softc
*fdc
= device_private(parent
);
547 struct fd_softc
*fd
= device_private(self
);
548 struct fdc_attach_args
*fa
= aux
;
549 struct fd_type
*type
= fa
->fa_deftype
;
550 int drive
= fa
->fa_drive
;
554 callout_init(&fd
->sc_motoron_ch
, 0);
555 callout_init(&fd
->sc_motoroff_ch
, 0);
557 /* XXX Allow `flags' to override device type? */
560 aprint_normal(": %s %d cyl, %d head, %d sec\n", type
->name
,
561 type
->tracks
, type
->heads
, type
->sectrac
);
563 aprint_normal(": density unknown\n");
565 bufq_alloc(&fd
->sc_q
, "disksort", BUFQ_SORT_CYLINDER
);
567 fd
->sc_drive
= drive
;
568 fd
->sc_deftype
= type
;
569 fdc
->sc_fd
[drive
] = fd
;
572 * Initialize and attach the disk structure.
574 disk_init(&fd
->sc_dk
, device_xname(self
), &fddkdriver
);
575 disk_attach(&fd
->sc_dk
);
579 * We're told if we're the boot device in fdcattach().
582 fa
->fa_bootpath
->dev
= self
;
584 #define OUT_FDC(sc, c) do { \
585 if (out_fdc((sc), (c)) != 0) \
586 printf("fdc: specify command failed.\n"); \
587 } while (/* CONSTCOND */ 0)
589 /* specify command */
590 OUT_FDC(fdc
, NE7CMD_SPECIFY
);
591 OUT_FDC(fdc
, type
->steprate
);
593 * The '|1' in the following statement turns on the 'Non-DMA' bit
594 * specifier in the last byte of the SPECIFY command as described in the
595 * datasheet I have. This is necessary for the driver to work on the
596 * sun3x, because the system will not respond to the chip's requests
597 * for DMA; there is no hardware on the motherboard to support it.
598 * By enabling this bit, we will force the chip to interrupt when its
599 * FIFO is full, at which point the interrupt handler will empty it and
600 * continue. This is ``pseudo-DMA''.
603 OUT_FDC(fdc
, 6|1); /* XXX head load time == 6ms */
607 * Establish a mountroot_hook anyway in case we booted
608 * with RB_ASKNAME and get selected as the boot device.
610 mountroothook_establish(fd_mountroot_hook
, self
);
612 /* Make sure the drive motor gets turned off at shutdown time. */
613 if (!pmf_device_register1(self
, NULL
, NULL
, fd_shutdown
))
614 aprint_error_dev(self
, "couldn't establish power handler\n");
618 fd_shutdown(device_t self
, int howto
)
622 fd
= device_private(self
);
628 inline struct fd_type
*
629 fd_dev_to_type(struct fd_softc
*fd
, dev_t dev
)
631 int type
= FDTYPE(dev
);
633 if (type
> (sizeof(fd_types
) / sizeof(fd_types
[0])))
635 return type
? &fd_types
[type
- 1] : fd
->sc_deftype
;
639 fdstrategy(struct buf
*bp
)
642 int unit
= FDUNIT(bp
->b_dev
);
646 /* Valid unit, controller, and request? */
647 if ((fd
= device_lookup_private(&fd_cd
, unit
)) == 0 ||
649 ((bp
->b_bcount
% FDC_BSIZE
) != 0 &&
650 (bp
->b_flags
& B_FORMAT
) == 0)) {
651 bp
->b_error
= EINVAL
;
655 /* If it's a null transfer, return immediately. */
656 if (bp
->b_bcount
== 0)
659 sz
= howmany(bp
->b_bcount
, FDC_BSIZE
);
661 if (bp
->b_blkno
+ sz
> fd
->sc_type
->size
) {
662 sz
= fd
->sc_type
->size
- bp
->b_blkno
;
664 /* If exactly at end of disk, return EOF. */
665 bp
->b_resid
= bp
->b_bcount
;
669 /* If past end of disk, return EINVAL. */
670 bp
->b_error
= EINVAL
;
673 /* Otherwise, truncate request. */
674 bp
->b_bcount
= sz
<< DEV_BSHIFT
;
677 bp
->b_rawblkno
= bp
->b_blkno
;
679 bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
) / fd
->sc_type
->seccyl
;
683 printf("%s: b_blkno %d b_bcount %d blkno %d cylin %d\n",
684 __func__
, (int)bp
->b_blkno
, bp
->b_bcount
,
685 (int)fd
->sc_blkno
, bp
->b_cylinder
);
688 /* Queue transfer on drive, activate drive and controller if idle. */
690 bufq_put(fd
->sc_q
, bp
);
691 callout_stop(&fd
->sc_motoroff_ch
); /* a good idea */
692 if (fd
->sc_active
== 0)
696 struct fdc_softc
*fdc
;
698 fdc
= device_private(device_parent(fd
->sc_dv
));
699 if (fdc
->sc_state
== DEVIDLE
) {
700 printf("%s: controller inactive\n", __func__
);
709 /* Toss transfer; we're done early. */
714 fdstart(struct fd_softc
*fd
)
716 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dv
));
717 bool active
= fdc
->sc_drives
.tqh_first
!= 0;
719 /* Link into controller queue. */
721 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
723 /* If controller not already active, start it. */
729 fdfinish(struct fd_softc
*fd
, struct buf
*bp
)
731 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dv
));
734 * Move this drive to the end of the queue to give others a `fair'
735 * chance. We only force a switch if N operations are completed while
736 * another drive is waiting to be serviced, since there is a long motor
737 * startup delay whenever we switch.
739 (void)bufq_get(fd
->sc_q
);
740 if (TAILQ_NEXT(fd
, sc_drivechain
) && ++fd
->sc_ops
>= 8) {
742 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
743 if (bufq_peek(fd
->sc_q
) != NULL
) {
744 TAILQ_INSERT_TAIL(&fdc
->sc_drives
, fd
, sc_drivechain
);
748 bp
->b_resid
= fd
->sc_bcount
;
752 /* turn off motor 5s from now */
753 callout_reset(&fd
->sc_motoroff_ch
, 5 * hz
, fd_motor_off
, fd
);
754 fdc
->sc_state
= DEVIDLE
;
758 fdc_reset(struct fdc_softc
*fdc
)
764 *fdc
->sc_reg_drs
= DRS_RESET
;
766 *fdc
->sc_reg_drs
= 0;
770 printf("fdc reset\n");
775 fd_set_motor(struct fdc_softc
*fdc
)
782 for (n
= 0; n
< 4; n
++)
783 if ((fd
= fdc
->sc_fd
[n
]) && (fd
->sc_flags
& FD_MOTOR
))
786 fdc
->sc_fcr
|= FCR_DSEL(0)|FCR_MTRON
; /* XXX */
788 fdc
->sc_fcr
&= ~(FCR_DSEL(0)|FCR_MTRON
); /* XXX */
794 fd_motor_off(void *arg
)
796 struct fd_softc
*fd
= arg
;
800 fd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
801 fd_set_motor(device_private(device_parent(fd
->sc_dv
)));
806 fd_motor_on(void *arg
)
808 struct fd_softc
*fd
= arg
;
809 struct fdc_softc
*fdc
= device_private(device_parent(fd
->sc_dv
));
813 fd
->sc_flags
&= ~FD_MOTOR_WAIT
;
814 if ((TAILQ_FIRST(&fdc
->sc_drives
) == fd
) &&
815 (fdc
->sc_state
== MOTORWAIT
))
821 fdcresult(struct fdc_softc
*fdc
)
826 for (j
= 100000; j
; j
--) {
827 i
= *fdc
->sc_reg_msr
& (NE7_DIO
| NE7_RQM
| NE7_CB
);
832 if (i
== (NE7_DIO
| NE7_RQM
| NE7_CB
)) {
833 if (n
>= sizeof(fdc
->sc_status
)) {
834 log(LOG_ERR
, "fdcresult: overrun\n");
837 fdc
->sc_status
[n
++] = *fdc
->sc_reg_fifo
;
841 log(LOG_ERR
, "fdcresult: timeout\n");
847 out_fdc(struct fdc_softc
*fdc
, u_char x
)
851 while (((*fdc
->sc_reg_msr
& (NE7_DIO
|NE7_RQM
)) != NE7_RQM
) && i
-- > 0)
856 *fdc
->sc_reg_fifo
= x
;
861 fdopen(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
865 struct fd_type
*type
;
868 fd
= device_lookup_private(&fd_cd
, unit
);
871 type
= fd_dev_to_type(fd
, dev
);
875 if ((fd
->sc_flags
& FD_OPEN
) != 0 &&
881 fd
->sc_flags
|= FD_OPEN
;
884 * Only update the disklabel if we're not open anywhere else.
886 if (fd
->sc_dk
.dk_openmask
== 0)
889 pmask
= (1 << DISKPART(dev
));
893 fd
->sc_dk
.dk_copenmask
|= pmask
;
897 fd
->sc_dk
.dk_bopenmask
|= pmask
;
900 fd
->sc_dk
.dk_openmask
=
901 fd
->sc_dk
.dk_copenmask
| fd
->sc_dk
.dk_bopenmask
;
907 fdclose(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
909 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
910 int pmask
= (1 << DISKPART(dev
));
912 fd
->sc_flags
&= ~FD_OPEN
;
913 fd
->sc_opts
&= ~(FDOPT_NORETRY
|FDOPT_SILENT
);
917 fd
->sc_dk
.dk_copenmask
&= ~pmask
;
921 fd
->sc_dk
.dk_bopenmask
&= ~pmask
;
924 fd
->sc_dk
.dk_openmask
=
925 fd
->sc_dk
.dk_copenmask
| fd
->sc_dk
.dk_bopenmask
;
931 fdread(dev_t dev
, struct uio
*uio
, int flag
)
934 return physio(fdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
);
938 fdwrite(dev_t dev
, struct uio
*uio
, int flag
)
941 return physio(fdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
);
945 fdcstart(struct fdc_softc
*fdc
)
949 /* only got here if controller's drive queue was inactive; should
951 if (fdc
->sc_state
!= DEVIDLE
) {
952 printf("%s: not idle\n", __func__
);
960 fdcpstatus(int n
, struct fdc_softc
*fdc
)
969 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
970 printf(" (st0 %s cyl %d)\n", bits
, fdc
->sc_status
[1]);
973 snprintb(bits
, sizeof(bits
), NE7_ST0BITS
, fdc
->sc_status
[0]);
974 printf(" (st0 %s", bits
);
975 snprintb(bits
, sizeof(bits
), NE7_ST1BITS
, fdc
->sc_status
[1]);
976 printf(" st1 %s", bits
);
977 snprintb(bits
, sizeof(bits
), NE7_ST2BITS
, fdc
->sc_status
[2]);
978 printf(" st2 %s", bits
);
979 printf(" cyl %d head %d sec %d)\n",
980 fdc
->sc_status
[3], fdc
->sc_status
[4], fdc
->sc_status
[5]);
984 printf("\nfdcstatus: weird size");
991 fdcstatus(device_t dv
, int n
, const char *s
)
993 struct fdc_softc
*fdc
= device_private(device_parent(dv
));
996 * A 82072 seems to return <invalid command> on
997 * gratuitous Sense Interrupt commands.
999 if (n
== 0 && (fdc
->sc_flags
& FDC_82077
)) {
1000 out_fdc(fdc
, NE7CMD_SENSEI
);
1001 (void)fdcresult(fdc
);
1006 /* Just print last status */
1009 printf("%s: %s: state %d", device_xname(dv
), s
, fdc
->sc_state
);
1015 fdctimeout(void *arg
)
1017 struct fdc_softc
*fdc
= arg
;
1018 struct fd_softc
*fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1022 fdcstatus(fd
->sc_dv
, 0, "timeout");
1024 if (bufq_peek(fd
->sc_q
) != NULL
)
1027 fdc
->sc_state
= DEVIDLE
;
1029 (void)fdcstate(fdc
);
1034 fdcpseudointr(void *arg
)
1036 struct fdc_softc
*fdc
= arg
;
1039 /* Just ensure it has the right spl. */
1041 (void)fdcstate(fdc
);
1047 * hardware interrupt entry point: must be converted to `fast'
1048 * (in-window) handler.
1051 fdchwintr(void *arg
)
1053 struct fdc_softc
*fdc
= arg
;
1056 * This code was reverse engineered from the SPARC bsd_fdintr.s.
1058 switch (fdc
->sc_istate
) {
1062 out_fdc(fdc
, NE7CMD_SENSEI
);
1064 fdc
->sc_istate
= ISTATE_DONE
;
1070 log(LOG_ERR
, "fdc: stray hard interrupt.\n");
1071 fdc
->sc_fcr
&= ~(FCR_DSEL(0)); /* Does this help? */
1072 fdc
->sc_istate
= ISTATE_SPURIOUS
;
1080 msr
= *fdc
->sc_reg_msr
;
1082 if ((msr
& NE7_RQM
) == 0)
1085 if ((msr
& NE7_NDM
) == 0) {
1086 /* Execution phase finished, get result. */
1088 fdc
->sc_istate
= ISTATE_DONE
;
1092 log(LOG_ERR
, "fdc: overrun: tc = %d\n",
1098 if (msr
& NE7_DIO
) {
1099 *fdc
->sc_data
++ = *fdc
->sc_reg_fifo
;
1101 *fdc
->sc_reg_fifo
= *fdc
->sc_data
++;
1103 if (--fdc
->sc_tc
== 0) {
1104 fdc
->sc_fcr
|= FCR_TC
;
1107 fdc
->sc_fcr
&= ~FCR_TC
;
1116 fdcswintr(void *arg
)
1118 struct fdc_softc
*fdc
= arg
;
1121 if (fdc
->sc_istate
!= ISTATE_DONE
)
1124 fdc
->sc_istate
= ISTATE_IDLE
;
1131 fdcstate(struct fdc_softc
*fdc
)
1133 #define st0 fdc->sc_status[0]
1134 #define st1 fdc->sc_status[1]
1135 #define cyl fdc->sc_status[1]
1136 #define OUT_FDC(fdc, c, s) \
1138 if (out_fdc(fdc, (c))) { \
1139 (fdc)->sc_state = (s); \
1142 } while (/* CONSTCOND */ 0)
1144 struct fd_softc
*fd
;
1146 int read
, head
, sec
, nblks
;
1147 struct fd_type
*type
;
1148 struct ne7_fd_formb
*finfo
= NULL
;
1151 if (fdc
->sc_istate
!= ISTATE_IDLE
) {
1153 printf("fdc: spurious interrupt: state %d, istate=%d\n",
1154 fdc
->sc_state
, fdc
->sc_istate
);
1155 fdc
->sc_istate
= ISTATE_IDLE
;
1156 if (fdc
->sc_state
== RESETCOMPLETE
||
1157 fdc
->sc_state
== RESETTIMEDOUT
) {
1158 panic("%s: spurious interrupt can't be cleared",
1165 /* Is there a drive for the controller to do a transfer with? */
1166 fd
= TAILQ_FIRST(&fdc
->sc_drives
);
1168 fdc
->sc_state
= DEVIDLE
;
1172 /* Is there a transfer to this drive? If not, deactivate drive. */
1173 bp
= bufq_peek(fd
->sc_q
);
1176 TAILQ_REMOVE(&fdc
->sc_drives
, fd
, sc_drivechain
);
1181 if (bp
->b_flags
& B_FORMAT
)
1182 finfo
= (struct ne7_fd_formb
*)bp
->b_data
;
1184 switch (fdc
->sc_state
) {
1188 fd
->sc_bcount
= bp
->b_bcount
;
1189 fd
->sc_blkno
= bp
->b_blkno
/ (FDC_BSIZE
/ DEV_BSIZE
);
1190 callout_stop(&fd
->sc_motoroff_ch
);
1191 if ((fd
->sc_flags
& FD_MOTOR_WAIT
) != 0) {
1192 fdc
->sc_state
= MOTORWAIT
;
1195 if ((fd
->sc_flags
& FD_MOTOR
) == 0) {
1196 /* Turn on the motor, being careful about pairing. */
1197 struct fd_softc
*ofd
= fdc
->sc_fd
[fd
->sc_drive
^ 1];
1198 if (ofd
&& ofd
->sc_flags
& FD_MOTOR
) {
1199 callout_stop(&ofd
->sc_motoroff_ch
);
1200 ofd
->sc_flags
&= ~(FD_MOTOR
| FD_MOTOR_WAIT
);
1202 fd
->sc_flags
|= FD_MOTOR
| FD_MOTOR_WAIT
;
1204 fdc
->sc_state
= MOTORWAIT
;
1205 if (fdc
->sc_flags
& FDC_82077
) { /* XXX */
1206 /* Allow .25s for motor to stabilize. */
1207 callout_reset(&fd
->sc_motoron_ch
, hz
/ 4,
1210 fd
->sc_flags
&= ~FD_MOTOR_WAIT
;
1215 /* Make sure the right drive is selected. */
1221 if ((fdc
->sc_flags
& FDC_EIS
) &&
1222 (bp
->b_flags
& B_FORMAT
) == 0) {
1223 fd
->sc_cylin
= bp
->b_cylinder
;
1224 /* We use implied seek */
1228 if (fd
->sc_cylin
== bp
->b_cylinder
)
1231 /* specify command */
1232 OUT_FDC(fdc
, NE7CMD_SPECIFY
, SEEKTIMEDOUT
);
1233 OUT_FDC(fdc
, fd
->sc_type
->steprate
, SEEKTIMEDOUT
);
1234 OUT_FDC(fdc
, 6|1, SEEKTIMEDOUT
); /* XXX head load time == 6ms */
1236 fdc
->sc_istate
= ISTATE_SENSEI
;
1238 OUT_FDC(fdc
, NE7CMD_SEEK
, SEEKTIMEDOUT
);
1239 OUT_FDC(fdc
, fd
->sc_drive
, SEEKTIMEDOUT
); /* drive number */
1240 OUT_FDC(fdc
, bp
->b_cylinder
* fd
->sc_type
->step
, SEEKTIMEDOUT
);
1243 fdc
->sc_state
= SEEKWAIT
;
1246 iostat_seek(fd
->sc_dk
.dk_stats
);
1247 disk_busy(&fd
->sc_dk
);
1249 callout_reset(&fdc
->sc_timo_ch
, 4 * hz
, fdctimeout
, fdc
);
1255 /* Check to see if the disk has changed */
1256 if (fdc
->sc_reg_dir
& FDI_DCHG
) {
1258 * The disk in the drive has changed since
1259 * the last transfer. We need to see if its geometry
1266 fd
->sc_skip
= (char *)&(finfo
->fd_formb_cylno(0)) -
1269 sec
= fd
->sc_blkno
% type
->seccyl
;
1270 nblks
= type
->seccyl
- sec
;
1271 nblks
= min(nblks
, fd
->sc_bcount
/ FDC_BSIZE
);
1272 nblks
= min(nblks
, FDC_MAXIOSIZE
/ FDC_BSIZE
);
1273 fd
->sc_nblks
= nblks
;
1274 fd
->sc_nbytes
= finfo
? bp
->b_bcount
: nblks
* FDC_BSIZE
;
1275 head
= sec
/ type
->sectrac
;
1276 sec
-= head
* type
->sectrac
;
1281 block
= (fd
->sc_cylin
* type
->heads
+ head
) *
1282 type
->sectrac
+ sec
;
1283 if (block
!= fd
->sc_blkno
) {
1284 printf("%s: block %d != blkno %" PRIu64
"\n",
1285 device_xname(fdc
->sc_dev
), block
,
1293 read
= bp
->b_flags
& B_READ
;
1295 /* Setup for pseudo DMA */
1296 fdc
->sc_data
= (char *)bp
->b_data
+ fd
->sc_skip
;
1297 fdc
->sc_tc
= fd
->sc_nbytes
;
1299 *fdc
->sc_reg_drs
= type
->rate
;
1302 printf("%s: %s drive %d track %d head %d sec %d "
1303 "nblks %d\n", __func__
,
1304 read
? "read" : "write", fd
->sc_drive
,
1305 fd
->sc_cylin
, head
, sec
, nblks
);
1307 fdc
->sc_state
= IOCOMPLETE
;
1308 fdc
->sc_istate
= ISTATE_DMA
;
1312 OUT_FDC(fdc
, NE7CMD_FORMAT
, IOTIMEDOUT
);
1313 OUT_FDC(fdc
, (head
<< 2) | fd
->sc_drive
, IOTIMEDOUT
);
1314 OUT_FDC(fdc
, finfo
->fd_formb_secshift
, IOTIMEDOUT
);
1315 OUT_FDC(fdc
, finfo
->fd_formb_nsecs
, IOTIMEDOUT
);
1316 OUT_FDC(fdc
, finfo
->fd_formb_gaplen
, IOTIMEDOUT
);
1317 OUT_FDC(fdc
, finfo
->fd_formb_fillbyte
, IOTIMEDOUT
);
1320 OUT_FDC(fdc
, NE7CMD_READ
, IOTIMEDOUT
);
1322 OUT_FDC(fdc
, NE7CMD_WRITE
, IOTIMEDOUT
);
1323 OUT_FDC(fdc
, (head
<< 2) | fd
->sc_drive
, IOTIMEDOUT
);
1324 OUT_FDC(fdc
, fd
->sc_cylin
, IOTIMEDOUT
); /*track*/
1325 OUT_FDC(fdc
, head
, IOTIMEDOUT
);
1326 OUT_FDC(fdc
, sec
+ 1, IOTIMEDOUT
); /*sector+1*/
1327 OUT_FDC(fdc
, type
->secsize
, IOTIMEDOUT
);/*sector size*/
1328 OUT_FDC(fdc
, type
->sectrac
, IOTIMEDOUT
);/*secs/track*/
1329 OUT_FDC(fdc
, type
->gap1
, IOTIMEDOUT
); /*gap1 size*/
1330 OUT_FDC(fdc
, type
->datalen
, IOTIMEDOUT
);/*data length*/
1333 disk_busy(&fd
->sc_dk
);
1335 /* allow 2 seconds for operation */
1336 callout_reset(&fdc
->sc_timo_ch
, 2 * hz
, fdctimeout
, fdc
);
1337 return 1; /* will return later */
1340 callout_stop(&fdc
->sc_timo_ch
);
1341 fdc
->sc_state
= SEEKCOMPLETE
;
1342 if (fdc
->sc_flags
& FDC_NEEDHEADSETTLE
) {
1343 /* allow 1/50 second for heads to settle */
1344 callout_reset(&fdc
->sc_intr_ch
, hz
/ 50,
1345 fdcpseudointr
, fdc
);
1346 return 1; /* will return later */
1350 /* no data on seek */
1351 disk_unbusy(&fd
->sc_dk
, 0, 0);
1353 /* Make sure seek really happened. */
1354 if (fdc
->sc_nstat
!= 2 || (st0
& 0xf8) != 0x20 ||
1355 cyl
!= bp
->b_cylinder
* fd
->sc_type
->step
) {
1358 fdcstatus(fd
->sc_dv
, 2, "seek failed");
1363 fd
->sc_cylin
= bp
->b_cylinder
;
1367 fdc
->sc_fcr
|= FCR_TC
;
1370 fdc
->sc_fcr
&= ~FCR_TC
;
1372 (void)fdcresult(fdc
);
1380 case IOCOMPLETE
: /* IO DONE, post-analyze */
1381 callout_stop(&fdc
->sc_timo_ch
);
1383 disk_unbusy(&fd
->sc_dk
, (bp
->b_bcount
- bp
->b_resid
),
1384 (bp
->b_flags
& B_READ
));
1386 if (fdc
->sc_nstat
!= 7 || (st0
& 0xf8) != 0 || st1
!= 0) {
1389 fdcstatus(fd
->sc_dv
, 7,
1390 bp
->b_flags
& B_READ
1391 ? "read failed" : "write failed");
1392 printf("blkno %d nblks %d tc %d\n",
1393 (int)fd
->sc_blkno
, fd
->sc_nblks
,
1397 if (fdc
->sc_nstat
== 7 &&
1398 (st1
& ST1_OVERRUN
) == ST1_OVERRUN
) {
1401 * Silently retry overruns if no other
1402 * error bit is set. Adjust threshold.
1404 int thr
= fdc
->sc_cfg
& CFG_THRHLD_MASK
;
1407 fdc
->sc_cfg
&= ~CFG_THRHLD_MASK
;
1408 fdc
->sc_cfg
|= (thr
& CFG_THRHLD_MASK
);
1411 printf("fdc: %d -> threshold\n",
1415 fdc
->sc_overruns
= 0;
1417 if (++fdc
->sc_overruns
< 3) {
1418 fdc
->sc_state
= DOIO
;
1425 if (fdc
->sc_errors
) {
1426 diskerr(bp
, "fd", "soft error", LOG_PRINTF
,
1427 fd
->sc_skip
/ FDC_BSIZE
, NULL
);
1431 if (--fdc
->sc_overruns
< -20) {
1432 int thr
= fdc
->sc_cfg
& CFG_THRHLD_MASK
;
1435 fdc
->sc_cfg
&= ~CFG_THRHLD_MASK
;
1436 fdc
->sc_cfg
|= (thr
& CFG_THRHLD_MASK
);
1439 printf("fdc: %d -> threshold\n",
1444 fdc
->sc_overruns
= 0;
1447 fd
->sc_blkno
+= fd
->sc_nblks
;
1448 fd
->sc_skip
+= fd
->sc_nbytes
;
1449 fd
->sc_bcount
-= fd
->sc_nbytes
;
1450 if (!finfo
&& fd
->sc_bcount
> 0) {
1451 bp
->b_cylinder
= fd
->sc_blkno
/ fd
->sc_type
->seccyl
;
1459 /* try a reset, keep motor on */
1464 fdc
->sc_istate
= ISTATE_SENSEI
;
1465 fdc
->sc_state
= RESETCOMPLETE
;
1466 callout_reset(&fdc
->sc_timo_ch
, hz
/ 2, fdctimeout
, fdc
);
1467 return 1; /* will return later */
1470 callout_stop(&fdc
->sc_timo_ch
);
1475 fdc
->sc_state
= RECALWAIT
;
1476 fdc
->sc_istate
= ISTATE_SENSEI
;
1478 /* recalibrate function */
1479 OUT_FDC(fdc
, NE7CMD_RECAL
, RECALTIMEDOUT
);
1480 OUT_FDC(fdc
, fd
->sc_drive
, RECALTIMEDOUT
);
1481 callout_reset(&fdc
->sc_timo_ch
, 5 * hz
, fdctimeout
, fdc
);
1482 return 1; /* will return later */
1485 callout_stop(&fdc
->sc_timo_ch
);
1486 fdc
->sc_state
= RECALCOMPLETE
;
1487 if (fdc
->sc_flags
& FDC_NEEDHEADSETTLE
) {
1488 /* allow 1/30 second for heads to settle */
1489 callout_reset(&fdc
->sc_intr_ch
, hz
/ 30,
1490 fdcpseudointr
, fdc
);
1491 return 1; /* will return later */
1495 if (fdc
->sc_nstat
!= 2 || (st0
& 0xf8) != 0x20 || cyl
!= 0) {
1498 fdcstatus(fd
->sc_dv
, 2, "recalibrate failed");
1507 if (fd
->sc_flags
& FD_MOTOR_WAIT
)
1508 return 1; /* time's not up yet */
1512 fdcstatus(fd
->sc_dv
, 0, "stray interrupt");
1516 panic("%s: impossible", __func__
);
1524 fdcretry(struct fdc_softc
*fdc
)
1526 struct fd_softc
*fd
;
1529 fd
= fdc
->sc_drives
.tqh_first
;
1530 bp
= bufq_peek(fd
->sc_q
);
1532 fdc
->sc_overruns
= 0;
1533 if (fd
->sc_opts
& FDOPT_NORETRY
)
1536 switch (fdc
->sc_errors
) {
1540 (fdc
->sc_flags
& FDC_EIS
) ? DOIO
: DOSEEK
;
1546 /* didn't work; try recalibrating */
1547 fdc
->sc_state
= DORECAL
;
1551 /* still no go; reset the bastard */
1552 fdc
->sc_state
= DORESET
;
1557 if ((fd
->sc_opts
& FDOPT_SILENT
) == 0) {
1558 diskerr(bp
, "fd", "hard error", LOG_PRINTF
,
1559 fd
->sc_skip
/ FDC_BSIZE
, NULL
);
1571 fdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
1573 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
1574 struct fdformat_parms
*form_parms
;
1575 struct fdformat_cmd
*form_cmd
;
1576 struct ne7_fd_formb
*fd_formb
;
1577 int il
[FD_MAX_NSEC
+ 1];
1583 *(struct disklabel
*)addr
= *(fd
->sc_dk
.dk_label
);
1587 if ((flag
& FWRITE
) == 0)
1589 /* XXX do something */
1593 if ((flag
& FWRITE
) == 0)
1596 error
= setdisklabel(fd
->sc_dk
.dk_label
,
1597 (struct disklabel
*)addr
, 0, fd
->sc_dk
.dk_cpulabel
);
1601 error
= writedisklabel(dev
, fdstrategy
, fd
->sc_dk
.dk_label
,
1602 fd
->sc_dk
.dk_cpulabel
);
1607 * Nothing to do here, really.
1612 if (*(int *)addr
== 0) {
1613 int part
= DISKPART(dev
);
1615 * Don't force eject: check that we are the only
1616 * partition open. If so, unlock it.
1618 if ((fd
->sc_dk
.dk_openmask
& ~(1 << part
)) != 0 ||
1619 fd
->sc_dk
.dk_bopenmask
+ fd
->sc_dk
.dk_copenmask
!=
1620 fd
->sc_dk
.dk_openmask
) {
1626 fd_do_eject(device_private(device_parent(fd
->sc_dv
)),
1630 case FDIOCGETFORMAT
:
1631 form_parms
= (struct fdformat_parms
*)addr
;
1632 form_parms
->fdformat_version
= FDFORMAT_VERSION
;
1633 form_parms
->nbps
= 128 * (1 << fd
->sc_type
->secsize
);
1634 form_parms
->ncyl
= fd
->sc_type
->tracks
;
1635 form_parms
->nspt
= fd
->sc_type
->sectrac
;
1636 form_parms
->ntrk
= fd
->sc_type
->heads
;
1637 form_parms
->stepspercyl
= fd
->sc_type
->step
;
1638 form_parms
->gaplen
= fd
->sc_type
->gap2
;
1639 form_parms
->fillbyte
= fd
->sc_type
->fillbyte
;
1640 form_parms
->interleave
= fd
->sc_type
->interleave
;
1641 switch (fd
->sc_type
->rate
) {
1643 form_parms
->xfer_rate
= 500 * 1024;
1646 form_parms
->xfer_rate
= 300 * 1024;
1649 form_parms
->xfer_rate
= 250 * 1024;
1656 case FDIOCSETFORMAT
:
1657 if ((flag
& FWRITE
) == 0)
1658 return EBADF
; /* must be opened for writing */
1660 form_parms
= (struct fdformat_parms
*)addr
;
1661 if (form_parms
->fdformat_version
!= FDFORMAT_VERSION
)
1662 return EINVAL
; /* wrong version of formatting prog */
1664 i
= form_parms
->nbps
>> 7;
1665 if ((form_parms
->nbps
& 0x7f) || ffs(i
) == 0 ||
1666 i
& ~(1 << (ffs(i
) - 1)))
1667 /* not a power-of-two multiple of 128 */
1670 switch (form_parms
->xfer_rate
) {
1672 fd
->sc_type
->rate
= FDC_500KBPS
;
1675 fd
->sc_type
->rate
= FDC_300KBPS
;
1678 fd
->sc_type
->rate
= FDC_250KBPS
;
1684 if (form_parms
->nspt
> FD_MAX_NSEC
||
1685 form_parms
->fillbyte
> 0xff ||
1686 form_parms
->interleave
> 0xff)
1688 fd
->sc_type
->sectrac
= form_parms
->nspt
;
1689 if (form_parms
->ntrk
!= 2 && form_parms
->ntrk
!= 1)
1691 fd
->sc_type
->heads
= form_parms
->ntrk
;
1692 fd
->sc_type
->seccyl
= form_parms
->nspt
* form_parms
->ntrk
;
1693 fd
->sc_type
->secsize
= ffs(i
) - 1;
1694 fd
->sc_type
->gap2
= form_parms
->gaplen
;
1695 fd
->sc_type
->tracks
= form_parms
->ncyl
;
1696 fd
->sc_type
->size
= fd
->sc_type
->seccyl
* form_parms
->ncyl
*
1697 form_parms
->nbps
/ DEV_BSIZE
;
1698 fd
->sc_type
->step
= form_parms
->stepspercyl
;
1699 fd
->sc_type
->fillbyte
= form_parms
->fillbyte
;
1700 fd
->sc_type
->interleave
= form_parms
->interleave
;
1703 case FDIOCFORMAT_TRACK
:
1704 if((flag
& FWRITE
) == 0)
1705 /* must be opened for writing */
1707 form_cmd
= (struct fdformat_cmd
*)addr
;
1708 if (form_cmd
->formatcmd_version
!= FDFORMAT_VERSION
)
1709 /* wrong version of formatting prog */
1712 if (form_cmd
->head
>= fd
->sc_type
->heads
||
1713 form_cmd
->cylinder
>= fd
->sc_type
->tracks
) {
1717 fd_formb
= malloc(sizeof(struct ne7_fd_formb
),
1722 fd_formb
->head
= form_cmd
->head
;
1723 fd_formb
->cyl
= form_cmd
->cylinder
;
1724 fd_formb
->transfer_rate
= fd
->sc_type
->rate
;
1725 fd_formb
->fd_formb_secshift
= fd
->sc_type
->secsize
;
1726 fd_formb
->fd_formb_nsecs
= fd
->sc_type
->sectrac
;
1727 fd_formb
->fd_formb_gaplen
= fd
->sc_type
->gap2
;
1728 fd_formb
->fd_formb_fillbyte
= fd
->sc_type
->fillbyte
;
1730 memset(il
, 0, sizeof(il
));
1731 for (j
= 0, i
= 1; i
<= fd_formb
->fd_formb_nsecs
; i
++) {
1732 while (il
[(j
%fd_formb
->fd_formb_nsecs
) + 1])
1734 il
[(j
% fd_formb
->fd_formb_nsecs
) + 1] = i
;
1735 j
+= fd
->sc_type
->interleave
;
1737 for (i
= 0; i
< fd_formb
->fd_formb_nsecs
; i
++) {
1738 fd_formb
->fd_formb_cylno(i
) = form_cmd
->cylinder
;
1739 fd_formb
->fd_formb_headno(i
) = form_cmd
->head
;
1740 fd_formb
->fd_formb_secno(i
) = il
[i
+1];
1741 fd_formb
->fd_formb_secsize(i
) = fd
->sc_type
->secsize
;
1744 error
= fdformat(dev
, fd_formb
, l
->l_proc
);
1745 free(fd_formb
, M_TEMP
);
1748 case FDIOCGETOPTS
: /* get drive options */
1749 *(int *)addr
= fd
->sc_opts
;
1752 case FDIOCSETOPTS
: /* set drive options */
1753 fd
->sc_opts
= *(int *)addr
;
1760 struct fdc_softc
*fdc
=
1761 device_private(device_parent(fd
->sc_dv
));
1763 out_fdc(fdc
, NE7CMD_DUMPREG
);
1765 printf("dumpreg(%d regs): <", fdc
->sc_nstat
);
1766 for (k
= 0; k
< fdc
->sc_nstat
; k
++)
1767 printf(" %x", fdc
->sc_status
[k
]);
1772 case _IOW('f', 101, int):
1773 struct fdc_softc
*fdc
=
1774 device_private(device_parent(fd
->sc_dv
));
1776 fdc
->sc_cfg
&= ~CFG_THRHLD_MASK
;
1777 fdc
->sc_cfg
|= (*(int *)addr
& CFG_THRHLD_MASK
);
1784 struct fdc_softc
*fdc
=
1785 device_private(device_parent(fd
->sc_dv
));
1787 out_fdc(fdc
, NE7CMD_SENSEI
);
1789 printf("sensei(%d regs): <", fdc
->sc_nstat
);
1790 for (k
=0; k
< fdc
->sc_nstat
; k
++)
1791 printf(" 0x%x", fdc
->sc_status
[k
]);
1801 panic("%s: impossible", __func__
);
1806 fdformat(dev_t dev
, struct ne7_fd_formb
*finfo
, struct proc
*p
)
1809 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, FDUNIT(dev
));
1810 struct fd_type
*type
= fd
->sc_type
;
1813 /* set up a buffer header for fdstrategy() */
1814 bp
= getiobuf(NULL
, false);
1819 bp
->b_cflags
= BC_BUSY
;
1820 bp
->b_flags
= B_PHYS
| B_FORMAT
;
1825 * Calculate a fake blkno, so fdstrategy() would initiate a
1826 * seek to the requested cylinder.
1828 bp
->b_blkno
= (finfo
->cyl
* (type
->sectrac
* type
->heads
)
1829 + finfo
->head
* type
->sectrac
) * FDC_BSIZE
/ DEV_BSIZE
;
1831 bp
->b_bcount
= sizeof(struct fd_idfield_data
) * finfo
->fd_formb_nsecs
;
1832 bp
->b_data
= (void *)finfo
;
1836 printf("%s: blkno %x count %d\n",
1837 __func__
, (int)bp
->b_blkno
, bp
->b_bcount
);
1840 /* now do the format */
1843 /* ...and wait for it to complete */
1850 fdgetdisklabel(dev_t dev
)
1852 int unit
= FDUNIT(dev
), i
;
1853 struct fd_softc
*fd
= device_lookup_private(&fd_cd
, unit
);
1854 struct disklabel
*lp
= fd
->sc_dk
.dk_label
;
1855 struct cpu_disklabel
*clp
= fd
->sc_dk
.dk_cpulabel
;
1857 memset(lp
, 0, sizeof(struct disklabel
));
1858 memset(lp
, 0, sizeof(struct cpu_disklabel
));
1860 lp
->d_type
= DTYPE_FLOPPY
;
1861 lp
->d_secsize
= FDC_BSIZE
;
1862 lp
->d_secpercyl
= fd
->sc_type
->seccyl
;
1863 lp
->d_nsectors
= fd
->sc_type
->sectrac
;
1864 lp
->d_ncylinders
= fd
->sc_type
->tracks
;
1865 lp
->d_ntracks
= fd
->sc_type
->heads
; /* Go figure... */
1866 lp
->d_rpm
= 3600; /* XXX like it matters... */
1868 strncpy(lp
->d_typename
, "floppy", sizeof(lp
->d_typename
));
1869 strncpy(lp
->d_packname
, "fictitious", sizeof(lp
->d_packname
));
1870 lp
->d_interleave
= 1;
1872 lp
->d_partitions
[RAW_PART
].p_offset
= 0;
1873 lp
->d_partitions
[RAW_PART
].p_size
= lp
->d_secpercyl
* lp
->d_ncylinders
;
1874 lp
->d_partitions
[RAW_PART
].p_fstype
= FS_UNUSED
;
1875 lp
->d_npartitions
= RAW_PART
+ 1;
1877 lp
->d_magic
= DISKMAGIC
;
1878 lp
->d_magic2
= DISKMAGIC
;
1879 lp
->d_checksum
= dkcksum(lp
);
1882 * Call the generic disklabel extraction routine. If there's
1883 * not a label there, fake it.
1885 if (readdisklabel(dev
, fdstrategy
, lp
, clp
) != NULL
) {
1886 strncpy(lp
->d_packname
, "default label",
1887 sizeof(lp
->d_packname
));
1889 * Reset the partition info; it might have gotten
1890 * trashed in readdisklabel().
1892 * XXX Why do we have to do this? readdisklabel()
1895 for (i
= 0; i
< MAXPARTITIONS
; ++i
) {
1896 lp
->d_partitions
[i
].p_offset
= 0;
1897 if (i
== RAW_PART
) {
1898 lp
->d_partitions
[i
].p_size
=
1899 lp
->d_secpercyl
* lp
->d_ncylinders
;
1900 lp
->d_partitions
[i
].p_fstype
= FS_BSDFFS
;
1902 lp
->d_partitions
[i
].p_size
= 0;
1903 lp
->d_partitions
[i
].p_fstype
= FS_UNUSED
;
1906 lp
->d_npartitions
= RAW_PART
+ 1;
1911 fd_do_eject(struct fdc_softc
*fdc
, int unit
)
1914 fdc
->sc_fcr
|= FCR_DSEL(unit
)|FCR_EJECT
;
1917 fdc
->sc_fcr
&= ~(FCR_DSEL(unit
)|FCR_EJECT
);
1921 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet
1922 int fd_read_md_image(size_t *, void **);
1927 fd_mountroot_hook(device_t dev
)
1929 struct fd_softc
*fd
;
1930 struct fdc_softc
*fdc
;
1933 fd
= device_private(dev
);
1934 fdc
= device_private(device_parent(dev
));
1935 fd_do_eject(fdc
, fd
->sc_drive
);
1936 printf("Insert filesystem floppy and press return.");
1939 if ((c
== '\r') || (c
== '\n')) {
1944 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet
1946 extern int (*md_read_image
)(size_t *, void **);
1948 md_read_image
= fd_read_md_image
;
1953 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet
1955 #define FDMICROROOTSIZE ((2*18*80) << DEV_BSHIFT)
1958 fd_read_md_image(size_t *sizep
, void **addrp
)
1960 struct fdc_softc
*fdc
;
1961 struct fd_softc
*fd
;
1962 struct buf buf
, *bp
= &buf
;
1967 dev
= makedev(cdevsw_lookup_major(&fd_cdevsw
), 0); /* XXX */
1969 addr
= malloc(FDMICROROOTSIZE
, M_DEVBUF
, M_WAITOK
);
1972 if (fdopen(dev
, 0, S_IFCHR
, NULL
))
1973 panic("fd: mountroot: fdopen");
1982 bp
->b_flags
= B_PHYS
| B_RAW
| B_READ
;
1983 bp
->b_cflags
= BC_BUSY
;
1984 bp
->b_blkno
= btodb(offset
);
1985 bp
->b_bcount
= DEV_BSIZE
;
1990 panic("fd: mountroot: fdread error %d", bp
->b_error
);
1992 if (bp
->b_resid
!= 0)
1996 offset
+= DEV_BSIZE
;
1997 if (offset
+ DEV_BSIZE
> FDMICROROOTSIZE
)
2000 (void)fdclose(dev
, 0, S_IFCHR
, NULL
);
2002 fd
= device_lookup_private(&fd_cd
, 0);
2003 fdc
= device_private(device_parent(fd
->sc_dv
));
2004 fd_do_eject(fdc
, 0); /* XXX */