1 /* 2 * Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 * $Id$ 33 */ 34 #include "sdp.h" 35 36 static void sdp_nagle_timeout(void *data); 37 38 #ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA 39 void _dump_packet(const char *func, int line, struct socket *sk, char *str, 40 struct mbuf *mb, const struct sdp_bsdh *h) 41 { 42 struct sdp_hh *hh; 43 struct sdp_hah *hah; 44 struct sdp_chrecvbuf *req_size; 45 struct sdp_rrch *rrch; 46 struct sdp_srcah *srcah; 47 int len = 0; 48 char buf[256]; 49 len += snprintf(buf, 255-len, "%s mb: %p mid: %2x:%-20s flags: 0x%x " 50 "bufs: 0x%x len: 0x%x mseq: 0x%x mseq_ack: 0x%x | ", 51 str, mb, h->mid, mid2str(h->mid), h->flags, 52 ntohs(h->bufs), ntohl(h->len), ntohl(h->mseq), 53 ntohl(h->mseq_ack)); 54 55 switch (h->mid) { 56 case SDP_MID_HELLO: 57 hh = (struct sdp_hh *)h; 58 len += snprintf(buf + len, 255-len, 59 "max_adverts: %d majv_minv: 0x%x " 60 "localrcvsz: 0x%x desremrcvsz: 0x%x |", 61 hh->max_adverts, hh->majv_minv, 62 ntohl(hh->localrcvsz), 63 ntohl(hh->desremrcvsz)); 64 break; 65 case SDP_MID_HELLO_ACK: 66 hah = (struct sdp_hah *)h; 67 len += snprintf(buf + len, 255-len, "actrcvz: 0x%x |", 68 ntohl(hah->actrcvsz)); 69 break; 70 case SDP_MID_CHRCVBUF: 71 case SDP_MID_CHRCVBUF_ACK: 72 req_size = (struct sdp_chrecvbuf *)(h+1); 73 len += snprintf(buf + len, 255-len, "req_size: 0x%x |", 74 ntohl(req_size->size)); 75 break; 76 case SDP_MID_DATA: 77 len += snprintf(buf + len, 255-len, "data_len: 0x%lx |", 78 ntohl(h->len) - sizeof(struct sdp_bsdh)); 79 break; 80 case SDP_MID_RDMARDCOMPL: 81 rrch = (struct sdp_rrch *)(h+1); 82 83 len += snprintf(buf + len, 255-len, " | len: 0x%x |", 84 ntohl(rrch->len)); 85 break; 86 case SDP_MID_SRCAVAIL: 87 srcah = (struct sdp_srcah *)(h+1); 88 89 len += snprintf(buf + len, 255-len, " | payload: 0x%lx, " 90 "len: 0x%x, rkey: 0x%x, vaddr: 0x%jx |", 91 ntohl(h->len) - sizeof(struct sdp_bsdh) - 92 sizeof(struct sdp_srcah), 93 ntohl(srcah->len), ntohl(srcah->rkey), 94 be64_to_cpu(srcah->vaddr)); 95 break; 96 default: 97 break; 98 } 99 buf[len] = 0; 100 _sdp_printk(func, line, KERN_WARNING, sk, "%s: %s\n", str, buf); 101 } 102 #endif 103 104 static inline int 105 sdp_nagle_off(struct sdp_sock *ssk, struct mbuf *mb) 106 { 107 108 struct sdp_bsdh *h; 109 110 h = mtod(mb, struct sdp_bsdh *); 111 int send_now = 112 #ifdef SDP_ZCOPY 113 BZCOPY_STATE(mb) || 114 #endif 115 unlikely(h->mid != SDP_MID_DATA) || 116 (ssk->flags & SDP_NODELAY) || 117 !ssk->nagle_last_unacked || 118 mb->m_pkthdr.len >= ssk->xmit_size_goal / 4 || 119 (mb->m_flags & M_PUSH); 120 121 if (send_now) { 122 unsigned long mseq = ring_head(ssk->tx_ring); 123 ssk->nagle_last_unacked = mseq; 124 } else { 125 if (!callout_pending(&ssk->nagle_timer)) { 126 callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT, 127 sdp_nagle_timeout, ssk); 128 sdp_dbg_data(ssk->socket, "Starting nagle timer\n"); 129 } 130 } 131 sdp_dbg_data(ssk->socket, "send_now = %d last_unacked = %ld\n", 132 send_now, ssk->nagle_last_unacked); 133 134 return send_now; 135 } 136 137 static void 138 sdp_nagle_timeout(void *data) 139 { 140 struct sdp_sock *ssk = (struct sdp_sock *)data; 141 struct socket *sk = ssk->socket; 142 143 sdp_dbg_data(sk, "last_unacked = %ld\n", ssk->nagle_last_unacked); 144 145 if (!callout_active(&ssk->nagle_timer)) 146 return; 147 callout_deactivate(&ssk->nagle_timer); 148 149 if (!ssk->nagle_last_unacked) 150 goto out; 151 if (ssk->state == TCPS_CLOSED) 152 return; 153 ssk->nagle_last_unacked = 0; 154 sdp_post_sends(ssk, M_NOWAIT); 155 156 sowwakeup(ssk->socket); 157 out: 158 if (sk->so_snd.sb_sndptr) 159 callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT, 160 sdp_nagle_timeout, ssk); 161 } 162 163 void 164 sdp_post_sends(struct sdp_sock *ssk, int wait) 165 { 166 struct mbuf *mb; 167 int post_count = 0; 168 struct socket *sk; 169 int low; 170 171 sk = ssk->socket; 172 if (unlikely(!ssk->id)) { 173 if (sk->so_snd.sb_sndptr) { 174 sdp_dbg(ssk->socket, 175 "Send on socket without cmid ECONNRESET.\n"); 176 sdp_notify(ssk, ECONNRESET); 177 } 178 return; 179 } 180 again: 181 if (sdp_tx_ring_slots_left(ssk) < SDP_TX_SIZE / 2) 182 sdp_xmit_poll(ssk, 1); 183 184 if (ssk->recv_request && 185 ring_tail(ssk->rx_ring) >= ssk->recv_request_head && 186 tx_credits(ssk) >= SDP_MIN_TX_CREDITS && 187 sdp_tx_ring_slots_left(ssk)) { 188 mb = sdp_alloc_mb_chrcvbuf_ack(sk, 189 ssk->recv_bytes - SDP_HEAD_SIZE, wait); 190 if (mb == NULL) 191 goto allocfail; 192 ssk->recv_request = 0; 193 sdp_post_send(ssk, mb); 194 post_count++; 195 } 196 197 if (tx_credits(ssk) <= SDP_MIN_TX_CREDITS && 198 sdp_tx_ring_slots_left(ssk) && sk->so_snd.sb_sndptr && 199 sdp_nagle_off(ssk, sk->so_snd.sb_sndptr)) { 200 SDPSTATS_COUNTER_INC(send_miss_no_credits); 201 } 202 203 while (tx_credits(ssk) > SDP_MIN_TX_CREDITS && 204 sdp_tx_ring_slots_left(ssk) && (mb = sk->so_snd.sb_sndptr) && 205 sdp_nagle_off(ssk, mb)) { 206 struct mbuf *n; 207 208 SOCKBUF_LOCK(&sk->so_snd); 209 sk->so_snd.sb_sndptr = mb->m_nextpkt; 210 sk->so_snd.sb_mb = mb->m_nextpkt; 211 mb->m_nextpkt = NULL; 212 SB_EMPTY_FIXUP(&sk->so_snd); 213 for (n = mb; n != NULL; n = n->m_next) 214 sbfree(&sk->so_snd, n); 215 SOCKBUF_UNLOCK(&sk->so_snd); 216 sdp_post_send(ssk, mb); 217 post_count++; 218 } 219 220 if (credit_update_needed(ssk) && ssk->state >= TCPS_ESTABLISHED && 221 ssk->state < TCPS_FIN_WAIT_2) { 222 mb = sdp_alloc_mb_data(ssk->socket, wait); 223 if (mb == NULL) 224 goto allocfail; 225 sdp_post_send(ssk, mb); 226 227 SDPSTATS_COUNTER_INC(post_send_credits); 228 post_count++; 229 } 230 231 /* send DisConn if needed 232 * Do not send DisConn if there is only 1 credit. Compliance with CA4-82 233 * If one credit is available, an implementation shall only send SDP 234 * messages that provide additional credits and also do not contain ULP 235 * payload. */ 236 if ((ssk->flags & SDP_NEEDFIN) && !sk->so_snd.sb_sndptr && 237 tx_credits(ssk) > 1) { 238 mb = sdp_alloc_mb_disconnect(sk, wait); 239 if (mb == NULL) 240 goto allocfail; 241 ssk->flags &= ~SDP_NEEDFIN; 242 sdp_post_send(ssk, mb); 243 post_count++; 244 } 245 low = (sdp_tx_ring_slots_left(ssk) <= SDP_MIN_TX_CREDITS); 246 if (post_count || low) { 247 if (low) 248 sdp_arm_tx_cq(ssk); 249 if (sdp_xmit_poll(ssk, low)) 250 goto again; 251 } 252 return; 253 254 allocfail: 255 ssk->nagle_last_unacked = -1; 256 callout_reset(&ssk->nagle_timer, 1, sdp_nagle_timeout, ssk); 257 return; 258 } 259