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

#ifndef _SYS_MD_MIRROR_H
#define	_SYS_MD_MIRROR_H

#pragma ident	"@(#)md_mirror.h	2.9	03/02/06 SMI"

#include <sys/lvm/mdvar.h>
#include <sys/lvm/md_mirror_shared.h>
#include <sys/lvm/md_rename.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * following bits are used in status word in the common section
 * of unit structure
 */
#define	SMS_IS(sm, state) (((sm)->sm_state & (state)) != 0)
#define	SMS_BY_INDEX_IS(un, index, state) \
		(((un)->un_sm[(index)].sm_state & (state)) != 0)

#define	SMS_BY_INDEX_IS_TARGET(un, index) \
		((un)->un_sm[(index)].sm_flags & MD_SM_RESYNC_TARGET)

#define	SUBMIRROR_IS_READABLE(un, isubmirror)				\
	((((un)->un_sm[(isubmirror)].sm_state & SMS_IGNORE) == 0) &&	\
	    ((un)->un_sm[(isubmirror)].sm_state & 			\
	    (SMS_RUNNING | SMS_COMP_ERRED | SMS_COMP_RESYNC)))

#define	SUBMIRROR_IS_WRITEABLE(un, isubmirror)			\
	((un)->un_sm[(isubmirror)].sm_state &			\
	    (SMS_RUNNING | SMS_COMP_ERRED | SMS_COMP_RESYNC |	\
	    SMS_ATTACHED_RESYNC | SMS_OFFLINE_RESYNC))

/*
 * mm_submirror32_od and mm_unit32_od are used only for 32 bit old format
 */
typedef struct  mm_submirror32_od {	/* submirrors */
	mdkey_t		sm_key;
	dev32_t		sm_dev;
	sm_state_t	sm_state;
	sm_flags_t	sm_flags;
	caddr32_t	xx_sm_shared_by_blk;	/* really void *) */
	caddr32_t	xx_sm_shared_by_indx;	/* really void *) */
	caddr32_t	xx_sm_get_component_count;
	caddr32_t	xx_sm_get_bcss;	/* block count skip size */
	md_m_shared32_od_t sm_shared;	/* used for mirroring plain devices */
	int		sm_hsp_id;	/* used for mirroring plain devices */
	struct timeval32 sm_timestamp;	/* time of last state change */
} mm_submirror32_od_t;

typedef struct	mm_submirror {		/* submirrors */
	mdkey_t		sm_key;
	md_dev64_t	sm_dev;		/* 64 bit */
	sm_state_t	sm_state;
	sm_flags_t	sm_flags;
	md_m_shared_t	sm_shared;	/* used for mirroring plain devices */
	int		sm_hsp_id;	/* used for mirroring plain devices */
	md_timeval32_t	sm_timestamp;	/* time of last state change, 32 bit */
} mm_submirror_t;

typedef struct mm_unit32_od {
	mdc_unit32_od_t	c;			/* common stuff */

	int		un_last_read;		/* last submirror index read */
	uint_t		un_changecnt;
	ushort_t	un_nsm;			/* number of submirrors */
	mm_submirror32_od_t un_sm[NMIRROR];
	int		un_ovrlap_chn_flg;
	int		xx_un_ovrlap_chn_mx[2];	/* replaces mutex */
	ushort_t	xx_un_ovrlap_chn_cv;
	caddr32_t	xx_un_ovrlap_chn;
	mm_rd_opt_t	un_read_option;		/* mirror read option */
	mm_wr_opt_t	un_write_option;	/* mirror write option */
	mm_pass_num_t	un_pass_num;		/* resync pass number */
	/*
	 * following used to keep dirty bitmaps
	 */
	int		xx_un_resync_mx[2];	/* replaces mutex */
	ushort_t	xx_un_resync_cv;
	uint_t		un_resync_flg;
	uint_t		un_waiting_to_mark;
	uint_t		un_waiting_to_commit;
	caddr32_t	xx_un_outstanding_writes;	/* outstanding write */
	caddr32_t	xx_un_goingclean_bm;
	caddr32_t	xx_un_goingdirty_bm;
	caddr32_t	xx_un_dirty_bm;
	caddr32_t	xx_un_resync_bm;
	uint_t		un_rrd_blksize;	/* The blocksize of the dirty bits */
	uint_t		un_rrd_num;	/* The number of resync regions */
	mddb_recid_t	un_rr_dirty_recid;	/* resync region bm record id */
	/*
	 * following stuff is private to resync process
	 */
	int		un_rs_copysize;
	int		un_rs_dests;	/* destinations */
	daddr32_t	un_rs_resync_done;	/* used for percent done */
	daddr32_t	un_rs_resync_2_do;	/* user for percent done */
	int		un_rs_dropped_lock;
	caddr32_t	xx_un_rs_buffer;
	/*
	 * Incore elements in this old structure are no longer referenced by
	 * current 64 bit kernel.  Comment them out for maintenance purpose.
	 *
	 * 	mm_submirror_ic_t	un_smic[NMIRROR];
	 * 	kmutex_t		un_ovrlap_chn_mx;
	 * 	kcondvar_t		un_ovrlap_chn_cv;
	 * 	struct md_mps		*un_ovrlap_chn;
	 * 	kmutex_t		un_resync_mx;
	 * 	kcondvar_t		un_resync_cv;
	 * 	short			*un_outstanding_writes;
	 * 	uchar_t			*un_goingclean_bm;
	 * 	uchar_t			*un_goingdirty_bm;
	 * 	uchar_t			*un_dirty_bm;
	 * 	uchar_t			*un_resync_bm;
	 * 	char			*un_rs_buffer;
	 */
} mm_unit32_od_t;

