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;