2323#include <linux/workqueue.h>
2424#include <linux/in.h>
2525#include <linux/sched/signal.h>
26+ #include <linux/if_vlan.h>
2627
2728#include <net/sock.h>
2829#include <net/tcp.h>
3536#include "smc_cdc.h"
3637#include "smc_core.h"
3738#include "smc_ib.h"
39+ #include "smc_ism.h"
3840#include "smc_pnet.h"
3941#include "smc_tx.h"
4042#include "smc_rx.h"
@@ -372,8 +374,8 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc)
372374 return 0 ;
373375}
374376
375- static void smc_conn_save_peer_info (struct smc_sock * smc ,
376- struct smc_clc_msg_accept_confirm * clc )
377+ static void smcr_conn_save_peer_info (struct smc_sock * smc ,
378+ struct smc_clc_msg_accept_confirm * clc )
377379{
378380 int bufsize = smc_uncompress_bufsize (clc -> rmbe_size );
379381
@@ -384,6 +386,28 @@ static void smc_conn_save_peer_info(struct smc_sock *smc,
384386 smc -> conn .tx_off = bufsize * (smc -> conn .peer_rmbe_idx - 1 );
385387}
386388
389+ static void smcd_conn_save_peer_info (struct smc_sock * smc ,
390+ struct smc_clc_msg_accept_confirm * clc )
391+ {
392+ int bufsize = smc_uncompress_bufsize (clc -> dmbe_size );
393+
394+ smc -> conn .peer_rmbe_idx = clc -> dmbe_idx ;
395+ smc -> conn .peer_token = clc -> token ;
396+ /* msg header takes up space in the buffer */
397+ smc -> conn .peer_rmbe_size = bufsize - sizeof (struct smcd_cdc_msg );
398+ atomic_set (& smc -> conn .peer_rmbe_space , smc -> conn .peer_rmbe_size );
399+ smc -> conn .tx_off = bufsize * smc -> conn .peer_rmbe_idx ;
400+ }
401+
402+ static void smc_conn_save_peer_info (struct smc_sock * smc ,
403+ struct smc_clc_msg_accept_confirm * clc )
404+ {
405+ if (smc -> conn .lgr -> is_smcd )
406+ smcd_conn_save_peer_info (smc , clc );
407+ else
408+ smcr_conn_save_peer_info (smc , clc );
409+ }
410+
387411static void smc_link_save_peer_info (struct smc_link * link ,
388412 struct smc_clc_msg_accept_confirm * clc )
389413{
@@ -450,15 +474,51 @@ static int smc_check_rdma(struct smc_sock *smc, struct smc_ib_device **ibdev,
450474 return reason_code ;
451475}
452476
477+ /* check if there is an ISM device available for this connection. */
478+ /* called for connect and listen */
479+ static int smc_check_ism (struct smc_sock * smc , struct smcd_dev * * ismdev )
480+ {
481+ /* Find ISM device with same PNETID as connecting interface */
482+ smc_pnet_find_ism_resource (smc -> clcsock -> sk , ismdev );
483+ if (!(* ismdev ))
484+ return SMC_CLC_DECL_CNFERR ; /* configuration error */
485+ return 0 ;
486+ }
487+
488+ /* Check for VLAN ID and register it on ISM device just for CLC handshake */
489+ static int smc_connect_ism_vlan_setup (struct smc_sock * smc ,
490+ struct smcd_dev * ismdev ,
491+ unsigned short vlan_id )
492+ {
493+ if (vlan_id && smc_ism_get_vlan (ismdev , vlan_id ))
494+ return SMC_CLC_DECL_CNFERR ;
495+ return 0 ;
496+ }
497+
498+ /* cleanup temporary VLAN ID registration used for CLC handshake. If ISM is
499+ * used, the VLAN ID will be registered again during the connection setup.
500+ */
501+ static int smc_connect_ism_vlan_cleanup (struct smc_sock * smc , bool is_smcd ,
502+ struct smcd_dev * ismdev ,
503+ unsigned short vlan_id )
504+ {
505+ if (!is_smcd )
506+ return 0 ;
507+ if (vlan_id && smc_ism_put_vlan (ismdev , vlan_id ))
508+ return SMC_CLC_DECL_CNFERR ;
509+ return 0 ;
510+ }
511+
453512/* CLC handshake during connect */
454513static int smc_connect_clc (struct smc_sock * smc , int smc_type ,
455514 struct smc_clc_msg_accept_confirm * aclc ,
456- struct smc_ib_device * ibdev , u8 ibport )
515+ struct smc_ib_device * ibdev , u8 ibport ,
516+ struct smcd_dev * ismdev )
457517{
458518 int rc = 0 ;
459519
460520 /* do inband token exchange */
461- rc = smc_clc_send_proposal (smc , smc_type , ibdev , ibport , NULL );
521+ rc = smc_clc_send_proposal (smc , smc_type , ibdev , ibport , ismdev );
462522 if (rc )
463523 return rc ;
464524 /* receive SMC Accept CLC message */
@@ -538,11 +598,50 @@ static int smc_connect_rdma(struct smc_sock *smc,
538598 return 0 ;
539599}
540600
601+ /* setup for ISM connection of client */
602+ static int smc_connect_ism (struct smc_sock * smc ,
603+ struct smc_clc_msg_accept_confirm * aclc ,
604+ struct smcd_dev * ismdev )
605+ {
606+ int local_contact = SMC_FIRST_CONTACT ;
607+ int rc = 0 ;
608+
609+ mutex_lock (& smc_create_lgr_pending );
610+ local_contact = smc_conn_create (smc , true, aclc -> hdr .flag , NULL , 0 ,
611+ NULL , ismdev , aclc -> gid );
612+ if (local_contact < 0 )
613+ return smc_connect_abort (smc , SMC_CLC_DECL_MEM , 0 );
614+
615+ /* Create send and receive buffers */
616+ if (smc_buf_create (smc , true))
617+ return smc_connect_abort (smc , SMC_CLC_DECL_MEM , local_contact );
618+
619+ smc_conn_save_peer_info (smc , aclc );
620+ smc_close_init (smc );
621+ smc_rx_init (smc );
622+ smc_tx_init (smc );
623+
624+ rc = smc_clc_send_confirm (smc );
625+ if (rc )
626+ return smc_connect_abort (smc , rc , local_contact );
627+ mutex_unlock (& smc_create_lgr_pending );
628+
629+ smc_copy_sock_settings_to_clc (smc );
630+ if (smc -> sk .sk_state == SMC_INIT )
631+ smc -> sk .sk_state = SMC_ACTIVE ;
632+
633+ return 0 ;
634+ }
635+
541636/* perform steps before actually connecting */
542637static int __smc_connect (struct smc_sock * smc )
543638{
639+ bool ism_supported = false, rdma_supported = false;
544640 struct smc_clc_msg_accept_confirm aclc ;
545641 struct smc_ib_device * ibdev ;
642+ struct smcd_dev * ismdev ;
643+ unsigned short vlan ;
644+ int smc_type ;
546645 int rc = 0 ;
547646 u8 ibport ;
548647
@@ -559,20 +658,52 @@ static int __smc_connect(struct smc_sock *smc)
559658 if (using_ipsec (smc ))
560659 return smc_connect_decline_fallback (smc , SMC_CLC_DECL_IPSEC );
561660
562- /* check if a RDMA device is available; if not, fall back */
563- if (smc_check_rdma (smc , & ibdev , & ibport ))
661+ /* check for VLAN ID */
662+ if (smc_vlan_by_tcpsk (smc -> clcsock , & vlan ))
663+ return smc_connect_decline_fallback (smc , SMC_CLC_DECL_CNFERR );
664+
665+ /* check if there is an ism device available */
666+ if (!smc_check_ism (smc , & ismdev ) &&
667+ !smc_connect_ism_vlan_setup (smc , ismdev , vlan )) {
668+ /* ISM is supported for this connection */
669+ ism_supported = true;
670+ smc_type = SMC_TYPE_D ;
671+ }
672+
673+ /* check if there is a rdma device available */
674+ if (!smc_check_rdma (smc , & ibdev , & ibport )) {
675+ /* RDMA is supported for this connection */
676+ rdma_supported = true;
677+ if (ism_supported )
678+ smc_type = SMC_TYPE_B ; /* both */
679+ else
680+ smc_type = SMC_TYPE_R ; /* only RDMA */
681+ }
682+
683+ /* if neither ISM nor RDMA are supported, fallback */
684+ if (!rdma_supported && !ism_supported )
564685 return smc_connect_decline_fallback (smc , SMC_CLC_DECL_CNFERR );
565686
566687 /* perform CLC handshake */
567- rc = smc_connect_clc (smc , SMC_TYPE_R , & aclc , ibdev , ibport );
568- if (rc )
688+ rc = smc_connect_clc (smc , smc_type , & aclc , ibdev , ibport , ismdev );
689+ if (rc ) {
690+ smc_connect_ism_vlan_cleanup (smc , ism_supported , ismdev , vlan );
569691 return smc_connect_decline_fallback (smc , rc );
692+ }
570693
571- /* connect using rdma */
572- rc = smc_connect_rdma (smc , & aclc , ibdev , ibport );
573- if (rc )
694+ /* depending on previous steps, connect using rdma or ism */
695+ if (rdma_supported && aclc .hdr .path == SMC_TYPE_R )
696+ rc = smc_connect_rdma (smc , & aclc , ibdev , ibport );
697+ else if (ism_supported && aclc .hdr .path == SMC_TYPE_D )
698+ rc = smc_connect_ism (smc , & aclc , ismdev );
699+ else
700+ rc = SMC_CLC_DECL_CNFERR ;
701+ if (rc ) {
702+ smc_connect_ism_vlan_cleanup (smc , ism_supported , ismdev , vlan );
574703 return smc_connect_decline_fallback (smc , rc );
704+ }
575705
706+ smc_connect_ism_vlan_cleanup (smc , ism_supported , ismdev , vlan );
576707 return 0 ;
577708}
578709
@@ -909,6 +1040,44 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
9091040 return 0 ;
9101041}
9111042
1043+ /* listen worker: initialize connection and buffers for SMC-D */
1044+ static int smc_listen_ism_init (struct smc_sock * new_smc ,
1045+ struct smc_clc_msg_proposal * pclc ,
1046+ struct smcd_dev * ismdev ,
1047+ int * local_contact )
1048+ {
1049+ struct smc_clc_msg_smcd * pclc_smcd ;
1050+
1051+ pclc_smcd = smc_get_clc_msg_smcd (pclc );
1052+ * local_contact = smc_conn_create (new_smc , true, 0 , NULL , 0 , NULL ,
1053+ ismdev , pclc_smcd -> gid );
1054+ if (* local_contact < 0 ) {
1055+ if (* local_contact == - ENOMEM )
1056+ return SMC_CLC_DECL_MEM ;/* insufficient memory*/
1057+ return SMC_CLC_DECL_INTERR ; /* other error */
1058+ }
1059+
1060+ /* Check if peer can be reached via ISM device */
1061+ if (smc_ism_cantalk (new_smc -> conn .lgr -> peer_gid ,
1062+ new_smc -> conn .lgr -> vlan_id ,
1063+ new_smc -> conn .lgr -> smcd )) {
1064+ if (* local_contact == SMC_FIRST_CONTACT )
1065+ smc_lgr_forget (new_smc -> conn .lgr );
1066+ smc_conn_free (& new_smc -> conn );
1067+ return SMC_CLC_DECL_CNFERR ;
1068+ }
1069+
1070+ /* Create send and receive buffers */
1071+ if (smc_buf_create (new_smc , true)) {
1072+ if (* local_contact == SMC_FIRST_CONTACT )
1073+ smc_lgr_forget (new_smc -> conn .lgr );
1074+ smc_conn_free (& new_smc -> conn );
1075+ return SMC_CLC_DECL_MEM ;
1076+ }
1077+
1078+ return 0 ;
1079+ }
1080+
9121081/* listen worker: register buffers */
9131082static int smc_listen_rdma_reg (struct smc_sock * new_smc , int local_contact )
9141083{
@@ -967,6 +1136,8 @@ static void smc_listen_work(struct work_struct *work)
9671136 struct smc_clc_msg_accept_confirm cclc ;
9681137 struct smc_clc_msg_proposal * pclc ;
9691138 struct smc_ib_device * ibdev ;
1139+ bool ism_supported = false;
1140+ struct smcd_dev * ismdev ;
9701141 u8 buf [SMC_CLC_MAX_LEN ];
9711142 int local_contact = 0 ;
9721143 int reason_code = 0 ;
@@ -1007,13 +1178,21 @@ static void smc_listen_work(struct work_struct *work)
10071178 smc_rx_init (new_smc );
10081179 smc_tx_init (new_smc );
10091180
1181+ /* check if ISM is available */
1182+ if ((pclc -> hdr .path == SMC_TYPE_D || pclc -> hdr .path == SMC_TYPE_B ) &&
1183+ !smc_check_ism (new_smc , & ismdev ) &&
1184+ !smc_listen_ism_init (new_smc , pclc , ismdev , & local_contact )) {
1185+ ism_supported = true;
1186+ }
1187+
10101188 /* check if RDMA is available */
1011- if ((pclc -> hdr .path != SMC_TYPE_R && pclc -> hdr .path != SMC_TYPE_B ) ||
1012- smc_check_rdma (new_smc , & ibdev , & ibport ) ||
1013- smc_listen_rdma_check (new_smc , pclc ) ||
1014- smc_listen_rdma_init (new_smc , pclc , ibdev , ibport ,
1015- & local_contact ) ||
1016- smc_listen_rdma_reg (new_smc , local_contact )) {
1189+ if (!ism_supported &&
1190+ ((pclc -> hdr .path != SMC_TYPE_R && pclc -> hdr .path != SMC_TYPE_B ) ||
1191+ smc_check_rdma (new_smc , & ibdev , & ibport ) ||
1192+ smc_listen_rdma_check (new_smc , pclc ) ||
1193+ smc_listen_rdma_init (new_smc , pclc , ibdev , ibport ,
1194+ & local_contact ) ||
1195+ smc_listen_rdma_reg (new_smc , local_contact ))) {
10171196 /* SMC not supported, decline */
10181197 mutex_unlock (& smc_create_lgr_pending );
10191198 smc_listen_decline (new_smc , SMC_CLC_DECL_CNFERR , local_contact );
@@ -1038,7 +1217,8 @@ static void smc_listen_work(struct work_struct *work)
10381217 }
10391218
10401219 /* finish worker */
1041- smc_listen_rdma_finish (new_smc , & cclc , local_contact );
1220+ if (!ism_supported )
1221+ smc_listen_rdma_finish (new_smc , & cclc , local_contact );
10421222 smc_conn_save_peer_info (new_smc , & cclc );
10431223 mutex_unlock (& smc_create_lgr_pending );
10441224 smc_listen_out_connected (new_smc );
0 commit comments