root/usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_stats.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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _ISCSI_STATS_H
#define _ISCSI_STATS_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * This file contains all the definitions and prototypes relevant to KSTAT.
 * It also contains the declaration and initialization of data.  When including
 * this file, if _INIT_KSTAT_DATA_ is defined, the data is declared AND
 * initialized. As a consequence, this file should be included only once with
 * _INIT_KSTAT_DATA_ defined.  Failure to do so will lead to a link error.
 * Today, iscsi_stats.c is the only file defining _INIT_KSTAT_DATA_.
 *
 * Four types of KSTAT structures are created for iSCSI.
 *
 *   sun_iscsi_hba
 *   -------------
 *
 *      This structure gathers statistics relevant to an HBA. Each HBA or
 *      software state structure is given one.  It contains the following
 *      fieds:
 *
 *        _name                 iSCSI name of the HBA
 *        _alias                iSCSI alias of the HBA
 *        _cntr_sess            Numbers of sessions created
 *
 *   sun_iscsi_sess
 *   --------------
 *
 *      This structure gathers statistics relevant to a session.  Each session
 *      is given one.  It contains the following fields:
 *
 *        _state                State of the session
 *        _oid                  OID of the session
 *        _hba                  HBA the session belongs to.  It is the name
 *                              of the sun_iscsi_hba structure of the HBA
 *        _cntr_conn            Number of connections
 *        _cntr_pkt_pending     Number of scsi_pkt in the pending queue
 *        _cmd_sn               CmdSN
 *        _cmd_sn_exp           CmdSNExp,
 *        _cmd_sn_max           CmdSNMax
 *
 *   sun_iscsi_sess_io
 *   -----------------
 *
 *      This structure is completely defined by the KSTAT frame work of Solaris.
 *      It contains accumulated time and queue length statistics.  It assumes
 *      the driver has a pending queue and an active.  In our implementation,
 *      the pending queue is the pending queue defined in the session context.
 *      The active queue is any queue defined in the connection context.
 *      If you want more information about the meaning of the fields of this
 *      structure you can read the nice explanation contained in the file:
 *      /usr/src/uts/common/sys/kstat.h.
 *      At any rate, all the sessions are given a sun_iscsi_sess_io structure.
 *      The fields are:
 *
 *        nread                 number of bytes read without iSCSI overhead.
 *        nwritten              number of bytes written without iSCSI overhead.
 *        reads                 number of read operations
 *        writes                number of write operations
 *        wtime                 cumulative wait (pre-service) time
 *        wlentime              cumulative wait length*time product
 *        wlastupdate           last time wait queue changed
 *        rtime                 cumulative run (service) time
 *        rlentime              cumulative run length*time product
 *        rlastupdate           last time run queue changed
 *        wcnt                  count of elements in wait state
 *        rcnt                  count of elements in run state
 *
 *      The time is expressed in nanoseconds.
 *
 *   sun_iscsi_conn
 *   --------------
 *
 *      This structure gathers statistics relevant to a connection.  Each
 *      connection is given one.  It contains the following fields:
 *
 *        _state                State of the connection
 *        _cid                  iSCSI CID
 *        _oid                  OID of the connection
 *        _session              Session the connection belongs to.  It is the
 *                              name of the sun_iscsi_sess structure of the
 *                              session.
 *        _err_header_digest    Number of header digest errors
 *        _err_data_digest      Number of data digest errors
 *        _err_connection_reset Number of reset
 *        _err_protocol_error   Number of protocol errors
 *        _cntr_tx_bytes        Number of bytes transmitted with iSCSI overhead.
 *        _cntr_rx_bytes        Number of bytes received with iSCSI overhead.
 *        _cntr_qactive         Number of requests in the active queue.
 *        _stat_sn_exp          ExpStatusSN
 *        _stat_sn_last         LastStatusSN (Last one sent to the target)
 *
 *
 *
 * The KSTAT frame work of Solaris associates a module name, a instance number
 * a class and a name to every kstat structure.  All the kstat structures of
 * iSCSI have the same module name. It is define farther down in this file to
 * "iscsi".  Regarding the class, three classes are defined here. Those classes
 * are:
 *
 *   - issci_hba
 *   - iscsi_sess
 *   - iscsi_conn
 *
 * The instance number is the number returned by ddi_get_instance.  Today the
 * the driver creates one HBA only.  Therefore, all the structures will have
 * zero as instance number.
 *
 *
 * Each kstat structure can be named.  The naming convention is the following:
 *
 *      KSTAT Struct       Class        Name
 *
 *      sun_iscsi_hba      iscsi_hba    "sun_iscsi_hba" + instance number
 *      sun_iscsi_sess     iscsi_sess   "sun_iscsi_sess" + session oid
 *      sun_iscsi_sess_io  iscsi_sess   "sun_iscsi_sess_io" + session oid
 *      sun_iscsi_conn     iscsi_conn   "sun_iscsi_conn" + connection oid
 */

