2023-11-30 11:28:48

by Wen Gu

[permalink] [raw]
Subject: [PATCH net-next v3 0/7] net/smc: implement SMCv2.1 virtual ISM device support

The fourth edition of SMCv2 adds the SMC version 2.1 feature updates for
SMC-Dv2 with virtual ISM. Virtual ISM are created and supported mainly by
OS or hypervisor software, comparable to IBM ISM which is based on platform
firmware or hardware.

With the introduction of virtual ISM, SMCv2.1 makes some updates:

- Introduce feature bitmask to indicate supplemental features.
- Reserve a range of CHIDs for virtual ISM.
- Support extended GIDs (128 bits) in CLC handshake.

So this patch set aims to implement these updates in Linux kernel. And it
acts as the first part of SMC-D virtual ISM extension & loopback-ism [1].

[1] https://lore.kernel.org/netdev/[email protected]/

v3->v2:
- Rename smc_clc_fill_fce as smc_clc_fill_fce_v2x;
- Remove ISM_IDENT_MASK from drivers/s390/net/ism.h;
- Add explicitly assigning 'false' to ism_v2_capable in ism_dev_init();
- Remove smc_ism_set_v2_capable() helper for now, and introduce it in
later loopback-ism implementation;

v2->v1:
- Fix sparse complaint;
- Rebase to the latest net-next;

Wen Gu (7):
net/smc: Rename some variable 'fce' to 'fce_v2x' for clarity
net/smc: support SMCv2.x supplemental features negotiation
net/smc: introduce virtual ISM device support feature
net/smc: define a reserved CHID range for virtual ISM devices
net/smc: compatible with 128-bits extend GID of virtual ISM device
net/smc: disable SEID on non-s390 archs where virtual ISM may be used
net/smc: manage system EID in SMC stack instead of ISM driver

drivers/s390/net/ism.h | 7 ----
drivers/s390/net/ism_drv.c | 56 ++++++++-------------------
include/linux/ism.h | 1 -
include/net/smc.h | 16 +++++---
net/smc/af_smc.c | 68 ++++++++++++++++++++++++++-------
net/smc/smc.h | 7 ++++
net/smc/smc_clc.c | 95 ++++++++++++++++++++++++++++++++--------------
net/smc/smc_clc.h | 22 +++++++----
net/smc/smc_core.c | 32 ++++++++++------
net/smc/smc_core.h | 8 ++--
net/smc/smc_diag.c | 7 +++-
net/smc/smc_ism.c | 50 ++++++++++++++++--------
net/smc/smc_ism.h | 30 ++++++++++++++-
net/smc/smc_pnet.c | 4 +-
14 files changed, 266 insertions(+), 137 deletions(-)

--
1.8.3.1


2023-11-30 11:28:56

by Wen Gu

[permalink] [raw]
Subject: [PATCH net-next v3 4/7] net/smc: define a reserved CHID range for virtual ISM devices

According to virtual ISM support feature defined by SMCv2.1, CHIDs in
the range 0xFF00 to 0xFFFF are reserved for use by virtual ISM devices.

And two helpers are introduced to distinguish virtual ISM devices from
the existing platform firmware ISM devices.

Signed-off-by: Wen Gu <[email protected]>
---
net/smc/smc_ism.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index 832b2f4..d1228a6 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -15,6 +15,8 @@

#include "smc.h"

+#define SMC_VIRTUAL_ISM_CHID_MASK 0xFF00
+
struct smcd_dev_list { /* List of SMCD devices */
struct list_head list;
struct mutex mutex; /* Protects list of devices */
@@ -56,4 +58,22 @@ static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok,
return rc < 0 ? rc : 0;
}

+static inline bool __smc_ism_is_virtual(u16 chid)
+{
+ /* CHIDs in range of 0xFF00 to 0xFFFF are reserved
+ * for virtual ISM device.
+ *
+ * loopback-ism: 0xFFFF
+ * virtio-ism: 0xFF00 ~ 0xFFFE
+ */
+ return ((chid & 0xFF00) == 0xFF00);
+}
+
+static inline bool smc_ism_is_virtual(struct smcd_dev *smcd)
+{
+ u16 chid = smcd->ops->get_chid(smcd);
+
+ return __smc_ism_is_virtual(chid);
+}
+
#endif
--
1.8.3.1

2023-11-30 11:29:03

by Wen Gu

[permalink] [raw]
Subject: [PATCH net-next v3 6/7] net/smc: disable SEID on non-s390 archs where virtual ISM may be used

The system EID (SEID) is an internal EID used by SMC-D to represent the
s390 physical machine that OS is executing on. On s390 architecture, it
predefined by fixed string and part of cpuid and is enabled regardless
of whether underlay device is virtual ISM or platform firmware ISM.

However on non-s390 architectures where SMC-D can be used with virtual
ISM devices, there is no similar information to identify physical
machines, especially in virtualization scenarios. So in such cases, SEID
is forcibly disabled and the user-defined UEID will be used to represent
the communicable space.

Signed-off-by: Wen Gu <[email protected]>
---
net/smc/smc_clc.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
index 2d8bc0b..ead2e2e 100644
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -155,10 +155,12 @@ static int smc_clc_ueid_remove(char *ueid)
rc = 0;
}
}
+#if IS_ENABLED(CONFIG_S390)
if (!rc && !smc_clc_eid_table.ueid_cnt) {
smc_clc_eid_table.seid_enabled = 1;
rc = -EAGAIN; /* indicate success and enabling of seid */
}
+#endif
write_unlock(&smc_clc_eid_table.lock);
return rc;
}
@@ -273,22 +275,30 @@ int smc_nl_dump_seid(struct sk_buff *skb, struct netlink_callback *cb)

int smc_nl_enable_seid(struct sk_buff *skb, struct genl_info *info)
{
+#if IS_ENABLED(CONFIG_S390)
write_lock(&smc_clc_eid_table.lock);
smc_clc_eid_table.seid_enabled = 1;
write_unlock(&smc_clc_eid_table.lock);
return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}

int smc_nl_disable_seid(struct sk_buff *skb, struct genl_info *info)
{
int rc = 0;

+#if IS_ENABLED(CONFIG_S390)
write_lock(&smc_clc_eid_table.lock);
if (!smc_clc_eid_table.ueid_cnt)
rc = -ENOENT;
else
smc_clc_eid_table.seid_enabled = 0;
write_unlock(&smc_clc_eid_table.lock);
+#else
+ rc = -EOPNOTSUPP;
+#endif
return rc;
}

@@ -1300,7 +1310,11 @@ void __init smc_clc_init(void)
INIT_LIST_HEAD(&smc_clc_eid_table.list);
rwlock_init(&smc_clc_eid_table.lock);
smc_clc_eid_table.ueid_cnt = 0;
+#if IS_ENABLED(CONFIG_S390)
smc_clc_eid_table.seid_enabled = 1;
+#else
+ smc_clc_eid_table.seid_enabled = 0;
+#endif
}

void smc_clc_exit(void)
--
1.8.3.1

2023-11-30 11:29:12

by Wen Gu

[permalink] [raw]
Subject: [PATCH net-next v3 7/7] net/smc: manage system EID in SMC stack instead of ISM driver

The System EID (SEID) is an internal EID that is used by the SMCv2
software stack that has a predefined and constant value representing
the s390 physical machine that the OS is executing on. So it should
be managed by SMC stack instead of ISM driver and be consistent for
all ISMv2 device (including virtual ISM devices) on s390 architecture.

Suggested-by: Alexandra Winter <[email protected]>
Signed-off-by: Wen Gu <[email protected]>
---
drivers/s390/net/ism.h | 7 -------
drivers/s390/net/ism_drv.c | 38 ++++++--------------------------------
include/linux/ism.h | 1 -
include/net/smc.h | 1 -
net/smc/smc_ism.c | 33 ++++++++++++++++++++++++---------
net/smc/smc_ism.h | 7 +++++++
6 files changed, 37 insertions(+), 50 deletions(-)

diff --git a/drivers/s390/net/ism.h b/drivers/s390/net/ism.h
index 70c5bbd..047fa610 100644
--- a/drivers/s390/net/ism.h
+++ b/drivers/s390/net/ism.h
@@ -16,7 +16,6 @@
*/
#define ISM_DMB_WORD_OFFSET 1
#define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32)
-#define ISM_IDENT_MASK 0x00FFFF

