int megaraid_io_interface(int device, int target, struct scsi_cmnd_io *, int);

#undef u32

#define u8  uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t

/*======================================================
 * PERC2/3/4 Passthrough SCSI Command Interface
 *
 * Contents from:
 *  drivers/scsi/megaraid/megaraid_ioctl.h
 *  drivers/scsi/megaraid/mbox_defs.h
 *======================================================*/
#define MEGAIOC_MAGIC  	'm'
#define MEGAIOCCMD     	_IOWR(MEGAIOC_MAGIC, 0, struct uioctl_t)

/* Following subopcode work for opcode == 0x82 */
#define MKADAP(adapno)   (MEGAIOC_MAGIC << 8 | adapno)
#define MEGAIOC_QNADAP     'm'
#define MEGAIOC_QDRVRVER   'e'
#define MEGAIOC_QADAPINFO  'g'

#define MEGA_MBOXCMD_PASSTHRU 0x03

#define MAX_REQ_SENSE_LEN  0x20
#define MAX_CDB_LEN 10

typedef struct
{
	uint8_t  timeout : 3;
	uint8_t  ars : 1;
	uint8_t  reserved : 3;
	uint8_t  islogical : 1;
	uint8_t  logdrv;
	uint8_t  channel;
	uint8_t  target;
	uint8_t  queuetag;
	uint8_t  queueaction;
	uint8_t  cdb[MAX_CDB_LEN];
	uint8_t  cdblen;
	uint8_t  reqsenselen;
	uint8_t  reqsensearea[MAX_REQ_SENSE_LEN];
	uint8_t  numsgelements;
	uint8_t  scsistatus;
	uint32_t dataxferaddr;
	uint32_t dataxferlen;
} __attribute__((packed)) mega_passthru;

typedef struct
{
	uint8_t   cmd;
	uint8_t   cmdid;
	uint8_t   opcode;
	uint8_t   subopcode;
	uint32_t  lba;
	uint32_t  xferaddr;
	uint8_t   logdrv;
	uint8_t   resvd[3];
	uint8_t   numstatus;
	uint8_t   status;
} __attribute__((packed)) megacmd_t;

typedef union {
	uint8_t   *pointer;
	uint8_t    pad[8];
} ptr_t;

// The above definition assumes sizeof(void*) <= 8.
// This assumption also exists in the linux megaraid device driver.
// So define a macro to check expected size of ptr_t at compile time using
// a dummy typedef.  On size mismatch, compiler reports a negative array
// size.  If you see an error message of this form, it means that
// you have an unexpected pointer size on your platform and can not
// use megaraid support in smartmontools.
typedef char assert_sizeof_ptr_t[sizeof(ptr_t) == 8 ? 1 : -1];

struct uioctl_t
{
	uint32_t       inlen;
	uint32_t       outlen;
	union {
		uint8_t      fca[16];
		struct {
			uint8_t  opcode;
			uint8_t  subopcode;
			uint16_t adapno;
			ptr_t    buffer;
			uint32_t length;
		} __attribute__((packed)) fcs;
	} __attribute__((packed)) ui;

	megacmd_t     mbox;
	mega_passthru pthru;
	ptr_t         data;
} __attribute__((packed));

/*===================================================
 * PERC5/6 Passthrough SCSI Command Interface
 *
 * Contents from:
 *  drivers/scsi/megaraid/megaraid_sas.h
 *===================================================*/
#define MEGASAS_MAGIC          'M'
#define MEGASAS_IOC_FIRMWARE   _IOWR(MEGASAS_MAGIC, 1, struct megasas_iocpacket)

#define MFI_CMD_PD_SCSI_IO        0x04
#define MFI_FRAME_SGL64           0x02
#define MFI_FRAME_DIR_READ        0x10 

#define MAX_IOCTL_SGE			16

struct megasas_sge32 {

	u32 phys_addr;
	u32 length;

} __attribute__ ((packed));

struct megasas_sge64 {

	u64 phys_addr;
	u32 length;

} __attribute__ ((packed));

union megasas_sgl {

	struct megasas_sge32 sge32[1];
	struct megasas_sge64 sge64[1];

} __attribute__ ((packed));

struct megasas_header {

	u8 cmd;			/*00h */
	u8 sense_len;		/*01h */
	u8 cmd_status;		/*02h */
	u8 scsi_status;		/*03h */

	u8 target_id;		/*04h */
	u8 lun;			/*05h */
	u8 cdb_len;		/*06h */
	u8 sge_count;		/*07h */

	u32 context;		/*08h */
	u32 pad_0;		/*0Ch */

	u16 flags;		/*10h */
	u16 timeout;		/*12h */
	u32 data_xferlen;	/*14h */

} __attribute__ ((packed));

struct megasas_pthru_frame {

	u8 cmd;			/*00h */
	u8 sense_len;		/*01h */
	u8 cmd_status;		/*02h */
	u8 scsi_status;		/*03h */

	u8 target_id;		/*04h */
	u8 lun;			/*05h */
	u8 cdb_len;		/*06h */
	u8 sge_count;		/*07h */

	u32 context;		/*08h */
	u32 pad_0;		/*0Ch */

	u16 flags;		/*10h */
	u16 timeout;		/*12h */
	u32 data_xfer_len;	/*14h */

	u32 sense_buf_phys_addr_lo;	/*18h */
	u32 sense_buf_phys_addr_hi;	/*1Ch */

	u8 cdb[16];		/*20h */
	union megasas_sgl sgl;	/*30h */

} __attribute__ ((packed));

struct megasas_dcmd_frame {

	u8 cmd;			/*00h */
	u8 reserved_0;		/*01h */
	u8 cmd_status;		/*02h */
	u8 reserved_1[4];	/*03h */
	u8 sge_count;		/*07h */

	u32 context;		/*08h */
	u32 pad_0;		/*0Ch */

	u16 flags;		/*10h */
	u16 timeout;		/*12h */

	u32 data_xfer_len;	/*14h */
	u32 opcode;		/*18h */

	union {			/*1Ch */
		u8 b[12];
		u16 s[6];
		u32 w[3];
	} mbox;

	union megasas_sgl sgl;	/*28h */

} __attribute__ ((packed));

struct megasas_iocpacket {

	u16 host_no;
	u16 __pad1;
	u32 sgl_off;
	u32 sge_count;
	u32 sense_off;
	u32 sense_len;
	union {
		u8 raw[128];
		struct megasas_header hdr;
		struct megasas_pthru_frame pthru;
	} frame;

	struct iovec sgl[MAX_IOCTL_SGE];

} __attribute__ ((packed));

#undef u8
#undef u16
#undef u32
#undef u64

