Blame fcping.c

Packit a132db
/*
Packit a132db
 * Copyright(c) 2010 Intel Corporation. All rights reserved.
Packit a132db
 *
Packit a132db
 * This program is free software; you can redistribute it and/or modify it
Packit a132db
 * under the terms and conditions of the GNU General Public License,
Packit a132db
 * version 2, as published by the Free Software Foundation.
Packit a132db
 *
Packit a132db
 * This program is distributed in the hope it will be useful, but WITHOUT
Packit a132db
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit a132db
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
Packit a132db
 * more details.
Packit a132db
 *
Packit a132db
 * You should have received a copy of the GNU General Public License along with
Packit a132db
 * this program; if not, write to the Free Software Foundation, Inc.,
Packit a132db
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit a132db
 *
Packit a132db
 * Maintained at www.Open-FCoE.org
Packit a132db
 */
Packit a132db
Packit a132db
/*
Packit a132db
 * FCPing - FC fabric diagnostic.
Packit a132db
 */
Packit a132db
#include <stdio.h>
Packit a132db
#include <stdlib.h>
Packit a132db
#include <stddef.h>
Packit a132db
#include <stdarg.h>
Packit a132db
#include <unistd.h>
Packit a132db
#include <inttypes.h>
Packit a132db
#include <errno.h>
Packit a132db
#include <string.h>
Packit a132db
#include <time.h>
Packit a132db
#include <fcntl.h>
Packit a132db
#include <malloc.h>
Packit a132db
#include <limits.h>
Packit a132db
#include <signal.h>
Packit a132db
#include <libgen.h>
Packit a132db
#include <assert.h>
Packit a132db
#include <syslog.h>
Packit a132db
#include <sys/stat.h>
Packit a132db
#include <sys/param.h>
Packit a132db
#include <sys/ioctl.h>
Packit a132db
#include <sys/time.h>
Packit a132db
#include <net/ethernet.h>
Packit a132db
#include <netinet/ether.h>
Packit a132db
#include <linux/types.h>
Packit a132db
#include <linux/bsg.h>
Packit a132db
#include "net_types.h"
Packit a132db
#include "fc_types.h"
Packit a132db
#include "fcoe_utils.h"
Packit a132db
typedef uint8_t u8;
Packit a132db
#include <scsi/sg.h>
Packit a132db
#include "fc_ns.h"
Packit a132db
#include "fc_gs.h"
Packit a132db
#include "fc_els.h"
Packit a132db
#include "scsi_bsg_fc.h"
Packit a132db
Packit a132db
#include "sysfs_hba.h"
Packit a132db
Packit a132db
static const char *cmdname;
Packit a132db
Packit a132db
#define FC_MAX_PAYLOAD  2112UL	/* Max FC payload */
Packit a132db
#define MAX_SENSE_LEN	96	/* SCSI_SENSE_BUFFERSIZE */
Packit a132db
#define MAX_HBA_COUNT	128
Packit a132db
/* FC ELS ECHO Command takes 4 bytes */
Packit a132db
#define FP_LEN_ECHO	sizeof(net32_t)
Packit a132db
/* default max ping data length, excluding 4 bytes of ELS ECHO command */
Packit a132db
#define FP_LEN_MAX	(FC_MAX_PAYLOAD - FP_LEN_ECHO)
Packit a132db
#define FP_LEN_MIN	4	/* fcping needs 4 bytes as sequence number */
Packit a132db
#define FP_LEN_DEF	32	/* default ping payload length */
Packit a132db
#define FP_LEN_PAD	32	/* extra length for response */
Packit a132db
#define FP_MIN_INTVL	0.001	/* minimum interval in seconds */
Packit a132db
#define FP_DEF_INTVL	1.000	/* default sending interval in seconds */
Packit a132db
#define SYSFS_HBA_DIR   "/sys/class/net"
Packit a132db
Packit a132db
/* Check if it is WKA accoriding to FC-FS-3 Rev 1.00 Clause 11 Table 30 */
Packit a132db
#define FCID_IS_WKA(i) ((((i) >= 0xfffc01) && ((i) <= 0xfffcfe)) || \
Packit a132db
			(((i) >= 0xfffff0) && ((i) <= 0xffffff)))
Packit a132db
Packit a132db
#define FC_WKA_FABRIC_CONTROLLER ((fc_fid_t)0xfffffd)
Packit a132db
#define FC_WKA_DIRECTORY_SERVICE ((fc_fid_t)0xfffffc)
Packit a132db
Packit a132db
static void fp_usage(void)
Packit a132db
{
Packit a132db
	fprintf(stderr,
Packit a132db
		"Usage: %s [ -fqx ] [ -i <interval> ] [ -c <count> ] -h <hba> "
Packit a132db
		"[ -s <size> ] { -F <FC-ID> | -P <WWPN> | -N <WWNN> }\n"
Packit a132db
		"  flags:\n"
Packit a132db
		"     -f:            Flood ping\n"
Packit a132db
		"     -q:            Quiet! just print summary\n"
Packit a132db
		"     -x:            Hex dump of responses\n"
Packit a132db
		"     -i <interval>: Wait <interval> seconds between each ping\n"
Packit a132db
		"     -c <count>:    Stop after sending <count> pings\n"
Packit a132db
		"     -h <hba>:      eth<n>, MAC address, WWPN, or FC-ID of the HBA\n"
Packit a132db
		"     -s <size>:     Byte-length of ping request payload (max %lu)\n"
Packit a132db
		"     -F <FC-ID>:    Destination port ID\n"
Packit a132db
		"     -P <WWPN>:     Destination world-wide port name\n"
Packit a132db
		"     -N <WWNN>:     Destination world-wide node name\n",
Packit a132db
		cmdname, FP_LEN_MAX);
Packit a132db
Packit a132db
	fprintf(stderr, "\nNote that the default maximum FC payload allowed "
Packit a132db
		"is %lu bytes and the default maximum fcping payload, "
Packit a132db
		"i.e., the FC ELS ECHO data, allowed is %lu "
Packit a132db
		"bytes.\n",
Packit a132db
		FC_MAX_PAYLOAD, FP_LEN_MAX);
Packit a132db
Packit a132db
	exit(1);
Packit a132db
}
Packit a132db
Packit a132db
static fc_fid_t fp_did;
Packit a132db
static fc_wwn_t fp_port_wwn;
Packit a132db
static fc_wwn_t fp_node_wwn;
Packit a132db
static int fp_count = -1;	/* send indefinitely by default */
Packit a132db
static uint32_t fp_len = FP_LEN_DEF + FP_LEN_ECHO;
Packit a132db
static int fp_flood;			/* send as fast as possible */
Packit a132db
static uint32_t fp_interval = FP_DEF_INTVL * 1000; /* in milliseconds */
Packit a132db
static int fp_quiet;
Packit a132db
static int fp_hex;
Packit a132db
static char *fp_hba;	/* name of interface to be used */
Packit a132db
static char fp_dev[64];
Packit a132db
static int fp_fd;	/* file descriptor for openfc ioctls */
Packit a132db
static void *fp_buf;	/* sending buffer */
Packit a132db
static int fp_debug;
Packit a132db
static char *host;
Packit a132db
static struct port_attributes *port_attrs;
Packit a132db
Packit a132db
struct fp_stats {
Packit a132db
	uint32_t fp_tx_frames;
Packit a132db
	uint32_t fp_rx_frames;
Packit a132db
	uint32_t fp_rx_errors;
Packit a132db
	uint64_t fp_transit_time_us; /* total transit time in microseconds */
Packit a132db
	uint32_t fp_rx_times;        /* valid times on receive */
Packit a132db
};
Packit a132db
static struct fp_stats fp_stats;
Packit a132db
Packit a132db
#define hton24(p, v)				\
Packit a132db
	do {					\
Packit a132db
		p[0] = (((v) >> 16) & 0xFF);	\
Packit a132db
		p[1] = (((v) >> 8) & 0xFF);	\
Packit a132db
		p[2] = ((v) & 0xFF);		\
Packit a132db
	} while (0)
