>-----Original Message----- >From: Fastabend, John R >Sent: Friday, June 05, 2009 10:12 AM >To: Ma, Steve >Cc: [email protected] >Subject: Re: [Open-FCoE] [PATCH] fcoe-utils: fcping implementation via FC >pass-through interface > >Steve Ma wrote: >> This is the implementation of fcping by invoking the FCoE ELS/CT >> pass-through interface in the kernel. fcping is added as one of the >> command tools in fcoe-utils. Pinging is to send an ECHO ELS from >> a local port of an HBA to a remote FCoE destination(e.g. target, >> directory server, etc.). Issue fcping -h to see a summary of the >> command usage. libHBAAPI and libhbalinux libraries are used by >> fcping to find HBA information. >> >> Signed-off-by: Steve Ma <[email protected]> >> --- >> >> Makefile.am | 10 + >> fcping.c | 919 >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 928 insertions(+), 1 deletions(-) >> create mode 100644 fcping.c >> >> diff --git a/Makefile.am b/Makefile.am >> index 5d896bf..6c812d9 100644 >> --- a/Makefile.am >> +++ b/Makefile.am >> @@ -1,5 +1,5 @@ >> ## target programs, to be built and installed in $(prefix)/sbin >> -sbin_PROGRAMS = fcoeadm >> +sbin_PROGRAMS = fcoeadm fcping >> if WITH_DCB >> sbin_PROGRAMS += fcoemon >> endif >> @@ -19,6 +19,14 @@ include/fc_scsi.h include/fc_types.h >include/net_types.h >> fcoeadm_CFLAGS = $(HBAAPI_CFLAGS) >> fcoeadm_LDFLAGS = $(HBAAPI_LIBS) >> >> +## rules for building fcping >> +## only listed sources get packaged, so must list all headers too >> +fcping_SOURCES = fcping.c >> + >> +## fcping uses HBAAPI, so get the right flags for compiling and linking >> +fcping_CFLAGS = $(HBAAPI_CFLAGS) >> +fcping_LDFLAGS = $(HBAAPI_LIBS) -lrt >> + >> ## rules for building fcoemon >> ## only listed sources get packaged, so must list all headers too >> fcoemon_SOURCES = fcoemon_utils.c fcoemon.c fcoemon.h fcoemon_utils.h \ >> diff --git a/fcping.c b/fcping.c >> new file mode 100644 >> index 0000000..cb268ea >> --- /dev/null >> +++ b/fcping.c >> @@ -0,0 +1,919 @@ >> +/* >> + * Copyright(c) 2009 Intel Corporation. All rights reserved. >> + * >> + * This program is free software; you can redistribute it and/or modify >it >> + * under the terms and conditions of the GNU General Public License, >> + * version 2, as published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope it will be useful, but >WITHOUT >> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or >> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License >for >> + * more details. >> + * >> + * You should have received a copy of the GNU General Public License >along with >> + * this program; if not, write to the Free Software Foundation, Inc., >> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. >> + * >> + * Maintained at www.Open-FCoE.org >> + */ >> + >> +/* >> + * FCPing - FC fabric diagnostic. >> + */ >> +#include <stdio.h> >> +#include <stdlib.h> >> +#include <stddef.h> >> +#include <stdarg.h> >> +#include <unistd.h> >> +#include <errno.h> >> +#include <string.h> >> +#include <time.h> >> +#include <fcntl.h> >> +#include <malloc.h> >> +#include <limits.h> >> +#include <signal.h> >> +#include <libgen.h> >> +#include <assert.h> >> +#include <syslog.h> >> +#include <sys/stat.h> >> +#include <sys/param.h> >> +#include <sys/ioctl.h> >> +#include <sys/time.h> >> +#include <scsi/sg.h> >> +#include <net/ethernet.h> >> +#include <netinet/ether.h> >> +#include <hbaapi.h> >> +#include <vendorhbaapi.h> >> +#include <linux/types.h> >> +#include <linux/bsg.h> >> +#include "net_types.h" >> +#include "fc_types.h" >> +#include <scsi/fc/fc_ns.h> >> +#include <scsi/fc/fc_gs.h> >> +#include <scsi/fc/fc_els.h> >> +#include <scsi/scsi_bsg_fc.h> >> + >> +static const char *cmdname; >> + >> +static void >> +fp_usage() >> +{ >> + fprintf(stderr, >> + "Usage: %s [-fqx] -i <interval> -c <count> -h <hba> -s <size> >\\\n" >> + " [ -F <FC-ID> | -P <WWPN> | -N <WWNN>]\n" >> + " flags: \n" >> + " -f: Flood ping\n" >> + " -q: Quiet! just print summary\n" >> + " -x: Hex dump of responses\n" >> + " -i <interval>: Wait <interval> seconds between each ping\n" >> + " -c <count>: Stop after sending <count> pings\n" >> + " -h <hba>: eth<n>, MAC address, WWPN, or FC-ID of the >HBA\n" >> + " -s <size>: Byte-length of ping request payload\n" >> + " -F <FC-ID>: Destination port ID\n" >> + " -P <WWPN>: Destination world-wide port name\n" >> + " -N <WWNN>: Destination world-wide node name\n", >> + cmdname); >> + exit(1); >> +} >> + >> +#define FC_MAX_PAYLOAD 2112U >> +#define MAX_SENSE_LEN 96 /* SCSI_SENSE_BUFFERSIZE */ >> +#define MAX_HBA_COUNT 128 >> +#define FP_LEN_DEF 32 /* default ping payload length */ >> +#define FP_LEN_PAD 32 /* extra length for response */ >> +#define FP_MIN_INTVL 0.001 /* minimum interval in seconds */ >> +#define FP_DEF_INTVL 1.000 /* default sending interval in seconds */ >> + >> +static fc_fid_t fp_did; >> +static fc_wwn_t fp_port_wwn; >> +static fc_wwn_t fp_node_wwn; >> +static int fp_count = -1; /* send indefinitely by default */ >> +static uint32_t fp_len = FP_LEN_DEF; >> +static int fp_flood; /* send as fast as possible */ >> +static uint32_t fp_interval = FP_DEF_INTVL * 1000; /* in milliseconds */ >> +static int fp_quiet; >> +static int fp_hex; >> +static char *fp_hba; /* name of interface to be used */ >> +static int fp_hba_type; >> +#define FP_HBA_FCID_TYPE 1 >> +#define FP_HBA_WWPN_TYPE 2 >> +#define FP_HBA_HOST_TYPE 3 >> +#define FP_HBA_ETH_TYPE 4 >> +static char fp_dev[64]; >> +static int fp_fd; /* file descriptor for openfc ioctls */ >> +static void *fp_buf; /* sending buffer */ >> +static int fp_debug; >> + >> +struct fp_stats { >> + uint32_t fp_tx_frames; >> + uint32_t fp_rx_frames; >> + uint32_t fp_rx_errors; >> + uint64_t fp_transit_time_us; /* total transit time in >microseconds */ >> + uint32_t fp_rx_times; /* valid times on receive */ >> +}; >> +static struct fp_stats fp_stats; >> + >> +#define hton24(p, v) \ >> +do { \ >> + p[0] = (((v) >> 16) & 0xFF); \ >> + p[1] = (((v) >> 8) & 0xFF); \ >> + p[2] = ((v) & 0xFF); \ >> +} while (0) >> + >> +#define hton64(p, v) \ >> +do { \ >> + p[0] = (u_char) ((v) >> 56) & 0xFF; \ >> + p[1] = (u_char) ((v) >> 48) & 0xFF; \ >> + p[2] = (u_char) ((v) >> 40) & 0xFF; \ >> + p[3] = (u_char) ((v) >> 32) & 0xFF; \ >> + p[4] = (u_char) ((v) >> 24) & 0xFF; \ >> + p[5] = (u_char) ((v) >> 16) & 0xFF; \ >> + p[6] = (u_char) ((v) >> 8) & 0xFF; \ >> + p[7] = (u_char) (v) & 0xFF; \ >> +} while (0) >> + >> +static void sa_log_func(const char *func, const char *format, ...); >> +static void sa_log_err(int, const char *func, const char *format, ...); >> +static void sa_log_output(const char *buf); >> + >> +/* >> + * Log message. >> + */ >> +#define SA_LOG(...) \ >> + do { sa_log_func(__func__, __VA_ARGS__); } while (0) >> + >> +#define SA_LOG_ERR(error, ...) \ >> + do { sa_log_err(error, NULL, __VA_ARGS__); } while (0) >> + >> +/* >> + * Logging exits. >> + */ >> +#define SA_LOG_EXIT(...) \ >> + do { sa_log_func(__func__, __VA_ARGS__); \ >> + if (fp_debug) \ >> + sa_log_func(__func__, \ >> + "Exiting at %s:%d", __FILE__, __LINE__); \ >> + exit(1); \ >> + } while (0) >> + >> +#define SA_LOG_ERR_EXIT(error, ...) \ >> + do { sa_log_func(__func__, __VA_ARGS__); \ >> + if (fp_debug) \ >> + sa_log_err(error, __func__, \ >> + "Exiting at %s:%d", __FILE__, __LINE__); \ >> + else \ >> + sa_log_err(error, NULL, NULL); \ >> + exit(1); \ >> + } while (0) >> + >> +#define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */ >> + >> +/* >> + * log with a variable argument list. >> + */ >> +static void >> +sa_log_va(const char *func, const char *format, va_list arg) >> +{ >> + size_t len; >> + size_t flen; >> + int add_newline; >> + char sa_buf[SA_LOG_BUF_LEN]; >> + char *bp; >> + >> + /* >> + * If the caller didn't provide a newline at the end, we will. >> + */ >> + len = strlen(format); >> + add_newline = 0; >> + if (!len || format[len - 1] != '\n') >> + add_newline = 1; >> + bp = sa_buf; >> + len = sizeof(sa_buf); >> + if (func) { >> + flen = snprintf(bp, len, "%s: ", func); >> + len -= flen; >> + bp += flen; >> + } >> + flen = vsnprintf(bp, len, format, arg); >> + if (add_newline && flen < len) { >> + bp += flen; >> + *bp++ = '\n'; >> + *bp = '\0'; >> + } >> + sa_log_output(sa_buf); >> +} >> + >> +/* >> + * log with function name. >> + */ >> +static void >> +sa_log_func(const char *func, const char *format, ...) >> +{ >> + va_list arg; >> + >> + va_start(arg, format); >> + if (fp_debug) >> + sa_log_va(func, format, arg); >> + else >> + sa_log_va(NULL, format, arg); >> + va_end(arg); >> +} >> + >> +/* >> + * log with error number. >> + */ >> +static void >> +sa_log_err(int error, const char *func, const char *format, ...) >> +{ >> + va_list arg; >> + char buf[SA_LOG_BUF_LEN]; >> + >> + sa_log_func(func, "errno=%d %s", error, >> + strerror_r(error, buf, sizeof(buf))); >> + if (format) { >> + va_start(arg, format); >> + sa_log_va(func, format, arg); >> + va_end(arg); >> + } >> +} >> + >> +static void >> +sa_log_output(const char *buf) >> +{ >> + fprintf(stderr, "%s", buf); >> + fflush(stderr); >> +} >> + >> +static char * >> +sa_hex_format(char *buf, size_t buflen, >> + const unsigned char *data, size_t data_len, >> + unsigned int group_len, char *inter_group_sep) >> +{ >> + size_t rlen, tlen; >> + char *bp, *sep; >> + unsigned int i; >> + >> + rlen = buflen; >> + bp = buf; >> + sep = ""; >> + for (i = 0; rlen > 0 && i < data_len; ) { >> + tlen = snprintf(bp, rlen, "%s%2.2x", sep, data[i]); >> + rlen -= tlen; >> + bp += tlen; >> + i++; >> + sep = (i % group_len) ? "" : inter_group_sep; >> + } >> + return buf; >> +} >> + >> +/* >> + * Hex dump buffer to file. >> + */ >> +static void sa_hex_dump(unsigned char *bp, size_t len, FILE *fp) >> +{ >> + char lbuf[120]; >> + size_t tlen; >> + uint32_t offset = 0; >> + >> + while (len > 0) { >> + tlen = 16; /* bytes per line */ >> + if (tlen > len) >> + tlen = len; >> + sa_hex_format(lbuf, sizeof(lbuf), bp, tlen, 4, " "); >> + fprintf(fp, "%6x %s\n", offset, lbuf); >> + offset += tlen; >> + len -= tlen; >> + bp += tlen; >> + } >> +} >> + >> +/* >> + * Convert 48-bit IEEE MAC address to 64-bit FC WWN. >> + */ >> +fc_wwn_t >> +fc_wwn_from_mac(uint64_t mac, uint32_t scheme, uint32_t port) >> +{ >> + fc_wwn_t wwn; >> + >> + assert(mac < (1ULL << 48)); >> + wwn = mac | ((fc_wwn_t) scheme << 60); >> + switch (scheme) { >> + case 1: >> + assert(port == 0); >> + break; >> + case 2: >> + assert(port < 0xfff); >> + wwn |= (fc_wwn_t) port << 48; >> + break; >> + default: >> + assert(1); >> + break; >> + } >> + return wwn; >> +} >> + >> +/* >> + * Handle WWN/MAC arguments >> + */ >> +static fc_wwn_t >> +fp_parse_wwn(const char *arg, char *msg, uint32_t scheme, uint32_t port) >> +{ >> + char *endptr; >> + fc_wwn_t wwn; >> + fc_wwn_t oui; >> + struct ether_addr mac; >> + >> + wwn = strtoull(arg, &endptr, 16); >> + if (*endptr != '\0') { >> + if (ether_aton_r(arg, &mac) == NULL && >> + ether_hostton(arg, &mac) != 0) { >> + SA_LOG_EXIT("invalid %s WWN or MAC addr %s", msg, >arg); >> + } >> + oui = net48_get((net48_t *)mac.ether_addr_octet); >> + wwn = fc_wwn_from_mac(oui, scheme, port); >> + } >> + return wwn; >> +} >> + >> +/* >> + * Handle options. >> + */ >> +static void >> +fp_options(int argc, char *argv[]) >> +{ >> + int opt; >> + char *endptr; >> + float sec; >> + int targ_spec = 0; >> + >> + cmdname = basename(argv[0]); >> + if (argc <= 1) >> + fp_usage(); >> + >> + while ((opt = getopt(argc, argv, "c:fi:h:qs:xF:P:N:")) != -1) { >> + switch (opt) { >> + case 'c': >> + fp_count = (int) strtoul(optarg, &endptr, 10); >> + if (*endptr != '\0') >> + SA_LOG_EXIT("bad count %s\n", optarg); >> + break; >> + case 'f': >> + fp_flood = 1; >> + break; >> + case 'i': >> + if (sscanf(optarg, "%f", &sec) != 1 || >> + sec < FP_MIN_INTVL) >> + SA_LOG_EXIT("bad interval %s\n", optarg); >> + fp_interval = sec * 1000; >> + break; >> + case 'h': >> + fp_hba = optarg; >> + break; >> + case 'q': >> + fp_quiet = 1; >> + break; >> + case 's': >> + fp_len = strtoul(optarg, &endptr, 0); >> + if (*endptr != '\0' || fp_len > FC_MAX_PAYLOAD) >> + SA_LOG_EXIT("bad size %s max %d\n", >> + optarg, FC_MAX_PAYLOAD); >> + if (fp_len < 4) >> + SA_LOG_EXIT("bad size %s min %d\n", >> + optarg, 4); >> + break; >> + case 'x': >> + fp_hex = 1; >> + break; >> + >> + /* >> + * -F specifies the target FC_ID. >> + */ >> + case 'F': >> + fp_did = strtoull(optarg, &endptr, 16); >> + if (*endptr != '\0') >> + SA_LOG_EXIT("bad target FC_ID %s\n", >optarg); >> + targ_spec++; >> + break; >> + >> + /* >> + * The -P and -N flags take a world-wide name in hex, >> + * or an ethernet addr, or an etherhost entry from >/etc/ethers. >> + */ >> + case 'N': >> + fp_node_wwn = fp_parse_wwn(optarg, "Node", 1, 0); >> + targ_spec++; >> + break; >> + >> + case 'P': >> + fp_port_wwn = fp_parse_wwn(optarg, "Port", 2, 0); >> + targ_spec++; >> + break; >> + >> + case '?': >> + default: >> + fp_usage(); /* exits */ >> + break; >> + } >> + } >> + argc -= optind; >> + argv += optind; >> + >> + if (fp_hba == NULL) >> + SA_LOG_EXIT("FCoE interface not specified"); >> + >> + if (targ_spec == 0) >> + SA_LOG_EXIT("no target specified"); >> + >> + if (targ_spec > 1) >> + SA_LOG_EXIT("too many targets specified;" >> + " only one is allowed."); >> + >> + return; >> +} >> + >> +/* >> + * Lookup specified adapter using HBAAPI. >> + */ >> +static int >> +fp_find_hba(void) >> +{ >> + HBA_STATUS retval; >> + HBA_UINT32 hba_cnt; >> + HBA_HANDLE hba_handle = 0; >> + HBA_ADAPTERATTRIBUTES hba_attrs; >> + HBA_PORTATTRIBUTES port_attrs; >> + HBA_UINT32 fcid = 0; >> + char namebuf[1028]; >> + fc_wwn_t wwn = 0; >> + HBA_WWN wwpn; >> + char *endptr; >> + int i, found = 0; >> + >> + /* >> + * Parse HBA spec. if there is one. >> + * These formats are tried: >> + * host<n> = match the index <n>. >> + * eth<n> or some other name - strtoull fails. >> + * Try matching the name. >> + * otherwise, try parsing as a wwn and match that. >> + */ >> + if (strstr(fp_hba, "eth") == fp_hba) { >> + > >This will not work for virtual interfaces such as ethx.y. > >> i = strtoul(fp_hba + 3, &endptr, 10); >> + if (*endptr != '\0') >> + SA_LOG_EXIT("invalid hba name %s", fp_hba); >> + fp_hba_type = FP_HBA_ETH_TYPE; >> + } else if (strstr(fp_hba, "host") == fp_hba) { >> + i = strtoul(fp_hba + 4, &endptr, 10); >> + if (*endptr != '\0') >> + SA_LOG_EXIT("invalid hba name %s", fp_hba); >> + fp_hba_type = FP_HBA_HOST_TYPE; >> + } else if (strstr(fp_hba, ":")) { >> + wwn = fp_parse_wwn(fp_hba, "HBA", 2, 0); >> + hton64(wwpn.wwn, wwn); >> + fp_hba_type = FP_HBA_WWPN_TYPE; >> + } else { >> + wwn = strtoull(fp_hba, &endptr, 16); >> + if (wwn < 0x1000000) { >> + fcid = wwn; >> + fp_hba_type = FP_HBA_FCID_TYPE; >> + } else { >> + if (*endptr != '\0') >> + SA_LOG_EXIT("unsupported hba name"); >> + wwn = fp_parse_wwn(fp_hba, "HBA", 2, 0); >> + hton64(wwpn.wwn, wwn); >> + fp_hba_type = FP_HBA_WWPN_TYPE; >> + } >> + } >> + >> + hba_cnt = HBA_GetNumberOfAdapters(); >> + if (!hba_cnt) >> + SA_LOG_EXIT("No FCoE interfaces created"); >> + >> + for (i = 0; i < hba_cnt; i++) { >> + retval = HBA_GetAdapterName(i, namebuf); >> + if (retval != HBA_STATUS_OK) { >> + SA_LOG("HBA_GetAdapterName" >> + " failed, retval=%d", retval); >> + continue; >> + } >> + >> + hba_handle = HBA_OpenAdapter(namebuf); >> + if (!hba_handle) { >> + SA_LOG("HBA_OpenAdapter failed"); >> + continue; >> + } >> + >> + retval = HBA_GetAdapterAttributes(hba_handle, >&hba_attrs); >> + if (retval != HBA_STATUS_OK) { >> + SA_LOG("HBA_GetAdapterAttributes" >> + " failed, retval=%d", retval); >> + HBA_CloseAdapter(hba_handle); >> + continue; >> + } >> + >> + retval = HBA_GetAdapterPortAttributes( >> + hba_handle, 0, &port_attrs); >> + if (retval != HBA_STATUS_OK) { >> + SA_LOG("HBA_GetAdapterPortAttributes" >> + " failed, retval=%d", retval); >> + HBA_CloseAdapter(hba_handle); >> + continue; >> + } >> + >> + switch (fp_hba_type) { >> + case FP_HBA_FCID_TYPE: >> + if (port_attrs.PortFcId != fcid) { >> + HBA_CloseAdapter(hba_handle); >> + continue; >> + } >> + break; >> + case FP_HBA_WWPN_TYPE: >> + if (memcmp(&port_attrs.PortWWN, &wwpn, >sizeof(wwpn))) { >> + HBA_CloseAdapter(hba_handle); >> + continue; >> + } >> + break; >> + case FP_HBA_HOST_TYPE: >> + if (!strstr(port_attrs.OSDeviceName, fp_hba)) { >> + HBA_CloseAdapter(hba_handle); >> + continue; >> + } >> + break; >> + default: >> + if (!strstr(port_attrs.PortSymbolicName, fp_hba)) >{ >> + HBA_CloseAdapter(hba_handle); >> + continue; >> + } >> + break; >> + } >> + >> + snprintf(fp_dev, sizeof(fp_dev), >> + "fc_%s", port_attrs.OSDeviceName); >> + found = 1; >> + break; >> + } >> + if (!found) >> + SA_LOG("FCoE interface %s not found", fp_hba); >> + >> + return found; >> +} >> + >> +static void >> +fp_report(void) >> +{ >> + double loss; >> + struct fp_stats *sp = &fp_stats; >> + >> + loss = 100.0 * (sp->fp_tx_frames - sp->fp_rx_frames) / sp- >>fp_tx_frames; >> + printf("%d frames sent, %d received %d errors, %.3f%% loss, " >> + "avg. rt time %.3f ms\n", >> + sp->fp_tx_frames, sp->fp_rx_frames, sp->fp_rx_errors, >loss, >> + sp->fp_rx_times ? sp->fp_transit_time_us * 1.0 / >> + (1000.0 * sp->fp_rx_times) : 0.0); >> +} >> + >> +/* >> + * Lookup ID from port name or node name. >> + */ >> +static int >> +fp_ns_get_id(uint32_t op, fc_wwn_t wwn, char *response, size_t >*resp_len) >> +{ >> + struct ct_get_id { >> + struct fc_ct_hdr hdr; >> + net64_t wwn; >> + } ct; >> + struct fc_bsg_request cdb; >> + struct sg_io_v4 sg_io; >> + char sense[MAX_SENSE_LEN]; >> + size_t actual_len; >> + int cmd, rc = 0; >> + >> + memset((char *)&cdb, 0, sizeof(cdb)); >> + memset(&ct, 0, sizeof(ct)); >> + ct.hdr.ct_rev = FC_CT_REV; >> + hton24(ct.hdr.ct_in_id, 0xfffffc); >> + ct.hdr.ct_fs_type = FC_FST_DIR; >> + ct.hdr.ct_fs_subtype = FC_NS_SUBTYPE; >> + ct.hdr.ct_options = 0; >> + ct.hdr.ct_cmd = op; >> + ct.hdr.ct_mr_size = *resp_len; >> + net64_put(&ct.wwn, wwn); >> + >> + cdb.msgcode = FC_BSG_HST_CT; >> + >> + sg_io.guard = 'Q'; >> + sg_io.protocol = BSG_PROTOCOL_SCSI; >> + sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; >> + sg_io.request_len = sizeof(cdb); >> + sg_io.request = (__u64)&cdb; >> + sg_io.dout_xfer_len = sizeof(ct); >> + sg_io.dout_xferp = (__u64)&ct; >> + sg_io.din_xfer_len = *resp_len; >> + sg_io.din_xferp = (__u64)response; >> + sg_io.max_response_len = sizeof(sense); >> + sg_io.response = (__u64)sense; >> + sg_io.timeout = 1000; /* millisecond */ >> + memset(sense, 0, sizeof(sense)); >> + memset(response, 0, sizeof(response)); >> + >> + rc = ioctl(fp_fd, SG_IO, &sg_io); >> + if (rc < 0) { >> + perror("ioctl"); >> + return rc; >> + } >> + >> + cmd = ((response[8]<<8) | response[9]) & 0xffff; >> + if (cmd != FC_FS_ACC) { >> + errno = ENOENT; >> + return -1; >> + } >> + >> + actual_len = (size_t)(sg_io.din_xfer_len - sg_io.din_resid); >> + if (actual_len < *resp_len) >> + *resp_len = actual_len; >> + >> + return 0; >> +} >> + >> +static int >> +fp_lookup_target() >> +{ >> + char response[32]; >> + size_t resp_len; >> + int rc; >> + >> + if (fp_did != 0) >> + return 0; >> + >> + if (fp_port_wwn != 0) { >> + resp_len = sizeof(response); >> + memset(&response, 0, sizeof(response)); >> + rc = fp_ns_get_id(FC_NS_GID_PN, fp_port_wwn, >> + response, &resp_len); >> + if (rc == 0) { >> + fp_did = ((response[17] << 16) & 0xff0000) | >> + ((response[18] << 8) & 0x00ff00) | >> + (response[19] & 0x0000ff); >> + return 0; >> + } >> + SA_LOG("cannot find fcid of destination @ wwpn 0x%llX", >> + fp_port_wwn); >> + } >> + if (fp_node_wwn != 0) { >> + resp_len = sizeof(response); >> + memset(&response, 0, sizeof(response)); >> + rc = fp_ns_get_id(FC_NS_GID_NN, fp_node_wwn, >> + response, &resp_len); >> + if (rc == 0) { >> + fp_did = ((response[17] << 16) & 0xff0000) | >> + ((response[18] << 8) & 0x00ff00) | >> + (response[19] & 0x0000ff); >> + return 0; >> + } >> + SA_LOG("cannot find fcid of destination @ wwnn 0x%llX", >> + fp_node_wwn); >> + } >> + return 1; >> +} >> + >> +/* >> + * ELS_ECHO request format being used. >> + * Put a sequence number in the payload, followed by the pattern. >> + */ >> +struct fcping_echo { >> + net8_t fe_op; /* opcode */ >> + net24_t fe_resvd; /* reserved, must be zero */ >> + net32_t fe_seq; /* sequence number */ >> +}; >> + >> +/* >> + * Setup buffer to be sent. >> + */ >> +static void >> +fp_buf_setup(void) >> +{ >> + struct fcping_echo *ep; >> + net8_t *pp; >> + int len; >> + int i; >> + >> + /* >> + * Alloc extra in case of odd len or shorter than minimum. >> + */ >> + len = fp_len + sizeof(*ep) + sizeof(net32_t); >> + ep = calloc(1, len); >> + if (ep == NULL) >> + SA_LOG_ERR_EXIT(errno, "calloc %d bytes failed", len); >> + ep->fe_op = ELS_ECHO; >> + net32_put(&ep->fe_seq, 1); /* starting sequence number */ >> + i = 0; >> + for (pp = (net8_t *) (ep + 1); pp < (net8_t *) ep + fp_len; pp++) >> + *pp = i++; >> + fp_buf = ep; >> +} >> + >> +static unsigned long long >> +fp_get_time_usec(void) >> +{ >> +#ifdef _POSIX_TIMERS >> + struct timespec ts; >> + int rc; >> + >> + rc = clock_gettime(CLOCK_MONOTONIC, &ts); >> + if (rc) >> + SA_LOG_ERR_EXIT(errno, "clock_gettime error"); >> + return ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; >> +#else >> +#warning no _POSIX_TIMERS >> + struct timeval ts; >> + >> + gettimeofday(&ts, NULL); >> + return ts.tv_sec * 1000000ULL + ts.tv_usec; >> +#endif /* _POSIX_TIMERS */ >> +} >> + >> +static int >> +send_els_echo(int fp_fd, void *fp_buf, uint32_t fp_len, >> + unsigned char *resp, uint32_t *resp_len, fc_fid_t fp_did) >> +{ >> + struct fc_bsg_request cdb; >> + char sense[MAX_SENSE_LEN]; >> + struct sg_io_v4 sg_io; >> + int rc; >> + >> + cdb.msgcode = FC_BSG_HST_ELS_NOLOGIN; >> + cdb.rqst_data.h_els.command_code = ELS_ECHO; >> + hton24(cdb.rqst_data.h_els.port_id, fp_did); >> + >> + sg_io.guard = 'Q'; >> + sg_io.protocol = BSG_PROTOCOL_SCSI; >> + sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; >> + sg_io.request_len = sizeof(cdb); >> + sg_io.request = (__u64)&cdb; >> + sg_io.dout_xfer_len = fp_len; >> + sg_io.dout_xferp = (__u64)fp_buf; >> + sg_io.din_xfer_len = *resp_len; >> + sg_io.din_xferp = (__u64)resp; >> + sg_io.max_response_len = sizeof(sense); >> + sg_io.response = (__u64)sense; >> + sg_io.timeout = 20000; >> + memset(sense, 0, sizeof(sense)); >> + >> + rc = ioctl(fp_fd, SG_IO, &sg_io); >> + if (rc < 0) >> + return 1; >> + >> + *resp_len = sg_io.din_xfer_len - sg_io.din_resid; >> + return 0; >> +} >> + >> +/* >> + * Send ELS ECHO. >> + */ >> +static int fp_send_ping(void) >> +{ >> + struct fp_stats *sp = &fp_stats; >> + struct fcping_echo *ep; >> + int rc; >> + uint32_t resp_len; >> + unsigned char *resp; >> + unsigned long long tx_time; >> + unsigned long long usec; >> + char msg[80]; >> + char time_msg[80]; >> + >> + resp_len = fp_len + FP_LEN_PAD; /* for odd-byte padding and then >some */ >> + resp = calloc(1, resp_len); >> + if (resp == NULL) >> + SA_LOG_EXIT("calloc %d bytes failed", resp_len); >> + >> + sp->fp_tx_frames++; >> + if (fp_len >= sizeof(*ep)) { >> + ep = (struct fcping_echo *) fp_buf; >> + net32_put(&ep->fe_seq, sp->fp_tx_frames); >> + } >> + tx_time = fp_get_time_usec(); >> + >> + /* send ELS ECHO frame and receive */ >> + rc = send_els_echo(fp_fd, fp_buf, fp_len, resp, &resp_len, >fp_did); >> + if (rc) { >> + sp->fp_rx_errors++; >> + printf("echo %4d error: %s\n", >> + sp->fp_tx_frames, strerror(errno)); >> + } else { >> + usec = fp_get_time_usec(); >> + sp->fp_rx_frames++; >> + ep = (struct fcping_echo *) resp; >> + if (usec < tx_time) { >> + snprintf(time_msg, sizeof(time_msg), >> + "time unknown now %llx old %llx", >> + usec, tx_time); >> + usec = 0; /* as if time went backwards */ >> + } else { >> + usec = usec - tx_time; >> + snprintf(time_msg, sizeof(time_msg), >> + "%6.3f ms", usec / 1000.0); >> + sp->fp_transit_time_us += usec; >> + sp->fp_rx_times++; >> + } >> + if (ep->fe_op == ELS_LS_ACC) { >> + if (memcmp((char *) ep + 1, >> + (char *) fp_buf + 1, fp_len - 1) >== 0) >> + snprintf(msg, sizeof(msg), "accepted"); >> + else { >> + sp->fp_rx_errors++; >> + snprintf(msg, sizeof(msg), >> + "accept data mismatches"); >> + } >> + } else if (ep->fe_op == ELS_LS_RJT) { >> + sp->fp_rx_errors++; >> + snprintf(msg, sizeof(msg), "REJECT received"); >> + } else { >> + sp->fp_rx_errors++; >> + snprintf(msg, sizeof(msg), >> + "op %x received", ep->fe_op); >> + } >> + if (fp_quiet == 0) >> + printf("echo %4d %-30s %s\n", >> + sp->fp_tx_frames, msg, time_msg); >> + } >> + if (fp_hex) { >> + printf("response length %u\n", resp_len); >> + sa_hex_dump(resp, resp_len, stdout); >> + printf("\n"); >> + } >> + free(resp); >> + return rc; >> +} >> + >> +static void >> +fp_signal_handler(int sig) >> +{ >> + /* >> + * Allow graceful termination of the >> + * for loop in fp_start. >> + */ >> + fp_count = 0; >> +} >> + >> +/* >> + * Main loop. >> + */ >> +static void fp_start(void) >> +{ >> + struct sigaction act; >> + int i; >> + int rc; >> + >> + memset(&act, 0, sizeof(act)); >> + act.sa_handler = fp_signal_handler; >> + act.sa_flags = 0; >> + >> + sigaction(SIGTERM, &act, NULL); /* Signal 15: kill <pid> >*/ >> + sigaction(SIGQUIT, &act, NULL); /* Signal 3: Ctrl-\ */ >> + sigaction(SIGINT, &act, NULL); /* Signal 2: Ctrl-C */ >> + >> + printf("sending echo to 0x%X\n", fp_did); >> + for (i = 0; fp_count == -1 || i < fp_count; i++) { >> + rc = fp_send_ping(); >> + if (rc != 0 && errno == EMSGSIZE) >> + break; >> + if (fp_flood == 0) >> + usleep(fp_interval * 1000); >> + if (!fp_count) >> + break; >> + } >> +} >> + >> +/* >> + * Main. >> + */ >> +int main(int argc, char *argv[]) >> +{ >> + char bsg_dev[80]; >> + int rc = 1; >> + >> + fp_options(argc, argv); >> + >> + if (HBA_LoadLibrary() != HBA_STATUS_OK) >> + SA_LOG_ERR_EXIT(errno, "HBA_LoadLibrary failed"); >> + >> + if (fp_find_hba()) { >> + sprintf(bsg_dev, "/dev/bsg/%s", fp_dev); >> + fp_fd = open(bsg_dev, O_RDWR); >> + if (fp_fd < 0) >> + SA_LOG_ERR_EXIT(errno, >> + "open of %s failed", bsg_dev); >> + >> + if (!fp_lookup_target()) { >> + fp_buf_setup(); >> + fp_start(); >> + fp_report(); >> + rc = 0; >> + } >> + close(fp_fd); >> + } >> + >> + HBA_FreeLibrary(); >> + return rc; >> +} >> >> _______________________________________________ >> devel mailing list >> [email protected] >> http://www.open-fcoe.org/mailman/listinfo/devel >> >Steve, > >Please fix the stroul above so that it will work for virtual devices >(ethx.y). Currently, this will fail immediately here for virtual devices. > >Thanks, >john.
John, The fcping replies on libhbalinux to find devices. But libhbalinux does not support ethx.y yet. -Steve _______________________________________________ devel mailing list [email protected] http://www.open-fcoe.org/mailman/listinfo/devel
