From b13a8f810b143f5f0f465ab45eab453c1e65de7d Mon Sep 17 00:00:00 2001
From: yixuanzhang <yixuan_z@hotmail.com>
Date: Fri, 12 Jan 2018 15:33:25 +0800
Subject: [PATCH] Storwize: modify hyperswap host_site configuration

The new configuration storwize_preferred_host_site was introduced in
volume type for hyperswap feature on Queens release. Actually, the
host_site is related to host rather than volume.

This patch removes the parameter storwzie_preferred_host_site from
volume type configuration and updates it from StrOpt to DictOpt in cinder
back-end configuration.

Closes-Bug:  1742866

Change-Id: Ie1df4cc45c2d1f72f33beea7ddc5bb3797a34728
---
 .../volume/drivers/ibm/test_storwize_svc.py   | 191 +++++++-----------
 .../ibm/storwize_svc/storwize_svc_common.py   |  60 +++++-
 .../ibm/storwize_svc/storwize_svc_fc.py       |  36 ++--
 .../ibm/storwize_svc/storwize_svc_iscsi.py    |  38 ++--
 .../drivers/ibm-storwize-svc-driver.rst       |  21 +-
 ...wap-host-site-update-621e763768fab9ee.yaml |   6 +
 6 files changed, 178 insertions(+), 174 deletions(-)
 create mode 100644 releasenotes/notes/storwize-hyperswap-host-site-update-621e763768fab9ee.yaml

diff --git a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py
index 25b873d8366..54649ecc871 100644
--- a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py
+++ b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py
@@ -3038,6 +3038,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
         if self.USESIM:
             self.iscsi_driver = StorwizeSVCISCSIFakeDriver(
                 configuration=conf.Configuration([], conf.SHARED_CONF_GROUP))
+            self.host_site = {'site1': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
             self._def_flags = {'san_ip': 'hostname',
                                'san_login': 'user',
                                'san_password': 'pass',
@@ -3045,7 +3046,8 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
                                'storwize_svc_flashcopy_timeout': 20,
                                'storwize_svc_flashcopy_rate': 49,
                                'storwize_svc_multipath_enabled': False,
-                               'storwize_svc_allow_tenant_qos': True}
+                               'storwize_svc_allow_tenant_qos': True,
+                               'storwize_preferred_host_site': self.host_site}
             wwpns = [
                 six.text_type(random.randint(0, 9999999999999999)).zfill(16),
                 six.text_type(random.randint(0, 9999999999999999)).zfill(16)]
@@ -3210,73 +3212,37 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 
-        # host_site is None
-        volume0_iSCSI = self._create_volume()
-        vol_type_iSCSI_0 = volume_types.create(self.ctxt, 'iSCSI0', None)
-        volume0_iSCSI['volume_type_id'] = vol_type_iSCSI_0['id']
-        self.iscsi_driver.initialize_connection(volume0_iSCSI, connector)
-
-        # host_site is site1
+        volume_iSCSI_1 = self._create_volume()
         volume_iSCSI = self._create_volume()
         extra_spec = {'drivers:volume_topology': 'hyperswap',
-                      'peer_pool': 'openstack1',
-                      'host_site': 'site1'}
+                      'peer_pool': 'openstack1'}
         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
+        volume_iSCSI_2 = self._create_volume()
+        volume_iSCSI_2['volume_type_id'] = vol_type_iSCSI['id']
         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