typedef struct	mm_submirror_ic {
	intptr_t	(*sm_shared_by_blk)(md_dev64_t, void *,
				diskaddr_t, u_longlong_t *);
	intptr_t	(*sm_shared_by_indx)(md_dev64_t, void *, int);
	int		(*sm_get_component_count)(md_dev64_t, void *);
	int		(*sm_get_bcss)(md_dev64_t, void *, int, diskaddr_t *,
				size_t *, u_longlong_t *, u_longlong_t *);
} mm_submirror_ic_t;

typedef struct  mm_mirror_ic {
	kmutex_t	un_ovrlap_chn_mx;
	kcondvar_t	un_ovrlap_chn_cv;
	struct md_mps	*un_ovrlap_chn;
	kmutex_t	un_resync_mx;
	kcondvar_t	un_resync_cv;
	short		*un_outstanding_writes; /* outstanding write array */
	uchar_t		*un_goingclean_bm;
	uchar_t		*un_goingdirty_bm;
	uchar_t		*un_dirty_bm;
	uchar_t		*un_resync_bm;
	char		*un_rs_buffer;
}mm_mirror_ic_t;

typedef struct mm_unit {
	mdc_unit_t	c;			/* common stuff */

	int		un_last_read;		/* last submirror index read */
	uint_t		un_changecnt;
	ushort_t	un_nsm;			/* number of submirrors */
	mm_submirror_t	un_sm[NMIRROR];
	int		un_ovrlap_chn_flg;
	mm_rd_opt_t	un_read_option;		/* mirror read option */
	mm_wr_opt_t	un_write_option;	/* mirror write option */
	mm_pass_num_t	un_pass_num;		/* resync pass number */
	/*
	 * following used to keep dirty bitmaps
	 */
	uint_t		un_resync_flg;
	uint_t		un_waiting_to_mark;
	uint_t		un_waiting_to_commit;
	uint_t		un_rrd_blksize;	  /* The blocksize of the dirty bits */
	uint_t		un_rrd_num;	  /* The number of resync regions */
	mddb_recid_t	un_rr_dirty_recid; /* resync region bm db record id */
	/*
	 * following stuff is private to resync process
	 */
	int 		un_rs_copysize;
	int 		un_rs_dests;		/* destinations */
	diskaddr_t	un_rs_resync_done;	/* used for percent done */
	diskaddr_t	un_rs_resync_2_do;	/* user for percent done */
	int		un_rs_dropped_lock;
	/*
	 * Incore only elements
	 */
	mm_submirror_ic_t un_smic[NMIRROR];	/* NMIRROR elements array */
	mm_mirror_ic_t	un_mmic;
	kmutex_t	un_rrp_inflight_mx;
} mm_unit_t;

#define	un_ovrlap_chn_mx	un_mmic.un_ovrlap_chn_mx
#define	un_ovrlap_chn_cv	un_mmic.un_ovrlap_chn_cv
#define	un_ovrlap_chn		un_mmic.un_ovrlap_chn
#define	un_resync_mx		un_mmic.un_resync_mx
#define	un_resync_cv		un_mmic.un_resync_cv
#define	un_outstanding_writes	un_mmic.un_outstanding_writes
#define	un_goingclean_bm	un_mmic.un_goingclean_bm
#define	un_goingdirty_bm	un_mmic.un_goingdirty_bm
#define	un_dirty_bm		un_mmic.un_dirty_bm
#define	un_resync_bm		un_mmic.un_resync_bm
#define	un_rs_buffer		un_mmic.un_rs_buffer


