root/usr/src/uts/common/sys/sata/impl/sata.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
/*
 * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
 */

#ifndef _SATA_H
#define _SATA_H

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * Generic SATA Host Adapter Implementation
 */

#include <sys/types.h>
#include <sys/scsi/scsi.h>
#include <sys/scsi/impl/services.h>
#include <sys/sata/sata_defs.h>
#include <sys/sata/sata_hba.h>

/* Common flags specifying current state of a port or an attached drive. */
#define SATA_STATE_PROBING              0x000001
#define SATA_STATE_PROBED               0x000002

/* Statistics counters */
struct sata_port_stats {
        uint64_t        link_lost;              /* event counter */
        uint64_t        link_established;       /* event counter */
        uint64_t        device_attached;        /* event counter */
        uint64_t        device_detached;        /* event counter */
        uint64_t        port_reset;             /* event counter */
        uint64_t        port_pwr_changed;       /* event counter */
};

typedef struct sata_port_stats sata_port_stats_t;

struct sata_drive_stats {
        uint64_t        media_error;            /* available ??? */
        uint64_t        drive_reset;            /* event counter */
} sata_drv_stats_t;

typedef struct sata_drive_stats sata_drive_stats_t;

struct sata_ctrl_stats {
        uint64_t        ctrl_reset;             /* event counter */
        uint64_t        ctrl_pwr_change;        /* event counter */
};

typedef struct sata_ctrl_stats sata_ctrl_stats_t;


/*
 * SATA HBA instance info structure
 */
struct sata_hba_inst {
        dev_info_t              *satahba_dip;   /* this HBA instance devinfo */
        struct sata_hba_inst    *satahba_next;  /* ptr to next sata_hba_inst */
        struct sata_hba_inst    *satahba_prev;  /* ptr to prev sata_hba_inst */
        struct scsi_hba_tran    *satahba_scsi_tran; /* scsi_hba_tran */
        struct sata_hba_tran    *satahba_tran;  /* sata_hba_tran */
        kmutex_t                satahba_mutex;  /* sata hba cntrl mutex */
        struct taskq            *satahba_taskq; /* cmd completion task queue */

                                                /*
                                                 * HBA event flags:
                                                 * SATA_EVNT_MAIN
                                                 * SATA_EVNT_PWR_LEVEL_CHANGED
                                                 * SATA_EVNT_SKIP
                                                 */
        uint_t                  satahba_event_flags;

        struct sata_cport_info  *satahba_dev_port[SATA_MAX_CPORTS];

                                                /*
                                                 * DEVCTL open flag:
                                                 * SATA_DEVCTL_SOPENED
                                                 * SATA_DEVCTL_EXOPENED
                                                 */
        uint_t                  satahba_open_flag; /* shared open flag */
        struct sata_ctrl_stats  satahba_stats;  /* HBA cntrl statistics */

        uint_t                  satahba_attached; /* HBA attaching: */
                                                /* 0 - not completed */
                                                /* 1 - completed */
};

typedef struct sata_hba_inst    sata_hba_inst_t;

/*
 * SATA controller's device port info and state.
 * This structure is pointed to by the sata_hba_inst.satahba_dev_port[x]
 * where x is a device port number.
 * cport_state holds port state flags, defined in sata_hba.h file.
 * cport_event_flags holds SATA_EVNT_* flags defined in this file and in
 * sata_hba.h file.
 * cport_dev_type holds SATA_DTYPE_* types defined in sata_hba.h file.
 */
struct sata_cport_info {
        sata_address_t          cport_addr;     /* this port SATA address */
        kmutex_t                cport_mutex;    /* port mutex */

                                                /*
                                                 * Port state flags
                                                 * SATA_STATE_UNKNOWN
                                                 * SATA_STATE_PROBING
                                                 * SATA_STATE_PROBED
                                                 * SATA_STATE_READY
                                                 * SATA_PSTATE_PWRON
                                                 * SATA_PSTATE_PWROFF
                                                 * SATA_PSTATE_SHUTDOWN
                                                 * SATA_PSTATE_FAILED
                                                 */
        uint32_t                cport_state;

                                                /*
                                                 * Port event flags:
                                                 * SATA_EVNT_DEVICE_ATTACHED
                                                 * SATA_EVNT_DEVICE_DETACHED
                                                 * SATA_EVNT_LINK_LOST
                                                 * SATA_EVNT_LINK_ESTABLISHED
                                                 * SATA_EVNT_PORT_FAILED
                                                 * SATA_EVNT_PWR_LEVEL_CHANGED
                                                 */
        uint32_t                cport_event_flags;

        struct sata_port_scr    cport_scr;      /* Port status and ctrl regs */

