1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * iSCSI Software Initiator
26  */
27 
28 #define	ISCSI_ICS_NAMES
29 #include "iscsi.h"	/* main header */
30 
31 kstat_item_t	kstat_items_hba[KN_HBA_IDX_MAX] = {
32 	{"_name", KSTAT_DATA_STRING},
33 	{"_alias", KSTAT_DATA_STRING},
34 	{"_cntr_sess", KSTAT_DATA_ULONG}
35 };
36 
37 kstat_item_t	kstat_items_sess[KN_SESS_IDX_MAX] = {
38 	{"_state", KSTAT_DATA_STRING},
39 	{"_oid", KSTAT_DATA_ULONG},
40 	{"_hba", KSTAT_DATA_STRING},
41 	{"_cntr_conn", KSTAT_DATA_ULONG},
42 	{"_cntr_reset", KSTAT_DATA_ULONG},
43 	{"_cntr_pkt_pending", KSTAT_DATA_ULONG},
44 	{"_cmd_sn", KSTAT_DATA_ULONG},
45 	{"_cmd_sn_exp", KSTAT_DATA_ULONG},
46 	{"_cmd_sn_max", KSTAT_DATA_ULONG},
47 	{"_target_name", KSTAT_DATA_STRING},
48 	{"_target_alias", KSTAT_DATA_STRING},
49 	{"_tpgt", KSTAT_DATA_ULONG}
50 };
51 
52 kstat_item_t	kstat_items_conn[KN_CONN_IDX_MAX] = {
53 	{"_state", KSTAT_DATA_STRING},
54 	{"_cid", KSTAT_DATA_ULONG},
55 	{"_oid", KSTAT_DATA_ULONG},
56 	{"_session", KSTAT_DATA_STRING},
57 	{"_err_header_digest", KSTAT_DATA_ULONG},
58 	{"_err_data_digest", KSTAT_DATA_ULONG},
59 	{"_err_connection_reset", KSTAT_DATA_ULONG},
60 	{"_err_protocol_error", KSTAT_DATA_ULONG},
61 	{"_cntr_tx_bytes", KSTAT_DATA_ULONGLONG},
62 	{"_cntr_rx_bytes", KSTAT_DATA_ULONGLONG},
63 	{"_cntr_qactive", KSTAT_DATA_ULONG},
64 	{"_stat_sn_exp", KSTAT_DATA_ULONG},
65 	{"_stat_sn_last", KSTAT_DATA_ULONG}
66 };
67 
68 int iscsi_hba_kstat_update(kstat_t *ks, int rw);
69 int iscsi_sess_kstat_update(kstat_t *ks, int rw);
70 int iscsi_conn_kstat_update(kstat_t *ks, int rw);
71 
72 /*
73  * HBA
74  */
75 
76 /*
77  * iscsi_hba_kstat_init - This function registers with the kstat service.
78  */
79 boolean_t
iscsi_hba_kstat_init(iscsi_hba_t * ihp)80 iscsi_hba_kstat_init(iscsi_hba_t *ihp)
81 {
82 	char			ks_name[KSTAT_STRLEN];
83 	iscsi_hba_stats_t	*ihs;
84 	int			i;
85 
86 	/*
87 	 * The name of the KSTAT structure is built.
88 	 */
89 	bzero(ks_name, sizeof (ks_name));
90 
91 	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_HBA_BASE_NAME,
92 	    ihp->hba_oid) >= sizeof (ks_name)) {
93 		return (TRUE);
94 	}
95 
96 	ihp->stats.ks = kstat_create(iSCSI_MODULE_NAME,
97 	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_HBA,
98 	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
99 
100 	if (ihp->stats.ks == NULL) {
101 		cmn_err(CE_NOTE, "iscsi kstat creation failed for hba(%d)",
102 		    ihp->hba_oid);
103 		return (TRUE);
104 	}
105 
106 	ihs = &ihp->stats.ks_data;
107 	ihp->stats.ks->ks_data = &ihp->stats.ks_data;
108 	ihp->stats.ks->ks_data_size = sizeof (ihp->stats.ks_data);
109 	ihp->stats.ks->ks_ndata = KN_HBA_IDX_MAX;
110 
111 	for (i = 0; i < KN_HBA_IDX_MAX; i++) {
112 		kstat_named_init(&ihs->kn[i], kstat_items_hba[i]._name,
113 		    kstat_items_hba[i]._data_type);
114 	}
115 
116 	ihp->stats.ks->ks_update = iscsi_hba_kstat_update;
117 	ihp->stats.ks->ks_private = (void *)ihp;
118 
119 	kstat_install(ihp->stats.ks);
120 
121 	return (FALSE);
122 }
123 
124 /*
125  * iscsi_hba_kstat_term - This function deregisters from the kstat service.
126  */
127 boolean_t
iscsi_hba_kstat_term(iscsi_hba_t * ihp)128 iscsi_hba_kstat_term(iscsi_hba_t *ihp)
129 {
130 	kstat_delete(ihp->stats.ks);
131 	return (FALSE);
132 }
133 
134 /*
135  * iscsi_hba_kstat_update - This function update the kstat structure of the HBA.
136  */
137 int
iscsi_hba_kstat_update(kstat_t * ks,int rw)138 iscsi_hba_kstat_update(kstat_t *ks, int rw)
139 {
140 	iscsi_hba_t		*ihp = (iscsi_hba_t *)ks->ks_private;
141 	iscsi_hba_stats_t	*ihs = &ihp->stats.ks_data;
142 
143 	if (rw == KSTAT_READ) {
144 		rw_enter(&ihp->hba_sess_list_rwlock, RW_READER);
145 		bcopy(ihp->hba_name, ihs->name, ihp->hba_name_length);
146 
147 		bcopy(ihp->hba_alias, ihs->alias, ihp->hba_alias_length);
148 
149 		ihs->name[ihp->hba_name_length] = 0;
150 		ihs->alias[ihp->hba_alias_length] = 0;
151 
152 		kstat_named_setstr(&ihs->kn[KN_HBA_IDX_NAME],
153 		    (const char *)ihs->name);
154 		kstat_named_setstr(&ihs->kn[KN_HBA_IDX_ALIAS],
155 		    (const char *)ihs->alias);
156 		rw_exit(&ihp->hba_sess_list_rwlock);
157 	}
158 	return (0);
159 }
160 
161 /*
162  * Session
163  */
164 
165 /*
166  * iscsi_sess_kstat_init - This function registers with the kstat service.
167  */
168 boolean_t
iscsi_sess_kstat_init(iscsi_sess_t * isp)169 iscsi_sess_kstat_init(iscsi_sess_t *isp)
170 {
171 	iscsi_hba_t		*ihp;
172 	char			ks_name[KSTAT_STRLEN];
173 	iscsi_sess_stats_t	*iss;
174 	int			i;
175 
176 	ASSERT(isp != NULL);
177 	ihp = isp->sess_hba;
178 	ASSERT(ihp != NULL);
179 
180 	/*
181 	 * The name of the KSTAT structure is built.
182 	 */
183 	bzero(ks_name, sizeof (ks_name));
184 
185 	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_SESS_BASE_NAME,
186 	    isp->sess_hba->hba_oid, isp->sess_oid) >= sizeof (ks_name)) {
187 		cmn_err(CE_NOTE, "iscsi kstat creation failed for "
188 		    "session(%u)", isp->sess_oid);
189 		return (TRUE);
190 	}
191 
192 	isp->stats.ks = kstat_create(iSCSI_MODULE_NAME,
193 	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_SESS,
194 	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
195 
196 	if (isp->stats.ks == NULL) {
197 		cmn_err(CE_NOTE, "iscsi kstat creation failed "
198 		    "for session(%u)", isp->sess_oid);
199 		return (TRUE);
200 	}
201 
202 	iss = &isp->stats.ks_data;
203 	isp->stats.ks->ks_data = (void *)&isp->stats.ks_data;
204 	isp->stats.ks->ks_data_size = sizeof (isp->stats.ks_data);
205 	isp->stats.ks->ks_ndata = KN_SESS_IDX_MAX;
206 
207 	for (i = 0; i < KN_SESS_IDX_MAX; i++) {
208 		kstat_named_init(&iss->kn[i], kstat_items_sess[i]._name,
209 		    kstat_items_sess[i]._data_type);
210 	}
211 
212 	/* The static information is updated immediately */
213 	bzero(iss->hba_str, sizeof (iss->hba_str));
214 	bcopy(ihp->stats.ks->ks_name, iss->hba_str, sizeof (iss->hba_str));
215 	kstat_named_setstr(&iss->kn[KN_SESS_IDX_HBA],
216 	    (const char *)iss->hba_str);
217 
218 	iss->kn[KN_SESS_IDX_OID].value.ul = isp->sess_oid;
219 
220 	isp->stats.ks->ks_update = iscsi_sess_kstat_update;
221 	isp->stats.ks->ks_private = (void *)isp;
222 
223 	/* The IO KSTAT structure is created */
224 	bzero(ks_name, sizeof (ks_name));
225 
226 	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_SESS_IO_BASE_NAME,
227 	    isp->sess_hba->hba_oid, isp->sess_oid) >= sizeof (ks_name)) {
228 		cmn_err(CE_NOTE, "iscsi kstat createion failed "
229 		    "for session(%u)", isp->sess_oid);
230 		kstat_delete(isp->stats.ks);
231 		return (TRUE);
232 	}
233 
234 	isp->stats.ks_io = kstat_create(iSCSI_MODULE_NAME,
235 	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_SESS,
236 	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_VIRTUAL);
237 
238 	if (isp->stats.ks_io == NULL) {
239 		kstat_delete(isp->stats.ks);
240 		cmn_err(CE_NOTE, "iscsi kstat creation failed "
241 		    "for session(%u)", isp->sess_oid);
242 		return (TRUE);
243 	}
244 	mutex_init(&isp->stats.ks_io_lock, NULL, MUTEX_DRIVER, NULL);
245 	isp->stats.ks_io->ks_data = &isp->stats.ks_io_data;
246 	isp->stats.ks_io->ks_lock = &isp->stats.ks_io_lock;
247 
248 	kstat_install(isp->stats.ks);
249 	kstat_install(isp->stats.ks_io);
250 
251 	return (FALSE);
252 }
253 
254 /*
255  * iscsi_sess_kstat_term - This function deregisters with the kstat service.
256  */
257 boolean_t
iscsi_sess_kstat_term(iscsi_sess_t * isp)258 iscsi_sess_kstat_term(iscsi_sess_t *isp)
259 {
260 	kstat_delete(isp->stats.ks_io);
261 	mutex_destroy(&isp->stats.ks_io_lock);
262 	kstat_delete(isp->stats.ks);
263 	return (FALSE);
264 }
265 
266 /*
267  * iscsi_sess_kstat_update - This function update the kstat
268  *	structure of the HBA.
269  */
270 int
iscsi_sess_kstat_update(kstat_t * ks,int rw)271 iscsi_sess_kstat_update(kstat_t *ks, int rw)
272 {
273 	iscsi_sess_t		*isp = (iscsi_sess_t *)ks->ks_private;
274 	iscsi_sess_stats_t	*iss = &isp->stats.ks_data;
275 	char			*ptr;
276 	int			len;
277 
278 	if (rw == KSTAT_READ) {
279 
280 		/* String indicating the state of the session */
281 		ptr = iscsi_sess_state_str(isp->sess_state);
282 		len =  strlen(ptr);
283 		if (len > (sizeof (iss->state_str) - 1)) {
284 			len = sizeof (iss->state_str) - 1;
285 		}
286 		bzero(iss->state_str, sizeof (iss->state_str));
287 		bcopy(ptr, iss->state_str, len);
288 		kstat_named_setstr(
289 		    &iss->kn[KN_SESS_IDX_STATE],
290 		    (const char *)iss->state_str);
291 
292 		/* Target name string */
293 		if (isp->sess_name_length > sizeof (iss->target_name)) {
294 			len = sizeof (iss->target_name);
295 		} else {
296 			len =  isp->sess_name_length;
297 		}
298 		bzero(iss->target_name, sizeof (iss->target_name));
299 		bcopy(isp->sess_name, iss->target_name, len);
300 		kstat_named_setstr(&iss->kn[KN_SESS_IDX_TARGET_NAME],
301 		    (const char *)iss->target_name);
302 
303 		/* Target alias string */
304 		if (isp->sess_alias_length > sizeof (iss->target_alias)) {
305 			len = sizeof (iss->target_alias);
306 		} else {
307 			len =  isp->sess_alias_length;
308 		}
309 		bzero(iss->target_alias, sizeof (iss->target_alias));
310 		bcopy(isp->sess_alias, iss->target_alias, len);
311 		kstat_named_setstr(
312 		    &iss->kn[KN_SESS_IDX_TARGET_ALIAS],
313 		    (const char *)iss->target_alias);
314 
315 		iss->kn[KN_SESS_IDX_CNTR_PKT_PENDING].value.ul =
316 		    isp->sess_queue_pending.count;
317 		iss->kn[KN_SESS_IDX_CMDSN].value.ul =
318 		    isp->sess_cmdsn;
319 		iss->kn[KN_SESS_IDX_EXPCMDSN].value.ul =
320 		    isp->sess_expcmdsn;
321 		iss->kn[KN_SESS_IDX_MAXCMDSN].value.ul =
322 		    isp->sess_maxcmdsn;
323 		iss->kn[KN_SESS_IDX_TPGT].value.ul =
324 		    isp->sess_tpgt_conf;
325 
326 	}
327 	return (0);
328 }
329 
330 /*
331  * Connection
332  */
333 
334 /*
335  * iscsi_conn_kstat_init - This function registers with the kstat service.
336  */
337 boolean_t
iscsi_conn_kstat_init(iscsi_conn_t * icp)338 iscsi_conn_kstat_init(iscsi_conn_t *icp)
339 {
340 	iscsi_sess_t		*isp = icp->conn_sess;
341 	iscsi_hba_t		*ihp = isp->sess_hba;
342 	iscsi_conn_stats_t	*ics;
343 	int			i;
344 	char			ks_name[KSTAT_STRLEN];
345 
346 	/*
347 	 * The name of the KSTAT structure is built.
348 	 */
349 	bzero(ks_name, sizeof (ks_name));
350 
351 	if (snprintf(ks_name, sizeof (ks_name) - 1, iSCSI_CONN_BASE_NAME,
352 	    icp->conn_sess->sess_hba->hba_oid, icp->conn_sess->sess_oid,
353 	    icp->conn_oid) >= sizeof (ks_name)) {
354 		return (TRUE);
355 	}
356 
357 	icp->stats.ks = kstat_create(iSCSI_MODULE_NAME,
358 	    ddi_get_instance(ihp->hba_dip), ks_name, iSCSI_CLASS_CONN,
359 	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
360 
361 	if (icp->stats.ks == NULL) {
362 		cmn_err(CE_NOTE, "iscsi kstat creation failed "
363 		    "for connection(%d)", icp->conn_oid);
364 		return (TRUE);
365 	}
366 
367 	ics = &icp->stats.ks_data;
368 	icp->stats.ks->ks_data = (void *)ics;
369 	icp->stats.ks->ks_data_size = sizeof (*ics);
370 	icp->stats.ks->ks_ndata = KN_CONN_IDX_MAX;
371 
372 	for (i = 0; i < KN_CONN_IDX_MAX; i++) {
373 		kstat_named_init(&ics->kn[i], kstat_items_conn[i]._name,
374 		    kstat_items_conn[i]._data_type);
375 	}
376 
377 	/* The static information is updated immediately */
378 	bzero(ics->sess_str, sizeof (ics->sess_str));
379 	bcopy(isp->stats.ks->ks_name,
380 	    ics->sess_str,
381 	    sizeof (ics->sess_str));
382 
383 	kstat_named_setstr(&ics->kn[KN_CONN_IDX_SESS],
384 	    (const char *)ics->sess_str);
385 
386 	ics->kn[KN_CONN_IDX_OID].value.ul = isp->sess_oid;
387 	ics->kn[KN_CONN_IDX_CID].value.ul = icp->conn_cid;
388 	icp->stats.ks->ks_update = iscsi_conn_kstat_update;
389 	icp->stats.ks->ks_private = (void *)icp;
390 
391 	kstat_install(icp->stats.ks);
392 
393 	return (FALSE);
394 }
395 
396 /*
397  * iscsi_conn_kstat_term - This function deregisters with the kstat service.
398  */
399 void
iscsi_conn_kstat_term(iscsi_conn_t * icp)400 iscsi_conn_kstat_term(iscsi_conn_t *icp)
401 {
402 	kstat_delete(icp->stats.ks);
403 }
404 
405 /*
406  * iscsi_conn_kstat_update - This function update the kstat
407  *	structure of the HBA.
408  */
409 int
iscsi_conn_kstat_update(kstat_t * ks,int rw)410 iscsi_conn_kstat_update(kstat_t *ks, int rw)
411 {
412 	iscsi_conn_t	*icp = (iscsi_conn_t *)ks->ks_private;
413 	iscsi_conn_stats_t	*ics = &icp->stats.ks_data;
414 	int			len;
415 
416 	if (rw == KSTAT_READ) {
417 		len =  strlen(iscsi_ics_name[icp->conn_state]);
418 		if (len > (sizeof (ics->state_str) - 1)) {
419 			len = sizeof (ics->state_str) - 1;
420 		}
421 		bzero(ics->state_str, sizeof (ics->state_str));
422 		bcopy(iscsi_ics_name[icp->conn_state], ics->state_str, len);
423 		kstat_named_setstr(&ics->kn[KN_CONN_IDX_STATE],
424 		    (const char *)ics->state_str);
425 
426 		ics->kn[KN_CONN_IDX_CNTR_QACTIVE].value.ul =
427 		    icp->conn_queue_active.count;
428 		ics->kn[KN_CONN_IDX_EXPSTATSN].value.ul =
429 		    icp->conn_expstatsn;
430 		ics->kn[KN_CONN_IDX_LASTSTATSN].value.ul =
431 		    icp->conn_laststatsn;
432 	}
433 	return (0);
434 }
435