/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
 */

#ifndef	_CPQARY3_H
#define	_CPQARY3_H

#include <sys/types.h>
#include <sys/pci.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/map.h>
#include <sys/modctl.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
#include <sys/stat.h>
#include <sys/scsi/scsi.h>
#include <sys/devops.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

#include <cpqary3_ciss.h>
#include <cpqary3_bd.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 *	Ioctl Commands
 */
#define	CPQARY3_IOCTL_CMD		('c' << 4)
#define	CPQARY3_IOCTL_DRIVER_INFO	CPQARY3_IOCTL_CMD | 0x01
#define	CPQARY3_IOCTL_CTLR_INFO		CPQARY3_IOCTL_CMD | 0x02
#define	CPQARY3_IOCTL_BMIC_PASS		CPQARY3_IOCTL_CMD | 0x04
#define	CPQARY3_IOCTL_SCSI_PASS		CPQARY3_IOCTL_CMD | 0x08

/* Driver Revision : Used in Ioctl */
#define	CPQARY3_MINOR_REV_NO	00
#define	CPQARY3_MAJOR_REV_NO	01
#define	CPQARY3_REV_DATE	05
#define	CPQARY3_REV_MONTH	04
#define	CPQARY3_REV_YEAR	2001

/* Some Useful definations */
#define	CPQARY3_FAILURE		0
#define	CPQARY3_SUCCESS		1
#define	CPQARY3_SENT		2
#define	CPQARY3_SUBMITTED	3
#define	CPQARY3_NO_SIG		4

#define	CPQARY3_TRUE		1
#define	CPQARY3_FALSE		0

#define	CTLR_SCSI_ID		7
#define	CPQARY3_LD_FAILED	1
/*
 * Defines for cleanup in cpqary3_attach and cpqary3_detach.
 */
#define	CPQARY3_HBA_TRAN_ALLOC_DONE	0x0001
#define	CPQARY3_HBA_TRAN_ATTACH_DONE	0x0002
#define	CPQARY3_CTLR_CONFIG_DONE	0x0004
#define	CPQARY3_INTR_HDLR_SET		0x0008
#define	CPQARY3_CREATE_MINOR_NODE	0x0010
#define	CPQARY3_SOFTSTATE_ALLOC_DONE	0x0020
#define	CPQARY3_MUTEX_INIT_DONE		0x0040
#define	CPQARY3_TICK_TMOUT_REGD		0x0080
#define	CPQARY3_MEM_MAPPED		0x0100
#define	CPQARY3_SW_INTR_HDLR_SET	0x0200
#define	CPQARY3_SW_MUTEX_INIT_DONE	0x0400
#define	CPQARY3_NOE_INIT_DONE		0x0800

#define	CPQARY3_CLEAN_ALL		0x0FFF

#define	CPQARY3_TICKTMOUT_VALUE		180000000    /* 180 seconds */

/*
 * Defines for Maximum and Default Settings.
 */

#define	MAX_LOGDRV		64	/* Max supported Logical Drivers */
#define	MAX_CTLRS		8	/* Max supported Controllers */
#define	MAX_TAPE		28
/*
 * NOTE: When changing the below two entries, Max SG count in cpqary3_ciss.h
 * should also be changed.
 */
/* SG */
#define	MAX_PERF_SG_CNT		64	/* Maximum S/G in performant mode */
#define	CPQARY3_SG_CNT		30	/* minimum S/G in simple mode */
#define	CPQARY3_PERF_SG_CNT	31	/* minimum S/G for performant mode */
/* SG */


#define	CPQARY3_MAX_TGT		(MAX_LOGDRV + MAX_TAPE + 1)

/*
 * SCSI Capabilities Related IDs
 */
#define	CPQARY3_CAP_DISCON_ENABLED		0x01
#define	CPQARY3_CAP_SYNC_ENABLED		0x02
#define	CPQARY3_CAP_WIDE_XFER_ENABLED		0x04
#define	CPQARY3_CAP_ARQ_ENABLED			0x08
#define	CPQARY3_CAP_TAG_QING_ENABLED		0x10
#define	CPQARY3_CAP_TAG_QING_SUPP		0x20
#define	CPQARY3_CAP_UNTAG_DRV_QING_ENABLED	0x40

