root/drivers/scsi/mvumi.h
/* SPDX-License-Identifier: GPL-2.0-only */
/*
  * Marvell UMI head file
  *
  * Copyright 2011 Marvell. <jyli@marvell.com>
 */

#ifndef MVUMI_H
#define MVUMI_H

#define MAX_BASE_ADDRESS        6

#define VER_MAJOR               1
#define VER_MINOR               1
#define VER_OEM                 0
#define VER_BUILD               1500

#define MV_DRIVER_NAME                  "mvumi"
#define PCI_DEVICE_ID_MARVELL_MV9143    0x9143
#define PCI_DEVICE_ID_MARVELL_MV9580    0x9580

#define MVUMI_INTERNAL_CMD_WAIT_TIME    45
#define MVUMI_INQUIRY_LENGTH            44
#define MVUMI_INQUIRY_UUID_OFF          36
#define MVUMI_INQUIRY_UUID_LEN          8

#define IS_DMA64                        (sizeof(dma_addr_t) == 8)

enum mvumi_qc_result {
        MV_QUEUE_COMMAND_RESULT_SENT = 0,
        MV_QUEUE_COMMAND_RESULT_NO_RESOURCE,
};

struct mvumi_hw_regs {
        /* For CPU */
        void *main_int_cause_reg;
        void *enpointa_mask_reg;
        void *enpointb_mask_reg;
        void *rstoutn_en_reg;
        void *ctrl_sts_reg;
        void *rstoutn_mask_reg;
        void *sys_soft_rst_reg;

        /* For Doorbell */
        void *pciea_to_arm_drbl_reg;
        void *arm_to_pciea_drbl_reg;
        void *arm_to_pciea_mask_reg;
        void *pciea_to_arm_msg0;
        void *pciea_to_arm_msg1;
        void *arm_to_pciea_msg0;
        void *arm_to_pciea_msg1;

        /* reset register */
        void *reset_request;
        void *reset_enable;

        /* For Message Unit */
        void *inb_list_basel;
        void *inb_list_baseh;
        void *inb_aval_count_basel;
        void *inb_aval_count_baseh;
        void *inb_write_pointer;
        void *inb_read_pointer;
        void *outb_list_basel;
        void *outb_list_baseh;
        void *outb_copy_basel;
        void *outb_copy_baseh;
        void *outb_copy_pointer;
        void *outb_read_pointer;
        void *inb_isr_cause;
        void *outb_isr_cause;
        void *outb_coal_cfg;
        void *outb_coal_timeout;

        /* Bit setting for HW */
        u32 int_comaout;
        u32 int_comaerr;
        u32 int_dl_cpu2pciea;
        u32 int_mu;
        u32 int_drbl_int_mask;
        u32 int_main_int_mask;
        u32 cl_pointer_toggle;
        u32 cl_slot_num_mask;
        u32 clic_irq;
        u32 clic_in_err;
        u32 clic_out_err;
};

struct mvumi_dyn_list_entry {
        u32 src_low_addr;
        u32 src_high_addr;
        u32 if_length;
        u32 reserve;
};

#define SCSI_CMD_MARVELL_SPECIFIC       0xE1
#define CDB_CORE_MODULE                 0x1
#define CDB_CORE_SHUTDOWN               0xB

enum {
        DRBL_HANDSHAKE                  = 1 << 0,
        DRBL_SOFT_RESET                 = 1 << 1,
        DRBL_BUS_CHANGE                 = 1 << 2,
        DRBL_EVENT_NOTIFY               = 1 << 3,
        DRBL_MU_RESET                   = 1 << 4,
        DRBL_HANDSHAKE_ISR              = DRBL_HANDSHAKE,

        /*
        * Command flag is the flag for the CDB command itself
        */
        /* 1-non data; 0-data command */
        CMD_FLAG_NON_DATA               = 1 << 0,
        CMD_FLAG_DMA                    = 1 << 1,
        CMD_FLAG_PIO                    = 1 << 2,
        /* 1-host read data */
        CMD_FLAG_DATA_IN                = 1 << 3,
        /* 1-host write data */
        CMD_FLAG_DATA_OUT               = 1 << 4,
        CMD_FLAG_PRDT_IN_HOST           = 1 << 5,
};

#define APICDB0_EVENT                   0xF4
#define APICDB1_EVENT_GETEVENT          0
#define APICDB1_HOST_GETEVENT           1
#define MAX_EVENTS_RETURNED             6

