/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_MD_TRANS_H
#define	_SYS_MD_TRANS_H

#pragma ident	"@(#)md_trans.h	2.8	04/09/29 SMI"

#include <sys/lvm/mdvar.h>
#include <sys/buf.h>
#include <sys/fs/ufs_trans.h>
#include <sys/lvm/md_rename.h>

#ifdef	__cplusplus
extern "C" {
#endif

#define	LDL_META_SBLK		(16)

#define	LDL_MINLOGSIZE		(1024*1024)
#define	LDL_MAXLOGSIZE		(1024*1024*1024)
#define	LDL_MINBUFSIZE		(32*1024)
#define	LDL_USABLE_BSIZE	(DEV_BSIZE - sizeof (sect_trailer_t))
#define	NB_LEFT_IN_SECTOR(off) 	(LDL_USABLE_BSIZE - ((off) - dbtob(btodb(off))))

typedef struct cirbuf32 {
	caddr32_t	xx_cb_bp;	/* buf's with space in circular buf */
	caddr32_t	xx_cb_dirty;	/* filling this buffer for log write */
	caddr32_t	xx_cb_free;	/* free bufs list */
	caddr32_t	xx_cb_va;	/* address of circular buffer */
	uint_t		xx_cb_nb;	/* size of circular buffer */
	uint_t		xx_cb_rwlock[3]; /* r/w lock to protect list mgmt. */
} cirbuf32_t;

typedef struct cirbuf_ic {
	buf_t		*cb_bp;		/* buf's with space in circular buf */
	buf_t		*cb_dirty;	/* filling this buffer for log write */
	buf_t		*cb_free;	/* free bufs list */
	caddr_t		cb_va;		/* address of circular buffer */
	size_t		cb_nb;		/* size of circular buffer */
	md_krwlock_t	cb_rwlock;	/* r/w lock to protect list mgmt. */
} cirbuf_ic_t;


typedef struct ml_unit {
	uint_t		un_revision;	/* revision number */
	/*
	 * mdd infrastructure stuff
	 */
	mddb_recid_t	un_recid;	/* db record id */
	mdkey_t		un_key;		/* namespace key */
	md_dev64_t	un_dev;		/* device number */
	uint_t		un_opencnt;	/* open count */

	/*
	 * metatrans infrastructure stuff
	 */
	uint_t		un_transcnt;	/* #open metatrans devices */

	/*
	 * log specific stuff
	 */
	off32_t		un_head_lof;	/* byte offset of head */
	uint_t		un_head_ident;	/* head sector id # */
	off32_t		un_tail_lof;	/* byte offset of tail */
	uint_t		un_tail_ident;	/* tail sector id # */
	off32_t		un_bol_lof;	/* byte offset of begin of log */
	off32_t		un_eol_lof;	/* byte offset of end of log */
	daddr32_t	un_nblks;	/* total blocks of log space */
	daddr32_t	un_tblks;	/* total blocks in log device */
	uint_t		un_maxtransfer;	/* max transfer in bytes */
	uint_t		un_status;	/* status bits */
	uint_t		un_maxresv;	/* maximum reservable space */
	daddr32_t	un_pwsblk;	/* block number of prewrite area */
	ulong_t		un_devbsize;	/* device bsize */
	uint_t		un_resv;	/* reserved byte count for this trans */
	uint_t		un_resv_wantin;	/* reserved byte count for next trans */
	mt_l_error_t	un_error;	/* error state */
	uint_t		un_tid;		/* used during logscan */
	uint_t		un_head_tid;	/* used for logscan; set at sethead */
	struct timeval32 un_timestamp;	/* time of last state change */
	/*
	 * spares
	 */
	uint_t		un_spare[16];
	/*
	 * following are incore only elements.
	 * Incore elements must always be at the end
	 * of this data struture.
	 */
	struct ml_unit	*un_next;
	struct mt_unit	*un_utlist;
	struct mt_map	*un_logmap;
	cirbuf_ic_t	un_rdbuf;
	cirbuf_ic_t	un_wrbuf;
	kmutex_t	un_log_mutex;
} ml_unit_t;


#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack(4)
#endif
typedef struct ml_unit32_od {
	uint_t		un_revision;	/* revision number */
	/*
	 * mdd infrastructure stuff
	 */
	caddr32_t	xx_un_next;	/* next log unit struct */
	mddb_recid_t	un_recid;	/* db record id */
	mdkey_t		un_key;		/* namespace key */
	dev32_t		un_dev;		/* device number */
	uint_t		un_opencnt;	/* open count */

	/*
	 * metatrans infrastructure stuff
	 */
	uint_t		un_transcnt;	/* #open metatrans devices */
	caddr32_t	xx_un_utlist;	/* list of metatrans devices */
	caddr32_t	xx_un_logmap;	/* address of logmap */

	/*
	 * log specific stuff
	 */
	off32_t		un_head_lof;	/* byte offset of head */
	uint_t		un_head_ident;	/* head sector id # */
	off32_t		un_tail_lof;	/* byte offset of tail */
	uint_t		un_tail_ident;	/* tail sector id # */
	off32_t		un_bol_lof;	/* byte offset of begin of log */
	off32_t		un_eol_lof;	/* byte offset of end of log */
	daddr32_t	un_nblks;	/* total blocks of log space */
	daddr32_t	un_tblks;	/* total blocks in log device */
	uint_t		un_maxtransfer;	/* max transfer in bytes */
	uint_t		un_status;	/* status bits */
	uint_t		un_maxresv;	/* maximum reservable space */
	daddr32_t	un_pwsblk;	/* block number of prewrite area */
	uint_t		un_devbsize;	/* device bsize */
	uint_t		un_resv;	/* reserved byte count for this trans */
	uint_t		un_resv_wantin;	/* reserved byte count for next trans */
	mt_l_error_t	un_error;	/* error state */
	uint_t		un_tid;		/* used during logscan */
	uint_t		un_head_tid;	/* used for logscan; set at sethead */
	cirbuf32_t	xx_un_rdbuf;	/* read buffer space */
	cirbuf32_t	xx_un_wrbuf;	/* write buffer space */
	int		xx_un_log_mutex[2]; /* allows one log write at a time */
	struct timeval32 un_timestamp;	/* time of last state change */
	/*
	 * spares
	 */
	uint_t		un_spare[16];
} ml_unit32_od_t;
#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack()
#endif



#define	ML_UNIT_ONDSZ	((size_t)((caddr_t)&((ml_unit_t *)0)->un_spare[15] +\
				sizeof (uint_t)))


