/*
 *----------------------------------------------------------------------------
 *	LSI Corporation
 *	1621 Barber Lane
 *	Milpitas, California 95035
 *----------------------------------------------------------------------------
 * Copyright © 2004-2006, LSI Corporation All Rights Reserved.
 * 
 * LSI's source code is an unpublished work and the use of copyright
 * notice does not imply otherwise. This source code contains confidential,
 * trade secret material of LSI Corporation. Any attempt or
 * participation in deciphering, decoding, reverse engineering or
 * in any way altering the source code is strictly prohibited, unless the
 * prior written consent of LSI Corporation.
 *---------------------------------------------------------------------------- 
 */

/** 
 *@file linux_osl.h
 *
 *@brief
 * This file contains the Linux OSL implementation.
 *
 * All Linux related implementation will be centralized here. This file will
 * makeup the top most layer and has full knowledge of everything underneath.
 * 
 *@bug
 *	None
 *
 *@warning
 *	None
 *
 *@note
 *	06-23-2004	: Created this file 
 */

#ifndef LSI_MEGA_SWR_LINUX_OSL_H
#define LSI_MEGA_SWR_LINUX_OSL_H

#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uio.h>
#include <linux/pci_ids.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/blkdev.h>
#else
#include <linux/blk.h>
#endif
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/module.h>
#include <linux/interrupt.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)

#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <linux/moduleparam.h>

#ifdef CONFIG_COMPAT
#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && defined(__x86_64__)) //include only for >2.6.27 32bit kernels.
#include <linux/ioctl32.h>
#endif
#include <linux/compat.h>
#endif

#else

#include "scsi.h"
#include "hosts.h"

#if defined(CONFIG_COMPAT) || defined(__x86_64__)
#include <asm/ioctl32.h>
#include <asm/compat.h>

struct compat_iovec {
	compat_uptr_t iov_base;
	compat_size_t iov_len;
};
#endif

#endif

#include "../../cmn_defs.h"

#define LINOSL_MAX_IDS					20
#define LINOSL_MAX_CONTROLLERS			5

#define LSI_RAID_DISPLAY_DRIVER_VERSION \
	con_log(CL_ANN, ("%s version v%s, built on %s at %s\n", LSIRAID_DRIVER_NAME, LSIRAID_VERSION_STRING, __DATE__, __TIME__));

/* > 2.6 kernel related definitions */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)

#define LSI_RAID_SCSI_REGISTER		scsi_host_alloc
#define LSI_RAID_SCSI_HOST_DEALLOC	scsi_host_put
#define LSI_RAID_SCSI_ADD_HOST(x,y)	scsi_add_host(x,y)
#define LSI_RAID_SCSI_REMOVE_HOST(x)	scsi_remove_host(x)
#define LSI_RAID_SCSI_SCAN_HOST(x)	scsi_scan_host(x)
#define LSI_RAID_SCSI_SET_PCI_DEVICE(host, pdev) do {} while(0)
/* conversion from scsi command */
#define LSI_RAID_SCP2_HOST(scp)		(scp)->device->host		/* host */
#define LSI_RAID_SCP2_HOSTDATA(scp)	LSI_RAID_SCP2_HOST(scp)->hostdata[0]
#define LSI_RAID_SCP2_CHANNEL(scp)	(scp)->device->channel	/* channel */
#define LSI_RAID_SCP2_TARGET(scp)	(scp)->device->id		/* target */
#define LSI_RAID_SCP2_LUN(scp)		(scp)->device->lun		/* LUN */
#define LSI_RAID_IRQRETURN_T 		irqreturn_t

#define LSI_RAID_HOST_SET_LOCK(host, lock) scsi_assign_lock(host, lock)
#define LSI_RAID_CURRENT_TIME_IN_SEC (CURRENT_TIME.tv_sec)

#else