/*
 * Defines for HBA
 */
#define	CAP_NOT_DEFINED		-1
#define	CAP_CHG_NOT_ALLOWED	0
#define	CAP_CHG_SUCCESS		1

/*
 * Macros for Data Access
 */

/* SCSI Addr to Per Controller */
#define	SA2CTLR(saddr)	((cpqary3_t *)((saddr)->a_hba_tran->tran_hba_private))
#define	SA2TGT(sa)	(sa)->a_target	/* SCSI Addr to Target ID */
#define	SD2TGT(sd)	(sd)->sd_address.a_target /* SCSI Dev to Target ID */
#define	SD2LUN(sd)	(sd)->sd_address.a_lun	/* SCSI Dev to Lun */
#define	SD2SA(sd)	((sd)->sd_address)	/* SCSI Dev to SCSI Addr */

/* SCSI Dev to Per Controller */
#define	SD2CTLR(sd)	\
	((cpqary3_t *)sd->sd_address.a_hba_tran->tran_hba_private)

#define	PKT2PVTPKT(sp)  	((cpqary3_pkt_t *)((sp)->pkt_ha_private))
#define	PVTPKT2MEM(p)		((cpqary3_cmdpvt_t *)p->memp)
#define	MEM2CMD(m)		((CommandList_t *)m->cmdlist_memaddr)
#define	SP2CMD(sp)		MEM2CMD(PVTPKT2MEM(PKT2PVTPKT(sp)))
#define	CTLR2MEMLISTP(ctlr)	((cpqary3_cmdmemlist_t *)ctlr->cmdmemlistp)
#define	MEM2PVTPKT(m)		((cpqary3_pkt_t *)m->pvt_pkt)
#define	MEM2DRVPVT(m)		((cpqary3_private_t *)m->driverdata)
#define	TAG2MEM(ctlr, tag)	\
	((cpqary3_cmdpvt_t *)(CTLR2MEMLISTP(ctlr)->pool[tag]))

/* MACROS */
#define	CPQARY3_MIN(x, y)    		(x < y ? x : y)
#define	CPQARY3_SWAP(val)   		((val >> 8) | ((val & 0xff) << 8))
#define	RETURN_VOID_IF_NULL(x)  	if (NULL == x) return
#define	RETURN_NULL_IF_NULL(x)  	if (NULL == x) return (NULL)
#define	RETURN_FAILURE_IF_NULL(x)	if (NULL == x) return (CPQARY3_FAILURE)

/*
 * Macros for memory allocation/deallocations
 */
#define	MEM_ZALLOC(x)		kmem_zalloc(x, KM_NOSLEEP)
#define	MEM_SFREE(x, y)		if (x) kmem_free((void*)x, y)

/*
 * Convenient macros for reading/writing Configuration table registers
 */
#define	DDI_GET8(ctlr, regp)	 		\
	ddi_get8((ctlr)->ct_handle, (uint8_t *)(regp))
#define	DDI_PUT8(ctlr, regp, value)		\
	ddi_put8((ctlr)->ct_handle, (uint8_t *)(regp), (value))
#define	DDI_GET16(ctlr, regp)	 		\
	ddi_get16((ctlr)->ct_handle, (uint16_t *)(regp))
#define	DDI_PUT16(ctlr, regp, value)	\
	ddi_put16((ctlr)->ct_handle, (uint16_t *)(regp), (value))
#define	DDI_GET32(ctlr, regp)	 		\
	ddi_get32((ctlr)->ct_handle, (uint32_t *)(regp))
#define	DDI_PUT32(ctlr, regp, value) 	\
	ddi_put32((ctlr)->ct_handle, (uint32_t *)(regp), (value))
			/* PERF */
#define	DDI_PUT32_CP(ctlr, regp, value)   \
	ddi_put32((ctlr)->cp_handle, (uint32_t *)(regp), (value))
			/* PERF */

#define	CPQARY3_BUFFER_ERROR_CLEAR	0x0	/* to be used with bioerror */
#define	CPQARY3_DMA_NO_CALLBACK		0x0	/* to be used with DMA calls */
#define	CPQARY3_DMA_ALLOC_HANDLE_DONE	0x01
#define	CPQARY3_DMA_ALLOC_MEM_DONE	0x02
#define	CPQARY3_DMA_BIND_ADDR_DONE	0x04
#define	CPQARY3_FREE_PHYCTG_MEM		0x07
#define	CPQARY3_SYNCCMD_SEND_WAITSIG	(0x0001)