-
-        # host_site is site2, different with site1.
-        volume1_iSCSI = self._create_volume()
-        extra_spec_1 = {'drivers:volume_topology': 'hyperswap',
-                        'peer_pool': 'openstack1',
-                        'host_site': 'site2'}
-        vol_type_iSCSI_1 = volume_types.create(self.ctxt, 'iSCSI1',
-                                               extra_spec_1)
-        volume1_iSCSI['volume_type_id'] = vol_type_iSCSI_1['id']
-        self.assertRaises(exception.VolumeDriverException,
-                          self.iscsi_driver.initialize_connection,
-                          volume1_iSCSI,
-                          connector)
-
-        # host_site is None.
-        volume2_iSCSI = self._create_volume()
-        vol_type_iSCSI_2 = volume_types.create(self.ctxt, 'iSCSI2', None)
-        volume2_iSCSI['volume_type_id'] = vol_type_iSCSI_2['id']
-        self.iscsi_driver.initialize_connection(volume2_iSCSI, connector)
-
-        # create new host with host_site, the host site should be update
-        connector2 = {'host': 'STORWIZE-SVC-HOST',
-                      'wwnns': ['30000090fa17311e', '30000090fa17311f'],
-                      'wwpns': ['ffff000000000000', 'ffff000000000001'],
-                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1bbb'}
-        # attach hyperswap volume without host_site
-        volume3_iSCSI = self._create_volume()
-        extra_spec_3 = {'drivers:volume_topology': 'hyperswap',
-                        'peer_pool': 'openstack1'}
-        vol_type_iSCSI_3 = volume_types.create(self.ctxt, 'iSCSI3',
-                                               extra_spec_3)
-        volume3_iSCSI['volume_type_id'] = vol_type_iSCSI_3['id']
         with mock.patch.object(storwize_svc_common.StorwizeHelpers,
-                               'is_volume_hyperswap') as hyperswap:
-            hyperswap.return_value = True
-            self.assertRaises(exception.VolumeDriverException,
-                              self.iscsi_driver.initialize_connection,
-                              volume3_iSCSI,
-                              connector2)
+                               'is_volume_hyperswap') as is_volume_hyperswap:
+            is_volume_hyperswap.return_value = True
+            self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
+            host_name = self.iscsi_driver._helpers.get_host_from_connector(
+                connector, iscsi=True)
+            host_info = self.iscsi_driver._helpers.ssh.lshost(host=host_name)
+            self.assertEqual('site1', host_info[0]['site_name'])
+            self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
+        self.iscsi_driver.initialize_connection(volume_iSCSI_1, connector)
+        with mock.patch.object(storwize_svc_common.StorwizeHelpers,
+                               'is_volume_hyperswap') as is_volume_hyperswap:
+            is_volume_hyperswap.return_value = True
+            self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 
-        # attach hyperswap volume with host_site
-        volume4_iSCSI = self._create_volume()
-        extra_spec_4 = {'drivers:volume_topology': 'hyperswap',
-                        'peer_pool': 'openstack1',
-                        'host_site': 'site2'}
-        vol_type_iSCSI_4 = volume_types.create(self.ctxt, 'iSCSI4',
-                                               extra_spec_4)
-        volume4_iSCSI['volume_type_id'] = vol_type_iSCSI_4['id']
-        self.iscsi_driver.initialize_connection(volume4_iSCSI, connector2)
-        host_name = self.iscsi_driver._helpers.get_host_from_connector(
-            connector2, iscsi=True)
-        host_info = self.iscsi_driver._helpers.ssh.lshost(host=host_name)
-        self.assertEqual('site2', host_info[0]['site_name'])
+            host_site = {'site1': 'iqn.1993-08.org.debian:01:eac5ccc1aaa',
+                         'site2': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
+            self._set_flag('storwize_preferred_host_site', host_site)
+            self.assertRaises(exception.InvalidConfigurationValue,
+                              self.iscsi_driver.initialize_connection,
+                              volume_iSCSI_2,
+                              connector)
 
     @mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
                        '_do_terminate_connection')
@@ -4040,73 +4006,60 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
     def test_storwize_initialize_fc_connection_with_host_site(self):
         connector = {'host': 'storwize-svc-host',
                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
-                     'wwpns': ['ff00000000000000', 'ff00000000000001'],
+                     'wwpns': ['ffff000000000000', 'ffff000000000001'],
                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
-
-        # host_site is None
-        volume0_fc = self._create_volume()
-        vol_type_fc_0 = volume_types.create(self.ctxt, 'FC0', None)
-        volume0_fc['volume_type_id'] = vol_type_fc_0['id']
-        self.fc_driver.initialize_connection(volume0_fc, connector)
-
-        # host_site is site1
+        # attach hyperswap volume without host_site
         volume_fc = self._create_volume()
         extra_spec = {'drivers:volume_topology': 'hyperswap',
-                      'peer_pool': 'openstack1',
-                      'host_site': 'site1'}
+                      'peer_pool': 'openstack1'}
         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
         volume_fc['volume_type_id'] = vol_type_fc['id']