                                                /*
                                                 * Attached device type:
                                                 * SATA_DTYPE_NONE
                                                 * SATA_DTYPE_ATADISK
                                                 * SATA_DTYPE_ATAPICD
                                                 * SATA_DTYPE_ATAPITAPE
                                                 * SATA_DTYPE_ATAPIDISK
                                                 * SATA_DTYPE_PMULT
                                                 * SATA_DTYPE_UNKNOWN
                                                 * SATA_DTYPE_ATAPIPROC
                                                 */
        uint32_t                cport_dev_type;
        union {
            struct sata_drive_info *cport_sata_drive; /* Attached drive info */
            struct sata_pmult_info *cport_sata_pmult; /* Attached Port Mult */
        }                       cport_devp;
                                                /* lbolt value at link lost */
        clock_t                 cport_link_lost_time;
                                                /* lbolt value @ dev attached */
        clock_t                 cport_dev_attach_time;

        struct sata_port_stats  cport_stats;    /* Port statistics */

        boolean_t               cport_tgtnode_clean; /* Target node usable */
};

typedef struct sata_cport_info sata_cport_info_t;

/*
 * Attached SATA drive info and state.
 * This structure is pointed to by sata_cport_info's cport_sata_drive field
 * when a drive is attached directly to a controller device port.
 */
struct sata_drive_info {
        sata_address_t  satadrv_addr;           /* this drive SATA address */

                                                /*
                                                 * Drive state flags
                                                 * SATA_STATE_UNKNOWN
                                                 * SATA_STATE_PROBING
                                                 * SATA_STATE_PROBED
                                                 * SATA_STATE_READY
                                                 * SATA_DSTATE_PWR_ACTIVE
                                                 * SATA_DSTATE_PWR_IDLE
                                                 * SATA_DSTATE_RESET
                                                 * SATA_DSTATE_FAILED
                                                 */
        uint32_t        satadrv_state;

                                                /*
                                                 * drive event flags:
                                                 * SATA_EVNT_DRIVE_RESET
                                                 */
        uint32_t        satadrv_event_flags;
                                                /*
                                                 * lbolt value @ start of
                                                 * device reset processing
                                                 */
        clock_t         satadrv_reset_time;
                                                /*
                                                 * Attached device type:
                                                 * SATA_DTYPE_ATADISK
                                                 * SATA_DTYPE_ATAPICD
                                                 * SATA_DTYPE_ATAPITAPE
                                                 * SATA_DTYPE_ATAPIDISK
                                                 * SATA_DTYPE_ATAPIPROC
                                                 */
        uint32_t        satadrv_type;

        uint32_t        satadrv_status_reg;     /* drive status reg */
        uint32_t        satadrv_error_reg;      /* drive error reg */
        uint16_t        satadrv_features_support; /* drive features support */
        uint16_t        satadrv_queue_depth;    /* drive queue depth */
        uint16_t        satadrv_atapi_cdb_len;  /* atapi supported cdb length */
        uint16_t        satadrv_atapi_trans_ver; /* atapi transport version */
        uint16_t        satadrv_settings;       /* drive settings flags */
        uint16_t        satadrv_features_enabled; /* drive features enabled */
        uint64_t        satadrv_capacity;       /* drive capacity */
        uint64_t        satadrv_max_queue_depth; /* maximum queue depth */
        sata_id_t       satadrv_id;             /* Device Identify Data */
        struct sata_drive_stats satadrv_stats;  /* drive statistics */

        /*
         * saved standby timer
         * [0] - [3] = high - low
         */
        uint8_t         satadrv_standby_timer[4];
        uint8_t         satadrv_power_level; /* saved power level */
};

typedef struct sata_drive_info sata_drive_info_t;

_NOTE(SCHEME_PROTECTS_DATA("unshared data", sata_drive_info))


/* Port Multiplier & host port info and state */
struct sata_pmult_info {
        sata_address_t  pmult_addr;             /* this PMult SATA Address */
                                                /*
                                                 * PMult state flags
                                                 * SATA_STATE_UNKNOWN
                                                 * SATA_STATE_PROBING
                                                 * SATA_STATE_PROBED
                                                 * SATA_STATE_READY
                                                 * SATA_PSTATE_FAILED
                                                 */
        uint32_t        pmult_state;
        uint32_t        pmult_event_flags;      /* Undefined for now */
        struct sata_pmult_gscr pmult_gscr;      /* PMult GSCR block */
        uint32_t        pmult_num_dev_ports;    /* Number of data ports */
        struct sata_pmport_info *pmult_dev_port[SATA_MAX_PMPORTS - 1];
};

