root/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_scsi.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_SCSI_H
#define _SMRT_SCSI_H

#include <sys/types.h>

#include <sys/scsi/adapters/smrt/smrt_ciss.h>

#ifdef  __cplusplus
extern "C" {
#endif

/* CISS LUN Addressing MODEs */
#define PERIPHERIAL_DEV_ADDR                    0x0
#define LOGICAL_VOL_ADDR                        0x1
#define MASK_PERIPHERIAL_DEV_ADDR               0x3
#define CISS_PHYS_MODE                          0x0

/*
 * Vendor-specific SCSI Commands
 *
 * These command opcodes are for use in the opcode byte of the CDB in a request
 * of type CISS_TYPE_CMD.  They are custom SCSI commands, using the
 * vendor-specific part of the opcode space; i.e., 0xC0 through 0xFF.
 */
#define CISS_SCMD_READ                          0xC0
#define CISS_SCMD_WRITE                         0xC1
#define CISS_SCMD_REPORT_LOGICAL_LUNS           0xC2
#define CISS_SCMD_REPORT_PHYSICAL_LUNS          0xC3

/*
 * These command opcodes are _not_ in the usual vendor-specific space, but are
 * nonetheless vendor-specific.  They allow BMIC commands to be written to and
 * read from the controller.  If a command transfers no data, the specification
 * suggests that BMIC_WRITE (0x27) is appropriate.
 */
#define CISS_SCMD_BMIC_READ                     0x26
#define CISS_SCMD_BMIC_WRITE                    0x27

/*
 * CISS Messages
 *
 * The CISS specification describes several directives that do not behave like
 * SCSI commands.  They are sent in requests of type CISS_TYPE_MSG.
 *
 * The Abort, Reset, and Nop, messages are defined in "8. Messages" in the CISS
 * Specification.
 */
#define CISS_MSG_ABORT                          0x0
#define CISS_ABORT_TASK                         0x0
#define CISS_ABORT_TASKSET                      0x1

#define CISS_MSG_RESET                          0x1
#define CISS_RESET_CTLR                         0x0
#define CISS_RESET_BUS                          0x1
#define CISS_RESET_TGT                          0x3
#define CISS_RESET_LUN                          0x4

#define CISS_MSG_NOP                            0x3

/*
 * BMIC Commands
 *
 * These commands allow for the use of non-standard facilities specific to the
 * Smart Array firmware.  They are sent to the controller through a specially
 * constructed CDB with the CISS_SCMD_BMIC_READ or CISS_SCMD_BMIC_WRITE opcode.
 */
#define CISS_BMIC_IDENTIFY_CONTROLLER           0x11
#define CISS_BMIC_IDENTIFY_PHYSICAL_DEVICE      0x15
#define CISS_BMIC_NOTIFY_ON_EVENT               0xD0
#define CISS_BMIC_NOTIFY_ON_EVENT_CANCEL        0xD1

/*
 * Device and Phy type codes.  These are used across many commands, including
 * IDENTIFY PHYSICAL DEVICE and the REPORT PHYSICAL LUN extended reporting.
 */
#define SMRT_DTYPE_PSCSI                        0x00
#define SMRT_DTYPE_SATA                         0x01
#define SMRT_DTYPE_SAS                          0x02
#define SMRT_DTYPE_SATA_BW                      0x03
#define SMRT_DTYPE_SAS_BW                       0x04
#define SMRT_DTYPE_EXPANDER                     0x05
#define SMRT_DTYPE_SES                          0x06
#define SMRT_DTYPE_CONTROLLER                   0x07
#define SMRT_DTYPE_SGPIO                        0x08
#define SMRT_DTYPE_NVME                         0x09
#define SMRT_DTYPE_NOPHY                        0xFF

/*
 * The following packed structures are used to ease the manipulation of SCSI
 * and BMIC commands sent to, and status information returned from, the
 * controller.
 */
#pragma pack(1)

typedef struct smrt_report_logical_lun_ent {
        LogDevAddr_t smrle_addr;
} smrt_report_logical_lun_ent_t;

typedef struct smrt_report_logical_lun_extent {
        LogDevAddr_t smrle_addr;
        uint8_t smrle_wwn[16];
} smrt_report_logical_lun_extent_t;

typedef struct smrt_report_logical_lun {
        uint32_t smrll_datasize; /* Big Endian */
        uint8_t smrll_extflag;
        uint8_t smrll_reserved1[3];
        union {
                smrt_report_logical_lun_ent_t ents[SMRT_MAX_LOGDRV];
                smrt_report_logical_lun_extent_t extents[SMRT_MAX_LOGDRV];
        } smrll_data;
} smrt_report_logical_lun_t;

typedef struct smrt_report_logical_lun_req {
        uint8_t smrllr_opcode;
        uint8_t smrllr_extflag;
        uint8_t smrllr_reserved1[4];
        uint32_t smrllr_datasize; /* Big Endian */
        uint8_t smrllr_reserved2;
        uint8_t smrllr_control;
} smrt_report_logical_lun_req_t;

typedef struct smrt_report_physical_lun_ent {
        PhysDevAddr_t srple_addr;
} smrt_report_physical_lun_ent_t;

/*
 * This structure represents the 'physical node identifier' extended option for
 * REPORT PHYSICAL LUNS.  This is triggered when the extended flags is set to
 * 0x1.  Note that for SAS the other structure should always be used.
 */
typedef struct smrt_report_physical_pnid {
        uint8_t srpp_node[8];
        uint8_t srpp_port[8];
} smrt_report_physical_pnid_t;

/*
 * This structure represents the 'other physical device info' extended option
 * for report physical luns.  This is triggered when the extended flags is set
 * to 0x2.
 */
typedef struct smrt_report_physical_opdi {
        uint8_t srpo_wwid[8];
        uint8_t srpo_dtype;
        uint8_t srpo_flags;
        uint8_t srpo_multilun;
        uint8_t srpo_paths;
        uint32_t srpo_iohdl;
} smrt_report_physical_opdi_t;

typedef struct smrt_report_physical_lun_extent {
        PhysDevAddr_t srple_addr;
        union {
                smrt_report_physical_pnid_t srple_pnid;
                smrt_report_physical_opdi_t srple_opdi;
        } srple_extdata;
} smrt_report_physical_lun_extent_t;

/*
 * Values that can be ORed together into smrllr_extflag. smprl_extflag indicates
 * if any extended processing was done or not.
 */
#define SMRT_REPORT_PHYSICAL_LUN_EXT_NONE       0x00
#define SMRT_REPORT_PHYSICAL_LUN_EXT_PNID       0x01
#define SMRT_REPORT_PHYSICAL_LUN_EXT_OPDI       0x02
#define SMRT_REPORT_PHYSICAL_LUN_EXT_MASK       0x0f
#define SMRT_REPORT_PHYSICAL_LUN_CTRL_ONLY      (1 << 6)
#define SMRT_REPORT_PHYSICAL_LUN_ALL_PATHS      (1 << 7)

typedef struct smrt_report_physical_lun {
        uint32_t smrpl_datasize; /* Big Endian */
        uint8_t smrpl_extflag;
        uint8_t smrpl_reserved1[3];
        union {
                smrt_report_physical_lun_ent_t ents[SMRT_MAX_PHYSDEV];
                smrt_report_physical_lun_extent_t extents[SMRT_MAX_PHYSDEV];
        } smrpl_data;
} smrt_report_physical_lun_t;


typedef struct smrt_report_physical_lun_req {
        uint8_t smrplr_opcode;
        uint8_t smrplr_extflag;
        uint8_t smrplr_reserved[1];
        uint32_t smrplr_datasize; /* Big Endian */
        uint8_t smrplr_reserved2;
        uint8_t smrplr_control;
} smrt_report_physical_lun_req_t;

/*
 * Request structure for the BMIC command IDENTIFY CONTROLLER.  This structure
 * is written into the CDB with the CISS_SCMD_BMIC_READ SCSI opcode.  Reserved
 * fields should be filled with zeroes.
 */
typedef struct smrt_identify_controller_req {
        uint8_t smicr_opcode;
        uint8_t smicr_lun;
        uint8_t smicr_reserved1[4];
        uint8_t smicr_command;
        uint8_t smicr_reserved2[2];
        uint8_t smicr_reserved3[1];
        uint8_t smicr_reserved4[6];
} smrt_identify_controller_req_t;

/*
 * Response structure for IDENTIFY CONTROLLER.  This structure is used to
 * interpret the response the controller will write into the data buffer.
 */
typedef struct smrt_identify_controller {
        uint8_t smic_logical_drive_count;
        uint32_t smic_config_signature;
        uint8_t smic_firmware_rev[4];
        uint8_t smic_recovery_rev[4];
        uint8_t smic_hardware_version;
        uint8_t smic_bootblock_rev[4];

        /*
         * These are obsolete for SAS controllers:
         */
        uint32_t smic_drive_present_map;
        uint32_t smic_external_drive_map;

        uint32_t smic_board_id;
} smrt_identify_controller_t;

/*
 * Request structure for IDENTIFY PHYSICAL DEVICE.  This structure is written
 * into the CDB with the CISS_SCMD_BMIC_READ SCSI opcode.  Reserved fields
 * should be filled with zeroes.  Note, the lower 8 bits of the BMIC ID are in
 * index1, whereas the upper 8 bites are in index2; however, the controller may
 * only support 8 bits worth of devices (and this driver does not support that
 * many devices).
 */
typedef struct smrt_identify_physical_drive_req {
        uint8_t sipdr_opcode;
        uint8_t sipdr_lun;
        uint8_t sipdr_bmic_index1;
        uint8_t sipdr_reserved1[3];
        uint8_t sipdr_command;
        uint8_t sipdr_reserved2[2];
        uint8_t sipdr_bmic_index2;
        uint8_t sipdr_reserved4[6];
} smrt_identify_physical_drive_req_t;

/*
 * Relevant values for the sipd_more_flags member.
 */
#define SMRT_MORE_FLAGS_LOGVOL  (1 << 5)
#define SMRT_MORE_FLAGS_SPARE   (1 << 6)

/*
 * Response structure for IDENTIFY PHYSICAL DEVICE.  This structure is used to
 * describe aspects of a physical drive. Note, not all fields are valid in all
 * firmware revisions.
 */
typedef struct smrt_identify_physical_drive {
        uint8_t         sipd_scsi_bus;  /* Invalid for SAS */
        uint8_t         sipd_scsi_id;   /* Invalid for SAS */
        uint16_t        sipd_lblk_size;
        uint32_t        sipd_nblocks;
        uint32_t        sipd_rsrvd_blocsk;
        uint8_t         sipd_model[40];
        uint8_t         sipd_serial[40];
        uint8_t         sipd_firmware[8];
        uint8_t         sipd_scsi_inquiry;
        uint8_t         sipd_compaq_stamp;
        uint8_t         sipd_last_failure;
        uint8_t         sipd_flags;
        uint8_t         sipd_more_flags;
        uint8_t         sipd_scsi_lun;  /* Invalid for SAS */
        uint8_t         sipd_yet_more_flags;
        uint8_t         sipd_even_more_flags;
        uint32_t        sipd_spi_speed_rules;
        uint8_t         sipd_phys_connector[2];
        uint8_t         sipd_phys_box_on_bus;
        uint8_t         sipd_phys_bay_in_box;
        uint32_t        sipd_rpm;
        uint8_t         sipd_device_type;
        uint8_t         sipd_sata_version;
        uint64_t        sipd_big_nblocks;
        uint64_t        sipd_ris_slba;
        uint32_t        sipd_ris_size;
        uint8_t         sipd_wwid[20];
        uint8_t         sipd_controller_phy_map[32];
        uint16_t        sipd_phy_count;
        uint8_t         sipd_phy_connected_dev_type[256];
        uint8_t         sipd_phy_to_drive_bay[256];
        uint16_t        sipd_phy_to_attached_dev[256];
        uint8_t         sipd_box_index;
        uint8_t         sipd_drive_support;
        uint16_t        sipd_extra_flags;
        uint8_t         sipd_neogiated_link_rate[256];
        uint8_t         sipd_phy_to_phy_map[256];
        uint8_t         sipd_pad[312];
} smrt_identify_physical_drive_t;

/*
 * Note that this structure describes the CISS version of the command. There
 * also exists a BMIC version, but it has a slightly different structure.  This
 * structure is also used for the cancellation request; however, in that case,
 * the senr_flags field is reserved.
 */
typedef struct smrt_event_notify_req {
        uint8_t         senr_opcode;
        uint8_t         senr_subcode;
        uint8_t         senr_reserved1[2];
        uint32_t        senr_flags;     /* Big Endian */
        uint32_t        senr_size;      /* Big Endian */
        uint8_t         senr_control;
} smrt_event_notify_req_t;

/*
 * When receiving event notifications, the buffer size must be 512 bytes large.
 * We make sure that we always allocate a buffer of this size, even though we
 * define a structure that is much shorter and only uses the fields that we end
 * up caring about.  This size requirement comes from the specification.
 */
#define SMRT_EVENT_NOTIFY_BUFLEN        512

#define SMRT_EVENT_CLASS_PROTOCOL               0
#define SMRT_EVENT_PROTOCOL_SUBCLASS_ERROR      1

#define SMRT_EVENT_CLASS_HOTPLUG                1
#define SMRT_EVENT_HOTPLUG_SUBCLASS_DRIVE       0

#define SMRT_EVENT_CLASS_HWERROR                2
#define SMRT_EVENT_CLASS_ENVIRONMENT            3

#define SMRT_EVENT_CLASS_PHYS                   4
#define SMRT_EVENT_PHYS_SUBCLASS_STATE          0

#define SMRT_EVENT_CLASS_LOGVOL                 5

typedef struct smrt_event_notify {
        uint32_t        sen_timestamp;
        uint16_t        sen_class;
        uint16_t        sen_subclass;
        uint16_t        sen_detail;
        uint8_t         sen_data[64];
        char            sen_message[80];
        uint32_t        sen_tag;
        uint16_t        sen_date;
        uint16_t        sen_year;
        uint32_t        sen_time;
        uint16_t        sen_pre_power_time;
        LUNAddr_t       sen_addr;
} smrt_event_notify_t;

#pragma pack()

#ifdef  __cplusplus
}
#endif

#endif  /* _SMRT_SCSI_H */