/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * $Log:	str_stream.h,v $
 * Revision 4.2  91/09/19  22:54:49  devbld
 * Adding ODE Headers
 * 
 * $EndLog$
 */
/*	
 *	@(#)$RCSfile: str_stream.h,v $ $Revision: 4.2 $ (DEC) $Date: 91/09/19 22:54:49 $
 */ 
/*
 *
 * 01-Jul-91 wca
 *      Resubmitting - didn't seem to make it thru 1st try...
 */

/*
 * (c) Copyright 1990, 1991, OPEN SOFTWARE FOUNDATION, INC.
 * ALL RIGHTS RESERVED
 */
/*
 * OSF/1 Release 1.0.1
 */

/** Copyright (c) 1989  Mentat Inc.  **/

#ifndef	_STR_STREAM_H
#define	_STR_STREAM_H

#include <sys/secdefines.h>

#include <cpus.h>
#include <kern/lock.h>
#include <kern/thread.h>

/*
 * Note: <sys/stream.h> is included later, since we need to complete
 * the configuration first.
 */

/*
 * Configuration switches.
 *
 * Some of these might be useful for modules in the debug phase. In that
 * case, those modules should #include this file instead of <stream.h>.
 * However, that hurts binary compatibility!
 *
 * STREAMS_DEBUG	enables debug code in stream head code.
 *			Note that there are additional switches in str_debug.h
 *			standard setting:    determined by configuration file
 *			recommended setting: undefined
 *
 * OSF_SIMPLE_IOCTL	enables some glue code for TTY ioctl's at the
 *			stream head level. This is possible due to BSD4.3-style
 *			ioctl commands, and eliminates most application level
 *			changes. V.4 STREAMS will implement yet another scheme
 *			here, which still does not require application changes,
 *			but module-level changes.
 *
 *			standard setting:    defined
 *			recommended setting: defined
 *
 * staticf		if defined to "static", makes some routines invisible
 *			in the global name space. If just (defined), makes them
 *			visible (useful for debugging).
 *			Module using this feature should contain
 *				#ifndef staticf
 *				#define staticf static
 *				#endif
 *
 *			standard setting:    defined "" if STREAMS_DEBUG
 *			recommended setting: defined to "static"
 *
 * VOIDP		hack to get around certain compiler problems with
 *			"void *". Should go away.
 *
 *			standard setting:	defined to void *
 *			recommended setting:	defined to void *
 *
 * MULTI_DEBUG		Normally, we derive the uniprocessor/multiprocessor
 *			version based on the NCPUS variable which we get from
 *			the <cpus.h> file. In order to get the MULTI_CPU code
 *			on a single CPU system, with appropriate debug verions
 *			for things like simple locks, change the #undef
 *			statement below.
 *
 *			Note that MULTI_DEBUG code is not suitable for
 *			a real MP system, since some of the debug assertions
 *			don't hold on such architectures. Therefor, we override
 *			MULTI_DEBUG in that case (see below).
 *
 *			standard setting:	undefined
 *			recommended setting:	undefined
 *
 * MULTI_CPU		This switch enables additional synchronization code
 *			throughout the stream head code. It should not be
 *			set manually. since it is derived from the NCPUS
 *			variable. It overrides MULTI_DEBUG.
 *
 *			standard setting:	derived from NCPUS
 *			recommended setting:	derived from NCPUS
 */

#include <streams_debug.h>
#if	STREAMS_DEBUG == 0
#undef	STREAMS_DEBUG
#endif

#define OSF_SIMPLE_IOCTL
#define VOIDP	void *
#ifdef	STREAMS_DEBUG
#define staticf
#else
#define staticf	static
#undef	MULTI_DEBUG
#endif

#if	NCPUS == 1

#ifdef	MULTI_DEBUG
#define	MULTI_CPU
#endif

#else	/* NCPUS > 1 */

#define	MULTI_CPU
#undef	MULTI_DEBUG

#endif

/*
 * The central MULTI_CPU dependent data structures...
 *
 * The first three elements (next, prev and flags) of SQ and SQH
 * must be identical!!!
 * TODO: SQ+SQH - make the first part a structure, so that the above comment
 * TODO: SQ+SQH - can disappear.
 */

struct sqh_s {
/* -------------------------------------------------- */
	struct sq_s *		sqh_next;
	struct sq_s *		sqh_prev;
	long			sqh_flags;
/* -------------------------------------------------- */
	struct sqh_s *		sqh_parent;
#ifdef	MULTI_CPU
	long			sqh_refcnt;
	long			sqh_owner;
	simple_lock_data_t	sqh_inuse_lock;
	simple_lock_data_t	sqh_queue_lock;
#endif	/* MULTI_CPU */
};
typedef	struct sqh_s	SQH;
typedef	struct sqh_s *	SQHP;

struct sq_s {
/* -------------------------------------------------- */
	struct sq_s *		sq_next;
	struct sq_s *		sq_prev;
	long			sq_flags;
/* -------------------------------------------------- */
	struct streams_queue *	sq_queue;
	int			(*sq_entry)();
	long			sq_arg0;
	long			sq_arg1;
#ifdef	MULTI_CPU
	struct sqh_s *		sq_target;
	simple_lock_data_t	sq_inuse_lock;
#endif	/* MULTI_CPU */
};

typedef struct sq_s	SQ;
typedef struct sq_s *	SQP;

/* SQ flags */
#define	SQ_IS_HEAD	0x00000001
#define	SQ_INUSE	0x00000002
#define	SQ_HOLD		0x00000004
#define	SQ_IS_TIMEOUT	0x00000008

/*
 * The following macros define some additional parts of certain data
 * structures, which are needed by the stream head inorder to provide the
 * additional synchronization for the MULTI_CPU case.
 *
 * Note that these macros are undefined for normal modules and drivers.
 * This gives them a wrong impression about the size of those structures.
 * But that should not matter, since - according to the STREAMS spec -
 * they should not make such assumptions anyway. The good message is that
 * module code also becomes independent of the configuration, and binary
 * compatibility is guaranteed.
 *
 * The alternative to this method is to put some pointers into those data
 * structures, put the extra fields into separate data structures, supply
 * appropirate nicknames, and look closely into the allocation and
 * deallocation of queues and messages.
 *
 * Note: even modules which include this file for debugging purposes, should
 * not refer to these fields, since they do not necessarily form a standard
 * to which OSF/1 will adhere in the future.
 */

/*
 * Extra fields for a queue structure:
 *
 *	struct queue *	q_ffcp;		Forward flow control pointer
 *	struct queue *	q_bfcp;		Backward flow control pointer
 *
 *	struct queue *	q_act_next;	to form DLL of...
 *	struct queue *	q_act_prev;	... currently active queues
 *	VOIDP		q_thread;	thread pointer, for identification
 *	simple_lock_data_t q_qlock;	short term lock for (de)queueing
 */

#ifdef	MULTI_CPU

#define QUEUE_KERNEL_MULTI_FIELDS \
	struct queue *	q_act_next; \
	struct queue *	q_act_prev; \
	VOIDP		q_thread; \
	simple_lock_data_t q_qlock;

#define	MSG_KERNEL_MULTI_FIELDS \
	SQ		b_sq;

#else

#define QUEUE_KERNEL_MULTI_FIELDS
#define	MSG_KERNEL_MULTI_FIELDS

#endif

#if SEC_BASE

#define MSG_KERNEL_SEC_FIELDS \
        struct msgb *   b_attr;         /* pointer to security attributes */

#else

#define MSG_KERNEL_SEC_FIELDS

#endif

#define	QUEUE_KERNEL_FIELDS \
	struct queue *	q_ffcp; \
	struct queue *	q_bfcp; \
	SQH		q_sqh;	 \
	SQ		q_runq_sq; \
	QUEUE_KERNEL_MULTI_FIELDS

#define	MSG_KERNEL_FIELDS \
	MSG_KERNEL_MULTI_FIELDS \
	MSG_KERNEL_SEC_FIELDS

/*
 * OK, we can include <sys/stream.h> *now*, after having defined those
 * extra pieces.
 */

#include <sys/stream.h>

#define SEMI_TRANSPARENT	(TRANSPARENT | 0x001)
#define FULLY_TRANSPARENT	(TRANSPARENT | 0x002)

typedef	struct msgb *	MBLKP;
typedef	struct msgb **	MBLKPP;

/*
 * SPL macros: where we actually always need spl symchronization
 * (multi-processor code should better do something in addition...)
 */

#define	STR_SPLDECL		int	_savpri;
/*
 * Choose spltty() to attempt to circumvent all kernel utilities,
 * which SHOULD use this macro, to not lower IPL out from under the
 * kernel utility caller.
 */