typedef struct sata_pmult_info sata_pmult_info_t;

_NOTE(SCHEME_PROTECTS_DATA("unshared data", sata_pmult_info))
_NOTE(MUTEX_PROTECTS_DATA(sata_cport_info::cport_mutex, \
    sata_pmult_info::pmult_dev_port))

/* Port Multiplier's device port info & state */
struct sata_pmport_info {
        sata_address_t  pmport_addr;            /* this SATA port address */
        kmutex_t        pmport_mutex;           /* pmult device port mutex */

                                                /*
                                                 * Port state flags
                                                 * SATA_STATE_UNKNOWN
                                                 * SATA_STATE_PROBING
                                                 * SATA_STATE_PROBED
                                                 * SATA_STATE_READY
                                                 * SATA_PSTATE_PWRON
                                                 * SATA_PSTATE_PWROFF
                                                 * SATA_PSTATE_SHUTDOWN
                                                 * SATA_PSTATE_FAILED
                                                 */
        uint32_t        pmport_state;

                                                /*
                                                 * Port event flags:
                                                 * SATA_EVNT_DEVICE_ATTACHED
                                                 * SATA_EVNT_DEVICE_DETACHED
                                                 * SATA_EVNT_LINK_LOST
                                                 * SATA_EVNT_LINK_ESTABLISHED
                                                 * SATA_EVNT_PORT_FAILED
                                                 * SATA_EVNT_PWR_LEVEL_CHANGED
                                                 */
        uint32_t        pmport_event_flags;

        struct sata_port_scr pmport_scr;        /* PMult device port scr */

                                                /*
                                                 * Attached device type:
                                                 * SATA_DTYPE_NONE
                                                 * SATA_DTYPE_ATADISK
                                                 * SATA_DTYPE_ATAPICD
                                                 * SATA_DTYPE_ATAPITAPE
                                                 * SATA_DTYPE_ATAPIDISK
                                                 * SATA_DTYPE_UNKNOWN
                                                 * SATA_DTYPE_ATAPIPROC
                                                 */
        uint32_t        pmport_dev_type;

        struct sata_drive_info  *pmport_sata_drive; /* Attached drive info */

                                                /* lbolt value at link lost */
        clock_t         pmport_link_lost_time;
                                                /* lbolt value @ dev attached */
        clock_t         pmport_dev_attach_time;

        struct sata_port_stats  pmport_stats;   /* Port statistics */

        boolean_t       pmport_tgtnode_clean;   /* Target node usable */
};

typedef struct sata_pmport_info sata_pmport_info_t;

/*
 * sata drive's power level
 * default value is active
 */
#define SATA_POWER_ACTIVE       0x00
#define SATA_POWER_IDLE         0x01
#define SATA_POWER_STANDBY      0x02
#define SATA_POWER_STOPPED      0x03

/*
 * pm-capable value definition according to PSARC 2009/310
 */
#define SATA_CAP_POWER_CONDITON PM_CAPABLE_SPC4
#define SATA_CAP_SMART_PAGE     PM_CAPABLE_SMART_LOG
#define SATA_CAP_LOG_SENSE      PM_CAPABLE_LOG_SUPPORTED

/*
 * Port SSTATUS register (sata_port_scr sport_sstatus field).
 * Link bits are valid only in port active state.
 */
#define SATA_PORT_DEVLINK_UP    0x00000103      /* Link with dev established */
#define SATA_PORT_DEVLINK_UP_MASK 0x0000010F    /* Mask for link bits */

/*
 * Port state clear mask (cport_state and pmport_state fields).
 * SATA_PSTATE_SHUTDOWN and power state are preserved.
 */
#define SATA_PORT_STATE_CLEAR_MASK      (~(SATA_PSTATE_SHUTDOWN))

/*
 * Valid i.e.supported device types mask (cport_dev_type, satadrv_type,
 * pmult_dev_type fields).
 * ATA disks and ATAPI CD/DVD now.
 */
#define SATA_VALID_DEV_TYPE     (SATA_DTYPE_ATADISK | \
                                SATA_DTYPE_ATAPICD | \
                                SATA_DTYPE_ATAPITAPE | \
                                SATA_DTYPE_ATAPIDISK)

/*
 * Device feature_support (satadrv_features_support)
 */
#define SATA_DEV_F_DMA                  0x01
#define SATA_DEV_F_LBA28                0x02
#define SATA_DEV_F_LBA48                0x04
#define SATA_DEV_F_NCQ                  0x08
#define SATA_DEV_F_SATA1                0x10
#define SATA_DEV_F_SATA2                0x20
#define SATA_DEV_F_TCQ                  0x40    /* Non NCQ tagged queuing */
#define SATA_DEV_F_SATA3                0x80

