/* $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.
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: stream.h 1.48 90/04/05 $"

#ifndef _SYS_STREAM_H_

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

/*
 * The streams queue.
 *
 * Note that changes in the queue structure are mutexed via its stream's sd_mutex.
 * The exceptions are q_linkr, q_linkl, and q_svcflag fields - which are mutexed
 * by the svc_mutex.
 */
struct	queue {
	struct	stdata	*q_str;		/* to stream head for synchronizing */
	struct	qinit	*q_qinfo;	/* procs and limits for queue */
	struct	msgb	*q_first;	/* first data block */
	struct	msgb	*q_last;	/* last data block */
	struct	queue	*q_next;	/* next Q in stream */
	struct	queue	*q_prev;	/* previous Q in stream */
	struct	queue	*q_linkr;	/* next Q in svc_q */
	struct	queue	*q_linkl;	/* previous Q in svc_q */
	caddr_t	q_ptr;			/* to private data structure */
	ushort	q_count;		/* number of blocks on Q */
	ushort	q_putcnt;		/* number of put procs running */
	ushort	q_flag;			/* queue state */
	ushort	q_svcflag;		/* svc_q state (mutexed by svc_mutex) */
	short q_minpsz;			/* min packet size accepted by this module */
	short q_maxpsz;			/* max packet size accepted by this module */
	ushort q_hiwat;			/* queue high water mark */
	ushort q_lowat;			/* queue low water mark */
};

typedef struct queue queue_t;

/*
 * Queue flags for q_flag field.
 */
#define	QENAB		01			/* Queue is already enabled to run */
#define	QWANTR		02			/* Someone wants to read Q */
#define	QWANTW		04			/* Someone wants to write Q */
#define	QFULL		010			/* Q is considered full */
#define	QREADR		020			/* This is the reader (first) Q */
#define	QUSE		040			/* This queue in use (allocation) */
#define	QNOENB		0100			/* Don't enable Q via putq */
#define	QFREEZE		0200			/* Freeze all Q activity */
#define	QSVCBUSY	0400			/* Q's service proc is running */
#define	QTOENAB		01000			/* setup to enable Q */
#define	QPROCENAB	02000			/* Q's procs are enabled */


/*
 * module information structure
 */
struct module_info {
	ushort	mi_idnum;		/* module id number */
	char 	*mi_idname;		/* module name */
	short   mi_minpsz;		/* min packet size accepted */
	short   mi_maxpsz;		/* max packet size accepted */
	ushort	mi_hiwat;		/* hi-water mark */
	ushort 	mi_lowat;		/* lo-water mark */
};


/*
 * queue information structure
 */
struct	qinit {
	struct _qinit {
		int	(*_qi_putp)();		/* put procedure */
		int	(*_qi_srvp)();		/* service procedure */
		int	(*_qi_qopen)();		/* called on startup */
		int	(*_qi_qclose)();		/* called on finish */
		int	(*_qi_qadmin)();		/* unused for now */
		struct module_info *_qi_minfo;	/* module information structure */
		struct module_stat *_qi_mstat;	/* module statistics structure */
	} _qinit[2];
};

/*
 * The second qinit is used only temporarily during a 
 * module open to re-define the value of qi_putp.
 */
#define qi_putp		_qinit[0]._qi_putp
#define qi_srvp		_qinit[0]._qi_srvp
#define qi_qopen	_qinit[0]._qi_qopen
#define qi_qclose	_qinit[0]._qi_qclose
#define qi_qadmin	_qinit[0]._qi_qadmin
#define qi_minfo	_qinit[0]._qi_minfo
#define qi_mstat	_qinit[0]._qi_mstat


/*
 * Streamtab (used in cdevsw and fmodsw to point to module or driver)
 */

struct streamtab {
	struct qinit *st_rdinit;
	struct qinit *st_wrinit;
	struct qinit *st_muxrinit;
	struct qinit *st_muxwinit;
};



#ifdef INKERNEL
/*
 * Header for a stream: interface to rest of system
 */

