1910 lines
58 KiB
Plaintext
1910 lines
58 KiB
Plaintext
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=<kernel-src-directory> 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=<kernel-src-directory> 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:
|
|
+
|
|
+<target iqn.2008-09.com.example:server.target1>
|
|
+ backing-store /dev/LVM/somedevice
|
|
+</target>
|
|
+
|
|
+
|
|
+# 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".
|
|
+
|
|
+<target iqn.2008-09.com.example:server.target2>
|
|
+ direct-store /dev/sdd
|
|
+ incominguser someuser secretpass12
|
|
+</target>
|
|
+
|
|
+
|
|
+# An example with multiple LUNs, disabled write-cache (tgtd enables write-cache
|
|
+# by default) and vendor identification set to "MyVendor"
|
|
+
|
|
+<target iqn.2008-09.com.example:server.target3>
|
|
+ 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.
|
|
+</target>
|
|
+
|
|
+
|
|
+# 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"
|
|
+
|
|
+<target iqn.2008-09.com.example:server.target4>
|
|
+ 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.
|
|
+</target>
|
|
+
|
|
+
|
|
+# 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.
|
|
+
|
|
+<target iqn.2008-09.com.example:server.target4>
|
|
+ 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
|
|
+</target>
|
|
+
|
|
+
|
|
+# 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.
|
|
+
|
|
+<target iqn.2008-09.com.example:server.target5>
|
|
+
|
|
+ <direct-store /dev/sdd>
|
|
+ vendor_id VENDOR1
|
|
+ removable 1
|
|
+ device-type cd
|
|
+ # lun 1 # Not yet supported
|
|
+ </direct-store>
|
|
+
|
|
+ <direct-store /dev/sda>
|
|
+ vendor_id VENDOR2
|
|
+ # lun 2 # Not yet supported
|
|
+ </direct-store>
|
|
+
|
|
+ <backing-store /dev/sdb1>
|
|
+ vendor_id back1
|
|
+ scsi_sn SERIAL
|
|
+ write-cache on
|
|
+ # lun 3 # Not yet supported
|
|
+ </backing-store>
|
|
+
|
|
+ <backing-store /dev/sdd1>
|
|
+ vendor_id back2
|
|
+ #mode_page 8:0:18:0x10:0:0xff....
|
|
+ #mode_page 8:0:18:0x10:0:0xff....
|
|
+ # lun 4 # Not yet supported
|
|
+ </backing-store>
|
|
+
|
|
+ # 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
|
|
+
|
|
+</target>
|
|
+
|
|
+
|
|
+
|
|
+# Not supported configurations, and therefore, commented out:
|
|
+
|
|
+#<target iqn.2008-09.com.example:server.target6>
|
|
+# <direct-store /dev/sdd>
|
|
+# vendor_id VENDOR1
|
|
+# </direct-store>
|
|
+#
|
|
+# direct-store /dev/sdc
|
|
+#</target>
|
|
+
|
|
+# This one will break the parser:
|
|
+
|
|
+#<target iqn.2008-09.com.example:server.target7>
|
|
+# <direct-store /dev/sdd>
|
|
+# vendor_id VENDOR1
|
|
+# </direct-store>
|
|
+#
|
|
+# direct-store /dev/sdc
|
|
+#
|
|
+# <direct-store /dev/sdd>
|
|
+# vendor_id VENDOR1
|
|
+# </direct-store>
|
|
+#</target>
|
|
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 <value> put all or selected targets in ready state
|
|
(see "--ready help" for more info)
|
|
+ --update <value> update configuration for all or selected targets
|
|
+ (see "--update help" for more info)
|
|
-s, --show show all the targets
|
|
-c, --conf <conf file> 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 "<target $2>\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 "<target $target_name>\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 "</target>\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 <<EOF;
|
|
@@ -539,7 +795,7 @@ sub delete_targets {
|
|
The target will be deleted only if it's not used
|
|
(no initiator is connected to it).
|
|
If you want to delete targets which are in use,
|
|
- you have to add "--force" flag
|
|
+ you have to add "--force" flag.
|
|
|
|
Example usage:
|
|
--delete help - display this help
|
|
@@ -550,27 +806,131 @@ Example usage:
|
|
EOF
|
|
exit;
|
|
} elsif ($delete eq "ALL") {
|
|
- &process_targets;
|
|
- # Run over all targets and delete them if they are not in use
|
|
+ process_targets;
|
|
+ # Run over all targets and delete them
|
|
my @all_targets = keys %tgtadm_output_tid;
|
|
- foreach my $existing_target (@all_targets) {
|
|
- &check_in_use($existing_target);
|
|
+ foreach my $current_target (@all_targets) {
|
|
+ main_delete($current_target);
|
|
}
|
|
- } elsif ($delete =~ m/tid=(.+)/) {
|
|
+ } elsif ($delete =~ m/^tid=(.+)/) {
|
|
# Delete by tid
|
|
- &process_targets;
|
|
- my $existing_target = $1;
|
|
- &check_in_use($tgtadm_output_name{$existing_target}, "tid", $existing_target);
|
|
+ process_targets;
|
|
+ my $current_target = $tgtadm_output_name{$1};
|
|
+ main_delete($current_target, $1);
|
|
} else {
|
|
# Delete by name
|
|
- &process_targets;
|
|
- my $existing_target = $delete;
|
|
- &check_in_use($existing_target);
|
|
+ process_targets;
|
|
+ my $current_target = $delete;
|
|
+ main_delete($current_target);
|
|
}
|
|
}
|
|
|
|
-# Some checks
|
|
-sub check {
|
|
+# Update targets
|
|
+sub update_targets {
|
|
+ if ($update eq "help") {
|
|
+ print <<EOF;
|
|
+ --update <value> 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,<FH>);
|
|
+ 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=<FH>;
|
|
+ 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 <unistd.h>
|
|
#include <errno.h>
|
|
#include <endian.h>
|
|
+#include "be_byteshift.h"
|
|
|
|
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|