usr/src/uts/common/io/scsi/adapters/iscsi/iscsi_stats.c
author Peter Dunlap <Peter.Dunlap@Sun.COM>
Tue, 24 Mar 2009 17:50:49 -0600
changeset 9162 b011b0287065
parent 7836 4e95154b5b7a
permissions -rw-r--r--
PSARC 2008/395 iSER: iSCSI Extensions for RDMA 6702590 iSCSI initiator needs to support iSER transport 6702591 COMSTAR iSCSI port provider needs to support iSER transport 6797024 COMSTAR iscsit asserted at iscsit_login.c line: 679 6776635 panic[cpu0]/thread=ffffff000f874c60,assertion failed: 0, file: ../../common/io/idm/idm.c, line: 1465 6802232 Bad kernel fault at addr=0x0 from idm_crc32c call

/*
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * iSCSI Software Initiator
 */

#define	ISCSI_ICS_NAMES
#include "iscsi.h"	/* main header */

kstat_item_t	kstat_items_hba[KN_HBA_IDX_MAX] = {
	{"_name", KSTAT_DATA_STRING},
	{"_alias", KSTAT_DATA_STRING},
	{"_cntr_sess", KSTAT_DATA_ULONG}
};

kstat_item_t	kstat_items_sess[KN_SESS_IDX_MAX] = {
	{"_state", KSTAT_DATA_STRING},
	{"_oid", KSTAT_DATA_ULONG},
	{"_hba", KSTAT_DATA_STRING},
	{"_cntr_conn", KSTAT_DATA_ULONG},
	{"_cntr_reset", KSTAT_DATA_ULONG},
	{"_cntr_pkt_pending", KSTAT_DATA_ULONG},
	{"_cmd_sn", KSTAT_DATA_ULONG},
	{"_cmd_sn_exp", KSTAT_DATA_ULONG},
	{"_cmd_sn_max", KSTAT_DATA_ULONG},
	{"_target_name", KSTAT_DATA_STRING},
	{"_target_alias", KSTAT_DATA_STRING},
	{"_tpgt", KSTAT_DATA_ULONG}
};

kstat_item_t	kstat_items_conn[KN_CONN_IDX_MAX] = {
	{"_state", KSTAT_DATA_STRING},
	{"_cid", KSTAT_DATA_ULONG},
	{"_oid", KSTAT_DATA_ULONG},
	{"_session", KSTAT_DATA_STRING},
	{"_err_header_digest", KSTAT_DATA_ULONG},
	{"_err_data_digest", KSTAT_DATA_ULONG},
	{"_err_connection_reset", KSTAT_DATA_ULONG},
	{"_err_protocol_error", KSTAT_DATA_ULONG},
	{"_cntr_tx_bytes", KSTAT_DATA_ULONGLONG},
	{"_cntr_rx_bytes", KSTAT_DATA_ULONGLONG},
	{"_cntr_qactive", KSTAT_DATA_ULONG},
	{"_stat_sn_exp", KSTAT_DATA_ULONG},
	{"_stat_sn_last", KSTAT_DATA_ULONG}
};

int iscsi_hba_kstat_update(kstat_t *ks, int rw);
int iscsi_sess_kstat_update(kstat_t *ks, int rw);
int iscsi_conn_kstat_update(kstat_t *ks, int rw);

/*
 * HBA
 */

/*
 * iscsi_hba_kstat_init - This function registers with the kstat service.
 */
