Whamcloud - gitweb
b=2776
[fs/lustre-release.git] / lustre / portals / knals / scimacnal / scimacnal_cb.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:cindent:
3  *
4  * Copyright (C) 2003 High Performance Computing Center North (HPC2N)
5  *   Author: Niklas Edmundsson <nikke@hpc2n.umu.se>
6
7  *
8  * This file is part of Portals, http://www.sf.net/projects/lustre/
9  *
10  * Portals is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General Public
12  * License as published by the Free Software Foundation.
13  *
14  * Portals is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Portals; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25 #include "scimacnal.h"
26
27 static int 
28 kscimacnal_read (nal_cb_t *nal, void *private,
29                 void *dst_addr, user_ptr src_addr, size_t len)
30 {
31         CDEBUG(D_NET, "0x%Lx: reading %ld bytes from %p -> %p\n",
32                nal->ni.nid, (long)len, src_addr, dst_addr );
33         memcpy( dst_addr, src_addr, len );
34         return 0;
35 }
36
37
38 static int 
39 kscimacnal_write(nal_cb_t *nal, void *private,
40                 user_ptr dst_addr, void *src_addr, size_t len)
41 {
42         CDEBUG(D_NET, "0x%Lx: writing %ld bytes from %p -> %p\n",
43                nal->ni.nid, (long)len, src_addr, dst_addr );
44         memcpy( dst_addr, src_addr, len );
45         return 0;
46 }
47
48
49 static void *
50 kscimacnal_malloc(nal_cb_t *nal, size_t len)
51 {
52         void *buf;
53
54         PORTAL_ALLOC(buf, len);
55         return buf;
56 }
57
58
59 static void 
60 kscimacnal_free(nal_cb_t *nal, void *buf, size_t len)
61 {
62         PORTAL_FREE(buf, len);
63 }
64
65
66 static void 
67 kscimacnal_printf(nal_cb_t *nal, const char *fmt, ...)
68 {
69         va_list         ap;
70         char msg[256]; 
71
72         if (portal_debug & D_NET) {
73                 va_start( ap, fmt );
74                 vsnprintf( msg, sizeof(msg), fmt, ap );
75                 va_end( ap );
76
77                 printk("Lustre: CPUId: %d %s",smp_processor_id(), msg);
78         }
79 }
80
81
82 static void 
83 kscimacnal_cli(nal_cb_t *nal, unsigned long *flags)
84 {
85         kscimacnal_data_t *data= nal->nal_data;
86
87         spin_lock_irqsave(&data->ksci_dispatch_lock,*flags);
88 }
89
90
91 static void 
92 kscimacnal_sti(nal_cb_t *nal, unsigned long *flags)
93 {
94         kscimacnal_data_t *data= nal->nal_data; 
95
96         spin_unlock_irqrestore(&data->ksci_dispatch_lock,*flags);
97 }
98
99
100 static void 
101 kscimacnal_callback(nal_cb_t *nal, void *private, lib_eq_t *eq, ptl_event_t *ev)
102 {
103         /* holding ksci_dispatch_lock */
104
105         if (eq->event_callback != NULL)
106                 eq->event_callback(ev);
107
108         /* We will wake theads sleeping in yield() here, AFTER the
109          * callback, when we implement blocking yield */
110 }
111
112 static int 
113 kscimacnal_dist(nal_cb_t *nal, ptl_nid_t nid, unsigned long *dist)
114 {
115         /* FIXME: Network distance has a meaning, but is there no easy
116          * way to figure it out (depends on routing) */
117
118         if ( nal->ni.nid == nid ) {
119                 *dist = 0;
120         } else {
121                 *dist = 1;
122         }
123
124         return 0;
125 }
126
127
128 static
129 char * get_mac_error(mac_status_t status) 
130 {
131         switch(status) {
132                 case MAC_MSG_STAT_OK:
133                         return "MAC_MSG_STAT_OK";
134                 case MAC_MSG_STAT_FREED:
135                         return "MAC_MSG_STAT_FREED";
136                 case MAC_MSG_STAT_ABORTED:
137                         return "MAC_MSG_STAT_ABORTED";
138                 case MAC_MSG_STAT_TIMEDOUT:
139                         return "MAC_MSG_STAT_TIMEDOUT";
140                 case MAC_MSG_STAT_NODEUNREACH:
141                         return "MAC_MSG_STAT_NODEUNREACH";
142                 case MAC_MSG_STAT_NETDOWN:
143                         return "MAC_MSG_STAT_NETDOWN";
144                 case MAC_MSG_STAT_RESET:
145                         return "MAC_MSG_STAT_RESET";
146                 case MAC_MSG_STAT_INITFAILED:
147                         return "MAC_MSG_STAT_INITFAILED";
148                 case MAC_MSG_STAT_SYNCFAILED:
149                         return "MAC_MSG_STAT_SYNCFAILED";
150                 case MAC_MSG_STAT_BADPROTO:
151                         return "MAC_MSG_STAT_BADPROTO";
152                 case MAC_MSG_STAT_NOBUFSPACE:
153                         return "MAC_MSG_STAT_NOBUFSPACE";
154                 case MAC_MSG_STAT_CONGESTION:
155                         return "MAC_MSG_STAT_CONGESTION";
156                 case MAC_MSG_STAT_OTHER:
157                         return "MAC_MSG_STAT_OTHER";
158                 default:
159                         return "Unknown error";
160         }
161 }
162
163
164 /* FIXME add routing code here ? */
165
166 /* Called by ScaMac when transmission is complete  (ie. message is released) */
167 static void 
168 kscimacnal_txrelease(mac_mblk_t *msg, mac_msg_status_t status, void *context)
169 {
170         kscimacnal_tx_t *ktx = (kscimacnal_tx_t *)context;
171         int err=0, i;
172         
173         LASSERT (ktx != NULL);
174         /* Unmap any mapped pages */
175         for(i=0; i<ktx->ktx_nmapped; i++) {
176                 kunmap(ktx->ktx_kpages[i]);
177         }
178
179         CDEBUG(D_NET, "kunmapped %d pages\n", ktx->ktx_nmapped);
180
181         /* Euh, there is no feedback when transmission fails?! */
182         switch(status) {
183                 case MAC_MSG_STAT_OK:        /* normal */
184                         break;
185                 default:
186                         CERROR("%s (%d):\n", get_mac_error(status), status);
187                         err = -EIO;
188                         break;
189         }
190
191         lib_finalize(ktx->ktx_nal, ktx->ktx_private, ktx->ktx_cookie,
192                      (err == 0) ? PTL_OK : PTL_FAIL);
193
194         PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
195 }
196
197
198 /* Called by portals when it wants to send a message.
199  * Since ScaMAC has it's own TX thread we don't bother setting up our own. */
200
201 /* FIXME: Read comments in qswnal_cb.c for _sendmsg and fix return-on-error
202  *        issues */
203 static inline int 
204 kscimacnal_sendmsg(nal_cb_t        *nal,
205                    void            *private,
206                    lib_msg_t       *cookie,
207                    ptl_hdr_t       *hdr,
208                    int              type, 
209                    ptl_nid_t        nid,
210                    ptl_pid_t        pid,
211                    unsigned int     payload_niov,
212                    struct iovec    *payload_iov,
213                    ptl_kiov_t      *payload_kiov,
214                    size_t           payload_len)
215 {
216         kscimacnal_tx_t    *ktx=NULL;
217         kscimacnal_data_t  *ksci = nal->nal_data;
218         int              rc=0;
219         int              buf_len = sizeof(ptl_hdr_t) + payload_len;
220         mac_mblk_t      *msg=NULL, *lastblk, *newblk;
221         unsigned long   physaddr;
222         
223
224         CDEBUG(D_NET, "sending %d bytes from %p/%p to nid "LPX64" niov: %d\n",
225                payload_len, payload_iov, payload_kiov, nid, payload_niov);
226
227         /* Basic sanity checks */
228         LASSERT(ksci != NULL);
229         LASSERT(hdr != NULL);
230         LASSERT (payload_len == 0 || payload_niov > 0);
231         LASSERT (payload_niov <= PTL_MD_MAX_IOV);
232         /* It must be OK to kmap() if required */
233         LASSERT (payload_kiov == NULL || !in_interrupt ());
234         /* payload is either all vaddrs or all pages */
235         LASSERT (!(payload_kiov != NULL && payload_iov != NULL));
236
237         /* Do real check if we can send this */
238         if (buf_len > mac_get_mtusize(ksci->ksci_machandle)) {
239                 CERROR("kscimacnal:request exceeds TX MTU size (%ld).\n",
240                                 mac_get_mtusize(ksci->ksci_machandle));
241                 return PTL_FAIL;
242         }
243
244
245         /* save transaction info for later finalize and cleanup */
246         PORTAL_ALLOC(ktx, (sizeof(kscimacnal_tx_t)));
247         if (!ktx) {
248                 return PTL_NO_SPACE;
249         }
250
251         ktx->ktx_nmapped = 0; /* Start with no mapped pages :) */
252
253         /* *SIGH* hdr is a stack variable in the calling function, so we
254          * need to copy it to a buffer. Zerocopy magic (or is it just
255          * deferred memcpy?) is annoying sometimes.  */
256         memcpy(&ktx->ktx_hdr, hdr, sizeof(ptl_hdr_t));
257
258         /* First, put the header in the main message mblk */
259         msg = mac_alloc_mblk(&ktx->ktx_hdr, sizeof(ptl_hdr_t),
260                         kscimacnal_txrelease, ktx);
261         if (!msg) {
262                 PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
263                 return PTL_NO_SPACE;
264         }
265         mac_put_mblk(msg, sizeof(ptl_hdr_t));
266         lastblk=msg;
267
268         /* Allocate additional mblks for each iov as needed.
269          * Essentially lib_copy_(k)iov2buf with a twist or two */
270         while (payload_len > 0)
271         {
272                 ptl_size_t       nob;
273                 char            *addr;
274
275                 LASSERT (payload_niov > 0);
276
277                 if(payload_iov != NULL) {
278                         nob = MIN (payload_iov->iov_len, payload_len);
279                         addr = payload_iov->iov_base;
280                 }
281                 else {
282                         nob = MIN (payload_kiov->kiov_len, payload_len);
283                         /* Bollocks. We need to handle paged IO for things to
284                          * work but there is no good way to do this. We
285                          * do it by kmap():ing all pages and keep them
286                          * mapped until scimac is done with them. */
287                         /* FIXME: kunmap() on error */
288                         addr = kmap(payload_kiov->kiov_page);
289                         ktx->ktx_kpages[ktx->ktx_nmapped++] = 
290                                 payload_kiov->kiov_page;
291                 }
292                 /* We don't need a callback on the additional mblks,
293                  * since all release callbacks seems to be called when
294                  * the entire message has been sent */
295                 newblk=mac_alloc_mblk(addr, nob, NULL, NULL);
296
297                 if(!newblk) {
298                         mac_free_msg(msg);
299                         PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
300                         return PTL_NO_SPACE;
301                 }
302                 mac_put_mblk(newblk, nob);
303                 mac_link_mblk(lastblk, newblk);
304                 lastblk=newblk;
305
306                 payload_len -= nob;
307                 payload_niov--;
308                 if(payload_iov != NULL) {
309                         payload_iov++;
310                 }
311                 else {
312                         payload_kiov++;
313                 }
314         }
315
316         CDEBUG(D_NET, "kmapped %d pages\n", ktx->ktx_nmapped);
317
318         ktx->ktx_nal = nal;
319         ktx->ktx_private = private;
320         ktx->ktx_cookie = cookie;
321
322         CDEBUG(D_NET, "mac_send %d bytes to nid: 0x%Lx\n", buf_len, nid);
323
324         physaddr = htonl(nid);
325
326         if((rc=mac_send(ksci->ksci_machandle, msg,
327                                         (mac_physaddr_t *) &physaddr))) {
328                 CERROR("kscimacnal: mac_send() failed, rc=%d\n", rc);
329                 mac_free_msg(msg);
330                 PORTAL_FREE(ktx, (sizeof(kscimacnal_tx_t)));
331                 return PTL_FAIL;
332         }
333
334         return PTL_OK;
335 }
336
337
338 static int
339 kscimacnal_send (nal_cb_t     *nal,
340                  void         *private,
341                  lib_msg_t    *cookie,
342                  ptl_hdr_t    *hdr,
343                  int           type,
344                  ptl_nid_t     nid,
345                  ptl_pid_t     pid,
346                  unsigned int  payload_niov,
347                  struct iovec *payload_iov,
348                  size_t        payload_nob)
349 {
350         return (kscimacnal_sendmsg (nal, private, cookie, hdr, type, nid, pid,
351                                 payload_niov, payload_iov, NULL, payload_nob));
352 }
353
354 static int
355 kscimacnal_send_pages (nal_cb_t     *nal,
356                        void         *private,
357                        lib_msg_t    *cookie,
358                        ptl_hdr_t    *hdr,
359                        int           type,
360                        ptl_nid_t     nid,
361                        ptl_pid_t     pid,
362                        unsigned int  payload_niov,
363                        ptl_kiov_t   *payload_kiov,
364                        size_t        payload_nob)
365 {
366         return (kscimacnal_sendmsg (nal, private, cookie, hdr, type, nid, pid,
367                                 payload_niov, NULL, payload_kiov, payload_nob));
368 }
369
370
371 void
372 kscimacnal_fwd_packet (void *arg, kpr_fwd_desc_t *fwd)
373 {
374         CERROR ("forwarding not implemented\n");
375 }
376
377
378 /* Process a received portals packet */
379 /* Called by the ScaMac RX thread when a packet is received */
380 void
381 kscimacnal_rx(mac_handle_t *handle, mac_mblk_t *msg, mac_msg_type_t type,
382                 void *userdata)
383 {
384         ptl_hdr_t       *hdr = NULL;
385         kscimacnal_rx_t     krx; 
386         mac_size_t       size;
387         kscimacnal_data_t  *ksci = userdata;
388
389         LASSERT(ksci != NULL);
390
391         if ( !ksci->ksci_init || ksci->ksci_shuttingdown || 
392                     type == MAC_MSG_TYPE_CTRL || type == MAC_MSG_TYPE_OTHER ) {
393                 /* We're not interested in messages not for us, ignore */
394                 mac_free_msg(msg);
395                 return;
396         }
397
398         size = mac_msg_size(msg);
399
400         CDEBUG(D_NET,"msg %p type %d, size %ld bytes (%ld mblks)\n", 
401                         msg, type, size, mac_msg_mblks(msg));
402
403         if( size < sizeof( ptl_hdr_t ) ) {
404                 /* XXX what's this for? */
405                 if (ksci->ksci_shuttingdown)
406                         return;
407                 CERROR("kscimacnal: did not receive complete portal header,"
408                                 "size= %ld\n", size);
409                 /* Free the message before exiting */
410                 mac_free_msg(msg);
411                 return;
412         }
413
414         /* Provide everything we know */
415         krx.handle = handle;
416         krx.msg = msg;
417         krx.type = type;
418         krx.userdata = userdata;
419
420         /* mac_msg_next returns the next mblk with unread data */
421         hdr = mac_get_mblk(mac_msg_next(msg), sizeof(ptl_hdr_t) );
422
423         if(!hdr) {
424                 CERROR("kscimacnal: no data block in message %p\n", msg);
425                 mac_free_msg(msg);
426                 return;
427         }
428
429         if ( hdr->dest_nid == kscimacnal_lib.ni.nid ) {
430                 PROF_START(lib_parse);
431                 /* sets wanted_len, iovs etc and calls our callback */
432                 lib_parse(&kscimacnal_lib, hdr, &krx);
433                 PROF_FINISH(lib_parse);
434 #if 0 /* FIXME: Is it possible to detect this? */
435         } else if (kgmnal_ispeer(hdr->dest_nid)) {
436                 /* should have gone direct to peer */
437                 CERROR("dropping packet from 0x%llx to 0x%llx:"
438                                 "target is a  peer\n",
439                                 hdr->src_nid, hdr->dest_nid);
440                 kgmnal_requeue_rx(&krx);
441 #endif /* if 0 FIXME */
442         } else {
443                 /* forward to gateway */
444                 CERROR("forwarding not implemented, mynid=0x%llx dest=0x%llx\n",
445                                 kscimacnal_lib.ni.nid, hdr->dest_nid);
446         }
447
448         mac_free_msg(msg);
449
450         CDEBUG(D_NET, "msg %p: Done\n", msg);
451 }
452
453
454 /* Called by portals to process a recieved packet */
455 inline static int 
456 kscimacnal_recvmsg(nal_cb_t     *nal, 
457                    void         *private, 
458                    lib_msg_t    *cookie, 
459                    unsigned int  niov, 
460                    struct iovec *iov, 
461                    ptl_kiov_t   *kiov,
462                    size_t        mlen, 
463                    size_t        rlen)
464 {
465         kscimacnal_rx_t    *krx = private;
466         mac_mblk_t      *mblk;
467         void            *src;
468         mac_size_t       pkt_len;
469         ptl_size_t       iovused=0;
470         char            *base=NULL;
471
472         LASSERT (krx != NULL);
473         LASSERT (krx->msg != NULL);
474
475         CDEBUG(D_NET,"msg %p: mlen=%d, rlen=%d, niov=%d\n",
476                         krx->msg, mlen, rlen, niov);
477
478         /* What was actually received must be >= what sender claims to have
479          * sent. */
480         LASSERT (mlen <= rlen); /* something is wrong if this isn't true */
481         if (mac_msg_size(krx->msg) < sizeof(ptl_hdr_t)+mlen) {
482                 /* We didn't receive everything lib thinks we did */
483                 CERROR("Bad message size: have %d, need %d + %d\n",
484                        mac_msg_size(krx->msg), sizeof(ptl_hdr_t), mlen);
485                 return (PTL_FAIL);
486         }
487
488         /* It must be OK to kmap() if required */
489         LASSERT (kiov == NULL || !in_interrupt ());
490         /* Either all pages or all vaddrs */
491         LASSERT (!(kiov != NULL && iov != NULL));
492
493         PROF_START(memcpy);
494
495         /* mac_msg_next returns next mblk with unread data (ie. can
496          * be same mblk */
497         while (mlen != 0 && (mblk = mac_msg_next(krx->msg))) {
498                 pkt_len = mac_mblk_len(mblk);
499                 src = mac_get_mblk(mblk, pkt_len); /* Next unread block */
500
501                 CDEBUG(D_NET,"msg %p: mblk: %p pkt_len: %ld  src: %p\n",
502                                 krx->msg, mblk, pkt_len, src);
503
504                 LASSERT(src != NULL);
505
506                 /* Essentially lib_copy_buf2(k)iov but with continuation
507                  * support, we "gracefully" thrash the argument vars ;) */
508                 while (pkt_len > 0) {
509                         ptl_size_t  nob, len;
510
511                         LASSERT (niov > 0);
512
513                         if(iov != NULL) {
514                                 LASSERT(iovused < iov->iov_len);
515                                 len = iov->iov_len;
516                                 base = iov->iov_base;
517                         }
518                         else {
519                                 LASSERT(iovused < kiov->kiov_len);
520                                 len = kiov->kiov_len;
521                                 if(base==NULL) {
522                                         /* New page */
523                                         base = kmap(kiov->kiov_page);
524                                 }
525                         }
526
527                         nob = MIN (len-iovused, pkt_len);
528                         CDEBUG(D_NET, "base: %p len: %d src: %p  nob: %d "
529                                         "iovused: %d\n",
530                                         base, len, src, nob, iovused);
531
532                         memcpy (base+iovused, src, nob);
533                         pkt_len -= nob;
534                         src += nob;
535
536                         if(nob+iovused < len) {
537                                 /* We didn't use all of the iov */
538                                 iovused+=nob;
539                         }
540                         else {
541                                 niov--;
542                                 iovused=0;
543                                 if(iov != NULL) {
544                                         iov++;
545                                 }
546                                 else {
547                                         kunmap(kiov->kiov_page);
548                                         base=NULL;
549                                         kiov++;
550                                 }
551                         }
552                 }
553         }
554         /* Just to make sure the last page is unmapped */
555         if(kiov!=NULL && base!=NULL) {
556                 kunmap(kiov->kiov_page);
557                 base=NULL;
558         }
559         PROF_FINISH(memcpy);
560
561         CDEBUG(D_NET, "Calling lib_finalize.\n");
562
563         PROF_START(lib_finalize);
564         lib_finalize(nal, private, cookie, PTL_OK);
565         PROF_FINISH(lib_finalize);
566
567         CDEBUG(D_NET, "Done.\n");
568
569         return PTL_OK;
570 }
571
572
573 static int
574 kscimacnal_recv(nal_cb_t     *nal,
575              void         *private,
576              lib_msg_t    *cookie,
577              unsigned int  niov,
578              struct iovec *iov,
579              size_t        mlen,
580              size_t        rlen)
581 {
582         return (kscimacnal_recvmsg (nal, private, cookie, niov, iov, NULL, mlen, rlen));
583 }
584
585
586 static int
587 kscimacnal_recv_pages (nal_cb_t     *nal,
588                     void         *private,
589                     lib_msg_t    *cookie,
590                     unsigned int  niov,
591                     ptl_kiov_t   *kiov,
592                     size_t        mlen,
593                     size_t        rlen)
594 {
595         return (kscimacnal_recvmsg (nal, private, cookie, niov, NULL, kiov, mlen, rlen));
596 }
597
598
599 nal_cb_t kscimacnal_lib = {
600         nal_data:       &kscimacnal_data,               /* NAL private data */
601         cb_send:         kscimacnal_send,
602         cb_send_pages:   kscimacnal_send_pages,
603         cb_recv:         kscimacnal_recv,
604         cb_recv_pages:   kscimacnal_recv_pages,
605         cb_read:         kscimacnal_read,
606         cb_write:        kscimacnal_write,
607         cb_malloc:       kscimacnal_malloc,
608         cb_free:         kscimacnal_free,
609         cb_printf:       kscimacnal_printf,
610         cb_cli:          kscimacnal_cli,
611         cb_sti:          kscimacnal_sti,
612         cb_callback:     kscimacnal_callback,
613         cb_dist:         kscimacnal_dist
614 };