Module Name:    src
Committed By:   riz
Date:           Sun Nov 18 21:56:37 UTC 2012

Modified Files:
        src/sys/arch/x68k/dev [netbsd-6]: fd.c fdreg.h intio_dmac.c

Log Message:
Pull up following revision(s) (requested by tsutsui in ticket #646):
        sys/arch/x68k/dev/intio_dmac.c: revision 1.34
        sys/arch/x68k/dev/fd.c: revision 1.100
        sys/arch/x68k/dev/fd.c: revision 1.101
        sys/arch/x68k/dev/fd.c: revision 1.102
        sys/arch/x68k/dev/fd.c: revision 1.103
        sys/arch/x68k/dev/fd.c: revision 1.104
        sys/arch/x68k/dev/fd.c: revision 1.105
        sys/arch/x68k/dev/fd.c: revision 1.98
        sys/arch/x68k/dev/fd.c: revision 1.99
        sys/arch/x68k/dev/fdreg.h: revision 1.5
        sys/arch/x68k/dev/fdreg.h: revision 1.6
Explicitly specify a proper FDC data register address for HD63450 DMAC
to avoid confusion.
Previous one (fdc->sc_addr + fddata) wasn't a right address for
the FDC's data register but one for the command register by accident,
but FDC ignores A0 address input (connected to A1 of x68k address bus)
during DMA xfer (i.e. when DACK is asserted) so it happened to work
as expected on the real X680x0 hardware, but caused trouble on emulators.
The inconsistency was found by Y.Sugahara during debugging XM6i emulator
(and it will be fixed in the next release).
FDC behavior during DMA is confirmed by uPD72068 hardware application note.
XXX: There is no proper MI API to specify DMA address for DMA controller
     (like MC68450) to access devices mapped to memory space by bus_space(9).
- use <sys/bus.h> rather than <machine/bus.h>
- no need to include uvm_extern.h
- include "ioconf.h" for struct cfdriver foo_cd
KNF and cosmetics.  No binary change.
- check bus_space_map(9) return value
- use BUS_SPACE_MAP_SHIFTED_ODD for clarify
- define and use proper macro instead of magic
To abort DMA in dmac_abort_xfer(), set DMAC_CCR_SAB (software abort)
rather than DMAC_CCR_HLT (halt operation).
DMAC_CCR_HLT doesn't abort DMA xfers but only suspends DMA ops
(i.e. clearing HLT bit will resume DMA xfers), so previously
DMAC error always occurs on the next DMA xfer ops after
dmac_abort_xfer() is called.
Also suppress DMAC error messages in dmac_error() if it's caused
by software abort command because it can happen during normal
audio play/record DMA ops in vs(4) driver.
Before probing floppy drives, call NE7CMD_SENSEI and fdcresult()
to drain possible pending FDC interrupts.  Taken from sys/dev/isa/fd.c.
Hopefully might fix occasional fd drive probe failure (but not confirmed).
Terminate DMAC and call bus_dmamap_unload(9) properly in all FDC xfer
error paths, as sys/dev/isa/fd.c does.  Fixes unexpected DMAC errors
(and possible VM panic due to un-unloaded dmamap) on the first floppy
access after read/write errors.
Add floppy format support.  Mostly taken from sys/dev/isa/fd.c.
Tested both fdNa (1232KB, 1024bytes/sector, 8sectors/track) and
fdNc (1200KB, 512bytes/sector, 15sectors/track) format on X68030
using fdformat(1).
Finally we can prepare NetBSD/x68k install floppies without Human68k
(except actual initial bootstrap).
KNF and space nits


To generate a diff of this commit:
cvs rdiff -u -r1.96.2.1 -r1.96.2.2 src/sys/arch/x68k/dev/fd.c
cvs rdiff -u -r1.4 -r1.4.118.1 src/sys/arch/x68k/dev/fdreg.h
cvs rdiff -u -r1.33 -r1.33.14.1 src/sys/arch/x68k/dev/intio_dmac.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x68k/dev/fd.c
diff -u src/sys/arch/x68k/dev/fd.c:1.96.2.1 src/sys/arch/x68k/dev/fd.c:1.96.2.2
--- src/sys/arch/x68k/dev/fd.c:1.96.2.1	Wed May  9 20:01:51 2012
+++ src/sys/arch/x68k/dev/fd.c	Sun Nov 18 21:56:37 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: fd.c,v 1.96.2.1 2012/05/09 20:01:51 riz Exp $	*/
+/*	$NetBSD: fd.c,v 1.96.2.2 2012/11/18 21:56:37 riz Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -64,13 +64,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.96.2.1 2012/05/09 20:01:51 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.96.2.2 2012/11/18 21:56:37 riz Exp $");
 
 #include "opt_ddb.h"
 #include "opt_m68k_arch.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/bus.h>
 #include <sys/callout.h>
 #include <sys/kernel.h>
 #include <sys/conf.h>
@@ -86,14 +87,12 @@ __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.96.
 #include <sys/uio.h>
 #include <sys/syslog.h>
 #include <sys/queue.h>
+#include <sys/proc.h>
 #include <sys/fdio.h>
 #include <sys/rnd.h>
 
-#include <uvm/uvm_extern.h>
-
 #include <dev/cons.h>
 
-#include <machine/bus.h>
 #include <machine/cpu.h>
 
 #include <arch/x68k/dev/intiovar.h>
@@ -102,6 +101,7 @@ __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.96.
 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
 
 #include "locators.h"
+#include "ioconf.h"
 
 #ifdef FDDEBUG
 #define DPRINTF(x)      if (fddebug) printf x
@@ -113,6 +113,9 @@ int     fddebug = 0;
 #define FDUNIT(dev)	(minor(dev) / 8)
 #define FDTYPE(dev)	(minor(dev) % 8)
 
+/* (mis)use device use flag to identify format operation */
+#define B_FORMAT B_DEVPRIVATE
+
 enum fdc_state {
 	DEVIDLE = 0,
 	MOTORWAIT,
@@ -145,7 +148,7 @@ struct fdc_softc {
 
 	bus_dma_tag_t sc_dmat;		/* intio DMA tag */
 	bus_dmamap_t sc_dmamap;		/* DMA map */
-	u_int8_t *sc_addr;			/* physical address */
+	uint8_t *sc_addr;		/* physical address */
 	struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
 	struct dmac_dma_xfer *sc_xfer;	/* DMA transfer */
 	int sc_read;
@@ -154,7 +157,7 @@ struct fdc_softc {
 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
 	enum fdc_state sc_state;
 	int sc_errors;			/* number of retries so far */
-	u_char sc_status[7];		/* copy of registers */
+	uint8_t sc_status[7];		/* copy of registers */
 } fdc_softc;
 
 int fdcintr(void *);
@@ -168,8 +171,6 @@ int fdprint(void *, const char *);
 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
     fdcprobe, fdcattach, NULL, NULL);
 
-extern struct cfdriver fdc_cd;
-
 /*
  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
  * we tell them apart.
@@ -187,19 +188,29 @@ struct fd_type {
 	int	size;		/* size of disk in sectors */
 	int	step;		/* steps per cylinder */
 	int	rate;		/* transfer speed code */
+	uint8_t	fillbyte;	/* format fill byte */
+	uint8_t	interleave;	/* interleave factor (formatting) */
 	const char *name;
 };
 
 /* The order of entries in the following table is important -- BEWARE! */
 struct fd_type fd_types[] = {
-        {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
-        { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
-        { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
-        {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
-        {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
-        {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
-        {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
-        {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
+	{  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, 0xf6, 1,
+	    "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
+	{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS, 0xf6, 1,
+	    "1.44MB"    }, /* 1.44MB diskette */
+	{ 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, 0xf6, 1,
+	    "1.2MB"    }, /* 1.2 MB AT-diskettes */
+	{  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, 0xf6, 1,
+	    "360KB/AT" }, /* 360kB in 1.2MB drive */
+	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, 0xf6, 1,
+	    "360KB/PC" }, /* 360kB PC diskettes */
+	{  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, 0xf6, 1,
+	    "720KB"    }, /* 3.5" 720kB diskette */
+	{  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, 0xf6, 1,
+	    "720KB/x"  }, /* 720kB in 1.2MB drive */
+	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, 0xf6, 1,
+	    "360KB/x"  }, /* 360kB in 720kB drive */
 };
 
 /* software state, per disk (with up to 4 disks per ctlr) */
@@ -236,8 +247,8 @@ struct fd_softc {
 	int sc_ops;		/* I/O ops since last switch */
 	struct bufq_state *sc_q;/* pending I/O requests */
 	int sc_active;		/* number of active I/O operations */
-	u_char *sc_copybuf;	/* for secsize >=3 */
-	u_char sc_part;		/* for secsize >=3 */
+	uint8_t *sc_copybuf;	/* for secsize >=3 */
+	uint8_t sc_part;	/* for secsize >=3 */
 #define	SEC_P10	0x02		/* first part */
 #define	SEC_P01	0x01		/* second part */
 #define	SEC_P11	0x03		/* both part */
@@ -252,8 +263,6 @@ void fdattach(device_t, device_t, void *
 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
     fdprobe, fdattach, NULL, NULL);
 
-extern struct cfdriver fd_cd;
-
 dev_type_open(fdopen);
 dev_type_close(fdclose);
 dev_type_read(fdread);
@@ -280,7 +289,7 @@ void fd_motor_off(void *);
 void fd_motor_on(void *);
 #endif
 int fdcresult(struct fdc_softc *);
-int out_fdc(bus_space_tag_t, bus_space_handle_t, u_char);
+int out_fdc(bus_space_tag_t, bus_space_handle_t, uint8_t);
 void fdcstart(struct fdc_softc *);
 void fdcstatus(device_t, int, const char *);
 void fdctimeout(void *);
@@ -288,6 +297,7 @@ void fdcpseudointr(void *);
 void fdcretry(struct fdc_softc *);
 void fdfinish(struct fd_softc *, struct buf *);
 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
+int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
 static int fdcpoll(struct fdc_softc *);
 static int fdgetdisklabel(struct fd_softc *, dev_t);
 static void fd_do_eject(struct fdc_softc *, int);
@@ -296,6 +306,7 @@ void fd_mountroot_hook(device_t);
 
 /* DMA transfer routines */
 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
+inline static void fdc_dmaabort(struct fdc_softc *);
 static int fdcdmaintr(void *);
 static int fdcdmaerrintr(void *);
 
@@ -305,30 +316,47 @@ fdc_dmastart(struct fdc_softc *fdc, int 
 	int error;
 
 	DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
-		 read ? "read" : "write", (void *) addr, count));
+	    read ? "read" : "write", (void *)addr, count));
 
 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
-				0, BUS_DMA_NOWAIT);
+	    0, BUS_DMA_NOWAIT);
 	if (error) {
-		panic ("fdc_dmastart: cannot load dmamap");
+		panic("fdc_dmastart: cannot load dmamap");
 	}
 
 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
-			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
+	    read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
 
+	/*
+	 * Note 1:
+	 *  uPD72065 ignores A0 input (connected to x68k bus A1)
+	 *  during DMA xfer access, but it's better to explicitly
+	 *  specify FDC data register address for clarification.
+	 * Note 2:
+	 *  FDC is connected to LSB 8 bits of X68000 16 bit bus
+	 *  (as BUS_SPACE_MAP_SHIFTED_ODD defined in bus.h)
+	 *  so each FDC regsiter is mapped at sparse odd address.
+	 *
+	 * XXX: No proper API to get DMA address of FDC register for DMAC.
+	 */
 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
-					 fdc->sc_dmamap,
-					 (read?
-					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
-					 (DMAC_SCR_MAC_COUNT_UP|
-					  DMAC_SCR_DAC_NO_COUNT),
-					 (u_int8_t*) (fdc->sc_addr +
-						      fddata));	/* XXX */
+	    fdc->sc_dmamap,
+	    read ? DMAC_OCR_DIR_DTM : DMAC_OCR_DIR_MTD,
+	    DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT,
+	    fdc->sc_addr + fddata * 2 + 1);
 
 	fdc->sc_read = read;
 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
 }
 
+inline static void
+fdc_dmaabort(struct fdc_softc *fdc)
+{
+
+	dmac_abort_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
+	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
+}
+
 static int
 fdcdmaintr(void *arg)
 {
@@ -346,6 +374,7 @@ fdcdmaintr(void *arg)
 static int
 fdcdmaerrintr(void *dummy)
 {
+
 	DPRINTF(("fdcdmaerrintr\n"));
 
 	return 0;
@@ -372,8 +401,8 @@ fdcprobe(device_t parent, cfdata_t cf, v
 	if ((ia->ia_intr & 0x03) != 0)
 		return 0;
 
-	ia->ia_size = 0x2000;
-	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
+	ia->ia_size = FDC_MAPSIZE;
+	if (intio_map_allocate_region(parent, ia, INTIO_MAP_TESTONLY))
 		return 0;
 
 	/* builtin device; always there */
@@ -400,7 +429,7 @@ fdprint(void *aux, const char *fdc)
 {
 	struct fdc_attach_args *fa = aux;
 
-	if (!fdc)
+	if (fdc == NULL)
 		aprint_normal(" drive %d", fa->fa_drive);
 	return QUIET;
 }
@@ -418,12 +447,16 @@ fdcattach(device_t parent, device_t self
 
 	aprint_normal("\n");
 
+	/* Re-map the I/O space. */
+	if (bus_space_map(iot, ia->ia_addr, ia->ia_size,
+	    BUS_SPACE_MAP_SHIFTED_ODD, &ioh) != 0) {
+		aprint_error_dev(self, "unable to map I/O space\n");
+		return;
+	}
+
 	callout_init(&fdc->sc_timo_ch, 0);
 	callout_init(&fdc->sc_intr_ch, 0);
 
-	/* Re-map the I/O space. */
-	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
-
 	fdc->sc_iot = iot;
 	fdc->sc_ioh = ioh;
 	fdc->sc_addr = (void *)ia->ia_addr;
@@ -434,18 +467,16 @@ fdcattach(device_t parent, device_t self
 
 	/* Initialize DMAC channel */
 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
-					     ia->ia_dmaintr, fdcdmaintr, fdc,
-					     ia->ia_dmaintr+1, fdcdmaerrintr,
-					     fdc);
+	    ia->ia_dmaintr, fdcdmaintr, fdc,
+	    ia->ia_dmaintr + 1, fdcdmaerrintr, fdc);
 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
-			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
-			      &fdc->sc_dmamap)) {
+	    0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &fdc->sc_dmamap)) {
 		aprint_error_dev(self, "can't set up intio DMA map\n");
 		return;
 	}
 
-	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
-		panic ("Could not establish interrupt (duplicated vector?).");
+	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc) != 0)
+		panic("Could not establish interrupt (duplicated vector?).");
 	intio_set_ivec(ia->ia_intr);
 
 	/* reset */
