diff --git a/scsi_tgt_if.h b/scsi_tgt_if.h deleted file mode 100644 index d99154f..0000000 --- a/scsi_tgt_if.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SCSI target kernel/user interface - * - * Copyright (C) 2005 FUJITA Tomonori - * Copyright (C) 2005 Mike Christie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that 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 - */ -#ifndef __SCSI_TARGET_IF_H -#define __SCSI_TARGET_IF_H - -/* user -> kernel */ -#define TGT_UEVENT_CMD_RSP 0x0001 -#define TGT_UEVENT_IT_NEXUS_RSP 0x0002 -#define TGT_UEVENT_TSK_MGMT_RSP 0x0003 - -/* kernel -> user */ -#define TGT_KEVENT_CMD_REQ 0x1001 -#define TGT_KEVENT_CMD_DONE 0x1002 -#define TGT_KEVENT_IT_NEXUS_REQ 0x1003 -#define TGT_KEVENT_TSK_MGMT_REQ 0x1004 - -struct tgt_event_hdr { - uint16_t version; - uint16_t status; - uint16_t type; - uint16_t len; -} __attribute__ ((aligned (sizeof(uint64_t)))); - -struct tgt_event { - struct tgt_event_hdr hdr; - - union { - /* user-> kernel */ - struct { - int host_no; - int result; - aligned_u64 itn_id; - aligned_u64 tag; - aligned_u64 uaddr; - aligned_u64 sense_uaddr; - uint32_t len; - uint32_t sense_len; - uint8_t rw; - } cmd_rsp; - struct { - int host_no; - int result; - aligned_u64 itn_id; - aligned_u64 mid; - } tsk_mgmt_rsp; - struct { - __s32 host_no; - __s32 result; - aligned_u64 itn_id; - __u32 function; - } it_nexus_rsp; - - /* kernel -> user */ - struct { - int host_no; - uint32_t data_len; - aligned_u64 itn_id; - uint8_t scb[16]; - uint8_t lun[8]; - int attribute; - aligned_u64 tag; - } cmd_req; - struct { - int host_no; - int result; - aligned_u64 itn_id; - aligned_u64 tag; - } cmd_done; - struct { - int host_no; - int function; - aligned_u64 itn_id; - aligned_u64 tag; - uint8_t lun[8]; - aligned_u64 mid; - } tsk_mgmt_req; - struct { - __s32 host_no; - __u32 function; - aligned_u64 itn_id; - __u32 max_cmds; - __u8 initiator_id[16]; - } it_nexus_req; - } p; -} __attribute__ ((aligned (sizeof(uint64_t)))); - -#define TGT_RING_SIZE (1UL << 16) - -#endif diff --git a/tgt-0.9.0-update b/tgt-0.9.0-update deleted file mode 100644 index f44ea04..0000000 --- a/tgt-0.9.0-update +++ /dev/null @@ -1,1909 +0,0 @@ -diff --git a/README b/README -index dd99e74..22785fc 100644 ---- a/README -+++ b/README -@@ -3,46 +3,53 @@ Introduction - Linux target framework (tgt) aims to simplify various SCSI target - driver (iSCSI, Fibre Channel, SRP, etc) creation and maintenance. - --Tgt consists of kernel modules, user-space daemon, and user-space --tools. Some target drivers uses all of them and some use only --user-space daemon and tools (i.e. they completely runs in user space). -+Currently, tgt supports the following target drivers: - --Currently, tgt supports three target drivers: -+- iSCSI software target driver for Ethernet NICs - --- IBM VIO server (ibmvstgt) --- iSCSI --- Xen vscsifront/back -+- iSER software target driver for Infiniband and RDMA NICs - --Note that tgt is under active development. Don't play with important --data. -+- IBM System p VIO server - --The code is under the GNU General Public License version 2. -+- FCoE software target driver for Ethernet NICs (in progress) - -+- Qlogic qla2xxx FC target driver (in progress) - --Preparation --------------- --The iSCSI target driver can works with the 2.6.X kernels. It requires --OpenSSL library (libssl-dev for debian, openssl-devel for Fedora). -+Tgt consists of kernel modules, user-space daemon, and user-space -+tools. iSCSI, iSER, and FCoE target drivers use only user-space daemon -+and tools (i.e. they are just user-space applications. They don't need -+any kernel support). -+ -+tgt can emulate the following device types: - --host:~/tgt/usr$ make ISCSI=1 -+- SBC: a virtual disk drive that can use a file to store the content. - --If you want IBM VIO target driver, get kernel version 2.6.20, rebuild --the kernel, and reboot with the new kernel. Note you need to enable --SCSI_TGT, SCSI_SRP, and SCSI_IBMVSCSIS kernel options. -+- SMC: a virtual media jukebox that can be controlled by the "mtx" -+tool (partially functional). - --host:~/tgt/usr$ make KERNELSRC= IBMVIO=1 -+- MMC: a virtual DVD drive that can read DVD-ROM iso files and create -+burnable DVD+R. It can be combined with SMC to provide a fully -+operational DVD jukebox. - --Make sure that everything is built successfully. -+- SSC: a virtual tape device (aka VTL) that can use a file to store -+the content (in progress). - --Now you can run tgt. Target drivers have their own ways for --configuration. So find an appropriate documentation in the doc --directory. -+- OSD: a virtual object-based storage device that can use a file to -+store the content (in progress). -+ -+The code is under the GNU General Public License version 2. -+ -+ -+Preparation -+------------- -+Target drivers have their own ways to build, configure, etc. So find -+an appropriate documentation in the doc directory. - - - Developer Notes - ------------- - The central resource for tgt development is the mailing list --(stgt-devel@lists.berlios.de). -+(stgt@vger.kernel.org). - - First, please read the following documents (in short, follow Linux - kernel development rules): -diff --git a/doc/README.ibmvstgt b/doc/README.ibmvstgt -index 9a9dbd8..d77f932 100644 ---- a/doc/README.ibmvstgt -+++ b/doc/README.ibmvstgt -@@ -1,5 +1,13 @@ - Starting - ------------- -+If you want IBM VIO target driver, get kernel version 2.6.20, rebuild -+the kernel, and reboot with the new kernel. Note you need to enable -+SCSI_TGT, SCSI_SRP, and SCSI_IBMVSCSIS kernel options. -+ -+host:~/tgt/usr$ make KERNELSRC= IBMVIO=1 -+ -+Make sure that everything is built successfully. -+ - Try the following commands: - - host:~/tgt$ su -diff --git a/doc/README.iscsi b/doc/README.iscsi -index 5aec190..e6b4d09 100644 ---- a/doc/README.iscsi -+++ b/doc/README.iscsi -@@ -5,6 +5,13 @@ This show a simple example to set up some targets. - - Starting the daemon - ------------- -+The iSCSI target driver works with the 2.6.X kernels. It requires -+OpenSSL library (libssl-dev for debian, openssl-devel for Fedora). -+ -+First, you need to compile the source code: -+ -+host:~/tgt/usr$ make ISCSI=1 -+ - Try the following commands: - - host:~/tgt$ su -diff --git a/doc/targets.conf.example b/doc/targets.conf.example -new file mode 100644 -index 0000000..46be8fe ---- /dev/null -+++ b/doc/targets.conf.example -@@ -0,0 +1,168 @@ -+# This is a sample config file for tgt-admin. -+# By default, tgt-admin looks for its config file in /etc/tgt/targets.conf -+ -+# This one includes other config files: -+ -+include /etc/tgt/temp/*.conf -+ -+ -+# Set the driver. If not specified, defaults to "iscsi". -+ -+default-driver iscsi -+ -+ -+# Sample target with one LUN only. Defaults to allow access for all initiators: -+ -+ -+ backing-store /dev/LVM/somedevice -+ -+ -+ -+# Similar, but we use "direct-store" instead of "backing-store". -+# "direct-store" reads drive parameters with sg_inq command and sets them to -+# the target. -+# Parameters fatched with sg_inq are: -+# - Vendor identification -+# - Product identification -+# - Product revision level -+# - Unit serial number (if present) -+# We also specify "incominguser". -+ -+ -+ direct-store /dev/sdd -+ incominguser someuser secretpass12 -+ -+ -+ -+# An example with multiple LUNs, disabled write-cache (tgtd enables write-cache -+# by default) and vendor identification set to "MyVendor" -+ -+ -+ backing-store /dev/LVM/somedevice1 # Becomes LUN 1 -+ backing-store /dev/LVM/somedevice2 # Becomes LUN 2 -+ backing-store /dev/LVM/somedevice3 # Becomes LUN 3 -+ write-cache off -+ vendor_id MyCompany Inc. -+ -+ -+ -+# Similar to the one above, but we fetch vendor_id, product_id, product_rev and -+# scsi_sn from the disks. -+# Vendor identification (vendor_id) is replaced in all disks by "MyVendor" -+ -+ -+ direct-store /dev/sdb # Becomes LUN 1 -+ direct-store /dev/sdc # Becomes LUN 2 -+ direct-store /dev/sdd # Becomes LUN 3 -+ write-cache off -+ vendor_id MyCompany Inc. -+ -+ -+ -+# Note that "first-device-first-lun numbering" will work only for simple -+# scenarios above, where _only_ direct-store _or_ backing-store is used. -+# If you mix backing-store and direct-store, then all backing-store entries -+# are processed before direct-store-entries. -+ -+ -+ direct-store /dev/sdb # Becomes LUN 3 -+ backing-store /dev/sdc # Becomes LUN 1 -+ direct-store /dev/sdd # Becomes LUN 4 -+ backing-store /dev/sde # Becomes LUN 2 -+ -+ -+ -+# Even more complicated example - each device has different parameters. -+# You can use indentation to make the config file more readable. -+# Note that LUNs will be assigned more or less randomly here (and still -+# backing-store get LUNs assigned before drect-store). -+# You can specify multiple mode_page parameters (they are commented out -+# in this example). -+# Note that some parameters (write-cache, scsi_sn) were specified "globally". -+# "Global" parameters will be applied to all LUNs; they can be overwritten -+# "locally", per LUN. -+ -+ -+ -+ -+ vendor_id VENDOR1 -+ removable 1 -+ device-type cd -+ # lun 1 # Not yet supported -+ -+ -+ -+ vendor_id VENDOR2 -+ # lun 2 # Not yet supported -+ -+ -+ -+ vendor_id back1 -+ scsi_sn SERIAL -+ write-cache on -+ # lun 3 # Not yet supported -+ -+ -+ -+ vendor_id back2 -+ #mode_page 8:0:18:0x10:0:0xff.... -+ #mode_page 8:0:18:0x10:0:0xff.... -+ # lun 4 # Not yet supported -+ -+ -+ # Some more parameters which can be specified locally or globally: -+ #scsi_id ... -+ #scsi_sn ... -+ #vendor_id ... -+ #product_id ... -+ #product_rev ... -+ #sense_format ... -+ #removable ... -+ #online ... -+ #path ... -+ #mode_page 8:0:18:0x10:0:0xff.... -+ #mode_page 8:0:18:0x10:0:0xff.... -+ #device-type -+ -+ write-cache off -+ scsi_sn multipath-10 -+ -+ # Parameters below are global. They can't be configured per LUN. -+ # Only allow connections from 192.168.100.1 and 192.168.200.5 -+ initiator-address 192.168.100.1 -+ initiator-address 192.168.200.5 -+ -+ # Allowed incoming users -+ incominguser user1 secretpass12 -+ incominguser user2 secretpass23 -+ -+ # Outgoing user -+ outgoinguser userA secretpassA -+ -+ -+ -+ -+ -+# Not supported configurations, and therefore, commented out: -+ -+# -+# -+# vendor_id VENDOR1 -+# -+# -+# direct-store /dev/sdc -+# -+ -+# This one will break the parser: -+ -+# -+# -+# vendor_id VENDOR1 -+# -+# -+# direct-store /dev/sdc -+# -+# -+# vendor_id VENDOR1 -+# -+# -diff --git a/scripts/tgt-admin b/scripts/tgt-admin -index fe95723..e4be373 100755 ---- a/scripts/tgt-admin -+++ b/scripts/tgt-admin -@@ -11,7 +11,6 @@ - - use strict; - use Config::General qw(ParseConfig); --use Data::Dumper; - use Getopt::Long; - - # Our config file -@@ -30,12 +29,15 @@ This tool configures tgt targets. - (see "--offline help" for more info) - --ready put all or selected targets in ready state - (see "--ready help" for more info) -+ --update update configuration for all or selected targets -+ (see "--update help" for more info) - -s, --show show all the targets - -c, --conf specify an alternative configuration file - --ignore-errors continue even if tgtadm exits with non-zero code - -f, --force force some operations even if the target is in use - -p, --pretend only print tgtadm options -- --dump dump current tgtd configuration -+ --dump dump current tgtd configuration (note: does not -+ include detailed parameters, like write caching) - -v, --verbose increase verbosity (show tgtadm commands) - -h, --help show this help - -@@ -49,6 +51,7 @@ my $execute = 0; - my $delete = 0; - my $offline = 0; - my $ready = 0; -+my $update = 0; - my $show = 0; - my $alternate_conf="0"; - my $ignore_errors = 0; -@@ -62,6 +65,7 @@ my $result = GetOptions ( - "delete=s" => \$delete, - "offline=s" => \$offline, - "ready=s" => \$ready, -+ "update=s" => \$update, - "s|show" => \$show, - "c|conf=s" => \$alternate_conf, - "ignore-errors" => \$ignore_errors, -@@ -73,7 +77,7 @@ my $result = GetOptions ( - ); - - if (($help == 1) || ($param eq undef)) { -- &usage -+ usage; - } - - # Show all the targets and exit -@@ -99,7 +103,6 @@ sub process_targets { - my @show_target = `tgtadm --op show --mode target`; - my $tid; - my $targetname; -- - # Here, we create hashes of target names (all target data) and target tids - foreach my $show_target_line (@show_target) { - if ( $show_target_line =~ m/^Target (\d*): (.+)/ ) { -@@ -128,7 +131,7 @@ sub parse_configs { - %conf = ParseConfig(-ConfigFile => "$alternate_conf", -UseApacheInclude => 1, -IncludeGlob => 1,); - } - else { -- die("file $alternate_conf not found. Exiting...\n"); -+ die("Config file $alternate_conf not found. Exiting...\n"); - } - } else { - # Parse the config file with Config::General -@@ -145,13 +148,17 @@ my $default_driver; - my $target; - my $option; - my $value; -+my $lun; - - sub add_targets { -- -+ my $single_target = $_[0]; -+ my $configured = $_[1]; -+ my $connected = $_[2]; -+ my $in_configfile = $_[3]; - foreach my $k (sort keys %conf) { - -- if ( $k eq "default-driver" ) { -- if ( not length ref($conf{$k}) ) { -+ if ($k eq "default-driver") { -+ if (not length ref($conf{$k})) { - $default_driver = $conf{$k}; - } else { - print "Multiple default-driver definitions are not allowed!\n"; -@@ -162,134 +169,344 @@ sub add_targets { - } - - # If $default_driver is empty, default to iscsi -- if ( not defined $default_driver ) { -+ if (not defined $default_driver) { - execute("# default-driver not defined, defaulting to iscsi.\n"); - $default_driver = "iscsi"; - } - - foreach my $k (sort keys %conf) { -- if ( $k eq "target" ) { -+ if ($k eq "target") { - foreach my $k2 (sort keys %{$conf{$k}}) { -- $target = $k2; -- my $allowall = 1; -- if ( not defined $tgtadm_output{$k2} ) { -- # We have to find available tid -- $next_tid = $next_tid + 1; -+ # Do we run update or execute? -+ if (length $single_target) { -+ if ($single_target ne $k2) { -+ next; -+ } else { -+ $target = $single_target; -+ } -+ } else { -+ $target = $k2; - } -- else { -- execute("# Target $target already exist!"); -- execute("# Updating Target $target"); -- execute("tgtadm --op update --mode target --tid=$next_tid -n state -v offline"); -- execute("tgtadm --mode target --op delete --tid=$next_tid"); -+ -+ my $in_use = 0; -+ if (length $single_target) { -+ $in_use = main_delete($target); - } -+ my $allowall = 1; -+ if ((not defined $tgtadm_output{$k2}) || -+ ($update ne 0 && $in_use == 0) || -+ ($update ne 0 && $in_use == 1 && $pretend == 1 && $force == 1)) -+ { -+ # We have to find available tid -+ if ($in_configfile == 1 && $configured == 0 && $pretend == 0) { -+ my $maxtid = find_max_tid(); -+ $next_tid = $maxtid + 1; -+ } elsif (length $single_target && $configured == 1) { -+ $next_tid = $tgtadm_output_tid{$target}; -+ } else { -+ $next_tid = $next_tid + 1; -+ } -+ -+ # Before we add a target, we need to know its type -+ # and other parameters which can be specified globally -+ my %target_options; -+ my $target_options_ref; -+ foreach my $k3 (sort keys %{$conf{$k}{$k2}}) { -+ $lun = 1; -+ $option = $k3; -+ $value = $conf{$k}{$k2}{$k3}; -+ check_value($value); -+ $target_options{$option} = $value; -+ $target_options_ref = \%target_options; -+ } - -- # Before we add a target, we need to know its type -- my $driver; -- foreach my $k3 (sort keys %{$conf{$k}{$k2}}) { -- $option = $k3; -- $value = $conf{$k}{$k2}{$k3}; -- &check($value); -- if ( $option eq "driver" ) { -- if (ref($value) eq "ARRAY") { -- print "Multiple driver definitions not allowed!\n"; -- print "Check your config file for errors (target: $target).\n"; -- exit 1; -+ if (not defined $target_options{"driver"}) { -+ $target_options{"driver"} = $default_driver; -+ } -+ my $driver = $target_options{"driver"}; -+ execute("# Adding target: $target"); -+ execute("tgtadm --lld $driver --op new --mode target --tid $next_tid -T $target"); -+ foreach my $k3 (sort keys %{$conf{$k}{$k2}}) { -+ $option = $k3; -+ $value = $conf{$k}{$k2}{$k3}; -+ check_value($value); -+ process_options($target_options_ref); -+ # If there was no option called "initiator-address", it means -+ # we want to allow ALL initiators for this target -+ if ($option eq "initiator-address") { -+ $allowall = 0; - } -- $driver = $value; -+ } -+ -+ if ($allowall == 1) { -+ execute("tgtadm --lld $driver --op bind --mode target --tid $next_tid -I ALL"); -+ } -+ -+ } else { -+ if (not length $configured || $in_use eq 1) { -+ execute("# Target $target already exists!"); - } - } -+ } -+ if (length $single_target && $in_configfile == 0 && $configured == 0) { -+ print "Target $single_target is currently not configured\n"; -+ print "and does not exist in the config file - can't continue!\n"; -+ exit 1; -+ } -+ execute(); -+ } -+ } -+} - -- if ( not defined $driver ) { -- $driver = $default_driver; -+# Some options can be specified only once -+sub check_if_hash_array { -+ my $check = $_[0]; -+ my $definition = $_[1]; -+ if (ref($check) eq 'ARRAY' || ref($check) eq "HASH") { -+ print "Multiple '$definition' definitions in '$option' not allowed!\n"; -+ print "Check your config file for errors (target: $target).\n"; -+ exit 1; -+ } -+} -+ -+# Force an array if we just have one command -+sub force_array { -+ unless (ref($value) eq 'ARRAY') { -+ $value = [ $value ]; -+ } -+} -+ -+# If we start any external command, we want to know if it exists -+sub check_exe { -+ my $command = $_[0]; -+ my $option = $_[1]; -+ my @path = split(":", $ENV{PATH}); -+ my $exists = 0; -+ foreach my $path (@path) { -+ if ( -x "$path/$command" && -f "$path/$command" ) { $exists = 1 } -+ } -+ if ( $exists == 0 ) { -+ print "Command $command (needed by $option option in your config file) is not in your path - can't continue!\n"; -+ exit 1; -+ } -+} -+ -+# Apply additional parameters -+sub add_params { -+ my $param = shift; -+ my $param_value = shift; -+ my $lun = shift; -+ my $driver = shift; -+ -+ if ($param eq "write-cache") { -+ if ($param_value eq "off") { -+ return("tgtadm --lld $driver --op update --mode logicalunit --tid $next_tid --lun=$lun --params mode_page=8:0:18:0x10:0:0xff:0xff:0:0:0xff:0xff:0xff:0xff:0x80:0x14:0:0:0:0:0:0"); -+ } elsif ($param_value eq "on" || not length $param_value) { -+ return("# Write cache is enabled (default) for lun $lun."); -+ } else { -+ return("# WARNING! Unknown value ($param_value) to write-cache! Accepted values are \"on\" and \"off\"."); -+ } -+ } -+ -+ if ($param eq "scsi_id" || $param eq "scsi_sn" || $param eq "vendor_id" || $param eq "product_id" || -+ $param eq "product_rev" || $param eq "sense_format" || $param eq "removable" || $param eq "online" || -+ $param eq "path" || $param eq "mode_page") { -+ return("tgtadm --lld $driver --op update --mode logicalunit --tid $next_tid --lun=$lun --params $param=\"$param_value\""); -+ } -+} -+ -+# Add backing or direct store -+sub add_backing_direct { -+ my $backing_store = $_[0]; -+ my $target_options_ref = $_[1]; -+ my $lun = $_[2]; -+ my $direct_store = $_[3]; -+ my $driver = $$target_options_ref{"driver"}; -+ -+ # Is the device in use? -+ (my $can_alloc, my $dev) = check_device($backing_store); -+ -+ # Needed if the config file has mixed definitions -+ if (ref($backing_store) eq "HASH") { -+ foreach my $backing_store (sort keys %$value) { -+ add_backing_direct($backing_store,$target_options_ref,$lun,$direct_store); -+ $lun += 1; -+ } -+ return $lun; -+ } elsif (-e $backing_store && $can_alloc == 1) { -+ my @exec_commands; -+ my $device_type; -+ # Process parameters for each lun / backing store -+ if (ref $value eq "HASH") { -+ my %params_added; -+ my @mode_page; -+ foreach my $store (keys %$value) { -+ if (ref $$value{$store} eq "HASH" && $store eq $backing_store) { -+ foreach my $store_option (keys %{$$value{$store}}) { -+ my $result = $$value{$store}{$store_option}; -+ check_value($result); -+ if ($store_option ne "mode_page") { check_if_hash_array($result,$store_option) } -+ # write-cache can be set globally per target and overridden per lun, -+ # so we treat it differently -+ if ($store_option ne "mode_page" && $store_option ne "write-cache") { -+ my $exec_command = add_params($store_option, $result, $lun, $driver); -+ push(@exec_commands, $exec_command); -+ $params_added{$store_option} = 1; -+ } -+ if ($store_option eq "write-cache") { -+ my $exec_command = add_params($store_option, $result, $lun, $driver); -+ $params_added{write_cache} = 1; -+ push(@exec_commands, $exec_command); -+ } -+ if ($store_option eq "device-type") { -+ $device_type = $result; -+ $params_added{$store_option} = 1; -+ } -+ if ($store_option eq "mode_page") { -+ @mode_page = @$result; -+ foreach my $mode_page (@mode_page) { -+ my $exec_command = add_params("mode_page", $mode_page, $lun, $driver); -+ push(@exec_commands, $exec_command); -+ } -+ } -+ } - } -- execute("# Adding target: $target"); -- execute("tgtadm --lld $driver --op new --mode target --tid $next_tid -T $target"); -- foreach my $k3 (sort keys %{$conf{$k}{$k2}}) { -- $option = $k3; -- $value = $conf{$k}{$k2}{$k3}; -- &check($value); -- &process_options($driver); -- # If there was no option called "initiator-address", it means -- # we want to allow ALL initiators for this target -- if ( $option eq "initiator-address" ) { -- $allowall = 0; -+ } -+ # Used only if lun is a direct-store -+ my $sg_inq; -+ my %direct_params; -+ if ($direct_store == 1) { -+ $sg_inq=`sg_inq $backing_store`; -+ if ($sg_inq=~m { -+ Vendor\ identification:\s+?(.*?)\n -+ \s+Product\ identification:\s+(.*?)\n -+ \s+Product\ revision\ level:\s+(.*?)\n -+ (?:\s+Unit\ serial\ number:\s+(.*?)\n)? -+ }xs ) { -+ # If they were not defined globally for a target, -+ # add them now -+ if (not length $$target_options_ref{vendor_id}) { -+ $direct_params{vendor_id} = $1; -+ } -+ if (not length $$target_options_ref{product_id}) { -+ $direct_params{product_id} = $2; -+ } -+ if (not length $$target_options_ref{product_rev}) { -+ $direct_params{product_rev} = $3; -+ } -+ if (not length $$target_options_ref{scsi_sn}) { -+ $direct_params{scsi_sn} = $4; - } - } -+ } - -- if ( $allowall == 1 ) { -- execute("tgtadm --lld $driver --op bind --mode target --tid $next_tid -I ALL"); -+ # Add these parameters if they were not overwritten in the config file -+ my @opts = ("scsi_id", "sense_format", "removable", "online", "path"); -+ foreach my $single_opt (@opts) { -+ check_if_hash_array($$target_options_ref{$single_opt},$single_opt); -+ if ($params_added{$single_opt} ne 1 && length $$target_options_ref{$single_opt}) { -+ my $exec_command = add_params($single_opt, $$target_options_ref{$single_opt}, $lun, $driver); -+ push(@exec_commands, $exec_command); -+ $params_added{$single_opt} = 1; - } -- execute(); - } -+ # These options can be fetched by sg_inq for direct-store -+ my @opts = ("vendor_id", "product_id", "product_rev", "scsi_sn"); -+ foreach my $single_opt (@opts) { -+ check_if_hash_array($$target_options_ref{$single_opt},$single_opt); -+ my $this_opt; -+ if (length $$target_options_ref{$single_opt}) { -+ $this_opt = $$target_options_ref{$single_opt}; -+ } elsif (length $direct_params{$single_opt}) { -+ $this_opt = $direct_params{$single_opt}; -+ } -+ if ($params_added{$single_opt} ne 1 && length $this_opt) { -+ my $exec_command = add_params($single_opt, $this_opt, $lun, $driver); -+ push(@exec_commands, $exec_command); -+ $params_added{$single_opt} = 1; -+ } -+ } -+ # write-cache -+ if ($params_added{write_cache} ne 1) { -+ my $exec_command = add_params("write-cache", $$target_options_ref{"write-cache"}, $lun, $driver); -+ push(@exec_commands, $exec_command); -+ $params_added{write_cache} = 1; -+ } -+ # mode_page -+ unless (ref($$target_options_ref{mode_page}) eq 'ARRAY') { -+ $$target_options_ref{mode_page} = [ $$target_options_ref{mode_page} ]; -+ } -+ foreach my $mode_page (@{$$target_options_ref{"mode_page"}}) { -+ if (length $mode_page) { -+ my $exec_command = add_params("mode_page", $mode_page, $lun, $driver); -+ push(@exec_commands, $exec_command); -+ } -+ } -+ # device-type -+ if ($params_added{"device-type"} ne 1) { -+ check_if_hash_array($$target_options_ref{"device-type"}, "device-type"); -+ $device_type = $$target_options_ref{"device-type"}; -+ } -+ } else { -+ print "If you got here, this means your config file is not supported.\n"; -+ print "Please report it to stgt mailing list and attach your config files.\n"; -+ exit 1; -+ } -+ # Execute commands for a given LUN -+ if (length $device_type) { $device_type = "--device-type $device_type" }; -+ execute("tgtadm --lld $driver --op new --mode logicalunit --tid $next_tid --lun $lun -b $backing_store $device_type"); -+ foreach my $exec_command (@exec_commands) { -+ if (length $exec_command) { execute($exec_command) } - } -+ $lun += 1; -+ return $lun; -+ } elsif ($can_alloc == 0) { -+ execute("# Skipping device $backing_store ($dev is mounted / in use)"); -+ } else { -+ execute("# Skipping device: $backing_store"); -+ execute("# $backing_store does not exist - please check the configuration file"); - } - } - - # Process options from the config file - sub process_options { -- my $driver = $_[0]; -- if ( $option eq "backing-store" ) { -- # if we have one command, force it to be an array anyway -- unless (ref($value) eq 'ARRAY') { -- $value = [ $value ]; -+ my $target_options_ref = $_[0]; -+ my $driver = $$target_options_ref{"driver"}; -+ if ($option eq "backing-store" || $option eq "direct-store") { -+ my $direct_store = 0; -+ if ($option eq "direct-store") { -+ check_exe("sg_inq", "direct-store"); -+ $direct_store = 1; - } -- my @value_arr = @$value; -- my $i = 1; - -- foreach my $backing_store (@value_arr) { -- # Check if device exists -- if ( -e $backing_store) { -- execute("tgtadm --lld $driver --op new --mode logicalunit --tid $next_tid --lun $i -b $backing_store"); -- $i += 1; -- } -- else { -- print("skipping device $backing_store\n"); -- print("$backing_store does not exist - please check the configuration file\n"); -- } -+ # We want to make everything a hash to use it -+ # in the same way later on -+ unless (ref($value)) { -+ $value = { $value } - } -- } - -- if ( $option eq "direct-store" ) { -- my $inq; -- my $vendor_id=""; -- my $prod_id=""; -- my $prod_rev=""; -- my $scsi_serial=""; -- # if we have one command, force it to be an array anyway -- unless (ref($value) eq 'ARRAY') { -- $value = [ $value ]; -- } -- my @value_arr = @$value; -- my $i = 1; -- foreach my $direct_store (@value_arr) { -- $inq=`sg_inq $direct_store`; -- if ($inq=~/Vendor identification:\s*(\w+)\s*\n*Product identification:\s*([\w\s\/\-]+)\n\s*\n*Product revision level:\s*(\w*)\s*\n*Unit serial number:\s*(\w+)/) -- { -- $vendor_id="$1"; -- $prod_id="$2"; -- $prod_rev="$3"; -- $scsi_serial="$4"; -+ my %arrvalue; -+ if (ref($value) eq "ARRAY") { -+ foreach my $backing_store (@$value) { -+ $arrvalue{$backing_store} = 1; - } -- $vendor_id =~ s/\s+$//; -- $prod_id =~ s/\s+$//; -- $prod_rev =~ s/\s+$//; -- $scsi_serial =~ s/\s+$//; -+ $value = \%arrvalue; -+ } - -- execute("tgtadm --lld $driver --op new --mode logicalunit --tid $next_tid --lun 1 -b $direct_store"); -- execute("tgtadm --lld $driver --op update --mode logicalunit --tid $next_tid --lun 1 --params vendor_id=\"$vendor_id\",product_id=\"$prod_id\",product_rev=\"$prod_rev\",scsi_sn=\"$scsi_serial\""); -- $i += 1; -+ if (ref($value) eq "HASH") { -+ foreach my $backing_store (sort keys %$value) { -+ $lun = add_backing_direct($backing_store,$target_options_ref,$lun,$direct_store); -+ } - } - } - - if ( $option eq "incominguser" ) { - # if we have one command, force it to be an array anyway -- unless (ref($value) eq 'ARRAY') { -- $value = [ $value ]; -- } -+ force_array(); - my @value_arr = @$value; - foreach my $incominguser (@value_arr) { - my @userpass = split(/ /, $incominguser); -- &check($userpass[1]); -+ check_value($userpass[1]); - execute("tgtadm --lld $driver --mode account --op delete --user=$userpass[0]"); - execute("tgtadm --lld $driver --mode account --op new --user=$userpass[0] --password=$userpass[1]"); - execute("tgtadm --lld $driver --mode account --op bind --tid=$next_tid --user=$userpass[0]"); -@@ -298,12 +515,10 @@ sub process_options { - - if ( $option eq "outgoinguser" ) { - # if we have one command, force it to be an array anyway -- unless (ref($value) eq 'ARRAY') { -- $value = [ $value ]; -- } -+ force_array(); - execute("# Warning: only one outgoinguser is allowed. Will only use the first one."); - my @userpass = split(/ /, @$value[0]); -- &check($userpass[1]); -+ check_value($userpass[1]); - execute("tgtadm --lld $driver --mode account --op delete --user=$userpass[0]"); - execute("tgtadm --lld $driver --mode account --op new --user=$userpass[0] --password=$userpass[1]"); - execute("tgtadm --lld $driver --mode account --op bind --tid=$next_tid --user=$userpass[0] --outgoing"); -@@ -311,21 +526,20 @@ sub process_options { - - if ( $option eq "initiator-address" ) { - # if we have one command, force it to be an array anyway -- unless (ref($value) eq 'ARRAY') { -- $value = [ $value ]; -- } -+ force_array(); - my @value_arr = @$value; - foreach my $initiator_address (@value_arr) { -+ check_value($initiator_address); - execute("tgtadm --lld $driver --op bind --mode target --tid $next_tid -I $initiator_address"); - } - } - } - - # If the target is configured, but not present in the config file, --# offline it and try to remove it -+# try to remove it - sub remove_targets { - -- &process_targets; -+ process_targets; - my @all_targets = keys %tgtadm_output_tid; - - foreach my $existing_target (@all_targets) { -@@ -340,13 +554,8 @@ sub remove_targets { - } - - if ( $dontremove == 0 ) { -- # Right now, it is not possible to remove a target if any initiators -- # are connected to it. We'll do our best - offline the target first -- # (so it won't accept any new connections), and remove. -- # Note that remove will only work if no initiator is connected. -- execute("# Removing target: $existing_target"); -- execute("tgtadm --op update --mode target --tid=$tgtadm_output_tid{$existing_target} -n state -v offline"); -- execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$existing_target}"); -+ # Remove the target -+ main_delete($existing_target); - } - } - } -@@ -356,61 +565,54 @@ sub remove_targets { - # Dump current tgtd configuration - sub dump_config { - -- &process_targets; -+ process_targets; - - my @all_targets = keys %tgtadm_output_tid; - -- foreach my $target (@all_targets) { -- foreach my $show_target_line ($tgtadm_output{$target}) { -- if ( $show_target_line =~ m/^Target (\d*): (.+)/ ) { -- print "\n"; -- } -+ # If all targets use the same driver, us it only once in the config -+ my $skip_driver = 0; -+ my @drivers_combined; -+ foreach my $current_target (@all_targets) { -+ my $driver = show_target_info($current_target, "driver"); -+ push (@drivers_combined, $driver); -+ } - -- if ( $show_target_line =~ m/\s+Driver: (.+)/ ) { -- print "\tdriver $1\n"; -- } -+ my %drivers_uniq; -+ @drivers_uniq{@drivers_combined} = (); -+ my @drivers_combined_uniq = sort keys %drivers_uniq; - -- if ( $show_target_line =~ m/\s+Backing store: (?!No backing store)(.+)/ ) { -- print "\tbacking-store $1\n"; -- } -- } -+ if (scalar @drivers_combined_uniq == 1) { -+ print "default-driver $drivers_combined_uniq[0]\n\n"; -+ } - -- # Process account and ACL information -- my $account_acl; -+ # Print everything else in the config -+ foreach my $current_target (@all_targets) { -+ my $target_name = show_target_info($current_target, "target_name"); -+ print "\n"; - -- foreach my $show_target_line ($tgtadm_output{$target}) { -- $account_acl .= $show_target_line -+ if (scalar @drivers_combined_uniq gt 1) { -+ my $driver = show_target_info($current_target, "driver"); -+ print "\tdriver $driver\n"; - } - -- # start with account information... -- while ($account_acl =~ m{ -- \s+Account\ information:\n(.*)ACL\ information: -- }xmgs -- ) { -- -- my @account = split(/\n/, $1); -- -- foreach my $user (@account) { -- my @var = split(/^\s+/, $user); -- @var = split(/\s/, $var[1]); -+ my @backing_stores = show_target_info($current_target, "backing_stores"); -+ foreach my $backing_store (@backing_stores) { -+ print "\tbacking-store $backing_store\n"; -+ } - -- if ( $var[1] eq "(outgoing)" ) { -- print "\toutgoinguser $var[0] PLEASE_CORRECT_THE_PASSWORD\n"; -- } elsif ( ($var[0] ne "") && ($var[1] eq "") ) { -- print "\tincominguser $var[0] PLEASE_CORRECT_THE_PASSWORD\n"; -- } -+ my @account_information = show_target_info($current_target, "account_information"); -+ foreach my $account (@account_information) { -+ if ($account =~ /(.+)\ \(outgoing\)/) { -+ print "\toutgoinguser $1 PLEASE_CORRECT_THE_PASSWORD\n"; -+ } elsif (length $account) { -+ print "\tincominguser $account PLEASE_CORRECT_THE_PASSWORD\n"; - } - } - -- #...and finish with ACL information -- while ($account_acl =~ m{ -- \s+ACL\ information:\n(.*) -- }xmgs -- ) { -- my @ini_addresses = split(/\n/, $1); -- foreach my $ini_address (@ini_addresses) { -- my @var = split(/^\s+/, $ini_address); -- print "\tinitiator-address $var[1]\n"; -+ my @acl_information = show_target_info($current_target, "acl_information"); -+ if (scalar(@acl_information) != 1 || $acl_information[0] ne "ALL") { -+ foreach my $ini_address (@acl_information) { -+ print "\tinitiator-address $ini_address\n"; - } - } - print "\n\n"; -@@ -441,17 +643,17 @@ Example usage: - - EOF - } elsif ($off_ready eq "ALL") { -- &process_targets; -+ process_targets; - # Run over all targets and offline/ready them - my @all_targets = keys %tgtadm_output_tid; - foreach my $existing_target (@all_targets) { - execute("tgtadm --op update --mode target --tid=$tgtadm_output_tid{$existing_target} -n state -v $var"); - } - } elsif ($off_ready =~ m/tid=(.+)/) { -- &process_targets; -+ process_targets; - execute("tgtadm --op update --mode target --tid=$1 -n state -v $var"); - } else { -- &process_targets; -+ process_targets; - if (length $tgtadm_output_tid{$off_ready}) { - execute("tgtadm --op update --mode target --tid=$tgtadm_output_tid{$off_ready} --name=\"$off_ready\" -n state -v $var"); - } else { -@@ -465,17 +667,42 @@ EOF - sub show_target_info { - my $existing_target = $_[0]; - my $task = $_[1]; -+ # Returns target information -+ if ($task eq "target_name") { -+ if ($tgtadm_output{$existing_target} =~ m/^Target (\d*): (.+)/ ) { -+ return $2; -+ } - # Returns driver information -- if ($task eq "driver") { -- if ( $tgtadm_output{$existing_target} =~ m/\s+Driver: (.+)/ ) { -- print $1; -+ } elsif ($task eq "driver") { -+ if ($tgtadm_output{$existing_target} =~ m/\s+Driver: (.+)/ ) { - return $1; - } -+ # Returns backing store -+ } elsif ($task eq "backing_stores") { -+ if ($tgtadm_output{$existing_target} =~ m/\s+Backing store: (?!No backing store)(.+)/ ) { -+ my @backing_stores = $tgtadm_output{$existing_target} =~ m{\s+Backing store: (?!No backing store\n)(.+)}g; -+ return @backing_stores; -+ } -+ return; -+ # Returns account information: -+ } elsif ($task eq "account_information") { -+ if ($tgtadm_output{$existing_target} =~ m{ -+ \s+Account\ information:\n(.*)\n\s+ACL\ information: -+ }xs -+ ) { -+ my @accounts = split(/\n/, $1); -+ my @account_information; -+ foreach my $user (@accounts) { -+ my @var = split(/^\s+/, $user); -+ push(@account_information, $var[1]); -+ } -+ return @account_information; -+ } - # Returns ACL information - } elsif ($task eq "acl_information") { -- while ($tgtadm_output{$existing_target} =~ m{ -+ if ($tgtadm_output{$existing_target} =~ m{ - \s+ACL\ information:\n(.*) -- }xmgs -+ }xs - ) { - my @ini_addresses = split(/\n/, $1); - my @acls; -@@ -487,51 +714,80 @@ sub show_target_info { - } - # Returns sessions - } elsif ($task eq "sessions") { -- my @var = split(/\n/, $tgtadm_output{$existing_target}); -- my @sids; -- foreach my $sid (@var) { -- if ( $sid =~ m/\s+I_T nexus: (.+)/ ) { -- push(@sids, $1); -+ my %sessions; -+ if ($tgtadm_output{$existing_target} =~ m{ -+ \s+I_T\ nexus\ information:\n(.*)LUN\ information: -+ }xs -+ ) { -+ my @var = split(/\n/, $1); -+ my $sid; -+ my $cid; -+ -+ foreach my $line (@var) { -+ if ($line =~ m/\s+I_T nexus:\ (.+)/) { -+ $sid = $1; -+ } else { -+ if ($line =~ m/\s+Connection:\ (.+)/) { -+ $cid = $1; -+ $sessions{$sid} = $cid; -+ } -+ } - } - } -- return @sids; -+ return %sessions; - } - } - --# Delete the targets which are not in use --sub delete_targets { -- -- # Check if the target is used by an initiator -- sub check_in_use { -- my $existing_target = $_[0]; -- my $cur_option = $_[1]; -- my $cur_tid = $_[2]; -- if ($tgtadm_output{$existing_target} =~ m/\s+Connection:/) { -- if ($force == 1) { -- # Remove ACLs first -- my @acl_info = &show_target_info($existing_target, "acl_information"); -- foreach my $acl (@acl_info) { -- execute("tgtadm --op unbind --mode target --tid $tgtadm_output_tid{$existing_target} -I $acl"); -- } -- # Now, remove all sessions / connections from that tid -- my @sessions = &show_target_info($existing_target, "sessions"); -- foreach my $session (@sessions) { -- execute("tgtadm --op delete --mode conn --tid $tgtadm_output_tid{$existing_target} --sid $session --cid 0"); -+# Main subroutine for deleting targets -+sub main_delete { -+ my $current_target = $_[0]; -+ my $current_tid = $_[1]; -+ my $configured = check_configured($current_target); -+ my $del_upd_text; -+ # Check if the target has initiators connected -+ if ($tgtadm_output{$current_target} =~ m/\s+Connection:/) { -+ if ($force == 1) { -+ execute("# Removing target: $current_target"); -+ # Remove ACLs first -+ my @acl_info = show_target_info($current_target, "acl_information"); -+ foreach my $acl (@acl_info) { -+ execute("tgtadm --op unbind --mode target --tid $tgtadm_output_tid{$current_target} -I $acl"); -+ } -+ # Now, remove all sessions / connections from that tid -+ my %sessions = show_target_info($current_target, "sessions"); -+ foreach my $sid (keys %sessions) { -+ foreach my $cid ($sessions{$sid}) { -+ execute("tgtadm --op delete --mode conn --tid $tgtadm_output_tid{$current_target} --sid $sid --cid $cid"); - } -- execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$existing_target}"); -- } else { -- execute("# Target with tid $tgtadm_output_tid{$existing_target} ($existing_target) is in use, it won't be deleted."); - } -- } elsif (length $tgtadm_output_tid{$existing_target}) { -- execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$existing_target}"); -+ execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$current_target}"); - } else { -- if ($cur_option eq "tid") { -- execute("# Target with tid $cur_tid does not exist!"); -+ if ($update ne 0) { -+ $del_upd_text = "updated"; - } else { -- execute("# Target $existing_target does not exist!"); -+ $del_upd_text = "deleted"; - } -+ execute("# Target with tid $tgtadm_output_tid{$current_target} ($current_target) is in use, it won't be $del_upd_text."); -+ return 1; -+ } -+ } elsif (length $tgtadm_output_tid{$current_target}) { -+ execute("# Removing target: $current_target"); -+ execute("tgtadm --mode target --op delete --tid=$tgtadm_output_tid{$current_target}"); -+ } else { -+ if (length $current_tid) { -+ execute("# Target with tid $current_tid does not exist!"); -+ } else { -+ execute("# Target with name $current_target does not exist!"); - } - } -+ if ($configured ne 0) { -+ execute(); -+ } -+ return 0; -+} -+ -+# Delete the targets -+sub delete_targets { - - if ($delete eq "help") { - print < update all or selected targets -+ The target will be updated only if it's not used -+ (no initiator is connected to it). -+ If you want to update targets which are in use, -+ you have to add "--force" flag. -+ -+Example usage: -+ --update help - display this help -+ --update ALL - update all targets -+ --update tid=4 - update target 4 (target with tid 4) -+ --update iqn.2008-08.com.example:some.target - update this target -+ -+EOF -+ exit; -+ } elsif ($update eq "ALL") { -+ # Run over all targets and delete them if they are not in use -+ parse_configs; -+ process_targets; -+ my @targets_combined = combine_targets(); -+ foreach my $current_target (@targets_combined) { -+ my $configured = check_configured($current_target); -+ my $connected = check_connected($current_target); -+ my $in_configfile = check_in_configfile($current_target); -+ combine_targets(); -+ if (($in_configfile == 0) && ($configured == 1)) { -+ # Delete the target if it's not in the config file -+ main_delete($current_target); -+ } else { -+ add_targets($current_target, $configured, $connected, $in_configfile); -+ } -+ -+ } -+ } elsif ($update =~ m/^tid=(.+)/) { -+ # Update by tid -+ parse_configs; -+ process_targets; -+ my $current_target = $tgtadm_output_name{$1}; -+ my $configured = check_configured($current_target); -+ my $connected = check_connected($current_target); -+ my $in_configfile = check_in_configfile($current_target); -+ if (($in_configfile == 0) && ($configured == 1)) { -+ # Delete the target if it's not in the config file -+ main_delete($current_target); -+ } elsif ($configured == 1) { -+ add_targets($current_target, $configured, $connected, $in_configfile); -+ } else { -+ print "There is no target with tid $1, can't continue!\n"; -+ exit 1; -+ } -+ } else { -+ # Update by name -+ parse_configs; -+ process_targets; -+ my $current_target = $update; -+ my $configured = check_configured($current_target); -+ my $connected = check_connected($current_target); -+ my $in_configfile = check_in_configfile($current_target); -+ if ($in_configfile == 0 && $configured == 1) { -+ # Delete the target if it's not in the config file -+ main_delete($current_target); -+ } else { -+ add_targets($current_target, $configured, $connected, $in_configfile); -+ } -+ } -+} -+ -+# Find the biggest tid -+sub find_max_tid { -+ process_targets; -+ my @all_targets = keys %tgtadm_output_tid; -+ my $maxtid = 0; -+ foreach my $var (@all_targets) { -+ if ($tgtadm_output_tid{$var} > $maxtid) { -+ $maxtid = $tgtadm_output_tid{$var}; -+ } -+ } -+ return $maxtid; -+} -+ -+# Combine targets from the config file and currently configured targets -+sub combine_targets { -+ my @targets_in_configfile; -+ my @all_targets = keys %tgtadm_output_tid; -+ my @targets_combined; -+ # Make an array of targets in the config file -+ foreach my $k (sort keys %conf) { -+ if ( $k eq "target" ) { -+ foreach my $k2 (sort keys %{$conf{$k}}) { -+ push(@targets_in_configfile, $k2) -+ } -+ } -+ } -+ # Use only unique elements from both arrays -+ foreach my $current_target (@all_targets) { -+ push (@targets_combined, $current_target) unless grep { $_ eq $current_target } @targets_in_configfile; -+ } -+ @targets_combined = (@targets_combined, @targets_in_configfile); -+ return @targets_combined; -+} -+ -+# Check if a value is correct -+sub check_value { - if ( not defined $_[0] or not length $_[0] ) { - print "\nOption $option has a missing value!\n"; - print "Check your config file for errors (target: $target)\n"; -@@ -578,6 +938,102 @@ sub check { - } - } - -+# Check if the target is in the config file -+sub check_in_configfile { -+ my $current_target = $_[0]; -+ my $result; -+ foreach my $k (sort keys %conf) { -+ if ( $k eq "target" ) { -+ foreach my $k2 (sort keys %{$conf{$k}}) { -+ if ($k2 eq $current_target) { -+ return 1; -+ } -+ } -+ # If we're here, we didn't find a match -+ return 0; -+ } -+ } -+} -+ -+# Check if the target is configured in tgtd -+sub check_configured { -+ my $current_target = $_[0]; -+ if (length $tgtadm_output_tid{$current_target}) { -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ -+# Check if any initiators are connected to the target -+sub check_connected { -+ my $current_target = $_[0]; -+ if ($tgtadm_output{$current_target} =~ m/\s+Connection:/) { -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ -+# Check if a device can be allocated -+my @rootfs_dev; -+sub check_device { -+ my $tmp_dev = $_[0]; -+ -+ # Check if force flag is set -+ if ( $force == 0) { -+ # Check for rootfs devices -+ &find_rootfs_device(); -+ $tmp_dev =~ s/\d//g; -+ # Check if device is on the same disk as rootfs -+ if (grep {$_ eq $tmp_dev} @rootfs_dev) { -+ return (0,$tmp_dev); -+ } -+ } -+ return 1; -+} -+ -+# finds all the devices that rootfs is mounted on -+sub find_rootfs_device { -+ my @files=("/etc/mtab","/proc/mounts"); -+ my @lines; -+ # read files -+ foreach my $file (@files){ -+ if (open(FH,"$file")) { -+ @lines=(@lines,); -+ close (FH); -+ } -+ } -+ -+ # parse files and finds all the device which mounted on / -+ foreach my $line (@lines){ -+ chomp $line; -+ if (($line=~/^\/dev\//) && ($line=~/ \/ /)){ -+ my @ln=split(' ',$line); -+ $ln[0]=~s/\d//g; -+ push(@rootfs_dev,$ln[0]); -+ } -+ } -+ -+ # read swap file -+ my $swap_file="/proc/swap"; -+ if (open(FH,"$swap_file")) { -+ @lines=; -+ close (FH); -+ } -+ # parse swap file and finds all the swap devices -+ foreach my $line (@lines){ -+ chomp $line; -+ if ($line=~/^\/dev\//) { -+ my @ln=split(' ',$line); -+ $ln[0]=~s/\d//g; -+ push(@rootfs_dev,$ln[0]); -+ } -+ } -+ # remove duplicate entries from @rootfs_dev -+ my %seen = (); -+ @rootfs_dev = grep { ! $seen{ $_ }++ } @rootfs_dev; -+} - - # Execute or just print (or both) everything we start or would start - sub execute { -@@ -589,7 +1045,7 @@ sub execute { - } - # Don't try to execute if it's a comment - my @execargs = split(/#/, $args); -- if ( $execargs[0] ne undef ) { -+ if ($execargs[0] ne undef) { - system($args); - - # If non-zero exit code was return, exit -@@ -600,24 +1056,26 @@ sub execute { - } - } - -- } elsif ( $pretend == 1 ) { -+ } elsif ($pretend == 1) { - print "@_\n"; - } - } - - if ($execute == 1) { -- &process_targets; -- &parse_configs; -- &add_targets; -- &remove_targets; -+ process_targets; -+ parse_configs; -+ add_targets; -+ remove_targets; - } elsif ($delete ne 0) { -- &delete_targets; -+ delete_targets; -+} elsif ($update ne 0) { -+ update_targets; - } elsif ($dump == 1) { -- &dump_config; -+ dump_config; - } elsif ($offline ne 0) { -- &ready_offline_targets("offline"); -+ ready_offline_targets("offline"); - } elsif ($ready ne 0) { -- &ready_offline_targets("ready"); -+ ready_offline_targets("ready"); - } else { - print "No action specified.\n"; - } -diff --git a/usr/Makefile b/usr/Makefile -index 4245709..82ddf07 100644 ---- a/usr/Makefile -+++ b/usr/Makefile -@@ -55,10 +55,12 @@ CFLAGS += -g -O2 -Wall -Wstrict-prototypes -fPIC - LIBS += -lpthread - - PROGRAMS += tgtd tgtadm --SCRIPTS += ../scripts/tgt-setup-lun -+SCRIPTS += ../scripts/tgt-setup-lun ../scripts/tgt-admin - TGTD_OBJS += tgtd.o mgmt.o target.o scsi.o log.o driver.o util.o work.o \ -- parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o ssc.o bs_ssc.o bs.o --MANPAGES = ../doc/manpages/tgtadm.8 ../doc/manpages/tgt-setup-lun.8 -+ parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o ssc.o bs_ssc.o \ -+ bs.o -+MANPAGES = ../doc/manpages/tgtadm.8 ../doc/manpages/tgt-admin.8 \ -+ ../doc/manpages/tgt-setup-lun.8 - - TGTD_DEP = $(TGTD_OBJS:.o=.d) - -diff --git a/usr/be_byteshift.h b/usr/be_byteshift.h -new file mode 100644 -index 0000000..5c6a619 ---- /dev/null -+++ b/usr/be_byteshift.h -@@ -0,0 +1,68 @@ -+#ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H -+#define _LINUX_UNALIGNED_BE_BYTESHIFT_H -+ -+static inline uint16_t __get_unaligned_be16(const uint8_t *p) -+{ -+ return p[0] << 8 | p[1]; -+} -+ -+static inline uint32_t __get_unaligned_be32(const uint8_t *p) -+{ -+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; -+} -+ -+static inline uint64_t __get_unaligned_be64(const uint8_t *p) -+{ -+ return (uint64_t)__get_unaligned_be32(p) << 32 | -+ __get_unaligned_be32(p + 4); -+} -+ -+static inline void __put_unaligned_be16(uint16_t val, uint8_t *p) -+{ -+ *p++ = val >> 8; -+ *p++ = val; -+} -+ -+static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) -+{ -+ __put_unaligned_be16(val >> 16, p); -+ __put_unaligned_be16(val, p + 2); -+} -+ -+static inline void __put_unaligned_be64(uint64_t val, uint8_t *p) -+{ -+ __put_unaligned_be32(val >> 32, p); -+ __put_unaligned_be32(val, p + 4); -+} -+ -+static inline uint16_t get_unaligned_be16(const void *p) -+{ -+ return __get_unaligned_be16((const uint8_t *)p); -+} -+ -+static inline uint32_t get_unaligned_be32(const void *p) -+{ -+ return __get_unaligned_be32((const uint8_t *)p); -+} -+ -+static inline uint64_t get_unaligned_be64(const void *p) -+{ -+ return __get_unaligned_be64((const uint8_t *)p); -+} -+ -+static inline void put_unaligned_be16(uint16_t val, void *p) -+{ -+ __put_unaligned_be16(val, p); -+} -+ -+static inline void put_unaligned_be32(uint32_t val, void *p) -+{ -+ __put_unaligned_be32(val, p); -+} -+ -+static inline void put_unaligned_be64(uint64_t val, void *p) -+{ -+ __put_unaligned_be64(val, p); -+} -+ -+#endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */ -diff --git a/usr/bs.c b/usr/bs.c -index f100e2c..cef7b19 100644 ---- a/usr/bs.c -+++ b/usr/bs.c -@@ -125,7 +125,15 @@ static void bs_thread_request_done(int fd, int events, void *data) - cmd->scsi_cmd_done(cmd, scsi_get_result(cmd)); - } - -- write(info->command_fd[1], &nr_events, sizeof(nr_events)); -+rewrite: -+ ret = write(info->command_fd[1], &nr_events, sizeof(nr_events)); -+ if (ret < 0) { -+ eprintf("can't write done, %m\n"); -+ if (errno == EAGAIN || errno == EINTR) -+ goto rewrite; -+ -+ return; -+ } - } - - static void *bs_thread_worker_fn(void *arg) -@@ -140,7 +148,7 @@ static void *bs_thread_worker_fn(void *arg) - pthread_cond_wait(&info->pending_cond, &info->pending_lock); - if (info->stop) { - pthread_mutex_unlock(&info->pending_lock); -- break; -+ pthread_exit(NULL); - } - goto retest; - } -@@ -200,11 +208,32 @@ int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn) - for (i = 0; i < ARRAY_SIZE(info->worker_thread); i++) { - ret = pthread_create(&info->worker_thread[i], NULL, - bs_thread_worker_fn, info); -+ if (ret) -+ goto destroy_threads; -+ } -+rewrite: -+ ret = write(info->command_fd[1], &ret, sizeof(ret)); -+ if (ret < 0) { -+ eprintf("can't write done, %m\n"); -+ if (errno == EAGAIN || errno == EINTR) -+ goto rewrite; - } - -+ return 0; -+destroy_threads: - write(info->command_fd[1], &ret, sizeof(ret)); -+ pthread_cancel(info->ack_thread); -+ pthread_cond_signal(&info->finished_cond); -+ pthread_join(info->ack_thread, NULL); - -- return 0; -+ info->stop = 1; -+ for (i = 0; info->worker_thread[i]; i++) { -+ pthread_cancel(info->worker_thread[i]); -+ pthread_cond_signal(&info->pending_cond); -+ } -+ -+ for (i = 0; info->worker_thread[i]; i++) -+ pthread_join(info->worker_thread[i], NULL); - event_del: - tgt_event_del(info->done_fd[0]); - close_done_fd: -diff --git a/usr/bs_aio.h b/usr/bs_aio.h -index ad1cc3a..f62e99c 100644 ---- a/usr/bs_aio.h -+++ b/usr/bs_aio.h -@@ -44,6 +44,10 @@ enum { - #define __NR_eventfd 284 - #elif defined(__i386__) - #define __NR_eventfd 323 -+#elif defined(__powerpc__) -+#define __NR_eventfd 307 -+#elif defined(__powerpc64__) -+#define __NR_eventfd 307 - #elif defined(__ia64__) - #define __NR_eventfd 1309 - #elif defined(__sparc__) || defined(__sparc64__) -diff --git a/usr/log.c b/usr/log.c -index 4b71216..076c770 100644 ---- a/usr/log.c -+++ b/usr/log.c -@@ -108,9 +108,6 @@ static int logarea_init (int size) - return 1; - } - -- la->ops[0].sem_num = 0; -- la->ops[0].sem_flg = 0; -- - return 0; - } - -@@ -237,21 +234,24 @@ static void log_syslog (void * buff) - static void dolog(int prio, const char *fmt, va_list ap) - { - struct timespec ts; -+ struct sembuf ops; - - if (la) { - ts.tv_sec = 0; - ts.tv_nsec = 10000; - -- la->ops[0].sem_op = -1; -- if (semtimedop(la->semid, la->ops, 1, &ts) < 0) { -+ ops.sem_num = 0; -+ ops.sem_flg = 0; -+ ops.sem_op = -1; -+ if (semtimedop(la->semid, &ops, 1, &ts) < 0) { - syslog(LOG_ERR, "semop up failed"); - return; - } - - log_enqueue(prio, fmt, ap); - -- la->ops[0].sem_op = 1; -- if (semop(la->semid, la->ops, 1) < 0) { -+ ops.sem_op = 1; -+ if (semop(la->semid, &ops, 1) < 0) { - syslog(LOG_ERR, "semop down failed"); - return; - } -@@ -291,15 +291,21 @@ void log_debug(const char *fmt, ...) - - static void log_flush(void) - { -+ struct sembuf ops; -+ - while (!la->empty) { -- la->ops[0].sem_op = -1; -- if (semop(la->semid, la->ops, 1) < 0) { -+ ops.sem_num = 0; -+ ops.sem_flg = 0; -+ ops.sem_op = -1; -+ if (semop(la->semid, &ops, 1) < 0) { - syslog(LOG_ERR, "semop up failed"); - exit(1); - } -+ - log_dequeue(la->buff); -- la->ops[0].sem_op = 1; -- if (semop(la->semid, la->ops, 1) < 0) { -+ -+ ops.sem_op = 1; -+ if (semop(la->semid, &ops, 1) < 0) { - syslog(LOG_ERR, "semop down failed"); - exit(1); - } -diff --git a/usr/log.h b/usr/log.h -index 6993235..b84f6d6 100644 ---- a/usr/log.h -+++ b/usr/log.h -@@ -55,7 +55,6 @@ struct logarea { - void *start; - void *end; - char *buff; -- struct sembuf ops[1]; - int semid; - union semun semarg; - }; -diff --git a/usr/parser.c b/usr/parser.c -index 7b892a5..0b244e4 100644 ---- a/usr/parser.c -+++ b/usr/parser.c -@@ -30,6 +30,7 @@ static int match_one(char *s, char *p, substring_t args[]) - { - char *meta; - int argc = 0; -+ unsigned long long ret; - - if (!p) - return 1; -@@ -68,16 +69,16 @@ static int match_one(char *s, char *p, substring_t args[]) - args[argc].to = s + len; - break; - case 'd': -- strtol(s, &args[argc].to, 0); -+ ret = strtol(s, &args[argc].to, 0); - goto num; - case 'u': -- strtoul(s, &args[argc].to, 0); -+ ret = strtoul(s, &args[argc].to, 0); - goto num; - case 'o': -- strtoul(s, &args[argc].to, 8); -+ ret = strtoul(s, &args[argc].to, 8); - goto num; - case 'x': -- strtoul(s, &args[argc].to, 16); -+ ret = strtoul(s, &args[argc].to, 16); - num: - if (args[argc].to == args[argc].from) - return 0; -diff --git a/usr/smc.c b/usr/smc.c -index 9d7f681..ab36e9c 100644 ---- a/usr/smc.c -+++ b/usr/smc.c -@@ -225,6 +225,41 @@ static int build_element_descriptors(uint8_t *data, struct list_head *head, - } - - /** -+ * smc_initialize_element_status with range -+ * - INITIALIZE ELEMENT STATUS WITH RANGE op code -+ * -+ * Support the SCSI op code INITIALIZE_ELEMENT_STATUS_WITH_RANGE -+ * Ref: smc3r11, 6.5 -+ */ -+static int smc_initialize_element_status_range(int host_no, struct scsi_cmd *cmd) -+{ -+ scsi_set_in_resid_by_actual(cmd, 0); -+ -+ if (device_reserved(cmd)) -+ return SAM_STAT_RESERVATION_CONFLICT; -+ else -+ return SAM_STAT_GOOD; -+} -+ -+/** -+ * smc_initialize_element_status - INITIALIZE ELEMENT STATUS op code -+ * -+ * Some backup libraries seem to require this. -+ * -+ * Support the SCSI op code INITIALIZE_ELEMENT_STATUS -+ * Ref: smc3r10a, 6.2 -+ */ -+static int smc_initialize_element_status(int host_no, struct scsi_cmd *cmd) -+{ -+ scsi_set_in_resid_by_actual(cmd, 0); -+ -+ if (device_reserved(cmd)) -+ return SAM_STAT_RESERVATION_CONFLICT; -+ else -+ return SAM_STAT_GOOD; -+} -+ -+/** - * smc_read_element_status - READ ELEMENT STATUS op code - * - * Support the SCSI op code READ ELEMENT STATUS -@@ -748,7 +783,7 @@ struct device_type_template smc_template = { - {spc_illegal_op,}, - {spc_illegal_op,}, - {spc_illegal_op,}, -- {spc_illegal_op,}, -+ {smc_initialize_element_status,}, - - {spc_illegal_op,}, - {spc_illegal_op,}, -@@ -778,7 +813,28 @@ struct device_type_template smc_template = { - {spc_illegal_op,}, - {spc_illegal_op,}, - -- [0x20 ... 0x4f] = {spc_illegal_op,}, -+ [0x20 ... 0x2f] = {spc_illegal_op,}, -+ -+ /* 0x30 */ -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {smc_initialize_element_status_range,}, -+ -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ {spc_illegal_op,}, -+ -+ [0x40 ... 0x4f] = {spc_illegal_op,}, - - /* 0x50 */ - {spc_illegal_op,}, -diff --git a/usr/spc.c b/usr/spc.c -index bd2c975..60fd7d7 100644 ---- a/usr/spc.c -+++ b/usr/spc.c -@@ -318,6 +318,16 @@ int spc_test_unit(int host_no, struct scsi_cmd *cmd) - return SAM_STAT_CHECK_CONDITION; - } - -+int spc_prevent_allow_media_removal(int host_no, struct scsi_cmd *cmd) -+{ -+ /* TODO: implement properly */ -+ -+ if (device_reserved(cmd)) -+ return SAM_STAT_RESERVATION_CONFLICT; -+ else -+ return SAM_STAT_GOOD; -+} -+ - int spc_mode_select(int host_no, struct scsi_cmd *cmd, - int (*update)(struct scsi_cmd *, uint8_t *, int *)) - { -diff --git a/usr/spc.h b/usr/spc.h -index 8fe3e3c..cfc9cf3 100644 ---- a/usr/spc.h -+++ b/usr/spc.h -@@ -8,6 +8,7 @@ extern int spc_report_luns(int host_no, struct scsi_cmd *cmd); - extern int spc_start_stop(int host_no, struct scsi_cmd *cmd); - extern int spc_test_unit(int host_no, struct scsi_cmd *cmd); - extern int spc_request_sense(int host_no, struct scsi_cmd *cmd); -+extern int spc_prevent_allow_media_removal(int host_no, struct scsi_cmd *cmd); - extern int spc_illegal_op(int host_no, struct scsi_cmd *cmd); - extern int spc_lu_init(struct scsi_lu *lu); - -diff --git a/usr/ssc.c b/usr/ssc.c -index 2630a6a..96c3242 100644 ---- a/usr/ssc.c -+++ b/usr/ssc.c -@@ -192,7 +192,7 @@ static struct device_type_template ssc_template = { - {spc_start_stop,}, - {spc_illegal_op,}, - {spc_illegal_op,}, -- {spc_illegal_op,}, -+ {spc_prevent_allow_media_removal,}, - {spc_illegal_op,}, - - /* 0x20 */ -@@ -298,7 +298,7 @@ static struct device_type_template ssc_template = { - {spc_report_luns,}, - {spc_illegal_op,}, - {spc_illegal_op,}, -- {spc_illegal_op,}, -+ {spc_maint_in, maint_in_service_actions,}, - {spc_illegal_op,}, - {spc_illegal_op,}, - {spc_illegal_op,}, -diff --git a/usr/target.c b/usr/target.c -index 70bf72a..32812d9 100644 ---- a/usr/target.c -+++ b/usr/target.c -@@ -491,7 +491,7 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, - if (lu->bst->bs_init) { - ret = lu->bst->bs_init(lu); - if (ret) -- goto fail_bs_init; -+ goto fail_lu_init; - } - - if (backing && !path && !lu->attrs.removable) { -diff --git a/usr/util.h b/usr/util.h -index ac4b380..794c70b 100644 ---- a/usr/util.h -+++ b/usr/util.h -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include "be_byteshift.h" - - #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) diff --git a/tgt-1.0.28.tar.bz2 b/tgt-1.0.28.tar.bz2 new file mode 100644 index 0000000..8165c59 --- /dev/null +++ b/tgt-1.0.28.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efbf102d2345f0648a091fbd58e3c35e0c810ed4a5f15c872bb8b28f090c5e08 +size 193228 diff --git a/tgt-20080805.tar.bz2 b/tgt-20080805.tar.bz2 deleted file mode 100644 index 05b28fa..0000000 --- a/tgt-20080805.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98fdd166cd0af2b944ab53df0d1f4290aacc833e3b49ee926e213339f31ca216 -size 223414 diff --git a/tgt-fix-build b/tgt-fix-build index e2fcff7..a137a69 100644 --- a/tgt-fix-build +++ b/tgt-fix-build @@ -1,260 +1,20 @@ -diff --git a/scripts/tgt-setup-lun b/scripts/tgt-setup-lun -index 1e214ee..2ae9193 100755 ---- a/scripts/tgt-setup-lun -+++ b/scripts/tgt-setup-lun -@@ -1,3 +1,5 @@ -+#!/bin/bash -+ - # LUN assignment script - # - # Copyright (C) 2007 Erez Zilber -@@ -17,8 +19,6 @@ - # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - # 02110-1301 USA - --#!/bin/bash -- - usage() - { - name=$(basename $0) diff --git a/usr/Makefile b/usr/Makefile -index a59364b..bf264f4 100644 +index 64cb58c..deb7e39 100644 --- a/usr/Makefile +++ b/usr/Makefile -@@ -50,7 +50,7 @@ INCLUDES += -I. -I../include -I$(KERNELSRC)/include +@@ -28,12 +28,15 @@ INCLUDES += -I. CFLAGS += -D_GNU_SOURCE CFLAGS += $(INCLUDES) --CFLAGS += -g -O2 -Wall -Wstrict-prototypes -fPIC ++ifneq ($(OPTFLAGS),) +CFLAGS += $(OPTFLAGS) + ifneq ($(DEBUG),) + CFLAGS += -g -O0 -ggdb -rdynamic + else + CFLAGS += -g -O2 -fno-strict-aliasing + endif + CFLAGS += -Wall -Wstrict-prototypes -fPIC ++endif + CFLAGS += -DTGT_VERSION=\"$(VERSION)$(EXTRAVERSION)\" LIBS += -lpthread - -diff --git a/usr/fc/fc.c b/usr/fc/fc.c -index febb1e9..59f7573 100644 ---- a/usr/fc/fc.c -+++ b/usr/fc/fc.c -@@ -29,6 +29,8 @@ - #include - #include - #include -+#include -+typedef __u8 u8; - #include - #include - -diff --git a/usr/iscsi/iscsi_rdma.c b/usr/iscsi/iscsi_rdma.c -index d3b5147..c155b48 100644 ---- a/usr/iscsi/iscsi_rdma.c -+++ b/usr/iscsi/iscsi_rdma.c -@@ -144,7 +144,7 @@ struct conn_info { - /* but count so we can drain CQ on close */ - int recvl_posted; - -- struct tgt_event tx_sched; -+ struct tgtd_event tx_sched; - - /* login phase resources, freed at full-feature */ - void *srbuf_login; -@@ -196,7 +196,7 @@ struct iser_device { - void *mempool_listbuf; - struct ibv_mr *mempool_mr; - -- struct tgt_event poll_sched; -+ struct tgtd_event poll_sched; - - /* free and allocated mempool entries */ - struct list_head mempool_free, mempool_alloc; -@@ -281,9 +281,9 @@ static void iscsi_rdma_release(struct iscsi_connection *conn); - static int iscsi_rdma_show(struct iscsi_connection *conn, char *buf, - int rest); - static void iscsi_rdma_event_modify(struct iscsi_connection *conn, int events); --static void iser_sched_poll_cq(struct tgt_event *tev); --static void iser_sched_consume_cq(struct tgt_event *tev); --static void iser_sched_tx(struct tgt_event *evt); -+static void iser_sched_poll_cq(struct tgtd_event *tev); -+static void iser_sched_consume_cq(struct tgtd_event *tev); -+static void iser_sched_tx(struct tgtd_event *evt); - - /* - * Called when ready for full feature, builds resources. -@@ -1058,7 +1058,7 @@ static void iser_poll_cq_armable(struct iser_device *dev) - /* Scheduled to poll cq after a completion event has been - received and acknowledged, if no more completions are found - the interrupts are re-armed */ --static void iser_sched_poll_cq(struct tgt_event *tev) -+static void iser_sched_poll_cq(struct tgtd_event *tev) - { - struct iser_device *dev = tev->data; - iser_poll_cq_armable(dev); -@@ -1069,7 +1069,7 @@ static void iser_sched_poll_cq(struct tgt_event *tev) - the notification interrupts were re-armed. - Intended to consume those remaining completions only, - this function does not re-arm interrupts. */ --static void iser_sched_consume_cq(struct tgt_event *tev) -+static void iser_sched_consume_cq(struct tgtd_event *tev) - { - struct iser_device *dev = tev->data; - int ret; -@@ -1112,7 +1112,7 @@ static void iser_cqe_handler(int fd __attribute__((unused)), - * tries to push tx on a connection, until nothing - * is ready anymore. No progress limit here. - */ --static void iser_sched_tx(struct tgt_event *evt) -+static void iser_sched_tx(struct tgtd_event *evt) - { - struct conn_info *ci = evt->data; - struct iscsi_connection *conn = &ci->iscsi_conn; -diff --git a/usr/tgtd.c b/usr/tgtd.c -index 62aaa04..a226906 100644 ---- a/usr/tgtd.c -+++ b/usr/tgtd.c -@@ -99,7 +99,7 @@ static int oom_adjust(void) - int tgt_event_add(int fd, int events, event_handler_t handler, void *data) - { - struct epoll_event ev; -- struct tgt_event *tev; -+ struct tgtd_event *tev; - int err; - - tev = zalloc(sizeof(*tev)); -@@ -123,9 +123,9 @@ int tgt_event_add(int fd, int events, event_handler_t handler, void *data) - return err; - } - --static struct tgt_event *tgt_event_lookup(int fd) -+static struct tgtd_event *tgt_event_lookup(int fd) - { -- struct tgt_event *tev; -+ struct tgtd_event *tev; - - list_for_each_entry(tev, &tgt_events_list, e_list) { - if (tev->fd == fd) -@@ -136,7 +136,7 @@ static struct tgt_event *tgt_event_lookup(int fd) - - void tgt_event_del(int fd) - { -- struct tgt_event *tev; -+ struct tgtd_event *tev; - - tev = tgt_event_lookup(fd); - if (!tev) { -@@ -152,7 +152,7 @@ void tgt_event_del(int fd) - int tgt_event_modify(int fd, int events) - { - struct epoll_event ev; -- struct tgt_event *tev; -+ struct tgtd_event *tev; - - tev = tgt_event_lookup(fd); - if (!tev) { -@@ -167,7 +167,7 @@ int tgt_event_modify(int fd, int events) - return epoll_ctl(ep_fd, EPOLL_CTL_MOD, fd, &ev); - } - --void tgt_init_sched_event(struct tgt_event *evt, -+void tgt_init_sched_event(struct tgtd_event *evt, - sched_event_handler_t sched_handler, void *data) - { - evt->sched_handler = sched_handler; -@@ -176,7 +176,7 @@ void tgt_init_sched_event(struct tgt_event *evt, - INIT_LIST_HEAD(&evt->e_list); - } - --void tgt_add_sched_event(struct tgt_event *evt) -+void tgt_add_sched_event(struct tgtd_event *evt) - { - if (!evt->scheduled) { - evt->scheduled = 1; -@@ -184,7 +184,7 @@ void tgt_add_sched_event(struct tgt_event *evt) - } - } - --void tgt_remove_sched_event(struct tgt_event *evt) -+void tgt_remove_sched_event(struct tgtd_event *evt) - { - if (evt->scheduled) { - evt->scheduled = 0; -@@ -195,7 +195,7 @@ void tgt_remove_sched_event(struct tgt_event *evt) - static int tgt_exec_scheduled(void) - { - struct list_head *last_sched; -- struct tgt_event *tev, *tevn; -+ struct tgtd_event *tev, *tevn; - int work_remains = 0; - - if (!list_empty(&tgt_sched_events_list)) { -@@ -218,7 +218,7 @@ static void event_loop(void) - { - int nevent, i, sched_remains, timeout; - struct epoll_event events[1024]; -- struct tgt_event *tev; -+ struct tgtd_event *tev; - - retry: - sched_remains = tgt_exec_scheduled(); -@@ -232,7 +232,7 @@ retry: - } - } else if (nevent) { - for (i = 0; i < nevent; i++) { -- tev = (struct tgt_event *) events[i].data.ptr; -+ tev = (struct tgtd_event *) events[i].data.ptr; - tev->handler(tev->fd, events[i].events, tev->data); - } - } else -diff --git a/usr/tgtd.h b/usr/tgtd.h -index da751c8..207c167 100644 ---- a/usr/tgtd.h -+++ b/usr/tgtd.h -@@ -206,21 +206,21 @@ extern int tgt_bind_host_to_target(int tid, int host_no); - extern int tgt_unbind_host_to_target(int tid, int host_no); - extern int tgt_bound_target_lookup(int host_no); - --struct tgt_event; --typedef void (*sched_event_handler_t)(struct tgt_event *tev); -+struct tgtd_event; -+typedef void (*sched_event_handler_t)(struct tgtd_event *tev); - --extern void tgt_init_sched_event(struct tgt_event *evt, -+extern void tgt_init_sched_event(struct tgtd_event *evt, - sched_event_handler_t sched_handler, void *data); - - typedef void (*event_handler_t)(int fd, int events, void *data); - --extern int tgt_event_add(int fd, int events, event_handler_t handler, void *data); --extern void tgt_event_del(int fd); -+extern int tgtd_event_add(int fd, int events, event_handler_t handler, void *data); -+extern void tgtd_event_del(int fd); - --extern void tgt_add_sched_event(struct tgt_event *evt); --extern void tgt_remove_sched_event(struct tgt_event *evt); -+extern void tgt_add_sched_event(struct tgtd_event *evt); -+extern void tgt_remove_sched_event(struct tgtd_event *evt); - --extern int tgt_event_modify(int fd, int events); -+extern int tgtd_event_modify(int fd, int events); - extern int target_cmd_queue(int tid, struct scsi_cmd *cmd); - extern void target_cmd_done(struct scsi_cmd *cmd); - struct scsi_cmd *target_cmd_lookup(int tid, uint64_t itn_id, uint64_t tag); -@@ -269,7 +269,7 @@ extern int dtd_load_unload(int tid, uint64_t lun, int load, char *file); - extern int register_backingstore_template(struct backingstore_template *bst); - extern struct backingstore_template *get_backingstore_template(const char *name); - --struct tgt_event { -+struct tgtd_event { - union { - event_handler_t handler; - sched_event_handler_t sched_handler; -diff --git a/usr/tgtif.c b/usr/tgtif.c -index fd5ad5b..9b87b13 100644 ---- a/usr/tgtif.c -+++ b/usr/tgtif.c -@@ -36,7 +36,7 @@ - #ifndef aligned_u64 - #define aligned_u64 unsigned long long __attribute__((aligned(8))) - #endif --#include -+#include "scsi_tgt_if.h" - - #include "list.h" - #include "util.h" diff --git a/tgt-git-update b/tgt-git-update index 84da72d..c614bed 100644 --- a/tgt-git-update +++ b/tgt-git-update @@ -1,1326 +1,265 @@ -diff --git a/doc/targets.conf.example b/doc/targets.conf.example -index 46be8fe..ac8cf69 100644 ---- a/doc/targets.conf.example -+++ b/doc/targets.conf.example -@@ -81,6 +81,7 @@ default-driver iscsi - # Note that some parameters (write-cache, scsi_sn) were specified "globally". - # "Global" parameters will be applied to all LUNs; they can be overwritten - # "locally", per LUN. -+# If lun is not specified, it will be allocated automatically (first available). - - - -@@ -88,26 +89,26 @@ default-driver iscsi - vendor_id VENDOR1 - removable 1 - device-type cd -- # lun 1 # Not yet supported -+ lun 1 - - - - vendor_id VENDOR2 -- # lun 2 # Not yet supported -+ lun 2 - - - - vendor_id back1 - scsi_sn SERIAL - write-cache on -- # lun 3 # Not yet supported -+ # lun 3 # lun is commented out - will be allocated automatically - - - - vendor_id back2 - #mode_page 8:0:18:0x10:0:0xff.... - #mode_page 8:0:18:0x10:0:0xff.... -- # lun 4 # Not yet supported -+ lun 15 - - - # Some more parameters which can be specified locally or globally: -@@ -123,11 +124,12 @@ default-driver iscsi - #mode_page 8:0:18:0x10:0:0xff.... - #mode_page 8:0:18:0x10:0:0xff.... - #device-type -+ #allow-in-use # if specified globally, can't be overwritten locally - - write-cache off - scsi_sn multipath-10 - -- # Parameters below are global. They can't be configured per LUN. -+ # Parameters below are only global. They can't be configured per LUN. - # Only allow connections from 192.168.100.1 and 192.168.200.5 - initiator-address 192.168.100.1 - initiator-address 192.168.200.5 -@@ -142,10 +144,47 @@ default-driver iscsi - - - -+# The device will have lun 1 unless you specify something else -+ -+ backing-store /dev/LVM/somedevice -+ lun 10 -+ -+ -+ -+# Devices which are in use (by system: mounted, for swap, part of RAID, or by -+# userspace: dd, by tgtd for another target etc.) can't be used, unless you use -+# --force flag or add 'allow-in-use yes' option -+ -+ backing-store /dev/LVM/somedevice -+ allow-in-use yes -+ -+ -+ -+ -+ scsi_sn serial1 -+ -+ -+ -+ scsi_sn serial2 -+ -+ -+ allow-in-use yes -+ -+ -+ -+ +diff --git a/usr/sbc.c b/usr/sbc.c +index cf2b609..248a547 100644 +--- a/usr/sbc.c ++++ b/usr/sbc.c +@@ -23,6 +23,9 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ ++#define _FILE_OFFSET_BITS 64 ++#define __USE_GNU + + #include + #include + #include +@@ -30,6 +33,7 @@ + #include + #include + #include ++#include - # Not supported configurations, and therefore, commented out: + #include "list.h" + #include "util.h" +@@ -45,6 +49,23 @@ --# -+# -+# backing-store /dev/LVM/somedevice1 -+# backing-store /dev/LVM/somedevice2 -+# lun 10 -+# lun 11 -+# -+ -+# - # - # vendor_id VENDOR1 - # -@@ -155,7 +194,7 @@ default-driver iscsi + static unsigned int blk_shift = DEFAULT_BLK_SHIFT; - # This one will break the parser: - --# -+# - # - # vendor_id VENDOR1 - # -diff --git a/scripts/tgt-admin b/scripts/tgt-admin -index e4be373..c352952 100755 ---- a/scripts/tgt-admin -+++ b/scripts/tgt-admin -@@ -125,7 +125,7 @@ sub process_targets { - sub parse_configs { - # Parse the config - if ($alternate_conf ne 0) { -- # Check if alternative configuration file exist -+ # Check if alternative configuration file exists - if (-e "$alternate_conf") { - execute("# Using $alternate_conf as configuration file\n"); - %conf = ParseConfig(-ConfigFile => "$alternate_conf", -UseApacheInclude => 1, -IncludeGlob => 1,); -@@ -211,6 +211,7 @@ sub add_targets { - # and other parameters which can be specified globally - my %target_options; - my $target_options_ref; -+ my $data_key; - foreach my $k3 (sort keys %{$conf{$k}{$k2}}) { - $lun = 1; - $option = $k3; -@@ -218,6 +219,7 @@ sub add_targets { - check_value($value); - $target_options{$option} = $value; - $target_options_ref = \%target_options; -+ $data_key = make_key($target_options_ref, "lun", "allow-in-use"); - } - - if (not defined $target_options{"driver"}) { -@@ -230,7 +232,7 @@ sub add_targets { - $option = $k3; - $value = $conf{$k}{$k2}{$k3}; - check_value($value); -- process_options($target_options_ref); -+ process_options($target_options_ref,$data_key); - # If there was no option called "initiator-address", it means - # we want to allow ALL initiators for this target - if ($option eq "initiator-address") { -@@ -258,6 +260,27 @@ sub add_targets { - } - } - -+# Pre-parse the config and get some values we need -+sub make_key { -+ my $target_options_ref = shift; -+ my @actions = @_; -+ my %data_key; -+ -+ foreach my $action (@actions) { -+ if (ref $$target_options_ref{'backing-store'} eq "HASH") { -+ foreach my $testlun (keys %{$$target_options_ref{'backing-store'}}) { -+ $data_key{$testlun}{$action} = $$target_options_ref{'backing-store'}{$testlun}{$action}; -+ } -+ } -+ if (ref $$target_options_ref{'direct-store'} eq "HASH") { -+ foreach my $testlun (keys %{$$target_options_ref{'direct-store'}}) { -+ $data_key{$testlun}{$action} = $$target_options_ref{'direct-store'}{$testlun}{$action}; -+ } -+ } -+ } -+ return \%data_key; ++static off_t find_next_data(struct scsi_lu *dev, off_t offset) ++{ ++#ifdef SEEK_DATA ++ return lseek64(dev->fd, offset, SEEK_DATA); ++#else ++ return offset; ++#endif ++} ++static off_t find_next_hole(struct scsi_lu *dev, off_t offset) ++{ ++#ifdef SEEK_HOLE ++ return lseek64(dev->fd, offset, SEEK_HOLE); ++#else ++ return dev->size; ++#endif +} + - # Some options can be specified only once - sub check_if_hash_array { - my $check = $_[0]; -@@ -285,9 +308,15 @@ sub check_exe { - foreach my $path (@path) { - if ( -x "$path/$command" && -f "$path/$command" ) { $exists = 1 } - } -- if ( $exists == 0 ) { -- print "Command $command (needed by $option option in your config file) is not in your path - can't continue!\n"; -- exit 1; -+ if ($exists == 0) { -+ if ($command eq "sg_inq") { -+ print "Command '$command' (needed by '$option') is not in your path - can't continue!\n"; -+ exit 1; -+ } elsif ($command eq "lsof") { -+ execute("# Command '$command' is not in your path."); -+ execute("# Can't reliably check if device is not in use."); -+ return 1; + static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *changed) + { + uint8_t pcode = data[0] & 0x3f; +@@ -281,10 +302,18 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd) + + /* Verify that we are not doing i/o beyond + the end-of-lun */ +- if (tl && (lba + tl > lu->size)) { +- key = ILLEGAL_REQUEST; +- asc = ASC_LBA_OUT_OF_RANGE; +- goto sense; ++ if (tl) { ++ if (lba + tl > lu->size) { ++ key = ILLEGAL_REQUEST; ++ asc = ASC_LBA_OUT_OF_RANGE; ++ goto sense; ++ } ++ } else { ++ if (lba >= lu->size) { ++ key = ILLEGAL_REQUEST; ++ asc = ASC_LBA_OUT_OF_RANGE; ++ goto sense; + } } + + cmd->offset = lba; +@@ -421,7 +450,7 @@ sense: + return SAM_STAT_CHECK_CONDITION; } -@@ -315,27 +344,61 @@ sub add_params { +-static int sbc_service_action(int host_no, struct scsi_cmd *cmd) ++static int sbc_readcapacity16(int host_no, struct scsi_cmd *cmd) + { + uint32_t *data; + unsigned int bshift; +@@ -437,9 +466,6 @@ static int sbc_service_action(int host_no, struct scsi_cmd *cmd) + goto sense; } - } -+# Find next available LUN -+sub find_next_lun { -+ my $backing_store = $_[0]; -+ my $data_key_ref = $_[1]; -+ my $lun_collision = 0; -+ my $lun_is_free = 0; -+ my $found_lun = 1; -+ while ($lun_is_free == 0) { -+ foreach my $testlun (keys %$data_key_ref) { -+ foreach my $testlun2 (values %{$$data_key_ref{$testlun}}) { -+ if ($found_lun eq $testlun2) { -+ $lun_collision = 1; -+ } -+ } -+ } -+ if ($lun_collision == 0) { -+ $lun_is_free = 1; -+ } else { -+ $found_lun += 1; -+ } -+ $lun_collision = 0; -+ } -+ $$data_key_ref{$backing_store}{'lun'} = $found_lun; -+ return $found_lun; -+} -+ - # Add backing or direct store - sub add_backing_direct { - my $backing_store = $_[0]; - my $target_options_ref = $_[1]; -- my $lun = $_[2]; -+ my $lun; -+ my $data_key_ref = $_[2]; - my $direct_store = $_[3]; - my $driver = $$target_options_ref{"driver"}; - - # Is the device in use? -- (my $can_alloc, my $dev) = check_device($backing_store); -+ my $can_alloc = 1; -+ if ($force != 1 && $$target_options_ref{'allow-in-use'} ne "yes") { -+ $can_alloc = check_device($backing_store,$data_key_ref); -+ } - -- # Needed if the config file has mixed definitions -- if (ref($backing_store) eq "HASH") { -- foreach my $backing_store (sort keys %$value) { -- add_backing_direct($backing_store,$target_options_ref,$lun,$direct_store); -- $lun += 1; -- } -- return $lun; -- } elsif (-e $backing_store && $can_alloc == 1) { -+ if (-e $backing_store && ! -d $backing_store && $can_alloc == 1) { - my @exec_commands; - my $device_type; -+ my %luns; -+ my @added_luns; -+ # Find out LUNs which are "reserved" in the config file -+ if (ref $value eq "HASH") { -+ if (length $$data_key_ref{$backing_store}{'lun'}) { -+ $lun = $$data_key_ref{$backing_store}{'lun'}; -+ } else { -+ # Find an available lun if it wasn't specified -+ $lun = find_next_lun($backing_store,$data_key_ref); -+ } -+ } - # Process parameters for each lun / backing store - if (ref $value eq "HASH") { - my %params_added; -@@ -447,6 +510,11 @@ sub add_backing_direct { - check_if_hash_array($$target_options_ref{"device-type"}, "device-type"); - $device_type = $$target_options_ref{"device-type"}; - } -+ # lun -+ if (length $$target_options_ref{"lun"}) { -+ check_if_hash_array($$target_options_ref{"lun"}, "lun"); -+ $lun = $$target_options_ref{"lun"}; -+ } - } else { - print "If you got here, this means your config file is not supported.\n"; - print "Please report it to stgt mailing list and attach your config files.\n"; -@@ -461,7 +529,9 @@ sub add_backing_direct { - $lun += 1; - return $lun; - } elsif ($can_alloc == 0) { -- execute("# Skipping device $backing_store ($dev is mounted / in use)"); -+ execute("# Skipping device $backing_store - it is in use."); -+ execute("# You can override it with --force or 'allow-in-use yes' config option."); -+ execute("# Note - do so only if you know what you're doing, you may damage your data."); - } else { - execute("# Skipping device: $backing_store"); - execute("# $backing_store does not exist - please check the configuration file"); -@@ -471,11 +541,12 @@ sub add_backing_direct { - # Process options from the config file - sub process_options { - my $target_options_ref = $_[0]; -+ my $data_key_ref = $_[1]; - my $driver = $$target_options_ref{"driver"}; - if ($option eq "backing-store" || $option eq "direct-store") { - my $direct_store = 0; - if ($option eq "direct-store") { -- check_exe("sg_inq", "direct-store"); -+ check_exe("sg_inq", "option direct-store"); - $direct_store = 1; - } - -@@ -495,7 +566,13 @@ sub process_options { - - if (ref($value) eq "HASH") { - foreach my $backing_store (sort keys %$value) { -- $lun = add_backing_direct($backing_store,$target_options_ref,$lun,$direct_store); -+ if ($backing_store =~ m/HASH/) { -+ print "\nYour config file is not supported. See targets.conf.example for details.\n"; -+ exit 1; -+ } -+ } -+ foreach my $backing_store (sort keys %$value) { -+ add_backing_direct($backing_store,$target_options_ref,$data_key_ref,$direct_store); - } - } - } -@@ -569,7 +646,7 @@ sub dump_config { - - my @all_targets = keys %tgtadm_output_tid; - -- # If all targets use the same driver, us it only once in the config -+ # If all targets use the same driver, use it only once in the config - my $skip_driver = 0; - my @drivers_combined; - foreach my $current_target (@all_targets) { -@@ -976,63 +1053,43 @@ sub check_connected { - } - - # Check if a device can be allocated --my @rootfs_dev; -+# Device can be used "by system" (i.e. mounted, used as swap, as a part of -+# a RAID array etc.) or "by user" - i.e., already by tgtd, or someone doing: -+# dd if=/dev/1st_device of=/dev/2nd_device -+# We shouldn't allow a device to be used more than one time, as it could -+# cause corruption when written several times. Unless the user really wants to. - sub check_device { -- my $tmp_dev = $_[0]; +- if (cmd->scb[1] != SAI_READ_CAPACITY_16) +- goto sense; - -- # Check if force flag is set -- if ( $force == 0) { -- # Check for rootfs devices -- &find_rootfs_device(); -- $tmp_dev =~ s/\d//g; -- # Check if device is on the same disk as rootfs -- if (grep {$_ eq $tmp_dev} @rootfs_dev) { -- return (0,$tmp_dev); -- } -- } -- return 1; --} -- --# finds all the devices that rootfs is mounted on --sub find_rootfs_device { -- my @files=("/etc/mtab","/proc/mounts"); -- my @lines; -- # read files -- foreach my $file (@files){ -- if (open(FH,"$file")) { -- @lines=(@lines,); -- close (FH); -- } -- } -+ my $backing_store = $_[0]; -+ my $data_key_ref = $_[1]; + if (scsi_get_in_length(cmd) < 12) + goto overflow; -- # parse files and finds all the device which mounted on / -- foreach my $line (@lines){ -- chomp $line; -- if (($line=~/^\/dev\//) && ($line=~/ \/ /)){ -- my @ln=split(' ',$line); -- $ln[0]=~s/\d//g; -- push(@rootfs_dev,$ln[0]); -- } -+ # If allow-in-use is "yes", there is no need to do -+ # farther tests -+ if ($$data_key_ref{$backing_store}{'allow-in-use'} eq "yes") { -+ return 1; - } - -- # read swap file -- my $swap_file="/proc/swap"; -- if (open(FH,"$swap_file")) { -- @lines=; -- close (FH); -+ # Check if the system uses this device -+ use Fcntl qw(O_RDONLY O_EXCL); -+ use Errno; -+ sysopen(FH, $backing_store, O_RDONLY | O_EXCL); -+ if ($!{EBUSY}) { -+ execute("# Device $backing_store is used by the system (mounted, used by swap?)."); -+ return 0; - } -- # parse swap file and finds all the swap devices -- foreach my $line (@lines){ -- chomp $line; -- if ($line=~/^\/dev\//) { -- my @ln=split(' ',$line); -- $ln[0]=~s/\d//g; -- push(@rootfs_dev,$ln[0]); -+ close(FH); -+ -+ # Check if userspace uses this device -+ my $lsof_check = check_exe("lsof"); -+ if ($lsof_check ne 1) { -+ system("lsof $backing_store &>/dev/null"); -+ my $exit_value = $? >> 8; -+ if ($exit_value eq 0) { -+ execute("# Device $backing_store is used (already tgtd target?)."); -+ execute("# Run 'lsof $backing_store' to see the details."); -+ return 0; - } - } -- # remove duplicate entries from @rootfs_dev -- my %seen = (); -- @rootfs_dev = grep { ! $seen{ $_ }++ } @rootfs_dev; -+ return 1; +@@ -468,6 +494,106 @@ sense: + return SAM_STAT_CHECK_CONDITION; } - # Execute or just print (or both) everything we start or would start -diff --git a/usr/Makefile b/usr/Makefile -index 82ddf07..a59364b 100644 ---- a/usr/Makefile -+++ b/usr/Makefile -@@ -58,7 +58,7 @@ PROGRAMS += tgtd tgtadm - SCRIPTS += ../scripts/tgt-setup-lun ../scripts/tgt-admin - TGTD_OBJS += tgtd.o mgmt.o target.o scsi.o log.o driver.o util.o work.o \ - parser.o spc.o sbc.o mmc.o osd.o scc.o smc.o ssc.o bs_ssc.o \ -- bs.o -+ bs_null.o bs.o - MANPAGES = ../doc/manpages/tgtadm.8 ../doc/manpages/tgt-admin.8 \ - ../doc/manpages/tgt-setup-lun.8 - -diff --git a/usr/be_byteshift.h b/usr/be_byteshift.h -index 5c6a619..82b7da6 100644 ---- a/usr/be_byteshift.h -+++ b/usr/be_byteshift.h -@@ -40,6 +40,11 @@ static inline uint16_t get_unaligned_be16(const void *p) - return __get_unaligned_be16((const uint8_t *)p); - } - -+static inline uint32_t get_unaligned_be24(const uint8_t *p) ++static int sbc_getlbastatus(int host_no, struct scsi_cmd *cmd) +{ -+ return p[0] << 16 | p[1] << 8 | p[2]; -+} ++ int len = 32; ++ uint64_t offset; ++ uint32_t pdl; ++ int type; ++ unsigned char *buf; ++ unsigned char key = ILLEGAL_REQUEST; ++ uint16_t asc = ASC_INVALID_OP_CODE; + - static inline uint32_t get_unaligned_be32(const void *p) - { - return __get_unaligned_be32((const uint8_t *)p); -@@ -55,6 +60,13 @@ static inline void put_unaligned_be16(uint16_t val, void *p) - __put_unaligned_be16(val, p); - } - -+static inline void put_unaligned_be24(uint32_t val, void *p) -+{ -+ ((uint8_t *)p)[0] = (val >> 16) & 0xff; -+ ((uint8_t *)p)[1] = (val >> 8) & 0xff; -+ ((uint8_t *)p)[2] = val & 0xff; -+} -+ - static inline void put_unaligned_be32(uint32_t val, void *p) - { - __put_unaligned_be32(val, p); -diff --git a/usr/bs.c b/usr/bs.c -index cef7b19..542ef55 100644 ---- a/usr/bs.c -+++ b/usr/bs.c -@@ -173,7 +173,8 @@ static void *bs_thread_worker_fn(void *arg) - return NULL; - } - --int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn) -+int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn, -+ int nr_threads) - { - int i, ret; - -@@ -205,12 +206,18 @@ int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn) - if (ret) - goto event_del; - -- for (i = 0; i < ARRAY_SIZE(info->worker_thread); i++) { -+ if (nr_threads > ARRAY_SIZE(info->worker_thread)) { -+ eprintf("too many threads %d\n", nr_threads); -+ nr_threads = ARRAY_SIZE(info->worker_thread); ++ if (cmd->dev->attrs.removable && !cmd->dev->attrs.online) { ++ key = NOT_READY; ++ asc = ASC_MEDIUM_NOT_PRESENT; ++ goto sense; + } + -+ for (i = 0; i < nr_threads; i++) { - ret = pthread_create(&info->worker_thread[i], NULL, - bs_thread_worker_fn, info); - if (ret) - goto destroy_threads; - } ++ if (scsi_get_in_length(cmd) < 24) ++ goto overflow; + - rewrite: - ret = write(info->command_fd[1], &ret, sizeof(ret)); - if (ret < 0) { -@@ -261,7 +268,8 @@ void bs_thread_close(struct bs_thread_info *info) - info->stop = 1; - pthread_cond_broadcast(&info->pending_cond); - -- for (i = 0; i < ARRAY_SIZE(info->worker_thread); i++) -+ for (i = 0; info->worker_thread[i] && -+ i < ARRAY_SIZE(info->worker_thread); i++) - pthread_join(info->worker_thread[i], NULL); - - pthread_cond_destroy(&info->finished_cond); -diff --git a/usr/bs_mmap.c b/usr/bs_mmap.c -index fff19d3..bb24f5e 100644 ---- a/usr/bs_mmap.c -+++ b/usr/bs_mmap.c -@@ -96,7 +96,7 @@ static void bs_mmap_close(struct scsi_lu *lu) - static int bs_mmap_init(struct scsi_lu *lu) - { - struct bs_thread_info *info = BS_THREAD_I(lu); -- return bs_thread_open(info, bs_mmap_request); -+ return bs_thread_open(info, bs_mmap_request, NR_WORKER_THREADS); - } - - static void bs_mmap_exit(struct scsi_lu *lu) -diff --git a/usr/bs_null.c b/usr/bs_null.c -new file mode 100644 -index 0000000..00137ff ---- /dev/null -+++ b/usr/bs_null.c -@@ -0,0 +1,68 @@ -+/* -+ * NULL I/O backing store routine -+ * -+ * Copyright (C) 2008 Alexander Nezhinsky -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation, version 2 of the -+ * License. -+ * -+ * This program is distributed in the hope that 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 -+ */ ++ len = scsi_get_in_length(cmd); ++ buf = scsi_get_in_buffer(cmd); ++ memset(buf, 0, len); + -+#include -+#include -+#include -+#include ++ offset = get_unaligned_be64(&cmd->scb[2]) << cmd->dev->blk_shift; ++ if (offset >= cmd->dev->size) { ++ key = ILLEGAL_REQUEST; ++ asc = ASC_LBA_OUT_OF_RANGE; ++ goto sense; ++ } + -+#include "list.h" -+#include "tgtd.h" -+#include "scsi.h" ++ pdl = 4; ++ put_unaligned_be32(pdl, &buf[0]); + -+#define NULL_BS_DEV_SIZE (1ULL << 40) ++ type = 0; ++ while (len >= 4 + pdl + 16) { ++ off_t next_offset; + -+int bs_null_cmd_submit(struct scsi_cmd *cmd) -+{ -+ scsi_set_result(cmd, SAM_STAT_GOOD); -+ return 0; ++ put_unaligned_be32(pdl + 16, &buf[0]); ++ ++ if (offset >= cmd->dev->size) ++ break; ++ ++ next_offset = (type == 0) ? ++ find_next_hole(cmd->dev, offset) : ++ find_next_data(cmd->dev, offset); ++ if (next_offset == offset) { ++ type = 1 - type; ++ continue; ++ } ++ ++ put_unaligned_be64(offset >> cmd->dev->blk_shift, ++ &buf[4 + pdl + 0]); ++ put_unaligned_be32((next_offset - offset) ++ >> cmd->dev->blk_shift, ++ &buf[4 + pdl + 8]); ++ buf[4 + pdl + 12] = type; ++ ++ pdl += 16; ++ type = 1 - type; ++ offset = next_offset; ++ } ++ len = 4 + pdl; ++ ++overflow: ++ scsi_set_in_resid_by_actual(cmd, len); ++ return SAM_STAT_GOOD; ++ ++sense: ++ sense_data_build(cmd, key, asc); ++ return SAM_STAT_CHECK_CONDITION; +} + -+static int bs_null_open(struct scsi_lu *lu, char *path, -+ int *fd, uint64_t *size) -+{ -+ *size = NULL_BS_DEV_SIZE; -+ dprintf("NULL backing store open, size: %" PRIu64 "\n", *size); -+ return 0; -+} -+ -+static void bs_null_close(struct scsi_lu *lu) -+{ -+} -+ -+static int bs_null_cmd_done(struct scsi_cmd *cmd) -+{ -+ return 0; -+} -+ -+static struct backingstore_template null_bst = { -+ .bs_name = "null", -+ .bs_datasize = 0, -+ .bs_open = bs_null_open, -+ .bs_close = bs_null_close, -+ .bs_cmd_submit = bs_null_cmd_submit, -+ .bs_cmd_done = bs_null_cmd_done, ++struct service_action sbc_service_actions[] = { ++ {SAI_READ_CAPACITY_16, sbc_readcapacity16}, ++ {SAI_GET_LBA_STATUS, sbc_getlbastatus}, ++ {0, NULL} +}; + -+__attribute__((constructor)) static void bs_null_constructor(void) ++ ++static int sbc_service_action(int host_no, struct scsi_cmd *cmd) +{ -+ register_backingstore_template(&null_bst); -+} -diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c -index e2ece4a..65a6136 100644 ---- a/usr/bs_rdwr.c -+++ b/usr/bs_rdwr.c -@@ -147,7 +147,7 @@ static int bs_rdwr_init(struct scsi_lu *lu) - { - struct bs_thread_info *info = BS_THREAD_I(lu); - -- return bs_thread_open(info, bs_rdwr_request); -+ return bs_thread_open(info, bs_rdwr_request, NR_WORKER_THREADS); - } - - static void bs_rdwr_exit(struct scsi_lu *lu) -diff --git a/usr/bs_ssc.c b/usr/bs_ssc.c -index dcc3e30..b2e8818 100644 ---- a/usr/bs_ssc.c -+++ b/usr/bs_ssc.c -@@ -208,7 +208,7 @@ static void bs_ssc_close(struct scsi_lu *lu) - static int bs_ssc_init(struct scsi_lu *lu) - { - struct bs_thread_info *info = BS_THREAD_I(lu); -- return bs_thread_open(info, ssc_rdwr_request); -+ return bs_thread_open(info, ssc_rdwr_request, 1); - } - - static void bs_ssc_exit(struct scsi_lu *lu) -diff --git a/usr/bs_thread.h b/usr/bs_thread.h -index b97861c..b2975a5 100644 ---- a/usr/bs_thread.h -+++ b/usr/bs_thread.h -@@ -33,7 +33,8 @@ static inline struct bs_thread_info *BS_THREAD_I(struct scsi_lu *lu) - return (struct bs_thread_info *) ((char *)lu + sizeof(*lu)); - } - --extern int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn); -+extern int bs_thread_open(struct bs_thread_info *info, request_func_t *rfn, -+ int nr_threads); - extern void bs_thread_close(struct bs_thread_info *info); - extern int bs_thread_cmd_submit(struct scsi_cmd *cmd); - -diff --git a/usr/iscsi/iscsi_rdma.c b/usr/iscsi/iscsi_rdma.c -index 46e6ea8..d3b5147 100644 ---- a/usr/iscsi/iscsi_rdma.c -+++ b/usr/iscsi/iscsi_rdma.c -@@ -144,6 +144,8 @@ struct conn_info { - /* but count so we can drain CQ on close */ - int recvl_posted; - -+ struct tgt_event tx_sched; ++ uint8_t action; ++ unsigned char op = cmd->scb[0]; ++ struct service_action *service_action, *actions; + - /* login phase resources, freed at full-feature */ - void *srbuf_login; - void *listbuf_login; -@@ -194,6 +196,8 @@ struct iser_device { - void *mempool_listbuf; - struct ibv_mr *mempool_mr; - -+ struct tgt_event poll_sched; ++ action = cmd->scb[1] & 0x1f; ++ actions = cmd->dev->dev_type_template.ops[op].service_actions; + - /* free and allocated mempool entries */ - struct list_head mempool_free, mempool_alloc; - }; -@@ -217,10 +221,6 @@ static struct list_head iser_conn_list; - /* if any task needs an rdma read or write slot to proceed */ - static int waiting_rdma_slot; - --/* progress available, used with tgt_counter_event */ --static int num_tx_ready; --static int num_rx_ready; -- - #define uint64_from_ptr(p) (uint64_t)(uintptr_t)(p) - #define ptr_from_int64(p) (void *)(unsigned long)(p) - -@@ -251,6 +251,9 @@ static int num_rx_ready; - #define RDMA_PER_CONN 20 - #define RDMA_TRANSFER_SIZE (512 * 1024) - ++ service_action = find_service_action(actions, action); + -+#define MAX_POLL_WC 8 -+ - /* - * Number of allocatable data buffers, each of this size. Do at least 128 - * for linux iser. The mempool size is rounded up at initialization time -@@ -270,13 +273,17 @@ static inline struct conn_info *RDMA_CONN(struct iscsi_connection *conn) - return container_of(conn, struct conn_info, iscsi_conn); - } - --static void iser_cqe_handler(int fd, int events, void *data); --static void iser_rx_progress(int *counter, void *data); -+static void iser_cqe_handler(int fd __attribute__((unused)), -+ int events __attribute__((unused)), -+ void *data); - static void iser_rdma_read_completion(struct rdmalist *rdma); - static void iscsi_rdma_release(struct iscsi_connection *conn); - static int iscsi_rdma_show(struct iscsi_connection *conn, char *buf, - int rest); - static void iscsi_rdma_event_modify(struct iscsi_connection *conn, int events); -+static void iser_sched_poll_cq(struct tgt_event *tev); -+static void iser_sched_consume_cq(struct tgt_event *tev); -+static void iser_sched_tx(struct tgt_event *evt); - - /* - * Called when ready for full feature, builds resources. -@@ -612,6 +619,8 @@ static int iser_device_init(struct iser_device *dev) - goto out; - } - -+ tgt_init_sched_event(&dev->poll_sched, iser_sched_poll_cq, dev); -+ - ret = ibv_req_notify_cq(dev->cq, 0); - if (ret) { - eprintf("ibv_req_notify failed: %s\n", strerror(ret)); -@@ -691,6 +700,9 @@ static void iser_accept_connection(struct rdma_cm_event *event) - ci->login_phase = LOGIN_PHASE_START; - INIT_LIST_HEAD(&ci->conn_tx_ready); - list_add(&ci->iser_conn_list, &temp_conn); -+ -+ tgt_init_sched_event(&ci->tx_sched, iser_sched_tx, ci); -+ - /* initiator sits at dst, we are src */ - memcpy(&ci->peer_addr, &event->id->route.addr.dst_addr, - sizeof(ci->peer_addr)); -@@ -940,7 +952,7 @@ static void handle_wc(struct ibv_wc *wc) - list_add(&rdmal->list, &ci->rdmal); - if (waiting_rdma_slot) { - waiting_rdma_slot = 0; -- num_tx_ready = 1; -+ tgt_add_sched_event(&ci->tx_sched); - } - break; - -@@ -957,7 +969,7 @@ static void handle_wc(struct ibv_wc *wc) - list_add(&rdmal->list, &ci->rdmal); - if (waiting_rdma_slot) { - waiting_rdma_slot = 0; -- num_tx_ready = 1; -+ tgt_add_sched_event(&ci->tx_sched); - } - break; - -@@ -974,85 +986,14 @@ close_err: - } - - /* -- * Called directly from main event loop when a CQ notification is -- * available. -- */ --static void iser_cqe_handler(int fd __attribute__((unused)), -- int events __attribute__((unused)), -- void *data) --{ -- int ret; -- void *cq_context; -- struct iser_device *dev = data; -- -- ret = ibv_get_cq_event(dev->cq_channel, &dev->cq, &cq_context); -- if (ret != 0) { -- eprintf("notification, but no CQ event\n"); -- exit(1); -- } -- -- ibv_ack_cq_events(dev->cq, 1); -- -- ret = ibv_req_notify_cq(dev->cq, 0); -- if (ret) { -- eprintf("ibv_req_notify_cq: %s\n", strerror(ret)); -- exit(1); -- } -- -- iser_rx_progress(NULL, dev); --} -- --/* -- * Called from tgtd when num_tx_ready (counter) non-zero. Walks the -- * list of active connections and tries to push tx on each, until nothing -- * is ready anymore. No progress limit here. -- */ --static void iser_tx_progress(int *counter __attribute__((unused)), -- void *data __attribute__((unused))) --{ -- int reloop, ret; -- struct conn_info *ci, *cin; -- struct iscsi_connection *conn; -- -- dprintf("entry\n"); -- num_tx_ready = 0; -- -- do { -- reloop = 0; -- list_for_each_entry_safe(ci, cin, &conn_tx_ready, -- conn_tx_ready) { -- conn = &ci->iscsi_conn; -- if (conn->state == STATE_CLOSE) { -- dprintf("ignoring tx for closed conn\n"); -- } else { -- dprintf("trying tx\n"); -- ret = iscsi_tx_handler(conn); -- if (conn->state == STATE_CLOSE) { -- conn_close(conn); -- dprintf("connection %p closed\n", ci); -- } else { -- if (ret == 0) { -- reloop = 1; -- } else { -- /* but leave on tx ready list */ -- waiting_rdma_slot = 1; -- } -- } -- } -- } -- } while (reloop); --} -- --/* - * Could read as many entries as possible without blocking, but - * that just fills up a list of tasks. Instead pop out of here - * so that tx progress, like issuing rdma reads and writes, can - * happen periodically. - */ --#define MAX_RX_PROGRESS 8 --static void iser_rx_progress_one(struct iser_device *dev) -+static int iser_poll_cq(struct iser_device *dev, int max_wc) - { -- int ret, numwc = 0; -+ int ret = 0, numwc = 0; - struct ibv_wc wc; - struct conn_info *ci; - struct recvlist *recvl; -@@ -1069,8 +1010,8 @@ static void iser_rx_progress_one(struct iser_device *dev) - VALGRIND_MAKE_MEM_DEFINED(&wc, sizeof(wc)); - if (wc.status == IBV_WC_SUCCESS) { - handle_wc(&wc); -- if (++numwc == MAX_RX_PROGRESS) { -- num_rx_ready = 1; -+ if (++numwc == max_wc) { -+ ret = 1; - break; - } - } else if (wc.status == IBV_WC_WR_FLUSH_ERR) { -@@ -1089,23 +1030,114 @@ static void iser_rx_progress_one(struct iser_device *dev) - wc.status, (unsigned long long) wc.wr_id); - } - } -+ return ret; -+} -+ -+static void iser_poll_cq_armable(struct iser_device *dev) -+{ -+ int ret; -+ -+ ret = iser_poll_cq(dev, MAX_POLL_WC); -+ if (ret < 0) -+ exit(1); -+ -+ if (ret == 0) { -+ /* no more completions on cq, arm the completion interrupts */ -+ ret = ibv_req_notify_cq(dev->cq, 0); -+ if (ret) { -+ eprintf("ibv_req_notify_cq: %s\n", strerror(ret)); -+ exit(1); -+ } -+ dev->poll_sched.sched_handler = iser_sched_consume_cq; -+ } else -+ dev->poll_sched.sched_handler = iser_sched_poll_cq; -+ -+ tgt_add_sched_event(&dev->poll_sched); -+} -+ -+/* Scheduled to poll cq after a completion event has been -+ received and acknowledged, if no more completions are found -+ the interrupts are re-armed */ -+static void iser_sched_poll_cq(struct tgt_event *tev) -+{ -+ struct iser_device *dev = tev->data; -+ iser_poll_cq_armable(dev); -+} -+ -+/* Scheduled to consume completion events that could arrive -+ after the cq had been seen empty but just before -+ the notification interrupts were re-armed. -+ Intended to consume those remaining completions only, -+ this function does not re-arm interrupts. */ -+static void iser_sched_consume_cq(struct tgt_event *tev) -+{ -+ struct iser_device *dev = tev->data; -+ int ret; -+ -+ ret = iser_poll_cq(dev, MAX_POLL_WC); -+ if (ret < 0) -+ exit(1); -+} -+ -+/* -+ * Called directly from main event loop when a CQ notification is -+ * available. -+ */ -+static void iser_cqe_handler(int fd __attribute__((unused)), -+ int events __attribute__((unused)), -+ void *data) -+{ -+ struct iser_device *dev = data; -+ void *cq_context; -+ int ret; -+ -+ ret = ibv_get_cq_event(dev->cq_channel, &dev->cq, &cq_context); -+ if (ret != 0) { -+ eprintf("notification, but no CQ event\n"); -+ exit(1); ++ if (!service_action) { ++ scsi_set_in_resid_by_actual(cmd, 0); ++ sense_data_build(cmd, ILLEGAL_REQUEST, ++ ASC_INVALID_FIELD_IN_CDB); ++ return SAM_STAT_CHECK_CONDITION; + } + -+ ibv_ack_cq_events(dev->cq, 1); ++ return service_action->cmd_perform(host_no, cmd); ++} + -+ /* if a poll was previosuly scheduled, remove it, -+ as it will be scheduled when necessary */ -+ if (dev->poll_sched.scheduled) -+ tgt_remove_sched_event(&dev->poll_sched); -+ -+ iser_poll_cq_armable(dev); - } - - /* -- * Only one progress counter, must look across all devs. -+ * Called from tgtd as a scheduled event -+ * tries to push tx on a connection, until nothing -+ * is ready anymore. No progress limit here. - */ --static void iser_rx_progress(int *counter __attribute__((unused)), void *data) -+static void iser_sched_tx(struct tgt_event *evt) + static int sbc_sync_cache(int host_no, struct scsi_cmd *cmd) { -- struct iser_device *dev; -+ struct conn_info *ci = evt->data; -+ struct iscsi_connection *conn = &ci->iscsi_conn; -+ int ret; + int ret; +@@ -711,7 +837,7 @@ static struct device_type_template sbc_template = { + {spc_illegal_op,}, + {spc_illegal_op,}, + {spc_illegal_op,}, +- {sbc_service_action,}, ++ {sbc_service_action, sbc_service_actions,}, + {spc_illegal_op,}, - dprintf("entry\n"); -- num_rx_ready = 0; -- if (data == NULL) { -- list_for_each_entry(dev, &iser_dev_list, list) -- iser_rx_progress_one(dev); -- } else { -- dev = data; -- iser_rx_progress_one(dev); -+ -+ if (conn->state == STATE_CLOSE) { -+ dprintf("ignoring tx for closed conn\n"); -+ return; -+ } -+ -+ for (;;) { -+ dprintf("trying tx\n"); -+ ret = iscsi_tx_handler(conn); -+ if (conn->state == STATE_CLOSE) { -+ conn_close(conn); -+ dprintf("connection %p closed\n", ci); -+ break; -+ } -+ if (ret != 0) { -+ /* but leave on tx ready list */ -+ waiting_rdma_slot = 1; -+ break; -+ } - } - } - -@@ -1165,10 +1197,7 @@ static int iscsi_rdma_init(void) - INIT_LIST_HEAD(&iser_dev_list); - INIT_LIST_HEAD(&iser_conn_list); - INIT_LIST_HEAD(&temp_conn); -- num_tx_ready = 0; -- num_rx_ready = 0; -- ret = tgt_counter_event_add(&num_tx_ready, iser_tx_progress, NULL); -- ret = tgt_counter_event_add(&num_rx_ready, iser_rx_progress, NULL); -+ - return ret; - } - -@@ -1397,10 +1426,6 @@ static void iscsi_iser_write_end(struct iscsi_connection *conn) - - ci->writeb = 0; /* reset count */ - ci->send_comm_event = NULL; -- -- /* wake up the progress engine to do the done */ -- dprintf("inc progress to finish cmd\n"); -- num_tx_ready = 1; - } - - /* -@@ -1505,7 +1530,7 @@ static int iscsi_rdma_rdma_write(struct iscsi_connection *conn) - iscsi_rdma_event_modify(conn, EPOLLIN); - } else { - /* poke ourselves to do the next rdma */ -- num_tx_ready = 1; -+ tgt_add_sched_event(&ci->tx_sched); - } - - return ret; -@@ -1628,7 +1653,7 @@ static void iscsi_rdma_event_modify(struct iscsi_connection *conn, int events) - dprintf("tx ready adding %p\n", ci); - list_add(&ci->conn_tx_ready, &conn_tx_ready); - } -- num_tx_ready = 1; -+ tgt_add_sched_event(&ci->tx_sched); - } else { - dprintf("tx ready removing %p\n", ci); - list_del_init(&ci->conn_tx_ready); -diff --git a/usr/log.c b/usr/log.c -index 076c770..056314a 100644 ---- a/usr/log.c -+++ b/usr/log.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -52,29 +53,39 @@ static int logarea_init (int size) - logdbg(stderr,"enter logarea_init\n"); - - if ((shmid = shmget(IPC_PRIVATE, sizeof(struct logarea), -- 0644 | IPC_CREAT | IPC_EXCL)) == -1) -+ 0644 | IPC_CREAT | IPC_EXCL)) == -1) { -+ syslog(LOG_ERR, "shmget logarea failed %d", errno); - return 1; -+ } - - la = shmat(shmid, NULL, 0); -- if (!la) -+ if (!la) { -+ syslog(LOG_ERR, "shmat logarea failed %d", errno); - return 1; -+ } -+ -+ shmctl(shmid, IPC_RMID, NULL); - - if (size < MAX_MSG_SIZE) - size = LOG_SPACE_SIZE; - - if ((shmid = shmget(IPC_PRIVATE, size, - 0644 | IPC_CREAT | IPC_EXCL)) == -1) { -+ syslog(LOG_ERR, "shmget msg failed %d", errno); - shmdt(la); - return 1; - } - - la->start = shmat(shmid, NULL, 0); - if (!la->start) { -+ syslog(LOG_ERR, "shmat msg failed %d", errno); - shmdt(la); - return 1; - } - memset(la->start, 0, size); - -+ shmctl(shmid, IPC_RMID, NULL); -+ - la->empty = 1; - la->end = la->start + size; - la->head = la->start; -@@ -82,18 +93,23 @@ static int logarea_init (int size) - - if ((shmid = shmget(IPC_PRIVATE, MAX_MSG_SIZE + sizeof(struct logmsg), - 0644 | IPC_CREAT | IPC_EXCL)) == -1) { -+ syslog(LOG_ERR, "shmget logmsg failed %d", errno); - shmdt(la->start); - shmdt(la); - return 1; - } - la->buff = shmat(shmid, NULL, 0); - if (!la->buff) { -+ syslog(LOG_ERR, "shmat logmsgfailed %d", errno); - shmdt(la->start); - shmdt(la); - return 1; - } - -+ shmctl(shmid, IPC_RMID, NULL); -+ - if ((la->semid = semget(SEMKEY, 1, 0666 | IPC_CREAT)) < 0) { -+ syslog(LOG_ERR, "semget failed %d", errno); - shmdt(la->buff); - shmdt(la->start); - shmdt(la); -@@ -102,6 +118,7 @@ static int logarea_init (int size) - - la->semarg.val=1; - if (semctl(la->semid, 0, SETVAL, la->semarg) < 0) { -+ syslog(LOG_ERR, "semctl failed %d", errno); - shmdt(la->buff); - shmdt(la->start); - shmdt(la); + /* 0xA0 */ +diff --git a/usr/scsi.h b/usr/scsi.h +index 0a02c36..2b994f9 100644 +--- a/usr/scsi.h ++++ b/usr/scsi.h +@@ -80,6 +80,7 @@ + #define WRITE_SAME_16 0x93 + #define SERVICE_ACTION_IN 0x9e + #define SAI_READ_CAPACITY_16 0x10 ++#define SAI_GET_LBA_STATUS 0x12 + #define REPORT_LUNS 0xa0 + #define MOVE_MEDIUM 0xa5 + #define EXCHANGE_MEDIUM 0xa6 diff --git a/usr/spc.c b/usr/spc.c -index 60fd7d7..ac5c3de 100644 +index a7f9a36..117c9f3 100644 --- a/usr/spc.c +++ b/usr/spc.c -@@ -383,6 +383,9 @@ int spc_mode_select(int host_no, struct scsi_cmd *cmd, - if (block_descriptor_len != BLOCK_DESCRIPTOR_LEN) - goto sense; - -+ memcpy(cmd->dev->mode_block_descriptor, data + offset, -+ BLOCK_DESCRIPTOR_LEN); -+ - offset += 8; - } +@@ -794,7 +794,7 @@ struct service_action maint_in_service_actions[] = { + {0, NULL} + }; +-static struct service_action * ++struct service_action * + find_service_action(struct service_action *service_action, uint32_t action) + { + while (service_action->cmd_perform) { diff --git a/usr/tgtd.c b/usr/tgtd.c -index 0b1cb4c..62aaa04 100644 +index 4ec6f23..cba2b66 100644 --- a/usr/tgtd.c +++ b/usr/tgtd.c -@@ -38,26 +38,13 @@ - #include "work.h" - #include "util.h" - --struct tgt_event { -- union { -- event_handler_t *handler; -- counter_event_handler_t *counter_handler; -- }; -- union { -- int fd; -- int *counter; -- }; -- void *data; -- struct list_head e_list; --}; -- - unsigned long pagesize, pageshift, pagemask; - - int system_active = 1; - static int ep_fd; - static char program_name[] = "tgtd"; - static LIST_HEAD(tgt_events_list); --static LIST_HEAD(tgt_counter_events_list); -+static LIST_HEAD(tgt_sched_events_list); - - static struct option const long_options[] = +@@ -487,6 +487,7 @@ int main(int argc, char **argv) { -@@ -136,22 +123,6 @@ int tgt_event_add(int fd, int events, event_handler_t handler, void *data) - return err; - } + struct sigaction sa_old; + struct sigaction sa_new; ++ char *spare_args; + int err, ch, longindex, nr_lld = 0; + int is_daemon = 1, is_debug = 0; + int ret; +@@ -549,7 +550,9 @@ int main(int argc, char **argv) + exit(1); + } --int tgt_counter_event_add(int *counter, counter_event_handler_t handler, -- void *data) --{ -- struct tgt_event *tev; -- -- tev = zalloc(sizeof(*tev)); -- if (!tev) -- return -ENOMEM; -- -- tev->data = data; -- tev->counter_handler = handler; -- tev->counter = counter; -- list_add(&tev->e_list, &tgt_counter_events_list); -- return 0; --} -- - static struct tgt_event *tgt_event_lookup(int fd) - { - struct tgt_event *tev; -@@ -163,17 +134,6 @@ static struct tgt_event *tgt_event_lookup(int fd) - return NULL; - } - --static struct tgt_event *tgt_counter_event_lookup(int *counter) --{ -- struct tgt_event *tev; -- -- list_for_each_entry(tev, &tgt_counter_events_list, e_list) { -- if (tev->counter == counter) -- return tev; -- } -- return NULL; --} -- - void tgt_event_del(int fd) - { - struct tgt_event *tev; -@@ -189,20 +149,6 @@ void tgt_event_del(int fd) - free(tev); - } - --void tgt_counter_event_del(int *counter) --{ -- struct tgt_event *tev; -- -- tev = tgt_counter_event_lookup(counter); -- if (!tev) { -- eprintf("Cannot find counter event %p\n", counter); -- return; -- } -- -- list_del(&tev->e_list); -- free(tev); --} -- - int tgt_event_modify(int fd, int events) - { - struct epoll_event ev; -@@ -221,26 +167,62 @@ int tgt_event_modify(int fd, int events) - return epoll_ctl(ep_fd, EPOLL_CTL_MOD, fd, &ev); - } - -+void tgt_init_sched_event(struct tgt_event *evt, -+ sched_event_handler_t sched_handler, void *data) -+{ -+ evt->sched_handler = sched_handler; -+ evt->scheduled = 0; -+ evt->data = data; -+ INIT_LIST_HEAD(&evt->e_list); -+} +- nr_lld = lld_init(argv[optind]); ++ spare_args = optind < argc ? argv[optind] : NULL; + -+void tgt_add_sched_event(struct tgt_event *evt) -+{ -+ if (!evt->scheduled) { -+ evt->scheduled = 1; -+ list_add_tail(&evt->e_list, &tgt_sched_events_list); -+ } -+} -+ -+void tgt_remove_sched_event(struct tgt_event *evt) -+{ -+ if (evt->scheduled) { -+ evt->scheduled = 0; -+ list_del_init(&evt->e_list); -+ } -+} -+ -+static int tgt_exec_scheduled(void) -+{ -+ struct list_head *last_sched; -+ struct tgt_event *tev, *tevn; -+ int work_remains = 0; -+ -+ if (!list_empty(&tgt_sched_events_list)) { -+ /* execute only work scheduled till now */ -+ last_sched = tgt_sched_events_list.prev; -+ list_for_each_entry_safe(tev, tevn, &tgt_sched_events_list, -+ e_list) { -+ tgt_remove_sched_event(tev); -+ tev->sched_handler(tev); -+ if (&tev->e_list == last_sched) -+ break; -+ } -+ if (!list_empty(&tgt_sched_events_list)) -+ work_remains = 1; -+ } -+ return work_remains; -+} -+ - static void event_loop(void) - { -- int nevent, i, done, timeout = TGTD_TICK_PERIOD * 1000; -+ int nevent, i, sched_remains, timeout; - struct epoll_event events[1024]; -- struct tgt_event *tev, *tevn; -+ struct tgt_event *tev; - - retry: -- /* -- * Check the counter events to see if they have any work to run. -- */ -- do { -- done = 1; -- list_for_each_entry_safe(tev, tevn, &tgt_counter_events_list, -- e_list) { -- if (*tev->counter) { -- done = 0; -- tev->counter_handler(tev->counter, tev->data); -- } -- } -- } while (!done); -+ sched_remains = tgt_exec_scheduled(); -+ timeout = sched_remains ? 0 : TGTD_TICK_PERIOD * 1000; - - nevent = epoll_wait(ep_fd, events, ARRAY_SIZE(events), timeout); - if (nevent < 0) { ++ nr_lld = lld_init(spare_args); + if (!nr_lld) { + fprintf(stderr, "No available low level driver!\n"); + exit(1); diff --git a/usr/tgtd.h b/usr/tgtd.h -index 4febcd3..da751c8 100644 +index b303e21..aa9b9d5 100644 --- a/usr/tgtd.h +++ b/usr/tgtd.h -@@ -206,13 +206,20 @@ extern int tgt_bind_host_to_target(int tid, int host_no); - extern int tgt_unbind_host_to_target(int tid, int host_no); - extern int tgt_bound_target_lookup(int host_no); +@@ -353,4 +353,8 @@ int call_program(const char *cmd, --typedef void (event_handler_t)(int fd, int events, void *data); --typedef void (counter_event_handler_t)(int *counter, void *data); -+struct tgt_event; -+typedef void (*sched_event_handler_t)(struct tgt_event *tev); -+ -+extern void tgt_init_sched_event(struct tgt_event *evt, -+ sched_event_handler_t sched_handler, void *data); -+ -+typedef void (*event_handler_t)(int fd, int events, void *data); -+ - extern int tgt_event_add(int fd, int events, event_handler_t handler, void *data); --extern int tgt_counter_event_add(int *counter, counter_event_handler_t handler, -- void *data); - extern void tgt_event_del(int fd); --extern void tgt_counter_event_del(int *counter); -+ -+extern void tgt_add_sched_event(struct tgt_event *evt); -+extern void tgt_remove_sched_event(struct tgt_event *evt); -+ - extern int tgt_event_modify(int fd, int events); - extern int target_cmd_queue(int tid, struct scsi_cmd *cmd); - extern void target_cmd_done(struct scsi_cmd *cmd); -@@ -262,4 +269,17 @@ extern int dtd_load_unload(int tid, uint64_t lun, int load, char *file); - extern int register_backingstore_template(struct backingstore_template *bst); - extern struct backingstore_template *get_backingstore_template(const char *name); + void update_lbppbe(struct scsi_lu *lu, int blksize); -+struct tgt_event { -+ union { -+ event_handler_t handler; -+ sched_event_handler_t sched_handler; -+ }; -+ union { -+ int fd; -+ int scheduled; -+ }; -+ void *data; -+ struct list_head e_list; -+}; ++struct service_action * ++find_service_action(struct service_action *service_action, ++ uint32_t action); + #endif diff --git a/tgt.changes b/tgt.changes index 132b8d6..5ca5bd9 100644 --- a/tgt.changes +++ b/tgt.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Thu Jun 14 09:51:09 CEST 2012 - vuntz@opensuse.org + +- Remove "# pidfile: /var/run/tgtd.pid" from tgt.init, as it makes + the script hang on systemd-based systems. This is the same bug as + rh#797913, and the fix was used in Fedora. Apparently, there's no + such pid file written by tgtd. + +------------------------------------------------------------------- +Mon Jun 4 14:39:47 CEST 2012 - hare@suse.de + +- Update to latest upstream release 1.0.23 + * Improved SCSI emulation + * Various small fixes + ------------------------------------------------------------------- Mon Sep 21 11:02:59 CEST 2009 - dmueller@suse.de diff --git a/tgt.init b/tgt.init index 0ef3607..e50a9d7 100644 --- a/tgt.init +++ b/tgt.init @@ -16,10 +16,10 @@ # # -# pidfile: /var/run/tgtd.pid DAEMON=/usr/sbin/tgtd PIDFILE=/var/run/tgtd.pid +TGTD_CONFIG=/etc/tgt/targets.conf # Source LSB init functions . /etc/rc.status @@ -28,29 +28,133 @@ rc_reset PATH=/sbin:/bin:/usr/sbin:/usr/bin +start() +{ + echo "Starting target framework daemon" + # Start tgtd first. + tgtd &>/dev/null + RETVAL=$? + if [ "$RETVAL" -ne 0 ] ; then + rc_failed -v + else + # Put tgtd into "offline" state until all the targets are configured. + # We don't want initiators to (re)connect and fail the connection + # if it's not ready. + tgtadm --op update --mode sys --name State -v offline + # Configure the targets. + tgt-admin -e -c $TGTD_CONFIG + # Put tgtd into "ready" state. + tgtadm --op update --mode sys --name State -v ready + rc_failed 0 + fi + rc_status -v +} + +stop() +{ + if [ "$RUNLEVEL" == 0 -o "$RUNLEVEL" == 6 ] ; then + forcedstop + fi + echo "Stopping target framework daemon" + # Remove all targets. It only removes targets which are not in use. + tgt-admin --update ALL -c /dev/null &>/dev/null + # tgtd will exit if all targets were removed + tgtadm --op delete --mode system &>/dev/null + RETVAL=$? + if [ "$RETVAL" -eq 107 ] ; then + rc_failed 7 + [ "$TASK" != "restart" ] && exit 1 + elif [ "$RETVAL" -ne 0 ] ; then + echo -n "(Some initiators are still connected)" + rc_failed 1 + fi + rc_status -v +} + +forcedstop() +{ + # NOTE: Forced shutdown of the iscsi target may cause data corruption + # for initiators that are connected. + echo "Force-stopping target framework daemon" + # Offline everything first. May be needed if we're rebooting, but + # expect the initiators to reconnect cleanly when we boot again + # (i.e. we don't want them to reconnect to a tgtd which is still + # working, but the target is gone). + tgtadm --op update --mode sys --name State -v offline &>/dev/null + RETVAL=$? + if [ "$RETVAL" -eq 107 ] ; then + rc_failed 7 + [ "$TASK" != "restart" ] && exit 1 + else + tgt-admin --offline ALL + # Remove all targets, even if they are still in use. + tgt-admin --update ALL -c /dev/null -f + # It will shut down tgtd only after all targets were removed. + tgtadm --op delete --mode system + RETVAL=$? + if [ "$RETVAL" -ne 0 ] ; then + rc_failed 1 + fi + fi +} + +reload() +{ + echo "Updating target framework daemon configuration" + # Update configuration for targets. Only targets which + # are not in use will be updated. + tgt-admin --update ALL -c $TGTD_CONFIG &>/dev/null + RETVAL=$? + if [ "$RETVAL" -eq 107 ] ; then + rc_failed 7 + fi +} + +forcedreload() +{ + echo "Force-updating target framework daemon configuration" + # Update configuration for targets, even those in use. + tgt-admin --update ALL -f -c $TGTD_CONFIG &>/dev/null + RETVAL=$? + if [ "$RETVAL" -eq 107 ] ; then + rc_failed 7 + fi +} + case "$1" in start) echo -n "Starting SCSI target service: " - modprobe crc32c - modprobe scsi_tgt - startproc -p $PIDFILE $DAEMON + start rc_status -v ;; stop) echo -n "Stopping SCSI target service: " - tgtadm --op delete >/dev/null 2>/dev/null - killproc -p $PIDFILE -TERM $DAEMON - modprobe -r scsi_tgt 2>/dev/null - RETVAL=$? - modprobe -r crc32c 2>/dev/null + stop if [ $RETVAL != "0" ]; then - rc_failed + rc_failed + else + modprobe -r scsi_tgt 2>/dev/null + modprobe -r crc32c 2>/dev/null + rc_failed 0 fi rc_status -v ;; + forcedstop) + forcedstop + rc_status -v + ;; + forcereload) + forcedreload + rc_status -v + ;; restart|reload) - $0 stop - $0 start + TASK=$1 + stop + RETVAL=$? + if [ $RETVAL -eq 0 ] ; then + start + fi + rc_status -v ;; status) echo -n "Checking for SCSI target service" @@ -58,7 +162,7 @@ case "$1" in rc_status -v ;; *) - echo $"Usage: $0 {start|stop|restart|status}" + echo $"Usage: $0 {start|stop|restart|reload|forcedreload|forcedstop|status}" exit 1 esac rc_exit diff --git a/tgt.spec b/tgt.spec index 6fb59eb..caafb57 100644 --- a/tgt.spec +++ b/tgt.spec @@ -1,7 +1,7 @@ # -# spec file for package tgt (Version 0.9.0) +# spec file for package tgt # -# Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -15,28 +15,26 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # -# norootforbuild - Name: tgt -BuildRequires: libaio-devel openssl-devel perl-Config-General +BuildRequires: docbook-xsl-stylesheets +BuildRequires: libaio-devel +BuildRequires: libxslt +BuildRequires: openssl-devel +BuildRequires: perl-Config-General Obsoletes: iscsitarget -Provides: iscsitarget Requires: perl-Config-General Url: http://stgt.berlios.de +PreReq: %fillup_prereq %insserv_prereq +Version: 1.0.28 +Release: 0 +Summary: Generic Linux target framework (tgt) License: GPL-2.0+ Group: System/Daemons -PreReq: %fillup_prereq %insserv_prereq -AutoReqProv: on -Version: 0.9.0 -Release: 2 -Summary: Generic Linux target framework (tgt) -Source: %{name}-20080805.tar.bz2 +Source: %{name}-%{version}.tar.bz2 Source1: %{name}.init -Source2: scsi_tgt_if.h Source3: %{name}.services -Patch1: %{name}-0.9.0-update -Patch2: %{name}-git-update +Patch1: %{name}-git-update Patch11: %{name}-fix-build BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -56,14 +54,11 @@ Authors: Mike Christie %prep -%setup -n %{name}-20080805 +%setup -n %{name}-%{version} %patch1 -p1 -%patch2 -p1 %patch11 -p1 -cp %{S:2} usr %build -cd usr %ifarch ppc ppc64 %define backends ISCSI=1 FCP=1 FCOE=1 IBMVIO=1 %else @@ -72,10 +67,7 @@ cd usr %{__make} OPTFLAGS="${RPM_OPT_FLAGS}" %{backends} %install -cd usr -%{__make} DESTDIR=${RPM_BUILD_ROOT} install -cd ../scripts -install -vD -m 755 tgt-admin ${RPM_BUILD_ROOT}/usr/sbin/tgt-admin +%{__make} DESTDIR=${RPM_BUILD_ROOT} docdir=%_docdir/%{name} install install -vD -m 755 %{S:1} ${RPM_BUILD_ROOT}/etc/init.d/tgtd ln -sf /etc/init.d/tgtd ${RPM_BUILD_ROOT}/usr/sbin/rctgtd install -vD %{S:3} ${RPM_BUILD_ROOT}/etc/sysconfig/SuSEfirewall2.d/services/iscsitarget @@ -97,8 +89,13 @@ rm -f filelist %defattr(-,root,root) /usr/sbin/* /etc/init.d/tgtd +%dir /etc/tgt +%dir /etc/tgt/examples +%config %attr(0644,root,root) /etc/tgt/targets.conf +%config %attr(0644,root,root) /etc/tgt/examples/* %config %attr(0644,root,root) /etc/sysconfig/SuSEfirewall2.d/services/iscsitarget -%doc README doc/README.iscsi doc/TODO +%doc README doc/README.iscsi doc/README.iser doc/README.lu_configuration +%doc doc/README.mmc doc/README.passthrough doc/README.sbcjukebox doc/README.ssc %doc %{_mandir}/man8/* %changelog