File:  [DragonFly] / src / sys / dev / disk / fd / fd.c
Revision 1.15: download - view: text, annotated - select for diffs
Thu May 13 23:49:15 2004 UTC (10 years, 2 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*
    2:  * Copyright (c) 1990 The Regents of the University of California.
    3:  * All rights reserved.
    4:  *
    5:  * This code is derived from software contributed to Berkeley by
    6:  * Don Ahn.
    7:  *
    8:  * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
    9:  * aided by the Linux floppy driver modifications from David Bateman
   10:  * (dbateman@eng.uts.edu.au).
   11:  *
   12:  * Copyright (c) 1993, 1994 by
   13:  *  jc@irbs.UUCP (John Capo)
   14:  *  vak@zebub.msk.su (Serge Vakulenko)
   15:  *  ache@astral.msk.su (Andrew A. Chernov)
   16:  *
   17:  * Copyright (c) 1993, 1994, 1995 by
   18:  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
   19:  *  dufault@hda.com (Peter Dufault)
   20:  *
   21:  * Copyright (c) 2001 Joerg Wunsch,
   22:  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
   23:  *
   24:  * Redistribution and use in source and binary forms, with or without
   25:  * modification, are permitted provided that the following conditions
   26:  * are met:
   27:  * 1. Redistributions of source code must retain the above copyright
   28:  *    notice, this list of conditions and the following disclaimer.
   29:  * 2. Redistributions in binary form must reproduce the above copyright
   30:  *    notice, this list of conditions and the following disclaimer in the
   31:  *    documentation and/or other materials provided with the distribution.
   32:  * 3. All advertising materials mentioning features or use of this software
   33:  *    must display the following acknowledgement:
   34:  *	This product includes software developed by the University of
   35:  *	California, Berkeley and its contributors.
   36:  * 4. Neither the name of the University nor the names of its contributors
   37:  *    may be used to endorse or promote products derived from this software
   38:  *    without specific prior written permission.
   39:  *
   40:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   41:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   42:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   43:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   44:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   45:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   46:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   47:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   48:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   49:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   50:  * SUCH DAMAGE.
   51:  *
   52:  *	from:	@(#)fd.c	7.4 (Berkeley) 5/25/91
   53:  * $FreeBSD: src/sys/isa/fd.c,v 1.176.2.8 2002/05/15 21:56:14 joerg Exp $
   54:  * $DragonFly: src/sys/dev/disk/fd/fd.c,v 1.15 2004/05/13 23:49:15 dillon Exp $
   55:  *
   56:  */
   57: 
   58: #include "opt_fdc.h"
   59: #include "use_pccard.h"
   60: 
   61: #include <sys/param.h>
   62: #include <sys/systm.h>
   63: #include <sys/bootmaj.h>
   64: #include <sys/kernel.h>
   65: #include <sys/buf.h>
   66: #include <sys/bus.h>
   67: #include <sys/conf.h>
   68: #include <sys/disklabel.h>
   69: #include <sys/devicestat.h>
   70: #include <sys/fcntl.h>
   71: #include <sys/malloc.h>
   72: #include <sys/module.h>
   73: #include <sys/proc.h>
   74: #include <sys/syslog.h>
   75: #include <sys/device.h>
   76: 
   77: #include <sys/bus.h>
   78: #include <machine/bus.h>
   79: #include <sys/rman.h>
   80: 
   81: #include <sys/buf2.h>
   82: 
   83: #include <machine/clock.h>
   84: #include <machine/ioctl_fd.h>
   85: #include <machine/resource.h>
   86: #include <machine/stdarg.h>
   87: 
   88: #include <bus/isa/isavar.h>
   89: #include <bus/isa/isareg.h>
   90: #include "fdreg.h"
   91: #include "fdc.h"
   92: #include <bus/isa/rtc.h>
   93: 
   94: /* misuse a flag to identify format operation */
   95: #define B_FORMAT B_XXX
   96: 
   97: /* configuration flags */
   98: #define FDC_PRETEND_D0	(1 << 0)	/* pretend drive 0 to be there */
   99: #define FDC_NO_FIFO	(1 << 2)	/* do not enable FIFO  */
  100: 
  101: /* internally used only, not really from CMOS: */
  102: #define RTCFDT_144M_PRETENDED	0x1000
  103: 
  104: /* error returns for fd_cmd() */
  105: #define FD_FAILED -1
  106: #define FD_NOT_VALID -2
  107: #define FDC_ERRMAX	100	/* do not log more */
  108: /*
  109:  * Stop retrying after this many DMA overruns.  Since each retry takes
  110:  * one revolution, with 300 rpm., 25 retries take approximately 10
  111:  * seconds which the read attempt will block in case the DMA overrun
  112:  * is persistent.
  113:  */
  114: #define FDC_DMAOV_MAX	25
  115: 
  116: /*
  117:  * Timeout value for the PIO loops to wait until the FDC main status
  118:  * register matches our expectations (request for master, direction
  119:  * bit).  This is supposed to be a number of microseconds, although
  120:  * timing might actually not be very accurate.
  121:  *
  122:  * Timeouts of 100 msec are believed to be required for some broken
  123:  * (old) hardware.
  124:  */
  125: #define	FDSTS_TIMEOUT	100000
  126: 
  127: #define NUMTYPES 17
  128: #define NUMDENS  (NUMTYPES - 7)
  129: 
  130: /* These defines (-1) must match index for fd_types */
  131: #define F_TAPE_TYPE	0x020	/* bit for fd_types to indicate tape */
  132: #define NO_TYPE		0	/* must match NO_TYPE in ft.c */
  133: #define FD_1720         1
  134: #define FD_1480         2
  135: #define FD_1440         3
  136: #define FD_1200         4
  137: #define FD_820          5
  138: #define FD_800          6
  139: #define FD_720          7
  140: #define FD_360          8
  141: #define FD_640          9
  142: #define FD_1232         10
  143: 
  144: #define FD_1480in5_25   11
  145: #define FD_1440in5_25   12
  146: #define FD_820in5_25    13
  147: #define FD_800in5_25    14
  148: #define FD_720in5_25    15
  149: #define FD_360in5_25    16
  150: #define FD_640in5_25    17
  151: 
  152: 
  153: static struct fd_type fd_types[NUMTYPES] =
  154: {
  155: { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
  156: { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
  157: { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
  158: { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /*  1.2M in HD 5.25/3.5 */
  159: { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /*  820K in HD 3.5in */
  160: { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /*  800K in HD 3.5in */
  161: {  9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /*  720K in HD 3.5in */
  162: {  9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /*  360K in DD 5.25in */
  163: {  8,2,0xFF,0x2A,80,1280,1,FDC_250KBPS,2,0x50,1 }, /*  640K in DD 5.25in */
  164: {  8,3,0xFF,0x35,77,1232,1,FDC_500KBPS,2,0x74,1 }, /* 1.23M in HD 5.25in */
  165: 
  166: { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
  167: { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
  168: { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /*  820K in HD 5.25in */
  169: { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /*  800K in HD 5.25in */
  170: {  9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /*  720K in HD 5.25in */
  171: {  9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /*  360K in HD 5.25in */
  172: {  8,2,0xFF,0x2A,80,1280,1,FDC_300KBPS,2,0x50,1 }, /*  640K in HD 5.25in */
  173: };
  174: 
  175: #define DRVS_PER_CTLR 2		/* 2 floppies */
  176: 
  177: /***********************************************************************\
  178: * Per controller structure.						*
  179: \***********************************************************************/
  180: devclass_t fdc_devclass;
  181: 
  182: /***********************************************************************\
  183: * Per drive structure.							*
  184: * N per controller  (DRVS_PER_CTLR)					*
  185: \***********************************************************************/
  186: struct fd_data {
  187: 	struct	fdc_data *fdc;	/* pointer to controller structure */
  188: 	int	fdsu;		/* this units number on this controller */
  189: 	int	type;		/* Drive type (FD_1440...) */
  190: 	struct	fd_type *ft;	/* pointer to the type descriptor */
  191: 	int	flags;
  192: #define	FD_OPEN		0x01	/* it's open		*/
  193: #define	FD_ACTIVE	0x02	/* it's active		*/
  194: #define	FD_MOTOR	0x04	/* motor should be on	*/
  195: #define	FD_MOTOR_WAIT	0x08	/* motor coming up	*/
  196: 	int	skip;
  197: 	int	hddrv;
  198: #define FD_NO_TRACK -2
  199: 	int	track;		/* where we think the head is */
  200: 	int	options;	/* user configurable options, see ioctl_fd.h */
  201: 	struct	callout_handle toffhandle;
  202: 	struct	callout_handle tohandle;
  203: 	struct	devstat device_stats;
  204: 	device_t dev;
  205: 	fdu_t	fdu;
  206: };
  207: 
  208: struct fdc_ivars {
  209: 	int	fdunit;
  210: };
  211: static devclass_t fd_devclass;
  212: 
  213: /***********************************************************************\
  214: * Throughout this file the following conventions will be used:		*
  215: * fd is a pointer to the fd_data struct for the drive in question	*
  216: * fdc is a pointer to the fdc_data struct for the controller		*
  217: * fdu is the floppy drive unit number					*
  218: * fdcu is the floppy controller unit number				*
  219: * fdsu is the floppy drive unit number on that controller. (sub-unit)	*
  220: \***********************************************************************/
  221: 
  222: /* internal functions */
  223: static	void fdc_intr(void *);
  224: static void set_motor(struct fdc_data *, int, int);
  225: #  define TURNON 1
  226: #  define TURNOFF 0
  227: static timeout_t fd_turnoff;
  228: static timeout_t fd_motor_on;
  229: static void fd_turnon(struct fd_data *);
  230: static void fdc_reset(fdc_p);
  231: static int fd_in(struct fdc_data *, int *);
  232: static int out_fdc(struct fdc_data *, int);
  233: static void fdstart(struct fdc_data *);
  234: static timeout_t fd_iotimeout;
  235: static timeout_t fd_pseudointr;
  236: static int fdstate(struct fdc_data *);
  237: static int retrier(struct fdc_data *);
  238: static int fdformat(dev_t, struct fd_formb *, struct thread *);
  239: 
  240: static int enable_fifo(fdc_p fdc);
  241: 
  242: static int fifo_threshold = 8;	/* XXX: should be accessible via sysctl */
  243: 
  244: 
  245: #define DEVIDLE		0
  246: #define FINDWORK	1
  247: #define	DOSEEK		2
  248: #define SEEKCOMPLETE 	3
  249: #define	IOCOMPLETE	4
  250: #define RECALCOMPLETE	5
  251: #define	STARTRECAL	6
  252: #define	RESETCTLR	7
  253: #define	SEEKWAIT	8
  254: #define	RECALWAIT	9
  255: #define	MOTORWAIT	10
  256: #define	IOTIMEDOUT	11
  257: #define	RESETCOMPLETE	12
  258: #define PIOREAD		13
  259: 
  260: #ifdef	FDC_DEBUG
  261: static char const * const fdstates[] =
  262: {
  263: "DEVIDLE",
  264: "FINDWORK",
  265: "DOSEEK",
  266: "SEEKCOMPLETE",
  267: "IOCOMPLETE",
  268: "RECALCOMPLETE",
  269: "STARTRECAL",
  270: "RESETCTLR",
  271: "SEEKWAIT",
  272: "RECALWAIT",
  273: "MOTORWAIT",
  274: "IOTIMEDOUT",
  275: "RESETCOMPLETE",
  276: "PIOREAD",
  277: };
  278: 
  279: /* CAUTION: fd_debug causes huge amounts of logging output */
  280: static int volatile fd_debug = 0;
  281: #define TRACE0(arg) if(fd_debug) printf(arg)
  282: #define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
  283: #else /* FDC_DEBUG */
  284: #define TRACE0(arg)
  285: #define TRACE1(arg1, arg2)
  286: #endif /* FDC_DEBUG */
  287: 
  288: void
  289: fdout_wr(fdc_p fdc, u_int8_t v)
  290: {
  291: 	bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
  292: }
  293: 
  294: static u_int8_t
  295: fdsts_rd(fdc_p fdc)
  296: {
  297: 	return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off);
  298: }
  299: 
  300: static void
  301: fddata_wr(fdc_p fdc, u_int8_t v)
  302: {
  303: 	bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v);
  304: }
  305: 
  306: static u_int8_t
  307: fddata_rd(fdc_p fdc)
  308: {
  309: 	return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off);
  310: }
  311: 
  312: static void
  313: fdctl_wr_isa(fdc_p fdc, u_int8_t v)
  314: {
  315: 	bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
  316: }
  317: 
  318: #if 0
  319: 
  320: static u_int8_t
  321: fdin_rd(fdc_p fdc)
  322: {
  323: 	return bus_space_read_1(fdc->portt, fdc->porth, FDIN);
  324: }
  325: 
  326: #endif
  327: 
  328: static	d_open_t	Fdopen;	/* NOTE, not fdopen */
  329: static	d_close_t	fdclose;
  330: static	d_ioctl_t	fdioctl;
  331: static	d_strategy_t	fdstrategy;
  332: 
  333: static struct cdevsw fd_cdevsw = {
  334: 	/* name */	"fd",
  335: 	/* maj */	FD_CDEV_MAJOR,
  336: 	/* flags */	D_DISK,
  337: 	/* port */	NULL,
  338: 	/* clone */	NULL,
  339: 
  340: 	/* open */	Fdopen,
  341: 	/* close */	fdclose,
  342: 	/* read */	physread,
  343: 	/* write */	physwrite,
  344: 	/* ioctl */	fdioctl,
  345: 	/* poll */	nopoll,
  346: 	/* mmap */	nommap,
  347: 	/* strategy */	fdstrategy,
  348: 	/* dump */	nodump,
  349: 	/* psize */	nopsize
  350: };
  351: 
  352: static int
  353: fdc_err(struct fdc_data *fdc, const char *s)
  354: {
  355: 	fdc->fdc_errs++;
  356: 	if (s) {
  357: 		if (fdc->fdc_errs < FDC_ERRMAX)
  358: 			device_printf(fdc->fdc_dev, "%s", s);
  359: 		else if (fdc->fdc_errs == FDC_ERRMAX)
  360: 			device_printf(fdc->fdc_dev, "too many errors, not "
  361: 						    "logging any more\n");
  362: 	}
  363: 
  364: 	return FD_FAILED;
  365: }
  366: 
  367: /*
  368:  * fd_cmd: Send a command to the chip.  Takes a varargs with this structure:
  369:  * Unit number,
  370:  * # of output bytes, output bytes as ints ...,
  371:  * # of input bytes, input bytes as ints ...
  372:  */
  373: int
  374: fd_cmd(struct fdc_data *fdc, int n_out, ...)
  375: {
  376: 	u_char cmd;
  377: 	int n_in;
  378: 	int n;
  379: 	__va_list ap;
  380: 
  381: 	__va_start(ap, n_out);
  382: 	cmd = (u_char)(__va_arg(ap, int));
  383: 	__va_end(ap);
  384: 	__va_start(ap, n_out);
  385: 	for (n = 0; n < n_out; n++)
  386: 	{
  387: 		if (out_fdc(fdc, __va_arg(ap, int)) < 0)
  388: 		{
  389: 			char msg[50];
  390: 			snprintf(msg, sizeof(msg),
  391: 				"cmd %x failed at out byte %d of %d\n",
  392: 				cmd, n + 1, n_out);
  393: 			return fdc_err(fdc, msg);
  394: 		}
  395: 	}
  396: 	n_in = __va_arg(ap, int);
  397: 	for (n = 0; n < n_in; n++)
  398: 	{
  399: 		int *ptr = __va_arg(ap, int *);
  400: 		if (fd_in(fdc, ptr) < 0)
  401: 		{
  402: 			char msg[50];
  403: 			snprintf(msg, sizeof(msg),
  404: 				"cmd %02x failed at in byte %d of %d\n",
  405: 				cmd, n + 1, n_in);
  406: 			return fdc_err(fdc, msg);
  407: 		}
  408: 	}
  409: 
  410: 	return 0;
  411: }
  412: 
  413: static int 
  414: enable_fifo(fdc_p fdc)
  415: {
  416: 	int i, j;
  417: 
  418: 	if ((fdc->flags & FDC_HAS_FIFO) == 0) {
  419: 		
  420: 		/*
  421: 		 * XXX: 
  422: 		 * Cannot use fd_cmd the normal way here, since
  423: 		 * this might be an invalid command. Thus we send the
  424: 		 * first byte, and check for an early turn of data directon.
  425: 		 */
  426: 		
  427: 		if (out_fdc(fdc, I8207X_CONFIGURE) < 0)
  428: 			return fdc_err(fdc, "Enable FIFO failed\n");
  429: 		
  430: 		/* If command is invalid, return */
  431: 		j = FDSTS_TIMEOUT;
  432: 		while ((i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM))
  433: 		       != NE7_RQM && j-- > 0) {
  434: 			if (i == (NE7_DIO | NE7_RQM)) {
  435: 				fdc_reset(fdc);
  436: 				return FD_FAILED;
  437: 			}
  438: 			DELAY(1);
  439: 		}
  440: 		if (j<0 || 
  441: 		    fd_cmd(fdc, 3,
  442: 			   0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
  443: 			fdc_reset(fdc);
  444: 			return fdc_err(fdc, "Enable FIFO failed\n");
  445: 		}
  446: 		fdc->flags |= FDC_HAS_FIFO;
  447: 		return 0;
  448: 	}
  449: 	if (fd_cmd(fdc, 4,
  450: 		   I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
  451: 		return fdc_err(fdc, "Re-enable FIFO failed\n");
  452: 	return 0;
  453: }
  454: 
  455: static int
  456: fd_sense_drive_status(fdc_p fdc, int *st3p)
  457: {
  458: 	int st3;
  459: 
  460: 	if (fd_cmd(fdc, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
  461: 	{
  462: 		return fdc_err(fdc, "Sense Drive Status failed\n");
  463: 	}
  464: 	if (st3p)
  465: 		*st3p = st3;
  466: 
  467: 	return 0;
  468: }
  469: 
  470: static int
  471: fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
  472: {
  473: 	int cyl, st0, ret;
  474: 
  475: 	ret = fd_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0);
  476: 	if (ret) {
  477: 		(void)fdc_err(fdc,
  478: 			      "sense intr err reading stat reg 0\n");
  479: 		return ret;
  480: 	}
  481: 
  482: 	if (st0p)
  483: 		*st0p = st0;
  484: 
  485: 	if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) {
  486: 		/*
  487: 		 * There doesn't seem to have been an interrupt.
  488: 		 */
  489: 		return FD_NOT_VALID;
  490: 	}
  491: 
  492: 	if (fd_in(fdc, &cyl) < 0) {
  493: 		return fdc_err(fdc, "can't get cyl num\n");
  494: 	}
  495: 
  496: 	if (cylp)
  497: 		*cylp = cyl;
  498: 
  499: 	return 0;
  500: }
  501: 
  502: 
  503: static int
  504: fd_read_status(fdc_p fdc, int fdsu)
  505: {
  506: 	int i, ret;
  507: 
  508: 	for (i = 0; i < 7; i++) {
  509: 		/*
  510: 		 * XXX types are poorly chosen.  Only bytes can by read
  511: 		 * from the hardware, but fdc->status[] wants u_ints and
  512: 		 * fd_in() gives ints.
  513: 		 */
  514: 		int status;
  515: 
  516: 		ret = fd_in(fdc, &status);
  517: 		fdc->status[i] = status;
  518: 		if (ret != 0)
  519: 			break;
  520: 	}
  521: 
  522: 	if (ret == 0)
  523: 		fdc->flags |= FDC_STAT_VALID;
  524: 	else
  525: 		fdc->flags &= ~FDC_STAT_VALID;
  526: 
  527: 	return ret;
  528: }
  529: 
  530: /****************************************************************************/
  531: /*                      autoconfiguration stuff                             */
  532: /****************************************************************************/
  533: 
  534: int
  535: fdc_alloc_resources(struct fdc_data *fdc)
  536: {
  537: 	device_t dev;
  538: 	int ispnp, ispcmcia;
  539: 
  540: 	dev = fdc->fdc_dev;
  541: 	ispnp = (fdc->flags & FDC_ISPNP) != 0;
  542: 	ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
  543: 	fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
  544: 	fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
  545: 
  546: 	/*
  547: 	 * On standard ISA, we don't just use an 8 port range
  548: 	 * (e.g. 0x3f0-0x3f7) since that covers an IDE control
  549: 	 * register at 0x3f6.
  550: 	 *
  551: 	 * Isn't PC hardware wonderful.
  552: 	 *
  553: 	 * The Y-E Data PCMCIA FDC doesn't have this problem, it
  554: 	 * uses the register with offset 6 for pseudo-DMA, and the
  555: 	 * one with offset 7 as control register.
  556: 	 */
  557: 	fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
  558: 					     &fdc->rid_ioport, 0ul, ~0ul, 
  559: 					     ispcmcia ? 8 : (ispnp ? 1 : 6),
  560: 					     RF_ACTIVE);
  561: 	if (fdc->res_ioport == 0) {
  562: 		device_printf(dev, "cannot reserve I/O port range\n");
  563: 		return ENXIO;
  564: 	}
  565: 	fdc->portt = rman_get_bustag(fdc->res_ioport);
  566: 	fdc->porth = rman_get_bushandle(fdc->res_ioport);
  567: 
  568: 	if (!ispcmcia) {
  569: 		/*
  570: 		 * Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
  571: 		 * and some at 0x3f0-0x3f5,0x3f7. We detect the former
  572: 		 * by checking the size and adjust the port address
  573: 		 * accordingly.
  574: 		 */
  575: 		if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
  576: 			fdc->port_off = -2;
  577: 
  578: 		/*
  579: 		 * Register the control port range as rid 1 if it
  580: 		 * isn't there already. Most PnP BIOSen will have
  581: 		 * already done this but non-PnP configurations don't.
  582: 		 *
  583: 		 * And some (!!) report 0x3f2-0x3f5 and completely
  584: 		 * leave out the control register!  It seems that some
  585: 		 * non-antique controller chips have a different
  586: 		 * method of programming the transfer speed which
  587: 		 * doesn't require the control register, but it's
  588: 		 * mighty bogus as the chip still responds to the
  589: 		 * address for the control register.
  590: 		 */
  591: 		if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
  592: 			u_long ctlstart;
  593: 
  594: 			/* Find the control port, usually 0x3f7 */
  595: 			ctlstart = rman_get_start(fdc->res_ioport) +
  596: 				fdc->port_off + 7;
  597: 
  598: 			bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
  599: 		}
  600: 
  601: 		/*
  602: 		 * Now (finally!) allocate the control port.
  603: 		 */
  604: 		fdc->rid_ctl = 1;
  605: 		fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT,
  606: 						  &fdc->rid_ctl,
  607: 						  0ul, ~0ul, 1, RF_ACTIVE);
  608: 		if (fdc->res_ctl == 0) {
  609: 			device_printf(dev,
  610: 				      "cannot reserve control I/O port range\n");
  611: 			return ENXIO;
  612: 		}
  613: 		fdc->ctlt = rman_get_bustag(fdc->res_ctl);
  614: 		fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
  615: 	}
  616: 
  617: 	fdc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
  618: 					  &fdc->rid_irq, 0ul, ~0ul, 1, 
  619: 					  RF_ACTIVE);
  620: 	if (fdc->res_irq == 0) {
  621: 		device_printf(dev, "cannot reserve interrupt line\n");
  622: 		return ENXIO;
  623: 	}
  624: 
  625: 	if ((fdc->flags & FDC_NODMA) == 0) {
  626: 		fdc->res_drq = bus_alloc_resource(dev, SYS_RES_DRQ,
  627: 						  &fdc->rid_drq, 0ul, ~0ul, 1, 
  628: 						  RF_ACTIVE);
  629: 		if (fdc->res_drq == 0) {
  630: 			device_printf(dev, "cannot reserve DMA request line\n");
  631: 			return ENXIO;
  632: 		}
  633: 		fdc->dmachan = fdc->res_drq->r_start;
  634: 	}
  635: 
  636: 	return 0;
  637: }
  638: 
  639: void
  640: fdc_release_resources(struct fdc_data *fdc)
  641: {
  642: 	device_t dev;
  643: 
  644: 	dev = fdc->fdc_dev;
  645: 	if (fdc->res_irq != 0) {
  646: 		bus_deactivate_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
  647: 					fdc->res_irq);
  648: 		bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
  649: 				     fdc->res_irq);
  650: 	}
  651: 	if (fdc->res_ctl != 0) {
  652: 		bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
  653: 					fdc->res_ctl);
  654: 		bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
  655: 				     fdc->res_ctl);
  656: 	}
  657: 	if (fdc->res_ioport != 0) {
  658: 		bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
  659: 					fdc->res_ioport);
  660: 		bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
  661: 				     fdc->res_ioport);
  662: 	}
  663: 	if (fdc->res_drq != 0) {
  664: 		bus_deactivate_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
  665: 					fdc->res_drq);
  666: 		bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
  667: 				     fdc->res_drq);
  668: 	}
  669: }
  670: 
  671: /****************************************************************************/
  672: /*                      autoconfiguration stuff                             */
  673: /****************************************************************************/
  674: 
  675: static struct isa_pnp_id fdc_ids[] = {
  676: 	{0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
  677: 	{0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */
  678: 	{0}
  679: };
  680: 
  681: int
  682: fdc_read_ivar(device_t dev, device_t child, int which, u_long *result)
  683: {
  684: 	struct fdc_ivars *ivars = device_get_ivars(child);
  685: 
  686: 	switch (which) {
  687: 	case FDC_IVAR_FDUNIT:
  688: 		*result = ivars->fdunit;
  689: 		break;
  690: 	default:
  691: 		return ENOENT;
  692: 	}
  693: 	return 0;
  694: }
  695: 
  696: /*
  697:  * fdc controller section.
  698:  */
  699: static int
  700: fdc_probe(device_t dev)
  701: {
  702: 	int	error, ic_type;
  703: 	struct	fdc_data *fdc;
  704: 
  705: 	fdc = device_get_softc(dev);
  706: 	bzero(fdc, sizeof *fdc);
  707: 	fdc->fdc_dev = dev;
  708: 	fdc->fdctl_wr = fdctl_wr_isa;
  709: 
  710: 	/* Check pnp ids */
  711: 	error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
  712: 	if (error == ENXIO)
  713: 		return ENXIO;
  714: 	if (error == 0)
  715: 		fdc->flags |= FDC_ISPNP;
  716: 
  717: 	/* Attempt to allocate our resources for the duration of the probe */
  718: 	error = fdc_alloc_resources(fdc);
  719: 	if (error)
  720: 		goto out;
  721: 
  722: 	/* First - lets reset the floppy controller */
  723: 	fdout_wr(fdc, 0);
  724: 	DELAY(100);
  725: 	fdout_wr(fdc, FDO_FRST);
  726: 
  727: 	/* see if it can handle a command */
  728: 	if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), 
  729: 		   NE7_SPEC_2(2, 0), 0)) {
  730: 		error = ENXIO;
  731: 		goto out;
  732: 	}
  733: 
  734: 	if (fd_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
  735: 		ic_type = (u_char)ic_type;
  736: 		switch (ic_type) {
  737: 		case 0x80:
  738: 			device_set_desc(dev, "NEC 765 or clone");
  739: 			fdc->fdct = FDC_NE765;
  740: 			break;
  741: 		case 0x81:
  742: 			device_set_desc(dev, "Intel 82077 or clone");
  743: 			fdc->fdct = FDC_I82077;
  744: 			break;
  745: 		case 0x90:
  746: 			device_set_desc(dev, "NEC 72065B or clone");
  747: 			fdc->fdct = FDC_NE72065;
  748: 			break;
  749: 		default:
  750: 			device_set_desc(dev, "generic floppy controller");
  751: 			fdc->fdct = FDC_UNKNOWN;
  752: 			break;
  753: 		}
  754: 	}
  755: 
  756: out:
  757: 	fdc_release_resources(fdc);
  758: 	return (error);
  759: }
  760: 
  761: /*
  762:  * Add a child device to the fdc controller.  It will then be probed etc.
  763:  */
  764: static void
  765: fdc_add_child(device_t dev, const char *name, int unit)
  766: {
  767: 	int	disabled;
  768: 	struct fdc_ivars *ivar;
  769: 	device_t child;
  770: 
  771: 	ivar = malloc(sizeof *ivar, M_DEVBUF /* XXX */, M_WAITOK | M_ZERO);
  772: 	if (resource_int_value(name, unit, "drive", &ivar->fdunit) != 0)
  773: 		ivar->fdunit = 0;
  774: 	child = device_add_child(dev, name, unit);
  775: 	if (child == NULL)
  776: 		return;
  777: 	device_set_ivars(child, ivar);
  778: 	if (resource_int_value(name, unit, "disabled", &disabled) == 0
  779: 	    && disabled != 0)
  780: 		device_disable(child);
  781: }
  782: 
  783: int
  784: fdc_attach(device_t dev)
  785: {
  786: 	struct	fdc_data *fdc;
  787: 	int	i, error;
  788: 
  789: 	fdc = device_get_softc(dev);
  790: 	error = fdc_alloc_resources(fdc);
  791: 	if (error) {
  792: 		device_printf(dev, "cannot re-aquire resources\n");
  793: 		return error;
  794: 	}
  795: 	error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
  796: 			       INTR_TYPE_BIO, fdc_intr, fdc, &fdc->fdc_intr);
  797: 	if (error) {
  798: 		device_printf(dev, "cannot setup interrupt\n");
  799: 		return error;
  800: 	}
  801: 	fdc->fdcu = device_get_unit(dev);
  802: 	fdc->flags |= FDC_ATTACHED;
  803: 
  804: 	if ((fdc->flags & FDC_NODMA) == 0) {
  805: 		/* Acquire the DMA channel forever, The driver will do the rest */
  806: 				/* XXX should integrate with rman */
  807: 		isa_dma_acquire(fdc->dmachan);
  808: 		isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
  809: 	}
  810: 	fdc->state = DEVIDLE;
  811: 
  812: 	/* reset controller, turn motor off, clear fdout mirror reg */
  813: 	fdout_wr(fdc, ((fdc->fdout = 0)));
  814: 	bufq_init(&fdc->head);
  815: 
  816: 	/*
  817: 	 * Probe and attach any children.  We should probably detect
  818: 	 * devices from the BIOS unless overridden.
  819: 	 */
  820: 	for (i = resource_query_string(-1, "at", device_get_nameunit(dev));
  821: 	     i != -1;
  822: 	     i = resource_query_string(i, "at", device_get_nameunit(dev)))
  823: 		fdc_add_child(dev, resource_query_name(i),
  824: 			       resource_query_unit(i));
  825: 
  826: 	return (bus_generic_attach(dev));
  827: }
  828: 
  829: int
  830: fdc_print_child(device_t me, device_t child)
  831: {
  832: 	int retval = 0;
  833: 
  834: 	retval += bus_print_child_header(me, child);
  835: 	retval += printf(" on %s drive %d\n", device_get_nameunit(me),
  836: 	       fdc_get_fdunit(child));
  837: 	
  838: 	return (retval);
  839: }
  840: 
  841: static device_method_t fdc_methods[] = {
  842: 	/* Device interface */
  843: 	DEVMETHOD(device_probe,		fdc_probe),
  844: 	DEVMETHOD(device_attach,	fdc_attach),
  845: 	DEVMETHOD(device_detach,	bus_generic_detach),
  846: 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
  847: 	DEVMETHOD(device_suspend,	bus_generic_suspend),
  848: 	DEVMETHOD(device_resume,	bus_generic_resume),
  849: 
  850: 	/* Bus interface */
  851: 	DEVMETHOD(bus_print_child,	fdc_print_child),
  852: 	DEVMETHOD(bus_read_ivar,	fdc_read_ivar),
  853: 	/* Our children never use any other bus interface methods. */
  854: 
  855: 	{ 0, 0 }
  856: };
  857: 
  858: static driver_t fdc_driver = {
  859: 	"fdc",
  860: 	fdc_methods,
  861: 	sizeof(struct fdc_data)
  862: };
  863: 
  864: DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, 0, 0);
  865: 
  866: /******************************************************************/
  867: /*
  868:  * devices attached to the controller section.  
  869:  */
  870: static int
  871: fd_probe(device_t dev)
  872: {
  873: 	int	i;
  874: 	u_int	fdt, st0, st3;
  875: 	struct	fd_data *fd;
  876: 	struct	fdc_data *fdc;
  877: 	fdsu_t	fdsu;
  878: 	static int fd_fifo = 0;
  879: 
  880: 	fdsu = *(int *)device_get_ivars(dev); /* xxx cheat a bit... */
  881: 	fd = device_get_softc(dev);
  882: 	fdc = device_get_softc(device_get_parent(dev));
  883: 
  884: 	bzero(fd, sizeof *fd);
  885: 	fd->dev = dev;
  886: 	fd->fdc = fdc;
  887: 	fd->fdsu = fdsu;
  888: 	fd->fdu = device_get_unit(dev);
  889: 
  890: #ifdef __i386__
  891: 	/* look up what bios thinks we have */
  892: 	switch (fd->fdu) {
  893: 	case 0:
  894: 		if ((fdc->flags & FDC_ISPCMCIA))
  895: 			fdt = RTCFDT_144M;
  896: 		else if (device_get_flags(fdc->fdc_dev) & FDC_PRETEND_D0)
  897: 			fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
  898: 		else
  899: 			fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
  900: 		break;
  901: 	case 1:
  902: 		fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
  903: 		break;
  904: 	default:
  905: 		fdt = RTCFDT_NONE;
  906: 		break;
  907: 	}
  908: #else
  909: 	fdt = RTCFDT_144M;	/* XXX probably */
  910: #endif
  911: 
  912: 	/* is there a unit? */
  913: 	if (fdt == RTCFDT_NONE)
  914: 		return (ENXIO);
  915: 
  916: 	/* select it */
  917: 	set_motor(fdc, fdsu, TURNON);
  918: 	DELAY(1000000);	/* 1 sec */
  919: 
  920: 	/* XXX This doesn't work before the first set_motor() */
  921: 	if (fd_fifo == 0 && fdc->fdct != FDC_NE765 && fdc->fdct != FDC_UNKNOWN
  922: 	    && (device_get_flags(fdc->fdc_dev) & FDC_NO_FIFO) == 0
  923: 	    && enable_fifo(fdc) == 0) {
  924: 		device_printf(device_get_parent(dev),
  925: 		    "FIFO enabled, %d bytes threshold\n", fifo_threshold);
  926: 	}
  927: 	fd_fifo = 1;
  928: 
  929: 	if ((fd_cmd(fdc, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0)
  930: 	    && (st3 & NE7_ST3_T0)) {
  931: 		/* if at track 0, first seek inwards */
  932: 		/* seek some steps: */
  933: 		fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0);
  934: 		DELAY(300000); /* ...wait a moment... */
  935: 		fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
  936: 	}
  937: 
  938: 	/* If we're at track 0 first seek inwards. */
  939: 	if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
  940: 		/* Seek some steps... */
  941: 		if (fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
  942: 			/* ...wait a moment... */
  943: 			DELAY(300000);
  944: 			/* make ctrlr happy: */
  945: 			fd_sense_int(fdc, 0, 0);
  946: 		}
  947: 	}
  948: 
  949: 	for (i = 0; i < 2; i++) {
  950: 		/*
  951: 		 * we must recalibrate twice, just in case the
  952: 		 * heads have been beyond cylinder 76, since most
  953: 		 * FDCs still barf when attempting to recalibrate
  954: 		 * more than 77 steps
  955: 		 */
  956: 		/* go back to 0: */
  957: 		if (fd_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
  958: 			/* a second being enough for full stroke seek*/
  959: 			DELAY(i == 0 ? 1000000 : 300000);
  960: 
  961: 			/* anything responding? */
  962: 			if (fd_sense_int(fdc, &st0, 0) == 0 &&
  963: 			    (st0 & NE7_ST0_EC) == 0)
  964: 				break; /* already probed succesfully */
  965: 		}
  966: 	}
  967: 
  968: 	set_motor(fdc, fdsu, TURNOFF);
  969: 
  970: 	if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
  971: 		return (ENXIO);
  972: 
  973: 	fd->track = FD_NO_TRACK;
  974: 	fd->fdc = fdc;
  975: 	fd->fdsu = fdsu;
  976: 	fd->options = 0;
  977: 	callout_handle_init(&fd->toffhandle);
  978: 	callout_handle_init(&fd->tohandle);
  979: 
  980: 	switch (fdt) {
  981: 	case RTCFDT_12M:
  982: 		device_set_desc(dev, "1200-KB 5.25\" drive");
  983: 		fd->type = FD_1200;
  984: 		break;
  985: 	case RTCFDT_144M | RTCFDT_144M_PRETENDED:
  986: 		device_set_desc(dev, "config-pretended 1440-MB 3.5\" drive");
  987: 		fdt = RTCFDT_144M;
  988: 		fd->type = FD_1440;
  989: 	case RTCFDT_144M:
  990: 		device_set_desc(dev, "1440-KB 3.5\" drive");
  991: 		fd->type = FD_1440;
  992: 		break;
  993: 	case RTCFDT_288M:
  994: 	case RTCFDT_288M_1:
  995: 		device_set_desc(dev, "2880-KB 3.5\" drive (in 1440-KB mode)");
  996: 		fd->type = FD_1440;
  997: 		break;
  998: 	case RTCFDT_360K:
  999: 		device_set_desc(dev, "360-KB 5.25\" drive");
 1000: 		fd->type = FD_360;
 1001: 		break;
 1002: 	case RTCFDT_720K:
 1003: 		printf("720-KB 3.5\" drive");
 1004: 		fd->type = FD_720;
 1005: 		break;
 1006: 	default:
 1007: 		return (ENXIO);
 1008: 	}
 1009: 	return (0);
 1010: }
 1011: 
 1012: static int
 1013: fd_attach(device_t dev)
 1014: {
 1015: 	struct	fd_data *fd;
 1016: #if 0
 1017: 	int	i;
 1018: 	int	mynor;
 1019: 	int	typemynor;
 1020: 	int	typesize;
 1021: #endif
 1022: 	static int cdevsw_add_done = 0;
 1023: 
 1024: 	fd = device_get_softc(dev);
 1025: 
 1026: 	if (!cdevsw_add_done) {
 1027: 		cdevsw_add(&fd_cdevsw);	/* XXX */
 1028: 		cdevsw_add_done++;
 1029: 	}
 1030: 	make_dev(&fd_cdevsw, (fd->fdu << 6),
 1031: 		UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
 1032: 
 1033: #if 0
 1034: 	/* Other make_dev() go here. */
 1035: #endif
 1036: 
 1037: 	/*
 1038: 	 * Export the drive to the devstat interface.
 1039: 	 */
 1040: 	devstat_add_entry(&fd->device_stats, device_get_name(dev), 
 1041: 			  device_get_unit(dev), 512, DEVSTAT_NO_ORDERED_TAGS,
 1042: 			  DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
 1043: 			  DEVSTAT_PRIORITY_FD);
 1044: 	return (0);
 1045: }
 1046: 
 1047: static int
 1048: fd_detach(device_t dev)
 1049: {
 1050: 	struct	fd_data *fd;
 1051: 
 1052: 	fd = device_get_softc(dev);
 1053: 	untimeout(fd_turnoff, fd, fd->toffhandle);
 1054: 
 1055: 	return (0);
 1056: }
 1057: 
 1058: static device_method_t fd_methods[] = {
 1059: 	/* Device interface */
 1060: 	DEVMETHOD(device_probe,		fd_probe),
 1061: 	DEVMETHOD(device_attach,	fd_attach),
 1062: 	DEVMETHOD(device_detach,	fd_detach),
 1063: 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
 1064: 	DEVMETHOD(device_suspend,	bus_generic_suspend), /* XXX */
 1065: 	DEVMETHOD(device_resume,	bus_generic_resume), /* XXX */
 1066: 
 1067: 	{ 0, 0 }
 1068: };
 1069: 
 1070: static driver_t fd_driver = {
 1071: 	"fd",
 1072: 	fd_methods,
 1073: 	sizeof(struct fd_data)
 1074: };
 1075: 
 1076: DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
 1077: 
 1078: /****************************************************************************/
 1079: /*                            motor control stuff                           */
 1080: /*		remember to not deselect the drive we're working on         */
 1081: /****************************************************************************/
 1082: static void
 1083: set_motor(struct fdc_data *fdc, int fdsu, int turnon)
 1084: {
 1085: 	int fdout = fdc->fdout;
 1086: 	int needspecify = 0;
 1087: 
 1088: 	if(turnon) {
 1089: 		fdout &= ~FDO_FDSEL;
 1090: 		fdout |= (FDO_MOEN0 << fdsu) + fdsu;
 1091: 	} else
 1092: 		fdout &= ~(FDO_MOEN0 << fdsu);
 1093: 
 1094: 	if(!turnon
 1095: 	   && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
 1096: 		/* gonna turn off the last drive, put FDC to bed */
 1097: 		fdout &= ~ (FDO_FRST|FDO_FDMAEN);
 1098: 	else {
 1099: 		/* make sure controller is selected and specified */
 1100: 		if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
 1101: 			needspecify = 1;
 1102: 		fdout |= (FDO_FRST|FDO_FDMAEN);
 1103: 	}
 1104: 
 1105: 	fdout_wr(fdc, fdout);
 1106: 	fdc->fdout = fdout;
 1107: 	TRACE1("[0x%x->FDOUT]", fdout);
 1108: 
 1109: 	if (needspecify) {
 1110: 		/*
 1111: 		 * XXX
 1112: 		 * special case: since we have just woken up the FDC
 1113: 		 * from its sleep, we silently assume the command will
 1114: 		 * be accepted, and do not test for a timeout
 1115: 		 */
 1116: 		(void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
 1117: 			     NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
 1118: 			     0);
 1119: 		if (fdc->flags & FDC_HAS_FIFO)
 1120: 			(void) enable_fifo(fdc);
 1121: 	}
 1122: }
 1123: 
 1124: static void
 1125: fd_turnoff(void *xfd)
 1126: {
 1127: 	int	s;
 1128: 	fd_p fd = xfd;
 1129: 
 1130: 	TRACE1("[fd%d: turnoff]", fd->fdu);
 1131: 
 1132: 	s = splbio();
 1133: 	/*
 1134: 	 * Don't turn off the motor yet if the drive is active.
 1135: 	 *
 1136: 	 * If we got here, this could only mean we missed an interrupt.
 1137: 	 * This can e. g. happen on the Y-E Date PCMCIA floppy controller
 1138: 	 * after a controller reset.  Just schedule a pseudo-interrupt
 1139: 	 * so the state machine gets re-entered.
 1140: 	 */
 1141: 	if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
 1142: 		fdc_intr(fd->fdc);
 1143: 		splx(s);
 1144: 		return;
 1145: 	}
 1146: 
 1147: 	fd->flags &= ~FD_MOTOR;
 1148: 	set_motor(fd->fdc, fd->fdsu, TURNOFF);
 1149: 	splx(s);
 1150: }
 1151: 
 1152: static void
 1153: fd_motor_on(void *xfd)
 1154: {
 1155: 	int	s;
 1156: 	fd_p fd = xfd;
 1157: 
 1158: 	s = splbio();
 1159: 	fd->flags &= ~FD_MOTOR_WAIT;
 1160: 	if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
 1161: 	{
 1162: 		fdc_intr(fd->fdc);
 1163: 	}
 1164: 	splx(s);
 1165: }
 1166: 
 1167: static void
 1168: fd_turnon(fd_p fd)
 1169: {
 1170: 	if(!(fd->flags & FD_MOTOR))
 1171: 	{
 1172: 		fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
 1173: 		set_motor(fd->fdc, fd->fdsu, TURNON);
 1174: 		timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */
 1175: 	}
 1176: }
 1177: 
 1178: static void
 1179: fdc_reset(fdc_p fdc)
 1180: {
 1181: 	/* Try a reset, keep motor on */
 1182: 	fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
 1183: 	TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
 1184: 	DELAY(100);
 1185: 	/* enable FDC, but defer interrupts a moment */
 1186: 	fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
 1187: 	TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
 1188: 	DELAY(100);
 1189: 	fdout_wr(fdc, fdc->fdout);
 1190: 	TRACE1("[0x%x->FDOUT]", fdc->fdout);
 1191: 
 1192: 	/* XXX after a reset, silently believe the FDC will accept commands */
 1193: 	(void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
 1194: 		     NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
 1195: 		     0);
 1196: 	if (fdc->flags & FDC_HAS_FIFO)
 1197: 		(void) enable_fifo(fdc);
 1198: }
 1199: 
 1200: /****************************************************************************/
 1201: /*                             fdc in/out                                   */
 1202: /****************************************************************************/
 1203: /*
 1204:  * FDC IO functions, take care of the main status register, timeout
 1205:  * in case the desired status bits are never set.
 1206:  *
 1207:  * These PIO loops initially start out with short delays between
 1208:  * each iteration in the expectation that the required condition
 1209:  * is usually met quickly, so it can be handled immediately.  After
 1210:  * about 1 ms, stepping is increased to achieve a better timing
 1211:  * accuracy in the calls to DELAY().
 1212:  */
 1213: static int
 1214: fd_in(struct fdc_data *fdc, int *ptr)
 1215: {
 1216: 	int i, j, step;
 1217: 
 1218: 	for (j = 0, step = 1;
 1219: 	    (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM) &&
 1220: 	    j < FDSTS_TIMEOUT;
 1221: 	    j += step) {
 1222: 		if (i == NE7_RQM)
 1223: 			return (fdc_err(fdc, "ready for output in input\n"));
 1224: 		if (j == 1000)
 1225: 			step = 1000;
 1226: 		DELAY(step);
 1227: 	}
 1228: 	if (j >= FDSTS_TIMEOUT)
 1229: 		return (fdc_err(fdc, bootverbose? "input ready timeout\n": 0));
 1230: #ifdef	FDC_DEBUG
 1231: 	i = fddata_rd(fdc);
 1232: 	TRACE1("[FDDATA->0x%x]", (unsigned char)i);
 1233: 	*ptr = i;
 1234: 	return (0);
 1235: #else	/* !FDC_DEBUG */
 1236: 	i = fddata_rd(fdc);
 1237: 	if (ptr)
 1238: 		*ptr = i;
 1239: 	return (0);
 1240: #endif	/* FDC_DEBUG */
 1241: }
 1242: 
 1243: static int
 1244: out_fdc(struct fdc_data *fdc, int x)
 1245: {
 1246: 	int i, j, step;
 1247: 
 1248: 	for (j = 0, step = 1;
 1249: 	    (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != NE7_RQM &&
 1250: 	    j < FDSTS_TIMEOUT;
 1251: 	    j += step) {
 1252: 		if (i == (NE7_DIO|NE7_RQM))
 1253: 			return (fdc_err(fdc, "ready for input in output\n"));
 1254: 		if (j == 1000)
 1255: 			step = 1000;
 1256: 		DELAY(step);
 1257: 	}
 1258: 	if (j >= FDSTS_TIMEOUT)
 1259: 		return (fdc_err(fdc, bootverbose? "output ready timeout\n": 0));
 1260: 
 1261: 	/* Send the command and return */
 1262: 	fddata_wr(fdc, x);
 1263: 	TRACE1("[0x%x->FDDATA]", x);
 1264: 	return (0);
 1265: }
 1266: 
 1267: /****************************************************************************/
 1268: /*                           fdopen/fdclose                                 */
 1269: /****************************************************************************/
 1270: int
 1271: Fdopen(dev_t dev, int flags, int mode, struct thread *td)
 1272: {
 1273:  	fdu_t fdu = FDUNIT(minor(dev));
 1274: 	int type = FDTYPE(minor(dev));
 1275: 	fd_p	fd;
 1276: 	fdc_p	fdc;
 1277: 
 1278: 	/* check bounds */
 1279: 	if ((fd = devclass_get_softc(fd_devclass, fdu)) == 0)
 1280: 		return (ENXIO);
 1281: 	fdc = fd->fdc;
 1282: 	if ((fdc == NULL) || (fd->type == NO_TYPE))
 1283: 		return (ENXIO);
 1284: 	if (type > NUMDENS)
 1285: 		return (ENXIO);
 1286: 	if (type == 0)
 1287: 		type = fd->type;
 1288: 	else {
 1289: 		/*
 1290: 		 * For each type of basic drive, make sure we are trying
 1291: 		 * to open a type it can do,
 1292: 		 */
 1293: 		if (type != fd->type) {
 1294: 			switch (fd->type) {
 1295: 			case FD_360:
 1296: 				return (ENXIO);
 1297: 			case FD_720:
 1298: 				if (   type != FD_820
 1299: 				    && type != FD_800
 1300: 				    && type != FD_640
 1301: 				   )
 1302: 					return (ENXIO);
 1303: 				break;
 1304: 			case FD_1200:
 1305: 				switch (type) {
 1306: 				case FD_1480:
 1307: 					type = FD_1480in5_25;
 1308: 					break;
 1309: 				case FD_1440:
 1310: 					type = FD_1440in5_25;
 1311: 					break;
 1312: 				case FD_1232:
 1313: 					break;
 1314: 				case FD_820:
 1315: 					type = FD_820in5_25;
 1316: 					break;
 1317: 				case FD_800:
 1318: 					type = FD_800in5_25;
 1319: 					break;
 1320: 				case FD_720:
 1321: 					type = FD_720in5_25;
 1322: 					break;
 1323: 				case FD_640:
 1324: 					type = FD_640in5_25;
 1325: 					break;
 1326: 				case FD_360:
 1327: 					type = FD_360in5_25;
 1328: 					break;
 1329: 				default:
 1330: 					return(ENXIO);
 1331: 				}
 1332: 				break;
 1333: 			case FD_1440:
 1334: 				if (   type != FD_1720
 1335: 				    && type != FD_1480
 1336: 				    && type != FD_1200
 1337: 				    && type != FD_820
 1338: 				    && type != FD_800
 1339: 				    && type != FD_720
 1340: 				    && type != FD_640
 1341: 				    )
 1342: 					return(ENXIO);
 1343: 				break;
 1344: 			}
 1345: 		}
 1346: 	}
 1347: 	fd->ft = fd_types + type - 1;
 1348: 	fd->flags |= FD_OPEN;
 1349: 	/*
 1350: 	 * Clearing the DMA overrun counter at open time is a bit messy.
 1351: 	 * Since we're only managing one counter per controller, opening
 1352: 	 * the second drive could mess it up.  Anyway, if the DMA overrun
 1353: 	 * condition is really persistent, it will eventually time out
 1354: 	 * still.  OTOH, clearing it here will ensure we'll at least start
 1355: 	 * trying again after a previous (maybe even long ago) failure.
 1356: 	 * Also, this is merely a stop-gap measure only that should not
 1357: 	 * happen during normal operation, so we can tolerate it to be a
 1358: 	 * bit sloppy about this.
 1359: 	 */
 1360: 	fdc->dma_overruns = 0;
 1361: 
 1362: 	return 0;
 1363: }
 1364: 
 1365: int
 1366: fdclose(dev_t dev, int flags, int mode, struct thread *td)
 1367: {
 1368:  	fdu_t fdu = FDUNIT(minor(dev));
 1369: 	struct fd_data *fd;
 1370: 
 1371: 	fd = devclass_get_softc(fd_devclass, fdu);
 1372: 	fd->flags &= ~FD_OPEN;
 1373: 	fd->options &= ~(FDOPT_NORETRY | FDOPT_NOERRLOG);
 1374: 
 1375: 	return (0);
 1376: }
 1377: 
 1378: /****************************************************************************/
 1379: /*                               fdstrategy                                 */
 1380: /****************************************************************************/
 1381: void
 1382: fdstrategy(struct buf *bp)
 1383: {
 1384: 	unsigned nblocks, blknum, cando;
 1385:  	int	s;
 1386:  	fdu_t	fdu;
 1387:  	fdc_p	fdc;
 1388:  	fd_p	fd;
 1389: 	size_t	fdblk;
 1390: 
 1391:  	fdu = FDUNIT(minor(bp->b_dev));
 1392: 	fd = devclass_get_softc(fd_devclass, fdu);
 1393: 	if (fd == 0)
 1394: 		panic("fdstrategy: buf for nonexistent device (%#lx, %#lx)",
 1395: 		      (u_long)major(bp->b_dev), (u_long)minor(bp->b_dev));
 1396: 	fdc = fd->fdc;
 1397: 	if (fd->type == NO_TYPE) {
 1398: 		bp->b_error = ENXIO;
 1399: 		bp->b_flags |= B_ERROR;
 1400: 		goto bad;
 1401: 	};
 1402: 
 1403: 	fdblk = 128 << (fd->ft->secsize);
 1404: 	if (!(bp->b_flags & B_FORMAT)) {
 1405: 		if (bp->b_blkno < 0) {
 1406: 			printf(
 1407: 		"fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
 1408: 			       fdu, (u_long)bp->b_blkno, bp->b_bcount);
 1409: 			bp->b_error = EINVAL;
 1410: 			bp->b_flags |= B_ERROR;
 1411: 			goto bad;
 1412: 		}
 1413: 		if ((bp->b_bcount % fdblk) != 0) {
 1414: 			bp->b_error = EINVAL;
 1415: 			bp->b_flags |= B_ERROR;
 1416: 			goto bad;
 1417: 		}
 1418: 	}
 1419: 
 1420: 	/*
 1421: 	 * Set up block calculations.
 1422: 	 */
 1423: 	if (bp->b_blkno > 20000000) {
 1424: 		/*
 1425: 		 * Reject unreasonably high block number, prevent the
 1426: 		 * multiplication below from overflowing.
 1427: 		 */
 1428: 		bp->b_error = EINVAL;
 1429: 		bp->b_flags |= B_ERROR;
 1430: 		goto bad;
 1431: 	}
 1432: 	blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk;
 1433:  	nblocks = fd->ft->size;
 1434: 	bp->b_resid = 0;
 1435: 	if (blknum + (bp->b_bcount / fdblk) > nblocks) {
 1436: 		if (blknum <= nblocks) {
 1437: 			cando = (nblocks - blknum) * fdblk;
 1438: 			bp->b_resid = bp->b_bcount - cando;
 1439: 			if (cando == 0)
 1440: 				goto bad;	/* not actually bad but EOF */
 1441: 		} else {
 1442: 			bp->b_error = EINVAL;
 1443: 			bp->b_flags |= B_ERROR;
 1444: 			goto bad;
 1445: 		}
 1446: 	}
 1447:  	bp->b_pblkno = bp->b_blkno;
 1448: 	s = splbio();
 1449: 	bufqdisksort(&fdc->head, bp);
 1450: 	untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
 1451: 
 1452: 	/* Tell devstat we are starting on the transaction */
 1453: 	devstat_start_transaction(&fd->device_stats);
 1454: 	device_busy(fd->dev);
 1455: 
 1456: 	fdstart(fdc);
 1457: 	splx(s);
 1458: 	return;
 1459: 
 1460: bad:
 1461: 	biodone(bp);
 1462: }
 1463: 
 1464: /***************************************************************\
 1465: *				fdstart				*
 1466: * We have just queued something.. if the controller is not busy	*
 1467: * then simulate the case where it has just finished a command	*
 1468: * So that it (the interrupt routine) looks on the queue for more*
 1469: * work to do and picks up what we just added.			*
 1470: * If the controller is already busy, we need do nothing, as it	*
 1471: * will pick up our work when the present work completes		*
 1472: \***************************************************************/
 1473: static void
 1474: fdstart(struct fdc_data *fdc)
 1475: {
 1476: 	int s;
 1477: 
 1478: 	s = splbio();
 1479: 	if(fdc->state == DEVIDLE)
 1480: 	{
 1481: 		fdc_intr(fdc);
 1482: 	}
 1483: 	splx(s);
 1484: }
 1485: 
 1486: static void
 1487: fd_iotimeout(void *xfdc)
 1488: {
 1489:  	fdc_p fdc;
 1490: 	int s;
 1491: 
 1492: 	fdc = xfdc;
 1493: 	TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
 1494: 
 1495: 	/*
 1496: 	 * Due to IBM's brain-dead design, the FDC has a faked ready
 1497: 	 * signal, hardwired to ready == true. Thus, any command
 1498: 	 * issued if there's no diskette in the drive will _never_
 1499: 	 * complete, and must be aborted by resetting the FDC.
 1500: 	 * Many thanks, Big Blue!
 1501: 	 * The FDC must not be reset directly, since that would
 1502: 	 * interfere with the state machine.  Instead, pretend that
 1503: 	 * the command completed but was invalid.  The state machine
 1504: 	 * will reset the FDC and retry once.
 1505: 	 */
 1506: 	s = splbio();
 1507: 	fdc->status[0] = NE7_ST0_IC_IV;
 1508: 	fdc->flags &= ~FDC_STAT_VALID;
 1509: 	fdc->state = IOTIMEDOUT;
 1510: 	fdc_intr(fdc);
 1511: 	splx(s);
 1512: }
 1513: 
 1514: /* just ensure it has the right spl */
 1515: static void
 1516: fd_pseudointr(void *xfdc)
 1517: {
 1518: 	int	s;
 1519: 
 1520: 	s = splbio();
 1521: 	fdc_intr(xfdc);
 1522: 	splx(s);
 1523: }
 1524: 
 1525: /***********************************************************************\
 1526: *                                 fdintr				*
 1527: * keep calling the state machine until it returns a 0			*
 1528: * ALWAYS called at SPLBIO 						*
 1529: \***********************************************************************/
 1530: static void
 1531: fdc_intr(void *xfdc)
 1532: {
 1533: 	fdc_p fdc = xfdc;
 1534: 	while(fdstate(fdc))
 1535: 		;
 1536: }
 1537: 
 1538: /*
 1539:  * magic pseudo-DMA initialization for YE FDC. Sets count and
 1540:  * direction
 1541:  */
 1542: #define SET_BCDR(fdc,wr,cnt,port) \
 1543: 	bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port,	 \
 1544: 	    ((cnt)-1) & 0xff);						 \
 1545: 	bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
 1546: 	    ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
 1547: 
 1548: /*
 1549:  * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
 1550:  */
 1551: static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
 1552: {
 1553: 	u_char *cptr = (u_char *)addr;
 1554: 
 1555: 	if (flags & B_READ) {
 1556: 		if (fdc->state != PIOREAD) {
 1557: 			fdc->state = PIOREAD;
 1558: 			return(0);
 1559: 		};
 1560: 		SET_BCDR(fdc, 0, count, 0);
 1561: 		bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
 1562: 		    FDC_YE_DATAPORT, cptr, count);
 1563: 	} else {
 1564: 		bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
 1565: 		    FDC_YE_DATAPORT, cptr, count);
 1566: 		SET_BCDR(fdc, 0, count, 0);
 1567: 	};
 1568: 	return(1);
 1569: }
 1570: 
 1571: /***********************************************************************\
 1572: * The controller state machine.						*
 1573: * if it returns a non zero value, it should be called again immediatly	*
 1574: \***********************************************************************/
 1575: static int
 1576: fdstate(fdc_p fdc)
 1577: {
 1578: 	int read, format, head, i, sec = 0, sectrac, st0, cyl, st3;
 1579: 	unsigned blknum = 0, b_cylinder = 0;
 1580: 	fdu_t fdu = fdc->fdu;
 1581: 	fd_p fd;
 1582: 	struct buf *bp;
 1583: 	struct fd_formb *finfo = NULL;
 1584: 	size_t fdblk;
 1585: 
 1586: 	bp = fdc->bp;
 1587: 	if (bp == NULL) {
 1588: 		bp = bufq_first(&fdc->head);
 1589: 		if (bp != NULL) {
 1590: 			bufq_remove(&fdc->head, bp);
 1591: 			fdc->bp = bp;
 1592: 		}
 1593: 	}
 1594: 	if (bp == NULL) {
 1595: 		/***********************************************\
 1596: 		* nothing left for this controller to do	*
 1597: 		* Force into the IDLE state,			*
 1598: 		\***********************************************/
 1599: 		fdc->state = DEVIDLE;
 1600: 		if (fdc->fd) {
 1601: 			device_printf(fdc->fdc_dev,
 1602: 			    "unexpected valid fd pointer\n");
 1603: 			fdc->fd = (fd_p) 0;
 1604: 			fdc->fdu = -1;
 1605: 		}
 1606: 		TRACE1("[fdc%d IDLE]", fdc->fdcu);
 1607:  		return (0);
 1608: 	}
 1609: 	fdu = FDUNIT(minor(bp->b_dev));
 1610: 	fd = devclass_get_softc(fd_devclass, fdu);
 1611: 	fdblk = 128 << fd->ft->secsize;
 1612: 	if (fdc->fd && (fd != fdc->fd))
 1613: 		device_printf(fd->dev, "confused fd pointers\n");
 1614: 	read = bp->b_flags & B_READ;
 1615: 	format = bp->b_flags & B_FORMAT;
 1616: 	if (format) {
 1617: 		finfo = (struct fd_formb *)bp->b_data;
 1618: 		fd->skip = (char *)&(finfo->fd_formb_cylno(0))
 1619: 			- (char *)finfo;
 1620: 	}
 1621: 	if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
 1622: 		blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk +
 1623: 			fd->skip/fdblk;
 1624: 		b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
 1625: 	}
 1626: 	TRACE1("fd%d", fdu);
 1627: 	TRACE1("[%s]", fdstates[fdc->state]);
 1628: 	TRACE1("(0x%x)", fd->flags);
 1629: 	untimeout(fd_turnoff, fd, fd->toffhandle);
 1630: 	fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
 1631: 	switch (fdc->state)
 1632: 	{
 1633: 	case DEVIDLE:
 1634: 	case FINDWORK:	/* we have found new work */
 1635: 		fdc->retry = 0;
 1636: 		fd->skip = 0;
 1637: 		fdc->fd = fd;
 1638: 		fdc->fdu = fdu;
 1639: 		fdc->fdctl_wr(fdc, fd->ft->trans);
 1640: 		TRACE1("[0x%x->FDCTL]", fd->ft->trans);
 1641: 		/*******************************************************\
 1642: 		* If the next drive has a motor startup pending, then	*
 1643: 		* it will start up in its own good time		*
 1644: 		\*******************************************************/
 1645: 		if(fd->flags & FD_MOTOR_WAIT) {
 1646: 			fdc->state = MOTORWAIT;
 1647: 			return (0); /* come back later */
 1648: 		}
 1649: 		/*******************************************************\
 1650: 		* Maybe if it's not starting, it SHOULD be starting	*
 1651: 		\*******************************************************/
 1652: 		if (!(fd->flags & FD_MOTOR))
 1653: 		{
 1654: 			fdc->state = MOTORWAIT;
 1655: 			fd_turnon(fd);
 1656: 			return (0);
 1657: 		}
 1658: 		else	/* at least make sure we are selected */
 1659: 		{
 1660: 			set_motor(fdc, fd->fdsu, TURNON);
 1661: 		}
 1662: 		if (fdc->flags & FDC_NEEDS_RESET) {
 1663: 			fdc->state = RESETCTLR;
 1664: 			fdc->flags &= ~FDC_NEEDS_RESET;
 1665: 		} else
 1666: 			fdc->state = DOSEEK;
 1667: 		break;
 1668: 	case DOSEEK:
 1669: 		if (b_cylinder == (unsigned)fd->track)
 1670: 		{
 1671: 			fdc->state = SEEKCOMPLETE;
 1672: 			break;
 1673: 		}
 1674: 		if (fd_cmd(fdc, 3, NE7CMD_SEEK,
 1675: 			   fd->fdsu, b_cylinder * fd->ft->steptrac,
 1676: 			   0))
 1677: 		{
 1678: 			/*
 1679: 			 * seek command not accepted, looks like
 1680: 			 * the FDC went off to the Saints...
 1681: 			 */
 1682: 			fdc->retry = 6;	/* try a reset */
 1683: 			return(retrier(fdc));
 1684: 		}
 1685: 		fd->track = FD_NO_TRACK;
 1686: 		fdc->state = SEEKWAIT;
 1687: 		return(0);	/* will return later */
 1688: 	case SEEKWAIT:
 1689: 		/* allow heads to settle */
 1690: 		timeout(fd_pseudointr, fdc, hz / 16);
 1691: 		fdc->state = SEEKCOMPLETE;
 1692: 		return(0);	/* will return later */
 1693: 	case SEEKCOMPLETE : /* SEEK DONE, START DMA */
 1694: 		/* Make sure seek really happened*/
 1695: 		if(fd->track == FD_NO_TRACK) {
 1696: 			int descyl = b_cylinder * fd->ft->steptrac;
 1697: 			do {
 1698: 				/*
 1699: 				 * This might be a "ready changed" interrupt,
 1700: 				 * which cannot really happen since the
 1701: 				 * RDY pin is hardwired to + 5 volts.  This
 1702: 				 * generally indicates a "bouncing" intr
 1703: 				 * line, so do one of the following:
 1704: 				 *
 1705: 				 * When running on an enhanced FDC that is
 1706: 				 * known to not go stuck after responding
 1707: 				 * with INVALID, fetch all interrupt states
 1708: 				 * until seeing either an INVALID or a
 1709: 				 * real interrupt condition.
 1710: 				 *
 1711: 				 * When running on a dumb old NE765, give
 1712: 				 * up immediately.  The controller will
 1713: 				 * provide up to four dummy RC interrupt
 1714: 				 * conditions right after reset (for the
 1715: 				 * corresponding four drives), so this is
 1716: 				 * our only chance to get notice that it
 1717: 				 * was not the FDC that caused the interrupt.
 1718: 				 */
 1719: 				if (fd_sense_int(fdc, &st0, &cyl)
 1720: 				    == FD_NOT_VALID)
 1721: 					return 0;
 1722: 				if(fdc->fdct == FDC_NE765
 1723: 				   && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 1724: 					return 0; /* hope for a real intr */
 1725: 			} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 1726: 
 1727: 			if (0 == descyl) {
 1728: 				int failed = 0;
 1729: 				/*
 1730: 				 * seek to cyl 0 requested; make sure we are
 1731: 				 * really there
 1732: 				 */
 1733: 				if (fd_sense_drive_status(fdc, &st3))
 1734: 					failed = 1;
 1735: 				if ((st3 & NE7_ST3_T0) == 0) {
 1736: 					printf(
 1737: 		"fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
 1738: 					       fdu, st3, NE7_ST3BITS);
 1739: 					failed = 1;
 1740: 				}
 1741: 
 1742: 				if (failed) {
 1743: 					if(fdc->retry < 3)
 1744: 						fdc->retry = 3;
 1745: 					return (retrier(fdc));
 1746: 				}
 1747: 			}
 1748: 
 1749: 			if (cyl != descyl) {
 1750: 				printf(
 1751: 		"fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
 1752: 				       fdu, descyl, cyl, st0);
 1753: 				if (fdc->retry < 3)
 1754: 					fdc->retry = 3;
 1755: 				return (retrier(fdc));
 1756: 			}
 1757: 		}
 1758: 
 1759: 		fd->track = b_cylinder;
 1760: 		if (!(fdc->flags & FDC_NODMA))
 1761: 			isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
 1762: 				format ? bp->b_bcount : fdblk, fdc->dmachan);
 1763: 		sectrac = fd->ft->sectrac;
 1764: 		sec = blknum %  (sectrac * fd->ft->heads);
 1765: 		head = sec / sectrac;
 1766: 		sec = sec % sectrac + 1;
 1767: 		fd->hddrv = ((head&1)<<2)+fdu;
 1768: 
 1769: 		if(format || !read)
 1770: 		{
 1771: 			/* make sure the drive is writable */
 1772: 			if(fd_sense_drive_status(fdc, &st3) != 0)
 1773: 			{
 1774: 				/* stuck controller? */
 1775: 				if (!(fdc->flags & FDC_NODMA))
 1776: 					isa_dmadone(bp->b_flags,
 1777: 						    bp->b_data + fd->skip,
 1778: 						    format ? bp->b_bcount : fdblk,
 1779: 						    fdc->dmachan);
 1780: 				fdc->retry = 6;	/* reset the beast */
 1781: 				return (retrier(fdc));
 1782: 			}
 1783: 			if(st3 & NE7_ST3_WP)
 1784: 			{
 1785: 				/*
 1786: 				 * XXX YES! this is ugly.
 1787: 				 * in order to force the current operation
 1788: 				 * to fail, we will have to fake an FDC
 1789: 				 * error - all error handling is done
 1790: 				 * by the retrier()
 1791: 				 */
 1792: 				fdc->status[0] = NE7_ST0_IC_AT;
 1793: 				fdc->status[1] = NE7_ST1_NW;
 1794: 				fdc->status[2] = 0;
 1795: 				fdc->status[3] = fd->track;
 1796: 				fdc->status[4] = head;
 1797: 				fdc->status[5] = sec;
 1798: 				fdc->retry = 8;	/* break out immediately */
 1799: 				fdc->state = IOTIMEDOUT; /* not really... */
 1800: 				return (1);
 1801: 			}
 1802: 		}
 1803: 
 1804: 		if (format) {
 1805: 			if (fdc->flags & FDC_NODMA) {
 1806: 				/*
 1807: 				 * This seems to be necessary for
 1808: 				 * whatever obscure reason; if we omit
 1809: 				 * it, we end up filling the sector ID
 1810: 				 * fields of the newly formatted track
 1811: 				 * entirely with garbage, causing
 1812: 				 * `wrong cylinder' errors all over
 1813: 				 * the place when trying to read them
 1814: 				 * back.
 1815: 				 *
 1816: 				 * Umpf.
 1817: 				 */
 1818: 				SET_BCDR(fdc, 1, bp->b_bcount, 0);
 1819: 
 1820: 				(void)fdcpio(fdc,bp->b_flags,
 1821: 					bp->b_data+fd->skip,
 1822: 					bp->b_bcount);
 1823: 
 1824: 			}
 1825: 			/* formatting */
 1826: 			if(fd_cmd(fdc, 6,  NE7CMD_FORMAT, head << 2 | fdu,
 1827: 				  finfo->fd_formb_secshift,
 1828: 				  finfo->fd_formb_nsecs,
 1829: 				  finfo->fd_formb_gaplen,
 1830: 				  finfo->fd_formb_fillbyte, 0)) {
 1831: 				/* controller fell over */
 1832: 				if (!(fdc->flags & FDC_NODMA))
 1833: 					isa_dmadone(bp->b_flags,
 1834: 						    bp->b_data + fd->skip,
 1835: 						    format ? bp->b_bcount : fdblk,
 1836: 						    fdc->dmachan);
 1837: 				fdc->retry = 6;
 1838: 				return (retrier(fdc));
 1839: 			}
 1840: 		} else {
 1841: 			if (fdc->flags & FDC_NODMA) {
 1842: 				/*
 1843: 				 * this seems to be necessary even when
 1844: 				 * reading data
 1845: 				 */
 1846: 				SET_BCDR(fdc, 1, fdblk, 0);
 1847: 
 1848: 				/*
 1849: 				 * perform the write pseudo-DMA before
 1850: 				 * the WRITE command is sent
 1851: 				 */
 1852: 				if (!read)
 1853: 					(void)fdcpio(fdc,bp->b_flags,
 1854: 					    bp->b_data+fd->skip,
 1855: 					    fdblk);
 1856: 			}
 1857: 			if (fd_cmd(fdc, 9,
 1858: 				   (read ? NE7CMD_READ : NE7CMD_WRITE),
 1859: 				   head << 2 | fdu,  /* head & unit */
 1860: 				   fd->track,        /* track */
 1861: 				   head,
 1862: 				   sec,              /* sector + 1 */
 1863: 				   fd->ft->secsize,  /* sector size */
 1864: 				   sectrac,          /* sectors/track */
 1865: 				   fd->ft->gap,      /* gap size */
 1866: 				   fd->ft->datalen,  /* data length */
 1867: 				   0)) {
 1868: 				/* the beast is sleeping again */
 1869: 				if (!(fdc->flags & FDC_NODMA))
 1870: 					isa_dmadone(bp->b_flags,
 1871: 						    bp->b_data + fd->skip,
 1872: 						    format ? bp->b_bcount : fdblk,
 1873: 						    fdc->dmachan);
 1874: 				fdc->retry = 6;
 1875: 				return (retrier(fdc));
 1876: 			}
 1877: 		}
 1878: 		if (fdc->flags & FDC_NODMA)
 1879: 			/*
 1880: 			 * if this is a read, then simply await interrupt
 1881: 			 * before performing PIO
 1882: 			 */
 1883: 			if (read && !fdcpio(fdc,bp->b_flags,
 1884: 			    bp->b_data+fd->skip,fdblk)) {
 1885: 				fd->tohandle = timeout(fd_iotimeout, fdc, hz);
 1886: 				return(0);      /* will return later */
 1887: 			};
 1888: 
 1889: 		/*
 1890: 		 * write (or format) operation will fall through and
 1891: 		 * await completion interrupt
 1892: 		 */
 1893: 		fdc->state = IOCOMPLETE;
 1894: 		fd->tohandle = timeout(fd_iotimeout, fdc, hz);
 1895: 		return (0);	/* will return later */
 1896: 	case PIOREAD:
 1897: 		/* 
 1898: 		 * actually perform the PIO read.  The IOCOMPLETE case
 1899: 		 * removes the timeout for us.  
 1900: 		 */
 1901: 		(void)fdcpio(fdc,bp->b_flags,bp->b_data+fd->skip,fdblk);
 1902: 		fdc->state = IOCOMPLETE;
 1903: 		/* FALLTHROUGH */
 1904: 	case IOCOMPLETE: /* IO DONE, post-analyze */
 1905: 		untimeout(fd_iotimeout, fdc, fd->tohandle);
 1906: 
 1907: 		if (fd_read_status(fdc, fd->fdsu)) {
 1908: 			if (!(fdc->flags & FDC_NODMA))
 1909: 				isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
 1910: 					    format ? bp->b_bcount : fdblk,
 1911: 					    fdc->dmachan);
 1912: 			if (fdc->retry < 6)
 1913: 				fdc->retry = 6;	/* force a reset */
 1914: 			return (retrier(fdc));
 1915:   		}
 1916: 
 1917: 		fdc->state = IOTIMEDOUT;
 1918: 
 1919: 		/* FALLTHROUGH */
 1920: 
 1921: 	case IOTIMEDOUT:
 1922: 		if (!(fdc->flags & FDC_NODMA))
 1923: 			isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
 1924: 				format ? bp->b_bcount : fdblk, fdc->dmachan);
 1925: 		if (fdc->status[0] & NE7_ST0_IC) {
 1926:                         if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 1927: 			    && fdc->status[1] & NE7_ST1_OR) {
 1928:                                 /*
 1929: 				 * DMA overrun. Someone hogged the bus and
 1930: 				 * didn't release it in time for the next
 1931: 				 * FDC transfer.
 1932: 				 *
 1933: 				 * We normally restart this without bumping
 1934: 				 * the retry counter.  However, in case
 1935: 				 * something is seriously messed up (like
 1936: 				 * broken hardware), we rather limit the
 1937: 				 * number of retries so the IO operation
 1938: 				 * doesn't block indefinately.
 1939: 				 */
 1940: 				if (fdc->dma_overruns++ < FDC_DMAOV_MAX) {
 1941: 					fdc->state = SEEKCOMPLETE;
 1942: 					return (1);
 1943: 				} /* else fall through */
 1944:                         }
 1945: 			if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
 1946: 				&& fdc->retry < 6)
 1947: 				fdc->retry = 6;	/* force a reset */
 1948: 			else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 1949: 				&& fdc->status[2] & NE7_ST2_WC
 1950: 				&& fdc->retry < 3)
 1951: 				fdc->retry = 3;	/* force recalibrate */
 1952: 			return (retrier(fdc));
 1953: 		}
 1954: 		/* All OK */
 1955: 		/* Operation successful, retry DMA overruns again next time. */
 1956: 		fdc->dma_overruns = 0;
 1957: 		fd->skip += fdblk;
 1958: 		if (!format && fd->skip < bp->b_bcount - bp->b_resid) {
 1959: 			/* set up next transfer */
 1960: 			fdc->state = DOSEEK;
 1961: 		} else {
 1962: 			/* ALL DONE */
 1963: 			fd->skip = 0;
 1964: 			fdc->bp = NULL;
 1965: 			device_unbusy(fd->dev);
 1966: 			devstat_end_transaction_buf(&fd->device_stats, bp);
 1967: 			biodone(bp);
 1968: 			fdc->fd = (fd_p) 0;
 1969: 			fdc->fdu = -1;
 1970: 			fdc->state = FINDWORK;
 1971: 		}
 1972: 		return (1);
 1973: 	case RESETCTLR:
 1974: 		fdc_reset(fdc);
 1975: 		fdc->retry++;
 1976: 		fdc->state = RESETCOMPLETE;
 1977: 		return (0);
 1978: 	case RESETCOMPLETE:
 1979: 		/*
 1980: 		 * Discard all the results from the reset so that they
 1981: 		 * can't cause an unexpected interrupt later.
 1982: 		 */
 1983: 		for (i = 0; i < 4; i++)
 1984: 			(void)fd_sense_int(fdc, &st0, &cyl);
 1985: 		fdc->state = STARTRECAL;
 1986: 		/* Fall through. */
 1987: 	case STARTRECAL:
 1988: 		if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) {
 1989: 			/* arrgl */
 1990: 			fdc->retry = 6;
 1991: 			return (retrier(fdc));
 1992: 		}
 1993: 		fdc->state = RECALWAIT;
 1994: 		return (0);	/* will return later */
 1995: 	case RECALWAIT:
 1996: 		/* allow heads to settle */
 1997: 		timeout(fd_pseudointr, fdc, hz / 8);
 1998: 		fdc->state = RECALCOMPLETE;
 1999: 		return (0);	/* will return later */
 2000: 	case RECALCOMPLETE:
 2001: 		do {
 2002: 			/*
 2003: 			 * See SEEKCOMPLETE for a comment on this:
 2004: 			 */
 2005: 			if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
 2006: 				return 0;
 2007: 			if(fdc->fdct == FDC_NE765
 2008: 			   && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 2009: 				return 0; /* hope for a real intr */
 2010: 		} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 2011: 		if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
 2012: 		{
 2013: 			if(fdc->retry > 3)
 2014: 				/*
 2015: 				 * a recalibrate from beyond cylinder 77
 2016: 				 * will "fail" due to the FDC limitations;
 2017: 				 * since people used to complain much about
 2018: 				 * the failure message, try not logging
 2019: 				 * this one if it seems to be the first
 2020: 				 * time in a line
 2021: 				 */
 2022: 				printf("fd%d: recal failed ST0 %b cyl %d\n",
 2023: 				       fdu, st0, NE7_ST0BITS, cyl);
 2024: 			if(fdc->retry < 3) fdc->retry = 3;
 2025: 			return (retrier(fdc));
 2026: 		}
 2027: 		fd->track = 0;
 2028: 		/* Seek (probably) necessary */
 2029: 		fdc->state = DOSEEK;
 2030: 		return (1);	/* will return immediatly */
 2031: 	case MOTORWAIT:
 2032: 		if(fd->flags & FD_MOTOR_WAIT)
 2033: 		{
 2034: 			return (0); /* time's not up yet */
 2035: 		}
 2036: 		if (fdc->flags & FDC_NEEDS_RESET) {
 2037: 			fdc->state = RESETCTLR;
 2038: 			fdc->flags &= ~FDC_NEEDS_RESET;
 2039: 		} else {
 2040: 			/*
 2041: 			 * If all motors were off, then the controller was
 2042: 			 * reset, so it has lost track of the current
 2043: 			 * cylinder.  Recalibrate to handle this case.
 2044: 			 * But first, discard the results of the reset.
 2045: 			 */
 2046: 			fdc->state = RESETCOMPLETE;
 2047: 		}
 2048: 		return (1);	/* will return immediatly */
 2049: 	default:
 2050: 		device_printf(fdc->fdc_dev, "unexpected FD int->");
 2051: 		if (fd_read_status(fdc, fd->fdsu) == 0)
 2052: 			printf("FDC status :%x %x %x %x %x %x %x   ",
 2053: 			       fdc->status[0],
 2054: 			       fdc->status[1],
 2055: 			       fdc->status[2],
 2056: 			       fdc->status[3],
 2057: 			       fdc->status[4],
 2058: 			       fdc->status[5],
 2059: 			       fdc->status[6] );
 2060: 		else
 2061: 			printf("No status available   ");
 2062: 		if (fd_sense_int(fdc, &st0, &cyl) != 0)
 2063: 		{
 2064: 			printf("[controller is dead now]\n");
 2065: 			return (0);
 2066: 		}
 2067: 		printf("ST0 = %x, PCN = %x\n", st0, cyl);
 2068: 		return (0);
 2069: 	}
 2070: 	/*XXX confusing: some branches return immediately, others end up here*/
 2071: 	return (1); /* Come back immediatly to new state */
 2072: }
 2073: 
 2074: static int
 2075: retrier(struct fdc_data *fdc)
 2076: {
 2077: 	struct buf *bp;
 2078: 	struct fd_data *fd;
 2079: 	int fdu;
 2080: 
 2081: 	bp = fdc->bp;
 2082: 
 2083: 	/* XXX shouldn't this be cached somewhere?  */
 2084: 	fdu = FDUNIT(minor(bp->b_dev));
 2085: 	fd = devclass_get_softc(fd_devclass, fdu);
 2086: 	if (fd->options & FDOPT_NORETRY)
 2087: 		goto fail;
 2088: 
 2089: 	switch (fdc->retry) {
 2090: 	case 0: case 1: case 2:
 2091: 		fdc->state = SEEKCOMPLETE;
 2092: 		break;
 2093: 	case 3: case 4: case 5:
 2094: 		fdc->state = STARTRECAL;
 2095: 		break;
 2096: 	case 6:
 2097: 		fdc->state = RESETCTLR;
 2098: 		break;
 2099: 	case 7:
 2100: 		break;
 2101: 	default:
 2102: 	fail:
 2103: 		{
 2104: 			int printerror = (fd->options & FDOPT_NOERRLOG) == 0;
 2105: 			dev_t sav_b_dev = bp->b_dev;
 2106: 
 2107: 			/* Trick diskerr */
 2108: 			bp->b_dev = makedev(major(bp->b_dev),
 2109: 				    (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
 2110: 			if (printerror)
 2111: 				diskerr(bp, "hard error", LOG_PRINTF,
 2112: 					fdc->fd->skip / DEV_BSIZE,
 2113: 					(struct disklabel *)NULL);
 2114: 			bp->b_dev = sav_b_dev;
 2115: 			if (printerror) {
 2116: 				if (fdc->flags & FDC_STAT_VALID)
 2117: 					printf(
 2118: 			" (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n",
 2119: 					       fdc->status[0], NE7_ST0BITS,
 2120: 					       fdc->status[1], NE7_ST1BITS,
 2121: 					       fdc->status[2], NE7_ST2BITS,
 2122: 					       fdc->status[3], fdc->status[4],
 2123: 					       fdc->status[5]);
 2124: 				else
 2125: 					printf(" (No status)\n");
 2126: 			}
 2127: 		}
 2128: 		bp->b_flags |= B_ERROR;
 2129: 		bp->b_error = EIO;
 2130: 		bp->b_resid += bp->b_bcount - fdc->fd->skip;
 2131: 		fdc->bp = NULL;
 2132: 		fdc->fd->skip = 0;
 2133: 		device_unbusy(fd->dev);
 2134: 		devstat_end_transaction_buf(&fdc->fd->device_stats, bp);
 2135: 		biodone(bp);
 2136: 		fdc->state = FINDWORK;
 2137: 		fdc->flags |= FDC_NEEDS_RESET;
 2138: 		fdc->fd = (fd_p) 0;
 2139: 		fdc->fdu = -1;
 2140: 		return (1);
 2141: 	}
 2142: 	fdc->retry++;
 2143: 	return (1);
 2144: }
 2145: 
 2146: static int
 2147: fdformat(dev_t dev, struct fd_formb *finfo, struct thread *td)
 2148: {
 2149: 	struct proc *p = td->td_proc;
 2150:  	fdu_t	fdu;
 2151:  	fd_p	fd;
 2152: 
 2153: 	struct buf *bp;
 2154: 	int rv = 0, s;
 2155: 	size_t fdblk;
 2156: 
 2157:  	fdu	= FDUNIT(minor(dev));
 2158: 	fd	= devclass_get_softc(fd_devclass, fdu);
 2159: 	fdblk = 128 << fd->ft->secsize;
 2160: 
 2161: 	/* set up a buffer header for fdstrategy() */
 2162: 	bp = malloc(sizeof(struct buf), M_TEMP, M_WAITOK | M_ZERO);
 2163: 
 2164: 	/*
 2165: 	 * keep the process from being swapped
 2166: 	 */
 2167: 	PHOLD(p);
 2168: 	BUF_LOCKINIT(bp);
 2169: 	BUF_LOCK(bp, LK_EXCLUSIVE);
 2170: 	bp->b_flags = B_PHYS | B_FORMAT;
 2171: 
 2172: 	/*
 2173: 	 * calculate a fake blkno, so fdstrategy() would initiate a
 2174: 	 * seek to the requested cylinder
 2175: 	 */
 2176: 	bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
 2177: 		+ finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
 2178: 
 2179: 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
 2180: 	bp->b_data = (caddr_t)finfo;
 2181: 
 2182: 	/* now do the format */
 2183: 	bp->b_dev = dev;
 2184: 	BUF_STRATEGY(bp, 0);
 2185: 
 2186: 	/* ...and wait for it to complete */
 2187: 	s = splbio();
 2188: 	while(!(bp->b_flags & B_DONE)) {
 2189: 		rv = tsleep((caddr_t)bp, 0, "fdform", 20 * hz);
 2190: 		if (rv == EWOULDBLOCK)
 2191: 			break;
 2192: 	}
 2193: 	splx(s);
 2194: 
 2195: 	if (rv == EWOULDBLOCK) {
 2196: 		/* timed out */
 2197: 		rv = EIO;
 2198: 		device_unbusy(fd->dev);
 2199: 		biodone(bp);
 2200: 	}
 2201: 	if (bp->b_flags & B_ERROR)
 2202: 		rv = bp->b_error;
 2203: 	/*
 2204: 	 * allow the process to be swapped
 2205: 	 */
 2206: 	PRELE(p);
 2207: 	BUF_UNLOCK(bp);
 2208: 	BUF_LOCKFREE(bp);
 2209: 	free(bp, M_TEMP);
 2210: 	return rv;
 2211: }
 2212: 
 2213: /*
 2214:  * TODO: don't allocate buffer on stack.
 2215:  */
 2216: 
 2217: static int
 2218: fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
 2219: {
 2220:  	fdu_t	fdu = FDUNIT(minor(dev));
 2221:  	fd_p	fd = devclass_get_softc(fd_devclass, fdu);
 2222: 	size_t fdblk;
 2223: 
 2224: 	struct fd_type *fdt;
 2225: 	struct disklabel *dl;
 2226: 	struct fdc_status *fsp;
 2227: 	char buffer[DEV_BSIZE];
 2228: 	int error = 0;
 2229: 
 2230: 	fdblk = 128 << fd->ft->secsize;
 2231: 
 2232: 	switch (cmd) {
 2233: 	case DIOCGDINFO:
 2234: 		bzero(buffer, sizeof (buffer));
 2235: 		dl = (struct disklabel *)buffer;
 2236: 		dl->d_secsize = fdblk;
 2237: 		fdt = fd->ft;
 2238: 		dl->d_secpercyl = fdt->size / fdt->tracks;
 2239: 		dl->d_type = DTYPE_FLOPPY;
 2240: 
 2241: 		if (readdisklabel(dev, dl)
 2242: 		    == NULL)
 2243: 			error = 0;
 2244: 		else
 2245: 			error = EINVAL;
 2246: 
 2247: 		*(struct disklabel *)addr = *dl;
 2248: 		break;
 2249: 
 2250: 	case DIOCSDINFO:
 2251: 		if ((flag & FWRITE) == 0)
 2252: 			error = EBADF;
 2253: 		break;
 2254: 
 2255: 	case DIOCWLABEL:
 2256: 		if ((flag & FWRITE) == 0)
 2257: 			error = EBADF;
 2258: 		break;
 2259: 
 2260: 	case DIOCWDINFO:
 2261: 		if ((flag & FWRITE) == 0) {
 2262: 			error = EBADF;
 2263: 			break;
 2264: 		}
 2265: 
 2266: 		dl = (struct disklabel *)addr;
 2267: 
 2268: 		if ((error = setdisklabel((struct disklabel *)buffer, dl,
 2269: 					  (u_long)0)) != 0)
 2270: 			break;
 2271: 
 2272: 		error = writedisklabel(dev, (struct disklabel *)buffer);
 2273: 		break;
 2274: 	case FD_FORM:
 2275: 		if ((flag & FWRITE) == 0)
 2276: 			error = EBADF;	/* must be opened for writing */
 2277: 		else if (((struct fd_formb *)addr)->format_version !=
 2278: 			FD_FORMAT_VERSION)
 2279: 			error = EINVAL;	/* wrong version of formatting prog */
 2280: 		else
 2281: 			error = fdformat(dev, (struct fd_formb *)addr, td);
 2282: 		break;
 2283: 
 2284: 	case FD_GTYPE:                  /* get drive type */
 2285: 		*(struct fd_type *)addr = *fd->ft;
 2286: 		break;
 2287: 
 2288: 	case FD_STYPE:                  /* set drive type */
 2289: 		/* this is considered harmful; only allow for superuser */
 2290: 		if (suser(td) != 0)
 2291: 			return EPERM;
 2292: 		*fd->ft = *(struct fd_type *)addr;
 2293: 		break;
 2294: 
 2295: 	case FD_GOPTS:			/* get drive options */
 2296: 		*(int *)addr = fd->options;
 2297: 		break;
 2298: 
 2299: 	case FD_SOPTS:			/* set drive options */
 2300: 		fd->options = *(int *)addr;
 2301: 		break;
 2302: 
 2303: 	case FD_GSTAT:
 2304: 		fsp = (struct fdc_status *)addr;
 2305: 		if ((fd->fdc->flags & FDC_STAT_VALID) == 0)
 2306: 			return EINVAL;
 2307: 		memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int));
 2308: 		break;
 2309: 
 2310: 	default:
 2311: 		error = ENOTTY;
 2312: 		break;
 2313: 	}
 2314: 	return (error);
 2315: }
 2316: 
 2317: /*
 2318:  * Hello emacs, these are the
 2319:  * Local Variables:
 2320:  *  c-indent-level:               8
 2321:  *  c-continued-statement-offset: 8
 2322:  *  c-continued-brace-offset:     0
 2323:  *  c-brace-offset:              -8
 2324:  *  c-brace-imaginary-offset:     0
 2325:  *  c-argdecl-indent:             8
 2326:  *  c-label-offset:              -8
 2327:  *  c++-hanging-braces:           1
 2328:  *  c++-access-specifier-offset: -8
 2329:  *  c++-empty-arglist-indent:     8
 2330:  *  c++-friend-offset:            0
 2331:  * End:
 2332:  */