struct stdata {
	lock_t	sd_mutex;		/* lock for stream mutexing */
	struct stdata *sd_forw;		/* forward link into hash table */
	struct stdata *sd_back;		/* backward link into hash table */
	sema_t	sd_plumb;		/* used to wait for plumbing op completion */
	sema_t	sd_open;		/* used to wait during open */
	sema_t	sd_freeze;		/* used to wait for freeze completion */
	sema_t	sd_read;		/* used to wait for read/getmsg completion */
	sema_t	sd_write;		/* used to wait for write/putmsg completion */
	sema_t	sd_timer;		/* used to wait for timeouts completion */
	sema_t	sd_timer2;		/* used to wait for timeouts completion */
	sema_t	sd_timer3;		/* used to wait for ioctl/timeouts completion */
	sema_t	sd_waitbuf;		/* used to wait for buffers */
	sema_t	sd_vhangup;		/* used to wait for inactivity */
	int	sd_opcnt;		/* read/write/ioctl count */
	struct	queue *sd_wrq;		/* write queue */
	struct	msgb *sd_iocblk;	/* return block for ioctl */
	struct 	streamtab *sd_strtab;	/* pointer to streamtab for stream */
	long	sd_flag;		/* state/flags */
	long	sd_iocid;		/* ioctl id */
	ushort	sd_iocwait;		/* count of procs waiting to do ioctl */
	struct ctty sd_ctty;		/* controlling tty information */
	int	sd_openflag;		/* open flag (last open) */
	ushort	sd_wroff;		/* write offset */
	unsigned char  sd_vmin;		/* min bytes read blocks for */
	unsigned char  sd_vtime;	/* min time read blocks for */
	unsigned char  sd_tostop;	/* SIGTTOU job control flag */
	unsigned char  sd_error;	/* hangup or error to set u.u_error */
	int	sd_pushcnt;		/* number of pushes done on stream */
	int	sd_refcnt;		/* number of references to stream */
	dev_t	sd_rdev;		/* device number */
	struct  strevent *sd_siglist;	/* pid linked list to rcv SIGPOLL sig */
	struct	strevent *sd_pollist;	/* pid linked list to wakeup poll() */
	int	sd_sigflags;		/* logical OR of all siglist events */
	int	sd_pollflags;		/* logical OR of all sellist events */
};


/* Used for hash table and freelist headers (first three fields of stdata */
struct stdatahdr {
	lock_t	sd_mutex;		/* lock for stream mutexing */
	struct stdata *sd_forw;		/* forward link into hash table */
	struct stdata *sd_back;		/* backward link into hash table */
};

/*
 * Determine if the given vnode identifies a streams device.  Return
 * 0 if it does not.  Return a pointer to the stream if it does.
 */
#define V_STREAM(vp)            ((vp->v_op == &spec_vnodeops) ?   \
                                             VTOS(vp)->s_sptr : 0)

#endif	/* INKERNEL */

/*
 * stdata flag field defines
 */
#define	IOCWAIT		01		/* someone wants to do ioctl */
#define	RSLEEP		02		/* someone wants to read/recv msg */
#define	WSLEEP		04		/* someone wants to write */
#define	STRPRI	       010		/* an M_PCPROTO is at stream head */
#define	STRHUP	       020		/* device has vanished */
#define	STWOPEN	       040		/* open is waiting to complete */
#define STPLEX	      0100		/* stream is being multiplexed */
#define CTTYFLG	      0200		/* used of finding control tty */
#define RMSGDIS	      0400		/* read msg discard */
#define RMSGNODIS    01000		/* read msg no discard */
#define STRERR	     02000		/* fatal error from M_ERROR */
#define STRTIME      04000		/* used with timeout strtime */
#define STR2TIME    010000		/* used with timeout str2time */
#define STR3TIME    020000		/* used with timeout str3time */
#define STRCLOSE    040000		/* wait for a close to complete */
#define SNDMREAD   0100000              /* used for read notification */
#define OLDNDELAY  0200000		/* use old TTY semantics for NDELAY rw */
#define RDBUFWAIT  0400000              /* used with bufcall in strqbuf() */
#define STRVTIME  01000000              /* used with timeout strvtime */
#define TTYVMODE  02000000              /* use TTY VMIN/VTIME semantics for read */
#define FLUSHWAIT 04000000              /* stream is being flushed */
#define STRINUSE 010000000              /* stream is in use */

