root/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_ciss.h
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
 * Copyright (c) 2017, Joyent, Inc.
 */

#ifndef _SMRT_CISS_H
#define _SMRT_CISS_H

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * Maximum number of Scatter/Gather List entries.  These entries are statically
 * allocated for all commands.
 */
#define CISS_MAXSGENTRIES                       64

/*
 * If the controller advertises a value of 0 for the maximum S/G list length it
 * supports, the specification states that we should assume a value of 31.
 */
#define CISS_SGCNT_FALLBACK                     31

/*
 * The CDB field in the request block is fixed at 16 bytes in length.  (See
 * "3.2. Request Block" in the CISS specification.)
 */
#define CISS_CDBLEN                             16

/*
 * Command Status Values.  These are listed in "Table 2 Command Status" in "3.3
 * Error Info" of the CISS specification.
 */
#define CISS_CMD_SUCCESS                        0x00
#define CISS_CMD_TARGET_STATUS                  0x01
#define CISS_CMD_DATA_UNDERRUN                  0x02
#define CISS_CMD_DATA_OVERRUN                   0x03
#define CISS_CMD_INVALID                        0x04
#define CISS_CMD_PROTOCOL_ERR                   0x05
#define CISS_CMD_HARDWARE_ERR                   0x06
#define CISS_CMD_CONNECTION_LOST                0x07
#define CISS_CMD_ABORTED                        0x08
#define CISS_CMD_ABORT_FAILED                   0x09
#define CISS_CMD_UNSOLICITED_ABORT              0x0a
#define CISS_CMD_TIMEOUT                        0x0b
#define CISS_CMD_UNABORTABLE                    0x0c

/*
 * Request Transfer Directions, used in "RequestBlock.Type.Direction":
 */
#define CISS_XFER_NONE                          0x00
#define CISS_XFER_WRITE                         0x01
#define CISS_XFER_READ                          0x02
#define CISS_XFER_RSVD                          0x03

/*
 * Request Attributes, used in "RequestBlock.Type.Attribute":
 */
#define CISS_ATTR_UNTAGGED                      0x00
#define CISS_ATTR_SIMPLE                        0x04
#define CISS_ATTR_HEADOFQUEUE                   0x05
#define CISS_ATTR_ORDERED                       0x06

/*
 * Request Type, used in "RequestBlock.Type.Type":
 */
#define CISS_TYPE_CMD                           0x00
#define CISS_TYPE_MSG                           0x01

/*
 * I2O Space Register Offsets
 *
 * The name "I2O", and these register offsets, appear to be amongst the last
 * vestiges of a long-defunct attempt at standardising mainframe-style I/O
 * channels in the Intel server space: the Intelligent Input/Output (I2O)
 * Architecture Specification.
 *
 * The draft of version 1.5 of this specification, in section "4.2.1.5.1
 * Extensions for PCI", suggests that the following are memory offsets into
 * "the memory region specified by the first base address configuration
 * register indicating memory space (offset 10h, 14h, and so forth)".  These
 * match up with the offsets of the first two BARs in a PCI configuration space
 * type 0 header.
 *
 * The specification also calls out the Inbound Post List FIFO, write-only at
 * offset 40h; the Outbound Post List FIFO, read-only at offset 44h; the
 * Interrupt Status Register, at offset 30h; and the Interrupt Mask Register,
 * at offset 34h.
 *
 * This ill-fated attempt to increase the proprietary complexity of (and
 * presumably, thus, the gross margin on) computer systems is all but extinct.
 * The transport layer of this storage controller is all that's left of their
 * religion.
 */
#define CISS_I2O_INBOUND_DOORBELL               0x20
#define CISS_I2O_INTERRUPT_STATUS               0x30
#define CISS_I2O_INTERRUPT_MASK                 0x34
#define CISS_I2O_INBOUND_POST_Q                 0x40
#define CISS_I2O_OUTBOUND_POST_Q                0x44
#define CISS_I2O_OUTBOUND_DOORBELL_STATUS       0x9c
#define CISS_I2O_OUTBOUND_DOORBELL_CLEAR        0xa0
#define CISS_I2O_SCRATCHPAD                     0xb0
#define CISS_I2O_CFGTBL_CFG_OFFSET              0xb4
#define CISS_I2O_CFGTBL_MEM_OFFSET              0xb8

