/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: devsw.h 1.23 90/09/07 $"

#ifndef	_SYS_DEVSW_H_

/*
 * Definitions which support the dev object
 */

/* $Log:	devsw.h,v $
 */

/*
 * devops routines
 *
 * In all of these routines, the first parameter is a pointer to
 * a struct dev which represents the device being acted upon.
 *
 * d_open(dp, mode, type)
 *	Driver confirms that the device can be accessed in the mode described
 *	by flag.  See sys/file.h for definitions of mode, and
 *	sys/open.h for definitions of type.  Usually called as a
 *	result of the open(2) syscall.
 *
 * d_close(dp, flag, type)
 *	Type is as in d_open, and flag is typically unused.  Usually
 *	called as a result of the close(2) syscall.
 *
 * d_strategy(dp, bp, offset)
 *	Schedule IO to be done to a block device either synchronously or
 *	asynchronously.  bp points to a buf header which describes the
 *	operation.  offset is a block offset to be applied to the
 *	block number described in the buf header.
 *
 * d_minphys(dp, bp)
 *	Compare the size of an IO request against device-specific
 *	maximums and potentially reduce the IO request to fit the
 *	device.  bp points to a buf header which will then be passed to
 *	a d_strategy routine.
 *
 * d_size(dp)
 *	Return the capacity of the device.  Used by the swap driver to
 *	determine if a device can be swapped on and to calculate how much
 *	swap space is available on it.
 *
 * d_print(dp, str)
 *	Print an error message on the console prepended with the device's
 *	name.  str points to the error message.
 *
 * d_read(dp, uio, ioflag)
 *	Read from the raw interface of a device.  uio is described
 *	by sys/uio.h, and points to a uio struct which describes the
 *	operation.  ioflag is defined in sys/vnode.h (IO_*).  Usually
 *	called as a result of the read(2) syscall.
 *
 * d_write(dp, uio, ioflag)
 *	Write to the raw interface of a device.  uio is described
 *      by sys/uio.h, and points to a uio struct which describes the
 *      operation.  ioflag is defined in sys/vnode.h (IO_*).  Usually
 *      called as a result of the write(2) syscall.
 *
 * d_ioctl(dp, cmd, data, flag)
 *	Driver-specific control function.  cmd is the function to be
 *	performed, data points to data to be used in the function,
 *	and flag is normally unused.
 *
 * d_mmap(dp, cmd, off, size, prot)
 *	Device is to perform memory mapping.  The mmap function in cmd
 *	(which is defined in sys/mman.h) is performed at the given
 *	offset for the given size.  prot is defined in sys/mman.h and
 *	is passed in with the mmap(2) syscall.
 *
 * d_shutdown(dp, chld)
 *	A catastrophic device failure has occurred, and the device represented
 *	by dp should assume that the device represented by chld is no longer
 *	usable.
 *
 * d_str
 *	Points to the stream table for this device.  Only used by stream
 *	devices.
 *
 * d_strmsgio
 *	A device supporting indirection to another (possibly streams) device
 *	supports this function for streams message I/O requests.  Example
 *	devices supporting this function are the generic tty (/dev/tty), and
 *	the system console (/dev/console) devices.  Non-streams devices
 *	not implementing indirection must set this function to nostrmsgio().
 *
 * d_strpoll
 *	A device supporting indirection to another (possibly streams) device
 *	supports this function for streams poll requests.  Example devices
 *	supporting this function are the generic tty (/dev/tty), and the system
 *	console (/dev/console) devices.  Non-streams devices not implementing
 *	indirection must set this function to nostrpoll().
 *
 * d_firstsect(dp)
 *	Return the first usable sector for this device.  This is supplied by
 *	disk drives which have reserved sectors at the front of the drive.
 *	Calling this routine allows one to find things which would
 *	otherwise reside at the front of the device.
 *
 * d_sync(dp)
 *	Flush out all pending IO to a device.
 *
 * d_set_history(dp, hp)
 *	The device is instructed to turn history recording on or off.  The
 *	caller supplies parameters pointed to by hp to describe where to
 *	put history records and how many to save.
 */
struct devops {
	int		(*d_open)();
	int		(*d_close)();
	int		(*d_strategy)();
	int		(*d_minphys)();
	int		(*d_size)();
	int		(*d_print)();
	int		(*d_read)();
	int		(*d_write)();
	int		(*d_ioctl)();
	int		(*d_mmap)();
	int		(*d_shutdown)();
	struct streamtab *d_str;
	int		(*d_strmsgio)();
	int		(*d_strpoll)();
	int		(*d_firstsect)();
	int		(*d_sync)();
	int		(*d_set_history)();
};

/*
 * Device object.  There is one of these for every valid major/minor
 * number pair in the system, usually generated at boot time.  When an
 * action needs to be taken on a device, a routine from d_ops is used
 * and a pointer to the dev is passed to tis driver routine.
 */

struct dev {
	struct	dev	*d_chain[2];	/* link into hash structure */
	struct	dev	*d_parent;	/* parent device in tree */
	dev_t		d_dev;		/* major/minor of this device */
	uint		d_refcnt;	/* active references to this object */
	int		d_flags;	/* described below */
	struct	devops	*d_ops;		/* device-driver hooks */
	long		d_reserved;	/* reserved for later use */
	caddr_t		d_private;	/* driver-specific data */
};