/*
 * strings used by kstat (Module name and Class name).
 */
#define iSCSI_MODULE_NAME       "iscsi"

typedef struct _kstat_item {
        char            *_name;
        uchar_t         _data_type;
} kstat_item_t;

/*
 * ========================= Connection Class Section ======================
 */

#define iSCSI_CLASS_CONN                        "iscsi_conn"
#define iSCSI_CONN_BASE_NAME                    "iscsi_conn_%d_%d_%d"

#define ISCSI_CONN_STATE_FREE_STR               "free"
#define ISCSI_CONN_STATE_IN_LOGIN_STR           "in_login"
#define ISCSI_CONN_STATE_LOGGED_IN_STR          "logged_in"
#define ISCSI_CONN_STATE_IN_LOGOUT_STR          "in_logout"
#define ISCSI_CONN_STATE_CLEANUP_WAIT_STR       "cleanup_wait"

/*
 * WARNING: The order of this enum important.  If you change it you have to
 *          reorder the table kstat_items_conn (in the file iscsi_stats.c)
 *          accordingly.
 */
typedef enum _kn_conn_idx {
        KN_CONN_IDX_STATE = 0,
        KN_CONN_IDX_CID,
        KN_CONN_IDX_OID,
        KN_CONN_IDX_SESS,
        KN_CONN_IDX_ERR_HDR_DIGEST,
        KN_CONN_IDX_ERR_DATA_DIGEST,
        KN_CONN_IDX_ERR_CONN_RESET,
        KN_CONN_IDX_ERR_PROTOCOL,
        KN_CONN_IDX_CNTR_TX_BYTES,
        KN_CONN_IDX_CNTR_RX_BYTES,
        KN_CONN_IDX_CNTR_QACTIVE,
        KN_CONN_IDX_EXPSTATSN,
        KN_CONN_IDX_LASTSTATSN,
        KN_CONN_IDX_MAX
} kn_conn_idx_t;

typedef struct _iscsi_conn_kstats {
        kstat_named_t   kn[KN_CONN_IDX_MAX];
        char            sess_str[KSTAT_STRLEN];
        char            state_str[KSTAT_STRLEN];
} iscsi_conn_stats_t;

#define KSTAT_INC_CONN_ERR_HEADER_DIGEST(_icp_) \
        (_icp_->stats.ks_data.kn[KN_CONN_IDX_ERR_HDR_DIGEST].value.ul++)

#define KSTAT_INC_CONN_ERR_DATA_DIGEST(_icp_) \
        (_icp_->stats.ks_data.kn[KN_CONN_IDX_ERR_DATA_DIGEST].value.ul++)

#define KSTAT_INC_CONN_ERR_PROTOCOL(_icp_) \
        (_icp_->stats.ks_data.kn[KN_CONN_IDX_ERR_PROTOCOL].value.ul++)

#define KSTAT_INC_CONN_ERR_RESET(_icp_) \
        (_icp_->stats.ks_data.kn[KN_CONN_IDX_ERR_CONN_RESET].value.ul++)

#define KSTAT_ADD_CONN_TX_BYTES(_icp_, _v_) \
        (_icp_->stats.ks_data.kn[KN_CONN_IDX_CNTR_TX_BYTES].value.ui64 += \
        _v_)

#define KSTAT_ADD_CONN_RX_BYTES(_icp_, _v_) \
        (_icp_->stats.ks_data.kn[KN_CONN_IDX_CNTR_RX_BYTES].value.ui64 += \
        _v_)

/*
 * ========================== Session Class Section ========================
 */

/* Session Class */
#define iSCSI_CLASS_SESS                        "iscsi_sess"
#define iSCSI_SESS_BASE_NAME                    "iscsi_sess_%d_%d"
#define iSCSI_SESS_IO_BASE_NAME                 "iscsi_sess_io_%d_%d"

#define ISCSI_SESS_STATE_FREE_STR               "free"
#define ISCSI_SESS_STATE_LOGGED_IN_STR          "logged_in"
#define ISCSI_SESS_STATE_FAILED_STR             "failed"

/*
 * WARNING: The order of this enum important.  If you change it you have to
 *          reorder the table kstat_items_sess (in the file iscsi_stats.c)
 *          accordingly.
 */
