diff --git a/Makefile.am b/Makefile.am index e5d0442..af34ee1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,8 +12,9 @@ AM_CFLAGS = -DSYSCONFDIR="\"${sysconfdir}\"" ## rules for building fcoeadm ## only listed sources get packaged, so must list all headers too -fcoeadm_SOURCES = fcoeadm_display.c fcoeadm.c fcoeadm.h fcoe_utils.h \ -include/fc_scsi.h include/fc_types.h include/net_types.h fcoe_clif.c fcoe_clif.h +fcoeadm_SOURCES = fcoeadm_display.c fcoeadm.c fcoeadm.h fcoe_utils.c \ +fcoe_utils.h fcoe_utils_version.h include/fc_scsi.h include/fc_types.h \ +include/net_types.h fcoe_clif.h ## fcoeadm uses HBAAPI, so get the right flags for compiling and linking fcoeadm_CFLAGS = $(HBAAPI_CFLAGS) @@ -21,7 +22,7 @@ fcoeadm_LDFLAGS = $(HBAAPI_LIBS) ## rules for building fcping ## only listed sources get packaged, so must list all headers too -fcping_SOURCES = fcping.c +fcping_SOURCES = fcping.c fcoe_utils.c fcoe_utils.h ## fcping uses HBAAPI, so get the right flags for compiling and linking fcping_CFLAGS = $(HBAAPI_CFLAGS) @@ -30,8 +31,8 @@ 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 \ -fcoe_utils.h include/fc_scsi.h include/fc_types.h include/net_types.h \ -fcoe_clif.c fcoe_clif.h +fcoe_utils.c fcoe_utils.h fcoe_utils_version.h include/fc_scsi.h \ +include/fc_types.h include/net_types.h fcoe_clif.h ## fcoemon needs headers from dcbd, get the right include path for them fcoemon_CFLAGS = $(DCBD_CFLAGS) @@ -39,12 +40,12 @@ fcoemon_LDFLAGS = -lrt ## rules for building fipvlan ## only listed sources get packaged, so must list all headers too -fipvlan_SOURCES = fipvlan.c fcoe_utils.h include/fip.h \ +fipvlan_SOURCES = fipvlan.c fcoe_utils_version.h include/fip.h \ log.c include/log.h include/list.h ## install configuration file in $(prefix)/etc/fcoe fcoe_configdir = ${sysconfdir}/fcoe -dist_fcoe_config_DATA = etc/config etc/cfg-ethx +dist_fcoe_config_DATA = etc/cfg-ethx ## man pages for fcoeadm and fcoemon dist_man_MANS = doc/fcoeadm.8 @@ -69,3 +70,7 @@ init_d_SCRIPTS = etc/initd/fcoe dist_noinst_DATA = README COPYING INSTALL fcoe-utils.spec +install-data-hook: + if [ ! -f ${fcoe_configdir}/config ] ; then \ + cp etc/config ${fcoe_configdir}/config; \ + fi diff --git a/QUICKSTART b/QUICKSTART index dffe24d..a1789af 100644 --- a/QUICKSTART +++ b/QUICKSTART @@ -1,7 +1,11 @@ -This document is a quickstart guide for a user connected -to a Fibre Channel Forwarder (FCF) and not a SW target. -It covers the installation of Data Center Bridging (DCB), -the HBA API wrapper library, libhbalinux and fcoe-utils. +This document is a quickstart guide for a user connected to a Fibre Channel +Forwarder (FCF) and not a SW target. It covers the configuration of the kernel +and installation and configuration of Data Center Bridging (DCB), the HBA API +wrapper library, libhbalinux and fcoe-utils. + +This document was written using Fedora 11 as the installed operating system. +The instructions may need adjustments for them to work on other +distributions. ## # Dependencies @@ -11,6 +15,63 @@ git://open-fcoe.org/openfc/hbaapi_build.git git://open-fcoe.org/openfc/libhbalinux.git git://open-fcoe.org/openfc/fcoe-utils.git +## +# Kernel Configuration and Compilation +###################################### + +1) Download kernel source + There are a number of good choices regarding the most appropriate + kernel source for your needs. fcoe-next.git is a repository that may be + unstable, but will have the latest code. Downloading a released kernel + from kernel.org will give you the most stable kernel, but you'll need to + get user space code that matches the kernel version you've chosen. You can + get user space code that matches stable kernels on the Open-FCoE.org + "Downloads" page or you can pull directly from the git repositories using + tags. + +2) Configure the kernel + # make menuconfig + + Select the following: + + Networking Support -> Networking Options + Data Center Bridging + 802.1Q VLAN Support + GVRP (GARP VLAN Registration Protocol) support + + Networking Support -> Networking Options -> QoS and/or fair queuing + Multi Band Priority Queueing (PRIO) + Hardware Multiqueue-aware Multi Band Queuing (MULTIQ) + Elementary classification (BASIC) + Universal 32bit comparisons w/ hashing (U32) + Extended Matches + U32 key + Actions + SKB Editing + + Device Drivers -> SCSI Device Support -> SCSI Low-level drivers + LibFC + LibFCoE + FCoE + + Device Drivers -> Network Device Support -> Ethernet (10000 Mbit) + Intel(R) 10GbE PCI Express adapters support + Data Center Bridging (DCB) Support + + [ Replace with desired driver if not using Intel adapter. ] + + Exit Saving Changes + +3) Compile the kernel + # make && make modules_install && make install + + If you're going to build fcoe-utils, you can run 'make headers_install' + at this stage to skip a later step. + +4) Configure Grub + Change the default kernel so that this new kernel is used when booting + # reboot + ## # DCB @@ -119,13 +180,12 @@ DEPENDENCIES PROCESS 1) Ensure correct header files - - fcping requires certain kernel header files to be exported - or it cannot be compiled. These header files were included - in the 2.6.31 Linux kernel. If you are using a distribution - kernel that is >= 2.6.31 then you shouldn't have to take - this step. If you are building your own kernel or are using - a pre-2.6.31 kernel you will need to take this step to - export the appropriate header files. + - fcping requires certain kernel header files to be exported or it + cannot be compiled. These header files were included in the 2.6.31 Linux + kernel. If you are using a distribution kernel that is >= 2.6.31 then you + shouldn't have to take this step. If you are building your own kernel or + are using a pre-2.6.31 kernel you will need to take this step to export + the appropriate header files. # pushd # make headers_install @@ -139,3 +199,59 @@ PROCESS # rpm --eval "%configure" | sh # make # make install + +## +# Example Configuration +####################### + +This example sets up a VLAN (101) for interface eth3 and configures the +system to automatically connect to storage over this interface. + +1) Create a VLAN + # cd /etc/sysconfig/network-scripts/ + # cp ifcfg-eth3 ifcfg-eth3.101 + Edit ifcfg-eth3.101 so the file has the following settings, + + DEVICE=eth3.101 + VLAN=yes + ONBOOT=yes + +2) Congigure fcoe for the VLAN + # cd /etc/fcoe/ + # cp cfg-ethx cfg-eth3.101 + +3) Start dcbd and configure the VLAN interface + # /etc/init.d/dcbd start + # dcbtool sc eth3 dcb on + # dcbtool sc eth3 pfc e:1 + # dcbtool sc eth3 app:fcoe e:1 + + As a convenience there is a script that will confirm if DCB has been + configured correctly for FCoE. The script is run as follows, + + /debug/dcbcheck.sh eth3 + (note: this is on the root device, not the VLAN) + + Follow the suggestions and repeatedly run the script until it states that + DCB is configured correctly. + +4) Start fcoe + # /etc/init.d/fcoe start + After a few moments your storage should apear (assuming everything is + configured correctly on the fabric) + +5) Setup dcbd and fcoe to start when booting + # chkconfig dcbd on + # chkconfig fcoe on + + +## +# Reporting Errors +################## + +Most steps cannot be skipped. Resolve issues before moving forward. + +Please run '/debug/fcoedump.sh eth3.101 2>&1 > dump.out' +and provide the dump.out file with the bug report. Defects can be filed +against the distribution used, reported to the Ethernet vendor of the +card in use, or mailed to devel@open-fcoe.org. diff --git a/configure.ac b/configure.ac index 6d764e0..60817e6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([fcoe-utils], [1.0.10], [devel@open-fcoe.org]) +AC_INIT([fcoe-utils], [1.0.11], [devel@open-fcoe.org]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_PROG_CC @@ -19,6 +19,6 @@ AS_IF([test "X$with_dcb" != Xno], [PKG_CHECK_MODULES([DCBD], [dcbd]) AC_SUBST([DCBD_CFLAGS])]) -AC_CONFIG_FILES([Makefile fcoe-utils.spec fcoe_utils.h]) +AC_CONFIG_FILES([Makefile fcoe-utils.spec fcoe_utils_version.h]) AC_OUTPUT diff --git a/contrib/fcc.sh b/contrib/fcc.sh old mode 100644 new mode 100755 index 053e3bd..46a8345 --- a/contrib/fcc.sh +++ b/contrib/fcc.sh @@ -19,7 +19,7 @@ # # Please send comments and changes to jeykholt at cisco dot com -VERSION="fcc v1.0.2 10/07/2009" +VERSION="fcc v1.0.3 02/19/2010" fcoe_dir=/sys/module/fcoe fdir=/sys/class/fc_host @@ -41,6 +41,7 @@ cmd: luns Show LUN list and status stats Show HBA statistics reset Reset the HBA + scan Scan the HBA version Show version USAGE } @@ -366,22 +367,33 @@ fcoe_ctl() { fc_host_ctl() { local hba=$1 + local host=$1 local cmd=$2 - local value=$3 + local value local file local dir - dir=$fdir/$hba + dir=$fdir/$host if [ ! -d "$dir" ] then - dir=$fdir/`hba_name $hba` + host=`hba_name $hba` + dir=$fdir/$host if [ $? != 0 ] then echo "$cmdname: hba $hba not found" >&2 exit 1 fi fi - file=$dir/$cmd + + case "$cmd" in + reset) + file=$dir/issue_lip + value=1 + ;; + scan) + file=$dir/device/scsi_host/$host/scan + value="- - -" + esac if [ -w "$file" ] then @@ -478,16 +490,15 @@ case "$cmd" in realname) hba_name $hba ;; - reset) + reset | scan) if [ "$hba_spec" != y ] then - echo "$cmdname: reset requires hba name" >&2 + echo "$cmdname: $cmd requires hba name" >&2 exit 2 fi for hba in $hbas do - (fc_host_ctl $hba issue_lip 1 && - echo "reset $hba") || break + fc_host_ctl $hba $cmd || break done ;; version) diff --git a/contrib/sysfs_edd.sh b/contrib/sysfs_edd.sh new file mode 100755 index 0000000..1f14f1b --- /dev/null +++ b/contrib/sysfs_edd.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# Script to read EDD information from sysfs and +# echo the FCoE interface name and target info. +# This is a work in progress and will be enhanced +# with more options as we progress further. +# +# Author: Supreeth Venkataraman +# Intel Corporation +# +# Usage: edd.sh -i for getting the interface name. +# edd.sh -t for getting target information. +# edd.sh -h for displaying help information. + +DisplayHelp(){ + echo "Usage: sysfs_edd.sh -i for getting the interface name." + echo " sysfs_edd.sh -t for getting target information." + echo " sysfs_edd.sh -h for displaying help options." + exit; +} + +GetTargetInfo(){ + if [ -e /sys/firmware/edd/int13_dev80/interface ]; then + cd -P /sys/firmware/edd/int13_dev80 + else + echo "Target information not found in EDD!"; exit; + fi + + line=`cat interface`; + echo $line; +} + + +GetFcoeIfName(){ + if [ -e /sys/firmware/edd/int13_dev80/pci_dev ]; then + cd -P /sys/firmware/edd/int13_dev80/pci_dev + else + echo "Disk 80 not found in EDD!"; exit; + fi + + for if in net/eth* ; + do [ -d $if ] && echo ${if##*/}; done +} + +while getopts ith OptionName; do + case "$OptionName" in + t) GetTargetInfo;; + i) GetFcoeIfName;; + h) DisplayHelp;; + *) echo "Invalid Option. Use -h option for help.";; + esac +done diff --git a/doc/fcoeadm.8 b/doc/fcoeadm.8 index e8f477d..916f263 100644 --- a/doc/fcoeadm.8 +++ b/doc/fcoeadm.8 @@ -12,9 +12,9 @@ .P \fBfcoeadm\fR [\fB\-t\fR|\fB\-\-target\fR] [\fI\fR] .P -\fBfcoeadm\fR [\fB\-l\fR|\fB\-\-lun\fR] [\fI\fR [\fI\fR]] +\fBfcoeadm\fR [\fB\-l\fR|\fB\-\-lun\fR] [\fI\fR] .P -\fBfcoeadm\fR [\fB\-s\fR|\fB\-\-stats\fR] [\fI\fR [\fB\-n\fR \fI\fR]] +\fBfcoeadm\fR [\fB\-s\fR|\fB\-\-stats\fR \fI\fR [\fI\fR]] .P \fBfcoeadm\fR [\fB\-v\fR|\fB\-\-version\fR] .P @@ -44,21 +44,21 @@ Destroys an FCoE instance based on the given \fI\fR. Resets the fc_host associated with the FCoE interface given by \fI\fR. .TP \fB\-i\fR, \fB\-\-interface\fR \fI\fR -Show the information of the FCoE instances created at \fI\fR. +Show the information of the FCoE instance created at \fI\fR. If \fI\fR is not specified the command will show the information of all the FCoE instances created on the system. .TP \fB\-t\fR, \fB\-\-target\fR \fI\fR -Show the information of all the discovered targets from the FCoE instances created +Show the information of all the discovered targets from the FCoE instance created at \fI\fR. If \fI\fR is not specified the command will show the information of all the discovered targets from all the FCoE instances created. .TP -\fB\-l\fR, \fB\-\-lun\fR \fI\fR \fI\fR -Show the detailed information of a specific LUN with \fI\fR at the target -with port id \fI\fR. port id is also known as FC\-ID. If \fI\fR -is not specified, all the LUNs associated with the target will be shown. +\fB\-l\fR, \fB\-\-lun\fR \fI\fR +Show the information of all the discovered LUNs from the FCoE instance created +at \fI\fR. If \fI\fR is not specified the command will +show the information of all the discovered LUNs from all the FCoE instances created. .TP -\fB\-s\fR, \fB\-\-stats\fR \fI\fR \fB\-n\fR \fI\fR +\fB\-s\fR, \fB\-\-stats\fR \fI\fR \fI\fR Show the statistics (including FC4 statistics) of the FCoE instances created at \fI\fR. The information will be display in one line on the screen per given time interval. \fI\fR should be specified in whole intergers greater than 0. It specifies the time interval in the unit of second. @@ -104,37 +104,22 @@ created. A brief listing of discovered LUNs are listed after each target they ar .IP $ \fBfcoeadm\fR \-t eth3 .P -Show the detailed information of all the LUNs associated with a specific target. -The target is identified by its port id (aka FC\-ID) 0xD700EF. -.IP -$ \fBfcoeadm\fR \-l 0xD700EF -.P -.IP -$ \fBfcoeadm\fR \-l D700EF -.P +Show the detailed information of all the LUNs discovered on all FCoE connections. .IP -$ \fBfcoeadm\fR \-l 0xd700ef +$ \fBfcoeadm\fR \-l .P +Show the detailed information of all the LUNs associated with a specific interface. .IP -$ \fBfcoeadm\fR \-l d700ef -.P -Show the detailed information of a LUN associated with a specific target. -The target is identified by its port id (aka FC\-ID) 0xD700EF and the LUN -is identified by its LUN id. -.IP -$ \fBfcoeadm\fR \-l 0xD700EF 1 +$ \fBfcoeadm\fR \-l eth3.101 .P Show the statistics information of a specific port eth3 having FCoE instances created. The statistics are displayed one line per time interval. The default interval is one -second if \-n option is not specified. +second if an interval is not specified. .IP $ \fBfcoeadm\fR \-s eth3 .P .IP -$ \fBfcoeadm\fR \-s eth3 \-n 3 -.P -.IP -$ \fBfcoeadm\fR \-s eth3 \-n3 +$ \fBfcoeadm\fR \-s eth3 3 .SH "REPORTING BUGS" If you have identified a defect please either file a bug or engage the development mailing list at diff --git a/etc/initd/initd.fedora b/etc/initd/initd.fedora index edc0f87..ef62bdd 100755 --- a/etc/initd/initd.fedora +++ b/etc/initd/initd.fedora @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright(c) 2009 Intel Corporation. All rights reserved. +# Copyright(c) 2010 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, @@ -23,7 +23,7 @@ # Required-Stop: # Default-Start: 3 5 # Default-Stop: 3 5 -# Description: Open-FCoE SAN Setup +# Description: Open-FCoE Initiator ### END INIT INFO CONFIG_DIR=/etc/fcoe @@ -31,70 +31,21 @@ PID_FILE="/var/run/fcoemon.pid" LOG_FILE="/var/log/fcoemon.log" FCOEMON=/usr/sbin/fcoemon FCOEADM=/usr/sbin/fcoeadm -DCBD=dcbd -LOGGER="echo" FCOEMON_OPTS= . /etc/init.d/functions - -varify_yesno_values() -{ - value=$1 - - case $value in - "yes" | "YES" ) return 1 ;; - "no" | "NO" ) return 2 ;; - *) return 0 ;; - esac -} - -verify_configuration() -{ - . $CONFIG_DIR/config - varify_yesno_values $USE_SYSLOG - if [ $? -eq 0 ]; then - echo "Invalid USE_SYSLOG in $CONFIG_DIR/config" - return 1 - fi - varify_yesno_values $DEBUG - if [ $? -eq 0 ]; then - echo "Invalid DEBUG in $CONFIG_DIR/config" - return 1 - fi - - for ifcfg_file in `ls $CONFIG_DIR/cfg-eth*` - do - . $ifcfg_file - varify_yesno_values $FCOE_ENABLE - if [ $? -eq 0 ]; then - echo "Invalid FCOE_ENABLE in $ifcfg_file" - return 1 - fi - varify_yesno_values $DCB_REQUIRED - if [ $? -eq 0 ]; then - echo "Invalid DCB_REQUIRED in $ifcfg_file" - return 1 - fi - done - return 0 -} - -verify_configuration -if [ $? -ne 0 ]; then - failure -fi +. $CONFIG_DIR/config if [ "$USE_SYSLOG" = "yes" ] || [ "$USE_SYSLOG" = "YES" ]; then - LOGGER="logger -t fcoe" FCOEMON_OPTS+=" --syslog" fi if [ "$DEBUG" = "yes" ] || [ "$DEBUG" = "YES" ]; then - FCOEMON_OPTS+=" --debug" + FCOEMON_OPTS+=" --debug" fi test -x $FCOEADM || { - $LOGGER "$FCOEADM not installed"; + echo "$FCOEADM not installed"; if [ "$1" = "stop" ]; then exit 0; else failure @@ -102,41 +53,38 @@ test -x $FCOEADM || { } test -x $FCOEMON || { - $LOGGER "$FCOEMON not installed"; + echo "$FCOEMON not installed"; if [ "$1" = "stop" ]; then exit 0; else failure fi } -service_start() +start() { - pidof $FCOEMON - if [ $? -eq 0 ]; then - $LOGGER "Warning: daemon already running." - return - fi - - rm -f /var/run/fcoemon.* + echo -n $"Starting FCoE initiator service: " modprobe -q libfc modprobe -q fcoe daemon --pidfile ${PID_FILE} ${FCOEMON} ${FCOEMON_OPTS} - return + echo } -service_stop() +stop() { - pidof $FCOEMON - [ $? -eq 0 ] && kill -TERM `pidof $FCOEMON` + echo -n $"Stopping FCoE initiator service: " + + killproc $FCOEMON rm -f /var/run/fcoemon.* rm -f /tmp/fcoemon.dcbd.* + + echo } -service_status() +status() { pidof $FCOEMON if [ $? -eq 0 ]; then @@ -144,56 +92,48 @@ service_status() else echo "$FCOEMON -- UNUSED" fi - IF_LIST=`$FCOEADM -i 2>&1 | \ - awk '/Symbolic Name:/{print $6}' | \ - sort | awk '{printf("%s ", $1)}'` - if [ -z "$IF_LIST" ]; then + + interfaces=`$FCOEADM -i 2>&1 | \ + awk '/Symbolic Name:/{print $6}' | \ + sort | awk '{printf("%s ", $1)}'` + + if [ -z "$interfaces" ]; then echo "No interfaces created." else - echo "Created interfaces: $IF_LIST" + echo "Created interfaces: $interfaces" fi } case "$1" in start) - $LOGGER "Service starting up" - service_start + start ;; + stop) - $LOGGER "Service shutting down" - service_stop + stop ;; - try-restart|condrestart) - if test "$1" = "condrestart"; then - $LOGGER "${attn} Use try-restart ${done}(LSB)${attn} " \ - "rather than condrestart ${warn}(RH)${norm}" - fi - $0 status - if test $? = 0; then - $0 restart - else - failure - fi - ;; restart) - $0 stop - $0 start - + stop + start ;; - force-reload) - $0 try-restart + force-reload) + echo "force-reload not yet implemented" + failure ;; + reload) - $LOGGER "Service reloading" + echo "reload not yet implemented" failure ;; + status) - service_status + status ;; + *) - echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" + echo "Usage: $0 {start|stop|status|restart}" exit 1 ;; esac diff --git a/etc/initd/initd.suse b/etc/initd/initd.suse index 7fef7f2..659b3ad 100755 --- a/etc/initd/initd.suse +++ b/etc/initd/initd.suse @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright(c) 2009 Intel Corporation. All rights reserved. +# Copyright(c) 2010 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, @@ -36,7 +36,7 @@ # Required-Stop: $network $remote_fs # Default-Start: 3 5 # Default-Stop: 3 5 -# Description: Open-FCoE SAN Setup +# Description: Open-FCoE Initiator ### END INIT INFO CONFIG_DIR=/etc/fcoe @@ -45,73 +45,14 @@ LOG_FILE="/var/log/fcoemon.log" FCOEMON=/usr/sbin/fcoemon FCOEADM=/usr/sbin/fcoeadm DCBD=dcbd -LOGGER="echo" FCOEMON_OPTS= . /etc/rc.status rc_reset -test -r $CONFIG_DIR/config || { - $LOGGER "$CONFIG_DIR/config not installed"; - if [ "$1" = "stop" ]; then exit 0; - else - rc_failed - rc_status -v - rc_exit - fi -} - -varify_yesno_values() -{ - value=$1 - - case $value in - "yes" | "YES" ) return 1 ;; - "no" | "NO" ) return 2 ;; - *) return 0 ;; - esac -} - -verify_configuration() -{ - . $CONFIG_DIR/config - varify_yesno_values $USE_SYSLOG - if [ $? -eq 0 ]; then - echo "Invalid USE_SYSLOG in $CONFIG_DIR/config" - return 1 - fi - varify_yesno_values $DEBUG - if [ $? -eq 0 ]; then - echo "Invalid DEBUG in $CONFIG_DIR/config" - return 1 - fi - - for ifcfg_file in `ls $CONFIG_DIR/cfg-eth*` - do - . $ifcfg_file - varify_yesno_values $FCOE_ENABLE - if [ $? -eq 0 ]; then - echo "Invalid FCOE_ENABLE in $ifcfg_file" - return 1 - fi - varify_yesno_values $DCB_REQUIRED - if [ $? -eq 0 ]; then - echo "Invalid DCB_REQUIRED in $ifcfg_file" - return 1 - fi - done - return 0 -} - -verify_configuration -if [ $? -ne 0 ]; then - rc_failed - rc_status -v - rc_exit -fi +. $CONFIG_DIR/config if [ "$USE_SYSLOG" = "yes" ] || [ "$USE_SYSLOG" = "YES" ]; then - LOGGER="logger -t fcoe" FCOEMON_OPTS+=" --syslog" fi @@ -120,7 +61,7 @@ if [ "$DEBUG" = "yes" ] || [ "$DEBUG" = "YES" ]; then fi test -x $FCOEADM || { - $LOGGER "$FCOEADM not installed"; + echo "$FCOEADM not installed"; if [ "$1" = "stop" ]; then exit 0; else rc_failed @@ -130,7 +71,7 @@ test -x $FCOEADM || { } test -x $FCOEMON || { - $LOGGER "$FCOEMON not installed"; + echo "$FCOEMON not installed"; if [ "$1" = "stop" ]; then exit 0; else rc_failed @@ -144,113 +85,78 @@ startup_fcoe_modules() modprobe fcoe > /dev/null 2>&1 } -validate_link_flow_control() +start() { - ifname=$1 - - retry_count=1 - while true - do - TX_STATUS=`ethtool -a $ifname 2>&1 | awk '/TX:/{print $2}'` - RX_STATUS=`ethtool -a $ifname 2>&1 | awk '/RX:/{print $2}'` - - if [ "$TX_STATUS" = "on" ] && [ "$RX_STATUS" = "on" ]; then - return 0 - fi - - ethtool -A $ifname rx on tx on - [ $retry_count -eq 0 ] && return 0 - retry_count=$(($retry_count-1)) - usleep 500000 - done - $LOGGER "Warning: Failed to bring up link flow control of $ifname." - return 1 -} - -service_start() -{ - checkproc ${FCOEMON} - if [ $? -eq 0 ]; then - $LOGGER "Warning: daemon already running." - return - fi - rm -f /var/run/fcoemon.* + echo -n $"Starting FCoE initiator service: " startup_fcoe_modules startproc -l ${LOG_FILE} -p ${PID_FILE} ${FCOEMON} ${FCOEMON_OPTS} rc_status -v - return + + echo } -service_stop() +stop() { - checkproc $FCOEMON - [ $? -eq 0 ] && killproc -TERM $FCOEMON + echo -n $"Stopping FCoE initiator service: " + + killproc -TERM $FCOEMON rm -f /var/run/fcoemon.* rm -f /tmp/fcoemon.dcbd.* rc_status -v + + echo } -service_status() +status() { echo -n "Checking status for fcoe service " checkproc -p ${PID_FILE} ${FCOEMON} rc_status -v - IF_LIST=`$FCOEADM -i 2>&1 | \ - awk '/Symbolic Name:/{print $6}' | \ - sort | awk '{printf("%s ", $1)}'` - if [ -z "$IF_LIST" ]; then + interfaces=`$FCOEADM -i 2>&1 | \ + awk '/Symbolic Name:/{print $6}' | \ + sort | awk '{printf("%s ", $1)}'` + if [ -z "$interfaces" ]; then echo "No interfaces created." else - echo "Created interfaces: $IF_LIST" + echo "Created interfaces: $interfaces" fi } case "$1" in start) - $LOGGER "Service starting up" - service_start + start ;; + stop) - $LOGGER "Service shutting down" - service_stop - ;; - try-restart|condrestart) - if test "$1" = "condrestart"; then - $LOGGER "${attn} Use try-restart ${done}(LSB)${attn} " \ - "rather than condrestart ${warn}(RH)${norm}" - fi - $0 status - if test $? = 0; then - $0 restart - else - rc_reset # Not running is not a failure. - fi - rc_status + stop ;; + restart) - $0 stop - $0 start + stop + start rc_status ;; + force-reload) - $0 try-restart - rc_status + echo "force-reload not yet implemented" ;; + reload) - $LOGGER "Service reloading" + echo "reload not yet implemented" rc_failed 3 - rc_status -v ;; + status) - service_status + status ;; + *) - echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" + echo "Usage: $0 {start|stop|status|restart}" exit 1 ;; esac diff --git a/fcoe_clif.c b/fcoe_clif.c deleted file mode 100644 index 3f33ba8..0000000 --- a/fcoe_clif.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include "fcoe_clif.h" - -static char *fcoeclif_read(const char *path) -{ - FILE *fp; - char *buf; - int size = 512; - - buf = malloc(size); - if (!buf) - return NULL; - memset(buf, 0, size); - - fp = fopen(path, "r"); - if (fp) { - if (fgets(buf, size, fp)) { - fclose(fp); - return buf; - } - } - fclose(fp); - free(buf); - return NULL; -} - -static int fcoeclif_check_fchost(const char *ifname, const char *dname) -{ - char *buf; - char path[512]; - - if (dname[0] == '.') - return -EINVAL; - - sprintf(path, "%s/%s/symbolic_name", SYSFS_FCHOST, dname); - buf = fcoeclif_read(path); - if (!buf) - return -EINVAL; - - if (!strstr(buf, ifname)) { - free(buf); - return -EINVAL; - } - free(buf); - return 0; -} - -static int fcoeclif_find_fchost(char *ifname, char *fchost, int len) -{ - int n, dname_len; - int found = 0; - struct dirent **namelist; - - memset(fchost, 0, len); - n = scandir(SYSFS_FCHOST, &namelist, 0, alphasort); - if (n > 0) { - while (n--) { - /* check symbolic name */ - if (!fcoeclif_check_fchost(ifname, - namelist[n]->d_name)) { - dname_len = strnlen(namelist[n]->d_name, len); - if (dname_len != len) { - /* - * This assumes that d_name is always - * NULL terminated. - */ - strncpy(fchost, namelist[n]->d_name, - dname_len + 1); - found = 1; - } else { - fprintf(stderr, "scsi_host (%s) is " - "too large for a buffer that " - "is only %d bytes large\n", - namelist[n]->d_name, dname_len); - free(namelist[n]); - } - } - free(namelist[n]); - } - free(namelist); - } - - return found; -} - -/* - * Validate an existing instance for an FC interface - */ -int fcoeclif_validate_interface(char *ifname, char *fchost, int len) -{ - if ((!ifname) || (!fchost) || (len <= 0)) - return -EINVAL; - - if (!fcoeclif_find_fchost(ifname, fchost, len)) { - fprintf(stderr, "No fc_host found for %s\n", ifname); - return -EINVAL; - } - - return 0; -} - - -/* - * Open and close to check if directory exists - */ -int fcoeclif_checkdir(char *dir) -{ - DIR *d = NULL; - - if (!dir) - return -EINVAL; - /* check if we have sysfs */ - d = opendir(dir); - if (!d) - return -EINVAL; - closedir(d); - return 0; -} diff --git a/fcoe_clif.h b/fcoe_clif.h index 4ff8afe..84b6828 100644 --- a/fcoe_clif.h +++ b/fcoe_clif.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2010 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, @@ -20,15 +20,21 @@ #ifndef _FCOE_CLIF_H_ #define _FCOE_CLIF_H_ -#define SYSFS_MOUNT "/sys" -#define SYSFS_NET SYSFS_MOUNT "/class/net" -#define SYSFS_FCHOST SYSFS_MOUNT "/class/fc_host" -#define SYSFS_FCOE SYSFS_MOUNT "/module/fcoe/parameters" +/* + * A DCB file is incorrectly including linux/if.h which is redefining + * IFF_UP. This makes it so we cannot include net/if.h. We have to + * redefine IFNAMSIZ to work around this until DCB is corrected. + +*/ + #define FCM_SRV_DIR "/var/run/fcm" #define CLIF_IFNAME "fcm_clif" -#define FCHOSTBUFLEN 64 +#define CLIF_SOCK_FILE FCM_SRV_DIR "/" CLIF_IFNAME + +#define CLIF_PID_FILE _PATH_VARRUN "fcoemon.pid" + +#define CLIF_CMD_RESPONSE_TIMEOUT 5 #define MAX_MSGBUF 512 -#define CLIF_PID_FILE _PATH_VARRUN "fcoemon.pid" enum clif_status { CLI_SUCCESS = 0, @@ -36,20 +42,31 @@ enum clif_status { CLI_NO_ACTION }; -enum { - FCOE_CREATE_CMD = 1, - FCOE_DESTROY_CMD, - FCOE_RESET_CMD, +enum clif_action { + CLIF_NONE = 0, + CLIF_CREATE_CMD, + CLIF_DESTROY_CMD, + CLIF_RESET_CMD, + CLIF_SCAN_CMD +}; + +/** + * struct clif - Internal structure for client interface library + * + * This structure is used by fcoeadm client interface to store internal data. + */ +struct clif_sock_info { + int socket_fd; + struct sockaddr_un local; + struct sockaddr_un dest; }; /* * Description of fcoemon and fcoeadm socket data structure interface */ struct clif_data { - int cmd; + enum clif_action cmd; char ifname[IFNAMSIZ]; }; -int fcoeclif_validate_interface(char *ifname, char *fchost, int len); -int fcoeclif_checkdir(char *dir); #endif /* _FCOE_CLIF_H_ */ diff --git a/fcoe_utils.c b/fcoe_utils.c new file mode 100644 index 0000000..016dc0f --- /dev/null +++ b/fcoe_utils.c @@ -0,0 +1,188 @@ +/* + * Copyright(c) 2010 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 + */ + +#include "fcoe_utils.h" + +static int fcoe_sysfs_read(char *buf, int size, const char *path) +{ + FILE *fp; + int i, rc = -EINVAL; + + fp = fopen(path, "r"); + if (fp) { + if (fgets(buf, size, fp)) { + /* + * Strip trailing newline by replacing + * any '\r' or '\n' instances with '\0'. + * It's not as elegant as it could be, but + * we know that the symbolic name won't + * have either of those characters until + * the end of the line. + */ + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n' || + buf[i] == '\r') { + buf[i] = '\0'; + break; + } + } + rc = 0; + } + + fclose(fp); + } + + return rc; +} + +static int fcoe_check_fchost(const char *ifname, const char *dname) +{ + char buf[MAX_STR_LEN]; + char path[MAX_PATH_LEN]; + int rc = -EINVAL; + + sprintf(path, "%s/%s/symbolic_name", SYSFS_FCHOST, dname); + + if (!fcoe_sysfs_read(buf, MAX_STR_LEN, path)) + rc = check_symbolic_name_for_interface(buf, ifname); + + return rc; +} + +enum fcoe_err fcoe_find_fchost(char *ifname, char *fchost, int len) +{ + int n, dname_len; + struct dirent **namelist; + int rc = ENOFCOECONN; + + n = scandir(SYSFS_FCHOST, &namelist, 0, alphasort); + + for (n-- ; n >= 0 ; n--) { + if (rc) { + /* check symbolic name */ + if (!fcoe_check_fchost(ifname, namelist[n]->d_name)) { + dname_len = strnlen(namelist[n]->d_name, len); + + if (len > dname_len) { + strncpy(fchost, namelist[n]->d_name, + dname_len + 1); + /* rc = 0 indicates found */ + rc = NOERR; + } else { + /* + * The fc_host is too large + * for the buffer. + */ + rc = EINTERR; + } + } + } + free(namelist[n]); + + } + free(namelist); + + return rc; +} + +enum fcoe_err fcoe_validate_interface(char *ifname) +{ + enum fcoe_err rc = NOERR; + char path[MAX_PATH_LEN]; + + + if (!strlen(ifname)) + rc = ENOETHDEV; + + /* + * TODO: Is there a better way to check if the + * interface name is correct? + */ + sprintf(path, "%s/%s", SYSFS_NET, ifname); + if (!rc && fcoe_checkdir(path)) + rc = ENOETHDEV; + + return rc; +} + +/* + * Validate an existing instance for an FC interface + */ +enum fcoe_err fcoe_validate_fcoe_conn(char *ifname) +{ + char fchost[FCHOSTBUFLEN]; + enum fcoe_err rc = NOERR; + + rc = fcoe_validate_interface(ifname); + + if (!rc) + rc = fcoe_find_fchost(ifname, fchost, FCHOSTBUFLEN); + + return rc; +} + +/* + * Open and close to check if directory exists + */ +int fcoe_checkdir(char *dir) +{ + DIR *d = NULL; + + if (!dir) + return -EINVAL; + /* check if we have sysfs */ + d = opendir(dir); + if (!d) + return -EINVAL; + closedir(d); + return 0; +} + +char *get_ifname_from_symbolic_name(const char *symbolic_name) +{ + int symbolic_name_len = strlen(symbolic_name); + int lead_len = strlen(SYMB_NAME_LEAD); + + if (lead_len < symbolic_name_len) + return (char *)(symbolic_name + lead_len); + + return NULL; +} + +int check_symbolic_name_for_interface(const char *symbolic_name, + const char *ifname) +{ + int rc = -EINVAL; + char *symb; + + symb = get_ifname_from_symbolic_name(symbolic_name); + + /* + * It's important to use the length of the ifname + * from the symbolic_name here. If the ifname length + * were used then if the user passed in a substring + * of the the interface name it would match because + * we'd only be looking for the first few characters, + * not the whole string. + */ + if (symb && !strncmp(ifname, symb, strlen(symb))) + rc = 0; + + return rc; +} diff --git a/fcoe_utils.h b/fcoe_utils.h new file mode 100644 index 0000000..3215804 --- /dev/null +++ b/fcoe_utils.h @@ -0,0 +1,84 @@ +/* + * Copyright(c) 2010 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 + */ + +#ifndef _FCOE_UTILS_H_ +#define _FCOE_UTILS_H_ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include + +/* + * Used when trying to get the interface name from the symbolic_name. + * Not very elegant as this code will need to change if fcoe.ko changes + * its version. + */ +#define FCOE_MODULE_VERSION "v0.1" +#define SYMB_NAME_LEAD "fcoe " FCOE_MODULE_VERSION " over " + +#define MAX_STR_LEN 512 +#define MAX_PATH_LEN MAX_STR_LEN + +#define SYSFS_MOUNT "/sys" +#define SYSFS_NET SYSFS_MOUNT "/class/net" +#define SYSFS_FCHOST SYSFS_MOUNT "/class/fc_host" +#define SYSFS_FCOE SYSFS_MOUNT "/module/fcoe/parameters" + +#define FCHOSTBUFLEN 64 + +/* + * This macro assumes that progname has been set + */ +#define FCOE_LOG_ERR(fmt, args...) \ + do { \ + fprintf(stderr, "%s: " fmt, progname, ##args); \ + } while (0) + + +enum fcoe_err { + NOERR = 0, /* No error */ + ENOFCOECONN, /* No FCoE connection on interface */ + EINTERR, /* Internal error */ + EINVALARG, /* Invalid argument */ + EBADNUMARGS, /* Invalid number of arguments */ + EIGNORE, /* Ignore this error value */ + ENOSYSFS, /* sysfs is not present */ + ENOETHDEV, /* Not a valid Ethernet interface */ + ENOMONCONN, /* Not connected to fcoemon */ + ECONNTMOUT, /* Connection to fcoemon timed out */ + EHBAAPIERR, /* Error using HBAAPI/libhbalinux */ +}; + +enum fcoe_err fcoe_validate_interface(char *ifname); +enum fcoe_err fcoe_find_fchost(char *ifname, char *fchost, int len); +int fcoe_checkdir(char *dir); +int check_symbolic_name_for_interface(const char *symbolic_name, + const char *ifname); +char *get_ifname_from_symbolic_name(const char *symbolic_name); +int valid_ifname(const char *ifname); + +#endif /* _FCOE_UTILS_H_ */ diff --git a/fcoe_utils.h.in b/fcoe_utils.h.in deleted file mode 100644 index 695ba87..0000000 --- a/fcoe_utils.h.in +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _FCOE_UTILS_H_ -#define _FCOE_UTILS_H_ - -#define FCOE_UTILS_VERSION "@VERSION@" - -#endif /* _FCOE_UTILS_H_ */ diff --git a/fcoe_utils_version.h.in b/fcoe_utils_version.h.in new file mode 100644 index 0000000..642f37d --- /dev/null +++ b/fcoe_utils_version.h.in @@ -0,0 +1,6 @@ +#ifndef _FCOE_UTILS_VERSION_H_ +#define _FCOE_UTILS_VERSION_H_ + +#define FCOE_UTILS_VERSION "@VERSION@" + +#endif /* _FCOE_UTILS_VERSION_H_ */ diff --git a/fcoeadm.c b/fcoeadm.c index 8b2a6b6..97cd1bd 100644 --- a/fcoeadm.c +++ b/fcoeadm.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2010 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, @@ -17,391 +17,223 @@ * Maintained at www.Open-FCoE.org */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif #include #include -#include "fcoe_utils.h" +#include +#include + +#include "fcoe_utils_version.h" #include "fcoeadm.h" #include "fcoe_clif.h" -static char *fcoeadm_version = -"fcoeadm v" FCOE_UTILS_VERSION "\n Copyright (c) 2009, Intel Corporation.\n"; - -#define CMD_RESPONSE_TIMEOUT 5 - +static const char *optstring = "c:d:r:S:itlshv"; static struct option fcoeadm_opts[] = { - {"create", 1, 0, 'c'}, - {"destroy", 1, 0, 'd'}, - {"reset", 1, 0, 'r'}, - {"interface", 1, 0, 'i'}, - {"target", 1, 0, 't'}, - {"lun", 2, 0, 'l'}, - {"stats", 1, 0, 's'}, - {"help", 0, 0, 'h'}, - {"version", 0, 0, 'v'}, + {"create", required_argument, 0, 'c'}, + {"destroy", required_argument, 0, 'd'}, + {"reset", required_argument, 0, 'r'}, + {"interface", no_argument, 0, 'i'}, + {"target", no_argument, 0, 't'}, + {"lun", no_argument, 0, 'l'}, + {"stats", no_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; struct opt_info _opt_info, *opt_info = &_opt_info; char progname[20]; -struct clif *clif_conn; - static void fcoeadm_help(void) { - printf("%s\n", fcoeadm_version); + printf("Version %s\n", FCOE_UTILS_VERSION); printf("Usage: %s\n" "\t [-c|--create] \n" "\t [-d|--destroy] \n" "\t [-r|--reset] \n" + "\t [-S|--Scan] \n" "\t [-i|--interface] []\n" "\t [-t|--target] []\n" - "\t [-l|--lun] [ []]\n" - "\t [-s|--stats] [-n ]\n" + "\t [-l|--lun] []\n" + "\t [-s|--stats] []\n" "\t [-v|--version]\n" "\t [-h|--help]\n\n", progname); } -/* - * TODO - check this ifname before performing any action - */ -static int fcoeadm_check(char *ifname) +static enum fcoe_err fcoeadm_check_fcoemon() { - char path[256]; int fd; - int status = 0; - - /* check if we have sysfs */ - if (fcoeclif_checkdir(SYSFS_MOUNT)) { - fprintf(stderr, - "%s: Sysfs mount point %s not found\n", - progname, SYSFS_MOUNT); - status = -EINVAL; - } - - /* check target interface */ - if (!ifname) { - fprintf(stderr, "%s: Invalid interface name\n", progname); - status = -EINVAL; - } - sprintf(path, "%s/%s", SYSFS_NET, ifname); - if (fcoeclif_checkdir(path)) { - fprintf(stderr, - "%s: Interface %s not found\n", progname, ifname); - status = -EINVAL; - } fd = open(CLIF_PID_FILE, O_RDWR, S_IRUSR | S_IWUSR); - if (fd < 0) { - fprintf(stderr, - "%s: fcoemon was not running\n", progname); - status = -EINVAL; - } + if (fd < 0) + return ENOMONCONN; + + close(fd); - return status; + return NOERR; } -static int fcoeadm_clif_request(const struct clif_data *cmd, size_t cmd_len, - char *reply, size_t *reply_len) +static enum fcoe_err fcoeadm_clif_request(struct clif_sock_info *clif_info, + const struct clif_data *cmd, + size_t cmd_len, char *reply, + size_t *reply_len) { struct timeval tv; int ret; fd_set rfds; - if (send(clif_conn->s, cmd, cmd_len, 0) < 0) - return -1; + if (send(clif_info->socket_fd, cmd, cmd_len, 0) < 0) + return ENOMONCONN; for (;;) { - tv.tv_sec = CMD_RESPONSE_TIMEOUT; + tv.tv_sec = CLIF_CMD_RESPONSE_TIMEOUT; tv.tv_usec = 0; FD_ZERO(&rfds); - FD_SET(clif_conn->s, &rfds); - ret = select(clif_conn->s + 1, &rfds, NULL, NULL, &tv); - if (FD_ISSET(clif_conn->s, &rfds)) { - ret = recv(clif_conn->s, reply, *reply_len, 0); + FD_SET(clif_info->socket_fd, &rfds); + ret = select(clif_info->socket_fd + 1, &rfds, NULL, NULL, &tv); + if (FD_ISSET(clif_info->socket_fd, &rfds)) { + ret = recv(clif_info->socket_fd, reply, *reply_len, 0); if (ret < 0) - return ret; + return EINTERR; + *reply_len = ret; break; } else { - return -2; + return EINTERR; } } - return 0; + return NOERR; } -static int fcoeadm_request(int cmd, char *s) +static enum fcoe_err fcoeadm_request(struct clif_sock_info *clif_info, + struct clif_data *data) { - struct clif_data *data = NULL; char rbuf[MAX_MSGBUF]; size_t len; - int ret; - - if (clif_conn == NULL) { - fprintf(stderr, "Not connected to fcoemon\n"); - return -EINVAL; - } - - data = (struct clif_data *)malloc(sizeof(struct clif_data)); - if (data == NULL) - return -EINVAL; + int rc = NOERR; - memset(data, 0, sizeof(data)); - data->cmd = cmd; - strcpy(data->ifname, s); + /* + * TODO: This is odd that we read the response code back as a + * string. We should just write the error code into a member + * of clif_data and then just read it directly. + */ - len = sizeof(rbuf)-1; + len = MAX_MSGBUF - 1; + rc = fcoeadm_clif_request(clif_info, data, sizeof(struct clif_data), + rbuf, &len); - ret = fcoeadm_clif_request(data, sizeof(struct clif_data), rbuf, &len); - if (ret == -2) { - fprintf(stderr, "Command timed out\n"); - goto fail; - } else if (ret < 0) { - fprintf(stderr, "Command failed\n"); - goto fail; + if (!rc) { + rbuf[len] = '\0'; + rc = atoi(rbuf); } - rbuf[len] = '\0'; - ret = atoi(rbuf); - free(data); - return ret; - -fail: - free(data); - return -EINVAL; + return rc; } -static void fcoeadm_close_cli(void) +static void fcoeadm_close_cli(struct clif_sock_info *clif_info) { - if (clif_conn == NULL) - return; - - unlink(clif_conn->local.sun_path); - close(clif_conn->s); - free(clif_conn); - clif_conn = NULL; + unlink(clif_info->local.sun_path); + close(clif_info->socket_fd); } /* * Create fcoeadm client interface */ -static struct clif *fcoeadm_open_cli(const char *ifname) +static enum fcoe_err fcoeadm_open_cli(struct clif_sock_info *clif_info) { - char *fcmon_file = NULL; - int flen; - static int counter; - - flen = strlen(FCM_SRV_DIR) + strlen(ifname) + 2; - fcmon_file = malloc(flen); - if (fcmon_file == NULL) - goto fail; - snprintf(fcmon_file, flen, "%s/%s", FCM_SRV_DIR, ifname); - - clif_conn = malloc(sizeof(*clif_conn)); - if (clif_conn == NULL) - goto fail; - memset(clif_conn, 0, sizeof(*clif_conn)); - - clif_conn->s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (clif_conn->s < 0) - goto fail; - - clif_conn->local.sun_family = AF_UNIX; - snprintf(clif_conn->local.sun_path, sizeof(clif_conn->local.sun_path), - "/tmp/fcadm_clif_%d-%d", getpid(), counter++); - if (bind(clif_conn->s, (struct sockaddr *) &clif_conn->local, - sizeof(clif_conn->local)) < 0) { - close(clif_conn->s); - goto fail; - } + int counter; + enum fcoe_err rc = NOERR; - clif_conn->dest.sun_family = AF_UNIX; - snprintf(clif_conn->dest.sun_path, sizeof(clif_conn->dest.sun_path), - "%s", fcmon_file); - if (connect(clif_conn->s, (struct sockaddr *) &clif_conn->dest, - sizeof(clif_conn->dest)) < 0) { - close(clif_conn->s); - unlink(clif_conn->local.sun_path); - goto fail; + clif_info->socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (clif_info->socket_fd < 0) { + rc = ENOMONCONN; + goto err; } - free(fcmon_file); - return clif_conn; - -fail: - free(fcmon_file); - free(clif_conn); - return NULL; -} - -/* - * Send request to fcoemon - */ -static int fcoeadm_action(int cmd, char *device_name) -{ - char *clif_ifname = NULL; - int ret = 0; + clif_info->local.sun_family = AF_UNIX; + snprintf(clif_info->local.sun_path, sizeof(clif_info->local.sun_path), + "/tmp/fcadm_clif_%d-%d", getpid(), counter++); - if (!device_name) - return -EINVAL; - - for (;;) { - if (clif_ifname == NULL) { - struct dirent *dent; - DIR *dir = opendir(FCM_SRV_DIR); - if (dir) { - while ((dent = readdir(dir))) { - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - clif_ifname = strdup(dent->d_name); - break; - } - closedir(dir); - } - } - - clif_conn = fcoeadm_open_cli(clif_ifname); - if (clif_conn) { - break; - } else { - fprintf(stderr, "Failed to connect to fcoemon\n"); - free(clif_ifname); - return -1; - } + if (bind(clif_info->socket_fd, (struct sockaddr *)&clif_info->local, + sizeof(clif_info->local)) < 0) { + rc = ENOMONCONN; + goto err_close; } - ret = fcoeadm_request(cmd, device_name); + clif_info->dest.sun_family = AF_UNIX; + strncpy(clif_info->dest.sun_path, CLIF_SOCK_FILE, + sizeof(clif_info->dest.sun_path)); - free(clif_ifname); - fcoeadm_close_cli(); + if (!connect(clif_info->socket_fd, (struct sockaddr *)&clif_info->dest, + sizeof(clif_info->dest)) < 0) { + rc = ENOMONCONN; + unlink(clif_info->local.sun_path); + goto err_close; + } - return ret; -} + return rc; -/* - * Create FCoE instance for this ifname - */ -static int fcoeadm_create(char *ifname) -{ - if (fcoeadm_check(ifname)) { - fprintf(stderr, - "%s: Failed to create FCoE instance on %s\n", - progname, ifname); - return -EINVAL; - } - return fcoeadm_action(FCOE_CREATE_CMD, ifname); +err_close: + close(clif_info->socket_fd); +err: + return rc; } /* - * Remove FCoE instance for this ifname + * Send request to fcoemon */ -static int fcoeadm_destroy(char *ifname) +static enum fcoe_err fcoeadm_action(enum clif_action cmd, char *ifname) { - if (fcoeadm_check(ifname)) { - fprintf(stderr, - "%s: Failed to destroy FCoE instance on %s\n", - progname, ifname); - return -EINVAL; - } - return fcoeadm_action(FCOE_DESTROY_CMD, ifname); -} + struct clif_data data; + struct clif_sock_info clif_info; + enum fcoe_err rc; -/* - * Reset the fc_host that is associated w/ this ifname - */ -static int fcoeadm_reset(char *ifname) -{ - return fcoeadm_action(FCOE_RESET_CMD, ifname); -} + strncpy(data.ifname, ifname, sizeof(data.ifname)); + data.cmd = cmd; -/* - * Parse a user-entered hex field. - * Format may be xx-xx-xx OR xxxxxx OR xx:xx:xx for len bytes (up to 8). - * Leading zeros may be omitted. - */ -static int parse_hex_ll(unsigned long long *hexp, const char *input, u_int len) -{ - int i; - unsigned long long hex = 0; - unsigned long long byte; - char *endptr = ""; - int error = EINVAL; - char sep = 0; - - for (i = 0; i < len; i++) { - byte = strtoull(input, &endptr, 16); - if (i == 0 && *endptr == '\0') { - hex = byte; - if (len == 8 || hex < (1ULL << (8 * len))) - error = 0; - break; - } - if (sep == 0 && (*endptr == ':' || *endptr == '-')) - sep = *endptr; - if ((*endptr == '\0' || *endptr == sep) && byte < 256) - hex = (hex << 8) | byte; - else - break; - input = endptr + 1; + rc = fcoeadm_open_cli(&clif_info); + if (!rc) { + rc = fcoeadm_request(&clif_info, &data); + fcoeadm_close_cli(&clif_info); } - if (i == len && *endptr == '\0') - error = 0; - if (error == 0) - *hexp = hex; - return error; + + return rc; } -static int parse_fcid(HBA_UINT32 *fcid, const char *input) +static enum fcoe_err fcoeadm_loadhba() { - int rc; - unsigned long long hex; + if (HBA_STATUS_OK != HBA_LoadLibrary()) + return EHBAAPIERR; - rc = parse_hex_ll(&hex, input, 3); - if (rc == 0) - *fcid = (HBA_UINT32) hex; - return rc; + return NOERR; } /* * Display adapter information */ -static int fcoeadm_display_adapter_info(struct opt_info *opt_info) +static enum fcoe_err fcoeadm_display_adapter_info(struct opt_info *opt_info) { - HBA_STATUS retval; - - retval = HBA_LoadLibrary(); - if (retval != HBA_STATUS_OK) { - perror("HBA_LoadLibrary"); - return -EINVAL; - } + if (fcoeadm_loadhba()) + return EHBAAPIERR; display_adapter_info(opt_info); HBA_FreeLibrary(); - return 0; + return NOERR; } /* * Display target information */ -static int fcoeadm_display_target_info(struct opt_info *opt_info) +static enum fcoe_err fcoeadm_display_target_info(struct opt_info *opt_info) { - HBA_STATUS retval; - - retval = HBA_LoadLibrary(); - if (retval != HBA_STATUS_OK) { - perror("HBA_LoadLibrary"); - return -EINVAL; - } + if (fcoeadm_loadhba()) + return EHBAAPIERR; display_target_info(opt_info); HBA_FreeLibrary(); - return 0; + return NOERR; } /* @@ -409,19 +241,14 @@ static int fcoeadm_display_target_info(struct opt_info *opt_info) */ static int fcoeadm_display_port_stats(struct opt_info *opt_info) { - HBA_STATUS retval; - if (!opt_info->s_flag) return -EINVAL; if (!opt_info->n_flag) opt_info->n_interval = DEFAULT_STATS_INTERVAL; - retval = HBA_LoadLibrary(); - if (retval != HBA_STATUS_OK) { - perror("HBA_LoadLibrary"); + if (fcoeadm_loadhba()) return -EINVAL; - } display_port_stats(opt_info); @@ -431,168 +258,255 @@ static int fcoeadm_display_port_stats(struct opt_info *opt_info) #define MAX_ARG_LEN 32 +/* + * getopts_long(3) does not handle optional arguments + * correctly. It will not allow a ' ' between the option + * and its argument. For required arguments the user can + * specify, '-i X' or '-iX' but with optional arguments + * only the first style is valid. + * + * This is being worked around by making '-i/-t/-l' have + * no arguments, but then process any following argv + * elements. + */ int main(int argc, char *argv[]) { - char fchost[FCHOSTBUFLEN], *s; - int opt, rc = -1; - + int opt; + enum clif_action cmd = CLIF_NONE; + enum fcoe_err rc = NOERR; + + /* + * This has to be first because the error print macro + * expects progname to be valid. + */ strncpy(progname, basename(argv[0]), sizeof(progname)); + + /* check if we have sysfs */ + if (fcoe_checkdir(SYSFS_MOUNT)) { + rc = ENOSYSFS; + goto err; + } + + /* Check if fcoemon is running */ + rc = fcoeadm_check_fcoemon(); + if (rc) + goto err; + memset(opt_info, 0, sizeof(*opt_info)); - while ((opt = getopt_long(argc, argv, "c:d:r:itls:n:hv", - fcoeadm_opts, NULL)) != -1) { + opt = getopt_long(argc, argv, optstring, fcoeadm_opts, NULL); + if (opt != -1) { switch (opt) { case 'c': - if ((argc < 2 || argc > 3) || - strnlen(optarg, MAX_ARG_LEN) > (IFNAMSIZ - 1) || - ((argc == 3) && strnlen(argv[1], MAX_ARG_LEN) > 2 && - argv[1][1] != '-')) - goto error; - rc = fcoeadm_create(optarg); - goto done; + cmd = CLIF_CREATE_CMD; case 'd': - if ((argc < 2 || argc > 3) || - strnlen(optarg, MAX_ARG_LEN) > (IFNAMSIZ - 1) || - ((argc == 3) && strnlen(argv[1], MAX_ARG_LEN) > 2 && - argv[1][1] != '-')) - goto error; - rc = fcoeadm_destroy(optarg); - goto done; + if (cmd == CLIF_NONE) + cmd = CLIF_DESTROY_CMD; case 'r': - if ((argc < 2 || argc > 3) || - strnlen(optarg, MAX_ARG_LEN) > (IFNAMSIZ - 1) || - ((argc == 3) && strnlen(argv[1], MAX_ARG_LEN) > 2 && - argv[1][1] != '-')) - goto error; - rc = fcoeadm_reset(optarg); - goto done; + if (cmd == CLIF_NONE) + cmd = CLIF_RESET_CMD; + case 'S': + if (cmd == CLIF_NONE) + cmd = CLIF_SCAN_CMD; + + if (argc > 3) { + rc = EBADNUMARGS; + break; + } + + strncpy(opt_info->ifname, optarg, + sizeof(opt_info->ifname)); + + if (opt == 'c') + rc = fcoe_validate_interface(opt_info->ifname); + else + rc = fcoe_validate_fcoe_conn(opt_info->ifname); + + if (!rc) + rc = fcoeadm_action(cmd, opt_info->ifname); + break; + case 'i': - if (argc < 2 || argc > 3 || - (argc == 3 && strnlen(argv[1], MAX_ARG_LEN) > 2 && - (argv[1][1] != '-' || strchr(argv[1], '=') - != NULL))) - goto error; - s = NULL; - if (argc == 2) { - if (argv[1][1] == '-') - s = strchr(argv[1], '=')+1; - else - s = argv[1]+2; - } else - s = argv[2]; - - if (s) { - if (strnlen(s, MAX_ARG_LEN) > (IFNAMSIZ - 1)) - goto error; - strncpy(opt_info->ifname, s, - sizeof(opt_info->ifname)); + if (argc > 3) { + rc = EBADNUMARGS; + break; } - if (strnlen(opt_info->ifname, IFNAMSIZ - 1)) { - if (fcoeclif_validate_interface( - opt_info->ifname, - fchost, FCHOSTBUFLEN)) - goto done; + + /* + * If there's an aditional argument + * treat it as the interface name. + */ + if (optind != argc) { + strncpy(opt_info->ifname, argv[optind], + sizeof(opt_info->ifname)); + + rc = fcoe_validate_fcoe_conn(opt_info->ifname); } - opt_info->a_flag = 1; - rc = fcoeadm_display_adapter_info(opt_info); - goto done; + + if (!rc) + rc = fcoeadm_display_adapter_info(opt_info); + + break; + case 't': - if (argc < 2 || argc > 3 || - (argc == 3 && strnlen(argv[1], MAX_ARG_LEN) > 2 && - (argv[1][1] != '-' || strchr(argv[1], '=') - != NULL))) - goto error; - s = NULL; - if (argc == 2) { - if (argv[1][1] == '-') - s = strchr(argv[1], '=')+1; - else - s = argv[1]+2; - } else { - s = argv[2]; + if (argc > 3) { + rc = EBADNUMARGS; + break; } - if (s) { - if (strnlen(s, MAX_ARG_LEN) > (IFNAMSIZ - 1)) - goto error; - strncpy(opt_info->ifname, s, + + /* + * If there's an aditional argument + * treat it as the interface name. + */ + if (optind != argc) { + strncpy(opt_info->ifname, argv[optind], sizeof(opt_info->ifname)); + + rc = fcoe_validate_fcoe_conn(opt_info->ifname); } - if (strnlen(opt_info->ifname, IFNAMSIZ - 1)) { - if (fcoeclif_validate_interface( - opt_info->ifname, - fchost, FCHOSTBUFLEN)) - goto done; + + if (!rc) { + opt_info->t_flag = 1; + rc = fcoeadm_display_target_info(opt_info); } - opt_info->t_flag = 1; - rc = fcoeadm_display_target_info(opt_info); - goto done; + + break; + case 'l': - if (argc < 2 || argc > 4) - goto error; - if (optarg) { - if (parse_fcid(&opt_info->l_fcid, optarg)) - goto error; - opt_info->l_fcid_present = 1; - if (argv[optind]) { - opt_info->l_lun_id = atoi(argv[optind]); - opt_info->l_lun_id_present = 1; - } + if (argc > 3) { + rc = EBADNUMARGS; + break; } - opt_info->l_flag = 1; - rc = fcoeadm_display_target_info(opt_info); - goto done; - case 's': - if ((argc < 2 || argc > 5) || - strnlen(optarg, MAX_ARG_LEN) > (IFNAMSIZ - 1)) - goto error; - if (optarg) - strncpy(opt_info->ifname, optarg, + + /* + * If there's an aditional argument + * treat it as the interface name. + */ + if (optind != argc) { + strncpy(opt_info->ifname, argv[optind], sizeof(opt_info->ifname)); - if (strnlen(opt_info->ifname, IFNAMSIZ - 1)) { - if (fcoeclif_validate_interface( - opt_info->ifname, - fchost, FCHOSTBUFLEN)) - goto done; + + rc = fcoe_validate_fcoe_conn(opt_info->ifname); } - opt_info->s_flag = 1; - if (argv[optind] && !strncmp(argv[optind], "-n", 2)) + + if (!rc) { + opt_info->l_flag = 1; + rc = fcoeadm_display_target_info(opt_info); + } + + break; + + case 's': + if (argc > 4) { + rc = EBADNUMARGS; break; - goto stats; - case 'n': - if (!opt_info->s_flag) - goto error; - opt_info->n_interval = atoi(optarg); - if (opt_info->n_interval <= 0) - goto error; - if (argv[optind] && - strnlen(argv[optind], MAX_ARG_LEN<<1) > MAX_ARG_LEN) - goto error; - opt_info->n_flag = 1; - goto stats; + } + + if (optind != argc) { + strncpy(opt_info->ifname, argv[optind], + sizeof(opt_info->ifname)); + + rc = fcoe_validate_fcoe_conn(opt_info->ifname); + } + + if (!rc && ++optind != argc) { + opt_info->n_interval = atoi(argv[optind]); + if (opt_info->n_interval <= 0) + rc = EINVALARG; + else + opt_info->n_flag = 1; + } + + if (!rc) { + opt_info->s_flag = 1; + rc = fcoeadm_display_port_stats(opt_info); + } + + break; + case 'v': - if (argc != 2) - goto error; - printf("%s\n", fcoeadm_version); - goto done; + if (argc > 2) { + rc = EBADNUMARGS; + break; + } + + printf("%s\n", FCOE_UTILS_VERSION); + break; + case 'h': - default: - if (argc != 2) - goto error; + if (argc > 2) { + rc = EBADNUMARGS; + break; + } + fcoeadm_help(); - exit(-EINVAL); + break; + + case '?': + rc = EIGNORE; + break; } } - goto error; -stats: - if (!fcoeadm_display_port_stats(opt_info)) - goto done; +err: + if (rc) { + switch (rc) { + case ENOFCOECONN: + FCOE_LOG_ERR("No connection created on " + "interface %s\n", opt_info->ifname); + break; + + case EINVALARG: + FCOE_LOG_ERR("Invalid argument\n"); + break; + + case EBADNUMARGS: + /* + * Overloading E2BIG for too many argumets + * and too few arguments. + */ + FCOE_LOG_ERR("Incorrect number of arguments\n"); + break; + + case EIGNORE: + /* + * getopt_long will print the initial error, just break + * through to get the --help suggestion. + */ + break; -error: - fprintf(stderr, "%s: Invalid command options\n", progname); - fcoeadm_help(); - exit(-EINVAL); + case ENOETHDEV: + FCOE_LOG_ERR("Invalid interface name %s\n", + opt_info->ifname); + break; + + case ENOSYSFS: + FCOE_LOG_ERR("sysfs not mounted\n"); + break; + + case ENOMONCONN: + FCOE_LOG_ERR("Could not connect to fcoemon\n"); + break; + + case ECONNTMOUT: + FCOE_LOG_ERR("Connection to fcoemon timed out\n"); + break; + + case EINTERR: + FCOE_LOG_ERR("Internal error\n"); + break; + + default: + /* + * This will catch EOPNOTSUPP which should never happen + */ + FCOE_LOG_ERR("Unknown error\n"); + break; + } + + fprintf(stderr, "Try \'%s --help\' for more information.\n", + progname); + } -done: return rc; } diff --git a/fcoeadm.h b/fcoeadm.h index fdda13a..8536fb7 100644 --- a/fcoeadm.h +++ b/fcoeadm.h @@ -26,11 +26,11 @@ #include #include #include -#include + #include #include +#include #include -#include #include #include #include @@ -42,14 +42,12 @@ #include #include #include -#include - #include "hbaapi.h" #include "net_types.h" #include "fc_types.h" #include "fc_scsi.h" -#define FCOE_MAX_LUN 255 +#include "fcoe_utils.h" struct opt_info { char ifname[IFNAMSIZ]; @@ -66,22 +64,8 @@ struct opt_info { int n_interval; /* seconds */ }; -/** - * struct clif - Internal structure for client interface library - * - * This structure is used by fcoeadm client interface to store internal data. - */ -struct clif { - int s; - struct sockaddr_un local; - struct sockaddr_un dest; -}; - -extern struct opt_info *opt_info; -extern char build_date[]; - -extern void display_adapter_info(struct opt_info *opt_info); -extern void display_target_info(struct opt_info *opt_info); -extern void display_port_stats(struct opt_info *opt_info); +void display_adapter_info(struct opt_info *opt_info); +void display_target_info(struct opt_info *opt_info); +void display_port_stats(struct opt_info *opt_info); #endif /* _FCOEADM_H_ */ diff --git a/fcoeadm_display.c b/fcoeadm_display.c index 9ba3027..8687bb3 100644 --- a/fcoeadm_display.c +++ b/fcoeadm_display.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2010 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, @@ -43,6 +43,8 @@ /* Minimum byte size of the received inquiry data */ #define MIN_INQ_DATA_SIZE 36 +#define FCP_TARG_STR "FCP Target" + struct sa_nameval { char *nv_name; u_int32_t nv_val; @@ -195,6 +197,19 @@ sa_sys_read_u32(const char *dir, const char *file, u_int32_t *vp) return rc; } +static int is_fcp_target(HBA_PORTATTRIBUTES *rp_info) +{ + char buf[MAX_STR_LEN]; + + if (sa_sys_read_line(rp_info->OSDeviceName, "roles", buf, sizeof(buf))) + return -EINVAL; + + if (!strncmp(buf, FCP_TARG_STR, strlen(buf))) + return 0; + + return -EINVAL; +} + static void show_wwn(unsigned char *pWwn) { sa_dump_wwn(pWwn, 8, 0); @@ -203,8 +218,7 @@ static void show_wwn(unsigned char *pWwn) static void show_hba_info(int hba_index, HBA_ADAPTERATTRIBUTES *hba_info, int flags) { - printf("\n"); - printf("HBA #%d\n", hba_index); + printf("Adapter #%d\n", hba_index); printf(" Description: %s\n", hba_info->ModelDescription); printf(" Revision: %s\n", hba_info->HardwareVersion); printf(" Manufacturer: %s\n", hba_info->Manufacturer); @@ -212,6 +226,7 @@ show_hba_info(int hba_index, HBA_ADAPTERATTRIBUTES *hba_info, int flags) printf(" Driver: %s %s\n", hba_info->DriverName, hba_info->DriverVersion); printf(" Number of Ports: %d\n", hba_info->NumberOfPorts); + printf("\n"); } static void @@ -222,7 +237,7 @@ show_port_info(int hba_index, int lp_index, char buf[256]; int len = sizeof(buf); - printf("\n Port #%d\n", lp_index); + printf(" Port #%d\n", lp_index); printf(" Symbolic Name: %s\n", lp_info->PortSymbolicName); @@ -256,21 +271,23 @@ show_port_info(int hba_index, int lp_index, sa_enum_decode(buf, sizeof(buf), port_states, lp_info->PortState); printf(" State: %s\n", buf); - + printf("\n"); /* TODO: Display PortSupportedFc4Types and PortActiveFc4Types */ } -static void -show_target_info(int hba_index, int lp_index, int rp_index, - HBA_ADAPTERATTRIBUTES *hba_info, - HBA_PORTATTRIBUTES *rp_info) +static void show_target_info(const char *symbolic_name, int hba_index, + int lp_index, int rp_index, + HBA_ADAPTERATTRIBUTES *hba_info, + HBA_PORTATTRIBUTES *rp_info) { char buf[256]; u_int32_t tgt_id; int rc; + char *ifname; + + ifname = get_ifname_from_symbolic_name(symbolic_name); - printf("Target #%d @ %s\n", - rp_index, hba_info->NodeSymbolicName + 5); + printf("Target #%d @ %s\n", rp_index, ifname); rc = sa_sys_read_line(rp_info->OSDeviceName, "roles", buf, sizeof(buf)); printf(" Roles: %s\n", buf); @@ -296,8 +313,7 @@ show_target_info(int hba_index, int lp_index, int rp_index, sa_enum_decode(buf, sizeof(buf), port_states, rp_info->PortState); printf(" State: %s\n", buf); - - printf(" \n"); + printf("\n"); } static void @@ -906,7 +922,6 @@ scan_device_map(HBA_HANDLE hba_handle, opt_info->l_lun_id_present && ep->ScsiId.ScsiOSLun != opt_info->l_lun_id) continue; - dev = ep->ScsiId.OSDeviceName; if (strstr(dev, "/dev/") == dev) dev += 5; @@ -934,7 +949,6 @@ scan_device_map(HBA_HANDLE hba_handle, #endif if (status != HBA_STATUS_OK) continue; - if (opt_info->t_flag) { if (!print_header) { show_short_lun_info_header(); @@ -956,8 +970,11 @@ scan_device_map(HBA_HANDLE hba_handle, #endif } + /* Newline at the end of the short lun report */ + if (opt_info->t_flag) + printf("\n"); + free(map); - printf("\n"); } static void @@ -1051,7 +1068,9 @@ display_port_stats(struct opt_info *opt_info) continue; } - if (strstr(port_attrs.PortSymbolicName, opt_info->ifname)) { + if (!check_symbolic_name_for_interface( + port_attrs.PortSymbolicName, + opt_info->ifname)) { found = 1; break; } @@ -1209,7 +1228,7 @@ display_adapter_info(struct opt_info *opt_info) for (j = 0; j < lport_cnt_per_hba; j++) { retval = HBA_GetAdapterPortAttributes( - hba_handle, j, &port_attrs); + hba_handle, j, &port_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterPortAttributes failed, " @@ -1218,12 +1237,16 @@ display_adapter_info(struct opt_info *opt_info) } lp_index++; - if (opt_info->ifname && - !strstr(port_attrs.PortSymbolicName, - opt_info->ifname)) - continue; - show_port_info(hba_index, lp_index, &hba_attrs, - &port_attrs); + + if (strlen(opt_info->ifname)) { + if (check_symbolic_name_for_interface( + port_attrs.PortSymbolicName, + opt_info->ifname)) + continue; + } + + show_port_info(hba_index, lp_index, + &hba_attrs, &port_attrs); } HBA_CloseAdapter(hba_handle); } @@ -1300,10 +1323,13 @@ display_target_info(struct opt_info *opt_info) } lp_index++; - if (opt_info->ifname && - !strstr(port_attrs.PortSymbolicName, - opt_info->ifname)) - continue; + + if (strlen(opt_info->ifname)) { + if (check_symbolic_name_for_interface( + port_attrs.PortSymbolicName, + opt_info->ifname)) + continue; + } for (rp_index = 0; rp_index < port_attrs.NumberofDiscoveredPorts; @@ -1329,10 +1355,20 @@ display_target_info(struct opt_info *opt_info) rport_attrs.PortFcId != opt_info->l_fcid) continue; - show_target_info(hba_index, lp_index, - rp_index, &hba_attrs, - &rport_attrs); + /* + * Skip any targets that are not FCP targets + */ + if (is_fcp_target(&rport_attrs)) + continue; + + show_target_info(port_attrs.PortSymbolicName, + hba_index, lp_index, rp_index, + &hba_attrs, &rport_attrs); + /* + * This will print the LUN table + * under the target. + */ scan_device_map(hba_handle, &hba_attrs, &port_attrs, &rport_attrs, opt_info); diff --git a/fcoemon.c b/fcoemon.c index b4f6b6a..e188d49 100644 --- a/fcoemon.c +++ b/fcoemon.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2010 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, @@ -18,15 +18,12 @@ */ #include -#include #include #include #include #include #include #include -#include -#include #include #include #include @@ -53,10 +50,7 @@ #include #include /* for event msg level definitions */ -#include "net_types.h" -#include "fc_types.h" - -#include "fcoe_utils.h" +#include "fcoe_utils_version.h" #include "fcoemon_utils.h" #include "fcoemon.h" #include "fcoe_clif.h" @@ -88,17 +82,12 @@ #define FCOE_ENABLE SYSFS_FCOE "/enable" #define FCOE_DISABLE SYSFS_FCOE "/disable" -static char *fcoemon_version = -"fcoemon v" FCOE_UTILS_VERSION "\n Copyright (c) 2009, Intel Corporation.\n"; - enum fcm_srv_status { fcm_success = 0, fcm_fail, fcm_no_action }; -static struct fcm_srv_data *srv_data; - /* * fcoe service configuration data * Note: These information are read in from the fcoe service @@ -115,8 +104,8 @@ struct fcoe_port { int dcb_required; /* following track data required to manage FCoE interface state */ - u_int32_t action; /* current state */ - u_int32_t last_action; /* last action */ + enum fcp_action action; /* current state */ + enum fcp_action last_action; /* last action */ int last_msg_type; /* last rtnetlink msg type received on if name */ struct sock_info *sock_reply; }; @@ -295,8 +284,8 @@ static int fcm_read_config_files(void) char val[CONFIG_MAX_VAL_LEN + 1]; DIR *dir; struct dirent *dp; - struct fcoe_port *curr; - struct fcoe_port *next; + struct fcoe_port *curr = NULL; + struct fcoe_port *next = NULL; int rc; dir = opendir(CONFIG_DIR); @@ -542,6 +531,7 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action) case FCP_ENABLE_IF: case FCP_DISABLE_IF: case FCP_RESET_IF: + case FCP_SCAN_IF: p->action = action; break; case FCP_ACTIVATE_IF: @@ -570,6 +560,7 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action) case FCP_DESTROY_IF: case FCP_DISABLE_IF: case FCP_RESET_IF: + case FCP_SCAN_IF: p->action = action; break; default: @@ -593,11 +584,13 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action) } break; case FCP_RESET_IF: + case FCP_SCAN_IF: switch (action) { case FCP_DESTROY_IF: case FCP_ENABLE_IF: case FCP_DISABLE_IF: case FCP_RESET_IF: + case FCP_SCAN_IF: p->action = action; break; case FCP_ACTIVATE_IF: @@ -1760,7 +1753,6 @@ static void fcm_dcbd_event(char *msg, size_t len) FCM_LOG_DEV_DBG(ff, "Operational config changed"); } - return; } static void fcm_cli_reply(struct sock_info *r, int status) @@ -1829,13 +1821,35 @@ static void fcm_fcoe_action(struct fcm_netif *ff, struct fcoe_port *p) break; case FCP_RESET_IF: FCM_LOG_DBG("OP: RESET %s\n", p->ifname); - if (fcoeclif_validate_interface(ifname, fchost, FCHOSTBUFLEN)) { + /* + * This call validates that the interface name + * has an active fcoe session by checking for + * the fc_host in sysfs. + */ + if (fcoe_find_fchost(ifname, fchost, FCHOSTBUFLEN)) { fcm_cli_reply(p->sock_reply, CLI_FAIL); return; } + sprintf(path, "%s/%s/issue_lip", SYSFS_FCHOST, fchost); rc = fcm_fcoe_if_action(path, "1"); break; + case FCP_SCAN_IF: + FCM_LOG_DBG("OP: SCAN %s\n", p->ifname); + /* + * This call validates that the interface name + * has an active fcoe session by checking for + * the fc_host in sysfs. + */ + if (fcoe_find_fchost(ifname, fchost, FCHOSTBUFLEN)) { + fcm_cli_reply(p->sock_reply, CLI_FAIL); + return; + } + + sprintf(path, "%s/%s/device/scsi_host/%s/scan", + SYSFS_FCHOST, fchost, fchost); + rc = fcm_fcoe_if_action(path, "- - -"); + break; default: return; break; @@ -2007,9 +2021,7 @@ next_port: static void fcm_usage(void) { - printf("%s\n", fcoemon_version); printf("Usage: %s\n" - "\t [-e|--exec ]\n" "\t [-f|--foreground]\n" "\t [-d|--debug]\n" "\t [-s|--syslog]\n" @@ -2133,7 +2145,7 @@ static int fcm_cli_destroy(char *ifname, int cmd, struct sock_info **r) return fcm_fail; } -static int fcm_cli_reset(char *ifname, int cmd, struct sock_info **r) +static int fcm_cli_action(char *ifname, int cmd, struct sock_info **r) { struct fcoe_port *p; @@ -2172,7 +2184,7 @@ int fcm_save_reply(struct sock_info **r, struct sockaddr_un *f, socklen_t flen, */ static void fcm_srv_receive(void *arg) { - struct fcm_srv_data *fcm_srv_rdata = arg; + struct fcm_srv_info *srv_info = arg; struct clif_data *data; struct sockaddr_un from; socklen_t fromlen = sizeof(struct sockaddr_un); @@ -2181,7 +2193,7 @@ static void fcm_srv_receive(void *arg) char *ifname; int res, cmd, snum; - snum = fcm_srv_rdata->srv_sock; + snum = srv_info->srv_sock; res = recvfrom(snum, buf, sizeof(buf) - 1, MSG_DONTWAIT, (struct sockaddr *)&from, &fromlen); if (res < 0) { @@ -2198,30 +2210,34 @@ static void fcm_srv_receive(void *arg) goto err; switch (cmd) { - case FCP_CREATE_IF: + case CLIF_CREATE_CMD: FCM_LOG_DBG("FCMON CREATE\n"); if (fcm_save_reply(&reply, &from, fromlen, snum)) goto err_out; if (fcm_cli_create(ifname, FCP_CREATE_IF, &reply)) goto err_out; break; - case FCP_DESTROY_IF: + case CLIF_DESTROY_CMD: FCM_LOG_DBG("FCMON DESTROY\n"); if (fcm_save_reply(&reply, &from, fromlen, snum)) goto err_out; if (fcm_cli_destroy(ifname, FCP_DESTROY_IF, &reply)) goto err_out; break; - case FCP_RESET_IF: + case CLIF_RESET_CMD: FCM_LOG_DBG("FCMON RESET\n"); if (fcm_save_reply(&reply, &from, fromlen, snum)) goto err_out; - if (fcm_cli_reset(ifname, FCP_RESET_IF, &reply)) + if (fcm_cli_action(ifname, FCP_RESET_IF, &reply)) + goto err_out; + break; + case CLIF_SCAN_CMD: + FCM_LOG_DBG("FCMON SCAN\n"); + if (fcm_save_reply(&reply, &from, fromlen, snum)) + goto err_out; + if (fcm_cli_action(ifname, FCP_SCAN_IF, &reply)) goto err_out; break; - default: - fprintf(stderr, "BAD COMMAND\n"); - goto err_out; } free(ifname); @@ -2233,136 +2249,80 @@ err_out: err: snprintf(rbuf, MSG_RBUF, "%d", CLI_FAIL); sendto(snum, rbuf, MSG_RBUF, 0, (struct sockaddr *)&from, fromlen); - return; } -static int fcm_srv_create(struct fcm_srv_data *srv_data) +static int fcm_srv_create(struct fcm_srv_info *srv_info) { struct sockaddr_un addr; - int s = -1; - char *fname = NULL; - int retry; - size_t len; - - srv_data->srv_sock = -1; + int rc = 0; - if (srv_data->srv_interface == NULL) - return -1; - - if (mkdir(srv_data->srv_interface, S_IRWXU | S_IRWXG) < 0) { + if (mkdir(FCM_SRV_DIR, S_IRWXU | S_IRWXG) < 0) { if (errno == EEXIST) { - FCM_LOG_DBG("fcm_srv_create: directory existed."); + FCM_LOG_ERR(errno, "Failed to create socket " + "directory %s, this indicates that " + "fcoemon was not shutdown cleanly", + FCM_SRV_DIR); } else { - FCM_LOG_ERR(errno, "fcm_srv_create: mkdir[interface]"); - goto fail; + rc = errno; + FCM_LOG_ERR(errno, "Failed to create socket " + "directory %s\n", FCM_SRV_DIR); + goto err; } } - if (srv_data->srv_if_gid_set && - chown(srv_data->srv_interface, 0, - srv_data->srv_if_gid) < 0) { - FCM_LOG_ERR(errno, "fcm_srv_create: chown[srv_interface]"); - goto fail; - } - - if (strlen(srv_data->srv_interface) + 1 + strlen(srv_data->iface) - >= sizeof(addr.sun_path)) - goto fail; - - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) { - FCM_LOG_ERR(errno, "socket(PF_UNIX)"); - goto fail; + srv_info->srv_sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (srv_info->srv_sock < 0) { + FCM_LOG_ERR(errno, "Failed to create socket\n"); + rc = errno; + goto err_rmdir; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, CLIF_SOCK_FILE, sizeof(addr.sun_path)); - len = strlen(srv_data->srv_interface) + strlen(srv_data->iface) + 2; - fname = malloc(len); - memset(fname, 0, len); - if (fname == NULL) - goto fail; - - snprintf(fname, len, "%s/%s", - srv_data->srv_interface, srv_data->iface); - fname[len - 1] = '\0'; - - strncpy(addr.sun_path, fname, sizeof(addr.sun_path)); - for (retry = 0; retry < 2; retry++) { - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - if (errno == EADDRINUSE) - unlink(fname); - } else { - break; - } - } - if (retry == 2) { - FCM_LOG_ERR(errno, "bind(PF_UNIX)"); - goto fail; - } - - if (srv_data->srv_if_gid_set && - chown(fname, 0, srv_data->srv_if_gid) < 0) { - FCM_LOG_ERR(errno, "chown[srv_interface/ifname]"); - goto fail; - } + /* + * If there was a previous socket file unlink. If we don't + * then bind will fail. + */ + unlink(CLIF_SOCK_FILE); - if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { - FCM_LOG_ERR(errno, "chmod[srv_interface/ifname]"); - goto fail; + if (bind(srv_info->srv_sock, (struct sockaddr *)&addr, + sizeof(addr)) < 0) { + FCM_LOG_ERR(errno, "Failed to bind socket\n"); + rc = errno; + goto err_close; } - free(fname); - srv_data->srv_sock = s; - FCM_LOG_DBG("fcm_srv_create: created"); - sa_select_add_fd(s, fcm_srv_receive, NULL, NULL, srv_data); + sa_select_add_fd(srv_info->srv_sock, fcm_srv_receive, + NULL, NULL, srv_info); - return 0; + FCM_LOG_DBG("Successfully created socket, socket file and binding\n"); -fail: - if (s >= 0) - close(s); - if (fname) { - unlink(fname); - free(fname); - } - return -1; -} + return rc; -/* - * Create fcoemon server interface - */ -static void fcm_srv_init(void) -{ - if (!srv_data) { - srv_data = malloc(sizeof(struct fcm_srv_data)); - if (srv_data == NULL) { - FCM_LOG_ERR(errno, "srv_data malloc error\n"); - exit(EXIT_FAILURE); - } - } - - srv_data->srv_interface = (char *)FCM_SRV_DIR; - strncpy(srv_data->iface, CLIF_IFNAME, sizeof(CLIF_IFNAME)+1); - srv_data->srv_if_gid_set = 0; - srv_data->srv_if_gid = 0; +err_close: + close(srv_info->srv_sock); + unlink(CLIF_SOCK_FILE); - if (fcm_srv_create(srv_data)) - FCM_LOG_ERR(errno, "fcm_srv_init : fcm_srv_create() failed"); +err_rmdir: + rmdir(FCM_SRV_DIR); +err: + return rc; } -static void fcm_srv_shutdown(void) +static void fcm_srv_destroy(struct fcm_srv_info *srv_info) { FCM_LOG_DBG("Shutdown fcmon server"); - close(srv_data->srv_sock); - free(srv_data); - return; + close(srv_info->srv_sock); + unlink(CLIF_SOCK_FILE); + rmdir(FCM_SRV_DIR); } int main(int argc, char **argv) { + struct fcm_srv_info srv_info; struct sigaction sig; int fcm_fg = 0; int rc; @@ -2388,7 +2348,7 @@ int main(int argc, char **argv) enable_syslog(1); break; case 'v': - printf("%s\n", fcoemon_version); + printf("%s\n", FCOE_UTILS_VERSION); return 0; case 'h': default: @@ -2426,25 +2386,26 @@ int main(int argc, char **argv) */ memset(&sig, 0, sizeof(sig)); sig.sa_handler = fcm_sig; + rc = sigaction(SIGINT, &sig, NULL); if (rc < 0) { - FCM_LOG_ERR(errno, "sigaction failed"); + FCM_LOG_ERR(errno, "Failed to register handler for SIGINT"); exit(1); } rc = sigaction(SIGTERM, &sig, NULL); if (rc < 0) { - FCM_LOG_ERR(errno, "sigaction failed"); + FCM_LOG_ERR(errno, "Failed to register handler for SIGTERM"); exit(1); } rc = sigaction(SIGHUP, &sig, NULL); if (rc < 0) { - FCM_LOG_ERR(errno, "sigaction failed"); + FCM_LOG_ERR(errno, "Failed to register handler for SIGHUP"); exit(1); } fcm_pidfile_create(); /* check fcoe module */ - if (fcoeclif_checkdir(SYSFS_FCOE)) { + if (fcoe_checkdir(SYSFS_FCOE)) { FCM_LOG_ERR(errno, "make sure FCoE driver module is loaded!"); exit(1); } @@ -2452,7 +2413,7 @@ int main(int argc, char **argv) fcm_fcoe_init(); fcm_link_init(); /* NETLINK_ROUTE protocol */ fcm_dcbd_init(); - fcm_srv_init(); + fcm_srv_create(&srv_info); sa_select_set_callback(fcm_handle_changes); rc = sa_select_loop(); @@ -2461,7 +2422,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } fcm_dcbd_shutdown(); - fcm_srv_shutdown(); + fcm_srv_destroy(&srv_info); fcm_cleanup(); return 0; } diff --git a/fcoemon.h b/fcoemon.h index 74a3bad..a36128d 100644 --- a/fcoemon.h +++ b/fcoemon.h @@ -20,6 +20,8 @@ #ifndef _FCOEMON_H_ #define _FCOEMON_H_ +#include "fcoe_utils.h" + struct fcoe_config { int debug; int use_syslog; @@ -88,6 +90,7 @@ enum fcp_action { FCP_CREATE_IF, /* create FCoE interface */ FCP_DESTROY_IF, /* destroy FCoE interface */ FCP_RESET_IF, /* reset FCoE interface */ + FCP_SCAN_IF, /* scan FCoE interface */ FCP_ENABLE_IF, /* enable FCoE interface */ FCP_DISABLE_IF, /* disable FCoE interface */ FCP_ACTIVATE_IF, /* create or enable FCoE interface */ @@ -143,24 +146,17 @@ struct fcm_netif { /* * Description of fcoe socket server interface */ -struct fcm_srv_data { - char iface[IFNAMSIZ+1]; - char *srv_interface; - gid_t srv_if_gid; - int srv_if_gid_set; +struct fcm_srv_info { int srv_sock; }; TAILQ_HEAD(fcm_netif_head, fcm_netif); struct fcm_netif_head fcm_netif_head; -extern char build_date[]; static void fcm_dcbd_init(void); static void fcm_dcbd_shutdown(void); static void fcm_fcoe_init(void); -static void fcm_srv_init(void); -static void fcm_srv_shutdown(void); static struct fcm_netif *fcm_netif_lookup(char *); static struct fcm_netif *fcm_netif_lookup_create(char *); static int fcm_link_init(void); diff --git a/fcping.c b/fcping.c index e75bc01..302dc2d 100644 --- a/fcping.c +++ b/fcping.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2010 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, @@ -54,6 +54,8 @@ typedef uint8_t u8; #include #include +#include "fcoe_utils.h" + static const char *cmdname; #define FC_MAX_PAYLOAD (2112U - sizeof(net32_t)) @@ -69,8 +71,9 @@ static void fp_usage() { fprintf(stderr, - "Usage: %s [-fqx] -i -c -h -s \\\n" - " [ -F | -P | -N ]\n" + "Usage: %s [-fqx] -i [ -c ] -h " + "[ -s ] \n" + " [ -F | -P | -N ]\n" " flags: \n" " -f: Flood ping\n" " -q: Quiet! just print summary\n" @@ -547,7 +550,9 @@ fp_find_hba(void) } break; default: - if (!strstr(port_attrs.PortSymbolicName, fp_hba)) { + if (check_symbolic_name_for_interface( + port_attrs.PortSymbolicName, + fp_hba)) { HBA_CloseAdapter(hba_handle); continue; } diff --git a/fipvlan.c b/fipvlan.c index ffdd8f9..cc8a785 100644 --- a/fipvlan.c +++ b/fipvlan.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2009 Intel Corporation. All rights reserved. + * Copyright(c) 2010 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, @@ -36,7 +36,7 @@ #include #include #include -#include "fcoe_utils.h" +#include "fcoe_utils_version.h" #include "fip.h" #include "log.h" #include "list.h"