/*
 * Device features enabled (satadrv_features_enabled)
 */
#define SATA_DEV_F_E_TAGGED_QING        0x01    /* Tagged queuing enabled */
#define SATA_DEV_F_E_UNTAGGED_QING      0x02    /* Untagged queuing enabled */

/*
 * Drive settings flags (satdrv_settings)
 */
#define SATA_DEV_READ_AHEAD             0x0001  /* Read Ahead enabled */
#define SATA_DEV_WRITE_CACHE            0x0002  /* Write cache ON */
#define SATA_DEV_DMA                    0x0004  /* DMA selected */
#define SATA_DEV_SERIAL_FEATURES        0x8000  /* Serial ATA feat. enabled */
#define SATA_DEV_ASYNCH_NOTIFY          0x2000  /* Asynch-event enabled */
#define SATA_DEV_RMSN                   0x0100  /* Rem Media Stat Notfc enbl */

/*
 * Internal event and flags.
 * These flags are set in the *_event_flags fields of various structures.
 * Events and lock flags defined below are used internally by the
 * SATA framework (they are not reported by SATA HBA drivers).
 */
#define SATA_EVNT_MAIN                  0x80000000
#define SATA_EVNT_SKIP                  0x40000000
#define SATA_EVNT_INPROC_DEVICE_RESET   0x08000000
#define SATA_EVNT_CLEAR_DEVICE_RESET    0x04000000
#define SATA_EVNT_TARGET_NODE_CLEANUP   0x00000100
#define SATA_EVNT_AUTOONLINE_DEVICE     0x00000200

/*
 * Lock flags - used to serialize configuration operations
 * on ports and devices.
 * SATA_EVNT_LOCK_PORT_BUSY is set by event daemon to prevent
 * simultaneous cfgadm operations.
 * SATA_APCTL_LOCK_PORT_BUSY is set by cfgadm ioctls to prevent
 * simultaneous event processing.
 */
#define SATA_EVNT_LOCK_PORT_BUSY        0x00800000
#define SATA_APCTL_LOCK_PORT_BUSY       0x00400000

/* Mask for port events */
#define SATA_EVNT_PORT_EVENTS           (SATA_EVNT_DEVICE_ATTACHED | \
                                        SATA_EVNT_DEVICE_DETACHED | \
                                        SATA_EVNT_LINK_LOST | \
                                        SATA_EVNT_LINK_ESTABLISHED | \
                                        SATA_EVNT_PMULT_LINK_CHANGED | \
                                        SATA_EVNT_PORT_FAILED | \
                                        SATA_EVNT_TARGET_NODE_CLEANUP | \
                                        SATA_EVNT_AUTOONLINE_DEVICE)
/* Mask for drive events */
#define SATA_EVNT_DRIVE_EVENTS          (SATA_EVNT_DEVICE_RESET | \
                                        SATA_EVNT_INPROC_DEVICE_RESET)
#define SATA_EVNT_CONTROLLER_EVENTS     SATA_EVNT_PWR_LEVEL_CHANGED

/* Delays and timeout duration definitions */
#define SATA_EVNT_DAEMON_SLEEP_TIME     50000   /* 50 ms */
#define SATA_EVNT_DAEMON_TERM_TIMEOUT   100000  /* 100 ms */
#define SATA_EVNT_DAEMON_TERM_WAIT      60000000 /* 60 s */
#define SATA_EVNT_LINK_LOST_TIMEOUT     1000000 /* 1 s */

#define SATA_DEV_IDENTIFY_TIMEOUT       60000000 /* 60 s, device enumeration */
#define SATA_DEV_REPROBE_TIMEOUT        30000000  /* 30 s, dev resp after rst */
#define SATA_DEV_RETRY_DLY              10000   /* 10 ms */

/* DEVICE IDENTIFY and device initialization retry delay */
#define SATA_DEV_IDENTIFY_RETRY         1
#define SATA_DEV_IDENTIFY_NORETRY       0

/*
 * sata_scsi's hba_open_flag: field indicating open devctl instance.
 *      0 = closed, 1 = shared open, 2 = exclusive open.
 */
#define SATA_DEVCTL_CLOSED      0
#define SATA_DEVCTL_SOPENED     1
#define SATA_DEVCTL_EXOPENED    2

/*
 * sata_pkt_txlate structure contains info about resources allocated
 * for the packet
 * Address of this structure is stored in scsi_pkt.pkt_ha_private and
 * in sata_pkt.sata_hba_private fields, so all three strucures are
 * cross-linked, with sata_pkt_txlate as a centerpiece.
 */

