1 /* 2 * dev.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 (at) mellanox.com> 10 */ 11 12 #include "rdma.h" 13 14 static int dev_help(struct rd *rd) 15 { 16 pr_out("Usage: %s dev show [DEV]\n", rd->filename); 17 return 0; 18 } 19 20 static const char *dev_caps_to_str(uint32_t idx) 21 { 22 #define RDMA_DEV_FLAGS(x) \ 23 x(RESIZE_MAX_WR, 0) \ 24 x(BAD_PKEY_CNTR, 1) \ 25 x(BAD_QKEY_CNTR, 2) \ 26 x(RAW_MULTI, 3) \ 27 x(AUTO_PATH_MIG, 4) \ 28 x(CHANGE_PHY_PORT, 5) \ 29 x(UD_AV_PORT_ENFORCE_PORT_ENFORCE, 6) \ 30 x(CURR_QP_STATE_MOD, 7) \ 31 x(SHUTDOWN_PORT, 8) \ 32 x(INIT_TYPE, 9) \ 33 x(PORT_ACTIVE_EVENT, 10) \ 34 x(SYS_IMAGE_GUID, 11) \ 35 x(RC_RNR_NAK_GEN, 12) \ 36 x(SRQ_RESIZE, 13) \ 37 x(N_NOTIFY_CQ, 14) \ 38 x(LOCAL_DMA_LKEY, 15) \ 39 x(MEM_WINDOW, 17) \ 40 x(UD_IP_CSUM, 18) \ 41 x(UD_TSO, 19) \ 42 x(XRC, 20) \ 43 x(MEM_MGT_EXTENSIONS, 21) \ 44 x(BLOCK_MULTICAST_LOOPBACK, 22) \ 45 x(MEM_WINDOW_TYPE_2A, 23) \ 46 x(MEM_WINDOW_TYPE_2B, 24) \ 47 x(RC_IP_CSUM, 25) \ 48 x(RAW_IP_CSUM, 26) \ 49 x(CROSS_CHANNEL, 27) \ 50 x(MANAGED_FLOW_STEERING, 29) \ 51 x(SIGNATURE_HANDOVER, 30) \ 52 x(ON_DEMAND_PAGING, 31) \ 53 x(SG_GAPS_REG, 32) \ 54 x(VIRTUAL_FUNCTION, 33) \ 55 x(RAW_SCATTER_FCS, 34) \ 56 x(RDMA_NETDEV_OPA_VNIC, 35) 57 58 enum { RDMA_DEV_FLAGS(RDMA_BITMAP_ENUM) }; 59 60 static const char * const 61 rdma_dev_names[] = { RDMA_DEV_FLAGS(RDMA_BITMAP_NAMES) }; 62 #undef RDMA_DEV_FLAGS 63 64 if (idx < ARRAY_SIZE(rdma_dev_names) && rdma_dev_names[idx]) 65 return rdma_dev_names[idx]; 66 return "UNKNOWN"; 67 } 68 69 static void dev_print_caps(struct rd *rd, struct nlattr **tb) 70 { 71 uint64_t caps; 72 uint32_t idx; 73 74 if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS]) 75 return; 76 77 caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]); 78 79 if (rd->json_output) { 80 jsonw_name(rd->jw, "caps"); 81 jsonw_start_array(rd->jw); 82 } else { 83 pr_out("\n caps: <"); 84 } 85 for (idx = 0; caps; idx++) { 86 if (caps & 0x1) { 87 if (rd->json_output) { 88 jsonw_string(rd->jw, dev_caps_to_str(idx)); 89 } else { 90 pr_out("%s", dev_caps_to_str(idx)); 91 if (caps >> 0x1) 92 pr_out(", "); 93 } 94 } 95 caps >>= 0x1; 96 } 97 98 if (rd->json_output) 99 jsonw_end_array(rd->jw); 100 else 101 pr_out(">"); 102 } 103 104 static void dev_print_fw(struct rd *rd, struct nlattr **tb) 105 { 106 const char *str; 107 if (!tb[RDMA_NLDEV_ATTR_FW_VERSION]) 108 return; 109 110 str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_FW_VERSION]); 111 if (rd->json_output) 112 jsonw_string_field(rd->jw, "fw", str); 113 else 114 pr_out("fw %s ", str); 115 } 116 117 static void dev_print_node_guid(struct rd *rd, struct nlattr **tb) 118 { 119 uint64_t node_guid; 120 uint16_t vp[4]; 121 char str[32]; 122 123 if (!tb[RDMA_NLDEV_ATTR_NODE_GUID]) 124 return; 125 126 node_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_NODE_GUID]); 127 memcpy(vp, &node_guid, sizeof(uint64_t)); 128 snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]); 129 if (rd->json_output) 130 jsonw_string_field(rd->jw, "node_guid", str); 131 else 132 pr_out("node_guid %s ", str); 133 } 134 135 static void dev_print_sys_image_guid(struct rd *rd, struct nlattr **tb) 136 { 137 uint64_t sys_image_guid; 138 uint16_t vp[4]; 139 char str[32]; 140 141 if (!tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]) 142 return; 143 144 sys_image_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]); 145 memcpy(vp, &sys_image_guid, sizeof(uint64_t)); 146 snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]); 147 if (rd->json_output) 148 jsonw_string_field(rd->jw, "sys_image_guid", str); 149 else 150 pr_out("sys_image_guid %s ", str); 151 } 152 153 static const char *node_type_to_str(uint8_t node_type) 154 { 155 static const char * const node_type_str[] = { "unknown", "ca", 156 "switch", "router", 157 "rnic", "usnic", 158 "usnic_dp" }; 159 if (node_type < ARRAY_SIZE(node_type_str)) 160 return node_type_str[node_type]; 161 return "unknown"; 162 } 163 164 static void dev_print_node_type(struct rd *rd, struct nlattr **tb) 165 { 166 const char *node_str; 167 uint8_t node_type; 168 169 if (!tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]) 170 return; 171 172 node_type = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]); 173 node_str = node_type_to_str(node_type); 174 if (rd->json_output) 175 jsonw_string_field(rd->jw, "node_type", node_str); 176 else 177 pr_out("node_type %s ", node_str); 178 } 179 180 static int dev_parse_cb(const struct nlmsghdr *nlh, void *data) 181 { 182 struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; 183 struct rd *rd = data; 184 const char *name; 185 uint32_t idx; 186 187 mnl_attr_parse(nlh, 0, rd_attr_cb, tb); 188 if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME]) 189 return MNL_CB_ERROR; 190 191 idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 192 name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); 193 if (rd->json_output) { 194 jsonw_uint_field(rd->jw, "ifindex", idx); 195 jsonw_string_field(rd->jw, "ifname", name); 196 } else { 197 pr_out("%u: %s: ", idx, name); 198 } 199 200 dev_print_node_type(rd, tb); 201 dev_print_fw(rd, tb); 202 dev_print_node_guid(rd, tb); 203 dev_print_sys_image_guid(rd, tb); 204 if (rd->show_details) 205 dev_print_caps(rd, tb); 206 207 if (!rd->json_output) 208 pr_out("\n"); 209 return MNL_CB_OK; 210 } 211 212 static int dev_no_args(struct rd *rd) 213 { 214 uint32_t seq; 215 int ret; 216 217 rd_prepare_msg(rd, RDMA_NLDEV_CMD_GET, 218 &seq, (NLM_F_REQUEST | NLM_F_ACK)); 219 mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); 220 ret = rd_send_msg(rd); 221 if (ret) 222 return ret; 223 224 if (rd->json_output) 225 jsonw_start_object(rd->jw); 226 ret = rd_recv_msg(rd, dev_parse_cb, rd, seq); 227 if (rd->json_output) 228 jsonw_end_object(rd->jw); 229 return ret; 230 } 231 232 static int dev_one_show(struct rd *rd) 233 { 234 const struct rd_cmd cmds[] = { 235 { NULL, dev_no_args}, 236 { 0 } 237 }; 238 239 return rd_exec_cmd(rd, cmds, "parameter"); 240 } 241 242 static int dev_show(struct rd *rd) 243 { 244 struct dev_map *dev_map; 245 int ret = 0; 246 247 if (rd->json_output) 248 jsonw_start_array(rd->jw); 249 if (rd_no_arg(rd)) { 250 list_for_each_entry(dev_map, &rd->dev_map_list, list) { 251 rd->dev_idx = dev_map->idx; 252 ret = dev_one_show(rd); 253 if (ret) 254 goto out; 255 } 256 } else { 257 dev_map = dev_map_lookup(rd, false); 258 if (!dev_map) { 259 pr_err("Wrong device name\n"); 260 ret = -ENOENT; 261 goto out; 262 } 263 rd_arg_inc(rd); 264 rd->dev_idx = dev_map->idx; 265 ret = dev_one_show(rd); 266 } 267 out: 268 if (rd->json_output) 269 jsonw_end_array(rd->jw); 270 return ret; 271 } 272 273 int cmd_dev(struct rd *rd) 274 { 275 const struct rd_cmd cmds[] = { 276 { NULL, dev_show }, 277 { "show", dev_show }, 278 { "list", dev_show }, 279 { "help", dev_help }, 280 { 0 } 281 }; 282 283 return rd_exec_cmd(rd, cmds, "dev command"); 284 } 285