/*
 * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef	_SYS_FIBRE_CHANNEL_ULP_FCPVAR_H
#define	_SYS_FIBRE_CHANNEL_ULP_FCPVAR_H

#pragma ident	"@(#)fcpvar.h	1.7	00/08/18 SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#include <sys/types.h>

/*
 * Stuff to be defined in fc_ulpif.h FIXIT
 */
#define	PORT_DEVICE_CREATE	0x40

#define	SCMD_REPORT_LUN		0xa0	/* SCSI cmd to report on LUNs */

#define	FC4_SCSI_FCP		0x08	/* our (SCSI) FC4 type number */

#define	SSFCP_QUEUE_DELAY	(4)
#define	SSFCP_FAILED_DELAY	20
#define	SSFCP_RESET_DELAY	3	/* target reset dealy of 3 secs */
#define	SSFCP_OFFLINE_DELAY	20	/* Wait for 20 seconds */

/*
 * Highest possible timeout value to indicate
 * the watch thread to return the I/O
 */
#define	SSFCP_INVALID_TIMEOUT	(0xFFFFFFFF)

/*
 * Events supported by soc+ HBA driver
 */
#define	FCAL_INSERT_EVENT	"SUNW,sf:DEVICE-INSERTION.1"
#define	FCAL_REMOVE_EVENT	"SUNW,sf:DEVICE-REMOVAL.1"

/*
 * All the stuff above needs to move intp appropriate header files.
 */

#define	SSFCP_NUM_HASH			128

#define	SSFCP_HASH(x)	((x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+x[7]) & \
				(SSFCP_NUM_HASH-1))

#define	FCP_STATEC_MASK	(FC_STATE_OFFLINE | FC_STATE_ONLINE | \
			FC_STATE_LOOP | FC_STATE_NAMESERVICE | \
			FC_STATE_RESET | FC_STATE_RESET_REQUESTED | \
			FC_STATE_LIP | FC_STATE_DEVICE_CHANGE)

#define	PKT_PRIV_SIZE			2

#ifdef	KSTATS_CODE
/*
 * ssfcp_stats : Statistics provided for fcp.
 */
struct ssfcp_stats {
	uint_t  version;		/* version of this struct */
	uint_t  lip_count;		/* lips forced by fcp */
	uint_t  link_reset_count; 	/* lip failures, ie, no ONLINE */
					/* response after forcing lip */
	uint_t  ncmds;			/* outstanding commands */
	uint_t  throttle_limit;		/* current throttle limit */
	char	drvr_name[MAXNAMELEN];	/* Name of driver, NULL term. */
};
#endif

/*
 * the per-instance port data structure
 */
struct ssfcp_port {
	kmutex_t		ssfcp_mutex; 	/* protect whole struct */
	struct ssfcp_port	*ssfcp_next; 	/* link to next in list */
	struct	ssfcp_ipkt	*ssfcp_ipkt_list;

	volatile int		ssfcp_tmp_cnt; 	/* used for dev cnt */
	volatile uint32_t	ssfcp_state; 	/* port state bitmap */

	uint32_t		ssfcpp_top;
	uint32_t		ssfcpp_sid;

	volatile uint32_t	ssfcpp_state; 	/* port state: fctl.h */
	uint32_t		ssfcp_dev_cnt;

	struct ssfcp_reset_elem	*ssfcp_reset_list;
	volatile uint32_t	ssfcp_link_cnt;
	int			ssfcp_deadline;

	la_wwn_t		ssfcpp_nwwn;
	la_wwn_t		ssfcpp_pwwn;

	opaque_t		*ssfcpp_handle;
	struct kmem_cache	*ssfcp_pkt_cache;

	kmutex_t		ssfcp_cmd_mutex;
	uint32_t		ssfcp_ncmds; 		/* # cmds outstanding */
	struct ssfcp_pkt	*ssfcp_pkt_head;
	struct ssfcp_pkt	*ssfcp_pkt_tail;

	struct ssfcp_tgt	*ssfcp_tgt_head;
	struct ssfcp_tgt	*ssfcp_tgt_tail;

	/* hotplugging */
	kmutex_t		ssfcp_hp_mutex;
	struct  ssfcp_hp_elem   *ssfcp_hp_elem_head;
	struct  ssfcp_hp_elem   *ssfcp_hp_elem_tail;
	uint32_t		ssfcp_hp_initted;
	volatile int		ssfcp_ipkt_cnt;
	volatile int		ssfcp_hp_nele;
	kcondvar_t		ssfcp_hp_cv;