#define	MM_RF_GATECLOSED	0x0001
#define	MM_RF_COMMIT_NEEDED	0x0002
#define	MM_RF_COMMITING		0x0004
#define	MM_RF_STALL_CLEAN	(MM_RF_COMMITING | \
				    MM_RF_COMMIT_NEEDED | \
				    MM_RF_GATECLOSED)

typedef struct err_comp {
	struct err_comp	*ec_next;
	int		ec_smi;
	int		ec_ci;
} err_comp_t;

extern	int	md_min_rr_size;
extern	int	md_def_num_rr;

/* Optimized resync records controllers */
#define	MD_MIN_RR_SIZE		(md_min_rr_size)
#define	MD_DEF_NUM_RR		(md_def_num_rr)
#define	MD_MAX_NUM_RR		(4192*NBBY - sizeof (struct optim_resync))

/* default resync buffer size */
#define	MD_DEF_RESYNC_BUF_SIZE	(128)

/* Structure for optimized resync records */
#define	OR_MAGIC	0xFECA	/* Only missing the L */
typedef struct optim_resync {
	uint_t	or_revision;
	uint_t	or_magic;
	uint_t	or_blksize;
	uint_t	or_num;
	uchar_t	or_rr[1];
} optim_resync_t;

/* Type 2 for mirror records */
#define	MIRROR_REC	1
#define	RESYNC_REC	2

#ifdef _KERNEL

#define	NO_SUBMIRRORS	(0)
#define	ALL_SUBMIRRORS	(0xFFF)
#define	SMI2BIT(smi)	(1 << (smi))

/* For use with mirror_other_sources() */
#define	WHOLE_SM	(-1)

#define	BLK_TO_RR(i, b, un)  {\
	(i) = ((b) / ((un))->un_rrd_blksize); \
	if ((i) > ((un))->un_rrd_num) \
		{ panic("md: BLK_TO_RR"); } \
}

#define	RR_TO_BLK(b, i, un) \
	(b) = ((i) * ((un))->un_rrd_blksize)

#define	IS_GOING_DIRTY(i, un)	(isset((un)->un_goingdirty_bm, (i)))
#define	CLR_GOING_DIRTY(i, un)	(clrbit((un)->un_goingdirty_bm, (i)))
#define	SET_GOING_DIRTY(i, un)	(setbit((un)->un_goingdirty_bm, (i)))

#define	IS_GOING_CLEAN(i, un)	(isset((un)->un_goingclean_bm, (i)))
#define	CLR_GOING_CLEAN(i, un)	(clrbit((un)->un_goingclean_bm, (i)))
#define	SET_GOING_CLEAN(i, un)	(setbit((un)->un_goingclean_bm, (i)))

#define	IS_REGION_DIRTY(i, un)	(isset((un)->un_dirty_bm, (i)))
#define	CLR_REGION_DIRTY(i, un)	(clrbit((un)->un_dirty_bm, (i)))
#define	SET_REGION_DIRTY(i, un)	(setbit((un)->un_dirty_bm, (i)))

#define	IS_KEEPDIRTY(i, un)	(isset((un)->un_resync_bm, (i)))
#define	CLR_KEEPDIRTY(i, un)	(clrbit((un)->un_resync_bm, (i)))


typedef struct md_mps {
	DAEMON_QUEUE
	buf_t		*ps_bp;
	mm_unit_t	*ps_un;
	mdi_unit_t	*ps_ui;
	uint_t		 ps_childbflags;
	caddr_t		 ps_addr;
	diskaddr_t	 ps_firstblk;
	diskaddr_t	 ps_lastblk;
	uint_t		 ps_flags;
	uint_t		 ps_allfrom_sm;		/* entire read came from here */
	uint_t		 ps_writable_sm;
	uint_t		 ps_current_sm;
	uint_t		 ps_active_cnt;
	int		 ps_frags;
	uint_t		 ps_changecnt;
	struct md_mps	*ps_ovrlap_next;
	struct md_mps	*ps_ovrlap_prev;
	void		 (*ps_call)();
	kmutex_t	 ps_mx;
} md_mps_t;