#define DEVICE_OFFLINE  0
#define DEVICE_ONLINE   1

struct mvumi_hotplug_event {
        u16 size;
        u8 dummy[2];
        u8 bitmap[];
};

struct mvumi_driver_event {
        u32     time_stamp;
        u32     sequence_no;
        u32     event_id;
        u8      severity;
        u8      param_count;
        u16     device_id;
        u32     params[4];
        u8      sense_data_length;
        u8      Reserved1;
        u8      sense_data[30];
};

struct mvumi_event_req {
        unsigned char   count;
        unsigned char   reserved[3];
        struct mvumi_driver_event  events[MAX_EVENTS_RETURNED];
};

struct mvumi_events_wq {
        struct work_struct work_q;
        struct mvumi_hba *mhba;
        unsigned int event;
        void *param;
};

#define HS_CAPABILITY_SUPPORT_COMPACT_SG        (1U << 4)
#define HS_CAPABILITY_SUPPORT_PRD_HOST          (1U << 5)
#define HS_CAPABILITY_SUPPORT_DYN_SRC           (1U << 6)
#define HS_CAPABILITY_NEW_PAGE_IO_DEPTH_DEF     (1U << 14)

#define MVUMI_MAX_SG_ENTRY      32
#define SGD_EOT                 (1L << 27)
#define SGD_EOT_CP              (1L << 22)

struct mvumi_sgl {
        u32     baseaddr_l;
        u32     baseaddr_h;
        u32     flags;
        u32     size;
};
struct mvumi_compact_sgl {
        u32     baseaddr_l;
        u32     baseaddr_h;
        u32     flags;
};

#define GET_COMPACT_SGD_SIZE(sgd)       \
        ((((struct mvumi_compact_sgl *)(sgd))->flags) & 0x3FFFFFL)

#define SET_COMPACT_SGD_SIZE(sgd, sz) do {                      \
        (((struct mvumi_compact_sgl *)(sgd))->flags) &= ~0x3FFFFFL;     \
        (((struct mvumi_compact_sgl *)(sgd))->flags) |= (sz);           \
} while (0)
#define sgd_getsz(_mhba, sgd, sz) do {                          \
        if (_mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG)   \
                (sz) = GET_COMPACT_SGD_SIZE(sgd);       \
        else \
                (sz) = (sgd)->size;                     \
} while (0)

#define sgd_setsz(_mhba, sgd, sz) do {                          \
        if (_mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG)   \
                SET_COMPACT_SGD_SIZE(sgd, sz);          \
        else \
                (sgd)->size = (sz);                     \
} while (0)

#define sgd_inc(_mhba, sgd) do {        \
        if (_mhba->hba_capability & HS_CAPABILITY_SUPPORT_COMPACT_SG)   \
                sgd = (struct mvumi_sgl *)(((unsigned char *) (sgd)) + 12); \
        else \
                sgd = (struct mvumi_sgl *)(((unsigned char *) (sgd)) + 16); \
} while (0)

struct mvumi_res {
        struct list_head entry;
        dma_addr_t bus_addr;
        void *virt_addr;
        unsigned int size;
        unsigned short type;    /* enum Resource_Type */
};

/* Resource type */
enum resource_type {
        RESOURCE_CACHED_MEMORY = 0,
        RESOURCE_UNCACHED_MEMORY
};

struct mvumi_sense_data {
        u8 error_code:7;
        u8 valid:1;
        u8 segment_number;
        u8 sense_key:4;
        u8 reserved:1;
        u8 incorrect_length:1;
        u8 end_of_media:1;
        u8 file_mark:1;
        u8 information[4];
        u8 additional_sense_length;
        u8 command_specific_information[4];
        u8 additional_sense_code;
        u8 additional_sense_code_qualifier;
        u8 field_replaceable_unit_code;
        u8 sense_key_specific[3];
};

/* Request initiator must set the status to REQ_STATUS_PENDING. */
#define REQ_STATUS_PENDING              0x80

struct mvumi_cmd {
        struct list_head queue_pointer;
        struct mvumi_msg_frame *frame;
        dma_addr_t frame_phys;
        struct scsi_cmnd *scmd;
        atomic_t sync_cmd;
        void *data_buf;
        unsigned short request_id;
        unsigned char cmd_status;
};

struct mvumi_cmd_priv {
        struct mvumi_cmd *cmd_priv;
};

static inline struct mvumi_cmd_priv *mvumi_priv(struct scsi_cmnd *cmd)
{
        return scsi_cmd_priv(cmd);
}

