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