1/*
2 * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
3 * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
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#include <stdio.h>
40#include <stdlib.h>
41#include <unistd.h>
42#include <string.h>
43#include <inttypes.h>
44#include <netinet/in.h>
45
46#include <mad.h>
47#include <infiniband/common.h>
48
49void
50mad_dump_int(char *buf, int bufsz, void *val, int valsz)
51{
52	switch (valsz) {
53	case 1:
54		snprintf(buf, bufsz, "%d", *(uint8_t *)val);
55		break;
56	case 2:
57		snprintf(buf, bufsz, "%d", *(uint16_t *)val);
58		break;
59	case 3:
60	case 4:
61		snprintf(buf, bufsz, "%d", *(uint32_t *)val);
62		break;
63	case 5:
64	case 6:
65	case 7:
66	case 8:
67		snprintf(buf, bufsz, "%" PRIu64, *(uint64_t *)val);
68		break;
69	default:
70		IBWARN("bad int sz %d", valsz);
71		buf[0] = 0;
72	}
73}
74
75void
76mad_dump_uint(char *buf, int bufsz, void *val, int valsz)
77{
78	switch (valsz) {
79	case 1:
80		snprintf(buf, bufsz, "%u", *(uint8_t *)val);
81		break;
82	case 2:
83		snprintf(buf, bufsz, "%u", *(uint16_t *)val);
84		break;
85	case 3:
86	case 4:
87		snprintf(buf, bufsz, "%u", *(uint32_t *)val);
88		break;
89	case 5:
90	case 6:
91	case 7:
92	case 8:
93		snprintf(buf, bufsz, "%" PRIu64, *(uint64_t *)val);
94		break;
95	default:
96		IBWARN("bad int sz %u", valsz);
97		buf[0] = 0;
98	}
99}
100
101void
102mad_dump_hex(char *buf, int bufsz, void *val, int valsz)
103{
104	switch (valsz) {
105	case 1:
106		snprintf(buf, bufsz, "0x%02x", *(uint8_t *)val);
107		break;
108	case 2:
109		snprintf(buf, bufsz, "0x%04x", *(uint16_t *)val);
110		break;
111	case 3:
112		snprintf(buf, bufsz, "0x%06x", *(uint32_t *)val & 0xffffff);
113		break;
114	case 4:
115		snprintf(buf, bufsz, "0x%08x", *(uint32_t *)val);
116		break;
117	case 5:
118		snprintf(buf, bufsz, "0x%010" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffllu);
119		break;
120	case 6:
121		snprintf(buf, bufsz, "0x%012" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffllu);
122		break;
123	case 7:
124		snprintf(buf, bufsz, "0x%014" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffffllu);
125		break;
126	case 8:
127		snprintf(buf, bufsz, "0x%016" PRIx64, *(uint64_t *)val);
128		break;
129	default:
130		IBWARN("bad int sz %d", valsz);
131		buf[0] = 0;
132	}
133}
134
135void
136mad_dump_rhex(char *buf, int bufsz, void *val, int valsz)
137{
138	switch (valsz) {
139	case 1:
140		snprintf(buf, bufsz, "%02x", *(uint8_t *)val);
141		break;
142	case 2:
143		snprintf(buf, bufsz, "%04x", *(uint16_t *)val);
144		break;
145	case 3:
146		snprintf(buf, bufsz, "%06x", *(uint32_t *)val & 0xffffff);
147		break;
148	case 4:
149		snprintf(buf, bufsz, "%08x", *(uint32_t *)val);
150		break;
151	case 5:
152		snprintf(buf, bufsz, "%010" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffllu);
153		break;
154	case 6:
155		snprintf(buf, bufsz, "%012" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffllu);
156		break;
157	case 7:
158		snprintf(buf, bufsz, "%014" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffffllu);
159		break;
160	case 8:
161		snprintf(buf, bufsz, "%016" PRIx64, *(uint64_t *)val);
162		break;
163	default:
164		IBWARN("bad int sz %d", valsz);
165		buf[0] = 0;
166	}
167}
168
169void
170mad_dump_linkwidth(char *buf, int bufsz, void *val, int valsz)
171{
172	int width = *(int *)val;
173
174	switch (width) {
175	case 1:
176		snprintf(buf, bufsz, "1X");
177		break;
178	case 2:
179		snprintf(buf, bufsz, "4X");
180		break;
181	case 4:
182		snprintf(buf, bufsz, "8X");
183		break;
184	case 8:
185		snprintf(buf, bufsz, "12X");
186		break;
187	default:
188		IBWARN("bad width %d", width);
189		buf[0] = 0;
190	}
191}
192
193static void
194dump_linkwidth(char *buf, int bufsz, int width)
195{
196	int n = 0;
197
198	if (width & 0x1)
199		n += snprintf(buf + n, bufsz - n, "1X or ");
200	if (n < bufsz && (width & 0x2))
201		n += snprintf(buf + n, bufsz - n, "4X or ");
202	if (n < bufsz && (width & 0x4))
203		n += snprintf(buf + n, bufsz - n, "8X or ");
204	if (n < bufsz && (width & 0x8))
205		n += snprintf(buf + n, bufsz - n, "12X or ");
206
207	if (n >= bufsz)
208		return;
209	else if (width == 0 || (width >> 4))
210		snprintf(buf + n, bufsz - n, "undefined (%d)", width);
211	else if (bufsz > 3)
212		buf[n-4] = '\0';
213}
214
215void
216mad_dump_linkwidthsup(char *buf, int bufsz, void *val, int valsz)
217{
218	int width = *(int *)val;
219
220	dump_linkwidth(buf, bufsz, width);
221
222	switch(width) {
223	case 1:
224	case 3:
225	case 7:
226	case 11:
227	case 15:
228		break;
229
230	default:
231		if (!(width >> 4))
232			snprintf(buf + strlen(buf), bufsz - strlen(buf),
233				 " (IBA extension)");
234		break;
235	}
236}
237
238void
239mad_dump_linkwidthen(char *buf, int bufsz, void *val, int valsz)
240{
241	int width = *(int *)val;
242
243	dump_linkwidth(buf, bufsz, width);
244}
245
246void
247mad_dump_linkspeed(char *buf, int bufsz, void *val, int valsz)
248{
249	int speed = *(int *)val;
250
251	switch (speed) {
252	case 1:
253		snprintf(buf, bufsz, "2.5 Gbps");
254		break;
255	case 2:
256		snprintf(buf, bufsz, "5.0 Gbps");
257		break;
258	case 4:
259		snprintf(buf, bufsz, "10.0 Gbps");
260		break;
261	default:
262		snprintf(buf, bufsz, "undefined (%d)", speed);
263		break;
264	}
265}
266
267static void
268dump_linkspeed(char *buf, int bufsz, int speed)
269{
270	int n = 0;
271
272	if (speed & 0x1)
273		n += snprintf(buf + n, bufsz - n, "2.5 Gbps or ");
274	if (n < bufsz && (speed & 0x2))
275		n += snprintf(buf + n, bufsz - n, "5.0 Gbps or ");
276	if (n < bufsz && (speed & 0x4))
277		n += snprintf(buf + n, bufsz - n, "10.0 Gbps or ");
278
279	if (n >= bufsz)
280		return;
281	else if (speed == 0 || (speed >> 3)) {
282		n += snprintf(buf + n, bufsz - n, "undefined (%d)", speed);
283		if (n >= bufsz)
284			return;
285	} else if (bufsz > 3) {
286		buf[n-4] = '\0';
287		n -= 4;
288	}
289
290	switch (speed) {
291	case 1:
292	case 3:
293	case 5:
294	case 7:
295		break;
296	default:
297		if (!(speed >> 3))
298			snprintf(buf + n, bufsz - n, " (IBA extension)");
299		break;
300	}
301}
302
303void
304mad_dump_linkspeedsup(char *buf, int bufsz, void *val, int valsz)
305{
306	int speed = *(int *)val;
307
308	dump_linkspeed(buf, bufsz, speed);
309}
310
311void
312mad_dump_linkspeeden(char *buf, int bufsz, void *val, int valsz)
313{
314	int speed = *(int *)val;
315
316	dump_linkspeed(buf, bufsz, speed);
317}
318
319void
320mad_dump_portstate(char *buf, int bufsz, void *val, int valsz)
321{
322	int state = *(int *)val;
323
324	switch (state) {
325	case 0:
326		snprintf(buf, bufsz, "NoChange");
327		break;
328	case 1:
329		snprintf(buf, bufsz, "Down");
330		break;
331	case 2:
332		snprintf(buf, bufsz, "Initialize");
333		break;
334	case 3:
335		snprintf(buf, bufsz, "Armed");
336		break;
337	case 4:
338		snprintf(buf, bufsz, "Active");
339		break;
340	default:
341		snprintf(buf, bufsz, "?(%d)", state);
342	}
343}
344
345void
346mad_dump_linkdowndefstate(char *buf, int bufsz, void *val, int valsz)
347{
348	int state = *(int *)val;
349
350	switch(state) {
351	case 0:
352		snprintf(buf, bufsz, "NoChange");
353		break;
354	case 1:
355		snprintf(buf, bufsz, "Sleep");
356		break;
357	case 2:
358		snprintf(buf, bufsz, "Polling");
359		break;
360	default:
361		snprintf(buf, bufsz, "?(%d)", state);
362		break;
363	}
364}
365
366void
367mad_dump_physportstate(char *buf, int bufsz, void *val, int valsz)
368{
369	int state = *(int *)val;
370
371	switch (state) {
372	case 0:
373		snprintf(buf, bufsz, "NoChange");
374		break;
375	case 1:
376		snprintf(buf, bufsz, "Sleep");
377		break;
378	case 2:
379		snprintf(buf, bufsz, "Polling");
380		break;
381	case 3:
382		snprintf(buf, bufsz, "Disabled");
383		break;
384	case 4:
385		snprintf(buf, bufsz, "PortConfigurationTraining");
386		break;
387	case 5:
388		snprintf(buf, bufsz, "LinkUp");
389		break;
390	case 6:
391		snprintf(buf, bufsz, "LinkErrorRecovery");
392		break;
393	case 7:
394		snprintf(buf, bufsz, "PhyTest");
395		break;
396	default:
397		snprintf(buf, bufsz, "?(%d)", state);
398	}
399}
400
401void
402mad_dump_mtu(char *buf, int bufsz, void *val, int valsz)
403{
404	int mtu = *(int *)val;
405
406	switch (mtu) {
407	case 1:
408		snprintf(buf, bufsz, "256");
409		break;
410	case 2:
411		snprintf(buf, bufsz, "512");
412		break;
413	case 3:
414		snprintf(buf, bufsz, "1024");
415		break;
416	case 4:
417		snprintf(buf, bufsz, "2048");
418		break;
419	case 5:
420		snprintf(buf, bufsz, "4096");
421		break;
422	default:
423		snprintf(buf, bufsz, "?(%d)", mtu);
424		buf[0] = 0;
425	}
426}
427
428void
429mad_dump_vlcap(char *buf, int bufsz, void *val, int valsz)
430{
431	int vlcap = *(int *)val;
432
433	switch (vlcap) {
434	case 1:
435		snprintf(buf, bufsz, "VL0");
436		break;
437	case 2:
438		snprintf(buf, bufsz, "VL0-1");
439		break;
440	case 3:
441		snprintf(buf, bufsz, "VL0-3");
442		break;
443	case 4:
444		snprintf(buf, bufsz, "VL0-7");
445		break;
446	case 5:
447		snprintf(buf, bufsz, "VL0-14");
448		break;
449	default:
450		snprintf(buf, bufsz, "?(%d)", vlcap);
451	}
452}
453
454void
455mad_dump_opervls(char *buf, int bufsz, void *val, int valsz)
456{
457	int opervls = *(int *)val;
458
459	switch (opervls) {
460	case 0:
461		snprintf(buf, bufsz, "No change");
462		break;
463	case 1:
464		snprintf(buf, bufsz, "VL0");
465		break;
466	case 2:
467		snprintf(buf, bufsz, "VL0-1");
468		break;
469	case 3:
470		snprintf(buf, bufsz, "VL0-3");
471		break;
472	case 4:
473		snprintf(buf, bufsz, "VL0-7");
474		break;
475	case 5:
476		snprintf(buf, bufsz, "VL0-14");
477		break;
478	default:
479		snprintf(buf, bufsz, "?(%d)", opervls);
480	}
481}
482
483void
484mad_dump_portcapmask(char *buf, int bufsz, void *val, int valsz)
485{
486	unsigned mask = *(unsigned *)val;
487	char *s = buf;
488
489	s += sprintf(s, "0x%x\n", mask);
490	if (mask & (1 << 1))
491		s += sprintf(s, "\t\t\t\tIsSM\n");
492	if (mask & (1 << 2))
493		s += sprintf(s, "\t\t\t\tIsNoticeSupported\n");
494	if (mask & (1 << 3))
495		s += sprintf(s, "\t\t\t\tIsTrapSupported\n");
496	if (mask & (1 << 5))
497		s += sprintf(s, "\t\t\t\tIsAutomaticMigrationSupported\n");
498	if (mask & (1 << 6))
499		s += sprintf(s, "\t\t\t\tIsSLMappingSupported\n");
500	if (mask & (1 << 7))
501		s += sprintf(s, "\t\t\t\tIsMKeyNVRAM\n");
502	if (mask & (1 << 8))
503		s += sprintf(s, "\t\t\t\tIsPKeyNVRAM\n");
504	if (mask & (1 << 9))
505		s += sprintf(s, "\t\t\t\tIsLedInfoSupported\n");
506	if (mask & (1 << 10))
507		s += sprintf(s, "\t\t\t\tIsSMdisabled\n");
508	if (mask & (1 << 11))
509		s += sprintf(s, "\t\t\t\tIsSystemImageGUIDsupported\n");
510	if (mask & (1 << 12))
511		s += sprintf(s, "\t\t\t\tIsPkeySwitchExternalPortTrapSupported\n");
512	if (mask & (1 << 16))
513		s += sprintf(s, "\t\t\t\tIsCommunicatonManagementSupported\n");
514	if (mask & (1 << 17))
515		s += sprintf(s, "\t\t\t\tIsSNMPTunnelingSupported\n");
516	if (mask & (1 << 18))
517		s += sprintf(s, "\t\t\t\tIsReinitSupported\n");
518	if (mask & (1 << 19))
519		s += sprintf(s, "\t\t\t\tIsDeviceManagementSupported\n");
520	if (mask & (1 << 20))
521		s += sprintf(s, "\t\t\t\tIsVendorClassSupported\n");
522	if (mask & (1 << 21))
523		s += sprintf(s, "\t\t\t\tIsDRNoticeSupported\n");
524	if (mask & (1 << 22))
525		s += sprintf(s, "\t\t\t\tIsCapabilityMaskNoticeSupported\n");
526	if (mask & (1 << 23))
527		s += sprintf(s, "\t\t\t\tIsBootManagementSupported\n");
528	if (mask & (1 << 24))
529		s += sprintf(s, "\t\t\t\tIsLinkRoundTripLatencySupported\n");
530	if (mask & (1 << 25))
531		s += sprintf(s, "\t\t\t\tIsClientRegistrationSupported\n");
532	if (mask & (1 << 26))
533		s += sprintf(s, "\t\t\t\tIsOtherLocalChangesNoticeSupported\n");
534	if (mask & (1 << 27))
535		s += sprintf(s, "\t\t\t\tIsLinkSpeedWidthPairsTableSupported\n");
536
537	if (s != buf)
538		*(--s) = 0;
539}
540
541void
542mad_dump_bitfield(char *buf, int bufsz, void *val, int valsz)
543{
544	snprintf(buf, bufsz, "0x%x", *(uint32_t *)val);
545}
546
547void
548mad_dump_array(char *buf, int bufsz, void *val, int valsz)
549{
550	uint8_t *p = val, *e;
551	char *s = buf;
552
553	if (bufsz < valsz*2)
554		valsz = bufsz/2;
555
556	for (p = val, e = p + valsz; p < e; p++, s += 2)
557		sprintf(s, "%02x", *p);
558}
559
560void
561mad_dump_string(char *buf, int bufsz, void *val, int valsz)
562{
563	if (bufsz < valsz)
564		valsz = bufsz;
565
566	snprintf(buf, valsz, "'%s'", (char *)val);
567}
568
569void
570mad_dump_node_type(char *buf, int bufsz, void *val, int valsz)
571{
572	int nodetype = *(int*)val;
573
574	switch (nodetype) {
575 	case 1:
576		snprintf(buf, bufsz, "Channel Adapter");
577		break;
578 	case 2:
579		snprintf(buf, bufsz, "Switch");
580		break;
581 	case 3:
582		snprintf(buf, bufsz, "Router");
583		break;
584	default:
585		snprintf(buf, bufsz, "?(%d)?", nodetype);
586		break;
587	}
588}
589
590#define IB_MAX_NUM_VLS 16
591#define IB_MAX_NUM_VLS_TO_U8 ((IB_MAX_NUM_VLS)/2)
592
593typedef struct _ib_slvl_table {
594	uint8_t vl_by_sl_num[IB_MAX_NUM_VLS_TO_U8];
595} ib_slvl_table_t;
596
597static inline void
598ib_slvl_get_i(ib_slvl_table_t *tbl, int i, uint8_t *vl)
599{
600	*vl = (tbl->vl_by_sl_num[i >> 1] >> ((!(i&1)) << 2)) & 0xf;
601}
602
603#define IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK 32
604
605typedef struct _ib_vl_arb_table {
606	struct {
607		uint8_t res_vl;
608		uint8_t weight;
609	} vl_entry[IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK];
610} __attribute__((packed)) ib_vl_arb_table_t;
611
612static inline void
613ib_vl_arb_get_vl(uint8_t res_vl, uint8_t *const vl )
614{
615	*vl = res_vl & 0x0F;
616}
617
618void
619mad_dump_sltovl(char *buf, int bufsz, void *val, int valsz)
620{
621	ib_slvl_table_t* p_slvl_tbl = val;
622	uint8_t vl;
623	int i, n = 0;
624	n = snprintf(buf, bufsz, "|");
625	for (i = 0; i < 16; i++) {
626		ib_slvl_get_i(p_slvl_tbl, i, &vl);
627		n += snprintf(buf + n, bufsz - n, "%2u|", vl);
628		if (n >= bufsz)
629			break;
630	}
631	snprintf(buf + n, bufsz - n, "\n");
632}
633
634void
635mad_dump_vlarbitration(char *buf, int bufsz, void *val, int num)
636{
637	ib_vl_arb_table_t* p_vla_tbl = val;
638	unsigned i, n;
639	uint8_t vl;
640
641	num /= sizeof(p_vla_tbl->vl_entry[0]);
642
643	n = snprintf(buf, bufsz, "\nVL    : |");
644	if (n >= bufsz)
645		return;
646	for (i = 0; i < num; i++) {
647		ib_vl_arb_get_vl(p_vla_tbl->vl_entry[i].res_vl, &vl);
648		n += snprintf(buf + n, bufsz - n, "0x%-2X|", vl);
649		if (n >= bufsz)
650			return;
651	}
652
653	n += snprintf(buf + n, bufsz - n, "\nWEIGHT: |");
654	if (n >= bufsz)
655		return;
656	for (i = 0; i < num; i++) {
657		n += snprintf(buf + n, bufsz - n, "0x%-2X|",
658			      p_vla_tbl->vl_entry[i].weight);
659		if (n >= bufsz)
660			return;
661	}
662
663	snprintf(buf + n, bufsz - n, "\n");
664}
665
666static int
667_dump_fields(char *buf, int bufsz, void *data, int start, int end)
668{
669	char val[64];
670	char *s = buf;
671	int n, field;
672
673	for (field = start; field < end && bufsz > 0; field++) {
674		mad_decode_field(data, field, val);
675		if (!mad_dump_field(field, s, bufsz, val))
676			return -1;
677		n = strlen(s);
678		s += n;
679		*s++ = '\n';
680		*s = 0;
681		n++;
682		bufsz -= n;
683	}
684
685	return s - buf;
686}
687
688void
689mad_dump_nodedesc(char *buf, int bufsz, void *val, int valsz)
690{
691	strncpy(buf, val, bufsz);
692
693	if (valsz < bufsz)
694		buf[valsz] = 0;
695}
696
697void
698mad_dump_nodeinfo(char *buf, int bufsz, void *val, int valsz)
699{
700	_dump_fields(buf, bufsz, val, IB_NODE_FIRST_F, IB_NODE_LAST_F);
701}
702
703void
704mad_dump_portinfo(char *buf, int bufsz, void *val, int valsz)
705{
706	_dump_fields(buf, bufsz, val, IB_PORT_FIRST_F, IB_PORT_LAST_F);
707}
708
709void
710mad_dump_portstates(char *buf, int bufsz, void *val, int valsz)
711{
712	_dump_fields(buf, bufsz, val, IB_PORT_STATE_F, IB_PORT_LINK_DOWN_DEF_F);
713}
714
715void
716mad_dump_switchinfo(char *buf, int bufsz, void *val, int valsz)
717{
718	_dump_fields(buf, bufsz, val, IB_SW_FIRST_F, IB_SW_LAST_F);
719}
720
721void
722mad_dump_perfcounters(char *buf, int bufsz, void *val, int valsz)
723{
724	_dump_fields(buf, bufsz, val, IB_PC_FIRST_F, IB_PC_LAST_F);
725}
726
727void
728mad_dump_perfcounters_ext(char *buf, int bufsz, void *val, int valsz)
729{
730	_dump_fields(buf, bufsz, val, IB_PC_EXT_FIRST_F, IB_PC_EXT_LAST_F);
731}
732
733/************************/
734
735char *
736_mad_dump_val(ib_field_t *f, char *buf, int bufsz, void *val)
737{
738	f->def_dump_fn(buf, bufsz, val, ALIGN(f->bitlen, 8) / 8);
739	buf[bufsz - 1] = 0;
740
741	return buf;
742}
743
744char *
745_mad_dump_field(ib_field_t *f, char *name, char *buf, int bufsz, void *val)
746{
747	char dots[128];
748	int l, n;
749
750	if (bufsz <= 32)
751		return 0;		/* buf too small */
752
753	if (!name)
754		name = f->name;
755
756	l = strlen(name);
757	if (l < 32) {
758		memset(dots, '.', 32 - l);
759		dots[32 - l] = 0;
760	}
761
762	n = snprintf(buf, bufsz, "%s:%s", name, dots);
763	_mad_dump_val(f, buf + n, bufsz - n, val);
764	buf[bufsz - 1] = 0;
765
766	return buf;
767}
768
769int
770_mad_dump(ib_mad_dump_fn *fn, char *name, void *val, int valsz)
771{
772	ib_field_t f = { .def_dump_fn = fn, .bitlen = valsz * 8};
773	char buf[512];
774
775	return printf("%s\n", _mad_dump_field(&f, name, buf, sizeof buf, val));
776}
777
778int
779_mad_print_field(ib_field_t *f, char *name, void *val, int valsz)
780{
781	return _mad_dump(f->def_dump_fn, name ? name : f->name, val, valsz ? valsz : ALIGN(f->bitlen, 8) / 8);
782}
783