boolean_t
iscsi_hba_kstat_init(iscsi_hba_t *ihp)
{
	char			ks_name[KSTAT_STRLEN];
	iscsi_hba_stats_t	*ihs;
	int			i;

	/*
	 * The name of the KSTAT structure is built.
	 */
	bzero(ks_name, sizeof (ks_name));

	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_HBA_BASE_NAME,
	    ihp->hba_oid) >= sizeof (ks_name)) {
		return (TRUE);
	}

	ihp->stats.ks = kstat_create(iSCSI_MODULE_NAME,
	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_HBA,
	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);

	if (ihp->stats.ks == NULL) {
		cmn_err(CE_NOTE, "iscsi kstat creation failed for hba(%d)",
		    ihp->hba_oid);
		return (TRUE);
	}

	ihs = &ihp->stats.ks_data;
	ihp->stats.ks->ks_data = &ihp->stats.ks_data;
	ihp->stats.ks->ks_data_size = sizeof (ihp->stats.ks_data);
	ihp->stats.ks->ks_ndata = KN_HBA_IDX_MAX;

	for (i = 0; i < KN_HBA_IDX_MAX; i++) {
		kstat_named_init(&ihs->kn[i], kstat_items_hba[i]._name,
		    kstat_items_hba[i]._data_type);
	}

	ihp->stats.ks->ks_update = iscsi_hba_kstat_update;
	ihp->stats.ks->ks_private = (void *)ihp;

	kstat_install(ihp->stats.ks);

	return (FALSE);
}

/*
 * iscsi_hba_kstat_term - This function deregisters from the kstat service.
 */
boolean_t
iscsi_hba_kstat_term(iscsi_hba_t *ihp)
{
	kstat_delete(ihp->stats.ks);
	return (FALSE);
}

/*
 * iscsi_hba_kstat_update - This function update the kstat structure of the HBA.
 */
int
iscsi_hba_kstat_update(kstat_t *ks, int rw)
{
	iscsi_hba_t		*ihp = (iscsi_hba_t *)ks->ks_private;
	iscsi_hba_stats_t	*ihs = &ihp->stats.ks_data;

	if (rw == KSTAT_READ) {
		rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
		bcopy(ihp->hba_name, ihs->name, ihp->hba_name_length);

		bcopy(ihp->hba_alias, ihs->alias, ihp->hba_alias_length);

		ihs->name[ihp->hba_name_length] = 0;
		ihs->alias[ihp->hba_alias_length] = 0;

		kstat_named_setstr(&ihs->kn[KN_HBA_IDX_NAME],
		    (const char *)ihs->name);
		kstat_named_setstr(&ihs->kn[KN_HBA_IDX_ALIAS],
		    (const char *)ihs->alias);
		rw_exit(&ihp->hba_sess_list_rwlock);
	}
	return (0);
}

/*
 * Session
 */

/*
 * iscsi_sess_kstat_init - This function registers with the kstat service.
 */
boolean_t
iscsi_sess_kstat_init(iscsi_sess_t *isp)
{
	iscsi_hba_t		*ihp;
	char			ks_name[KSTAT_STRLEN];
	iscsi_sess_stats_t	*iss;
	int			i;

	ASSERT(isp != NULL);
	ihp = isp->sess_hba;
	ASSERT(ihp != NULL);

	/*
	 * The name of the KSTAT structure is built.
	 */
	bzero(ks_name, sizeof (ks_name));

	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_SESS_BASE_NAME,
	    isp->sess_hba->hba_oid, isp->sess_oid) >= sizeof (ks_name)) {
		cmn_err(CE_NOTE, "iscsi kstat creation failed for "
		    "session(%u)", isp->sess_oid);
		return (TRUE);
	}

	isp->stats.ks = kstat_create(iSCSI_MODULE_NAME,
	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_SESS,
	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);

	if (isp->stats.ks == NULL) {
		cmn_err(CE_NOTE, "iscsi kstat creation failed "
		    "for session(%u)", isp->sess_oid);
		return (TRUE);
	}

	iss = &isp->stats.ks_data;
	isp->stats.ks->ks_data = (void *)&isp->stats.ks_data;
	isp->stats.ks->ks_data_size = sizeof (isp->stats.ks_data);
	isp->stats.ks->ks_ndata = KN_SESS_IDX_MAX;

	for (i = 0; i < KN_SESS_IDX_MAX; i++) {
		kstat_named_init(&iss->kn[i], kstat_items_sess[i]._name,
		    kstat_items_sess[i]._data_type);
	}

	/* The static information is updated immediately */
	bzero(iss->hba_str, sizeof (iss->hba_str));
	bcopy(ihp->stats.ks->ks_name, iss->hba_str, sizeof (iss->hba_str));
	kstat_named_setstr(&iss->kn[KN_SESS_IDX_HBA],
	    (const char *)iss->hba_str);

	iss->kn[KN_SESS_IDX_OID].value.ul = isp->sess_oid;

	isp->stats.ks->ks_update = iscsi_sess_kstat_update;
	isp->stats.ks->ks_private = (void *)isp;

	/* The IO KSTAT structure is created */
	bzero(ks_name, sizeof (ks_name));

	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_SESS_IO_BASE_NAME,
	    isp->sess_hba->hba_oid, isp->sess_oid) >= sizeof (ks_name)) {
		cmn_err(CE_NOTE, "iscsi kstat createion failed "
		    "for session(%u)", isp->sess_oid);
		kstat_delete(isp->stats.ks);
		return (TRUE);
	}

	isp->stats.ks_io = kstat_create(iSCSI_MODULE_NAME,
	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_SESS,
	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_VIRTUAL);

	if (isp->stats.ks_io == NULL) {
		kstat_delete(isp->stats.ks);
		cmn_err(CE_NOTE, "iscsi kstat creation failed "
		    "for session(%u)", isp->sess_oid);
		return (TRUE);
	}
	mutex_init(&isp->stats.ks_io_lock, NULL, MUTEX_DRIVER, NULL);
	isp->stats.ks_io->ks_data = &isp->stats.ks_io_data;
	isp->stats.ks_io->ks_lock = &isp->stats.ks_io_lock;

	kstat_install(isp->stats.ks);
	kstat_install(isp->stats.ks_io);

	return (FALSE);
}

