]>
Commit | Line | Data |
---|---|---|
da990ab4 LR |
1 | /* |
2 | * link.c RDMA tool | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Authors: Leon Romanovsky <leonro@mellanox.com> | |
10 | */ | |
11 | ||
12 | #include "rdma.h" | |
13 | ||
14 | static int link_help(struct rd *rd) | |
15 | { | |
16 | pr_out("Usage: %s link show [DEV/PORT_INDEX]\n", rd->filename); | |
17 | return 0; | |
18 | } | |
19 | ||
20 | static const char *caps_to_str(uint32_t idx) | |
21 | { | |
22 | #define RDMA_PORT_FLAGS(x) \ | |
23 | x(SM, 1) \ | |
24 | x(NOTICE, 2) \ | |
25 | x(TRAP, 3) \ | |
26 | x(OPT_IPD, 4) \ | |
27 | x(AUTO_MIGR, 5) \ | |
28 | x(SL_MAP, 6) \ | |
29 | x(MKEY_NVRAM, 7) \ | |
30 | x(PKEY_NVRAM, 8) \ | |
31 | x(LED_INFO, 9) \ | |
32 | x(SM_DISABLED, 10) \ | |
33 | x(SYS_IMAGE_GUIG, 11) \ | |
34 | x(PKEY_SW_EXT_PORT_TRAP, 12) \ | |
35 | x(EXTENDED_SPEEDS, 14) \ | |
36 | x(CM, 16) \ | |
37 | x(SNMP_TUNNEL, 17) \ | |
38 | x(REINIT, 18) \ | |
39 | x(DEVICE_MGMT, 19) \ | |
40 | x(VENDOR_CLASS, 20) \ | |
41 | x(DR_NOTICE, 21) \ | |
42 | x(CAP_MASK_NOTICE, 22) \ | |
43 | x(BOOT_MGMT, 23) \ | |
44 | x(LINK_LATENCY, 24) \ | |
45 | x(CLIENT_REG, 23) \ | |
46 | x(IP_BASED_GIDS, 26) | |
47 | ||
48 | enum { RDMA_PORT_FLAGS(RDMA_BITMAP_ENUM) }; | |
49 | ||
50 | static const char * const | |
51 | rdma_port_names[] = { RDMA_PORT_FLAGS(RDMA_BITMAP_NAMES) }; | |
52 | #undef RDMA_PORT_FLAGS | |
53 | ||
54 | if (idx < ARRAY_SIZE(rdma_port_names) && rdma_port_names[idx]) | |
55 | return rdma_port_names[idx]; | |
56 | return "UNKNOWN"; | |
57 | } | |
58 | ||
59 | static void link_print_caps(struct nlattr **tb) | |
60 | { | |
61 | uint64_t caps; | |
62 | uint32_t idx; | |
63 | ||
64 | if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS]) | |
65 | return; | |
66 | ||
67 | caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]); | |
68 | ||
69 | pr_out("\n caps: <"); | |
70 | for (idx = 0; caps; idx++) { | |
71 | if (caps & 0x1) { | |
72 | pr_out("%s", caps_to_str(idx)); | |
73 | if (caps >> 0x1) | |
74 | pr_out(", "); | |
75 | } | |
76 | caps >>= 0x1; | |
77 | } | |
78 | ||
79 | pr_out(">"); | |
80 | } | |
81 | ||
82 | static void link_print_subnet_prefix(struct nlattr **tb) | |
83 | { | |
84 | uint64_t subnet_prefix; | |
85 | ||
86 | if (!tb[RDMA_NLDEV_ATTR_SUBNET_PREFIX]) | |
87 | return; | |
88 | ||
89 | subnet_prefix = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SUBNET_PREFIX]); | |
90 | rd_print_u64("subnet_prefix", subnet_prefix); | |
91 | } | |
92 | ||
93 | static void link_print_lid(struct nlattr **tb) | |
94 | { | |
95 | if (!tb[RDMA_NLDEV_ATTR_LID]) | |
96 | return; | |
97 | ||
98 | pr_out("lid %u ", | |
99 | mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_LID])); | |
100 | } | |
101 | ||
102 | static void link_print_sm_lid(struct nlattr **tb) | |
103 | { | |
104 | if (!tb[RDMA_NLDEV_ATTR_SM_LID]) | |
105 | return; | |
106 | ||
107 | pr_out("sm_lid %u ", | |
108 | mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_SM_LID])); | |
109 | } | |
110 | ||
111 | static void link_print_lmc(struct nlattr **tb) | |
112 | { | |
113 | if (!tb[RDMA_NLDEV_ATTR_LMC]) | |
114 | return; | |
115 | ||
116 | pr_out("lmc %u ", mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_LMC])); | |
117 | } | |
118 | ||
119 | static const char *link_state_to_str(uint8_t link_state) | |
120 | { | |
121 | static const char * const link_state_str[] = { "NOP", "DOWN", | |
122 | "INIT", "ARMED", | |
123 | "ACTIVE", | |
124 | "ACTIVE_DEFER" }; | |
125 | if (link_state < ARRAY_SIZE(link_state_str)) | |
126 | return link_state_str[link_state]; | |
127 | return "UNKNOWN"; | |
128 | } | |
129 | ||
130 | static void link_print_state(struct nlattr **tb) | |
131 | { | |
132 | uint8_t state; | |
133 | ||
134 | if (!tb[RDMA_NLDEV_ATTR_PORT_STATE]) | |
135 | return; | |
136 | ||
137 | state = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_PORT_STATE]); | |
138 | pr_out("state %s ", link_state_to_str(state)); | |
139 | } | |
140 | ||
141 | static const char *phys_state_to_str(uint8_t phys_state) | |
142 | { | |
143 | static const char * const phys_state_str[] = { "NOP", "SLEEP", | |
144 | "POLLING", "DISABLED", | |
145 | "ARMED", "LINK_UP", | |
146 | "LINK_ERROR_RECOVER", | |
147 | "PHY_TEST", "UNKNOWN", | |
148 | "OPA_OFFLINE", | |
149 | "UNKNOWN", "OPA_TEST" }; | |
150 | if (phys_state < ARRAY_SIZE(phys_state_str)) | |
151 | return phys_state_str[phys_state]; | |
152 | return "UNKNOWN"; | |
153 | }; | |
154 | ||
155 | static void link_print_phys_state(struct nlattr **tb) | |
156 | { | |
157 | uint8_t phys_state; | |
158 | ||
159 | if (!tb[RDMA_NLDEV_ATTR_PORT_PHYS_STATE]) | |
160 | return; | |
161 | ||
162 | phys_state = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_PORT_PHYS_STATE]); | |
163 | pr_out("physical_state %s ", phys_state_to_str(phys_state)); | |
164 | } | |
165 | ||
166 | static int link_parse_cb(const struct nlmsghdr *nlh, void *data) | |
167 | { | |
168 | struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; | |
169 | struct rd *rd = data; | |
170 | ||
171 | mnl_attr_parse(nlh, 0, rd_attr_cb, tb); | |
172 | if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME]) | |
173 | return MNL_CB_ERROR; | |
174 | ||
175 | if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) { | |
176 | pr_err("This tool doesn't support switches yet\n"); | |
177 | return MNL_CB_ERROR; | |
178 | } | |
179 | ||
180 | pr_out("%u/%u: %s/%u: ", | |
181 | mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]), | |
182 | mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]), | |
183 | mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]), | |
184 | mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX])); | |
185 | link_print_subnet_prefix(tb); | |
186 | link_print_lid(tb); | |
187 | link_print_sm_lid(tb); | |
188 | link_print_lmc(tb); | |
189 | link_print_state(tb); | |
190 | link_print_phys_state(tb); | |
191 | if (rd->show_details) | |
192 | link_print_caps(tb); | |
193 | ||
194 | pr_out("\n"); | |
195 | return MNL_CB_OK; | |
196 | } | |
197 | ||
198 | static int link_no_args(struct rd *rd) | |
199 | { | |
200 | uint32_t seq; | |
201 | int ret; | |
202 | ||
203 | rd_prepare_msg(rd, RDMA_NLDEV_CMD_PORT_GET, &seq, | |
204 | (NLM_F_REQUEST | NLM_F_ACK)); | |
205 | mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); | |
206 | mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx); | |
207 | ret = rd_send_msg(rd); | |
208 | if (ret) | |
209 | return ret; | |
210 | ||
211 | return rd_recv_msg(rd, link_parse_cb, rd, seq); | |
212 | } | |
213 | ||
214 | static int link_one_show(struct rd *rd) | |
215 | { | |
216 | const struct rd_cmd cmds[] = { | |
217 | { NULL, link_no_args}, | |
218 | { 0 } | |
219 | }; | |
220 | ||
221 | return rd_exec_cmd(rd, cmds, "parameter"); | |
222 | } | |
223 | ||
224 | static int link_show(struct rd *rd) | |
225 | { | |
226 | struct dev_map *dev_map; | |
227 | uint32_t port; | |
228 | int ret; | |
229 | ||
230 | if (rd_no_arg(rd)) { | |
231 | list_for_each_entry(dev_map, &rd->dev_map_list, list) { | |
232 | rd->dev_idx = dev_map->idx; | |
233 | for (port = 1; port < dev_map->num_ports + 1; port++) { | |
234 | rd->port_idx = port; | |
235 | ret = link_one_show(rd); | |
236 | if (ret) | |
237 | return ret; | |
238 | } | |
239 | } | |
240 | ||
241 | } else { | |
242 | dev_map = dev_map_lookup(rd, true); | |
243 | port = get_port_from_argv(rd); | |
244 | if (!dev_map || port > dev_map->num_ports) { | |
245 | pr_err("Wrong device name\n"); | |
246 | return -ENOENT; | |
247 | } | |
248 | rd_arg_inc(rd); | |
249 | rd->dev_idx = dev_map->idx; | |
250 | rd->port_idx = port ? : 1; | |
251 | for (; rd->port_idx < dev_map->num_ports + 1; rd->port_idx++) { | |
252 | ret = link_one_show(rd); | |
253 | if (ret) | |
254 | return ret; | |
255 | if (port) | |
256 | /* | |
257 | * We got request to show link for devname | |
258 | * with port index. | |
259 | */ | |
260 | break; | |
261 | } | |
262 | } | |
263 | return 0; | |
264 | } | |
265 | ||
266 | int cmd_link(struct rd *rd) | |
267 | { | |
268 | const struct rd_cmd cmds[] = { | |
269 | { NULL, link_show }, | |
270 | { "show", link_show }, | |
271 | { "list", link_show }, | |
272 | { "help", link_help }, | |
273 | { 0 } | |
274 | }; | |
275 | ||
276 | return rd_exec_cmd(rd, cmds, "link command"); | |
277 | } |