-        self.fc_driver.initialize_connection(volume_fc, connector)
-        host_name = self.fc_driver._helpers.get_host_from_connector(
-            connector, iscsi=True)
-        host_info = self.fc_driver._helpers.ssh.lshost(host=host_name)
-        self.assertEqual('site1', host_info[0]['site_name'])
-
-        # host_site is site2, different with site1.
-        volume1_fc = self._create_volume()
-        extra_spec_1 = {'drivers:volume_topology': 'hyperswap',
-                        'peer_pool': 'openstack1',
-                        'host_site': 'site2'}
-        vol_type_fc_1 = volume_types.create(self.ctxt, 'FC1', extra_spec_1)
-        volume1_fc['volume_type_id'] = vol_type_fc_1['id']
-        self.assertRaises(exception.VolumeDriverException,
-                          self.fc_driver.initialize_connection,
-                          volume1_fc,
-                          connector)
-
-        # host_site is None.
-        volume2_fc = self._create_volume()
-        vol_type_fc_2 = volume_types.create(self.ctxt, 'FC2', None)
-        volume2_fc['volume_type_id'] = vol_type_fc_2['id']
-        self.fc_driver.initialize_connection(volume2_fc, connector)
-
-        # create new host with host_site
-        connector2 = {'host': 'STORWIZE-SVC-HOST',
-                      'wwnns': ['30000090fa17311e', '30000090fa17311f'],
-                      'wwpns': ['ffff000000000000', 'ffff000000000001'],
-                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1bbb'}
-        # attach hyperswap volume without host_site
-        volume3_fc = self._create_volume()
-        extra_spec_3 = {'drivers:volume_topology': 'hyperswap',
-                        'peer_pool': 'openstack1'}
-        vol_type_fc_3 = volume_types.create(self.ctxt, 'FC3', extra_spec_3)
-        volume3_fc['volume_type_id'] = vol_type_fc_3['id']
+        volume_fc_2 = self._create_volume()
+        volume_fc_2['volume_type_id'] = vol_type_fc['id']
         with mock.patch.object(storwize_svc_common.StorwizeHelpers,
                                'is_volume_hyperswap') as is_volume_hyperswap:
             is_volume_hyperswap.return_value = True
             self.assertRaises(exception.VolumeDriverException,
                               self.fc_driver.initialize_connection,
-                              volume3_fc,
-                              connector2)
+                              volume_fc,
+                              connector)
+            # the wwpns of 1 host config to 2 different sites
+            host_site = {'site1': 'ffff000000000000',
+                         'site2': 'ffff000000000001'}
+            self.fc_driver.configuration.set_override(
+                'storwize_preferred_host_site', host_site)
+            self.assertRaises(exception.InvalidConfigurationValue,
+                              self.fc_driver.initialize_connection,
+                              volume_fc,
+                              connector)
+            # All the wwpns of this host are not configured.
+            host_site_2 = {'site1': 'ff00000000000000',
+                           'site1': 'ff00000000000001'}
+            self.fc_driver.configuration.set_override(
+                'storwize_preferred_host_site', host_site_2)
+            self.assertRaises(exception.VolumeDriverException,
+                              self.fc_driver.initialize_connection,
+                              volume_fc,
+                              connector)
 