Packit a132db
Packit a132db
#define hton64(p, v)					\
Packit a132db
	do {						\
Packit a132db
		p[0] = (u_char) ((v) >> 56) & 0xFF;	\
Packit a132db
		p[1] = (u_char) ((v) >> 48) & 0xFF;	\
Packit a132db
		p[2] = (u_char) ((v) >> 40) & 0xFF;	\
Packit a132db
		p[3] = (u_char) ((v) >> 32) & 0xFF;	\
Packit a132db
		p[4] = (u_char) ((v) >> 24) & 0xFF;	\
Packit a132db
		p[5] = (u_char) ((v) >> 16) & 0xFF;	\
Packit a132db
		p[6] = (u_char) ((v) >> 8) & 0xFF;	\
Packit a132db
		p[7] = (u_char) (v) & 0xFF;		\
Packit a132db
	} while (0)
Packit a132db
Packit a132db
__attribute__((__format__(__printf__, 2, 3)))
Packit a132db
static void sa_log_func(const char *func, const char *format, ...);
Packit a132db
__attribute__((__format__(__printf__, 3, 4)))
Packit a132db
static void sa_log_err(int, const char *func, const char *format, ...);
Packit a132db
static void sa_log_output(const char *buf);
Packit a132db
Packit a132db
/*
Packit a132db
 * Log message.
Packit a132db
 */
Packit a132db
#define SA_LOG(...)						\
Packit a132db
	do { sa_log_func(__func__, __VA_ARGS__); } while (0)
Packit a132db
Packit a132db
#define SA_LOG_ERR(error, ...)					\
Packit a132db
	do { sa_log_err(error, NULL, __VA_ARGS__); } while (0)
Packit a132db
Packit a132db
/*
Packit a132db
 * Logging exits.
Packit a132db
 */
Packit a132db
#define SA_LOG_EXIT(...)						\
Packit a132db
	do {	sa_log_func(__func__, __VA_ARGS__);			\
Packit a132db
		if (fp_debug)						\
Packit a132db
			sa_log_func(__func__,				\
Packit a132db
				    "Exiting at %s:%d", __FILE__, __LINE__); \
Packit a132db
		exit(1);						\
Packit a132db
	} while (0)
Packit a132db
Packit a132db
#define SA_LOG_ERR_EXIT(error, ...)					\
Packit a132db
	do {	sa_log_func(__func__, __VA_ARGS__);			\
Packit a132db
		if (fp_debug)						\
Packit a132db
			sa_log_err(error, __func__,			\
Packit a132db
				   "Exiting at %s:%d", __FILE__, __LINE__); \
Packit a132db
		else							\
Packit a132db
			sa_log_err(error, NULL, NULL);			\
Packit a132db
		exit(1);						\
Packit a132db
	} while (0)
Packit a132db
Packit a132db
#define SA_LOG_BUF_LEN  200     /* on-stack line buffer size */
Packit a132db
Packit a132db
/*
Packit a132db
 * log with a variable argument list.
Packit a132db
 */