#define STR_SPLSTR		_savpri = spltty()
#define STR_SPLX		splx(_savpri)

/*
 * UNI_SPL* macros: used where synchronization via spl is needed
 * ONLY if synchronization via synch queues is not guaranteed,
 * i.e. in a pure uniprocessor environment.
 */

#ifdef	   MULTI_CPU

#define	UNI_SPLDECL
#define UNI_SPLSTR
#define UNI_SPLX

#else	/* MULTI_CPU */

#define	UNI_SPLDECL	STR_SPLDECL
#define UNI_SPLSTR	STR_SPLSTR
#define UNI_SPLX	STR_SPLX

#endif	/* MULTI_CPU */

/*
 * Use of Spin Locks:
 *
 * On a MULTI_CPU system, we use spin locks to protect very short pieces of
 * code, and to construct the synchronization queues. Additionally, we also
 * use spin locks to atomically set a bit whether or not a queue is currently
 * scheduled or not.
 *
 * We want to be able to use the spin lock code even on a uniprocessor, and
 * the system-wide "simple_lock" package is inadequate in that case
 * (simple_lock_try panics when it finds a lock which is already locked, but
 * we need it to return false).
 *
 * Finally, we want to be independent of whether or not other pieces of the
 * kernel are being configured for debugging MP code.
 *
 * Therefor, we use "spin_lock" throughout the code, and map it:
 *
 * MULTI_CPU	MULTI_DEBUG	effect
 * ----------------------------------------------------------------
 * yes		yes		C routines in pse/str_synch.c
 * no		yes		(does not happen, MULTI_DEBUG implies MULTI_CPU)
 * yes		no		map to simple_lock -> inline expansion
 * no		no		statements disappear from the code
 */

#ifndef	MULTI_DEBUG

#ifdef	MULTI_CPU

#define	spin_lock_init(l)	simple_lock_init(l)
#define	spin_lock(l)		simple_lock(l)
#define	spin_lock_try(l)	simple_lock_try(l)
#if	!MACH_LDEBUG
#define	spin_unlock(l)		simple_unlock(l)
#else
/*
 * The unlock of the sync queue is done by another thread.
 * This TEMPORARY code is to workaround the panic in sunhack().
 */
#define	spin_unlock(l)	{ if (((int)(l)->slthread & 0x80000000) == 0) \
				(l)->slthread = (char *)current_thread(); \
			 	simple_unlock(l);}
#endif

#else	/* MULTI_CPU */

#define	spin_lock_init(l)
#define	spin_lock(l)
#define	spin_lock_try(l)
#define	spin_unlock(l)

#endif	/* MULTI_CPU */

#endif /* MULTI_DEBUG */


#ifdef	   MULTI_CPU

#define os_sq_get(sq)	spin_lock_try(&(sq)->sq_inuse_lock)

#else	/* MULTI_CPU */

#define	os_sq_get(sq)		(((sq)->sq_flags & SQ_INUSE) \
					? FALSE \
					: (((sq)->sq_flags |= SQ_INUSE), TRUE))

#endif	/* MULTI_CPU */


#define	LOCK_DECL		STR_SPLDECL
#define	LOCK_QUEUE(sqh)		STR_SPLSTR; spin_lock(&(sqh)->sqh_queue_lock)
#define	UNLOCK_QUEUE(sqh)	spin_unlock(&(sqh)->sqh_queue_lock); STR_SPLX

#define SIMPLE_LOCK_DECL	STR_SPLDECL
#define	SIMPLE_LOCK_INIT(lock)	spin_lock_init(lock)
#define	SIMPLE_LOCK(lock)	STR_SPLSTR; spin_lock(lock)
#define	SIMPLE_UNLOCK(lock)	spin_unlock(lock); STR_SPLX

#define	TAS_RESOURCE(sqh)	spin_lock_try(&(sqh)->sqh_inuse_lock)
#define	REL_RESOURCE(sqh)	spin_unlock(&(sqh)->sqh_inuse_lock)


#ifndef  MULTI_CPU

#define	csq_lateral(sqh,sq)	(*(sq)->sq_entry)((sq)->sq_arg0, (sq)->sq_arg1)
#define	csq_protect(q1, q2, func, arg, sq)	(*func)(arg)
#define	csq_acquire(sqh,sq)
#define	csq_release(sqh)
#define	csq_newparent(osr, q, str)
#define	csq_cleanup(sqh)
#define	mult_sqh_acquire(osr)
#define mult_sqh_release(osr)