/*
 *	un_status
 */
#define	LDL_BEING_RESET	0x0001	/* delete the log record at snarf */
#define	LDL_FIND_TAIL	0x0002	/* find tail of the log */
#define	LDL_SCAN_ACTIVE	0x0004	/* log scan in progress */
#define	LDL_METADEVICE	0x0008	/* underlying device is metadevice */
#define	LDL_PWVALID	0x0010	/* prewrite area is valid */
#define	LDL_INFO	0x0020	/* prewrite state is valid */

typedef struct sect_trailer {
	uint_t		st_tid;		/* transaction id */
	uint_t		st_ident;	/* unique sector id */
} sect_trailer_t;


/*
 * ioctls
 */
#define	MD_IOCGET_LOG		(MDIOC_MISC|0)
#define	MD_IOC_DEBUG		(MDIOC_MISC|4)
#define	MD_IOCGET_TRANSSTATS	(MDIOC_MISC|5)
#define	MD_IOC_TSD		(MDIOC_MISC|6)
#define	MD_IOC_TRYGETBLK	(MDIOC_MISC|7)
#define	MD_IOC_TRYPAGE		(MDIOC_MISC|8)
#define	MD_IOC_SETSHADOW	(MDIOC_MISC|11)
#define	MD_IOC_INJECTERRORS	(MDIOC_MISC|13)
#define	MD_IOC_STOPERRORS	(MDIOC_MISC|14)
#define	MD_IOC_UFSERROR		(MDIOC_MISC|15)
#define	MD_IOC_ISDEBUG		(MDIOC_MISC|17)

#define	MD_IOC_TRANS_DETACH	(MDIOC_MISC|32)

/*
 * following bits are used in status word in the common section
 * of unit structure
 */
#define	MD_UN_LOG_DELETED	(0x00010000)	/* don't need to del @snarf */

/*
 * map block
 */
#define	MAPBLOCKSIZE	(8192)
#define	MAPBLOCKSHIFT	(13)
#define	MAPBLOCKOFF	(MAPBLOCKSIZE-1)
#define	MAPBLOCKMASK	(~MAPBLOCKOFF)

/*
 * delta header
 */
struct delta {
	offset_t	d_mof;
	off32_t		d_nb;
	dev32_t		d_dev;
	delta_t 	d_typ;
};

/*
 * common map entry
 */
typedef struct mapentry	mapentry_t;
struct mapentry {
	/*
	 * doubly linked list of all mapentries in map -- MUST BE FIRST
	 */
	mapentry_t	*me_next;
	mapentry_t	*me_prev;

	mapentry_t	*me_hash;
	mapentry_t	*me_agenext;
	mapentry_t	*me_cancel;
	int		(*me_func)();
	uintptr_t	me_arg;
	off_t		me_lof;
	uint_t		me_flags;
	uint_t		me_tid;
	uint_t		me_age;
	struct delta	me_delta;
};

#define	me_mof	me_delta.d_mof
#define	me_nb	me_delta.d_nb
#define	me_dt	me_delta.d_typ
#define	me_dev	me_delta.d_dev

/*
 * me_flags
 */