#define RESERVED	1

/* 
 * structure for storing triples of mux'ed streams 
 */
struct linkblk {
	queue_t *l_qtop;	/* lowest level write queue of upper stream */
	queue_t *l_qbot;	/* highest level write queue of lower stream */
	int      l_index;	/* file[] index for lower stream. */
};


/*
 * Structure of list of processes to be sent SIGPOLL signal
 * on request, or for processes sleeping on poll().  The valid 
 * SIGPOLL events are defined in stropts.h, and the valid poll()
 * events are defined in poll.h.
 */
struct strevent {
	union {
		struct {
			struct proc 	*procp;
			long 		events;
			} e;
		struct {
			int (*func)();
			long arg;
			unsigned short id;
			} b;
	} x;
	struct strevent *se_next;
};

#define se_procp x.e.procp
#define se_events x.e.events
#define se_func x.b.func
#define se_arg x.b.arg
#define se_id x.b.id

#define SE_SLEEP	0	/* ok to sleep in allocation */
#define SE_NOSLP	1	/* don't sleep in allocation */


/*
 *  Data block descriptor
 */
struct datab {
	struct datab	*db_freep;
	unsigned char	*db_base;
	unsigned char	*db_lim;
	unsigned char	db_ref;
	unsigned char	db_type;
	unsigned char	db_class;
	int 		(*db_func)();	/* for private buffer support */
	long 		db_arg;		/* for private buffer support */
};

#define SIZE_PRIV	-1		/* size value for private buffers */

/*
 * Message block descriptor
 */
struct	msgb {
	struct	msgb	*b_next;
	struct  msgb	*b_prev;
	struct	msgb	*b_cont;
	unsigned char	*b_rptr;
	unsigned char	*b_wptr;
	struct datab 	*b_datap;
};

typedef struct msgb mblk_t;
typedef struct datab dblk_t;


/*
 * Data block allocation information.  Defines cutoffs for allocation 
 * priorities; bufcall lists. 
 */

struct dbalcst {
	int dba_cnt;
	int dba_lo;
	int dba_med;
	struct strevent *dba_lop;
	struct strevent *dba_medp;
	struct strevent *dba_hip;
};



/********************************************************************************/
/* 			Streams message types					*/
/********************************************************************************/


/*
 * Data and protocol messages (regular priority)
 */
#define	M_DATA		00		/* regular data */
#define M_PROTO		01		/* protocol control */

/*
 * Control messages (regular priority)
 */
#define	M_BREAK		010		/* line break */
#define M_PASSFP	011		/* pass file pointer */
#define	M_SIG		013		/* generate process signal */
#define	M_DELAY		014		/* real-time xmit delay (1 param) */
#define M_CTL		015		/* device-specific control message */
#define	M_IOCTL		016		/* ioctl; set/get params */
#define M_SETOPTS	020		/* set various stream head options */
#define M_RSE		021		/* reserved for RSE use only */


/*
 * Control messages (high priority; go to head of queue)
 * (These must be defined > 0200 in value.)
 */

#define	M_IOCACK	0201		/* acknowledge ioctl */
#define	M_IOCNAK	0202		/* negative ioctl acknowledge */
#define M_PCPROTO	0203		/* priority M_PROTO message */
#define	M_PCSIG		0204		/* priority M_SIG message */
#define	M_READ		0205		/* generate read notification */
#define	M_FLUSH		0206		/* flush your queues */
#define	M_STOP		0207		/* stop transmission immediately */
#define	M_START		0210		/* restart transmission after stop */
#define	M_HANGUP	0211		/* line disconnect */
#define M_ERROR		0212		/* fatal error used to set u.u_error */
#define M_COPYIN	0213		/* request to copin data */
#define M_COPYOUT	0214		/* request to copyout data */
#define M_IOCDATA	0215		/* response to M_COPYIN and M_COPYOUT */
#define M_PCRSE		0216		/* reserved for RSE use only */