/*
 * Include the driver specific relevant header files here.
 */
#include "cpqary3_ciss.h"
#include "cpqary3_q_mem.h"
#include "cpqary3_noe.h"
#include "cpqary3_scsi.h"
#include "cpqary3_ioctl.h"

/*
 * Per Target Structure
 */

typedef struct cpqary3_target {
	uint32_t	logical_id : 30; /* at most 64 : 63 drives + 1 CTLR */
	uint32_t	type : 2;	/* NONE, CTLR, LOGICAL DRIVE, TAPE */
	PhysDevAddr_t	PhysID;
	union {
		struct {
			uint8_t	id;
			uint8_t	bus;
		} scsi;		/* To support tapes */
		struct {
			uint8_t	heads;
			uint8_t	sectors;
		} drive;	/* Logical drives */
	} properties;

	uint32_t	ctlr_flags;
	dev_info_t	*tgt_dip;
	ddi_dma_attr_t	dma_attrs;
} cpqary3_tgt_t;


/*
 * Values for the type field in the Per Target Structure (above)
 */
#define	CPQARY3_TARGET_NONE		0	/* No Device */
#define	CPQARY3_TARGET_CTLR		1	/* Controller */
#define	CPQARY3_TARGET_LOG_VOL		2	/* Logical Volume */
#define	CPQARY3_TARGET_TAPE		3	/* SCSI Device - Tape */

/*
 * Index into PCI Configuration Registers for Base Address Registers(BAR)
 * Currently, only index for BAR 0 and BAR 1 are defined
 */
#define	INDEX_PCI_BASE0			1	/* offset 0x10 */
#define	INDEX_PCI_BASE1			2	/* offset 0x14 */

/* Offset Values for IO interface from BAR 0 */
#define	INBOUND_DOORBELL		0x20
#define	OUTBOUND_LIST_STATUS		0x30
#define	OUTBOUND_INTERRUPT_MASK		0x34
#define	INBOUND_QUEUE			0x40
#define	OUTBOUND_QUEUE			0x44

/* Offset Values for IO interface from BAR 1 */
#define	CONFIGURATION_TABLE		0x00

#define	INTR_DISABLE_5300_MASK		0x00000008l
#define	INTR_DISABLE_5I_MASK		0x00000004l

#define	OUTBOUND_LIST_5300_EXISTS	0x00000008l
#define	OUTBOUND_LIST_5I_EXISTS		0x00000004l

#define	INTR_PERF_MASK			0x00000001l

#define	INTR_PERF_LOCKUP_MASK		0x00000004l

#define	INTR_E200_PERF_MASK		0x00000004l

#define	INTR_SIMPLE_MASK		0x00000008l
#define	INTR_SIMPLE_LOCKUP_MASK		0x0000000cl


#define	INTR_SIMPLE_5I_MASK		0x00000004l
#define	INTR_SIMPLE_5I_LOCKUP_MASK	0x0000000cl

typedef struct cpqary3_per_controller CTLR;
/*
 * Per Controller Structure
 */
