Merge "SCSI: Support non SAM LUN addressing" into stable/2023.1
This commit is contained in:
commit
9f5796f4c2
25
os_brick/constants.py
Normal file
25
os_brick/constants.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
# Valid SCSI addressing values for 'addressing_mode' in connection info.
|
||||||
|
# More information in os_bric.initiator.linuxscsi.LinuxSCSI.lun_for_addressing
|
||||||
|
SCSI_ADDRESSING_TRANSPARENT = 'transparent'
|
||||||
|
SCSI_ADDRESSING_SAM = 'SAM'
|
||||||
|
SCSI_ADDRESSING_SAM2 = 'SAM2'
|
||||||
|
SCSI_ADDRESSING_SAM3_FLAT = 'SAM3-flat'
|
||||||
|
|
||||||
|
SCSI_ADDRESSING_MODES = (SCSI_ADDRESSING_TRANSPARENT,
|
||||||
|
SCSI_ADDRESSING_SAM,
|
||||||
|
SCSI_ADDRESSING_SAM2,
|
||||||
|
SCSI_ADDRESSING_SAM3_FLAT)
|
@ -161,7 +161,9 @@ class FibreChannelConnector(base.BaseLinuxConnector):
|
|||||||
self,
|
self,
|
||||||
connection_properties: dict, hbas) -> list[str]:
|
connection_properties: dict, hbas) -> list[str]:
|
||||||
targets = connection_properties['targets']
|
targets = connection_properties['targets']
|
||||||
possible_devs = self._get_possible_devices(hbas, targets)
|
addressing_mode = connection_properties.get('addressing_mode')
|
||||||
|
possible_devs = self._get_possible_devices(hbas, targets,
|
||||||
|
addressing_mode)
|
||||||
host_paths = self._get_host_devices(possible_devs)
|
host_paths = self._get_host_devices(possible_devs)
|
||||||
return host_paths
|
return host_paths
|
||||||
|
|
||||||
@ -309,7 +311,8 @@ class FibreChannelConnector(base.BaseLinuxConnector):
|
|||||||
host_devices.append(host_device)
|
host_devices.append(host_device)
|
||||||
return host_devices
|
return host_devices
|
||||||
|
|
||||||
def _get_possible_devices(self, hbas: list, targets: list) -> list:
|
def _get_possible_devices(self, hbas: list, targets: list,
|
||||||
|
addressing_mode: Optional[str] = None) -> list:
|
||||||
"""Compute the possible fibre channel device options.
|
"""Compute the possible fibre channel device options.
|
||||||
|
|
||||||
:param hbas: available hba devices.
|
:param hbas: available hba devices.
|
||||||
@ -328,6 +331,8 @@ class FibreChannelConnector(base.BaseLinuxConnector):
|
|||||||
platform, pci_num = self._get_pci_num(hba)
|
platform, pci_num = self._get_pci_num(hba)
|
||||||
if pci_num is not None:
|
if pci_num is not None:
|
||||||
for wwn, lun in targets:
|
for wwn, lun in targets:
|
||||||
|
lun = self._linuxscsi.lun_for_addressing(lun,
|
||||||
|
addressing_mode)
|
||||||
target_wwn = "0x%s" % wwn.lower()
|
target_wwn = "0x%s" % wwn.lower()
|
||||||
raw_devices.append((platform, pci_num, target_wwn, lun))
|
raw_devices.append((platform, pci_num, target_wwn, lun))
|
||||||
return raw_devices
|
return raw_devices
|
||||||
|
@ -90,7 +90,9 @@ class FibreChannelConnectorS390X(fibre_channel.FibreChannelConnector):
|
|||||||
force, exc):
|
force, exc):
|
||||||
hbas = self._linuxfc.get_fc_hbas_info()
|
hbas = self._linuxfc.get_fc_hbas_info()
|
||||||
targets = connection_properties['targets']
|
targets = connection_properties['targets']
|
||||||
possible_devs = self._get_possible_devices(hbas, targets)
|
addressing_mode = connection_properties.get('addressing_mode')
|
||||||
|
possible_devs = self._get_possible_devices(hbas, targets,
|
||||||
|
addressing_mode)
|
||||||
for platform, pci_num, target_wwn, lun in possible_devs:
|
for platform, pci_num, target_wwn, lun in possible_devs:
|
||||||
target_lun = self._get_lun_string(lun)
|
target_lun = self._get_lun_string(lun)
|
||||||
with exc.context(force, 'Removing device %s:%s:%s failed',
|
with exc.context(force, 'Removing device %s:%s:%s failed',
|
||||||
|
@ -168,6 +168,17 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||||||
# entry: [tcp, [1], 192.168.121.250:3260,1 ...]
|
# entry: [tcp, [1], 192.168.121.250:3260,1 ...]
|
||||||
return [entry[2] for entry in self._get_iscsi_sessions_full()]
|
return [entry[2] for entry in self._get_iscsi_sessions_full()]
|
||||||
|
|
||||||
|
def _get_all_targets(
|
||||||
|
self,
|
||||||
|
connection_properties: dict) -> list[tuple[str, str, list]]:
|
||||||
|
addressing_mode = connection_properties.get('addressing_mode')
|
||||||
|
res = super()._get_all_targets(connection_properties)
|
||||||
|
|
||||||
|
return [(portal,
|
||||||
|
iqn,
|
||||||
|
self._linuxscsi.lun_for_addressing(lun, addressing_mode))
|
||||||
|
for portal, iqn, lun in res]
|
||||||
|
|
||||||
def _get_ips_iqns_luns(
|
def _get_ips_iqns_luns(
|
||||||
self,
|
self,
|
||||||
connection_properties: dict,
|
connection_properties: dict,
|
||||||
|
@ -136,8 +136,12 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
|
|||||||
# If we didn't find any target ports use wildcards if they are enabled
|
# If we didn't find any target ports use wildcards if they are enabled
|
||||||
process = process or skipped
|
process = process or skipped
|
||||||
|
|
||||||
|
addressing_mode = connection_properties.get('addressing_mode')
|
||||||
|
|
||||||
for hba, ctls in process:
|
for hba, ctls in process:
|
||||||
for hba_channel, target_id, target_lun in ctls:
|
for hba_channel, target_id, target_lun in ctls:
|
||||||
|
target_lun = self.lun_for_addressing(target_lun,
|
||||||
|
addressing_mode)
|
||||||
LOG.debug('Scanning %(host)s (wwnn: %(wwnn)s, c: '
|
LOG.debug('Scanning %(host)s (wwnn: %(wwnn)s, c: '
|
||||||
'%(channel)s, t: %(target)s, l: %(lun)s)',
|
'%(channel)s, t: %(target)s, l: %(lun)s)',
|
||||||
{'host': hba['host_device'],
|
{'host': hba['host_device'],
|
||||||
|
@ -29,6 +29,7 @@ from oslo_concurrency import processutils as putils
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
|
|
||||||
|
from os_brick import constants
|
||||||
from os_brick import exception
|
from os_brick import exception
|
||||||
from os_brick import executor
|
from os_brick import executor
|
||||||
from os_brick.privileged import rootwrap as priv_rootwrap
|
from os_brick.privileged import rootwrap as priv_rootwrap
|
||||||
@ -48,6 +49,70 @@ class LinuxSCSI(executor.Executor):
|
|||||||
# As found in drivers/scsi/scsi_lib.c
|
# As found in drivers/scsi/scsi_lib.c
|
||||||
WWN_TYPES = {'t10.': '1', 'eui.': '2', 'naa.': '3'}
|
WWN_TYPES = {'t10.': '1', 'eui.': '2', 'naa.': '3'}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def lun_for_addressing(lun, addressing_mode=None):
|
||||||
|
"""Convert luns to values used by the system.
|
||||||
|
|
||||||
|
How a LUN is codified depends on the standard being used by the storage
|
||||||
|
array and the mode, which is unknown by the host.
|
||||||
|
|
||||||
|
Addressing modes based on the standard:
|
||||||
|
* SAM:
|
||||||
|
- 64bit address
|
||||||
|
|
||||||
|
* SAM-2:
|
||||||
|
- Peripheral device addressing method (Code 00b)
|
||||||
|
+ Single level
|
||||||
|
+ Multi level
|
||||||
|
- Flat space addressing method (Code 01b)
|
||||||
|
- Logical unit addressing mode (Code 10b)
|
||||||
|
- Extended logical unit addressing method (Code 11b)
|
||||||
|
|
||||||
|
* SAM-3: Mostly same as SAM-2 but with some differences,
|
||||||
|
like supporting addressing LUNs < 256 with flat address space.
|
||||||
|
|
||||||
|
This means that the same LUN numbers could have different addressing
|
||||||
|
values. Examples:
|
||||||
|
* LUN 1:
|
||||||
|
- SAM representation: 1
|
||||||
|
- SAM-2 peripheral: 1
|
||||||
|
- SAM-2 flat addressing: Invalid
|
||||||
|
- SAM-3 flat addressing: 16384
|
||||||
|
|
||||||
|
* LUN 256
|
||||||
|
- SAM representation: 256
|
||||||
|
- SAM-2 peripheral: Not possible to represent
|
||||||
|
- SAM-2 flat addressing: 16640
|
||||||
|
- SAM-3 flat addressing: 16640
|
||||||
|
|
||||||
|
This method makes the transformation from the numerical LUN value to
|
||||||
|
the right addressing value based on the addressing_mode.
|
||||||
|
|
||||||
|
Acceptable values are:
|
||||||
|
- SAM: 64bit address with no translation
|
||||||
|
- transparent: Same as SAM but used by drivers that want to use non
|
||||||
|
supported addressing modes by using the addressing mode
|
||||||
|
instead of the LUN without being misleading (untested).
|
||||||
|
- SAM2: Peripheral for LUN < 256 and flat for LUN >= 256. In SAM-2
|
||||||
|
flat cannot be used for 0-255
|
||||||
|
- SAM3-flat: Force flat-space addressing
|
||||||
|
|
||||||
|
The default is SAM/transparent and nothing will be done with the LUNs.
|
||||||
|
"""
|
||||||
|
mode = addressing_mode or constants.SCSI_ADDRESSING_SAM
|
||||||
|
if mode not in constants.SCSI_ADDRESSING_MODES:
|
||||||
|
raise exception.InvalidParameterValue('Invalid addressing_mode '
|
||||||
|
f'{addressing_mode}')
|
||||||
|
|
||||||
|
if (mode == constants.SCSI_ADDRESSING_SAM3_FLAT
|
||||||
|
or (mode == constants.SCSI_ADDRESSING_SAM2 and lun >= 256)):
|
||||||
|
old_lun = lun
|
||||||
|
lun += 16384
|
||||||
|
LOG.info('Transforming LUN value for addressing: %s -> %s',
|
||||||
|
old_lun, lun)
|
||||||
|
|
||||||
|
return lun
|
||||||
|
|
||||||
def echo_scsi_command(self, path, content) -> None:
|
def echo_scsi_command(self, path, content) -> None:
|
||||||
"""Used to echo strings to scsi subsystem."""
|
"""Used to echo strings to scsi subsystem."""
|
||||||
|
|
||||||
|
@ -942,3 +942,53 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase):
|
|||||||
True, mock.ANY)
|
True, mock.ANY)
|
||||||
self.assertEqual(len(expected), realpath_mock.call_count)
|
self.assertEqual(len(expected), realpath_mock.call_count)
|
||||||
realpath_mock.assert_has_calls(expected)
|
realpath_mock.assert_has_calls(expected)
|
||||||
|
|
||||||
|
@ddt.data(None, mock.sentinel.addressing_mode)
|
||||||
|
@mock.patch.object(fibre_channel.FibreChannelConnector,
|
||||||
|
'_get_host_devices')
|
||||||
|
@mock.patch.object(fibre_channel.FibreChannelConnector,
|
||||||
|
'_get_possible_devices')
|
||||||
|
def test__get_possible_volume_paths(self, addressing_mode,
|
||||||
|
pos_devs_mock, host_devs_mock):
|
||||||
|
conn_props = {'targets': mock.sentinel.targets}
|
||||||
|
if addressing_mode:
|
||||||
|
conn_props['addressing_mode'] = addressing_mode
|
||||||
|
res = self.connector._get_possible_volume_paths(conn_props,
|
||||||
|
mock.sentinel.hbas)
|
||||||
|
pos_devs_mock.assert_called_once_with(mock.sentinel.hbas,
|
||||||
|
mock.sentinel.targets,
|
||||||
|
addressing_mode)
|
||||||
|
host_devs_mock.assert_called_once_with(pos_devs_mock.return_value)
|
||||||
|
self.assertEqual(host_devs_mock.return_value, res)
|
||||||
|
|
||||||
|
@mock.patch.object(linuxscsi.LinuxSCSI, 'lun_for_addressing')
|
||||||
|
@mock.patch.object(fibre_channel.FibreChannelConnector, '_get_pci_num')
|
||||||
|
def test__get_possible_devices(self, pci_mock, lun_mock):
|
||||||
|
pci_mock.side_effect = [
|
||||||
|
(mock.sentinel.platform1, mock.sentinel.pci_num1),
|
||||||
|
(mock.sentinel.platform2, mock.sentinel.pci_num2)]
|
||||||
|
hbas = [mock.sentinel.hba1, mock.sentinel.hba2]
|
||||||
|
lun_mock.side_effect = [mock.sentinel.lun1B, mock.sentinel.lun2B] * 2
|
||||||
|
targets = [('wwn1', mock.sentinel.lun1), ('wwn2', mock.sentinel.lun2)]
|
||||||
|
|
||||||
|
res = self.connector._get_possible_devices(
|
||||||
|
hbas, targets, mock.sentinel.addressing_mode)
|
||||||
|
|
||||||
|
self.assertEqual(2, pci_mock.call_count)
|
||||||
|
pci_mock.assert_has_calls([mock.call(mock.sentinel.hba1),
|
||||||
|
mock.call(mock.sentinel.hba2)])
|
||||||
|
self.assertEqual(4, lun_mock.call_count)
|
||||||
|
lun_mock.assert_has_calls([
|
||||||
|
mock.call(mock.sentinel.lun1, mock.sentinel.addressing_mode),
|
||||||
|
mock.call(mock.sentinel.lun2, mock.sentinel.addressing_mode)] * 2)
|
||||||
|
expected = [
|
||||||
|
(mock.sentinel.platform1, mock.sentinel.pci_num1, '0xwwn1',
|
||||||
|
mock.sentinel.lun1B),
|
||||||
|
(mock.sentinel.platform1, mock.sentinel.pci_num1, '0xwwn2',
|
||||||
|
mock.sentinel.lun2B),
|
||||||
|
(mock.sentinel.platform2, mock.sentinel.pci_num2, '0xwwn1',
|
||||||
|
mock.sentinel.lun1B),
|
||||||
|
(mock.sentinel.platform2, mock.sentinel.pci_num2, '0xwwn2',
|
||||||
|
mock.sentinel.lun2B),
|
||||||
|
]
|
||||||
|
self.assertEqual(expected, res)
|
||||||
|
@ -74,7 +74,7 @@ class FibreChannelConnectorS390XTestCase(test_connector.ConnectorTestCase):
|
|||||||
mock_deconfigure_scsi_device.assert_called_with(3, 5,
|
mock_deconfigure_scsi_device.assert_called_with(3, 5,
|
||||||
"0x0002000000000000")
|
"0x0002000000000000")
|
||||||
mock_get_fc_hbas_info.assert_called_once_with()
|
mock_get_fc_hbas_info.assert_called_once_with()
|
||||||
mock_get_possible_devices.assert_called_once_with([], [5, 2])
|
mock_get_possible_devices.assert_called_once_with([], [5, 2], None)
|
||||||
self.assertFalse(bool(exc))
|
self.assertFalse(bool(exc))
|
||||||
|
|
||||||
@mock.patch.object(fibre_channel_s390x.FibreChannelConnectorS390X,
|
@mock.patch.object(fibre_channel_s390x.FibreChannelConnectorS390X,
|
||||||
@ -94,5 +94,5 @@ class FibreChannelConnectorS390XTestCase(test_connector.ConnectorTestCase):
|
|||||||
mock_deconfigure_scsi_device.assert_called_with(3, 5,
|
mock_deconfigure_scsi_device.assert_called_with(3, 5,
|
||||||
"0x0002000000000000")
|
"0x0002000000000000")
|
||||||
mock_get_fc_hbas_info.assert_called_once_with()
|
mock_get_fc_hbas_info.assert_called_once_with()
|
||||||
mock_get_possible_devices.assert_called_once_with([], [5, 2])
|
mock_get_possible_devices.assert_called_once_with([], [5, 2], None)
|
||||||
self.assertTrue(bool(exc))
|
self.assertTrue(bool(exc))
|
||||||
|
@ -1748,3 +1748,31 @@ Setting up iSCSI targets: unused
|
|||||||
connection_properties['data'], old_node_startup_values)
|
connection_properties['data'], old_node_startup_values)
|
||||||
iscsiadm_update_mock.assert_called_once_with(
|
iscsiadm_update_mock.assert_called_once_with(
|
||||||
recover_connection['data'], "node.startup", "manual")
|
recover_connection['data'], "node.startup", "manual")
|
||||||
|
|
||||||
|
@ddt.data(None, 'SAM2')
|
||||||
|
@mock.patch.object(linuxscsi.LinuxSCSI, 'lun_for_addressing')
|
||||||
|
@mock.patch.object(iscsi.base_iscsi.BaseISCSIConnector, '_get_all_targets')
|
||||||
|
def test__get_all_targets_no_addressing_mode(self, addressing_mode,
|
||||||
|
get_mock, luns_mock):
|
||||||
|
get_mock.return_value = [
|
||||||
|
(mock.sentinel.portal1, mock.sentinel.iqn1, mock.sentinel.lun1),
|
||||||
|
(mock.sentinel.portal2, mock.sentinel.iqn2, mock.sentinel.lun2)
|
||||||
|
]
|
||||||
|
luns_mock.side_effect = [mock.sentinel.lun1B, mock.sentinel.lun2B]
|
||||||
|
conn_props = self.CON_PROPS.copy()
|
||||||
|
if addressing_mode:
|
||||||
|
conn_props['addressing_mode'] = addressing_mode
|
||||||
|
|
||||||
|
res = self.connector._get_all_targets(conn_props)
|
||||||
|
|
||||||
|
self.assertEqual(2, luns_mock.call_count)
|
||||||
|
luns_mock.assert_has_calls(
|
||||||
|
[mock.call(mock.sentinel.lun1, addressing_mode),
|
||||||
|
mock.call(mock.sentinel.lun2, addressing_mode)])
|
||||||
|
get_mock.assert_called_once_with(conn_props)
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
(mock.sentinel.portal1, mock.sentinel.iqn1, mock.sentinel.lun1B),
|
||||||
|
(mock.sentinel.portal2, mock.sentinel.iqn2, mock.sentinel.lun2B)
|
||||||
|
]
|
||||||
|
self.assertListEqual(expected, res)
|
||||||
|
@ -268,15 +268,18 @@ class LinuxFCTestCase(base.TestCase):
|
|||||||
mock.call(hbas[1], con_props)]
|
mock.call(hbas[1], con_props)]
|
||||||
mock_get_chan.assert_has_calls(expected_calls)
|
mock_get_chan.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
def test_rescan_hosts_single_wwnn(self):
|
@mock.patch.object(linuxfc.LinuxFibreChannel, 'lun_for_addressing')
|
||||||
|
def test_rescan_hosts_single_wwnn(self, lun_addr_mock):
|
||||||
"""Test FC rescan with no initiator map and single WWNN for ports."""
|
"""Test FC rescan with no initiator map and single WWNN for ports."""
|
||||||
|
lun_addr_mock.return_value = 16640
|
||||||
get_chan_results = [
|
get_chan_results = [
|
||||||
[[['2', '3', 1], ['4', '5', 1]], set()],
|
[[['2', '3', 256], ['4', '5', 256]], set()],
|
||||||
[[['6', '7', 1]], set()],
|
[[['6', '7', 256]], set()],
|
||||||
[[], {1}],
|
[[], {1}],
|
||||||
]
|
]
|
||||||
|
|
||||||
hbas, con_props = self.__get_rescan_info(zone_manager=False)
|
hbas, con_props = self.__get_rescan_info(zone_manager=False)
|
||||||
|
con_props['addressing_mode'] = 'SAM2'
|
||||||
|
|
||||||
# This HBA is the one that is not included in the single WWNN.
|
# This HBA is the one that is not included in the single WWNN.
|
||||||
hbas.append({'device_path': ('/sys/devices/pci0000:00/0000:00:02.0/'
|
hbas.append({'device_path': ('/sys/devices/pci0000:00/0000:00:02.0/'
|
||||||
@ -293,13 +296,13 @@ class LinuxFCTestCase(base.TestCase):
|
|||||||
self.lfc.rescan_hosts(hbas, con_props)
|
self.lfc.rescan_hosts(hbas, con_props)
|
||||||
expected_commands = [
|
expected_commands = [
|
||||||
mock.call('tee', '-a', '/sys/class/scsi_host/host6/scan',
|
mock.call('tee', '-a', '/sys/class/scsi_host/host6/scan',
|
||||||
process_input='2 3 1',
|
process_input='2 3 16640',
|
||||||
root_helper=None, run_as_root=True),
|
root_helper=None, run_as_root=True),
|
||||||
mock.call('tee', '-a', '/sys/class/scsi_host/host6/scan',
|
mock.call('tee', '-a', '/sys/class/scsi_host/host6/scan',
|
||||||
process_input='4 5 1',
|
process_input='4 5 16640',
|
||||||
root_helper=None, run_as_root=True),
|
root_helper=None, run_as_root=True),
|
||||||
mock.call('tee', '-a', '/sys/class/scsi_host/host7/scan',
|
mock.call('tee', '-a', '/sys/class/scsi_host/host7/scan',
|
||||||
process_input='6 7 1',
|
process_input='6 7 16640',
|
||||||
root_helper=None, run_as_root=True)]
|
root_helper=None, run_as_root=True)]
|
||||||
|
|
||||||
execute_mock.assert_has_calls(expected_commands)
|
execute_mock.assert_has_calls(expected_commands)
|
||||||
@ -308,6 +311,7 @@ class LinuxFCTestCase(base.TestCase):
|
|||||||
expected_calls = [mock.call(hbas[0], con_props),
|
expected_calls = [mock.call(hbas[0], con_props),
|
||||||
mock.call(hbas[1], con_props)]
|
mock.call(hbas[1], con_props)]
|
||||||
mock_get_chan.assert_has_calls(expected_calls)
|
mock_get_chan.assert_has_calls(expected_calls)
|
||||||
|
lun_addr_mock.assert_has_calls([mock.call(256, 'SAM2')] * 3)
|
||||||
|
|
||||||
def test_rescan_hosts_initiator_map_single_wwnn(self):
|
def test_rescan_hosts_initiator_map_single_wwnn(self):
|
||||||
"""Test FC rescan with initiator map and single WWNN."""
|
"""Test FC rescan with initiator map and single WWNN."""
|
||||||
|
@ -1380,3 +1380,27 @@ loop0 0"""
|
|||||||
if real_paths:
|
if real_paths:
|
||||||
mocked.assert_has_calls([mock.call(path),
|
mocked.assert_has_calls([mock.call(path),
|
||||||
mock.call(path_used)])
|
mock.call(path_used)])
|
||||||
|
|
||||||
|
@ddt.data(None, 'SAM', 'transparent')
|
||||||
|
def test_lun_for_addressing_transparent_sam(self, mode):
|
||||||
|
lun = self.linuxscsi.lun_for_addressing(1, mode)
|
||||||
|
self.assertEqual(1, lun)
|
||||||
|
lun = self.linuxscsi.lun_for_addressing(256, mode)
|
||||||
|
self.assertEqual(256, lun)
|
||||||
|
|
||||||
|
@ddt.data(1, 'SAM3', 'TRANSPARENT', 'sam', 'sam2')
|
||||||
|
def test_lun_for_addressing_bad(self, mode):
|
||||||
|
self.assertRaises(exception.InvalidParameterValue,
|
||||||
|
self.linuxscsi.lun_for_addressing, 1, mode)
|
||||||
|
|
||||||
|
@ddt.data((1, 1), (100, 100), (256, 16640), (1010, 17394))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_lun_for_addressing_sam2(self, original_lun, expected_lun):
|
||||||
|
lun = self.linuxscsi.lun_for_addressing(original_lun, 'SAM2')
|
||||||
|
self.assertEqual(expected_lun, lun)
|
||||||
|
|
||||||
|
@ddt.data((0, 16384), (100, 16484), (256, 16640), (1010, 17394))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_lun_for_addressing_sam3_flat(self, original_lun, expected_lun):
|
||||||
|
lun = self.linuxscsi.lun_for_addressing(original_lun, 'SAM3-flat')
|
||||||
|
self.assertEqual(expected_lun, lun)
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
iSCSI and FCP: Support for different SCSI addressing modes: SAM, SAM-2, and
|
||||||
|
SAM-3 flat addressing. Defaults to SAM/transparent, but cinder drivers can
|
||||||
|
set key ``addressing_mode`` in the connection properties to indicate other
|
||||||
|
addressing modes using one of the constants from
|
||||||
|
``os_brick.constants.SCSI_ADDRESSING_*`` as the value.
|
Loading…
Reference in New Issue
Block a user