Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / lnet / klnds / socklnd / socklnd_lib-darwin.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see [sun.com URL with a
20  * copy of GPLv2].
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lnet/klnds/socklnd/socklnd_lib-darwin.c
37  *
38  * Darwin porting library
39  * Make things easy to port
40  *
41  * Author: Phil Schwan <phil@clusterfs.com>
42  */
43 #include <mach/mach_types.h>
44 #include <string.h>
45 #include <netinet/in.h>
46 #include <netinet/tcp.h>
47 #include <sys/file.h>
48
49 #include "socklnd.h"
50
51 # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM
52
53 SYSCTL_DECL(_lnet);
54
55 SYSCTL_NODE (_lnet,           OID_AUTO,         ksocknal,        CTLFLAG_RW, 
56              0,                                 "ksocknal_sysctl");
57
58 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         timeout, 
59            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_timeout, 
60            0,                                   "timeout");
61 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         credits, 
62            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_credits, 
63            0,                                   "credits");
64 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         peer_credits, 
65            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_peercredits, 
66            0,                                   "peer_credits");
67 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         nconnds, 
68            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_nconnds, 
69            0,                                   "nconnds");
70 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         min_reconnectms, 
71            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_min_reconnectms, 
72            0,                                   "min_reconnectms");
73 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         max_reconnectms, 
74            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_max_reconnectms, 
75            0,                                   "max_reconnectms");
76 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         eager_ack, 
77            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_eager_ack, 
78            0,                                   "eager_ack");
79 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         typed, 
80            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_typed_conns, 
81            0,                                   "typed");
82 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         min_bulk, 
83            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_min_bulk, 
84            0,                                   "min_bulk");
85 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         rx_buffer_size, 
86            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_rx_buffer_size, 
87            0,                                   "rx_buffer_size");
88 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         tx_buffer_size, 
89            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_tx_buffer_size, 
90            0,                                   "tx_buffer_size");
91 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         nagle, 
92            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_nagle, 
93            0,                                   "nagle");
94 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         keepalive_idle, 
95            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_keepalive_idle, 
96            0,                                   "keepalive_idle");
97 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         keepalive_count, 
98            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_keepalive_count, 
99            0,                                   "keepalive_count");
100 SYSCTL_INT(_lnet_ksocknal,    OID_AUTO,         keepalive_intvl, 
101            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_keepalive_intvl, 
102            0,                                   "keepalive_intvl");
103
104 cfs_sysctl_table_t      ksocknal_top_ctl_table [] = {
105         &sysctl__lnet_ksocknal,
106         &sysctl__lnet_ksocknal_timeout,
107         &sysctl__lnet_ksocknal_credits,
108         &sysctl__lnet_ksocknal_peer_credits,
109         &sysctl__lnet_ksocknal_nconnds,
110         &sysctl__lnet_ksocknal_min_reconnectms,
111         &sysctl__lnet_ksocknal_max_reconnectms,
112         &sysctl__lnet_ksocknal_eager_ack,
113         &sysctl__lnet_ksocknal_typed,
114         &sysctl__lnet_ksocknal_min_bulk,
115         &sysctl__lnet_ksocknal_rx_buffer_size,
116         &sysctl__lnet_ksocknal_tx_buffer_size,
117         &sysctl__lnet_ksocknal_nagle,
118         &sysctl__lnet_ksocknal_keepalive_idle,
119         &sysctl__lnet_ksocknal_keepalive_count,
120         &sysctl__lnet_ksocknal_keepalive_intvl,
121         NULL
122 };
123
124 int
125 ksocknal_lib_tunables_init ()
126 {
127         ksocknal_tunables.ksnd_sysctl =
128                 cfs_register_sysctl_table (ksocknal_top_ctl_table, 0);
129
130         if (ksocknal_tunables.ksnd_sysctl == NULL)
131                 return -ENOMEM;
132
133         return 0;
134 }
135
136 void
137 ksocknal_lib_tunables_fini ()
138 {
139         if (ksocknal_tunables.ksnd_sysctl != NULL)
140                 cfs_unregister_sysctl_table (ksocknal_tunables.ksnd_sysctl);    
141 }
142 #else
143 int
144 ksocknal_lib_tunables_init ()
145 {
146         return 0;
147 }
148
149 void
150 ksocknal_lib_tunables_fini ()
151 {
152 }
153 #endif
154
155 /*
156  * To use bigger buffer for socket:
157  * 1. Increase nmbclusters (Cannot increased by sysctl because it's ready only, so
158  *    we must patch kernel).
159  * 2. Increase net.inet.tcp.reass.maxsegments
160  * 3. Increase net.inet.tcp.sendspace
161  * 4. Increase net.inet.tcp.recvspace
162  * 5. Increase kern.ipc.maxsockbuf
163  */
164 #define KSOCKNAL_MAX_BUFFER        (1152*1024)
165
166 void
167 ksocknal_lib_bind_irq (unsigned int irq)
168 {
169         return;
170 }
171
172 unsigned int
173 ksocknal_lib_sock_irq (cfs_socket_t *sock)
174 {
175         return 0;
176 }
177
178 int
179 ksocknal_lib_get_conn_addrs (ksock_conn_t *conn)
180
181         int rc = libcfs_sock_getaddr(conn->ksnc_sock, 1,
182                                      &conn->ksnc_ipaddr,
183                                      &conn->ksnc_port);
184
185         /* Didn't need the {get,put}connsock dance to deref ksnc_sock... */
186         LASSERT (!conn->ksnc_closing);
187
188         if (rc != 0) {
189                 CERROR ("Error %d getting sock peer IP\n", rc);
190                 return rc;
191         }
192
193         rc = libcfs_sock_getaddr(conn->ksnc_sock, 0,
194                                  &conn->ksnc_myipaddr, NULL);
195         if (rc != 0) {
196                 CERROR ("Error %d getting sock local IP\n", rc);
197                 return rc;
198         }
199
200         return 0;
201 }
202
203 #ifdef __DARWIN8__
204
205 int
206 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
207 {
208         socket_t        sock = C2B_SOCK(conn->ksnc_sock);
209         size_t          sndlen;
210         int             nob;
211         int             rc;
212
213 #if SOCKNAL_SINGLE_FRAG_TX
214         struct iovec    scratch;
215         struct iovec   *scratchiov = &scratch;
216         unsigned int    niov = 1;
217 #else
218         struct iovec   *scratchiov = conn->ksnc_tx_scratch_iov;
219         unsigned int    niov = tx->tx_niov;
220 #endif
221         struct msghdr msg = {
222                 .msg_name       = NULL,
223                 .msg_namelen    = 0,
224                 .msg_iov        = scratchiov,
225                 .msg_iovlen     = niov,
226                 .msg_control    = NULL,
227                 .msg_controllen = 0,
228                 .msg_flags      = MSG_DONTWAIT
229         };
230         
231         int  i;
232         
233         for (nob = i = 0; i < niov; i++) {
234                 scratchiov[i] = tx->tx_iov[i];
235                 nob += scratchiov[i].iov_len;
236         } 
237         
238         /* 
239          * XXX Liang:
240          * Linux has MSG_MORE, do we have anything to
241          * reduce number of partial TCP segments sent?
242          */
243         rc = -sock_send(sock, &msg, MSG_DONTWAIT, &sndlen);
244         if (rc == 0)
245                 rc = sndlen;
246         return rc;
247 }
248
249 int
250 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
251 {
252         socket_t       sock = C2B_SOCK(conn->ksnc_sock);
253         lnet_kiov_t   *kiov = tx->tx_kiov;
254         int            rc;
255         int            nob;
256         size_t         sndlen;
257
258 #if SOCKNAL_SINGLE_FRAG_TX
259         struct iovec  scratch;
260         struct iovec *scratchiov = &scratch;
261         unsigned int  niov = 1;
262 #else
263         struct iovec *scratchiov = conn->ksnc_tx_scratch_iov;
264         unsigned int  niov = tx->tx_nkiov;
265 #endif
266         struct msghdr msg = {
267                 .msg_name       = NULL,
268                 .msg_namelen    = 0,
269                 .msg_iov        = scratchiov,
270                 .msg_iovlen     = niov,
271                 .msg_control    = NULL,
272                 .msg_controllen = 0,
273                 .msg_flags      = MSG_DONTWAIT
274         };
275         
276         int           i;
277         
278         for (nob = i = 0; i < niov; i++) {
279                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) +
280                                          kiov[i].kiov_offset;
281                 nob += scratchiov[i].iov_len = kiov[i].kiov_len;
282         }
283
284         /* 
285          * XXX Liang:
286          * Linux has MSG_MORE, do wen have anyting to
287          * reduce number of partial TCP segments sent?
288          */
289         rc = -sock_send(sock, &msg, MSG_DONTWAIT, &sndlen);
290         for (i = 0; i < niov; i++)
291                 cfs_kunmap(kiov[i].kiov_page);
292         if (rc == 0)
293                 rc = sndlen;
294         return rc;
295 }
296
297 int
298 ksocknal_lib_recv_iov (ksock_conn_t *conn)
299 {
300 #if SOCKNAL_SINGLE_FRAG_RX
301         struct iovec  scratch;
302         struct iovec *scratchiov = &scratch;
303         unsigned int  niov = 1;
304 #else
305         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov;
306         unsigned int  niov = conn->ksnc_rx_niov;
307 #endif
308         struct iovec *iov = conn->ksnc_rx_iov;
309         struct msghdr msg = {
310                 .msg_name       = NULL,
311                 .msg_namelen    = 0,
312                 .msg_iov        = scratchiov,
313                 .msg_iovlen     = niov,
314                 .msg_control    = NULL,
315                 .msg_controllen = 0,
316                 .msg_flags      = 0
317         };
318         size_t       rcvlen;
319         int          nob;
320         int          i;
321         int          rc;
322
323         LASSERT (niov > 0);
324
325         for (nob = i = 0; i < niov; i++) {
326                 scratchiov[i] = iov[i];
327                 nob += scratchiov[i].iov_len;
328         }
329         LASSERT (nob <= conn->ksnc_rx_nob_wanted); 
330         rc = -sock_receive (C2B_SOCK(conn->ksnc_sock), &msg, MSG_DONTWAIT, &rcvlen);
331         if (rc == 0)
332                 rc = rcvlen;
333
334         return rc;
335 }
336
337 int
338 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
339 {
340 #if SOCKNAL_SINGLE_FRAG_RX
341         struct iovec  scratch;
342         struct iovec *scratchiov = &scratch;
343         unsigned int  niov = 1;
344 #else
345         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov;
346         unsigned int  niov = conn->ksnc_rx_nkiov;
347 #endif
348         lnet_kiov_t   *kiov = conn->ksnc_rx_kiov;
349         struct msghdr msg = {
350                 .msg_name       = NULL,
351                 .msg_namelen    = 0,
352                 .msg_iov        = scratchiov,
353                 .msg_iovlen     = niov,
354                 .msg_control    = NULL,
355                 .msg_controllen = 0,
356                 .msg_flags      = 0
357         };
358         int          nob;
359         int          i;
360         size_t       rcvlen;
361         int          rc;
362
363         /* NB we can't trust socket ops to either consume our iovs
364          * or leave them alone. */
365         for (nob = i = 0; i < niov; i++) {
366                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + \
367                                          kiov[i].kiov_offset;
368                 nob += scratchiov[i].iov_len = kiov[i].kiov_len;
369         }
370         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
371         rc = -sock_receive(C2B_SOCK(conn->ksnc_sock), &msg, MSG_DONTWAIT, &rcvlen); 
372         for (i = 0; i < niov; i++)
373                 cfs_kunmap(kiov[i].kiov_page); 
374         if (rc == 0)
375                 rc = rcvlen;
376         return (rc);
377 }
378
379 void
380 ksocknal_lib_eager_ack (ksock_conn_t *conn)
381 {
382         /* XXX Liang: */
383 }
384
385 int
386 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
387 {
388         socket_t       sock = C2B_SOCK(conn->ksnc_sock);
389         int            len;
390         int            rc;
391
392         rc = ksocknal_connsock_addref(conn);
393         if (rc != 0) {
394                 LASSERT (conn->ksnc_closing);
395                 *txmem = *rxmem = *nagle = 0;
396                 return (-ESHUTDOWN);
397         }
398         rc = libcfs_sock_getbuf(conn->ksnc_sock, txmem, rxmem);
399         if (rc == 0) {
400                 len = sizeof(*nagle);
401                 rc = -sock_getsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
402                                       nagle, &len);
403         }
404         ksocknal_connsock_decref(conn);
405
406         if (rc == 0)
407                 *nagle = !*nagle;
408         else
409                 *txmem = *rxmem = *nagle = 0;
410
411         return (rc);
412 }
413
414 int
415 ksocknal_lib_setup_sock (cfs_socket_t *sock)
416 {
417         int             rc; 
418         int             option; 
419         int             keep_idle; 
420         int             keep_intvl; 
421         int             keep_count; 
422         int             do_keepalive; 
423         socket_t        so = C2B_SOCK(sock);
424         struct linger   linger;
425
426         /* Ensure this socket aborts active sends immediately when we close
427          * it. */
428         linger.l_onoff = 0;
429         linger.l_linger = 0;
430         rc = -sock_setsockopt(so, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
431         if (rc != 0) {
432                 CERROR ("Can't set SO_LINGER: %d\n", rc);
433                 return (rc);
434         }
435
436         if (!*ksocknal_tunables.ksnd_nagle) { 
437                 option = 1; 
438                 rc = -sock_setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option));
439                 if (rc != 0) { 
440                         CERROR ("Can't disable nagle: %d\n", rc); 
441                         return (rc);
442                 } 
443         } 
444
445         rc = libcfs_sock_setbuf(sock,
446                                 *ksocknal_tunables.ksnd_tx_buffer_size,
447                                 *ksocknal_tunables.ksnd_rx_buffer_size);
448         if (rc != 0) {
449                 CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
450                         *ksocknal_tunables.ksnd_tx_buffer_size,
451                         *ksocknal_tunables.ksnd_rx_buffer_size, rc);
452                 return (rc);
453         }
454
455         /* snapshot tunables */ 
456         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle; 
457         keep_count = *ksocknal_tunables.ksnd_keepalive_count; 
458         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
459
460         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); 
461         option = (do_keepalive ? 1 : 0); 
462
463         rc = -sock_setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)); 
464         if (rc != 0) { 
465                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); 
466                 return (rc);
467         }
468         
469         if (!do_keepalive)
470                 return (rc);
471         rc = -sock_setsockopt(so, IPPROTO_TCP, TCP_KEEPALIVE, 
472                               &keep_idle, sizeof(keep_idle));
473         
474         return (rc);
475 }
476
477 void
478 ksocknal_lib_push_conn(ksock_conn_t *conn)
479
480         socket_t        sock; 
481         int             val = 1; 
482         int             rc; 
483         
484         rc = ksocknal_connsock_addref(conn); 
485         if (rc != 0)            /* being shut down */ 
486                 return; 
487         sock = C2B_SOCK(conn->ksnc_sock); 
488
489         rc = -sock_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 
490         LASSERT(rc == 0);
491
492         ksocknal_connsock_decref(conn);
493         return;
494 }
495
496 extern void ksocknal_read_callback (ksock_conn_t *conn);
497 extern void ksocknal_write_callback (ksock_conn_t *conn);
498
499 static void
500 ksocknal_upcall(socket_t so, void *arg, int waitf)
501 {
502         ksock_conn_t  *conn = (ksock_conn_t *)arg;
503         ENTRY;
504
505         read_lock (&ksocknal_data.ksnd_global_lock);
506         if (conn == NULL)
507                 goto out;
508
509         ksocknal_read_callback (conn);
510         /* XXX Liang */
511         ksocknal_write_callback (conn);
512 out:
513         read_unlock (&ksocknal_data.ksnd_global_lock);
514         EXIT;
515 }
516
517 void
518 ksocknal_lib_save_callback(cfs_socket_t *sock, ksock_conn_t *conn)
519
520         /* No callback need to save in osx */
521         return;
522 }
523
524 void
525 ksocknal_lib_set_callback(cfs_socket_t *sock, ksock_conn_t *conn)
526
527         libcfs_sock_set_cb(sock, ksocknal_upcall, (void *)conn);
528         return;
529 }
530
531 void 
532 ksocknal_lib_reset_callback(cfs_socket_t *sock, ksock_conn_t *conn)
533
534         libcfs_sock_reset_cb(sock);
535 }
536
537 #else /* !__DARWIN8__ */
538
539 int
540 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
541
542 #if SOCKNAL_SINGLE_FRAG_TX 
543         struct iovec    scratch; 
544         struct iovec   *scratchiov = &scratch; 
545         unsigned int    niov = 1;
546 #else 
547         struct iovec   *scratchiov = conn->ksnc_tx_scratch_iov; 
548         unsigned int    niov = tx->tx_niov;
549 #endif
550         struct socket *sock = conn->ksnc_sock;
551         int            nob;
552         int            rc;
553         int            i;
554         struct uio  suio = {
555                 .uio_iov        = scratchiov,
556                 .uio_iovcnt     = niov,
557                 .uio_offset     = 0,
558                 .uio_resid      = 0,            /* This will be valued after a while */
559                 .uio_segflg     = UIO_SYSSPACE,
560                 .uio_rw         = UIO_WRITE,
561                 .uio_procp      = NULL
562         };
563         int  flags = MSG_DONTWAIT;
564         CFS_DECL_NET_DATA;
565
566         for (nob = i = 0; i < niov; i++) { 
567                 scratchiov[i] = tx->tx_iov[i]; 
568                 nob += scratchiov[i].iov_len; 
569         }
570         suio.uio_resid = nob;
571
572         CFS_NET_IN;
573         rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
574         CFS_NET_EX; 
575
576         /* NB there is no return value can indicate how many 
577          * have been sent and how many resid, we have to get 
578          * sent bytes from suio. */
579         if (rc != 0) {
580                 if (suio.uio_resid != nob &&\
581                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
582                         /* We have sent something */
583                         rc = nob - suio.uio_resid;
584                 else if ( rc == EWOULDBLOCK ) 
585                         /* Actually, EAGAIN and EWOULDBLOCK have same value in OSX */
586                         rc = -EAGAIN;   
587                 else 
588                         rc = -rc;
589         } else  /* rc == 0 */
590                 rc = nob - suio.uio_resid;
591
592         return rc;
593 }
594
595 int
596 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
597 {
598 #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK 
599         struct iovec  scratch; 
600         struct iovec *scratchiov = &scratch; 
601         unsigned int  niov = 1;
602 #else
603         struct iovec *scratchiov = conn->ksnc_tx_scratch_iov; 
604         unsigned int  niov = tx->tx_nkiov;
605 #endif
606         struct socket *sock = conn->ksnc_sock;
607         lnet_kiov_t    *kiov = tx->tx_kiov;
608         int            nob;
609         int            rc;
610         int            i;
611         struct  uio suio = {
612                 .uio_iov        = scratchiov,
613                 .uio_iovcnt     = niov,
614                 .uio_offset     = 0, 
615                 .uio_resid      = 0,    /* It should be valued after a while */
616                 .uio_segflg     = UIO_SYSSPACE,
617                 .uio_rw         = UIO_WRITE,
618                 .uio_procp      = NULL
619         };
620         int  flags = MSG_DONTWAIT;
621         CFS_DECL_NET_DATA; 
622         
623         for (nob = i = 0; i < niov; i++) { 
624                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + 
625                                          kiov[i].kiov_offset; 
626                 nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
627         }
628         suio.uio_resid = nob;
629
630         CFS_NET_IN;
631         rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
632         CFS_NET_EX;
633
634         for (i = 0; i < niov; i++) 
635                 cfs_kunmap(kiov[i].kiov_page);
636
637         if (rc != 0) {
638                 if (suio.uio_resid != nob &&\
639                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
640                         /* We have sent something */
641                         rc = nob - suio.uio_resid; 
642                 else if ( rc == EWOULDBLOCK ) 
643                         /* EAGAIN and EWOULD BLOCK have same value in OSX */
644                         rc = -EAGAIN;   
645                 else 
646                         rc = -rc;
647         } else  /* rc == 0 */
648                 rc = nob - suio.uio_resid;
649
650         return rc;
651 }
652
653 /*
654  * liang: Hack of inpcb and tcpcb.
655  * To get tcpcb of a socket, and call tcp_output
656  * to send quick ack.
657  */
658 struct ks_tseg_qent{
659         int foo;
660 };
661
662 struct ks_tcptemp{
663         int foo;
664 };
665
666 LIST_HEAD(ks_tsegqe_head, ks_tseg_qent);
667
668 struct ks_tcpcb {
669         struct ks_tsegqe_head t_segq;
670         int     t_dupacks;
671         struct ks_tcptemp *unused;
672         int    t_timer[4];
673         struct inpcb *t_inpcb;
674         int    t_state;
675         u_int  t_flags;
676         /*
677          * There are more fields but we dont need
678          * ......
679          */
680 };
681
682 #define TF_ACKNOW       0x00001
683 #define TF_DELACK       0x00002
684
685 struct ks_inpcb {
686         LIST_ENTRY(ks_inpcb) inp_hash;
687         struct  in_addr reserved1;
688         struct  in_addr reserved2;
689         u_short inp_fport;
690         u_short inp_lport;
691         LIST_ENTRY(inpcb) inp_list;
692         caddr_t inp_ppcb;
693         /*
694          * There are more fields but we dont need
695          * ......
696          */
697 };
698
699 #define ks_sotoinpcb(so)   ((struct ks_inpcb *)(so)->so_pcb)
700 #define ks_intotcpcb(ip)   ((struct ks_tcpcb *)(ip)->inp_ppcb)
701 #define ks_sototcpcb(so)   (intotcpcb(sotoinpcb(so)))
702
703 void
704 ksocknal_lib_eager_ack (ksock_conn_t *conn)
705 {
706         struct socket *sock = conn->ksnc_sock;
707         struct ks_inpcb  *inp = ks_sotoinpcb(sock);
708         struct ks_tcpcb  *tp = ks_intotcpcb(inp);
709         int s;
710         CFS_DECL_NET_DATA;
711
712         extern int tcp_output(register struct ks_tcpcb *tp);
713
714         CFS_NET_IN;
715         s = splnet();
716
717         /*
718          * No TCP_QUICKACK supported in BSD, so I have to call tcp_fasttimo
719          * to send immediate ACK. 
720          */
721         if (tp && tp->t_flags & TF_DELACK){
722                 tp->t_flags &= ~TF_DELACK;
723                 tp->t_flags |= TF_ACKNOW;
724                 (void) tcp_output(tp);
725         }
726         splx(s);
727
728         CFS_NET_EX;
729
730         return;
731 }
732
733 int
734 ksocknal_lib_recv_iov (ksock_conn_t *conn)
735 {
736 #if SOCKNAL_SINGLE_FRAG_RX 
737         struct iovec  scratch; 
738         struct iovec *scratchiov = &scratch; 
739         unsigned int  niov = 1;
740 #else 
741         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov; 
742         unsigned int  niov = conn->ksnc_rx_niov;
743 #endif
744         struct iovec *iov = conn->ksnc_rx_iov;
745         int          nob;
746         int          rc;
747         int          i;
748         struct uio  ruio = {
749                 .uio_iov        = scratchiov,
750                 .uio_iovcnt     = niov,
751                 .uio_offset     = 0,
752                 .uio_resid      = 0,    /* It should be valued after a while */
753                 .uio_segflg     = UIO_SYSSPACE,
754                 .uio_rw         = UIO_READ,
755                 .uio_procp      = NULL
756         };
757         int         flags = MSG_DONTWAIT;
758         CFS_DECL_NET_DATA;
759
760         for (nob = i = 0; i < niov; i++) { 
761                 scratchiov[i] = iov[i]; 
762                 nob += scratchiov[i].iov_len; 
763         } 
764         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
765
766         ruio.uio_resid = nob;
767
768         CFS_NET_IN;
769         rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, &flags);
770         CFS_NET_EX;
771         if (rc){
772                 if (ruio.uio_resid != nob && \
773                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK || rc == EAGAIN))
774                         /* data particially received */
775                         rc = nob - ruio.uio_resid; 
776                 else if (rc == EWOULDBLOCK) 
777                         /* EAGAIN and EWOULD BLOCK have same value in OSX */
778                         rc = -EAGAIN; 
779                 else
780                         rc = -rc;
781         } else 
782                 rc = nob - ruio.uio_resid;
783
784         return (rc);
785 }
786
787 int
788 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
789 {
790 #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK 
791         struct iovec  scratch; 
792         struct iovec *scratchiov = &scratch; 
793         unsigned int  niov = 1;
794 #else 
795         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov; 
796         unsigned int  niov = conn->ksnc_rx_nkiov;
797 #endif
798         lnet_kiov_t    *kiov = conn->ksnc_rx_kiov;
799         int           nob;
800         int           rc;
801         int           i;
802         struct uio  ruio = {
803                 .uio_iov        = scratchiov,
804                 .uio_iovcnt     = niov,
805                 .uio_offset     = 0,
806                 .uio_resid      = 0,
807                 .uio_segflg     = UIO_SYSSPACE,
808                 .uio_rw         = UIO_READ,
809                 .uio_procp      = NULL
810         };
811         int         flags = MSG_DONTWAIT;
812         CFS_DECL_NET_DATA;
813
814         for (nob = i = 0; i < niov; i++) { 
815                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + kiov[i].kiov_offset; 
816                 nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
817         } 
818         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
819
820         ruio.uio_resid = nob;
821
822         CFS_NET_IN;
823         rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, NULL, &flags);
824         CFS_NET_EX;
825
826         for (i = 0; i < niov; i++) 
827                 cfs_kunmap(kiov[i].kiov_page);
828
829         if (rc){
830                 if (ruio.uio_resid != nob && \
831                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
832                         /* data particially received */
833                         rc = nob - ruio.uio_resid; 
834                 else if (rc == EWOULDBLOCK)
835                         /* receive blocked, EWOULDBLOCK == EAGAIN */ 
836                         rc = -EAGAIN; 
837                 else
838                         rc = -rc;
839         } else
840                 rc = nob - ruio.uio_resid;
841
842         return (rc);
843 }
844
845 int
846 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
847 {
848         struct socket *sock = conn->ksnc_sock;
849         int            rc;
850
851         rc = ksocknal_connsock_addref(conn);
852         if (rc != 0) {
853                 LASSERT (conn->ksnc_closing);
854                 *txmem = *rxmem = *nagle = 0;
855                 return -ESHUTDOWN;
856         }
857         rc = libcfs_sock_getbuf(sock, txmem, rxmem);
858         if (rc == 0) {
859                 struct sockopt  sopt;
860                 int            len;
861                 CFS_DECL_NET_DATA;
862
863                 len = sizeof(*nagle);
864                 bzero(&sopt, sizeof sopt);
865                 sopt.sopt_dir = SOPT_GET; 
866                 sopt.sopt_level = IPPROTO_TCP;
867                 sopt.sopt_name = TCP_NODELAY;
868                 sopt.sopt_val = nagle;
869                 sopt.sopt_valsize = len;
870
871                 CFS_NET_IN;
872                 rc = -sogetopt(sock, &sopt);
873                 CFS_NET_EX;
874         }
875
876         ksocknal_connsock_decref(conn);
877
878         if (rc == 0)
879                 *nagle = !*nagle;
880         else
881                 *txmem = *rxmem = *nagle = 0;
882         return (rc);
883 }
884
885 int
886 ksocknal_lib_setup_sock (struct socket *so)
887 {
888         struct sockopt  sopt;
889         int             rc; 
890         int             option; 
891         int             keep_idle; 
892         int             keep_intvl; 
893         int             keep_count; 
894         int             do_keepalive; 
895         struct linger   linger;
896         CFS_DECL_NET_DATA;
897
898         rc = libcfs_sock_setbuf(so,
899                                 *ksocknal_tunables.ksnd_tx_buffer_size,
900                                 *ksocknal_tunables.ksnd_rx_buffer_size);
901         if (rc != 0) {
902                 CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n",
903                         *ksocknal_tunables.ksnd_tx_buffer_size,
904                         *ksocknal_tunables.ksnd_rx_buffer_size, rc);
905                 return (rc);
906         }
907
908         /* Ensure this socket aborts active sends immediately when we close
909          * it. */
910         bzero(&sopt, sizeof sopt);
911
912         linger.l_onoff = 0;
913         linger.l_linger = 0;
914         sopt.sopt_dir = SOPT_SET;
915         sopt.sopt_level = SOL_SOCKET;
916         sopt.sopt_name = SO_LINGER;
917         sopt.sopt_val = &linger;
918         sopt.sopt_valsize = sizeof(linger);
919
920         CFS_NET_IN;
921         rc = -sosetopt(so, &sopt);
922         if (rc != 0) {
923                 CERROR ("Can't set SO_LINGER: %d\n", rc);
924                 goto out;
925         }
926
927         if (!*ksocknal_tunables.ksnd_nagle) { 
928                 option = 1; 
929                 bzero(&sopt, sizeof sopt);
930                 sopt.sopt_dir = SOPT_SET; 
931                 sopt.sopt_level = IPPROTO_TCP;
932                 sopt.sopt_name = TCP_NODELAY; 
933                 sopt.sopt_val = &option; 
934                 sopt.sopt_valsize = sizeof(option);
935                 rc = -sosetopt(so, &sopt);
936                 if (rc != 0) { 
937                         CERROR ("Can't disable nagle: %d\n", rc); 
938                         goto out;
939                 } 
940         } 
941
942         /* snapshot tunables */ 
943         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle; 
944         keep_count = *ksocknal_tunables.ksnd_keepalive_count; 
945         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
946
947         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); 
948         option = (do_keepalive ? 1 : 0); 
949         bzero(&sopt, sizeof sopt); 
950         sopt.sopt_dir = SOPT_SET; 
951         sopt.sopt_level = SOL_SOCKET; 
952         sopt.sopt_name = SO_KEEPALIVE; 
953         sopt.sopt_val = &option; 
954         sopt.sopt_valsize = sizeof(option); 
955         rc = -sosetopt(so, &sopt); 
956         if (rc != 0) { 
957                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); 
958                 goto out; 
959         }
960         
961         if (!do_keepalive) { 
962                 /* no more setting, just return */
963                 rc = 0;
964                 goto out;
965         } 
966         
967         bzero(&sopt, sizeof sopt); 
968         sopt.sopt_dir = SOPT_SET; 
969         sopt.sopt_level = IPPROTO_TCP; 
970         sopt.sopt_name = TCP_KEEPALIVE; 
971         sopt.sopt_val = &keep_idle; 
972         sopt.sopt_valsize = sizeof(keep_idle); 
973         rc = -sosetopt(so, &sopt); 
974         if (rc != 0) { 
975                 CERROR ("Can't set TCP_KEEPALIVE : %d\n", rc); 
976                 goto out; 
977         }
978 out:
979         CFS_NET_EX;
980         return (rc);
981 }
982
983 void
984 ksocknal_lib_push_conn(ksock_conn_t *conn)
985
986         struct socket   *sock; 
987         struct sockopt  sopt; 
988         int             val = 1; 
989         int             rc; 
990         CFS_DECL_NET_DATA; 
991         
992         rc = ksocknal_connsock_addref(conn); 
993         if (rc != 0)            /* being shut down */ 
994                 return; 
995         sock = conn->ksnc_sock; 
996         bzero(&sopt, sizeof sopt); 
997         sopt.sopt_dir = SOPT_SET; 
998         sopt.sopt_level = IPPROTO_TCP; 
999         sopt.sopt_name = TCP_NODELAY; 
1000         sopt.sopt_val = &val; 
1001         sopt.sopt_valsize = sizeof val; 
1002
1003         CFS_NET_IN; 
1004         sosetopt(sock, &sopt); 
1005         CFS_NET_EX; 
1006
1007         ksocknal_connsock_decref(conn);
1008         return;
1009 }
1010
1011
1012 extern void ksocknal_read_callback (ksock_conn_t *conn);
1013 extern void ksocknal_write_callback (ksock_conn_t *conn);
1014
1015 static void
1016 ksocknal_upcall(struct socket *so, caddr_t arg, int waitf)
1017 {
1018         ksock_conn_t  *conn = (ksock_conn_t *)arg;
1019         ENTRY;
1020
1021         read_lock (&ksocknal_data.ksnd_global_lock);
1022         if (conn == NULL)
1023                 goto out;
1024
1025         if (so->so_rcv.sb_flags & SB_UPCALL) {
1026                 extern int soreadable(struct socket *so);
1027                 if (conn->ksnc_rx_nob_wanted && soreadable(so))
1028                         /* To verify whether the upcall is for receive */
1029                         ksocknal_read_callback (conn);
1030         }
1031         /* go foward? */
1032         if (so->so_snd.sb_flags & SB_UPCALL){
1033                 extern int sowriteable(struct socket *so);
1034                 if (sowriteable(so))
1035                         /* socket is writable */
1036                         ksocknal_write_callback(conn);
1037         }
1038 out:
1039         read_unlock (&ksocknal_data.ksnd_global_lock);
1040
1041         EXIT;
1042 }
1043
1044 void
1045 ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
1046
1047         /* No callback need to save in osx */
1048         return;
1049 }
1050
1051 void
1052 ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn)
1053
1054         CFS_DECL_NET_DATA;
1055
1056         CFS_NET_IN;
1057         sock->so_upcallarg = (void *)conn;
1058         sock->so_upcall = ksocknal_upcall; 
1059         sock->so_snd.sb_timeo = 0; 
1060         sock->so_rcv.sb_timeo = cfs_time_seconds(2);
1061         sock->so_rcv.sb_flags |= SB_UPCALL; 
1062         sock->so_snd.sb_flags |= SB_UPCALL; 
1063         CFS_NET_EX;
1064         return;
1065 }
1066
1067 void
1068 ksocknal_lib_act_callback(struct socket *sock, ksock_conn_t *conn)
1069 {
1070         CFS_DECL_NET_DATA;
1071
1072         CFS_NET_IN;
1073         ksocknal_upcall (sock, (void *)conn, 0);
1074         CFS_NET_EX;
1075 }
1076
1077 void 
1078 ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn)
1079
1080         CFS_DECL_NET_DATA;
1081
1082         CFS_NET_IN;
1083         sock->so_rcv.sb_flags &= ~SB_UPCALL; 
1084         sock->so_snd.sb_flags &= ~SB_UPCALL;
1085         sock->so_upcall = NULL; 
1086         sock->so_upcallarg = NULL; 
1087         CFS_NET_EX;
1088 }
1089
1090 #endif  /* !__DARWIN8__ */