#define ISM_REG_SBA 0x1
#define ISM_REG_IEQ 0x2
@@ -192,12 +191,6 @@ struct ism_sba {
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \
((dmb) | (idx) << 24 | (sf) << 23 | (offset))

-struct ism_systemeid {
- u8 seid_string[24];
- u8 serial_number[4];
- u8 type[4];
-};
-
static inline void __ism_read_cmd(struct ism_dev *ism, void *data,
unsigned long offset, unsigned long len)
{
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 250248b..0590027 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -36,6 +36,7 @@
/* a list for fast mapping */
static u8 max_client;
static DEFINE_MUTEX(clients_lock);
+static bool ism_v2_capable;
struct ism_dev_list {
struct list_head list;
struct mutex mutex; /* protects ism device list */
@@ -443,32 +444,6 @@ int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,
}
EXPORT_SYMBOL_GPL(ism_move);

-static struct ism_systemeid SYSTEM_EID = {
- .seid_string = "IBM-SYSZ-ISMSEID00000000",
- .serial_number = "0000",
- .type = "0000",
-};
-
-static void ism_create_system_eid(void)
-{
- struct cpuid id;
- u16 ident_tail;
- char tmp[5];
-
- get_cpu_id(&id);
- ident_tail = (u16)(id.ident & ISM_IDENT_MASK);
- snprintf(tmp, 5, "%04X", ident_tail);
- memcpy(&SYSTEM_EID.serial_number, tmp, 4);
- snprintf(tmp, 5, "%04X", id.machine);
- memcpy(&SYSTEM_EID.type, tmp, 4);
-}
-
-u8 *ism_get_seid(void)
-{
- return SYSTEM_EID.seid_string;
-}
-EXPORT_SYMBOL_GPL(ism_get_seid);
-
static void ism_handle_event(struct ism_dev *ism)
{
struct ism_event *entry;
@@ -560,7 +535,9 @@ static int ism_dev_init(struct ism_dev *ism)

if (!ism_add_vlan_id(ism, ISM_RESERVED_VLANID))
/* hardware is V2 capable */
- ism_create_system_eid();
+ ism_v2_capable = true;
+ else
+ ism_v2_capable = false;

mutex_lock(&ism_dev_list.mutex);
mutex_lock(&clients_lock);
@@ -665,8 +642,7 @@ static void ism_dev_exit(struct ism_dev *ism)
}
mutex_unlock(&clients_lock);

- if (SYSTEM_EID.serial_number[0] != '0' ||
- SYSTEM_EID.type[0] != '0')
+ if (ism_v2_capable)
ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
unregister_ieq(ism);
unregister_sba(ism);
@@ -812,8 +788,7 @@ static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,

static int smcd_supports_v2(void)
{
- return SYSTEM_EID.serial_number[0] != '0' ||
- SYSTEM_EID.type[0] != '0';
+ return ism_v2_capable;
}

static u64 ism_get_local_gid(struct ism_dev *ism)
@@ -859,7 +834,6 @@ static inline struct device *smcd_get_dev(struct smcd_dev *dev)
.signal_event = smcd_signal_ieq,
.move_data = smcd_move,
.supports_v2 = smcd_supports_v2,
- .get_system_eid = ism_get_seid,
.get_local_gid = smcd_get_local_gid,
.get_chid = smcd_get_chid,
.get_dev = smcd_get_dev,
diff --git a/include/linux/ism.h b/include/linux/ism.h
index 9a4c204..5428edd 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -86,7 +86,6 @@ int ism_register_dmb(struct ism_dev *dev, struct ism_dmb *dmb,
int ism_unregister_dmb(struct ism_dev *dev, struct ism_dmb *dmb);
int ism_move(struct ism_dev *dev, u64 dmb_tok, unsigned int idx, bool sf,
unsigned int offset, void *data, unsigned int size);
-u8 *ism_get_seid(void);

const struct smcd_ops *ism_get_smcd_ops(void);

diff --git a/include/net/smc.h b/include/net/smc.h
index a0dc1187e..c9dcb30 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -73,7 +73,6 @@ struct smcd_ops {
bool sf, unsigned int offset, void *data,
unsigned int size);
int (*supports_v2)(void);
- u8* (*get_system_eid)(void);
void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
u16 (*get_chid)(struct smcd_dev *dev);
struct device* (*get_dev)(struct smcd_dev *dev);
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index a33f861..ac88de2 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -43,6 +43,27 @@ static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
};
#endif

+static void smc_ism_create_system_eid(void)
+{
+ struct smc_ism_seid *seid =
+ (struct smc_ism_seid *)smc_ism_v2_system_eid;
+#if IS_ENABLED(CONFIG_S390)
+ struct cpuid id;
+ u16 ident_tail;
+ char tmp[5];
+
+ memcpy(seid->seid_string, "IBM-SYSZ-ISMSEID00000000", 24);
+ get_cpu_id(&id);
+ ident_tail = (u16)(id.ident & SMC_ISM_IDENT_MASK);
+ snprintf(tmp, 5, "%04X", ident_tail);
+ memcpy(seid->serial_number, tmp, 4);
+ snprintf(tmp, 5, "%04X", id.machine);
+ memcpy(seid->type, tmp, 4);
+#else
+ memset(seid, 0, SMC_MAX_EID_LEN);
+#endif
+}
+
/* Test if an ISM communication is possible - same CPC */
int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
struct smcd_dev *smcd)
@@ -431,14 +452,8 @@ static void smcd_register_dev(struct ism_dev *ism)

mutex_lock(&smcd_dev_list.mutex);
if (list_empty(&smcd_dev_list.list)) {
- u8 *system_eid = NULL;
-
- system_eid = smcd->ops->get_system_eid();
- if (smcd->ops->supports_v2()) {
+ if (smcd->ops->supports_v2())
smc_ism_v2_capable = true;
- memcpy(smc_ism_v2_system_eid, system_eid,
- SMC_MAX_EID_LEN);
- }
}
/* sort list: devices without pnetid before devices with pnetid */
if (smcd->pnetid[0])
@@ -542,10 +557,10 @@ int smc_ism_init(void)
{
int rc = 0;

-#if IS_ENABLED(CONFIG_ISM)
smc_ism_v2_capable = false;
- memset(smc_ism_v2_system_eid, 0, SMC_MAX_EID_LEN);
+ smc_ism_create_system_eid();

+#if IS_ENABLED(CONFIG_ISM)
rc = ism_register_client(&smc_ism_client);
#endif
return rc;
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index 0e5e563..ffff40c 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -16,6 +16,7 @@
#include "smc.h"

#define SMC_VIRTUAL_ISM_CHID_MASK 0xFF00
+#define SMC_ISM_IDENT_MASK 0x00FFFF

struct smcd_dev_list { /* List of SMCD devices */
struct list_head list;
@@ -30,6 +31,12 @@ struct smc_ism_vlanid { /* VLAN id set on ISM device */
refcount_t refcnt; /* Reference count */
};

+struct smc_ism_seid {
+ u8 seid_string[24];
+ u8 serial_number[4];
+ u8 type[4];
+};
+
struct smcd_dev;

int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
--
1.8.3.1

2023-11-30 11:29:41

by Wen Gu

[permalink] [raw]
Subject: [PATCH net-next v3 5/7] net/smc: compatible with 128-bits extend GID of virtual ISM device

According to virtual ISM support feature defined by SMCv2.1, GIDs of
virtual ISM device are UUIDs defined by RFC4122, which are 128-bits
long. So some adaptation work is required. And note that the GIDs of
existing platform firmware ISM devices still remain 64-bits long.

Signed-off-by: Wen Gu <[email protected]>
---
drivers/s390/net/ism_drv.c | 18 +++++++------
include/net/smc.h | 15 +++++++----
net/smc/af_smc.c | 66 +++++++++++++++++++++++++++++++++++++---------
net/smc/smc_clc.c | 46 ++++++++++++++++++++++----------
net/smc/smc_clc.h | 8 +++---
net/smc/smc_core.c | 32 ++++++++++++++--------
net/smc/smc_core.h | 7 ++---
net/smc/smc_diag.c | 7 +++--
net/smc/smc_ism.c | 17 +++++++-----
net/smc/smc_ism.h | 3 ++-
net/smc/smc_pnet.c | 4 +--
11 files changed, 154 insertions(+), 69 deletions(-)

diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 81aabbf..250248b 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -743,10 +743,10 @@ static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid,
return ism_cmd(ism, &cmd);
}

-static int smcd_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid,
- u32 vid)
+static int smcd_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid,
+ u32 vid_valid, u32 vid)
{
- return ism_query_rgid(smcd->priv, rgid, vid_valid, vid);
+ return ism_query_rgid(smcd->priv, rgid->gid, vid_valid, vid);
}

static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
@@ -797,10 +797,10 @@ static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
return ism_cmd(ism, &cmd);
}

-static int smcd_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq,
- u32 event_code, u64 info)
+static int smcd_signal_ieq(struct smcd_dev *smcd, struct smcd_gid *rgid,
+ u32 trigger_irq, u32 event_code, u64 info)
{
- return ism_signal_ieq(smcd->priv, rgid, trigger_irq, event_code, info);
+ return ism_signal_ieq(smcd->priv, rgid->gid, trigger_irq, event_code, info);
}

static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
@@ -821,9 +821,11 @@ static u64 ism_get_local_gid(struct ism_dev *ism)
return ism->local_gid;
}

-static u64 smcd_get_local_gid(struct smcd_dev *smcd)
+static void smcd_get_local_gid(struct smcd_dev *smcd,
+ struct smcd_gid *smcd_gid)
{
- return ism_get_local_gid(smcd->priv);
+ smcd_gid->gid = ism_get_local_gid(smcd->priv);
+ smcd_gid->gid_ext = 0;
}

static u16 ism_get_chid(struct ism_dev *ism)
diff --git a/include/net/smc.h b/include/net/smc.h
index a002552..a0dc1187e 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -52,9 +52,14 @@ struct smcd_dmb {
struct smcd_dev;
struct ism_client;

+struct smcd_gid {
+ u64 gid;
+ u64 gid_ext;
+};
+
struct smcd_ops {
- int (*query_remote_gid)(struct smcd_dev *dev, u64 rgid, u32 vid_valid,
- u32 vid);
+ int (*query_remote_gid)(struct smcd_dev *dev, struct smcd_gid *rgid,
+ u32 vid_valid, u32 vid);
int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb,
struct ism_client *client);
int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
@@ -62,14 +67,14 @@ struct smcd_ops {
int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
int (*set_vlan_required)(struct smcd_dev *dev);
int (*reset_vlan_required)(struct smcd_dev *dev);
- int (*signal_event)(struct smcd_dev *dev, u64 rgid, u32 trigger_irq,
- u32 event_code, u64 info);
+ int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
+ u32 trigger_irq, u32 event_code, u64 info);
int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
bool sf, unsigned int offset, void *data,
unsigned int size);
int (*supports_v2)(void);
u8* (*get_system_eid)(void);
- u64 (*get_local_gid)(struct smcd_dev *dev);
+ void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
u16 (*get_chid)(struct smcd_dev *dev);
struct device* (*get_dev)(struct smcd_dev *dev);
};
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 766a1f1..d1e18bf 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -723,7 +723,7 @@ static void smcd_conn_save_peer_info(struct smc_sock *smc,
int bufsize = smc_uncompress_bufsize(clc->d0.dmbe_size);

smc->conn.peer_rmbe_idx = clc->d0.dmbe_idx;
- smc->conn.peer_token = clc->d0.token;
+ smc->conn.peer_token = ntohll(clc->d0.token);
/* msg header takes up space in the buffer */
smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg);
atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
@@ -1048,7 +1048,8 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
{
int rc = SMC_CLC_DECL_NOSMCDDEV;
struct smcd_dev *smcd;
- int i = 1;
+ int i = 1, entry = 1;
+ bool is_virtual;
u16 chid;

if (smcd_indicated(ini->smc_type_v1))
@@ -1060,14 +1061,23 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
chid = smc_ism_get_chid(smcd);
if (!smc_find_ism_v2_is_unique_chid(chid, ini, i))
continue;
+ is_virtual = __smc_ism_is_virtual(chid);
if (!smc_pnet_is_pnetid_set(smcd->pnetid) ||
smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) {
+ if (is_virtual && entry == SMC_MAX_ISM_DEVS)
+ /* only one GID-CHID entry left in CLC Proposal SMC-Dv2
+ * extension. but a virtual ISM device's GID takes two
+ * entries. So give up it and try the next potential ISM
+ * device.
+ */
+ continue;
ini->ism_dev[i] = smcd;
ini->ism_chid[i] = chid;
ini->is_smcd = true;
rc = 0;
i++;
- if (i > SMC_MAX_ISM_DEVS)
+ entry = is_virtual ? entry + 2 : entry + 1;
+ if (entry > SMC_MAX_ISM_DEVS)
break;
}
}
@@ -1414,8 +1424,13 @@ static int smc_connect_ism(struct smc_sock *smc,
rc = smc_v2_determine_accepted_chid(aclc_v2, ini);
if (rc)
return rc;
+
+ if (__smc_ism_is_virtual(ini->ism_chid[ini->ism_selected]))
+ ini->ism_peer_gid[ini->ism_selected].gid_ext =
+ ntohll(aclc_v2->d1.gid_ext);
+ /* for non-virtual ISM devices, peer gid_ext remains 0. */
}
- ini->ism_peer_gid[ini->ism_selected] = aclc->d0.gid;
+ ini->ism_peer_gid[ini->ism_selected].gid = ntohll(aclc->d0.gid);

