FC fix for scanning only connected HBA's

When provided an initiator target map and attempting a rescan
in LinuxFibreChannel.rescan_hosts(...) if the system doesn't
yet have /sys/class/fc_host/fc_transport/** directories then
we can get into a position where the call to
LinuxFibreChannel._get_hba_channel_scsi_target will return
"None". Later on when we iterate through "process" and attempt
to iterate on "cts" this will raise an exception. We used to
fall back to a wildcard scan, and still do if no target map
is provided. This fix will do just that, for cases where we
don't have enough other information we just use wildcards.

In testing it seems like this happens on first-time connections
to a target after the ACLs have been setup on the arrays for
the initiator. After that we can get the HBA channel and SCSI
target with the grep call in _get_hba_channel_scsi_target

Change-Id: Ifd79b055882bb513fccf21d584baaeb1d60e67f2
Closes-Bug: #1774283
Patrick East 5 years ago
parent 6545454c7e
commit 50ef90251c
  1. 14
  2. 8

@ -40,9 +40,10 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
This method only works for Fibre Channel targets that implement a
single WWNN for all ports, so caller should expect us to return either
None or an empty list.
explicit channel and targets or wild cards if we cannot determine them.
:returns: List or None
:returns: List of lists with [c, t] entries, the channel and target
may be '-' wildcards if unable to determine them.
# We want the target's WWPNs, so we use the initiator_target_map if
# present for this hba or default to target_wwns if not present.
@ -74,7 +75,7 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
LOG.debug('Could not get HBA channel and SCSI target ID, path: '
'%(path)s*, reason: %(reason)s', {'path': path,
'reason': exc})
return None
return [['-', '-']]
def rescan_hosts(self, hbas, connection_properties):
LOG.debug('Rescaning HBAs %(hbas)s with connection properties '
@ -100,8 +101,11 @@ class LinuxFibreChannel(linuxscsi.LinuxSCSI):
for hba in hbas:
cts = get_cts(hba, connection_properties)
target_list = with_info if cts else no_info
cts = cts or [('-', '-')]
found_info = True
for hba_channel, target_id in cts:
if hba_channel == '-' or target_id == '-':
found_info = False
target_list = with_info if found_info else no_info
target_list.append((hba, cts))
process = with_info or no_info

@ -135,7 +135,7 @@ class LinuxFCTestCase(base.TestCase):
'grep -Gil "514f0c50023f6c00" '
self.assertEqual([['-', '-']], res)
def test_rescan_hosts_initiator_map(self):
"""Test FC rescan with initiator map and not every HBA connected."""
@ -177,7 +177,8 @@ class LinuxFCTestCase(base.TestCase):
def test_rescan_hosts_single_wwnn(self):
"""Test FC rescan with no initiator map and single WWNN for ports."""
get_chan_results = [[['2', '3'], ['4', '5']], [['6', '7']], None]
get_chan_results = [[['2', '3'], ['4', '5']],
[['6', '7']], [['-', '-']]]
hbas, con_props = self.__get_rescan_info(zone_manager=True)
# Remove the initiator map
@ -215,11 +216,12 @@ class LinuxFCTestCase(base.TestCase):
def test_rescan_hosts_wildcard(self):
"""Test when we don't have initiator map or target is single WWNN."""
get_chan_results = [[['-', '-']], [['-', '-']]]
hbas, con_props = self.__get_rescan_info(zone_manager=True)
# Remove the initiator map
with mock.patch.object(self.lfc, '_get_hba_channel_scsi_target',
side_effect=(None, [])), \
side_effect=get_chan_results), \
mock.patch.object(self.lfc, '_execute',
side_effect=None) as execute_mock: