1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 25f08318fSUrsula Braun /* 35f08318fSUrsula Braun * Shared Memory Communications over RDMA (SMC-R) and RoCE 45f08318fSUrsula Braun * 55f08318fSUrsula Braun * Connection Data Control (CDC) 65f08318fSUrsula Braun * handles flow control 75f08318fSUrsula Braun * 85f08318fSUrsula Braun * Copyright IBM Corp. 2016 95f08318fSUrsula Braun * 105f08318fSUrsula Braun * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 115f08318fSUrsula Braun */ 125f08318fSUrsula Braun 135f08318fSUrsula Braun #include <linux/spinlock.h> 145f08318fSUrsula Braun 155f08318fSUrsula Braun #include "smc.h" 165f08318fSUrsula Braun #include "smc_wr.h" 175f08318fSUrsula Braun #include "smc_cdc.h" 18e6727f39SUrsula Braun #include "smc_tx.h" 19952310ccSUrsula Braun #include "smc_rx.h" 20b38d7324SUrsula Braun #include "smc_close.h" 215f08318fSUrsula Braun 225f08318fSUrsula Braun /********************************** send *************************************/ 235f08318fSUrsula Braun 245f08318fSUrsula Braun /* handler for send/transmission completion of a CDC msg */ 255f08318fSUrsula Braun static void smc_cdc_tx_handler(struct smc_wr_tx_pend_priv *pnd_snd, 265f08318fSUrsula Braun struct smc_link *link, 275f08318fSUrsula Braun enum ib_wc_status wc_status) 285f08318fSUrsula Braun { 295f08318fSUrsula Braun struct smc_cdc_tx_pend *cdcpend = (struct smc_cdc_tx_pend *)pnd_snd; 30bac6de7bSStefan Raspl struct smc_connection *conn = cdcpend->conn; 315f08318fSUrsula Braun struct smc_sock *smc; 325f08318fSUrsula Braun int diff; 335f08318fSUrsula Braun 34bac6de7bSStefan Raspl smc = container_of(conn, struct smc_sock, conn); 355f08318fSUrsula Braun bh_lock_sock(&smc->sk); 365f08318fSUrsula Braun if (!wc_status) { 3769cb7dc0SHans Wippel diff = smc_curs_diff(cdcpend->conn->sndbuf_desc->len, 385f08318fSUrsula Braun &cdcpend->conn->tx_curs_fin, 395f08318fSUrsula Braun &cdcpend->cursor); 405f08318fSUrsula Braun /* sndbuf_space is decreased in smc_sendmsg */ 415f08318fSUrsula Braun smp_mb__before_atomic(); 425f08318fSUrsula Braun atomic_add(diff, &cdcpend->conn->sndbuf_space); 4369cb7dc0SHans Wippel /* guarantee 0 <= sndbuf_space <= sndbuf_desc->len */ 445f08318fSUrsula Braun smp_mb__after_atomic(); 45bac6de7bSStefan Raspl smc_curs_copy(&conn->tx_curs_fin, &cdcpend->cursor, conn); 46f0ec4f1dSKarsten Graul smc_curs_copy(&conn->local_tx_ctrl_fin, &cdcpend->p_cursor, 47f0ec4f1dSKarsten Graul conn); 48f0ec4f1dSKarsten Graul conn->tx_cdc_seq_fin = cdcpend->ctrl_seq; 495f08318fSUrsula Braun } 50349d4312SDust Li 51*dcd2cf5fSDust Li if (atomic_dec_and_test(&conn->cdc_pend_tx_wr)) { 52*dcd2cf5fSDust Li /* If this is the last pending WR complete, we must push to 53*dcd2cf5fSDust Li * prevent hang when autocork enabled. 54*dcd2cf5fSDust Li */ 55*dcd2cf5fSDust Li smc_tx_sndbuf_nonempty(conn); 56*dcd2cf5fSDust Li if (unlikely(wq_has_sleeper(&conn->cdc_pend_tx_wq))) 57349d4312SDust Li wake_up(&conn->cdc_pend_tx_wq); 58*dcd2cf5fSDust Li } 59349d4312SDust Li WARN_ON(atomic_read(&conn->cdc_pend_tx_wr) < 0); 60349d4312SDust Li 61e6727f39SUrsula Braun smc_tx_sndbuf_nonfull(smc); 625f08318fSUrsula Braun bh_unlock_sock(&smc->sk); 635f08318fSUrsula Braun } 645f08318fSUrsula Braun 6551957bc5SUrsula Braun int smc_cdc_get_free_slot(struct smc_connection *conn, 66c6f02ebeSKarsten Graul struct smc_link *link, 675f08318fSUrsula Braun struct smc_wr_buf **wr_buf, 68ad6f317fSUrsula Braun struct smc_rdma_wr **wr_rdma_buf, 695f08318fSUrsula Braun struct smc_cdc_tx_pend **pend) 705f08318fSUrsula Braun { 711a0a04c7SUrsula Braun int rc; 7251957bc5SUrsula Braun 731a0a04c7SUrsula Braun rc = smc_wr_tx_get_free_slot(link, smc_cdc_tx_handler, wr_buf, 74ad6f317fSUrsula Braun wr_rdma_buf, 755f08318fSUrsula Braun (struct smc_wr_tx_pend_priv **)pend); 762bced6aeSKarsten Graul if (conn->killed) { 771a0a04c7SUrsula Braun /* abnormal termination */ 782bced6aeSKarsten Graul if (!rc) 792bced6aeSKarsten Graul smc_wr_tx_put_slot(link, 802bced6aeSKarsten Graul (struct smc_wr_tx_pend_priv *)pend); 811a0a04c7SUrsula Braun rc = -EPIPE; 822bced6aeSKarsten Graul } 831a0a04c7SUrsula Braun return rc; 845f08318fSUrsula Braun } 855f08318fSUrsula Braun 865f08318fSUrsula Braun static inline void smc_cdc_add_pending_send(struct smc_connection *conn, 875f08318fSUrsula Braun struct smc_cdc_tx_pend *pend) 885f08318fSUrsula Braun { 895f08318fSUrsula Braun BUILD_BUG_ON_MSG( 905f08318fSUrsula Braun sizeof(struct smc_cdc_msg) > SMC_WR_BUF_SIZE, 915f08318fSUrsula Braun "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_cdc_msg)"); 925f08318fSUrsula Braun BUILD_BUG_ON_MSG( 93b9a22dd9SUrsula Braun offsetofend(struct smc_cdc_msg, reserved) > SMC_WR_TX_SIZE, 945f08318fSUrsula Braun "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()"); 955f08318fSUrsula Braun BUILD_BUG_ON_MSG( 965f08318fSUrsula Braun sizeof(struct smc_cdc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE, 975f08318fSUrsula Braun "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_cdc_tx_pend)"); 985f08318fSUrsula Braun pend->conn = conn; 995f08318fSUrsula Braun pend->cursor = conn->tx_curs_sent; 1005f08318fSUrsula Braun pend->p_cursor = conn->local_tx_ctrl.prod; 1015f08318fSUrsula Braun pend->ctrl_seq = conn->tx_cdc_seq; 1025f08318fSUrsula Braun } 1035f08318fSUrsula Braun 1045f08318fSUrsula Braun int smc_cdc_msg_send(struct smc_connection *conn, 1055f08318fSUrsula Braun struct smc_wr_buf *wr_buf, 1065f08318fSUrsula Braun struct smc_cdc_tx_pend *pend) 1075f08318fSUrsula Braun { 108387707fdSKarsten Graul struct smc_link *link = conn->lnk; 109b8649efaSUrsula Braun union smc_host_cursor cfed; 1105f08318fSUrsula Braun int rc; 1115f08318fSUrsula Braun 1125f08318fSUrsula Braun smc_cdc_add_pending_send(conn, pend); 1135f08318fSUrsula Braun 1145f08318fSUrsula Braun conn->tx_cdc_seq++; 1155f08318fSUrsula Braun conn->local_tx_ctrl.seqno = conn->tx_cdc_seq; 116ccc8ca9bSUrsula Braun smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf, conn, &cfed); 117349d4312SDust Li 118349d4312SDust Li atomic_inc(&conn->cdc_pend_tx_wr); 119349d4312SDust Li smp_mb__after_atomic(); /* Make sure cdc_pend_tx_wr added before post */ 120349d4312SDust Li 1215f08318fSUrsula Braun rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); 1224dff63c2SKarsten Graul if (!rc) { 123b8649efaSUrsula Braun smc_curs_copy(&conn->rx_curs_confirmed, &cfed, conn); 1244dff63c2SKarsten Graul conn->local_rx_ctrl.prod_flags.cons_curs_upd_req = 0; 125f0ec4f1dSKarsten Graul } else { 126f0ec4f1dSKarsten Graul conn->tx_cdc_seq--; 127f0ec4f1dSKarsten Graul conn->local_tx_ctrl.seqno = conn->tx_cdc_seq; 128349d4312SDust Li atomic_dec(&conn->cdc_pend_tx_wr); 1294dff63c2SKarsten Graul } 1305f08318fSUrsula Braun 1315f08318fSUrsula Braun return rc; 1325f08318fSUrsula Braun } 1335f08318fSUrsula Braun 13429bd73dbSKarsten Graul /* send a validation msg indicating the move of a conn to an other QP link */ 135b8ded9deSKarsten Graul int smcr_cdc_msg_send_validation(struct smc_connection *conn, 136b8ded9deSKarsten Graul struct smc_cdc_tx_pend *pend, 137b8ded9deSKarsten Graul struct smc_wr_buf *wr_buf) 13829bd73dbSKarsten Graul { 13929bd73dbSKarsten Graul struct smc_host_cdc_msg *local = &conn->local_tx_ctrl; 14029bd73dbSKarsten Graul struct smc_link *link = conn->lnk; 14129bd73dbSKarsten Graul struct smc_cdc_msg *peer; 14229bd73dbSKarsten Graul int rc; 14329bd73dbSKarsten Graul 14429bd73dbSKarsten Graul peer = (struct smc_cdc_msg *)wr_buf; 14529bd73dbSKarsten Graul peer->common.type = local->common.type; 14629bd73dbSKarsten Graul peer->len = local->len; 14729bd73dbSKarsten Graul peer->seqno = htons(conn->tx_cdc_seq_fin); /* seqno last compl. tx */ 14829bd73dbSKarsten Graul peer->token = htonl(local->token); 14929bd73dbSKarsten Graul peer->prod_flags.failover_validation = 1; 15029bd73dbSKarsten Graul 151349d4312SDust Li /* We need to set pend->conn here to make sure smc_cdc_tx_handler() 152349d4312SDust Li * can handle properly 153349d4312SDust Li */ 154349d4312SDust Li smc_cdc_add_pending_send(conn, pend); 155349d4312SDust Li 156349d4312SDust Li atomic_inc(&conn->cdc_pend_tx_wr); 157349d4312SDust Li smp_mb__after_atomic(); /* Make sure cdc_pend_tx_wr added before post */ 158349d4312SDust Li 15929bd73dbSKarsten Graul rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); 160349d4312SDust Li if (unlikely(rc)) 161349d4312SDust Li atomic_dec(&conn->cdc_pend_tx_wr); 162349d4312SDust Li 16329bd73dbSKarsten Graul return rc; 16429bd73dbSKarsten Graul } 16529bd73dbSKarsten Graul 166be244f28SHans Wippel static int smcr_cdc_get_slot_and_msg_send(struct smc_connection *conn) 1675f08318fSUrsula Braun { 1685f08318fSUrsula Braun struct smc_cdc_tx_pend *pend; 1695f08318fSUrsula Braun struct smc_wr_buf *wr_buf; 170c6f02ebeSKarsten Graul struct smc_link *link; 171c6f02ebeSKarsten Graul bool again = false; 1725f08318fSUrsula Braun int rc; 1735f08318fSUrsula Braun 174c6f02ebeSKarsten Graul again: 175c6f02ebeSKarsten Graul link = conn->lnk; 17695f7f3e7SKarsten Graul if (!smc_wr_tx_link_hold(link)) 17795f7f3e7SKarsten Graul return -ENOLINK; 178c6f02ebeSKarsten Graul rc = smc_cdc_get_free_slot(conn, link, &wr_buf, NULL, &pend); 1795f08318fSUrsula Braun if (rc) 18095f7f3e7SKarsten Graul goto put_out; 1815f08318fSUrsula Braun 1822dee25afSKarsten Graul spin_lock_bh(&conn->send_lock); 183c6f02ebeSKarsten Graul if (link != conn->lnk) { 184c6f02ebeSKarsten Graul /* link of connection changed, try again one time*/ 185c6f02ebeSKarsten Graul spin_unlock_bh(&conn->send_lock); 186c6f02ebeSKarsten Graul smc_wr_tx_put_slot(link, 187c6f02ebeSKarsten Graul (struct smc_wr_tx_pend_priv *)pend); 18895f7f3e7SKarsten Graul smc_wr_tx_link_put(link); 189c6f02ebeSKarsten Graul if (again) 190c6f02ebeSKarsten Graul return -ENOLINK; 191c6f02ebeSKarsten Graul again = true; 192c6f02ebeSKarsten Graul goto again; 193c6f02ebeSKarsten Graul } 1942dee25afSKarsten Graul rc = smc_cdc_msg_send(conn, wr_buf, pend); 1952dee25afSKarsten Graul spin_unlock_bh(&conn->send_lock); 19695f7f3e7SKarsten Graul put_out: 19795f7f3e7SKarsten Graul smc_wr_tx_link_put(link); 1982dee25afSKarsten Graul return rc; 1995f08318fSUrsula Braun } 2005f08318fSUrsula Braun 201be244f28SHans Wippel int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) 202be244f28SHans Wippel { 203be244f28SHans Wippel int rc; 204be244f28SHans Wippel 205ea89c6c0SWen Gu if (!smc_conn_lgr_valid(conn) || 206ea89c6c0SWen Gu (conn->lgr->is_smcd && conn->lgr->peer_shutdown)) 20750c6b20eSUrsula Braun return -EPIPE; 20850c6b20eSUrsula Braun 209be244f28SHans Wippel if (conn->lgr->is_smcd) { 210be244f28SHans Wippel spin_lock_bh(&conn->send_lock); 211be244f28SHans Wippel rc = smcd_cdc_msg_send(conn); 212be244f28SHans Wippel spin_unlock_bh(&conn->send_lock); 213be244f28SHans Wippel } else { 214be244f28SHans Wippel rc = smcr_cdc_get_slot_and_msg_send(conn); 215be244f28SHans Wippel } 216be244f28SHans Wippel 217be244f28SHans Wippel return rc; 218be244f28SHans Wippel } 219be244f28SHans Wippel 220349d4312SDust Li void smc_cdc_wait_pend_tx_wr(struct smc_connection *conn) 2215f08318fSUrsula Braun { 222349d4312SDust Li wait_event(conn->cdc_pend_tx_wq, !atomic_read(&conn->cdc_pend_tx_wr)); 2235f08318fSUrsula Braun } 2245f08318fSUrsula Braun 225be244f28SHans Wippel /* Send a SMC-D CDC header. 226be244f28SHans Wippel * This increments the free space available in our send buffer. 227be244f28SHans Wippel * Also update the confirmed receive buffer with what was sent to the peer. 228be244f28SHans Wippel */ 229be244f28SHans Wippel int smcd_cdc_msg_send(struct smc_connection *conn) 230be244f28SHans Wippel { 231be244f28SHans Wippel struct smc_sock *smc = container_of(conn, struct smc_sock, conn); 232b9a22dd9SUrsula Braun union smc_host_cursor curs; 233be244f28SHans Wippel struct smcd_cdc_msg cdc; 234be244f28SHans Wippel int rc, diff; 235be244f28SHans Wippel 236be244f28SHans Wippel memset(&cdc, 0, sizeof(cdc)); 237be244f28SHans Wippel cdc.common.type = SMC_CDC_MSG_TYPE; 238b9a22dd9SUrsula Braun curs.acurs.counter = atomic64_read(&conn->local_tx_ctrl.prod.acurs); 239b9a22dd9SUrsula Braun cdc.prod.wrap = curs.wrap; 240b9a22dd9SUrsula Braun cdc.prod.count = curs.count; 241b9a22dd9SUrsula Braun curs.acurs.counter = atomic64_read(&conn->local_tx_ctrl.cons.acurs); 242b9a22dd9SUrsula Braun cdc.cons.wrap = curs.wrap; 243b9a22dd9SUrsula Braun cdc.cons.count = curs.count; 244b9a22dd9SUrsula Braun cdc.cons.prod_flags = conn->local_tx_ctrl.prod_flags; 245b9a22dd9SUrsula Braun cdc.cons.conn_state_flags = conn->local_tx_ctrl.conn_state_flags; 246be244f28SHans Wippel rc = smcd_tx_ism_write(conn, &cdc, sizeof(cdc), 0, 1); 247be244f28SHans Wippel if (rc) 248be244f28SHans Wippel return rc; 249b9a22dd9SUrsula Braun smc_curs_copy(&conn->rx_curs_confirmed, &curs, conn); 2504dff63c2SKarsten Graul conn->local_rx_ctrl.prod_flags.cons_curs_upd_req = 0; 251be244f28SHans Wippel /* Calculate transmitted data and increment free send buffer space */ 252be244f28SHans Wippel diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin, 253be244f28SHans Wippel &conn->tx_curs_sent); 254be244f28SHans Wippel /* increased by confirmed number of bytes */ 255be244f28SHans Wippel smp_mb__before_atomic(); 256be244f28SHans Wippel atomic_add(diff, &conn->sndbuf_space); 257be244f28SHans Wippel /* guarantee 0 <= sndbuf_space <= sndbuf_desc->len */ 258be244f28SHans Wippel smp_mb__after_atomic(); 259bac6de7bSStefan Raspl smc_curs_copy(&conn->tx_curs_fin, &conn->tx_curs_sent, conn); 260be244f28SHans Wippel 261be244f28SHans Wippel smc_tx_sndbuf_nonfull(smc); 262be244f28SHans Wippel return rc; 263be244f28SHans Wippel } 264be244f28SHans Wippel 2655f08318fSUrsula Braun /********************************* receive ***********************************/ 2665f08318fSUrsula Braun 2675f08318fSUrsula Braun static inline bool smc_cdc_before(u16 seq1, u16 seq2) 2685f08318fSUrsula Braun { 2695f08318fSUrsula Braun return (s16)(seq1 - seq2) < 0; 2705f08318fSUrsula Braun } 2715f08318fSUrsula Braun 272de8474ebSStefan Raspl static void smc_cdc_handle_urg_data_arrival(struct smc_sock *smc, 273de8474ebSStefan Raspl int *diff_prod) 274de8474ebSStefan Raspl { 275de8474ebSStefan Raspl struct smc_connection *conn = &smc->conn; 276de8474ebSStefan Raspl char *base; 277de8474ebSStefan Raspl 278de8474ebSStefan Raspl /* new data included urgent business */ 279bac6de7bSStefan Raspl smc_curs_copy(&conn->urg_curs, &conn->local_rx_ctrl.prod, conn); 280de8474ebSStefan Raspl conn->urg_state = SMC_URG_VALID; 281de8474ebSStefan Raspl if (!sock_flag(&smc->sk, SOCK_URGINLINE)) 282de8474ebSStefan Raspl /* we'll skip the urgent byte, so don't account for it */ 283de8474ebSStefan Raspl (*diff_prod)--; 284be244f28SHans Wippel base = (char *)conn->rmb_desc->cpu_addr + conn->rx_off; 285de8474ebSStefan Raspl if (conn->urg_curs.count) 286de8474ebSStefan Raspl conn->urg_rx_byte = *(base + conn->urg_curs.count - 1); 287de8474ebSStefan Raspl else 288de8474ebSStefan Raspl conn->urg_rx_byte = *(base + conn->rmb_desc->len - 1); 289de8474ebSStefan Raspl sk_send_sigurg(&smc->sk); 290de8474ebSStefan Raspl } 291de8474ebSStefan Raspl 292b286a065SKarsten Graul static void smc_cdc_msg_validate(struct smc_sock *smc, struct smc_cdc_msg *cdc, 293b286a065SKarsten Graul struct smc_link *link) 294b286a065SKarsten Graul { 295b286a065SKarsten Graul struct smc_connection *conn = &smc->conn; 296b286a065SKarsten Graul u16 recv_seq = ntohs(cdc->seqno); 297b286a065SKarsten Graul s16 diff; 298b286a065SKarsten Graul 299b286a065SKarsten Graul /* check that seqnum was seen before */ 300b286a065SKarsten Graul diff = conn->local_rx_ctrl.seqno - recv_seq; 301b286a065SKarsten Graul if (diff < 0) { /* diff larger than 0x7fff */ 302b286a065SKarsten Graul /* drop connection */ 303b286a065SKarsten Graul conn->out_of_sync = 1; /* prevent any further receives */ 304b286a065SKarsten Graul spin_lock_bh(&conn->send_lock); 305b286a065SKarsten Graul conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; 306b286a065SKarsten Graul conn->lnk = link; 307b286a065SKarsten Graul spin_unlock_bh(&conn->send_lock); 308b286a065SKarsten Graul sock_hold(&smc->sk); /* sock_put in abort_work */ 30922ef473dSKarsten Graul if (!queue_work(smc_close_wq, &conn->abort_work)) 310b286a065SKarsten Graul sock_put(&smc->sk); 311b286a065SKarsten Graul } 312b286a065SKarsten Graul } 313b286a065SKarsten Graul 3145f08318fSUrsula Braun static void smc_cdc_msg_recv_action(struct smc_sock *smc, 3155f08318fSUrsula Braun struct smc_cdc_msg *cdc) 3165f08318fSUrsula Braun { 3175f08318fSUrsula Braun union smc_host_cursor cons_old, prod_old; 3185f08318fSUrsula Braun struct smc_connection *conn = &smc->conn; 3195f08318fSUrsula Braun int diff_cons, diff_prod; 3205f08318fSUrsula Braun 321bac6de7bSStefan Raspl smc_curs_copy(&prod_old, &conn->local_rx_ctrl.prod, conn); 322bac6de7bSStefan Raspl smc_curs_copy(&cons_old, &conn->local_rx_ctrl.cons, conn); 3235f08318fSUrsula Braun smc_cdc_msg_to_host(&conn->local_rx_ctrl, cdc, conn); 3245f08318fSUrsula Braun 3255f08318fSUrsula Braun diff_cons = smc_curs_diff(conn->peer_rmbe_size, &cons_old, 3265f08318fSUrsula Braun &conn->local_rx_ctrl.cons); 3275f08318fSUrsula Braun if (diff_cons) { 3285f08318fSUrsula Braun /* peer_rmbe_space is decreased during data transfer with RDMA 3295f08318fSUrsula Braun * write 3305f08318fSUrsula Braun */ 3315f08318fSUrsula Braun smp_mb__before_atomic(); 3325f08318fSUrsula Braun atomic_add(diff_cons, &conn->peer_rmbe_space); 3335f08318fSUrsula Braun /* guarantee 0 <= peer_rmbe_space <= peer_rmbe_size */ 3345f08318fSUrsula Braun smp_mb__after_atomic(); 3355f08318fSUrsula Braun } 3365f08318fSUrsula Braun 33769cb7dc0SHans Wippel diff_prod = smc_curs_diff(conn->rmb_desc->len, &prod_old, 3385f08318fSUrsula Braun &conn->local_rx_ctrl.prod); 3395f08318fSUrsula Braun if (diff_prod) { 340de8474ebSStefan Raspl if (conn->local_rx_ctrl.prod_flags.urg_data_present) 341de8474ebSStefan Raspl smc_cdc_handle_urg_data_arrival(smc, &diff_prod); 3425f08318fSUrsula Braun /* bytes_to_rcv is decreased in smc_recvmsg */ 3435f08318fSUrsula Braun smp_mb__before_atomic(); 3445f08318fSUrsula Braun atomic_add(diff_prod, &conn->bytes_to_rcv); 34569cb7dc0SHans Wippel /* guarantee 0 <= bytes_to_rcv <= rmb_desc->len */ 3465f08318fSUrsula Braun smp_mb__after_atomic(); 347952310ccSUrsula Braun smc->sk.sk_data_ready(&smc->sk); 348de8474ebSStefan Raspl } else { 349cf0cfe53SKarsten Graul if (conn->local_rx_ctrl.prod_flags.write_blocked) 350cf0cfe53SKarsten Graul smc->sk.sk_data_ready(&smc->sk); 351de8474ebSStefan Raspl if (conn->local_rx_ctrl.prod_flags.urg_data_pending) 352de8474ebSStefan Raspl conn->urg_state = SMC_URG_NOTYET; 3535f08318fSUrsula Braun } 3545f08318fSUrsula Braun 35551f1de79SUrsula Braun /* trigger sndbuf consumer: RDMA write into peer RMBE and CDC */ 356cf0cfe53SKarsten Graul if ((diff_cons && smc_tx_prepared_sends(conn)) || 357cf0cfe53SKarsten Graul conn->local_rx_ctrl.prod_flags.cons_curs_upd_req || 358cf0cfe53SKarsten Graul conn->local_rx_ctrl.prod_flags.urg_data_pending) 35951f1de79SUrsula Braun smc_tx_sndbuf_nonempty(conn); 360cf0cfe53SKarsten Graul 361de8474ebSStefan Raspl if (diff_cons && conn->urg_tx_pend && 362de8474ebSStefan Raspl atomic_read(&conn->peer_rmbe_space) == conn->peer_rmbe_size) { 363de8474ebSStefan Raspl /* urg data confirmed by peer, indicate we're ready for more */ 364de8474ebSStefan Raspl conn->urg_tx_pend = false; 365de8474ebSStefan Raspl smc->sk.sk_write_space(&smc->sk); 366de8474ebSStefan Raspl } 36751f1de79SUrsula Braun 368b38d7324SUrsula Braun if (conn->local_rx_ctrl.conn_state_flags.peer_conn_abort) { 3695f08318fSUrsula Braun smc->sk.sk_err = ECONNRESET; 370b38d7324SUrsula Braun conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; 371b38d7324SUrsula Braun } 37246c28dbdSUrsula Braun if (smc_cdc_rxed_any_close_or_senddone(conn)) { 37346c28dbdSUrsula Braun smc->sk.sk_shutdown |= RCV_SHUTDOWN; 37446c28dbdSUrsula Braun if (smc->clcsock && smc->clcsock->sk) 37546c28dbdSUrsula Braun smc->clcsock->sk->sk_shutdown |= RCV_SHUTDOWN; 37646c28dbdSUrsula Braun sock_set_flag(&smc->sk, SOCK_DONE); 37751f1de79SUrsula Braun sock_hold(&smc->sk); /* sock_put in close_work */ 37822ef473dSKarsten Graul if (!queue_work(smc_close_wq, &conn->close_work)) 37951f1de79SUrsula Braun sock_put(&smc->sk); 380b38d7324SUrsula Braun } 3815f08318fSUrsula Braun } 3825f08318fSUrsula Braun 3835f08318fSUrsula Braun /* called under tasklet context */ 384d7b0e37cSHans Wippel static void smc_cdc_msg_recv(struct smc_sock *smc, struct smc_cdc_msg *cdc) 3855f08318fSUrsula Braun { 3865f08318fSUrsula Braun sock_hold(&smc->sk); 3875f08318fSUrsula Braun bh_lock_sock(&smc->sk); 388d7b0e37cSHans Wippel smc_cdc_msg_recv_action(smc, cdc); 3895f08318fSUrsula Braun bh_unlock_sock(&smc->sk); 3905f08318fSUrsula Braun sock_put(&smc->sk); /* no free sk in softirq-context */ 3915f08318fSUrsula Braun } 3925f08318fSUrsula Braun 393be244f28SHans Wippel /* Schedule a tasklet for this connection. Triggered from the ISM device IRQ 394be244f28SHans Wippel * handler to indicate update in the DMBE. 395be244f28SHans Wippel * 396be244f28SHans Wippel * Context: 397be244f28SHans Wippel * - tasklet context 398be244f28SHans Wippel */ 399fcb8e3a3SAllen Pais static void smcd_cdc_rx_tsklet(struct tasklet_struct *t) 400be244f28SHans Wippel { 401fcb8e3a3SAllen Pais struct smc_connection *conn = from_tasklet(conn, t, rx_tsklet); 402b9a22dd9SUrsula Braun struct smcd_cdc_msg *data_cdc; 403be244f28SHans Wippel struct smcd_cdc_msg cdc; 404be244f28SHans Wippel struct smc_sock *smc; 405be244f28SHans Wippel 406b2900980SUrsula Braun if (!conn || conn->killed) 407be244f28SHans Wippel return; 408be244f28SHans Wippel 409b9a22dd9SUrsula Braun data_cdc = (struct smcd_cdc_msg *)conn->rmb_desc->cpu_addr; 410b9a22dd9SUrsula Braun smcd_curs_copy(&cdc.prod, &data_cdc->prod, conn); 411b9a22dd9SUrsula Braun smcd_curs_copy(&cdc.cons, &data_cdc->cons, conn); 412be244f28SHans Wippel smc = container_of(conn, struct smc_sock, conn); 413be244f28SHans Wippel smc_cdc_msg_recv(smc, (struct smc_cdc_msg *)&cdc); 414be244f28SHans Wippel } 415be244f28SHans Wippel 416be244f28SHans Wippel /* Initialize receive tasklet. Called from ISM device IRQ handler to start 417be244f28SHans Wippel * receiver side. 418be244f28SHans Wippel */ 419be244f28SHans Wippel void smcd_cdc_rx_init(struct smc_connection *conn) 420be244f28SHans Wippel { 421fcb8e3a3SAllen Pais tasklet_setup(&conn->rx_tsklet, smcd_cdc_rx_tsklet); 422be244f28SHans Wippel } 423be244f28SHans Wippel 4245f08318fSUrsula Braun /***************************** init, exit, misc ******************************/ 4255f08318fSUrsula Braun 4265f08318fSUrsula Braun static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) 4275f08318fSUrsula Braun { 4285f08318fSUrsula Braun struct smc_link *link = (struct smc_link *)wc->qp->qp_context; 4295f08318fSUrsula Braun struct smc_cdc_msg *cdc = buf; 430d7b0e37cSHans Wippel struct smc_connection *conn; 431d7b0e37cSHans Wippel struct smc_link_group *lgr; 432d7b0e37cSHans Wippel struct smc_sock *smc; 4335f08318fSUrsula Braun 4345f08318fSUrsula Braun if (wc->byte_len < offsetof(struct smc_cdc_msg, reserved)) 4355f08318fSUrsula Braun return; /* short message */ 436cbba07a7SKarsten Graul if (cdc->len != SMC_WR_TX_SIZE) 4375f08318fSUrsula Braun return; /* invalid message */ 438d7b0e37cSHans Wippel 439d7b0e37cSHans Wippel /* lookup connection */ 44000e5fb26SStefan Raspl lgr = smc_get_lgr(link); 441d7b0e37cSHans Wippel read_lock_bh(&lgr->conns_lock); 442d7b0e37cSHans Wippel conn = smc_lgr_find_conn(ntohl(cdc->token), lgr); 443d7b0e37cSHans Wippel read_unlock_bh(&lgr->conns_lock); 444b286a065SKarsten Graul if (!conn || conn->out_of_sync) 445d7b0e37cSHans Wippel return; 446d7b0e37cSHans Wippel smc = container_of(conn, struct smc_sock, conn); 447d7b0e37cSHans Wippel 448b286a065SKarsten Graul if (cdc->prod_flags.failover_validation) { 449b286a065SKarsten Graul smc_cdc_msg_validate(smc, cdc, link); 450b286a065SKarsten Graul return; 451b286a065SKarsten Graul } 452d7b0e37cSHans Wippel if (smc_cdc_before(ntohs(cdc->seqno), 453d7b0e37cSHans Wippel conn->local_rx_ctrl.seqno)) 454d7b0e37cSHans Wippel /* received seqno is old */ 455d7b0e37cSHans Wippel return; 456b286a065SKarsten Graul 457d7b0e37cSHans Wippel smc_cdc_msg_recv(smc, cdc); 4585f08318fSUrsula Braun } 4595f08318fSUrsula Braun 4605f08318fSUrsula Braun static struct smc_wr_rx_handler smc_cdc_rx_handlers[] = { 4615f08318fSUrsula Braun { 4625f08318fSUrsula Braun .handler = smc_cdc_rx_handler, 4635f08318fSUrsula Braun .type = SMC_CDC_MSG_TYPE 4645f08318fSUrsula Braun }, 4655f08318fSUrsula Braun { 4665f08318fSUrsula Braun .handler = NULL, 4675f08318fSUrsula Braun } 4685f08318fSUrsula Braun }; 4695f08318fSUrsula Braun 4705f08318fSUrsula Braun int __init smc_cdc_init(void) 4715f08318fSUrsula Braun { 4725f08318fSUrsula Braun struct smc_wr_rx_handler *handler; 4735f08318fSUrsula Braun int rc = 0; 4745f08318fSUrsula Braun 4755f08318fSUrsula Braun for (handler = smc_cdc_rx_handlers; handler->handler; handler++) { 4765f08318fSUrsula Braun INIT_HLIST_NODE(&handler->list); 4775f08318fSUrsula Braun rc = smc_wr_rx_register_handler(handler); 4785f08318fSUrsula Braun if (rc) 4795f08318fSUrsula Braun break; 4805f08318fSUrsula Braun } 4815f08318fSUrsula Braun return rc; 4825f08318fSUrsula Braun } 483