typedef struct sata_pkt_txlate {
        struct sata_hba_inst    *txlt_sata_hba_inst;
        struct scsi_pkt         *txlt_scsi_pkt;
        struct sata_pkt         *txlt_sata_pkt;
        ddi_dma_handle_t        txlt_buf_dma_handle;
        uint_t                  txlt_flags;     /* data-in / data-out */
        uint_t                  txlt_num_dma_win; /* number of DMA windows */
        uint_t                  txlt_cur_dma_win; /* current DMA window */

                                /* cookies in the current DMA window */
        uint_t                  txlt_curwin_num_dma_cookies;

                                /* processed dma cookies in current DMA win */
        uint_t                  txlt_curwin_processed_dma_cookies;
        size_t                  txlt_total_residue;
        ddi_dma_cookie_t        txlt_dma_cookie; /* default dma cookie */
        int                     txlt_dma_cookie_list_len; /* alloc list len */
        ddi_dma_cookie_t        *txlt_dma_cookie_list; /* dma cookie list */
        int                     txlt_num_dma_cookies; /* dma cookies in list */

                                /* temporary buffer access handle */
        ddi_acc_handle_t        txlt_tmp_buf_handle;
        caddr_t                 txlt_tmp_buf;   /* temp buffer address */
} sata_pkt_txlate_t;

_NOTE(SCHEME_PROTECTS_DATA("unshared data", sata_pkt_txlate))
_NOTE(SCHEME_PROTECTS_DATA("unshared data", scsi_pkt))

/* Length of largest sense buffer used by sata */
#define SATA_MAX_SENSE_LEN      MAX(sizeof (struct scsi_arq_status), \
    sizeof (struct scsi_arq_status) - sizeof (struct scsi_extended_sense) + \
    sizeof (struct scsi_descr_sense_hdr) + \
    MAX(sizeof (struct scsi_cmd_specific_sense_descr), \
    sizeof (struct scsi_ata_status_ret_sense_descr)))

/*
 * Sense Data structure for ATA Pass Through
 * This is the entire sense data block passed back up to scsi.  It is
 * effectively the scsi_arq_status structure for ATA Sense Return descriptor
 * format sense data.
 */
struct sata_apt_sense_data {
        struct scsi_status                              apt_status;
        struct scsi_status                              apt_rqpkt_status;
        uchar_t                                         apt_rqpkt_reason;
        uchar_t                                         apt_rqpkt_resid;
        uint_t                                          apt_rqpkt_state;
        uint_t                                          apt_rqpkt_statistics;
        struct scsi_descr_sense_hdr                     apt_sd_hdr;
        struct scsi_ata_status_ret_sense_descr          apt_sd_sense;
};


/*
 * Additional scsi sense code definitions.
 * These definition should eventually be moved to scsi header file
 * usr/src/uts/common/sys/scsi/generic/sense.h
 */
#define SD_SCSI_ASC_NO_ADD_SENSE                        0x00
#define SD_SCSI_ASC_APT_INFO_AVAIL                      0x00
#define SD_SCSI_ASC_LU_NOT_READY                        0x04
#define SD_SCSI_ASC_LU_NOT_RESPONSE                     0x05
#define SD_SCSI_ASC_WRITE_ERR                           0x0c
#define SD_SCSI_ASC_UNREC_READ_ERR                      0x11
#define SD_SCSI_ASC_INVALID_COMMAND_CODE                0x20
#define SD_SCSI_ASC_LBA_OUT_OF_RANGE                    0x21
#define SD_SCSI_ASC_INVALID_FIELD_IN_CDB                0x24
#define SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST        0x26
#define SD_SCSI_ASC_WRITE_PROTECTED                     0x27
#define SD_SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED             0x28
#define SD_SCSI_ASC_RESET                               0x29
#define SD_SCSI_ASC_CMD_SEQUENCE_ERR                    0x2c
#define SD_SCSI_ASC_MEDIUM_NOT_PRESENT                  0x3a
#define SD_SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED         0x39
#define SD_SCSI_ASC_INTERNAL_TARGET_FAILURE             0x44
#define SD_SCSI_ASC_INFO_UNIT_IUCRC_ERR                 0x47
#define SD_SCSI_ASC_OP_MEDIUM_REM_REQ                   0x5a
#define SD_SCSI_ASC_LOW_POWER_CONDITION_ON              0x5e


/* SCSI defs missing from scsi headers */
/* Missing from sys/scsi/generic/commands.h */
#define SCMD_SYNCHRONIZE_CACHE_G1               0x91
/*
 * Missing from sys/scsi/impl/mode.h, although defined
 * in sys/scsi/targets/sddefs.h as MODEPAGE_ERR_RECOV
 */