#endif /* MULTI_CPU */

/* Extra PSE mblk type */
#define       M_MI            64
/* Subfields for M_MI messages */
#define       M_MI_READ_RESET 1
#define       M_MI_READ_SEEK  2
#define       M_MI_READ_END   4

#define	DEF_CLOSE_WAIT	15	/* seconds to wait per non-empty module
				 * or driver during close. */
#define	DEF_LINK_WAIT	15	/* seconds to wait for reply from a
				 * multiplexing driver */

#ifndef	MULTI_CPU

/** Put a message to this queue */
#define	puthere(q, mp)	\
	(((q) && (q)->q_qinfo->qi_putp) ? \
	(*(q)->q_qinfo->qi_putp)(q, mp) \
	: freemsg(mp))

#else

#ifdef	_NO_PROTO

extern	void	puthere();

#else

extern	void	puthere(queue_t *, mblk_t *);

#endif

#endif	/* MULTI_CPU */

typedef	struct osr_ioc_arg_s {
	char	* oia_ubuf;
	union {
		int	oia_arg_iocu;
		char	* oia_argp_iocu;
		ulong	* oia_argup_iocu;
	} iocu;
	int	oia_len;
} OIA, * OIAP;

#define	oia_arg			iocu.oia_arg_iocu
#define	oia_argp		iocu.oia_argp_iocu
#define	oia_argup		iocu.oia_argup_iocu

typedef struct ioctl_osr_s {
	int		ioc_cmd;
	mblk_t *	ioc_mp1;
	OIA		ioc_oia[3];
} IOCTL_OSR;

#define	osr_ioctl_cmd		osr_osru.ioctl_osr.ioc_cmd
#define	osr_ioctl_mp1		osr_osru.ioctl_osr.ioc_mp1
#define	osr_ioctl_ubuf0		osr_osru.ioctl_osr.ioc_oia[0].oia_ubuf
#define	osr_ioctl_arg0		osr_osru.ioctl_osr.ioc_oia[0].oia_arg
#define	osr_ioctl_arg0p		osr_osru.ioctl_osr.ioc_oia[0].oia_argp
#define	osr_ioctl_arg0up	osr_osru.ioctl_osr.ioc_oia[0].oia_argup
#define	osr_ioctl_arg0_len	osr_osru.ioctl_osr.ioc_oia[0].oia_len
#define	osr_ioctl_ubuf1		osr_osru.ioctl_osr.ioc_oia[1].oia_ubuf
#define	osr_ioctl_arg1		osr_osru.ioctl_osr.ioc_oia[1].oia_arg
#define	osr_ioctl_arg1p		osr_osru.ioctl_osr.ioc_oia[1].oia_argp
#define	osr_ioctl_arg1up	osr_osru.ioctl_osr.ioc_oia[1].oia_argup
#define	osr_ioctl_arg1_len	osr_osru.ioctl_osr.ioc_oia[1].oia_len
#define	osr_ioctl_ubuf2		osr_osru.ioctl_osr.ioc_oia[2].oia_ubuf
#define	osr_ioctl_arg2		osr_osru.ioctl_osr.ioc_oia[2].oia_arg
#define	osr_ioctl_arg2p		osr_osru.ioctl_osr.ioc_oia[2].oia_argp
#define	osr_ioctl_arg2up	osr_osru.ioctl_osr.ioc_oia[2].oia_argup
#define	osr_ioctl_arg2_len	osr_osru.ioctl_osr.ioc_oia[2].oia_len

typedef struct open_osr_s {
	int	open_dev;
	int	open_dindex;
} OPEN_OSR;

#define	osr_open_dev		osr_osru.open_osr.open_dev
#define	osr_open_dindex		osr_osru.open_osr.open_dindex

typedef struct rw_osr_s {
	int	rw_total;
	ulong	rw_flags;
	OIA	rw_oia[3];	/* Only one used, but we have to match the IOCTL structure */
} RD_OSR;

#define       F_OSR_RW_MREAD_SENT     0x1
#define osr_rw_flags    osr_osru.rw_osr.rw_flags