/* there is only one lgr role for SMC-D; use server lock */
mutex_lock(&smc_server_lgr_pending);
@@ -2108,7 +2123,8 @@ static bool smc_is_already_selected(struct smcd_dev *smcd,

/* check for ISM devices matching proposed ISM devices */
static void smc_check_ism_v2_match(struct smc_init_info *ini,
- u16 proposed_chid, u64 proposed_gid,
+ u16 proposed_chid,
+ struct smcd_gid *proposed_gid,
unsigned int *matches)
{
struct smcd_dev *smcd;
@@ -2120,7 +2136,11 @@ static void smc_check_ism_v2_match(struct smc_init_info *ini,
continue;
if (smc_ism_get_chid(smcd) == proposed_chid &&
!smc_ism_cantalk(proposed_gid, ISM_RESERVED_VLANID, smcd)) {
- ini->ism_peer_gid[*matches] = proposed_gid;
+ ini->ism_peer_gid[*matches].gid = proposed_gid->gid;
+ if (__smc_ism_is_virtual(proposed_chid))
+ ini->ism_peer_gid[*matches].gid_ext =
+ proposed_gid->gid_ext;
+ /* non-virtual ISM's peer gid_ext remains 0. */
ini->ism_dev[*matches] = smcd;
(*matches)++;
break;
@@ -2142,9 +2162,11 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
struct smc_clc_v2_extension *smc_v2_ext;
struct smc_clc_msg_smcd *pclc_smcd;
unsigned int matches = 0;
+ struct smcd_gid smcd_gid;
u8 smcd_version;
u8 *eid = NULL;
int i, rc;
+ u16 chid;

if (!(ini->smcd_version & SMC_V2) || !smcd_indicated(ini->smc_type_v2))
goto not_found;
@@ -2154,18 +2176,35 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);

mutex_lock(&smcd_dev_list.mutex);
- if (pclc_smcd->ism.chid)
+ if (pclc_smcd->ism.chid) {
/* check for ISM device matching proposed native ISM device */
+ smcd_gid.gid = ntohll(pclc_smcd->ism.gid);
+ smcd_gid.gid_ext = 0;
smc_check_ism_v2_match(ini, ntohs(pclc_smcd->ism.chid),
- ntohll(pclc_smcd->ism.gid), &matches);
+ &smcd_gid, &matches);
+ }
for (i = 1; i <= smc_v2_ext->hdr.ism_gid_cnt; i++) {
/* check for ISM devices matching proposed non-native ISM
* devices
*/
- smc_check_ism_v2_match(ini,
- ntohs(smcd_v2_ext->gidchid[i - 1].chid),
- ntohll(smcd_v2_ext->gidchid[i - 1].gid),
- &matches);
+ smcd_gid.gid = ntohll(smcd_v2_ext->gidchid[i - 1].gid);
+ smcd_gid.gid_ext = 0;
+ chid = ntohs(smcd_v2_ext->gidchid[i - 1].chid);
+ if (__smc_ism_is_virtual(chid)) {
+ if (i == smc_v2_ext->hdr.ism_gid_cnt ||
+ chid != ntohs(smcd_v2_ext->gidchid[i].chid))
+ /* a virtual ISM device takes two GID-CHID entries
+ * and CHID of the second entry repeats that of the
+ * first entry.
+ *
+ * So check if the second GID-CHID entry exists and
+ * the CHIDs of these two entries are the same.
+ */
+ continue;
+
+ smcd_gid.gid_ext = ntohll(smcd_v2_ext->gidchid[i++].gid);
+ }
+ smc_check_ism_v2_match(ini, chid, &smcd_gid, &matches);
}
mutex_unlock(&smcd_dev_list.mutex);

@@ -2214,7 +2253,8 @@ static void smc_find_ism_v1_device_serv(struct smc_sock *new_smc,
if (!(ini->smcd_version & SMC_V1) || !smcd_indicated(ini->smc_type_v1))
goto not_found;
ini->is_smcd = true; /* prepare ISM check */
- ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid);
+ ini->ism_peer_gid[0].gid = ntohll(pclc_smcd->ism.gid);
+ ini->ism_peer_gid[0].gid_ext = 0;
rc = smc_find_ism_device(new_smc, ini);
if (rc)
goto not_found;
diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
index e2e437b..2d8bc0b 100644
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -883,11 +883,13 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
ETH_ALEN);
}
if (smcd_indicated(ini->smc_type_v1)) {
+ struct smcd_gid smcd_gid;
+
/* add SMC-D specifics */
if (ini->ism_dev[0]) {
smcd = ini->ism_dev[0];
- pclc_smcd->ism.gid =
- htonll(smcd->ops->get_local_gid(smcd));
+ smcd->ops->get_local_gid(smcd, &smcd_gid);
+ pclc_smcd->ism.gid = htonll(smcd_gid.gid);
pclc_smcd->ism.chid =
htons(smc_ism_get_chid(ini->ism_dev[0]));
}
@@ -920,10 +922,11 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
read_unlock(&smc_clc_eid_table.lock);
}
if (smcd_indicated(ini->smc_type_v2)) {
+ struct smcd_gid smcd_gid;
u8 *eid = NULL;
+ int entry = 0;

v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled;
- v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
offsetofend(struct smc_clnt_opts_area_hdr,
smcd_v2_ext_offset) +
@@ -935,14 +938,24 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
if (ini->ism_offered_cnt) {
for (i = 1; i <= ini->ism_offered_cnt; i++) {
smcd = ini->ism_dev[i];
- gidchids[i - 1].gid =
- htonll(smcd->ops->get_local_gid(smcd));
- gidchids[i - 1].chid =
+ smcd->ops->get_local_gid(smcd, &smcd_gid);
+ gidchids[entry].chid =
htons(smc_ism_get_chid(ini->ism_dev[i]));
+ gidchids[entry].gid = htonll(smcd_gid.gid);
+ if (smc_ism_is_virtual(smcd)) {
+ /* a virtual ISM device takes two entries.
+ * CHID of the second entry repeats that of the
+ * first entry.
+ */
+ gidchids[entry + 1].chid = gidchids[entry].chid;
+ gidchids[entry + 1].gid = htonll(smcd_gid.gid_ext);
+ entry++;
+ }
+ entry++;
}
- plen += ini->ism_offered_cnt *
- sizeof(struct smc_clc_smcd_gid_chid);
+ plen += entry * sizeof(struct smc_clc_smcd_gid_chid);
}
+ v2_ext->hdr.ism_gid_cnt = entry;
}
if (smcr_indicated(ini->smc_type_v2)) {
memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE);
@@ -978,7 +991,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
vec[i++].iov_len = sizeof(*smcd_v2_ext);
if (ini->ism_offered_cnt) {
vec[i].iov_base = gidchids;
- vec[i++].iov_len = ini->ism_offered_cnt *
+ vec[i++].iov_len = v2_ext->hdr.ism_gid_cnt *
sizeof(struct smc_clc_smcd_gid_chid);
}
}
@@ -1020,23 +1033,28 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
if (first_contact)
clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
if (conn->lgr->is_smcd) {
+ struct smcd_gid smcd_gid;
+ u16 chid;
+
/* SMC-D specific settings */
memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
sizeof(SMCD_EYECATCHER));
+ conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd, &smcd_gid);
clc->hdr.typev1 = SMC_TYPE_D;
- clc->d0.gid =
- conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd);
- clc->d0.token = conn->rmb_desc->token;
+ clc->d0.gid = htonll(smcd_gid.gid);
+ clc->d0.token = htonll(conn->rmb_desc->token);
clc->d0.dmbe_size = conn->rmbe_size_comp;
clc->d0.dmbe_idx = 0;
memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
if (version == SMC_V1) {
clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
} else {
- clc_v2->d1.chid =
- htons(smc_ism_get_chid(conn->lgr->smcd));
+ chid = smc_ism_get_chid(conn->lgr->smcd);
+ clc_v2->d1.chid = htons(chid);
if (eid && eid[0])
memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
+ if (__smc_ism_is_virtual(chid))
+ clc_v2->d1.gid_ext = htonll(smcd_gid.gid_ext);
len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
if (first_contact) {
fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h
index e64c235..dcc63f4 100644
--- a/net/smc/smc_clc.h
+++ b/net/smc/smc_clc.h
@@ -205,8 +205,8 @@ struct smcr_clc_msg_accept_confirm { /* SMCR accept/confirm */
} __packed;

struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */
- u64 gid; /* Sender GID */
- u64 token; /* DMB token */
+ __be64 gid; /* Sender GID */
+ __be64 token; /* DMB token */
u8 dmbe_idx; /* DMBE index */
#if defined(__BIG_ENDIAN_BITFIELD)
u8 dmbe_size : 4, /* buf size (compressed) */
@@ -285,8 +285,8 @@ struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */
struct smcd_clc_msg_accept_confirm_common d0;
__be16 chid;
u8 eid[SMC_MAX_EID_LEN];
- u8 reserved5[8];
- } d1;
+ __be64 gid_ext;
+ } __packed d1;
};
};

diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index d520ee6..32eece5 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -506,6 +506,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
{
char smc_pnet[SMC_MAX_PNETID_LEN + 1];
struct smcd_dev *smcd = lgr->smcd;
+ struct smcd_gid smcd_gid;
struct nlattr *attrs;
void *nlh;

@@ -521,11 +522,11 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,

if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id)))
goto errattr;
+ smcd->ops->get_local_gid(smcd, &smcd_gid);
if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID,
- smcd->ops->get_local_gid(smcd),
- SMC_NLA_LGR_D_PAD))
+ smcd_gid.gid, SMC_NLA_LGR_D_PAD))
goto errattr;
- if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid,
+ if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid.gid,
SMC_NLA_LGR_D_PAD))
goto errattr;
if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id))
@@ -876,7 +877,10 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
/* SMC-D specific settings */
smcd = ini->ism_dev[ini->ism_selected];
get_device(smcd->ops->get_dev(smcd));
- lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
+ lgr->peer_gid.gid =
+ ini->ism_peer_gid[ini->ism_selected].gid;
+ lgr->peer_gid.gid_ext =
+ ini->ism_peer_gid[ini->ism_selected].gid_ext;
lgr->smcd = ini->ism_dev[ini->ism_selected];
lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
lgr_lock = &lgr->smcd->lgr_lock;
@@ -1514,7 +1518,8 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr)
}

