Whamcloud - gitweb
- merge 0.7rc1 from b_devel to HEAD (20030612 merge point)
[fs/lustre-release.git] / lustre / portals / knals / gmnal / gmnal_cb.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Based on ksocknal and qswnal
5  *
6  * Copyright (C) 2002 Cluster File Systems, Inc.
7  *  Author: Robert Read  <rread@datarithm.net>
8  *
9  *   This file is part of Portals, http://www.sf.net/projects/sandiaportals/
10  *
11  *   Portals 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  *   Portals 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 Portals; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /* TODO
26  * preallocate send buffers, store on list
27  * put receive buffers on queue, handle with receive threads
28  * use routing
29  */
30
31 #include "gmnal.h"
32
33 extern kgmnal_rx_t *kgm_add_recv(kgmnal_data_t *,int);
34
35 static kgmnal_tx_t *
36 get_trans(void)
37 {
38         kgmnal_tx_t *t;
39         PORTAL_ALLOC(t, (sizeof(kgmnal_tx_t)));
40         return t;
41 }
42
43 static void
44 put_trans(kgmnal_tx_t *t)
45 {
46         PORTAL_FREE(t, sizeof(kgmnal_tx_t));
47 }
48
49 int
50 kgmnal_ispeer (ptl_nid_t nid)
51 {
52    unsigned int gmnid = (unsigned int)nid;
53    unsigned int nnids;
54
55    gm_max_node_id_in_use(kgmnal_data.kgm_port, &nnids);
56
57    return ((ptl_nid_t)gmnid == nid &&/* didn't lose high bits on conversion ? */
58            gmnid < nnids); /* it's in this machine */
59 }
60
61 /*
62  *  LIB functions follow
63  *
64  */
65 static int
66 kgmnal_read (nal_cb_t *nal, void *private, void *dst_addr, user_ptr src_addr,
67              size_t len)
68 {
69         CDEBUG(D_NET, "0x%Lx: reading %ld bytes from %p -> %p\n",
70                nal->ni.nid, (long)len, src_addr, dst_addr );
71         memcpy( dst_addr, src_addr, len );
72         return 0;
73 }
74
75 static int
76 kgmnal_write(nal_cb_t *nal, void *private, user_ptr dst_addr, void *src_addr,
77              size_t len)
78 {
79         CDEBUG(D_NET, "0x%Lx: writing %ld bytes from %p -> %p\n",
80                nal->ni.nid, (long)len, src_addr, dst_addr );
81         memcpy( dst_addr, src_addr, len );
82         return 0;
83 }
84
85 static void *
86 kgmnal_malloc(nal_cb_t *nal, size_t len)
87 {
88         void *buf;
89
90         PORTAL_ALLOC(buf, len);
91         return buf;
92 }
93
94 static void
95 kgmnal_free(nal_cb_t *nal, void *buf, size_t len)
96 {
97         PORTAL_FREE(buf, len);
98 }
99
100 static void
101 kgmnal_printf(nal_cb_t *nal, const char *fmt, ...)
102 {
103         va_list                ap;
104         char msg[256];
105
106         if (portal_debug & D_NET) {
107                 va_start( ap, fmt );
108                 vsnprintf( msg, sizeof(msg), fmt, ap );
109                 va_end( ap );
110
111                 printk("CPUId: %d %s",smp_processor_id(), msg);
112         }
113 }
114
115
116 static void
117 kgmnal_cli(nal_cb_t *nal, unsigned long *flags)
118 {
119         kgmnal_data_t *data= nal->nal_data;
120
121         spin_lock_irqsave(&data->kgm_dispatch_lock,*flags);
122 }
123
124
125 static void
126 kgmnal_sti(nal_cb_t *nal, unsigned long *flags)
127 {
128         kgmnal_data_t *data= nal->nal_data;
129
130         spin_unlock_irqrestore(&data->kgm_dispatch_lock,*flags);
131 }
132
133
134 static int
135 kgmnal_dist(nal_cb_t *nal, ptl_nid_t nid, unsigned long *dist)
136 {
137         /* network distance doesn't mean much for this nal */
138         if ( nal->ni.nid == nid ) {
139                 *dist = 0;
140         } else {
141                 *dist = 1;
142         }
143
144         return 0;
145 }
146
147 /* FIXME rmr: add rounting code here */
148 static void
149 kgmnal_tx_done(kgmnal_tx_t  *trans, int error)
150 {
151         lib_finalize(trans->ktx_nal, trans->ktx_private, trans->ktx_cookie);
152
153         gm_dma_free(kgmnal_data.kgm_port, trans->ktx_buffer);
154
155         trans->ktx_buffer = NULL;
156         trans->ktx_len = 0;
157
158         put_trans(trans);
159 }
160 static char * gm_error_strings[GM_NUM_STATUS_CODES] = {
161         [GM_SUCCESS] = "GM_SUCCESS",
162         [GM_SEND_TIMED_OUT] = "GM_SEND_TIMED_OUT",
163         [GM_SEND_REJECTED] = "GM_SEND_REJECTED",
164         [GM_SEND_TARGET_PORT_CLOSED] = "GM_SEND_TARGET_PORT_CLOSED",
165         [GM_SEND_TARGET_NODE_UNREACHABLE] = "GM_SEND_TARGET_NODE_UNREACHABLE",
166         [GM_SEND_DROPPED] = "GM_SEND_DROPPED",
167         [GM_SEND_PORT_CLOSED] = "GM_SEND_PORT_CLOSED",
168 };
169
170 inline char * get_error(int status)
171 {
172         if (gm_error_strings[status] != NULL)
173                 return gm_error_strings[status];
174         else
175                 return "Unknown error";
176 }
177
178 static void
179 kgmnal_errhandler(struct gm_port *p, void *context, gm_status_t status)
180 {
181         CDEBUG(D_NET,"error callback: ktx %p status %d\n", context, status);
182 }
183
184 static void
185 kgmnal_txhandler(struct gm_port *p, void *context, gm_status_t status)
186 {
187         kgmnal_tx_t *ktx = (kgmnal_tx_t *)context;
188         int err = 0;
189
190         LASSERT (p != NULL);
191         LASSERT (ktx != NULL);
192
193         CDEBUG(D_NET,"ktx %p status %d nid 0x%x pid %d\n", ktx, status,
194                 ktx->ktx_tgt_node, ktx->ktx_tgt_port_id);
195
196         switch((int)status) {
197         case GM_SUCCESS:        /* normal */
198                 break;
199         case GM_SEND_TIMED_OUT: /* application error */
200         case GM_SEND_REJECTED:  /* size of msg unacceptable */
201         case GM_SEND_TARGET_PORT_CLOSED:
202                 CERROR("%s (%d):\n", get_error(status), status);
203                 gm_resume_sending(kgmnal_data.kgm_port, ktx->ktx_priority,
204                                   ktx->ktx_tgt_node, ktx->ktx_tgt_port_id,
205                                   kgmnal_errhandler, NULL);
206                 err = -EIO;
207                 break;
208         case GM_SEND_TARGET_NODE_UNREACHABLE:
209         case GM_SEND_PORT_CLOSED:
210                 CERROR("%s (%d):\n", get_error(status), status);
211                 gm_drop_sends(kgmnal_data.kgm_port, ktx->ktx_priority,
212                               ktx->ktx_tgt_node, ktx->ktx_tgt_port_id,
213                               kgmnal_errhandler, NULL);
214                 err = -EIO;
215                 break;
216         case GM_SEND_DROPPED:
217                 CERROR("%s (%d):\n", get_error(status), status);
218                 err = -EIO;
219                 break;
220         default:
221                 CERROR("Unknown status: %d\n", status);
222                 err = -EIO;
223                 break;
224         }
225
226         kgmnal_tx_done(ktx, err);
227 }
228
229 /*
230  */
231
232 static int
233 kgmnal_send(nal_cb_t        *nal,
234            void            *private,
235            lib_msg_t       *cookie,
236            ptl_hdr_t       *hdr,
237            int              type,
238            ptl_nid_t        nid,
239            ptl_pid_t        pid,
240            int              options,
241            unsigned int     niov,
242            lib_md_iov_t    *iov,
243            size_t           len)
244 {
245         /*
246          * ipnal assumes that this is the private as passed to lib_dispatch..
247          * so do we :/
248          */
249         kgmnal_tx_t *ktx=NULL;
250         int rc=0;
251         void * buf;
252         int buf_len = sizeof(ptl_hdr_t) + len;
253         int buf_size = 0;
254
255         LASSERT ((options & PTL_MD_KIOV) == 0);
256         
257         PROF_START(gmnal_send);
258
259
260         CDEBUG(D_NET, "sending %d bytes from %p to nid: 0x%Lx pid %d\n",
261                len, iov, nid, KGM_PORT_NUM);
262
263         /* ensure there is an available tx handle */
264
265         /* save transaction info to trans for later finalize and cleanup */
266         ktx = get_trans();
267         if (ktx == NULL) {
268                 rc = -ENOMEM;
269                 goto send_exit;
270         }
271
272         /* hmmm... GM doesn't support vectored write, so need to allocate buffer to coalesce
273            header and data.
274            Also, memory must be dma'able or registered with GM. */
275
276         if (buf_len <= MSG_LEN_SMALL) {
277                 buf_size = MSG_SIZE_SMALL;
278         } else if (buf_len <= MSG_LEN_LARGE) {
279                 buf_size = MSG_SIZE_LARGE;
280         } else {
281                 printk("kgmnal:request exceeds TX MTU size (%d).\n",
282                        MSG_SIZE_LARGE);
283                 rc = -1;
284                 goto send_exit;
285         }
286
287                buf = gm_dma_malloc(kgmnal_data.kgm_port, buf_len);
288         if (buf == NULL) {
289                 rc = -ENOMEM;
290                 goto send_exit;
291         }
292         memcpy(buf, hdr, sizeof(ptl_hdr_t));
293
294         if (len != 0)
295                 lib_copy_iov2buf(((char *)buf) + sizeof (ptl_hdr_t), 
296                                  options, niov, iov, len);
297
298         ktx->ktx_nal = nal;
299         ktx->ktx_private = private;
300         ktx->ktx_cookie = cookie;
301         ktx->ktx_len = buf_len;
302         ktx->ktx_size = buf_size;
303         ktx->ktx_buffer = buf;
304         ktx->ktx_priority = GM_LOW_PRIORITY;
305         ktx->ktx_tgt_node = nid;
306         ktx->ktx_tgt_port_id = KGM_PORT_NUM;
307
308         CDEBUG(D_NET, "gm_send %d bytes (size %d) from %p to nid: 0x%Lx "
309                "pid %d pri %d\n", buf_len, buf_size, iov, nid, KGM_PORT_NUM,
310                GM_LOW_PRIORITY);
311
312         gm_send_with_callback(kgmnal_data.kgm_port, buf, buf_size,
313                               buf_len, GM_LOW_PRIORITY,
314                               nid, KGM_PORT_NUM,
315                               kgmnal_txhandler, ktx);
316
317         PROF_FINISH(gmnal_send);
318  send_exit:
319         return rc;
320 }
321 void
322 kgmnal_fwd_packet (void *arg, kpr_fwd_desc_t *fwd)
323 {
324         CERROR ("forwarding not implemented\n");
325 }
326
327 void
328 kqswnal_fwd_callback (void *arg, int error)
329 {
330         CERROR ("forwarding not implemented\n");
331 }
332
333
334 static inline void
335 kgmnal_requeue_rx(kgmnal_rx_t *krx)
336 {
337         gm_provide_receive_buffer(kgmnal_data.kgm_port, krx->krx_buffer,
338                                   krx->krx_size, krx->krx_priority);
339 }
340
341 /* Process a received portals packet */
342
343 /* Receive Interrupt Handler */
344 static void kgmnal_rx(kgmnal_data_t *kgm, unsigned long len, unsigned int size,
345                       void * buf, unsigned int pri)
346 {
347         ptl_hdr_t  *hdr = buf;
348         kgmnal_rx_t krx;
349
350         CDEBUG(D_NET,"buf %p, len %ld\n", buf, len);
351
352         if ( len < sizeof( ptl_hdr_t ) ) {
353                 /* XXX what's this for? */
354                 if (kgm->kgm_shuttingdown)
355                         return;
356                 CERROR("kgmnal: did not receive complete portal header, "
357                        "len= %ld", len);
358                 gm_provide_receive_buffer(kgm->kgm_port, buf, size, pri);
359                 return;
360         }
361
362        /* might want to use seperate threads to handle receive */
363         krx.krx_buffer = buf;
364         krx.krx_len = len;
365         krx.krx_size = size;
366         krx.krx_priority = pri;
367
368         if ( hdr->dest_nid == kgmnal_lib.ni.nid ) {
369                 PROF_START(lib_parse);
370                 lib_parse(&kgmnal_lib, (ptl_hdr_t *)krx.krx_buffer, &krx);
371                 PROF_FINISH(lib_parse);
372         } else if (kgmnal_ispeer(hdr->dest_nid)) {
373                 /* should have gone direct to peer */
374                 CERROR("dropping packet from 0x%llx to 0x%llx: target is "
375                        "a peer", hdr->src_nid, hdr->dest_nid);
376                 kgmnal_requeue_rx(&krx);
377         } else {
378                 /* forward to gateway */
379                 CERROR("forwarding not implemented yet");
380                 kgmnal_requeue_rx(&krx);
381         }
382
383         return;
384 }
385
386
387 static int kgmnal_recv(nal_cb_t     *nal,
388                       void         *private,
389                       lib_msg_t    *cookie,
390                       int           options,
391                       unsigned int  niov,
392                       lib_md_iov_t *iov,
393                       size_t        mlen,
394                       size_t        rlen)
395 {
396         kgmnal_rx_t *krx = private;
397
398         LASSERT ((options & PTL_MD_KIOV) == 0);
399
400         CDEBUG(D_NET,"mlen=%d, rlen=%d\n", mlen, rlen);
401
402         /* What was actually received must be >= what sender claims to
403          * have sent.  This is an LASSERT, since lib-move doesn't
404          * check cb return code yet. */
405         LASSERT (krx->krx_len >= sizeof (ptl_hdr_t) + rlen);
406         LASSERT (mlen <= rlen);
407
408         PROF_START(gmnal_recv);
409
410         if(mlen != 0) {
411                 PROF_START(memcpy);
412                 lib_copy_buf2iov (options, niov, iov, 
413                                   krx->krx_buffer + sizeof (ptl_hdr_t), mlen);
414                 PROF_FINISH(memcpy);
415         }
416
417         PROF_START(lib_finalize);
418         lib_finalize(nal, private, cookie);
419         PROF_FINISH(lib_finalize);
420
421         kgmnal_requeue_rx(krx);
422
423         PROF_FINISH(gmnal_recv);
424
425         return rlen;
426 }
427
428
429 static void kgmnal_shutdown(void * none)
430 {
431         CERROR("called\n");
432         return;
433 }
434
435 /*
436  * Set terminate and use alarm to wake up the recv thread.
437  */
438 static void  recv_shutdown(kgmnal_data_t *kgm)
439 {
440         gm_alarm_t alarm;
441
442         kgm->kgm_shuttingdown = 1;
443         gm_initialize_alarm(&alarm);
444         gm_set_alarm(kgm->kgm_port, &alarm, 1, kgmnal_shutdown, NULL);
445 }
446
447 int kgmnal_end(kgmnal_data_t *kgm)
448 {
449
450         /* wait for sends to finish ? */
451         /* remove receive buffers */
452         /* shutdown receive thread */
453
454         recv_shutdown(kgm);
455
456         return 0;
457 }
458
459 /* Used only for the spinner */
460 int kgmnal_recv_thread(void *arg)
461 {
462         kgmnal_data_t *kgm = arg;
463
464         LASSERT(kgm != NULL);
465
466         kportal_daemonize("kgmnal_rx");
467         
468         while(1) {
469                 gm_recv_event_t *e;
470                 int priority = GM_LOW_PRIORITY;
471                 if (kgm->kgm_shuttingdown)
472                         break;
473
474                 e = gm_blocking_receive_no_spin(kgm->kgm_port);
475                 if (e == NULL) {
476                         CERROR("gm_blocking_receive returned NULL\n");
477                         break;
478                 }
479
480                 switch(gm_ntohc(e->recv.type)) {
481                 case GM_HIGH_RECV_EVENT:
482                         priority = GM_HIGH_PRIORITY;
483                         /* fall through */
484                 case GM_RECV_EVENT:
485                         kgmnal_rx(kgm, gm_ntohl(e->recv.length),
486                                   gm_ntohc(e->recv.size),
487                                   gm_ntohp(e->recv.buffer), priority);
488                         break;
489                 case GM_ALARM_EVENT:
490                         CERROR("received alarm");
491                         gm_unknown(kgm->kgm_port, e);
492                         break;
493                 case GM_BAD_SEND_DETECTED_EVENT: /* ?? */
494                         CERROR("received bad send!\n");
495                         break;
496                 default:
497                         gm_unknown(kgm->kgm_port, e);
498                 }
499         }
500
501         CERROR("shuttting down.\n");
502         return 0;
503 }
504
505 nal_cb_t kgmnal_lib = {
506         nal_data: &kgmnal_data,                /* NAL private data */
507         cb_send: kgmnal_send,
508         cb_recv: kgmnal_recv,
509         cb_read: kgmnal_read,
510         cb_write: kgmnal_write,
511         cb_malloc: kgmnal_malloc,
512         cb_free: kgmnal_free,
513         cb_printf: kgmnal_printf,
514         cb_cli: kgmnal_cli,
515         cb_sti: kgmnal_sti,
516         cb_dist: kgmnal_dist
517 };