typedef struct cpqary3_per_controller {
	/* System Dependent Entities */
	uint8_t			bus;
	uint8_t			dev : 5;
	uint8_t			fun : 3;
	uint32_t		instance;
	dev_info_t		*dip;

	/* Controller Specific Information */
	int8_t			hba_name[38];
	ulong_t			num_of_targets;
	uint32_t		heartbeat;
	uint32_t		board_id;
	cpqary3_bd_t		*bddef;

	/* Condition Variables used */
	kcondvar_t		cv_immediate_wait;
	kcondvar_t		cv_noe_wait;
	kcondvar_t		cv_flushcache_wait;
	kcondvar_t		cv_abort_wait;
	kcondvar_t		cv_ioctl_wait; /* Variable for ioctls */

	/*
	 * CPQary3 driver related entities related to :
	 * 	Hardware & Software Interrupts, Cookies & Mutex.
	 * 	Timeout Handler
	 *	Driver Transport Layer/Structure
	 *	Database for the per-controller Command Memory Pool
	 *	Target List for the per-controller
	 */
	uint8_t			irq;		/* h/w IRQ */
	ddi_iblock_cookie_t	hw_iblock_cookie; /* cookie for h/w intr */
	kmutex_t		hw_mutex;	/* h/w mutex */
	ddi_iblock_cookie_t	sw_iblock_cookie; /* cookie for s/w intr */
	kmutex_t		sw_mutex;	/* s/w mutex */
	ddi_softintr_t		cpqary3_softintr_id; /* s/w intr identifier */
	uint8_t			swintr_flag;
	timeout_id_t		tick_tmout_id;	/* timeout identifier */
	uint8_t			cpqary3_tick_hdlr;
	scsi_hba_tran_t		*hba_tran;	/* transport structure */
	cpqary3_cmdmemlist_t	*cmdmemlistp;	/* database - Memory Pool */
	cpqary3_tgt_t		*cpqary3_tgtp[CPQARY3_MAX_TGT];
	cpqary3_drvr_replyq_t	*drvr_replyq;


	uint8_t			(*check_ctlr_intr)(CTLR *);

	/*
	 * PCI Configuration Registers
	 * 0x10	Primary I2O Memory BAR 	- for Host Interface
	 * 0x14	Primary DRAM 1 BAR	- for Transport Configuration Table
	 *
	 * Host Interface Registers
	 * Offset from Primary I2O Memory BAR
	 * 0x20 Inbound Doorbell	- for interrupting controller
	 * 0x30	Outbound List Status 	- for signalling status of Reply Q
	 * 0x34	Outbound Interrupt Mask	- for masking Interrupts to host
	 * 0x40	Host Inbound Queue	- Request Q
	 * 0x44	Host Outbound Queue	- reply Q
	 *
	 * Offset from Primary DRAM 1 BAR
	 * 0x00	Configuration Table 	- for Controller Transport Layer
	 */

	uint32_t		*idr;
	ddi_acc_handle_t	idr_handle;

	/* LOCKUP CODE */
	uint32_t		*spr0;
	ddi_acc_handle_t    	spr0_handle;
	/* LOCKUP CODE */

	uint32_t		*odr;
	ddi_acc_handle_t	odr_handle;

	uint32_t		*odr_cl;
	ddi_acc_handle_t	odr_cl_handle;

	uint32_t		*isr;
	ddi_acc_handle_t	isr_handle;

	uint32_t		*imr;
	ddi_acc_handle_t	imr_handle;

	uint32_t		*ipq;
	ddi_acc_handle_t	ipq_handle;

	uint32_t		*opq;
	ddi_acc_handle_t	opq_handle;

	CfgTable_t		*ct;
	ddi_acc_handle_t	ct_handle;

	CfgTrans_Perf_t		*cp;
	ddi_acc_handle_t	cp_handle;

	uint32_t		legacy_mapping;
	uint32_t		noe_support;
	/* SG */
	uint32_t		sg_cnt;
	/* SG */
	uint32_t		ctlr_maxcmds;
	uint32_t		host_support;
	uint8_t			controller_lockup;
	uint8_t			lockup_logged;
	uint32_t		poll_flag;
} cpqary3_t;


/*
 * Private Structure for Self Issued Commands
 */

typedef struct cpqary3_driver_private {
	void				*sg;
	cpqary3_phyctg_t	*phyctgp;
}cpqary3_private_t;

/* cmd_flags */
#define	CFLAG_DMASEND	0x01
#define	CFLAG_CMDIOPB	0x02
#define	CFLAG_DMAVALID	0x04

/*
 * Driver Private Packet
 */
typedef struct cpqary3_pkt {
	struct scsi_pkt		*scsi_cmd_pkt;
	ddi_dma_win_t		prev_winp;
	ddi_dma_seg_t		prev_segp;
	clock_t			cmd_start_time;
	/* SG */
	ddi_dma_cookie_t	cmd_dmacookies[MAX_PERF_SG_CNT];
	/* SG */
	uint32_t		cmd_ncookies;
	uint32_t		cmd_cookie;
	uint32_t		cmd_cookiecnt;
	uint32_t		cmd_nwin;
	uint32_t		cmd_curwin;
	off_t			cmd_dma_offset;
	size_t			cmd_dma_len;
	size_t			cmd_dmacount;
	struct buf		*bf;
	ddi_dma_handle_t   	cmd_dmahandle;
	uint32_t		bytes;
	uint32_t		cmd_flags;
	uint32_t		cdb_len;
	uint32_t		scb_len;
	cpqary3_cmdpvt_t	*memp;
} cpqary3_pkt_t;