/* definitions for 2.4 kernels */
#define LSI_RAID_SCSI_REGISTER		scsi_register
#define LSI_RAID_SCSI_HOST_DEALLOC	scsi_unregister
#define LSI_RAID_SCSI_ADD_HOST(x,y)	(0)
#define LSI_RAID_SCSI_REMOVE_HOST(x)	do {} while(0)
#define LSI_RAID_SCSI_SCAN_HOST(x)	scsi_scan_host(x)
#define LSI_RAID_SCSI_SET_PCI_DEVICE(host, dev) \
			scsi_set_pci_device(host, dev);
/* conversion from scsi command */
#define LSI_RAID_SCP2_HOST(scp)		(scp)->host		/* host*/
#define LSI_RAID_SCP2_HOSTDATA(scp)	LSI_RAID_SCP2_HOST(scp)->hostdata[0]
#ifdef __VMKERNEL_MODULE__
#define LSI_RAID_SCP2_CHANNEL(scp)	(((scp)->target)/MAX_LD_PER_ADP)	/* channel */
#define LSI_RAID_SCP2_TARGET(scp)	(((scp)->target)%MAX_LD_PER_ADP)	/* target */
#else
#define LSI_RAID_SCP2_CHANNEL(scp)	(scp)->channel	/* channel */
#define LSI_RAID_SCP2_TARGET(scp)		(scp)->target	/* target */
#endif
#define LSI_RAID_SCP2_LUN(scp)		(scp)->lun		/* LUN */
#define LSI_RAID_IRQRETURN_T 			void	
#define	IRQ_RETVAL(x)

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,18)
#define LSI_RAID_HOST_SET_LOCK(host, lock) lock = &io_request_lock;
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21)
#define LSI_RAID_HOST_SET_LOCK(host, lock) host->host_lock = lock;
#else
//#define LSI_RAID_HOST_SET_LOCK(host, lock) scsi_assign_lock(host, lock)
#define LSI_RAID_HOST_SET_LOCK(host, lock) lock = &io_request_lock;
#endif
#define LSI_RAID_CURRENT_TIME_IN_SEC	(CURRENT_TIME)
	
#endif

const char *lsraid_info(struct Scsi_Host *host);
int lsraid_queue_cmd(struct scsi_cmnd* scp, void (*done) (struct scsi_cmnd*));
int lsraid_abort(struct scsi_cmnd* scp);
int lsraid_device_reset(struct scsi_cmnd* scp);
int lsraid_bus_reset(struct scsi_cmnd* scp);
int lsraid_host_reset(struct scsi_cmnd* scp);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)

int lsraid_slave_configure(struct scsi_device *);

/** Linux SCSI Host Template for 2.6 Kernel */
#define LSI_RAID_TEMPLATE { 							\
	.module					= THIS_MODULE,				\
	.name					= LSIRAID_DRIVER_SIGNATURE,	\
	.proc_name				= LSIRAID_DRIVER_SIGNATURE, \
	.info					= lsraid_info, 				\
	.can_queue				= 128,	 					\
	.max_sectors			= 128, 						\
	.sg_tablesize			= 16, 						\
	.cmd_per_lun 			= 64, 						\
	.slave_configure		= lsraid_slave_configure,	\
	.queuecommand			= lsraid_queue_cmd,	 		\
	.eh_abort_handler		= lsraid_abort, 			\
	.eh_device_reset_handler= lsraid_device_reset, 		\
	.eh_bus_reset_handler	= lsraid_bus_reset, 		\
	.eh_host_reset_handler	= lsraid_host_reset,		\
	.unchecked_isa_dma		= 0, 						\
}

#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */

int lsraid_release(struct Scsi_Host* host);

#ifdef __VMKERNEL_MODULE__

static int lsraid_detect(Scsi_Host_Template *template);

