Commit be589d04 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-smc-introduce-SMC-Dv2-support'

Karsten Graul says:

====================
net/smc: introduce SMC-Dv2 support

SMC-Dv2 support (see https://www.ibm.com/support/pages/node/6326337)
provides multi-subnet support for SMC-D, eliminating the current
same-subnet restriction. The new version detects if any of the virtual
ISM devices are on the same system and can therefore be used for an
SMC-Dv2 connection. Furthermore, SMC-Dv2 eliminates the need for
PNET IDs on s390.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 414698f6 e8d726c8
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define ISM_DMB_WORD_OFFSET 1 #define ISM_DMB_WORD_OFFSET 1
#define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32) #define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32)
#define ISM_NR_DMBS 1920 #define ISM_NR_DMBS 1920
#define ISM_IDENT_MASK 0x00FFFF
#define ISM_REG_SBA 0x1 #define ISM_REG_SBA 0x1
#define ISM_REG_IEQ 0x2 #define ISM_REG_IEQ 0x2
...@@ -206,6 +207,12 @@ struct ism_dev { ...@@ -206,6 +207,12 @@ struct ism_dev {
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \ #define ISM_CREATE_REQ(dmb, idx, sf, offset) \
((dmb) | (idx) << 24 | (sf) << 23 | (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, static inline void __ism_read_cmd(struct ism_dev *ism, void *data,
unsigned long offset, unsigned long len) unsigned long offset, unsigned long len)
{ {
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/ctype.h>
#include <linux/processor.h>
#include <net/smc.h> #include <net/smc.h>
#include <asm/debug.h> #include <asm/debug.h>
...@@ -387,6 +389,42 @@ static int ism_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx, ...@@ -387,6 +389,42 @@ static int ism_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
return 0; return 0;
} }
static struct ism_systemeid SYSTEM_EID = {
.seid_string = "IBM-SYSZ-IBMSEID00000000",
.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);
}
static void ism_get_system_eid(struct smcd_dev *smcd, u8 **eid)
{
*eid = &SYSTEM_EID.seid_string[0];
}
static u16 ism_get_chid(struct smcd_dev *smcd)
{
struct ism_dev *ismdev;
ismdev = (struct ism_dev *)smcd->priv;
if (!ismdev || !ismdev->pdev)
return 0;
return to_zpci(ismdev->pdev)->pchid;
}
static void ism_handle_event(struct ism_dev *ism) static void ism_handle_event(struct ism_dev *ism)
{ {
struct smcd_event *entry; struct smcd_event *entry;
...@@ -443,6 +481,8 @@ static const struct smcd_ops ism_ops = { ...@@ -443,6 +481,8 @@ static const struct smcd_ops ism_ops = {
.reset_vlan_required = ism_reset_vlan_required, .reset_vlan_required = ism_reset_vlan_required,
.signal_event = ism_signal_ieq, .signal_event = ism_signal_ieq,
.move_data = ism_move, .move_data = ism_move,
.get_system_eid = ism_get_system_eid,
.get_chid = ism_get_chid,
}; };
static int ism_dev_init(struct ism_dev *ism) static int ism_dev_init(struct ism_dev *ism)
...@@ -471,6 +511,10 @@ static int ism_dev_init(struct ism_dev *ism) ...@@ -471,6 +511,10 @@ static int ism_dev_init(struct ism_dev *ism)
if (ret) if (ret)
goto unreg_ieq; goto unreg_ieq;
if (!ism_add_vlan_id(ism->smcd, ISM_RESERVED_VLANID))
/* hardware is V2 capable */
ism_create_system_eid();
ret = smcd_register_dev(ism->smcd); ret = smcd_register_dev(ism->smcd);
if (ret) if (ret)
goto unreg_ieq; goto unreg_ieq;
...@@ -550,6 +594,9 @@ static void ism_dev_exit(struct ism_dev *ism) ...@@ -550,6 +594,9 @@ static void ism_dev_exit(struct ism_dev *ism)
struct pci_dev *pdev = ism->pdev; struct pci_dev *pdev = ism->pdev;
smcd_unregister_dev(ism->smcd); smcd_unregister_dev(ism->smcd);
if (SYSTEM_EID.serial_number[0] != '0' ||
SYSTEM_EID.type[0] != '0')
ism_del_vlan_id(ism->smcd, ISM_RESERVED_VLANID);
unregister_ieq(ism); unregister_ieq(ism);
unregister_sba(ism); unregister_sba(ism);
free_irq(pci_irq_vector(pdev, 0), ism); free_irq(pci_irq_vector(pdev, 0), ism);
......
...@@ -37,6 +37,8 @@ struct smcd_dmb { ...@@ -37,6 +37,8 @@ struct smcd_dmb {
#define ISM_EVENT_GID 1 #define ISM_EVENT_GID 1
#define ISM_EVENT_SWR 2 #define ISM_EVENT_SWR 2
#define ISM_RESERVED_VLANID 0x1FFF
#define ISM_ERROR 0xFFFF #define ISM_ERROR 0xFFFF
struct smcd_event { struct smcd_event {
...@@ -63,6 +65,8 @@ struct smcd_ops { ...@@ -63,6 +65,8 @@ struct smcd_ops {
int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx, int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
bool sf, unsigned int offset, void *data, bool sf, unsigned int offset, void *data,
unsigned int size); unsigned int size);
void (*get_system_eid)(struct smcd_dev *dev, u8 **eid);
u16 (*get_chid)(struct smcd_dev *dev);
}; };
struct smcd_dev { struct smcd_dev {
......
This diff is collapsed.
...@@ -19,10 +19,19 @@ ...@@ -19,10 +19,19 @@
#include "smc_ib.h" #include "smc_ib.h"
#define SMC_V1 1 /* SMC version V1 */ #define SMC_V1 1 /* SMC version V1 */
#define SMC_V2 2 /* SMC version V2 */
#define SMC_RELEASE 0
#define SMCPROTO_SMC 0 /* SMC protocol, IPv4 */ #define SMCPROTO_SMC 0 /* SMC protocol, IPv4 */
#define SMCPROTO_SMC6 1 /* SMC protocol, IPv6 */ #define SMCPROTO_SMC6 1 /* SMC protocol, IPv6 */
#define SMC_MAX_ISM_DEVS 8 /* max # of proposed non-native ISM
* devices
*/
#define SMC_MAX_HOSTNAME_LEN 32
#define SMC_MAX_EID_LEN 32
extern struct proto smc_proto; extern struct proto smc_proto;
extern struct proto smc_proto6; extern struct proto smc_proto6;
...@@ -246,6 +255,9 @@ extern struct workqueue_struct *smc_close_wq; /* wq for close work */ ...@@ -246,6 +255,9 @@ extern struct workqueue_struct *smc_close_wq; /* wq for close work */
extern u8 local_systemid[SMC_SYSTEMID_LEN]; /* unique system identifier */ extern u8 local_systemid[SMC_SYSTEMID_LEN]; /* unique system identifier */
#define ntohll(x) be64_to_cpu(x)
#define htonll(x) cpu_to_be64(x)
/* convert an u32 value into network byte order, store it into a 3 byte field */ /* convert an u32 value into network byte order, store it into a 3 byte field */
static inline void hton24(u8 *net, u32 host) static inline void hton24(u8 *net, u32 host)
{ {
......
This diff is collapsed.
...@@ -54,19 +54,19 @@ ...@@ -54,19 +54,19 @@
#define SMC_CLC_DECL_ERR_RDYLNK 0x09990002 /* ib ready link failed */ #define SMC_CLC_DECL_ERR_RDYLNK 0x09990002 /* ib ready link failed */
#define SMC_CLC_DECL_ERR_REGRMB 0x09990003 /* reg rmb failed */ #define SMC_CLC_DECL_ERR_REGRMB 0x09990003 /* reg rmb failed */
#define SMC_FIRST_CONTACT_MASK 0b10 /* first contact bit within typev2 */
struct smc_clc_msg_hdr { /* header1 of clc messages */ struct smc_clc_msg_hdr { /* header1 of clc messages */
u8 eyecatcher[4]; /* eye catcher */ u8 eyecatcher[4]; /* eye catcher */
u8 type; /* proposal / accept / confirm / decline */ u8 type; /* proposal / accept / confirm / decline */
__be16 length; __be16 length;
#if defined(__BIG_ENDIAN_BITFIELD) #if defined(__BIG_ENDIAN_BITFIELD)
u8 version : 4, u8 version : 4,
flag : 1, typev2 : 2,
rsvd : 1, typev1 : 2;
path : 2;
#elif defined(__LITTLE_ENDIAN_BITFIELD) #elif defined(__LITTLE_ENDIAN_BITFIELD)
u8 path : 2, u8 typev1 : 2,
rsvd : 1, typev2 : 2,
flag : 1,
version : 4; version : 4;
#endif #endif
} __packed; /* format defined in RFC7609 */ } __packed; /* format defined in RFC7609 */
...@@ -81,8 +81,6 @@ struct smc_clc_msg_local { /* header2 of clc messages */ ...@@ -81,8 +81,6 @@ struct smc_clc_msg_local { /* header2 of clc messages */
u8 mac[6]; /* mac of ib_device port */ u8 mac[6]; /* mac of ib_device port */
}; };
#define SMC_CLC_MAX_V6_PREFIX 8
/* Struct would be 4 byte aligned, but it is used in an array that is sent /* Struct would be 4 byte aligned, but it is used in an array that is sent
* to peers and must conform to RFC7609, hence we need to use packed here. * to peers and must conform to RFC7609, hence we need to use packed here.
*/ */
...@@ -91,6 +89,44 @@ struct smc_clc_ipv6_prefix { ...@@ -91,6 +89,44 @@ struct smc_clc_ipv6_prefix {
u8 prefix_len; u8 prefix_len;
} __packed; /* format defined in RFC7609 */ } __packed; /* format defined in RFC7609 */
#if defined(__BIG_ENDIAN_BITFIELD)
struct smc_clc_v2_flag {
u8 release : 4,
rsvd : 3,
seid : 1;
};
#elif defined(__LITTLE_ENDIAN_BITFIELD)
struct smc_clc_v2_flag {
u8 seid : 1,
rsvd : 3,
release : 4;
};
#endif
struct smc_clnt_opts_area_hdr {
u8 eid_cnt; /* number of user defined EIDs */
u8 ism_gid_cnt; /* number of ISMv2 GIDs */
u8 reserved1;
struct smc_clc_v2_flag flag;
u8 reserved2[2];
__be16 smcd_v2_ext_offset; /* SMC-Dv2 Extension Offset */
};
struct smc_clc_smcd_gid_chid {
__be64 gid; /* ISM GID */
__be16 chid; /* ISMv2 CHID */
} __packed; /* format defined in
* IBM Shared Memory Communications Version 2
* (https://www.ibm.com/support/pages/node/6326337)
*/
struct smc_clc_v2_extension {
struct smc_clnt_opts_area_hdr hdr;
u8 roce[16]; /* RoCEv2 GID */
u8 reserved[16];
u8 user_eids[0][SMC_MAX_EID_LEN];
};
struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
__be32 outgoing_subnet; /* subnet mask */ __be32 outgoing_subnet; /* subnet mask */
u8 prefix_len; /* number of significant bits in mask */ u8 prefix_len; /* number of significant bits in mask */
...@@ -99,8 +135,15 @@ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/ ...@@ -99,8 +135,15 @@ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
} __aligned(4); } __aligned(4);
struct smc_clc_msg_smcd { /* SMC-D GID information */ struct smc_clc_msg_smcd { /* SMC-D GID information */
u64 gid; /* ISM GID of requestor */ struct smc_clc_smcd_gid_chid ism; /* ISM native GID+CHID of requestor */
u8 res[32]; __be16 v2_ext_offset; /* SMC Version 2 Extension Offset */
u8 reserved[28];
};
struct smc_clc_smcd_v2_extension {
u8 system_eid[SMC_MAX_EID_LEN];
u8 reserved[16];
struct smc_clc_smcd_gid_chid gidchid[0];
}; };
struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
...@@ -109,11 +152,16 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ ...@@ -109,11 +152,16 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
__be16 iparea_offset; /* offset to IP address information area */ __be16 iparea_offset; /* offset to IP address information area */
} __aligned(4); } __aligned(4);
#define SMC_CLC_MAX_V6_PREFIX 8
struct smc_clc_msg_proposal_area { struct smc_clc_msg_proposal_area {
struct smc_clc_msg_proposal pclc_base; struct smc_clc_msg_proposal pclc_base;
struct smc_clc_msg_smcd pclc_smcd; struct smc_clc_msg_smcd pclc_smcd;
struct smc_clc_msg_proposal_prefix pclc_prfx; struct smc_clc_msg_proposal_prefix pclc_prfx;
struct smc_clc_ipv6_prefix pclc_prfx_ipv6[SMC_CLC_MAX_V6_PREFIX]; struct smc_clc_ipv6_prefix pclc_prfx_ipv6[SMC_CLC_MAX_V6_PREFIX];
struct smc_clc_v2_extension pclc_v2_ext;
struct smc_clc_smcd_v2_extension pclc_smcd_v2_ext;
struct smc_clc_smcd_gid_chid pclc_gidchids[SMC_MAX_ISM_DEVS];
struct smc_clc_msg_trail pclc_trl; struct smc_clc_msg_trail pclc_trl;
}; };
...@@ -134,11 +182,9 @@ struct smcr_clc_msg_accept_confirm { /* SMCR accept/confirm */ ...@@ -134,11 +182,9 @@ struct smcr_clc_msg_accept_confirm { /* SMCR accept/confirm */
__be64 rmb_dma_addr; /* RMB virtual address */ __be64 rmb_dma_addr; /* RMB virtual address */
u8 reserved2; u8 reserved2;
u8 psn[3]; /* packet sequence number */ u8 psn[3]; /* packet sequence number */
struct smc_clc_msg_trail smcr_trl;
/* eye catcher "SMCR" EBCDIC */
} __packed; } __packed;
struct smcd_clc_msg_accept_confirm { /* SMCD accept/confirm */ struct smcd_clc_msg_accept_confirm_common { /* SMCD accept/confirm */
u64 gid; /* Sender GID */ u64 gid; /* Sender GID */
u64 token; /* DMB token */ u64 token; /* DMB token */
u8 dmbe_idx; /* DMBE index */ u8 dmbe_idx; /* DMBE index */
...@@ -150,26 +196,63 @@ struct smcd_clc_msg_accept_confirm { /* SMCD accept/confirm */ ...@@ -150,26 +196,63 @@ struct smcd_clc_msg_accept_confirm { /* SMCD accept/confirm */
dmbe_size : 4; dmbe_size : 4;
#endif #endif
u16 reserved4; u16 reserved4;
u32 linkid; /* Link identifier */ __be32 linkid; /* Link identifier */
u32 reserved5[3];
struct smc_clc_msg_trail smcd_trl;
/* eye catcher "SMCD" EBCDIC */
} __packed; } __packed;
#define SMC_CLC_OS_ZOS 1
#define SMC_CLC_OS_LINUX 2
#define SMC_CLC_OS_AIX 3
struct smc_clc_first_contact_ext {
u8 reserved1;
#if defined(__BIG_ENDIAN_BITFIELD)
u8 os_type : 4,
release : 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
u8 release : 4,
os_type : 4;
#endif
u8 reserved2[2];
u8 hostname[SMC_MAX_HOSTNAME_LEN];
};
struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
struct smc_clc_msg_hdr hdr; struct smc_clc_msg_hdr hdr;
union { union {
struct smcr_clc_msg_accept_confirm r0; /* SMC-R */ struct smcr_clc_msg_accept_confirm r0; /* SMC-R */
struct smcd_clc_msg_accept_confirm d0; /* SMC-D */ struct { /* SMC-D */
struct smcd_clc_msg_accept_confirm_common d0;
u32 reserved5[3];
};
}; };
} __packed; /* format defined in RFC7609 */ } __packed; /* format defined in RFC7609 */
struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */
struct smc_clc_msg_hdr hdr;
union {
struct smcr_clc_msg_accept_confirm r0; /* SMC-R */
struct { /* SMC-D */
struct smcd_clc_msg_accept_confirm_common d0;
__be16 chid;
u8 eid[SMC_MAX_EID_LEN];
u8 reserved5[8];
};
};
};
struct smc_clc_msg_decline { /* clc decline message */ struct smc_clc_msg_decline { /* clc decline message */
struct smc_clc_msg_hdr hdr; struct smc_clc_msg_hdr hdr;
u8 id_for_peer[SMC_SYSTEMID_LEN]; /* sender peer_id */ u8 id_for_peer[SMC_SYSTEMID_LEN]; /* sender peer_id */
__be32 peer_diagnosis; /* diagnosis information */ __be32 peer_diagnosis; /* diagnosis information */
u8 reserved2[4]; #if defined(__BIG_ENDIAN_BITFIELD)
struct smc_clc_msg_trail trl; /* eye catcher "SMCR" EBCDIC */ u8 os_type : 4,
reserved : 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
u8 reserved : 4,
os_type : 4;
#endif
u8 reserved2[3];
struct smc_clc_msg_trail trl; /* eye catcher "SMCD" or "SMCR" EBCDIC */
} __aligned(4); } __aligned(4);
/* determine start of the prefix area within the proposal message */ /* determine start of the prefix area within the proposal message */
...@@ -180,16 +263,58 @@ smc_clc_proposal_get_prefix(struct smc_clc_msg_proposal *pclc) ...@@ -180,16 +263,58 @@ smc_clc_proposal_get_prefix(struct smc_clc_msg_proposal *pclc)
((u8 *)pclc + sizeof(*pclc) + ntohs(pclc->iparea_offset)); ((u8 *)pclc + sizeof(*pclc) + ntohs(pclc->iparea_offset));
} }
static inline bool smcr_indicated(int smc_type)
{
return smc_type == SMC_TYPE_R || smc_type == SMC_TYPE_B;
}
static inline bool smcd_indicated(int smc_type)
{
return smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B;
}
/* get SMC-D info from proposal message */ /* get SMC-D info from proposal message */
static inline struct smc_clc_msg_smcd * static inline struct smc_clc_msg_smcd *
smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop) smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop)
{ {
if (ntohs(prop->iparea_offset) != sizeof(struct smc_clc_msg_smcd)) if (smcd_indicated(prop->hdr.typev1) &&
ntohs(prop->iparea_offset) != sizeof(struct smc_clc_msg_smcd))
return NULL; return NULL;
return (struct smc_clc_msg_smcd *)(prop + 1); return (struct smc_clc_msg_smcd *)(prop + 1);
} }
static inline struct smc_clc_v2_extension *
smc_get_clc_v2_ext(struct smc_clc_msg_proposal *prop)
{
struct smc_clc_msg_smcd *prop_smcd = smc_get_clc_msg_smcd(prop);
if (!prop_smcd || !ntohs(prop_smcd->v2_ext_offset))
return NULL;
return (struct smc_clc_v2_extension *)
((u8 *)prop_smcd +
offsetof(struct smc_clc_msg_smcd, v2_ext_offset) +
sizeof(prop_smcd->v2_ext_offset) +
ntohs(prop_smcd->v2_ext_offset));
}
static inline struct smc_clc_smcd_v2_extension *
smc_get_clc_smcd_v2_ext(struct smc_clc_v2_extension *prop_v2ext)
{
if (!prop_v2ext)
return NULL;
if (!ntohs(prop_v2ext->hdr.smcd_v2_ext_offset))
return NULL;
return (struct smc_clc_smcd_v2_extension *)
((u8 *)prop_v2ext +
offsetof(struct smc_clc_v2_extension, hdr) +
offsetof(struct smc_clnt_opts_area_hdr, smcd_v2_ext_offset) +
sizeof(prop_v2ext->hdr.smcd_v2_ext_offset) +
ntohs(prop_v2ext->hdr.smcd_v2_ext_offset));
}
struct smcd_dev; struct smcd_dev;
struct smc_init_info; struct smc_init_info;
...@@ -197,10 +322,12 @@ int smc_clc_prfx_match(struct socket *clcsock, ...@@ -197,10 +322,12 @@ int smc_clc_prfx_match(struct socket *clcsock,
struct smc_clc_msg_proposal_prefix *prop); struct smc_clc_msg_proposal_prefix *prop);
int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen, int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
u8 expected_type, unsigned long timeout); u8 expected_type, unsigned long timeout);
int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info); int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version);
int smc_clc_send_proposal(struct smc_sock *smc, int smc_type, int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini);
struct smc_init_info *ini); int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
int smc_clc_send_confirm(struct smc_sock *smc); u8 version);
int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact); int smc_clc_send_accept(struct smc_sock *smc, bool srv_first_contact,
u8 version);
void smc_clc_init(void) __init;
#endif #endif
...@@ -375,7 +375,8 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -375,7 +375,8 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
int i; int i;
if (ini->is_smcd && ini->vlan_id) { if (ini->is_smcd && ini->vlan_id) {
if (smc_ism_get_vlan(ini->ism_dev, ini->vlan_id)) { if (smc_ism_get_vlan(ini->ism_dev[ini->ism_selected],
ini->vlan_id)) {
rc = SMC_CLC_DECL_ISMVLANERR; rc = SMC_CLC_DECL_ISMVLANERR;
goto out; goto out;
} }
...@@ -412,13 +413,14 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -412,13 +413,14 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
lgr->conns_all = RB_ROOT; lgr->conns_all = RB_ROOT;
if (ini->is_smcd) { if (ini->is_smcd) {
/* SMC-D specific settings */ /* SMC-D specific settings */
get_device(&ini->ism_dev->dev); get_device(&ini->ism_dev[ini->ism_selected]->dev);
lgr->peer_gid = ini->ism_peer_gid; lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
lgr->smcd = ini->ism_dev; lgr->smcd = ini->ism_dev[ini->ism_selected];
lgr_list = &ini->ism_dev->lgr_list; lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
lgr_lock = &lgr->smcd->lgr_lock; lgr_lock = &lgr->smcd->lgr_lock;
lgr->smc_version = ini->smcd_version;
lgr->peer_shutdown = 0; lgr->peer_shutdown = 0;
atomic_inc(&ini->ism_dev->lgr_cnt); atomic_inc(&ini->ism_dev[ini->ism_selected]->lgr_cnt);
} else { } else {
/* SMC-R specific settings */ /* SMC-R specific settings */
lgr->role = smc->listen_smc ? SMC_SERV : SMC_CLNT; lgr->role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
...@@ -449,7 +451,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -449,7 +451,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
kfree(lgr); kfree(lgr);
ism_put_vlan: ism_put_vlan:
if (ini->is_smcd && ini->vlan_id) if (ini->is_smcd && ini->vlan_id)
smc_ism_put_vlan(ini->ism_dev, ini->vlan_id); smc_ism_put_vlan(ini->ism_dev[ini->ism_selected], ini->vlan_id);
out: out:
if (rc < 0) { if (rc < 0) {
if (rc == -ENOMEM) if (rc == -ENOMEM)
...@@ -1288,8 +1290,10 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -1288,8 +1290,10 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
spinlock_t *lgr_lock; spinlock_t *lgr_lock;
int rc = 0; int rc = 0;
lgr_list = ini->is_smcd ? &ini->ism_dev->lgr_list : &smc_lgr_list.list; lgr_list = ini->is_smcd ? &ini->ism_dev[ini->ism_selected]->lgr_list :
lgr_lock = ini->is_smcd ? &ini->ism_dev->lgr_lock : &smc_lgr_list.lock; &smc_lgr_list.list;
lgr_lock = ini->is_smcd ? &ini->ism_dev[ini->ism_selected]->lgr_lock :
&smc_lgr_list.lock;
ini->first_contact_local = 1; ini->first_contact_local = 1;
role = smc->listen_smc ? SMC_SERV : SMC_CLNT; role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
if (role == SMC_CLNT && ini->first_contact_peer) if (role == SMC_CLNT && ini->first_contact_peer)
...@@ -1301,7 +1305,8 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -1301,7 +1305,8 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
list_for_each_entry(lgr, lgr_list, list) { list_for_each_entry(lgr, lgr_list, list) {
write_lock_bh(&lgr->conns_lock); write_lock_bh(&lgr->conns_lock);
if ((ini->is_smcd ? if ((ini->is_smcd ?
smcd_lgr_match(lgr, ini->ism_dev, ini->ism_peer_gid) : smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected],
ini->ism_peer_gid[ini->ism_selected]) :
smcr_lgr_match(lgr, ini->ib_lcl, role, ini->ib_clcqpn)) && smcr_lgr_match(lgr, ini->ib_lcl, role, ini->ib_clcqpn)) &&
!lgr->sync_err && !lgr->sync_err &&
lgr->vlan_id == ini->vlan_id && lgr->vlan_id == ini->vlan_id &&
......
...@@ -231,6 +231,11 @@ struct smc_link_group { ...@@ -231,6 +231,11 @@ struct smc_link_group {
u8 freeing : 1; /* lgr is being freed */ u8 freeing : 1; /* lgr is being freed */
bool is_smcd; /* SMC-R or SMC-D */ bool is_smcd; /* SMC-R or SMC-D */
u8 smc_version;
u8 negotiated_eid[SMC_MAX_EID_LEN];
u8 peer_os; /* peer operating system */
u8 peer_smc_release;
u8 peer_hostname[SMC_MAX_HOSTNAME_LEN];
union { union {
struct { /* SMC-R */ struct { /* SMC-R */
enum smc_lgr_role role; enum smc_lgr_role role;
...@@ -291,6 +296,8 @@ struct smc_clc_msg_local; ...@@ -291,6 +296,8 @@ struct smc_clc_msg_local;
struct smc_init_info { struct smc_init_info {
u8 is_smcd; u8 is_smcd;
u8 smc_type_v1;
u8 smc_type_v2;
u8 first_contact_peer; u8 first_contact_peer;
u8 first_contact_local; u8 first_contact_local;
unsigned short vlan_id; unsigned short vlan_id;
...@@ -301,8 +308,12 @@ struct smc_init_info { ...@@ -301,8 +308,12 @@ struct smc_init_info {
u8 ib_port; u8 ib_port;
u32 ib_clcqpn; u32 ib_clcqpn;
/* SMC-D */ /* SMC-D */
u64 ism_peer_gid; u64 ism_peer_gid[SMC_MAX_ISM_DEVS + 1];
struct smcd_dev *ism_dev; 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 */
u8 ism_selected; /* index of selected ISM dev*/
u8 smcd_version;
}; };
/* Find the connection associated with the given alert token in the link group. /* Find the connection associated with the given alert token in the link group.
......
...@@ -21,7 +21,9 @@ struct smcd_dev_list smcd_dev_list = { ...@@ -21,7 +21,9 @@ struct smcd_dev_list smcd_dev_list = {
.mutex = __MUTEX_INITIALIZER(smcd_dev_list.mutex) .mutex = __MUTEX_INITIALIZER(smcd_dev_list.mutex)
}; };
/* Test if an ISM communication is possible. */ bool smc_ism_v2_capable;
/* 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(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
{ {
return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0, return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
...@@ -39,6 +41,16 @@ int smc_ism_write(struct smcd_dev *smcd, const struct smc_ism_position *pos, ...@@ -39,6 +41,16 @@ int smc_ism_write(struct smcd_dev *smcd, const struct smc_ism_position *pos,
return rc < 0 ? rc : 0; return rc < 0 ? rc : 0;
} }
void smc_ism_get_system_eid(struct smcd_dev *smcd, u8 **eid)
{
smcd->ops->get_system_eid(smcd, eid);
}
u16 smc_ism_get_chid(struct smcd_dev *smcd)
{
return smcd->ops->get_chid(smcd);
}
/* Set a connection using this DMBE. */ /* Set a connection using this DMBE. */
void smc_ism_set_conn(struct smc_connection *conn) void smc_ism_set_conn(struct smc_connection *conn)
{ {
...@@ -319,7 +331,18 @@ EXPORT_SYMBOL_GPL(smcd_alloc_dev); ...@@ -319,7 +331,18 @@ EXPORT_SYMBOL_GPL(smcd_alloc_dev);
int smcd_register_dev(struct smcd_dev *smcd) int smcd_register_dev(struct smcd_dev *smcd)
{ {
mutex_lock(&smcd_dev_list.mutex); mutex_lock(&smcd_dev_list.mutex);
list_add_tail(&smcd->list, &smcd_dev_list.list); if (list_empty(&smcd_dev_list.list)) {
u8 *system_eid = NULL;
smc_ism_get_system_eid(smcd, &system_eid);
if ((*system_eid) + 24 != '0' || (*system_eid) + 28 != '0')
smc_ism_v2_capable = true;
}
/* sort list: devices without pnetid before devices with pnetid */
if (smcd->pnetid[0])
list_add_tail(&smcd->list, &smcd_dev_list.list);
else
list_add(&smcd->list, &smcd_dev_list.list);
mutex_unlock(&smcd_dev_list.mutex); mutex_unlock(&smcd_dev_list.mutex);
pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n", pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
...@@ -399,3 +422,8 @@ void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno) ...@@ -399,3 +422,8 @@ void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno)
spin_unlock_irqrestore(&smcd->lock, flags); spin_unlock_irqrestore(&smcd->lock, flags);
} }
EXPORT_SYMBOL_GPL(smcd_handle_irq); EXPORT_SYMBOL_GPL(smcd_handle_irq);
void __init smc_ism_init(void)
{
smc_ism_v2_capable = false;
}
...@@ -19,7 +19,10 @@ struct smcd_dev_list { /* List of SMCD devices */ ...@@ -19,7 +19,10 @@ struct smcd_dev_list { /* List of SMCD devices */
struct mutex mutex; /* Protects list of devices */ struct mutex mutex; /* Protects list of devices */
}; };
extern struct smcd_dev_list smcd_dev_list; /* list of smcd devices */ extern struct smcd_dev_list smcd_dev_list; /* list of smcd devices */
extern bool smc_ism_v2_capable; /* HW supports ISM V2 and thus
* System EID is defined
*/
struct smc_ism_vlanid { /* VLAN id set on ISM device */ struct smc_ism_vlanid { /* VLAN id set on ISM device */
struct list_head list; struct list_head list;
...@@ -47,4 +50,7 @@ int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc); ...@@ -47,4 +50,7 @@ int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc);
int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos, int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos,
void *data, size_t len); void *data, size_t len);
int smc_ism_signal_shutdown(struct smc_link_group *lgr); int smc_ism_signal_shutdown(struct smc_link_group *lgr);
void smc_ism_get_system_eid(struct smcd_dev *dev, u8 **eid);
u16 smc_ism_get_chid(struct smcd_dev *dev);
void smc_ism_init(void);
#endif #endif
...@@ -16,5 +16,6 @@ extern unsigned int smc_net_id; ...@@ -16,5 +16,6 @@ extern unsigned int smc_net_id;
/* per-network namespace private data */ /* per-network namespace private data */
struct smc_net { struct smc_net {
struct smc_pnettable pnettable; struct smc_pnettable pnettable;
struct smc_pnetids_ndev pnetids_ndev;
}; };
#endif #endif
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
#include "smc_ism.h" #include "smc_ism.h"
#include "smc_core.h" #include "smc_core.h"
#define SMC_ASCII_BLANK 32 static struct net_device *__pnet_find_base_ndev(struct net_device *ndev);
static struct net_device *pnet_find_base_ndev(struct net_device *ndev); static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
static const struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { static const struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
...@@ -73,14 +72,22 @@ struct smc_pnetentry { ...@@ -73,14 +72,22 @@ struct smc_pnetentry {
}; };
}; };
/* Check if the pnetid is set */
bool smc_pnet_is_pnetid_set(u8 *pnetid)
{
if (pnetid[0] == 0 || pnetid[0] == _S)
return false;
return true;
}
/* Check if two given pnetids match */ /* Check if two given pnetids match */
static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2) static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2)
{ {
int i; int i;
for (i = 0; i < SMC_MAX_PNETID_LEN; i++) { for (i = 0; i < SMC_MAX_PNETID_LEN; i++) {
if ((pnetid1[i] == 0 || pnetid1[i] == SMC_ASCII_BLANK) && if ((pnetid1[i] == 0 || pnetid1[i] == _S) &&
(pnetid2[i] == 0 || pnetid2[i] == SMC_ASCII_BLANK)) (pnetid2[i] == 0 || pnetid2[i] == _S))
break; break;
if (pnetid1[i] != pnetid2[i]) if (pnetid1[i] != pnetid2[i])
return false; return false;
...@@ -238,11 +245,10 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev) ...@@ -238,11 +245,10 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
static bool smc_pnet_apply_ib(struct smc_ib_device *ib_dev, u8 ib_port, static bool smc_pnet_apply_ib(struct smc_ib_device *ib_dev, u8 ib_port,
char *pnet_name) char *pnet_name)
{ {
u8 pnet_null[SMC_MAX_PNETID_LEN] = {0};
bool applied = false; bool applied = false;
mutex_lock(&smc_ib_devices.mutex); mutex_lock(&smc_ib_devices.mutex);
if (smc_pnet_match(ib_dev->pnetid[ib_port - 1], pnet_null)) { if (!smc_pnet_is_pnetid_set(ib_dev->pnetid[ib_port - 1])) {
memcpy(ib_dev->pnetid[ib_port - 1], pnet_name, memcpy(ib_dev->pnetid[ib_port - 1], pnet_name,
SMC_MAX_PNETID_LEN); SMC_MAX_PNETID_LEN);
ib_dev->pnetid_by_user[ib_port - 1] = true; ib_dev->pnetid_by_user[ib_port - 1] = true;
...@@ -256,11 +262,10 @@ static bool smc_pnet_apply_ib(struct smc_ib_device *ib_dev, u8 ib_port, ...@@ -256,11 +262,10 @@ static bool smc_pnet_apply_ib(struct smc_ib_device *ib_dev, u8 ib_port,
*/ */
static bool smc_pnet_apply_smcd(struct smcd_dev *smcd_dev, char *pnet_name) static bool smc_pnet_apply_smcd(struct smcd_dev *smcd_dev, char *pnet_name)
{ {
u8 pnet_null[SMC_MAX_PNETID_LEN] = {0};
bool applied = false; bool applied = false;
mutex_lock(&smcd_dev_list.mutex); mutex_lock(&smcd_dev_list.mutex);
if (smc_pnet_match(smcd_dev->pnetid, pnet_null)) { if (!smc_pnet_is_pnetid_set(smcd_dev->pnetid)) {
memcpy(smcd_dev->pnetid, pnet_name, SMC_MAX_PNETID_LEN); memcpy(smcd_dev->pnetid, pnet_name, SMC_MAX_PNETID_LEN);
smcd_dev->pnetid_by_user = true; smcd_dev->pnetid_by_user = true;
applied = true; applied = true;
...@@ -708,10 +713,115 @@ static struct genl_family smc_pnet_nl_family __ro_after_init = { ...@@ -708,10 +713,115 @@ static struct genl_family smc_pnet_nl_family __ro_after_init = {
.n_ops = ARRAY_SIZE(smc_pnet_ops) .n_ops = ARRAY_SIZE(smc_pnet_ops)
}; };
bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid)
{
struct smc_net *sn = net_generic(net, smc_net_id);
struct smc_pnetids_ndev_entry *pe;
bool rc = false;
read_lock(&sn->pnetids_ndev.lock);
list_for_each_entry(pe, &sn->pnetids_ndev.list, list) {
if (smc_pnet_match(pnetid, pe->pnetid)) {
rc = true;
goto unlock;
}
}
unlock:
read_unlock(&sn->pnetids_ndev.lock);
return rc;
}
static int smc_pnet_add_pnetid(struct net *net, u8 *pnetid)
{
struct smc_net *sn = net_generic(net, smc_net_id);
struct smc_pnetids_ndev_entry *pe, *pi;
pe = kzalloc(sizeof(*pe), GFP_KERNEL);
if (!pe)
return -ENOMEM;
write_lock(&sn->pnetids_ndev.lock);
list_for_each_entry(pi, &sn->pnetids_ndev.list, list) {
if (smc_pnet_match(pnetid, pe->pnetid)) {
refcount_inc(&pi->refcnt);
kfree(pe);
goto unlock;
}
}
refcount_set(&pe->refcnt, 1);
memcpy(pe->pnetid, pnetid, SMC_MAX_PNETID_LEN);
list_add_tail(&pe->list, &sn->pnetids_ndev.list);
unlock:
write_unlock(&sn->pnetids_ndev.lock);
return 0;
}
static void smc_pnet_remove_pnetid(struct net *net, u8 *pnetid)
{
struct smc_net *sn = net_generic(net, smc_net_id);
struct smc_pnetids_ndev_entry *pe, *pe2;
write_lock(&sn->pnetids_ndev.lock);
list_for_each_entry_safe(pe, pe2, &sn->pnetids_ndev.list, list) {
if (smc_pnet_match(pnetid, pe->pnetid)) {
if (refcount_dec_and_test(&pe->refcnt)) {
list_del(&pe->list);
kfree(pe);
}
break;
}
}
write_unlock(&sn->pnetids_ndev.lock);
}
static void smc_pnet_add_base_pnetid(struct net *net, struct net_device *dev,
u8 *ndev_pnetid)
{
struct net_device *base_dev;
base_dev = __pnet_find_base_ndev(dev);
if (base_dev->flags & IFF_UP &&
!smc_pnetid_by_dev_port(base_dev->dev.parent, base_dev->dev_port,
ndev_pnetid)) {
/* add to PNETIDs list */
smc_pnet_add_pnetid(net, ndev_pnetid);
}
}
/* create initial list of netdevice pnetids */
static void smc_pnet_create_pnetids_list(struct net *net)
{
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
struct net_device *dev;
rtnl_lock();
for_each_netdev(net, dev)
smc_pnet_add_base_pnetid(net, dev, ndev_pnetid);
rtnl_unlock();
}
/* clean up list of netdevice pnetids */
static void smc_pnet_destroy_pnetids_list(struct net *net)
{
struct smc_net *sn = net_generic(net, smc_net_id);
struct smc_pnetids_ndev_entry *pe, *temp_pe;
write_lock(&sn->pnetids_ndev.lock);
list_for_each_entry_safe(pe, temp_pe, &sn->pnetids_ndev.list, list) {
list_del(&pe->list);
kfree(pe);
}
write_unlock(&sn->pnetids_ndev.lock);
}
static int smc_pnet_netdev_event(struct notifier_block *this, static int smc_pnet_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
struct net *net = dev_net(event_dev);
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
switch (event) { switch (event) {
case NETDEV_REBOOT: case NETDEV_REBOOT:
...@@ -721,6 +831,17 @@ static int smc_pnet_netdev_event(struct notifier_block *this, ...@@ -721,6 +831,17 @@ static int smc_pnet_netdev_event(struct notifier_block *this,
case NETDEV_REGISTER: case NETDEV_REGISTER:
smc_pnet_add_by_ndev(event_dev); smc_pnet_add_by_ndev(event_dev);
return NOTIFY_OK; return NOTIFY_OK;
case NETDEV_UP:
smc_pnet_add_base_pnetid(net, event_dev, ndev_pnetid);
return NOTIFY_OK;
case NETDEV_DOWN:
event_dev = __pnet_find_base_ndev(event_dev);
if (!smc_pnetid_by_dev_port(event_dev->dev.parent,
event_dev->dev_port, ndev_pnetid)) {
/* remove from PNETIDs list */
smc_pnet_remove_pnetid(net, ndev_pnetid);
}
return NOTIFY_OK;
default: default:
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -735,9 +856,14 @@ int smc_pnet_net_init(struct net *net) ...@@ -735,9 +856,14 @@ int smc_pnet_net_init(struct net *net)
{ {
struct smc_net *sn = net_generic(net, smc_net_id); struct smc_net *sn = net_generic(net, smc_net_id);
struct smc_pnettable *pnettable = &sn->pnettable; struct smc_pnettable *pnettable = &sn->pnettable;
struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev;
INIT_LIST_HEAD(&pnettable->pnetlist); INIT_LIST_HEAD(&pnettable->pnetlist);
rwlock_init(&pnettable->lock); rwlock_init(&pnettable->lock);
INIT_LIST_HEAD(&pnetids_ndev->list);
rwlock_init(&pnetids_ndev->lock);
smc_pnet_create_pnetids_list(net);
return 0; return 0;
} }
...@@ -752,6 +878,7 @@ int __init smc_pnet_init(void) ...@@ -752,6 +878,7 @@ int __init smc_pnet_init(void)
rc = register_netdevice_notifier(&smc_netdev_notifier); rc = register_netdevice_notifier(&smc_netdev_notifier);
if (rc) if (rc)
genl_unregister_family(&smc_pnet_nl_family); genl_unregister_family(&smc_pnet_nl_family);
return rc; return rc;
} }
...@@ -760,6 +887,7 @@ void smc_pnet_net_exit(struct net *net) ...@@ -760,6 +887,7 @@ void smc_pnet_net_exit(struct net *net)
{ {
/* flush pnet table */ /* flush pnet table */
smc_pnet_remove_by_pnetid(net, NULL); smc_pnet_remove_by_pnetid(net, NULL);
smc_pnet_destroy_pnetids_list(net);
} }
void smc_pnet_exit(void) void smc_pnet_exit(void)
...@@ -768,16 +896,11 @@ void smc_pnet_exit(void) ...@@ -768,16 +896,11 @@ void smc_pnet_exit(void)
genl_unregister_family(&smc_pnet_nl_family); genl_unregister_family(&smc_pnet_nl_family);
} }
/* Determine one base device for stacked net devices. static struct net_device *__pnet_find_base_ndev(struct net_device *ndev)
* If the lower device level contains more than one devices
* (for instance with bonding slaves), just the first device
* is used to reach a base device.
*/
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
{ {
int i, nest_lvl; int i, nest_lvl;
rtnl_lock(); ASSERT_RTNL();
nest_lvl = ndev->lower_level; nest_lvl = ndev->lower_level;
for (i = 0; i < nest_lvl; i++) { for (i = 0; i < nest_lvl; i++) {
struct list_head *lower = &ndev->adj_list.lower; struct list_head *lower = &ndev->adj_list.lower;
...@@ -787,6 +910,18 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev) ...@@ -787,6 +910,18 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
lower = lower->next; lower = lower->next;
ndev = netdev_lower_get_next(ndev, &lower); ndev = netdev_lower_get_next(ndev, &lower);
} }
return ndev;
}
/* Determine one base device for stacked net devices.
* If the lower device level contains more than one devices
* (for instance with bonding slaves), just the first device
* is used to reach a base device.
*/
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
{
rtnl_lock();
ndev = __pnet_find_base_ndev(ndev);
rtnl_unlock(); rtnl_unlock();
return ndev; return ndev;
} }
...@@ -929,10 +1064,10 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev, ...@@ -929,10 +1064,10 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
list_for_each_entry(ismdev, &smcd_dev_list.list, list) { list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) && if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) &&
!ismdev->going_away && !ismdev->going_away &&
(!ini->ism_peer_gid || (!ini->ism_peer_gid[0] ||
!smc_ism_cantalk(ini->ism_peer_gid, ini->vlan_id, !smc_ism_cantalk(ini->ism_peer_gid[0], ini->vlan_id,
ismdev))) { ismdev))) {
ini->ism_dev = ismdev; ini->ism_dev[0] = ismdev;
break; break;
} }
} }
...@@ -966,7 +1101,7 @@ void smc_pnet_find_ism_resource(struct sock *sk, struct smc_init_info *ini) ...@@ -966,7 +1101,7 @@ void smc_pnet_find_ism_resource(struct sock *sk, struct smc_init_info *ini)
{ {
struct dst_entry *dst = sk_dst_get(sk); struct dst_entry *dst = sk_dst_get(sk);
ini->ism_dev = NULL; ini->ism_dev[0] = NULL;
if (!dst) if (!dst)
goto out; goto out;
if (!dst->dev) if (!dst->dev)
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#ifndef _SMC_PNET_H #ifndef _SMC_PNET_H
#define _SMC_PNET_H #define _SMC_PNET_H
#include <net/smc.h>
#if IS_ENABLED(CONFIG_HAVE_PNETID) #if IS_ENABLED(CONFIG_HAVE_PNETID)
#include <asm/pnet.h> #include <asm/pnet.h>
#endif #endif
...@@ -31,6 +33,17 @@ struct smc_pnettable { ...@@ -31,6 +33,17 @@ struct smc_pnettable {
struct list_head pnetlist; struct list_head pnetlist;
}; };
struct smc_pnetids_ndev { /* list of pnetids for net devices in UP state*/
struct list_head list;
rwlock_t lock;
};
struct smc_pnetids_ndev_entry {
struct list_head list;
u8 pnetid[SMC_MAX_PNETID_LEN];
refcount_t refcnt;
};
static inline int smc_pnetid_by_dev_port(struct device *dev, static inline int smc_pnetid_by_dev_port(struct device *dev,
unsigned short port, u8 *pnetid) unsigned short port, u8 *pnetid)
{ {
...@@ -52,4 +65,6 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcd); ...@@ -52,4 +65,6 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcd);
void smc_pnet_find_alt_roce(struct smc_link_group *lgr, void smc_pnet_find_alt_roce(struct smc_link_group *lgr,
struct smc_init_info *ini, struct smc_init_info *ini,
struct smc_ib_device *known_dev); struct smc_ib_device *known_dev);
bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid);
bool smc_pnet_is_pnetid_set(u8 *pnetid);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment