1/*
2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5/*
6 * This file contains code imported from the OFED rds source file stats.c
7 * Oracle elects to have and use the contents of stats.c under and governed
8 * by the OpenIB.org BSD license (see below for full license text). However,
9 * the following notice accompanied the original version of this file:
10 */
11
12/*
13 * Copyright (c) 2006 Oracle.  All rights reserved.
14 *
15 * This software is available to you under a choice of one of two
16 * licenses.  You may choose to be licensed under the terms of the GNU
17 * General Public License (GPL) Version 2, available from the file
18 * COPYING in the main directory of this source tree, or the
19 * OpenIB.org BSD license below:
20 *
21 *     Redistribution and use in source and binary forms, with or
22 *     without modification, are permitted provided that the following
23 *     conditions are met:
24 *
25 *      - Redistributions of source code must retain the above
26 *        copyright notice, this list of conditions and the following
27 *        disclaimer.
28 *
29 *      - Redistributions in binary form must reproduce the above
30 *        copyright notice, this list of conditions and the following
31 *        disclaimer in the documentation and/or other materials
32 *        provided with the distribution.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
37 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
38 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
39 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41 * SOFTWARE.
42 *
43 */
44#include <sys/rds.h>
45
46#include <sys/ib/clients/rdsv3/rdsv3.h>
47
48struct rdsv3_statistics *rdsv3_stats = NULL;
49uint_t	nr_cpus;
50
51static char *rdsv3_stat_names[] = {
52	"conn_reset",
53	"recv_drop_bad_checksum",
54	"recv_drop_old_seq",
55	"recv_drop_no_sock",
56	"recv_drop_dead_sock",
57	"recv_deliver_raced",
58	"recv_delivered",
59	"recv_queued",
60	"recv_immediate_retry",
61	"recv_delayed_retry",
62	"recv_ack_required",
63	"recv_rdma_bytes",
64	"recv_ping",
65	"send_queue_empty",
66	"send_queue_full",
67	"send_sem_contention",
68	"send_sem_queue_raced",
69	"send_immediate_retry",
70	"send_delayed_retry",
71	"send_drop_acked",
72	"send_ack_required",
73	"send_queued",
74	"send_rdma",
75	"send_rdma_bytes",
76	"send_pong",
77	"page_remainder_hit",
78	"page_remainder_miss",
79	"copy_to_user",
80	"copy_from_user",
81	"cong_update_queued",
82	"cong_update_received",
83	"cong_send_error",
84	"cong_send_blocked",
85};
86
87void
88rdsv3_stats_info_copy(struct rdsv3_info_iterator *iter,
89    uint64_t *values, char **names, size_t nr)
90{
91	struct rds_info_counter ctr;
92	size_t i;
93
94	for (i = 0; i < nr; i++) {
95		ASSERT(!(strlen(names[i]) >= sizeof (ctr.name)));
96		(void) strncpy((char *)ctr.name, names[i],
97		    sizeof (ctr.name) - 1);
98		ctr.value = values[i];
99
100		rdsv3_info_copy(iter, &ctr, sizeof (ctr));
101	}
102}
103
104/*
105 * This gives global counters across all the transports.  The strings
106 * are copied in so that the tool doesn't need knowledge of the specific
107 * stats that we're exporting.  Some are pretty implementation dependent
108 * and may change over time.  That doesn't stop them from being useful.
109 *
110 * This is the only function in the chain that knows about the byte granular
111 * length in userspace.  It converts it to number of stat entries that the
112 * rest of the functions operate in.
113 */
114/* ARGSUSED */
115static void
116rdsv3_stats_info(struct rsock *sock, unsigned int len,
117    struct rdsv3_info_iterator *iter,
118    struct rdsv3_info_lengths *lens)
119{
120	struct rdsv3_statistics stats;
121	uint64_t *src;
122	uint64_t *sum;
123	size_t i;
124	int cpu;
125	unsigned int avail;
126
127	avail = len / sizeof (struct rds_info_counter);
128
129	if (avail < ARRAY_SIZE(rdsv3_stat_names)) {
130		avail = 0;
131		goto trans;
132	}
133
134	bzero(&stats, sizeof (struct rdsv3_statistics));
135
136	for (cpu = 0; cpu < nr_cpus; cpu++) {
137		src = (uint64_t *)&(rdsv3_per_cpu(rdsv3_stats, cpu));
138		sum = (uint64_t *)&stats;
139		for (i = 0;
140		    i < sizeof (struct rdsv3_statistics) / sizeof (uint64_t);
141		    i++)
142			*(sum++) += *(src++);
143	}
144
145	rdsv3_stats_info_copy(iter, (uint64_t *)&stats, rdsv3_stat_names,
146	    ARRAY_SIZE(rdsv3_stat_names));
147	avail -= ARRAY_SIZE(rdsv3_stat_names);
148
149trans:
150	lens->each = sizeof (struct rds_info_counter);
151	lens->nr = rdsv3_trans_stats_info_copy(iter, avail) +
152	    ARRAY_SIZE(rdsv3_stat_names);
153}
154
155void
156rdsv3_stats_exit(void)
157{
158	rdsv3_info_deregister_func(RDS_INFO_COUNTERS, rdsv3_stats_info);
159
160	ASSERT(rdsv3_stats);
161	kmem_free(rdsv3_stats,
162	    nr_cpus * sizeof (struct rdsv3_statistics));
163	rdsv3_stats = NULL;
164}
165
166int
167rdsv3_stats_init(void)
168{
169	/*
170	 * Note the max number of cpus that this system can have at most.
171	 */
172	nr_cpus = max_ncpus;
173	ASSERT(rdsv3_stats == NULL);
174	rdsv3_stats = kmem_zalloc(nr_cpus *
175	    sizeof (struct rdsv3_statistics), KM_SLEEP);
176
177	rdsv3_info_register_func(RDS_INFO_COUNTERS, rdsv3_stats_info);
178	return (0);
179}
180