1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#define _GNU_SOURCE 35219820Sjeff 36219820Sjeff#if HAVE_CONFIG_H 37219820Sjeff# include <config.h> 38219820Sjeff#endif /* HAVE_CONFIG_H */ 39219820Sjeff 40219820Sjeff#include <inttypes.h> 41219820Sjeff#include <string.h> 42219820Sjeff#include <errno.h> 43219820Sjeff#include <stdio.h> 44219820Sjeff#include <stdlib.h> 45219820Sjeff#include <unistd.h> 46219820Sjeff#include <stdarg.h> 47219820Sjeff#include <sys/types.h> 48219820Sjeff#include <sys/stat.h> 49219820Sjeff#include <fcntl.h> 50219820Sjeff#include <sys/ioctl.h> 51219820Sjeff#include <unistd.h> 52219820Sjeff#include <getopt.h> 53219820Sjeff#include <endian.h> 54219820Sjeff#include <byteswap.h> 55219820Sjeff#include <sys/poll.h> 56219820Sjeff#include <syslog.h> 57219820Sjeff#include <netinet/in.h> 58219820Sjeff 59219820Sjeff#include <infiniband/common.h> 60219820Sjeff#include <infiniband/mad.h> 61219820Sjeff#include <infiniband/umad.h> 62219820Sjeff 63219820Sjeff#include <ibdiag_common.h> 64219820Sjeff 65219820Sjeffstatic const uint8_t CLASS_SUBN_DIRECTED_ROUTE = 0x81; 66219820Sjeffstatic const uint8_t CLASS_SUBN_LID_ROUTE = 0x1; 67219820Sjeff 68219820Sjeff#define ATTR_NODE_DESC ((uint16_t)(htons(0x10))) 69219820Sjeff#define ATTR_NODE_INFO ((uint16_t)(htons(0x11))) 70219820Sjeff#define ATTR_PORT_INFO ((uint16_t)(htons(0x15))) 71219820Sjeff 72219820Sjeffstatic int mad_agent; 73219820Sjeffstatic int drmad_tid = 0x123; 74219820Sjeff 75219820Sjeffstatic int debug, verbose; 76219820Sjeff 77219820Sjeffchar *argv0 = "smpdump"; 78219820Sjeff 79219820Sjefftypedef struct { 80219820Sjeff char path[64]; 81219820Sjeff int hop_cnt; 82219820Sjeff} DRPath; 83219820Sjeff 84219820Sjeffstruct drsmp { 85219820Sjeff uint8_t base_version; 86219820Sjeff uint8_t mgmt_class; 87219820Sjeff uint8_t class_version; 88219820Sjeff uint8_t method; 89219820Sjeff uint16_t status; 90219820Sjeff uint8_t hop_ptr; 91219820Sjeff uint8_t hop_cnt; 92219820Sjeff uint64_t tid; 93219820Sjeff uint16_t attr_id; 94219820Sjeff uint16_t resv; 95219820Sjeff uint32_t attr_mod; 96219820Sjeff uint64_t mkey; 97219820Sjeff uint16_t dr_slid; 98219820Sjeff uint16_t dr_dlid; 99219820Sjeff uint8_t reserved[28]; 100219820Sjeff uint8_t data[64]; 101219820Sjeff uint8_t initial_path[64]; 102219820Sjeff uint8_t return_path[64]; 103219820Sjeff}; 104219820Sjeff 105219820Sjeffvoid 106219820Sjeffdrsmp_get_init(void *umad, DRPath *path, int attr, int mod) 107219820Sjeff{ 108219820Sjeff struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); 109219820Sjeff 110219820Sjeff memset(smp, 0, sizeof (*smp)); 111219820Sjeff 112219820Sjeff smp->base_version = 1; 113219820Sjeff smp->mgmt_class = CLASS_SUBN_DIRECTED_ROUTE; 114219820Sjeff smp->class_version = 1; 115219820Sjeff 116219820Sjeff smp->method = 1; 117219820Sjeff smp->attr_id = (uint16_t)htons((uint16_t)attr); 118219820Sjeff smp->attr_mod = htonl(mod); 119219820Sjeff smp->tid = htonll(drmad_tid++); 120219820Sjeff smp->dr_slid = 0xffff; 121219820Sjeff smp->dr_dlid = 0xffff; 122219820Sjeff 123219820Sjeff umad_set_addr(umad, 0xffff, 0, 0, 0); 124219820Sjeff 125219820Sjeff if (path) 126219820Sjeff memcpy(smp->initial_path, path->path, path->hop_cnt+1); 127219820Sjeff 128219820Sjeff smp->hop_cnt = path->hop_cnt; 129219820Sjeff} 130219820Sjeff 131219820Sjeffvoid 132219820Sjeffsmp_get_init(void *umad, int lid, int attr, int mod) 133219820Sjeff{ 134219820Sjeff struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); 135219820Sjeff 136219820Sjeff memset(smp, 0, sizeof (*smp)); 137219820Sjeff 138219820Sjeff smp->base_version = 1; 139219820Sjeff smp->mgmt_class = CLASS_SUBN_LID_ROUTE; 140219820Sjeff smp->class_version = 1; 141219820Sjeff 142219820Sjeff smp->method = 1; 143219820Sjeff smp->attr_id = (uint16_t)htons((uint16_t)attr); 144219820Sjeff smp->attr_mod = htonl(mod); 145219820Sjeff smp->tid = htonll(drmad_tid++); 146219820Sjeff 147219820Sjeff umad_set_addr(umad, lid, 0, 0xffff, 0); 148219820Sjeff} 149219820Sjeff 150219820Sjeffvoid 151219820Sjeffdrsmp_set_init(void *umad, DRPath *path, int attr, int mod, void *data) 152219820Sjeff{ 153219820Sjeff struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); 154219820Sjeff 155219820Sjeff memset(smp, 0, sizeof (*smp)); 156219820Sjeff 157219820Sjeff smp->method = 2; /* SET */ 158219820Sjeff smp->attr_id = (uint16_t)htons((uint16_t)attr); 159219820Sjeff smp->attr_mod = htonl(mod); 160219820Sjeff smp->tid = htonll(drmad_tid++); 161219820Sjeff smp->dr_slid = 0xffff; 162219820Sjeff smp->dr_dlid = 0xffff; 163219820Sjeff 164219820Sjeff umad_set_addr(umad, 0xffff, 0, 0, 0); 165219820Sjeff 166219820Sjeff if (path) 167219820Sjeff memcpy(smp->initial_path, path->path, path->hop_cnt+1); 168219820Sjeff 169219820Sjeff if (data) 170219820Sjeff memcpy(smp->data, data, sizeof smp->data); 171219820Sjeff 172219820Sjeff smp->hop_cnt = path->hop_cnt; 173219820Sjeff} 174219820Sjeff 175219820Sjeffchar * 176219820Sjeffdrmad_status_str(struct drsmp *drsmp) 177219820Sjeff{ 178219820Sjeff switch (drsmp->status) { 179219820Sjeff case 0: 180219820Sjeff return "success"; 181219820Sjeff case ETIMEDOUT: 182219820Sjeff return "timeout"; 183219820Sjeff } 184219820Sjeff return "unknown error"; 185219820Sjeff} 186219820Sjeff 187219820Sjeffint 188219820Sjeffstr2DRPath(char *str, DRPath *path) 189219820Sjeff{ 190219820Sjeff char *s; 191219820Sjeff 192219820Sjeff path->hop_cnt = -1; 193219820Sjeff 194219820Sjeff DEBUG("DR str: %s", str); 195219820Sjeff while (str && *str) { 196219820Sjeff if ((s = strchr(str, ','))) 197219820Sjeff *s = 0; 198219820Sjeff path->path[++path->hop_cnt] = atoi(str); 199219820Sjeff if (!s) 200219820Sjeff break; 201219820Sjeff str = s+1; 202219820Sjeff } 203219820Sjeff 204219820Sjeff#if 0 205219820Sjeff if (path->path[0] != 0 || 206219820Sjeff (path->hop_cnt > 0 && dev_port && path->path[1] != dev_port)) { 207219820Sjeff DEBUG("hop 0 != 0 or hop 1 != dev_port"); 208219820Sjeff return -1; 209219820Sjeff } 210219820Sjeff#endif 211219820Sjeff 212219820Sjeff return path->hop_cnt; 213219820Sjeff} 214219820Sjeff 215219820Sjeffvoid 216219820Sjeffusage(void) 217219820Sjeff{ 218219820Sjeff fprintf(stderr, "Usage: %s [-s(ring) -D(irect) -V(ersion) -C ca_name -P ca_port -t(imeout) timeout_ms] <dlid|dr_path> <attr> [mod]\n", argv0); 219219820Sjeff fprintf(stderr, "\tDR examples:\n"); 220219820Sjeff fprintf(stderr, "\t\t%s -D 0,1,2,3,5 16 # NODE DESC\n", argv0); 221219820Sjeff fprintf(stderr, "\t\t%s -D 0,1,2 0x15 2 # PORT INFO, port 2\n", argv0); 222219820Sjeff fprintf(stderr, "\n\tLID routed examples:\n"); 223219820Sjeff fprintf(stderr, "\t\t%s 3 0x15 2 # PORT INFO, lid 3 port 2\n", argv0); 224219820Sjeff fprintf(stderr, "\t\t%s 0xa0 0x11 # NODE INFO, lid 0xa0\n", argv0); 225219820Sjeff fprintf(stderr, "\n"); 226219820Sjeff exit(-1); 227219820Sjeff} 228219820Sjeff 229219820Sjeffint 230219820Sjeffmain(int argc, char *argv[]) 231219820Sjeff{ 232219820Sjeff int dump_char = 0, timeout_ms = 1000; 233219820Sjeff int dev_port = 0, mgmt_class = CLASS_SUBN_LID_ROUTE, dlid = 0; 234219820Sjeff char *dev_name = 0; 235219820Sjeff void *umad; 236219820Sjeff struct drsmp *smp; 237219820Sjeff int i, portid, mod = 0, attr; 238219820Sjeff DRPath path; 239219820Sjeff uint8_t *desc; 240219820Sjeff int length; 241219820Sjeff 242219820Sjeff static char const str_opts[] = "C:P:t:dsDVhu"; 243219820Sjeff static const struct option long_opts[] = { 244219820Sjeff { "C", 1, 0, 'C'}, 245219820Sjeff { "P", 1, 0, 'P'}, 246219820Sjeff { "debug", 0, 0, 'd'}, 247219820Sjeff { "sring", 0, 0, 's'}, 248219820Sjeff { "Direct", 0, 0, 'D'}, 249219820Sjeff { "timeout", 1, 0, 't'}, 250219820Sjeff { "Version", 0, 0, 'V'}, 251219820Sjeff { "help", 0, 0, 'h'}, 252219820Sjeff { "usage", 0, 0, 'u'}, 253219820Sjeff { } 254219820Sjeff }; 255219820Sjeff 256219820Sjeff argv0 = argv[0]; 257219820Sjeff 258219820Sjeff while (1) { 259219820Sjeff int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 260219820Sjeff if ( ch == -1 ) 261219820Sjeff break; 262219820Sjeff switch(ch) { 263219820Sjeff case 's': 264219820Sjeff dump_char++; 265219820Sjeff break; 266219820Sjeff case 'd': 267219820Sjeff debug++; 268219820Sjeff if (debug > 1) 269219820Sjeff umad_debug(debug-1); 270219820Sjeff break; 271219820Sjeff case 'D': 272219820Sjeff mgmt_class = CLASS_SUBN_DIRECTED_ROUTE; 273219820Sjeff break; 274219820Sjeff case 'C': 275219820Sjeff dev_name = optarg; 276219820Sjeff break; 277219820Sjeff case 'P': 278219820Sjeff dev_port = atoi(optarg); 279219820Sjeff break; 280219820Sjeff case 't': 281219820Sjeff timeout_ms = strtoul(optarg, 0, 0); 282219820Sjeff break; 283219820Sjeff case 'V': 284219820Sjeff fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 285219820Sjeff exit(-1); 286219820Sjeff default: 287219820Sjeff usage(); 288219820Sjeff break; 289219820Sjeff } 290219820Sjeff } 291219820Sjeff argc -= optind; 292219820Sjeff argv += optind; 293219820Sjeff 294219820Sjeff if (argc < 2) 295219820Sjeff usage(); 296219820Sjeff 297219820Sjeff if (mgmt_class == CLASS_SUBN_DIRECTED_ROUTE && 298219820Sjeff str2DRPath(strdup(argv[0]), &path) < 0) 299219820Sjeff IBPANIC("bad path str '%s'", argv[0]); 300219820Sjeff 301219820Sjeff if (mgmt_class == CLASS_SUBN_LID_ROUTE) 302219820Sjeff dlid = strtoul(argv[0], 0, 0); 303219820Sjeff 304219820Sjeff attr = strtoul(argv[1], 0, 0); 305219820Sjeff if (argc > 2) 306219820Sjeff mod = strtoul(argv[2], 0, 0); 307219820Sjeff 308219820Sjeff if (umad_init() < 0) 309219820Sjeff IBPANIC("can't init UMAD library"); 310219820Sjeff 311219820Sjeff if ((portid = umad_open_port(dev_name, dev_port)) < 0) 312219820Sjeff IBPANIC("can't open UMAD port (%s:%d)", dev_name, dev_port); 313219820Sjeff 314219820Sjeff if ((mad_agent = umad_register(portid, mgmt_class, 1, 0, 0)) < 0) 315219820Sjeff IBPANIC("Couldn't register agent for SMPs"); 316219820Sjeff 317219820Sjeff if (!(umad = umad_alloc(1, umad_size() + IB_MAD_SIZE))) 318219820Sjeff IBPANIC("can't alloc MAD"); 319219820Sjeff 320219820Sjeff smp = umad_get_mad(umad); 321219820Sjeff 322219820Sjeff if (mgmt_class == CLASS_SUBN_DIRECTED_ROUTE) 323219820Sjeff drsmp_get_init(umad, &path, attr, mod); 324219820Sjeff else 325219820Sjeff smp_get_init(umad, dlid, attr, mod); 326219820Sjeff 327219820Sjeff if (debug > 1) 328219820Sjeff xdump(stderr, "before send:\n", smp, 256); 329219820Sjeff 330219820Sjeff length = IB_MAD_SIZE; 331219820Sjeff if (umad_send(portid, mad_agent, umad, length, timeout_ms, 0) < 0) 332219820Sjeff IBPANIC("send failed"); 333219820Sjeff 334219820Sjeff if (umad_recv(portid, umad, &length, -1) != mad_agent) 335219820Sjeff IBPANIC("recv error: %s", drmad_status_str(smp)); 336219820Sjeff 337219820Sjeff if (!dump_char) { 338219820Sjeff xdump(stdout, 0, smp->data, 64); 339219820Sjeff if (smp->status) 340219820Sjeff fprintf(stdout, "SMP status: 0x%x\n", ntohs(smp->status)); 341219820Sjeff return 0; 342219820Sjeff } 343219820Sjeff 344219820Sjeff desc = smp->data; 345219820Sjeff for (i = 0; i < 64; ++i) { 346219820Sjeff if (!desc[i]) 347219820Sjeff break; 348219820Sjeff putchar(desc[i]); 349219820Sjeff } 350219820Sjeff putchar('\n'); 351219820Sjeff if (smp->status) 352219820Sjeff fprintf(stdout, "SMP status: 0x%x\n", ntohs(smp->status)); 353219820Sjeff return 0; 354219820Sjeff} 355