/* Called when peer lgr shutdown (regularly or abnormally) is received */
-void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
+void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
+ unsigned short vlan)
{
struct smc_link_group *lgr, *l;
LIST_HEAD(lgr_free_list);
@@ -1522,9 +1527,12 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
/* run common cleanup function and build free list */
spin_lock_bh(&dev->lgr_lock);
list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) {
- if ((!peer_gid || lgr->peer_gid == peer_gid) &&
+ if ((!peer_gid->gid ||
+ (lgr->peer_gid.gid == peer_gid->gid &&
+ !smc_ism_is_virtual(dev) ? 1 :
+ lgr->peer_gid.gid_ext == peer_gid->gid_ext)) &&
(vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
- if (peer_gid) /* peer triggered termination */
+ if (peer_gid->gid) /* peer triggered termination */
lgr->peer_shutdown = 1;
list_move(&lgr->list, &lgr_free_list);
lgr->freeing = 1;
@@ -1859,10 +1867,12 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, u8 smcr_version,
return false;
}

-static bool smcd_lgr_match(struct smc_link_group *lgr,
- struct smcd_dev *smcismdev, u64 peer_gid)
+static bool smcd_lgr_match(struct smc_link_group *lgr, struct smcd_dev *smcismdev,
+ struct smcd_gid *peer_gid)
{
- return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev;
+ return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev &&
+ smc_ism_is_virtual(smcismdev) ?
+ (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1;
}

/* create a new SMC connection (and a new link group if necessary) */
@@ -1892,7 +1902,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
write_lock_bh(&lgr->conns_lock);
if ((ini->is_smcd ?
smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
- ini->ism_peer_gid[ini->ism_selected]) :
+ &ini->ism_peer_gid[ini->ism_selected]) :
smcr_lgr_match(lgr, ini->smcr_version,
ini->peer_systemid,
ini->peer_gid, ini->peer_mac, role,
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
index 9f65678..d57eb9b 100644
--- a/net/smc/smc_core.h
+++ b/net/smc/smc_core.h
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <rdma/ib_verbs.h>
#include <net/genetlink.h>
+#include <net/smc.h>

#include "smc.h"
#include "smc_ib.h"
@@ -355,7 +356,7 @@ struct smc_link_group {
/* max links can be added in lgr */
};
struct { /* SMC-D */
- u64 peer_gid;
+ struct smcd_gid peer_gid;
/* Peer GID (remote) */
struct smcd_dev *smcd;
/* ISM device for VLAN reg. */
@@ -417,7 +418,7 @@ struct smc_init_info {
u32 ib_clcqpn;
struct smc_init_info_smcrv2 smcrv2;
/* SMC-D */
- u64 ism_peer_gid[SMC_MAX_ISM_DEVS + 1];
+ struct smcd_gid ism_peer_gid[SMC_MAX_ISM_DEVS + 1];
struct smcd_dev *ism_dev[SMC_MAX_ISM_DEVS + 1];
u16 ism_chid[SMC_MAX_ISM_DEVS + 1];
u8 ism_offered_cnt; /* # of ISM devices offered */
@@ -545,7 +546,7 @@ static inline void smc_set_pci_values(struct pci_dev *pci_dev,
void smc_lgr_put(struct smc_link_group *lgr);
void smcr_port_add(struct smc_ib_device *smcibdev, u8 ibport);
void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport);
-void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
+void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
unsigned short vlan);
void smc_smcd_terminate_all(struct smcd_dev *dev);
void smc_smcr_terminate_all(struct smc_ib_device *smcibdev);
diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
index a584613..c180c18 100644
--- a/net/smc/smc_diag.c
+++ b/net/smc/smc_diag.c
@@ -21,6 +21,7 @@

#include "smc.h"
#include "smc_core.h"
+#include "smc_ism.h"

struct smc_diag_dump_ctx {
int pos[2];
@@ -168,12 +169,14 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
struct smc_connection *conn = &smc->conn;
struct smcd_diag_dmbinfo dinfo;
struct smcd_dev *smcd = conn->lgr->smcd;
+ struct smcd_gid smcd_gid;

memset(&dinfo, 0, sizeof(dinfo));

dinfo.linkid = *((u32 *)conn->lgr->id);
- dinfo.peer_gid = conn->lgr->peer_gid;
- dinfo.my_gid = smcd->ops->get_local_gid(smcd);
+ dinfo.peer_gid = conn->lgr->peer_gid.gid;
+ smcd->ops->get_local_gid(smcd, &smcd_gid);
+ dinfo.my_gid = smcd_gid.gid;
dinfo.token = conn->rmb_desc->token;
dinfo.peer_token = conn->peer_token;

diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index fbee249..a33f861 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -44,7 +44,8 @@ static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
#endif

/* Test if an ISM communication is possible - same CPC */
-int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
+int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
+ struct smcd_dev *smcd)
{
return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
vlan_id);
@@ -208,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
dmb.dmb_len = dmb_len;
dmb.sba_idx = dmb_desc->sba_idx;
dmb.vlan_id = lgr->vlan_id;
- dmb.rgid = lgr->peer_gid;
+ dmb.rgid = lgr->peer_gid.gid;
rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client);
if (!rc) {
dmb_desc->sba_idx = dmb.sba_idx;
@@ -340,18 +341,20 @@ struct smc_ism_event_work {

static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
{
+ struct smcd_gid peer_gid = { .gid = wrk->event.tok,
+ .gid_ext = 0 };
union smcd_sw_event_info ev_info;

ev_info.info = wrk->event.info;
switch (wrk->event.code) {
case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */
- smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id);
+ smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
break;
case ISM_EVENT_CODE_TESTLINK: /* Activity timer */
if (ev_info.code == ISM_EVENT_REQUEST) {
ev_info.code = ISM_EVENT_RESPONSE;
wrk->smcd->ops->signal_event(wrk->smcd,
- wrk->event.tok,
+ &peer_gid,
ISM_EVENT_REQUEST_IR,
ISM_EVENT_CODE_TESTLINK,
ev_info.info);
@@ -365,10 +368,12 @@ static void smc_ism_event_work(struct work_struct *work)
{
struct smc_ism_event_work *wrk =
container_of(work, struct smc_ism_event_work, work);
+ struct smcd_gid smcd_gid = { .gid = wrk->event.tok,
+ .gid_ext = 0 };

switch (wrk->event.type) {
case ISM_EVENT_GID: /* GID event, token is peer GID */
- smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK);
+ smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK);
break;
case ISM_EVENT_DMB:
break;
@@ -525,7 +530,7 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
ev_info.vlan_id = lgr->vlan_id;
ev_info.code = ISM_EVENT_REQUEST;
- rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
+ rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid,
ISM_EVENT_REQUEST_IR,
ISM_EVENT_CODE_SHUTDOWN,
ev_info.info);
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index d1228a6..0e5e563 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -32,7 +32,8 @@ struct smc_ism_vlanid { /* VLAN id set on ISM device */

struct smcd_dev;

-int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *dev);
+int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
+ struct smcd_dev *dev);
void smc_ism_set_conn(struct smc_connection *conn);
void smc_ism_unset_conn(struct smc_connection *conn);
int smc_ism_get_vlan(struct smcd_dev *dev, unsigned short vlan_id);
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 1177540..9f2c58c 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -1103,8 +1103,8 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) &&
!ismdev->going_away &&
- (!ini->ism_peer_gid[0] ||
- !smc_ism_cantalk(ini->ism_peer_gid[0], ini->vlan_id,
+ (!ini->ism_peer_gid[0].gid ||
+ !smc_ism_cantalk(&ini->ism_peer_gid[0], ini->vlan_id,
ismdev))) {
ini->ism_dev[0] = ismdev;
break;
--
1.8.3.1

2023-12-01 08:34:10

by Wenjia Zhang

[permalink] [raw]
Subject: Re: [PATCH net-next v3 0/7] net/smc: implement SMCv2.1 virtual ISM device support



On 30.11.23 12:28, Wen Gu wrote:
> The fourth edition of SMCv2 adds the SMC version 2.1 feature updates for
> SMC-Dv2 with virtual ISM. Virtual ISM are created and supported mainly by
> OS or hypervisor software, comparable to IBM ISM which is based on platform
> firmware or hardware.
>
> With the introduction of virtual ISM, SMCv2.1 makes some updates:
>
> - Introduce feature bitmask to indicate supplemental features.
> - Reserve a range of CHIDs for virtual ISM.
> - Support extended GIDs (128 bits) in CLC handshake.
>
> So this patch set aims to implement these updates in Linux kernel. And it
> acts as the first part of SMC-D virtual ISM extension & loopback-ism [1].
>
> [1] https://lore.kernel.org/netdev/[email protected]/
>
> v3->v2:
> - Rename smc_clc_fill_fce as smc_clc_fill_fce_v2x;
> - Remove ISM_IDENT_MASK from drivers/s390/net/ism.h;
> - Add explicitly assigning 'false' to ism_v2_capable in ism_dev_init();
> - Remove smc_ism_set_v2_capable() helper for now, and introduce it in
> later loopback-ism implementation;
>
> v2->v1:
> - Fix sparse complaint;
> - Rebase to the latest net-next;
>
Hi Wen Gu,

LGTM, Thank you!

Reviewed-and-tested-by: Wenjia Zhang <[email protected]>

2023-12-01 11:20:14

by Alexandra Winter

[permalink] [raw]
Subject: Re: [PATCH net-next v3 7/7] net/smc: manage system EID in SMC stack instead of ISM driver



On 30.11.23 12:28, Wen Gu wrote:
> The System EID (SEID) is an internal EID that is used by the SMCv2
> software stack that has a predefined and constant value representing
> the s390 physical machine that the OS is executing on. So it should
> be managed by SMC stack instead of ISM driver and be consistent for
> all ISMv2 device (including virtual ISM devices) on s390 architecture.
>
> Suggested-by: Alexandra Winter <[email protected]>
> Signed-off-by: Wen Gu <[email protected]>
> ---

Reviewed-by: Alexandra Winter <[email protected]>


[...]
> diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
> index a33f861..ac88de2 100644
> --- a/net/smc/smc_ism.c
> +++ b/net/smc/smc_ism.c
[...]
> @@ -431,14 +452,8 @@ static void smcd_register_dev(struct ism_dev *ism)
>
> mutex_lock(&smcd_dev_list.mutex);
> if (list_empty(&smcd_dev_list.list)) {
> - u8 *system_eid = NULL;
> -
> - system_eid = smcd->ops->get_system_eid();
> - if (smcd->ops->supports_v2()) {
> + if (smcd->ops->supports_v2())
> smc_ism_v2_capable = true;
> - memcpy(smc_ism_v2_system_eid, system_eid,
> - SMC_MAX_EID_LEN);
> - }
> }

Just a comment:
Here we only check the first smcd device to determine whether we support v2.
Which is ok, for today's platform firmware ISM devices, as they are always the same version.

When you add virtual ISM devices (loopback-ism, virtio-ism) then this needs to be changed.
IMO the logic then needs to be "if all smcd devices support v2,
then smc_ism_v2_capable = true;
else smc_ism_v2_capable = false;"

I don't know if you would like to change that now in this patch, or later when
you add when you add the support for loopback.



2023-12-01 16:31:38

by Alexandra Winter

[permalink] [raw]
Subject: Re: [PATCH net-next v3 5/7] net/smc: compatible with 128-bits extend GID of virtual ISM device



On 30.11.23 12:28, Wen Gu wrote:
[...]
> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
> index 766a1f1..d1e18bf 100644
> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
[...]
> @@ -1048,7 +1048,8 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
> {
> int rc = SMC_CLC_DECL_NOSMCDDEV;
> struct smcd_dev *smcd;
> - int i = 1;
> + int i = 1, entry = 1;
> + bool is_virtual;
> u16 chid;
>
> if (smcd_indicated(ini->smc_type_v1))
> @@ -1060,14 +1061,23 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
> chid = smc_ism_get_chid(smcd);
> if (!smc_find_ism_v2_is_unique_chid(chid, ini, i))
> continue;
> + is_virtual = __smc_ism_is_virtual(chid);
> if (!smc_pnet_is_pnetid_set(smcd->pnetid) ||
> smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) {
> + if (is_virtual && entry == SMC_MAX_ISM_DEVS)
> + /* only one GID-CHID entry left in CLC Proposal SMC-Dv2
> + * extension. but a virtual ISM device's GID takes two
> + * entries. So give up it and try the next potential ISM
> + * device.
> + */

It is really importatnt to note that virtual ISMs take 2 entries.
But it is still hard to understand this piece of code. e.g. I was wondering for a while,
why you mention CLC here...
Maybe it would be easier to understand this, if you rename SMC_MAX_ISM_DEVS to something else?
Something like SMCD_MAX_V2_GID_ENTRIES?

> + continue;
> ini->ism_dev[i] = smcd;
> ini->ism_chid[i] = chid;
> ini->is_smcd = true;
> rc = 0;
> i++;
> - if (i > SMC_MAX_ISM_DEVS)
> + entry = is_virtual ? entry + 2 : entry + 1;
> + if (entry > SMC_MAX_ISM_DEVS)
> break;
> }
> }
[...]



> @@ -2154,18 +2176,35 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
> smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
>
> mutex_lock(&smcd_dev_list.mutex);
> - if (pclc_smcd->ism.chid)
> + if (pclc_smcd->ism.chid) {
> /* check for ISM device matching proposed native ISM device */
> + smcd_gid.gid = ntohll(pclc_smcd->ism.gid);
> + smcd_gid.gid_ext = 0;
> smc_check_ism_v2_match(ini, ntohs(pclc_smcd->ism.chid),
> - ntohll(pclc_smcd->ism.gid), &matches);
> + &smcd_gid, &matches);
> + }
> for (i = 1; i <= smc_v2_ext->hdr.ism_gid_cnt; i++) {

IMO the following code would be easier to read, if you change the above to count
from i = 0; i < smc_v2_ext->hdr.ism_gid_cnt;
and then use i and i+1 as indexes below.

> /* check for ISM devices matching proposed non-native ISM
> * devices
> */
> - smc_check_ism_v2_match(ini,
> - ntohs(smcd_v2_ext->gidchid[i - 1].chid),
> - ntohll(smcd_v2_ext->gidchid[i - 1].gid),
> - &matches);
> + smcd_gid.gid = ntohll(smcd_v2_ext->gidchid[i - 1].gid);
> + smcd_gid.gid_ext = 0;
> + chid = ntohs(smcd_v2_ext->gidchid[i - 1].chid);
> + if (__smc_ism_is_virtual(chid)) {
> + if (i == smc_v2_ext->hdr.ism_gid_cnt ||
> + chid != ntohs(smcd_v2_ext->gidchid[i].chid))
> + /* a virtual ISM device takes two GID-CHID entries
> + * and CHID of the second entry repeats that of the
> + * first entry.
> + *
> + * So check if the second GID-CHID entry exists and
> + * the CHIDs of these two entries are the same.
> + */
> + continue;
> +
> + smcd_gid.gid_ext = ntohll(smcd_v2_ext->gidchid[i++].gid);
> + }
> + smc_check_ism_v2_match(ini, chid, &smcd_gid, &matches);
> }
> mutex_unlock(&smcd_dev_list.mutex);
>
[...]



> diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
> index e2e437b..2d8bc0b 100644
> --- a/net/smc/smc_clc.c
> +++ b/net/smc/smc_clc.c
[...]
> @@ -1020,23 +1033,28 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
> if (first_contact)
> clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
> if (conn->lgr->is_smcd) {

It would be nice to have 2 subfunctions for ism and rdma instead of this large if/else block.

> + struct smcd_gid smcd_gid;
> + u16 chid;
> +
> /* SMC-D specific settings */
> memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
> sizeof(SMCD_EYECATCHER));
> + conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd, &smcd_gid);
> clc->hdr.typev1 = SMC_TYPE_D;
> - clc->d0.gid =
> - conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd);
> - clc->d0.token = conn->rmb_desc->token;
> + clc->d0.gid = htonll(smcd_gid.gid);
> + clc->d0.token = htonll(conn->rmb_desc->token);
> clc->d0.dmbe_size = conn->rmbe_size_comp;
> clc->d0.dmbe_idx = 0;
> memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
> if (version == SMC_V1) {
> clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
> } else {
> - clc_v2->d1.chid =
> - htons(smc_ism_get_chid(conn->lgr->smcd));
> + chid = smc_ism_get_chid(conn->lgr->smcd);
> + clc_v2->d1.chid = htons(chid);
> if (eid && eid[0])
> memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
> + if (__smc_ism_is_virtual(chid))
> + clc_v2->d1.gid_ext = htonll(smcd_gid.gid_ext);
> len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
> if (first_contact) {
> fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
> diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h
> index e64c235..dcc63f4 100644
> --- a/net/smc/smc_clc.h
> +++ b/net/smc/smc_clc.h
> @@ -205,8 +205,8 @@ struct smcr_clc_msg_accept_confirm { /* SMCR accept/confirm */
> } __packed;
>
> struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */
> - u64 gid; /* Sender GID */
> - u64 token; /* DMB token */
> + __be64 gid; /* Sender GID */
> + __be64 token; /* DMB token */

Good catch, that this needs to be __be. (including the host to net conversions you did above)
This is not related to the subject of this patch though. So either this should be in a separate patch
or at least mentioned in the commit message.

> u8 dmbe_idx; /* DMBE index */
> #if defined(__BIG_ENDIAN_BITFIELD)
> u8 dmbe_size : 4, /* buf size (compressed) */
> @@ -285,8 +285,8 @@ struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */
> struct smcd_clc_msg_accept_confirm_common d0;
> __be16 chid;
> u8 eid[SMC_MAX_EID_LEN];
> - u8 reserved5[8];
> - } d1;
> + __be64 gid_ext;
> + } __packed d1;
> };
> };
>
> diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
> index d520ee6..32eece5 100644
> --- a/net/smc/smc_core.c
> +++ b/net/smc/smc_core.> @@ -506,6 +506,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
> {
> char smc_pnet[SMC_MAX_PNETID_LEN + 1];
> struct smcd_dev *smcd = lgr->smcd;
> + struct smcd_gid smcd_gid;
> struct nlattr *attrs;
> void *nlh;
>
> @@ -521,11 +522,11 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
>
> if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id)))
> goto errattr;
> + smcd->ops->get_local_gid(smcd, &smcd_gid);
> if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID,
> - smcd->ops->get_local_gid(smcd),
> - SMC_NLA_LGR_D_PAD))
> + smcd_gid.gid, SMC_NLA_LGR_D_PAD))
> goto errattr;
> - if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid,
> + if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid.gid,
> SMC_NLA_LGR_D_PAD))
> goto errattr;

