summaryrefslogtreecommitdiff
path: root/i386/i386at/fd.c
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /i386/i386at/fd.c
Initial source
Diffstat (limited to 'i386/i386at/fd.c')
-rw-r--r--i386/i386at/fd.c1701
1 files changed, 1701 insertions, 0 deletions
diff --git a/i386/i386at/fd.c b/i386/i386at/fd.c
new file mode 100644
index 0000000..773411b
--- /dev/null
+++ b/i386/i386at/fd.c
@@ -0,0 +1,1701 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/* Copyright (c) 1987, 1988 TOSHIBA Corp. */
+/* All Rights Reserved */
+
+#if 0
+
+#include <fd.h>
+
+#ifdef MACH_KERNEL
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <device/buf.h>
+#include <device/errno.h>
+#else MACH_KERNEL
+#include <sys/buf.h>
+#include <sys/errno.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#endif MACH_KERNEL
+#include <i386/pio.h>
+#include <i386/machspl.h>
+#include <chips/busses.h>
+#include <i386at/fdreg.h>
+#include <i386at/disk.h>
+#include <vm/vm_kern.h>
+
+#ifdef DEBUG
+#define D(x) x
+#define DD(x) x
+#else /* DEBUG */
+#define D(x)
+#define DD(x)
+#endif /* DEBUG */
+
+/*
+ * Floppy Device-Table Definitions (drtabs)
+ *
+ * Cyls,Sec,spc,part,Mtype,RWFpl,FGpl
+ */
+struct fddrtab m765f[] = { /* format table */
+ 80, 18, 1440, 9, 0x88, 0x2a, 0x50, /* [0] 3.50" 720 Kb */
+ 80, 36, 2880, 18, 0x08, 0x1b, 0x6c, /* [1] 3.50" 1.44 Meg */
+ 40, 18, 720, 9, 0xa8, 0x2a, 0x50, /* [2] 5.25" 360 Kb */
+ 80, 30, 2400, 15, 0x08, 0x1b, 0x54 /* [3] 5.25" 1.20 Meg */
+};
+
+/*
+ * The following are static initialization variables
+ * which are based on the configuration.
+ */
+struct ctrl_info ctrl_info[MAXUNIT>>1] = { /* device data table */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+struct unit_info unit_info[MAXUNIT]; /* unit buffer headers */
+
+char *fderr = "FD Error on unit";
+char *fdmsg[] = {
+ "?",
+ "Missing data address mark",
+ "Write protected",
+ "Sector not found",
+ "Data Overrun", /* Over run error */
+ "Uncorrectable data read error", /* CRC Error */
+ "FDC Error",
+ "Illegal format type",
+ "Drive not ready",
+ "diskette not present - please insert",
+ "Illegal interrupt type"
+};
+
+struct buf fdrbuf[MAXUNIT]; /* data transfer buffer structures */
+
+int fdminphys();
+int fdintr(), fdprobe(), fdslave();
+void fdattach();
+int FdDmaEISA = 0;
+int FdDmaThreshold = 16 * 1024 * 1024;
+vm_offset_t FdDmaPage = (vm_offset_t) 0;
+vm_offset_t fd_std[NFD] = { 0 };
+struct bus_device *fd_dinfo[NFD*2];
+struct bus_ctlr *fd_minfo[NFD];
+struct bus_driver fddriver =
+ {fdprobe, fdslave, fdattach, 0, fd_std, "fd", fd_dinfo, "fdc", fd_minfo, 0};
+
+int m765verify[MAXUNIT] = {1,1,1,1}; /* write after read flag */
+ /* 0 != verify mode */
+ /* 0 == not verify mode */
+#ifdef MACH_KERNEL
+extern struct buf *geteblk();
+#endif MACH_KERNEL
+
+#define trfrate(uip, type) outb(VFOREG(uip->addr),(((type)&RATEMASK)>>6))
+#define rbskrate(uip, type) trfrate(uip,(type)&RAPID?RPSEEK:NMSEEK)
+#define getparm(type) ((type<0||type>3)?(struct fddrtab *)ERROR:&m765f[type])
+#define relative(s1,s2) ((s1)>(s2)?(s1)-(s2):(s2)-(s1))
+
+fdprobe(port, ctlr)
+struct bus_ctlr *ctlr;
+{
+ int spot = STSREG((int) ctlr->address);
+ struct ctrl_info *cip = &ctrl_info[ctlr->unit];
+ int i, in;
+
+ outb(spot, DATAOK);
+ for (i = 1000; i--;) {
+ in = inb(spot);
+ if ((in&DATAOK) == DATAOK && !(in&0x0f)) {
+ take_ctlr_irq(ctlr);
+ cip->b_cmd.c_rbmtr = 0; /* recalibrate/moter flag */
+ cip->b_cmd.c_intr = CMDRST; /* interrupt flag */
+ cip->b_unitf = 0;
+ cip->b_uip = 0;
+ cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
+ cip->usebuf = 0;
+ if (FdDmaPage) {
+ cip->b_pbuf = FdDmaPage + PAGE_SIZE * ctlr->unit;
+ if (kmem_alloc_pageable(kernel_map,
+ (vm_offset_t *)&cip->b_vbuf,
+ PAGE_SIZE) != KERN_SUCCESS) {
+ printf("%s%d: can not kmem_alloc_pageable.\n",
+ ctlr->name, ctlr->unit);
+ return 0;
+ }
+ (void)pmap_map(cip->b_vbuf,
+ (vm_offset_t)cip->b_pbuf,
+ (vm_offset_t)cip->b_pbuf+PAGE_SIZE,
+ VM_PROT_READ | VM_PROT_WRITE);
+ }
+ printf("%s%d: port = %x, spl = %d, pic = %d.\n", ctlr->name,
+ ctlr->unit, ctlr->address, ctlr->sysdep, ctlr->sysdep1);
+ return(1);
+ }
+ }
+ return(0);
+}
+
+fdslave(dev, xxxx)
+struct bus_device *dev;
+{
+ return(1); /* gross hack */
+}
+
+void fdattach(dev)
+struct bus_device *dev;
+{
+ struct unit_info *uip = &unit_info[dev->unit];
+ struct ctrl_info *cip = &ctrl_info[dev->ctlr];
+
+ uip->dev = dev;
+ dev->address = dev->mi->address;
+ uip->addr = dev->address;
+ uip->b_cmd = &cip->b_cmd;
+ uip->b_seekaddr = 0;
+ uip->av_forw = 0;
+ uip->wakeme = 0;
+ if (cip->b_unitf) {
+ uip->b_unitf=cip->b_unitf->b_unitf;
+ cip->b_unitf->b_unitf=uip;
+ } else {
+ uip->b_unitf=uip;
+ cip->b_unitf=uip;
+ }
+ uip->d_drtab.dr_type &= ~OKTYPE;
+
+ printf(", port = %x, spl = %d, pic = %d.",
+ dev->address, dev->sysdep, dev->sysdep1);
+
+ rstout(uip);
+ specify(uip);
+}
+/*****************************************************************************
+ *
+ * TITLE: fdopen
+ *
+ * ABSTRACT: Open a unit.
+ *
+ ****************************************************************************/
+fdopen(dev, flag, otyp)
+dev_t dev;
+int flag; /* not used */
+int otyp; /* not used */
+{
+ struct fddrtab *driv;
+ struct buf *wbp;
+ spl_t x = SPL();
+ int error = 0;
+ int unit = UNIT(dev);
+ struct unit_info *uip = &unit_info[unit];
+ int slave = uip->dev->slave;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+ if (unit < MAXUNIT){
+ /* Since all functions that use this are called from open, we only
+ set this once, right here. */
+ rstout(uip);
+ cip->b_wup = uip;
+ openchk(cmdp);
+ cmdp->c_devflag |= FDMCHK;
+ chkbusy(cmdp);
+ cmdp->c_stsflag |= MTRFLAG;
+ mtr_on(uip);
+ if(inb(VFOREG(uip->addr))&OPENBIT ||
+ !(uip->d_drtab.dr_type&OKTYPE)){
+ uip->d_drtab.dr_type &= ~OKTYPE;
+ if(!rbrate(RAPID, uip))
+ fdseek(RAPID, uip, 2);
+ if(inb(VFOREG(uip->addr))&OPENBIT)
+ error = ENXIO;
+ }
+ cmdp->c_stsflag &= ~MTRFLAG;
+ mtr_on(uip);
+ openfre(cmdp);
+ if(!error && !(uip->d_drtab.dr_type & OKTYPE)) {
+ if (MEDIATYPE(dev)>3)
+ goto endopen;
+ driv = &m765f[MEDIATYPE(dev)];
+ wbp = geteblk(BLKSIZE);
+ m765sweep(uip, driv);
+ cmdp->c_rbmtr &= ~(1<<(RBSHIFT+(slave)));
+ ++cip->b_rwerr;
+ wbp->b_dev = dev; wbp->b_error = 0; wbp->b_resid = 0;
+ wbp->b_flags = (B_READ|B_VERIFY); wbp->b_bcount = 512;
+ wbp->b_pfcent = 2*driv->dr_spc + driv->dr_nsec - 1;
+ setqueue(wbp, uip);
+ biowait(wbp);
+ brelse(wbp);
+ error = 0;
+ uip->d_drtab.dr_type |= OKTYPE;
+ }
+ } else
+ error = ENXIO;
+ endopen:
+ splx(x);
+ return(error);
+}
+/*****************************************************************************
+ *
+ * TITLE: fdclose
+ *
+ * ABSTRACT: Close a unit.
+ *
+ * Called on last close. mark the unit closed and not-ready.
+ *
+ * Unix doesn't actually "open" an inode for rootdev, swapdev or pipedev.
+ * If UNIT(swapdev) != UNIT(rootdev), then must add code in init() to
+ * "open" swapdev. These devices should never be closed.
+ *
+ *****************************************************************************/
+fdclose(dev, flag, otyp, offset)
+dev_t dev; /* major, minor numbers */
+int flag; /* not used */
+int otyp; /* not used */
+off_t offset; /* not used */
+{
+ extern dev_t rootdev, swapdev;
+ struct unit_info *uip = &unit_info[UNIT(dev)];
+ spl_t s;
+
+#ifdef MACH_KERNEL
+#else MACH_KERNEL
+ if ((dev == rootdev) || (dev == swapdev)) /* never close these */
+ return(0);
+#endif MACH_KERNEL
+
+ /* Clear the bit.
+ * If last close of drive insure drtab queue is empty before returning.
+ */
+ s = SPL();
+ while(uip->av_forw != 0) {
+ uip->wakeme = 1;
+ sleep(uip, PRIBIO);
+ }
+ splx(s);
+#ifdef MACH_KERNEL
+ return(0);
+#else MACH_KERNEL
+ close(0);
+#endif MACH_KERNEL
+}
+/*****************************************************************************
+ *
+ * TITLE: fdstrategy
+ *
+ * ABSTRACT: Queue an I/O Request, and start it if not busy already.
+ *
+ * Reject request if unit is not-ready.
+ *
+ * Note: check for not-ready done here ==> could get requests
+ * queued prior to unit going not-ready.
+ * not-ready status to those requests that are attempted
+ * before a new volume is inserted. Once a new volume is
+ * inserted, would get good I/O's to wrong volume.
+ *
+ * CALLS: iodone(),setqueue()
+ *
+ * CALLING ROUTINES: fdread (indirectly, thru physio)
+ * fdwrite (indirectly, thru physio)
+ *
+ ****************************************************************************/
+fdstrategy(bp)
+struct buf *bp; /* buffer header */
+{
+ unsigned bytes_left;
+ daddr_t secno;
+ struct unit_info *uip = &unit_info[UNIT(bp->b_dev)];
+ struct fddrtab *dr = &uip->d_drtab;
+ struct fddrtab *sdr;
+
+ bp->b_error = 0;
+ /* set b_resid to b_bcount because we haven't done anything yet */
+ bp->b_resid = bp->b_bcount;
+ if (!(dr->dr_type & OKTYPE) ||
+ ((sdr = getparm(MEDIATYPE(bp->b_dev)))==(struct fddrtab *)ERROR) ||
+ /* wrong parameters */
+ (sdr->dr_ncyl != dr->dr_ncyl) || (sdr->dr_nsec != dr->dr_nsec) ||
+ ((sdr->dr_type|OKTYPE) != dr->dr_type) ||
+ (sdr->dr_rwgpl != dr->dr_rwgpl) ||
+ (sdr->dr_fgpl != dr->dr_fgpl)) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ biodone(bp);
+ return(0);
+ }
+ /*
+ * Figure "secno" from b_blkno. Adjust sector # for partition.
+ *
+ * If reading just past the end of the device, it's
+ * End of File. If not reading, or if read starts further in
+ * than the first sector after the partition, it's an error.
+ *
+ * secno is logical blockno / # of logical blocks per sector */
+ secno = (bp->b_blkno * NBPSCTR) >> 9;
+ if (secno >= dr->p_nsec) {
+ if (!((bp->b_flags & B_READ) && (secno == dr->p_nsec))){
+ /* off the deep end */
+ bp->b_flags |= B_ERROR;
+ bp->b_error = ENXIO;
+ }
+ biodone(bp);
+ return(0);
+ }
+/* At this point, it is no longer possible to directly return from strategy.
+ We now set b_resid to the number of bytes we cannot transfer because
+ they lie beyond the end of the request's partition. This value is 0
+ if the entire request is within the partition. */
+ bytes_left = (dr->p_nsec - secno) << 9;
+ bp->b_resid = ((bp->b_bcount<=bytes_left)?0:(bp->b_bcount-bytes_left));
+ bp->b_pfcent = secno;
+ setqueue(bp, uip);
+ return(0);
+}
+
+/***************************************************************************
+ *
+ * set queue to buffer
+ *
+ ***************************************************************************/
+setqueue(bp, uip)
+struct buf *bp;
+struct unit_info *uip;
+{
+ spl_t x = SPL();
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ openchk(cmdp); /* openning check */
+ cmdp->c_devflag |= STRCHK;
+ fd_disksort(uip, bp); /* queue the request */
+ /*
+ * If no requests are in progress, start this one up. Else
+ * leave it on the queue, and fdintr will call m765io later.
+ */
+ if(!cip->b_uip)
+ m765io(uip);
+ splx(x);
+}
+/***************************************************************************
+ *
+ * check io_busy routine
+ *
+ ***************************************************************************/
+chkbusy(cmdp)
+struct fdcmd *cmdp;
+{
+ while(cmdp->c_devflag & STRCHK){
+ cmdp->c_devflag |= STRWAIT;
+ sleep(&cmdp->c_devflag,PZERO);
+ }
+}
+/***************************************************************************
+ *
+ * check fdopen() routine
+ *
+ ***************************************************************************/
+openchk(cmdp)
+struct fdcmd *cmdp;
+{
+ while(cmdp->c_devflag & FDMCHK ){
+ cmdp->c_devflag |= FDWAIT;
+ sleep(&cmdp->c_devflag,PZERO);
+ }
+}
+/***************************************************************************
+ *
+ * free fdopen() routine
+ *
+ ***************************************************************************/
+openfre(cmdp)
+struct fdcmd *cmdp;
+{
+ cmdp->c_devflag &= ~FDMCHK;
+ if(cmdp->c_devflag & FDWAIT){
+ cmdp->c_devflag &= ~FDWAIT;
+ wakeup(&cmdp->c_devflag);
+ }
+}
+/*****************************************************************************
+ *
+ * TITLE: m765io
+ *
+ * ABSTRACT: Start handling an I/O request.
+ *
+ ****************************************************************************/
+m765io(uip)
+struct unit_info *uip;
+{
+ extern int(m765iosub)();
+ register struct buf *bp;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+
+ bp = uip->av_forw; /*move bp to ctrl_info[ctrl].b_buf*/
+ cip->b_buf = bp;
+ cip->b_uip = uip;
+ cip->b_xferaddr = bp->b_un.b_addr;
+ cip->b_xfercount = bp->b_bcount - bp->b_resid;
+ cip->b_sector = bp->b_pfcent;
+ uip->b_cmd->c_stsflag |= MTRFLAG;
+ if(!mtr_start(uip))
+ timeout(m765iosub, uip, HZ);
+ else
+ m765iosub(uip);
+}
+/****************************************************************************
+ *
+ * m765io subroutine
+ *
+ ****************************************************************************/
+m765iosub(uip)
+struct unit_info *uip;
+{
+ struct fddrtab *dr = &uip->d_drtab;
+ int startsec;
+ int slave = uip->dev->slave;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ rwcmdset(uip);
+ if(cip->b_buf->b_flags&B_FORMAT)
+ goto skipchk;
+ startsec = (cmdp->c_rwdata[3] * dr->dr_nsec) + cmdp->c_rwdata[4];
+ if(startsec+(cip->b_xfercount>>9)-1 > dr->dr_spc)
+ cip->b_xferdma = (dr->dr_spc-startsec+1) << 9;
+ else
+skipchk: cip->b_xferdma = cip->b_xfercount;
+ if(!(cmdp->c_rbmtr & (1<<(RBSHIFT+slave))))
+ cip->b_status = rbirate(uip);
+ else if(uip->b_seekaddr != cmdp->c_saddr)
+ cip->b_status = fdiseek(uip,cmdp->c_saddr);
+ else
+ cip->b_status = outicmd(uip);
+ if(cip->b_status)
+ intrerr0(uip);
+ return;
+}
+/***************************************************************************
+ *
+ * read / write / format / verify command set to command table
+ *
+ ***************************************************************************/
+rwcmdset(uip)
+struct unit_info *uip;
+{
+ short resid;
+ int slave = uip->dev->slave;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ switch(cip->b_buf->b_flags&(B_FORMAT|B_VERIFY|B_READ|B_WRITE)){
+ case B_VERIFY|B_WRITE: /* VERIFY after WRITE */
+ cmdp->c_rwdata[0] = RDMV;
+ break;
+ case B_FORMAT:
+ cmdp->c_dcount = FMTCNT;
+ cmdp->c_rwdata[0] = FMTM;
+ cmdp->c_saddr = cip->b_sector / uip->d_drtab.dr_spc;
+ resid = cip->b_sector % uip->d_drtab.dr_spc;
+ cmdp->c_rwdata[1] = slave|((resid/uip->d_drtab.dr_nsec)<<2);
+ cmdp->c_rwdata[2] =
+ ((struct fmttbl *)cip->b_buf->b_un.b_addr)->s_type;
+ cmdp->c_rwdata[3] = uip->d_drtab.dr_nsec;
+ cmdp->c_rwdata[4] = uip->d_drtab.dr_fgpl;
+ cmdp->c_rwdata[5] = FMTDATA;
+ break;
+ case B_WRITE:
+ case B_READ:
+ case B_READ|B_VERIFY:
+ cmdp->c_dcount = RWCNT;
+ if(cip->b_buf->b_flags&B_READ)
+ if(cip->b_buf->b_flags&B_VERIFY)
+ cmdp->c_rwdata[0] = RDMV;
+ else
+ cmdp->c_rwdata[0] = RDM;
+ else
+ cmdp->c_rwdata[0] = WTM; /* format or write */
+ resid = cip->b_sector % uip->d_drtab.dr_spc;
+ cmdp->c_rwdata[3] = resid / uip->d_drtab.dr_nsec;
+ cmdp->c_rwdata[1] = slave|(cmdp->c_rwdata[3]<<2);
+ cmdp->c_rwdata[2] = cmdp->c_saddr =
+ cip->b_sector / uip->d_drtab.dr_spc;
+ cmdp->c_rwdata[4] = (resid % uip->d_drtab.dr_nsec) + 1;
+ cmdp->c_rwdata[5] = 2;
+ cmdp->c_rwdata[6] = uip->d_drtab.dr_nsec;
+ cmdp->c_rwdata[7] = uip->d_drtab.dr_rwgpl;
+ cmdp->c_rwdata[8] = DTL;
+ D(printf("SET %x %x C%x H%x S%x %x %x %x %x ",
+ cmdp->c_rwdata[0], cmdp->c_rwdata[1],
+ cmdp->c_rwdata[2], cmdp->c_rwdata[3],
+ cmdp->c_rwdata[4], cmdp->c_rwdata[5],
+ cmdp->c_rwdata[6], cmdp->c_rwdata[7],
+ cmdp->c_rwdata[8]));
+ break;
+ }
+}
+/*****************************************************************************
+ *
+ * TITLE: fdread
+ *
+ * ABSTRACT: "Raw" read. Use physio().
+ *
+ * CALLS: m765breakup (indirectly, thru physio)
+ *
+ ****************************************************************************/
+fdread(dev, uio)
+register dev_t dev;
+struct uio *uio;
+{
+#ifdef MACH_KERNEL
+ /* no need for page-size restriction */
+ return (block_io(fdstrategy, minphys, uio));
+#else MACH_KERNEL
+ return(physio(fdstrategy,&fdrbuf[UNIT(dev)],dev,B_READ,fdminphys,uio));
+#endif MACH_KERNEL
+}
+/*****************************************************************************
+ *
+ * TITLE: fdwrite
+ *
+ * ABSTRACT: "Raw" write. Use physio().
+ *
+ * CALLS: m765breakup (indirectly, thru physio)
+ *
+ ****************************************************************************/
+fdwrite(dev, uio)
+register dev_t dev;
+struct uio *uio;
+{
+#ifdef MACH_KERNEL
+ /* no need for page-size restriction */
+ return (block_io(fdstrategy, minphys, uio));
+#else MACH_KERNEL
+ return(physio(fdstrategy,&fdrbuf[UNIT(dev)],dev,B_WRITE,fdminphys,uio));
+#endif MACH_KERNEL
+}
+/*****************************************************************************
+ *
+ * TITLE: fdminphys
+ *
+ * ABSTRACT: Trim buffer length if buffer-size is bigger than page size
+ *
+ * CALLS: physio
+ *
+ ****************************************************************************/
+fdminphys(bp)
+struct buf *bp;
+{
+ if (bp->b_bcount > PAGESIZ)
+ bp->b_bcount = PAGESIZ;
+}
+#ifdef MACH_KERNEL
+/* IOC_OUT only and not IOC_INOUT */
+io_return_t fdgetstat(dev, flavor, data, count)
+ dev_t dev;
+ int flavor;
+ int * data; /* pointer to OUT array */
+ unsigned int *count; /* OUT */
+{
+ switch (flavor) {
+
+ /* Mandatory flavors */
+
+ case DEV_GET_SIZE: {
+ int ret;
+ struct disk_parms p;
+
+ ret = fd_getparms(dev, &p);
+ if (ret) return ret;
+ data[DEV_GET_SIZE_DEVICE_SIZE] = p.dp_pnumsec * NBPSCTR;
+ data[DEV_GET_SIZE_RECORD_SIZE] = NBPSCTR;
+ *count = DEV_GET_SIZE_COUNT;
+ break;
+ }
+
+ /* Extra flavors */
+
+ case V_GETPARMS:
+ if (*count < sizeof (struct disk_parms)/sizeof (int))
+ return (D_INVALID_OPERATION);
+ *count = sizeof (struct disk_parms)/sizeof(int);
+ return (fd_getparms(dev, data));
+ default:
+ return (D_INVALID_OPERATION);
+ }
+}
+/* IOC_VOID or IOC_IN or IOC_INOUT */
+/*ARGSUSED*/
+io_return_t fdsetstat(dev, flavor, data, count)
+ dev_t dev;
+ int flavor;
+ int * data;
+ unsigned int count;
+{
+ int unit = UNIT(dev);
+ switch (flavor) {
+ case V_SETPARMS: /* Caller wants reset_parameters */
+ return(fd_setparms(unit,*(int *)data));
+ case V_FORMAT:
+ return(fd_format(dev,data));
+ case V_VERIFY: /* cmdarg : 0 == no verify, 0 != verify */
+ m765verify[unit] = *(int *)data;
+ return(D_SUCCESS);
+ default:
+ return(D_INVALID_OPERATION);
+ }
+}
+
+/*
+ * Get block size
+ */
+int
+fddevinfo(dev, flavor, info)
+dev_t dev;
+int flavor;
+char *info;
+{
+ register struct fddrtab *dr;
+ register struct fdpart *p;
+ register int result = D_SUCCESS;
+
+ switch (flavor) {
+ case D_INFO_BLOCK_SIZE:
+ dr = &unit_info[UNIT(dev)].d_drtab;
+
+ if(dr->dr_type & OKTYPE)
+ *((int *) info) = 512;
+ else
+ result = D_INVALID_OPERATION;
+
+ break;
+ default:
+ result = D_INVALID_OPERATION;
+ }
+
+ return(result);
+}
+#else MACH_KERNEL
+/*****************************************************************************
+ *
+ * TITLE: fdioctl
+ *
+ * ABSTRACT: m765 driver special functions.
+ *
+ * CALLING ROUTINES: kernel
+ *
+ ****************************************************************************/
+int
+fdioctl(dev, cmd, cmdarg, flag)
+dev_t dev; /* major, minor numbers */
+int cmd; /* command code */
+int *cmdarg; /* user structure with parameters */
+int flag; /* not used */
+{
+ register unsigned unit = UNIT(dev);
+ switch (cmd) {
+ case V_SETPARMS: /* Caller wants reset_parameters */
+ return(fd_setparms(unit,*cmdarg));
+ case V_GETPARMS: /* Caller wants device parameters */
+ return(fd_getparms(dev,cmdarg));
+ case V_FORMAT:
+ return(fd_format(dev,cmdarg));
+ case V_VERIFY: /* cmdarg : 0 == no verify, 0 != verify */
+ m765verify[unit] = *cmdarg;
+ return(0);
+ }
+ return(EINVAL);
+}
+#endif MACH_KERNEL
+/****************************************************************************
+ *
+ * set fd parameters
+ *
+ ****************************************************************************/
+int
+fd_setparms(unit, cmdarg)
+register unsigned int unit;
+long cmdarg;
+{
+ struct fddrtab *fdparm;
+ spl_t x;
+ struct unit_info *uip = &unit_info[unit];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ cmdp->c_rbmtr &= ~(1<<(RBSHIFT+uip->dev->slave));
+ if ((fdparm = getparm(MEDIATYPE(cmdarg))) == (struct fddrtab *)ERROR)
+ return(EINVAL);
+ x = SPL();
+ openchk(cmdp);
+ cmdp->c_devflag |= FDMCHK;
+ chkbusy(cmdp);
+ m765sweep(uip, fdparm);
+ uip->d_drtab.dr_type |= OKTYPE;
+ openfre(cmdp);
+ splx(x);
+ return(0);
+}
+/****************************************************************************
+ *
+ * get fd parameters
+ *
+ ****************************************************************************/
+int
+fd_getparms(dev,cmdarg)
+dev_t dev; /* major, minor numbers */
+int *cmdarg;
+{
+ struct disk_parms *diskp = (struct disk_parms *)cmdarg;
+ register struct fddrtab *dr = &unit_info[UNIT(dev)].d_drtab;
+
+ if(dr->dr_type & OKTYPE){
+ diskp->dp_type = DPT_FLOPPY;
+ diskp->dp_heads = 2;
+ diskp->dp_sectors = dr->dr_nsec;
+ diskp->dp_pstartsec = 0;
+ diskp->dp_cyls = dr->dr_ncyl;
+ diskp->dp_pnumsec = dr->p_nsec;
+ return(0);
+ }
+ return(ENXIO);
+}
+/****************************************************************************
+ *
+ * format command
+ *
+ ****************************************************************************/
+fd_format(dev,cmdarg)
+dev_t dev; /* major, minor numbers */
+int *cmdarg;
+
+{
+ register struct buf *bp;
+ register daddr_t track;
+ union io_arg *varg;
+ u_short num_trks;
+ register struct fddrtab *dr = &unit_info[UNIT(dev)].d_drtab;
+
+ if(!(dr->dr_type & OKTYPE))
+ return(EINVAL);
+ varg = (union io_arg *)cmdarg;
+ num_trks = varg->ia_fmt.num_trks;
+ track = (daddr_t)(varg->ia_fmt.start_trk*dr->dr_nsec);
+ if((track + (num_trks*dr->dr_nsec))>dr->p_nsec)
+ return(EINVAL);
+ bp = geteblk(BLKSIZE); /* get struct buf area */
+ while (num_trks>0) {
+ bp->b_flags &= ~B_DONE;
+ bp->b_dev = dev;
+ bp->b_error = 0; bp->b_resid = 0;
+ bp->b_flags = B_FORMAT;
+ bp->b_bcount = dr->dr_nsec * FMTID;
+ bp->b_blkno = (daddr_t)((track << 9) / NBPSCTR);
+ if(makeidtbl(bp->b_un.b_addr,dr,
+ varg->ia_fmt.start_trk++,varg->ia_fmt.intlv))
+ return(EINVAL);
+ fdstrategy(bp);
+ biowait(bp);
+ if(bp->b_error)
+ if((bp->b_error == (char)EBBHARD) ||
+ (bp->b_error == (char)EBBSOFT))
+ return(EIO);
+ else
+ return(bp->b_error);
+ num_trks--;
+ track += dr->dr_nsec;
+ }
+ brelse(bp);
+ return(0);
+}
+/****************************************************************************
+ *
+ * make id table for format
+ *
+ ****************************************************************************/
+makeidtbl(tblpt,dr,track,intlv)
+struct fmttbl *tblpt;
+struct fddrtab *dr;
+unsigned short track;
+unsigned short intlv;
+{
+ register int i,j,secno;
+
+ if(intlv >= dr->dr_nsec)
+ return(1);
+ for(i=0; i<dr->dr_nsec; i++)
+ tblpt[i].sector = 0;
+ for(i=0,j=0,secno=1; i<dr->dr_nsec; i++){
+ tblpt[j].cyl = track >> 1;
+ tblpt[j].head = track & 1;
+ tblpt[j].sector = secno++;
+ tblpt[j].s_type = 2;
+ if((j+=intlv) < dr->dr_nsec)
+ continue;
+ for(j-=dr->dr_nsec; j < dr->dr_nsec ; j++)
+ if(!tblpt[j].sector)
+ break;
+ }
+ return(0);
+}
+/*****************************************************************************
+ *
+ * TITLE: fdintr
+ *
+ * ABSTRACT: Handle interrupt.
+ *
+ * Interrupt procedure for m765 driver. Gets status of last
+ * operation and performs service function according to the
+ * type of interrupt. If it was an operation complete interrupt,
+ * switches on the current driver state and either declares the
+ * operation done, or starts the next operation
+ *
+ ****************************************************************************/
+fdintr(ctrl)
+int ctrl;
+{
+ extern int(m765intrsub)();
+ struct unit_info *uip = ctrl_info[ctrl].b_uip;
+ struct unit_info *wup = ctrl_info[ctrl].b_wup;
+ struct fdcmd *cmdp = &ctrl_info[ctrl].b_cmd;
+ if(cmdp->c_stsflag & INTROUT)
+ untimeout(fdintr, ctrl);
+ cmdp->c_stsflag &= ~INTROUT;
+ switch(cmdp->c_intr){
+ case RWFLAG:
+ rwintr(uip);
+ break;
+ case SKFLAG:
+ case SKEFLAG|SKFLAG:
+ case RBFLAG:
+ timeout(m765intrsub, uip, SEEKWAIT);
+ break;
+ case WUPFLAG:
+ cmdp->c_intr &= ~WUPFLAG;
+ wakeup(wup);
+ }
+ return(0);
+}
+/*****************************************************************************
+ *
+ * interrup subroutine (seek recalibrate)
+ *
+ *****************************************************************************/
+m765intrsub(uip)
+struct unit_info *uip;
+{
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+
+ if((cip->b_status = sis(uip))!= ST0OK)
+ switch(uip->b_cmd->c_intr){
+ case SKFLAG:
+ seekintr(uip);
+ break;
+ case SKEFLAG|SKFLAG:
+ seekintre(uip);
+ break;
+ case RBFLAG:
+ rbintr(uip);
+ }
+}
+/*****************************************************************************
+ *
+ * read / write / format / verify interrupt routine
+ *
+ *****************************************************************************/
+rwintr(uip)
+struct unit_info *uip;
+{
+ int rsult[7];
+ register int rtn, count;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ cmdp->c_intr &= ~RWFLAG;
+ if((cip->b_buf->b_flags&(B_READ|B_VERIFY))!=(B_READ|B_VERIFY))
+ if(inb(VFOREG(uip->addr))&OPENBIT){
+ if(cip->b_buf->b_flags&B_FORMAT){
+ cip->b_status = TIMEOUT;
+ intrerr0(uip);
+ } else {
+ if((inb(STSREG(uip->addr))&ST0OK)!=ST0OK)
+ printf("%s %d : %s\n",
+ fderr,
+ uip-unit_info,
+ fdmsg[DOORERR]);
+ rstout(uip);
+ specify(uip);
+ cmdp->c_rbmtr &= RBRST;
+ cmdp->c_intr |= SKEFLAG;
+ if(cmdp->c_saddr > 2)
+ fdiseek(uip, cmdp->c_saddr-2);
+ else
+ fdiseek(uip, cmdp->c_saddr+2);
+ }
+ return;
+ }
+ for( count = 0 ; count < 7 ; count++ ){
+ if(rtn = fdc_sts(FD_ISTS, uip)) /* status check */
+ goto rwend;
+ rsult[count] = inb(DATAREG(uip->addr));
+ }
+ rtn = 0;
+ if(rsult[0]&0xc0){
+ rtn = cmdp->c_rwdata[0]<<8;
+ if(rsult[0]&0x80){ rtn |= FDCERR; goto rwend; }
+ if(rsult[1]&0x80){ rtn |= NOREC; goto rwend; }
+ if(rsult[1]&0x20){ rtn |= CRCERR; goto rwend; }
+ if(rsult[1]&0x10){ rtn |= OVERRUN; goto rwend; }
+ if(rsult[1]&0x04){ rtn |= NOREC; goto rwend; }
+ if(rsult[1]&0x02){ rtn |= WTPRT; goto rwend; }
+ if(rsult[1]&0x01){ rtn |= ADDRERR; goto rwend; }
+ rtn |= FDCERR;
+rwend: outb(0x0a, 0x06);
+ }
+ if(cip->b_status = rtn) {
+ D(printf("\n->rwierr %x ", rtn));
+ rwierr(uip);
+ } else { /* write command */
+ if(((cip->b_buf->b_flags&(B_FORMAT|B_READ|B_WRITE))==B_WRITE)
+ && !(cip->b_buf->b_flags & B_VERIFY)) {
+ D(printf("->w/v "));
+ cip->b_buf->b_flags |= B_VERIFY;
+ rwcmdset(uip);
+ if(cip->b_status = outicmd(uip))
+ intrerr0(uip);
+ return;
+ }
+ /* clear retry count */
+ if (cip->usebuf) {
+ bcopy(cip->b_vbuf, cip->b_xferaddr, cip->b_xferdma);
+ DD(printf("R(%x, %x, %x)\n",
+ cip->b_vbuf, cip->b_xferaddr, cip->b_xferdma));
+ }
+ cip->b_buf->b_flags &= ~B_VERIFY;
+ cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
+ cip->b_xfercount -= cip->b_xferdma;
+ cip->b_xferaddr += cip->b_xferdma;
+ cip->b_sector = cip->b_sector+(cip->b_xferdma>>9);
+ D(printf("->done%s\n", cip->b_xfercount?"":"." ));
+ /* next address (cyl,head,sec) */
+ if((int)cip->b_xfercount>0)
+ m765iosub(uip);
+ else
+ quechk(uip);
+ }
+}
+/*****************************************************************************
+ *
+ * read / write / format / verify error routine
+ *
+ *****************************************************************************/
+rwierr(uip)
+struct unit_info *uip;
+{
+ short status;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ D(printf("%x-%x-%x ", cip->b_rwerr&SRMASK, cip->b_rwerr&MRMASK, cip->b_rwerr&LRMASK));
+ if((cip->b_buf->b_flags&(B_READ|B_VERIFY))==(B_READ|B_VERIFY)){
+ if((cip->b_rwerr&SRMASK)<MEDIARD)
+ goto rwrtry;
+ if((cip->b_rwerr&MRMASK)<MEDIASEEK)
+ goto rwseek;
+ goto rwexit;
+ } else
+ if(cip->b_buf->b_flags&B_VERIFY){
+ cip->b_buf->b_flags &= ~B_VERIFY;
+ rwcmdset(uip);
+ }
+rwrtry: status = cip->b_status;
+ if((++cip->b_rwerr&SRMASK)<SRETRY)
+ cip->b_status = outicmd(uip);
+ else {
+rwseek: cip->b_rwerr = (cip->b_rwerr&RMRMASK)+MINC;
+ if((cip->b_rwerr&MRMASK)<MRETRY){
+ cmdp->c_intr |= SKEFLAG;
+ if(cmdp->c_saddr > 2)
+ cip->b_status=fdiseek(uip,cmdp->c_saddr-2);
+ else
+ cip->b_status=fdiseek(uip,cmdp->c_saddr+2);
+ } else {
+ cip->b_rwerr = (cip->b_rwerr&LRMASK)+LINC;
+ if((cip->b_rwerr&LRMASK)<LRETRY)
+ cip->b_status=rbirate(uip);
+ }
+ }
+ if(cip->b_status){
+ D(printf("ERR->intrerr0 "));
+ cip->b_status = status;
+rwexit: intrerr0(uip);
+ }
+}
+/*****************************************************************************
+ *
+ * recalibrate interrupt routine
+ *
+ *****************************************************************************/
+rbintr(uip)
+struct unit_info *uip;
+{
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ cmdp->c_intr &= ~RBFLAG;
+ if(cip->b_status) {
+ if(++cip->b_rberr<SRETRY)
+ cip->b_status = rbirate(uip);
+ } else {
+ cmdp->c_rbmtr |= 1<<(RBSHIFT+uip->dev->slave);
+ uip->b_seekaddr = 0;
+ cip->b_rberr = 0;
+ cip->b_status=fdiseek(uip, cmdp->c_saddr);
+ }
+ if(cip->b_status)
+ intrerr0(uip);
+}
+/******************************************************************************
+ *
+ * seek interrupt routine
+ *
+ *****************************************************************************/
+seekintr(uip)
+struct unit_info *uip;
+{
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ cmdp->c_intr &= ~SKFLAG;
+ if(cip->b_status)
+ seekierr(uip, cmdp->c_saddr);
+ else {
+ uip->b_seekaddr = cmdp->c_saddr;
+ cip->b_status = outicmd(uip);
+ }
+ if(cip->b_status)
+ intrerr0(uip);
+ else
+ cip->b_seekerr = 0;
+}
+/*****************************************************************************
+ *
+ * seek error retry interrupt routine
+ *
+ *****************************************************************************/
+seekintre(uip)
+struct unit_info *uip;
+{
+ register char seekpoint;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ cmdp->c_intr &= ~(SKEFLAG|SKFLAG);
+ if(cmdp->c_saddr > 2)
+ seekpoint = cmdp->c_saddr-2;
+ else
+ seekpoint = cmdp->c_saddr+2;
+ if(cip->b_status)
+ seekierr(uip, seekpoint);
+ else {
+ uip->b_seekaddr = seekpoint;
+ cip->b_status = fdiseek(uip, cmdp->c_saddr);
+ }
+ if(cip->b_status)
+ intrerr0(uip);
+ else
+ cip->b_seekerr = 0;
+}
+/*****************************************************************************
+ *
+ * seek error routine
+ *
+ *****************************************************************************/
+seekierr(uip, seekpoint)
+struct unit_info *uip;
+register char seekpoint;
+{
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+
+ if((++cip->b_seekerr&SRMASK)<SRETRY)
+ cip->b_status=fdiseek(uip, seekpoint);
+ else {
+ cip->b_seekerr = (cip->b_seekerr&MRMASK) + MINC;
+ if((cip->b_seekerr&MRMASK)<MRETRY)
+ cip->b_status=rbirate(uip);
+ }
+ if(cip->b_status)
+ intrerr0(uip);
+}
+/*****************************************************************************
+ *
+ * TITLE: m765sweep
+ *
+ * ABSTRACT: Perform an initialization sweep.
+ *
+ **************************************************************************/
+m765sweep(uip, cdr)
+struct unit_info *uip;
+register struct fddrtab *cdr; /* device initialization data */
+{
+ register struct fddrtab *dr = &uip->d_drtab;
+
+ dr->dr_ncyl = cdr->dr_ncyl;
+ dr->dr_nsec = cdr->dr_nsec;
+ dr->dr_spc = cdr->dr_spc;
+ dr->p_nsec = cdr->p_nsec;
+ dr->dr_type = cdr->dr_type;
+ dr->dr_rwgpl= cdr->dr_rwgpl;
+ dr->dr_fgpl = cdr->dr_fgpl;
+}
+/*****************************************************************************
+ *
+ * TITLE: m765disksort
+ *
+ *****************************************************************************/
+fd_disksort(uip, bp)
+struct unit_info *uip; /* Pointer to head of active queue */
+register struct buf *bp; /* Pointer to buffer to be inserted */
+{
+ register struct buf *bp2; /* Pointer to next buffer in queue */
+ register struct buf *bp1; /* Pointer where to insert buffer */
+
+ if (!(bp1 = uip->av_forw)) {
+ /* No other buffers to compare against */
+ uip->av_forw = bp;
+ bp->av_forw = 0;
+ return;
+ }
+ bp2 = bp1->av_forw;
+ while(bp2 && (relative(bp1->b_pfcent,bp->b_pfcent) >=
+ relative(bp1->b_pfcent,bp2->b_pfcent))) {
+ bp1 = bp2;
+ bp2 = bp1->av_forw;
+ }
+ bp1->av_forw = bp;
+ bp->av_forw = bp2;
+}
+/*****************************************************************************
+ *
+ * Set Interrupt error and FDC reset
+ *
+ *****************************************************************************/
+intrerr0(uip)
+struct unit_info *uip;
+{
+ struct buf *bp; /* Pointer to next buffer in queue */
+ int resid;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+ register struct fddrtab *dr = &uip->d_drtab;
+
+ if((cip->b_buf->b_flags&(B_READ|B_VERIFY))!=(B_READ|B_VERIFY)){
+ resid = cip->b_xfercount = cip->b_xferdma-1-inb(DMACNT)*0x101;
+ resid = (cip->b_sector + (resid>>9)) % dr->dr_spc;
+ printf("%s %d : %s\n",
+ fderr,
+ uip->dev->slave,
+ fdmsg[cip->b_status&BYTEMASK]);
+ printf("cylinder = %d ",cmdp->c_saddr);
+ printf("head = %d sector = %d byte/sec = %d\n",
+ resid / dr->dr_nsec , (resid % dr->dr_nsec)+1 , 512);
+ }
+ cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
+ cmdp->c_intr = CMDRST;
+ if(((cip->b_buf->b_flags&(B_READ|B_VERIFY))!=(B_READ|B_VERIFY)) &&
+ uip->dev->slave)
+ dr->dr_type &= ~OKTYPE;
+ bp = cip->b_buf;
+ bp->b_flags |= B_ERROR;
+ switch(cip->b_status&BYTEMASK){
+ case ADDRERR:
+ case OVERRUN:
+ case FDCERR:
+ case TIMEOUT:
+ bp->b_error = EIO;
+ break;
+ case WTPRT:
+#ifdef MACH_KERNEL
+ bp->b_error = ENXIO;
+#else
+ bp->b_error = ENODEV;
+#endif
+ break;
+ case NOREC:
+ bp->b_error = EBBHARD;
+ break;
+ case CRCERR:
+ bp->b_error = EBBSOFT;
+ }
+ rstout(uip);
+ specify(uip);
+ cmdp->c_rbmtr &= RBRST;
+ quechk(uip);
+}
+/*****************************************************************************
+ *
+ * Next queue check routine
+ *
+ *****************************************************************************/
+quechk(uip)
+struct unit_info *uip;
+{
+ register struct buf *bp = uip->av_forw;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct unit_info *loop;
+ struct fdcmd *cmdp = uip->b_cmd;
+ /* clear retry count */
+ cip->b_rwerr = cip->b_seekerr = cip->b_rberr = 0;
+ bp->b_resid = bp->b_resid + cip->b_xfercount;
+ uip->av_forw=bp->av_forw;
+ if (!uip->av_forw && uip->wakeme) {
+ uip->wakeme = 0;
+ wakeup(uip);
+ }
+ biodone(bp);
+ loop = uip;
+ do {
+ loop=loop->b_unitf;
+ if (loop->av_forw) {
+ m765io(loop);
+ return;
+ }
+ } while (loop!=uip);
+ cip->b_uip = 0;
+ cmdp->c_stsflag &= ~MTRFLAG;
+ mtr_on(uip);
+ cmdp->c_devflag &= ~STRCHK;
+ if(cmdp->c_devflag & STRWAIT){
+ cmdp->c_devflag &= ~STRWAIT;
+ wakeup(&cmdp->c_devflag);
+ }
+}
+fdprint(dev,str)
+dev_t dev;
+char *str;
+{
+ printf("floppy disk driver: %s on bad dev %d, partition %d\n",
+ str, UNIT(dev), 0);
+}
+fdsize()
+{
+ printf("fdsize() -- not implemented\n");
+}
+fddump()
+{
+ printf("fddump() -- not implemented\n");
+}
+/*****************************************************************************
+ *
+ * fdc reset routine
+ *
+ *****************************************************************************/
+rstout(uip)
+struct unit_info *uip;
+{
+ register int outd;
+
+ outd = ((uip->b_cmd->c_rbmtr&MTRMASK)<<MTR_ON)|uip->dev->slave;
+ outb(CTRLREG(uip->addr), outd);
+ outd |= FDC_RST;
+ outb(CTRLREG(uip->addr), outd);
+ outd |= DMAREQ;
+ outb(CTRLREG(uip->addr), outd);
+}
+/*****************************************************************************
+ *
+ * specify command routine
+ *
+ *****************************************************************************/
+specify(uip)
+struct unit_info *uip;
+{
+ /* status check */
+ if(fdc_sts(FD_OSTS, uip))
+ return;
+ /* Specify command */
+ outb(DATAREG(uip->addr), SPCCMD);
+ /* status check */
+ if(fdc_sts(FD_OSTS, uip))
+ return;
+ /* Step rate,Head unload time */
+ outb(DATAREG(uip->addr), SRTHUT);
+ /* status check */
+ if(fdc_sts(FD_OSTS, uip))
+ return;
+ /* Head load time,Non DMA Mode*/
+ outb(DATAREG(uip->addr), HLTND);
+ return;
+}
+/****************************************************************************
+ *
+ * recalibrate command routine
+ *
+ ****************************************************************************/
+rbrate(mtype,uip)
+char mtype;
+struct unit_info *uip;
+{
+ register int rtn = 1, rty_flg=2;
+ spl_t x;
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ rbskrate(uip, mtype); /* set transfer rate */
+ while((rty_flg--)&&rtn){
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ break;
+ /*recalibrate command*/
+ outb(DATAREG(uip->addr), RBCMD);
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ break;
+ /* Device to wake up specified in open */
+ cmdp->c_intr |= WUPFLAG;
+ x = SPL();
+ outb(DATAREG(uip->addr), uip->dev->slave);
+ rtn = ERROR;
+ while(rtn) {
+ uip->wakeme = 1;
+ sleep(uip, PZERO);
+ if((rtn = sis(uip)) == ST0OK)
+ /* Device to wake up specified in open */
+ cmdp->c_intr |= WUPFLAG;
+ else
+ break;
+ }
+ splx(x);
+ }
+ return(rtn);
+}
+/*****************************************************************************
+ *
+ * seek command routine
+ *
+ ****************************************************************************/
+fdseek(mtype, uip, cylno)
+register char mtype;
+struct unit_info *uip;
+register int cylno;
+{
+ spl_t x;
+ int rtn;
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ rbskrate(uip, mtype);
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ return(rtn);
+ outb(DATAREG(uip->addr), SEEKCMD); /* seek command */
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ return(rtn);
+ outb(DATAREG(uip->addr), uip->dev->slave); /* drive number */
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ return(rtn);
+ x = SPL();
+ /* Device to wake up specified in open */
+ cmdp->c_intr |= WUPFLAG;
+ outb(DATAREG(uip->addr), cylno); /* seek count */
+ rtn = ERROR;
+ while(rtn){
+ uip->wakeme = 1;
+ sleep(uip, PZERO);
+ if((rtn = sis(uip)) == ST0OK)
+ /* Device to wake up specified in open */
+ cmdp->c_intr |= WUPFLAG;
+ else
+ break;
+ }
+ splx(x);
+ return(rtn);
+}
+/*****************************************************************************
+ *
+ * seek commnd routine(use interrupt)
+ *
+ *****************************************************************************/
+fdiseek(uip, cylno)
+struct unit_info *uip;
+int cylno;
+{
+ register int rtn;
+
+ D(printf("SK %x ", cylno));
+ rbskrate(uip, uip->d_drtab.dr_type);/* set transfer rate */
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ goto fdiend;
+ outb(DATAREG(uip->addr), SEEKCMD); /* seek command */
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ goto fdiend;
+ outb(DATAREG(uip->addr), uip->dev->slave); /* drive number */
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ goto fdiend;
+ uip->b_seekaddr = cylno;
+ if(uip->d_drtab.dr_type&DOUBLE)
+ cylno = cylno * 2;
+ uip->b_cmd->c_intr |= SKFLAG;
+ outb(DATAREG(uip->addr), cylno); /* seek count */
+fdiend:
+ if(rtn)
+ rtn |= SEEKCMD<<8;
+ return(rtn);
+}
+/*****************************************************************************
+ *
+ * recalibrate command routine(use interrupt)
+ *
+ *****************************************************************************/
+rbirate(uip)
+struct unit_info *uip;
+{
+ register int rtn;
+
+ rbskrate(uip, uip->d_drtab.dr_type);/* set transfer rate */
+ if(!(rtn = fdc_sts(FD_OSTS, uip))) { /* status check */
+ /* recalibrate command */
+ outb(DATAREG(uip->addr), RBCMD);
+ if(!(rtn = fdc_sts(FD_OSTS, uip))) { /* status check */
+ uip->b_cmd->c_intr |= RBFLAG;
+ outb(DATAREG(uip->addr), uip->dev->slave);
+ }
+ }
+ return(rtn ? rtn|RBCMD<<8 : 0);
+}
+/*****************************************************************************
+ *
+ * read / write / format / verify command out routine(use interrupt)
+ *
+ *****************************************************************************/
+outicmd(uip)
+struct unit_info *uip;
+{
+ int rtn;
+ register int *data,cnt0,dmalen;
+ register long address;
+ struct ctrl_info *cip = &ctrl_info[uip->dev->ctlr];
+ struct fdcmd *cmdp = uip->b_cmd;
+ spl_t x = splhi();
+
+ outb(DMACMD1,DMADATA0); /* DMA #1 command register */
+ outb(DMAMSK1,DMADATA1); /* DMA #1 all mask register */
+ /* Perhaps outb(0x0a,0x02); might work better on line above? */
+ switch(cmdp->c_rwdata[0]){
+ case RDM:
+ D(printf("RDM"));
+ outb(DMABPFF,DMARD);
+ outb(DMAMODE,DMARD);
+ break;
+ case WTM:
+ case FMTM:
+ D(printf("W"));
+ outb(DMABPFF,DMAWT);
+ outb(DMAMODE,DMAWT);
+ break;
+ case RDMV:
+ D(printf("RDMV"));
+ outb(DMABPFF,DMAVRF);
+ outb(DMAMODE,DMAVRF);
+ }
+ /* get work buffer physical address */
+ address = kvtophys(cip->b_xferaddr);
+ dmalen = i386_trunc_page(address) + I386_PGBYTES - address;
+ if ( (cip->b_rwerr&MRMASK) >= 0x10)
+ dmalen = 0x200;
+ if (dmalen<=cip->b_xferdma)
+ cip->b_xferdma = dmalen;
+ else
+ dmalen = cip->b_xferdma;
+ if (address >= FdDmaThreshold) {
+ DD(printf(">(%x[%x], %x[%x] L%x\n",
+ address, cip->b_pbuf,
+ cip->b_xferaddr, cip->b_vbuf, dmalen));
+ if (!FdDmaEISA) {
+ cip->usebuf = 1;
+ address = (long)cip->b_pbuf;
+ if (cmdp->c_rwdata[0] == WTM || cmdp->c_rwdata[0] == FMTM) {
+ bcopy(cip->b_xferaddr, cip->b_vbuf, dmalen);
+ DD(printf("W(%x, %x, %x)\n",
+ cip->b_xferaddr, cip->b_vbuf, dmalen));
+ }
+ } else
+ cip->usebuf = 0;
+ } else
+ cip->usebuf = 0;
+ D(printf(" %x L%x ", address, dmalen));
+ /* set buffer address */
+ outb(DMAADDR,(int)address&BYTEMASK);
+ outb(DMAADDR,(((int)address>>8)&BYTEMASK));
+ outb(DMAPAGE,(((int)address>>16)&BYTEMASK));
+ if (FdDmaEISA)
+ outb(FdDmaEISA+DMAPAGE-0x80,(((int)address>>24)&BYTEMASK));
+ /* set transfer count */
+ outb(DMACNT,(--dmalen)&BYTEMASK);
+ outb(DMACNT,((dmalen>>8)&BYTEMASK));
+ outb(DMAMSK,CHANNEL2);
+ splx(x);
+ trfrate(uip, uip->d_drtab.dr_type); /* set transfer rate */
+ data = &cmdp->c_rwdata[0];
+ for(cnt0 = 0; cnt0<cmdp->c_dcount; cnt0++,data++){
+ if(rtn = fdc_sts(FD_OSTS, uip)) /*status check*/
+ break;
+ outb(DATAREG(uip->addr), *data);
+ }
+ if(!rtn){
+ cmdp->c_intr |= RWFLAG;
+ cmdp->c_stsflag |= INTROUT;
+ cnt0 = ((cip->b_buf->b_flags&(B_READ|B_VERIFY)) ==
+ (B_READ|B_VERIFY))?TOUT:ITOUT;
+#ifdef MACH_KERNEL
+ timeout(fdintr,uip->dev->ctlr,cnt0);
+#else MACH_KERNEL
+ cmdp->c_timeid = timeout(fdintr,uip->dev->ctlr,cnt0);
+#endif MACH_KERNEL
+ }
+ return(rtn);
+}
+/*****************************************************************************
+ *
+ * sense interrupt status routine
+ *
+ *****************************************************************************/
+sis(uip)
+struct unit_info *uip;
+{
+ register int rtn, st0;
+
+ if(rtn = fdc_sts(FD_OSTS, uip)) /* status check */
+ return(rtn);
+ outb(DATAREG(uip->addr), SISCMD);
+ if(rtn = fdc_sts(FD_ISTS, uip)) /* status check */
+ return(rtn);
+ st0 = inb(DATAREG(uip->addr)) & ST0OK; /* get st0 */
+ if(rtn = fdc_sts(FD_ISTS, uip)) /* status check */
+ return(rtn);
+ inb(DATAREG(uip->addr)); /* get pcn */
+ if (st0&(ST0AT|ST0IC))
+ st0 = FDCERR;
+ return(st0);
+}
+
+/*****************************************************************************
+ *
+ * fdc status get routine
+ *
+ *****************************************************************************/
+fdc_sts(mode, uip)
+register int mode;
+struct unit_info *uip;
+{
+ register int ind;
+ int cnt0 = STSCHKCNT;
+
+ while(cnt0--)
+ if(((ind=inb(STSREG(uip->addr))) & DATAOK) &&
+ ((ind & DTOCPU) == mode))
+ return(0);
+ return(TIMEOUT);
+}
+/*****************************************************************************
+ *
+ * motor on routine
+ *
+ *****************************************************************************/
+mtr_on(uip)
+struct unit_info *uip;
+{
+ extern int(mtr_off)();
+ extern int(wakeup)();
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ if(!(mtr_start(uip))){
+ timeout(wakeup,&cmdp->c_stsflag,HZ);
+ sleep(&cmdp->c_stsflag,PZERO);
+ }
+ cmdp->c_stsflag |= MTROFF;
+#ifdef MACH_KERNEL
+ timeout(mtr_off,uip,MTRSTOP);
+#else MACH_KERNEL
+ cmdp->c_mtrid = timeout(mtr_off,uip,MTRSTOP);
+#endif MACH_KERNEL
+}
+/*****************************************************************************
+ *
+ * motor start routine
+ *
+ *****************************************************************************/
+mtr_start(uip)
+struct unit_info *uip;
+{
+ int status;
+ int (mtr_off)();
+ struct fdcmd *cmdp = uip->b_cmd;
+ int slave = uip->dev->slave;
+ if(cmdp->c_stsflag & MTROFF){
+ untimeout(mtr_off, uip);
+ cmdp->c_stsflag &= ~MTROFF;
+ }
+ status = cmdp->c_rbmtr&(1<<slave);
+ cmdp->c_rbmtr |= (1<<slave);
+ outb(CTRLREG(uip->addr), ((cmdp->c_rbmtr&MTRMASK)<<MTR_ON)|
+ FDC_RST|slave|DMAREQ);
+ return(status);
+}
+/*****************************************************************************
+ *
+ * motor off routine
+ *
+ *****************************************************************************/
+mtr_off(uip)
+struct unit_info *uip;
+{
+ struct fdcmd *cmdp = uip->b_cmd;
+
+ cmdp->c_stsflag &= ~MTROFF;
+ if(!(cmdp->c_stsflag&MTRFLAG)){
+ cmdp->c_rbmtr &= MTRRST;
+ outb(CTRLREG(uip->addr), FDC_RST | DMAREQ);
+ }
+}
+
+#endif