#ifndef	_MEGA_H
#define	_MEGA_H
/*
 *	Definitions of data structures used by the adapter and by our
 *	high-level interface.
 *
 *	Copyright (c) 2007 by Jefferson Ogata
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


#include	"logpage.h"

#include	<sys/types.h>
#include	<sys/uio.h>
#include	<scg/scsireg.h>


typedef signed char s8;
typedef unsigned char u8;

typedef signed short s16;
typedef unsigned short u16;

typedef signed int s32;
typedef unsigned int u32;

typedef signed long long s64;
typedef unsigned long long u64;

#define BITS_PER_LONG 32

#include	<stdint.h>
#ifdef	NEED_UINT8_T

typedef		__u8		uint8_t;
typedef		__u16		uint16_t;
typedef		__u32		uint32_t;
typedef		__u64		uint64_t;

#endif

/* DMA addresses come in generic and 64-bit flavours.  */

#ifdef CONFIG_HIGHMEM
typedef u64 dma_addr_t;
#else
typedef u32 dma_addr_t;
#endif
typedef u64 dma64_addr_t;

/* Hacks to get kernel module headers to compile. We're not using any data structures where these matter. */
typedef	struct
{
    volatile unsigned int	lock;
}				spinlock_t;
struct semaphore
{
    int				foo;
};

typedef struct { volatile int counter; } atomic_t;
struct tasklet_struct
{
	struct tasklet_struct *next;
	unsigned long state;
	atomic_t count;
	void (*func)(unsigned long);
	unsigned long data;
};

#define	__iomem

#define	__user
#define	wait_queue_head_t	void *
/* typedef	void	wait_queue_head_t; */

struct list_head {
	struct list_head *next, *prev;
};


/* Okay, should be able to include module headers now, hopefully. */
#include	"megaraid/mbox_defs.h"
#include	"megaraid/megaraid_ioctl.h"
#include	"megaraid/megaraid_sas.h"

#define	MAX_CONTROLLERS	32

#define	M_RD_IOCTL_CMD			0x80
#define	M_RD_IOCTL_CMD_NEW		0x81
#define	M_RD_DRIVER_IOCTL_INTERFACE	0x82


#define	SCSI_SELFTEST_DEFAULT		0x00
#define	SCSI_SELFTEST_BACKGROUND_SHORT	0x01
#define	SCSI_SELFTEST_BACKGROUND_LONG	0x02
#define	SCSI_SELFTEST_BACKGROUND_ABORT	0x04
#define	SCSI_SELFTEST_FOREGROUND_SHORT	0x05
#define	SCSI_SELFTEST_FOREGROUND_LONG	0x06

/* Drives without enclosure report this as the enclosure ID */
#define DISK_NOENC 0xffff

/* megaraid2 header file gets this wrong. */
typedef struct {
	uint8_t		max_commands;
	uint8_t		rebuild_rate;
	uint8_t		max_targ_per_chan;
	uint8_t		nchannels;
	uint8_t		fw_version[4];
	uint16_t	age_of_flash;
	uint8_t		chip_set_value;
	uint8_t		dram_size;
	uint8_t		cache_flush_interval;
	uint8_t		bios_version[4];
	uint8_t		board_type;
	uint8_t		sense_alert;
	uint8_t		write_config_count;
	uint8_t		drive_inserted_count;
	uint8_t		inserted_drive;
	uint8_t		battery_status;
	uint8_t		dec_fault_bus_info;
} __attribute__ ((packed)) mraid_adapinfo1_t;

typedef struct {
	mraid_adapinfo1_t	adapter_info;
	mraid_ldrv_info_t	logdrv_info;
	mraid_pdrv_info_t	pdrv_info;
} __attribute__ ((packed)) mraid_inquiry1_t;

typedef struct {
	mraid_inquiry1_t	raid_inq;
	uint16_t	phys_drv_format[MAX_MBOX_CHANNELS];
	uint8_t		stack_attn;
	uint8_t		modem_status;
	uint8_t		rsvd[2];
} __attribute__ ((packed)) mraid_extinq1_t;


/* Structures we've figured out over many hours of staring at hex data. */