For virtual ism, you will only see the first half of the GID.
Is that acceptable? Today we use netlink only for display purposes.
What if somebody uses the netlink content as functional input to a user space program?


> if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id))
> @@ -876,7 +877,10 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
> /* SMC-D specific settings */


I guess I never really understood, why we define a single linkgroup for SMC-D.
Probably because SMC-R linkgroups were implemented before SMC-D support was added.
To all: Do we want to keep that concept?


> smcd = ini->ism_dev[ini->ism_selected];
> get_device(smcd->ops->get_dev(smcd));
> - lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
> + lgr->peer_gid.gid =
> + ini->ism_peer_gid[ini->ism_selected].gid;
> + lgr->peer_gid.gid_ext =
> + ini->ism_peer_gid[ini->ism_selected].gid_ext;
> lgr->smcd = ini->ism_dev[ini->ism_selected];
> lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
> lgr_lock = &lgr->smcd->lgr_lock;
> @@ -1514,7 +1518,8 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr)
> }
>
> /* Called when peer lgr shutdown (regularly or abnormally) is received */
> -void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
> +void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
> + unsigned short vlan)
> {
> struct smc_link_group *lgr, *l;
> LIST_HEAD(lgr_free_list);
> @@ -1522,9 +1527,12 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
> /* run common cleanup function and build free list */
> spin_lock_bh(&dev->lgr_lock);
> list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) {
> - if ((!peer_gid || lgr->peer_gid == peer_gid) &&
> + if ((!peer_gid->gid ||
> + (lgr->peer_gid.gid == peer_gid->gid &&
> + !smc_ism_is_virtual(dev) ? 1 :
> + lgr->peer_gid.gid_ext == peer_gid->gid_ext)) &&
> (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
> - if (peer_gid) /* peer triggered termination */
> + if (peer_gid->gid) /* peer triggered termination */
> lgr->peer_shutdown = 1;
> list_move(&lgr->list, &lgr_free_list);
> lgr->freeing = 1;
> @@ -1859,10 +1867,12 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, u8 smcr_version,
> return false;
> }
>
> -static bool smcd_lgr_match(struct smc_link_group *lgr,
> - struct smcd_dev *smcismdev, u64 peer_gid)
> +static bool smcd_lgr_match(struct smc_link_group *lgr, struct smcd_dev *smcismdev,
> + struct smcd_gid *peer_gid)
> {
> - return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev;
> + return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev &&
> + smc_ism_is_virtual(smcismdev) ?
> + (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1;
> }
>
> /* create a new SMC connection (and a new link group if necessary) */
> @@ -1892,7 +1902,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
> write_lock_bh(&lgr->conns_lock);
> if ((ini->is_smcd ?
> smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
> - ini->ism_peer_gid[ini->ism_selected]) :
> + &ini->ism_peer_gid[ini->ism_selected]) :
> smcr_lgr_match(lgr, ini->smcr_version,
> ini->peer_systemid,
> ini->peer_gid, ini->peer_mac, role,
[...]
> diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
> index a584613..c180c18 100644
> --- a/net/smc/smc_diag.c
> +++ b/net/smc/smc_diag.c
> @@ -21,6 +21,7 @@
>
> #include "smc.h"
> #include "smc_core.h"
> +#include "smc_ism.h"
>
> struct smc_diag_dump_ctx {
> int pos[2];
> @@ -168,12 +169,14 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
> struct smc_connection *conn = &smc->conn;
> struct smcd_diag_dmbinfo dinfo;
> struct smcd_dev *smcd = conn->lgr->smcd;
> + struct smcd_gid smcd_gid;
>
> memset(&dinfo, 0, sizeof(dinfo));
>
> dinfo.linkid = *((u32 *)conn->lgr->id);
> - dinfo.peer_gid = conn->lgr->peer_gid;
> - dinfo.my_gid = smcd->ops->get_local_gid(smcd);
> + dinfo.peer_gid = conn->lgr->peer_gid.gid;
> + smcd->ops->get_local_gid(smcd, &smcd_gid);
> + dinfo.my_gid = smcd_gid.gid;

For virtual ism, you will only see the first half of the GID.
Is that acceptable?

> dinfo.token = conn->rmb_desc->token;
> dinfo.peer_token = conn->peer_token;
>
> diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
> index fbee249..a33f861 100644
> --- a/net/smc/smc_ism.c
> +++ b/net/smc/smc_ism.c

Some of the content of this file is specific to s390 firmware ISMs and some is
relevant to all future ism devices.
IMO there is some more work to do to create a clean "smcd-protocol to scmd-device" interface.
Maybe also some moving between this file and drivers/s390/net/ism_drv.c

Maybe this would be a good next patchset?

Whoever takes this work, remember:
https://lore.kernel.org/netdev/[email protected]/T/
We want to be able to combine SMC, ISM and future kernel modules in any combination.
Gerd's patch above was meant to solve the current problem. For additional ism devices,
we need some more improvements, I think.





> @@ -44,7 +44,8 @@ static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
> #endif
>
> /* Test if an ISM communication is possible - same CPC */
> -int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
> +int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
> + struct smcd_dev *smcd)
> {
> return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
> vlan_id);
> @@ -208,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
> dmb.dmb_len = dmb_len;
> dmb.sba_idx = dmb_desc->sba_idx;
> dmb.vlan_id = lgr->vlan_id;
> - dmb.rgid = lgr->peer_gid;
> + dmb.rgid = lgr->peer_gid.gid;
> rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client);
> if (!rc) {
> dmb_desc->sba_idx = dmb.sba_idx;
> @@ -340,18 +341,20 @@ struct smc_ism_event_work {
>
> static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
> {
> + struct smcd_gid peer_gid = { .gid = wrk->event.tok,
> + .gid_ext = 0 };
> union smcd_sw_event_info ev_info;
>
> ev_info.info = wrk->event.info;
> switch (wrk->event.code) {
> case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */
> - smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id);
> + smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
> break;
> case ISM_EVENT_CODE_TESTLINK: /* Activity timer */
> if (ev_info.code == ISM_EVENT_REQUEST) {
> ev_info.code = ISM_EVENT_RESPONSE;
> wrk->smcd->ops->signal_event(wrk->smcd,
> - wrk->event.tok,
> + &peer_gid,
> ISM_EVENT_REQUEST_IR,
> ISM_EVENT_CODE_TESTLINK,
> ev_info.info);
> @@ -365,10 +368,12 @@ static void smc_ism_event_work(struct work_struct *work)
> {
> struct smc_ism_event_work *wrk =
> container_of(work, struct smc_ism_event_work, work);
> + struct smcd_gid smcd_gid = { .gid = wrk->event.tok,
> + .gid_ext = 0 };
>
> switch (wrk->event.type) {
> case ISM_EVENT_GID: /* GID event, token is peer GID */
> - smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK);
> + smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK);
> break;
> case ISM_EVENT_DMB:
> break;
> @@ -525,7 +530,7 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
> memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
> ev_info.vlan_id = lgr->vlan_id;
> ev_info.code = ISM_EVENT_REQUEST;
> - rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
> + rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid,
> ISM_EVENT_REQUEST_IR,
> ISM_EVENT_CODE_SHUTDOWN,
> ev_info.info);
[...]

2023-12-01 16:33:15

by Alexandra Winter

[permalink] [raw]
Subject: Re: [PATCH net-next v3 0/7] net/smc: implement SMCv2.1 virtual ISM device support



On 30.11.23 12:28, Wen Gu wrote:
> The fourth edition of SMCv2 adds the SMC version 2.1 feature updates for
> SMC-Dv2 with virtual ISM. Virtual ISM are created and supported mainly by
> OS or hypervisor software, comparable to IBM ISM which is based on platform
> firmware or hardware.
>
> With the introduction of virtual ISM, SMCv2.1 makes some updates:
>
> - Introduce feature bitmask to indicate supplemental features.
> - Reserve a range of CHIDs for virtual ISM.
> - Support extended GIDs (128 bits) in CLC handshake.
>
> So this patch set aims to implement these updates in Linux kernel. And it
> acts as the first part of SMC-D virtual ISM extension & loopback-ism [1].
>
> [1] https://lore.kernel.org/netdev/[email protected]/
>
> v3->v2:
> - Rename smc_clc_fill_fce as smc_clc_fill_fce_v2x;
> - Remove ISM_IDENT_MASK from drivers/s390/net/ism.h;
> - Add explicitly assigning 'false' to ism_v2_capable in ism_dev_init();
> - Remove smc_ism_set_v2_capable() helper for now, and introduce it in
> later loopback-ism implementation;
>
> v2->v1:
> - Fix sparse complaint;
> - Rebase to the latest net-next;
>
> Wen Gu (7):
> net/smc: Rename some variable 'fce' to 'fce_v2x' for clarity
> net/smc: support SMCv2.x supplemental features negotiation
> net/smc: introduce virtual ISM device support feature
> net/smc: define a reserved CHID range for virtual ISM devices
> net/smc: compatible with 128-bits extend GID of virtual ISM device
> net/smc: disable SEID on non-s390 archs where virtual ISM may be used
> net/smc: manage system EID in SMC stack instead of ISM driver
>

Wen Gu,
as you can see in [1] your patches 5/7 and 1/7 still have formatting issues.
In this case they need to pass

scripts/checkpatch.pl --strict --max-line-length=80

(see linux/Documentation/process/coding-style.rst)

[1] https://patchwork.kernel.org/project/netdevbpf/list/?series=&submitter=&state=&q=net%2Fsmc&archive=&delegate=

2023-12-01 16:36:40

by Alexandra Winter

[permalink] [raw]
Subject: Re: [PATCH net-next v3 4/7] net/smc: define a reserved CHID range for virtual ISM devices



On 30.11.23 12:28, Wen Gu wrote:
> According to virtual ISM support feature defined by SMCv2.1, CHIDs in
> the range 0xFF00 to 0xFFFF are reserved for use by virtual ISM devices.
>
> And two helpers are introduced to distinguish virtual ISM devices from
> the existing platform firmware ISM devices.
>
> Signed-off-by: Wen Gu <[email protected]>
> ---

Reviewed-by: Alexandra Winter <[email protected]>

2023-12-04 02:01:25

by Wen Gu

[permalink] [raw]
Subject: Re: [PATCH net-next v3 0/7] net/smc: implement SMCv2.1 virtual ISM device support



On 2023/12/2 00:32, Alexandra Winter wrote:
>
>
> On 30.11.23 12:28, Wen Gu wrote:
>> The fourth edition of SMCv2 adds the SMC version 2.1 feature updates for
>> SMC-Dv2 with virtual ISM. Virtual ISM are created and supported mainly by
>> OS or hypervisor software, comparable to IBM ISM which is based on platform
>> firmware or hardware.
>>
>> With the introduction of virtual ISM, SMCv2.1 makes some updates:
>>
>> - Introduce feature bitmask to indicate supplemental features.
>> - Reserve a range of CHIDs for virtual ISM.
>> - Support extended GIDs (128 bits) in CLC handshake.
>>
>> So this patch set aims to implement these updates in Linux kernel. And it
>> acts as the first part of SMC-D virtual ISM extension & loopback-ism [1].
>>
>> [1] https://lore.kernel.org/netdev/[email protected]/
>>
>> v3->v2:
>> - Rename smc_clc_fill_fce as smc_clc_fill_fce_v2x;
>> - Remove ISM_IDENT_MASK from drivers/s390/net/ism.h;
>> - Add explicitly assigning 'false' to ism_v2_capable in ism_dev_init();
>> - Remove smc_ism_set_v2_capable() helper for now, and introduce it in
>> later loopback-ism implementation;
>>
>> v2->v1:
>> - Fix sparse complaint;
>> - Rebase to the latest net-next;
>>
>> Wen Gu (7):
>> net/smc: Rename some variable 'fce' to 'fce_v2x' for clarity
>> net/smc: support SMCv2.x supplemental features negotiation
>> net/smc: introduce virtual ISM device support feature
>> net/smc: define a reserved CHID range for virtual ISM devices
>> net/smc: compatible with 128-bits extend GID of virtual ISM device
>> net/smc: disable SEID on non-s390 archs where virtual ISM may be used
>> net/smc: manage system EID in SMC stack instead of ISM driver
>>
>
> Wen Gu,
> as you can see in [1] your patches 5/7 and 1/7 still have formatting issues.
> In this case they need to pass
>
> scripts/checkpatch.pl --strict --max-line-length=80
>
> (see linux/Documentation/process/coding-style.rst)
>
> [1] https://patchwork.kernel.org/project/netdevbpf/list/?series=&submitter=&state=&q=net%2Fsmc&archive=&delegate=

Thanks. They will be fixed and I will check the patches with tests provided by
https://github.com/kuba-moo/nipa/tree/master/tests/patch

2023-12-04 09:15:47

by Wenjia Zhang

[permalink] [raw]
Subject: Re: [PATCH net-next v3 5/7] net/smc: compatible with 128-bits extend GID of virtual ISM device



On 01.12.23 17:30, Alexandra Winter wrote:
>
>
> On 30.11.23 12:28, Wen Gu wrote:
> [...]
>[...]
>
>> if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id))
>> @@ -876,7 +877,10 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
>> /* SMC-D specific settings */
>
>
> I guess I never really understood, why we define a single linkgroup for SMC-D.
> Probably because SMC-R linkgroups were implemented before SMC-D support was added.
As I'm aware, this is indeed the reason.

> To all: Do we want to keep that concept?
>
Since SMC-D and SMC-R still share many common code, this concept should
be kept, at least for now and now for this patch.

>
>> smcd = ini->ism_dev[ini->ism_selected];
>> get_device(smcd->ops->get_dev(smcd));
>> - lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
>> + lgr->peer_gid.gid =
>> + ini->ism_peer_gid[ini->ism_selected].gid;
>> + lgr->peer_gid.gid_ext =
>> + ini->ism_peer_gid[ini->ism_selected].gid_ext;
>> lgr->smcd = ini->ism_dev[ini->ism_selected];
>> lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
>> lgr_lock = &lgr->smcd->lgr_lock;
>> @@ -1514,7 +1518,8 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr)
>> }
>>
>> /* Called when peer lgr shutdown (regularly or abnormally) is received */
>> -void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
>> +void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
>> + unsigned short vlan)
>> {
>> struct smc_link_group *lgr, *l;
>> LIST_HEAD(lgr_free_list);
>> @@ -1522,9 +1527,12 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
>> /* run common cleanup function and build free list */
>> spin_lock_bh(&dev->lgr_lock);
>> list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) {
>> - if ((!peer_gid || lgr->peer_gid == peer_gid) &&
>> + if ((!peer_gid->gid ||
>> + (lgr->peer_gid.gid == peer_gid->gid &&
>> + !smc_ism_is_virtual(dev) ? 1 :
>> + lgr->peer_gid.gid_ext == peer_gid->gid_ext)) &&
>> (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
>> - if (peer_gid) /* peer triggered termination */
>> + if (peer_gid->gid) /* peer triggered termination */
>> lgr->peer_shutdown = 1;
>> list_move(&lgr->list, &lgr_free_list);
>> lgr->freeing = 1;
>> @@ -1859,10 +1867,12 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, u8 smcr_version,
>> return false;
>> }
>>
>> -static bool smcd_lgr_match(struct smc_link_group *lgr,
>> - struct smcd_dev *smcismdev, u64 peer_gid)
>> +static bool smcd_lgr_match(struct smc_link_group *lgr, struct smcd_dev *smcismdev,
>> + struct smcd_gid *peer_gid)
>> {
>> - return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev;
>> + return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev &&
>> + smc_ism_is_virtual(smcismdev) ?
>> + (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1;
>> }
>>
>> /* create a new SMC connection (and a new link group if necessary) */
>> @@ -1892,7 +1902,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
>> write_lock_bh(&lgr->conns_lock);
>> if ((ini->is_smcd ?
>> smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
>> - ini->ism_peer_gid[ini->ism_selected]) :
>> + &ini->ism_peer_gid[ini->ism_selected]) :
>> smcr_lgr_match(lgr, ini->smcr_version,
>> ini->peer_systemid,
>> ini->peer_gid, ini->peer_mac, role,
> [...]
>> diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
>> index a584613..c180c18 100644
>> --- a/net/smc/smc_diag.c
>> +++ b/net/smc/smc_diag.c
>> @@ -21,6 +21,7 @@
>>
>> #include "smc.h"
>> #include "smc_core.h"
>> +#include "smc_ism.h"
>>
>> struct smc_diag_dump_ctx {
>> int pos[2];
>> @@ -168,12 +169,14 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
>> struct smc_connection *conn = &smc->conn;
>> struct smcd_diag_dmbinfo dinfo;
>> struct smcd_dev *smcd = conn->lgr->smcd;
>> + struct smcd_gid smcd_gid;
>>
>> memset(&dinfo, 0, sizeof(dinfo));
>>
>> dinfo.linkid = *((u32 *)conn->lgr->id);
>> - dinfo.peer_gid = conn->lgr->peer_gid;
>> - dinfo.my_gid = smcd->ops->get_local_gid(smcd);
>> + dinfo.peer_gid = conn->lgr->peer_gid.gid;
>> + smcd->ops->get_local_gid(smcd, &smcd_gid);
>> + dinfo.my_gid = smcd_gid.gid;
>
> For virtual ism, you will only see the first half of the GID.
> Is that acceptable?
>
>> dinfo.token = conn->rmb_desc->token;
>> dinfo.peer_token = conn->peer_token;
>>
>> diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
>> index fbee249..a33f861 100644
>> --- a/net/smc/smc_ism.c
>> +++ b/net/smc/smc_ism.c
>
> Some of the content of this file is specific to s390 firmware ISMs and some is
> relevant to all future ism devices.
> IMO there is some more work to do to create a clean "smcd-protocol to scmd-device" interface.
> Maybe also some moving between this file and drivers/s390/net/ism_drv.c
>
> Maybe this would be a good next patchset?
>

I see the need, too. However, there are bunch of things to do in order
to improve the SMC code. We need to get our priorities straight. What
clear is that this is not in the scope of this patchset ;-)

> Whoever takes this work, remember:
> https://lore.kernel.org/netdev/[email protected]/T/
> We want to be able to combine SMC, ISM and future kernel modules in any combination.
> Gerd's patch above was meant to solve the current problem. For additional ism devices,
> we need some more improvements, I think.
>
>
Thank you, Alexandra, for the remember! That we should keep in mind!
>
>
>
>> @@ -44,7 +44,8 @@ static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
>> #endif
>>
>> /* Test if an ISM communication is possible - same CPC */
>> -int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
>> +int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
>> + struct smcd_dev *smcd)
>> {
>> return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
>> vlan_id);
>> @@ -208,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
>> dmb.dmb_len = dmb_len;
>> dmb.sba_idx = dmb_desc->sba_idx;
>> dmb.vlan_id = lgr->vlan_id;
>> - dmb.rgid = lgr->peer_gid;
>> + dmb.rgid = lgr->peer_gid.gid;
>> rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client);
>> if (!rc) {
>> dmb_desc->sba_idx = dmb.sba_idx;
>> @@ -340,18 +341,20 @@ struct smc_ism_event_work {
>>
>> static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
>> {
>> + struct smcd_gid peer_gid = { .gid = wrk->event.tok,
>> + .gid_ext = 0 };
>> union smcd_sw_event_info ev_info;
>>
>> ev_info.info = wrk->event.info;
>> switch (wrk->event.code) {
>> case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */
>> - smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id);
>> + smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
>> break;
>> case ISM_EVENT_CODE_TESTLINK: /* Activity timer */
>> if (ev_info.code == ISM_EVENT_REQUEST) {
>> ev_info.code = ISM_EVENT_RESPONSE;
>> wrk->smcd->ops->signal_event(wrk->smcd,
>> - wrk->event.tok,
>> + &peer_gid,
>> ISM_EVENT_REQUEST_IR,
>> ISM_EVENT_CODE_TESTLINK,
>> ev_info.info);
>> @@ -365,10 +368,12 @@ static void smc_ism_event_work(struct work_struct *work)
>> {
>> struct smc_ism_event_work *wrk =
>> container_of(work, struct smc_ism_event_work, work);
>> + struct smcd_gid smcd_gid = { .gid = wrk->event.tok,
>> + .gid_ext = 0 };
>>
>> switch (wrk->event.type) {
>> case ISM_EVENT_GID: /* GID event, token is peer GID */
>> - smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK);
>> + smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK);
>> break;
>> case ISM_EVENT_DMB:
>> break;
>> @@ -525,7 +530,7 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
>> memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
>> ev_info.vlan_id = lgr->vlan_id;
>> ev_info.code = ISM_EVENT_REQUEST;
>> - rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
>> + rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid,
>> ISM_EVENT_REQUEST_IR,
>> ISM_EVENT_CODE_SHUTDOWN,
>> ev_info.info);
> [...]

2023-12-04 12:25:23

by Wen Gu

[permalink] [raw]
Subject: Re: [PATCH net-next v3 5/7] net/smc: compatible with 128-bits extend GID of virtual ISM device


Thank you very much for review. See below.

On 2023/12/2 00:30, Alexandra Winter wrote:
>
>
> On 30.11.23 12:28, Wen Gu wrote:
> [...]
>> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
>> index 766a1f1..d1e18bf 100644
>> --- a/net/smc/af_smc.c
>> +++ b/net/smc/af_smc.c
> [...]
>> @@ -1048,7 +1048,8 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
>> {
>> int rc = SMC_CLC_DECL_NOSMCDDEV;
>> struct smcd_dev *smcd;
>> - int i = 1;
>> + int i = 1, entry = 1;
>> + bool is_virtual;
>> u16 chid;
>>
>> if (smcd_indicated(ini->smc_type_v1))
>> @@ -1060,14 +1061,23 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
>> chid = smc_ism_get_chid(smcd);
>> if (!smc_find_ism_v2_is_unique_chid(chid, ini, i))
>> continue;
>> + is_virtual = __smc_ism_is_virtual(chid);
>> if (!smc_pnet_is_pnetid_set(smcd->pnetid) ||
>> smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) {
>> + if (is_virtual && entry == SMC_MAX_ISM_DEVS)
>> + /* only one GID-CHID entry left in CLC Proposal SMC-Dv2
>> + * extension. but a virtual ISM device's GID takes two
>> + * entries. So give up it and try the next potential ISM
>> + * device.
>> + */
>
> It is really importatnt to note that virtual ISMs take 2 entries.
> But it is still hard to understand this piece of code. e.g. I was wondering for a while,
> why you mention CLC here...
> Maybe it would be easier to understand this, if you rename SMC_MAX_ISM_DEVS to something else?
> Something like SMCD_MAX_V2_GID_ENTRIES?
>

I agree.

But I perfer to define a new macro to represent the max ISMv2 entries in CLC proposal message,
e.g. SMCD_CLC_MAX_V2_GID_ENTRIES, and keep using SMC_MAX_ISM_DEVS to represent the max devices
that can be proposed. Both semantics are required in the code, such as:

ini->ism_dev[SMC_MAX_ISM_DEVS] | smcd_v2_ext->gidchid[SMCD_CLC_MAX_V2_GID_ENTRIES]
-------------------------------------------------------------------------------------------
[1:virtual_ISM_1] | [1:virtual_ISM_1 GID]
| [2:virtual_ISM_1 extension GID]
[2:ISM_2] | [3:ISM_2 GID/CHID]
[3:ISM_3] | [4:ISM_3 GID/CHID]

And SMC_MAX_ISM_DEVS is required no more than SMCD_CLC_MAX_V2_GID_ENTRIES.

>> + continue;
>> ini->ism_dev[i] = smcd;
>> ini->ism_chid[i] = chid;
>> ini->is_smcd = true;
>> rc = 0;
>> i++;
>> - if (i > SMC_MAX_ISM_DEVS)
>> + entry = is_virtual ? entry + 2 : entry + 1;
>> + if (entry > SMC_MAX_ISM_DEVS)
>> break;
>> }
>> }
> [...]
>
>
>
>> @@ -2154,18 +2176,35 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
>> smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
>>
>> mutex_lock(&smcd_dev_list.mutex);
>> - if (pclc_smcd->ism.chid)
>> + if (pclc_smcd->ism.chid) {
>> /* check for ISM device matching proposed native ISM device */
>> + smcd_gid.gid = ntohll(pclc_smcd->ism.gid);
>> + smcd_gid.gid_ext = 0;
>> smc_check_ism_v2_match(ini, ntohs(pclc_smcd->ism.chid),
>> - ntohll(pclc_smcd->ism.gid), &matches);
>> + &smcd_gid, &matches);
>> + }
>> for (i = 1; i <= smc_v2_ext->hdr.ism_gid_cnt; i++) {
>
> IMO the following code would be easier to read, if you change the above to count
> from i = 0; i < smc_v2_ext->hdr.ism_gid_cnt;
> and then use i and i+1 as indexes below.
>

Thank you. I will change this.

>> /* check for ISM devices matching proposed non-native ISM
>> * devices
>> */
>> - smc_check_ism_v2_match(ini,
>> - ntohs(smcd_v2_ext->gidchid[i - 1].chid),
>> - ntohll(smcd_v2_ext->gidchid[i - 1].gid),
>> - &matches);
>> + smcd_gid.gid = ntohll(smcd_v2_ext->gidchid[i - 1].gid);
>> + smcd_gid.gid_ext = 0;
>> + chid = ntohs(smcd_v2_ext->gidchid[i - 1].chid);
>> + if (__smc_ism_is_virtual(chid)) {
>> + if (i == smc_v2_ext->hdr.ism_gid_cnt ||
>> + chid != ntohs(smcd_v2_ext->gidchid[i].chid))
>> + /* a virtual ISM device takes two GID-CHID entries
>> + * and CHID of the second entry repeats that of the
>> + * first entry.
>> + *
>> + * So check if the second GID-CHID entry exists and
>> + * the CHIDs of these two entries are the same.
>> + */
>> + continue;
>> +
>> + smcd_gid.gid_ext = ntohll(smcd_v2_ext->gidchid[i++].gid);
>> + }
>> + smc_check_ism_v2_match(ini, chid, &smcd_gid, &matches);
>> }
>> mutex_unlock(&smcd_dev_list.mutex);
>>
> [...]
>
>
>
>> diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
>> index e2e437b..2d8bc0b 100644
>> --- a/net/smc/smc_clc.c
>> +++ b/net/smc/smc_clc.c
> [...]
>> @@ -1020,23 +1033,28 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
>> if (first_contact)
>> clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
>> if (conn->lgr->is_smcd) {
>
> It would be nice to have 2 subfunctions for ism and rdma instead of this large if/else block.
>

OK. I will introduce two subfunctions in a separate patch.

>> + struct smcd_gid smcd_gid;
>> + u16 chid;
>> +
>> /* SMC-D specific settings */
>> memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
>> sizeof(SMCD_EYECATCHER));
>> + conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd, &smcd_gid);
>> clc->hdr.typev1 = SMC_TYPE_D;
>> - clc->d0.gid =
>> - conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd);
>> - clc->d0.token = conn->rmb_desc->token;
>> + clc->d0.gid = htonll(smcd_gid.gid);
>> + clc->d0.token = htonll(conn->rmb_desc->token);
>> clc->d0.dmbe_size = conn->rmbe_size_comp;
>> clc->d0.dmbe_idx = 0;
>> memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
>> if (version == SMC_V1) {
>> clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
>> } else {
>> - clc_v2->d1.chid =
>> - htons(smc_ism_get_chid(conn->lgr->smcd));
>> + chid = smc_ism_get_chid(conn->lgr->smcd);
>> + clc_v2->d1.chid = htons(chid);
>> if (eid && eid[0])
>> memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
>> + if (__smc_ism_is_virtual(chid))
>> + clc_v2->d1.gid_ext = htonll(smcd_gid.gid_ext);
>> len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
>> if (first_contact) {
>> fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini);
>> diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h
>> index e64c235..dcc63f4 100644
>> --- a/net/smc/smc_clc.h
>> +++ b/net/smc/smc_clc.h
>> @@ -205,8 +205,8 @@ struct smcr_clc_msg_accept_confirm { /* SMCR accept/confirm */
>> } __packed;
>>
>> struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */
>> - u64 gid; /* Sender GID */
>> - u64 token; /* DMB token */
>> + __be64 gid; /* Sender GID */
>> + __be64 token; /* DMB token */
>
> Good catch, that this needs to be __be. (including the host to net conversions you did above)
> This is not related to the subject of this patch though. So either this should be in a separate patch
> or at least mentioned in the commit message.
>

Thank you. I will doing this in a separate patch.

>> u8 dmbe_idx; /* DMBE index */
>> #if defined(__BIG_ENDIAN_BITFIELD)
>> u8 dmbe_size : 4, /* buf size (compressed) */
>> @@ -285,8 +285,8 @@ struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */
>> struct smcd_clc_msg_accept_confirm_common d0;
>> __be16 chid;
>> u8 eid[SMC_MAX_EID_LEN];
>> - u8 reserved5[8];
>> - } d1;
>> + __be64 gid_ext;
>> + } __packed d1;
>> };
>> };
>>
>> diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
>> index d520ee6..32eece5 100644
>> --- a/net/smc/smc_core.c
>> +++ b/net/smc/smc_core.> @@ -506,6 +506,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
>> {
>> char smc_pnet[SMC_MAX_PNETID_LEN + 1];
>> struct smcd_dev *smcd = lgr->smcd;
>> + struct smcd_gid smcd_gid;
>> struct nlattr *attrs;
>> void *nlh;
>>
>> @@ -521,11 +522,11 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
>>
>> if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id)))
>> goto errattr;
>> + smcd->ops->get_local_gid(smcd, &smcd_gid);
>> if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID,
>> - smcd->ops->get_local_gid(smcd),
>> - SMC_NLA_LGR_D_PAD))
>> + smcd_gid.gid, SMC_NLA_LGR_D_PAD))
>> goto errattr;
>> - if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid,
>> + if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid.gid,
>> SMC_NLA_LGR_D_PAD))
>> goto errattr;
>
> For virtual ism, you will only see the first half of the GID.
> Is that acceptable? Today we use netlink only for display purposes.
> What if somebody uses the netlink content as functional input to a user space program?
>