#define	ME_FREE		(0x0001)	/* on free   list */
#define	ME_HASH		(0x0002)	/* on hash   list */
#define	ME_CANCEL	(0x0004)	/* on cancel list */
#define	ME_AGE		(0x0008)	/* on age    list */
#define	ME_LIST		(0x0010)	/* on list   list */
#define	ME_ROLL		(0x0020)	/* on pseudo-roll list */

/*
 * TRANSACTION OPS STATS
 * mt_top_size_* should be 64bit but that would
 * require test recompilations. It does not hurt the kernel
 * so leave as 32 bit for now.
 */
struct topstats {
	uint_t		mtm_top_num[TOP_MAX];
	uint_t		mtm_top_size_etot[TOP_MAX];
	uint_t		mtm_top_size_rtot[TOP_MAX];
	uint_t		mtm_top_size_max[TOP_MAX];
	uint_t		mtm_top_size_min[TOP_MAX];
	uint_t		mtm_delta_num[DT_MAX];
};

/*
 * MAP STATS (global struct that is not updated if compiled w/o ASSERTs)
 * some members of transstats need to be 64bit. See the comment above.
 */
struct transstats {
	/* trans.c */
	uint_t		ts_trans_zalloc;
	uint_t		ts_trans_zalloc_nosleep;
	uint_t		ts_trans_alloc;
	uint_t		ts_trans_alloc_nosleep;
	uint_t		ts_trans_free;
	uint_t		ts_trans_alloced;
	uint_t		ts_trans_freed;
	uint_t		ts_trans_write;
	uint_t		ts_trans_write_roll;

	/* trans_delta.c */
	uint_t		ts_mapentry_alloc;
	uint_t		ts_mapentry_alloc_list;
	uint_t		ts_mapentry_free;

	uint_t		ts_delta_add;
	uint_t		ts_delta_add_scan;
	uint_t		ts_delta_add_hit;

	uint_t		ts_delta_remove;
	uint_t		ts_delta_remove_scan;
	uint_t		ts_delta_remove_hit;

	uint_t		ts_delta_del;
	uint_t		ts_delta_del_scan;

	uint_t		ts_delta_push;

	uint_t		ts_overlap;
	uint_t		ts_overlap_scan;
	uint_t		ts_overlap_hit;

	uint_t		ts_remove_roll;
	uint_t		ts_remove_roll_scan;
	uint_t		ts_remove_roll_hit;
	uint_t		ts_remove_roll_dolock;
	uint_t		ts_remove_roll_sud;

	uint_t		ts_next_roll;
	uint_t		ts_next_roll_scan;
	uint_t		ts_next_roll_hit;

	uint_t		ts_list_age;
	uint_t		ts_list_age_scan;

	uint_t		ts_list_get;
	uint_t		ts_list_get_scan;
	uint_t		ts_list_get_hit;
	uint_t		ts_list_get_again;

	uint_t		ts_list_put;
	uint_t		ts_list_put_scan;

	uint_t		ts_read_mstr;

	uint_t		ts_logmap_secmap_roll;

	uint_t		ts_read_log;

	uint_t		ts_logmap_abort;
	uint_t		ts_logmap_abort_hit;

	uint_t		ts_list_add;
	uint_t		ts_list_add_scan;
	uint_t		ts_list_add_cancel;
	uint_t		ts_list_add_unhash;

	uint_t		ts_free_cancel;
	uint_t		ts_free_cancel_again;
	uint_t		ts_free_cancel_scan;
	uint_t		ts_free_cancel_hit;

	uint_t		ts_commit;
	uint_t		ts_commit_hit;

	uint_t		ts_logmap_roll_dev;
	uint_t		ts_logmap_roll_dev_scan;
	uint_t		ts_logmap_roll_dev_hit;

	uint_t		ts_logmap_roll_sud;
	uint_t		ts_logmap_roll_sud_hit;

	uint_t		ts_logmap_ud_done;
	uint_t		ts_logmap_ud_done_scan;

	uint_t		ts_logmap_ud_wait;
	uint_t		ts_logmap_ud_wait_hit;

	uint_t		ts_logmap_ud_commit;
	uint_t		ts_logmap_ud_commit_scan;

	uint_t		ts_logmap_cancel;
	uint_t		ts_logmap_cancel_scan;
	uint_t		ts_logmap_cancel_hit;

	uint_t		ts_logmap_iscancel;
	uint_t		ts_logmap_iscancel_scan;
	uint_t		ts_logmap_iscancel_hit;

	uint_t		ts_logscan;
	uint_t		ts_logscan_ud;
	uint_t		ts_logscan_delta;
	uint_t		ts_logscan_cancel;
	uint_t		ts_logscan_commit;

