Whamcloud - gitweb
LU-1346 libcfs: replace libcfs wrappers with kernel API
[fs/lustre-release.git] / lnet / klnds / mxlnd / mxlnd.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (C) 2006 Myricom, Inc.
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/mxlnd/mxlnd.c
37  *
38  * Author: Eric Barton <eric@bartonsoftware.com>
39  * Author: Scott Atchley <atchley at myri.com>
40  */
41
42 #include "mxlnd.h"
43
44 lnd_t the_kmxlnd = {
45         .lnd_type       = MXLND,
46         .lnd_startup    = mxlnd_startup,
47         .lnd_shutdown   = mxlnd_shutdown,
48         .lnd_ctl        = mxlnd_ctl,
49         .lnd_send       = mxlnd_send,
50         .lnd_recv       = mxlnd_recv,
51 };
52
53 kmx_data_t               kmxlnd_data;
54
55 void
56 mxlnd_free_pages(kmx_pages_t *p)
57 {
58         int     npages = p->mxg_npages;
59         int     i;
60
61         CDEBUG(D_MALLOC, "freeing %d pages\n", npages);
62
63         for (i = 0; i < npages; i++) {
64                 if (p->mxg_pages[i] != NULL) {
65                         __free_page(p->mxg_pages[i]);
66                         spin_lock(&kmxlnd_data.kmx_mem_lock);
67                         kmxlnd_data.kmx_mem_used -= PAGE_SIZE;
68                         spin_unlock(&kmxlnd_data.kmx_mem_lock);
69                 }
70         }
71
72         MXLND_FREE(p, offsetof(kmx_pages_t, mxg_pages[npages]));
73 }
74
75 int
76 mxlnd_alloc_pages(kmx_pages_t **pp, int npages)
77 {
78         kmx_pages_t    *p       = NULL;
79         int             i       = 0;
80
81         CDEBUG(D_MALLOC, "allocing %d pages\n", npages);
82
83         MXLND_ALLOC(p, offsetof(kmx_pages_t, mxg_pages[npages]));
84         if (p == NULL) {
85                 CERROR("Can't allocate descriptor for %d pages\n", npages);
86                 return -ENOMEM;
87         }
88
89         memset(p, 0, offsetof(kmx_pages_t, mxg_pages[npages]));
90         p->mxg_npages = npages;
91
92         for (i = 0; i < npages; i++) {
93                 p->mxg_pages[i] = alloc_page(GFP_KERNEL);
94                 if (p->mxg_pages[i] == NULL) {
95                         CERROR("Can't allocate page %d of %d\n", i, npages);
96                         mxlnd_free_pages(p);
97                         return -ENOMEM;
98                 }
99                 spin_lock(&kmxlnd_data.kmx_mem_lock);
100                 kmxlnd_data.kmx_mem_used += PAGE_SIZE;
101                 spin_unlock(&kmxlnd_data.kmx_mem_lock);
102         }
103
104         *pp = p;
105         return 0;
106 }
107
108 /**
109  * mxlnd_ctx_init - reset ctx struct to the default values
110  * @ctx - a kmx_ctx pointer
111  */
112 void
113 mxlnd_ctx_init(kmx_ctx_t *ctx)
114 {
115         if (ctx == NULL) return;
116
117         /* do not change mxc_type */
118         ctx->mxc_incarnation = 0;
119         ctx->mxc_deadline = 0;
120         ctx->mxc_state = MXLND_CTX_IDLE;
121         if (!cfs_list_empty(&ctx->mxc_list))
122                 cfs_list_del_init(&ctx->mxc_list);
123         /* ignore mxc_rx_list */
124         if (ctx->mxc_type == MXLND_REQ_TX) {
125                 ctx->mxc_nid = 0;
126                 ctx->mxc_peer = NULL;
127                 ctx->mxc_conn = NULL;
128         }
129         /* ignore mxc_msg */
130         ctx->mxc_lntmsg[0] = NULL;
131         ctx->mxc_lntmsg[1] = NULL;
132         ctx->mxc_msg_type = 0;
133         ctx->mxc_cookie = 0LL;
134         ctx->mxc_match = 0LL;
135         /* ctx->mxc_seg.segment_ptr points to backing page */
136         ctx->mxc_seg.segment_length = 0;
137         if (ctx->mxc_seg_list != NULL) {
138                 LASSERT(ctx->mxc_nseg > 0);
139                 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
140         }
141         ctx->mxc_seg_list = NULL;
142         ctx->mxc_nseg = 0;
143         ctx->mxc_nob = 0;
144         memset(&ctx->mxc_mxreq, 0, sizeof(mx_request_t));
145         memset(&ctx->mxc_status, 0, sizeof(mx_status_t));
146         ctx->mxc_errno = 0;
147         /* ctx->mxc_get */
148         /* ctx->mxc_put */
149
150         ctx->mxc_msg->mxm_type = 0;
151         ctx->mxc_msg->mxm_credits = 0;
152         ctx->mxc_msg->mxm_nob = 0;
153
154         return;
155 }
156
157 /**
158  * mxlnd_free_txs - free kmx_txs and associated pages
159  *
160  * Called from mxlnd_shutdown()
161  */
162 void
163 mxlnd_free_txs(void)
164 {
165         int             i       = 0;
166         kmx_ctx_t       *tx     = NULL;
167
168         if (kmxlnd_data.kmx_tx_pages) {
169                 for (i = 0; i < MXLND_TX_MSGS(); i++) {
170                         tx = &kmxlnd_data.kmx_txs[i];
171                         if (tx->mxc_seg_list != NULL) {
172                                 LASSERT(tx->mxc_nseg > 0);
173                                 MXLND_FREE(tx->mxc_seg_list,
174                                            tx->mxc_nseg *
175                                            sizeof(*tx->mxc_seg_list));
176                         }
177                 }
178                 MXLND_FREE(kmxlnd_data.kmx_txs,
179                             MXLND_TX_MSGS() * sizeof(kmx_ctx_t));
180                 mxlnd_free_pages(kmxlnd_data.kmx_tx_pages);
181         }
182
183         return;
184 }
185
186 /**
187  * mxlnd_init_txs - allocate tx descriptors then stash on txs and idle tx lists
188  *
189  * Called from mxlnd_startup()
190  * returns 0 on success, else -ENOMEM
191  */
192 int
193 mxlnd_init_txs(void)
194 {
195         int             ret     = 0;
196         int             i       = 0;
197         int             ipage   = 0;
198         int             offset  = 0;
199         void           *addr    = NULL;
200         kmx_ctx_t      *tx      = NULL;
201         kmx_pages_t    *pages   = NULL;
202         struct page    *page    = NULL;
203
204         /* pre-mapped messages are not bigger than 1 page */
205         CLASSERT(MXLND_MSG_SIZE <= PAGE_SIZE);
206
207         /* No fancy arithmetic when we do the buffer calculations */
208         CLASSERT (PAGE_SIZE % MXLND_MSG_SIZE == 0);
209
210         ret = mxlnd_alloc_pages(&pages, MXLND_TX_MSG_PAGES());
211         if (ret != 0) {
212                 CERROR("Can't allocate tx pages\n");
213                 return -ENOMEM;
214         }
215         kmxlnd_data.kmx_tx_pages = pages;
216
217         MXLND_ALLOC(kmxlnd_data.kmx_txs, MXLND_TX_MSGS() * sizeof(kmx_ctx_t));
218         if (&kmxlnd_data.kmx_txs == NULL) {
219                 CERROR("Can't allocate %d tx descriptors\n", MXLND_TX_MSGS());
220                 mxlnd_free_pages(pages);
221                 return -ENOMEM;
222         }
223
224         memset(kmxlnd_data.kmx_txs, 0, MXLND_TX_MSGS() * sizeof(kmx_ctx_t));
225
226         for (i = 0; i < MXLND_TX_MSGS(); i++) {
227
228                 tx = &kmxlnd_data.kmx_txs[i];
229                 tx->mxc_type = MXLND_REQ_TX;
230
231                 CFS_INIT_LIST_HEAD(&tx->mxc_list);
232
233                 /* map mxc_msg to page */
234                 page = pages->mxg_pages[ipage];
235                 addr = page_address(page);
236                 LASSERT(addr != NULL);
237                 tx->mxc_msg = (kmx_msg_t *)(addr + offset);
238                 tx->mxc_seg.segment_ptr = MX_PA_TO_U64(virt_to_phys(tx->mxc_msg));
239
240                 mxlnd_ctx_init(tx);
241
242                 offset += MXLND_MSG_SIZE;
243                 LASSERT (offset <= PAGE_SIZE);
244
245                 if (offset == PAGE_SIZE) {
246                         offset = 0;
247                         ipage++;
248                         LASSERT (ipage <= MXLND_TX_MSG_PAGES());
249                 }
250
251                 /* in startup(), no locks required */
252                 cfs_list_add_tail(&tx->mxc_list, &kmxlnd_data.kmx_tx_idle);
253         }
254
255         return 0;
256 }
257
258 /**
259  * mxlnd_free_peers - free peers
260  *
261  * Called from mxlnd_shutdown()
262  */
263 void
264 mxlnd_free_peers(void)
265 {
266         int             i      = 0;
267         int             count  = 0;
268         kmx_peer_t     *peer   = NULL;
269         kmx_peer_t     *next   = NULL;
270
271         for (i = 0; i < MXLND_HASH_SIZE; i++) {
272                 cfs_list_for_each_entry_safe(peer, next,
273                                              &kmxlnd_data.kmx_peers[i],
274                                              mxp_list) {
275                         cfs_list_del_init(&peer->mxp_list);
276                         if (peer->mxp_conn) mxlnd_conn_decref(peer->mxp_conn);
277                         mxlnd_peer_decref(peer);
278                         count++;
279                 }
280         }
281         CDEBUG(D_NET, "%s: freed %d peers\n", __func__, count);
282 }
283
284 /**
285  * mxlnd_init_mx - open the endpoint, set our ID, register the EAGER callback
286  * @ni - the network interface
287  *
288  * Returns 0 on success, -1 on failure
289  */
290 int
291 mxlnd_init_mx(lnet_ni_t *ni)
292 {
293         int                     ret     = 0;
294         mx_return_t             mxret;
295         u32                     board   = *kmxlnd_tunables.kmx_board;
296         u32                     ep_id   = *kmxlnd_tunables.kmx_ep_id;
297         u64                     nic_id  = 0LL;
298         char                    *ifname = NULL;
299         __u32                   ip;
300         __u32                   netmask;
301         int                     if_up   = 0;
302
303         mxret = mx_init();
304         if (mxret != MX_SUCCESS) {
305                 CERROR("mx_init() failed with %s (%d)\n", mx_strerror(mxret), mxret);
306                 return -1;
307         }
308
309         if (ni->ni_interfaces[0] != NULL) {
310                 /* Use the IPoMX interface specified in 'networks=' */
311
312                 CLASSERT (LNET_MAX_INTERFACES > 1);
313                 if (ni->ni_interfaces[1] != NULL) {
314                         CERROR("Multiple interfaces not supported\n");
315                         goto failed_with_init;
316                 }
317
318                 ifname = ni->ni_interfaces[0];
319         } else {
320                 ifname = *kmxlnd_tunables.kmx_default_ipif;
321         }
322
323         ret = libcfs_ipif_query(ifname, &if_up, &ip, &netmask);
324         if (ret != 0) {
325                 CERROR("Can't query IPoMX interface %s: %d\n",
326                        ifname, ret);
327                 goto failed_with_init;
328         }
329
330         if (!if_up) {
331                 CERROR("Can't query IPoMX interface %s: it's down\n",
332                        ifname);
333                 goto failed_with_init;
334         }
335
336         mxret = mx_open_endpoint(board, ep_id, MXLND_MSG_MAGIC,
337                                  NULL, 0, &kmxlnd_data.kmx_endpt);
338         if (mxret != MX_SUCCESS) {
339                 CERROR("mx_open_endpoint() failed with %d\n", mxret);
340                 goto failed_with_init;
341         }
342
343         mx_get_endpoint_addr(kmxlnd_data.kmx_endpt, &kmxlnd_data.kmx_epa);
344         mx_decompose_endpoint_addr(kmxlnd_data.kmx_epa, &nic_id, &ep_id);
345         mxret = mx_connect(kmxlnd_data.kmx_endpt, nic_id, ep_id,
346                            MXLND_MSG_MAGIC, MXLND_CONNECT_TIMEOUT/CFS_HZ*1000,
347                            &kmxlnd_data.kmx_epa);
348         if (mxret != MX_SUCCESS) {
349                 CNETERR("unable to connect to myself (%s)\n", mx_strerror(mxret));
350                 goto failed_with_endpoint;
351         }
352
353         ni->ni_nid = LNET_MKNID(LNET_NIDNET(ni->ni_nid), ip);
354         CDEBUG(D_NET, "My NID is 0x%llx\n", ni->ni_nid);
355
356         /* this will catch all unexpected receives. */
357         mxret = mx_register_unexp_handler(kmxlnd_data.kmx_endpt,
358                                           (mx_unexp_handler_t) mxlnd_unexpected_recv,
359                                           NULL);
360         if (mxret != MX_SUCCESS) {
361                 CERROR("mx_register_unexp_callback() failed with %s\n",
362                          mx_strerror(mxret));
363                 goto failed_with_endpoint;
364         }
365         mxret = mx_set_request_timeout(kmxlnd_data.kmx_endpt, NULL,
366                                        MXLND_COMM_TIMEOUT/CFS_HZ*1000);
367         if (mxret != MX_SUCCESS) {
368                 CERROR("mx_set_request_timeout() failed with %s\n",
369                         mx_strerror(mxret));
370                 goto failed_with_endpoint;
371         }
372         return 0;
373
374 failed_with_endpoint:
375         mx_close_endpoint(kmxlnd_data.kmx_endpt);
376 failed_with_init:
377         mx_finalize();
378         return -1;
379 }
380
381
382 /**
383  * mxlnd_thread_start - spawn a kernel thread with this function
384  * @fn - function pointer
385  * @arg - pointer to the parameter data
386  *
387  * Returns 0 on success and a negative value on failure
388  */
389 int
390 mxlnd_thread_start(int (*fn)(void *arg), void *arg)
391 {
392         int     pid = 0;
393         int     i   = (int) ((long) arg);
394
395         cfs_atomic_inc(&kmxlnd_data.kmx_nthreads);
396         init_completion(&kmxlnd_data.kmx_completions[i]);
397
398         pid = cfs_create_thread(fn, arg, 0);
399         if (pid < 0) {
400                 CERROR("cfs_create_thread() failed with %d\n", pid);
401                 cfs_atomic_dec(&kmxlnd_data.kmx_nthreads);
402         }
403         return pid;
404 }
405
406 /**
407  * mxlnd_thread_stop - decrement thread counter
408  *
409  * The thread returns 0 when it detects shutdown.
410  * We are simply decrementing the thread counter.
411  */
412 void
413 mxlnd_thread_stop(long id)
414 {
415         int     i       = (int) id;
416         cfs_atomic_dec (&kmxlnd_data.kmx_nthreads);
417         complete(&kmxlnd_data.kmx_completions[i]);
418 }
419
420 /**
421  * mxlnd_shutdown - stop IO, clean up state
422  * @ni - LNET interface handle
423  *
424  * No calls to the LND should be made after calling this function.
425  */
426 void
427 mxlnd_shutdown (lnet_ni_t *ni)
428 {
429         int                     i               = 0;
430         int                     nthreads        = MXLND_NDAEMONS
431                                                   + *kmxlnd_tunables.kmx_n_waitd;
432
433         LASSERT (ni == kmxlnd_data.kmx_ni);
434         LASSERT (ni->ni_data == &kmxlnd_data);
435         CDEBUG(D_NET, "in shutdown()\n");
436
437         CDEBUG(D_MALLOC, "before MXLND cleanup: libcfs_kmemory %d "
438                          "kmx_mem_used %ld\n", cfs_atomic_read(&libcfs_kmemory),
439                          kmxlnd_data.kmx_mem_used);
440
441
442         CDEBUG(D_NET, "setting shutdown = 1\n");
443         cfs_atomic_set(&kmxlnd_data.kmx_shutdown, 1);
444
445         switch (kmxlnd_data.kmx_init) {
446
447         case MXLND_INIT_ALL:
448
449                 /* calls write_[un]lock(kmx_global_lock) */
450                 mxlnd_del_peer(LNET_NID_ANY);
451
452                 /* wakeup request_waitds */
453                 mx_wakeup(kmxlnd_data.kmx_endpt);
454                 up(&kmxlnd_data.kmx_tx_queue_sem);
455                 up(&kmxlnd_data.kmx_conn_sem);
456                 mxlnd_sleep(2 * CFS_HZ);
457
458                 /* fall through */
459
460         case MXLND_INIT_THREADS:
461
462                 CDEBUG(D_NET, "waiting on threads\n");
463                 /* wait for threads to complete */
464                 for (i = 0; i < nthreads; i++) {
465                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
466                 }
467                 LASSERT(cfs_atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
468
469                 CDEBUG(D_NET, "freeing completions\n");
470                 MXLND_FREE(kmxlnd_data.kmx_completions,
471                             nthreads * sizeof(struct completion));
472
473                 /* fall through */
474
475         case MXLND_INIT_MX:
476
477                 CDEBUG(D_NET, "stopping mx\n");
478
479                 /* no peers left, close the endpoint */
480                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
481                 mx_finalize();
482
483                 /* fall through */
484
485         case MXLND_INIT_TXS:
486
487                 CDEBUG(D_NET, "freeing txs\n");
488
489                 /* free all txs and associated pages */
490                 mxlnd_free_txs();
491
492                 /* fall through */
493
494         case MXLND_INIT_DATA:
495
496                 CDEBUG(D_NET, "freeing peers\n");
497
498                 /* peers should be gone, but check again */
499                 mxlnd_free_peers();
500
501                 /* conn zombies should be gone, but check again */
502                 mxlnd_free_conn_zombies();
503
504                 /* fall through */
505
506         case MXLND_INIT_NOTHING:
507                 break;
508         }
509         CDEBUG(D_NET, "shutdown complete\n");
510
511         CDEBUG(D_MALLOC, "after MXLND cleanup: libcfs_kmemory %d "
512                          "kmx_mem_used %ld\n", cfs_atomic_read(&libcfs_kmemory),
513                          kmxlnd_data.kmx_mem_used);
514
515         kmxlnd_data.kmx_init = MXLND_INIT_NOTHING;
516         PORTAL_MODULE_UNUSE;
517         return;
518 }
519
520 /**
521  * mxlnd_startup - initialize state, open an endpoint, start IO
522  * @ni - LNET interface handle
523  *
524  * Initialize state, open an endpoint, start monitoring threads.
525  * Should only be called once.
526  */
527 int
528 mxlnd_startup (lnet_ni_t *ni)
529 {
530         int             i               = 0;
531         int             ret             = 0;
532         int             nthreads        = MXLND_NDAEMONS /* tx_queued, timeoutd, connd */
533                                           + *kmxlnd_tunables.kmx_n_waitd;
534         struct timeval  tv;
535
536         LASSERT (ni->ni_lnd == &the_kmxlnd);
537
538         if (kmxlnd_data.kmx_init != MXLND_INIT_NOTHING) {
539                 CERROR("Only 1 instance supported\n");
540                 return -EPERM;
541         }
542         CDEBUG(D_MALLOC, "before MXLND startup: libcfs_kmemory %d "
543                          "kmx_mem_used %ld\n", cfs_atomic_read(&libcfs_kmemory),
544                          kmxlnd_data.kmx_mem_used);
545
546         ni->ni_maxtxcredits = MXLND_TX_MSGS();
547         ni->ni_peertxcredits = *kmxlnd_tunables.kmx_peercredits;
548         if (ni->ni_maxtxcredits < ni->ni_peertxcredits)
549                 ni->ni_maxtxcredits = ni->ni_peertxcredits;
550
551         PORTAL_MODULE_USE;
552         memset (&kmxlnd_data, 0, sizeof (kmxlnd_data));
553
554         kmxlnd_data.kmx_ni = ni;
555         ni->ni_data = &kmxlnd_data;
556
557         cfs_gettimeofday(&tv);
558         kmxlnd_data.kmx_incarnation = (((__u64)tv.tv_sec) * 1000000) + tv.tv_usec;
559         CDEBUG(D_NET, "my incarnation is %llu\n", kmxlnd_data.kmx_incarnation);
560
561         rwlock_init (&kmxlnd_data.kmx_global_lock);
562         spin_lock_init (&kmxlnd_data.kmx_mem_lock);
563
564         CFS_INIT_LIST_HEAD (&kmxlnd_data.kmx_conn_reqs);
565         CFS_INIT_LIST_HEAD (&kmxlnd_data.kmx_conn_zombies);
566         CFS_INIT_LIST_HEAD (&kmxlnd_data.kmx_orphan_msgs);
567         spin_lock_init (&kmxlnd_data.kmx_conn_lock);
568         sema_init(&kmxlnd_data.kmx_conn_sem, 0);
569
570         for (i = 0; i < MXLND_HASH_SIZE; i++) {
571                 CFS_INIT_LIST_HEAD (&kmxlnd_data.kmx_peers[i]);
572         }
573
574         CFS_INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_idle);
575         spin_lock_init (&kmxlnd_data.kmx_tx_idle_lock);
576         kmxlnd_data.kmx_tx_next_cookie = 1;
577         CFS_INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_queue);
578         spin_lock_init (&kmxlnd_data.kmx_tx_queue_lock);
579         sema_init(&kmxlnd_data.kmx_tx_queue_sem, 0);
580
581         kmxlnd_data.kmx_init = MXLND_INIT_DATA;
582         /*****************************************************/
583
584         ret = mxlnd_init_txs();
585         if (ret != 0) {
586                 CERROR("Can't alloc tx descs: %d\n", ret);
587                 goto failed;
588         }
589         kmxlnd_data.kmx_init = MXLND_INIT_TXS;
590         /*****************************************************/
591
592         ret = mxlnd_init_mx(ni);
593         if (ret != 0) {
594                 CERROR("Can't init mx\n");
595                 goto failed;
596         }
597
598         kmxlnd_data.kmx_init = MXLND_INIT_MX;
599         /*****************************************************/
600
601         /* start threads */
602
603         MXLND_ALLOC(kmxlnd_data.kmx_completions,
604                      nthreads * sizeof(struct completion));
605         if (kmxlnd_data.kmx_completions == NULL) {
606                 CERROR("failed to alloc kmxlnd_data.kmx_completions\n");
607                 goto failed;
608         }
609         memset(kmxlnd_data.kmx_completions, 0,
610                nthreads * sizeof(struct completion));
611
612         CDEBUG(D_NET, "using %d %s in mx_wait_any()\n",
613                 *kmxlnd_tunables.kmx_n_waitd,
614                 *kmxlnd_tunables.kmx_n_waitd == 1 ? "thread" : "threads");
615
616         for (i = 0; i < *kmxlnd_tunables.kmx_n_waitd; i++) {
617                 ret = mxlnd_thread_start(mxlnd_request_waitd, (void*)((long)i));
618                 if (ret < 0) {
619                         CERROR("Starting mxlnd_request_waitd[%d] failed with %d\n", i, ret);
620                         cfs_atomic_set(&kmxlnd_data.kmx_shutdown, 1);
621                         mx_wakeup(kmxlnd_data.kmx_endpt);
622                         for (--i; i >= 0; i--) {
623                                 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
624                         }
625                         LASSERT(cfs_atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
626                         MXLND_FREE(kmxlnd_data.kmx_completions,
627                                 nthreads * sizeof(struct completion));
628
629                         goto failed;
630                 }
631         }
632         ret = mxlnd_thread_start(mxlnd_tx_queued, (void*)((long)i++));
633         if (ret < 0) {
634                 CERROR("Starting mxlnd_tx_queued failed with %d\n", ret);
635                 cfs_atomic_set(&kmxlnd_data.kmx_shutdown, 1);
636                 mx_wakeup(kmxlnd_data.kmx_endpt);
637                 for (--i; i >= 0; i--) {
638                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
639                 }
640                 LASSERT(cfs_atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
641                 MXLND_FREE(kmxlnd_data.kmx_completions,
642                         nthreads * sizeof(struct completion));
643                 goto failed;
644         }
645         ret = mxlnd_thread_start(mxlnd_timeoutd, (void*)((long)i++));
646         if (ret < 0) {
647                 CERROR("Starting mxlnd_timeoutd failed with %d\n", ret);
648                 cfs_atomic_set(&kmxlnd_data.kmx_shutdown, 1);
649                 mx_wakeup(kmxlnd_data.kmx_endpt);
650                 up(&kmxlnd_data.kmx_tx_queue_sem);
651                 for (--i; i >= 0; i--) {
652                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
653                 }
654                 LASSERT(cfs_atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
655                 MXLND_FREE(kmxlnd_data.kmx_completions,
656                         nthreads * sizeof(struct completion));
657                 goto failed;
658         }
659         ret = mxlnd_thread_start(mxlnd_connd, (void*)((long)i++));
660         if (ret < 0) {
661                 CERROR("Starting mxlnd_connd failed with %d\n", ret);
662                 cfs_atomic_set(&kmxlnd_data.kmx_shutdown, 1);
663                 mx_wakeup(kmxlnd_data.kmx_endpt);
664                 up(&kmxlnd_data.kmx_tx_queue_sem);
665                 for (--i; i >= 0; i--) {
666                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
667                 }
668                 LASSERT(cfs_atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
669                 MXLND_FREE(kmxlnd_data.kmx_completions,
670                         nthreads * sizeof(struct completion));
671                 goto failed;
672         }
673
674         kmxlnd_data.kmx_init = MXLND_INIT_THREADS;
675         /*****************************************************/
676
677         kmxlnd_data.kmx_init = MXLND_INIT_ALL;
678         CDEBUG(D_MALLOC, "startup complete (kmx_mem_used %ld)\n", kmxlnd_data.kmx_mem_used);
679
680         return 0;
681 failed:
682         CERROR("mxlnd_startup failed\n");
683         mxlnd_shutdown(ni);
684         return (-ENETDOWN);
685 }
686
687 static int mxlnd_init(void)
688 {
689         lnet_register_lnd(&the_kmxlnd);
690         return 0;
691 }
692
693 static void mxlnd_exit(void)
694 {
695         lnet_unregister_lnd(&the_kmxlnd);
696         return;
697 }
698
699 module_init(mxlnd_init);
700 module_exit(mxlnd_exit);
701
702 MODULE_LICENSE("GPL");
703 MODULE_AUTHOR("Myricom, Inc. - help@myri.com");
704 MODULE_DESCRIPTION("Kernel MyrinetExpress LND");
705 MODULE_VERSION("0.6.0");