/*
 * Rather than make a lot of small mappings for each part of the address
 * space we wish to access, we will make one large mapping.  If more
 * offsets are added to the I2O list above, this space should be extended
 * appropriately.
 */
#define CISS_I2O_MAP_BASE                       0x20
#define CISS_I2O_MAP_LIMIT                      0x100

/*
 * The Scratchpad Register (I2O_SCRATCHPAD) is not mentioned in the CISS
 * specification.  It serves at least two known functions:
 *      - Signalling controller readiness
 *      - Exposing a debugging code when the controller firmware locks up
 */
#define CISS_SCRATCHPAD_INITIALISED             0xffff0000

/*
 * Outbound Doorbell Register Values.
 *
 * These are read from the Outbound Doorbell Set/Status Register
 * (CISS_I2O_OUTBOUND_DOORBELL_STATUS), but cleared by writing to the Clear
 * Register (CISS_I2O_OUTBOUND_DOORBELL_CLEAR).
 */
#define CISS_ODR_BIT_INTERRUPT                  (1UL << 0)
#define CISS_ODR_BIT_LOCKUP                     (1UL << 1)

/*
 * Inbound Doorbell Register Values.
 *
 * These are written to and read from the Inbound Doorbell Register
 * (CISS_I2O_INBOUND_DOORBELL).
 */
#define CISS_IDR_BIT_CFGTBL_CHANGE              (1UL << 0)

/*
 * Interrupt Mask Register Values.
 *
 * These are written to and read from the Interrupt Mask Register
 * (CISS_I2O_INTERRUPT_MASK).  Note that a 1 bit in this register masks or
 * disables the interrupt in question; to enable the interrupt the bit must be
 * set to 0.
 */
#define CISS_IMR_BIT_SIMPLE_INTR_DISABLE        (1UL << 3)

/*
 * Interrupt Status Register Values.
 *
 * These are read from the Interrupt Status Register
 * (CISS_I2O_INTERRUPT_STATUS).
 */
#define CISS_ISR_BIT_SIMPLE_INTR                (1UL << 3)

/*
 * Transport Methods.
 *
 * These bit positions are used in the Configuration Table to detect controller
 * support for a particular method, via "TransportSupport"; to request that the
 * controller enable a particular method, via "TransportRequest"; and to detect
 * whether the controller has acknowledged the request and enabled the desired
 * method, via "TransportActive".
 *
 * See: "9.1 Configuration Table" in the CISS Specification.
 */
#define CISS_CFGTBL_READY_FOR_COMMANDS          (1UL << 0)
#define CISS_CFGTBL_XPORT_SIMPLE                (1UL << 1)
#define CISS_CFGTBL_XPORT_PERFORMANT            (1UL << 2)
#define CISS_CFGTBL_XPORT_MEMQ                  (1UL << 4)

/*
 * In the Simple Transport Method, when the appropriate interrupt status bit is
 * set (CISS_ISR_BIT_SIMPLE_INTR), the Outbound Post Queue register is
 * repeatedly read for notifications of the completion of commands previously
 * submitted to the controller.  These macros help break up the read value into
 * its component fields: the tag number, and whether or not the command
 * completed in error.
 */
#define CISS_OPQ_READ_TAG(x)                    ((x) >> 2)
#define CISS_OPQ_READ_ERROR(x)                  ((x) & (1UL << 1))

/*
 * Physical devices that are reported may be marked as 'masked'. A masked device
 * is one that the driver can see, but must not perform any I/O to.
 */
#define SMRT_CISS_MODE_MASKED                   3

/*
 * The following packed structures are used to ease the manipulation of
 * requests and responses from the controller.
 */
#pragma pack(1)