struct mega_physical_drive_error_info
{
    uint8_t			media;
    uint8_t			other;
} __attribute__ ((packed));


struct mega_predictive_map
{
    uint8_t			map[FC_MAX_PHYSICAL_DEVICES / 8];
} __attribute__ ((packed));


struct mega_device_entry_sas {
    uint16_t				device_id;
    uint16_t				enclosure;
    uint8_t				value_1;	/* ? 1, 2 enclosure number + 1? backend port number? */
    uint8_t				slot;
    uint8_t				type;		/* INQ_DASD, INQ_ENCL */
    uint8_t				port;		/* 1 << connected port number */
    uint64_t				sas_address[2];
} __attribute__ ((packed));

/* opcode 0x02010000 */
struct mega_device_list_sas {
    uint32_t				length;
    uint16_t				num_devices;
    uint16_t				rsvd0;
    struct mega_device_entry_sas	device[32];	/* actually any number */
} __attribute__ ((packed));


struct mega_array_header_sas {
    uint32_t				length;
    uint16_t				num_span_defs;
    uint16_t				span_def_size;		/* 0x0120 */
    uint16_t				num_disk_defs;
    uint16_t				disk_def_size;		/* 0x0100 */
    uint16_t				num_hot_spares;
    uint16_t				value_0028;		/* ? 0x0028 */
    uint32_t				pad0[4];
} __attribute__ ((packed));

struct mega_array_span_disk_sas
{
    uint16_t				device_id;		/* 0xffff if device missing */
    uint16_t				sequence;		/* ? 0x0002, 0x0004, 0x0006... as disks are created */
    uint8_t				flag_0:1;
    uint8_t				hotspare:1;
    uint8_t				rebuild:1;
    uint8_t				online:1;
    uint8_t				present:1;
    uint8_t				flag_1;
    uint8_t				enclosure;
    uint8_t				slot;
} __attribute__ ((packed));

struct mega_array_span_def_sas
{
    uint64_t				sectors_per_disk;
    uint16_t				span_size;		/* number of disks in span */
    uint16_t				span_index;		/* 0, 1, 2... */
    uint32_t				value_1;		/* ? 0 */
    uint32_t				pad0[4];
    struct mega_array_span_disk_sas	disk[32];		/* real number is (config.span_def_size - offset .disks) / sizeof span_entry */
} __attribute__ ((packed));

struct mega_array_disk_entry_sas
{
    uint64_t				offset;			/* offset in sectors of this vd */
    uint64_t				sectors_per_disk;	/* sectors used for this vd on each disk */
    uint16_t				span_index;		/* number of this span */
    uint16_t				pad2;			/* ? 0 */
    uint32_t				pad3;			/* ? 0 */
} __attribute__ ((packed));

#define	MEGA_SAS_LD_OFFLINE		0
#define	MEGA_SAS_LD_PARTIALLY_DEGRADED	1
#define	MEGA_SAS_LD_DEGRADED		2
#define	MEGA_SAS_LD_OPTIMAL		3

struct mega_array_disk_def_sas {
    uint16_t				disk_index;		/* 0, 1, 2... */
    uint16_t				sequence;		/* ? 0x0004, 0x0003 */
    char				name[16];		/* null-terminated, max 15 chars */
    uint32_t				flags;			/* ? 0x01000001, 0x00000000 */
    uint32_t				pad0[2];		/* ? 0 */
    uint8_t				raid_level;		/* 0, 1, 5 */
    uint8_t				raid_level_secondary;	/* ? 3 for raid 5 with 4 spans, 0 for raid1 with 1 span */
    uint8_t				raid_level_qualifier;	/* ? 3 for raid 5 with 4 spans, 0 for raid1 with 1 span */
    uint8_t				stripe_size;		/* (2 << this) sectors per stripe; 4 == 8K, 5 == 16K, etc. */
    uint8_t				disks_per_span;
    uint8_t				num_spans;
    uint16_t				state;			/* ? 0 == offline, 1 == partially degraded, 2 == degraded, 3 == optimal */
    uint32_t				value_4;		/* ? 0x00000001, 0x00000000 */
    uint32_t				pad1[5];		/* ? 0 */
    struct mega_array_disk_entry_sas	span[8];		/* real number is (config.disk_def_size - offset .spans) / sizeof disk_entry */
} __attribute__ ((packed));