@@ -455,7 +486,7 @@ fdcattach(device_t parent, device_t self
 	fdcreset(fdc);
 
 	aprint_normal_dev(self, "uPD72065 FDC\n");
-	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
+	out_fdc(iot, ioh, NE7CMD_SPECIFY);	/* specify command */
 	out_fdc(iot, ioh, 0xd0);
 	out_fdc(iot, ioh, 0x10);
 
@@ -470,6 +501,7 @@ fdcattach(device_t parent, device_t self
 void
 fdcreset(struct fdc_softc *fdc)
 {
+
 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
 }
 
@@ -477,8 +509,9 @@ static int
 fdcpoll(struct fdc_softc *fdc)
 {
 	int i = 25000, n;
+
 	while (--i > 0) {
-		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
+		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) != 0) {
 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
 			n = fdcresult(fdc);
 			break;
@@ -507,6 +540,11 @@ fdprobe(device_t parent, cfdata_t cf, vo
 
 	type = &fd_types[0];	/* XXX 1.2MB */
 
+	/* toss any interrupt status */
+	for (n = 0; n < 4; n++) {
+		out_fdc(iot, ioh, NE7CMD_SENSEI);
+		(void)fdcresult(fdc);
+	}
 	intio_disable_intr(SICILIAN_INTR_FDC);
 
 	/* select drive and turn on motor */
@@ -514,13 +552,13 @@ fdprobe(device_t parent, cfdata_t cf, vo
 	fdc_force_ready(FDCRDY);
 	fdcpoll(fdc);
 
-retry:
+ retry:
 	out_fdc(iot, ioh, NE7CMD_RECAL);
 	out_fdc(iot, ioh, drive);
 
 	i = 25000;
 	while (--i > 0) {
-		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
+		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC) != 0) {
 			out_fdc(iot, ioh, NE7CMD_SENSEI);
 			n = fdcresult(fdc);
 			break;
@@ -547,7 +585,7 @@ retry:
 
 	/* turn off motor */
 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
-			  fdctl, (type->rate << 4)| drive);
+	    fdctl, (type->rate << 4) | drive);
 	fdc_force_ready(FDCSTBY);
 	if (!found) {
 		intio_enable_intr(SICILIAN_INTR_FDC);
@@ -579,7 +617,7 @@ fdattach(device_t parent, device_t self,
 
 	if (type)
 		aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
-		       type->cyls, type->heads, type->sectrac);
+		    type->cyls, type->heads, type->sectrac);
 	else
 		aprint_normal(": density unknown\n");
 
@@ -589,7 +627,7 @@ fdattach(device_t parent, device_t self,
 	fd->sc_deftype = type;
 	fdc->sc_fd[drive] = fd;
 
-	fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
+	fd->sc_copybuf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
 	if (fd->sc_copybuf == 0)
 		aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
 	fd->sc_flags |= FD_ALIVE;
@@ -607,7 +645,7 @@ fdattach(device_t parent, device_t self,
 	mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
 
 	rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
-			  RND_TYPE_DISK, 0);
+	    RND_TYPE_DISK, 0);
 }
 
 inline struct fd_type *
@@ -636,10 +674,11 @@ fdstrategy(struct buf *bp)
 	}
 
 	if (bp->b_blkno < 0 ||
-	    (bp->b_bcount % FDC_BSIZE) != 0) {
+	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
+	     (bp->b_flags & B_FORMAT) == 0)) {
 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
-			 "bcount=%d\n", unit,
-			 bp->b_blkno, bp->b_bcount));
+		    "bcount=%d\n", unit,
+		    bp->b_blkno, bp->b_bcount));
 		bp->b_error = EINVAL;
 		goto done;
 	}