/*
 * the function type of the in bound frame
 */
#define CL_FUN_SCSI_CMD                 0x1

struct mvumi_msg_frame {
        u16 device_id;
        u16 tag;
        u8 cmd_flag;
        u8 req_function;
        u8 cdb_length;
        u8 sg_counts;
        u32 data_transfer_length;
        u16 request_id;
        u16 reserved1;
        u8 cdb[MAX_COMMAND_SIZE];
        u32 payload[];
};

/*
 * the respond flag for data_payload of the out bound frame
 */
#define CL_RSP_FLAG_NODATA              0x0
#define CL_RSP_FLAG_SENSEDATA           0x1

struct mvumi_rsp_frame {
        u16 device_id;
        u16 tag;
        u8 req_status;
        u8 rsp_flag;    /* Indicates the type of Data_Payload.*/
        u16 request_id;
        u32 payload[];
};

struct mvumi_ob_data {
        struct list_head list;
        unsigned char data[];
};

struct version_info {
        u32 ver_major;
        u32 ver_minor;
        u32 ver_oem;
        u32 ver_build;
};

#define FW_MAX_DELAY                    30
#define MVUMI_FW_BUSY                   (1U << 0)
#define MVUMI_FW_ATTACH                 (1U << 1)
#define MVUMI_FW_ALLOC                  (1U << 2)

/*
 * State is the state of the MU
 */
#define FW_STATE_IDLE                   0
#define FW_STATE_STARTING               1
#define FW_STATE_HANDSHAKING            2
#define FW_STATE_STARTED                3
#define FW_STATE_ABORT                  4

#define HANDSHAKE_SIGNATURE             0x5A5A5A5AL
#define HANDSHAKE_READYSTATE            0x55AA5AA5L
#define HANDSHAKE_DONESTATE             0x55AAA55AL

/* HandShake Status definition */
#define HS_STATUS_OK                    1
#define HS_STATUS_ERR                   2
#define HS_STATUS_INVALID               3

/* HandShake State/Cmd definition */
#define HS_S_START                      1
#define HS_S_RESET                      2
#define HS_S_PAGE_ADDR                  3
#define HS_S_QUERY_PAGE                 4
#define HS_S_SEND_PAGE                  5
#define HS_S_END                        6
#define HS_S_ABORT                      7
#define HS_PAGE_VERIFY_SIZE             128

#define HS_GET_STATE(a)                 (a & 0xFFFF)
#define HS_GET_STATUS(a)                ((a & 0xFFFF0000) >> 16)
#define HS_SET_STATE(a, b)              (a |= (b & 0xFFFF))
#define HS_SET_STATUS(a, b)             (a |= ((b & 0xFFFF) << 16))

/* handshake frame */
struct mvumi_hs_frame {
        u16 size;
        /* host information */
        u8 host_type;
        u8 reserved_1[1];
        struct version_info host_ver; /* bios or driver version */

        /* controller information */
        u32 system_io_bus;
        u32 slot_number;
        u32 intr_level;
        u32 intr_vector;

        /* communication list configuration */
        u32 ib_baseaddr_l;
        u32 ib_baseaddr_h;
        u32 ob_baseaddr_l;
        u32 ob_baseaddr_h;

        u8 ib_entry_size;
        u8 ob_entry_size;
        u8 ob_depth;
        u8 ib_depth;

        /* system time */
        u64 seconds_since1970;
};

struct mvumi_hs_header {
        u8      page_code;
        u8      checksum;
        u16     frame_length;
        u32     frame_content[];
};

/*
 * the page code type of the handshake header
 */
#define HS_PAGE_FIRM_CAP        0x1
#define HS_PAGE_HOST_INFO       0x2
#define HS_PAGE_FIRM_CTL        0x3
#define HS_PAGE_CL_INFO         0x4
#define HS_PAGE_TOTAL           0x5

#define HSP_SIZE(i)     sizeof(struct mvumi_hs_page##i)

#define HSP_MAX_SIZE ({                                 \
        int size, m1, m2;                               \
        m1 = max(HSP_SIZE(1), HSP_SIZE(3));             \
        m2 = max(HSP_SIZE(2), HSP_SIZE(4));             \
        size = max(m1, m2);                             \
        size;                                           \
})

/* The format of the page code for Firmware capability */
struct mvumi_hs_page1 {
        u8 pagecode;
        u8 checksum;
        u16 frame_length;

