xref: /illumos-gate/usr/src/cmd/cxgbetool/cxgbetool.c (revision 6b1325cf)
15a9113e7SVishal Kulkarni /*
25a9113e7SVishal Kulkarni  * This file and its contents are supplied under the terms of the
35a9113e7SVishal Kulkarni  * Common Development and Distribution License ("CDDL"), version 1.0.
45a9113e7SVishal Kulkarni  * You may only use this file in accordance with the terms of version
55a9113e7SVishal Kulkarni  * 1.0 of the CDDL.
65a9113e7SVishal Kulkarni  *
75a9113e7SVishal Kulkarni  * A full copy of the text of the CDDL should have accompanied this
85a9113e7SVishal Kulkarni  * source.  A copy of the CDDL is also available via the Internet at
95a9113e7SVishal Kulkarni  * http://www.illumos.org/license/CDDL.
105a9113e7SVishal Kulkarni  */
115a9113e7SVishal Kulkarni 
125a9113e7SVishal Kulkarni /*
135a9113e7SVishal Kulkarni  * Copyright (c) 2018 by Chelsio Communications, Inc.
145a9113e7SVishal Kulkarni  */
155a9113e7SVishal Kulkarni 
1644bf619dSJohn Levon /*
1744bf619dSJohn Levon  * Copyright 2019 Joyent, Inc.
18d81537f4SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
1944bf619dSJohn Levon  */
2044bf619dSJohn Levon 
215a9113e7SVishal Kulkarni #include <stdio.h>
225a9113e7SVishal Kulkarni #include <stdlib.h>
235a9113e7SVishal Kulkarni #include <unistd.h>
245a9113e7SVishal Kulkarni #include <stropts.h>
255a9113e7SVishal Kulkarni #include <sys/types.h>
265a9113e7SVishal Kulkarni #include <sys/stat.h>
275a9113e7SVishal Kulkarni #include <fcntl.h>
285a9113e7SVishal Kulkarni #include <sys/socket.h>
295a9113e7SVishal Kulkarni #include <strings.h>
305a9113e7SVishal Kulkarni #include <sys/varargs.h>
315a9113e7SVishal Kulkarni #include <errno.h>
325a9113e7SVishal Kulkarni #include <sys/byteorder.h>
335a9113e7SVishal Kulkarni #include <inttypes.h>
345a9113e7SVishal Kulkarni #include <sys/sysmacros.h>
3565ecf399SYuri Pankov #include <err.h>
36d81537f4SRobert Mustacchi #include <libdevinfo.h>
375a9113e7SVishal Kulkarni 
385a9113e7SVishal Kulkarni #include "t4nex.h"
395a9113e7SVishal Kulkarni #include "version.h"
405a9113e7SVishal Kulkarni #include "osdep.h"
415a9113e7SVishal Kulkarni #include "t4fw_interface.h"
427e6ad469SVishal Kulkarni #include "cudbg.h"
437e6ad469SVishal Kulkarni #include "cudbg_lib_common.h"
447e6ad469SVishal Kulkarni 
457e6ad469SVishal Kulkarni #define CUDBG_SIZE (32 * 1024 * 1024)
467e6ad469SVishal Kulkarni #define CUDBG_MAX_ENTITY_STR_LEN 4096
477e6ad469SVishal Kulkarni #define MAX_PARAM_LEN 4096
487e6ad469SVishal Kulkarni 
49d81537f4SRobert Mustacchi static char cxgbetool_nexus[PATH_MAX];
50d81537f4SRobert Mustacchi 
517e6ad469SVishal Kulkarni char *option_list[] = {
527e6ad469SVishal Kulkarni 	"--collect",
537e6ad469SVishal Kulkarni 	"--view",
547e6ad469SVishal Kulkarni 	"--version",
557e6ad469SVishal Kulkarni };
567e6ad469SVishal Kulkarni 
577e6ad469SVishal Kulkarni enum {
587e6ad469SVishal Kulkarni 	CUDBG_OPT_COLLECT,
597e6ad469SVishal Kulkarni 	CUDBG_OPT_VIEW,
607e6ad469SVishal Kulkarni 	CUDBG_OPT_VERSION,
617e6ad469SVishal Kulkarni };
625a9113e7SVishal Kulkarni 
635a9113e7SVishal Kulkarni /*
645a9113e7SVishal Kulkarni  * Firmware Device Log Dumping
655a9113e7SVishal Kulkarni  */
665a9113e7SVishal Kulkarni 
675a9113e7SVishal Kulkarni static const char * const devlog_level_strings[] = {
685a9113e7SVishal Kulkarni 	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
695a9113e7SVishal Kulkarni 	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
705a9113e7SVishal Kulkarni 	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
715a9113e7SVishal Kulkarni 	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
725a9113e7SVishal Kulkarni 	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
735a9113e7SVishal Kulkarni 	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
745a9113e7SVishal Kulkarni };
755a9113e7SVishal Kulkarni 
765a9113e7SVishal Kulkarni static const char * const devlog_facility_strings[] = {
775a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
785a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_CF]		= "CF",
795a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
805a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
815a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_RES]	= "RES",
825a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_HW]		= "HW",
835a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
845a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
855a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
865a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
875a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
885a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_VI]		= "VI",
895a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
905a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
915a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_TM]		= "TM",
925a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
935a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
945a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
955a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
965a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_RI]		= "RI",
975a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
985a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
995a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
1005a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE",
1015a9113e7SVishal Kulkarni 	[FW_DEVLOG_FACILITY_CHNET]	= "CHNET",
1025a9113e7SVishal Kulkarni };
1035a9113e7SVishal Kulkarni 
1045a9113e7SVishal Kulkarni static const char *progname;
1057e6ad469SVishal Kulkarni int set_dbg_entity(u8 *dbg_bitmap, char *dbg_entity_list);
1067e6ad469SVishal Kulkarni 
check_option(char * opt)1077e6ad469SVishal Kulkarni static int check_option(char *opt)
1087e6ad469SVishal Kulkarni {
1097e6ad469SVishal Kulkarni 	int i;
1107e6ad469SVishal Kulkarni 
1117e6ad469SVishal Kulkarni 	for (i = 0; i < ARRAY_SIZE(option_list); i++) {
1127e6ad469SVishal Kulkarni 		if (!strcmp(opt, option_list[i]))
1137e6ad469SVishal Kulkarni 			return i;
1147e6ad469SVishal Kulkarni 	}
1157e6ad469SVishal Kulkarni 	return -1;
1167e6ad469SVishal Kulkarni }
1175a9113e7SVishal Kulkarni 
usage(FILE * fp)1185a9113e7SVishal Kulkarni static void usage(FILE *fp)
1195a9113e7SVishal Kulkarni {
120d81537f4SRobert Mustacchi 	fprintf(fp, "Usage: %s <t4nex# | cxgbe#> [operation]\n", progname);
1215a9113e7SVishal Kulkarni 	fprintf(fp,
1225a9113e7SVishal Kulkarni 	    "\tdevlog                              show device log\n"
1237e6ad469SVishal Kulkarni 	    "\tloadfw <FW image>                   Flash the FW image\n"
12465ecf399SYuri Pankov 	    "\tcudbg <option> [<args>]             Chelsio Unified Debugger\n");
1255a9113e7SVishal Kulkarni 	exit(fp == stderr ? 1 : 0);
1265a9113e7SVishal Kulkarni }
1275a9113e7SVishal Kulkarni 
1285a9113e7SVishal Kulkarni static int
doit(const char * iff_name,unsigned long cmd,void * data)1295a9113e7SVishal Kulkarni doit(const char *iff_name, unsigned long cmd, void *data)
1305a9113e7SVishal Kulkarni {
1315a9113e7SVishal Kulkarni 	int fd = 0;
1325a9113e7SVishal Kulkarni 	int rc = 0;
1335a9113e7SVishal Kulkarni 
1345a9113e7SVishal Kulkarni 	if ((fd = open(iff_name, O_RDWR)) < 0)
1355a9113e7SVishal Kulkarni 		return (-1);
1365a9113e7SVishal Kulkarni 
1375a9113e7SVishal Kulkarni 	rc = (ioctl(fd, cmd, data) < 0) ? errno : rc;
1385a9113e7SVishal Kulkarni 	close(fd);
1395a9113e7SVishal Kulkarni 	return (rc);
1405a9113e7SVishal Kulkarni }
1415a9113e7SVishal Kulkarni 
1425a9113e7SVishal Kulkarni static void
get_devlog(int argc,char * argv[],int start_arg,const char * iff_name)1435a9113e7SVishal Kulkarni get_devlog(int argc, char *argv[], int start_arg, const char *iff_name)
1445a9113e7SVishal Kulkarni {
1455a9113e7SVishal Kulkarni 	struct t4_devlog *devlog;
1465a9113e7SVishal Kulkarni 	struct fw_devlog_e *entry, *buf;
1475a9113e7SVishal Kulkarni 	int rc = 0, first = 0, nentries, i, j, len;
1485a9113e7SVishal Kulkarni 	uint64_t ftstamp = UINT64_MAX;
1495a9113e7SVishal Kulkarni 
1505a9113e7SVishal Kulkarni 	devlog = malloc(T4_DEVLOG_SIZE + sizeof (struct t4_devlog));
1515a9113e7SVishal Kulkarni 	if (!devlog)
1525a9113e7SVishal Kulkarni 		err(1, "%s: can't allocate devlog buffer", __func__);
1535a9113e7SVishal Kulkarni 
1545a9113e7SVishal Kulkarni 	devlog->len = T4_DEVLOG_SIZE;
1555a9113e7SVishal Kulkarni 	/* Get device log */
1565a9113e7SVishal Kulkarni 	rc = doit(iff_name, T4_IOCTL_DEVLOG, devlog);
1575a9113e7SVishal Kulkarni 	if (rc == ENOBUFS) {
1585a9113e7SVishal Kulkarni 		/*
1595a9113e7SVishal Kulkarni 		 * Default buffer size is not sufficient to hold device log.
1605a9113e7SVishal Kulkarni 		 * Driver has updated the devlog.len to indicate the expected
1615a9113e7SVishal Kulkarni 		 * size. Free the currently allocated devlog.data, allocate
1625a9113e7SVishal Kulkarni 		 * again with right size and retry.
1635a9113e7SVishal Kulkarni 		 */
1645a9113e7SVishal Kulkarni 		len = devlog->len;
1655a9113e7SVishal Kulkarni 		free(devlog);
1665a9113e7SVishal Kulkarni 
1675a9113e7SVishal Kulkarni 		if ((devlog = malloc(len + sizeof (struct t4_devlog))) == NULL)
1685a9113e7SVishal Kulkarni 			err(1, "%s: can't reallocate devlog buffer", __func__);
1695a9113e7SVishal Kulkarni 
1705a9113e7SVishal Kulkarni 		rc = doit(iff_name, T4_IOCTL_DEVLOG, devlog);
1715a9113e7SVishal Kulkarni 	}
1725a9113e7SVishal Kulkarni 	if (rc) {
1735a9113e7SVishal Kulkarni 		free(devlog);
17465ecf399SYuri Pankov 		errx(1, "%s: can't get device log", __func__);
1755a9113e7SVishal Kulkarni 	}
1765a9113e7SVishal Kulkarni 
1775a9113e7SVishal Kulkarni 	/* There are nentries number of entries in the buffer */
1785a9113e7SVishal Kulkarni 	nentries = (devlog->len / sizeof (struct fw_devlog_e));
1795a9113e7SVishal Kulkarni 
1805a9113e7SVishal Kulkarni 	buf = (struct fw_devlog_e *)devlog->data;
1815a9113e7SVishal Kulkarni 
1825a9113e7SVishal Kulkarni 	/* Find the first entry */
1835a9113e7SVishal Kulkarni 	for (i = 0; i < nentries; i++) {
1845a9113e7SVishal Kulkarni 		entry = &buf[i];
1855a9113e7SVishal Kulkarni 
1865a9113e7SVishal Kulkarni 		if (entry->timestamp == 0)
1875a9113e7SVishal Kulkarni 			break;
1885a9113e7SVishal Kulkarni 
1895a9113e7SVishal Kulkarni 		entry->timestamp = BE_64(entry->timestamp);
1905a9113e7SVishal Kulkarni 		entry->seqno = BE_32(entry->seqno);
1915a9113e7SVishal Kulkarni 		for (j = 0; j < 8; j++)
1925a9113e7SVishal Kulkarni 			entry->params[j] = BE_32(entry->params[j]);
1935a9113e7SVishal Kulkarni 
1945a9113e7SVishal Kulkarni 		if (entry->timestamp < ftstamp) {
1955a9113e7SVishal Kulkarni 			ftstamp = entry->timestamp;
1965a9113e7SVishal Kulkarni 			first = i;
1975a9113e7SVishal Kulkarni 		}
1985a9113e7SVishal Kulkarni 	}
1995a9113e7SVishal Kulkarni 
2005a9113e7SVishal Kulkarni 	printf("%10s  %15s  %8s  %8s  %s\n", "Seq#", "Tstamp", "Level",
2015a9113e7SVishal Kulkarni 	    "Facility", "Message");
2025a9113e7SVishal Kulkarni 
2035a9113e7SVishal Kulkarni 	i = first;
2045a9113e7SVishal Kulkarni 
2055a9113e7SVishal Kulkarni 	do {
2065a9113e7SVishal Kulkarni 		entry = &buf[i];
2075a9113e7SVishal Kulkarni 
2085a9113e7SVishal Kulkarni 		if (entry->timestamp == 0)
2095a9113e7SVishal Kulkarni 			break;
2105a9113e7SVishal Kulkarni 
2115a9113e7SVishal Kulkarni 		printf("%10d  %15llu  %8s  %8s  ", entry->seqno,
2125a9113e7SVishal Kulkarni 		    entry->timestamp,
2135a9113e7SVishal Kulkarni 		    (entry->level < ARRAY_SIZE(devlog_level_strings) ?
2145a9113e7SVishal Kulkarni 		    devlog_level_strings[entry->level] : "UNKNOWN"),
2155a9113e7SVishal Kulkarni 		    (entry->facility < ARRAY_SIZE(devlog_facility_strings) ?
2165a9113e7SVishal Kulkarni 		    devlog_facility_strings[entry->facility] : "UNKNOWN"));
2175a9113e7SVishal Kulkarni 
2185a9113e7SVishal Kulkarni 		printf((const char *)entry->fmt, entry->params[0],
2195a9113e7SVishal Kulkarni 		    entry->params[1], entry->params[2], entry->params[3],
2205a9113e7SVishal Kulkarni 		    entry->params[4], entry->params[5], entry->params[6],
2215a9113e7SVishal Kulkarni 		    entry->params[7]);
2225a9113e7SVishal Kulkarni 
2235a9113e7SVishal Kulkarni 		if (++i == nentries)
2245a9113e7SVishal Kulkarni 			i = 0;
2255a9113e7SVishal Kulkarni 
2265a9113e7SVishal Kulkarni 	} while (i != first);
2275a9113e7SVishal Kulkarni 
2285a9113e7SVishal Kulkarni 	free(devlog);
2295a9113e7SVishal Kulkarni }
2305a9113e7SVishal Kulkarni 
2315a9113e7SVishal Kulkarni static void
load_fw(int argc,char * argv[],int start_arg,const char * iff_name)2325a9113e7SVishal Kulkarni load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
2335a9113e7SVishal Kulkarni {
2345a9113e7SVishal Kulkarni 	const char *fname = argv[start_arg];
2355a9113e7SVishal Kulkarni 	struct t4_ldfw *fw;
2365a9113e7SVishal Kulkarni 	struct stat sb;
2375a9113e7SVishal Kulkarni 	size_t len;
2385a9113e7SVishal Kulkarni 	int fd;
2395a9113e7SVishal Kulkarni 
2405a9113e7SVishal Kulkarni 	if (argc != 4)
24165ecf399SYuri Pankov 		errx(1, "incorrect number of arguments");
2425a9113e7SVishal Kulkarni 
2435a9113e7SVishal Kulkarni 	fd = open(fname, O_RDONLY);
2445a9113e7SVishal Kulkarni 	if (fd < 0)
2455a9113e7SVishal Kulkarni 		err(1, "%s: opening %s failed", __func__, fname);
2465a9113e7SVishal Kulkarni 	if (fstat(fd, &sb) < 0) {
24765ecf399SYuri Pankov 		warn("%s: fstat %s failed", __func__, fname);
2485a9113e7SVishal Kulkarni 		close(fd);
24965ecf399SYuri Pankov 		exit(1);
2505a9113e7SVishal Kulkarni 	}
2515a9113e7SVishal Kulkarni 	len = (size_t)sb.st_size;
2525a9113e7SVishal Kulkarni 
2535a9113e7SVishal Kulkarni 	fw = malloc(sizeof (struct t4_ldfw) + len);
2545a9113e7SVishal Kulkarni 	if (!fw) {
255*6b1325cfSRobert Mustacchi 		warn("%s: %s allocate %zu bytes failed",
2565a9113e7SVishal Kulkarni 		    __func__, fname, sizeof (struct t4_ldfw) + len);
25765ecf399SYuri Pankov 		close(fd);
25865ecf399SYuri Pankov 		exit(1);
2595a9113e7SVishal Kulkarni 	}
2605a9113e7SVishal Kulkarni 
2615a9113e7SVishal Kulkarni 	if (read(fd, fw->data, len) < len) {
26265ecf399SYuri Pankov 		warn("%s: %s read failed", __func__, fname);
2635a9113e7SVishal Kulkarni 		close(fd);
2645a9113e7SVishal Kulkarni 		free(fw);
26565ecf399SYuri Pankov 		exit(1);
2665a9113e7SVishal Kulkarni 	}
2675a9113e7SVishal Kulkarni 
2685a9113e7SVishal Kulkarni 	close(fd);
2695a9113e7SVishal Kulkarni 
2705a9113e7SVishal Kulkarni 	fw->len = len;
2715a9113e7SVishal Kulkarni 
2725a9113e7SVishal Kulkarni 	if (doit(iff_name, T4_IOCTL_LOAD_FW, fw)) {
2735a9113e7SVishal Kulkarni 		free(fw);
2745a9113e7SVishal Kulkarni 		err(1, "%s: IOCTL failed", __func__);
2755a9113e7SVishal Kulkarni 	} else {
2765a9113e7SVishal Kulkarni 		printf("FW flash success, reload driver/reboot to take "
2775a9113e7SVishal Kulkarni 		    "effect\n");
2785a9113e7SVishal Kulkarni 	}
2795a9113e7SVishal Kulkarni 
2805a9113e7SVishal Kulkarni 	free(fw);
2815a9113e7SVishal Kulkarni }
2825a9113e7SVishal Kulkarni 
read_input_file(char * in_file,void ** buf,int * buf_size)2837e6ad469SVishal Kulkarni int read_input_file(char *in_file, void **buf, int *buf_size)
2847e6ad469SVishal Kulkarni {
2857e6ad469SVishal Kulkarni 	FILE *fptr = NULL;
2867e6ad469SVishal Kulkarni 	size_t count;
2877e6ad469SVishal Kulkarni 	int rc = 0;
2887e6ad469SVishal Kulkarni 
2897e6ad469SVishal Kulkarni 	fptr = fopen(in_file, "rb");
2907e6ad469SVishal Kulkarni 	if (!fptr) {
2917e6ad469SVishal Kulkarni 		perror("error in opening file ");
2927e6ad469SVishal Kulkarni 		rc = -1;
2937e6ad469SVishal Kulkarni 		goto out;
2947e6ad469SVishal Kulkarni 	}
2957e6ad469SVishal Kulkarni 	rc = fseek(fptr, 0, SEEK_END);
2967e6ad469SVishal Kulkarni 	if (rc < 0) {
2977e6ad469SVishal Kulkarni 		perror("error in seeking file ");
2987e6ad469SVishal Kulkarni 		rc = -1;
2997e6ad469SVishal Kulkarni 		goto out;
3007e6ad469SVishal Kulkarni 	}
3017e6ad469SVishal Kulkarni 	*buf_size = ftell(fptr);
3027e6ad469SVishal Kulkarni 	rc = fseek(fptr, 0, SEEK_SET);
3037e6ad469SVishal Kulkarni 	if (rc < 0) {
3047e6ad469SVishal Kulkarni 		perror("error in seeking file ");
3057e6ad469SVishal Kulkarni 		rc = -1;
3067e6ad469SVishal Kulkarni 		goto out;
3077e6ad469SVishal Kulkarni 	}
3087e6ad469SVishal Kulkarni 	*buf = (void *) malloc(*buf_size);
3097e6ad469SVishal Kulkarni 	if (*buf == NULL) {
3107e6ad469SVishal Kulkarni 		rc = CUDBG_STATUS_NOSPACE;
3117e6ad469SVishal Kulkarni 		goto out;
3127e6ad469SVishal Kulkarni 	}
3137e6ad469SVishal Kulkarni 	memset(*buf, 0, *buf_size);
3147e6ad469SVishal Kulkarni 
3157e6ad469SVishal Kulkarni 	count = fread(*buf, 1, *buf_size, fptr);
3167e6ad469SVishal Kulkarni 	if (count != *buf_size) {
3177e6ad469SVishal Kulkarni 		perror("error in reading from file ");
3187e6ad469SVishal Kulkarni 		goto out;
3197e6ad469SVishal Kulkarni 	}
3207e6ad469SVishal Kulkarni 
3217e6ad469SVishal Kulkarni out:
3227e6ad469SVishal Kulkarni 	if (fptr)
3237e6ad469SVishal Kulkarni 		fclose(fptr);
3247e6ad469SVishal Kulkarni 
3257e6ad469SVishal Kulkarni 	return rc;
3267e6ad469SVishal Kulkarni }
3277e6ad469SVishal Kulkarni 
3287e6ad469SVishal Kulkarni static void
do_collect(char * dbg_entity_list,const char * iff_name,const char * fname)3297e6ad469SVishal Kulkarni do_collect(char *dbg_entity_list, const char *iff_name, const char *fname)
3307e6ad469SVishal Kulkarni {
3317e6ad469SVishal Kulkarni 	struct t4_cudbg_dump *cudbg;
3327e6ad469SVishal Kulkarni 	int fd;
3337e6ad469SVishal Kulkarni 
3347e6ad469SVishal Kulkarni 	cudbg = malloc(sizeof(struct t4_cudbg_dump) + CUDBG_SIZE);
3357e6ad469SVishal Kulkarni 	if (!cudbg) {
336*6b1325cfSRobert Mustacchi 		err(1, "%s:allocate %d bytes failed", __func__, CUDBG_SIZE);
3377e6ad469SVishal Kulkarni 	}
3387e6ad469SVishal Kulkarni 
3397e6ad469SVishal Kulkarni 	memset(cudbg, 0, sizeof(struct t4_cudbg_dump) + CUDBG_SIZE);
3407e6ad469SVishal Kulkarni 
3417e6ad469SVishal Kulkarni 	cudbg->len = CUDBG_SIZE;
3427e6ad469SVishal Kulkarni 
3437e6ad469SVishal Kulkarni 	set_dbg_entity(cudbg->bitmap, dbg_entity_list);
3447e6ad469SVishal Kulkarni 
3457e6ad469SVishal Kulkarni 	if (doit(iff_name, T4_IOCTL_GET_CUDBG, cudbg)) {
3467e6ad469SVishal Kulkarni 		free(cudbg);
3477e6ad469SVishal Kulkarni 		err(1, "%s: IOCTL failed", __func__);
3487e6ad469SVishal Kulkarni 	}
3497e6ad469SVishal Kulkarni 
3507e6ad469SVishal Kulkarni 	fd = open(fname, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY,
3517e6ad469SVishal Kulkarni 		  S_IRUSR | S_IRGRP | S_IROTH);
3527e6ad469SVishal Kulkarni 	if (fd < 0) {
35365ecf399SYuri Pankov 		err(1, "%s: file open failed", __func__);
3547e6ad469SVishal Kulkarni 	}
3557e6ad469SVishal Kulkarni 
3567e6ad469SVishal Kulkarni 	write(fd, cudbg->data, cudbg->len);
3577e6ad469SVishal Kulkarni 	close(fd);
3587e6ad469SVishal Kulkarni 	free(cudbg);
3597e6ad469SVishal Kulkarni }
3607e6ad469SVishal Kulkarni 
3617e6ad469SVishal Kulkarni static void
do_view(char * dbg_entity_list,char * in_file)3627e6ad469SVishal Kulkarni do_view(char *dbg_entity_list, char *in_file)
3637e6ad469SVishal Kulkarni {
3647e6ad469SVishal Kulkarni 	void *handle = NULL;
3657e6ad469SVishal Kulkarni 	void *buf = NULL;
3667e6ad469SVishal Kulkarni 	int buf_size = 32 * 1024 * 1024;
3677e6ad469SVishal Kulkarni 	int  next_offset = 0;
3687e6ad469SVishal Kulkarni 	int data_len;
3697e6ad469SVishal Kulkarni 	int rc = 0;
3707e6ad469SVishal Kulkarni 
3717e6ad469SVishal Kulkarni 	handle = cudbg_alloc_handle();
3727e6ad469SVishal Kulkarni 	if (!handle)
3737e6ad469SVishal Kulkarni 		goto out;
3747e6ad469SVishal Kulkarni 	/* rcad from file */
3757e6ad469SVishal Kulkarni 	rc = read_input_file(in_file, &buf, &buf_size);
3767e6ad469SVishal Kulkarni 	if (rc < 0) {
3777e6ad469SVishal Kulkarni 		goto out;
3787e6ad469SVishal Kulkarni 	}
3797e6ad469SVishal Kulkarni 
3807e6ad469SVishal Kulkarni 	set_dbg_entity(((struct cudbg_private *)handle)->dbg_init.dbg_bitmap,
3817e6ad469SVishal Kulkarni 			dbg_entity_list);
3827e6ad469SVishal Kulkarni 	do {
3837e6ad469SVishal Kulkarni 		if (buf_size - next_offset <= 0)
3847e6ad469SVishal Kulkarni 			break;
3857e6ad469SVishal Kulkarni 
3867e6ad469SVishal Kulkarni 		data_len = cudbg_view(handle, buf+next_offset,
3877e6ad469SVishal Kulkarni 				buf_size-next_offset, NULL, 0);
3887e6ad469SVishal Kulkarni 		next_offset += data_len;
3897e6ad469SVishal Kulkarni 		if (data_len > 0)
3907e6ad469SVishal Kulkarni 			printf("\n\t\t<========================END============="\
3917e6ad469SVishal Kulkarni 					"===========>\t\t\n\n\n");
3927e6ad469SVishal Kulkarni 	} while (data_len > 0);
3937e6ad469SVishal Kulkarni 
3947e6ad469SVishal Kulkarni out:
3957e6ad469SVishal Kulkarni 	if (buf)
3967e6ad469SVishal Kulkarni 		free(buf);
3977e6ad469SVishal Kulkarni 	if (handle)
3987e6ad469SVishal Kulkarni 		cudbg_free_handle(handle);
3997e6ad469SVishal Kulkarni 	return;
4007e6ad469SVishal Kulkarni }
4017e6ad469SVishal Kulkarni 
4027e6ad469SVishal Kulkarni typedef void (*cudbg_alias_get_entities_cb)(char *dst, u32 dst_size);
4037e6ad469SVishal Kulkarni 
4047e6ad469SVishal Kulkarni struct entity_access_list {
4057e6ad469SVishal Kulkarni         const char *name;
4067e6ad469SVishal Kulkarni         cudbg_alias_get_entities_cb get_entities_cb;
4077e6ad469SVishal Kulkarni };
4087e6ad469SVishal Kulkarni 
4097e6ad469SVishal Kulkarni void
cudbg_append_string(char * dst,u32 dst_size,char * src)4107e6ad469SVishal Kulkarni cudbg_append_string(char *dst, u32 dst_size, char *src)
4117e6ad469SVishal Kulkarni {
4127e6ad469SVishal Kulkarni         strlcat(dst, src, dst_size);
4137e6ad469SVishal Kulkarni         strlcat(dst, ",", dst_size);
4147e6ad469SVishal Kulkarni }
4157e6ad469SVishal Kulkarni 
4167e6ad469SVishal Kulkarni static void
cudbg_alias_get_allregs(char * dst,u32 dst_size)4177e6ad469SVishal Kulkarni cudbg_alias_get_allregs(char *dst, u32 dst_size)
4187e6ad469SVishal Kulkarni {
4197e6ad469SVishal Kulkarni         u32 i;
4207e6ad469SVishal Kulkarni 
4217e6ad469SVishal Kulkarni         for (i = 0; i < ARRAY_SIZE(entity_list); i++)
4227e6ad469SVishal Kulkarni                 if (entity_list[i].flag & (1 << ENTITY_FLAG_REGISTER))
4237e6ad469SVishal Kulkarni                         cudbg_append_string(dst, dst_size, entity_list[i].name);
4247e6ad469SVishal Kulkarni }
4257e6ad469SVishal Kulkarni 
4267e6ad469SVishal Kulkarni static struct entity_access_list ATTRIBUTE_UNUSED entity_alias_list[] = {
4277e6ad469SVishal Kulkarni         {"allregs", cudbg_alias_get_allregs},
4287e6ad469SVishal Kulkarni };
4297e6ad469SVishal Kulkarni 
4307e6ad469SVishal Kulkarni static int
check_dbg_entity(char * entity)4317e6ad469SVishal Kulkarni check_dbg_entity(char *entity)
4327e6ad469SVishal Kulkarni {
4337e6ad469SVishal Kulkarni 	u32 i;
4347e6ad469SVishal Kulkarni 
4357e6ad469SVishal Kulkarni 	for (i = 0; i < ARRAY_SIZE(entity_list); i++)
4367e6ad469SVishal Kulkarni 		if (!strcmp(entity, entity_list[i].name))
4377e6ad469SVishal Kulkarni 			return entity_list[i].bit;
4387e6ad469SVishal Kulkarni 	return -1;
4397e6ad469SVishal Kulkarni }
4407e6ad469SVishal Kulkarni 
4417e6ad469SVishal Kulkarni /* Get matching alias index from entity_alias_list[] */
4427e6ad469SVishal Kulkarni static
get_alias(const char * entity)4437e6ad469SVishal Kulkarni int get_alias(const char *entity)
4447e6ad469SVishal Kulkarni {
4457e6ad469SVishal Kulkarni 	u32 i;
4467e6ad469SVishal Kulkarni 
4477e6ad469SVishal Kulkarni 	for (i = 0; i < ARRAY_SIZE(entity_alias_list); i++)
4487e6ad469SVishal Kulkarni 		if (!strcmp(entity, entity_alias_list[i].name))
4497e6ad469SVishal Kulkarni 			return i;
4507e6ad469SVishal Kulkarni 	return -1;
4517e6ad469SVishal Kulkarni }
4527e6ad469SVishal Kulkarni 
4537e6ad469SVishal Kulkarni static int
parse_entity_list(const char * dbg_entity_list,char * dst,u32 dst_size)4547e6ad469SVishal Kulkarni parse_entity_list(const char *dbg_entity_list, char *dst,
4557e6ad469SVishal Kulkarni 				    u32 dst_size)
4567e6ad469SVishal Kulkarni {
4577e6ad469SVishal Kulkarni 	char *tmp_dbg_entity_list;
4587e6ad469SVishal Kulkarni 	char *dbg_entity;
4597e6ad469SVishal Kulkarni 	int rc, i;
4607e6ad469SVishal Kulkarni 
4617e6ad469SVishal Kulkarni 	/* Holds single entity name de-limited by comma */
4627e6ad469SVishal Kulkarni 	tmp_dbg_entity_list = malloc(CUDBG_MAX_ENTITY_STR_LEN);
4637e6ad469SVishal Kulkarni 	if (!tmp_dbg_entity_list)
4647e6ad469SVishal Kulkarni 		return ENOMEM;
4657e6ad469SVishal Kulkarni 
4667e6ad469SVishal Kulkarni 	strlcpy(tmp_dbg_entity_list, dbg_entity_list, CUDBG_MAX_ENTITY_STR_LEN);
4677e6ad469SVishal Kulkarni 	dbg_entity = strtok(tmp_dbg_entity_list, ",");
4687e6ad469SVishal Kulkarni 	while (dbg_entity != NULL) {
4697e6ad469SVishal Kulkarni 		/* See if specified entity name exists.  If it doesn't
4707e6ad469SVishal Kulkarni 		 * exist, see if the entity name is an alias.
4717e6ad469SVishal Kulkarni 		 * If it's not a valid entity name, bail with error.
4727e6ad469SVishal Kulkarni 		 */
4737e6ad469SVishal Kulkarni 		rc = check_dbg_entity(dbg_entity);
4747e6ad469SVishal Kulkarni 		if (rc < 0) {
4757e6ad469SVishal Kulkarni 			i = get_alias(dbg_entity);
4767e6ad469SVishal Kulkarni 			if (i < 0) {
4777e6ad469SVishal Kulkarni 				/* Not an alias, and not a valid entity name */
4787e6ad469SVishal Kulkarni 				printf("\nUnknown entity: %s\n", dbg_entity);
4797e6ad469SVishal Kulkarni 				rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
4807e6ad469SVishal Kulkarni 				goto out_err;
4817e6ad469SVishal Kulkarni 			} else {
4827e6ad469SVishal Kulkarni 				/* If alias is found, get all the corresponding
4837e6ad469SVishal Kulkarni 				 * debug entities related to the alias.
4847e6ad469SVishal Kulkarni 				 */
4857e6ad469SVishal Kulkarni 				entity_alias_list[i].get_entities_cb(dst, dst_size);
4867e6ad469SVishal Kulkarni 			}
4877e6ad469SVishal Kulkarni 		} else {
4887e6ad469SVishal Kulkarni 			/* Not an alias, but is a valid entity name.
4897e6ad469SVishal Kulkarni 			 * So, append the corresponding debug entity.
4907e6ad469SVishal Kulkarni 			 */
4917e6ad469SVishal Kulkarni 			cudbg_append_string(dst, dst_size, entity_list[rc].name);
4927e6ad469SVishal Kulkarni 		}
4937e6ad469SVishal Kulkarni 		dbg_entity = strtok(NULL, ",");
4947e6ad469SVishal Kulkarni 	}
4957e6ad469SVishal Kulkarni 
4967e6ad469SVishal Kulkarni 	rc = 0;
4977e6ad469SVishal Kulkarni 
4987e6ad469SVishal Kulkarni out_err:
4997e6ad469SVishal Kulkarni 	free(tmp_dbg_entity_list);
5007e6ad469SVishal Kulkarni 	return rc;
5017e6ad469SVishal Kulkarni }
5027e6ad469SVishal Kulkarni 
5037e6ad469SVishal Kulkarni static
get_entity_list(const char * in_buff,char ** out_buff)5047e6ad469SVishal Kulkarni int get_entity_list(const char *in_buff, char **out_buff)
5057e6ad469SVishal Kulkarni {
5067e6ad469SVishal Kulkarni 	char *dbg_entity_list;
5077e6ad469SVishal Kulkarni 	int rc;
5087e6ad469SVishal Kulkarni 
5097e6ad469SVishal Kulkarni 	/* Allocate enough to hold converted alias string.
5107e6ad469SVishal Kulkarni 	 * Must be freed by caller
5117e6ad469SVishal Kulkarni 	 */
5127e6ad469SVishal Kulkarni 	dbg_entity_list = malloc(CUDBG_MAX_ENTITY_STR_LEN);
5137e6ad469SVishal Kulkarni 	if (!dbg_entity_list)
5147e6ad469SVishal Kulkarni 		return ENOMEM;
5157e6ad469SVishal Kulkarni 
5167e6ad469SVishal Kulkarni 	memset(dbg_entity_list, 0, CUDBG_MAX_ENTITY_STR_LEN);
5177e6ad469SVishal Kulkarni 	rc = parse_entity_list(in_buff, dbg_entity_list,
5187e6ad469SVishal Kulkarni 			       CUDBG_MAX_ENTITY_STR_LEN);
5197e6ad469SVishal Kulkarni 	if (rc) {
5207e6ad469SVishal Kulkarni 		free(dbg_entity_list);
5217e6ad469SVishal Kulkarni 		return rc;
5227e6ad469SVishal Kulkarni 	}
5237e6ad469SVishal Kulkarni 
5247e6ad469SVishal Kulkarni 	/* Remove the last comma */
5257e6ad469SVishal Kulkarni 	dbg_entity_list[strlen(dbg_entity_list) - 1] = '\0';
5267e6ad469SVishal Kulkarni 	*out_buff = dbg_entity_list;
5277e6ad469SVishal Kulkarni 	return 0;
5287e6ad469SVishal Kulkarni }
5297e6ad469SVishal Kulkarni 
5307e6ad469SVishal Kulkarni static void
put_entity_list(char * buf)5317e6ad469SVishal Kulkarni put_entity_list(char *buf)
5327e6ad469SVishal Kulkarni {
5337e6ad469SVishal Kulkarni 	if (buf)
5347e6ad469SVishal Kulkarni 		free(buf);
5357e6ad469SVishal Kulkarni }
5367e6ad469SVishal Kulkarni 
5377e6ad469SVishal Kulkarni int
set_dbg_entity(u8 * dbg_bitmap,char * dbg_entity_list)5387e6ad469SVishal Kulkarni set_dbg_entity(u8 *dbg_bitmap, char *dbg_entity_list)
5397e6ad469SVishal Kulkarni {
5407e6ad469SVishal Kulkarni 	int i, dbg_entity_bit, rc = 0;
5417e6ad469SVishal Kulkarni 	char *dbg_entity;
5427e6ad469SVishal Kulkarni 	char *dbg_entity_list_tmp;
5437e6ad469SVishal Kulkarni 
5447e6ad469SVishal Kulkarni 	dbg_entity_list_tmp = malloc(MAX_PARAM_LEN);
5457e6ad469SVishal Kulkarni 	if (!dbg_entity_list_tmp) {
5467e6ad469SVishal Kulkarni 		rc = CUDBG_STATUS_NOSPACE;
5477e6ad469SVishal Kulkarni 		return rc;
5487e6ad469SVishal Kulkarni 	}
5497e6ad469SVishal Kulkarni 
5507e6ad469SVishal Kulkarni 	if (dbg_entity_list != NULL) {
5517e6ad469SVishal Kulkarni 		strlcpy(dbg_entity_list_tmp, dbg_entity_list, MAX_PARAM_LEN);
5527e6ad469SVishal Kulkarni 		dbg_entity = strtok(dbg_entity_list_tmp, ",");
5537e6ad469SVishal Kulkarni 	}
5547e6ad469SVishal Kulkarni 	else
5557e6ad469SVishal Kulkarni 		dbg_entity = NULL;
5567e6ad469SVishal Kulkarni 
5577e6ad469SVishal Kulkarni 	while (dbg_entity != NULL) {
5587e6ad469SVishal Kulkarni 		rc = check_dbg_entity(dbg_entity);
5597e6ad469SVishal Kulkarni 		if (rc < 0) {
5607e6ad469SVishal Kulkarni 			printf("\n\tInvalid debug entity: %s\n", dbg_entity);
5617e6ad469SVishal Kulkarni 			//Vishal cudbg_usage();
5627e6ad469SVishal Kulkarni 			goto out_free;
5637e6ad469SVishal Kulkarni 		}
5647e6ad469SVishal Kulkarni 
5657e6ad469SVishal Kulkarni 		dbg_entity_bit = rc;
5667e6ad469SVishal Kulkarni 
5677e6ad469SVishal Kulkarni 		if (dbg_entity_bit == CUDBG_ALL) {
5687e6ad469SVishal Kulkarni 			for (i = 1; i < CUDBG_MAX_ENTITY; i++)
5697e6ad469SVishal Kulkarni 				set_dbg_bitmap(dbg_bitmap, i);
5707e6ad469SVishal Kulkarni 			set_dbg_bitmap(dbg_bitmap, CUDBG_ALL);
5717e6ad469SVishal Kulkarni 			break;
5727e6ad469SVishal Kulkarni 		} else {
5737e6ad469SVishal Kulkarni 			set_dbg_bitmap(dbg_bitmap, dbg_entity_bit);
5747e6ad469SVishal Kulkarni 		}
5757e6ad469SVishal Kulkarni 
5767e6ad469SVishal Kulkarni 		dbg_entity = strtok(NULL, ",");
5777e6ad469SVishal Kulkarni 	}
5787e6ad469SVishal Kulkarni 
5797e6ad469SVishal Kulkarni 	rc = 0;
5807e6ad469SVishal Kulkarni 
5817e6ad469SVishal Kulkarni out_free:
5827e6ad469SVishal Kulkarni 	free(dbg_entity_list_tmp);
5837e6ad469SVishal Kulkarni 	return rc;
5847e6ad469SVishal Kulkarni }
5857e6ad469SVishal Kulkarni 
5867e6ad469SVishal Kulkarni 
5877e6ad469SVishal Kulkarni static void
get_cudbg(int argc,char * argv[],int start_arg,const char * iff_name)5887e6ad469SVishal Kulkarni get_cudbg(int argc, char *argv[], int start_arg, const char *iff_name)
5897e6ad469SVishal Kulkarni {
5907e6ad469SVishal Kulkarni 	char *dbg_entity_list = NULL;
5917e6ad469SVishal Kulkarni 	int rc = 0, option;
59265ecf399SYuri Pankov 
59365ecf399SYuri Pankov 	if (start_arg >= argc)
59465ecf399SYuri Pankov 		errx(1, "no option provided");
59565ecf399SYuri Pankov 
5967e6ad469SVishal Kulkarni 	rc = check_option(argv[start_arg++]);
5977e6ad469SVishal Kulkarni 	if (rc < 0) {
59865ecf399SYuri Pankov 		errx(1, "%s:Invalid option provided", __func__);
5997e6ad469SVishal Kulkarni 	}
6007e6ad469SVishal Kulkarni 	option = rc;
6017e6ad469SVishal Kulkarni 
6027e6ad469SVishal Kulkarni 	if (option == CUDBG_OPT_VERSION) {
6037e6ad469SVishal Kulkarni 		printf("Library Version %d.%d.%d\n", CUDBG_MAJOR_VERSION,
6047e6ad469SVishal Kulkarni 			CUDBG_MINOR_VERSION, CUDBG_BUILD_VERSION);
6057e6ad469SVishal Kulkarni 		return;
6067e6ad469SVishal Kulkarni 	}
6077e6ad469SVishal Kulkarni 
6087e6ad469SVishal Kulkarni 	if (argc < 5) {
60965ecf399SYuri Pankov 		errx(1, "Invalid number of arguments\n");
6107e6ad469SVishal Kulkarni 	}
6117e6ad469SVishal Kulkarni 	rc = get_entity_list(argv[start_arg++],
6127e6ad469SVishal Kulkarni 			     &dbg_entity_list);
6137e6ad469SVishal Kulkarni 	if (rc) {
61465ecf399SYuri Pankov 		errx(1, "Error in parsing entity\n");
6157e6ad469SVishal Kulkarni 	}
6167e6ad469SVishal Kulkarni 
6177e6ad469SVishal Kulkarni 	if (argc < 6) {
61865ecf399SYuri Pankov 		errx(1, "File name is missing\n");
6197e6ad469SVishal Kulkarni 	}
6207e6ad469SVishal Kulkarni 
6217e6ad469SVishal Kulkarni 	switch (option) {
6227e6ad469SVishal Kulkarni 		case CUDBG_OPT_COLLECT:
6237e6ad469SVishal Kulkarni 			do_collect(dbg_entity_list, iff_name, argv[start_arg]);
6247e6ad469SVishal Kulkarni 			break;
6257e6ad469SVishal Kulkarni 		case CUDBG_OPT_VIEW:
6267e6ad469SVishal Kulkarni 			do_view(dbg_entity_list, argv[start_arg]);
6277e6ad469SVishal Kulkarni 			break;
6287e6ad469SVishal Kulkarni 		default:
62965ecf399SYuri Pankov 			errx(1, "Wrong option provided\n");
6307e6ad469SVishal Kulkarni 	}
6317e6ad469SVishal Kulkarni 
6327e6ad469SVishal Kulkarni 	put_entity_list(dbg_entity_list);
6337e6ad469SVishal Kulkarni }
6347e6ad469SVishal Kulkarni 
6355a9113e7SVishal Kulkarni static void
run_cmd(int argc,char * argv[],const char * iff_name)6365a9113e7SVishal Kulkarni run_cmd(int argc, char *argv[], const char *iff_name)
6375a9113e7SVishal Kulkarni {
6385a9113e7SVishal Kulkarni 	if (strcmp(argv[2], "devlog") == 0)
6395a9113e7SVishal Kulkarni 		get_devlog(argc, argv, 3, iff_name);
6405a9113e7SVishal Kulkarni 	else if (strcmp(argv[2], "loadfw") == 0)
6415a9113e7SVishal Kulkarni 		load_fw(argc, argv, 3, iff_name);
6427e6ad469SVishal Kulkarni 	else if (strcmp(argv[2], "cudbg") == 0)
6437e6ad469SVishal Kulkarni 		get_cudbg(argc, argv, 3, iff_name);
6445a9113e7SVishal Kulkarni 	else
6455a9113e7SVishal Kulkarni 		usage(stderr);
6465a9113e7SVishal Kulkarni }
6475a9113e7SVishal Kulkarni 
648d81537f4SRobert Mustacchi /*
649d81537f4SRobert Mustacchi  * Traditionally we expect to be given a path to the t4nex device control file
650d81537f4SRobert Mustacchi  * hidden in /devices. To make life easier, we want to also support folks using
651d81537f4SRobert Mustacchi  * the driver instance numbers for either a given t4nex%d or cxgbe%d. We check
652d81537f4SRobert Mustacchi  * to see if we've been given a path to a character device and if so, just
653d81537f4SRobert Mustacchi  * continue straight on with the given argument. Otherwise we attempt to map it
654d81537f4SRobert Mustacchi  * to something known.
655d81537f4SRobert Mustacchi  */
656d81537f4SRobert Mustacchi static const char *
cxgbetool_parse_path(char * arg)657d81537f4SRobert Mustacchi cxgbetool_parse_path(char *arg)
658d81537f4SRobert Mustacchi {
659d81537f4SRobert Mustacchi 	struct stat st;
660d81537f4SRobert Mustacchi 	di_node_t root, node;
661d81537f4SRobert Mustacchi 	const char *numptr, *errstr;
662d81537f4SRobert Mustacchi 	size_t drvlen;
663d81537f4SRobert Mustacchi 	int inst;
664d81537f4SRobert Mustacchi 	boolean_t is_t4nex = B_TRUE;
665d81537f4SRobert Mustacchi 	char mname[64];
666d81537f4SRobert Mustacchi 
667d81537f4SRobert Mustacchi 	if (stat(arg, &st) == 0) {
668d81537f4SRobert Mustacchi 		if (S_ISCHR(st.st_mode)) {
669d81537f4SRobert Mustacchi 			return (arg);
670d81537f4SRobert Mustacchi 		}
671d81537f4SRobert Mustacchi 	}
672d81537f4SRobert Mustacchi 
673d81537f4SRobert Mustacchi 	if (strncmp(arg, T4_NEXUS_NAME, sizeof (T4_NEXUS_NAME) - 1) == 0) {
674d81537f4SRobert Mustacchi 		drvlen = sizeof (T4_NEXUS_NAME) - 1;
675d81537f4SRobert Mustacchi 	} else if (strncmp(arg, T4_PORT_NAME, sizeof (T4_PORT_NAME) - 1) == 0) {
676d81537f4SRobert Mustacchi 		is_t4nex = B_FALSE;
677d81537f4SRobert Mustacchi 		drvlen = sizeof (T4_PORT_NAME) - 1;
678d81537f4SRobert Mustacchi 	} else {
679d81537f4SRobert Mustacchi 		errx(EXIT_FAILURE, "cannot use device %s: not a character "
680d81537f4SRobert Mustacchi 		    "device or a %s/%s device instance", arg, T4_PORT_NAME,
681d81537f4SRobert Mustacchi 		    T4_NEXUS_NAME);
682d81537f4SRobert Mustacchi 	}
683d81537f4SRobert Mustacchi 
684d81537f4SRobert Mustacchi 	numptr = arg + drvlen;
685d81537f4SRobert Mustacchi 	inst = (int)strtonum(numptr, 0, INT_MAX, &errstr);
686d81537f4SRobert Mustacchi 	if (errstr != NULL) {
687d81537f4SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse instance number '%s': %s",
688d81537f4SRobert Mustacchi 		    numptr, errstr);
689d81537f4SRobert Mustacchi 	}
690d81537f4SRobert Mustacchi 
691d81537f4SRobert Mustacchi 	/*
692d81537f4SRobert Mustacchi 	 * Now that we have the instance here, we need to truncate the string at
693d81537f4SRobert Mustacchi 	 * the end of the driver name otherwise di_drv_first_node() will be very
694d81537f4SRobert Mustacchi 	 * confused as there is no driver called say 't4nex0'.
695d81537f4SRobert Mustacchi 	 */
696d81537f4SRobert Mustacchi 	arg[drvlen] = '\0';
697d81537f4SRobert Mustacchi 	root = di_init("/", DINFOCPYALL);
698d81537f4SRobert Mustacchi 	if (root == DI_NODE_NIL) {
699d81537f4SRobert Mustacchi 		err(EXIT_FAILURE, "failed to initialize libdevinfo while "
700d81537f4SRobert Mustacchi 		    "trying to map device name %s", arg);
701d81537f4SRobert Mustacchi 	}
702d81537f4SRobert Mustacchi 
703d81537f4SRobert Mustacchi 	for (node = di_drv_first_node(arg, root); node != DI_NODE_NIL;
704d81537f4SRobert Mustacchi 	    node = di_drv_next_node(node)) {
705d81537f4SRobert Mustacchi 		char *bpath;
706d81537f4SRobert Mustacchi 		di_minor_t minor = DI_MINOR_NIL;
707d81537f4SRobert Mustacchi 
708d81537f4SRobert Mustacchi 		if (di_instance(node) != inst) {
709d81537f4SRobert Mustacchi 			continue;
710d81537f4SRobert Mustacchi 		}
711d81537f4SRobert Mustacchi 
712d81537f4SRobert Mustacchi 		if (!is_t4nex) {
713d81537f4SRobert Mustacchi 			const char *pdrv;
714d81537f4SRobert Mustacchi 			node = di_parent_node(node);
715d81537f4SRobert Mustacchi 			pdrv = di_driver_name(node);
716d81537f4SRobert Mustacchi 			if (pdrv == NULL || strcmp(pdrv, T4_NEXUS_NAME) != 0) {
717d81537f4SRobert Mustacchi 				errx(EXIT_FAILURE, "%s does not have %s "
718d81537f4SRobert Mustacchi 				    "parent, found %s%d", arg, T4_NEXUS_NAME,
719d81537f4SRobert Mustacchi 				    pdrv != NULL ? pdrv : "unknown",
720d81537f4SRobert Mustacchi 				    pdrv != NULL ? di_instance(node) : -1);
721d81537f4SRobert Mustacchi 			}
722d81537f4SRobert Mustacchi 		}
723d81537f4SRobert Mustacchi 
724d81537f4SRobert Mustacchi 		(void) snprintf(mname, sizeof (mname), "%s,%d", T4_NEXUS_NAME,
725d81537f4SRobert Mustacchi 		    di_instance(node));
726d81537f4SRobert Mustacchi 
727d81537f4SRobert Mustacchi 		while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
728d81537f4SRobert Mustacchi 			if (strcmp(di_minor_name(minor), mname) == 0) {
729d81537f4SRobert Mustacchi 				break;
730d81537f4SRobert Mustacchi 			}
731d81537f4SRobert Mustacchi 		}
732d81537f4SRobert Mustacchi 
733d81537f4SRobert Mustacchi 		if (minor == DI_MINOR_NIL) {
734d81537f4SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to find minor %s on %s%d",
735d81537f4SRobert Mustacchi 			    mname, di_driver_name(node), di_instance(node));
736d81537f4SRobert Mustacchi 		}
737d81537f4SRobert Mustacchi 
738d81537f4SRobert Mustacchi 		bpath = di_devfs_minor_path(minor);
739d81537f4SRobert Mustacchi 		if (bpath == NULL) {
740d81537f4SRobert Mustacchi 			err(EXIT_FAILURE, "failed to get minor path for "
741d81537f4SRobert Mustacchi 			    "%s%d:%s", di_driver_name(node), di_instance(node),
742d81537f4SRobert Mustacchi 			    di_minor_name(minor));
743d81537f4SRobert Mustacchi 		}
744d81537f4SRobert Mustacchi 		if (snprintf(cxgbetool_nexus, sizeof (cxgbetool_nexus),
745d81537f4SRobert Mustacchi 		    "/devices%s", bpath) >= sizeof (cxgbetool_nexus)) {
746d81537f4SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to construct full /devices "
747d81537f4SRobert Mustacchi 			    "path for %s: internal path buffer would have "
748*6b1325cfSRobert Mustacchi 			    "overflowed", bpath);
749d81537f4SRobert Mustacchi 		}
750d81537f4SRobert Mustacchi 		di_devfs_path_free(bpath);
751d81537f4SRobert Mustacchi 
752d81537f4SRobert Mustacchi 		di_fini(root);
753d81537f4SRobert Mustacchi 		return (cxgbetool_nexus);
754d81537f4SRobert Mustacchi 	}
755d81537f4SRobert Mustacchi 
756d81537f4SRobert Mustacchi 	errx(EXIT_FAILURE, "failed to map %s%d to a %s or %s instance",
757d81537f4SRobert Mustacchi 	    arg, inst, T4_PORT_NAME, T4_NEXUS_NAME);
758d81537f4SRobert Mustacchi }
759d81537f4SRobert Mustacchi 
7605a9113e7SVishal Kulkarni int
main(int argc,char * argv[])7615a9113e7SVishal Kulkarni main(int argc, char *argv[])
7625a9113e7SVishal Kulkarni {
7635a9113e7SVishal Kulkarni 	const char *iff_name;
7645a9113e7SVishal Kulkarni 
7655a9113e7SVishal Kulkarni 	progname = argv[0];
7665a9113e7SVishal Kulkarni 
7675a9113e7SVishal Kulkarni 	if (argc == 2) {
7685a9113e7SVishal Kulkarni 		if (strcmp(argv[1], "-h") == 0 ||
7695a9113e7SVishal Kulkarni 		    strcmp(argv[1], "--help") == 0) {
7705a9113e7SVishal Kulkarni 			usage(stdout);
7715a9113e7SVishal Kulkarni 		}
7725a9113e7SVishal Kulkarni 
7735a9113e7SVishal Kulkarni 		if (strcmp(argv[1], "-v") == 0 ||
7745a9113e7SVishal Kulkarni 		    strcmp(argv[1], "--version") == 0) {
7755a9113e7SVishal Kulkarni 			printf("cxgbetool version %s\n", DRV_VERSION);
7765a9113e7SVishal Kulkarni 			exit(0);
7775a9113e7SVishal Kulkarni 		}
7785a9113e7SVishal Kulkarni 	}
7795a9113e7SVishal Kulkarni 
7805a9113e7SVishal Kulkarni 	if (argc < 3)
7815a9113e7SVishal Kulkarni 		usage(stderr);
7825a9113e7SVishal Kulkarni 
783d81537f4SRobert Mustacchi 	iff_name = cxgbetool_parse_path(argv[1]);
7845a9113e7SVishal Kulkarni 
7855a9113e7SVishal Kulkarni 	run_cmd(argc, argv, iff_name);
7865a9113e7SVishal Kulkarni 
7875a9113e7SVishal Kulkarni 	return (0);
7885a9113e7SVishal Kulkarni }
789