#define LSI_RAID_TEMPLATE { 								\
	.name						= LSIRAID_DRIVER_SIGNATURE,	\
	.proc_name					= "megaswr_dummy",			\
	.info						= lsraid_info,				\
	.release					= lsraid_release,			\
	.can_queue					= 128,						\
	.max_sectors				= 128,						\
	.sg_tablesize				= 16,						\
	.cmd_per_lun 				= 64,						\
	.queuecommand				= lsraid_queue_cmd,			\
	.eh_abort_handler			= lsraid_abort,				\
	.eh_device_reset_handler	= lsraid_device_reset,		\
	.eh_bus_reset_handler		= lsraid_bus_reset,			\
	.eh_host_reset_handler		= lsraid_host_reset,		\
	.use_new_eh_code			= 1,						\
	.unchecked_isa_dma			= 0,						\
	.highmem_io					= 1,						\
	.vary_io					= 1,						\
	.detect						= lsraid_detect,			\
}

#else //__VMKERNEL_MODULE__

/** Linux SCSI Host Template for 2.4 Kernel */
#define LSI_RAID_TEMPLATE { 						\
	.name					= LSIRAID_DRIVER_SIGNATURE,	\
	.proc_name				= "megaswr_dummy",		\
	.info					= lsraid_info, 			\
	.release				= lsraid_release, 		\
	.can_queue				= 128,	 				\
	.max_sectors			= 128, 					\
	.sg_tablesize			= 16, 					\
	.cmd_per_lun 			= 64, 					\
	.queuecommand			= lsraid_queue_cmd,	 	\
	.eh_abort_handler		= lsraid_abort, 		\
	.eh_device_reset_handler= lsraid_device_reset, 	\
	.eh_bus_reset_handler	= lsraid_bus_reset, 	\
	.eh_host_reset_handler	= lsraid_host_reset,	\
	.use_new_eh_code		= 1, 					\
	.unchecked_isa_dma		= 0, 					\
}

int lsraid_detect(Scsi_Host_Template* sht);
int lsraid_release(struct Scsi_Host* host);

#endif /* __VMKERNEL_MODULE__ */
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */

#define MEGASR_LINUX_CRASHDUMP_MEMORY		(192 * 1024)	// Minimum memory required for crashdump driver
#define MEGASR_LINUX_CRASHDUMP_SECTORS		16		// Number of sectors transferred as part of low memory condition handling.
#define MEGASR_LINUX_CRAHSDUMP_DDF_MEM		(24 * 1024)	// Amount of crashdump memory reserved for DDF while loading in crashdump mode.

/**
 *@struct timer_object 
 *@brief
 * This structure is used to store information of a timer thread statrted by
 * linux operating sytstem layer.
 */
typedef struct timer_object {
	struct timer_list	timer;	//!< Timer list structure
	uint8_t			used_flag : 1;	//!< 1- if timer used
	uint8_t			active_flag : 1;		//!< 1- if timer active
	uint8_t			resreved1 : 6;	//!< reserved bits
	uint32_t		seconds;	//!< Wait time to call call back function
	timer_fn_t		timer_fn;	//!< Call back function
	void*			context1;	//!< First parameter to call back function
	void*			context2;	//!< First parameter to call back function
} timer_object_t;

#define LINUX_DMA_MEM_PCI_CONSISTENT	0x01
#define LINUX_DMA_MEM_PCI_COHERENT		0x04
#define LINUX_DMA_WAIT					0x01
#define LINUX_DMA_NOWAIT				0x02
typedef struct linux_dma_mem_list {
	dma_addr_t	dma_addr;
	uint8_t		*vir;
	uint32_t	len;
	uint8_t		flag;
} linux_dma_mem_list_t;

typedef struct mem_fr_st { //in linux_osl.h
	pvt_data_t		*os_context;
	uint32_t		size_in_bytes;
}mem_fr_st_t;

#define MAX_MEM_POOLS_PER_POOL_TYPE 336
typedef struct linux_dma_mem {
	uint16_t		list_count; //!< Dma memory chunk count
	linux_dma_mem_list_t list[MAX_MEM_POOLS_PER_POOL_TYPE];
} linux_dma_mem_t;

