1/*
2 * Copyright (c) 2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2007 The Regents of the University of California.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 */
34
35#if HAVE_CONFIG_H
36#  include <config.h>
37#endif				/* HAVE_CONFIG_H */
38
39#ifdef ENABLE_OSM_PERF_MGR
40
41#include <stdlib.h>
42#include <errno.h>
43#include <limits.h>
44#include <dlfcn.h>
45#include <sys/stat.h>
46
47#include <opensm/osm_perfmgr_db.h>
48#include <opensm/osm_perfmgr.h>
49#include <opensm/osm_opensm.h>
50
51/** =========================================================================
52 */
53perfmgr_db_t *perfmgr_db_construct(osm_perfmgr_t *perfmgr)
54{
55	perfmgr_db_t *db = malloc(sizeof(*db));
56	if (!db)
57		return (NULL);
58
59	cl_qmap_init(&(db->pc_data));
60	cl_plock_construct(&(db->lock));
61	cl_plock_init(&(db->lock));
62	db->perfmgr = perfmgr;
63	return ((void *)db);
64}
65
66/** =========================================================================
67 */
68void perfmgr_db_destroy(perfmgr_db_t * db)
69{
70	if (db) {
71		cl_plock_destroy(&(db->lock));
72		free(db);
73	}
74}
75
76/**********************************************************************
77 * Internal call db->lock should be held when calling
78 **********************************************************************/
79static inline _db_node_t *_get(perfmgr_db_t * db, uint64_t guid)
80{
81	cl_map_item_t *rc = cl_qmap_get(&(db->pc_data), guid);
82	const cl_map_item_t *end = cl_qmap_end(&(db->pc_data));
83
84	if (rc == end)
85		return (NULL);
86	return ((_db_node_t *) rc);
87}
88
89static inline perfmgr_db_err_t bad_node_port(_db_node_t * node, uint8_t port)
90{
91	if (!node)
92		return (PERFMGR_EVENT_DB_GUIDNOTFOUND);
93	if (port == 0 || port >= node->num_ports)
94		return (PERFMGR_EVENT_DB_PORTNOTFOUND);
95	return (PERFMGR_EVENT_DB_SUCCESS);
96}
97
98/** =========================================================================
99 */
100static _db_node_t *__malloc_node(uint64_t guid, uint8_t num_ports, char *name)
101{
102	int i = 0;
103	time_t cur_time = 0;
104	_db_node_t *rc = malloc(sizeof(*rc));
105	if (!rc)
106		return (NULL);
107
108	rc->ports = calloc(num_ports, sizeof(_db_port_t));
109	if (!rc->ports)
110		goto free_rc;
111	rc->num_ports = num_ports;
112	rc->node_guid = guid;
113
114	cur_time = time(NULL);
115	for (i = 0; i < num_ports; i++) {
116		rc->ports[i].last_reset = cur_time;
117		rc->ports[i].err_previous.time = cur_time;
118		rc->ports[i].dc_previous.time = cur_time;
119	}
120	snprintf(rc->node_name, NODE_NAME_SIZE, "%s", name);
121
122	return (rc);
123
124free_rc:
125	free(rc);
126	return (NULL);
127}
128
129/** =========================================================================
130 */
131static void __free_node(_db_node_t * node)
132{
133	if (!node)
134		return;
135	if (node->ports)
136		free(node->ports);
137	free(node);
138}
139
140/* insert nodes to the database */
141static perfmgr_db_err_t __insert(perfmgr_db_t * db, _db_node_t * node)
142{
143	cl_map_item_t *rc = cl_qmap_insert(&(db->pc_data), node->node_guid,
144					   (cl_map_item_t *) node);
145
146	if ((void *)rc != (void *)node)
147		return (PERFMGR_EVENT_DB_FAIL);
148	return (PERFMGR_EVENT_DB_SUCCESS);
149}
150
151/**********************************************************************
152 **********************************************************************/
153perfmgr_db_err_t
154perfmgr_db_create_entry(perfmgr_db_t * db, uint64_t guid,
155			uint8_t num_ports, char *name)
156{
157	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
158
159	cl_plock_excl_acquire(&(db->lock));
160	if (!_get(db, guid)) {
161		_db_node_t *pc_node = __malloc_node(guid, num_ports, name);
162		if (!pc_node) {
163			rc = PERFMGR_EVENT_DB_NOMEM;
164			goto Exit;
165		}
166		if (__insert(db, pc_node)) {
167			__free_node(pc_node);
168			rc = PERFMGR_EVENT_DB_FAIL;
169			goto Exit;
170		}
171	}
172Exit:
173	cl_plock_release(&(db->lock));
174	return (rc);
175}
176
177/**********************************************************************
178 * Dump a reading vs the previous reading to stdout
179 **********************************************************************/
180static inline void
181debug_dump_err_reading(perfmgr_db_t * db, uint64_t guid, uint8_t port_num,
182		       _db_port_t * port, perfmgr_db_err_reading_t * cur)
183{
184	osm_log_t *log = db->perfmgr->log;
185
186	if (!osm_log_is_active(log, OSM_LOG_DEBUG))
187		return;		/* optimize this a bit */
188
189	osm_log(log, OSM_LOG_DEBUG,
190		"GUID 0x%" PRIx64 " Port %u:\n", guid, port_num);
191	osm_log(log, OSM_LOG_DEBUG,
192		"sym %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
193		cur->symbol_err_cnt, port->err_previous.symbol_err_cnt,
194		port->err_total.symbol_err_cnt);
195	osm_log(log, OSM_LOG_DEBUG,
196		"ler %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
197		cur->link_err_recover, port->err_previous.link_err_recover,
198		port->err_total.link_err_recover);
199	osm_log(log, OSM_LOG_DEBUG,
200		"ld %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
201		cur->link_downed, port->err_previous.link_downed,
202		port->err_total.link_downed);
203	osm_log(log, OSM_LOG_DEBUG,
204		"re %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", cur->rcv_err,
205		port->err_previous.rcv_err, port->err_total.rcv_err);
206	osm_log(log, OSM_LOG_DEBUG,
207		"rrp %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
208		cur->rcv_rem_phys_err, port->err_previous.rcv_rem_phys_err,
209		port->err_total.rcv_rem_phys_err);
210	osm_log(log, OSM_LOG_DEBUG,
211		"rsr %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
212		cur->rcv_switch_relay_err,
213		port->err_previous.rcv_switch_relay_err,
214		port->err_total.rcv_switch_relay_err);
215	osm_log(log, OSM_LOG_DEBUG,
216		"xd %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
217		cur->xmit_discards, port->err_previous.xmit_discards,
218		port->err_total.xmit_discards);
219	osm_log(log, OSM_LOG_DEBUG,
220		"xce %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
221		cur->xmit_constraint_err,
222		port->err_previous.xmit_constraint_err,
223		port->err_total.xmit_constraint_err);
224	osm_log(log, OSM_LOG_DEBUG,
225		"rce %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
226		cur->rcv_constraint_err, port->err_previous.rcv_constraint_err,
227		port->err_total.rcv_constraint_err);
228	osm_log(log, OSM_LOG_DEBUG,
229		"li %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
230		cur->link_integrity, port->err_previous.link_integrity,
231		port->err_total.link_integrity);
232	osm_log(log, OSM_LOG_DEBUG,
233		"bo %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
234		cur->buffer_overrun, port->err_previous.buffer_overrun,
235		port->err_total.buffer_overrun);
236	osm_log(log, OSM_LOG_DEBUG,
237		"vld %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
238		cur->vl15_dropped, port->err_previous.vl15_dropped,
239		port->err_total.vl15_dropped);
240}
241
242/**********************************************************************
243 * perfmgr_db_err_reading_t functions
244 **********************************************************************/
245perfmgr_db_err_t
246perfmgr_db_add_err_reading(perfmgr_db_t * db, uint64_t guid,
247			   uint8_t port, perfmgr_db_err_reading_t * reading)
248{
249	_db_port_t *p_port = NULL;
250	_db_node_t *node = NULL;
251	perfmgr_db_err_reading_t *previous = NULL;
252	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
253	osm_epi_pe_event_t epi_pe_data;
254
255	cl_plock_excl_acquire(&(db->lock));
256	node = _get(db, guid);
257	if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS)
258		goto Exit;
259
260	p_port = &(node->ports[port]);
261	previous = &(node->ports[port].err_previous);
262
263	debug_dump_err_reading(db, guid, port, p_port, reading);
264
265	epi_pe_data.time_diff_s = (reading->time - previous->time);
266	osm_epi_create_port_id(&(epi_pe_data.port_id), guid, port,
267			       node->node_name);
268
269	/* calculate changes from previous reading */
270	epi_pe_data.symbol_err_cnt =
271	    (reading->symbol_err_cnt - previous->symbol_err_cnt);
272	p_port->err_total.symbol_err_cnt += epi_pe_data.symbol_err_cnt;
273	epi_pe_data.link_err_recover =
274	    (reading->link_err_recover - previous->link_err_recover);
275	p_port->err_total.link_err_recover += epi_pe_data.link_err_recover;
276	epi_pe_data.link_downed =
277	    (reading->link_downed - previous->link_downed);
278	p_port->err_total.link_downed += epi_pe_data.link_downed;
279	epi_pe_data.rcv_err = (reading->rcv_err - previous->rcv_err);
280	p_port->err_total.rcv_err += epi_pe_data.rcv_err;
281	epi_pe_data.rcv_rem_phys_err =
282	    (reading->rcv_rem_phys_err - previous->rcv_rem_phys_err);
283	p_port->err_total.rcv_rem_phys_err += epi_pe_data.rcv_rem_phys_err;
284	epi_pe_data.rcv_switch_relay_err =
285	    (reading->rcv_switch_relay_err - previous->rcv_switch_relay_err);
286	p_port->err_total.rcv_switch_relay_err +=
287	    epi_pe_data.rcv_switch_relay_err;
288	epi_pe_data.xmit_discards =
289	    (reading->xmit_discards - previous->xmit_discards);
290	p_port->err_total.xmit_discards += epi_pe_data.xmit_discards;
291	epi_pe_data.xmit_constraint_err =
292	    (reading->xmit_constraint_err - previous->xmit_constraint_err);
293	p_port->err_total.xmit_constraint_err +=
294	    epi_pe_data.xmit_constraint_err;
295	epi_pe_data.rcv_constraint_err =
296	    (reading->rcv_constraint_err - previous->rcv_constraint_err);
297	p_port->err_total.rcv_constraint_err += epi_pe_data.rcv_constraint_err;
298	epi_pe_data.link_integrity =
299	    (reading->link_integrity - previous->link_integrity);
300	p_port->err_total.link_integrity += epi_pe_data.link_integrity;
301	epi_pe_data.buffer_overrun =
302	    (reading->buffer_overrun - previous->buffer_overrun);
303	p_port->err_total.buffer_overrun += epi_pe_data.buffer_overrun;
304	epi_pe_data.vl15_dropped =
305	    (reading->vl15_dropped - previous->vl15_dropped);
306	p_port->err_total.vl15_dropped += epi_pe_data.vl15_dropped;
307
308	p_port->err_previous = *reading;
309
310	osm_opensm_report_event(db->perfmgr->osm, OSM_EVENT_ID_PORT_ERRORS,
311				&epi_pe_data);
312
313Exit:
314	cl_plock_release(&(db->lock));
315	return (rc);
316}
317
318perfmgr_db_err_t perfmgr_db_get_prev_err(perfmgr_db_t * db, uint64_t guid,
319					 uint8_t port,
320					 perfmgr_db_err_reading_t * reading)
321{
322	_db_node_t *node = NULL;
323	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
324
325	cl_plock_acquire(&(db->lock));
326
327	node = _get(db, guid);
328	if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS)
329		goto Exit;
330
331	*reading = node->ports[port].err_previous;
332
333Exit:
334	cl_plock_release(&(db->lock));
335	return (rc);
336}
337
338perfmgr_db_err_t
339perfmgr_db_clear_prev_err(perfmgr_db_t * db, uint64_t guid, uint8_t port)
340{
341	_db_node_t *node = NULL;
342	perfmgr_db_err_reading_t *previous = NULL;
343	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
344
345	cl_plock_excl_acquire(&(db->lock));
346	node = _get(db, guid);
347	if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS)
348		goto Exit;
349
350	previous = &(node->ports[port].err_previous);
351
352	memset(previous, 0, sizeof(*previous));
353	node->ports[port].err_previous.time = time(NULL);
354
355Exit:
356	cl_plock_release(&(db->lock));
357	return (rc);
358}
359
360static inline void
361debug_dump_dc_reading(perfmgr_db_t * db, uint64_t guid, uint8_t port_num,
362		      _db_port_t * port, perfmgr_db_data_cnt_reading_t * cur)
363{
364	osm_log_t *log = db->perfmgr->log;
365	if (!osm_log_is_active(log, OSM_LOG_DEBUG))
366		return;		/* optimize this a big */
367
368	osm_log(log, OSM_LOG_DEBUG,
369		"xd %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
370		cur->xmit_data, port->dc_previous.xmit_data,
371		port->dc_total.xmit_data);
372	osm_log(log, OSM_LOG_DEBUG,
373		"rd %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", cur->rcv_data,
374		port->dc_previous.rcv_data, port->dc_total.rcv_data);
375	osm_log(log, OSM_LOG_DEBUG,
376		"xp %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n",
377		cur->xmit_pkts, port->dc_previous.xmit_pkts,
378		port->dc_total.xmit_pkts);
379	osm_log(log, OSM_LOG_DEBUG,
380		"rp %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", cur->rcv_pkts,
381		port->dc_previous.rcv_pkts, port->dc_total.rcv_pkts);
382}
383
384/**********************************************************************
385 * perfmgr_db_data_cnt_reading_t functions
386 **********************************************************************/
387perfmgr_db_err_t
388perfmgr_db_add_dc_reading(perfmgr_db_t * db, uint64_t guid,
389			  uint8_t port, perfmgr_db_data_cnt_reading_t * reading)
390{
391	_db_port_t *p_port = NULL;
392	_db_node_t *node = NULL;
393	perfmgr_db_data_cnt_reading_t *previous = NULL;
394	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
395	osm_epi_dc_event_t epi_dc_data;
396
397	cl_plock_excl_acquire(&(db->lock));
398	node = _get(db, guid);
399	if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS)
400		goto Exit;
401
402	p_port = &(node->ports[port]);
403	previous = &(node->ports[port].dc_previous);
404
405	debug_dump_dc_reading(db, guid, port, p_port, reading);
406
407	epi_dc_data.time_diff_s = (reading->time - previous->time);
408	osm_epi_create_port_id(&(epi_dc_data.port_id), guid, port,
409			       node->node_name);
410
411	/* calculate changes from previous reading */
412	epi_dc_data.xmit_data = (reading->xmit_data - previous->xmit_data);
413	p_port->dc_total.xmit_data += epi_dc_data.xmit_data;
414	epi_dc_data.rcv_data = (reading->rcv_data - previous->rcv_data);
415	p_port->dc_total.rcv_data += epi_dc_data.rcv_data;
416	epi_dc_data.xmit_pkts = (reading->xmit_pkts - previous->xmit_pkts);
417	p_port->dc_total.xmit_pkts += epi_dc_data.xmit_pkts;
418	epi_dc_data.rcv_pkts = (reading->rcv_pkts - previous->rcv_pkts);
419	p_port->dc_total.rcv_pkts += epi_dc_data.rcv_pkts;
420	epi_dc_data.unicast_xmit_pkts =
421	    (reading->unicast_xmit_pkts - previous->unicast_xmit_pkts);
422	p_port->dc_total.unicast_xmit_pkts += epi_dc_data.unicast_xmit_pkts;
423	epi_dc_data.unicast_rcv_pkts =
424	    (reading->unicast_rcv_pkts - previous->unicast_rcv_pkts);
425	p_port->dc_total.unicast_rcv_pkts += epi_dc_data.unicast_rcv_pkts;
426	epi_dc_data.multicast_xmit_pkts =
427	    (reading->multicast_xmit_pkts - previous->multicast_xmit_pkts);
428	p_port->dc_total.multicast_xmit_pkts += epi_dc_data.multicast_xmit_pkts;
429	epi_dc_data.multicast_rcv_pkts =
430	    (reading->multicast_rcv_pkts - previous->multicast_rcv_pkts);
431	p_port->dc_total.multicast_rcv_pkts += epi_dc_data.multicast_rcv_pkts;
432
433	p_port->dc_previous = *reading;
434
435	osm_opensm_report_event(db->perfmgr->osm,
436				OSM_EVENT_ID_PORT_DATA_COUNTERS, &epi_dc_data);
437
438Exit:
439	cl_plock_release(&(db->lock));
440	return (rc);
441}
442
443perfmgr_db_err_t perfmgr_db_get_prev_dc(perfmgr_db_t * db, uint64_t guid,
444					uint8_t port,
445					perfmgr_db_data_cnt_reading_t * reading)
446{
447	_db_node_t *node = NULL;
448	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
449
450	cl_plock_acquire(&(db->lock));
451
452	node = _get(db, guid);
453	if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS)
454		goto Exit;
455
456	*reading = node->ports[port].dc_previous;
457
458Exit:
459	cl_plock_release(&(db->lock));
460	return (rc);
461}
462
463perfmgr_db_err_t
464perfmgr_db_clear_prev_dc(perfmgr_db_t * db, uint64_t guid, uint8_t port)
465{
466	_db_node_t *node = NULL;
467	perfmgr_db_data_cnt_reading_t *previous = NULL;
468	perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS;
469
470	cl_plock_excl_acquire(&(db->lock));
471	node = _get(db, guid);
472	if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS)
473		goto Exit;
474
475	previous = &(node->ports[port].dc_previous);
476
477	memset(previous, 0, sizeof(*previous));
478	node->ports[port].dc_previous.time = time(NULL);
479
480Exit:
481	cl_plock_release(&(db->lock));
482	return (rc);
483}
484
485static void __clear_counters(cl_map_item_t * const p_map_item, void *context)
486{
487	_db_node_t *node = (_db_node_t *) p_map_item;
488	int i = 0;
489	time_t ts = time(NULL);
490
491	for (i = 0; i < node->num_ports; i++) {
492		node->ports[i].err_total.symbol_err_cnt = 0;
493		node->ports[i].err_total.link_err_recover = 0;
494		node->ports[i].err_total.link_downed = 0;
495		node->ports[i].err_total.rcv_err = 0;
496		node->ports[i].err_total.rcv_rem_phys_err = 0;
497		node->ports[i].err_total.rcv_switch_relay_err = 0;
498		node->ports[i].err_total.xmit_discards = 0;
499		node->ports[i].err_total.xmit_constraint_err = 0;
500		node->ports[i].err_total.rcv_constraint_err = 0;
501		node->ports[i].err_total.link_integrity = 0;
502		node->ports[i].err_total.buffer_overrun = 0;
503		node->ports[i].err_total.vl15_dropped = 0;
504		node->ports[i].err_total.time = ts;
505
506		node->ports[i].dc_total.xmit_data = 0;
507		node->ports[i].dc_total.rcv_data = 0;
508		node->ports[i].dc_total.xmit_pkts = 0;
509		node->ports[i].dc_total.rcv_pkts = 0;
510		node->ports[i].dc_total.unicast_xmit_pkts = 0;
511		node->ports[i].dc_total.unicast_rcv_pkts = 0;
512		node->ports[i].dc_total.multicast_xmit_pkts = 0;
513		node->ports[i].dc_total.multicast_rcv_pkts = 0;
514		node->ports[i].dc_total.time = ts;
515
516		node->ports[i].last_reset = ts;
517	}
518}
519
520/**********************************************************************
521 * Clear all the counters from the db
522 **********************************************************************/
523void perfmgr_db_clear_counters(perfmgr_db_t * db)
524{
525	cl_plock_excl_acquire(&(db->lock));
526	cl_qmap_apply_func(&(db->pc_data), __clear_counters, (void *)db);
527	cl_plock_release(&(db->lock));
528#if 0
529	if (db->db_impl->clear_counters)
530		db->db_impl->clear_counters(db->db_data);
531#endif
532}
533
534/**********************************************************************
535 * Output a tab delimited output of the port counters
536 **********************************************************************/
537static void __dump_node_mr(_db_node_t * node, FILE * fp)
538{
539	int i = 0;
540
541	fprintf(fp, "\nName\tGUID\tPort\tLast Reset\t"
542		"%s\t%s\t"
543		"%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
544		"%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
545		"%s\t%s\t%s\t%s\n",
546		"symbol_err_cnt",
547		"link_err_recover",
548		"link_downed",
549		"rcv_err",
550		"rcv_rem_phys_err",
551		"rcv_switch_relay_err",
552		"xmit_discards",
553		"xmit_constraint_err",
554		"rcv_constraint_err",
555		"link_int_err",
556		"buf_overrun_err",
557		"vl15_dropped",
558		"xmit_data",
559		"rcv_data",
560		"xmit_pkts",
561		"rcv_pkts",
562		"unicast_xmit_pkts",
563		"unicast_rcv_pkts",
564		"multicast_xmit_pkts", "multicast_rcv_pkts");
565	for (i = 1; i < node->num_ports; i++) {
566		char *since = ctime(&(node->ports[i].last_reset));
567		since[strlen(since) - 1] = '\0';	/* remove \n */
568
569		fprintf(fp,
570			"%s\t0x%" PRIx64 "\t%d\t%s\t%" PRIu64 "\t%" PRIu64 "\t"
571			"%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t"
572			"%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t" "%" PRIu64
573			"\t%" PRIu64 "\t%" PRIu64 "\t" "%" PRIu64 "\t%" PRIu64
574			"\t%" PRIu64 "\t%" PRIu64 "\t" "%" PRIu64 "\t%" PRIu64
575			"\t%" PRIu64 "\t%" PRIu64 "\n", node->node_name,
576			node->node_guid, i, since,
577			node->ports[i].err_total.symbol_err_cnt,
578			node->ports[i].err_total.link_err_recover,
579			node->ports[i].err_total.link_downed,
580			node->ports[i].err_total.rcv_err,
581			node->ports[i].err_total.rcv_rem_phys_err,
582			node->ports[i].err_total.rcv_switch_relay_err,
583			node->ports[i].err_total.xmit_discards,
584			node->ports[i].err_total.xmit_constraint_err,
585			node->ports[i].err_total.rcv_constraint_err,
586			node->ports[i].err_total.link_integrity,
587			node->ports[i].err_total.buffer_overrun,
588			node->ports[i].err_total.vl15_dropped,
589			node->ports[i].dc_total.xmit_data,
590			node->ports[i].dc_total.rcv_data,
591			node->ports[i].dc_total.xmit_pkts,
592			node->ports[i].dc_total.rcv_pkts,
593			node->ports[i].dc_total.unicast_xmit_pkts,
594			node->ports[i].dc_total.unicast_rcv_pkts,
595			node->ports[i].dc_total.multicast_xmit_pkts,
596			node->ports[i].dc_total.multicast_rcv_pkts);
597	}
598}
599
600/**********************************************************************
601 * Output a human readable output of the port counters
602 **********************************************************************/
603static void __dump_node_hr(_db_node_t * node, FILE * fp)
604{
605	int i = 0;
606
607	fprintf(fp, "\n");
608	for (i = 1; i < node->num_ports; i++) {
609		char *since = ctime(&(node->ports[i].last_reset));
610		since[strlen(since) - 1] = '\0';	/* remove \n */
611
612		fprintf(fp, "\"%s\" 0x%" PRIx64 " port %d (Since %s)\n"
613			"     symbol_err_cnt       : %" PRIu64 "\n"
614			"     link_err_recover     : %" PRIu64 "\n"
615			"     link_downed          : %" PRIu64 "\n"
616			"     rcv_err              : %" PRIu64 "\n"
617			"     rcv_rem_phys_err     : %" PRIu64 "\n"
618			"     rcv_switch_relay_err : %" PRIu64 "\n"
619			"     xmit_discards        : %" PRIu64 "\n"
620			"     xmit_constraint_err  : %" PRIu64 "\n"
621			"     rcv_constraint_err   : %" PRIu64 "\n"
622			"     link_integrity_err   : %" PRIu64 "\n"
623			"     buf_overrun_err      : %" PRIu64 "\n"
624			"     vl15_dropped         : %" PRIu64 "\n"
625			"     xmit_data            : %" PRIu64 "\n"
626			"     rcv_data             : %" PRIu64 "\n"
627			"     xmit_pkts            : %" PRIu64 "\n"
628			"     rcv_pkts             : %" PRIu64 "\n"
629			"     unicast_xmit_pkts    : %" PRIu64 "\n"
630			"     unicast_rcv_pkts     : %" PRIu64 "\n"
631			"     multicast_xmit_pkts  : %" PRIu64 "\n"
632			"     multicast_rcv_pkts   : %" PRIu64 "\n",
633			node->node_name,
634			node->node_guid,
635			i,
636			since,
637			node->ports[i].err_total.symbol_err_cnt,
638			node->ports[i].err_total.link_err_recover,
639			node->ports[i].err_total.link_downed,
640			node->ports[i].err_total.rcv_err,
641			node->ports[i].err_total.rcv_rem_phys_err,
642			node->ports[i].err_total.rcv_switch_relay_err,
643			node->ports[i].err_total.xmit_discards,
644			node->ports[i].err_total.xmit_constraint_err,
645			node->ports[i].err_total.rcv_constraint_err,
646			node->ports[i].err_total.link_integrity,
647			node->ports[i].err_total.buffer_overrun,
648			node->ports[i].err_total.vl15_dropped,
649			node->ports[i].dc_total.xmit_data,
650			node->ports[i].dc_total.rcv_data,
651			node->ports[i].dc_total.xmit_pkts,
652			node->ports[i].dc_total.rcv_pkts,
653			node->ports[i].dc_total.unicast_xmit_pkts,
654			node->ports[i].dc_total.unicast_rcv_pkts,
655			node->ports[i].dc_total.multicast_xmit_pkts,
656			node->ports[i].dc_total.multicast_rcv_pkts);
657	}
658}
659
660/* Define a context for the __db_dump callback */
661typedef struct {
662	FILE *fp;
663	perfmgr_db_dump_t dump_type;
664} dump_context_t;
665
666/**********************************************************************
667 **********************************************************************/
668static void __db_dump(cl_map_item_t * const p_map_item, void *context)
669{
670	_db_node_t *node = (_db_node_t *) p_map_item;
671	dump_context_t *c = (dump_context_t *) context;
672	FILE *fp = c->fp;
673
674	switch (c->dump_type) {
675	case PERFMGR_EVENT_DB_DUMP_MR:
676		__dump_node_mr(node, fp);
677		break;
678	case PERFMGR_EVENT_DB_DUMP_HR:
679	default:
680		__dump_node_hr(node, fp);
681		break;
682	}
683}
684
685/**********************************************************************
686 * print node data to fp
687 **********************************************************************/
688void
689perfmgr_db_print_by_name(perfmgr_db_t * db, char *nodename, FILE *fp)
690{
691	cl_map_item_t *item = NULL;
692	_db_node_t *node = NULL;
693
694	cl_plock_acquire(&(db->lock));
695
696	/* find the node */
697	item = cl_qmap_head(&(db->pc_data));
698	while (item != cl_qmap_end(&(db->pc_data))) {
699		node = (_db_node_t *)item;
700		if (strcmp(node->node_name, nodename) == 0) {
701			__dump_node_hr(node, fp);
702			goto done;
703		}
704		item = cl_qmap_next(item);
705	}
706
707	fprintf(fp, "Node %s not found...\n", nodename);
708done:
709	cl_plock_release(&(db->lock));
710}
711
712/**********************************************************************
713 * print node data to fp
714 **********************************************************************/
715void
716perfmgr_db_print_by_guid(perfmgr_db_t * db, uint64_t nodeguid, FILE *fp)
717{
718	cl_map_item_t *node = NULL;
719
720	cl_plock_acquire(&(db->lock));
721
722	node = cl_qmap_get(&(db->pc_data), nodeguid);
723	if (node != cl_qmap_end(&(db->pc_data)))
724		__dump_node_hr((_db_node_t *)node, fp);
725	else
726		fprintf(fp, "Node %"PRIx64" not found...\n", nodeguid);
727
728	cl_plock_release(&(db->lock));
729}
730
731/**********************************************************************
732 * dump the data to the file "file"
733 **********************************************************************/
734perfmgr_db_err_t
735perfmgr_db_dump(perfmgr_db_t * db, char *file, perfmgr_db_dump_t dump_type)
736{
737	dump_context_t context;
738
739	context.fp = fopen(file, "w+");
740	if (!context.fp)
741		return (PERFMGR_EVENT_DB_FAIL);
742	context.dump_type = dump_type;
743
744	cl_plock_acquire(&(db->lock));
745	cl_qmap_apply_func(&(db->pc_data), __db_dump, (void *)&context);
746	cl_plock_release(&(db->lock));
747	fclose(context.fp);
748	return (PERFMGR_EVENT_DB_SUCCESS);
749}
750
751/**********************************************************************
752 * Fill in the various DB objects from their wire counter parts
753 **********************************************************************/
754void
755perfmgr_db_fill_err_read(ib_port_counters_t * wire_read,
756			 perfmgr_db_err_reading_t * reading)
757{
758	reading->symbol_err_cnt = cl_ntoh16(wire_read->symbol_err_cnt);
759	reading->link_err_recover = cl_ntoh16(wire_read->link_err_recover);
760	reading->link_downed = wire_read->link_downed;
761	reading->rcv_err = wire_read->rcv_err;
762	reading->rcv_rem_phys_err = cl_ntoh16(wire_read->rcv_rem_phys_err);
763	reading->rcv_switch_relay_err =
764	    cl_ntoh16(wire_read->rcv_switch_relay_err);
765	reading->xmit_discards = cl_ntoh16(wire_read->xmit_discards);
766	reading->xmit_constraint_err =
767	    cl_ntoh16(wire_read->xmit_constraint_err);
768	reading->rcv_constraint_err = wire_read->rcv_constraint_err;
769	reading->link_integrity =
770	    PC_LINK_INT(wire_read->link_int_buffer_overrun);
771	reading->buffer_overrun =
772	    PC_BUF_OVERRUN(wire_read->link_int_buffer_overrun);
773	reading->vl15_dropped = cl_ntoh16(wire_read->vl15_dropped);
774	reading->time = time(NULL);
775}
776
777void
778perfmgr_db_fill_data_cnt_read_pc(ib_port_counters_t * wire_read,
779				 perfmgr_db_data_cnt_reading_t * reading)
780{
781	reading->xmit_data = cl_ntoh32(wire_read->xmit_data);
782	reading->rcv_data = cl_ntoh32(wire_read->rcv_data);
783	reading->xmit_pkts = cl_ntoh32(wire_read->xmit_pkts);
784	reading->rcv_pkts = cl_ntoh32(wire_read->rcv_pkts);
785	reading->unicast_xmit_pkts = 0;
786	reading->unicast_rcv_pkts = 0;
787	reading->multicast_xmit_pkts = 0;
788	reading->multicast_rcv_pkts = 0;
789	reading->time = time(NULL);
790}
791
792void
793perfmgr_db_fill_data_cnt_read_epc(ib_port_counters_ext_t * wire_read,
794				  perfmgr_db_data_cnt_reading_t * reading)
795{
796	reading->xmit_data = cl_ntoh64(wire_read->xmit_data);
797	reading->rcv_data = cl_ntoh64(wire_read->rcv_data);
798	reading->xmit_pkts = cl_ntoh64(wire_read->xmit_pkts);
799	reading->rcv_pkts = cl_ntoh64(wire_read->rcv_pkts);
800	reading->unicast_xmit_pkts = cl_ntoh64(wire_read->unicast_xmit_pkts);
801	reading->unicast_rcv_pkts = cl_ntoh64(wire_read->unicast_rcv_pkts);
802	reading->multicast_xmit_pkts =
803	    cl_ntoh64(wire_read->multicast_xmit_pkts);
804	reading->multicast_rcv_pkts = cl_ntoh64(wire_read->multicast_rcv_pkts);
805	reading->time = time(NULL);
806}
807#endif				/* ENABLE_OSM_PERF_MGR */
808