@@ -669,12 +708,12 @@ fdstrategy(struct buf *bp)
 	}
 
 	bp->b_rawblkno = bp->b_blkno;
-	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
-		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
+	bp->b_cylinder = (bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)) /
+	    (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
 
 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
-		 bp->b_flags & B_READ ? "read" : "write",
-		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
+	    bp->b_flags & B_READ ? "read" : "write",
+	    bp->b_blkno, bp->b_bcount, bp->b_cylinder));
 	/* Queue transfer on drive, activate drive and controller if idle. */
 	s = splbio();
 	bufq_put(fd->sc_q, bp);
@@ -683,7 +722,9 @@ fdstrategy(struct buf *bp)
 		fdstart(fd);
 #ifdef DIAGNOSTIC
 	else {
-		struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
+		struct fdc_softc *fdc;
+
+		fdc = device_private(device_parent(fd->sc_dev));
 		if (fdc->sc_state == DEVIDLE) {
 			printf("fdstrategy: controller inactive\n");
 			fdcstart(fdc);
@@ -693,7 +734,7 @@ fdstrategy(struct buf *bp)
 	splx(s);
 	return;
 
-done:
+ done:
 	/* Toss transfer; we're done early. */
 	biodone(bp);
 }
@@ -728,9 +769,9 @@ fdfinish(struct fd_softc *fd, struct buf
 	if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
 		fd->sc_ops = 0;
 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
-		if (bufq_peek(fd->sc_q) != NULL) {
+		if (bufq_peek(fd->sc_q) != NULL)
 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
-		} else
+		else
 			fd->sc_active = 0;
 	}
 	bp->b_resid = fd->sc_bcount;
@@ -748,14 +789,14 @@ int
 fdread(dev_t dev, struct uio *uio, int flags)
 {
 
-	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
+	return physio(fdstrategy, NULL, dev, B_READ, minphys, uio);
 }
 
 int
 fdwrite(dev_t dev, struct uio *uio, int flags)
 {
 
-	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
+	return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio);
 }
 
 void