#define MODEPAGE_RW_ERRRECOV                    0x01 /* read/write recovery */
/* Missing from sys/scsi/impl/commands.h */
#define SCSI_READ_CAPACITY16_MAX_LBA            0xfffffffffffffffe

/*
 * medium access command
 */
#define SATA_IS_MEDIUM_ACCESS_CMD(cmd) \
        (((cmd) == SCMD_READ) || ((cmd) == SCMD_WRITE) || \
        ((cmd) == SCMD_READ_G1) || ((cmd) == SCMD_WRITE_G1) || \
        ((cmd) == SCMD_READ_G4) || ((cmd) == SCMD_WRITE_G4) || \
        ((cmd) == SCMD_READ_G5) || ((cmd) == SCMD_WRITE_G5) || \
        ((cmd) == SCMD_VERIFY) || ((cmd) == SCMD_VERIFY_G4) || \
        ((cmd) == SCMD_VERIFY_G5) || ((cmd) == 0x7f) /* VERIFY(32) */|| \
        ((cmd) == SCMD_SYNCHRONIZE_CACHE) || ((cmd) == SCMD_SPACE_G4) || \
        ((cmd) == SCMD_READ_POSITION) || \
        ((cmd) == 0x90) /* PRE-FETCH(16) */ || \
        ((cmd) == SCMD_READ_DEFECT_LIST) || \
        ((cmd) == 0xb7) /* READ DEFECT DATA */ || \
        ((cmd) == SCMD_READ_LONG) || ((cmd) == SCMD_SVC_ACTION_IN_G4) || \
        ((cmd) == SCMD_WRITE_LONG) || ((cmd) == SCMD_SVC_ACTION_OUT_G4) || \
        ((cmd) == 0x41) || ((cmd) == 0x93) || /* WRITE SAME */ \
        ((cmd) == 0x52) || ((cmd) == 0x50) || /* XDREAD & XDWRITE */ \
        ((cmd) == 0x53) || ((cmd) == 0x51) || /* XDWRITEREAD & XPWRITE */ \
        ((cmd) == 0x7f))

/*
 * Macros for accessing various structure fields
 */

#define SATA_TRAN(sata_hba_inst) \
        sata_hba_inst->satahba_tran

#define SATA_DIP(sata_hba_inst) \
        sata_hba_inst->satahba_dip

#define SATA_NUM_CPORTS(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_hba_num_cports

#define SATA_QDEPTH(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_hba_qdepth

#define SATA_FEATURES(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_hba_features_support

#define SATA_DMA_ATTR(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_hba_dma_attr

#define SATA_START_FUNC(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_start

#define SATA_ABORT_FUNC(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_abort

#define SATA_RESET_DPORT_FUNC(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_reset_dport

#define SATA_PORT_DEACTIVATE_FUNC(sata_hba_inst) \
        (sata_hba_inst->satahba_tran->sata_tran_hotplug_ops == NULL ? \
        NULL : \
        sata_hba_inst->satahba_tran->sata_tran_hotplug_ops->\
        sata_tran_port_deactivate)

#define SATA_PORT_ACTIVATE_FUNC(sata_hba_inst) \
        (sata_hba_inst->satahba_tran->sata_tran_hotplug_ops == NULL ? \
        NULL : \
        sata_hba_inst->satahba_tran->sata_tran_hotplug_ops->\
        sata_tran_port_activate)

#define SATA_PROBE_PORT_FUNC(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_probe_port

#define SATA_SELFTEST_FUNC(sata_hba_inst) \
        sata_hba_inst->satahba_tran->sata_tran_selftest

#define SATA_CPORT_MUTEX(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_mutex

#define SATA_CPORT_INFO(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]

#define SATA_CPORT_STATE(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_state

#define SATA_CPORT_EVENT_FLAGS(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_event_flags

#define SATA_CPORT_SCR(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_scr

#define SATA_CPORT_DEV_TYPE(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_dev_type

#define SATA_CPORT_DRV_INFO(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_devp.cport_sata_drive

#define SATA_CPORTINFO_DRV_TYPE(cportinfo) \
        cportinfo->cport_dev_type

#define SATA_CPORTINFO_DRV_INFO(cportinfo) \
        cportinfo->cport_devp.cport_sata_drive

#define SATA_CPORTINFO_PMULT_INFO(cportinfo) \
        cportinfo->cport_devp.cport_sata_pmult

#define SATA_PMULT_INFO(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->cport_devp.cport_sata_pmult

#define SATA_NUM_PMPORTS(sata_hba_inst, cport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_num_dev_ports

#define SATA_PMPORT_MUTEX(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]->pmport_mutex