	/* trans_thread.c */
	uint_t		ts_prewrite;
	uint_t		ts_prewrite_read;
	uint_t		ts_prewrite_write;
	uint_t		ts_trans_roll;
	uint_t		ts_trans_roll_wait;
	uint_t		ts_trans_roll_wait_nada;
	uint_t		ts_trans_roll_wait_slow;
	uint_t		ts_trans_roll_force;
	uint_t		ts_trans_roll_nsud;
	uint_t		ts_trans_roll_ref;
	uint_t		ts_trans_roll_full;
	uint_t		ts_trans_roll_logmap;
	uint_t		ts_trans_roll_read;
	uint_t		ts_trans_roll_reread;
	uint_t		ts_trans_roll_wait_inuse;
	uint_t		ts_trans_roll_prewrite;
	uint_t		ts_trans_roll_write;

	/* trans_top.c */
	uint_t		ts_delta;
	uint_t		ts_ud_delta;
	uint_t		ts_ud_delta_log;
	uint_t		ts_cancel;
	uint_t		ts_iscancel;
	uint_t		ts_error;
	uint_t		ts_iserror;
	uint_t		ts_beginsync;
	uint_t		ts_active;
	uint_t		ts_activesync;
	uint_t		ts_beginasync;
	uint_t		ts_endsync;
	uint_t		ts_wantin;
	uint_t		ts_endasync;
	uint_t		ts_read;
	uint_t		ts_read_roll;
	uint_t		ts_readmt;
	uint_t		ts_write;
	uint_t		ts_writemt;
	uint_t		ts_writemt_done;
	uint_t		ts_log;

	/* trans_log.c */
	uint_t		ts_logcommitdb;

	uint_t		ts_push_dirty_bp;
	uint_t		ts_push_dirty_bp_extra;
	uint_t		ts_push_dirty_bp_fail;

	uint_t		ts_alloc_bp;
	uint_t		ts_alloc_bp_free;

	uint_t		ts_find_bp;
	uint_t		ts_find_bp_scan;
	uint_t		ts_find_bp_hit;

	uint_t		ts_find_read_lof;
	uint_t		ts_find_read_lof_scan;
	uint_t		ts_find_read_lof_hit;

	uint_t		ts_get_read_bp;
	uint_t		ts_get_read_bp_wr;
	uint_t		ts_get_read_bp_rd;

	uint_t		ts_extend_write_bp;
	uint_t		ts_extend_write_bp_hit;

	uint_t		ts_storebuf;
	uint_t		ts_fetchbuf;
	uint_t		ts_round_commit;
	uint_t		ts_push_commit;

	uint_t		ts_inval_range;
	uint_t		ts_inval_range_scan;
	uint_t		ts_inval_range_hit;

	uint_t		ts_writelog;
	uint_t		ts_writelog_max;

	uint_t		ts_readlog;
	uint_t		ts_readlog_max;

	uint_t		ts_get_write_bp;
	uint_t		ts_get_write_bp_steal;

	uint_t		ts_writesync;
	uint_t		ts_writesync_log;
	uint_t		ts_writesync_nolog;

	uint_t		ts_longmof_cnt;

} transstats;

#ifdef	DEBUG
#define	TRANSSTATS(f)		(transstats.f++)
#define	TRANSSTATSADD(f, n)	(transstats.f += (n))
#define	TRANSSTATSMAX(m, v)	\
		if ((v) > transstats.m)\
			transstats.m = (v);
#else
#define	TRANSSTATS(f)
#define	TRANSSTATSADD(f, n)
#define	TRANSSTATSMAX(m, v)
#endif /* DEBUG */

/*
 * MAP TYPES
 */
enum maptypes	{
	deltamaptype, udmaptype, logmaptype, matamaptype, shadowmaptype
};

/*
 * MAP
 */
#define	DELTAMAP_NHASH	(512)
#define	LOGMAP_NHASH	(2048)
#define	MAP_INDEX(dev, mof, mtm) \
	((((mof) >> MAPBLOCKSHIFT) + (dev)) & ((mtm)->mtm_nhash-1))
#define	MAP_HASH(dev, mof, mtm) \
	(mtm->mtm_hash + MAP_INDEX(dev, mof, mtm))