@@ -765,26 +806,27 @@ fd_set_motor(struct fdc_softc *fdc, int 
 	int n;
 
 	DPRINTF(("fd_set_motor:\n"));
-	for (n = 0; n < 4; n++)
-		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
+	for (n = 0; n < 4; n++) {
+		fd = fdc->sc_fd[n];
+		if (fd != NULL && (fd->sc_flags & FD_MOTOR) != 0)
 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
-					  0x80 | (fd->sc_type->rate << 4)| n);
-		}
+			    0x80 | (fd->sc_type->rate << 4)| n);
+	}
 }
 
 void
 fd_motor_off(void *arg)
 {
 	struct fd_softc *fd = arg;
- 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
+	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
 	int s;
 
 	DPRINTF(("fd_motor_off:\n"));
 
 	s = splbio();
 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
-	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
-			   (fd->sc_type->rate << 4) | fd->sc_drive);
+	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
+	    (fd->sc_type->rate << 4) | fd->sc_drive);
 #if 0
 	fd_set_motor(fdc, 0); /* XXX */
 #endif
@@ -803,8 +845,9 @@ fd_motor_on(void *arg)
 
 	s = splbio();
 	fd->sc_flags &= ~FD_MOTOR_WAIT;
-	if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && (fdc->sc_state == MOTORWAIT))
-		(void) fdcintr(fdc);
+	if ((TAILQ_FIRST(&fdc->sc_drives) == fd) &&
+	    (fdc->sc_state == MOTORWAIT))
+		(void)fdcintr(fdc);
 	splx(s);
 }
 #endif
@@ -814,11 +857,11 @@ fdcresult(struct fdc_softc *fdc)
 {
 	bus_space_tag_t iot = fdc->sc_iot;
 	bus_space_handle_t ioh = fdc->sc_ioh;
-	u_char i;
-	int j = 100000,
-	    n = 0;
+	uint8_t i;
+	int j, n;
 
-	for (; j; j--) {
+	n = 0;
+	for (j = 100000; j != 0; j--) {
 		i = bus_space_read_1(iot, ioh, fdsts) &
 		  (NE7_DIO | NE7_RQM | NE7_CB);
 
@@ -830,7 +873,7 @@ fdcresult(struct fdc_softc *fdc)
 				return -1;
 			}
 			fdc->sc_status[n++] =
-			  bus_space_read_1(iot, ioh, fddata);
+			    bus_space_read_1(iot, ioh, fddata);
 		}
 		delay(10);
 	}
@@ -839,7 +882,7 @@ fdcresult(struct fdc_softc *fdc)
 }
 
 int
-out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
+out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t x)
 {
 	int i = 100000;
 
@@ -877,7 +920,7 @@ fdopen(dev_t dev, int flags, int mode, s
 	if ((fd->sc_flags & FD_OPEN) == 0) {
 		/* Lock eject button */
 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
-				  0x40 | ( 1 << unit));
+		    0x40 | (1 << unit));
 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
 	}
 
@@ -916,9 +959,12 @@ fdclose(dev_t dev, int flags, int mode, 
 		break;
 	}
 
+	/* clear flags */
+	fd->sc_opts &= ~(FDOPT_NORETRY | FDOPT_SILENT);
+
 	if ((fd->sc_flags & FD_OPEN) == 0) {
 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
-				  ( 1 << unit));
+		    (1 << unit));
 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
 	}
 	return 0;
@@ -929,14 +975,16 @@ fdcstart(struct fdc_softc *fdc)
 {
 
 #ifdef DIAGNOSTIC
-	/* only got here if controller's drive queue was inactive; should
-	   be in idle state */
+	/*
+	 * only got here if controller's drive queue was inactive; should
+	 * be in idle state
+	 */
 	if (fdc->sc_state != DEVIDLE) {
 		printf("fdcstart: not idle\n");
 		return;
 	}
 #endif
-	(void) fdcintr(fdc);
+	(void)fdcintr(fdc);
 }
 
 
@@ -978,7 +1026,7 @@ fdcstatus(device_t dv, int n, const char
 
 	if (n == 0) {
 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
-		(void) fdcresult(fdc);
+		(void)fdcresult(fdc);
 		n = 2;
 	}
 
@@ -1001,7 +1049,7 @@ fdctimeout(void *arg)
 	else
 		fdc->sc_state = DEVIDLE;
 
-	(void) fdcintr(fdc);
+	(void)fdcintr(fdc);
 	splx(s);
 }
 
@@ -1014,7 +1062,7 @@ fdcpseudointr(void *arg)
 
 	/* just ensure it has the right spl */
 	s = splbio();
-	(void) fdcintr(fdc);
+	(void)fdcintr(fdc);
 	splx(s);
 }
 #endif
@@ -1030,15 +1078,17 @@ fdcintr(void *arg)
 	bus_space_tag_t iot = fdc->sc_iot;
 	bus_space_handle_t ioh = fdc->sc_ioh;
 	int read, head, sec, pos, i, sectrac, nblks;
-	int	tmp;
+	int tmp;
 	struct fd_type *type;
+	struct ne7_fd_formb *finfo = NULL;
 
