Whamcloud - gitweb
659be44b80cfd808055f370ee0c0bb04bf16b93e
[fs/lustre-release.git] / lnet / klnds / mxlnd / mxlnd.c
1 /*
2  * -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
3  * vim:expandtab:shiftwidth=8:tabstop=8:
4  *
5  * GPL HEADER START
6  *
7  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 only,
11  * as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License version 2 for more details (a copy is included
17  * in the LICENSE file that accompanied this code).
18  *
19  * You should have received a copy of the GNU General Public License
20  * version 2 along with this program; If not, see [sun.com URL with a
21  * copy of GPLv2].
22  *
23  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24  * CA 95054 USA or visit www.sun.com if you need additional information or
25  * have any questions.
26  *
27  * GPL HEADER END
28  */
29 /*
30  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
31  * Use is subject to license terms.
32  *
33  * Copyright (C) 2006 Myricom, Inc.
34  */
35 /*
36  * This file is part of Lustre, http://www.lustre.org/
37  * Lustre is a trademark of Sun Microsystems, Inc.
38  *
39  * lnet/klnds/mxlnd/mxlnd.c
40  *
41  * Author: Eric Barton <eric@bartonsoftware.com>
42  * Author: Scott Atchley <atchley at myri.com>
43  */
44
45 #include "mxlnd.h"
46
47 lnd_t the_kmxlnd = {
48         .lnd_type       = MXLND,
49         .lnd_startup    = mxlnd_startup,
50         .lnd_shutdown   = mxlnd_shutdown,
51         .lnd_ctl        = mxlnd_ctl,
52         .lnd_send       = mxlnd_send,
53         .lnd_recv       = mxlnd_recv,
54 };
55
56 kmx_data_t               kmxlnd_data;
57
58 /**
59  * mxlnd_ctx_free - free ctx struct
60  * @ctx - a kmx_peer pointer
61  *
62  * The calling function should remove the ctx from the ctx list first
63  * then free it.
64  */
65 void
66 mxlnd_ctx_free(struct kmx_ctx *ctx)
67 {
68         if (ctx == NULL) return;
69
70         if (ctx->mxc_page != NULL) {
71                 __free_page(ctx->mxc_page);
72                 spin_lock(&kmxlnd_data.kmx_global_lock);
73                 kmxlnd_data.kmx_mem_used -= MXLND_EAGER_SIZE;
74                 spin_unlock(&kmxlnd_data.kmx_global_lock);
75         }
76
77         if (ctx->mxc_seg_list != NULL) {
78                 LASSERT(ctx->mxc_nseg > 0);
79                 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
80         }
81
82         MXLND_FREE (ctx, sizeof (*ctx));
83         return;
84 }
85
86 /**
87  * mxlnd_ctx_alloc - allocate and initialize a new ctx struct
88  * @ctxp - address of a kmx_ctx pointer
89  *
90  * Returns 0 on success and -EINVAL, -ENOMEM on failure
91  */
92 int
93 mxlnd_ctx_alloc(struct kmx_ctx **ctxp, enum kmx_req_type type)
94 {
95         int             ret     = 0;
96         struct kmx_ctx  *ctx    = NULL;
97
98         if (ctxp == NULL) return -EINVAL;
99
100         MXLND_ALLOC(ctx, sizeof (*ctx));
101         if (ctx == NULL) {
102                 CDEBUG(D_NETERROR, "Cannot allocate ctx\n");
103                 return -ENOMEM;
104         }
105         memset(ctx, 0, sizeof(*ctx));
106         spin_lock_init(&ctx->mxc_lock);
107
108         ctx->mxc_type = type;
109         ctx->mxc_page = alloc_page (GFP_KERNEL);
110         if (ctx->mxc_page == NULL) {
111                 CDEBUG(D_NETERROR, "Can't allocate page\n");
112                 ret = -ENOMEM;
113                 goto failed;
114         }
115         spin_lock(&kmxlnd_data.kmx_global_lock);
116         kmxlnd_data.kmx_mem_used += MXLND_EAGER_SIZE;
117         spin_unlock(&kmxlnd_data.kmx_global_lock);
118         ctx->mxc_msg = (struct kmx_msg *)((char *)page_address(ctx->mxc_page));
119         ctx->mxc_seg.segment_ptr = MX_PA_TO_U64(lnet_page2phys(ctx->mxc_page));
120         ctx->mxc_state = MXLND_CTX_IDLE;
121
122         *ctxp = ctx;
123         return 0;
124
125 failed:
126         mxlnd_ctx_free(ctx);
127         return ret;
128 }
129
130 /**
131  * mxlnd_ctx_init - reset ctx struct to the default values
132  * @ctx - a kmx_ctx pointer
133  */
134 void
135 mxlnd_ctx_init(struct kmx_ctx *ctx)
136 {
137         if (ctx == NULL) return;
138
139         /* do not change mxc_type */
140         ctx->mxc_incarnation = 0;
141         ctx->mxc_deadline = 0;
142         ctx->mxc_state = MXLND_CTX_IDLE;
143         /* ignore mxc_global_list */
144         if (ctx->mxc_list.next != NULL && !list_empty(&ctx->mxc_list)) {
145                 if (ctx->mxc_peer != NULL) spin_lock(&ctx->mxc_lock);
146                 list_del_init(&ctx->mxc_list);
147                 if (ctx->mxc_peer != NULL) spin_unlock(&ctx->mxc_lock);
148         }
149         /* ignore mxc_rx_list */
150         /* ignore mxc_lock */
151         ctx->mxc_nid = 0;
152         ctx->mxc_peer = NULL;
153         ctx->mxc_conn = NULL;
154         /* ignore mxc_msg */
155         /* ignore mxc_page */
156         ctx->mxc_lntmsg[0] = NULL;
157         ctx->mxc_lntmsg[1] = NULL;
158         ctx->mxc_msg_type = 0;
159         ctx->mxc_cookie = 0LL;
160         ctx->mxc_match = 0LL;
161         /* ctx->mxc_seg.segment_ptr points to mxc_page */
162         ctx->mxc_seg.segment_length = 0;
163         if (ctx->mxc_seg_list != NULL) {
164                 LASSERT(ctx->mxc_nseg > 0);
165                 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
166         }
167         ctx->mxc_seg_list = NULL;
168         ctx->mxc_nseg = 0;
169         ctx->mxc_nob = 0;
170         ctx->mxc_mxreq = NULL;
171         memset(&ctx->mxc_status, 0, sizeof(mx_status_t));
172         /* ctx->mxc_get */
173         /* ctx->mxc_put */
174
175         ctx->mxc_msg->mxm_type = 0;
176         ctx->mxc_msg->mxm_credits = 0;
177         ctx->mxc_msg->mxm_nob = 0;
178         ctx->mxc_msg->mxm_seq = 0;
179
180         return;
181 }
182
183 /**
184  * mxlnd_free_txs - free kmx_txs and associated pages
185  *
186  * Called from mxlnd_shutdown()
187  */
188 void
189 mxlnd_free_txs(void)
190 {
191         struct kmx_ctx          *tx     = NULL;
192         struct kmx_ctx          *next   = NULL;
193
194         list_for_each_entry_safe(tx, next, &kmxlnd_data.kmx_txs, mxc_global_list) {
195                 list_del_init(&tx->mxc_global_list);
196                 mxlnd_ctx_free(tx);
197         }
198         return;
199 }
200
201 /**
202  * mxlnd_init_txs - allocate tx descriptors then stash on txs and idle tx lists
203  *
204  * Called from mxlnd_startup()
205  * returns 0 on success, else -ENOMEM
206  */
207 int
208 mxlnd_init_txs(void)
209 {
210         int             ret     = 0;
211         int             i       = 0;
212         struct kmx_ctx  *tx      = NULL;
213
214         for (i = 0; i < *kmxlnd_tunables.kmx_ntx; i++) {
215                 ret = mxlnd_ctx_alloc(&tx, MXLND_REQ_TX);
216                 if (ret != 0) {
217                         mxlnd_free_txs();
218                         return ret;
219                 }
220                 mxlnd_ctx_init(tx);
221                 /* in startup(), no locks required */
222                 list_add_tail(&tx->mxc_global_list, &kmxlnd_data.kmx_txs);
223                 list_add_tail(&tx->mxc_list, &kmxlnd_data.kmx_tx_idle);
224         }
225         return 0;
226 }
227
228 /**
229  * mxlnd_free_rxs - free initial kmx_rx descriptors and associated pages
230  *
231  * Called from mxlnd_shutdown()
232  */
233 void
234 mxlnd_free_rxs(void)
235 {
236         struct kmx_ctx          *rx     = NULL;
237         struct kmx_ctx          *next   = NULL;
238
239         list_for_each_entry_safe(rx, next, &kmxlnd_data.kmx_rxs, mxc_global_list) {
240                 list_del_init(&rx->mxc_global_list);
241                 mxlnd_ctx_free(rx);
242         }
243         return;
244 }
245
246 /**
247  * mxlnd_init_rxs - allocate initial rx descriptors 
248  *
249  * Called from startup(). We create MXLND_MAX_PEERS plus MXLND_NTX
250  * rx descriptors. We create one for each potential peer to handle 
251  * the initial connect request. We create on for each tx in case the 
252  * send requires a non-eager receive.
253  *
254  * Returns 0 on success, else -ENOMEM
255  */
256 int
257 mxlnd_init_rxs(void)
258 {
259         int             ret     = 0;
260         int             i       = 0;
261         struct kmx_ctx  *rx      = NULL;
262
263         for (i = 0; i < (*kmxlnd_tunables.kmx_ntx + *kmxlnd_tunables.kmx_max_peers); i++) {
264                 ret = mxlnd_ctx_alloc(&rx, MXLND_REQ_RX);
265                 if (ret != 0) {
266                         mxlnd_free_rxs();
267                         return ret;
268                 }
269                 mxlnd_ctx_init(rx);
270                 /* in startup(), no locks required */
271                 list_add_tail(&rx->mxc_global_list, &kmxlnd_data.kmx_rxs);
272                 list_add_tail(&rx->mxc_list, &kmxlnd_data.kmx_rx_idle);
273         }
274         return 0;
275 }
276
277 /**
278  * mxlnd_free_peers - free peers
279  *
280  * Called from mxlnd_shutdown()
281  */
282 void
283 mxlnd_free_peers(void)
284 {
285         int                      i      = 0;
286         struct kmx_peer         *peer   = NULL;
287         struct kmx_peer         *next   = NULL;
288
289         for (i = 0; i < MXLND_HASH_SIZE; i++) {
290                 list_for_each_entry_safe(peer, next, &kmxlnd_data.kmx_peers[i], mxp_peers) {
291                         list_del_init(&peer->mxp_peers);
292                         if (peer->mxp_conn) mxlnd_conn_decref(peer->mxp_conn);
293                         mxlnd_peer_decref(peer);
294                 }
295         }
296 }
297
298 int
299 mxlnd_host_alloc(struct kmx_host **hostp)
300 {
301         struct kmx_host *host   = NULL;
302
303         MXLND_ALLOC(host, sizeof (*host));
304         if (host == NULL) {
305                 CDEBUG(D_NETERROR, "Cannot allocate host\n");
306                 return -1;
307         }
308         memset(host, 0, sizeof(*host));
309         spin_lock_init(&host->mxh_lock);
310
311         *hostp = host;
312
313         return 0;
314 }
315
316 void
317 mxlnd_host_free(struct kmx_host *host)
318 {
319         if (host == NULL) return;
320
321         if (host->mxh_hostname != NULL)
322                 MXLND_FREE(host->mxh_hostname, strlen(host->mxh_hostname) + 1);
323
324         MXLND_FREE(host, sizeof(*host));
325         return;
326 }
327
328 /**
329  * mxlnd_free_hosts - free kmx_hosts
330  *
331  * Called from mxlnd_shutdown()
332  */
333 void
334 mxlnd_free_hosts(void)
335 {
336         struct kmx_host         *host   = NULL;
337         struct kmx_host         *next   = NULL;
338
339         list_for_each_entry_safe(host, next, &kmxlnd_data.kmx_hosts, mxh_list) {
340                 list_del_init(&host->mxh_list);
341                 mxlnd_host_free(host);
342         }
343         return;
344 }
345
346 #define xstr(s) #s
347 #define str(s) xstr(s)
348 #define MXLND_MAX_BOARD 4       /* we expect hosts to have fewer NICs than this */
349 #define MXLND_MAX_EP_ID 16      /* we expect hosts to have less than this endpoints */
350
351 /* this parses a line that consists of:
352  * 
353  * IP              HOSTNAME           BOARD        ENDPOINT ID
354  * 169.192.0.113   mds01              0            3
355  * 
356  * By default MX uses the alias (short hostname). If you override
357  * it using mx_hostname to use the FQDN or some other name, the hostname
358  * here must match exactly.
359  */
360
361 /* MX_MAX_HOSTNAME_LEN = 80. See myriexpress.h */
362 int
363 mxlnd_parse_line(char *line)
364 {
365         int             i               = 0;
366         int             ret             = 0;
367         int             len             = 0;
368         u32             ip[4]           = { 0, 0, 0, 0 };
369         char            hostname[MX_MAX_HOSTNAME_LEN];
370         u32             board           = -1;
371         u32             ep_id           = -1;
372         struct kmx_host *host           = NULL;
373
374         if (line == NULL) return -1;
375
376         len = strlen(line);
377
378         if (len == 0) return -1;
379
380         /* convert tabs to spaces */
381         for (i = 0; i < len; i++) {
382                 if (line[i] == '\t') line[i] = ' ';
383         }
384
385         memset(&hostname, 0 , sizeof(hostname));
386         ret = sscanf(line, "%d.%d.%d.%d %" str(MX_MAX_HOSTNAME_LEN) "s %d %d", 
387                      &ip[0], &ip[1], &ip[2], &ip[3], hostname, &board, &ep_id);
388
389         if (ret != 7) {
390                 return -1;
391         }
392
393         /* check for valid values */
394         /* we assume a valid IP address (all <= 255), number of NICs,
395          * and number of endpoint IDs */
396         if (ip[0] > 255 || ip [1] > 255 || ip[2] > 255 || ip[3] > 255 ||
397             board > MXLND_MAX_BOARD || ep_id > MXLND_MAX_EP_ID) {
398                 CDEBUG(D_NETERROR, "Illegal value in \"%s\". Ignoring "
399                                    "this host.\n", line);
400                 return -1;
401         }
402
403         ret = mxlnd_host_alloc(&host);
404         if (ret != 0) return -1;
405
406         host->mxh_addr = ((ip[0]<<24)|(ip[1]<<16)|(ip[2]<<8)|ip[3]);
407         len = strlen(hostname);
408         MXLND_ALLOC(host->mxh_hostname, len + 1);
409         if (host->mxh_hostname == NULL) {
410                 mxlnd_host_free(host);
411                 return -ENOMEM;
412         }
413         memset(host->mxh_hostname, 0, len + 1);
414         strncpy(host->mxh_hostname, hostname, len);
415         host->mxh_board = board;
416         host->mxh_ep_id = ep_id;
417
418         spin_lock(&kmxlnd_data.kmx_hosts_lock);
419         list_add_tail(&host->mxh_list, &kmxlnd_data.kmx_hosts);
420         spin_unlock(&kmxlnd_data.kmx_hosts_lock);
421
422         return 0;
423 }
424
425 void
426 mxlnd_print_hosts(void)
427 {
428 #if MXLND_DEBUG
429         struct kmx_host         *host   = NULL;
430
431         list_for_each_entry(host, &kmxlnd_data.kmx_hosts, mxh_list) {
432                 int             ip[4];
433                 u32             addr    = host->mxh_addr;
434
435                 ip[0] = (addr >> 24) & 0xff;
436                 ip[1] = (addr >> 16) & 0xff;
437                 ip[2] = (addr >>  8) & 0xff;
438                 ip[3] = addr & 0xff;
439                 CDEBUG(D_NET, "\tip= %d.%d.%d.%d\n\thost= %s\n\tboard= %d\n\tep_id= %d\n\n",
440                             ip[0], ip[1], ip[2], ip[3],
441                             host->mxh_hostname, host->mxh_board, host->mxh_ep_id);
442         }
443 #endif
444         return;
445 }
446
447 #define MXLND_BUFSIZE (PAGE_SIZE - 1)
448
449 int
450 mxlnd_parse_hosts(char *filename)
451 {
452         int             ret             = 0;
453         s32             size            = 0;
454         s32             bufsize         = MXLND_BUFSIZE;
455         s32             allocd          = 0;
456         loff_t          offset          = 0;
457         struct file     *filp           = NULL;
458         struct inode    *inode          = NULL;
459         char            *buf            = NULL;
460         s32             buf_off         = 0;
461         char            *sep            = NULL;
462         char            *line           = NULL;
463
464         if (filename == NULL) return -1;
465
466         filp = filp_open(filename, O_RDONLY, 0);
467         if (IS_ERR(filp)) {
468                 CERROR("filp_open() failed for %s\n", filename);
469                 return -1;
470         }
471
472         inode = filp->f_dentry->d_inode;
473         if (!S_ISREG(inode->i_mode)) {
474                 CERROR("%s is not a regular file\n", filename);
475                 return -1;
476         }
477
478         size = (s32) inode->i_size;
479         if (size < MXLND_BUFSIZE) bufsize = size;
480         allocd = bufsize;
481         MXLND_ALLOC(buf, allocd + 1);
482         if (buf == NULL) {
483                 CERROR("Cannot allocate buf\n");
484                 filp_close(filp, current->files);
485                 return -1;
486         }
487
488         while (offset < size) {
489                 memset(buf, 0, bufsize + 1);
490                 ret = kernel_read(filp, (unsigned long) offset, buf, (unsigned long) bufsize);
491                 if (ret < 0) {
492                         CDEBUG(D_NETERROR, "kernel_read() returned %d - closing %s\n", ret, filename);
493                         filp_close(filp, current->files);
494                         MXLND_FREE(buf, allocd + 1);
495                         return -1;
496                 }
497
498                 if (ret < bufsize) bufsize = ret;
499                 buf_off = 0;
500                 while (buf_off < bufsize) {
501                         sep = strchr(buf + buf_off, '\n');
502                         if (sep != NULL) {
503                                 /* we have a line */
504                                 line = buf + buf_off;
505                                 *sep = '\0';
506                                 ret = mxlnd_parse_line(line);
507                                 if (ret != 0 && strlen(line) != 0) {
508                                         CDEBUG(D_NETERROR, "Failed to parse \"%s\". Ignoring this host.\n", line);
509                                 }
510                                 buf_off += strlen(line) + 1;
511                         } else {
512                                 /* last line or we need to read more */
513                                 line = buf + buf_off;
514                                 ret = mxlnd_parse_line(line);
515                                 if (ret != 0) {
516                                         bufsize -= strlen(line) + 1;
517                                 }
518                                 buf_off += strlen(line) + 1;
519                         }
520                 }
521                 offset += bufsize;
522                 bufsize = MXLND_BUFSIZE;
523         }
524
525         MXLND_FREE(buf, allocd + 1);
526         filp_close(filp, current->files);
527         mxlnd_print_hosts();
528
529         return 0;
530 }
531
532 /**
533  * mxlnd_init_mx - open the endpoint, set out ID, register the EAGER callback
534  * @ni - the network interface
535  *
536  * Returns 0 on success, -1 on failure
537  */
538 int
539 mxlnd_init_mx(lnet_ni_t *ni)
540 {
541         int                     ret     = 0;
542         int                     found   = 0;
543         mx_return_t             mxret;
544         mx_endpoint_addr_t      addr;
545         u32                     board   = *kmxlnd_tunables.kmx_board;
546         u32                     ep_id   = *kmxlnd_tunables.kmx_ep_id;
547         u64                     nic_id  = 0LL;
548         struct kmx_host         *host   = NULL;
549
550         mxret = mx_init();
551         if (mxret != MX_SUCCESS) {
552                 CERROR("mx_init() failed with %s (%d)\n", mx_strerror(mxret), mxret);
553                 return -1;
554         }
555
556         ret = mxlnd_parse_hosts(*kmxlnd_tunables.kmx_hosts);
557         if (ret != 0) {
558                 if (*kmxlnd_tunables.kmx_hosts != NULL) {
559                         CERROR("mxlnd_parse_hosts(%s) failed\n", *kmxlnd_tunables.kmx_hosts);
560                 }
561                 mx_finalize();
562                 return -1;
563         }
564
565         list_for_each_entry(host, &kmxlnd_data.kmx_hosts, mxh_list) {
566                 if (strcmp(host->mxh_hostname, system_utsname.nodename) == 0) {
567                         /* override the defaults and module parameters with 
568                          * the info from the hosts file */
569                         board = host->mxh_board;
570                         ep_id = host->mxh_ep_id;
571                         kmxlnd_data.kmx_localhost = host;
572                         CDEBUG(D_NET, "my hostname is %s board %d ep_id %d\n", kmxlnd_data.kmx_localhost->mxh_hostname, kmxlnd_data.kmx_localhost->mxh_board, kmxlnd_data.kmx_localhost->mxh_ep_id);
573                         found = 1;
574                         break;
575                 }
576         }
577
578         if (found == 0) {
579                 CERROR("no host entry found for localhost\n");
580                 mx_finalize();
581                 return -1;
582         }
583
584         mxret = mx_open_endpoint(board, ep_id, MXLND_MSG_MAGIC, 
585                                  NULL, 0, &kmxlnd_data.kmx_endpt);
586         if (mxret != MX_SUCCESS) {
587                 CERROR("mx_open_endpoint() failed with %d\n", mxret);
588                 mx_finalize();
589                 return -1;
590         }
591
592         mx_get_endpoint_addr(kmxlnd_data.kmx_endpt, &addr);
593         mx_decompose_endpoint_addr(addr, &nic_id, &ep_id);
594
595         LASSERT(host != NULL);
596         ni->ni_nid = LNET_MKNID(LNET_NIDNET(ni->ni_nid), host->mxh_addr);
597
598         CDEBUG(D_NET, "My NID is 0x%llx\n", ni->ni_nid);
599
600         /* this will catch all unexpected receives. */
601         mxret = mx_register_unexp_handler(kmxlnd_data.kmx_endpt,
602                                           (mx_unexp_handler_t) mxlnd_unexpected_recv,
603                                           NULL);
604         if (mxret != MX_SUCCESS) {
605                 CERROR("mx_register_unexp_callback() failed with %s\n", 
606                          mx_strerror(mxret));
607                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
608                 mx_finalize();
609                 return -1;
610         }
611         mxret = mx_set_request_timeout(kmxlnd_data.kmx_endpt, NULL, MXLND_COMM_TIMEOUT/HZ*1000);
612         if (mxret != MX_SUCCESS) {
613                 CERROR("mx_set_request_timeout() failed with %s\n", 
614                         mx_strerror(mxret));
615                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
616                 mx_finalize();
617                 return -1;
618         }
619         return 0;
620 }
621
622
623 /**
624  * mxlnd_thread_start - spawn a kernel thread with this function
625  * @fn - function pointer
626  * @arg - pointer to the parameter data
627  *
628  * Returns 0 on success and a negative value on failure
629  */
630 int
631 mxlnd_thread_start(int (*fn)(void *arg), void *arg)
632 {
633         int     pid = 0;
634         int     i   = (int) ((long) arg);
635
636         atomic_inc(&kmxlnd_data.kmx_nthreads);
637         init_completion(&kmxlnd_data.kmx_completions[i]);
638
639         pid = kernel_thread (fn, arg, 0);
640         if (pid < 0) {
641                 CERROR("kernel_thread() failed with %d\n", pid);
642                 atomic_dec(&kmxlnd_data.kmx_nthreads);
643         }
644         return pid;
645 }
646
647 /**
648  * mxlnd_thread_stop - decrement thread counter
649  *
650  * The thread returns 0 when it detects shutdown.
651  * We are simply decrementing the thread counter.
652  */
653 void
654 mxlnd_thread_stop(long id)
655 {
656         int     i       = (int) id;
657         atomic_dec (&kmxlnd_data.kmx_nthreads);
658         complete(&kmxlnd_data.kmx_completions[i]);
659 }
660
661 /**
662  * mxlnd_shutdown - stop IO, clean up state
663  * @ni - LNET interface handle
664  *
665  * No calls to the LND should be made after calling this function.
666  */
667 void
668 mxlnd_shutdown (lnet_ni_t *ni)
669 {
670         int     i               = 0;
671         int     nthreads        = 2 + *kmxlnd_tunables.kmx_n_waitd;
672
673         LASSERT (ni == kmxlnd_data.kmx_ni);
674         LASSERT (ni->ni_data == &kmxlnd_data);
675         CDEBUG(D_NET, "in shutdown()\n");
676
677         CDEBUG(D_MALLOC, "before MXLND cleanup: libcfs_kmemory %d "
678                          "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory), 
679                          kmxlnd_data.kmx_mem_used);
680
681         switch (kmxlnd_data.kmx_init) {
682
683         case MXLND_INIT_ALL:
684
685                 CDEBUG(D_NET, "setting shutdown = 1\n");
686                 /* set shutdown and wakeup request_waitds */
687                 kmxlnd_data.kmx_shutdown = 1;
688                 mb();
689                 mx_wakeup(kmxlnd_data.kmx_endpt);
690                 up(&kmxlnd_data.kmx_tx_queue_sem);
691                 mxlnd_sleep(2 * HZ);
692
693                 /* fall through */
694
695         case MXLND_INIT_THREADS:
696
697                 CDEBUG(D_NET, "waiting on threads\n");
698                 /* wait for threads to complete */
699                 for (i = 0; i < nthreads; i++) {
700                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
701                 }
702                 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
703
704                 CDEBUG(D_NET, "freeing completions\n");
705                 MXLND_FREE(kmxlnd_data.kmx_completions, 
706                             MXLND_NCOMPLETIONS * sizeof(struct completion));
707
708                 /* fall through */
709
710         case MXLND_INIT_MX:
711
712                 CDEBUG(D_NET, "stopping mx\n");
713
714                 /* wakeup waiters if they missed the above.
715                  * close endpoint to stop all traffic.
716                  * this will cancel and cleanup all requests, etc. */
717
718                 mx_wakeup(kmxlnd_data.kmx_endpt);
719                 mx_close_endpoint(kmxlnd_data.kmx_endpt);
720                 mx_finalize();
721
722                 CDEBUG(D_NET, "mxlnd_free_hosts();\n");
723                 mxlnd_free_hosts();
724
725                 /* fall through */
726
727         case MXLND_INIT_RXS:
728
729                 CDEBUG(D_NET, "freeing rxs\n");
730
731                 /* free all rxs and associated pages */
732                 mxlnd_free_rxs();
733
734                 /* fall through */
735
736         case MXLND_INIT_TXS:
737
738                 CDEBUG(D_NET, "freeing txs\n");
739
740                 /* free all txs and associated pages */
741                 mxlnd_free_txs();
742
743                 /* fall through */
744
745         case MXLND_INIT_DATA:
746
747                 CDEBUG(D_NET, "freeing peers\n");
748
749                 /* free peer list */
750                 mxlnd_free_peers();
751
752                 /* fall through */
753
754         case MXLND_INIT_NOTHING:
755                 break;
756         }
757         CDEBUG(D_NET, "shutdown complete\n");
758
759         CDEBUG(D_MALLOC, "after MXLND cleanup: libcfs_kmemory %d "
760                          "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory), 
761                          kmxlnd_data.kmx_mem_used);
762
763         kmxlnd_data.kmx_init = MXLND_INIT_NOTHING;
764         PORTAL_MODULE_UNUSE;
765         return;
766 }
767
768 /**
769  * mxlnd_startup - initialize state, open an endpoint, start IO
770  * @ni - LNET interface handle
771  *
772  * Initialize state, open an endpoint, start monitoring threads.
773  * Should only be called once.
774  */
775 int
776 mxlnd_startup (lnet_ni_t *ni)
777 {
778         int             i               = 0;
779         int             ret             = 0;
780         int             nthreads        = 2; /* for timeoutd and tx_queued */
781         struct timeval  tv;
782
783         LASSERT (ni->ni_lnd == &the_kmxlnd);
784
785         if (kmxlnd_data.kmx_init != MXLND_INIT_NOTHING) {
786                 CERROR("Only 1 instance supported\n");
787                 return -EPERM;
788         }
789         CDEBUG(D_MALLOC, "before MXLND startup: libcfs_kmemory %d "
790                          "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory), 
791                          kmxlnd_data.kmx_mem_used);
792
793         /* reserve 1/2 of tx for connect request messages */
794         ni->ni_maxtxcredits = *kmxlnd_tunables.kmx_ntx / 2;
795         ni->ni_peertxcredits = *kmxlnd_tunables.kmx_credits;
796         if (ni->ni_maxtxcredits < ni->ni_peertxcredits)
797                 ni->ni_maxtxcredits = ni->ni_peertxcredits;
798
799         PORTAL_MODULE_USE;
800         memset (&kmxlnd_data, 0, sizeof (kmxlnd_data));
801
802         kmxlnd_data.kmx_ni = ni;
803         ni->ni_data = &kmxlnd_data;
804
805         do_gettimeofday(&tv);
806         kmxlnd_data.kmx_incarnation = (((__u64)tv.tv_sec) * 1000000) + tv.tv_usec;
807         CDEBUG(D_NET, "my incarnation is %lld\n", kmxlnd_data.kmx_incarnation);
808
809         spin_lock_init (&kmxlnd_data.kmx_global_lock);
810
811         INIT_LIST_HEAD (&kmxlnd_data.kmx_conn_req);
812         spin_lock_init (&kmxlnd_data.kmx_conn_lock);
813         sema_init(&kmxlnd_data.kmx_conn_sem, 0);
814
815         INIT_LIST_HEAD (&kmxlnd_data.kmx_hosts);
816         spin_lock_init (&kmxlnd_data.kmx_hosts_lock);
817
818         for (i = 0; i < MXLND_HASH_SIZE; i++) {
819                 INIT_LIST_HEAD (&kmxlnd_data.kmx_peers[i]);
820         }
821         rwlock_init (&kmxlnd_data.kmx_peers_lock);
822
823         INIT_LIST_HEAD (&kmxlnd_data.kmx_txs);
824         INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_idle);
825         spin_lock_init (&kmxlnd_data.kmx_tx_idle_lock);
826         kmxlnd_data.kmx_tx_next_cookie = 1;
827         INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_queue);
828         spin_lock_init (&kmxlnd_data.kmx_tx_queue_lock);
829         sema_init(&kmxlnd_data.kmx_tx_queue_sem, 0);
830
831         INIT_LIST_HEAD (&kmxlnd_data.kmx_rxs);
832         spin_lock_init (&kmxlnd_data.kmx_rxs_lock);
833         INIT_LIST_HEAD (&kmxlnd_data.kmx_rx_idle);
834         spin_lock_init (&kmxlnd_data.kmx_rx_idle_lock);
835
836         kmxlnd_data.kmx_init = MXLND_INIT_DATA;
837         /*****************************************************/
838
839         ret = mxlnd_init_txs();
840         if (ret != 0) {
841                 CERROR("Can't alloc tx descs: %d\n", ret);
842                 goto failed;
843         }
844         kmxlnd_data.kmx_init = MXLND_INIT_TXS;
845         /*****************************************************/
846
847         ret = mxlnd_init_rxs();
848         if (ret != 0) {
849                 CERROR("Can't alloc rx descs: %d\n", ret);
850                 goto failed;
851         }
852         kmxlnd_data.kmx_init = MXLND_INIT_RXS;
853         /*****************************************************/
854
855         ret = mxlnd_init_mx(ni);
856         if (ret != 0) {
857                 CERROR("Can't init mx\n");
858                 goto failed;
859         }
860
861         kmxlnd_data.kmx_init = MXLND_INIT_MX;
862         /*****************************************************/
863
864         /* start threads */
865
866         nthreads += *kmxlnd_tunables.kmx_n_waitd;
867         MXLND_ALLOC (kmxlnd_data.kmx_completions,
868                      nthreads * sizeof(struct completion));
869         if (kmxlnd_data.kmx_completions == NULL) {
870                 CERROR("failed to alloc kmxlnd_data.kmx_completions\n");
871                 goto failed;
872         }
873         memset(kmxlnd_data.kmx_completions, 0, 
874                nthreads * sizeof(struct completion));
875
876         {
877                 CDEBUG(D_NET, "using %d %s in mx_wait_any()\n",
878                         *kmxlnd_tunables.kmx_n_waitd, 
879                         *kmxlnd_tunables.kmx_n_waitd == 1 ? "thread" : "threads");
880
881                 for (i = 0; i < *kmxlnd_tunables.kmx_n_waitd; i++) {
882                         ret = mxlnd_thread_start(mxlnd_request_waitd, (void*)((long)i));
883                         if (ret < 0) {
884                                 CERROR("Starting mxlnd_request_waitd[%d] failed with %d\n", i, ret);
885                                 kmxlnd_data.kmx_shutdown = 1;
886                                 mx_wakeup(kmxlnd_data.kmx_endpt);
887                                 for (--i; i >= 0; i--) {
888                                         wait_for_completion(&kmxlnd_data.kmx_completions[i]);
889                                 }
890                                 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
891                                 MXLND_FREE(kmxlnd_data.kmx_completions, 
892                                         MXLND_NCOMPLETIONS * sizeof(struct completion));
893
894                                 goto failed;
895                         }
896                 }
897                 ret = mxlnd_thread_start(mxlnd_tx_queued, (void*)((long)i++));
898                 if (ret < 0) {
899                         CERROR("Starting mxlnd_tx_queued failed with %d\n", ret);
900                         kmxlnd_data.kmx_shutdown = 1;
901                         mx_wakeup(kmxlnd_data.kmx_endpt);
902                         for (--i; i >= 0; i--) {
903                                 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
904                         }
905                         LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
906                         MXLND_FREE(kmxlnd_data.kmx_completions, 
907                                 MXLND_NCOMPLETIONS * sizeof(struct completion));
908                         goto failed;
909                 }
910                 ret = mxlnd_thread_start(mxlnd_timeoutd, (void*)((long)i++));
911                 if (ret < 0) {
912                         CERROR("Starting mxlnd_timeoutd failed with %d\n", ret);
913                         kmxlnd_data.kmx_shutdown = 1;
914                         mx_wakeup(kmxlnd_data.kmx_endpt);
915                         up(&kmxlnd_data.kmx_tx_queue_sem);
916                         for (--i; i >= 0; i--) {
917                                 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
918                         }
919                         LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
920                         MXLND_FREE(kmxlnd_data.kmx_completions, 
921                                 MXLND_NCOMPLETIONS * sizeof(struct completion));
922                         goto failed;
923                 }
924         }
925
926         kmxlnd_data.kmx_init = MXLND_INIT_THREADS;
927         /*****************************************************/
928
929         kmxlnd_data.kmx_init = MXLND_INIT_ALL;
930         CDEBUG(D_MALLOC, "startup complete (kmx_mem_used %ld)\n", kmxlnd_data.kmx_mem_used);
931
932         return 0;
933 failed:
934         CERROR("mxlnd_startup failed\n");
935         mxlnd_shutdown(ni);
936         return (-ENETDOWN);
937 }
938
939 static int mxlnd_init(void)
940 {
941         lnet_register_lnd(&the_kmxlnd);
942         return 0;
943 }
944
945 static void mxlnd_exit(void)
946 {
947         lnet_unregister_lnd(&the_kmxlnd);
948         return;
949 }
950
951 module_init(mxlnd_init);
952 module_exit(mxlnd_exit);
953
954 MODULE_LICENSE("GPL");
955 MODULE_AUTHOR("Myricom, Inc. - help@myri.com");
956 MODULE_DESCRIPTION("Kernel MyrinetExpress LND");
957 MODULE_VERSION("0.5.0");