-        # attach hyperswap volume with host_site
-        volume4_fc = self._create_volume()
-        extra_spec_4 = {'drivers:volume_topology': 'hyperswap',
-                        'peer_pool': 'openstack1',
-                        'host_site': 'site2'}
-        vol_type_fc_4 = volume_types.create(self.ctxt, 'FC4', extra_spec_4)
-        volume4_fc['volume_type_id'] = vol_type_fc_4['id']
-        self.fc_driver.initialize_connection(volume4_fc, connector2)
+            host_site_3 = {'site1': 'ffff000000000000',
+                           'site1': 'ffff000000000001'}
+            self.fc_driver.configuration.set_override(
+                'storwize_preferred_host_site', host_site_3)
+            self.fc_driver.initialize_connection(volume_fc, connector)
+            host_name = self.fc_driver._helpers.get_host_from_connector(
+                connector, iscsi=True)
+            host_info = self.fc_driver._helpers.ssh.lshost(host=host_name)
+            self.assertEqual('site1', host_info[0]['site_name'])
+
+            host_site_4 = {'site2': 'ffff000000000000',
+                           'site2': 'ffff000000000001'}
+            self.fc_driver.configuration.set_override(
+                'storwize_preferred_host_site', host_site_4)
+            self.assertRaises(exception.InvalidConfigurationValue,
+                              self.fc_driver.initialize_connection,
+                              volume_fc_2,
+                              connector)
 
     @mock.patch.object(storwize_svc_fc.StorwizeSVCFCDriver,
                        '_do_terminate_connection')
@@ -4812,8 +4765,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
 
     def _create_hyperswap_type(self, type_name):
         spec = {'drivers:volume_topology': 'hyperswap',
-                'peer_pool': 'hyperswap2',
-                'host_site': 'site1'}
+                'peer_pool': 'hyperswap2'}
         hyper_type = self._create_volume_type(spec, type_name)
         return hyper_type
 
@@ -4939,7 +4891,6 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
                'mirror_pool': None,
                'volume_topology': None,
                'peer_pool': None,
-               'host_site': None,
                'cycle_period_seconds': 300,
                }
         return opt
diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py
index a72817885c6..db076390883 100644
--- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py
+++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py
@@ -130,9 +130,14 @@ storwize_svc_opts = [
                default=None,
                help='Specifies the name of the peer pool for hyperswap '
                     'volume, the peer pool must exist on the other site.'),
-    cfg.StrOpt('storwize_preferred_host_site',
-               default=None,
-               help='Specifies the preferred host site name.'),
+    cfg.DictOpt('storwize_preferred_host_site',
+                default={},
+                help='Specifies the site information for host. '
+                     'One WWPN or multi WWPNs used in the host can be '
+                     'specified. For example: '
+                     'storwize_preferred_host_site=site1:wwpn1,'
+                     'site2:wwpn2&wwpn3 or '
+                     'storwize_preferred_host_site=site1:iqn1,site2:iqn2'),
     cfg.IntOpt('cycle_period_seconds',
                default=300,
                min=60, max=86400,
@@ -866,6 +871,10 @@ class StorwizeHelpers(object):
 
         site_iogrp = []
         pool_data = self.get_pool_attrs(pool)
+        if pool_data is None:
+            msg = (_('Failed getting details for pool %s.') % pool)
+            LOG.error(msg)
+            raise exception.InvalidConfigurationValue(message=msg)
         if 'site_id' in pool_data and pool_data['site_id']:
             for node in state['storage_nodes'].values():
                 if pool_data['site_id'] == node['site_id']:
@@ -1258,7 +1267,6 @@ class StorwizeHelpers(object):
                'mirror_pool': config.storwize_svc_mirror_pool,
                'volume_topology': None,
                'peer_pool': config.storwize_peer_pool,
-               'host_site': config.storwize_preferred_host_site,
                'cycle_period_seconds': config.cycle_period_seconds}
         return opt
 
@@ -5554,3 +5562,47 @@ class StorwizeSVCCommonDriver(san.SanDriver,
                           "from rccg. Exception: %(exception)s.",
                           {'vol': volume.name, 'exception': err})
         return model_update, added_vols, removed_vols