-loop:
+ loop:
 	fd = TAILQ_FIRST(&fdc->sc_drives);
 	if (fd == NULL) {
 		DPRINTF(("fdcintr: set DEVIDLE\n"));
 		if (fdc->sc_state == DEVIDLE) {
-			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
+			if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)
+			    != 0) {
 				out_fdc(iot, ioh, NE7CMD_SENSEI);
 				if ((tmp = fdcresult(fdc)) != 2 ||
 				    (st0 & 0xf8) != 0x20) {
@@ -1060,6 +1110,9 @@ loop:
 		goto loop;
 	}
 
+	if (bp->b_flags & B_FORMAT)
+		finfo = (struct ne7_fd_formb *)bp->b_data;
+
 	switch (fdc->sc_state) {
 	case DEVIDLE:
 		DPRINTF(("fdcintr: in DEVIDLE\n"));
@@ -1077,10 +1130,11 @@ loop:
 			/* being careful about other drives. */
 			for (i = 0; i < 4; i++) {
 				struct fd_softc *ofd = fdc->sc_fd[i];
-				if (ofd && ofd->sc_flags & FD_MOTOR) {
+				if (ofd != NULL &&
+				    (ofd->sc_flags & FD_MOTOR) != 0) {
 					callout_stop(&ofd->sc_motoroff_ch);
 					ofd->sc_flags &=
-						~(FD_MOTOR | FD_MOTOR_WAIT);
+					    ~(FD_MOTOR | FD_MOTOR_WAIT);
 					break;
 				}
 			}
@@ -1104,11 +1158,11 @@ loop:
 		if (fd->sc_cylin == bp->b_cylinder)
 			goto doio;
 
-		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
-		out_fdc(iot, ioh, 0xd0);	/* XXX const */
+		out_fdc(iot, ioh, NE7CMD_SPECIFY);	/* specify command */
+		out_fdc(iot, ioh, 0xd0);		/* XXX const */
 		out_fdc(iot, ioh, 0x10);
 
-		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
+		out_fdc(iot, ioh, NE7CMD_SEEK);		/* seek function */
 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
 
@@ -1125,10 +1179,13 @@ loop:
 	doio:
 		DPRINTF(("fdcintr: DOIO: "));
 		type = fd->sc_type;
+		if (finfo != NULL)
+			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
+			    (char *)finfo;
 		sectrac = type->sectrac;
 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
 		sec = pos / (1 << (type->secsize - 2));
-		if (type->secsize == 2) {
+		if (finfo != NULL || type->secsize == 2) {
 			fd->sc_part = SEC_P11;
 			nblks = (sectrac - sec) << (type->secsize - 2);
 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
@@ -1142,14 +1199,13 @@ loop:
 				} else {
 					fd->sc_part = SEC_P11;
 					nblks = (sectrac - sec) * 2;
-					nblks = min(nblks, fd->sc_bcount
-						    / FDC_BSIZE - 1);
+					nblks = min(nblks,
+					    fd->sc_bcount / FDC_BSIZE - 1);
 					DPRINTF(("nblks(2)"));
 				}
 			} else {
 				fd->sc_part = SEC_P11;
-				nblks = (sectrac - sec)
-					<< (type->secsize - 2);
+				nblks = (sectrac - sec) << (type->secsize - 2);
 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
 				DPRINTF(("nblks(3)"));
 			}
@@ -1161,52 +1217,69 @@ loop:
 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
 		DPRINTF((" %d\n", nblks));
 		fd->sc_nblks = nblks;
-		fd->sc_nbytes = nblks * FDC_BSIZE;
+		fd->sc_nbytes =
+		    (finfo != NULL) ? bp->b_bcount : nblks * FDC_BSIZE;
 		head = (fd->sc_blkno
-			% (type->seccyl * (1 << (type->secsize - 2))))
-			 / (type->sectrac * (1 << (type->secsize - 2)));
+		    % (type->seccyl * (1 << (type->secsize - 2))))
+		    / (type->sectrac * (1 << (type->secsize - 2)));
 
 #ifdef DIAGNOSTIC
-		{int block;
-		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
-			  + sec) * (1 << (type->secsize - 2));
-		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
-		 if (block != fd->sc_blkno) {
-			 printf("C H R N: %d %d %d %d\n",
-				fd->sc_cylin, head, sec, type->secsize);
-			 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
-				block, fd->sc_blkno);
+		{
+			int block;
+			block = ((fd->sc_cylin * type->heads + head) *
+			    type->sectrac + sec) * (1 << (type->secsize - 2));
+			block += (fd->sc_part == SEC_P01) ? 1 : 0;
+			if (block != fd->sc_blkno) {
+				printf("C H R N: %d %d %d %d\n",
+				    fd->sc_cylin, head, sec, type->secsize);
+				printf("fdcintr: doio: block %d != blkno %"
+				    PRId64 "\n",
+				    block, fd->sc_blkno);
 #ifdef DDB
-			 Debugger();
+				Debugger();
 #endif
-		 }
+			}
 		}
 #endif
 		read = bp->b_flags & B_READ;
 		DPRINTF(("fdcintr: %s drive %d track %d "
-		         "head %d sec %d nblks %d, skip %d\n",
-			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
-			 head, sec, nblks, fd->sc_skip));
+		    "head %d sec %d nblks %d, skip %d\n",
+		    read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
+		    head, sec, nblks, fd->sc_skip));
 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
-			 type->secsize));
+		    type->secsize));
 
-		if (fd->sc_part != SEC_P11)
+		if (finfo == NULL && fd->sc_part != SEC_P11)
 			goto docopy;
 
 		fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
-			     fd->sc_nbytes);
-		if (read)
-			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
-		else
-			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
-		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
-		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
-		out_fdc(iot, ioh, head);
-		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
-		out_fdc(iot, ioh, type->secsize);	/* sector size */
-		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
-		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
-		out_fdc(iot, ioh, type->datalen);	/* data length */
+		    fd->sc_nbytes);
+		if (finfo != NULL) {
+			/* formatting */
+			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
+				fdc->sc_errors = 4;
+				fdcretry(fdc);
+				goto loop;
+			}
+			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
+			out_fdc(iot, ioh, finfo->fd_formb_secshift);
+			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
+			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
+			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
+		} else {
+			if (read)
+				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
+			else
+				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
+			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
+			out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
+			out_fdc(iot, ioh, head);
+			out_fdc(iot, ioh, sec + 1);		/* sector +1 */
+			out_fdc(iot, ioh, type->secsize); /* sector size */
+			out_fdc(iot, ioh, type->sectrac); /* sectors/track */
+			out_fdc(iot, ioh, type->gap1);		/* gap1 size */
+			out_fdc(iot, ioh, type->datalen); /* data length */
+		}
 		fdc->sc_state = IOCOMPLETE;
 
 		disk_busy(&fd->sc_dk);
@@ -1220,9 +1293,10 @@ loop:
 		DPRINTF(("fdcintr: DOCOPY:\n"));
 		type = fd->sc_type;
 		head = (fd->sc_blkno
-			% (type->seccyl * (1 << (type->secsize - 2))))
-			 / (type->sectrac * (1 << (type->secsize - 2)));
-		pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
+		    % (type->seccyl * (1 << (type->secsize - 2))))
+		    / (type->sectrac * (1 << (type->secsize - 2)));
+		pos = fd->sc_blkno %
+		    (type->sectrac * (1 << (type->secsize - 2)));
 		sec = pos / (1 << (type->secsize - 2));
 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
