Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / lnet / klnds / socklnd / socklnd_lib-winnt.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-winnt.c
37  *
38  * windows socknal library
39  */
40
41 #include "socklnd.h"
42
43 # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM
44 static ctl_table ksocknal_ctl_table[18];
45
46 ctl_table ksocknal_top_ctl_table[] = {
47         {200, "socknal", NULL, 0, 0555, ksocknal_ctl_table},
48         { 0 }
49 };
50
51 int
52 ksocknal_lib_tunables_init () 
53 {
54             int    i = 0;
55             int    j = 1;
56         
57         ksocknal_ctl_table[i++] = (ctl_table)
58                 {j++, "timeout", ksocknal_tunables.ksnd_timeout, 
59                  sizeof (int), 0644, NULL, &proc_dointvec};
60         ksocknal_ctl_table[i++] = (ctl_table)
61                 {j++, "credits", ksocknal_tunables.ksnd_credits, 
62                  sizeof (int), 0444, NULL, &proc_dointvec};
63         ksocknal_ctl_table[i++] = (ctl_table)
64                 {j++, "peer_credits", ksocknal_tunables.ksnd_peercredits, 
65                  sizeof (int), 0444, NULL, &proc_dointvec};
66         ksocknal_ctl_table[i++] = (ctl_table)
67                 {j++, "nconnds", ksocknal_tunables.ksnd_nconnds, 
68                  sizeof (int), 0444, NULL, &proc_dointvec};
69         ksocknal_ctl_table[i++] = (ctl_table)
70                 {j++, "min_reconnectms", ksocknal_tunables.ksnd_min_reconnectms, 
71                  sizeof (int), 0444, NULL, &proc_dointvec};
72         ksocknal_ctl_table[i++] = (ctl_table)
73                 {j++, "max_reconnectms", ksocknal_tunables.ksnd_max_reconnectms, 
74                  sizeof (int), 0444, NULL, &proc_dointvec};
75         ksocknal_ctl_table[i++] = (ctl_table)
76                 {j++, "eager_ack", ksocknal_tunables.ksnd_eager_ack, 
77                  sizeof (int), 0644, NULL, &proc_dointvec};
78 #if SOCKNAL_ZC
79         ksocknal_ctl_table[i++] = (ctl_table)
80                 {j++, "zero_copy", ksocknal_tunables.ksnd_zc_min_frag, 
81                  sizeof (int), 0644, NULL, &proc_dointvec};
82 #endif
83         ksocknal_ctl_table[i++] = (ctl_table)
84                 {j++, "typed", ksocknal_tunables.ksnd_typed_conns, 
85                  sizeof (int), 0444, NULL, &proc_dointvec};
86         ksocknal_ctl_table[i++] = (ctl_table)
87                 {j++, "min_bulk", ksocknal_tunables.ksnd_min_bulk, 
88                  sizeof (int), 0644, NULL, &proc_dointvec};
89         ksocknal_ctl_table[i++] = (ctl_table)
90                 {j++, "buffer_size", ksocknal_tunables.ksnd_buffer_size, 
91                  sizeof(int), 0644, NULL, &proc_dointvec};
92         ksocknal_ctl_table[i++] = (ctl_table)
93                 {j++, "nagle", ksocknal_tunables.ksnd_nagle, 
94                  sizeof(int), 0644, NULL, &proc_dointvec};
95 #ifdef CPU_AFFINITY
96         ksocknal_ctl_table[i++] = (ctl_table)
97                 {j++, "irq_affinity", ksocknal_tunables.ksnd_irq_affinity, 
98                  sizeof(int), 0644, NULL, &proc_dointvec};
99 #endif
100         ksocknal_ctl_table[i++] = (ctl_table)
101                 {j++, "keepalive_idle", ksocknal_tunables.ksnd_keepalive_idle, 
102                  sizeof(int), 0644, NULL, &proc_dointvec};
103         ksocknal_ctl_table[i++] = (ctl_table)
104                 {j++, "keepalive_count", ksocknal_tunables.ksnd_keepalive_count, 
105                  sizeof(int), 0644, NULL, &proc_dointvec};
106         ksocknal_ctl_table[i++] = (ctl_table)
107                 {j++, "keepalive_intvl", ksocknal_tunables.ksnd_keepalive_intvl, 
108                  sizeof(int), 0644, NULL, &proc_dointvec};
109
110         LASSERT (j == i+1);
111         LASSERT (i < sizeof(ksocknal_ctl_table)/sizeof(ksocknal_ctl_table[0]));
112
113         ksocknal_tunables.ksnd_sysctl =
114                 register_sysctl_table(ksocknal_top_ctl_table, 0);
115
116         if (ksocknal_tunables.ksnd_sysctl == NULL)
117                 CWARN("Can't setup /proc tunables\n");
118
119         return 0;
120 }
121
122 void
123 ksocknal_lib_tunables_fini () 
124 {
125         if (ksocknal_tunables.ksnd_sysctl != NULL)
126                 unregister_sysctl_table(ksocknal_tunables.ksnd_sysctl); 
127 }
128 #else
129 int
130 ksocknal_lib_tunables_init () 
131 {
132         return 0;
133 }
134
135 void 
136 ksocknal_lib_tunables_fini ()
137 {
138 }
139 #endif
140
141 void
142 ksocknal_lib_bind_irq (unsigned int irq)
143 {
144 }
145
146 int
147 ksocknal_lib_get_conn_addrs (ksock_conn_t *conn)
148 {
149         int rc = libcfs_sock_getaddr(conn->ksnc_sock, 1,
150                                      &conn->ksnc_ipaddr, &conn->ksnc_port);
151
152         /* Didn't need the {get,put}connsock dance to deref ksnc_sock... */
153         LASSERT (!conn->ksnc_closing);
154
155         if (rc != 0) {
156                 CERROR ("Error %d getting sock peer IP\n", rc);
157                 return rc;
158         }
159
160         rc = libcfs_sock_getaddr(conn->ksnc_sock, 0,
161                                  &conn->ksnc_myipaddr, NULL);
162         if (rc != 0) {
163                 CERROR ("Error %d getting sock local IP\n", rc);
164                 return rc;
165         }
166
167         return 0;
168 }
169
170 unsigned int
171 ksocknal_lib_sock_irq (struct socket *sock)
172 {
173     return 0;
174 }
175
176 #if (SOCKNAL_ZC && SOCKNAL_VADDR_ZC)
177 static struct page *
178 ksocknal_kvaddr_to_page (unsigned long vaddr)
179 {
180         struct page *page;
181
182         if (vaddr >= VMALLOC_START &&
183             vaddr < VMALLOC_END)
184                 page = vmalloc_to_page ((void *)vaddr);
185 #ifdef CONFIG_HIGHMEM
186         else if (vaddr >= PKMAP_BASE &&
187                  vaddr < (PKMAP_BASE + LAST_PKMAP * PAGE_SIZE))
188                 page = vmalloc_to_page ((void *)vaddr);
189                 /* in 2.4 ^ just walks the page tables */
190 #endif
191         else
192                 page = virt_to_page (vaddr);
193
194         if (page == NULL ||
195             !VALID_PAGE (page))
196                 return (NULL);
197
198         return (page);
199 }
200 #endif
201
202 /*
203  * ks_lock_iovs
204  *   Lock the i/o vector buffers into MDL structure
205  *
206  * Arguments:
207  *   iov:  the array of i/o vectors
208  *   niov: number of i/o vectors to be locked
209  *   len:  the real length of the iov vectors
210  *
211  * Return Value:
212  *   ksock_mdl_t *: the Mdl of the locked buffers or
213  *         NULL pointer in failure case
214  *
215  * Notes: 
216  *   N/A
217  */
218
219 ksock_mdl_t *
220 ks_lock_iovs(
221     IN struct iovec  *iov,
222     IN int            niov,
223     IN int            recving,
224     IN int *          len )
225 {
226     int             rc = 0;
227
228     int             i = 0;
229     int             total = 0;
230     ksock_mdl_t *   mdl = NULL;
231     ksock_mdl_t *   tail = NULL;
232
233     LASSERT(iov != NULL);
234     LASSERT(niov > 0);
235     LASSERT(len != NULL);
236
237     for (i=0; i < niov; i++) {
238
239         ksock_mdl_t * Iovec = NULL;
240             
241         rc = ks_lock_buffer(
242                 iov[i].iov_base,
243                 FALSE,
244                 iov[i].iov_len,
245                 recving ? IoWriteAccess : IoReadAccess,
246                 &Iovec );
247
248         if (rc < 0) {
249             break;
250         }
251
252         if (tail) {
253             tail->Next = Iovec;
254         } else {
255             mdl = Iovec;
256         }
257
258         tail = Iovec;
259
260         total +=iov[i].iov_len;
261     }
262
263     if (rc >= 0) {
264         *len = total;
265     } else {
266         if (mdl) {
267             ks_release_mdl(mdl, FALSE);
268             mdl = NULL;
269         }
270     }
271
272     return mdl;
273 }
274
275 /*
276  * ks_lock_kiovs
277  *   Lock the kiov pages into MDL structure
278  *
279  * Arguments:
280  *   kiov:  the array of kiov pages
281  *   niov:  number of kiov to be locked
282  *   len:   the real length of the kiov arrary
283  *
284  * Return Value:
285  *   PMDL: the Mdl of the locked buffers or NULL
286  *         pointer in failure case
287  *
288  * Notes: 
289  *   N/A
290  */
291 ksock_mdl_t *
292 ks_lock_kiovs(
293     IN lnet_kiov_t *  kiov,
294     IN int            nkiov,
295     IN int            recving,
296     IN int *          len )
297 {
298     int             rc = 0;
299     int             i = 0;
300     int             total = 0;
301     ksock_mdl_t *   mdl = NULL;
302     ksock_mdl_t *   tail = NULL;
303
304     LASSERT(kiov != NULL);
305     LASSERT(nkiov > 0);
306     LASSERT(len != NULL);
307
308     for (i=0; i < nkiov; i++) {
309
310         ksock_mdl_t *        Iovec = NULL;
311
312
313         //
314         //  Lock the kiov page into Iovec Â¡Â­
315         //
316
317         rc = ks_lock_buffer(
318                 (PUCHAR)kiov[i].kiov_page->addr + 
319                      kiov[i].kiov_offset,
320                 FALSE,
321                 kiov[i].kiov_len,
322                 recving ? IoWriteAccess : IoReadAccess,
323                 &Iovec
324             );
325
326         if (rc < 0) {
327             break;
328         }
329
330         //
331         // Attach the Iovec to the mdl chain
332         //
333
334         if (tail) {
335             tail->Next = Iovec;
336         } else {
337             mdl = Iovec;
338         }
339
340         tail = Iovec;
341
342         total += kiov[i].kiov_len;
343
344     }
345
346     if (rc >= 0) {
347         *len = total;
348     } else {
349         if (mdl) {
350             ks_release_mdl(mdl, FALSE);
351             mdl = NULL;
352         }
353     }
354
355     return mdl;
356 }
357
358
359 int
360 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
361 {
362         struct socket *sock = conn->ksnc_sock;
363 #if (SOCKNAL_ZC && SOCKNAL_VADDR_ZC)
364         unsigned long  vaddr = (unsigned long)iov->iov_base
365         int            offset = vaddr & (PAGE_SIZE - 1);
366         int            zcsize = MIN (iov->iov_len, PAGE_SIZE - offset);
367         struct page   *page;
368 #endif
369         int            nob;
370         int            rc;
371         ksock_mdl_t *  mdl;
372
373         /* NB we can't trust socket ops to either consume our iovs
374          * or leave them alone. */
375
376 #if (SOCKNAL_ZC && SOCKNAL_VADDR_ZC)
377         if (zcsize >= ksocknal_data.ksnd_zc_min_frag &&
378             (sock->sk->sk_route_caps & NETIF_F_SG) &&
379             (sock->sk->sk_route_caps & (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)) &&
380             (page = ksocknal_kvaddr_to_page (vaddr)) != NULL) {
381                 int msgflg = MSG_DONTWAIT;
382
383                 CDEBUG(D_NET, "vaddr %p, page %p->%p + offset %x for %d\n",
384                        (void *)vaddr, page, page_address(page), offset, zcsize);
385
386                 if (!list_empty (&conn->ksnc_tx_queue) ||
387                     zcsize < tx->tx_resid)
388                         msgflg |= MSG_MORE;
389
390                 rc = tcp_sendpage_zccd(sock, page, offset, zcsize, msgflg, &tx->tx_zccd);
391         } else
392 #endif
393         {
394                 /* lock the whole tx iovs into a single mdl chain */
395                 mdl = ks_lock_iovs(tx->tx_iov, tx->tx_niov, FALSE, &nob);
396
397                 if (mdl) {
398                         /* send the total mdl chain */
399                         rc = ks_send_mdl( conn->ksnc_sock, tx, mdl, nob, 
400                                     (!list_empty (&conn->ksnc_tx_queue) || nob < tx->tx_resid) ? 
401                                     (MSG_DONTWAIT | MSG_MORE) : MSG_DONTWAIT);
402                 } else {
403                         rc = -ENOMEM;
404                 }
405         }
406
407             return rc;
408 }
409
410 int
411 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
412 {
413         struct socket *sock = conn->ksnc_sock;
414         lnet_kiov_t    *kiov = tx->tx_kiov;
415         int            rc;
416         int            nob;
417         ksock_mdl_t *  mdl;
418
419         /* NB we can't trust socket ops to either consume our iovs
420          * or leave them alone. */
421
422 #if SOCKNAL_ZC
423         if (kiov->kiov_len >= *ksocknal_tunables.ksnd_zc_min_frag &&
424             (sock->sk->sk_route_caps & NETIF_F_SG) &&
425             (sock->sk->sk_route_caps & (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM))) {
426                 struct page   *page = kiov->kiov_page;
427                 int            offset = kiov->kiov_offset;
428                 int            fragsize = kiov->kiov_len;
429                 int            msgflg = MSG_DONTWAIT;
430
431                 CDEBUG(D_NET, "page %p + offset %x for %d\n",
432                                page, offset, kiov->kiov_len);
433
434                 if (!list_empty(&conn->ksnc_tx_queue) ||
435                     fragsize < tx->tx_resid)
436                         msgflg |= MSG_MORE;
437
438                 rc = tcp_sendpage_zccd(sock, page, offset, fragsize, msgflg,
439                                        &tx->tx_zccd);
440         } else
441 #endif
442         {
443                 /* lock the whole tx kiovs into a single mdl chain */
444                 mdl = ks_lock_kiovs(tx->tx_kiov, tx->tx_nkiov, FALSE, &nob);
445
446                 if (mdl) {
447                         /* send the total mdl chain */
448                         rc = ks_send_mdl(
449                                     conn->ksnc_sock, tx, mdl, nob,
450                                     (!list_empty(&conn->ksnc_tx_queue) || nob < tx->tx_resid) ?
451                                     (MSG_DONTWAIT | MSG_MORE) : MSG_DONTWAIT);
452                 } else {
453                         rc = -ENOMEM;
454                 }
455         }
456
457             return rc;
458 }
459
460
461 int
462 ksocknal_lib_recv_iov (ksock_conn_t *conn)
463 {
464         struct iovec *iov = conn->ksnc_rx_iov;
465         int           rc;
466         int           size;
467         ksock_mdl_t * mdl;
468
469         /* lock the whole tx iovs into a single mdl chain */
470         mdl = ks_lock_iovs(iov, conn->ksnc_rx_niov, TRUE, &size);
471
472         if (!mdl) {
473             return (-ENOMEM);
474         }
475         
476         LASSERT (size <= conn->ksnc_rx_nob_wanted);
477
478         /* try to request data for the whole mdl chain */
479         rc = ks_recv_mdl (conn->ksnc_sock, mdl, size, MSG_DONTWAIT);
480
481         return rc;
482 }
483
484 int
485 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
486 {
487         lnet_kiov_t  *kiov = conn->ksnc_rx_kiov;
488         int           size;
489         int           rc;
490         ksock_mdl_t * mdl;
491
492         /* NB we can't trust socket ops to either consume our iovs
493          * or leave them alone, so we only receive 1 frag at a time. */
494         LASSERT (conn->ksnc_rx_nkiov > 0);
495
496         /* lock the whole tx kiovs into a single mdl chain */
497         mdl = ks_lock_kiovs(kiov, conn->ksnc_rx_nkiov, TRUE, &size);
498
499         if (!mdl) {
500             rc = -ENOMEM;
501             return (rc);
502         }
503         
504         LASSERT (size <= conn->ksnc_rx_nob_wanted);
505
506         /* try to request data for the whole mdl chain */
507         rc = ks_recv_mdl (conn->ksnc_sock, mdl, size, MSG_DONTWAIT);
508
509         return rc;
510 }
511
512 void
513 ksocknal_lib_eager_ack (ksock_conn_t *conn)
514 {
515         __u32   option = 1;
516         int     rc = 0;
517                 
518         rc = ks_set_tcp_option(
519                 conn->ksnc_sock, TCP_SOCKET_NODELAY,
520                 &option, sizeof(option) );
521         if (rc != 0) {
522                 CERROR("Can't disable nagle: %d\n", rc);
523         }
524 }
525
526 int
527 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
528 {
529         ksock_tconn_t * tconn = conn->ksnc_sock;
530         int             len;
531         int             rc;
532
533         ks_get_tconn (tconn);
534         
535         *txmem = *rxmem = 0;
536
537         len = sizeof(*nagle);
538
539         rc = ks_get_tcp_option(
540                     tconn, TCP_SOCKET_NODELAY,
541                     (__u32 *)nagle, &len);
542
543         ks_put_tconn (tconn);
544
545         printk("ksocknal_get_conn_tunables: nodelay = %d rc = %d\n", *nagle, rc);
546
547         if (rc == 0)
548                 *nagle = !*nagle;
549         else
550                 *txmem = *rxmem = *nagle = 0;
551                 
552         return (rc);
553 }
554
555 int
556 ksocknal_lib_buffersize (int current_sz, int tunable_sz)
557 {
558             /* ensure >= SOCKNAL_MIN_BUFFER */
559             if (current_sz < SOCKNAL_MIN_BUFFER)
560                         return MAX(SOCKNAL_MIN_BUFFER, tunable_sz);
561
562             if (tunable_sz > SOCKNAL_MIN_BUFFER)
563                         return tunable_sz;
564         
565             /* leave alone */
566             return 0;
567 }
568
569 int
570 ksocknal_lib_setup_sock (struct socket *sock)
571 {
572         int             rc;
573
574         int             keep_idle;
575         int             keep_count;
576         int             keep_intvl;
577         int             keep_alive;
578
579         __u32           option;
580
581         /* set the window size */
582
583 #if 0
584         tconn->kstc_snd_wnd = ksocknal_tunables.ksnd_buffer_size;
585         tconn->kstc_rcv_wnd = ksocknal_tunables.ksnd_buffer_size;
586 #endif
587
588         /* disable nagle */
589         if (!ksocknal_tunables.ksnd_nagle) {
590                 option = 1;
591                 
592                 rc = ks_set_tcp_option(
593                             sock, TCP_SOCKET_NODELAY,
594                             &option, sizeof (option));
595                 if (rc != 0) {
596                         printk ("Can't disable nagle: %d\n", rc);
597                         return (rc);
598                 }
599         }
600
601         /* snapshot tunables */
602         keep_idle  = *ksocknal_tunables.ksnd_keepalive_idle;
603         keep_count = *ksocknal_tunables.ksnd_keepalive_count;
604         keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl;
605         
606         keep_alive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0);
607
608         option = (__u32)(keep_alive ? 1 : 0);
609
610         rc = ks_set_tcp_option(
611                     sock, TCP_SOCKET_KEEPALIVE,
612                     &option, sizeof (option));
613         if (rc != 0) {
614                 CERROR ("Can't disable nagle: %d\n", rc);
615                 return (rc);
616         }
617
618         return (0);
619 }
620
621 void
622 ksocknal_lib_push_conn (ksock_conn_t *conn)
623 {
624         ksock_tconn_t * tconn;
625         __u32           nagle;
626         __u32           val = 1;
627         int             rc;
628
629         tconn = conn->ksnc_sock;
630
631         ks_get_tconn(tconn);
632
633         spin_lock(&tconn->kstc_lock);
634         if (tconn->kstc_type == kstt_sender) {
635             nagle = tconn->sender.kstc_info.nagle;
636             tconn->sender.kstc_info.nagle = 0;
637         } else {
638             LASSERT(tconn->kstc_type == kstt_child);
639             nagle = tconn->child.kstc_info.nagle;
640             tconn->child.kstc_info.nagle = 0;
641         }
642
643         spin_unlock(&tconn->kstc_lock);
644
645         val = 1;
646         rc = ks_set_tcp_option(
647                     tconn,
648                     TCP_SOCKET_NODELAY,
649                     &(val),
650                     sizeof(__u32)
651                     );
652
653         LASSERT (rc == 0);
654         spin_lock(&tconn->kstc_lock);
655
656         if (tconn->kstc_type == kstt_sender) {
657             tconn->sender.kstc_info.nagle = nagle;
658         } else {
659             LASSERT(tconn->kstc_type == kstt_child);
660             tconn->child.kstc_info.nagle = nagle;
661         }
662         spin_unlock(&tconn->kstc_lock);
663
664         ks_put_tconn(tconn);
665 }
666
667 /* @mode: 0: receiving mode / 1: sending mode */
668 void
669 ksocknal_sched_conn (ksock_conn_t *conn, int mode, ksock_tx_t *tx)
670 {
671         int             flags;
672         ksock_sched_t * sched;
673         ENTRY;
674
675         /* interleave correctly with closing sockets... */
676         read_lock (&ksocknal_data.ksnd_global_lock);
677
678         sched = conn->ksnc_scheduler;
679
680         spin_lock_irqsave (&sched->kss_lock, flags);
681
682         if (mode) { /* transmission can continue ... */ 
683
684 #error "This is out of date - we should be calling ksocknal_write_callback()"
685                 conn->ksnc_tx_ready = 1;
686
687                 if (tx) {
688                     /* Incomplete send: place tx on HEAD of tx_queue */
689                     list_add (&tx->tx_list, &conn->ksnc_tx_queue);
690                 }
691
692                 if ( !conn->ksnc_tx_scheduled &&
693                      !list_empty(&conn->ksnc_tx_queue)) {  //packets to send
694                         list_add_tail (&conn->ksnc_tx_list,
695                                        &sched->kss_tx_conns);
696                         conn->ksnc_tx_scheduled = 1;
697                         /* extra ref for scheduler */
698                         atomic_inc (&conn->ksnc_conn_refcount);
699
700                         cfs_waitq_signal (&sched->kss_waitq);
701                 }
702         } else {    /* receiving can continue ... */
703
704                 conn->ksnc_rx_ready = 1;
705
706                 if ( !conn->ksnc_rx_scheduled) {  /* not being progressed */
707                         list_add_tail(&conn->ksnc_rx_list,
708                                       &sched->kss_rx_conns);
709                         conn->ksnc_rx_scheduled = 1;
710                         /* extra ref for scheduler */
711                         atomic_inc (&conn->ksnc_conn_refcount);
712
713                         cfs_waitq_signal (&sched->kss_waitq);
714                 }
715         }
716
717         spin_unlock_irqrestore (&sched->kss_lock, flags);
718         read_unlock (&ksocknal_data.ksnd_global_lock);
719
720         EXIT;
721 }
722
723 void ksocknal_schedule_callback(struct socket*sock, int mode, void * tx, ulong_ptr bytes)
724 {
725     ksock_conn_t * conn = (ksock_conn_t *) sock->kstc_conn;
726
727     if (mode) {
728         ksocknal_sched_conn(conn, mode, tx);
729     } else {
730         if ( CAN_BE_SCHED(bytes, (ulong_ptr)conn->ksnc_rx_nob_wanted )) {
731             ksocknal_sched_conn(conn, mode, tx);
732         }
733     }
734 }
735
736 extern void
737 ksocknal_tx_launched (ksock_tx_t *tx);
738
739 void
740 ksocknal_fini_sending(ksock_tcpx_fini_t *tcpx)
741 {
742     ksocknal_tx_launched(tcpx->tx);
743     cfs_free(tcpx);
744 }
745
746 void *
747 ksocknal_update_tx(
748     struct socket*  tconn,
749     void *          txp,
750     ulong_ptr       rc
751     )
752 {
753     ksock_tx_t *    tx = (ksock_tx_t *)txp;
754
755     /*
756      *  the transmission was done, we need update the tx
757      */
758
759     LASSERT(tx->tx_resid >= (int)rc);
760     tx->tx_resid -= (int)rc;
761
762     /*
763      *  just partial of tx is sent out, we need update
764      *  the fields of tx and schedule later transmission.
765      */
766
767     if (tx->tx_resid) {
768
769         if (tx->tx_niov > 0) {
770
771             /* if there's iov, we need process iov first */
772             while (rc > 0 ) {
773                 if (rc < tx->tx_iov->iov_len) {
774                     /* didn't send whole iov entry... */
775                     tx->tx_iov->iov_base = 
776                         (char *)(tx->tx_iov->iov_base) + rc;
777                     tx->tx_iov->iov_len -= rc;
778                     rc = 0;
779                  } else {
780                     /* the whole of iov was sent out */
781                     rc -= tx->tx_iov->iov_len;
782                     tx->tx_iov++;
783                     tx->tx_niov--;
784                 }
785             }
786
787         } else {
788
789             /* now we need process the kiov queues ... */
790
791             while (rc > 0 ) {
792
793                 if (rc < tx->tx_kiov->kiov_len) {
794                     /* didn't send whole kiov entry... */
795                     tx->tx_kiov->kiov_offset += rc;
796                     tx->tx_kiov->kiov_len -= rc;
797                     rc = 0;
798                 } else {
799                     /* whole kiov was sent out */
800                     rc -= tx->tx_kiov->kiov_len;
801                     tx->tx_kiov++;
802                     tx->tx_nkiov--;
803                 }
804             }
805         }
806
807     } else {
808
809         ksock_tcpx_fini_t * tcpx = 
810                 cfs_alloc(sizeof(ksock_tcpx_fini_t), CFS_ALLOC_ZERO);
811
812         ASSERT(tx->tx_resid == 0);
813
814         if (!tcpx) {
815
816             ksocknal_tx_launched (tx);
817
818         } else {
819
820             tcpx->tx = tx;
821             ExInitializeWorkItem(
822                     &(tcpx->item), 
823                     ksocknal_fini_sending,
824                     tcpx
825             );
826             ExQueueWorkItem(
827                     &(tcpx->item),
828                     CriticalWorkQueue
829                     );
830         }
831
832         tx = NULL;
833     }
834
835     return (void *)tx;
836 }
837
838 void
839 ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
840 {
841 }
842
843 void
844 ksocknal_lib_set_callback(struct socket *sock,  ksock_conn_t *conn)
845 {
846         sock->kstc_conn      = conn;
847         sock->kstc_sched_cb  = ksocknal_schedule_callback;
848         sock->kstc_update_tx = ksocknal_update_tx;
849 }
850
851 void
852 ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn)
853 {
854         sock->kstc_conn      = NULL;
855         sock->kstc_sched_cb  = NULL;
856         sock->kstc_update_tx = NULL;
857 }