#define	osr_rw_base	  osr_osru.rw_osr.rw_oia[0].oia_argp
#define	osr_rw_uiop	  osr_rw_base 
#define	osr_rw_count	  osr_osru.rw_osr.rw_oia[0].oia_len
#define	osr_rw_total	  osr_osru.rw_osr.rw_total
#define osr_rw_orig_base  osr_osru.rw_osr.rw_oia[1].oia_argp
#define osr_rw_orig_count osr_osru.rw_osr.rw_oia[1].oia_len

#define	osr_sel_thread	osr_osru.sel_osr.sel_thread
#define osr_sel_events	osr_osru.sel_osr.sel_events
#define osr_sel_revents	osr_osru.sel_osr.sel_revents

struct osrq_s
{
	simple_lock_data_t	osrq_lock;
	struct osr_s *		osrq_first;
	struct osr_s *		osrq_last;
};

typedef	struct osrq_s	OSRQ;
typedef	struct osrq_s *	OSRQP;

struct osr_s
{
	SQ		osr_sq;	  /* this OSR's synch queue element */
	struct osrq_s *	osr_osrq; /* pointer to OSRQ where this OSR is queued */
	struct osr_s *	osr_next; /* next OSR in the same OSRQ */
	struct sth_s *	osr_sth;
	int		osr_ret_val;
	pfi_t		osr_handler;
	ulong		osr_pid;
	uid_t		osr_uid;
	gid_t		osr_gid;
	ulong		osr_closeout;
	ulong		osr_flags;
	union {
		IOCTL_OSR	ioctl_osr;
		OPEN_OSR	open_osr;
		RD_OSR		rw_osr;
	} osr_osru;
};

typedef	struct osr_s	OSR;
typedef struct osr_s *	OSRP;
typedef	struct osr_s **	OSRPP;

/*
 * Values for osr_flags
 *
 * F_OSR_WAITING_IN_LINE - queued in OSRQ, waiting to be activated
 * F_OSR_ASLEEP          - blocked
 * F_OSR_WAKEUP          - received an orderly wakeup
 * F_OSR_NEED_MULT_SQH	 - the OSR must allocate mult_sqh first
 * F_OSR_HAVE_MULT_SQH	 - this OSR is holding the mult_sqh
 * F_OSR_NDELAY		 - this OSR wants non-delay mode
 * F_OSR_NONBLOCK	 - this OSR wants non-block mode
 * F_OSR_OUTDEF_DATA 	 - Deferred output needs access checking
 * F_OSR_KERNEL_DATA	 - ioctl data can be found in kernel land
 */

#define F_OSR_WAITING_IN_LINE	0x00000001
#define F_OSR_ASLEEP		0x00000002
#define F_OSR_WAKEUP		0x00000004
#define F_OSR_NEED_MULT_SQH	0x00000008
#define F_OSR_HAVE_MULT_SQH	0x00000010
#define F_OSR_NDELAY		0x00000020
#define F_OSR_NONBLOCK		0x00000040
#define	F_OSR_OUTDEF_DATA 	0x00000100
#define	F_OSR_KERNEL_DATA	0x00000200


#define offset_ok(offset)	(!((offset) & 0x1))


struct polls_s {
	struct polls_s *	ps_next;
	struct event *		ps_event;
	short			ps_events;
	short			ps_pad;
};

typedef struct polls_s		POLLS;
typedef	struct polls_s *	POLLSP;

struct sigs_s {
	struct sigs_s *	ss_link;
	ulong   	ss_procid;
	ulong   	ss_process_cookie;
        ulong     	ss_mask;
};

typedef struct sigs_s		SIGS;
typedef struct sigs_s *		SIGSP;

struct sth_s {
	queue_t	*	sth_q;
	int		sth_dev;
	ulong		sth_read_mode;
	int		sth_error;
	ulong		sth_flags;
	SIGSP		sth_sigs;
	int		sth_ioc_id;	/* id of outstanding M_IOCTL */
	mblk_t *	sth_ioc_mp;	/* M_IOCACK or M_IOCNAK reply */
	OSRQ		sth_ioctl_osrq;
	OSRQ		sth_read_osrq;
	OSRQ		sth_write_osrq;
	ulong		sth_wroff;
	POLLSP		sth_polls;
	int		sth_muxid;	/* linked id of lower mux */
	struct sth_s *	sth_mux_link;	/* link to next muxed lower stream */
	struct sth_s *	sth_mux_top;	/* controlling mux list */
	struct tty *	sth_ttyp;	/* if controlling tty... */
#if SEC_ILB
        mblk_t *        sth_prev_attr;  /* attributes from previous receive */
#endif
	int		sth_push_count;	/* count of modules pushed on stream */
};