+
+    def _get_volume_host_site_from_conf(self, volume, connector, iscsi=False):
+        host_site = self.configuration.safe_get('storwize_preferred_host_site')
+        select_site = None
+        if not host_site:
+            LOG.debug('There is no host_site configured for volume %s.',
+                      volume.name)
+            return select_site
+        if iscsi:
+            for site, iqn in host_site.items():
+                if connector['initiator'].lower() in iqn.lower():
+                    if select_site is None:
+                        select_site = site
+                    elif select_site != site:
+                        msg = _('Configured the host IQN in both sites.')
+                        LOG.error(msg)
+                        raise exception.InvalidConfigurationValue(message=msg)
+        else:
+            for wwpn in connector['wwpns']:
+                for site, wwpn_list in host_site.items():
+                    if wwpn.lower() in wwpn_list.lower():
+                        if select_site is None:
+                            select_site = site
+                        elif select_site != site:
+                            msg = _('Configured the host wwpns not in the'
+                                    ' same site.')
+                            LOG.error(msg)
+                            raise exception.InvalidConfigurationValue(
+                                message=msg)
+        return select_site
+
+    def _update_host_site_for_hyperswap_volume(self, host_name, host_site):
+        host_info = self._helpers.ssh.lshost(host=host_name)
+        if not host_info[0]['site_name'] and host_site:
+            self._helpers.update_host(host_name, host_site)
+        elif host_info[0]['site_name']:
+            ref_host_site = host_info[0]['site_name']
+            if host_site and host_site != ref_host_site:
+                msg = (_('The existing host site is %(ref_host_site)s,'
+                         ' but the new host site is %(host_site)s.') %
+                       {'ref_host_site': ref_host_site,
+                        'host_site': host_site})
+                LOG.error(msg)
+                raise exception.InvalidConfigurationValue(message=msg)
diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py
index 910f7490f13..6e0ff48dee2 100644
--- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py
+++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py
@@ -165,36 +165,24 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
         else:
             volume_name, backend_helper, node_state = self._get_vol_sys_info(
                 volume)
-        opts = self._get_vdisk_params(volume.volume_type_id)
-        host_site = opts['host_site']
+
+        host_site = self._get_volume_host_site_from_conf(volume,
+                                                         connector)
+        is_hyper_volume = backend_helper.is_volume_hyperswap(volume_name)
+        # The host_site is necessary for hyperswap volume.
+        if is_hyper_volume and host_site is None:
+            msg = (_('There is no correct storwize_preferred_host_site '
+                     'configured for a hyperswap volume %s.') % volume.name)
+            LOG.error(msg)
+            raise exception.VolumeDriverException(message=msg)
 
         # Check if a host object is defined for this host name
         host_name = backend_helper.get_host_from_connector(connector)
         if host_name is None:
             # Host does not exist - add a new host to Storwize/SVC
-            # The host_site is necessary for hyperswap volume.
-            if backend_helper.is_volume_hyperswap(
-                    volume_name) and host_site is None:
-                msg = (_('There is no host_site configured for a hyperswap'
-                         ' volume %s.') % volume_name)
-                LOG.error(msg)
-                raise exception.VolumeDriverException(message=msg)
-
             host_name = backend_helper.create_host(connector, site=host_site)
-        else:
-            host_info = backend_helper.ssh.lshost(host=host_name)
-            if 'site_name' in host_info[0]:
-                if not host_info[0]['site_name'] and host_site:
-                    backend_helper.update_host(host_name, host_site)
-                elif host_info[0]['site_name']:
-                    ref_host_site = host_info[0]['site_name']
-                    if host_site and host_site != ref_host_site:
-                        msg = (_('The existing host site is %(ref_host_site)s,'
-                                 ' but the new host site is %(host_site)s.') %
-                               {'ref_host_site': ref_host_site,
-                                'host_site': host_site})
-                        LOG.error(msg)
-                        raise exception.VolumeDriverException(message=msg)
+        elif is_hyper_volume:
+            self._update_host_site_for_hyperswap_volume(host_name, host_site)
 
         volume_attributes = backend_helper.get_vdisk_attributes(volume_name)
         if volume_attributes is None:
diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py
index 9e7e4edc950..376da38f67f 100644
--- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py
+++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py
@@ -163,38 +163,26 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
         else:
             volume_name, backend_helper, node_state = self._get_vol_sys_info(
                 volume)
-        opts = self._get_vdisk_params(volume.volume_type_id)
-        host_site = opts['host_site']
+
+        host_site = self._get_volume_host_site_from_conf(volume,
+                                                         connector,
+                                                         iscsi=True)
+        is_hyper_volume = backend_helper.is_volume_hyperswap(volume_name)
+        if is_hyper_volume and host_site is None:
+            msg = (_('There is no correct storwize_preferred_host_site '
+                     'configured for a hyperswap volume %s.') % volume.name)
+            LOG.error(msg)
+            raise exception.VolumeDriverException(message=msg)
 
         # Check if a host object is defined for this host name
         host_name = backend_helper.get_host_from_connector(connector,
                                                            iscsi=True)
         if host_name is None:
             # Host does not exist - add a new host to Storwize/SVC
