root/sys/dev/vmware/pvscsi/pvscsi.h
/*-
 * Copyright (c) 2018 VMware, Inc.
 *
 * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
 */

#ifndef _PVSCSI_H_
#define _PVSCSI_H_

#define MASK(v) ((1 << (v)) - 1)

#define PCI_VENDOR_ID_VMWARE            0x15ad
#define PCI_DEVICE_ID_VMWARE_PVSCSI     0x07c0

enum pvscsi_reg_offset {
        PVSCSI_REG_OFFSET_COMMAND               = 0x0000,
        PVSCSI_REG_OFFSET_COMMAND_DATA          = 0x0004,
        PVSCSI_REG_OFFSET_COMMAND_STATUS        = 0x0008,
        PVSCSI_REG_OFFSET_LAST_STS_0            = 0x0100,
        PVSCSI_REG_OFFSET_LAST_STS_1            = 0x0104,
        PVSCSI_REG_OFFSET_LAST_STS_2            = 0x0108,
        PVSCSI_REG_OFFSET_LAST_STS_3            = 0x010c,
        PVSCSI_REG_OFFSET_INTR_STATUS           = 0x100c,
        PVSCSI_REG_OFFSET_INTR_MASK             = 0x2010,
        PVSCSI_REG_OFFSET_KICK_NON_RW_IO        = 0x3014,
        PVSCSI_REG_OFFSET_DEBUG                 = 0x3018,
        PVSCSI_REG_OFFSET_KICK_RW_IO            = 0x4018,
};

enum pvscsi_commands {
        PVSCSI_CMD_FIRST                        = 0,

        PVSCSI_CMD_ADAPTER_RESET                = 1,
        PVSCSI_CMD_ISSUE_SCSI                   = 2,
        PVSCSI_CMD_SETUP_RINGS                  = 3,
        PVSCSI_CMD_RESET_BUS                    = 4,
        PVSCSI_CMD_RESET_DEVICE                 = 5,
        PVSCSI_CMD_ABORT_CMD                    = 6,
        PVSCSI_CMD_CONFIG                       = 7,
        PVSCSI_CMD_SETUP_MSG_RING               = 8,
        PVSCSI_CMD_DEVICE_UNPLUG                = 9,
        PVSCSI_CMD_SETUP_REQCALLTHRESHOLD       = 10,
        PVSCSI_CMD_GET_MAX_TARGETS              = 11,

        PVSCSI_CMD_LAST                         = 12,
};

struct pvscsi_cmd_desc_reset_device {
        uint32_t        target;
        uint8_t         lun[8];
};

struct pvscsi_cmd_desc_abort_cmd {
        uint64_t        context;
        uint32_t        target;
        uint32_t        pad;
};

#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES        32
#define PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES     16