typedef enum _kn_sess_idx {
        KN_SESS_IDX_STATE = 0,
        KN_SESS_IDX_OID,
        KN_SESS_IDX_HBA,
        KN_SESS_IDX_CNTR_CONN,
        KN_SESS_IDX_CNTR_RESET,
        KN_SESS_IDX_CNTR_PKT_PENDING,
        KN_SESS_IDX_CMDSN,
        KN_SESS_IDX_EXPCMDSN,
        KN_SESS_IDX_MAXCMDSN,
        KN_SESS_IDX_TARGET_NAME,
        KN_SESS_IDX_TARGET_ALIAS,
        KN_SESS_IDX_TPGT,
        KN_SESS_IDX_MAX
} kn_sess_idx_t;

typedef struct _iscsi_sess_stats {
        kstat_named_t   kn[KN_SESS_IDX_MAX];
        char            hba_str[KSTAT_STRLEN];
        char            state_str[KSTAT_STRLEN];
        char            target_name[ISCSI_MAX_NAME_LEN];
        char            target_alias[ISCSI_MAX_NAME_LEN];
} iscsi_sess_stats_t;

#define KSTAT_INC_SESS_CNTR_RESET(_isp_) \
        (_isp_->stats.ks_data.kn[KN_SESS_IDX_CNTR_RESET].value.ul++)

#define KSTAT_INC_SESS_CNTR_CONN(_isp_) \
        (_isp_->stats.ks_data.kn[KN_SESS_IDX_CNTR_CONN].value.ul++)

#define KSTAT_DEC_SESS_CNTR_CONN(_isp_) \
        (_isp_->stats.ks_data.kn[KN_SESS_IDX_CNTR_CONN].value.ul--)

#define KSTAT_ADD_SESS_CNTR_TX_BYTES(_isp_, _v_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (_isp_->stats.ks_io_data.nwritten += _v_); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_ADD_SESS_CNTR_RX_BYTES(_isp_, _v_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (_isp_->stats.ks_io_data.nread += _v_); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_INC_SESS_CNTR_NWRITES(_isp_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (_isp_->stats.ks_io_data.writes++); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_INC_SESS_CNTR_NREADS(_isp_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (_isp_->stats.ks_io_data.reads++); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_WAITQ_ENTER(_isp_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (kstat_waitq_enter(&_isp_->stats.ks_io_data)); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_WAITQ_EXIT(_isp_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (kstat_waitq_exit(&_isp_->stats.ks_io_data)); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_RUNQ_ENTER(_isp_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (kstat_runq_enter(&_isp_->stats.ks_io_data)); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_RUNQ_EXIT(_isp_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (kstat_runq_exit(&_isp_->stats.ks_io_data)); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_SESS_TX_IO_DONE(_isp_, _v_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (_isp_->stats.ks_io_data.nwritten += _v_); \
        (_isp_->stats.ks_io_data.writes++); \
        mutex_exit(&_isp_->stats.ks_io_lock);

#define KSTAT_SESS_RX_IO_DONE(_isp_, _v_) \
        mutex_enter(&_isp_->stats.ks_io_lock); \
        (_isp_->stats.ks_io_data.nread += _v_); \
        (_isp_->stats.ks_io_data.reads++); \
        mutex_exit(&_isp_->stats.ks_io_lock);

/*
 * ============================ HBA Class Section ==========================
 */

#define iSCSI_CLASS_HBA         "iscsi_hba"
#define iSCSI_HBA_BASE_NAME     "iscsi_hba_%d"

/*
 * WARNING: The order of this enum important.  If you change it you have to
 *          reorder the table kstat_items_hba (in iscsi_stats.c) accordingly.
 */
typedef enum _kn_hba_idx {
        KN_HBA_IDX_NAME = 0,
        KN_HBA_IDX_ALIAS,
        KN_HBA_IDX_CNTR_SESS,
        KN_HBA_IDX_MAX
} kn_hba_idx_t;

typedef struct _iscsi_hba_stats {
        kstat_named_t   kn[KN_HBA_IDX_MAX];
        char            name[ISCSI_MAX_NAME_LEN];
        char            alias[ISCSI_MAX_NAME_LEN];
} iscsi_hba_stats_t;

#define KSTAT_INC_HBA_CNTR_SESS(_ihp_) \
        (_ihp_->stats.ks_data.kn[KN_HBA_IDX_CNTR_SESS].value.ul++)

#define KSTAT_DEC_HBA_CNTR_SESS(_ihp_) \
        (_ihp_->stats.ks_data.kn[KN_HBA_IDX_CNTR_SESS].value.ul--)

#ifdef __cplusplus
}
#endif

#endif  /* _ISCSI_STATS_H */