struct mega_array_hotspare_def_sas
{
    uint16_t				device_id;
    uint16_t				sequence;		/* ? 0x001c, 0x001e, 0x0020 */
    uint32_t				flags;			/* ? 0x00000000 for global, 0x01000001 for dedicated */
    uint32_t				array;			/* dedicated array index */
    uint32_t				pad0[7];		/* ? 0 */
} __attribute__ ((packed));

/* opcode 0x04010000: array config is { header span_def* disk_def* hotspare_def* } */
struct mega_array_config_sas
{
    struct mega_array_header_sas	*header;
    struct mega_array_span_def_sas	*span;
    struct mega_array_disk_def_sas	*disk;
    struct mega_array_hotspare_def_sas	*hotspare;
};

/* opcode 0x05010000 */
#define	MEGA_BATTERY_TYPE_NONE	0
#define	MEGA_BATTERY_TYPE_ITBBU	1
#define	MEGA_BATTERY_TYPE_TBBU	2

struct mega_battery_state_sas
{
    uint8_t				type;			/* see above */
    uint8_t				foo;			/* ? */
    uint16_t				voltage;		/* millivolts */
    uint16_t				current;		/* milliamps */
    uint16_t				temperature;		/* celsius */
    uint32_t				firmware_status;
    uint32_t				pad0[5];		/* ? 0 */

    uint8_t				pad1:4;

    uint8_t				fully_discharged:1;
    uint8_t				fully_charged:1;
    uint8_t				discharging:1;
    uint8_t				initialized:1;

    uint8_t				remaining_time_alarm:1;
    uint8_t				remaining_capacity_alarm:1;
    uint8_t				pad2:1;
    uint8_t				discharge_terminated:1;

    uint8_t				over_temperature:1;
    uint8_t				pad3:1;
    uint8_t				charging_terminated:1;
    uint8_t				over_charged:1;

    uint16_t				charge;			/* percentage */
    uint16_t				charger_status;		/* charger status 0 == off, 1 == complete, 2 == in progress */
    uint16_t				capacity_remaining;	/* milliamp-hours */
    uint16_t				capacity_full;		/* milliamp-hours */
    uint16_t				health;			/* state of health 0 == no, * == good */
    uint32_t				pad9[5];		/* ? 0 */
} __attribute__ ((packed));

/* opcode 0x05020000 */
struct mega_battery_capacity_sas
{
    uint16_t				charge_relative;	/* percentage */
    uint16_t				charge_absolute;	/* percentage */
    uint16_t				capacity_remaining;	/* milliamp-hours */
    uint16_t				capacity_full;		/* milliamp-hours */
    uint16_t				time_empty_run;		/* minutes */
    uint16_t				time_empty_average;	/* minutes */
    uint16_t				time_full_average;	/* minutes */
    uint16_t				cycles;
    uint16_t				error_max;		/* percentage */
    uint16_t				alarm_capacity;		/* milliamp-hours */
    uint16_t				alarm_time;		/* minutes */
    uint16_t				pad0;			/* ? 0 */
    uint32_t				pad1[6];		/* ? 0 */
} __attribute__ ((packed));

/* opcode 0x05030000 */
struct mega_battery_design_sas
{
    uint32_t				manufacture_date;	/* weird encoding: 0xfae87 == 2007/04/07, 0xfaebf == 2007/05/31 */
    uint16_t				design_capacity;	/* milliamp-hours */
    uint16_t				design_voltage;		/* millivolts */
    uint16_t				specification_info;
    uint16_t				serial_number;
    uint16_t				pack_stat_configuration;
    char				manufacturer[12];
    char				device_name[8];
    char				device_chemistry[5];
    char				device_vendor[5];
    uint32_t				pad0[5];		/* ? 0 */
} __attribute__ ((packed));