typedef struct smrt_tag {
        uint32_t reserved:1;
        uint32_t error:1;
        uint32_t tag_value:30;
        uint32_t unused;
} smrt_tag_t;

typedef union SCSI3Addr {
        struct {
                uint8_t Dev;
                uint8_t Bus:6;
                uint8_t Mode:2;
        } PeripDev;
        struct {
                uint8_t DevLSB;
                uint8_t DevMSB:6;
                uint8_t Mode:2;
        } LogDev;
        struct {
                uint8_t Dev:5;
                uint8_t Bus:3;
                uint8_t Targ:6;
                uint8_t Mode:2;
        } LogUnit;
} SCSI3Addr_t;

typedef struct PhysDevAddr {
        uint32_t TargetId:24;
        uint32_t Bus:6;
        uint32_t Mode:2;
        SCSI3Addr_t Target[2];
} PhysDevAddr_t;

typedef struct LogDevAddr {
        uint32_t VolId:30;
        uint32_t Mode:2;
        uint8_t reserved[4];
} LogDevAddr_t;

typedef union LUNAddr {
        uint8_t LunAddrBytes[8];
        SCSI3Addr_t SCSI3Lun[4];
        PhysDevAddr_t PhysDev;
        LogDevAddr_t LogDev;
} LUNAddr_t;

typedef struct CommandListHeader {
        uint8_t ReplyQueue;
        uint8_t SGList;
        uint16_t SGTotal;
        smrt_tag_t Tag;
        LUNAddr_t LUN;
} CommandListHeader_t;

typedef struct RequestBlock {
        uint8_t CDBLen;
        struct {
                uint8_t Type:3;
                uint8_t Attribute:3;
                uint8_t Direction:2;
        } Type;
        uint16_t Timeout;
        uint8_t CDB[CISS_CDBLEN];
} RequestBlock_t;

typedef struct ErrDescriptor {
        uint64_t Addr;
        uint32_t Len;
} ErrDescriptor_t;

typedef struct SGDescriptor {
        uint64_t Addr;
        uint32_t Len;
        uint32_t Ext;
} SGDescriptor_t;

typedef struct CommandList {
        CommandListHeader_t Header;
        RequestBlock_t Request;
        ErrDescriptor_t ErrDesc;
        SGDescriptor_t SG[CISS_MAXSGENTRIES];
} CommandList_t;

typedef union MoreErrInfo {
        struct {
                uint8_t Reserved[3];
                uint8_t Type;
                uint32_t ErrorInfo;
        } Common_Info;
        struct {
                uint8_t Reserved[2];
                uint8_t offense_size;
                uint8_t offense_num;
                uint32_t offense_value;
        } Invalid_Cmd;
} MoreErrInfo_t;

typedef struct ErrorInfo {
        uint8_t ScsiStatus;
        uint8_t SenseLen;
        uint16_t CommandStatus;
        uint32_t ResidualCnt;
        MoreErrInfo_t MoreErrInfo;
        uint8_t SenseInfo[MAX_SENSE_LENGTH];
} ErrorInfo_t;

typedef struct CfgTable {
        uint8_t Signature[4];
        uint32_t SpecValence;
        uint32_t TransportSupport;
        uint32_t TransportActive;
        uint32_t TransportRequest;
        uint32_t Upper32Addr;
        uint32_t CoalIntDelay;
        uint32_t CoalIntCount;
        uint32_t CmdsOutMax;
        uint32_t BusTypes;
        uint32_t TransportMethodOffset;
        uint8_t ServerName[16];
        uint32_t HeartBeat;
        uint32_t HostDrvrSupport;
        uint32_t MaxSGElements;
        uint32_t MaxLunSupport;
        uint32_t MaxPhyDevSupport;
        uint32_t MaxPhyDrvPerLun;
        uint32_t MaxPerfModeCmdsOutMax;
        uint32_t MaxBlockFetchCount;
} CfgTable_t;

#pragma pack()

#ifdef  __cplusplus
}
#endif

#endif /* _SMRT_CISS_H */