	uint32_t		ssfcpp_instance;
	uint32_t		ssfcpp_max_exch;
	fc_reset_action_t	ssfcpp_cmds_aborted;
	fc_dma_behavior_t	ssfcpp_cmds_dma_flags;
	fc_fcp_dma_t		ssfcpp_fcp_dma;
	uint32_t		ssfcpp_priv_pkt_len;

	struct modlinkage	ssfcpp_linkage;
	ddi_dma_attr_t		ssfcpp_dma_attr;
	ddi_device_acc_attr_t	ssfcpp_dma_acc_attr;
	struct scsi_hba_tran 	*ssfcp_tran; 		/* for SCSA */
	dev_info_t		*ssfcpp_dip;
	struct scsi_reset_notify_entry	*ssfcp_reset_notify_listf;

	/* for framework event management */
	ndi_event_definition_t	*ssfcp_event_defs;
	ndi_event_hdl_t		ssfcp_event_hdl;
	ndi_events_t		ssfcp_events;

	/* state change waiting */
	int			ssfcp_statec_wait;
	kcondvar_t		ssfcp_statec_cv;
	int			ssfcp_take_core;	/* bool */

	callb_cpr_t		ssfcp_cpr_info;

	/* hash lists of targets/LUNs attached to this port */
	struct ssfcp_tgt	*ssfcp_wwn_list[SSFCP_NUM_HASH];
#ifdef	KSTATS_CODE
	kstat_t			ssfcp_kstat;
#endif
};

/*
 * ssfcp_state definitions.
 */
#define	SSFCP_STATE_INIT		0x0001
#define	SSFCP_STATE_OFFLINE		0x0002
#define	SSFCP_STATE_ONLINE		0x0004
#define	SSFCP_STATE_SUSPENDED		0x0008
#define	SSFCP_STATE_POWER_DOWN		0x0010
#define	SSFCP_STATE_ONLINING		0x0020
#define	SSFCP_STATE_DETACHING		0x0040
#define	SSFCP_STATE_IN_WATCHDOG		0x0080

#define	SSFCP_MAX_DEVICES		127

#define	SSFCP_DAEMON_SUSPENDED(pptr)\
	((pptr)->ssfcp_cpr_info.cc_events & CALLB_CPR_START)

/* To remember that dip was allocated for a lun on this target. */

#define	SSFCP_DEVICE_CREATED		0x1

#define	SSFCP_EVENT_TAG_INSERT		0
#define	SSFCP_EVENT_TAG_REMOVE		1


/*
 * FCP packet
 */
struct ssfcp_pkt {
	struct ssfcp_pkt		*cmd_forw;
	struct ssfcp_pkt		*cmd_back;
	struct ssfcp_pkt		*cmd_next;
	struct buf			*cmd_bp;
	struct scsi_pkt			*cmd_pkt;
	struct fc_packet		*cmd_fp_pkt;
	struct fcp_cmd			cmd_fcp_cmd;
	uint_t				cmd_scblen;
	uint_t				cmd_state;
	uint_t				cmd_flags;
	uint_t				cmd_privlen;
	uint_t				cmd_dmacount;
	uint_t				cmd_timeout;
	uint64_t			cmd_pkt_private[PKT_PRIV_SIZE];
	char				cmd_fcp_rsp[FCP_MAX_RSP_IU_SIZE];
	struct scsi_arq_status		cmd_fcp_sense;
	struct scsi_pkt			cmd_scsi_pkt;
	struct fc_packet		cmd_fc_packet;
};

/*
 * ssfcp_ipkt : Packet for internal commands.
 */
struct ssfcp_ipkt {
	struct ssfcp_port		*ipkt_port;
	struct ssfcp_tgt		*ipkt_tgt;
	struct ssfcp_lun		*ipkt_lun;
	struct ssfcp_ipkt		*ipkt_next;
	struct ssfcp_ipkt		*ipkt_prev;
	struct fc_packet		*ipkt_fpkt;
	uint32_t			ipkt_lun_state;
	uint32_t			ipkt_restart;
	uint32_t			ipkt_link_cnt;
	uint32_t			ipkt_cmdlen;
	uint32_t			ipkt_resplen;
	uint32_t			ipkt_datalen;
	uint32_t			ipkt_retries;
	uint32_t			ipkt_change_cnt;
	int				ipkt_nodma;
	uchar_t				ipkt_opcode;
	struct fc_packet		ipkt_fc_packet;
};