typedef struct mt_map {
	/*
	 * anchor doubly linked list this map's entries -- MUST BE FIRST
	 */
	mapentry_t	*mtm_next;
	mapentry_t	*mtm_prev;

	int		mtm_flags;	/* generic flags */
	int		mtm_ref;	/* PTE like ref bit */
	uint_t		mtm_debug;	/* set at create time */
	uint_t		mtm_age;	/* mono-inc; tags mapentries */
	mapentry_t	*mtm_cancel;	/* to be canceled at commit */
	uint_t		mtm_nhash;	/* # of hash anchors */
	mapentry_t	**mtm_hash;	/* array of singly linked lists */
	struct topstats	*mtm_tops;	/* trans ops - enabled by an ioctl */
	int		mtm_nme;	/* # of mapentries */
	int		mtm_nmet;	/* # of mapentries this transaction */
	int		mtm_nud;	/* # of active userdata writes */
	int		mtm_nsud;	/* # of userdata scanned deltas */
	md_dev64_t	mtm_dev;	/* device identifying map */

	/*
	 * the following are protected by the global map_mutex
	 */
	struct mt_map	*mtm_mapnext;	/* singly linked list of all maps */
	uint_t		mtm_refcnt;	/* reference count to this map */
	enum maptypes	mtm_type;	/* type of map */

	/*
	 * used after logscan to set the log's tail
	 */
	off_t		mtm_tail_lof;
	size_t		mtm_tail_nb;

	/*
	 * debug field for Scan test
	 */
	off_t		mtm_trimlof;	/* log was trimmed to this lof */
	off_t		mtm_trimtail;	/* tail lof before trimming */
	off_t		mtm_trimalof;	/* lof of last allocation delta */
	off_t		mtm_trimclof;	/* lof of last commit delta */
	off_t		mtm_trimrlof;	/* lof of last rolled delta */
	struct ml_unit	*mtm_ul;	/* log unit for this map */

	/*
	 * moby trans stuff
	 */
	uint_t			mtm_tid;
	uint_t			mtm_committid;
	ushort_t		mtm_closed;
	ushort_t		mtm_seq;
	int			mtm_wantin;
	int			mtm_active;
	int			mtm_activesync;
	uint_t			mtm_dirty;
	kmutex_t		mtm_lock;
	kcondvar_t		mtm_cv_commit;
	kcondvar_t		mtm_cv_next;
	kcondvar_t		mtm_cv_eot;

	/*
	 * mutex that protects all the fields in mt_map except
	 * mtm_mapnext and mtm_refcnt
	 */
	kmutex_t	mtm_mutex;
	kcondvar_t	mtm_cv;		/* generic conditional */

	/*
	 * rw lock for the mapentry fields agenext and locnext
	 */
	md_krwlock_t	mtm_rwlock;
	/*
	 * DEBUG: runtestscan
	 */
	kmutex_t	mtm_scan_mutex;
} mt_map_t;

/*
 * mtm_flags
 */
#define	MTM_ROLL_EXIT		(0x00000001)
#define	MTM_ROLL_RUNNING	(0x00000002)
#define	MTM_FORCE_ROLL		(0x00000004)

/*
 * Generic range checking macros
 */
#define	OVERLAP(sof, snb, dof, dnb) \
	((sof >= dof && sof < (dof + dnb)) || \
	(dof >= sof && dof < (sof + snb)))

#define	WITHIN(sof, snb, dof, dnb) ((sof >= dof) && ((sof+snb) <= (dof+dnb)))

#define	DATAoverlapME(mof, hnb, me) (OVERLAP(mof, hnb, me->me_mof, me->me_nb))
#define	MEwithinDATA(me, mof, hnb) (WITHIN(me->me_mof, me->me_nb, mof, hnb))
#define	DATAwithinME(mof, hnb, me) (WITHIN(mof, hnb, me->me_mof, me->me_nb))


typedef struct mt_unit {
	struct mdc_unit	c;		/* common stuff */
	/*
	 * infrastructure
	 */
	mt_flags_t	un_flags;
	/*
	 * log and master device
	 */
	mdkey_t		un_m_key;
	md_dev64_t	un_m_dev;
	mdkey_t		un_l_key;
	md_dev64_t	un_l_dev;
	daddr32_t	un_l_sblk;	/* start block */
	daddr32_t	un_l_pwsblk;	/* prewrite start block */
	daddr32_t	un_l_nblks;	/* # of usable log blocks */
	daddr32_t	un_l_tblks;	/* total log blocks */
	daddr32_t	un_l_head;	/* sector offset of log head */
	daddr32_t	un_l_tail;	/* sector offset of log tail */
	uint_t		un_l_resv;	/* current log reservations */
	uint_t		un_l_maxresv;	/* max log reservations */
	uint_t		un_l_maxtransfer; /* maximum transfer at init */
	mddb_recid_t	un_l_recid;	/* database id */
	mt_l_error_t	un_l_error;	/* error state */
	struct timeval32 un_l_timestamp; /* time of last log state chg */
	md_dev64_t	un_s_dev;	/* shadow device for testing only */
	mt_debug_t	un_debug;	/* debug flags; set at create */
	md_dev64_t	un_dev;		/* this metatrans device */
	int		un_logreset;	/* part of _FIOLOGRESET ioctl stuff */
	struct timeval32 un_timestamp;	/* time of last trans state change */
	/*
	 * spares
	 */
	ulong_t		un_spare[16];
	/*
	 * following are incore only elements.
	 * Incore elements must always be at the end
	 * of this data struture.
	 */
	struct mt_unit	*un_next;
	struct ml_unit	*un_l_unit;
	struct ufstrans *un_ut;
	mt_map_t	*un_deltamap;
	mt_map_t	*un_udmap;
	mt_map_t	*un_logmap;
	mt_map_t	*un_matamap;
	mt_map_t	*un_shadowmap;
} mt_unit_t;