@@ -1248,21 +1322,22 @@ loop:
 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
 		sec = pos / (1 << (type->secsize - 2));
 		head = (fd->sc_blkno
-			% (type->seccyl * (1 << (type->secsize - 2))))
-			 / (type->sectrac * (1 << (type->secsize - 2)));
+		    % (type->seccyl * (1 << (type->secsize - 2))))
+		    / (type->sectrac * (1 << (type->secsize - 2)));
 #ifdef DIAGNOSTIC
-		{int block;
-		 block = ((fd->sc_cylin * type->heads + head) *
-			 type->sectrac + sec)
-			 * (1 << (type->secsize - 2));
-		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
-		 if (block != fd->sc_blkno) {
-			 printf("fdcintr: block %d != blkno %" PRId64 "\n",
-				block, fd->sc_blkno);
+		{
+			int block;
+			block = ((fd->sc_cylin * type->heads + head) *
+			    type->sectrac + sec) * (1 << (type->secsize - 2));
+			block += (fd->sc_part == SEC_P01) ? 1 : 0;
+			if (block != fd->sc_blkno) {
+				printf("fdcintr: block %d != blkno %" PRId64
+				    "\n",
+				    block, fd->sc_blkno);
 #ifdef DDB
-			 Debugger();
+				Debugger();
 #endif
-		 }
+			}
 		}
 #endif
 		if ((read = bp->b_flags & B_READ)) {
@@ -1303,7 +1378,7 @@ loop:
 	case SEEKCOMPLETE:
 		/* Make sure seek really happened */
 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
-			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
+		    bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
 		out_fdc(iot, ioh, NE7CMD_SENSEI);
 		tmp = fdcresult(fdc);
 		if ((st0 & 0xf8) == 0xc0) {
@@ -1311,8 +1386,8 @@ loop:
 			fdc->sc_state = DORECAL;
 			goto loop;
 		} else if (tmp != 2 ||
-			   (st0 & 0xf8) != 0x20 ||
-			   cyl != bp->b_cylinder) {
+		    (st0 & 0xf8) != 0x20 ||
+		    cyl != bp->b_cylinder) {
 #ifdef FDDEBUG
 			fdcstatus(fd->sc_dev, 2, "seek failed");
 #endif
@@ -1323,9 +1398,7 @@ loop:
 		goto doio;
 
 	case IOTIMEDOUT:
-#if 0
-		isa_dmaabort(fdc->sc_drq);
-#endif
+		fdc_dmaabort(fdc);
 	case SEEKTIMEDOUT:
 	case RECALTIMEDOUT:
 	case RESETTIMEDOUT:
@@ -1336,20 +1409,14 @@ loop:
 		callout_stop(&fdc->sc_timo_ch);
 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
-#if 0
-			isa_dmaabort(fdc->sc_drq);
-#endif
+			fdc_dmaabort(fdc);
 			fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ?
-				  "read failed" : "write failed");
+			    "read failed" : "write failed");
 			printf("blkno %" PRId64 " nblks %d\n",
 			    fd->sc_blkno, fd->sc_nblks);
 			fdcretry(fdc);
 			goto loop;
 		}
-#if 0
-		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
-		    nblks * FDC_BSIZE, fdc->sc_drq);
-#endif
 	iocomplete2:
 		if (fdc->sc_errors) {
 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
@@ -1361,10 +1428,10 @@ loop:
 		fd->sc_skip += fd->sc_nbytes;
 		fd->sc_bcount -= fd->sc_nbytes;
 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
-		if (fd->sc_bcount > 0) {
+		if (finfo == NULL && fd->sc_bcount > 0) {
 			bp->b_cylinder = fd->sc_blkno
-				/ (fd->sc_type->seccyl
-				   * (1 << (fd->sc_type->secsize - 2)));
+			    / (fd->sc_type->seccyl
+			    * (1 << (fd->sc_type->secsize - 2)));
 			goto doseek;
 		}
 		fdfinish(fd, bp);
@@ -1375,11 +1442,9 @@ loop:
 		callout_stop(&fdc->sc_timo_ch);
 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
-#if 0
-			isa_dmaabort(fdc->sc_drq);
-#endif
+			fdc_dmaabort(fdc);
 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
-				  "read failed" : "write failed");
+			    "read failed" : "write failed");
 			printf("blkno %" PRId64 " nblks %d\n",
 			    fd->sc_blkno, fd->sc_nblks);
 			fdcretry(fdc);
@@ -1403,7 +1468,7 @@ loop:
 		/* clear the controller output buffer */
 		for (i = 0; i < 4; i++) {
 			out_fdc(iot, ioh, NE7CMD_SENSEI);
-			(void) fdcresult(fdc);
+			(void)fdcresult(fdc);
 		}
 
 		/* fall through */
@@ -1483,13 +1548,18 @@ fdcretry(struct fdc_softc *fdc)
 	fd = TAILQ_FIRST(&fdc->sc_drives);
 	bp = bufq_peek(fd->sc_q);
 
+	if (fd->sc_opts & FDOPT_NORETRY)
+		goto fail;
+
 	switch (fdc->sc_errors) {
 	case 0:
 		/* try again */
 		fdc->sc_state = SEEKCOMPLETE;
 		break;
 
-	case 1: case 2: case 3:
+	case 1:
+	case 2:
+	case 3:
 		/* didn't work; try recalibrating */
 		fdc->sc_state = DORECAL;
 		break;
@@ -1500,9 +1570,12 @@ fdcretry(struct fdc_softc *fdc)
 		break;
 
 	default:
-		diskerr(bp, "fd", "hard error", LOG_PRINTF,
-			fd->sc_skip, (struct disklabel *)NULL);
-		fdcpstatus(7, fdc);
+	fail:
+		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
+			diskerr(bp, "fd", "hard error", LOG_PRINTF,
+			    fd->sc_skip, (struct disklabel *)NULL);
+			fdcpstatus(7, fdc);
+		}
 
 		bp->b_error = EIO;
 		fdfinish(fd, bp);