/* opcode 0x05050100 */
struct mega_battery_properties_sas
{
    uint32_t				device_learn_period;	/* seconds */
    uint32_t				next_learn_time;	/* seconds */
    uint32_t				learn_delay_interval;	/* ? hours */
    uint32_t				auto_learn_mode;	/* ? */
    uint32_t				pad0[4];		/* ? 0 */
} __attribute__ ((packed));

struct mega_battery_info_sas
{
    struct mega_battery_state_sas	state;
    struct mega_battery_capacity_sas	capacity;
    struct mega_battery_design_sas	design;
    struct mega_battery_properties_sas	properties;
};


/* opcode 0x02020000 */
struct mega_physical_disk_info_sas
{
    uint16_t				device_id;
    uint16_t				sequence;
    union
    {
	struct scsi_inquiry			inq;
	uint8_t					buf[96];
    }					inquiry;
    uint16_t				value_x;		/* ? 0x8300 */					/* 0x064 */
    uint16_t				value_y;		/* ? 0x4800, 0x2000 */
    struct
    {
	uint8_t					value[60];
    }					mystery_struct;								/* 0x0a4 */
    uint16_t				value_0;		/* ? 0x0000 */
    uint8_t				port;			/* 1 << connected port number */
    uint8_t				value_1;		/* ? 0 */
    uint32_t				media_errors;
    uint32_t				other_errors;
    uint32_t				predictive_failures;
    uint32_t				predictive_failure_event_sequence;
    uint8_t				failure:1;
    uint8_t				hotspare:1;
    uint8_t				rebuild:1;
    uint8_t				online:1;
    uint8_t				configured:1;
    uint8_t				flags_0:3;
    uint8_t				flags_1;
    uint16_t				value_4;		/* ? 0x0000 */
    uint32_t				value_5;		/* ? 0x00002002, 0x00003003, 0x00003009 */
    uint32_t				sas_address_count;	/* number of sas addresses */
    uint32_t				pad_sas_addr;		/* ? 0x00000000 */
    uint64_t				sas_address[4];
    uint64_t				raw_size;		/* sectors; MegaCli only sees 32 bits */	/* 0x0e8 */
    uint64_t				noncoerced_size;	/* sectors; MegaCli only sees 32 bits */	/* 0x0f0 */
    uint64_t				coerced_size;		/* sectors; MegaCli only sees 32 bits */	/* 0x0f8 */
    uint16_t				enclosure;								/* 0x100 */
    uint8_t				value_9;		/* 1 or 2, not sure what it means, goes with enclosure */
    uint8_t				slot;
    uint8_t				value_10[0xfc];
} __attribute__ ((packed));


/* Unified config structures for generic high-level interface. */

enum mega_adapter_enum {
    MEGA_ADAPTER_V2,				/* PERC2 */
    MEGA_ADAPTER_V34,				/* PERC3 or PERC4 */
    MEGA_ADAPTER_V5,				/* PERC5 (SAS) */
};

/* Structure for io to adapters. */
struct mega_adapter_path
{
    int				fd;		/* block device descriptor for adapter access */
    uint8_t			adapno;		/* adapter number */
    enum mega_adapter_enum	type;		/* adapter variant */
};


struct log_page_list
{
    struct logData		log;
    uint8_t			buf[4095];	/* rhl 7.3 croaks on >= 4096 */
    struct log_page_list	*next;
};

enum physical_drive_state
{
    PdStateUnknown,
    PdStateUnconfiguredGood,
    PdStateUnconfiguredBad,
    PdStateHotspare,
    PdStateFailed,
    PdStateRebuild,
    PdStateOnline,
};

struct physical_drive_info
{
    uint8_t			present;		/* whether drive responds to inquiry */
    struct adapter_config	*adapter;		/* adapter this drive belongs to */
    struct span_info		*span;			/* span this disk is a member of */
    char			name[16];		/* drive name (AxCyTz) */
    uint16_t			target;			/* scsi channel+id or device_id */
    uint16_t			channel;		/* channel or enclosure */
    uint8_t			id;			/* scsi id or enclosure slot */
    enum physical_drive_state	state;			/* drive state */
    char			*error_string;		/* status error string (NULL if okay) */
    uint64_t			blocks;			/* number of blocks */
    char			vendor[9];		/* vendor name */
    char			model[17];		/* vendor model */
    char			revision[5];		/* firmware version */
    char			serial[32];		/* serial number */
    uint32_t			predictive_failures;	/* predictive failure count */
    uint32_t			media_errors;
    uint32_t			other_errors;
    struct scsi_inquiry		inquiry;		/* scsi inquiry result */
    struct log_page_list	*log;