typedef struct mt_unit32_od {
	mdc_unit32_od_t	c;		/* common stuff */
	/*
	 * infrastructure
	 */
	mt_flags_t	un_flags;
	caddr32_t	xx_un_next;	/* anchored in log unit */
	/*
	 * log and master device
	 */
	mdkey_t		un_m_key;
	dev32_t		un_m_dev;
	mdkey_t		un_l_key;
	dev32_t		un_l_dev;
	daddr32_t	un_l_sblk;	/* start block */
	daddr32_t	un_l_pwsblk;	/* prewrite start block */
	daddr32_t	un_l_nblks;	/* # of usable log blocks */
	daddr32_t	un_l_tblks;	/* total log blocks */
	daddr32_t	un_l_head;	/* sector offset of log head */
	daddr32_t	un_l_tail;	/* sector offset of log tail */
	uint_t		un_l_resv;	/* current log reservations */
	uint_t		un_l_maxresv;	/* max log reservations */
	uint_t		un_l_maxtransfer; /* maximum transfer at init */
	mddb_recid_t	un_l_recid;	/* database id */
	caddr32_t	xx_un_l_unit;	/* log device unit struct */
	mt_l_error_t	un_l_error;	/* error state */
	struct timeval32 un_l_timestamp;	/* time of last log state chg */
	dev32_t		un_s_dev;	/* shadow device for testing only */

	mt_debug_t	un_debug;	/* debug flags; set at create */
	caddr32_t	xx_un_ut;	/* ufstrans struct */
	dev32_t		un_dev;		/* this metatrans device */
	caddr32_t	xx_un_deltamap;	/* deltamap */
	caddr32_t	xx_un_udmap;	/* userdata map */
	caddr32_t	xx_un_logmap;	/* logmap includes moby trans stuff */
	caddr32_t	xx_un_matamap;	/* optional - matamap */
	caddr32_t	xx_un_shadowmap; /* optional - shadowmap */
	int		un_logreset;	/* part of _FIOLOGRESET ioctl stuff */
	struct timeval32 un_timestamp;	/* time of last trans state change */
	/*
	 * spares
	 */
	uint_t		un_spare[16];
} mt_unit32_od_t;

/*
 * prewrite info (per buf); stored as array at beginning of prewrite area
 */
struct prewrite {
	int		pw_bufsize;	/* every buffer is this size */
	daddr32_t	pw_blkno;	/* block number */
	dev32_t		pw_dev;		/* device to write to */
	ushort_t	pw_secmap;	/* bitmap 	*/
					/* 1's write this sector in the buf */
	ushort_t	pw_flags;
};
/*
 * pw_flags
 */
#define	PW_INUSE	0x0001	/* this prewrite buf is in use */
#define	PW_WAIT		0x0002	/* write in progress; wait for completion */
#define	PW_REM		0x0004	/* remove deltas */

/*
 * log state
 */
struct  logstate {
	off32_t		ls_head_lof;	/* log head */
	uint_t		ls_head_ident;	/* log head ident */
	uint_t		ls_head_tid;	/* log head tid */
	uint_t		ls_chksum;	/* checksum of structure */
	off32_t		ls_bol_lof;	/* needed for TS_Tools/dumplog.c */
	off32_t		ls_eol_lof;	/* needed for TS_Tools/dumplog.c */
	uint_t		ls_maxtransfer;	/* needed for TS_Tools/dumplog.c */
	daddr32_t	ls_pwsblk;	/* needed for TS_Tools/dumplog.c */
};

/*
 * log state defines
 */
#define	LS_SECTORS	(2)	/* number of sectors used by state area */

/*
 * un_debug
 *	MT_TRANSACT		- keep per thread accounting of tranactions
 *	MT_MATAMAP		- double check deltas and ops against matamap
 *	MT_WRITE_CHECK		- check master+deltas against metadata write
 *	MT_LOG_WRITE_CHECK	- read after write for log writes
 *	MT_CHECK_MAP		- check map after every insert/delete
 *	MT_TRACE		- trace transactions (used with MT_TRANSACT)
 *	MT_SIZE			- fail on size errors (used with MT_TRANSACT)
 *	MT_NOASYNC		- force every op to be sync
 *	MT_FORCEROLL		- forcibly roll the log after every commit
 *	MT_SCAN			- running runtestscan; special case as needed
 *	MT_SHADOW		- copy metatrans device writes to shadow dev.
 *	MT_PREWRITE		- process prewrite area every roll
 */