struct pvscsi_cmd_desc_setup_rings {
        uint32_t        req_ring_num_pages;
        uint32_t        cmp_ring_num_pages;
        uint64_t        rings_state_ppn;
        uint64_t        req_ring_ppns[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
        uint64_t        cmp_ring_ppns[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
};

struct pvscsi_cmd_desc_setup_msg_ring {
        uint32_t        num_pages;
        uint32_t        pad_;
        uint64_t        ring_ppns[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES];
};

struct pvscsi_rings_state {
        uint32_t        req_prod_idx;
        uint32_t        req_cons_idx;
        uint32_t        req_num_entries_log2;
        uint32_t        cmp_prod_idx;
        uint32_t        cmp_cons_idx;
        uint32_t        cmp_num_entries_log2;
        uint32_t        req_call_threshold;
        uint8_t         _pad[100];
        uint32_t        msg_prod_idx;
        uint32_t        msg_cons_idx;
        uint32_t        msg_num_entries_log2;
};

#define PVSCSI_FLAG_CMD_WITH_SG_LIST    (1 << 0)
#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
#define PVSCSI_FLAG_CMD_DIR_NONE        (1 << 2)
#define PVSCSI_FLAG_CMD_DIR_TOHOST      (1 << 3)
#define PVSCSI_FLAG_CMD_DIR_TODEVICE    (1 << 4)

#define PVSCSI_FLAG_RESERVED_MASK       (~MASK(5))

#define PVSCSI_INTR_CMPL_0      (1 << 0)
#define PVSCSI_INTR_CMPL_1      (1 << 1)
#define PVSCSI_INTR_CMPL_MASK   MASK(2)

#define PVSCSI_INTR_MSG_0       (1 << 2)
#define PVSCSI_INTR_MSG_1       (1 << 3)
#define PVSCSI_INTR_MSG_MASK    (MASK(2) << 2)

#define PVSCSI_INTR_ALL_SUPPORTED       MASK(4)

struct pvscsi_ring_req_desc {
        uint64_t        context;
        uint64_t        data_addr;
        uint64_t        data_len;
        uint64_t        sense_addr;
        uint32_t        sense_len;
        uint32_t        flags;
        uint8_t         cdb[16];
        uint8_t         cdb_len;
        uint8_t         lun[8];
        uint8_t         tag;
        uint8_t         bus;
        uint8_t         target;
        uint16_t        vcpu_hint;
        uint8_t         unused[58];
};

struct pvscsi_ring_cmp_desc {
        uint64_t        context;
        uint64_t        data_len;
        uint32_t        sense_len;
        uint16_t        host_status;
        uint16_t        scsi_status;
        uint32_t        _pad[2];
};

#define PVSCSI_MAX_SG_ENTRIES_PER_SEGMENT       128
#define PVSCSI_MAX_NUM_SG_SEGMENTS              128
#define PVSCSI_SGE_FLAG_CHAIN_ELEMENT           (1 << 0)

struct pvscsi_sg_element {
        uint64_t        addr;
        uint32_t        length;
        uint32_t        flags;
};

enum pvscsi_msg_type {
        PVSCSI_MSG_DEV_ADDED    = 0,
        PVSCSI_MSG_DEV_REMOVED  = 1,
        PVSCSI_MSG_LAST = 2,
};

struct pvscsi_ring_msg_desc {
        uint32_t        type;
        uint32_t        args[31];
};

struct pvscsi_ring_msg_dev_status_changed {
        uint32_t        type;
        uint32_t        bus;
        uint32_t        target;
        uint8_t         lun[8];
        uint32_t        pad[27];
};

struct pvscsi_cmd_desc_setup_req_call {
        uint32_t        enable;
};

#define PVSCSI_MAX_NUM_PAGES_REQ_RING   PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
#define PVSCSI_MAX_NUM_PAGES_CMP_RING   PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
#define PVSCSI_MAX_NUM_PAGES_MSG_RING   PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES

#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE \
        (PAGE_SIZE / sizeof(struct pvscsi_ring_req_desc))
#define PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE \
        (PAGE_SIZE / sizeof(struct pvscs_ring_cmp_desc))
#define PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE \
        (PAGE_SIZE / sizeof(struct pvscsi_ring_msg_desc))

#define PVSCSI_MAX_REQ_QUEUE_DEPTH \
        (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE)
#define PVSCSI_MAX_CMP_QUEUE_DEPTH \
        (PVSCSI_MAX_NUM_PAGES_CMP_RING * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE)
#define PVSCSI_MAX_QUEUE_DEPTH \
        MAX(PVSCSI_MAX_REQ_QUEUE_DEPTH, PVSCSI_MAX_CMP_QUEUE_DEPTH)

enum pvscsi_host_status {
        BTSTAT_SUCCESS          = 0x00,
        BTSTAT_LINKED_COMMAND_COMPLETED                 = 0x0a,
        BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG       = 0x0b,
        BTSTAT_DATA_UNDERRUN    = 0x0c,
        BTSTAT_SELTIMEO         = 0x11,
        BTSTAT_DATARUN          = 0x12,
        BTSTAT_BUSFREE          = 0x13,
        BTSTAT_INVPHASE         = 0x14,
        BTSTAT_INVCODE          = 0x15,
        BTSTAT_INVOPCODE        = 0x16,
        BTSTAT_LUNMISMATCH      = 0x17,
        BTSTAT_INVPARAM         = 0x1a,
        BTSTAT_SENSFAILED       = 0x1b,
        BTSTAT_TAGREJECT        = 0x1c,
        BTSTAT_BADMSG           = 0x1d,
        BTSTAT_HAHARDWARE       = 0x20,
        BTSTAT_NORESPONSE       = 0x21,
        BTSTAT_SENTRST          = 0x22,
        BTSTAT_RECVRST          = 0x23,
        BTSTAT_DISCONNECT       = 0x24,
        BTSTAT_BUSRESET         = 0x25,
        BTSTAT_ABORTQUEUE       = 0x26,
        BTSTAT_HASOFTWARE       = 0x27,
        BTSTAT_HATIMEOUT        = 0x30,
        BTSTAT_SCSIPARITY       = 0x34,
};

#endif /* !_PVSCSI_H_ */