    union
    {
	struct
	{
	    struct mega_physical_disk_info_sas	info;
	}			v5;
    }				q;
};

struct span_info
{
    struct adapter_config	*adapter;		/* adapter this span belongs to */
    uint32_t			blocks_per_disk;	/* blocks used per disk for this span */
    uint32_t			num_disks;		/* number of disks in this span */
    struct physical_drive_info	**disk;			/* pointers to component disks */
    uint32_t			num_logical_drives;	/* how many logical drives this span belongs to */
    struct logical_drive_info	**logical_drive;	/* pointers to logical drives */
};

struct span_reference
{
    uint64_t			offset;			/* offset into each disk */
    uint64_t			blocks_per_disk;	/* number of blocks used per disk */
    struct span_info		*span;			/* the span */
};

enum logical_drive_state
{
    LdStateUnknown,
    LdStateOffline,
    LdStatePartiallyDegraded,
    LdStateDegraded,
    LdStateOptimal,
    LdStateDeleted,
};

struct logical_drive_info
{
    struct adapter_config	*adapter;		/* adapter this drive belongs to */
    char			name[16];		/* logical drive name (AxLDy) */
    uint16_t			target;			/* logical drive number */
    enum logical_drive_state	state;			/* logical drive state */
    uint8_t			raid_level;		/* raid level */
    uint8_t			num_spans;		/* how many spans in this logical drive */
    struct span_reference	*span;			/* pointers to component spans */
    uint8_t			span_size;		/* number of disks per span */
};

enum battery_charger_state
{
    ChargerStateUnknown,
    ChargerStateFailed,
    ChargerStateInProgress,
    ChargerStateComplete,
};

struct adapter_config
{
    struct mega_adapter_path	target;			/* adapter access path */
    uint8_t			is_sas;			/* adapter is a sas adapter */
    char			name[16];		/* adapter name (Ax) */
    char			product[81];		/* adapter product name */
    char			bios[17];		/* adapter bios version */
    char			firmware[17];		/* adapter firmware version */
    struct
    {
	uint8_t				healthy:1;
	uint8_t				module_missing:1;
	uint8_t				pack_missing:1;
	uint8_t				low_voltage:1;
	uint8_t				high_temperature:1;
	uint8_t				cycles_exceeded:1;
	uint8_t				over_charged:1;
	enum battery_charger_state	charger_state;
	int16_t				voltage;
	int16_t				temperature;
    }				battery;
    uint16_t			dram_size;		/* size of DRAM in MB */
    uint16_t			rebuild_rate;		/* rebuild rate as percentage */
    uint16_t			num_channels;		/* number of channels or enclosures */
    uint16_t			*channel;		/* channel/enclosure map */
    uint16_t			num_physicals;
    struct physical_drive_info	*physical;
    struct physical_drive_info	**physical_list;	/* ordered list of physical devices */
    uint16_t			num_spans;		/* number of spans */
    struct span_info		*span;
    uint16_t			num_logicals;		/* number of logical drives */
    struct logical_drive_info	*logical;		/* logical drives */
    struct adapter_config	*next;

    /* adapter-specific data structures */
    union
    {
	struct
	{
	    mraid_inquiry1_t			inquiry;
	    struct mega_predictive_map		map;
	    disk_array_8ld_span8_t		config;
	}			v2;
	struct
	{
	    mraid_pinfo_t			adapinfo;
	    mraid_inquiry3_t			enquiry3;
	    struct mega_predictive_map		map;
	    disk_array_40ld_t			config;
	}			v3;
	struct
	{
	    struct megasas_ctrl_info		adapinfo;
	    struct mega_device_list_sas		*device;
	    struct mega_array_config_sas	config;
	    struct mega_battery_info_sas	battery;
	}			v5;
    }				q;
};


#endif