#define	MT_TRANSACT		(0x00000001)
#define	MT_MATAMAP		(0x00000002)
#define	MT_WRITE_CHECK		(0x00000004)
#define	MT_LOG_WRITE_CHECK	(0x00000008)
#define	MT_CHECK_MAP		(0x00000010)
#define	MT_TRACE		(0x00000020)
#define	MT_SIZE			(0x00000040)
#define	MT_NOASYNC		(0x00000080)
#define	MT_FORCEROLL		(0x00000100)
#define	MT_SCAN			(0x00000200)
#define	MT_SHADOW		(0x00000400)
#define	MT_PREWRITE		(0x00000800)

/* Type 2 trans records */
#define	TRANS_REC	1
#define	LOG_REC		2

#ifdef _KERNEL

typedef struct md_tps {			/* trans parent save */
	DAEMON_QUEUE
	struct mt_unit	*ps_un;
	mdi_unit_t	*ps_ui;
	buf_t		*ps_bp;
	size_t		ps_count;	/* Used for testing only. */
	kmutex_t	ps_mx;		/* protects ps_count. */
} md_tps_t;

/*
 * Log layer protos -- trans_log.c
 */
extern void		_init_ldl(void);
extern void		_fini_ldl(void);
extern void		md_ldl_round_commit(mt_unit_t *);
extern void		md_ldl_push_commit(mt_unit_t *);
extern int		md_ldl_need_commit(ml_unit_t *);
extern int		md_ldl_has_space(ml_unit_t *, mapentry_t *);
extern void		md_ldl_write(mt_unit_t *, caddr_t, offset_t,
					mapentry_t *);
extern void		md_ldl_waito(ml_unit_t *);
extern int		md_ldl_read(ml_unit_t *, caddr_t, offset_t, off_t,
					mapentry_t *);
extern void		md_ldl_sethead(ml_unit_t *, off_t, uint_t,
					struct buf *);
extern void		md_ldl_settail(ml_unit_t *, off_t, off_t,
					struct buf *);
extern void		ldl_setpwvalid(ml_unit_t *);
extern int		ldl_build_incore(ml_unit_t *, int);
extern ml_unit_t	*ldl_findlog(mddb_recid_t);
extern mddb_recid_t	ldl_create(mdkey_t, mt_unit_t *);
extern void		ldl_utadd(mt_unit_t *);
extern int		ldl_open_dev(mt_unit_t *, ml_unit_t *);
extern void		ldl_close_dev(ml_unit_t *);
extern int		ldl_snarf(void);
extern void		ldl_logscan_seterror(ml_unit_t *);
extern void		ldl_logscan_saverror(ml_unit_t *);
extern size_t		md_ldl_logscan_nbcommit(off_t);
extern int		md_ldl_logscan_read(ml_unit_t *, off_t *, size_t,
					caddr_t);
extern void		md_ldl_logscan_begin(ml_unit_t *, daddr_t);
extern void		md_ldl_logscan_end(ml_unit_t *);
extern int		md_ldl_need_roll(ml_unit_t *);
extern int		md_ldl_empty(ml_unit_t *);
extern int		ldl_pwvalid(ml_unit_t *);
extern void		ldl_waitscan(ml_unit_t *);
extern void		ldl_errorbp(set_t, buf_t *, char *);
extern void		md_ldl_seterror(ml_unit_t *);
extern int		ldl_isherror(ml_unit_t *);
extern int		ldl_iserror(ml_unit_t *);
extern int		ldl_isanyerror(ml_unit_t *);
extern void		ldl_start_scan(mt_unit_t *);
extern void		ldl_opened_trans(mt_unit_t *, int);
extern void		ldl_open_trans(mt_unit_t *, int);
extern int		ldl_logreset(mt_unit_t *, buf_t *);
extern void		ldl_close_trans(mt_unit_t *);
extern size_t		md_ldl_bufsize(ml_unit_t *);
extern void		ldl_open_underlying(mt_unit_t *);
extern void		ldl_snarf_done();
extern int		ldl_reset(mt_unit_t *, int, int);
extern void		ldl_cleanup(ml_unit_t *);

/*
 * trans driver layer -- mdtrans.c
 */
extern kmem_cache_t	*trans_child_cache;
extern void		*md_trans_zalloc(size_t);
extern void		*md_trans_zalloc_nosleep(size_t);
extern void		*md_trans_alloc(size_t);
extern void		*md_trans_alloc_nosleep(size_t);
extern void		md_trans_free(void *, size_t);
extern int		md_trans_not_wait(struct buf *cb);
extern int		md_trans_not_done(struct buf *cb);
extern int		md_trans_wait(struct buf *cb);
extern int		trans_done(struct buf *cb);
extern int		trans_done_shadow(struct buf *cb);
extern void		trans_child_init(struct buf *bp);
extern void		trans_close_all_devs(mt_unit_t *);
extern int		trans_open_all_devs(mt_unit_t *);
extern int		trans_build_incore(void *, int);
extern void		trans_commit(mt_unit_t *, int);
extern int		trans_detach(mt_unit_t *, int);
extern void		trans_attach(mt_unit_t *, int);
extern int		trans_reset(mt_unit_t *, minor_t, int, int);