        u16 number_of_ports;
        u16 max_devices_support;
        u16 max_io_support;
        u16 umi_ver;
        u32 max_transfer_size;
        struct version_info fw_ver;
        u8 cl_in_max_entry_size;
        u8 cl_out_max_entry_size;
        u8 cl_inout_list_depth;
        u8 total_pages;
        u16 capability;
        u16 reserved1;
};

/* The format of the page code for Host information */
struct mvumi_hs_page2 {
        u8 pagecode;
        u8 checksum;
        u16 frame_length;

        u8 host_type;
        u8 host_cap;
        u8 reserved[2];
        struct version_info host_ver;
        u32 system_io_bus;
        u32 slot_number;
        u32 intr_level;
        u32 intr_vector;
        u64 seconds_since1970;
};

/* The format of the page code for firmware control  */
struct mvumi_hs_page3 {
        u8      pagecode;
        u8      checksum;
        u16     frame_length;
        u16     control;
        u8      reserved[2];
        u32     host_bufferaddr_l;
        u32     host_bufferaddr_h;
        u32     host_eventaddr_l;
        u32     host_eventaddr_h;
};

struct mvumi_hs_page4 {
        u8      pagecode;
        u8      checksum;
        u16     frame_length;
        u32     ib_baseaddr_l;
        u32     ib_baseaddr_h;
        u32     ob_baseaddr_l;
        u32     ob_baseaddr_h;
        u8      ib_entry_size;
        u8      ob_entry_size;
        u8      ob_depth;
        u8      ib_depth;
};

struct mvumi_tag {
        unsigned short *stack;
        unsigned short top;
        unsigned short size;
};

struct mvumi_device {
        struct list_head list;
        struct scsi_device *sdev;
        u64     wwid;
        u8      dev_type;
        int     id;
};

struct mvumi_hba {
        void *base_addr[MAX_BASE_ADDRESS];
        u32 pci_base[MAX_BASE_ADDRESS];
        void *mmio;
        struct list_head cmd_pool;
        struct Scsi_Host *shost;
        wait_queue_head_t int_cmd_wait_q;
        struct pci_dev *pdev;
        unsigned int unique_id;
        atomic_t fw_outstanding;
        struct mvumi_instance_template *instancet;

        void *ib_list;
        dma_addr_t ib_list_phys;

        void *ib_frame;
        dma_addr_t ib_frame_phys;

        void *ob_list;
        dma_addr_t ob_list_phys;

        void *ib_shadow;
        dma_addr_t ib_shadow_phys;

        void *ob_shadow;
        dma_addr_t ob_shadow_phys;

        void *handshake_page;
        dma_addr_t handshake_page_phys;

        unsigned int global_isr;
        unsigned int isr_status;

        unsigned short max_sge;
        unsigned short max_target_id;
        unsigned char *target_map;
        unsigned int max_io;
        unsigned int list_num_io;
        unsigned int ib_max_size;
        unsigned int ob_max_size;
        unsigned int ib_max_size_setting;
        unsigned int ob_max_size_setting;
        unsigned int max_transfer_size;
        unsigned char hba_total_pages;
        unsigned char fw_flag;
        unsigned char request_id_enabled;
        unsigned char eot_flag;
        unsigned short hba_capability;
        unsigned short io_seq;

        unsigned int ib_cur_slot;
        unsigned int ob_cur_slot;
        unsigned int fw_state;
        struct mutex sas_discovery_mutex;

        struct list_head ob_data_list;
        struct list_head free_ob_list;
        struct list_head res_list;
        struct list_head waiting_req_list;

        struct mvumi_tag tag_pool;
        struct mvumi_cmd **tag_cmd;
        struct mvumi_hw_regs *regs;
        struct mutex device_lock;
        struct list_head mhba_dev_list;
        struct list_head shost_dev_list;
        struct task_struct *dm_thread;
        atomic_t pnp_count;
};

struct mvumi_instance_template {
        void (*fire_cmd) (struct mvumi_hba *, struct mvumi_cmd *);
        void (*enable_intr) (struct mvumi_hba *);
        void (*disable_intr) (struct mvumi_hba *);
        int (*clear_intr) (void *);
        unsigned int (*read_fw_status_reg) (struct mvumi_hba *);
        unsigned int (*check_ib_list) (struct mvumi_hba *);
        int (*check_ob_list) (struct mvumi_hba *, unsigned int *,
                              unsigned int *);
        int (*reset_host) (struct mvumi_hba *);
};

extern struct timezone sys_tz;
#endif