/*
 * cmd_state definations
 */
#define	SSFCP_PKT_IDLE			0x1
#define	SSFCP_PKT_ISSUED		0x2
#define	SSFCP_PKT_ABORTING		0x3

/*
 * These are the defined cmd_flags for this structure.
 */
#define	CFLAG_DMAVALID		0x0010	/* dma mapping valid */
#define	CFLAG_DMASEND		0x0020	/* data is going 'out' */
#define	CFLAG_CMDIOPB		0x0040	/* this is an 'iopb' packet */
#define	CFLAG_NOWAIT		0x0080	/* Don't wait for DMA resource */
#define	CFLAG_CDBEXTERN		0x0100	/* cdb kmem_alloc'd */
#define	CFLAG_SCBEXTERN		0x0200	/* scb kmem_alloc'd */
#define	CFLAG_FREE		0x0400	/* packet is on free list */
#define	CFLAG_PRIVEXTERN	0x1000	/* target private was */
#define	CFLAG_IN_QUEUE		0x2000	/* command in fcp queue */
#define	CFLAG_RESET_OCCURED	0x4000	/* Reset occured on the SCSI address */

/*
 * Per target struct
 */
struct ssfcp_tgt {
	struct ssfcp_tgt	*tgt_next;
	struct ssfcp_port	*tgt_port;
	uint32_t		tgt_state;
	uint32_t		tgt_node_state;
	kmutex_t		tgt_mutex;
	struct ssfcp_lun	*tgt_lun;
	opaque_t		tgt_fca_dev;
	uint_t			tgt_lun_cnt;
	uint_t			tgt_tmp_cnt;
	opaque_t		tgt_pd_handle;
	la_wwn_t		tgt_node_wwn;
	la_wwn_t		tgt_port_wwn;
	uint32_t		tgt_d_id;
	uint32_t		tgt_hard_addr;
	uchar_t			tgt_device_created;
	uchar_t			tgt_report_lun_cnt;
	uint32_t		tgt_change_cnt;
	timeout_id_t		tgt_tid;
};

/*
 * Target State
 */
#define	SSFCP_TGT_INIT			0x01
#define	SSFCP_TGT_BUSY			0x02
#define	SSFCP_TGT_MARK			0x04
#define	SSFCP_TGT_OFFLINE		0x08
#define	SSFCP_TGT_ORPHAN		0x80


/*
 * Target node states (applicable to LUNs behind the target)
 */
#define	SSFCP_TGT_NODE_NONE		0x00	/* No node exists */
#define	SSFCP_TGT_NODE_ON_DEMAND	0x01	/* create only upon request */
#define	SSFCP_TGT_NODE_PRESENT		0x02	/* Node exists; rediscover it */


#define	SSFCP_NO_CHANGE			0x1
#define	SSFCP_LINK_CHANGE		0x2
#define	SSFCP_DEV_CHANGE		0x3

/* hotplug event struct */
struct ssfcp_hp_event {
	int (*callback)();
	void *arg;
};

/* per lun */
struct ssfcp_lun {
	kmutex_t		lun_mutex;
	uchar_t			lun_string[FCP_LUN_SIZE];
	struct ssfcp_pkt	*lun_pkt_head;
	struct ssfcp_pkt	*lun_pkt_tail;
	dev_info_t		*lun_dip;
	struct ssfcp_tgt	*lun_tgt;	/* back ptr to our tgt */
	uint_t			lun_state;
	uchar_t			lun_type;
	uchar_t			lun_tgt_count;
	uint16_t		lun_num;
	struct ssfcp_lun	*lun_next;
	struct ssfcp_lun	*lun_prev;
	struct scsi_hba_tran	*lun_tran;
	struct ssfcp_hp_event	ssfcp_insert_ev;
	struct ssfcp_hp_event	ssfcp_remove_ev;
};

/*
 * Lun State -- these have the same values as the target states so
 * that they can be interchanged (in cases where the same state occurs
 * for both targets and luns)
 */