/*
 * transaction ioctl -- trans_ioctl.c
 */

/* rename named service functions */
md_ren_list_svc_t	trans_rename_listkids;
md_ren_svc_t		trans_rename_check;
md_ren_roleswap_svc_t	trans_renexch_update_kids;
md_ren_roleswap_svc_t	trans_rename_update_self;
md_ren_roleswap_svc_t	trans_exchange_parent_update_to;
md_ren_roleswap_svc_t	trans_exchange_self_update_from_down;

/*
 * transaction op layer -- trans_top.c
 */
extern void	_init_md_top(void);
extern void	_fini_top(void);
extern void	top_read(struct buf *, char *, mt_unit_t *, int, void *);
extern void	md_top_read_roll(struct buf *, mt_unit_t *, ushort_t *);
extern void	top_build_incore(mt_unit_t *);
extern void	top_reset(mt_unit_t *, int, int);
extern void	top_write(struct buf *, char *, mt_unit_t *, int, void *);

/*
 * map layer -- trans_delta.c
 */
extern void		md_map_free_entries(mt_map_t *);
extern int		md_matamap_overlap(mt_map_t *, offset_t, off_t);
extern int		md_matamap_within(mt_map_t *, offset_t, off_t);
extern int		md_deltamap_need_commit(mt_map_t *);
extern void		md_deltamap_add(mt_map_t *, offset_t, off_t, delta_t,
				int (*)(), uintptr_t);
extern mapentry_t	*md_deltamap_remove(mt_map_t *, offset_t, off_t);
extern void		md_deltamap_del(mt_map_t *, offset_t, off_t);
extern void		md_deltamap_push(mt_unit_t *);
extern int		md_logmap_need_commit(mt_map_t *);
extern int		md_logmap_need_roll_async(mt_map_t *);
extern int		md_logmap_need_roll_sync(mt_map_t *);
extern int		md_logmap_need_roll(mt_map_t *);
extern void		md_logmap_start_roll(mt_unit_t *);
extern void		md_logmap_kill_roll(mt_map_t *);
extern void		md_logmap_forceroll(mt_map_t *);
extern int		md_logmap_overlap(mt_map_t *, md_dev64_t, offset_t,
				off_t);
extern void		md_logmap_remove_roll(mt_map_t *, md_dev64_t, offset_t,
				off_t);
extern int		md_logmap_next_roll(mt_map_t *, offset_t *,
				md_dev64_t *);
extern void		md_logmap_list_get(mt_map_t *, md_dev64_t, offset_t,
				off_t, mapentry_t **);
extern void		md_logmap_list_get_roll(mt_map_t *, md_dev64_t,
				offset_t, off_t, mapentry_t **);
extern void		md_logmap_list_put(mt_map_t *, mapentry_t *);
extern void		md_logmap_read_mstr(ml_unit_t *, struct buf *, int,
				void *);
extern void		md_logmap_secmap_roll(mapentry_t *, offset_t,
				ushort_t *);
extern int		logmap_read_log(ml_unit_t *, char *, offset_t, off_t,
				mapentry_t *);
extern void		md_logmap_make_space(mt_map_t *, ml_unit_t *,
				mapentry_t *);
extern void		md_logmap_add(mt_unit_t *, md_dev64_t, char *, offset_t,
				mapentry_t *);
extern void		md_logmap_add_ud(mt_unit_t *, md_dev64_t, char *,
				offset_t, mapentry_t *);
extern void		md_logmap_commit(mt_unit_t *);
extern void		md_logmap_sethead(mt_map_t *, ml_unit_t *,
				struct buf *);
extern void		md_logmap_roll_dev(mt_map_t *, ml_unit_t *ul,
				md_dev64_t);
extern void		md_logmap_roll_sud(mt_map_t *, ml_unit_t *ul,
				md_dev64_t, offset_t, off_t);
extern int		md_logmap_ud_done(struct buf *);
extern void		md_logmap_ud_wait();
extern void		md_logmap_cancel(mt_unit_t *, md_dev64_t, offset_t,
				off_t);
extern int		md_logmap_iscancel(mt_map_t *, md_dev64_t, offset_t,
				off_t);
extern void		md_logmap_logscan(mt_unit_t *, daddr_t);
extern void		map_build_incore(mt_unit_t *);
extern void		map_reset(mt_unit_t *, int, int);
extern void		_init_md_map(void);
extern void		_fini_map(void);

/*
 * scan and roll threads -- trans_thread.c
 */
extern void	md_trans_roll(ml_unit_t *);
extern void	trans_scan(mt_unit_t *);
extern void	trans_roll_prewrite(ml_unit_t *);

#endif	/* _KERNEL */

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_MD_TRANS_H */
