/** @file

  Macros and type definitions for LSI Fusion MPT SCSI devices.

  Copyright (C) 2020, Oracle and/or its affiliates.

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef __FUSION_MPT_SCSI_H__
#define __FUSION_MPT_SCSI_H__

//
// Device offsets and constants
//

#define LSI_LOGIC_PCI_VENDOR_ID 0x1000
#define LSI_53C1030_PCI_DEVICE_ID 0x0030
#define LSI_SAS1068_PCI_DEVICE_ID 0x0054
#define LSI_SAS1068E_PCI_DEVICE_ID 0x0058

#define MPT_REG_DOORBELL  0x00
#define MPT_REG_WRITE_SEQ 0x04
#define MPT_REG_HOST_DIAG 0x08
#define MPT_REG_TEST      0x0c
#define MPT_REG_DIAG_DATA 0x10
#define MPT_REG_DIAG_ADDR 0x14
#define MPT_REG_ISTATUS   0x30
#define MPT_REG_IMASK     0x34
#define MPT_REG_REQ_Q     0x40
#define MPT_REG_REP_Q     0x44

#define MPT_DOORBELL_RESET     0x40
#define MPT_DOORBELL_HANDSHAKE 0x42

#define MPT_IMASK_DOORBELL 0x01
#define MPT_IMASK_REPLY    0x08

#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST 0x00
#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT        0x02

#define MPT_SG_ENTRY_TYPE_SIMPLE 0x01

#define MPT_IOC_WHOINIT_ROM_BIOS 0x02

#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE  (0x00 << 24)
#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE (0x01 << 24)
#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ  (0x02 << 24)

#define MPT_SCSI_IOCSTATUS_SUCCESS          0x0000
#define MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE 0x0043
#define MPT_SCSI_IOCSTATUS_DATA_OVERRUN     0x0044
#define MPT_SCSI_IOCSTATUS_DATA_UNDERRUN    0x0045

//
// Device structures
//

#pragma pack (1)
typedef struct {
  UINT8     WhoInit;
  UINT8     Reserved1;
  UINT8     ChainOffset;
  UINT8     Function;
  UINT8     Flags;
  UINT8     MaxDevices;
  UINT8     MaxBuses;
  UINT8     MessageFlags;
  UINT32    MessageContext;
  UINT16    ReplyFrameSize;
  UINT16    Reserved2;
  UINT32    HostMfaHighAddr;
  UINT32    SenseBufferHighAddr;
} MPT_IO_CONTROLLER_INIT_REQUEST;

typedef struct {
  UINT8     WhoInit;
  UINT8     Reserved1;
  UINT8     MessageLength;
  UINT8     Function;
  UINT8     Flags;
  UINT8     MaxDevices;
  UINT8     MaxBuses;
  UINT8     MessageFlags;
  UINT32    MessageContext;
  UINT16    Reserved2;
  UINT16    IocStatus;
  UINT32    IocLogInfo;
} MPT_IO_CONTROLLER_INIT_REPLY;

typedef struct {
  UINT8     TargetId;
  UINT8     Bus;
  UINT8     ChainOffset;
  UINT8     Function;
  UINT8     CdbLength;
  UINT8     SenseBufferLength;
  UINT8     Reserved;
  UINT8     MessageFlags;
  UINT32    MessageContext;
  UINT8     Lun[8];
  UINT32    Control;
  UINT8     Cdb[16];
  UINT32    DataLength;
  UINT32    SenseBufferLowAddress;
} MPT_SCSI_IO_REQUEST;

typedef struct {
  UINT32    Length:             24;
  UINT32    EndOfList:          1;
  UINT32    Is64BitAddress:     1;
  //
  // True when the buffer contains data to be transfered. Otherwise it's the
  // destination buffer
  //
  UINT32    BufferContainsData: 1;
  UINT32    LocalAddress:       1;
  UINT32    ElementType:        2;
  UINT32    EndOfBuffer:        1;
  UINT32    LastElement:        1;
  UINT64    DataBufferAddress;
} MPT_SG_ENTRY_SIMPLE;

typedef struct {
  UINT8     TargetId;
  UINT8     Bus;
  UINT8     MessageLength;
  UINT8     Function;
  UINT8     CdbLength;
  UINT8     SenseBufferLength;
  UINT8     Reserved;
  UINT8     MessageFlags;
  UINT32    MessageContext;
  UINT8     ScsiStatus;
  UINT8     ScsiState;
  UINT16    IocStatus;
  UINT32    IocLogInfo;
  UINT32    TransferCount;
  UINT32    SenseCount;
  UINT32    ResponseInfo;
} MPT_SCSI_IO_REPLY;

typedef struct {
  MPT_SCSI_IO_REQUEST Header;
  MPT_SG_ENTRY_SIMPLE Sg;
} MPT_SCSI_REQUEST_WITH_SG;
#pragma pack ()

typedef union {
  MPT_SCSI_IO_REPLY        Data;
  UINT64                   Uint64; // 8 byte alignment required by HW
} MPT_SCSI_IO_REPLY_ALIGNED;

typedef union {
  MPT_SCSI_REQUEST_WITH_SG Data;
  UINT64                   Uint64; // 8 byte alignment required by HW
} MPT_SCSI_REQUEST_ALIGNED;

#endif // __FUSION_MPT_SCSI_H__