Packit a132db
static void
Packit a132db
sa_log_va(const char *func, const char *format, va_list arg)
Packit a132db
{
Packit a132db
	size_t len;
Packit a132db
	size_t flen;
Packit a132db
	int add_newline;
Packit a132db
	char sa_buf[SA_LOG_BUF_LEN];
Packit a132db
	char *bp;
Packit a132db
Packit a132db
	/*
Packit a132db
	 * If the caller didn't provide a newline at the end, we will.
Packit a132db
	 */
Packit a132db
	len = strlen(format);
Packit a132db
	add_newline = 0;
Packit a132db
	if (!len || format[len - 1] != '\n')
Packit a132db
		add_newline = 1;
Packit a132db
	bp = sa_buf;
Packit a132db
	len = sizeof(sa_buf);
Packit a132db
	if (func) {
Packit a132db
		flen = snprintf(bp, len, "%s: ", func);
Packit a132db
		len -= flen;
Packit a132db
		bp += flen;
Packit a132db
	}
Packit a132db
	flen = vsnprintf(bp, len, format, arg);
Packit a132db
	if (add_newline && flen < len) {
Packit a132db
		bp += flen;
Packit a132db
		*bp++ = '\n';
Packit a132db
		*bp = '\0';
Packit a132db
	}
Packit a132db
	sa_log_output(sa_buf);
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * log with function name.
Packit a132db
 */
Packit a132db
static void
Packit a132db
sa_log_func(const char *func, const char *format, ...)
Packit a132db
{
Packit a132db
	va_list arg;
Packit a132db
Packit a132db
	va_start(arg, format);
Packit a132db
	if (fp_debug)
Packit a132db
		sa_log_va(func, format, arg);
Packit a132db
	else
Packit a132db
		sa_log_va(NULL, format, arg);
Packit a132db
	va_end(arg);
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * log with error number.
Packit a132db
 */
Packit a132db
static void
Packit a132db
sa_log_err(int error, const char *func, const char *format, ...)
Packit a132db
{
Packit a132db
	va_list arg;
Packit a132db
	char buf[SA_LOG_BUF_LEN];
Packit a132db
Packit a132db
	strerror_r(error, buf, sizeof(buf));
Packit a132db
	sa_log_func(func, "errno=%d %s", error, buf);
Packit a132db
	if (format) {
Packit a132db
		va_start(arg, format);
Packit a132db
		sa_log_va(func, format, arg);
Packit a132db
		va_end(arg);
Packit a132db
	}
Packit a132db
}
Packit a132db
Packit a132db
static void
Packit a132db
sa_log_output(const char *buf)
Packit a132db
{
Packit a132db
	fprintf(stderr, "%s", buf);
Packit a132db
	fflush(stderr);
Packit a132db
}
Packit a132db
Packit a132db
static char *
Packit a132db
sa_hex_format(char *buf, size_t buflen,
Packit a132db
	      const unsigned char *data, size_t data_len,
Packit a132db
	      unsigned int group_len, char *inter_group_sep)
Packit a132db
{
Packit a132db
	size_t rlen, tlen;
Packit a132db
	char *bp, *sep;
Packit a132db
	unsigned int i;
Packit a132db
Packit a132db
	rlen = buflen;
Packit a132db
	bp = buf;
Packit a132db
	sep = "";
Packit a132db
	for (i = 0; rlen > 0 && i < data_len; ) {
Packit a132db
		tlen = snprintf(bp, rlen, "%s%2.2x", sep, data[i]);
Packit a132db
		rlen -= tlen;
Packit a132db
		bp += tlen;
Packit a132db
		i++;
Packit a132db
		sep = (i % group_len) ? "" : inter_group_sep;
Packit a132db
	}
Packit a132db
	return buf;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Hex dump buffer to file.
Packit a132db
 */
Packit a132db
static void sa_hex_dump(unsigned char *bp, size_t len, FILE *fp)
Packit a132db
{
Packit a132db
	char lbuf[120];
Packit a132db
	size_t tlen;
Packit a132db
	uint32_t offset = 0;
Packit a132db
Packit a132db
	while (len > 0) {
Packit a132db
		tlen = 16;  /* bytes per line */
Packit a132db
		if (tlen > len)
Packit a132db
			tlen = len;
Packit a132db
		sa_hex_format(lbuf, sizeof(lbuf), bp, tlen, 4, " ");
Packit a132db
		fprintf(fp, "%6x %s\n", offset, lbuf);
Packit a132db
		offset += tlen;
Packit a132db
		len -= tlen;
Packit a132db
		bp += tlen;
Packit a132db
	}
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Convert 48-bit IEEE MAC address to 64-bit FC WWN.
Packit a132db
 */
Packit a132db
fc_wwn_t
Packit a132db
fc_wwn_from_mac(uint64_t mac, uint32_t scheme, uint32_t port)
Packit a132db
{
Packit a132db
	fc_wwn_t wwn;
Packit a132db
Packit a132db
	assert(mac < (1ULL << 48));
Packit a132db
	wwn = mac | ((fc_wwn_t) scheme << 60);
Packit a132db
	switch (scheme) {
Packit a132db
	case 1:
Packit a132db
		assert(port == 0);
Packit a132db
		break;
Packit a132db
	case 2:
Packit a132db
		assert(port < 0xfff);
Packit a132db
		wwn |= (fc_wwn_t) port << 48;
Packit a132db
		break;
Packit a132db
	default:
Packit a132db
		assert(1);
Packit a132db
		break;
Packit a132db
	}
Packit a132db
	return wwn;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Handle WWN/MAC arguments
Packit a132db
 */
Packit a132db
static fc_wwn_t
Packit a132db
fp_parse_wwn(const char *arg, char *msg, uint32_t scheme, uint32_t port)
Packit a132db
{
Packit a132db
	char *endptr;
Packit a132db
	fc_wwn_t wwn;
Packit a132db
	fc_wwn_t oui;
Packit a132db
	struct ether_addr mac;
Packit a132db
Packit a132db
	wwn = strtoull(arg, &endptr, 16);
Packit a132db
	if (*endptr != '\0') {
Packit a132db
		if (ether_aton_r(arg, &mac) == NULL &&
Packit a132db
		    ether_hostton(arg, &mac) != 0) {
Packit a132db
			SA_LOG_EXIT("invalid %s WWN or MAC addr %s", msg, arg);
Packit a132db
		}
Packit a132db
		oui = net48_get((net48_t *)mac.ether_addr_octet);
Packit a132db
		wwn = fc_wwn_from_mac(oui, scheme, port);
Packit a132db
	}
Packit a132db
	return wwn;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Handle options.
Packit a132db
 */
Packit a132db
static void
Packit a132db
fp_options(int argc, char *argv[])
Packit a132db
{
Packit a132db
	int opt;
Packit a132db
	char *endptr;
Packit a132db
	float sec;
Packit a132db
	int targ_spec = 0;
Packit a132db
Packit a132db
	cmdname = basename(argv[0]);
Packit a132db
	if (argc <= 1)
Packit a132db
		fp_usage();
Packit a132db
Packit a132db
	while ((opt = getopt(argc, argv, "?c:fi:h:qs:xF:P:N:")) != -1) {
Packit a132db
		switch (opt) {
Packit a132db
		case 'c':
Packit a132db
			fp_count = (int) strtoul(optarg, &endptr, 10);
Packit a132db
			if (*endptr != '\0')
Packit a132db
				SA_LOG_EXIT("bad count %s\n", optarg);
Packit a132db
			break;
Packit a132db
		case 'f':
Packit a132db
			fp_flood = 1;
Packit a132db
			break;
Packit a132db
		case 'i':
Packit a132db
			if (sscanf(optarg, "%f", &sec) != 1 ||
Packit a132db
			    sec < FP_MIN_INTVL)
Packit a132db
				SA_LOG_EXIT("bad interval %s\n", optarg);
Packit a132db
			fp_interval = sec * 1000;
Packit a132db
			break;
Packit a132db
		case 'h':
Packit a132db
			fp_hba = optarg;
Packit a132db
			break;
Packit a132db
		case 'q':
Packit a132db
			fp_quiet = 1;
Packit a132db
			break;
Packit a132db
		case 's':
Packit a132db
			/* maximum ECHO data allowed is 2108 */
Packit a132db
			fp_len = strtoul(optarg, &endptr, 0);
Packit a132db
			if (*endptr != '\0' || fp_len > FP_LEN_MAX)
Packit a132db
				SA_LOG_EXIT("Bad size %s for FC ELS ECHO "
Packit a132db
					    "data, max %lu bytes allowed.\n",
Packit a132db
					    optarg, FP_LEN_MAX);
Packit a132db
			if (fp_len < FP_LEN_MIN)
Packit a132db
				SA_LOG_EXIT("Bad size %s for FC ELS ECHO "
Packit a132db
					    "data, min %d bytes allowed.\n",
Packit a132db
					    optarg, FP_LEN_MIN);
Packit a132db
			/* add 4 bytes for the ECHO command */
Packit a132db
			fp_len += FP_LEN_ECHO;
Packit a132db
			break;
Packit a132db
		case 'x':
Packit a132db
			fp_hex = 1;
Packit a132db
			break;
Packit a132db
Packit a132db
			/*
Packit a132db
			 * -F specifies the target FC_ID.
Packit a132db
			 */
Packit a132db
		case 'F':
Packit a132db
			fp_did = strtoull(optarg, &endptr, 16);
Packit a132db
			if (*endptr != '\0')
Packit a132db
				SA_LOG_EXIT("bad target FC_ID %s\n", optarg);
Packit a132db
			targ_spec++;
Packit a132db
			break;
Packit a132db
Packit a132db
			/*
Packit a132db
			 * The -P and -N flags take a world-wide name
Packit a132db
			 * in hex, or an ethernet addr, or an etherhost
Packit a132db
			 * entry from /etc/ethers.
Packit a132db
			 */
Packit a132db
		case 'N':
Packit a132db
			fp_node_wwn = fp_parse_wwn(optarg, "Node", 1, 0);
Packit a132db
			targ_spec++;
Packit a132db
			break;
Packit a132db
Packit a132db
		case 'P':
Packit a132db
			fp_port_wwn = fp_parse_wwn(optarg, "Port", 2, 0);
Packit a132db
			targ_spec++;
Packit a132db
			break;
Packit a132db
Packit a132db
		case '?':
Packit a132db
		default:
Packit a132db
			fp_usage();	/* exits */
Packit a132db
			break;
Packit a132db
		}
Packit a132db
	}
Packit a132db
	argc -= optind;
Packit a132db
	argv += optind;
Packit a132db
Packit a132db
	if (fp_hba == NULL)
Packit a132db
		SA_LOG_EXIT("FCoE interface not specified");
Packit a132db
Packit a132db
	if (targ_spec == 0)
Packit a132db
		SA_LOG_EXIT("no target specified");
Packit a132db
Packit a132db
	if (targ_spec > 1)
Packit a132db
		SA_LOG_EXIT("too many targets specified;"
Packit a132db
			    " only one is allowed.");
Packit a132db
Packit a132db
	return;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Lookup specified adapter using HBAAPI.
Packit a132db
 */
Packit a132db
static int
Packit a132db
fp_find_hba(void)
Packit a132db
{
Packit a132db
	struct stat statbuf;
Packit a132db
	char hba_dir[256];
Packit a132db
	fc_wwn_t wwn = 0;
Packit a132db
	struct hba_wwn wwpn;
Packit a132db
	char *endptr;
Packit a132db
	uint32_t fcid;
Packit a132db
	int hba_cnt;
Packit a132db
Packit a132db
	hba_cnt = get_number_of_adapters();
Packit a132db
	if (!hba_cnt)
Packit a132db
		SA_LOG_EXIT("No FCoE interfaces created");
Packit a132db
Packit a132db
	/*
Packit a132db
	 * Parse HBA spec. if there is one.
Packit a132db
	 * These formats are tried:
Packit a132db
	 *    If pass in an interface name, it does not need
Packit a132db
	 *    to be validated here. The interface name can be
Packit a132db
	 *    anything. It will have to be found via HBAAPI
Packit a132db
	 *    library. It fails if not found.
Packit a132db
	 *    host<n> = match the index <n>.
Packit a132db
	 *    mac address xx:xx:xx:xx:xx:xx
Packit a132db
	 *    otherwise, try parsing as a wwn and match that.
Packit a132db
	 */
Packit a132db
	snprintf(hba_dir, sizeof(hba_dir), SYSFS_HBA_DIR "/%s", fp_hba);
Packit a132db
	if (!stat(hba_dir, &statbuf)) {
Packit a132db
		host = get_host_from_netdev(fp_hba);
Packit a132db
	} else if (strstr(fp_hba, "host") == fp_hba) {
Packit a132db
		(void) strtoul(fp_hba + strlen("host"), &endptr, 10);
Packit a132db
		if (*endptr != '\0')
Packit a132db
			SA_LOG_EXIT("invalid hba name %s", fp_hba);
Packit a132db
		host = strdup(fp_hba);
Packit a132db
	} else if (strstr(fp_hba, ":")) {
Packit a132db
		if (strlen(fp_hba) == strlen("xx:yy:aa:bb:cc:dd:ee:ff")) {
Packit a132db
			fc_wwn_t wwn1;
Packit a132db
Packit a132db
			wwn1 = fp_parse_wwn(fp_hba, "HBA", 2, 0);
Packit a132db
			wwn1 &= 0xffff000000000000;
Packit a132db
			wwn = fp_parse_wwn(&fp_hba[6], "HBA", 2, 0);
Packit a132db
			wwn &= 0x0000ffffffffffff;
Packit a132db
			wwn |= wwn1;
Packit a132db
		} else if (strlen(fp_hba) == strlen("aa:bb:cc:dd:ee:ff")) {
Packit a132db
			wwn = fp_parse_wwn(fp_hba, "HBA", 2, 0);
Packit a132db
		} else {
Packit a132db
			SA_LOG_EXIT("invalid WWPN or MAC address %s", fp_hba);
Packit a132db
		}
Packit a132db
		hton64(wwpn.wwn, wwn);
Packit a132db
		host = get_host_by_wwpn(wwpn);
Packit a132db
	} else {
Packit a132db
		wwn = strtoull(fp_hba, &endptr, 16);
Packit a132db
		if (wwn < 0x1000000) {
Packit a132db
			fcid = wwn;
Packit a132db
			host = get_host_by_fcid(fcid);
Packit a132db
		} else {
Packit a132db
			if (*endptr != '\0')
Packit a132db
				SA_LOG_EXIT("unsupported hba name");
Packit a132db
			wwn = fp_parse_wwn(fp_hba, "HBA", 2, 0);
Packit a132db
			hton64(wwpn.wwn, wwn);
Packit a132db
			host = get_host_by_wwpn(wwpn);
Packit a132db
		}
Packit a132db
	}
Packit a132db
Packit a132db
	if (!host) {
Packit a132db
		SA_LOG("FCoE interface %s not found", fp_hba);
Packit a132db
		return 0;
Packit a132db
	}
Packit a132db
Packit a132db
	snprintf(fp_dev, sizeof(fp_dev), "fc_%s", host);
Packit a132db
Packit a132db
	port_attrs = get_port_attribs(host);
Packit a132db
	if (!port_attrs) {
Packit a132db
		free(host);
Packit a132db
		return 0;
Packit a132db
	}
Packit a132db
Packit a132db
	return 1;
Packit a132db
}
Packit a132db
Packit a132db
static void
Packit a132db
fp_report(void)
Packit a132db
{
Packit a132db
	double loss;
Packit a132db
	struct fp_stats *sp = &fp_stats;
Packit a132db
Packit a132db
	loss = 100.0 * (sp->fp_tx_frames - sp->fp_rx_frames) / sp->fp_tx_frames;
Packit a132db
	printf("%d frames sent, %d received %d errors, %.3f%% loss, "
Packit a132db
	       "avg. rt time %.3f ms\n",
Packit a132db
	       sp->fp_tx_frames, sp->fp_rx_frames, sp->fp_rx_errors, loss,
Packit a132db
	       sp->fp_rx_times ?  sp->fp_transit_time_us * 1.0 /
Packit a132db
	       (1000.0 * sp->fp_rx_times) : 0.0);
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Lookup ID from port name or node name.
Packit a132db
 */
Packit a132db
static int
Packit a132db
fp_ns_get_id(uint32_t op, fc_wwn_t wwn, char *response, size_t *resp_len)
Packit a132db
{
Packit a132db
	struct ct_get_id {
Packit a132db
		struct fc_ct_hdr hdr;
Packit a132db
		net64_t	 wwn;
Packit a132db
	} ct;
Packit a132db
	struct fc_bsg_request cdb;
Packit a132db
	struct fc_bsg_reply reply;
Packit a132db
	struct sg_io_v4 sg_io;
Packit a132db
	size_t actual_len;
Packit a132db
	int cmd, rc = 0;
Packit a132db
Packit a132db
	memset((char *)&cdb, 0, sizeof(cdb));
Packit a132db
	memset(&ct, 0, sizeof(ct));
Packit a132db
	ct.hdr.ct_rev = FC_CT_REV;
Packit a132db
	hton24(ct.hdr.ct_in_id, 0xfffffc);
Packit a132db
	ct.hdr.ct_fs_type = FC_FST_DIR;
Packit a132db
	ct.hdr.ct_fs_subtype = FC_NS_SUBTYPE;
Packit a132db
	ct.hdr.ct_options = 0;
Packit a132db
	ct.hdr.ct_cmd = htons(op);
Packit a132db
	ct.hdr.ct_mr_size = *resp_len;
Packit a132db
	net64_put(&ct.wwn, wwn);
Packit a132db
Packit a132db
	cdb.msgcode = FC_BSG_HST_CT;
Packit a132db
	hton24(cdb.rqst_data.h_ct.port_id, 0xfffffc);
Packit a132db
	memcpy(&cdb.rqst_data.h_ct.preamble_word0, &ct.hdr,
Packit a132db
	       3 * sizeof(uint32_t));
Packit a132db
Packit a132db
	sg_io.guard = 'Q';
Packit a132db
	sg_io.protocol = BSG_PROTOCOL_SCSI;
Packit a132db
	sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT;
Packit a132db
	sg_io.request_len = sizeof(cdb);
Packit a132db
	sg_io.request = (uintptr_t)&cdb;
Packit a132db
	sg_io.dout_xfer_len = sizeof(ct);
Packit a132db
	sg_io.dout_xferp = (uintptr_t)&ct;
Packit a132db
	sg_io.din_xfer_len = *resp_len;
Packit a132db
	sg_io.din_xferp = (uintptr_t)response;
Packit a132db
	sg_io.max_response_len = sizeof(reply);
Packit a132db
	sg_io.response = (uintptr_t)&reply;
Packit a132db
	sg_io.timeout = 1000;	/* millisecond */
Packit a132db
	memset(&reply, 0, sizeof(reply));
Packit a132db
	memset(response, 0, *resp_len);
Packit a132db
Packit a132db
	rc = ioctl(fp_fd, SG_IO, &sg_io);
Packit a132db
	if (rc < 0) {
Packit a132db
		if (op == FC_NS_GID_PN)
Packit a132db
			printf("GID_PN error: %s\n", strerror(errno));
Packit a132db
		if (op == FC_NS_GID_NN)
Packit a132db
			printf("GID_NN error: %s\n", strerror(errno));
Packit a132db
		return rc;
Packit a132db
	}
Packit a132db
Packit a132db
	cmd = ((response[8]<<8) | response[9]) & 0xffff;
Packit a132db
	if (cmd != FC_FS_ACC)
Packit a132db
		return -1;
Packit a132db
Packit a132db
	actual_len = reply.reply_payload_rcv_len;
Packit a132db
	if (actual_len < *resp_len)
Packit a132db
		*resp_len = actual_len;
Packit a132db
Packit a132db
	return 0;
Packit a132db
}
Packit a132db
Packit a132db
static int fp_lookup_target(void)
Packit a132db
{
Packit a132db
	char response[32];
Packit a132db
	size_t resp_len;
Packit a132db
	int rc;
Packit a132db
Packit a132db
	if (fp_did != 0)
Packit a132db
		return 0;
Packit a132db
Packit a132db
	if (fp_port_wwn != 0) {
Packit a132db
		resp_len = sizeof(response);
Packit a132db
		memset(&response, 0, sizeof(response));
Packit a132db
		rc = fp_ns_get_id(FC_NS_GID_PN, fp_port_wwn,
Packit a132db
				  response, &resp_len);
Packit a132db
		if (rc == 0) {
Packit a132db
			fp_did = ((response[17] << 16) & 0xff0000) |
Packit a132db
				((response[18] << 8) & 0x00ff00) |
Packit a132db
				(response[19] & 0x0000ff);
Packit a132db
			return 0;
Packit a132db
		}
Packit a132db
		SA_LOG("cannot find fcid of destination @ wwpn 0x%llX",
Packit a132db
		       fp_port_wwn);
Packit a132db
	}
Packit a132db
	if (fp_node_wwn != 0) {
Packit a132db
		resp_len = sizeof(response);
Packit a132db
		memset(&response, 0, sizeof(response));
Packit a132db
		rc = fp_ns_get_id(FC_NS_GID_NN, fp_node_wwn,
Packit a132db
				  response, &resp_len);
Packit a132db
		if (rc == 0) {
Packit a132db
			fp_did = ((response[17] << 16) & 0xff0000) |
Packit a132db
				((response[18] << 8) & 0x00ff00) |
Packit a132db
				(response[19] & 0x0000ff);
Packit a132db
			return 0;
Packit a132db
		}
Packit a132db
		SA_LOG("cannot find fcid of destination @ wwnn 0x%llX",
Packit a132db
		       fp_node_wwn);
Packit a132db
	}
Packit a132db
	return 1;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * fp_get_max_data_len - get the maximum ECHO data size by FCID
Packit a132db
 * @fcid: the fcid
Packit a132db
 *
Packit a132db
 * Returns the maximum allowed ECHO data size. The ECHO data plus the 4 bytes
Packit a132db
 * ECHO ELS command is the maximum payload allowed.
Packit a132db
 */
Packit a132db
static uint32_t fp_get_max_data_len(fc_fid_t fcid)
Packit a132db
{
Packit a132db
	struct port_attributes *rport_attrs;
Packit a132db
	uint32_t dlen = FP_LEN_DEF;
Packit a132db
	uint32_t maxframe_size;
Packit a132db
	char *rport;
Packit a132db
Packit a132db
	/* not found from disovered ports, if it's one of the
Packit a132db
	 * WKA from FC-LS Table 30, use FC_MAX_PAYLOAD */
Packit a132db
	if (FCID_IS_WKA(fcid)) {
Packit a132db
		dlen = FP_LEN_MAX;
Packit a132db
		goto out;
Packit a132db
	}
Packit a132db
Packit a132db
	rport = get_rport_by_fcid(fcid);
Packit a132db
	if (!rport)
Packit a132db
		goto out;
Packit a132db
Packit a132db
	rport_attrs = get_rport_attribs(rport);
Packit a132db
	if (!rport_attrs)
Packit a132db
		goto free_rport;
Packit a132db
Packit a132db
	maxframe_size = strtoul(rport_attrs->maxframe_size, NULL, 16);
Packit a132db
	dlen = maxframe_size - FP_LEN_ECHO;
Packit a132db
Packit a132db
	free(rport_attrs);
Packit a132db
free_rport:
Packit a132db
	free(rport);
Packit a132db
Packit a132db
out:
Packit a132db
	/* returns maximum allowed ECHO data length, excluding the 4
Packit a132db
	 * bytes ECHO command in the payload */
Packit a132db
	return dlen;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * fp_check_data_len - figure out maximum allowed ECHO data size
Packit a132db
 *
Packit a132db
 * From FC-LS 4.2.4, for maximum allowed payload when Login exists
Packit a132db
 *
Packit a132db
 * "If a Login with the destination Nx_Port exists, the ECHO data field size
Packit a132db
 * is limited by 4 less than the smallest Receive Data_Field Size supported by
Packit a132db
 * the destination Nx_Port, the Fabric, and the source Nx_Port for the class
Packit a132db
 * of service being use."
Packit a132db
 *
Packit a132db
 * So, here we figure out the minimum of the source PortMaxFrameSize, the target
Packit a132db
 * PortMaxFraemSize, and the Domain Controller (Fabric) PortMaxFrameSize
Packit a132db
 * (default to be FC_MAX_PAYLOAD). For any FCID that is in FC-LS Table 30 WKA,
Packit a132db
 * use FP_LEN_MAX for ECHO data, i.e., FC_MAX_PAYLOAD - 4.
Packit a132db
 */
Packit a132db
static void fp_check_data_len(void)
Packit a132db
{
Packit a132db
	fc_fid_t sid;
Packit a132db
	uint32_t slen = 0;
Packit a132db
	uint32_t dlen = 0;
Packit a132db
	uint32_t flen = 0;
Packit a132db
	uint32_t plen = FP_LEN_DEF;
Packit a132db
	uint32_t maxframe_size;
Packit a132db
Packit a132db
	/* find out maximum payload supported by the fabric */
Packit a132db
	flen = fp_get_max_data_len(FC_WKA_FABRIC_CONTROLLER);
Packit a132db
	if (!flen) {
Packit a132db
		flen = fp_get_max_data_len(FC_WKA_DIRECTORY_SERVICE);
Packit a132db
		if (!flen)
Packit a132db
			flen = FP_LEN_MAX;
Packit a132db
	}
Packit a132db
Packit a132db
	/* find out maximum payload supported by the target */
Packit a132db
	dlen = fp_get_max_data_len(fp_did);
Packit a132db
	if (!dlen)
Packit a132db
		dlen = FP_LEN_DEF;
Packit a132db
Packit a132db
Packit a132db
	maxframe_size = strtoul(port_attrs->maxframe_size, NULL, 16);
Packit a132db
	sid = strtoul(port_attrs->port_id, NULL, 16);
Packit a132db
Packit a132db
	slen = maxframe_size - FP_LEN_ECHO;
Packit a132db
	plen = MIN(flen, MIN(slen, dlen));
Packit a132db
Packit a132db
	printf("Maximum ECHO data allowed by the Fabric (0x%06x) : %d bytes.\n"
Packit a132db
	       "Maximum ECHO data allowed by the Source (0x%06x) : %d bytes.\n"
Packit a132db
	       "Maximum ECHO data allowed by the Target (0x%06x) : %d bytes.\n"
Packit a132db
	       "Maximum ECHO data requested from user input (-s) : %" PRIu32 " "
Packit a132db
	       "(default %d) bytes.\n",
Packit a132db
	       FC_WKA_FABRIC_CONTROLLER, flen, sid, slen, fp_did, dlen,
Packit a132db
	       (uint32_t)(fp_len - FP_LEN_ECHO), FP_LEN_DEF);
Packit a132db
Packit a132db
	/* fp_len is the total payload, including 4 bytes for ECHO command */
Packit a132db
	fp_len = MIN(fp_len, plen + FP_LEN_ECHO);
Packit a132db
	printf("Actual FC ELS ECHO data size used : %" PRIu32 " bytes.\n"
Packit a132db
	       "Actual FC ELS ECHO payload size used : %d bytes "
Packit a132db
	       "(including %zu bytes ECHO command).\n",
Packit a132db
	       (uint32_t)(fp_len - FP_LEN_ECHO), fp_len, FP_LEN_ECHO);
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * ELS_ECHO request format being used.
Packit a132db
 * Put a sequence number in the payload, followed by the pattern.
Packit a132db
 */
Packit a132db
struct fcping_echo {
Packit a132db
	net8_t      fe_op;              /* opcode */
Packit a132db
	net24_t     fe_resvd;           /* reserved, must be zero */
Packit a132db
	net32_t     fe_seq;             /* sequence number */
Packit a132db
};
Packit a132db
Packit a132db
/*
Packit a132db
 * Setup buffer to be sent.
Packit a132db
 */
Packit a132db
static void
Packit a132db
fp_buf_setup(void)
Packit a132db
{
Packit a132db
	struct fcping_echo *ep;
Packit a132db
	net8_t *pp;
Packit a132db
	int len;
Packit a132db
	int i;
Packit a132db
Packit a132db
	/*
Packit a132db
	 * Alloc extra in case of odd len or shorter than minimum.
Packit a132db
	 */
Packit a132db
	len = fp_len + sizeof(*ep) + sizeof(net32_t);
Packit a132db
	ep = calloc(1, len);
Packit a132db
	if (ep == NULL)
Packit a132db
		SA_LOG_ERR_EXIT(errno, "calloc %d bytes failed", len);
Packit a132db
	ep->fe_op = ELS_ECHO;
Packit a132db
	net32_put(&ep->fe_seq, 1);      /* starting sequence number */
Packit a132db
	i = 0;
Packit a132db
	for (pp = (net8_t *) (ep + 1); pp < (net8_t *) ep + fp_len; pp++)
Packit a132db
		*pp = i++;
Packit a132db
	fp_buf = ep;
Packit a132db
}
Packit a132db
Packit a132db
static unsigned long long
Packit a132db
fp_get_time_usec(void)
Packit a132db
{
Packit a132db
#ifdef _POSIX_TIMERS
Packit a132db
	struct timespec ts;
Packit a132db
	int rc;
Packit a132db
Packit a132db
	rc = clock_gettime(CLOCK_MONOTONIC, &ts);
Packit a132db
	if (rc)
Packit a132db
		SA_LOG_ERR_EXIT(errno, "clock_gettime error");
Packit a132db
	return ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
Packit a132db
#else
Packit a132db
#warning no _POSIX_TIMERS
Packit a132db
	struct timeval ts;
Packit a132db
Packit a132db
	gettimeofday(&ts, NULL);
Packit a132db
	return ts.tv_sec * 1000000ULL + ts.tv_usec;
Packit a132db
#endif /* _POSIX_TIMERS */
Packit a132db
}
Packit a132db
Packit a132db
static int
Packit a132db
send_els_echo(int fp_fd, void *fp_buf, uint32_t fp_len,
Packit a132db
	      unsigned char *resp, uint32_t *resp_len, fc_fid_t fp_did)
Packit a132db
{
Packit a132db
	struct fc_bsg_request cdb;
Packit a132db
	char sense[MAX_SENSE_LEN];
Packit a132db
	struct sg_io_v4 sg_io;
Packit a132db
	int rc;
Packit a132db
Packit a132db
	cdb.msgcode = FC_BSG_HST_ELS_NOLOGIN;
Packit a132db
	cdb.rqst_data.h_els.command_code = ELS_ECHO;
Packit a132db
	hton24(cdb.rqst_data.h_els.port_id, fp_did);
Packit a132db
Packit a132db
	sg_io.guard = 'Q';
Packit a132db
	sg_io.protocol = BSG_PROTOCOL_SCSI;
Packit a132db
	sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT;
Packit a132db
	sg_io.request_len = sizeof(cdb);
Packit a132db
	sg_io.request = (unsigned long)&cdb;
Packit a132db
	sg_io.dout_xfer_len = fp_len;
Packit a132db
	sg_io.dout_xferp = (unsigned long)fp_buf;
Packit a132db
	sg_io.din_xfer_len = *resp_len;
Packit a132db
	sg_io.din_xferp = (unsigned long)resp;
Packit a132db
	sg_io.max_response_len = sizeof(sense);
Packit a132db
	sg_io.response = (unsigned long)sense;
Packit a132db
	sg_io.timeout = 20000;
Packit a132db
	memset(sense, 0, sizeof(sense));
Packit a132db
Packit a132db
	rc = ioctl(fp_fd, SG_IO, &sg_io);
Packit a132db
	if (rc < 0)
Packit a132db
		return 1;
Packit a132db
Packit a132db
	*resp_len = sg_io.din_xfer_len - sg_io.din_resid;
Packit a132db
	return 0;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Send ELS ECHO.
Packit a132db
 */
Packit a132db
static int fp_send_ping(void)
Packit a132db
{
Packit a132db
	struct fp_stats *sp = &fp_stats;
Packit a132db
	struct fcping_echo *ep;
Packit a132db
	int rc;
Packit a132db
	uint32_t resp_len;
Packit a132db
	unsigned char *resp;
Packit a132db
	unsigned long long tx_time;
Packit a132db
	unsigned long long usec;
Packit a132db
	char msg[80];
Packit a132db
	char time_msg[80];
Packit a132db
Packit a132db
	resp_len = fp_len + FP_LEN_PAD; /* for odd-byte padding and then some */
Packit a132db
	resp = calloc(1, resp_len);
Packit a132db
	if (resp == NULL)
Packit a132db
		SA_LOG_EXIT("calloc %d bytes failed", resp_len);
Packit a132db
Packit a132db
	sp->fp_tx_frames++;
Packit a132db
	if (fp_len >= sizeof(*ep)) {
Packit a132db
		ep = (struct fcping_echo *) fp_buf;
Packit a132db
		net32_put(&ep->fe_seq, sp->fp_tx_frames);
Packit a132db
	}
Packit a132db
	tx_time = fp_get_time_usec();
Packit a132db
Packit a132db
	/* send ELS ECHO frame and receive */
Packit a132db
	rc = send_els_echo(fp_fd, fp_buf, fp_len, resp, &resp_len, fp_did);
Packit a132db
	if (rc) {
Packit a132db
		sp->fp_rx_errors++;
Packit a132db
		printf("echo %4d error: %s\n",
Packit a132db
		       sp->fp_tx_frames, strerror(errno));
Packit a132db
	} else {
Packit a132db
		usec = fp_get_time_usec();
Packit a132db
		sp->fp_rx_frames++;
Packit a132db
		ep = (struct fcping_echo *) resp;
Packit a132db
		if (usec < tx_time) {
Packit a132db
			snprintf(time_msg, sizeof(time_msg),
Packit a132db
				 "time unknown now %llx old %llx",
Packit a132db
				 usec, tx_time);
Packit a132db
			usec = 0;	/* as if time went backwards */
Packit a132db
		} else {
Packit a132db
			usec = usec - tx_time;
Packit a132db
			snprintf(time_msg, sizeof(time_msg),
Packit a132db
				 "%6.3f ms", usec / 1000.0);
Packit a132db
			sp->fp_transit_time_us += usec;
Packit a132db
			sp->fp_rx_times++;
Packit a132db
		}
Packit a132db
		if (ep->fe_op == ELS_LS_ACC) {
Packit a132db
			if (memcmp((char *) ep + 1,
Packit a132db
				   (char *) fp_buf + 1, fp_len - 1) == 0)
Packit a132db
				snprintf(msg, sizeof(msg), "accepted");
Packit a132db
			else {
Packit a132db
				sp->fp_rx_errors++;
Packit a132db
				snprintf(msg, sizeof(msg),
Packit a132db
					 "accept data mismatches");
Packit a132db
			}
Packit a132db
		} else if (ep->fe_op == ELS_LS_RJT) {
Packit a132db
			sp->fp_rx_errors++;
Packit a132db
			snprintf(msg, sizeof(msg), "REJECT received");
Packit a132db
		} else {
Packit a132db
			sp->fp_rx_errors++;
Packit a132db
			snprintf(msg, sizeof(msg),
Packit a132db
				 "op %x received", ep->fe_op);
Packit a132db
		}
Packit a132db
		if (fp_quiet == 0)
Packit a132db
			printf("echo %4d %-30s %s\n",
Packit a132db
			       sp->fp_tx_frames, msg, time_msg);
Packit a132db
	}
Packit a132db
	if (fp_hex) {
Packit a132db
		printf("response length %u\n", resp_len);
Packit a132db
		sa_hex_dump(resp, resp_len, stdout);
Packit a132db
		printf("\n");
Packit a132db
	}
Packit a132db
	free(resp);
Packit a132db
	return rc;
Packit a132db
}
Packit a132db
Packit a132db
static void fp_signal_handler(UNUSED int sig)
Packit a132db
{
Packit a132db
	/*
Packit a132db
	 * Allow graceful termination of the
Packit a132db
	 * for loop in fp_start.
Packit a132db
	 */
Packit a132db
	fp_count = 0;
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Main loop.
Packit a132db
 */
Packit a132db
static void fp_start(void)
Packit a132db
{
Packit a132db
	struct sigaction act;
Packit a132db
	int i;
Packit a132db
	int rc;
Packit a132db
Packit a132db
	memset(&act, 0, sizeof(act));
Packit a132db
	act.sa_handler = fp_signal_handler;
Packit a132db
	act.sa_flags = 0;
Packit a132db
Packit a132db
	sigaction(SIGTERM, &act, NULL);		/* Signal 15: kill <pid> */
Packit a132db
	sigaction(SIGQUIT, &act, NULL);		/* Signal 3: Ctrl-\ */
Packit a132db
	sigaction(SIGINT,  &act, NULL);		/* Signal 2: Ctrl-C */
Packit a132db
Packit a132db
	printf("Sending FC ELS ECHO from %s (%s) to 0x%X:\n",
Packit a132db
	       port_attrs->port_id, fp_dev, fp_did);
Packit a132db
Packit a132db
	for (i = 0; fp_count == -1 || i < fp_count; i++) {
Packit a132db
		rc = fp_send_ping();
Packit a132db
		if (rc != 0 && errno == EMSGSIZE)
Packit a132db
			break;
Packit a132db
		if (rc != 0 && errno == ECONNABORTED)
Packit a132db
			break;
Packit a132db
		if (fp_flood == 0)
Packit a132db
			usleep(fp_interval * 1000);
Packit a132db
		if (!fp_count)
Packit a132db
			break;
Packit a132db
	}
Packit a132db
}
Packit a132db
Packit a132db
/*
Packit a132db
 * Main.
Packit a132db
 */
Packit a132db
int main(int argc, char *argv[])
Packit a132db
{
Packit a132db
	char bsg_dev[80];
Packit a132db
	int rc = 1;
Packit a132db
Packit a132db
	fp_options(argc, argv);
Packit a132db
	if (fp_find_hba()) {
Packit a132db
		sprintf(bsg_dev, "/dev/bsg/%s", fp_dev);
Packit a132db
		fp_fd = open(bsg_dev, O_RDWR);
Packit a132db
		if (fp_fd < 0)
Packit a132db
			SA_LOG_ERR_EXIT(errno,
Packit a132db
					"open of %s failed", bsg_dev);
Packit a132db
Packit a132db
		if (!fp_lookup_target()) {
Packit a132db
			fp_check_data_len();
Packit a132db
			fp_buf_setup();
Packit a132db
			fp_start();
Packit a132db
			fp_report();
Packit a132db
			rc = 0;
Packit a132db
		}
Packit a132db
		free(port_attrs);
Packit a132db
		free(host);
Packit a132db
		close(fp_fd);
Packit a132db
	}
Packit a132db
Packit a132db
	return rc;
Packit a132db
}