@@ -1515,17 +1588,23 @@ fdioctl(dev_t dev, u_long cmd, void *add
 {
 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
+	struct fdformat_parms *form_parms;
+	struct fdformat_cmd *form_cmd;
+	struct ne7_fd_formb *fd_formb;
 	int part = DISKPART(dev);
 	struct disklabel buffer;
 	int error;
+	unsigned int scratch;
+	int il[FD_MAX_NSEC + 1];
+	int i, j;
 
 	DPRINTF(("fdioctl:"));
 	switch (cmd) {
 	case DIOCGDINFO:
 		DPRINTF(("DIOCGDINFO\n"));
 #if 1
-		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
-		return(0);
+		*(struct disklabel *)addr = *fd->sc_dk.dk_label;
+		return 0;
 #else
 		memset(&buffer, 0, sizeof(buffer));
 
@@ -1545,7 +1624,7 @@ fdioctl(dev_t dev, u_long cmd, void *add
 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
 		((struct partinfo *)addr)->part =
 		    &fd->sc_dk.dk_label->d_partitions[part];
-		return(0);
+		return 0;
 
 	case DIOCWLABEL:
 		DPRINTF(("DIOCWLABEL\n"));
@@ -1560,13 +1639,141 @@ fdioctl(dev_t dev, u_long cmd, void *add
 			return EBADF;
 
 		error = setdisklabel(&buffer, (struct disklabel *)addr,
-		                     0, NULL);
+		    0, NULL);
 		if (error)
 			return error;
 
 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
 		return error;
 
+	case FDIOCGETFORMAT:
+		DPRINTF(("FDIOCGETFORMAT\n"));
+		form_parms = (struct fdformat_parms *)addr;
+		form_parms->fdformat_version = FDFORMAT_VERSION;
+		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
+		form_parms->ncyl = fd->sc_type->cyls;
+		form_parms->nspt = fd->sc_type->sectrac;
+		form_parms->ntrk = fd->sc_type->heads;
+		form_parms->stepspercyl = fd->sc_type->step;
+		form_parms->gaplen = fd->sc_type->gap2;
+		form_parms->fillbyte = fd->sc_type->fillbyte;
+		form_parms->interleave = fd->sc_type->interleave;
+		switch (fd->sc_type->rate) {
+		case FDC_500KBPS:
+			form_parms->xfer_rate = 500 * 1024;
+			break;
+		case FDC_300KBPS:
+			form_parms->xfer_rate = 300 * 1024;
+			break;
+		case FDC_250KBPS:
+			form_parms->xfer_rate = 250 * 1024;
+			break;
+		default:
+			return EINVAL;
+		}
+		return 0;
+
+	case FDIOCSETFORMAT:
+		DPRINTF(("FDIOCSETFORMAT\n"));
+		if((flag & FWRITE) == 0)
+			return EBADF;	/* must be opened for writing */
+		form_parms = (struct fdformat_parms *)addr;
+		if (form_parms->fdformat_version != FDFORMAT_VERSION)
+			return EINVAL;	/* wrong version of formatting prog */
+
+		scratch = form_parms->nbps >> 7;
+		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
+		    scratch & ~(1 << (ffs(scratch) - 1)))
+			/* not a power-of-two multiple of 128 */
+			return EINVAL;
+
+		switch (form_parms->xfer_rate) {
+		case 500 * 1024:
+			fd->sc_type->rate = FDC_500KBPS;
+			break;
+		case 300 * 1024:
+			fd->sc_type->rate = FDC_300KBPS;
+			break;
+		case 250 * 1024:
+			fd->sc_type->rate = FDC_250KBPS;
+			break;
+		default:
+			return EINVAL;
+		}
+
+		if (form_parms->nspt > FD_MAX_NSEC ||
+		    form_parms->fillbyte > 0xff ||
+		    form_parms->interleave > 0xff)
+			return EINVAL;
+		fd->sc_type->sectrac = form_parms->nspt;
+		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
+			return EINVAL;
+		fd->sc_type->heads = form_parms->ntrk;
+		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
+		fd->sc_type->secsize = ffs(scratch)-1;
+		fd->sc_type->gap2 = form_parms->gaplen;
+		fd->sc_type->cyls = form_parms->ncyl;
+		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
+		    form_parms->nbps / DEV_BSIZE;
+		fd->sc_type->step = form_parms->stepspercyl;
+		fd->sc_type->fillbyte = form_parms->fillbyte;
+		fd->sc_type->interleave = form_parms->interleave;
+		return 0;
+
+	case FDIOCFORMAT_TRACK:
+		DPRINTF(("FDIOCFORMAT_TRACK\n"));
+		if ((flag & FWRITE) == 0)
+			return EBADF;	/* must be opened for writing */
+		form_cmd = (struct fdformat_cmd *)addr;
+		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
+			return EINVAL;	/* wrong version of formatting prog */
+
+		if (form_cmd->head >= fd->sc_type->heads ||
+		    form_cmd->cylinder >= fd->sc_type->cyls) {
+			return EINVAL;
+		}
+
+		fd_formb = malloc(sizeof(struct ne7_fd_formb),
+		    M_TEMP, M_NOWAIT);
+		if (fd_formb == NULL)
+			return ENOMEM;
+
+		fd_formb->head = form_cmd->head;
+		fd_formb->cyl = form_cmd->cylinder;
+		fd_formb->transfer_rate = fd->sc_type->rate;
+		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
+		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
+		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
+		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
+
+		memset(il, 0, sizeof il);
+		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
+			while (il[(j % fd_formb->fd_formb_nsecs) + 1])
+				j++;
+			il[(j % fd_formb->fd_formb_nsecs)+  1] = i;
+			j += fd->sc_type->interleave;
+		}
+		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
+			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
+			fd_formb->fd_formb_headno(i) = form_cmd->head;
+			fd_formb->fd_formb_secno(i) = il[i + 1];
+			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
+		}
+
+		error = fdformat(dev, fd_formb, l);
+		free(fd_formb, M_TEMP);
+		return error;
+
+	case FDIOCGETOPTS:		/* get drive options */
+		DPRINTF(("FDIOCGETOPTS\n"));
+		*(int *)addr = fd->sc_opts;
+		return 0;
+
+	case FDIOCSETOPTS:        	/* set drive options */
+		DPRINTF(("FDIOCSETOPTS\n"));
+		fd->sc_opts = *(int *)addr;
+		return 0;
+
 	case DIOCLOCK:
 		/*
 		 * Nothing to do here, really.
@@ -1583,7 +1790,7 @@ fdioctl(dev_t dev, u_long cmd, void *add
 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
 			    fd->sc_dk.dk_openmask) {
-				return (EBUSY);
+				return EBUSY;
 			}
 		}
 		/* FALLTHROUGH */
@@ -1601,11 +1808,53 @@ fdioctl(dev_t dev, u_long cmd, void *add
 #endif
 }
 
+int
+fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
+{
+	int rv = 0;
+	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
+	struct fd_type *type = fd->sc_type;
+	struct buf *bp;
+
+	/* set up a buffer header for fdstrategy() */
+	bp = getiobuf(NULL, false);
+	if (bp == NULL)
+		return ENOBUFS;
+
+	bp->b_cflags = BC_BUSY;
+	bp->b_flags = B_PHYS | B_FORMAT;
+	bp->b_proc = l->l_proc;
+	bp->b_dev = dev;
+
+	/*
+	 * calculate a fake blkno, so fdstrategy() would initiate a
+	 * seek to the requested cylinder
+	 */
+	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
+	    + finfo->head * type->sectrac) * (128 << type->secsize) / DEV_BSIZE;
+
+	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+	bp->b_data = (void *)finfo;
+
+#ifdef FD_DEBUG
+	printf("fdformat: blkno %" PRIx64 " count %x\n",
+	    bp->b_blkno, bp->b_bcount);
+#endif
+
+	/* now do the format */
+	fdstrategy(bp);
+
+	/* ...and wait for it to complete */
+	rv = biowait(bp);
+	putiobuf(bp);
+	return rv;
+}
+
 void
 fd_do_eject(struct fdc_softc *fdc, int unit)
 {
-	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
-			  0x20 | ( 1 << unit));
+
+	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20 | (1 << unit));
 	DELAY(1); /* XXX */
 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
 }