#pragma pack(push, 1)
/**
 *@struct _linux_ioctl_data_t 
 *@brief
 * Holds IOCTL related information
 */
typedef struct	_linux_ioctl_data_t {
	struct semaphore		ioctl_lock;
	wait_queue_head_t		wait_queue;
	uint32_t				status;
	uint32_t				activity_state;
	linux_dma_mem_list_t	dma;
} linux_ioctl_data_t;

struct megasas_iocpacket {
	uint16_t			host_no;
	uint16_t			__pad1;
	uint32_t			sgl_off;
	uint32_t			sge_count;
	uint32_t			sense_off;
	uint32_t			sense_len;
    
	union {
		u8				raw[128];
	} frame;

	struct iovec		sgl[16];
} ;
#pragma pack(pop)

#if defined(CONFIG_COMPAT) || defined(__x86_64__)
struct compat_megasas_iocpacket {
	
	uint16_t			host_no;
	uint16_t			__pad1;
	uint32_t			sgl_off;
	uint32_t			sge_count;
	uint32_t			sense_off;
	uint32_t			sense_len;
	
	union {
		uint8_t			raw[128];
	} __attribute__ ((packed)) frame;
	
	struct compat_iovec	sgl[16];

} __attribute__ ((packed));

#define LSRAID_IOC_FIRMWARE_COMPAT	_IOWR('R', 1, struct compat_megasas_iocpacket)
#endif

#define LSRAID_IOC_FIRMWARE	_IOWR('R', 1, struct megasas_iocpacket)
#define LSRAID_IOC_GET_AEN	_IOW('R', 3, struct megasas_aen)


/**
 *@struct linux_adp 
 *@brief
 * This structure is used to store information specific tp Linux operating 
 * system specific.
 */
typedef struct	linux_adp {
	struct Scsi_Host	*host;		//!< Kernel's Scsi Host structure pointer
	spinlock_t			lock;		//!< Spin Lock structure for SMP support
	spinlock_t			*host_lock;	//!< Spin Lock pointer for better implement
	struct pci_dev		*pdev;		//!< PCI device structure pointer
	uint8_t				timer_count;//!< Number of active timers
	timer_object_t		timer_objects[MAX_TIMERS];//!< Timer info structure
	unsigned long		flags;		//!< Flags used to strore spinlock info
	pvt_data_t			*static_mem;//!< static memory for the driver 		
	linux_dma_mem_t		dma;
	linux_ioctl_data_t	ioctl_data;

	/* for 2.4 kernel support, defined for PROC FS*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
	struct proc_dir_entry			*hba_proc_dir;
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
	struct work_struct		work_build_io_in;
	struct work_struct		work_build_io_out;
	struct megasr_clist	build_io_list_in;
	struct megasr_clist	build_io_list_out;
	uint8_t					dpc_scheduled;
#endif	
	rcl_packet_public_t	*rclp_crash;	///!< rclp packet reserved for crashdump
	uint8_t			rclp_crash_inuse;	//!< Set to indicate if crash packet is in use.
	uint8_t			crashdump_mode;
	uint16_t		crashdump_sectors;
	pvt_data_t *adp;	// pointer to global context
} linux_adp_t;

#pragma pack(push, 1)
typedef struct _megaswr_adp_map_t {
	uint16_t	unique_hndl;
	uint32_t	bus_dev_fn;
} megaswr_adp_map_t;
#pragma pack(pop)

uint32_t megasr_dma_alloc(struct pci_dev *hwdev, size_t size, linux_dma_mem_list_t *linux_dma, uint8_t wait);
void megasr_dma_free(struct pci_dev *hwdev, linux_dma_mem_list_t *linux_dma);
#endif /* LSI_MEGA_SWR_LINUX_OSL_H */

/* vim: set ts=4 sw=4 tw=78 wrap ai si: */
