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