#define SATA_PMPORT_INFO(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]

#define SATA_PMPORT_DRV_INFO(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]->\
        pmport_sata_drive

#define SATA_PMPORT_STATE(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]->pmport_state

#define SATA_PMPORT_SCR(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]->pmport_scr

#define SATA_PMPORT_DEV_TYPE(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]->pmport_dev_type

#define SATA_PMPORT_EVENT_FLAGS(sata_hba_inst, cport, pmport) \
        sata_hba_inst->satahba_dev_port[cport]->\
        cport_devp.cport_sata_pmult->pmult_dev_port[pmport]->\
        pmport_event_flags

#define SATA_PMPORTINFO_DRV_TYPE(pmportinfo) \
        pmportinfo->pmport_dev_type

#define SATA_PMPORTINFO_DRV_INFO(pmportinfo) \
        pmportinfo->pmport_sata_drive

#define SATA_TXLT_HBA_INST(spx) \
        spx->txlt_sata_hba_inst

#define SATA_TXLT_CPORT(spx) \
        spx->txlt_sata_pkt->satapkt_device.satadev_addr.cport

#define SATA_TXLT_PMPORT(spx) \
        spx->txlt_sata_pkt->satapkt_device.satadev_addr.pmport

#define SATA_TXLT_QUAL(spx) \
        spx->txlt_sata_pkt->satapkt_device.satadev_addr.qual

#define SATA_TXLT_CPORT_MUTEX(spx) \
        spx->txlt_sata_hba_inst->\
        satahba_dev_port[spx->txlt_sata_pkt->\
        satapkt_device.satadev_addr.cport]->cport_mutex

#define SATA_TXLT_TASKQ(spx) \
        spx->txlt_sata_hba_inst->\
        satahba_taskq

/*
 * Minor number construction for devctl and attachment point nodes.
 * All necessary information has to be encoded in NBITSMINOR32 bits.
 *
 * Devctl node minor number:
 * ((controller_instance << SATA_CNTRL_INSTANCE_SHIFT) | SATA_DEVCTL_NODE)
 *
 * Attachment point node minor number has to include controller
 * instance (7 bits), controller port number (5 bits) and port multiplier
 * device port number (4 bits) and port multiplier device port
 * indicator (1 bit).  Additionally, a single bit is used to
 * differentiate between attachment point node and device control node.
 *
 * Attachment point minor number:
 * ((controller_instance << SATA_CNTRL_INSTANCE_SHIFT) | SATA_AP_NODE |
 * [(port_multiplier_device_port << SATA_PMULT_PORT_SHIFT) | SATA_PMULT_AP] |
 * (controller_port))
 *
 * 17 bits are used (if 64 instances of controllers are expected)
 * bit 18 is reserved for future use.
 *
 *   --------------------------------------------------------
 *   |17|16|15|14|13|12|11|10 |09|08|07|06|05|04|03|02|01|00|
 *   --------------------------------------------------------
 *   | R| c| c| c| c| c| c|a/d|pm|pp|pp|pp|pp|cp|cp|cp|cp|cp|
 *   --------------------------------------------------------
 * Where:
 * cp  - device port number on the HBA SATA controller
 * pp  - device port number on the port multiplier
 * pm  - 0 - target attached to controller device port
 *       1 - target attached to port multiplier's device port
 * a/d - 0 - devctl node
 *       1 - attachment point node
 * c   - controller number
 * R   - reserved bit
 */

#define SATA_AP_NODE            0x400           /* Attachment Point node */
#define SATA_DEVCTL_NODE        0x000           /* DEVCTL node */
#define SATA_PMULT_AP           0x200           /* device on PMult port */
#define SATA_PMULT_PORT_SHIFT   5
#define SATA_CNTRL_INSTANCE_SHIFT 11
#define SATA_CPORT_MASK         0x1f            /* 32 device ports */
#define SATA_PMULT_PORT_MASK    0xf             /* 15 device ports */
#define SATA_CNTRL_INSTANCE_MASK 0x03F          /* 64 controllers */

/* Macro for creating devctl node minor number */
#define SATA_MAKE_DEVCTL_MINOR(controller_instance) \
        ((controller_instance << SATA_CNTRL_INSTANCE_SHIFT) | \
        SATA_DEVCTL_NODE)

/* Macro for creating an attachment point node minor number */
#define SATA_MAKE_AP_MINOR(cntrl_instance, cport, pmport, qual) \
        (qual & (SATA_ADDR_PMPORT | SATA_ADDR_DPMPORT) ? \
        (((cntrl_instance) << SATA_CNTRL_INSTANCE_SHIFT) | \
        SATA_AP_NODE | SATA_PMULT_AP | \
        (pmport << SATA_PMULT_PORT_SHIFT) | cport) : \
        (((cntrl_instance) << SATA_CNTRL_INSTANCE_SHIFT) | \
        SATA_AP_NODE | cport))