/* Types added by Parallel STREAMS */

#define M_PCCTL		0233		/* priority M_CTL message */
#define	M_PCIOCTL	0234		/* priority M_IOCTL message */
#define M_PCSETOPTS	0235		/* priority M_SETOPTS message */


/*
 * Queue message class definitions.  
 */
#define QNORM    0			/* normal messages */
#define QPCTL 0200			/* priority cntrl messages */



/*
 *  IOCTL structure - this structure is the format of the M_IOCTL message type.
 */
struct iocblk {
	int 	ioc_cmd;		/* ioctl command type */
	uid_t	ioc_uid;		/* effective uid of user */
	gid_t	ioc_gid;		/* effective gid of user */
	uint	ioc_id;			/* ioctl id */
	uint	ioc_count;		/* count of bytes in data field */
	int	ioc_error;		/* error code */
	int	ioc_rval;		/* return value  */
};


/*
 * structure for the M_COPYIN and M_COPYOUT message types.
 */

struct copyreq {
	int	cq_cmd;			/* ioctl command (from ioc_cmd) */
	uid_t	cq_uid;			/* effective uid of user */
	gid_t	cq_gid;			/* effective gid of user */
	uint	cq_id;			/* ioctl id (from ioc_id) */
	caddr_t	cq_addr;		/* address to copy data to/from */
	uint	cq_size;		/* number of bytes to copy */
	int	cq_flag;		/* see below */
	mblk_t *cq_private;		/* privtate state information */
};

/* cq_flag values */

#define STRCANON	0x01		/* b_cont data block contains canonical
					   format specifier */
#define RECOPY		0x02		/* perform I_STR copyin again, this time
					   using canonical format specifier */


/*
 * structure for the M_IOCDATA message type.
 */

struct copyresp {
	int	cp_cmd;			/* ioctl command (from ioc_cmd) */
	uid_t	cp_uid;			/* effective uid of user */
	gid_t	cp_gid;			/* effective gid of user */
	uint	cp_id;			/* ioctl id (from ioc_id) */
	caddr_t	cp_rval;		/* status of request: 0 -> success
							      non-zero -> failure */
	uint	cp_pad1;		/* reserved */
	int	cp_pad2;		/* reserved */
	mblk_t *cp_private;		/* private state information */
};

/*
 * Options structure for M_SETOPTS message.  This is sent upstream
 * by driver to set stream head options.
 */
struct stroptions {
	short so_flags;			/* options to set */
	short so_readopt;		/* read option */
	ushort so_wroff;		/* write offset */
	short so_minpsz;		/* minimum read packet size */
	short so_maxpsz;		/* maximum read packet size */
	ushort so_hiwat;		/* read queue high water mark */
	ushort so_lowat;		/* read queue low water mark */
	unsigned char so_vmin;		/* minimum number to block read for */
	unsigned char so_vtime;		/* minimum time to block read for */
	unsigned char so_tostop;	/* SIGTTOU job control flag */
};

/* flags for stream options set message */

#define SO_ALL		077777	/* set all options */
#define SO_READOPT	  01	/* set read option */
#define SO_WROFF	  02	/* set write offset */
#define SO_MINPSZ	  04	/* set min packet size */
#define SO_MAXPSZ	 010	/* set max packet size */
#define SO_HIWAT	 020	/* set high water mark */
#define SO_LOWAT	 040	/* set low water mark */
#define SO_MREADON       0100	/* set read notification ON */
#define SO_MREADOFF      0200	/* set read notification OFF */
#define SO_NDELON	 0400	/* old TTY semantics for NDELAY reads and writes */
#define SO_NDELOFF      01000	/* old TTY semantics for NDELAY reads and writes */
/* Defined for POSIX needs */
#define SO_VMODEON	02000	/* set so_vmin and so_vtime ON */
#define SO_VMODEOFF	04000	/* set so_vmin and so_vtime OFF */
#define SO_TOSTOPON	010000	/* set SIGTTOU job control flag ON */
#define SO_TOSTOPOFF	020000	/* set SIGTTOU job control flag OFF */