@@ -1649,7 +1898,7 @@ fdgetdisklabel(struct fd_softc *sc, dev_
 	lp->d_partitions[part].p_fsize  = 1024;
 	lp->d_partitions[part].p_frag   = 8;
 
-	return(0);
+	return 0;
 }
 
 /*

Index: src/sys/arch/x68k/dev/fdreg.h
diff -u src/sys/arch/x68k/dev/fdreg.h:1.4 src/sys/arch/x68k/dev/fdreg.h:1.4.118.1
--- src/sys/arch/x68k/dev/fdreg.h:1.4	Sun Dec 11 12:19:37 2005
+++ src/sys/arch/x68k/dev/fdreg.h	Sun Nov 18 21:56:37 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: fdreg.h,v 1.4 2005/12/11 12:19:37 christos Exp $	*/
+/*	$NetBSD: fdreg.h,v 1.4.118.1 2012/11/18 21:56:37 riz Exp $	*/
 
 /*-
  * Copyright (c) 1991 The Regents of the University of California.
@@ -56,6 +56,56 @@
 
 /* default attach args */
 #define FDC_ADDR 0xe94000	/* builtin fdc is here */
+#define FDC_MAPSIZE 0x2000	/* builtin fdc I/O range */
 #define FDC_INTR 96		/* interrupt vector */
 #define FDC_DMA 0		/* DMA ch# */
 #define FDC_DMAINTR 100		/* DMA interrupt vector */
+
+/*
+ * fdformat parameters
+ */
+
+#define FD_MAX_NSEC	18	/* highest known number of spt */
+
+struct ne7_fd_formb {
+	int cyl, head;
+	int transfer_rate;	/* fdreg.h: FDC_???KBPS */
+
+	union {
+		struct fd_form_data {
+			/*
+			 * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
+			 * it is hardware-dependent since it exactly
+			 * matches the byte sequence to write to FDC
+			 * during its `format track' operation
+			 */
+			uint8_t secshift; /* 0 -> 128, ...; usually 2 -> 512 */
+			uint8_t nsecs;    /* must be <= FD_MAX_NSEC */
+			uint8_t gaplen;   /* GAP 3 length; usually 84 */
+			uint8_t fillbyte; /* usually 0xf6 */
+			struct fd_idfield_data {
+				/*
+				 * data to write into id fields;
+				 * for obscure formats, they mustn't match
+				 * the real values (but mostly do)
+				 */
+				uint8_t cylno;		/* 0 thru 79 (or 39) */
+				uint8_t headno;		/* 0, or 1 */
+				uint8_t secno;		/* starting at 1! */
+				uint8_t secsize;	/* usually 2 */
+			} idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
+		} structured;
+		uint8_t raw[1];	/* to have continuous indexed access */
+	} format_info;
+};
+
+/* make life easier */
+# define fd_formb_secshift   format_info.structured.secshift
+# define fd_formb_nsecs      format_info.structured.nsecs
+# define fd_formb_gaplen     format_info.structured.gaplen
+# define fd_formb_fillbyte   format_info.structured.fillbyte
+/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */
+# define fd_formb_cylno(i)   format_info.structured.idfields[i].cylno
+# define fd_formb_headno(i)  format_info.structured.idfields[i].headno
+# define fd_formb_secno(i)   format_info.structured.idfields[i].secno
+# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize

Index: src/sys/arch/x68k/dev/intio_dmac.c
diff -u src/sys/arch/x68k/dev/intio_dmac.c:1.33 src/sys/arch/x68k/dev/intio_dmac.c:1.33.14.1
--- src/sys/arch/x68k/dev/intio_dmac.c:1.33	Sun Jun  6 04:50:08 2010
+++ src/sys/arch/x68k/dev/intio_dmac.c	Sun Nov 18 21:56:36 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: intio_dmac.c,v 1.33 2010/06/06 04:50:08 mrg Exp $	*/
+/*	$NetBSD: intio_dmac.c,v 1.33.14.1 2012/11/18 21:56:36 riz Exp $	*/
 
 /*-
  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
 #include "opt_m68k_arch.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intio_dmac.c,v 1.33 2010/06/06 04:50:08 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intio_dmac.c,v 1.33.14.1 2012/11/18 21:56:36 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -530,10 +530,18 @@ dmac_error(void *arg)
 {
 	struct dmac_channel_stat *chan = arg;
 	struct dmac_softc *sc = chan->ch_softc;
+	uint8_t csr, cer;
 
-	printf("DMAC transfer error CSR=%02x, CER=%02x\n",
-		bus_space_read_1(sc->sc_bst, chan->ch_bht, DMAC_REG_CSR),
-		bus_space_read_1(sc->sc_bst, chan->ch_bht, DMAC_REG_CER));
+	csr = bus_space_read_1(sc->sc_bst, chan->ch_bht, DMAC_REG_CSR);
+	cer = bus_space_read_1(sc->sc_bst, chan->ch_bht, DMAC_REG_CER);
+
+#ifndef DMAC_DEBUG
+	/* Software abort (CER=0x11) could happen on normal xfer termination */
+	if (cer != 0x11)
+#endif
+	{
+		printf("DMAC transfer error CSR=%02x, CER=%02x\n", csr, cer);
+	}
 	DDUMPREGS(3, ("registers were:\n"));
 
 	/* Clear the status bits */
@@ -552,7 +560,7 @@ dmac_abort_xfer(struct dmac_softc *dmac,
 	struct dmac_channel_stat *chan = xf->dx_channel;
 
 	bus_space_write_1(dmac->sc_bst, chan->ch_bht, DMAC_REG_CCR,
-			  DMAC_CCR_INT | DMAC_CCR_HLT);
+			  DMAC_CCR_INT | DMAC_CCR_SAB);
 	bus_space_write_1(dmac->sc_bst, chan->ch_bht, DMAC_REG_CSR, 0xff);
 	xf->dx_nextoff = xf->dx_nextsize = -1;
 

Reply via email to