aboutsummaryrefslogtreecommitdiffstats
path: root/net/smc
diff options
context:
space:
mode:
Diffstat (limited to 'net/smc')
-rw-r--r--net/smc/af_smc.c11
-rw-r--r--net/smc/smc_cdc.c26
-rw-r--r--net/smc/smc_cdc.h60
-rw-r--r--net/smc/smc_core.c20
-rw-r--r--net/smc/smc_core.h5
-rw-r--r--net/smc/smc_ism.c43
-rw-r--r--net/smc/smc_ism.h1
-rw-r--r--net/smc/smc_wr.c4
8 files changed, 120 insertions, 50 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 4b865250e238..63f08b4e51d6 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -127,6 +127,8 @@ static int smc_release(struct socket *sock)
127 smc = smc_sk(sk); 127 smc = smc_sk(sk);
128 128
129 /* cleanup for a dangling non-blocking connect */ 129 /* cleanup for a dangling non-blocking connect */
130 if (smc->connect_info && sk->sk_state == SMC_INIT)
131 tcp_abort(smc->clcsock->sk, ECONNABORTED);
130 flush_work(&smc->connect_work); 132 flush_work(&smc->connect_work);
131 kfree(smc->connect_info); 133 kfree(smc->connect_info);
132 smc->connect_info = NULL; 134 smc->connect_info = NULL;
@@ -551,7 +553,8 @@ static int smc_connect_rdma(struct smc_sock *smc,
551 553
552 mutex_lock(&smc_create_lgr_pending); 554 mutex_lock(&smc_create_lgr_pending);
553 local_contact = smc_conn_create(smc, false, aclc->hdr.flag, ibdev, 555 local_contact = smc_conn_create(smc, false, aclc->hdr.flag, ibdev,
554 ibport, &aclc->lcl, NULL, 0); 556 ibport, ntoh24(aclc->qpn), &aclc->lcl,
557 NULL, 0);
555 if (local_contact < 0) { 558 if (local_contact < 0) {
556 if (local_contact == -ENOMEM) 559 if (local_contact == -ENOMEM)
557 reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/ 560 reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/
@@ -621,7 +624,7 @@ static int smc_connect_ism(struct smc_sock *smc,
621 int rc = 0; 624 int rc = 0;
622 625
623 mutex_lock(&smc_create_lgr_pending); 626 mutex_lock(&smc_create_lgr_pending);
624 local_contact = smc_conn_create(smc, true, aclc->hdr.flag, NULL, 0, 627 local_contact = smc_conn_create(smc, true, aclc->hdr.flag, NULL, 0, 0,
625 NULL, ismdev, aclc->gid); 628 NULL, ismdev, aclc->gid);
626 if (local_contact < 0) 629 if (local_contact < 0)
627 return smc_connect_abort(smc, SMC_CLC_DECL_MEM, 0); 630 return smc_connect_abort(smc, SMC_CLC_DECL_MEM, 0);
@@ -1086,7 +1089,7 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
1086 int *local_contact) 1089 int *local_contact)
1087{ 1090{
1088 /* allocate connection / link group */ 1091 /* allocate connection / link group */
1089 *local_contact = smc_conn_create(new_smc, false, 0, ibdev, ibport, 1092 *local_contact = smc_conn_create(new_smc, false, 0, ibdev, ibport, 0,
1090 &pclc->lcl, NULL, 0); 1093 &pclc->lcl, NULL, 0);
1091 if (*local_contact < 0) { 1094 if (*local_contact < 0) {
1092 if (*local_contact == -ENOMEM) 1095 if (*local_contact == -ENOMEM)
@@ -1110,7 +1113,7 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
1110 struct smc_clc_msg_smcd *pclc_smcd; 1113 struct smc_clc_msg_smcd *pclc_smcd;
1111 1114
1112 pclc_smcd = smc_get_clc_msg_smcd(pclc); 1115 pclc_smcd = smc_get_clc_msg_smcd(pclc);
1113 *local_contact = smc_conn_create(new_smc, true, 0, NULL, 0, NULL, 1116 *local_contact = smc_conn_create(new_smc, true, 0, NULL, 0, 0, NULL,
1114 ismdev, pclc_smcd->gid); 1117 ismdev, pclc_smcd->gid);
1115 if (*local_contact < 0) { 1118 if (*local_contact < 0) {
1116 if (*local_contact == -ENOMEM) 1119 if (*local_contact == -ENOMEM)
diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c
index ed5dcf03fe0b..db83332ac1c8 100644
--- a/net/smc/smc_cdc.c
+++ b/net/smc/smc_cdc.c
@@ -81,7 +81,7 @@ static inline void smc_cdc_add_pending_send(struct smc_connection *conn,
81 sizeof(struct smc_cdc_msg) > SMC_WR_BUF_SIZE, 81 sizeof(struct smc_cdc_msg) > SMC_WR_BUF_SIZE,
82 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_cdc_msg)"); 82 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_cdc_msg)");
83 BUILD_BUG_ON_MSG( 83 BUILD_BUG_ON_MSG(
84 sizeof(struct smc_cdc_msg) != SMC_WR_TX_SIZE, 84 offsetofend(struct smc_cdc_msg, reserved) > SMC_WR_TX_SIZE,
85 "must adapt SMC_WR_TX_SIZE to sizeof(struct smc_cdc_msg); if not all smc_wr upper layer protocols use the same message size any more, must start to set link->wr_tx_sges[i].length on each individual smc_wr_tx_send()"); 85 "must adapt SMC_WR_TX_SIZE to sizeof(struct smc_cdc_msg); if not all smc_wr upper layer protocols use the same message size any more, must start to set link->wr_tx_sges[i].length on each individual smc_wr_tx_send()");
86 BUILD_BUG_ON_MSG( 86 BUILD_BUG_ON_MSG(
87 sizeof(struct smc_cdc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE, 87 sizeof(struct smc_cdc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
@@ -177,23 +177,24 @@ void smc_cdc_tx_dismiss_slots(struct smc_connection *conn)
177int smcd_cdc_msg_send(struct smc_connection *conn) 177int smcd_cdc_msg_send(struct smc_connection *conn)
178{ 178{
179 struct smc_sock *smc = container_of(conn, struct smc_sock, conn); 179 struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
180 union smc_host_cursor curs;
180 struct smcd_cdc_msg cdc; 181 struct smcd_cdc_msg cdc;
181 int rc, diff; 182 int rc, diff;
182 183
183 memset(&cdc, 0, sizeof(cdc)); 184 memset(&cdc, 0, sizeof(cdc));
184 cdc.common.type = SMC_CDC_MSG_TYPE; 185 cdc.common.type = SMC_CDC_MSG_TYPE;
185 cdc.prod_wrap = conn->local_tx_ctrl.prod.wrap; 186 curs.acurs.counter = atomic64_read(&conn->local_tx_ctrl.prod.acurs);
186 cdc.prod_count = conn->local_tx_ctrl.prod.count; 187 cdc.prod.wrap = curs.wrap;
187 188 cdc.prod.count = curs.count;
188 cdc.cons_wrap = conn->local_tx_ctrl.cons.wrap; 189 curs.acurs.counter = atomic64_read(&conn->local_tx_ctrl.cons.acurs);
189 cdc.cons_count = conn->local_tx_ctrl.cons.count; 190 cdc.cons.wrap = curs.wrap;
190 cdc.prod_flags = conn->local_tx_ctrl.prod_flags; 191 cdc.cons.count = curs.count;
191 cdc.conn_state_flags = conn->local_tx_ctrl.conn_state_flags; 192 cdc.cons.prod_flags = conn->local_tx_ctrl.prod_flags;
193 cdc.cons.conn_state_flags = conn->local_tx_ctrl.conn_state_flags;
192 rc = smcd_tx_ism_write(conn, &cdc, sizeof(cdc), 0, 1); 194 rc = smcd_tx_ism_write(conn, &cdc, sizeof(cdc), 0, 1);
193 if (rc) 195 if (rc)
194 return rc; 196 return rc;
195 smc_curs_copy(&conn->rx_curs_confirmed, &conn->local_tx_ctrl.cons, 197 smc_curs_copy(&conn->rx_curs_confirmed, &curs, conn);
196 conn);
197 /* Calculate transmitted data and increment free send buffer space */ 198 /* Calculate transmitted data and increment free send buffer space */
198 diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin, 199 diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin,
199 &conn->tx_curs_sent); 200 &conn->tx_curs_sent);
@@ -331,13 +332,16 @@ static void smc_cdc_msg_recv(struct smc_sock *smc, struct smc_cdc_msg *cdc)
331static void smcd_cdc_rx_tsklet(unsigned long data) 332static void smcd_cdc_rx_tsklet(unsigned long data)
332{ 333{
333 struct smc_connection *conn = (struct smc_connection *)data; 334 struct smc_connection *conn = (struct smc_connection *)data;
335 struct smcd_cdc_msg *data_cdc;
334 struct smcd_cdc_msg cdc; 336 struct smcd_cdc_msg cdc;
335 struct smc_sock *smc; 337 struct smc_sock *smc;
336 338
337 if (!conn) 339 if (!conn)
338 return; 340 return;
339 341
340 memcpy(&cdc, conn->rmb_desc->cpu_addr, sizeof(cdc)); 342 data_cdc = (struct smcd_cdc_msg *)conn->rmb_desc->cpu_addr;
343 smcd_curs_copy(&cdc.prod, &data_cdc->prod, conn);
344 smcd_curs_copy(&cdc.cons, &data_cdc->cons, conn);
341 smc = container_of(conn, struct smc_sock, conn); 345 smc = container_of(conn, struct smc_sock, conn);
342 smc_cdc_msg_recv(smc, (struct smc_cdc_msg *)&cdc); 346 smc_cdc_msg_recv(smc, (struct smc_cdc_msg *)&cdc);
343} 347}
diff --git a/net/smc/smc_cdc.h b/net/smc/smc_cdc.h
index 934df4473a7c..b5bfe38c7f9b 100644
--- a/net/smc/smc_cdc.h
+++ b/net/smc/smc_cdc.h
@@ -48,21 +48,31 @@ struct smc_cdc_msg {
48 struct smc_cdc_producer_flags prod_flags; 48 struct smc_cdc_producer_flags prod_flags;
49 struct smc_cdc_conn_state_flags conn_state_flags; 49 struct smc_cdc_conn_state_flags conn_state_flags;
50 u8 reserved[18]; 50 u8 reserved[18];
51} __packed; /* format defined in RFC7609 */ 51};
52
53/* SMC-D cursor format */
54union smcd_cdc_cursor {
55 struct {
56 u16 wrap;
57 u32 count;
58 struct smc_cdc_producer_flags prod_flags;
59 struct smc_cdc_conn_state_flags conn_state_flags;
60 } __packed;
61#ifdef KERNEL_HAS_ATOMIC64
62 atomic64_t acurs; /* for atomic processing */
63#else
64 u64 acurs; /* for atomic processing */
65#endif
66} __aligned(8);
52 67
53/* CDC message for SMC-D */ 68/* CDC message for SMC-D */
54struct smcd_cdc_msg { 69struct smcd_cdc_msg {
55 struct smc_wr_rx_hdr common; /* Type = 0xFE */ 70 struct smc_wr_rx_hdr common; /* Type = 0xFE */
56 u8 res1[7]; 71 u8 res1[7];
57 u16 prod_wrap; 72 union smcd_cdc_cursor prod;
58 u32 prod_count; 73 union smcd_cdc_cursor cons;
59 u8 res2[2];
60 u16 cons_wrap;
61 u32 cons_count;
62 struct smc_cdc_producer_flags prod_flags;
63 struct smc_cdc_conn_state_flags conn_state_flags;
64 u8 res3[8]; 74 u8 res3[8];
65} __packed; 75} __aligned(8);
66 76
67static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn) 77static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn)
68{ 78{
@@ -135,6 +145,21 @@ static inline void smc_curs_copy_net(union smc_cdc_cursor *tgt,
135#endif 145#endif
136} 146}
137 147
148static inline void smcd_curs_copy(union smcd_cdc_cursor *tgt,
149 union smcd_cdc_cursor *src,
150 struct smc_connection *conn)
151{
152#ifndef KERNEL_HAS_ATOMIC64
153 unsigned long flags;
154
155 spin_lock_irqsave(&conn->acurs_lock, flags);
156 tgt->acurs = src->acurs;
157 spin_unlock_irqrestore(&conn->acurs_lock, flags);
158#else
159 atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
160#endif
161}
162
138/* calculate cursor difference between old and new, where old <= new */ 163/* calculate cursor difference between old and new, where old <= new */
139static inline int smc_curs_diff(unsigned int size, 164static inline int smc_curs_diff(unsigned int size,
140 union smc_host_cursor *old, 165 union smc_host_cursor *old,
@@ -222,12 +247,17 @@ static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
222static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local, 247static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
223 struct smcd_cdc_msg *peer) 248 struct smcd_cdc_msg *peer)
224{ 249{
225 local->prod.wrap = peer->prod_wrap; 250 union smc_host_cursor temp;
226 local->prod.count = peer->prod_count; 251
227 local->cons.wrap = peer->cons_wrap; 252 temp.wrap = peer->prod.wrap;
228 local->cons.count = peer->cons_count; 253 temp.count = peer->prod.count;
229 local->prod_flags = peer->prod_flags; 254 atomic64_set(&local->prod.acurs, atomic64_read(&temp.acurs));
230 local->conn_state_flags = peer->conn_state_flags; 255
256 temp.wrap = peer->cons.wrap;
257 temp.count = peer->cons.count;
258 atomic64_set(&local->cons.acurs, atomic64_read(&temp.acurs));
259 local->prod_flags = peer->cons.prod_flags;
260 local->conn_state_flags = peer->cons.conn_state_flags;
231} 261}
232 262
233static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local, 263static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 1382ddae591e..35c1cdc93e1c 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -189,6 +189,8 @@ free:
189 189
190 if (!lgr->is_smcd && lnk->state != SMC_LNK_INACTIVE) 190 if (!lgr->is_smcd && lnk->state != SMC_LNK_INACTIVE)
191 smc_llc_link_inactive(lnk); 191 smc_llc_link_inactive(lnk);
192 if (lgr->is_smcd)
193 smc_ism_signal_shutdown(lgr);
192 smc_lgr_free(lgr); 194 smc_lgr_free(lgr);
193 } 195 }
194} 196}
@@ -495,7 +497,7 @@ void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport)
495} 497}
496 498
497/* Called when SMC-D device is terminated or peer is lost */ 499/* Called when SMC-D device is terminated or peer is lost */
498void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid) 500void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
499{ 501{
500 struct smc_link_group *lgr, *l; 502 struct smc_link_group *lgr, *l;
501 LIST_HEAD(lgr_free_list); 503 LIST_HEAD(lgr_free_list);
@@ -505,7 +507,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid)
505 list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) { 507 list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) {
506 if (lgr->is_smcd && lgr->smcd == dev && 508 if (lgr->is_smcd && lgr->smcd == dev &&
507 (!peer_gid || lgr->peer_gid == peer_gid) && 509 (!peer_gid || lgr->peer_gid == peer_gid) &&
508 !list_empty(&lgr->list)) { 510 (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
509 __smc_lgr_terminate(lgr); 511 __smc_lgr_terminate(lgr);
510 list_move(&lgr->list, &lgr_free_list); 512 list_move(&lgr->list, &lgr_free_list);
511 } 513 }
@@ -516,6 +518,8 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid)
516 list_for_each_entry_safe(lgr, l, &lgr_free_list, list) { 518 list_for_each_entry_safe(lgr, l, &lgr_free_list, list) {
517 list_del_init(&lgr->list); 519 list_del_init(&lgr->list);
518 cancel_delayed_work_sync(&lgr->free_work); 520 cancel_delayed_work_sync(&lgr->free_work);
521 if (!peer_gid && vlan == VLAN_VID_MASK) /* dev terminated? */
522 smc_ism_signal_shutdown(lgr);
519 smc_lgr_free(lgr); 523 smc_lgr_free(lgr);
520 } 524 }
521} 525}
@@ -569,7 +573,7 @@ out:
569 573
570static bool smcr_lgr_match(struct smc_link_group *lgr, 574static bool smcr_lgr_match(struct smc_link_group *lgr,
571 struct smc_clc_msg_local *lcl, 575 struct smc_clc_msg_local *lcl,
572 enum smc_lgr_role role) 576 enum smc_lgr_role role, u32 clcqpn)
573{ 577{
574 return !memcmp(lgr->peer_systemid, lcl->id_for_peer, 578 return !memcmp(lgr->peer_systemid, lcl->id_for_peer,
575 SMC_SYSTEMID_LEN) && 579 SMC_SYSTEMID_LEN) &&
@@ -577,7 +581,9 @@ static bool smcr_lgr_match(struct smc_link_group *lgr,
577 SMC_GID_SIZE) && 581 SMC_GID_SIZE) &&
578 !memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_mac, lcl->mac, 582 !memcmp(lgr->lnk[SMC_SINGLE_LINK].peer_mac, lcl->mac,
579 sizeof(lcl->mac)) && 583 sizeof(lcl->mac)) &&
580 lgr->role == role; 584 lgr->role == role &&
585 (lgr->role == SMC_SERV ||
586 lgr->lnk[SMC_SINGLE_LINK].peer_qpn == clcqpn);
581} 587}
582 588
583static bool smcd_lgr_match(struct smc_link_group *lgr, 589static bool smcd_lgr_match(struct smc_link_group *lgr,
@@ -588,7 +594,7 @@ static bool smcd_lgr_match(struct smc_link_group *lgr,
588 594
589/* create a new SMC connection (and a new link group if necessary) */ 595/* create a new SMC connection (and a new link group if necessary) */
590int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact, 596int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
591 struct smc_ib_device *smcibdev, u8 ibport, 597 struct smc_ib_device *smcibdev, u8 ibport, u32 clcqpn,
592 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd, 598 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
593 u64 peer_gid) 599 u64 peer_gid)
594{ 600{
@@ -613,7 +619,7 @@ int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
613 list_for_each_entry(lgr, &smc_lgr_list.list, list) { 619 list_for_each_entry(lgr, &smc_lgr_list.list, list) {
614 write_lock_bh(&lgr->conns_lock); 620 write_lock_bh(&lgr->conns_lock);
615 if ((is_smcd ? smcd_lgr_match(lgr, smcd, peer_gid) : 621 if ((is_smcd ? smcd_lgr_match(lgr, smcd, peer_gid) :
616 smcr_lgr_match(lgr, lcl, role)) && 622 smcr_lgr_match(lgr, lcl, role, clcqpn)) &&
617 !lgr->sync_err && 623 !lgr->sync_err &&
618 lgr->vlan_id == vlan_id && 624 lgr->vlan_id == vlan_id &&
619 (role == SMC_CLNT || 625 (role == SMC_CLNT ||
@@ -1034,6 +1040,8 @@ void smc_core_exit(void)
1034 smc_llc_link_inactive(lnk); 1040 smc_llc_link_inactive(lnk);
1035 } 1041 }
1036 cancel_delayed_work_sync(&lgr->free_work); 1042 cancel_delayed_work_sync(&lgr->free_work);
1043 if (lgr->is_smcd)
1044 smc_ism_signal_shutdown(lgr);
1037 smc_lgr_free(lgr); /* free link group */ 1045 smc_lgr_free(lgr); /* free link group */
1038 } 1046 }
1039} 1047}
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
index e177c6675038..b00287989a3d 100644
--- a/net/smc/smc_core.h
+++ b/net/smc/smc_core.h
@@ -249,7 +249,8 @@ struct smc_clc_msg_local;
249void smc_lgr_forget(struct smc_link_group *lgr); 249void smc_lgr_forget(struct smc_link_group *lgr);
250void smc_lgr_terminate(struct smc_link_group *lgr); 250void smc_lgr_terminate(struct smc_link_group *lgr);
251void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport); 251void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport);
252void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid); 252void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
253 unsigned short vlan);
253int smc_buf_create(struct smc_sock *smc, bool is_smcd); 254int smc_buf_create(struct smc_sock *smc, bool is_smcd);
254int smc_uncompress_bufsize(u8 compressed); 255int smc_uncompress_bufsize(u8 compressed);
255int smc_rmb_rtoken_handling(struct smc_connection *conn, 256int smc_rmb_rtoken_handling(struct smc_connection *conn,
@@ -264,7 +265,7 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id);
264 265
265void smc_conn_free(struct smc_connection *conn); 266void smc_conn_free(struct smc_connection *conn);
266int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact, 267int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
267 struct smc_ib_device *smcibdev, u8 ibport, 268 struct smc_ib_device *smcibdev, u8 ibport, u32 clcqpn,
268 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd, 269 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
269 u64 peer_gid); 270 u64 peer_gid);
270void smcd_conn_free(struct smc_connection *conn); 271void smcd_conn_free(struct smc_connection *conn);
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index e36f21ce7252..2fff79db1a59 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -187,22 +187,28 @@ struct smc_ism_event_work {
187#define ISM_EVENT_REQUEST 0x0001 187#define ISM_EVENT_REQUEST 0x0001
188#define ISM_EVENT_RESPONSE 0x0002 188#define ISM_EVENT_RESPONSE 0x0002
189#define ISM_EVENT_REQUEST_IR 0x00000001 189#define ISM_EVENT_REQUEST_IR 0x00000001
190#define ISM_EVENT_CODE_SHUTDOWN 0x80
190#define ISM_EVENT_CODE_TESTLINK 0x83 191#define ISM_EVENT_CODE_TESTLINK 0x83
191 192
193union smcd_sw_event_info {
194 u64 info;
195 struct {
196 u8 uid[SMC_LGR_ID_SIZE];
197 unsigned short vlan_id;
198 u16 code;
199 };
200};
201
192static void smcd_handle_sw_event(struct smc_ism_event_work *wrk) 202static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
193{ 203{
194 union { 204 union smcd_sw_event_info ev_info;
195 u64 info;
196 struct {
197 u32 uid;
198 unsigned short vlanid;
199 u16 code;
200 };
201 } ev_info;
202 205
206 ev_info.info = wrk->event.info;
203 switch (wrk->event.code) { 207 switch (wrk->event.code) {
208 case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */
209 smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id);
210 break;
204 case ISM_EVENT_CODE_TESTLINK: /* Activity timer */ 211 case ISM_EVENT_CODE_TESTLINK: /* Activity timer */
205 ev_info.info = wrk->event.info;
206 if (ev_info.code == ISM_EVENT_REQUEST) { 212 if (ev_info.code == ISM_EVENT_REQUEST) {
207 ev_info.code = ISM_EVENT_RESPONSE; 213 ev_info.code = ISM_EVENT_RESPONSE;
208 wrk->smcd->ops->signal_event(wrk->smcd, 214 wrk->smcd->ops->signal_event(wrk->smcd,
@@ -215,6 +221,21 @@ static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
215 } 221 }
216} 222}
217 223
224int smc_ism_signal_shutdown(struct smc_link_group *lgr)
225{
226 int rc;
227 union smcd_sw_event_info ev_info;
228
229 memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
230 ev_info.vlan_id = lgr->vlan_id;
231 ev_info.code = ISM_EVENT_REQUEST;
232 rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
233 ISM_EVENT_REQUEST_IR,
234 ISM_EVENT_CODE_SHUTDOWN,
235 ev_info.info);
236 return rc;
237}
238
218/* worker for SMC-D events */ 239/* worker for SMC-D events */
219static void smc_ism_event_work(struct work_struct *work) 240static void smc_ism_event_work(struct work_struct *work)
220{ 241{
@@ -223,7 +244,7 @@ static void smc_ism_event_work(struct work_struct *work)
223 244
224 switch (wrk->event.type) { 245 switch (wrk->event.type) {
225 case ISM_EVENT_GID: /* GID event, token is peer GID */ 246 case ISM_EVENT_GID: /* GID event, token is peer GID */
226 smc_smcd_terminate(wrk->smcd, wrk->event.tok); 247 smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK);
227 break; 248 break;
228 case ISM_EVENT_DMB: 249 case ISM_EVENT_DMB:
229 break; 250 break;
@@ -289,7 +310,7 @@ void smcd_unregister_dev(struct smcd_dev *smcd)
289 spin_unlock(&smcd_dev_list.lock); 310 spin_unlock(&smcd_dev_list.lock);
290 flush_workqueue(smcd->event_wq); 311 flush_workqueue(smcd->event_wq);
291 destroy_workqueue(smcd->event_wq); 312 destroy_workqueue(smcd->event_wq);
292 smc_smcd_terminate(smcd, 0); 313 smc_smcd_terminate(smcd, 0, VLAN_VID_MASK);
293 314
294 device_del(&smcd->dev); 315 device_del(&smcd->dev);
295} 316}
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index aee45b860b79..4da946cbfa29 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -45,4 +45,5 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int buf_size,
45int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc); 45int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc);
46int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos, 46int smc_ism_write(struct smcd_dev *dev, const struct smc_ism_position *pos,
47 void *data, size_t len); 47 void *data, size_t len);
48int smc_ism_signal_shutdown(struct smc_link_group *lgr);
48#endif 49#endif
diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
index 3c458d279855..c2694750a6a8 100644
--- a/net/smc/smc_wr.c
+++ b/net/smc/smc_wr.c
@@ -215,12 +215,14 @@ int smc_wr_tx_put_slot(struct smc_link *link,
215 215
216 pend = container_of(wr_pend_priv, struct smc_wr_tx_pend, priv); 216 pend = container_of(wr_pend_priv, struct smc_wr_tx_pend, priv);
217 if (pend->idx < link->wr_tx_cnt) { 217 if (pend->idx < link->wr_tx_cnt) {
218 u32 idx = pend->idx;
219
218 /* clear the full struct smc_wr_tx_pend including .priv */ 220 /* clear the full struct smc_wr_tx_pend including .priv */
219 memset(&link->wr_tx_pends[pend->idx], 0, 221 memset(&link->wr_tx_pends[pend->idx], 0,
220 sizeof(link->wr_tx_pends[pend->idx])); 222 sizeof(link->wr_tx_pends[pend->idx]));
221 memset(&link->wr_tx_bufs[pend->idx], 0, 223 memset(&link->wr_tx_bufs[pend->idx], 0,
222 sizeof(link->wr_tx_bufs[pend->idx])); 224 sizeof(link->wr_tx_bufs[pend->idx]));
223 test_and_clear_bit(pend->idx, link->wr_tx_mask); 225 test_and_clear_bit(idx, link->wr_tx_mask);
224 return 1; 226 return 1;
225 } 227 }
226 228