/********************************************************************************/
/*		Miscellaneous parameters and flags				*/
/********************************************************************************/

/*
 * Default timeout in seconds for ioctls and close
 */
#define STRTIMOUT 15

/*
 * Stream head default high/low water marks 
 */
#define STRHIGH 5120
#define STRLOW	1024

/*
 * flag values for stream io waiting procedure (strwaitq)
 */
#define WRITEWAIT	0x1	/* waiting for write event */
#define READWAIT	0x2	/* waiting for read event */
#define NOINTR		0x4	/* error is not to be set for signal */
#define GETWAIT		0x8	/* waiting for getmsg event */

/*
 * sleep priorities for stream io
 */
#define	STIPRI	PZERO+3
#define	STOPRI	PZERO+3

/*
 * Block allocation parameters
 */
#define NCLASS 		9		/* number of block classes */
#define QBSIZE		65		/* min size for block allocation retries */
#define MAXBSZ		4096		/* max block size */
#define MAXIOCBSZ	1024		/* max ioctl data block size */

/*
 * Copy modes for tty and I_STR ioctls
 */
#define	U_TO_K 	01			/* User to Kernel */
#define	K_TO_K  02			/* Kernel to Kernel */

/*
 * Values for stream flag in open to indicate driver open, module open, 
 * or clone open.  return value for failure.
 */
#define DRVROPEN	0		/* open as a driver */
#define MODOPEN 	0x1		/* open as a module */
#define CLONEOPEN	0x2		/* open for clone, pick own minor device */
#define OPENFAIL	-1		/* returned for open failure */
#define OPENOK		0		/* may be returned for open success */

/*
 * Priority definitions for block allocation.
 */
#define BPRI_LO		1
#define BPRI_MED	2
#define BPRI_HI		3

/*
 * Value for packet size that denotes infinity
 */
#define INFPSZ		-1

/*
 * Flags for flushq()
 */
#define FLUSHALL	1	/* flush all messages */
#define FLUSHDATA	0	/* don't flush control messages */


/*
 * flag for transparent ioctls
 */
#define TRANSPARENT	(unsigned int)(-1)

/*
 * canonical structure definitions
 */

#define STRLINK		"lli"
#define STRIOCTL	"iiil"
#define STRPEEK		"iiliill"
#define STRFDINSERT	"iiliillii"
#define STRRECVFD	"lssc8"
#define STRNAME		"c0"
#define STRINT		"i"
#define STRTERMIO	"ssssc12"
#define STRTERMCB	"c6"
#define STRSGTTYB	"c4i"

#define STRTERMIOS	"llllc12"

/************************************************************************/
/*	Defintions of Streams macros and function interfaces.		*/
/************************************************************************/

/*
 * determine block allocation cutoff for given class and priority.
 */
#define bcmax(class, pri) ((pri) == BPRI_LO ? dballoc[class].dba_lo : \
			   ((pri) == BPRI_HI ? nmblock : dballoc[class].dba_med))


/*
 * Definitions of spl function needed to provide critical region protection
 * for streams drivers and modules.
 */
#define SPLSTR		SPL5		/* for most streams locks */	
#define SPLMM		SPL6		/* for critical global locks */	

/*
 * Finding related queues
 */
#define	OTHERQ(q)	((q)->q_flag & QREADR ? (q)+1: (q)-1)
#define	WR(q)		(q+1)
#define	RD(q)		(q-1)
#define	l_backq(q)	((q)->q_prev)

/*
 * Test if data block type is one of the data messages (i.e. not a control
 * message).
 */
#define datamsg(type) (type == M_DATA || type == M_PROTO || type == M_PCPROTO)

