File:  [DragonFly] / src / sys / dev / disk / fd / fd.c
Revision 1.16: download - view: text, annotated - select for diffs
Wed May 19 22:52:41 2004 UTC (10 years, 5 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Device layer rollup commit.

* cdevsw_add() is now required.  cdevsw_add() and cdevsw_remove() may specify
  a mask/match indicating the range of supported minor numbers.  Multiple
  cdevsw_add()'s using the same major number, but distinctly different
  ranges, may be issued.  All devices that failed to call cdevsw_add() before
  now do.

* cdevsw_remove() now automatically marks all devices within its supported
  range as being destroyed.

* vnode->v_rdev is no longer resolved when the vnode is created.  Instead,
  only v_udev (a newly added field) is resolved.  v_rdev is resolved when
  the vnode is opened and cleared on the last close.

* A great deal of code was making rather dubious assumptions with regards
  to the validity of devices associated with vnodes, primarily due to
  the persistence of a device structure due to being indexed by (major, minor)
  instead of by (cdevsw, major, minor).  In particular, if you run a program
  which connects to a USB device and then you pull the USB device and plug
  it back in, the vnode subsystem will continue to believe that the device
  is open when, in fact, it isn't (because it was destroyed and recreated).

  In particular, note that all the VFS mount procedures now check devices
  via v_udev instead of v_rdev prior to calling VOP_OPEN(), since v_rdev
  is NULL prior to the first open.

* The disk layer's device interaction has been rewritten.  The disk layer
  (i.e. the slice and disklabel management layer) no longer overloads
  its data onto the device structure representing the underlying physical
  disk.  Instead, the disk layer uses the new cdevsw_add() functionality
  to register its own cdevsw using the underlying device's major number,
  and simply does NOT register the underlying device's cdevsw.  No
  confusion is created because the device hash is now based on
  (cdevsw,major,minor) rather then (major,minor).

  NOTE: This also means that underlying raw disk devices may use the entire
  device minor number instead of having to reserve the bits used by the disk
  layer, and also means that can we (theoretically) stack a fully
  disklabel-supported 'disk' on top of any block device.

* The new reference counting scheme prevents this by associating a device
  with a cdevsw and disconnecting the device from its cdevsw when the cdevsw
  is removed.  Additionally, all udev2dev() lookups run through the cdevsw
  mask/match and only successfully find devices still associated with an
  active cdevsw.

* Major work on MFS:  MFS no longer shortcuts vnode and device creation.  It
  now creates a real vnode and a real device and implements real open and
  close VOPs.  Additionally, due to the disk layer changes, MFS is no longer
  limited to 255 mounts.  The new limit is 16 million.  Since MFS creates a
  real device node, mount_mfs will now create a real /dev/mfs<PID> device
  that can be read from userland (e.g. so you can dump an MFS filesystem).

* BUF AND DEVICE STRATEGY changes.  The struct buf contains a b_dev field.
  In order to properly handle stacked devices we now require that the b_dev
  field be initialized before the device strategy routine is called.  This
  required some additional work in various VFS implementations.  To enforce
  this requirement, biodone() now sets b_dev to NODEV.  The new disk layer
  will adjust b_dev before forwarding a request to the actual physical
  device.

* A bug in the ISO CD boot sequence which resulted in a panic has been fixed.

Testing by: lots of people, but David Rhodus found the most aggregious bugs.

    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.16 2004/05/19 22:52:41 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: 
 1023: 	fd = device_get_softc(dev);
 1024: 
 1025: 	cdevsw_add(&fd_cdevsw, -1 << 6, fd->fdu << 6);
 1026: 	make_dev(&fd_cdevsw, (fd->fdu << 6),
 1027: 		UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
 1028: 
 1029: #if 0
 1030: 	/* Other make_dev() go here. */
 1031: #endif
 1032: 
 1033: 	/*
 1034: 	 * Export the drive to the devstat interface.
 1035: 	 */
 1036: 	devstat_add_entry(&fd->device_stats, device_get_name(dev), 
 1037: 			  device_get_unit(dev), 512, DEVSTAT_NO_ORDERED_TAGS,
 1038: 			  DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
 1039: 			  DEVSTAT_PRIORITY_FD);
 1040: 	return (0);
 1041: }
 1042: 
 1043: static int
 1044: fd_detach(device_t dev)
 1045: {
 1046: 	struct	fd_data *fd;
 1047: 
 1048: 	fd = device_get_softc(dev);
 1049: 	untimeout(fd_turnoff, fd, fd->toffhandle);
 1050: 
 1051: 	return (0);
 1052: }
 1053: 
 1054: static device_method_t fd_methods[] = {
 1055: 	/* Device interface */
 1056: 	DEVMETHOD(device_probe,		fd_probe),
 1057: 	DEVMETHOD(device_attach,	fd_attach),
 1058: 	DEVMETHOD(device_detach,	fd_detach),
 1059: 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
 1060: 	DEVMETHOD(device_suspend,	bus_generic_suspend), /* XXX */
 1061: 	DEVMETHOD(device_resume,	bus_generic_resume), /* XXX */
 1062: 
 1063: 	{ 0, 0 }
 1064: };
 1065: 
 1066: static driver_t fd_driver = {
 1067: 	"fd",
 1068: 	fd_methods,
 1069: 	sizeof(struct fd_data)
 1070: };
 1071: 
 1072: DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
 1073: 
 1074: /****************************************************************************/
 1075: /*                            motor control stuff                           */
 1076: /*		remember to not deselect the drive we're working on         */
 1077: /****************************************************************************/
 1078: static void
 1079: set_motor(struct fdc_data *fdc, int fdsu, int turnon)
 1080: {
 1081: 	int fdout = fdc->fdout;
 1082: 	int needspecify = 0;
 1083: 
 1084: 	if(turnon) {
 1085: 		fdout &= ~FDO_FDSEL;
 1086: 		fdout |= (FDO_MOEN0 << fdsu) + fdsu;
 1087: 	} else
 1088: 		fdout &= ~(FDO_MOEN0 << fdsu);
 1089: 
 1090: 	if(!turnon
 1091: 	   && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
 1092: 		/* gonna turn off the last drive, put FDC to bed */
 1093: 		fdout &= ~ (FDO_FRST|FDO_FDMAEN);
 1094: 	else {
 1095: 		/* make sure controller is selected and specified */
 1096: 		if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
 1097: 			needspecify = 1;
 1098: 		fdout |= (FDO_FRST|FDO_FDMAEN);
 1099: 	}
 1100: 
 1101: 	fdout_wr(fdc, fdout);
 1102: 	fdc->fdout = fdout;
 1103: 	TRACE1("[0x%x->FDOUT]", fdout);
 1104: 
 1105: 	if (needspecify) {
 1106: 		/*
 1107: 		 * XXX
 1108: 		 * special case: since we have just woken up the FDC
 1109: 		 * from its sleep, we silently assume the command will
 1110: 		 * be accepted, and do not test for a timeout
 1111: 		 */
 1112: 		(void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
 1113: 			     NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
 1114: 			     0);
 1115: 		if (fdc->flags & FDC_HAS_FIFO)
 1116: 			(void) enable_fifo(fdc);
 1117: 	}
 1118: }
 1119: 
 1120: static void
 1121: fd_turnoff(void *xfd)
 1122: {
 1123: 	int	s;
 1124: 	fd_p fd = xfd;
 1125: 
 1126: 	TRACE1("[fd%d: turnoff]", fd->fdu);
 1127: 
 1128: 	s = splbio();
 1129: 	/*
 1130: 	 * Don't turn off the motor yet if the drive is active.
 1131: 	 *
 1132: 	 * If we got here, this could only mean we missed an interrupt.
 1133: 	 * This can e. g. happen on the Y-E Date PCMCIA floppy controller
 1134: 	 * after a controller reset.  Just schedule a pseudo-interrupt
 1135: 	 * so the state machine gets re-entered.
 1136: 	 */
 1137: 	if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
 1138: 		fdc_intr(fd->fdc);
 1139: 		splx(s);
 1140: 		return;
 1141: 	}
 1142: 
 1143: 	fd->flags &= ~FD_MOTOR;
 1144: 	set_motor(fd->fdc, fd->fdsu, TURNOFF);
 1145: 	splx(s);
 1146: }
 1147: 
 1148: static void
 1149: fd_motor_on(void *xfd)
 1150: {
 1151: 	int	s;
 1152: 	fd_p fd = xfd;
 1153: 
 1154: 	s = splbio();
 1155: 	fd->flags &= ~FD_MOTOR_WAIT;
 1156: 	if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
 1157: 	{
 1158: 		fdc_intr(fd->fdc);
 1159: 	}
 1160: 	splx(s);
 1161: }
 1162: 
 1163: static void
 1164: fd_turnon(fd_p fd)
 1165: {
 1166: 	if(!(fd->flags & FD_MOTOR))
 1167: 	{
 1168: 		fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
 1169: 		set_motor(fd->fdc, fd->fdsu, TURNON);
 1170: 		timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */
 1171: 	}
 1172: }
 1173: 
 1174: static void
 1175: fdc_reset(fdc_p fdc)
 1176: {
 1177: 	/* Try a reset, keep motor on */
 1178: 	fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
 1179: 	TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
 1180: 	DELAY(100);
 1181: 	/* enable FDC, but defer interrupts a moment */
 1182: 	fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
 1183: 	TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
 1184: 	DELAY(100);
 1185: 	fdout_wr(fdc, fdc->fdout);
 1186: 	TRACE1("[0x%x->FDOUT]", fdc->fdout);
 1187: 
 1188: 	/* XXX after a reset, silently believe the FDC will accept commands */
 1189: 	(void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
 1190: 		     NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
 1191: 		     0);
 1192: 	if (fdc->flags & FDC_HAS_FIFO)
 1193: 		(void) enable_fifo(fdc);
 1194: }
 1195: 
 1196: /****************************************************************************/
 1197: /*                             fdc in/out                                   */
 1198: /****************************************************************************/
 1199: /*
 1200:  * FDC IO functions, take care of the main status register, timeout
 1201:  * in case the desired status bits are never set.
 1202:  *
 1203:  * These PIO loops initially start out with short delays between
 1204:  * each iteration in the expectation that the required condition
 1205:  * is usually met quickly, so it can be handled immediately.  After
 1206:  * about 1 ms, stepping is increased to achieve a better timing
 1207:  * accuracy in the calls to DELAY().
 1208:  */
 1209: static int
 1210: fd_in(struct fdc_data *fdc, int *ptr)
 1211: {
 1212: 	int i, j, step;
 1213: 
 1214: 	for (j = 0, step = 1;
 1215: 	    (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM) &&
 1216: 	    j < FDSTS_TIMEOUT;
 1217: 	    j += step) {
 1218: 		if (i == NE7_RQM)
 1219: 			return (fdc_err(fdc, "ready for output in input\n"));
 1220: 		if (j == 1000)
 1221: 			step = 1000;
 1222: 		DELAY(step);
 1223: 	}
 1224: 	if (j >= FDSTS_TIMEOUT)
 1225: 		return (fdc_err(fdc, bootverbose? "input ready timeout\n": 0));
 1226: #ifdef	FDC_DEBUG
 1227: 	i = fddata_rd(fdc);
 1228: 	TRACE1("[FDDATA->0x%x]", (unsigned char)i);
 1229: 	*ptr = i;
 1230: 	return (0);
 1231: #else	/* !FDC_DEBUG */
 1232: 	i = fddata_rd(fdc);
 1233: 	if (ptr)
 1234: 		*ptr = i;
 1235: 	return (0);
 1236: #endif	/* FDC_DEBUG */
 1237: }
 1238: 
 1239: static int
 1240: out_fdc(struct fdc_data *fdc, int x)
 1241: {
 1242: 	int i, j, step;
 1243: 
 1244: 	for (j = 0, step = 1;
 1245: 	    (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != NE7_RQM &&
 1246: 	    j < FDSTS_TIMEOUT;
 1247: 	    j += step) {
 1248: 		if (i == (NE7_DIO|NE7_RQM))
 1249: 			return (fdc_err(fdc, "ready for input in output\n"));
 1250: 		if (j == 1000)
 1251: 			step = 1000;
 1252: 		DELAY(step);
 1253: 	}
 1254: 	if (j >= FDSTS_TIMEOUT)
 1255: 		return (fdc_err(fdc, bootverbose? "output ready timeout\n": 0));
 1256: 
 1257: 	/* Send the command and return */
 1258: 	fddata_wr(fdc, x);
 1259: 	TRACE1("[0x%x->FDDATA]", x);
 1260: 	return (0);
 1261: }
 1262: 
 1263: /****************************************************************************/
 1264: /*                           fdopen/fdclose                                 */
 1265: /****************************************************************************/
 1266: int
 1267: Fdopen(dev_t dev, int flags, int mode, struct thread *td)
 1268: {
 1269:  	fdu_t fdu = FDUNIT(minor(dev));
 1270: 	int type = FDTYPE(minor(dev));
 1271: 	fd_p	fd;
 1272: 	fdc_p	fdc;
 1273: 
 1274: 	/* check bounds */
 1275: 	if ((fd = devclass_get_softc(fd_devclass, fdu)) == 0)
 1276: 		return (ENXIO);
 1277: 	fdc = fd->fdc;
 1278: 	if ((fdc == NULL) || (fd->type == NO_TYPE))
 1279: 		return (ENXIO);
 1280: 	if (type > NUMDENS)
 1281: 		return (ENXIO);
 1282: 	if (type == 0)
 1283: 		type = fd->type;
 1284: 	else {
 1285: 		/*
 1286: 		 * For each type of basic drive, make sure we are trying
 1287: 		 * to open a type it can do,
 1288: 		 */
 1289: 		if (type != fd->type) {
 1290: 			switch (fd->type) {
 1291: 			case FD_360:
 1292: 				return (ENXIO);
 1293: 			case FD_720:
 1294: 				if (   type != FD_820
 1295: 				    && type != FD_800
 1296: 				    && type != FD_640
 1297: 				   )
 1298: 					return (ENXIO);
 1299: 				break;
 1300: 			case FD_1200:
 1301: 				switch (type) {
 1302: 				case FD_1480:
 1303: 					type = FD_1480in5_25;
 1304: 					break;
 1305: 				case FD_1440:
 1306: 					type = FD_1440in5_25;
 1307: 					break;
 1308: 				case FD_1232:
 1309: 					break;
 1310: 				case FD_820:
 1311: 					type = FD_820in5_25;
 1312: 					break;
 1313: 				case FD_800:
 1314: 					type = FD_800in5_25;
 1315: 					break;
 1316: 				case FD_720:
 1317: 					type = FD_720in5_25;
 1318: 					break;
 1319: 				case FD_640:
 1320: 					type = FD_640in5_25;
 1321: 					break;
 1322: 				case FD_360:
 1323: 					type = FD_360in5_25;
 1324: 					break;
 1325: 				default:
 1326: 					return(ENXIO);
 1327: 				}
 1328: 				break;
 1329: 			case FD_1440:
 1330: 				if (   type != FD_1720
 1331: 				    && type != FD_1480
 1332: 				    && type != FD_1200
 1333: 				    && type != FD_820
 1334: 				    && type != FD_800
 1335: 				    && type != FD_720
 1336: 				    && type != FD_640
 1337: 				    )
 1338: 					return(ENXIO);
 1339: 				break;
 1340: 			}
 1341: 		}
 1342: 	}
 1343: 	fd->ft = fd_types + type - 1;
 1344: 	fd->flags |= FD_OPEN;
 1345: 	/*
 1346: 	 * Clearing the DMA overrun counter at open time is a bit messy.
 1347: 	 * Since we're only managing one counter per controller, opening
 1348: 	 * the second drive could mess it up.  Anyway, if the DMA overrun
 1349: 	 * condition is really persistent, it will eventually time out
 1350: 	 * still.  OTOH, clearing it here will ensure we'll at least start
 1351: 	 * trying again after a previous (maybe even long ago) failure.
 1352: 	 * Also, this is merely a stop-gap measure only that should not
 1353: 	 * happen during normal operation, so we can tolerate it to be a
 1354: 	 * bit sloppy about this.
 1355: 	 */
 1356: 	fdc->dma_overruns = 0;
 1357: 
 1358: 	return 0;
 1359: }
 1360: 
 1361: int
 1362: fdclose(dev_t dev, int flags, int mode, struct thread *td)
 1363: {
 1364:  	fdu_t fdu = FDUNIT(minor(dev));
 1365: 	struct fd_data *fd;
 1366: 
 1367: 	fd = devclass_get_softc(fd_devclass, fdu);
 1368: 	fd->flags &= ~FD_OPEN;
 1369: 	fd->options &= ~(FDOPT_NORETRY | FDOPT_NOERRLOG);
 1370: 
 1371: 	return (0);
 1372: }
 1373: 
 1374: /****************************************************************************/
 1375: /*                               fdstrategy                                 */
 1376: /****************************************************************************/
 1377: void
 1378: fdstrategy(struct buf *bp)
 1379: {
 1380: 	unsigned nblocks, blknum, cando;
 1381:  	int	s;
 1382:  	fdu_t	fdu;
 1383:  	fdc_p	fdc;
 1384:  	fd_p	fd;
 1385: 	size_t	fdblk;
 1386: 
 1387:  	fdu = FDUNIT(minor(bp->b_dev));
 1388: 	fd = devclass_get_softc(fd_devclass, fdu);
 1389: 	if (fd == 0)
 1390: 		panic("fdstrategy: buf for nonexistent device (%#lx, %#lx)",
 1391: 		      (u_long)major(bp->b_dev), (u_long)minor(bp->b_dev));
 1392: 	fdc = fd->fdc;
 1393: 	if (fd->type == NO_TYPE) {
 1394: 		bp->b_error = ENXIO;
 1395: 		bp->b_flags |= B_ERROR;
 1396: 		goto bad;
 1397: 	};
 1398: 
 1399: 	fdblk = 128 << (fd->ft->secsize);
 1400: 	if (!(bp->b_flags & B_FORMAT)) {
 1401: 		if (bp->b_blkno < 0) {
 1402: 			printf(
 1403: 		"fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
 1404: 			       fdu, (u_long)bp->b_blkno, bp->b_bcount);
 1405: 			bp->b_error = EINVAL;
 1406: 			bp->b_flags |= B_ERROR;
 1407: 			goto bad;
 1408: 		}
 1409: 		if ((bp->b_bcount % fdblk) != 0) {
 1410: 			bp->b_error = EINVAL;
 1411: 			bp->b_flags |= B_ERROR;
 1412: 			goto bad;
 1413: 		}
 1414: 	}
 1415: 
 1416: 	/*
 1417: 	 * Set up block calculations.
 1418: 	 */
 1419: 	if (bp->b_blkno > 20000000) {
 1420: 		/*
 1421: 		 * Reject unreasonably high block number, prevent the
 1422: 		 * multiplication below from overflowing.
 1423: 		 */
 1424: 		bp->b_error = EINVAL;
 1425: 		bp->b_flags |= B_ERROR;
 1426: 		goto bad;
 1427: 	}
 1428: 	blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk;
 1429:  	nblocks = fd->ft->size;
 1430: 	bp->b_resid = 0;
 1431: 	if (blknum + (bp->b_bcount / fdblk) > nblocks) {
 1432: 		if (blknum <= nblocks) {
 1433: 			cando = (nblocks - blknum) * fdblk;
 1434: 			bp->b_resid = bp->b_bcount - cando;
 1435: 			if (cando == 0)
 1436: 				goto bad;	/* not actually bad but EOF */
 1437: 		} else {
 1438: 			bp->b_error = EINVAL;
 1439: 			bp->b_flags |= B_ERROR;
 1440: 			goto bad;
 1441: 		}
 1442: 	}
 1443:  	bp->b_pblkno = bp->b_blkno;
 1444: 	s = splbio();
 1445: 	bufqdisksort(&fdc->head, bp);
 1446: 	untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
 1447: 
 1448: 	/* Tell devstat we are starting on the transaction */
 1449: 	devstat_start_transaction(&fd->device_stats);
 1450: 	device_busy(fd->dev);
 1451: 
 1452: 	fdstart(fdc);
 1453: 	splx(s);
 1454: 	return;
 1455: 
 1456: bad:
 1457: 	biodone(bp);
 1458: }
 1459: 
 1460: /***************************************************************\
 1461: *				fdstart				*
 1462: * We have just queued something.. if the controller is not busy	*
 1463: * then simulate the case where it has just finished a command	*
 1464: * So that it (the interrupt routine) looks on the queue for more*
 1465: * work to do and picks up what we just added.			*
 1466: * If the controller is already busy, we need do nothing, as it	*
 1467: * will pick up our work when the present work completes		*
 1468: \***************************************************************/
 1469: static void
 1470: fdstart(struct fdc_data *fdc)
 1471: {
 1472: 	int s;
 1473: 
 1474: 	s = splbio();
 1475: 	if(fdc->state == DEVIDLE)
 1476: 	{
 1477: 		fdc_intr(fdc);
 1478: 	}
 1479: 	splx(s);
 1480: }
 1481: 
 1482: static void
 1483: fd_iotimeout(void *xfdc)
 1484: {
 1485:  	fdc_p fdc;
 1486: 	int s;
 1487: 
 1488: 	fdc = xfdc;
 1489: 	TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
 1490: 
 1491: 	/*
 1492: 	 * Due to IBM's brain-dead design, the FDC has a faked ready
 1493: 	 * signal, hardwired to ready == true. Thus, any command
 1494: 	 * issued if there's no diskette in the drive will _never_
 1495: 	 * complete, and must be aborted by resetting the FDC.
 1496: 	 * Many thanks, Big Blue!
 1497: 	 * The FDC must not be reset directly, since that would
 1498: 	 * interfere with the state machine.  Instead, pretend that
 1499: 	 * the command completed but was invalid.  The state machine
 1500: 	 * will reset the FDC and retry once.
 1501: 	 */
 1502: 	s = splbio();
 1503: 	fdc->status[0] = NE7_ST0_IC_IV;
 1504: 	fdc->flags &= ~FDC_STAT_VALID;
 1505: 	fdc->state = IOTIMEDOUT;
 1506: 	fdc_intr(fdc);
 1507: 	splx(s);
 1508: }
 1509: 
 1510: /* just ensure it has the right spl */
 1511: static void
 1512: fd_pseudointr(void *xfdc)
 1513: {
 1514: 	int	s;
 1515: 
 1516: 	s = splbio();
 1517: 	fdc_intr(xfdc);
 1518: 	splx(s);
 1519: }
 1520: 
 1521: /***********************************************************************\
 1522: *                                 fdintr				*
 1523: * keep calling the state machine until it returns a 0			*
 1524: * ALWAYS called at SPLBIO 						*
 1525: \***********************************************************************/
 1526: static void
 1527: fdc_intr(void *xfdc)
 1528: {
 1529: 	fdc_p fdc = xfdc;
 1530: 	while(fdstate(fdc))
 1531: 		;
 1532: }
 1533: 
 1534: /*
 1535:  * magic pseudo-DMA initialization for YE FDC. Sets count and
 1536:  * direction
 1537:  */
 1538: #define SET_BCDR(fdc,wr,cnt,port) \
 1539: 	bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port,	 \
 1540: 	    ((cnt)-1) & 0xff);						 \
 1541: 	bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
 1542: 	    ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
 1543: 
 1544: /*
 1545:  * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
 1546:  */
 1547: static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
 1548: {
 1549: 	u_char *cptr = (u_char *)addr;
 1550: 
 1551: 	if (flags & B_READ) {
 1552: 		if (fdc->state != PIOREAD) {
 1553: 			fdc->state = PIOREAD;
 1554: 			return(0);
 1555: 		};
 1556: 		SET_BCDR(fdc, 0, count, 0);
 1557: 		bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
 1558: 		    FDC_YE_DATAPORT, cptr, count);
 1559: 	} else {
 1560: 		bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
 1561: 		    FDC_YE_DATAPORT, cptr, count);
 1562: 		SET_BCDR(fdc, 0, count, 0);
 1563: 	};
 1564: 	return(1);
 1565: }
 1566: 
 1567: /***********************************************************************\
 1568: * The controller state machine.						*
 1569: * if it returns a non zero value, it should be called again immediatly	*
 1570: \***********************************************************************/
 1571: static int
 1572: fdstate(fdc_p fdc)
 1573: {
 1574: 	int read, format, head, i, sec = 0, sectrac, st0, cyl, st3;
 1575: 	unsigned blknum = 0, b_cylinder = 0;
 1576: 	fdu_t fdu = fdc->fdu;
 1577: 	fd_p fd;
 1578: 	struct buf *bp;
 1579: 	struct fd_formb *finfo = NULL;
 1580: 	size_t fdblk;
 1581: 
 1582: 	bp = fdc->bp;
 1583: 	if (bp == NULL) {
 1584: 		bp = bufq_first(&fdc->head);
 1585: 		if (bp != NULL) {
 1586: 			bufq_remove(&fdc->head, bp);
 1587: 			fdc->bp = bp;
 1588: 		}
 1589: 	}
 1590: 	if (bp == NULL) {
 1591: 		/***********************************************\
 1592: 		* nothing left for this controller to do	*
 1593: 		* Force into the IDLE state,			*
 1594: 		\***********************************************/
 1595: 		fdc->state = DEVIDLE;
 1596: 		if (fdc->fd) {
 1597: 			device_printf(fdc->fdc_dev,
 1598: 			    "unexpected valid fd pointer\n");
 1599: 			fdc->fd = (fd_p) 0;
 1600: 			fdc->fdu = -1;
 1601: 		}
 1602: 		TRACE1("[fdc%d IDLE]", fdc->fdcu);
 1603:  		return (0);
 1604: 	}
 1605: 	fdu = FDUNIT(minor(bp->b_dev));
 1606: 	fd = devclass_get_softc(fd_devclass, fdu);
 1607: 	fdblk = 128 << fd->ft->secsize;
 1608: 	if (fdc->fd && (fd != fdc->fd))
 1609: 		device_printf(fd->dev, "confused fd pointers\n");
 1610: 	read = bp->b_flags & B_READ;
 1611: 	format = bp->b_flags & B_FORMAT;
 1612: 	if (format) {
 1613: 		finfo = (struct fd_formb *)bp->b_data;
 1614: 		fd->skip = (char *)&(finfo->fd_formb_cylno(0))
 1615: 			- (char *)finfo;
 1616: 	}
 1617: 	if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
 1618: 		blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk +
 1619: 			fd->skip/fdblk;
 1620: 		b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
 1621: 	}
 1622: 	TRACE1("fd%d", fdu);
 1623: 	TRACE1("[%s]", fdstates[fdc->state]);
 1624: 	TRACE1("(0x%x)", fd->flags);
 1625: 	untimeout(fd_turnoff, fd, fd->toffhandle);
 1626: 	fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
 1627: 	switch (fdc->state)
 1628: 	{
 1629: 	case DEVIDLE:
 1630: 	case FINDWORK:	/* we have found new work */
 1631: 		fdc->retry = 0;
 1632: 		fd->skip = 0;
 1633: 		fdc->fd = fd;
 1634: 		fdc->fdu = fdu;
 1635: 		fdc->fdctl_wr(fdc, fd->ft->trans);
 1636: 		TRACE1("[0x%x->FDCTL]", fd->ft->trans);
 1637: 		/*******************************************************\
 1638: 		* If the next drive has a motor startup pending, then	*
 1639: 		* it will start up in its own good time		*
 1640: 		\*******************************************************/
 1641: 		if(fd->flags & FD_MOTOR_WAIT) {
 1642: 			fdc->state = MOTORWAIT;
 1643: 			return (0); /* come back later */
 1644: 		}
 1645: 		/*******************************************************\
 1646: 		* Maybe if it's not starting, it SHOULD be starting	*
 1647: 		\*******************************************************/
 1648: 		if (!(fd->flags & FD_MOTOR))
 1649: 		{
 1650: 			fdc->state = MOTORWAIT;
 1651: 			fd_turnon(fd);
 1652: 			return (0);
 1653: 		}
 1654: 		else	/* at least make sure we are selected */
 1655: 		{
 1656: 			set_motor(fdc, fd->fdsu, TURNON);
 1657: 		}
 1658: 		if (fdc->flags & FDC_NEEDS_RESET) {
 1659: 			fdc->state = RESETCTLR;
 1660: 			fdc->flags &= ~FDC_NEEDS_RESET;
 1661: 		} else
 1662: 			fdc->state = DOSEEK;
 1663: 		break;
 1664: 	case DOSEEK:
 1665: 		if (b_cylinder == (unsigned)fd->track)
 1666: 		{
 1667: 			fdc->state = SEEKCOMPLETE;
 1668: 			break;
 1669: 		}
 1670: 		if (fd_cmd(fdc, 3, NE7CMD_SEEK,
 1671: 			   fd->fdsu, b_cylinder * fd->ft->steptrac,
 1672: 			   0))
 1673: 		{
 1674: 			/*
 1675: 			 * seek command not accepted, looks like
 1676: 			 * the FDC went off to the Saints...
 1677: 			 */
 1678: 			fdc->retry = 6;	/* try a reset */
 1679: 			return(retrier(fdc));
 1680: 		}
 1681: 		fd->track = FD_NO_TRACK;
 1682: 		fdc->state = SEEKWAIT;
 1683: 		return(0);	/* will return later */
 1684: 	case SEEKWAIT:
 1685: 		/* allow heads to settle */
 1686: 		timeout(fd_pseudointr, fdc, hz / 16);
 1687: 		fdc->state = SEEKCOMPLETE;
 1688: 		return(0);	/* will return later */
 1689: 	case SEEKCOMPLETE : /* SEEK DONE, START DMA */
 1690: 		/* Make sure seek really happened*/
 1691: 		if(fd->track == FD_NO_TRACK) {
 1692: 			int descyl = b_cylinder * fd->ft->steptrac;
 1693: 			do {
 1694: 				/*
 1695: 				 * This might be a "ready changed" interrupt,
 1696: 				 * which cannot really happen since the
 1697: 				 * RDY pin is hardwired to + 5 volts.  This
 1698: 				 * generally indicates a "bouncing" intr
 1699: 				 * line, so do one of the following:
 1700: 				 *
 1701: 				 * When running on an enhanced FDC that is
 1702: 				 * known to not go stuck after responding
 1703: 				 * with INVALID, fetch all interrupt states
 1704: 				 * until seeing either an INVALID or a
 1705: 				 * real interrupt condition.
 1706: 				 *
 1707: 				 * When running on a dumb old NE765, give
 1708: 				 * up immediately.  The controller will
 1709: 				 * provide up to four dummy RC interrupt
 1710: 				 * conditions right after reset (for the
 1711: 				 * corresponding four drives), so this is
 1712: 				 * our only chance to get notice that it
 1713: 				 * was not the FDC that caused the interrupt.
 1714: 				 */
 1715: 				if (fd_sense_int(fdc, &st0, &cyl)
 1716: 				    == FD_NOT_VALID)
 1717: 					return 0;
 1718: 				if(fdc->fdct == FDC_NE765
 1719: 				   && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 1720: 					return 0; /* hope for a real intr */
 1721: 			} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 1722: 
 1723: 			if (0 == descyl) {
 1724: 				int failed = 0;
 1725: 				/*
 1726: 				 * seek to cyl 0 requested; make sure we are
 1727: 				 * really there
 1728: 				 */
 1729: 				if (fd_sense_drive_status(fdc, &st3))
 1730: 					failed = 1;
 1731: 				if ((st3 & NE7_ST3_T0) == 0) {
 1732: 					printf(
 1733: 		"fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
 1734: 					       fdu, st3, NE7_ST3BITS);
 1735: 					failed = 1;
 1736: 				}
 1737: 
 1738: 				if (failed) {
 1739: 					if(fdc->retry < 3)
 1740: 						fdc->retry = 3;
 1741: 					return (retrier(fdc));
 1742: 				}
 1743: 			}
 1744: 
 1745: 			if (cyl != descyl) {
 1746: 				printf(
 1747: 		"fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
 1748: 				       fdu, descyl, cyl, st0);
 1749: 				if (fdc->retry < 3)
 1750: 					fdc->retry = 3;
 1751: 				return (retrier(fdc));
 1752: 			}
 1753: 		}
 1754: 
 1755: 		fd->track = b_cylinder;
 1756: 		if (!(fdc->flags & FDC_NODMA))
 1757: 			isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
 1758: 				format ? bp->b_bcount : fdblk, fdc->dmachan);
 1759: 		sectrac = fd->ft->sectrac;
 1760: 		sec = blknum %  (sectrac * fd->ft->heads);
 1761: 		head = sec / sectrac;
 1762: 		sec = sec % sectrac + 1;
 1763: 		fd->hddrv = ((head&1)<<2)+fdu;
 1764: 
 1765: 		if(format || !read)
 1766: 		{
 1767: 			/* make sure the drive is writable */
 1768: 			if(fd_sense_drive_status(fdc, &st3) != 0)
 1769: 			{
 1770: 				/* stuck controller? */
 1771: 				if (!(fdc->flags & FDC_NODMA))
 1772: 					isa_dmadone(bp->b_flags,
 1773: 						    bp->b_data + fd->skip,
 1774: 						    format ? bp->b_bcount : fdblk,
 1775: 						    fdc->dmachan);
 1776: 				fdc->retry = 6;	/* reset the beast */
 1777: 				return (retrier(fdc));
 1778: 			}
 1779: 			if(st3 & NE7_ST3_WP)
 1780: 			{
 1781: 				/*
 1782: 				 * XXX YES! this is ugly.
 1783: 				 * in order to force the current operation
 1784: 				 * to fail, we will have to fake an FDC
 1785: 				 * error - all error handling is done
 1786: 				 * by the retrier()
 1787: 				 */
 1788: 				fdc->status[0] = NE7_ST0_IC_AT;
 1789: 				fdc->status[1] = NE7_ST1_NW;
 1790: 				fdc->status[2] = 0;
 1791: 				fdc->status[3] = fd->track;
 1792: 				fdc->status[4] = head;
 1793: 				fdc->status[5] = sec;
 1794: 				fdc->retry = 8;	/* break out immediately */
 1795: 				fdc->state = IOTIMEDOUT; /* not really... */
 1796: 				return (1);
 1797: 			}
 1798: 		}
 1799: 
 1800: 		if (format) {
 1801: 			if (fdc->flags & FDC_NODMA) {
 1802: 				/*
 1803: 				 * This seems to be necessary for
 1804: 				 * whatever obscure reason; if we omit
 1805: 				 * it, we end up filling the sector ID
 1806: 				 * fields of the newly formatted track
 1807: 				 * entirely with garbage, causing
 1808: 				 * `wrong cylinder' errors all over
 1809: 				 * the place when trying to read them
 1810: 				 * back.
 1811: 				 *
 1812: 				 * Umpf.
 1813: 				 */
 1814: 				SET_BCDR(fdc, 1, bp->b_bcount, 0);
 1815: 
 1816: 				(void)fdcpio(fdc,bp->b_flags,
 1817: 					bp->b_data+fd->skip,
 1818: 					bp->b_bcount);
 1819: 
 1820: 			}
 1821: 			/* formatting */
 1822: 			if(fd_cmd(fdc, 6,  NE7CMD_FORMAT, head << 2 | fdu,
 1823: 				  finfo->fd_formb_secshift,
 1824: 				  finfo->fd_formb_nsecs,
 1825: 				  finfo->fd_formb_gaplen,
 1826: 				  finfo->fd_formb_fillbyte, 0)) {
 1827: 				/* controller fell over */
 1828: 				if (!(fdc->flags & FDC_NODMA))
 1829: 					isa_dmadone(bp->b_flags,
 1830: 						    bp->b_data + fd->skip,
 1831: 						    format ? bp->b_bcount : fdblk,
 1832: 						    fdc->dmachan);
 1833: 				fdc->retry = 6;
 1834: 				return (retrier(fdc));
 1835: 			}
 1836: 		} else {
 1837: 			if (fdc->flags & FDC_NODMA) {
 1838: 				/*
 1839: 				 * this seems to be necessary even when
 1840: 				 * reading data
 1841: 				 */
 1842: 				SET_BCDR(fdc, 1, fdblk, 0);
 1843: 
 1844: 				/*
 1845: 				 * perform the write pseudo-DMA before
 1846: 				 * the WRITE command is sent
 1847: 				 */
 1848: 				if (!read)
 1849: 					(void)fdcpio(fdc,bp->b_flags,
 1850: 					    bp->b_data+fd->skip,
 1851: 					    fdblk);
 1852: 			}
 1853: 			if (fd_cmd(fdc, 9,
 1854: 				   (read ? NE7CMD_READ : NE7CMD_WRITE),
 1855: 				   head << 2 | fdu,  /* head & unit */
 1856: 				   fd->track,        /* track */
 1857: 				   head,
 1858: 				   sec,              /* sector + 1 */
 1859: 				   fd->ft->secsize,  /* sector size */
 1860: 				   sectrac,          /* sectors/track */
 1861: 				   fd->ft->gap,      /* gap size */
 1862: 				   fd->ft->datalen,  /* data length */
 1863: 				   0)) {
 1864: 				/* the beast is sleeping again */
 1865: 				if (!(fdc->flags & FDC_NODMA))
 1866: 					isa_dmadone(bp->b_flags,
 1867: 						    bp->b_data + fd->skip,
 1868: 						    format ? bp->b_bcount : fdblk,
 1869: 						    fdc->dmachan);
 1870: 				fdc->retry = 6;
 1871: 				return (retrier(fdc));
 1872: 			}
 1873: 		}
 1874: 		if (fdc->flags & FDC_NODMA)
 1875: 			/*
 1876: 			 * if this is a read, then simply await interrupt
 1877: 			 * before performing PIO
 1878: 			 */
 1879: 			if (read && !fdcpio(fdc,bp->b_flags,
 1880: 			    bp->b_data+fd->skip,fdblk)) {
 1881: 				fd->tohandle = timeout(fd_iotimeout, fdc, hz);
 1882: 				return(0);      /* will return later */
 1883: 			};
 1884: 
 1885: 		/*
 1886: 		 * write (or format) operation will fall through and
 1887: 		 * await completion interrupt
 1888: 		 */
 1889: 		fdc->state = IOCOMPLETE;
 1890: 		fd->tohandle = timeout(fd_iotimeout, fdc, hz);
 1891: 		return (0);	/* will return later */
 1892: 	case PIOREAD:
 1893: 		/* 
 1894: 		 * actually perform the PIO read.  The IOCOMPLETE case
 1895: 		 * removes the timeout for us.  
 1896: 		 */
 1897: 		(void)fdcpio(fdc,bp->b_flags,bp->b_data+fd->skip,fdblk);
 1898: 		fdc->state = IOCOMPLETE;
 1899: 		/* FALLTHROUGH */
 1900: 	case IOCOMPLETE: /* IO DONE, post-analyze */
 1901: 		untimeout(fd_iotimeout, fdc, fd->tohandle);
 1902: 
 1903: 		if (fd_read_status(fdc, fd->fdsu)) {
 1904: 			if (!(fdc->flags & FDC_NODMA))
 1905: 				isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
 1906: 					    format ? bp->b_bcount : fdblk,
 1907: 					    fdc->dmachan);
 1908: 			if (fdc->retry < 6)
 1909: 				fdc->retry = 6;	/* force a reset */
 1910: 			return (retrier(fdc));
 1911:   		}
 1912: 
 1913: 		fdc->state = IOTIMEDOUT;
 1914: 
 1915: 		/* FALLTHROUGH */
 1916: 
 1917: 	case IOTIMEDOUT:
 1918: 		if (!(fdc->flags & FDC_NODMA))
 1919: 			isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
 1920: 				format ? bp->b_bcount : fdblk, fdc->dmachan);
 1921: 		if (fdc->status[0] & NE7_ST0_IC) {
 1922:                         if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 1923: 			    && fdc->status[1] & NE7_ST1_OR) {
 1924:                                 /*
 1925: 				 * DMA overrun. Someone hogged the bus and
 1926: 				 * didn't release it in time for the next
 1927: 				 * FDC transfer.
 1928: 				 *
 1929: 				 * We normally restart this without bumping
 1930: 				 * the retry counter.  However, in case
 1931: 				 * something is seriously messed up (like
 1932: 				 * broken hardware), we rather limit the
 1933: 				 * number of retries so the IO operation
 1934: 				 * doesn't block indefinately.
 1935: 				 */
 1936: 				if (fdc->dma_overruns++ < FDC_DMAOV_MAX) {
 1937: 					fdc->state = SEEKCOMPLETE;
 1938: 					return (1);
 1939: 				} /* else fall through */
 1940:                         }
 1941: 			if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
 1942: 				&& fdc->retry < 6)
 1943: 				fdc->retry = 6;	/* force a reset */
 1944: 			else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
 1945: 				&& fdc->status[2] & NE7_ST2_WC
 1946: 				&& fdc->retry < 3)
 1947: 				fdc->retry = 3;	/* force recalibrate */
 1948: 			return (retrier(fdc));
 1949: 		}
 1950: 		/* All OK */
 1951: 		/* Operation successful, retry DMA overruns again next time. */
 1952: 		fdc->dma_overruns = 0;
 1953: 		fd->skip += fdblk;
 1954: 		if (!format && fd->skip < bp->b_bcount - bp->b_resid) {
 1955: 			/* set up next transfer */
 1956: 			fdc->state = DOSEEK;
 1957: 		} else {
 1958: 			/* ALL DONE */
 1959: 			fd->skip = 0;
 1960: 			fdc->bp = NULL;
 1961: 			device_unbusy(fd->dev);
 1962: 			devstat_end_transaction_buf(&fd->device_stats, bp);
 1963: 			biodone(bp);
 1964: 			fdc->fd = (fd_p) 0;
 1965: 			fdc->fdu = -1;
 1966: 			fdc->state = FINDWORK;
 1967: 		}
 1968: 		return (1);
 1969: 	case RESETCTLR:
 1970: 		fdc_reset(fdc);
 1971: 		fdc->retry++;
 1972: 		fdc->state = RESETCOMPLETE;
 1973: 		return (0);
 1974: 	case RESETCOMPLETE:
 1975: 		/*
 1976: 		 * Discard all the results from the reset so that they
 1977: 		 * can't cause an unexpected interrupt later.
 1978: 		 */
 1979: 		for (i = 0; i < 4; i++)
 1980: 			(void)fd_sense_int(fdc, &st0, &cyl);
 1981: 		fdc->state = STARTRECAL;
 1982: 		/* Fall through. */
 1983: 	case STARTRECAL:
 1984: 		if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) {
 1985: 			/* arrgl */
 1986: 			fdc->retry = 6;
 1987: 			return (retrier(fdc));
 1988: 		}
 1989: 		fdc->state = RECALWAIT;
 1990: 		return (0);	/* will return later */
 1991: 	case RECALWAIT:
 1992: 		/* allow heads to settle */
 1993: 		timeout(fd_pseudointr, fdc, hz / 8);
 1994: 		fdc->state = RECALCOMPLETE;
 1995: 		return (0);	/* will return later */
 1996: 	case RECALCOMPLETE:
 1997: 		do {
 1998: 			/*
 1999: 			 * See SEEKCOMPLETE for a comment on this:
 2000: 			 */
 2001: 			if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
 2002: 				return 0;
 2003: 			if(fdc->fdct == FDC_NE765
 2004: 			   && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
 2005: 				return 0; /* hope for a real intr */
 2006: 		} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
 2007: 		if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
 2008: 		{
 2009: 			if(fdc->retry > 3)
 2010: 				/*
 2011: 				 * a recalibrate from beyond cylinder 77
 2012: 				 * will "fail" due to the FDC limitations;
 2013: 				 * since people used to complain much about
 2014: 				 * the failure message, try not logging
 2015: 				 * this one if it seems to be the first
 2016: 				 * time in a line
 2017: 				 */
 2018: 				printf("fd%d: recal failed ST0 %b cyl %d\n",
 2019: 				       fdu, st0, NE7_ST0BITS, cyl);
 2020: 			if(fdc->retry < 3) fdc->retry = 3;
 2021: 			return (retrier(fdc));
 2022: 		}
 2023: 		fd->track = 0;
 2024: 		/* Seek (probably) necessary */
 2025: 		fdc->state = DOSEEK;
 2026: 		return (1);	/* will return immediatly */
 2027: 	case MOTORWAIT:
 2028: 		if(fd->flags & FD_MOTOR_WAIT)
 2029: 		{
 2030: 			return (0); /* time's not up yet */
 2031: 		}
 2032: 		if (fdc->flags & FDC_NEEDS_RESET) {
 2033: 			fdc->state = RESETCTLR;
 2034: 			fdc->flags &= ~FDC_NEEDS_RESET;
 2035: 		} else {
 2036: 			/*
 2037: 			 * If all motors were off, then the controller was
 2038: 			 * reset, so it has lost track of the current
 2039: 			 * cylinder.  Recalibrate to handle this case.
 2040: 			 * But first, discard the results of the reset.
 2041: 			 */
 2042: 			fdc->state = RESETCOMPLETE;
 2043: 		}
 2044: 		return (1);	/* will return immediatly */
 2045: 	default:
 2046: 		device_printf(fdc->fdc_dev, "unexpected FD int->");
 2047: 		if (fd_read_status(fdc, fd->fdsu) == 0)
 2048: 			printf("FDC status :%x %x %x %x %x %x %x   ",
 2049: 			       fdc->status[0],
 2050: 			       fdc->status[1],
 2051: 			       fdc->status[2],
 2052: 			       fdc->status[3],
 2053: 			       fdc->status[4],
 2054: 			       fdc->status[5],
 2055: 			       fdc->status[6] );
 2056: 		else
 2057: 			printf("No status available   ");
 2058: 		if (fd_sense_int(fdc, &st0, &cyl) != 0)
 2059: 		{
 2060: 			printf("[controller is dead now]\n");
 2061: 			return (0);
 2062: 		}
 2063: 		printf("ST0 = %x, PCN = %x\n", st0, cyl);
 2064: 		return (0);
 2065: 	}
 2066: 	/*XXX confusing: some branches return immediately, others end up here*/
 2067: 	return (1); /* Come back immediatly to new state */
 2068: }
 2069: 
 2070: static int
 2071: retrier(struct fdc_data *fdc)
 2072: {
 2073: 	struct buf *bp;
 2074: 	struct fd_data *fd;
 2075: 	int fdu;
 2076: 
 2077: 	bp = fdc->bp;
 2078: 
 2079: 	/* XXX shouldn't this be cached somewhere?  */
 2080: 	fdu = FDUNIT(minor(bp->b_dev));
 2081: 	fd = devclass_get_softc(fd_devclass, fdu);
 2082: 	if (fd->options & FDOPT_NORETRY)
 2083: 		goto fail;
 2084: 
 2085: 	switch (fdc->retry) {
 2086: 	case 0: case 1: case 2:
 2087: 		fdc->state = SEEKCOMPLETE;
 2088: 		break;
 2089: 	case 3: case 4: case 5:
 2090: 		fdc->state = STARTRECAL;
 2091: 		break;
 2092: 	case 6:
 2093: 		fdc->state = RESETCTLR;
 2094: 		break;
 2095: 	case 7:
 2096: 		break;
 2097: 	default:
 2098: 	fail:
 2099: 		{
 2100: 			int printerror = (fd->options & FDOPT_NOERRLOG) == 0;
 2101: 			dev_t sav_b_dev;
 2102: 
 2103: 			/* Trick diskerr */
 2104: 			if (printerror) {
 2105: 				sav_b_dev = bp->b_dev;
 2106: 				bp->b_dev = make_sub_dev(bp->b_dev,
 2107: 				    (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
 2108: 				diskerr(bp, "hard error", LOG_PRINTF,
 2109: 					fdc->fd->skip / DEV_BSIZE,
 2110: 					(struct disklabel *)NULL);
 2111: 				bp->b_dev = sav_b_dev;
 2112: 			}
 2113: 			if (printerror) {
 2114: 				if (fdc->flags & FDC_STAT_VALID)
 2115: 					printf(
 2116: 			" (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n",
 2117: 					       fdc->status[0], NE7_ST0BITS,
 2118: 					       fdc->status[1], NE7_ST1BITS,
 2119: 					       fdc->status[2], NE7_ST2BITS,
 2120: 					       fdc->status[3], fdc->status[4],
 2121: 					       fdc->status[5]);
 2122: 				else
 2123: 					printf(" (No status)\n");
 2124: 			}
 2125: 		}
 2126: 		bp->b_flags |= B_ERROR;
 2127: 		bp->b_error = EIO;
 2128: 		bp->b_resid += bp->b_bcount - fdc->fd->skip;
 2129: 		fdc->bp = NULL;
 2130: 		fdc->fd->skip = 0;
 2131: 		device_unbusy(fd->dev);
 2132: 		devstat_end_transaction_buf(&fdc->fd->device_stats, bp);
 2133: 		biodone(bp);
 2134: 		fdc->state = FINDWORK;
 2135: 		fdc->flags |= FDC_NEEDS_RESET;
 2136: 		fdc->fd = (fd_p) 0;
 2137: 		fdc->fdu = -1;
 2138: 		return (1);
 2139: 	}
 2140: 	fdc->retry++;
 2141: 	return (1);
 2142: }
 2143: 
 2144: static int
 2145: fdformat(dev_t dev, struct fd_formb *finfo, struct thread *td)
 2146: {
 2147: 	struct proc *p = td->td_proc;
 2148:  	fdu_t	fdu;
 2149:  	fd_p	fd;
 2150: 
 2151: 	struct buf *bp;
 2152: 	int rv = 0, s;
 2153: 	size_t fdblk;
 2154: 
 2155:  	fdu	= FDUNIT(minor(dev));
 2156: 	fd	= devclass_get_softc(fd_devclass, fdu);
 2157: 	fdblk = 128 << fd->ft->secsize;
 2158: 
 2159: 	/* set up a buffer header for fdstrategy() */
 2160: 	bp = malloc(sizeof(struct buf), M_TEMP, M_WAITOK | M_ZERO);
 2161: 
 2162: 	/*
 2163: 	 * keep the process from being swapped
 2164: 	 */
 2165: 	PHOLD(p);
 2166: 	BUF_LOCKINIT(bp);
 2167: 	BUF_LOCK(bp, LK_EXCLUSIVE);
 2168: 	bp->b_flags = B_PHYS | B_FORMAT;
 2169: 
 2170: 	/*
 2171: 	 * calculate a fake blkno, so fdstrategy() would initiate a
 2172: 	 * seek to the requested cylinder
 2173: 	 */
 2174: 	bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
 2175: 		+ finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
 2176: 
 2177: 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
 2178: 	bp->b_data = (caddr_t)finfo;
 2179: 
 2180: 	/* now do the format */
 2181: 	bp->b_dev = dev;
 2182: 	BUF_STRATEGY(bp, 0);
 2183: 
 2184: 	/* ...and wait for it to complete */
 2185: 	s = splbio();
 2186: 	while(!(bp->b_flags & B_DONE)) {
 2187: 		rv = tsleep((caddr_t)bp, 0, "fdform", 20 * hz);
 2188: 		if (rv == EWOULDBLOCK)
 2189: 			break;
 2190: 	}
 2191: 	splx(s);
 2192: 
 2193: 	if (rv == EWOULDBLOCK) {
 2194: 		/* timed out */
 2195: 		rv = EIO;
 2196: 		device_unbusy(fd->dev);
 2197: 		biodone(bp);
 2198: 	}
 2199: 	if (bp->b_flags & B_ERROR)
 2200: 		rv = bp->b_error;
 2201: 	/*
 2202: 	 * allow the process to be swapped
 2203: 	 */
 2204: 	PRELE(p);
 2205: 	BUF_UNLOCK(bp);
 2206: 	BUF_LOCKFREE(bp);
 2207: 	free(bp, M_TEMP);
 2208: 	return rv;
 2209: }
 2210: 
 2211: /*
 2212:  * TODO: don't allocate buffer on stack.
 2213:  */
 2214: 
 2215: static int
 2216: fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
 2217: {
 2218:  	fdu_t	fdu = FDUNIT(minor(dev));
 2219:  	fd_p	fd = devclass_get_softc(fd_devclass, fdu);
 2220: 	size_t fdblk;
 2221: 
 2222: 	struct fd_type *fdt;
 2223: 	struct disklabel *dl;
 2224: 	struct fdc_status *fsp;
 2225: 	char buffer[DEV_BSIZE];
 2226: 	int error = 0;
 2227: 
 2228: 	fdblk = 128 << fd->ft->secsize;
 2229: 
 2230: 	switch (cmd) {
 2231: 	case DIOCGDINFO:
 2232: 		bzero(buffer, sizeof (buffer));
 2233: 		dl = (struct disklabel *)buffer;
 2234: 		dl->d_secsize = fdblk;
 2235: 		fdt = fd->ft;
 2236: 		dl->d_secpercyl = fdt->size / fdt->tracks;
 2237: 		dl->d_type = DTYPE_FLOPPY;
 2238: 
 2239: 		if (readdisklabel(dev, dl)
 2240: 		    == NULL)
 2241: 			error = 0;
 2242: 		else
 2243: 			error = EINVAL;
 2244: 
 2245: 		*(struct disklabel *)addr = *dl;
 2246: 		break;
 2247: 
 2248: 	case DIOCSDINFO:
 2249: 		if ((flag & FWRITE) == 0)
 2250: 			error = EBADF;
 2251: 		break;
 2252: 
 2253: 	case DIOCWLABEL:
 2254: 		if ((flag & FWRITE) == 0)
 2255: 			error = EBADF;
 2256: 		break;
 2257: 
 2258: 	case DIOCWDINFO:
 2259: 		if ((flag & FWRITE) == 0) {
 2260: 			error = EBADF;
 2261: 			break;
 2262: 		}
 2263: 
 2264: 		dl = (struct disklabel *)addr;
 2265: 
 2266: 		if ((error = setdisklabel((struct disklabel *)buffer, dl,
 2267: 					  (u_long)0)) != 0)
 2268: 			break;
 2269: 
 2270: 		error = writedisklabel(dev, (struct disklabel *)buffer);
 2271: 		break;
 2272: 	case FD_FORM:
 2273: 		if ((flag & FWRITE) == 0)
 2274: 			error = EBADF;	/* must be opened for writing */
 2275: 		else if (((struct fd_formb *)addr)->format_version !=
 2276: 			FD_FORMAT_VERSION)
 2277: 			error = EINVAL;	/* wrong version of formatting prog */
 2278: 		else
 2279: 			error = fdformat(dev, (struct fd_formb *)addr, td);
 2280: 		break;
 2281: 
 2282: 	case FD_GTYPE:                  /* get drive type */
 2283: 		*(struct fd_type *)addr = *fd->ft;
 2284: 		break;
 2285: 
 2286: 	case FD_STYPE:                  /* set drive type */
 2287: 		/* this is considered harmful; only allow for superuser */
 2288: 		if (suser(td) != 0)
 2289: 			return EPERM;
 2290: 		*fd->ft = *(struct fd_type *)addr;
 2291: 		break;
 2292: 
 2293: 	case FD_GOPTS:			/* get drive options */
 2294: 		*(int *)addr = fd->options;
 2295: 		break;
 2296: 
 2297: 	case FD_SOPTS:			/* set drive options */
 2298: 		fd->options = *(int *)addr;
 2299: 		break;
 2300: 
 2301: 	case FD_GSTAT:
 2302: 		fsp = (struct fdc_status *)addr;
 2303: 		if ((fd->fdc->flags & FDC_STAT_VALID) == 0)
 2304: 			return EINVAL;
 2305: 		memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int));
 2306: 		break;
 2307: 
 2308: 	default:
 2309: 		error = ENOTTY;
 2310: 		break;
 2311: 	}
 2312: 	return (error);
 2313: }
 2314: 
 2315: /*
 2316:  * Hello emacs, these are the
 2317:  * Local Variables:
 2318:  *  c-indent-level:               8
 2319:  *  c-continued-statement-offset: 8
 2320:  *  c-continued-brace-offset:     0
 2321:  *  c-brace-offset:              -8
 2322:  *  c-brace-imaginary-offset:     0
 2323:  *  c-argdecl-indent:             8
 2324:  *  c-label-offset:              -8
 2325:  *  c++-hanging-braces:           1
 2326:  *  c++-access-specifier-offset: -8
 2327:  *  c++-empty-arglist-indent:     8
 2328:  *  c++-friend-offset:            0
 2329:  * End:
 2330:  */