mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-21 20:51:27 +00:00
- Initial module support for ALUA
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3714 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -4,7 +4,7 @@ package SCST::SCST;
|
||||
|
||||
# Author: Mark R. Buechler
|
||||
# License: GPLv2
|
||||
# Copyright (c) 2005-2010 Mark R. Buechler
|
||||
# Copyright (c) 2005-2011 Mark R. Buechler
|
||||
# Copyright (c) 2011 Bart Van Assche <bvanassche@acm.org>.
|
||||
|
||||
use 5.005;
|
||||
@@ -29,6 +29,7 @@ SCST_SGV => 'sgv',
|
||||
SCST_HANDLERS => 'handlers',
|
||||
SCST_DEVICES => 'devices',
|
||||
SCST_TARGETS => 'targets',
|
||||
SCST_DEV_GROUPS => 'device_groups',
|
||||
SCST_QUEUE_RES => 'last_sysfs_mgmt_res',
|
||||
# Root level, new sysfs interface
|
||||
IN_SCST_HANDLERS => 'device_driver',
|
||||
@@ -41,6 +42,10 @@ SCST_TGT_ATTR => 'target_attributes',
|
||||
SCST_ADD_DEV_PARAMS => 'add_device_parameters',
|
||||
SCST_PARAM_ATTR => 'parameters',
|
||||
|
||||
# Device group specific
|
||||
SCST_DG_DEVICES => 'devices',
|
||||
SCST_DG_TGROUPS => 'target_groups',
|
||||
|
||||
# Target specific
|
||||
SCST_GROUPS => 'ini_groups',
|
||||
SCST_INITIATORS => 'initiators',
|
||||
@@ -131,6 +136,20 @@ SCST_C_INI_SETATTR_FAIL => 102,
|
||||
|
||||
SCST_C_NO_SESSION => 110,
|
||||
SCST_C_SESSION_CLOSE_FAIL => 111,
|
||||
|
||||
SCST_C_DEV_GRP_NO_GROUP => 120,
|
||||
SCST_C_DEV_GRP_EXISTS => 121,
|
||||
SCST_C_DEV_GRP_ADD_FAIL => 122,
|
||||
SCST_C_DEV_GRP_REM_FAIL => 123,
|
||||
|
||||
SCST_C_DGRP_ADD_DEV_FAIL => 130,
|
||||
SCST_C_DGRP_REM_DEV_FAIL => 131,
|
||||
SCST_C_DGRP_NO_DEVICE => 132,
|
||||
SCST_C_DGRP_DEVICE_EXISTS => 133,
|
||||
SCST_C_DGRP_ADD_GRP_FAIL => 134,
|
||||
SCST_C_DGRP_REM_GRP_FAIL => 135,
|
||||
SCST_C_DGRP_NO_GROUP => 136,
|
||||
SCST_C_DGRP_GROUP_EXISTS => 137,
|
||||
};
|
||||
|
||||
my %VERBOSE_ERROR = (
|
||||
@@ -209,6 +228,20 @@ my %VERBOSE_ERROR = (
|
||||
|
||||
(SCST_C_NO_SESSION) => 'Session not found for driver/target.',
|
||||
(SCST_C_SESSION_CLOSE_FAIL) => 'Failed to close session.',
|
||||
|
||||
(SCST_C_DEV_GRP_NO_GROUP) => 'No such device group exists.',
|
||||
(SCST_C_DEV_GRP_EXISTS) => 'Device group already exists.',
|
||||
(SCST_C_DEV_GRP_ADD_FAIL) => 'Failed to add device group. See "dmesg" for more information.',
|
||||
(SCST_C_DEV_GRP_REM_FAIL) => 'Failed to remove device group. See "dmesg" for more information.',
|
||||
|
||||
(SCST_C_DGRP_ADD_DEV_FAIL) => 'Failed to add device to device group. See "dmesg" for more information.',
|
||||
(SCST_C_DGRP_REM_DEV_FAIL) => 'Failed to remove device from device group. See "dmesg" for more information.',
|
||||
(SCST_C_DGRP_NO_DEVICE) => 'No such device in device group.',
|
||||
(SCST_C_DGRP_DEVICE_EXISTS) => 'Device already exists within device group.',
|
||||
(SCST_C_DGRP_ADD_GRP_FAIL) => 'Failed to add target group to device group. See "dmesg" for more information.',
|
||||
(SCST_C_DGRP_REM_GRP_FAIL) => 'Failed to remove target group from device group. See "dmesg" for more information.',
|
||||
(SCST_C_DGRP_NO_GROUP) => 'No such target group exists within device group.',
|
||||
(SCST_C_DGRP_GROUP_EXISTS) => 'Target group already exists within device group.',
|
||||
);
|
||||
|
||||
use vars qw(@ISA @EXPORT $VERSION);
|
||||
@@ -260,6 +293,15 @@ sub SCST_DEVICES_DIR {
|
||||
}
|
||||
}
|
||||
|
||||
# Device groups.
|
||||
sub SCST_DEV_GROUP_DIR {
|
||||
if (-d SCST_ROOT_OLD) {
|
||||
return SCST_ROOT_OLD . '/' . SCST_DEV_GROUPS;
|
||||
} else {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
# Target drivers.
|
||||
sub SCST_TARGETS_DIR {
|
||||
if (-d SCST_ROOT_OLD) {
|
||||
@@ -636,6 +678,90 @@ sub luns {
|
||||
return \%luns;
|
||||
}
|
||||
|
||||
sub deviceGroups {
|
||||
my $self = shift;
|
||||
my @groups;
|
||||
|
||||
my $dHandle = new IO::Handle;
|
||||
my $_path = SCST_DEV_GROUP_DIR();
|
||||
if (!(opendir $dHandle, $_path)) {
|
||||
$self->{'err_string'} = "deviceGroups(): Unable to read directory '$_path': $!";
|
||||
return undef;
|
||||
}
|
||||
|
||||
foreach my $group (readdir($dHandle)) {
|
||||
next if (($group eq '.') || ($group eq '..'));
|
||||
|
||||
if (-d make_path(SCST_DEV_GROUP_DIR(), $group)) {
|
||||
push @groups, $group;
|
||||
}
|
||||
}
|
||||
|
||||
close $dHandle;
|
||||
|
||||
return \@groups;
|
||||
}
|
||||
|
||||
sub deviceGroupDevices {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my @devices;
|
||||
|
||||
if ($self->deviceGroupExists($group) != TRUE) {
|
||||
$self->{'err_string'} = "deviceGroupDevices(): Device group '$group' does not exist";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $dHandle = new IO::Handle;
|
||||
my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES);
|
||||
if (!(opendir $dHandle, $_path)) {
|
||||
$self->{'err_string'} = "deviceGroupDevices(): Unable to read directory '$_path': $!";
|
||||
return undef;
|
||||
}
|
||||
|
||||
foreach my $device (readdir($dHandle)) {
|
||||
next if (($device eq '.') || ($device eq '..'));
|
||||
|
||||
if (-d make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES, $device)) {
|
||||
push @devices, $device;
|
||||
}
|
||||
}
|
||||
|
||||
close $dHandle;
|
||||
|
||||
return \@devices;
|
||||
}
|
||||
|
||||
sub deviceGroupTargetGroups {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my @tgroups;
|
||||
|
||||
if ($self->deviceGroupExists($group) != TRUE) {
|
||||
$self->{'err_string'} = "deviceGroupTargetGroups(): Device group '$group' does not exist";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $dHandle = new IO::Handle;
|
||||
my $_path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS);
|
||||
if (!(opendir $dHandle, $_path)) {
|
||||
$self->{'err_string'} = "deviceGroupTargetGroups(): Unable to read directory '$_path': $!";
|
||||
return undef;
|
||||
}
|
||||
|
||||
foreach my $tgroup (readdir($dHandle)) {
|
||||
next if (($tgroup eq '.') || ($tgroup eq '..'));
|
||||
|
||||
if (-d make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, $tgroup)) {
|
||||
push @tgroups, $tgroup;
|
||||
}
|
||||
}
|
||||
|
||||
close $dHandle;
|
||||
|
||||
return \@tgroups;
|
||||
}
|
||||
|
||||
sub driverExists {
|
||||
my $self = shift;
|
||||
my $driver = shift;
|
||||
@@ -1373,6 +1499,238 @@ sub removeGroup {
|
||||
return SCST_C_GRP_REM_FAIL;
|
||||
}
|
||||
|
||||
sub addDeviceGroup {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
|
||||
my $rc = $self->deviceGroupExists($group);
|
||||
return SCST_C_DEV_GRP_EXISTS if ($rc == TRUE);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
my ($path, $cmd);
|
||||
if (new_sysfs_interface()) {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
} else {
|
||||
$path = make_path(SCST_DEV_GROUP_DIR(), SCST_MGMT_IO);
|
||||
}
|
||||
$cmd .= "add $group";
|
||||
|
||||
my $io = new IO::File $path, O_WRONLY;
|
||||
|
||||
return SCST_C_DEV_GRP_ADD_FAIL if (!$io);
|
||||
|
||||
my $bytes;
|
||||
|
||||
if ($self->{'debug'}) {
|
||||
print "DBG($$): $path -> $cmd\n";
|
||||
} else {
|
||||
$bytes = _syswrite($io, $cmd, length($cmd));
|
||||
}
|
||||
|
||||
close $io;
|
||||
|
||||
return FALSE if ($self->{'debug'} || $bytes);
|
||||
return SCST_C_DEV_GRP_ADD_FAIL;
|
||||
}
|
||||
|
||||
sub removeDeviceGroup {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
|
||||
my $rc = $self->deviceGroupExists($group);
|
||||
return SCST_C_DEV_GRP_NO_GROUP if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
my ($path, $cmd);
|
||||
if (new_sysfs_interface()) {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
} else {
|
||||
$path = make_path(SCST_DEV_GROUP_DIR(), SCST_MGMT_IO);
|
||||
}
|
||||
$cmd .= "del $group";
|
||||
|
||||
my $io = new IO::File $path, O_WRONLY;
|
||||
|
||||
return SCST_C_DEV_GRP_REM_FAIL if (!$io);
|
||||
|
||||
my $bytes;
|
||||
|
||||
if ($self->{'debug'}) {
|
||||
print "DBG($$): $path -> $cmd\n";
|
||||
} else {
|
||||
$bytes = _syswrite($io, $cmd, length($cmd));
|
||||
}
|
||||
|
||||
close $io;
|
||||
|
||||
return FALSE if ($self->{'debug'} || $bytes);
|
||||
return SCST_C_DEV_GRP_REM_FAIL;
|
||||
}
|
||||
|
||||
sub addDeviceGroupDevice {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my $device = shift;
|
||||
|
||||
my $rc = $self->deviceGroupExists($group);
|
||||
return SCST_C_DEV_GRP_NO_GROUP if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
$rc = $self->deviceExists($device);
|
||||
return SCST_C_DEV_NO_DEVICE if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
$rc = $self->deviceGroupDeviceExists($group, $device);
|
||||
return SCST_C_DGRP_DEVICE_EXISTS if ($rc == TRUE);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
my ($path, $cmd);
|
||||
if (new_sysfs_interface()) {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
} else {
|
||||
$path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES, SCST_MGMT_IO);
|
||||
}
|
||||
$cmd .= "add $device";
|
||||
|
||||
my $io = new IO::File $path, O_WRONLY;
|
||||
|
||||
return SCST_C_DGRP_ADD_DEV_FAIL if (!$io);
|
||||
|
||||
my $bytes;
|
||||
|
||||
if ($self->{'debug'}) {
|
||||
print "DBG($$): $path -> $cmd\n";
|
||||
} else {
|
||||
$bytes = _syswrite($io, $cmd, length($cmd));
|
||||
}
|
||||
|
||||
close $io;
|
||||
|
||||
return FALSE if ($self->{'debug'} || $bytes);
|
||||
return SCST_C_DGRP_ADD_DEV_FAIL;
|
||||
}
|
||||
|
||||
sub addDeviceGroupTargetGroup {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my $tgroup = shift;
|
||||
|
||||
my $rc = $self->deviceGroupExists($group);
|
||||
return SCST_C_DEV_GRP_NO_GROUP if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
$rc = $self->deviceGroupTargetGroupExists($group, $tgroup);
|
||||
return SCST_C_DGRP_GROUP_EXISTS if ($rc == TRUE);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
my ($path, $cmd);
|
||||
if (new_sysfs_interface()) {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
} else {
|
||||
$path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, SCST_MGMT_IO);
|
||||
}
|
||||
$cmd .= "add $tgroup";
|
||||
|
||||
my $io = new IO::File $path, O_WRONLY;
|
||||
|
||||
return SCST_C_DGRP_ADD_GRP_FAIL if (!$io);
|
||||
|
||||
my $bytes;
|
||||
|
||||
if ($self->{'debug'}) {
|
||||
print "DBG($$): $path -> $cmd\n";
|
||||
} else {
|
||||
$bytes = _syswrite($io, $cmd, length($cmd));
|
||||
}
|
||||
|
||||
close $io;
|
||||
|
||||
return FALSE if ($self->{'debug'} || $bytes);
|
||||
return SCST_C_DGRP_ADD_GRP_FAIL;
|
||||
}
|
||||
|
||||
sub removeDeviceGroupDevice {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my $device = shift;
|
||||
|
||||
my $rc = $self->deviceGroupExists($group);
|
||||
return SCST_C_DEV_GRP_NO_GROUP if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
$rc = $self->deviceExists($device);
|
||||
return SCST_C_DEV_NO_DEVICE if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
$rc = $self->deviceGroupDeviceExists($group, $device);
|
||||
return SCST_C_DGRP_NO_DEVICE if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
my ($path, $cmd);
|
||||
if (new_sysfs_interface()) {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
} else {
|
||||
$path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_DEVICES, SCST_MGMT_IO);
|
||||
}
|
||||
$cmd .= "del $device";
|
||||
|
||||
my $io = new IO::File $path, O_WRONLY;
|
||||
|
||||
return SCST_C_DGRP_REM_DEV_FAIL if (!$io);
|
||||
|
||||
my $bytes;
|
||||
|
||||
if ($self->{'debug'}) {
|
||||
print "DBG($$): $path -> $cmd\n";
|
||||
} else {
|
||||
$bytes = _syswrite($io, $cmd, length($cmd));
|
||||
}
|
||||
|
||||
close $io;
|
||||
|
||||
return FALSE if ($self->{'debug'} || $bytes);
|
||||
return SCST_C_DGRP_REM_DEV_FAIL;
|
||||
}
|
||||
|
||||
sub removeDeviceGroupTargetGroup {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my $tgroup = shift;
|
||||
|
||||
my $rc = $self->deviceGroupExists($group);
|
||||
return SCST_C_DEV_GRP_NO_GROUP if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
$rc = $self->deviceGroupTargetGroupExists($group, $tgroup);
|
||||
return SCST_C_DGRP_NO_GROUP if (!$rc);
|
||||
return $rc if ($rc > 1);
|
||||
|
||||
my ($path, $cmd);
|
||||
if (new_sysfs_interface()) {
|
||||
die("New /sys interface for device groups not yet supported.");
|
||||
} else {
|
||||
$path = make_path(SCST_DEV_GROUP_DIR(), $group, SCST_DG_TGROUPS, SCST_MGMT_IO);
|
||||
}
|
||||
$cmd .= "del $group";
|
||||
|
||||
my $io = new IO::File $path, O_WRONLY;
|
||||
|
||||
return SCST_C_DGRP_REM_GRP_FAIL if (!$io);
|
||||
|
||||
my $bytes;
|
||||
|
||||
if ($self->{'debug'}) {
|
||||
print "DBG($$): $path -> $cmd\n";
|
||||
} else {
|
||||
$bytes = _syswrite($io, $cmd, length($cmd));
|
||||
}
|
||||
|
||||
close $io;
|
||||
|
||||
return FALSE if ($self->{'debug'} || $bytes);
|
||||
return SCST_C_DGRP_REM_GRP_FAIL;
|
||||
}
|
||||
|
||||
sub addInitiator {
|
||||
my $self = shift;
|
||||
my $driver = shift;
|
||||
@@ -3045,6 +3403,21 @@ sub handlerAttributes {
|
||||
return \%attributes;
|
||||
}
|
||||
|
||||
sub deviceExists {
|
||||
my $self = shift;
|
||||
my $device = shift;
|
||||
|
||||
my $handlers = $self->handlers();
|
||||
|
||||
return SCST_C_FATAL_ERROR if (!defined($handlers));
|
||||
|
||||
foreach my $handler (@{$handlers}) {
|
||||
return TRUE if $self->handlerDeviceExists($handler, $device);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sub handlerDeviceExists {
|
||||
my $self = shift;
|
||||
my $handler = shift;
|
||||
@@ -3408,6 +3781,63 @@ sub setT10DeviceId {
|
||||
return $self->setDeviceAttribute($device, 't10_dev_id', $t10_id);
|
||||
}
|
||||
|
||||
sub deviceGroupExists {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
|
||||
my $groups = $self->deviceGroups();
|
||||
|
||||
return SCST_C_FATAL_ERROR if (!defined($groups));
|
||||
|
||||
foreach my $_group (@{$groups}) {
|
||||
return TRUE if ($group eq $_group);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sub deviceGroupDeviceExists {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my $device = shift;
|
||||
|
||||
if ($self->deviceGroupExists($group) != TRUE) {
|
||||
$self->{'err_string'} = "deviceGroupDeviceExists(): Device group '$group' does not exist";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $devices = $self->deviceGroupDevices($group);
|
||||
|
||||
return SCST_C_FATAL_ERROR if (!defined($devices));
|
||||
|
||||
foreach my $_device (@{$devices}) {
|
||||
return TRUE if ($device eq $_device);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sub deviceGroupTargetGroupExists {
|
||||
my $self = shift;
|
||||
my $group = shift;
|
||||
my $tgroup = shift;
|
||||
|
||||
if ($self->deviceGroupExists($group) != TRUE) {
|
||||
$self->{'err_string'} = "deviceGroupTargetGroupExists(): Device group '$group' does not exist";
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $tgroups = $self->deviceGroupTargetGroups($group);
|
||||
|
||||
return SCST_C_FATAL_ERROR if (!defined($tgroups));
|
||||
|
||||
foreach my $_tgroup (@{$tgroups}) {
|
||||
return TRUE if ($tgroup eq $_tgroup);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sub checkLunCreateAttributes {
|
||||
my $self = shift;
|
||||
my $driver = shift;
|
||||
|
||||
Reference in New Issue
Block a user