/*
 * 	Devs which are in the devsw data structure are accessible via
 * normal open/close/read/write syscall interface.  Devs are removed from
 * devsw to "hide" them from use in the system.  This is done to protect
 * them from inadvertent access.
 * 
 * 	As far as the devsw interfaces are concerned, a reference only
 * has meaning within the context of the devsw data structure.  Dev's
 * which have been removed from the devsw structure will not place any
 * significance on the d_refcnt field of the dev structure.
 * 
 * 	Dev's can only enter or leave the devsw data structure with a
 * reference count of 1.  In the case of entry into devsw, the single
 * referent is the agent which is adding the dev to devsw, and in the case
 * of removal, the only referent is the agent removing the dev.
 * 
 * 	The reference count is not checked on devsw entry, but is
 * forced to be equal to 1.  This implies that code which adds a dev to
 * devsw must decrement the reference count after the dev has been added
 * to devsw.  (devsw_add() is used to add devs to devsw.)
 * 
 * 	As objects within the kernel gain access to the dev, the
 * reference count is incremented in an atomic fashion.  As references to
 * the dev are removed, it is necessary for the reference count to be
 * decremented in an atomic fashion as well.  This is accomplished
 * by dev_ref() and dev_deref().
 * 
 * 	If a dev is to be removed from the devsw structure, the
 * reference count must be 1.  The paradigm used in this case is that if
 * the device is in use by some other object within the kernel, it must
 * not be removed from membership in the devsw.  devsw_remove() is used
 * to remove devs from devsw.
 */

/* d_flags */

#define	D_INVALID	0x00000001	/* not currently bound to a device */
#define D_TAPE		0x00000010	/* a tape device */
#define D_SYNC		0x00000020	/* this device wants to sync.  This
					 * implies a d_sync in devops
					 */
#define	D_ASYNC		0x00000040	/* this device is capable of doing
					 * asynchronous I/O
					 */
#define D_UNSOFF	0x00000080	/* Unsigned offsets allowed */

/*
 * abstractions which allow one to call a driver hook through a dev.
 */
#define	DEV_OPEN(DP,MODE,TYPE)		(*(DP)->d_ops->d_open)(DP,MODE,TYPE)
#define	DEV_CLOSE(DP,FLAG,TYPE)		(*(DP)->d_ops->d_close)(DP,FLAG,TYPE)
#define	DEV_STRATEGY(DP,BP,OFFSET)	(*(DP)->d_ops->d_strategy)(DP,BP,OFFSET)
#define	DEV_MINPHYS(DP,BP)		(*(DP)->d_ops->d_minphys)(DP,BP)
#define	DEV_SIZE(DP)			(*(DP)->d_ops->d_size)(DP)
#define	DEV_PRINT(DP,STR)		(*(DP)->d_ops->d_print)(DP,STR)
#define	DEV_READ(DP,UIO,IOFLAG)		(*(DP)->d_ops->d_read)(DP,UIO,IOFLAG)
#define	DEV_WRITE(DP,UIO,IOFLAG)	(*(DP)->d_ops->d_write)(DP,UIO,IOFLAG)
#define	DEV_IOCTL(DP,CMD,DATA,FLAG)	\
				(*(DP)->d_ops->d_ioctl)(DP,CMD,DATA,FLAG)
#define	DEV_MMAP(DP,CMD,OFF,SIZE,PROT) \
				(*(DP)->d_ops->d_mmap)(DP,CMD,OFF,SIZE,PROT)
#define DEV_SHUTDOWN(DP,CHLD)	((DP)->d_ops&&(DP)->d_ops->d_shutdown&& \
				 (*(DP)->d_ops->d_shutdown)((DP),(CHLD)))
#define DEV_STREAMTAB(DP)		((DP)->d_ops->d_str)
#define DEV_STRMSGIO(DP,C,D,RW,FLG,IOFLG) \
				(*(DP)->d_ops->d_strmsgio)(DP,C,D,RW,FLG,IOFLG)
#define DEV_STRPOLL(DP,E,ANYYET)	(*(DP)->d_ops->d_strpoll)(DP,E,ANYYET)
#define DEV_FIRSTSECT(DP)		(*(DP)->d_ops->d_firstsect)(DP)
#define DEV_SET_HISTORY(DP,HP)	((DP)->d_ops&&(DP)->d_ops->d_set_history? \
				 (*(DP)->d_ops->d_set_history)((DP),(HP)) : -1)
#define DEV_FLAGS(DP)			((DP)->d_flags)

#ifdef INKERNEL
extern lock_t	devsw_lck;

extern	struct dev	*dev_ref();
extern  struct dev      *fdtodev();

extern	struct genallocator devlist;
extern	struct genallocator devopslist;

#define	DEV_ALLOC()	(struct dev *)genalloc(&devlist, 0)
#define	DEV_FREE(P)	genfree(&devlist, (P))
#define	DEVOPS_ALLOC()	(struct devops *)genalloc(&devopslist, 0)
#define	DEVOPS_FREE(P)	genfree(&devopslist, (P))
#endif /* INKERNEL */

/*
 * Devsw data structure: This union defines the hash buckets for
 * the devsw hash table.
 */
union devsw {
	union  devsw	*ds_head[2];
	struct dev	*ds_chain[2];
};

/*
 * DEV_DIAG_MASK is or-ed into a major number to arrive at the major/minor
 * of the diagnostic interface for a device.
 */
#define	DEV_DIAG_MASK	0x80000000

#define SPLDEV	SPL6			/* all but clocks disabled */
#define DEV_MEM_CLICK   NBPG

/* definitions for d_sync routines */
#define DSYNCSZ		(sizeof (void (*)()))
#define DSYNCPG		(NBPG/DSYNCSZ)
#define PSYNC 		(PZERO - 1)
#ifdef INKERNEL
extern d_sync_add(), d_sync_remove();
#endif /* INKERNEL */

#define	_SYS_DEVSW_H_
#endif	/* _SYS_DEVSW_H_ */