/* Macro retrieving controller number from a minor number */
#define SATA_MINOR2INSTANCE(minor) \
        ((minor >> SATA_CNTRL_INSTANCE_SHIFT) & SATA_CNTRL_INSTANCE_MASK)

/*
 * Macro for creating an attachment point number from sata address.
 * Address qualifier has to be one of:
 * SATA_ADDR_DCPORT, SATA_ADDR_DPMPORT, SATA_ADDR_CPORT or SATA_ADDR_PMPORT
 */
#define SATA_MAKE_AP_NUMBER(cport, pmport, qual) \
        ((qual & (SATA_ADDR_PMPORT | SATA_ADDR_DPMPORT)) ? \
        (SATA_PMULT_AP | (pmport << SATA_PMULT_PORT_SHIFT) | cport) : \
        (cport))

/*
 * SCSI target number format
 *
 *   -------------------------------
 *   | 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|    Bit number
 *   -------------------------------
 *   |pm|pp|pp|pp|pp|cp|cp|cp|cp|cp|
 *   -------------------------------
 * Where:
 * cp  - device port number on the HBA SATA controller
 * pp  - device port number on the port multiplier
 * pm  - 0 - target attached to controller device port
 *       1 - target attached to port multiplier's device port
 */

/* SATA ports to SCSI target number translation */

#define SATA_TO_SCSI_TARGET(cport, pmport, qual) \
        (qual == SATA_ADDR_DCPORT ? cport : \
        (cport | (pmport << SATA_PMULT_PORT_SHIFT) | SATA_PMULT_AP))

/* SCSI target number to SATA cntrl/pmport/cport translations */
#define SCSI_TO_SATA_CPORT(scsi_target) \
        (scsi_target & SATA_CPORT_MASK)

#define SCSI_TO_SATA_PMPORT(scsi_target) \
        ((scsi_target >> SATA_PMULT_PORT_SHIFT) & SATA_PMULT_PORT_MASK)

#define SCSI_TO_SATA_ADDR_QUAL(scsi_target) \
        ((scsi_target & SATA_PMULT_AP) ? SATA_ADDR_DPMPORT : \
        SATA_ADDR_DCPORT)


/* Debug flags */
#if     DEBUG

#define SATA_DEBUG
#define SATA_DBG_SCSI_IF        1
#define SATA_DBG_HBA_IF         2
#define SATA_DBG_NODES          4
#define SATA_DBG_IOCTL_IF       8
#define SATA_DBG_EVENTS         0x10
#define SATA_DBG_EVENTS_PROC    0x20
#define SATA_DBG_EVENTS_PROCPST 0x40
#define SATA_DBG_EVENTS_CNTRL   0x80
#define SATA_DBG_EVENTS_DAEMON  0x100
#define SATA_DBG_DMA_SETUP      0x400
#define SATA_DBG_DEV_SETTINGS   0x800
#define SATA_DBG_ATAPI          0x1000
#define SATA_DBG_ATAPI_PACKET   0x8000
#define SATA_DBG_INTR_CTX       0x10000
#define SATA_DBG_PMULT          0x20000

typedef struct sata_atapi_cmd {
        uint8_t acdb[SATA_ATAPI_MAX_CDB_LEN];
        uint8_t arqs[SATA_ATAPI_RQSENSE_LEN];
        uint_t sata_pkt_reason;
        uint_t scsi_pkt_reason;
} sata_atapi_cmd_t;

/* Debug macros */
#define SATADBG1(flag, sata, format, arg1) \
        if (sata_debug_flags & (flag)) { \
                sata_log(sata, CE_CONT, format, arg1); \
        }

#define SATADBG2(flag, sata, format, arg1, arg2) \
        if (sata_debug_flags & (flag)) { \
                sata_log(sata, CE_CONT, format, arg1, arg2); \
        }

#define SATADBG3(flag, sata, format, arg1, arg2, arg3) \
        if (sata_debug_flags & (flag)) { \
                sata_log(sata, CE_CONT, format, arg1, arg2, arg3); \
        }
#else

#define SATADBG1(flag, dip, frmt, arg1)
#define SATADBG2(flag, dip, frmt, arg1, arg2)
#define SATADBG3(flag, dip, frmt, arg1, arg2, arg3)

#endif

/* sata_rev_tag 1.46 */

#ifdef  __cplusplus
}
#endif

#endif /* _SATA_H */