#define	MD_MPS_ON_OVERLAP	0x0001
#define	MD_MPS_ERROR		0x0002
#define	MD_MPS_WRITE_AFTER_READ	0x0004
#define	MD_MPS_WOW		0x0008
#define	MD_MPS_DONTFREE		0x0010
#define	MD_MPS_DONE		0x0020
#define	MD_MPS_MAPPED		0x0040		/* re: MD_STR_MAPPED	*/
#define	MD_MPS_NOBLOCK		0x0080		/* re: MD_NOBLOCK	*/

#define	MPS_FREE(kc, ps)			\
	if ((ps)->ps_flags & MD_MPS_DONTFREE)	\
		(ps)->ps_flags |= MD_MPS_DONE;	\
	else					\
		kmem_cache_free((kc), (ps));

typedef struct md_mcs {
	DAEMON_QUEUE
	md_mps_t	*cs_ps;
	minor_t		 cs_mdunit;
	/* Add new structure members HERE!! */
	buf_t		 cs_buf;
	/*  DO NOT add struture members here; cs_buf is dynamically sized */
} md_mcs_t;

/*
 * Write-On-Write handling.
 *   flags for md_mirror_wow_flg
 *   structure for quing copy-writes
 *   macros for relative locating of header and buffer
 */
#define	WOW_DISABLE	0x0001	/* turn off WOW detection */
#define	WOW_PHYS_ENABLE	0x0020	/* turn on WOW for PHYS */
#define	WOW_LOGIT	0x0002	/* log non-disabled WOW detections */
#define	WOW_NOCOPY	0x0004	/* repeat normal write on WOW detection */

typedef	struct wowhdr {
	DAEMON_QUEUE
	md_mps_t	*wow_ps;
	int		wow_offset;
} wowhdr_t;

#define	WOWBUF_HDR(wowbuf)	((void *)(wowbuf-sizeof (wowhdr_t)))
#define	WOWHDR_BUF(wowhdr)	((char *)wowhdr+sizeof (wowhdr_t))


/* Externals from mirror.c */
extern mddb_recid_t	mirror_get_sm_unit(md_dev64_t);
extern void		mirror_release_sm_unit(md_dev64_t);

extern void		mirror_set_sm_state(mm_submirror_t *,
				mm_submirror_ic_t *, sm_state_t, int);

extern void		mirror_commit(mm_unit_t *, int, mddb_recid_t *);
extern int		poke_hotspares(void);
extern void		build_submirror(mm_unit_t *, int, int);
extern int		mirror_build_incore(mm_unit_t *, int);
extern void		reset_mirror(mm_unit_t *, minor_t, int);
extern int		mirror_internal_open(minor_t, int, int, int);
extern int		mirror_internal_close(minor_t, int, int);
extern void		set_sm_comp_state(mm_unit_t *, int, int, int,
			    mddb_recid_t *);
extern int		mirror_other_sources(mm_unit_t *, int, int, int);
extern void		md_mirror_strategy(buf_t *, int, void *);

/* Externals from mirror_ioctl.c */
extern void		reset_comp_states(mm_submirror_t *,
			    mm_submirror_ic_t *);
extern int		mirror_grow_unit(mm_unit_t *un, md_error_t *ep);
extern int		md_mirror_ioctl(dev_t dev, int cmd, void *data,
			    int mode, IOLOCK *lockp);
/* rename named service functions */
md_ren_list_svc_t	mirror_rename_listkids;
md_ren_svc_t		mirror_rename_check;
md_ren_roleswap_svc_t	mirror_renexch_update_kids;
md_ren_roleswap_svc_t	mirror_exchange_parent_update_to;
md_ren_roleswap_svc_t	mirror_exchange_self_update_from_down;

/* Externals from mirror_resync.c */
extern int		unit_setup_resync(mm_unit_t *, int);
extern int		mirror_resync_unit(minor_t mnum, md_resync_ioctl_t *ri,
			    md_error_t *ep);
extern int		mirror_ioctl_resync(md_resync_ioctl_t *p);
extern int		mirror_mark_resync_region(mm_unit_t *, diskaddr_t,
				diskaddr_t);
extern void		resync_start_timeout(set_t setno);
extern int		mirror_resize_resync_regions(mm_unit_t *, diskaddr_t);
extern int		mirror_add_resync_regions(mm_unit_t *, diskaddr_t);
extern int		mirror_probedevs(md_probedev_t *, IOLOCK *);
#endif	/* _KERNEL */

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_MD_MIRROR_H */