#define	SSFCP_LUN_INIT			SSFCP_TGT_INIT
#define	SSFCP_LUN_BUSY			SSFCP_TGT_BUSY
#define	SSFCP_LUN_MARK			SSFCP_TGT_MARK
#define	SSFCP_LUN_OFFLINE		SSFCP_TGT_OFFLINE
#define	SSFCP_SCSI_LUN_TGT_INIT		0x20	/* target/LUNs all inited */

/*
 * Report Lun Format
 */
struct fcp_reportlun_resp {
	uint32_t	num_lun;	/* num LUNs * 8 */
	uint32_t	reserved;
	longlong_t	lun_string[1];
};

struct fcp_onelun_resp {
	uint32_t	num_lun;	/* num LUNs * 8 */
	uint32_t	reserved;
	longlong_t	lun_string;
};


struct ssfcp_hp_elem {
	struct ssfcp_hp_elem	*next;
	struct ssfcp_lun	*lun;
	dev_info_t		*dip;
	int 			what;
	int 			flags;
	int			link_cnt;
};

struct ssfcp_reset_elem {
	struct ssfcp_reset_elem	*next;
	struct ssfcp_tgt	*tgt;
	clock_t			timeout;
	uint_t			link_cnt;
};

#define	ADDR2SSFCP(ap)	(struct ssfcp_port *) \
				((ap)->a_hba_tran->tran_hba_private)
#define	ADDR2LUN(ap)	(struct ssfcp_lun *)((ap)->a_hba_tran->tran_tgt_private)
#define	CMD2PKT(cmd)	((cmd)->cmd_pkt)
#define	PKT2CMD(pkt)	((struct ssfcp_pkt *)pkt->pkt_ha_private)

/*
 * timeout values
 */
#define	SSFCP_ELS_TIMEOUT		20 	/* 20 seconds */
#define	SSFCP_SCSI_CMD_TIMEOUT		25	/* 30 seconds */
#define	SSFCP_POLL_TIMEOUT		60	/* 60 seconds */
#define	SSFCP_TIMEOUT_DELTA		2	/* 2 seconds */
#define	SSFCP_ICMD_DEADLINE		120	/* 60 seconds */
#define	SSFCP_MAX_RETRIES		4


#if !defined(lint)
_NOTE(MUTEX_PROTECTS_DATA(ssfcp_port::ssfcp_mutex,
    ssfcp_port::ssfcp_state
    ssfcp_port::ssfcp_next ssfcp_port::ssfcp_wwn_list
    ssfcp_port::ssfcp_link_cnt ssfcp_port::ssfcp_reset_list
    ssfcp_port::ssfcp_tmp_cnt ssfcp_port::ssfcp_ipkt_list
    ssfcp_tgt::tgt_next))

_NOTE(MUTEX_PROTECTS_DATA(ssfcp_port::ssfcp_cmd_mutex,
    ssfcp_port::ssfcp_pkt_head ssfcp_port::ssfcp_pkt_tail
    ssfcp_port::ssfcp_tgt_head ssfcp_port::ssfcp_tgt_tail
    ssfcp_port::ssfcp_ncmds))

_NOTE(MUTEX_PROTECTS_DATA(ssfcp_port::ssfcp_hp_mutex,
    ssfcp_port::ssfcp_hp_initted ssfcp_port::ssfcp_hp_elem_head
    ssfcp_port::ssfcp_hp_elem_tail ssfcp_port::ssfcp_hp_nele))

_NOTE(MUTEX_PROTECTS_DATA(ssfcp_tgt::tgt_mutex,
    ssfcp_tgt::tgt_state  ssfcp_tgt::tgt_device_created
    ssfcp_tgt::tgt_change_cnt ssfcp_tgt::tgt_tid
    ssfcp_tgt::tgt_pd_handle ssfcp_tgt::tgt_tmp_cnt
    ssfcp_lun::lun_next ssfcp_lun::lun_state))

_NOTE(LOCK_ORDER(ssfcp_port::ssfcp_mutex ssfcp_tgt::tgt_mutex))
_NOTE(LOCK_ORDER(ssfcp_tgt::tgt_mutex ssfcp_lun::lun_mutex))

_NOTE(MUTEX_PROTECTS_DATA(ssfcp_lun::lun_mutex,
    ssfcp_lun::lun_pkt_head ssfcp_lun::lun_pkt_tail))

_NOTE(DATA_READABLE_WITHOUT_LOCK( ssfcp_tgt::tgt_state)) 
_NOTE(DATA_READABLE_WITHOUT_LOCK( ssfcp_tgt::tgt_pd_handle)) 