Thank you for the consideration. I will improve the netlink code about GID.

>
>> if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id))
>> @@ -876,7 +877,10 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
>> /* SMC-D specific settings */
>
>
> I guess I never really understood, why we define a single linkgroup for SMC-D.
> Probably because SMC-R linkgroups were implemented before SMC-D support was added.
My understand is similar to yours, that SMC-D reuses LGR concept to anchor all
connections with a specific peer.

> To all: Do we want to keep that concept?
>
>
I guess the concern is that the 'group' semantic is not clear in SMC-D?
IMHO it is acceptable and SMC-R also supports single link now. So I tend to keep
the concept in both SMC-R and SMC-D. Let's hear some other opinions as well.

>> smcd = ini->ism_dev[ini->ism_selected];
>> get_device(smcd->ops->get_dev(smcd));
>> - lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
>> + lgr->peer_gid.gid =
>> + ini->ism_peer_gid[ini->ism_selected].gid;
>> + lgr->peer_gid.gid_ext =
>> + ini->ism_peer_gid[ini->ism_selected].gid_ext;
>> lgr->smcd = ini->ism_dev[ini->ism_selected];
>> lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
>> lgr_lock = &lgr->smcd->lgr_lock;
>> @@ -1514,7 +1518,8 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr)
>> }
>>
>> /* Called when peer lgr shutdown (regularly or abnormally) is received */
>> -void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
>> +void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid,
>> + unsigned short vlan)
>> {
>> struct smc_link_group *lgr, *l;
>> LIST_HEAD(lgr_free_list);
>> @@ -1522,9 +1527,12 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
>> /* run common cleanup function and build free list */
>> spin_lock_bh(&dev->lgr_lock);
>> list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) {
>> - if ((!peer_gid || lgr->peer_gid == peer_gid) &&
>> + if ((!peer_gid->gid ||
>> + (lgr->peer_gid.gid == peer_gid->gid &&
>> + !smc_ism_is_virtual(dev) ? 1 :
>> + lgr->peer_gid.gid_ext == peer_gid->gid_ext)) &&
>> (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
>> - if (peer_gid) /* peer triggered termination */
>> + if (peer_gid->gid) /* peer triggered termination */
>> lgr->peer_shutdown = 1;
>> list_move(&lgr->list, &lgr_free_list);
>> lgr->freeing = 1;
>> @@ -1859,10 +1867,12 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, u8 smcr_version,
>> return false;
>> }
>>
>> -static bool smcd_lgr_match(struct smc_link_group *lgr,
>> - struct smcd_dev *smcismdev, u64 peer_gid)
>> +static bool smcd_lgr_match(struct smc_link_group *lgr, struct smcd_dev *smcismdev,
>> + struct smcd_gid *peer_gid)
>> {
>> - return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev;
>> + return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev &&
>> + smc_ism_is_virtual(smcismdev) ?
>> + (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1;
>> }
>>
>> /* create a new SMC connection (and a new link group if necessary) */
>> @@ -1892,7 +1902,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
>> write_lock_bh(&lgr->conns_lock);
>> if ((ini->is_smcd ?
>> smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
>> - ini->ism_peer_gid[ini->ism_selected]) :
>> + &ini->ism_peer_gid[ini->ism_selected]) :
>> smcr_lgr_match(lgr, ini->smcr_version,
>> ini->peer_systemid,
>> ini->peer_gid, ini->peer_mac, role,
> [...]
>> diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
>> index a584613..c180c18 100644
>> --- a/net/smc/smc_diag.c
>> +++ b/net/smc/smc_diag.c
>> @@ -21,6 +21,7 @@
>>
>> #include "smc.h"
>> #include "smc_core.h"
>> +#include "smc_ism.h"
>>
>> struct smc_diag_dump_ctx {
>> int pos[2];
>> @@ -168,12 +169,14 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
>> struct smc_connection *conn = &smc->conn;
>> struct smcd_diag_dmbinfo dinfo;
>> struct smcd_dev *smcd = conn->lgr->smcd;
>> + struct smcd_gid smcd_gid;
>>
>> memset(&dinfo, 0, sizeof(dinfo));
>>
>> dinfo.linkid = *((u32 *)conn->lgr->id);
>> - dinfo.peer_gid = conn->lgr->peer_gid;
>> - dinfo.my_gid = smcd->ops->get_local_gid(smcd);
>> + dinfo.peer_gid = conn->lgr->peer_gid.gid;
>> + smcd->ops->get_local_gid(smcd, &smcd_gid);
>> + dinfo.my_gid = smcd_gid.gid;
>
> For virtual ism, you will only see the first half of the GID.
> Is that acceptable?

Thanks. I will improve the netlink code about extended GID.
>
>> dinfo.token = conn->rmb_desc->token;
>> dinfo.peer_token = conn->peer_token;
>>
>> diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
>> index fbee249..a33f861 100644
>> --- a/net/smc/smc_ism.c
>> +++ b/net/smc/smc_ism.c
>
> Some of the content of this file is specific to s390 firmware ISMs and some is
> relevant to all future ism devices.
> IMO there is some more work to do to create a clean "smcd-protocol to scmd-device" interface.
> Maybe also some moving between this file and drivers/s390/net/ism_drv.c
>
> Maybe this would be a good next patchset?
>
> Whoever takes this work, remember:
> https://lore.kernel.org/netdev/[email protected]/T/
> We want to be able to combine SMC, ISM and future kernel modules in any combination.
> Gerd's patch above was meant to solve the current problem. For additional ism devices,
> we need some more improvements, I think.
>
>
That's a good suggestion.

The clean interface requires general consideration. I think it's better to design it
after loopback-ism is introduced since loopback-ism can be an appropriate example to
see what should be remained in smc_ism.{c|h} for all kinds of ISMs and what should be
moved to specific drivers.

I will record it to my list, but I am not sure if I can find an s390 environment to
develop and test. And anyone else who has interests in this, feel free to take, just
remember to let others know.

>
>
>
>> @@ -44,7 +44,8 @@ static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
>> #endif
>>
>> /* Test if an ISM communication is possible - same CPC */
>> -int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
>> +int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
>> + struct smcd_dev *smcd)
>> {
>> return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
>> vlan_id);
>> @@ -208,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
>> dmb.dmb_len = dmb_len;
>> dmb.sba_idx = dmb_desc->sba_idx;
>> dmb.vlan_id = lgr->vlan_id;
>> - dmb.rgid = lgr->peer_gid;
>> + dmb.rgid = lgr->peer_gid.gid;
>> rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client);
>> if (!rc) {
>> dmb_desc->sba_idx = dmb.sba_idx;
>> @@ -340,18 +341,20 @@ struct smc_ism_event_work {
>>
>> static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
>> {
>> + struct smcd_gid peer_gid = { .gid = wrk->event.tok,
>> + .gid_ext = 0 };
>> union smcd_sw_event_info ev_info;
>>
>> ev_info.info = wrk->event.info;
>> switch (wrk->event.code) {
>> case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */
>> - smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id);
>> + smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
>> break;
>> case ISM_EVENT_CODE_TESTLINK: /* Activity timer */
>> if (ev_info.code == ISM_EVENT_REQUEST) {
>> ev_info.code = ISM_EVENT_RESPONSE;
>> wrk->smcd->ops->signal_event(wrk->smcd,
>> - wrk->event.tok,
>> + &peer_gid,
>> ISM_EVENT_REQUEST_IR,
>> ISM_EVENT_CODE_TESTLINK,
>> ev_info.info);
>> @@ -365,10 +368,12 @@ static void smc_ism_event_work(struct work_struct *work)
>> {
>> struct smc_ism_event_work *wrk =
>> container_of(work, struct smc_ism_event_work, work);
>> + struct smcd_gid smcd_gid = { .gid = wrk->event.tok,
>> + .gid_ext = 0 };
>>
>> switch (wrk->event.type) {
>> case ISM_EVENT_GID: /* GID event, token is peer GID */
>> - smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK);
>> + smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK);
>> break;
>> case ISM_EVENT_DMB:
>> break;
>> @@ -525,7 +530,7 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
>> memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
>> ev_info.vlan_id = lgr->vlan_id;
>> ev_info.code = ISM_EVENT_REQUEST;
>> - rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
>> + rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid,
>> ISM_EVENT_REQUEST_IR,
>> ISM_EVENT_CODE_SHUTDOWN,
>> ev_info.info);
> [...]

2023-12-04 12:36:30

by Wen Gu

[permalink] [raw]
Subject: Re: [PATCH net-next v3 7/7] net/smc: manage system EID in SMC stack instead of ISM driver


On 2023/12/1 19:18, Alexandra Winter wrote:
>
>
> On 30.11.23 12:28, Wen Gu wrote:
>> The System EID (SEID) is an internal EID that is used by the SMCv2
>> software stack that has a predefined and constant value representing
>> the s390 physical machine that the OS is executing on. So it should
>> be managed by SMC stack instead of ISM driver and be consistent for
>> all ISMv2 device (including virtual ISM devices) on s390 architecture.
>>
>> Suggested-by: Alexandra Winter <[email protected]>
>> Signed-off-by: Wen Gu <[email protected]>
>> ---
>
> Reviewed-by: Alexandra Winter <[email protected]>
>
>
> [...]
>> diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
>> index a33f861..ac88de2 100644
>> --- a/net/smc/smc_ism.c
>> +++ b/net/smc/smc_ism.c
> [...]
>> @@ -431,14 +452,8 @@ static void smcd_register_dev(struct ism_dev *ism)
>>
>> mutex_lock(&smcd_dev_list.mutex);
>> if (list_empty(&smcd_dev_list.list)) {
>> - u8 *system_eid = NULL;
>> -
>> - system_eid = smcd->ops->get_system_eid();
>> - if (smcd->ops->supports_v2()) {
>> + if (smcd->ops->supports_v2())
>> smc_ism_v2_capable = true;
>> - memcpy(smc_ism_v2_system_eid, system_eid,
>> - SMC_MAX_EID_LEN);
>> - }
>> }
>
> Just a comment:
> Here we only check the first smcd device to determine whether we support v2.
> Which is ok, for today's platform firmware ISM devices, as they are always the same version.
>
> When you add virtual ISM devices (loopback-ism, virtio-ism) then this needs to be changed.
> IMO the logic then needs to be "if all smcd devices support v2,
> then smc_ism_v2_capable = true;
> else smc_ism_v2_capable = false;"
>

Thank you. I will change this in the loopback-ism patch set.

But I am wondering if loopback-ism coexists with s390 ISMv1, why smc_ism_v2_capable shouldn't be set?
Is it because the SEID generated in this way is not correct if the s390 ISMv2 does not exist?

> I don't know if you would like to change that now in this patch, or later when
> you add when you add the support for loopback.
>
>

2023-12-04 12:58:21

by Alexandra Winter

[permalink] [raw]
Subject: Re: [PATCH net-next v3 7/7] net/smc: manage system EID in SMC stack instead of ISM driver



On 04.12.23 13:36, Wen Gu wrote:
>> Here we only check the first smcd device to determine whether we support v2.
>> Which is ok, for today's platform firmware ISM devices, as they are always the same version.
>>
>> When you add virtual ISM devices (loopback-ism, virtio-ism) then this needs to be changed.
>> IMO the logic then needs to be "if all smcd devices support v2,
>> then smc_ism_v2_capable = true;
>> else smc_ism_v2_capable = false;"
>>
>
> Thank you. I will change this in the loopback-ism patch set.
>
> But I am wondering if loopback-ism coexists with s390 ISMv1, why smc_ism_v2_capable shouldn't be set?
> Is it because the SEID generated in this way is not correct if the s390 ISMv2 does not exist?

I think you're right: 'At least one IMSv2 device' is sufficient for smc_ism_v2_capable.

Actually, we could even always do smc_ism_v2_capable=true, and append an empty ISMv2 device list.
(I am not sure that would be a good idea...)

Interesting sceanrios to consider for ism-loopback:
e.g.: 2 ISMv1 device and 1 ism-loopback...

2023-12-05 09:52:16

by Alexandra Winter

[permalink] [raw]
Subject: Re: [PATCH net-next v3 5/7] net/smc: compatible with 128-bits extend GID of virtual ISM device



On 04.12.23 13:24, Wen Gu wrote:
> Thank you very much for review. See below.
>
> On 2023/12/2 00:30, Alexandra Winter wrote:
>>
>>
>> On 30.11.23 12:28, Wen Gu wrote:
>> [...]
>>> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
>>> index 766a1f1..d1e18bf 100644
>>> --- a/net/smc/af_smc.c
>>> +++ b/net/smc/af_smc.c
>> [...]
>>> @@ -1048,7 +1048,8 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
>>>   {
>>>       int rc = SMC_CLC_DECL_NOSMCDDEV;
>>>       struct smcd_dev *smcd;
>>> -    int i = 1;
>>> +    int i = 1, entry = 1;
>>> +    bool is_virtual;
>>>       u16 chid;
>>>         if (smcd_indicated(ini->smc_type_v1))
>>> @@ -1060,14 +1061,23 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc,
>>>           chid = smc_ism_get_chid(smcd);
>>>           if (!smc_find_ism_v2_is_unique_chid(chid, ini, i))
>>>               continue;
>>> +        is_virtual = __smc_ism_is_virtual(chid);
>>>           if (!smc_pnet_is_pnetid_set(smcd->pnetid) ||
>>>               smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) {
>>> +            if (is_virtual && entry == SMC_MAX_ISM_DEVS)
>>> +                /* only one GID-CHID entry left in CLC Proposal SMC-Dv2
>>> +                 * extension. but a virtual ISM device's GID takes two
>>> +                 * entries. So give up it and try the next potential ISM
>>> +                 * device.
>>> +                 */
>>
>> It is really importatnt to note that virtual ISMs take 2 entries.
>> But it is still hard to understand this piece of code. e.g. I was wondering for a while,
>> why you mention CLC here...
>> Maybe it would be easier to understand this, if you rename SMC_MAX_ISM_DEVS to something else?
>> Something like SMCD_MAX_V2_GID_ENTRIES?
>>
>
> I agree.
>
> But I perfer to define a new macro to represent the max ISMv2 entries in CLC proposal message,
> e.g. SMCD_CLC_MAX_V2_GID_ENTRIES, and keep using SMC_MAX_ISM_DEVS to represent the max devices
> that can be proposed. Both semantics are required in the code, such as:
>
> ini->ism_dev[SMC_MAX_ISM_DEVS]        | smcd_v2_ext->gidchid[SMCD_CLC_MAX_V2_GID_ENTRIES]
> -------------------------------------------------------------------------------------------
> [1:virtual_ISM_1]                     | [1:virtual_ISM_1 GID]
>                                       | [2:virtual_ISM_1 extension GID]
> [2:ISM_2]                             | [3:ISM_2 GID/CHID]
> [3:ISM_3]                             | [4:ISM_3 GID/CHID]
>
> And SMC_MAX_ISM_DEVS is required no more than SMCD_CLC_MAX_V2_GID_ENTRIES.

I agree, this is even better.

2023-12-07 03:42:52

by Wen Gu

[permalink] [raw]
Subject: Re: [PATCH net-next v3 7/7] net/smc: manage system EID in SMC stack instead of ISM driver



On 2023/12/4 20:57, Alexandra Winter wrote:
>
>
> On 04.12.23 13:36, Wen Gu wrote:
>>> Here we only check the first smcd device to determine whether we support v2.
>>> Which is ok, for today's platform firmware ISM devices, as they are always the same version.
>>>
>>> When you add virtual ISM devices (loopback-ism, virtio-ism) then this needs to be changed.
>>> IMO the logic then needs to be "if all smcd devices support v2,
>>> then smc_ism_v2_capable = true;
>>> else smc_ism_v2_capable = false;"
>>>
>>
>> Thank you. I will change this in the loopback-ism patch set.
>>
>> But I am wondering if loopback-ism coexists with s390 ISMv1, why smc_ism_v2_capable shouldn't be set?
>> Is it because the SEID generated in this way is not correct if the s390 ISMv2 does not exist?
>
> I think you're right: 'At least one IMSv2 device' is sufficient for smc_ism_v2_capable.
>
> Actually, we could even always do smc_ism_v2_capable=true, and append an empty ISMv2 device list.
> (I am not sure that would be a good idea...)
>
> Interesting sceanrios to consider for ism-loopback:
> e.g.: 2 ISMv1 device and 1 ism-loopback...

Yes. when virtual ISM is introduced (e.g. loopback-ism), I think logic can be

1) smc_ism_v2_capable is false initially as now;
2) Set smc_ism_v2_capable when ISMv2 or virtual ISM is registered, regardless of
whether there is already a device in smcd device list.

And I guess the intent of smc_ism_v2_capable is to indicate that this kernel is
capable of using v2 devices rather than indicate that there are v2 smcd devices
available in the list, since right now smc_ism_v2_capable won't be cleared even
ISMv2 devices are unregistered.