/*
 * iscsi_sess_kstat_term - This function deregisters with the kstat service.
 */
boolean_t
iscsi_sess_kstat_term(iscsi_sess_t *isp)
{
	kstat_delete(isp->stats.ks_io);
	mutex_destroy(&isp->stats.ks_io_lock);
	kstat_delete(isp->stats.ks);
	return (FALSE);
}

/*
 * iscsi_sess_kstat_update - This function update the kstat
 *	structure of the HBA.
 */
int
iscsi_sess_kstat_update(kstat_t *ks, int rw)
{
	iscsi_sess_t		*isp = (iscsi_sess_t *)ks->ks_private;
	iscsi_sess_stats_t	*iss = &isp->stats.ks_data;
	char			*ptr;
	int			len;

	if (rw == KSTAT_READ) {

		/* String indicating the state of the session */
		ptr = iscsi_sess_state_str(isp->sess_state);
		len =  strlen(ptr);
		if (len > (sizeof (iss->state_str) - 1)) {
			len = sizeof (iss->state_str) - 1;
		}
		bzero(iss->state_str, sizeof (iss->state_str));
		bcopy(ptr, iss->state_str, len);
		kstat_named_setstr(
		    &iss->kn[KN_SESS_IDX_STATE],
		    (const char *)iss->state_str);

		/* Target name string */
		if (isp->sess_name_length > sizeof (iss->target_name)) {
			len = sizeof (iss->target_name);
		} else {
			len =  isp->sess_name_length;
		}
		bzero(iss->target_name, sizeof (iss->target_name));
		bcopy(isp->sess_name, iss->target_name, len);
		kstat_named_setstr(&iss->kn[KN_SESS_IDX_TARGET_NAME],
		    (const char *)iss->target_name);

		/* Target alias string */
		if (isp->sess_alias_length > sizeof (iss->target_alias)) {
			len = sizeof (iss->target_alias);
		} else {
			len =  isp->sess_alias_length;
		}
		bzero(iss->target_alias, sizeof (iss->target_alias));
		bcopy(isp->sess_alias, iss->target_alias, len);
		kstat_named_setstr(
		    &iss->kn[KN_SESS_IDX_TARGET_ALIAS],
		    (const char *)iss->target_alias);

		iss->kn[KN_SESS_IDX_CNTR_PKT_PENDING].value.ul =
		    isp->sess_queue_pending.count;
		iss->kn[KN_SESS_IDX_CMDSN].value.ul =
		    isp->sess_cmdsn;
		iss->kn[KN_SESS_IDX_EXPCMDSN].value.ul =
		    isp->sess_expcmdsn;
		iss->kn[KN_SESS_IDX_MAXCMDSN].value.ul =
		    isp->sess_maxcmdsn;
		iss->kn[KN_SESS_IDX_TPGT].value.ul =
		    isp->sess_tpgt_conf;

	}
	return (0);
}