-            # The host_site is necessary for hyperswap volume
-            if backend_helper.is_volume_hyperswap(
-                    volume_name) and host_site is None:
-                msg = (_('There is no host_site configured for a hyperswap'
-                         ' volume %s.') % volume_name)
-                LOG.error(msg)
-                raise exception.VolumeDriverException(message=msg)
-
             host_name = backend_helper.create_host(connector, iscsi=True,
-                                                   site = host_site)
-        else:
-            host_info = backend_helper.ssh.lshost(host=host_name)
-            if 'site_name' in host_info[0]:
-                if not host_info[0]['site_name'] and host_site:
-                    backend_helper.update_host(host_name, host_site)
-                elif host_info[0]['site_name']:
-                    ref_host_site = host_info[0]['site_name']
-                    if host_site and host_site != ref_host_site:
-                        msg = (_('The existing host site is %(ref_host_site)s,'
-                                 ' but the new host site is %(host_site)s.') %
-                               {'ref_host_site': ref_host_site,
-                                'host_site': host_site})
-                        LOG.error(msg)
-                        raise exception.VolumeDriverException(message=msg)
+                                                   site=host_site)
+        elif is_hyper_volume:
+            self._update_host_site_for_hyperswap_volume(host_name, host_site)
 
         chap_secret = backend_helper.get_chap_secret_for_host(host_name)
         chap_enabled = self.configuration.storwize_svc_iscsi_chap_enabled
diff --git a/doc/source/configuration/block-storage/drivers/ibm-storwize-svc-driver.rst b/doc/source/configuration/block-storage/drivers/ibm-storwize-svc-driver.rst
index 0e8dcf7cb37..cb4a05ff79d 100755
--- a/doc/source/configuration/block-storage/drivers/ibm-storwize-svc-driver.rst
+++ b/doc/source/configuration/block-storage/drivers/ibm-storwize-svc-driver.rst
@@ -584,12 +584,31 @@ A hyperswap volume is created with a volume-type that has the extra spec
 ``drivers:volume_topology`` set to ``hyperswap``.
 To support hyperswap volumes, IBM Storwize/SVC firmware version 7.6.0 or
 later is required.
+Add the following to the back-end configuration to specify the host preferred
+site for hyperswap volume.
+FC:
+
+.. code-block:: ini
+
+   storwize_preferred_host_site = site1:20000090fa17311e&ff00000000000001,
+                                  site2:20000089762sedce&ff00000000000000
+
+iSCSI:
+
+.. code-block:: ini
+
+   storwize_preferred_host_site = site1:iqn.1993-08.org.debian:01:eac5ccc1aaa&iqn.1993-08.org.debian:01:be53b7e236be,
+                                  site2:iqn.1993-08.org.debian:01:eac5ccc1bbb&iqn.1993-08.org.debian:01:abcdefg9876w
+
+The site1 and site2 are names of the two host sites used in Storwize
+storage. The WWPNs and IQNs are the connectors used for host mapping in
+Storwize.
 
 .. code-block:: console
 
    $ cinder type-create hyper_type
    $ cinder type-key hyper_type set drivers:volume_topology=hyperswap \
-     drivers:peer_pool=Pool_site2 drivers:host_site=site1
+     drivers:peer_pool=Pool_site2
 
 .. note::
 
diff --git a/releasenotes/notes/storwize-hyperswap-host-site-update-621e763768fab9ee.yaml b/releasenotes/notes/storwize-hyperswap-host-site-update-621e763768fab9ee.yaml
new file mode 100644
index 00000000000..afd037701b4
--- /dev/null
+++ b/releasenotes/notes/storwize-hyperswap-host-site-update-621e763768fab9ee.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Updated the parameter storwzie_preferred_host_site from StrOpt to DictOpt
+    in cinder back-end configuration, and removed it from volume type
+    configuration.