/*
 * Test if message type is priority.
 */
#define pcmsg(type) (type > QPCTL)

/*
 * extract queue class of message block
 */
#define queclass(bp) (bp->b_datap->db_type & QPCTL)

/*
 * Align address on next lower word boundary
 */
#define straln(a)	(caddr_t)((long)(a) & ~(sizeof(int)-1))

/*
 * Copy data from one data buffer to another.
 */
#define	strbcpy(s, d, c)	bcopy(s, d, c)

/*
 * canenable - check if queue can be enabled by putq().
 */
#define canenable(q)	!((q)->q_flag & QNOENB)
/*
 * noenable - set queue so that putq() will not enable it.
 * Assumes stream is unlocked.
 */
#define noenable(q) 	\
{ \
	register spl_t s_ipl;  \
	s_ipl = p_lock(&(q)->q_str->sd_mutex, SPLSTR); \
	(q)->q_flag |= QNOENB; \
	v_lock(&(q)->q_str->sd_mutex, s_ipl); \
}

/*
 * enableok - set queue so that putq() can enable it.
 * Assumes stream is unlocked.
 */
#define enableok(q)	\
{ \
	register spl_t s_ipl;  \
	s_ipl = p_lock(&(q)->q_str->sd_mutex, SPLSTR);  \
	(q)->q_flag &= ~QNOENB; \
	v_lock(&(q)->q_str->sd_mutex, s_ipl); \
}


/*
 * declarations of common routines
 */

extern mblk_t *rmvb();
extern mblk_t *dupmsg();
extern mblk_t *copymsg();
extern mblk_t *allocb();
extern mblk_t *allocb_priv();
extern mblk_t *unlinkb();
extern mblk_t *dupb();
extern mblk_t *copyb();
extern mblk_t *getq();
extern int putq();
extern int qenable();
extern queue_t *backq();
extern queue_t *allocq();
extern mblk_t *unlinkb();
extern int pullupmsg();
extern int adjmsg();
extern struct queue *getendq();
extern struct linkblk *findlinks();
extern struct strevent *sealloc();

/*
 * shared or externally configured data structures
 */
extern struct stdata *streams;		/* table of streams */
extern struct stdatahdr *strfree;	/* list of free streams */
extern struct stdatahdr *strhash;	/* hash table of in-use streams */
extern queue_t *queue;			/* table of queues */
extern mblk_t *mblock; 			/* table of msg blk desc */
extern dblk_t *dblock;		 	/* table of data blk desc */
extern ushort rbsize[];			/* map of class to real block size */
extern struct linkblk *linkblk;		/* multiplexor link table */
extern struct strevent *strevent;	/* table of stream event cells */
extern struct strstat strst;		/* streams statistics structure */
extern queue_t *qhead;			/* head of runnable queue list */
extern queue_t *qtail;			/* tail of runnable queue list */
extern int strmsgsz;			/* maximum stream message size */
extern int strctlsz;			/* maximum size of ctl part of msg */
extern int nmblock;			/* number of msg blk desc */
extern int ndblock;			/* number of data blk desc */
extern int nmuxlink;			/* number of multiplexor links */
extern int nstrpush;			/* maxmimum number of pushes  */
extern int nstrevent;			/* number of stream event cells */


#define TRUE		1
#define FALSE		0

#define VHZ		10	/* used for vmin, assumes HZ = 100 */

#define	STRHASHSZ 	64	/* number of stream table hash buckets */
#define STRHASH(dev) ((struct stdatahdr *)&strhash[((dev) & (STRHASHSZ-1))])


#ifdef DEBUG

extern int strdebug;			/* turn on debug printfs */
#define DPRINTF(arg)	if (strdebug) printf(arg); else

/* May be used to debug leaky buffer type problems */
#define colour(mp, c)	(mp)->b_datap->db_arg = (long)(c);

#else  /* !DEBUG */
#define DPRINTF(arg)
#endif /* DEBUG */

#define _SYS_STREAM_H_
#endif /* _SYS_STREAM_H_ */