/*
 * Connection
 */

/*
 * iscsi_conn_kstat_init - This function registers with the kstat service.
 */
boolean_t
iscsi_conn_kstat_init(iscsi_conn_t *icp)
{
	iscsi_sess_t		*isp = icp->conn_sess;
	iscsi_hba_t		*ihp = isp->sess_hba;
	iscsi_conn_stats_t	*ics;
	int			i;
	char			ks_name[KSTAT_STRLEN];

	/*
	 * The name of the KSTAT structure is built.
	 */
	bzero(ks_name, sizeof (ks_name));

	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_CONN_BASE_NAME,
	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
	    icp->conn_oid) >= sizeof (ks_name)) {
		return (TRUE);
	}

	icp->stats.ks = kstat_create(iSCSI_MODULE_NAME,
	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_CONN,
	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);

	if (icp->stats.ks == NULL) {
		cmn_err(CE_NOTE, "iscsi kstat creation failed "
		    "for connection(%d)", icp->conn_oid);
		return (TRUE);
	}

	ics = &icp->stats.ks_data;
	icp->stats.ks->ks_data = (void *)ics;
	icp->stats.ks->ks_data_size = sizeof (*ics);
	icp->stats.ks->ks_ndata = KN_CONN_IDX_MAX;

	for (i = 0; i < KN_CONN_IDX_MAX; i++) {
		kstat_named_init(&ics->kn[i], kstat_items_conn[i]._name,
		    kstat_items_conn[i]._data_type);
	}

	/* The static information is updated immediately */
	bzero(ics->sess_str, sizeof (ics->sess_str));
	bcopy(isp->stats.ks->ks_name,
	    ics->sess_str,
	    sizeof (ics->sess_str));

	kstat_named_setstr(&ics->kn[KN_CONN_IDX_SESS],
	    (const char *)ics->sess_str);

	ics->kn[KN_CONN_IDX_OID].value.ul = isp->sess_oid;
	ics->kn[KN_CONN_IDX_CID].value.ul = icp->conn_cid;
	icp->stats.ks->ks_update = iscsi_conn_kstat_update;
	icp->stats.ks->ks_private = (void *)icp;

	kstat_install(icp->stats.ks);

	return (FALSE);
}

/*
 * iscsi_conn_kstat_term - This function deregisters with the kstat service.
 */
void
iscsi_conn_kstat_term(iscsi_conn_t *icp)
{
	kstat_delete(icp->stats.ks);
}

/*
 * iscsi_conn_kstat_update - This function update the kstat
 *	structure of the HBA.
 */
int
iscsi_conn_kstat_update(kstat_t *ks, int rw)
{
	iscsi_conn_t	*icp = (iscsi_conn_t *)ks->ks_private;
	iscsi_conn_stats_t	*ics = &icp->stats.ks_data;
	int			len;

	if (rw == KSTAT_READ) {
		len =  strlen(iscsi_ics_name[icp->conn_state]);
		if (len > (sizeof (ics->state_str) - 1)) {
			len = sizeof (ics->state_str) - 1;
		}
		bzero(ics->state_str, sizeof (ics->state_str));
		bcopy(iscsi_ics_name[icp->conn_state], ics->state_str, len);
		kstat_named_setstr(&ics->kn[KN_CONN_IDX_STATE],
		    (const char *)ics->state_str);

		ics->kn[KN_CONN_IDX_CNTR_QACTIVE].value.ul =
		    icp->conn_queue_active.count;
		ics->kn[KN_CONN_IDX_EXPSTATSN].value.ul =
		    icp->conn_expstatsn;
		ics->kn[KN_CONN_IDX_LASTSTATSN].value.ul =
		    icp->conn_laststatsn;
	}
	return (0);
}