#pragma pack(1)

typedef struct cpqary3_ioctlresp {
	/* Driver Revision */
	struct cpqary3_revision {
		uint8_t		minor; /* Version */
		uint8_t		major;
		uint8_t		mm;    /* Revision Date */
		uint8_t		dd;
		uint16_t	yyyy;
	} cpqary3_drvrev;

	/* HBA Info */
	struct cpqary3_ctlr {
		uint8_t		num_of_tgts; /* No of Logical Drive */
		uint8_t		*name;
	} cpqary3_ctlr;
} cpqary3_ioctlresp_t;

typedef struct cpqary3_ioctlreq {
	cpqary3_ioctlresp_t	*cpqary3_ioctlrespp;
} cpqary3_ioctlreq_t;

#pragma pack()

/* Driver function definitions */

void cpqary3_init_hbatran(cpqary3_t *);
void cpqary3_read_conf_file(dev_info_t *, cpqary3_t *);
void cpqary3_tick_hdlr(void *);
void cpqary3_flush_cache(cpqary3_t *);
void cpqary3_intr_onoff(cpqary3_t *, uint8_t);
void cpqary3_lockup_intr_onoff(cpqary3_t *, uint8_t);
uint8_t cpqary3_disable_NOE_command(cpqary3_t *);
uint8_t cpqary3_send_NOE_command(cpqary3_t *, cpqary3_cmdpvt_t *, uint8_t);
uint16_t cpqary3_init_ctlr_resource(cpqary3_t *);
uint32_t cpqary3_hw_isr(caddr_t);
uint32_t cpqary3_sw_isr(caddr_t);
int32_t cpqary3_ioctl_driver_info(uintptr_t, int);
int32_t cpqary3_ioctl_ctlr_info(uintptr_t, cpqary3_t *, int);
int32_t cpqary3_ioctl_bmic_pass(uintptr_t, cpqary3_t *, int);
int32_t cpqary3_ioctl_scsi_pass(uintptr_t, cpqary3_t *, int);
uint8_t cpqary3_probe4targets(cpqary3_t *);
void cpqary3_cmdlist_release(cpqary3_cmdpvt_t *, uint8_t);
int32_t cpqary3_submit(cpqary3_t *, uint32_t);
void cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *, uint8_t);
caddr_t cpqary3_alloc_phyctgs_mem(cpqary3_t *, size_t, uint32_t *,
    cpqary3_phyctg_t *);
cpqary3_cmdpvt_t *cpqary3_cmdlist_occupy(cpqary3_t *);
void cpqary3_synccmd_complete(cpqary3_cmdpvt_t *);
void cpqary3_NOE_handler(cpqary3_cmdpvt_t *);
uint8_t cpqary3_retrieve(cpqary3_t *);
void cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t *);
int cpqary3_target_geometry(struct scsi_address *);
uint8_t cpqary3_send_abortcmd(cpqary3_t *, uint16_t, CommandList_t *);
void cpqary3_memfini(cpqary3_t *, uint8_t);
uint8_t cpqary3_init_ctlr(cpqary3_t *);
int16_t cpqary3_meminit(cpqary3_t *);
void cpqary3_noe_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp);
cpqary3_cmdpvt_t *cpqary3_synccmd_alloc(cpqary3_t *, size_t);
void cpqary3_synccmd_free(cpqary3_t *, cpqary3_cmdpvt_t *);
int cpqary3_synccmd_send(cpqary3_t *, cpqary3_cmdpvt_t *, clock_t, int);
uint8_t cpqary3_poll_retrieve(cpqary3_t *cpqary3p, uint32_t poll_tag);
uint8_t cpqary3_build_cmdlist(cpqary3_cmdpvt_t *cpqary3_cmdpvtp, uint32_t tid);

#ifdef	__cplusplus
}
#endif

#endif	/* _CPQARY3_H */