typedef	struct sth_s	STH;
typedef struct sth_s *	STHP;
typedef struct sth_s **	STHPP;

/*
 * Values for sth_read_mode: see stropts.h
 * {RNORM, RFILL, RMSGD, RMSGN, ...}
 */

/*
 * Values for sth_flags
 *
 * F_STH_ERROR		- M_ERROR received, fail all calls
 * F_STH_HANGUP		- M_HANGUP received, no more data
 * F_STH_ONDELAY	- non-blocking mode (unused - in osr)
 * F_STH_NDELON		- do TTY semantics for ONDELAY handling
 * F_STH_ISATTY		- this stream acts a terminal
 * F_STH_READON		- generate M_READ messages
 *
 * F_STH_CLOSED		- stream has been closed, and should be free'd on unlink
 * F_STH_LINKED		- stream has one or more lower streams linked
 * F_STH_CLOSING	- actively on the way down
 *
 * EHL_FLAGS		- combination of error flags which prevent output ops
 * EL_FLAGS		- combination of flags which prevent input ops
 */
#define F_STH_ERROR		0x0001
#define	F_STH_HANGUP		0x0002 
/*#define	F_STH_ONDELAY		0x0004 */
#define F_STH_NDELON		0x0008
#define	F_STH_ISATTY		0x0010
#define F_STH_MREADON           0x0020

#define	F_STH_CLOSED		0x1000
#define	F_STH_LINKED		0x2000
#define	F_STH_CLOSING		0x4000

#define EHL_FLAGS		(F_STH_ERROR | F_STH_HANGUP | F_STH_LINKED)
#define EL_FLAGS		(F_STH_ERROR |                F_STH_LINKED)

#define	sth_id(sth)		(((ulong)(sth)) & ~LONG_SIGN_BIT)

#define	STREAM_END(q)		(!(q)->q_next \
				|| !((q)->q_next->q_flag & F_Q_IS_WRITE_Q))

/* structure of sth table for devices */
struct	stht_s {
	int	stht_len;		/* number of minors in table */
	STHP	stht_arr[1];		/* array of sths, indexed by minor */
};

typedef struct stht_s	STHT;
typedef struct stht_s *	STHTP;

#define	ALLOC_INC	5
#define	D_ALLOC_SIZE	(ALLOC_INC * sizeof(struct dmodsw))
#define	F_ALLOC_SIZE	(ALLOC_INC * sizeof(struct fmodsw))

/*
 * device switch
 *
 * d_sqh	synchronization queue for module-wide synchronization.
 *		Also, in the case of external synchronization, this element
 *		points to it.
 * d_lock	lock which synchronizes modifications in the stht
 * d_str	pointer to streamtab
 * d_stht	stream head table for this device
 * d_sq_level	synchronization level
 * d_name	device name
 * d_cookie	major device number of this device. (TODO: will go away?!)
 */

struct dmodsw {
	SQH		d_sqh;
	simple_lock_data_t d_lock;
	struct streamtab * d_str;
	STHTP		d_stht;
	int		d_sq_level;
	char		d_name[FMNAMESZ+1];
	char		d_pad[3];
	int		d_cookie;
	int		d_pad2;
};

/*
 * module switch
 *
 * f_name	module name
 * f_sqh	see d_sqh, above.
 * f_str	streamtab pointer
 * f_sq_level	synchronization level
 */

struct fmodsw {
	char		f_name[FMNAMESZ+1];
	char		f_pad[7];
	SQH		f_sqh;
	struct streamtab * f_str;
	int		f_sq_level;
};

struct file_cookie {
	int		fc_magic;
	struct file *	fc_fp;
	int		fc_flags;
};

#define FILE_COOKIE_MAGIC	0x6e616773

struct mh_s {
	mblk_t	mh_mblk;
	dblk_t	mh_dblk;
	pfi_t	mh_free;
	char *	mh_free_arg;
	char *	mh_free_base;
	char *	mh_hq;
};

typedef	struct mh_s	MH;
typedef	struct mh_s *	MHP;

#ifdef	MULTI_CPU

struct open_args {
	pfi_t		a_func;
	queue_t *	a_queue;
	dev_t		a_dev;
	int		a_flag;
	int		a_sflag;
};

#endif	/* MULTI_CPU */

#endif	/* _STR_STREAM_H */