_NOTE(DATA_READABLE_WITHOUT_LOCK(ssfcp_tgt::tgt_tid))


_NOTE(SCHEME_PROTECTS_DATA("Safe Data",
    ssfcp_port::ssfcpp_dma_attr ssfcp_port::ssfcpp_dma_acc_attr
    ssfcp_port::ssfcpp_fcp_dma ssfcp_port::ssfcp_tran
    ssfcp_port::ssfcp_events ssfcp_port::ssfcp_event_defs
    ssfcp_port::ssfcp_pkt_cache ssfcp_port::ssfcpp_dip ssfcp_port::ssfcpp_state
    ssfcp_port::ssfcpp_cmds_aborted ssfcp_port::ssfcpp_cmds_dma_flags
    ssfcp_port::ssfcpp_handle ssfcp_port::ssfcpp_instance
    ssfcp_port::ssfcpp_linkage ssfcp_port::ssfcpp_max_exch
    ssfcp_port::ssfcpp_priv_pkt_len ssfcp_port::ssfcpp_sid
    ssfcp_port::ssfcpp_top ssfcp_tgt::tgt_d_id ssfcp_port::ssfcp_deadline
    ssfcp_tgt::tgt_hard_addr ssfcp_tgt::tgt_lun_cnt ssfcp_tgt::tgt_port
    ssfcp_lun::lun_num ssfcp_lun::lun_tgt ssfcp_lun::lun_dip 
    ssfcp_lun::lun_type ssfcp_hp_elem::lun ssfcp_hp_elem::flags
    ssfcp_hp_elem::dip ssfcp_hp_elem::what ssfcp_reset_elem ssfcp_pkt
    ssfcp_ipkt scsi_pkt scsi_arq_status scsi_device scsi_hba_tran scsi_cdb))
#endif  /* lint */

#define	SSFCP_CP_IN(s, d, handle, len)	(ddi_rep_get8((handle), \
					(uint8_t *)(d), (uint8_t *)(s), \
					(len), DDI_DEV_AUTOINCR))

#define	SSFCP_CP_OUT(s, d, handle, len)	(ddi_rep_put8((handle), \
					(uint8_t *)(s), (uint8_t *)(d), \
					(len), DDI_DEV_AUTOINCR))

#define	SSFCP_ONLINE		0x1
#define	SSFCP_OFFLINE		0x2

#define	SSFCP_IDLE		0x0
#define	SSFCP_OPEN		0x1

#define	LFA(x)		(x & 0xFFFF00)
#define	FCP_SET		1
#define	FCP_RESET	0

/* init() and attach() wait timeout values (in usecs) */
#define	SSFCP_INIT_WAIT_TIMEOUT		60000000	/* 60 seconds */
#define	SSFCP_ATTACH_WAIT_TIMEOUT	10000000	/* 10 seconds */

#ifdef	TRUE
#undef	TRUE
#endif
#define	TRUE			1

#ifdef	FALSE
#undef	FALSE
#endif
#define	FALSE			0

#define	UNDEFINED		-1

/* for softstate */
#define	SSFCP_INIT_ITEMS	5

/*
 * debugging stuff
 */
#ifdef DEBUG

#ifndef	SSFCP_DEBUG_DEFAULT_VAL
#define	SSFCP_DEBUG_DEFAULT_VAL		1
#endif

extern int	ssfcp_debug;

#include <sys/debug.h>


#define	SSFCP_DEBUG(level, stmnt) \
	if (ssfcp_debug >= (level)) ssfcp_log stmnt

/* assume int is large enough for our debugging bitmap purposes */
extern int			ssfcp_debug_flag;

/* bitmap debug values */
#define	SSFCP_MODUNLOAD_DEBUG		0x1	/* to debug modunload */
#define	SSFCP_NO_LINKRESET_DEBUG	0x2	/* to disallow linkreset */
#define	SSFCP_ABORT_DEBUG		0x4	/* do just one abort */

/* for checking the debug flag for bitmap values */
#define	SSFCP_TEST_FLAG(f)		(ssfcp_debug_flag & (f))

#else	/* !DEBUG */

#define	SSFCP_DEBUG(level, stmnt)	/* do nothing */

#endif	/* !DEBUG */

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_FIBRE_CHANNEL_ULP_FCPVAR_H */
