Whamcloud - gitweb
b=17167 libcfs: ensure all libcfs exported symbols to have cfs_ prefix
[fs/lustre-release.git] / lnet / ulnds / ptllnd / ptllnd_cb.c
index ec6170f..6930f9c 100644 (file)
@@ -1,19 +1,41 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * Copyright (C) 2005 Cluster File Systems, Inc. All rights reserved.
- *   Author: Eric Barton <eeb@bartonsoftware.com>
+ * GPL HEADER START
  *
- *   This file is part of the Lustre file system, http://www.lustre.org
- *   Lustre is a trademark of Cluster File Systems, Inc.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
- *   This file is confidential source code owned by Cluster File Systems.
- *   No viewing, modification, compilation, redistribution, or any other
- *   form of use is permitted except through a signed license agreement.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
  *
- *   If you have not signed such an agreement, then you have no rights to
- *   this file.  Please destroy it immediately and contact CFS.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
  *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright  2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * lnet/ulnds/ptllnd/ptllnd_cb.c
+ *
+ * Author: Eric Barton <eeb@bartonsoftware.com>
  */
 
 #include "ptllnd.h"
@@ -33,8 +55,10 @@ ptllnd_post_tx(ptllnd_tx_t *tx)
 {
         ptllnd_peer_t  *peer = tx->tx_peer;
 
+        LASSERT (tx->tx_type != PTLLND_MSG_TYPE_NOOP);
+
         ptllnd_set_tx_deadline(tx);
-        list_add_tail(&tx->tx_list, &peer->plp_txq);
+        cfs_list_add_tail(&tx->tx_list, &peer->plp_txq);
         ptllnd_check_sends(peer);
 }
 
@@ -45,7 +69,7 @@ ptllnd_ptlid2str(ptl_process_id_t id)
         static int  idx = 0;
 
         char   *str = strs[idx++];
-        
+
         if (idx >= sizeof(strs)/sizeof(strs[0]))
                 idx = 0;
 
@@ -65,21 +89,22 @@ ptllnd_destroy_peer(ptllnd_peer_t *peer)
 
         LASSERT (peer->plp_closing);
         LASSERT (plni->plni_npeers > 0);
-        LASSERT (list_empty(&peer->plp_txq));
-        LASSERT (list_empty(&peer->plp_activeq));
+        LASSERT (cfs_list_empty(&peer->plp_txq));
+        LASSERT (cfs_list_empty(&peer->plp_noopq));
+        LASSERT (cfs_list_empty(&peer->plp_activeq));
         plni->plni_npeers--;
         LIBCFS_FREE(peer, sizeof(*peer));
 }
 
 void
-ptllnd_abort_txs(ptllnd_ni_t *plni, struct list_head *q)
+ptllnd_abort_txs(ptllnd_ni_t *plni, cfs_list_t *q)
 {
-        while (!list_empty(q)) {
-                ptllnd_tx_t *tx = list_entry(q->next, ptllnd_tx_t, tx_list);
+        while (!cfs_list_empty(q)) {
+                ptllnd_tx_t *tx = cfs_list_entry(q->next, ptllnd_tx_t, tx_list);
 
                 tx->tx_status = -ESHUTDOWN;
-                list_del(&tx->tx_list);
-                list_add_tail(&tx->tx_list, &plni->plni_zombie_txs);
+                cfs_list_del(&tx->tx_list);
+                cfs_list_add_tail(&tx->tx_list, &plni->plni_zombie_txs);
         }
 }
 
@@ -94,18 +119,20 @@ ptllnd_close_peer(ptllnd_peer_t *peer, int error)
 
         peer->plp_closing = 1;
 
-        if (!list_empty(&peer->plp_txq) ||
-            !list_empty(&peer->plp_activeq) ||
+        if (!cfs_list_empty(&peer->plp_txq) ||
+            !cfs_list_empty(&peer->plp_noopq) ||
+            !cfs_list_empty(&peer->plp_activeq) ||
             error != 0) {
-                CWARN("Closing %s\n", libcfs_id2str(peer->plp_id));
+                CWARN("Closing %s: %d\n", libcfs_id2str(peer->plp_id), error);
                 if (plni->plni_debug)
                         ptllnd_dump_debug(ni, peer->plp_id);
         }
-        
+
         ptllnd_abort_txs(plni, &peer->plp_txq);
+        ptllnd_abort_txs(plni, &peer->plp_noopq);
         ptllnd_abort_txs(plni, &peer->plp_activeq);
 
-        list_del(&peer->plp_list);
+        cfs_list_del(&peer->plp_list);
         ptllnd_peer_decref(peer);
 }
 
@@ -114,16 +141,13 @@ ptllnd_find_peer(lnet_ni_t *ni, lnet_process_id_t id, int create)
 {
         ptllnd_ni_t       *plni = ni->ni_data;
         unsigned int       hash = LNET_NIDADDR(id.nid) % plni->plni_peer_hash_size;
-        struct list_head  *tmp;
         ptllnd_peer_t     *plp;
         ptllnd_tx_t       *tx;
         int                rc;
 
         LASSERT (LNET_NIDNET(id.nid) == LNET_NIDNET(ni->ni_nid));
 
-        list_for_each(tmp, &plni->plni_peer_hash[hash]) {
-                plp = list_entry(tmp, ptllnd_peer_t, plp_list);
-
+        cfs_list_for_each_entry (plp, &plni->plni_peer_hash[hash], plp_list) {
                 if (plp->plp_id.nid == id.nid &&
                     plp->plp_id.pid == id.pid) {
                         ptllnd_peer_addref(plp);
@@ -162,15 +186,17 @@ ptllnd_find_peer(lnet_ni_t *ni, lnet_process_id_t id, int create)
         plp->plp_extra_lazy_credits = 0;
         plp->plp_match = 0;
         plp->plp_stamp = 0;
+        plp->plp_sent_hello = 0;
         plp->plp_recvd_hello = 0;
         plp->plp_closing = 0;
         plp->plp_refcount = 1;
         CFS_INIT_LIST_HEAD(&plp->plp_list);
         CFS_INIT_LIST_HEAD(&plp->plp_txq);
+        CFS_INIT_LIST_HEAD(&plp->plp_noopq);
         CFS_INIT_LIST_HEAD(&plp->plp_activeq);
 
         ptllnd_peer_addref(plp);
-        list_add_tail(&plp->plp_list, &plni->plni_peer_hash[hash]);
+        cfs_list_add_tail(&plp->plp_list, &plni->plni_peer_hash[hash]);
 
         tx = ptllnd_new_tx(plp, PTLLND_MSG_TYPE_HELLO, 0);
         if (tx == NULL) {
@@ -195,31 +221,31 @@ ptllnd_find_peer(lnet_ni_t *ni, lnet_process_id_t id, int create)
 }
 
 int
-ptllnd_count_q(struct list_head *q)
+ptllnd_count_q(cfs_list_t *q)
 {
-        struct list_head *e;
-        int               n = 0;
-        
-        list_for_each(e, q) {
+        cfs_list_t *e;
+        int         n = 0;
+
+        cfs_list_for_each(e, q) {
                 n++;
         }
-        
+
         return n;
 }
 
 const char *
-ptllnd_tx_typestr(int type) 
+ptllnd_tx_typestr(int type)
 {
         switch (type) {
         case PTLLND_RDMA_WRITE:
                 return "rdma_write";
-                
+
         case PTLLND_RDMA_READ:
                 return "rdma_read";
 
         case PTLLND_MSG_TYPE_PUT:
                 return "put_req";
-                
+
         case PTLLND_MSG_TYPE_GET:
                 return "get_req";
 
@@ -238,13 +264,13 @@ ptllnd_tx_typestr(int type)
 }
 
 void
-ptllnd_debug_tx(ptllnd_tx_t *tx) 
+ptllnd_debug_tx(ptllnd_tx_t *tx)
 {
         CDEBUG(D_WARNING, "%s %s b %ld.%06ld/%ld.%06ld"
                " r %ld.%06ld/%ld.%06ld status %d\n",
                ptllnd_tx_typestr(tx->tx_type),
                libcfs_id2str(tx->tx_peer->plp_id),
-               tx->tx_bulk_posted.tv_sec, tx->tx_bulk_posted.tv_usec, 
+               tx->tx_bulk_posted.tv_sec, tx->tx_bulk_posted.tv_usec,
                tx->tx_bulk_done.tv_sec, tx->tx_bulk_done.tv_usec,
                tx->tx_req_posted.tv_sec, tx->tx_req_posted.tv_usec,
                tx->tx_req_done.tv_sec, tx->tx_req_done.tv_usec,
@@ -255,59 +281,56 @@ void
 ptllnd_debug_peer(lnet_ni_t *ni, lnet_process_id_t id)
 {
         ptllnd_peer_t    *plp = ptllnd_find_peer(ni, id, 0);
-        struct list_head *tmp;
         ptllnd_ni_t      *plni = ni->ni_data;
         ptllnd_tx_t      *tx;
-        
+
         if (plp == NULL) {
                 CDEBUG(D_WARNING, "No peer %s\n", libcfs_id2str(id));
                 return;
         }
-        
-        CDEBUG(D_WARNING, "%s %s%s [%d] "LPU64".%06d m "LPU64" q %d/%d c %d/%d+%d(%d)\n",
-               libcfs_id2str(id), 
-               plp->plp_recvd_hello ? "H" : "_",
-               plp->plp_closing     ? "C" : "_",
-               plp->plp_refcount,
-               plp->plp_stamp / 1000000, (int)(plp->plp_stamp % 1000000),
-               plp->plp_match,
-               ptllnd_count_q(&plp->plp_txq),
-               ptllnd_count_q(&plp->plp_activeq),
-               plp->plp_credits, plp->plp_outstanding_credits, plp->plp_sent_credits,
-               plni->plni_peer_credits + plp->plp_lazy_credits);
+
+        CWARN("%s %s%s [%d] "LPU64".%06d m "LPU64" q %d/%d/%d c %d/%d+%d(%d)\n",
+              libcfs_id2str(id),
+              plp->plp_recvd_hello ? "H" : "_",
+              plp->plp_closing     ? "C" : "_",
+              plp->plp_refcount,
+              plp->plp_stamp / 1000000, (int)(plp->plp_stamp % 1000000),
+              plp->plp_match,
+              ptllnd_count_q(&plp->plp_txq),
+              ptllnd_count_q(&plp->plp_noopq),
+              ptllnd_count_q(&plp->plp_activeq),
+              plp->plp_credits, plp->plp_outstanding_credits, plp->plp_sent_credits,
+              plni->plni_peer_credits + plp->plp_lazy_credits);
 
         CDEBUG(D_WARNING, "txq:\n");
-        list_for_each (tmp, &plp->plp_txq) {
-                tx = list_entry(tmp, ptllnd_tx_t, tx_list);
-                
+        cfs_list_for_each_entry (tx, &plp->plp_txq, tx_list) {
+                ptllnd_debug_tx(tx);
+        }
+
+        CDEBUG(D_WARNING, "noopq:\n");
+        cfs_list_for_each_entry (tx, &plp->plp_noopq, tx_list) {
                 ptllnd_debug_tx(tx);
         }
 
         CDEBUG(D_WARNING, "activeq:\n");
-        list_for_each (tmp, &plp->plp_activeq) {
-                tx = list_entry(tmp, ptllnd_tx_t, tx_list);
-                
+        cfs_list_for_each_entry (tx, &plp->plp_activeq, tx_list) {
                 ptllnd_debug_tx(tx);
         }
 
         CDEBUG(D_WARNING, "zombies:\n");
-        list_for_each (tmp, &plni->plni_zombie_txs) {
-                tx = list_entry(tmp, ptllnd_tx_t, tx_list);
-                
+        cfs_list_for_each_entry (tx, &plni->plni_zombie_txs, tx_list) {
                 if (tx->tx_peer->plp_id.nid == id.nid &&
                     tx->tx_peer->plp_id.pid == id.pid)
                         ptllnd_debug_tx(tx);
         }
-        
+
         CDEBUG(D_WARNING, "history:\n");
-        list_for_each (tmp, &plni->plni_tx_history) {
-                tx = list_entry(tmp, ptllnd_tx_t, tx_list);
-                
+        cfs_list_for_each_entry (tx, &plni->plni_tx_history, tx_list) {
                 if (tx->tx_peer->plp_id.nid == id.nid &&
                     tx->tx_peer->plp_id.pid == id.pid)
                         ptllnd_debug_tx(tx);
         }
-        
+
         ptllnd_peer_decref(plp);
 }
 
@@ -318,46 +341,12 @@ ptllnd_dump_debug(lnet_ni_t *ni, lnet_process_id_t id)
         ptllnd_dump_history();
 }
 
-void
-ptllnd_notify(lnet_ni_t *ni, lnet_nid_t nid, int alive)
-{
-        lnet_process_id_t  id;
-        ptllnd_peer_t     *peer;
-        time_t             start = cfs_time_current_sec();
-        ptllnd_ni_t       *plni = ni->ni_data;
-        int                w = plni->plni_long_wait;
-
-        /* This is only actually used to connect to routers at startup! */
-        LASSERT(alive);
-
-        id.nid = nid;
-        id.pid = LUSTRE_SRV_LNET_PID;
-        
-        peer = ptllnd_find_peer(ni, id, 1);
-        if (peer == NULL)
-                return;
-
-        /* wait for the peer to reply */
-        while (!peer->plp_recvd_hello) {
-                if (w > 0 && cfs_time_current_sec() > start + w/1000) {
-                        CWARN("Waited %ds to connect to %s\n",
-                              (int)(cfs_time_current_sec() - start),
-                              libcfs_id2str(id));
-                        w *= 2;
-                }
-                
-                ptllnd_wait(ni, w);
-        }
-        
-        ptllnd_peer_decref(peer);
-}
-
 int
 ptllnd_setasync(lnet_ni_t *ni, lnet_process_id_t id, int nasync)
 {
         ptllnd_peer_t *peer = ptllnd_find_peer(ni, id, nasync > 0);
         int            rc;
-        
+
         if (peer == NULL)
                 return -ENOMEM;
 
@@ -382,7 +371,7 @@ ptllnd_setasync(lnet_ni_t *ni, lnet_process_id_t id, int nasync)
 
         nasync -= peer->plp_extra_lazy_credits;
         peer->plp_extra_lazy_credits = 0;
-        
+
         rc = ptllnd_size_buffers(ni, nasync);
         if (rc == 0) {
                 peer->plp_lazy_credits += nasync;
@@ -495,7 +484,7 @@ ptllnd_new_tx(ptllnd_peer_t *peer, int type, int payload_nob)
         ptllnd_peer_addref(peer);
         plni->plni_ntxs++;
 
-        CDEBUG(D_NET, "tx=%p\n",tx);
+        CDEBUG(D_NET, "tx=%p\n", tx);
 
         return tx;
 }
@@ -534,9 +523,9 @@ ptllnd_cull_tx_history(ptllnd_ni_t *plni)
         int max = plni->plni_max_tx_history;
 
         while (plni->plni_ntx_history > max) {
-                ptllnd_tx_t *tx = list_entry(plni->plni_tx_history.next, 
-                                             ptllnd_tx_t, tx_list);
-                list_del(&tx->tx_list);
+                ptllnd_tx_t *tx = cfs_list_entry(plni->plni_tx_history.next,
+                                                 ptllnd_tx_t, tx_list);
+                cfs_list_del(&tx->tx_list);
 
                 ptllnd_peer_decref(tx->tx_peer);
 
@@ -564,8 +553,8 @@ ptllnd_tx_done(ptllnd_tx_t *tx)
 
         tx->tx_completing = 1;
 
-        if (!list_empty(&tx->tx_list))
-                list_del_init(&tx->tx_list);
+        if (!cfs_list_empty(&tx->tx_list))
+                cfs_list_del_init(&tx->tx_list);
 
         if (tx->tx_status != 0) {
                 if (plni->plni_debug) {
@@ -575,7 +564,7 @@ ptllnd_tx_done(ptllnd_tx_t *tx)
                 }
                 ptllnd_close_peer(peer, tx->tx_status);
         }
-        
+
         ptllnd_abort_tx(tx, &tx->tx_reqmdh);
         ptllnd_abort_tx(tx, &tx->tx_bulkmdh);
 
@@ -596,8 +585,8 @@ ptllnd_tx_done(ptllnd_tx_t *tx)
         }
 
         plni->plni_ntx_history++;
-        list_add_tail(&tx->tx_list, &plni->plni_tx_history);
-        
+        cfs_list_add_tail(&tx->tx_list, &plni->plni_tx_history);
+
         ptllnd_cull_tx_history(plni);
 }
 
@@ -641,7 +630,7 @@ ptllnd_set_txiov(ptllnd_tx_t *tx,
 
                         piov[npiov].iov_base = iov[npiov].iov_base + temp_offset;
                         piov[npiov].iov_len = iov[npiov].iov_len - temp_offset;
-                        
+
                         if (piov[npiov].iov_len >= resid) {
                                 piov[npiov].iov_len = resid;
                                 npiov++;
@@ -713,7 +702,8 @@ ptllnd_post_buffer(ptllnd_buffer_t *buf)
                          anyid, LNET_MSG_MATCHBITS, 0,
                          PTL_UNLINK, PTL_INS_AFTER, &meh);
         if (rc != PTL_OK) {
-                CERROR("PtlMEAttach failed: %d\n", rc);
+                CERROR("PtlMEAttach failed: %s(%d)\n",
+                       ptllnd_errtype2str(rc), rc);
                 return -ENOMEM;
         }
 
@@ -724,7 +714,8 @@ ptllnd_post_buffer(ptllnd_buffer_t *buf)
         if (rc == PTL_OK)
                 return 0;
 
-        CERROR("PtlMDAttach failed: %d\n", rc);
+        CERROR("PtlMDAttach failed: %s(%d)\n",
+               ptllnd_errtype2str(rc), rc);
 
         buf->plb_posted = 0;
         plni->plni_nposted_buffers--;
@@ -735,11 +726,25 @@ ptllnd_post_buffer(ptllnd_buffer_t *buf)
         return -ENOMEM;
 }
 
+static inline int
+ptllnd_peer_send_noop (ptllnd_peer_t *peer)
+{
+        ptllnd_ni_t *plni = peer->plp_ni->ni_data;
+
+        if (!peer->plp_sent_hello ||
+            peer->plp_credits == 0 ||
+            !cfs_list_empty(&peer->plp_noopq) ||
+            peer->plp_outstanding_credits < PTLLND_CREDIT_HIGHWATER(plni))
+                return 0;
+
+        /* No tx to piggyback NOOP onto or no credit to send a tx */
+        return (cfs_list_empty(&peer->plp_txq) || peer->plp_credits == 1);
+}
+
 void
 ptllnd_check_sends(ptllnd_peer_t *peer)
 {
-        lnet_ni_t      *ni = peer->plp_ni;
-        ptllnd_ni_t    *plni = ni->ni_data;
+        ptllnd_ni_t    *plni = peer->plp_ni->ni_data;
         ptllnd_tx_t    *tx;
         ptl_md_t        md;
         ptl_handle_md_t mdh;
@@ -750,22 +755,30 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
                peer->plp_outstanding_credits, peer->plp_sent_credits,
                plni->plni_peer_credits + peer->plp_lazy_credits);
 
-        if (list_empty(&peer->plp_txq) &&
-            peer->plp_outstanding_credits >= PTLLND_CREDIT_HIGHWATER(plni) &&
-            peer->plp_credits != 0) {
-
+        if (ptllnd_peer_send_noop(peer)) {
                 tx = ptllnd_new_tx(peer, PTLLND_MSG_TYPE_NOOP, 0);
                 CDEBUG(D_NET, "NOOP tx=%p\n",tx);
                 if (tx == NULL) {
                         CERROR("Can't return credits to %s\n",
                                libcfs_id2str(peer->plp_id));
                 } else {
-                        list_add_tail(&tx->tx_list, &peer->plp_txq);
+                        ptllnd_set_tx_deadline(tx);
+                        cfs_list_add_tail(&tx->tx_list, &peer->plp_noopq);
                 }
         }
 
-        while (!list_empty(&peer->plp_txq)) {
-                tx = list_entry(peer->plp_txq.next, ptllnd_tx_t, tx_list);
+        for (;;) {
+                if (!cfs_list_empty(&peer->plp_noopq)) {
+                        LASSERT (peer->plp_sent_hello);
+                        tx = cfs_list_entry(peer->plp_noopq.next,
+                                            ptllnd_tx_t, tx_list);
+                } else if (!cfs_list_empty(&peer->plp_txq)) {
+                        tx = cfs_list_entry(peer->plp_txq.next,
+                                            ptllnd_tx_t, tx_list);
+                } else {
+                        /* nothing to send right now */
+                        break;
+                }
 
                 LASSERT (tx->tx_msgsize > 0);
 
@@ -775,6 +788,14 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
                          <= plni->plni_peer_credits + peer->plp_lazy_credits);
                 LASSERT (peer->plp_credits >= 0);
 
+                /* say HELLO first */
+                if (!peer->plp_sent_hello) {
+                        LASSERT (cfs_list_empty(&peer->plp_noopq));
+                        LASSERT (tx->tx_type == PTLLND_MSG_TYPE_HELLO);
+
+                        peer->plp_sent_hello = 1;
+                }
+
                 if (peer->plp_credits == 0) {   /* no credits */
                         PTLLND_HISTORY("%s[%d/%d+%d(%d)]: no creds for %p",
                                        libcfs_id2str(peer->plp_id),
@@ -785,9 +806,11 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
                                        peer->plp_lazy_credits, tx);
                         break;
                 }
-                
-                if (peer->plp_credits == 1 &&   /* last credit reserved for */
-                    peer->plp_outstanding_credits == 0) { /* returning credits */
+
+                /* Last/Initial credit reserved for NOOP/HELLO */
+                if (peer->plp_credits == 1 &&
+                    tx->tx_type != PTLLND_MSG_TYPE_NOOP &&
+                    tx->tx_type != PTLLND_MSG_TYPE_HELLO) {
                         PTLLND_HISTORY("%s[%d/%d+%d(%d)]: too few creds for %p",
                                        libcfs_id2str(peer->plp_id),
                                        peer->plp_credits,
@@ -797,17 +820,15 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
                                        peer->plp_lazy_credits, tx);
                         break;
                 }
-                
-                list_del(&tx->tx_list);
-                list_add_tail(&tx->tx_list, &peer->plp_activeq);
+
+                cfs_list_del(&tx->tx_list);
+                cfs_list_add_tail(&tx->tx_list, &peer->plp_activeq);
 
                 CDEBUG(D_NET, "Sending at TX=%p type=%s (%d)\n",tx,
-                        ptllnd_msgtype2str(tx->tx_type),tx->tx_type);
+                       ptllnd_msgtype2str(tx->tx_type),tx->tx_type);
 
                 if (tx->tx_type == PTLLND_MSG_TYPE_NOOP &&
-                    (!list_empty(&peer->plp_txq) ||
-                     peer->plp_outstanding_credits <
-                     PTLLND_CREDIT_HIGHWATER(plni))) {
+                    !ptllnd_peer_send_noop(peer)) {
                         /* redundant NOOP */
                         ptllnd_tx_done(tx);
                         continue;
@@ -820,9 +841,10 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
                 /*
                  * Return all the credits we have
                  */
-                tx->tx_msg.ptlm_credits = peer->plp_outstanding_credits;
-                peer->plp_sent_credits += peer->plp_outstanding_credits;
-                peer->plp_outstanding_credits = 0;
+                tx->tx_msg.ptlm_credits = MIN(PTLLND_MSG_MAX_CREDITS,
+                                              peer->plp_outstanding_credits);
+                peer->plp_sent_credits += tx->tx_msg.ptlm_credits;
+                peer->plp_outstanding_credits -= tx->tx_msg.ptlm_credits;
 
                 /*
                  * One less credit
@@ -843,8 +865,9 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
 
                 rc = PtlMDBind(plni->plni_nih, md, LNET_UNLINK, &mdh);
                 if (rc != PTL_OK) {
-                        CERROR("PtlMDBind for %s failed: %d\n",
-                               libcfs_id2str(peer->plp_id), rc);
+                        CERROR("PtlMDBind for %s failed: %s(%d)\n",
+                               libcfs_id2str(peer->plp_id),
+                               ptllnd_errtype2str(rc), rc);
                         tx->tx_status = -EIO;
                         ptllnd_tx_done(tx);
                         break;
@@ -852,7 +875,7 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
 
                 LASSERT (tx->tx_type != PTLLND_RDMA_WRITE &&
                          tx->tx_type != PTLLND_RDMA_READ);
-                
+
                 tx->tx_reqmdh = mdh;
                 gettimeofday(&tx->tx_req_posted, NULL);
 
@@ -869,8 +892,9 @@ ptllnd_check_sends(ptllnd_peer_t *peer)
                 rc = PtlPut(mdh, PTL_NOACK_REQ, peer->plp_ptlid,
                             plni->plni_portal, 0, LNET_MSG_MATCHBITS, 0, 0);
                 if (rc != PTL_OK) {
-                        CERROR("PtlPut for %s failed: %d\n",
-                               libcfs_id2str(peer->plp_id), rc);
+                        CERROR("PtlPut for %s failed: %s(%d)\n",
+                               libcfs_id2str(peer->plp_id),
+                               ptllnd_errtype2str(rc), rc);
                         tx->tx_status = -EIO;
                         ptllnd_tx_done(tx);
                         break;
@@ -902,15 +926,14 @@ ptllnd_passive_rdma(ptllnd_peer_t *peer, int type, lnet_msg_t *msg,
 
         if (tx == NULL) {
                 CERROR("Can't allocate %s tx for %s\n",
-                       type == PTLLND_MSG_TYPE_GET ? "GET" : "PUT/REPLY",
-                       libcfs_id2str(peer->plp_id));
+                       ptllnd_msgtype2str(type), libcfs_id2str(peer->plp_id));
                 return -ENOMEM;
         }
 
         rc = ptllnd_set_txiov(tx, niov, iov, offset, len);
         if (rc != 0) {
-                CERROR ("Can't allocate iov %d for %s\n",
-                        niov, libcfs_id2str(peer->plp_id));
+                CERROR("Can't allocate iov %d for %s\n",
+                       niov, libcfs_id2str(peer->plp_id));
                 rc = -ENOMEM;
                 goto failed;
         }
@@ -928,12 +951,24 @@ ptllnd_passive_rdma(ptllnd_peer_t *peer, int type, lnet_msg_t *msg,
 
         start = cfs_time_current_sec();
         w = plni->plni_long_wait;
+        ptllnd_set_tx_deadline(tx);
 
-        while (!peer->plp_recvd_hello) {        /* wait to validate plp_match */
+        while (!peer->plp_recvd_hello) {    /* wait to validate plp_match */
                 if (peer->plp_closing) {
                         rc = -EIO;
                         goto failed;
                 }
+
+                /* NB must check here to avoid unbounded wait - tx not yet
+                 * on peer->plp_txq, so ptllnd_watchdog can't expire it */
+                if (tx->tx_deadline < cfs_time_current_sec()) {
+                        CERROR("%s tx for %s timed out\n",
+                               ptllnd_msgtype2str(type),
+                               libcfs_id2str(peer->plp_id));
+                        rc = -ETIMEDOUT;
+                        goto failed;
+                }
+
                 if (w > 0 && cfs_time_current_sec() > start + w/1000) {
                         CWARN("Waited %ds to connect to %s\n",
                               (int)(cfs_time_current_sec() - start),
@@ -950,8 +985,9 @@ ptllnd_passive_rdma(ptllnd_peer_t *peer, int type, lnet_msg_t *msg,
         rc = PtlMEAttach(plni->plni_nih, plni->plni_portal, peer->plp_ptlid,
                          matchbits, 0, PTL_UNLINK, PTL_INS_BEFORE, &meh);
         if (rc != PTL_OK) {
-                CERROR("PtlMEAttach for %s failed: %d\n",
-                       libcfs_id2str(peer->plp_id), rc);
+                CERROR("PtlMEAttach for %s failed: %s(%d)\n",
+                       libcfs_id2str(peer->plp_id),
+                       ptllnd_errtype2str(rc), rc);
                 rc = -EIO;
                 goto failed;
         }
@@ -960,8 +996,9 @@ ptllnd_passive_rdma(ptllnd_peer_t *peer, int type, lnet_msg_t *msg,
 
         rc = PtlMDAttach(meh, md, LNET_UNLINK, &mdh);
         if (rc != PTL_OK) {
-                CERROR("PtlMDAttach for %s failed: %d\n",
-                       libcfs_id2str(peer->plp_id), rc);
+                CERROR("PtlMDAttach for %s failed: %s(%d)\n",
+                       libcfs_id2str(peer->plp_id),
+                       ptllnd_errtype2str(rc), rc);
                 rc2 = PtlMEUnlink(meh);
                 LASSERT (rc2 == PTL_OK);
                 rc = -EIO;
@@ -1005,6 +1042,7 @@ ptllnd_passive_rdma(ptllnd_peer_t *peer, int type, lnet_msg_t *msg,
         return 0;
 
  failed:
+        tx->tx_status = rc;
         ptllnd_tx_done(tx);
         return rc;
 }
@@ -1035,8 +1073,8 @@ ptllnd_active_rdma(ptllnd_peer_t *peer, int type,
 
         rc = ptllnd_set_txiov(tx, niov, iov, offset, len);
         if (rc != 0) {
-                CERROR ("Can't allocate iov %d for %s\n",
-                        niov, libcfs_id2str(peer->plp_id));
+                CERROR("Can't allocate iov %d for %s\n",
+                       niov, libcfs_id2str(peer->plp_id));
                 rc = -ENOMEM;
                 goto failed;
         }
@@ -1051,8 +1089,9 @@ ptllnd_active_rdma(ptllnd_peer_t *peer, int type,
 
         rc = PtlMDBind(plni->plni_nih, md, LNET_UNLINK, &mdh);
         if (rc != PTL_OK) {
-                CERROR("PtlMDBind for %s failed: %d\n",
-                       libcfs_id2str(peer->plp_id), rc);
+                CERROR("PtlMDBind for %s failed: %s(%d)\n",
+                       libcfs_id2str(peer->plp_id),
+                       ptllnd_errtype2str(rc), rc);
                 rc = -EIO;
                 goto failed;
         }
@@ -1061,7 +1100,7 @@ ptllnd_active_rdma(ptllnd_peer_t *peer, int type,
         tx->tx_lnetmsg = msg;
 
         ptllnd_set_tx_deadline(tx);
-        list_add_tail(&tx->tx_list, &peer->plp_activeq);
+        cfs_list_add_tail(&tx->tx_list, &peer->plp_activeq);
         gettimeofday(&tx->tx_bulk_posted, NULL);
 
         if (type == PTLLND_RDMA_READ)
@@ -1075,8 +1114,9 @@ ptllnd_active_rdma(ptllnd_peer_t *peer, int type,
         if (rc == PTL_OK)
                 return 0;
 
-        CERROR("Can't initiate RDMA with %s: %d\n",
-               libcfs_id2str(peer->plp_id), rc);
+        CERROR("Can't initiate RDMA with %s: %s(%d)\n",
+               libcfs_id2str(peer->plp_id),
+               ptllnd_errtype2str(rc), rc);
 
         tx->tx_lnetmsg = NULL;
  failed:
@@ -1099,7 +1139,7 @@ ptllnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *msg)
 
         LASSERT (msg->msg_niov <= PTL_MD_MAX_IOV); /* !!! */
 
-        CDEBUG(D_NET, "%s [%d]+%d,%d -> %s%s\n", 
+        CDEBUG(D_NET, "%s [%d]+%d,%d -> %s%s\n",
                lnet_msgtyp2str(msg->msg_type),
                msg->msg_niov, msg->msg_offset, msg->msg_len,
                libcfs_nid2str(msg->msg_target.nid),
@@ -1110,7 +1150,7 @@ ptllnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *msg)
                        libcfs_id2str(msg->msg_target));
                 return -EHOSTUNREACH;
         }
-        
+
         plp = ptllnd_find_peer(ni, msg->msg_target, 1);
         if (plp == NULL)
                 return -ENOMEM;
@@ -1192,8 +1232,7 @@ void
 ptllnd_rx_done(ptllnd_rx_t *rx)
 {
         ptllnd_peer_t *plp = rx->rx_peer;
-        lnet_ni_t     *ni = plp->plp_ni;
-        ptllnd_ni_t   *plni = ni->ni_data;
+        ptllnd_ni_t   *plni = plp->plp_ni->ni_data;
 
         plp->plp_outstanding_credits++;
 
@@ -1203,7 +1242,7 @@ ptllnd_rx_done(ptllnd_rx_t *rx)
                        plp->plp_sent_credits,
                        plni->plni_peer_credits + plp->plp_lazy_credits, rx);
 
-        ptllnd_check_sends(rx->rx_peer);
+        ptllnd_check_sends(plp);
 
         LASSERT (plni->plni_nrxs > 0);
         plni->plni_nrxs--;
@@ -1306,7 +1345,7 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
         msg_version = flip ? __swab16(msg->ptlm_version) : msg->ptlm_version;
 
         if (msg_version != PTLLND_MSG_VERSION) {
-                CERROR("Bad protocol version %04x from %s: %04x expected\n", 
+                CERROR("Bad protocol version %04x from %s: %04x expected\n",
                        (__u32)msg_version, ptllnd_ptlid2str(initiator), PTLLND_MSG_VERSION);
 
                 if (plni->plni_abort_on_protocol_mismatch)
@@ -1335,7 +1374,7 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
 
         msg->ptlm_version = msg_version;
         msg->ptlm_cksum = msg_cksum;
-        
+
         if (flip) {
                 /* NB stamps are opaque cookies */
                 __swab32s(&msg->ptlm_nob);
@@ -1344,7 +1383,7 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
                 __swab32s(&msg->ptlm_srcpid);
                 __swab32s(&msg->ptlm_dstpid);
         }
-        
+
         srcid.nid = msg->ptlm_srcnid;
         srcid.pid = msg->ptlm_srcpid;
 
@@ -1356,19 +1395,26 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
         }
 
         if (msg->ptlm_type == PTLLND_MSG_TYPE_NAK) {
-                CERROR("NAK from %s (%s)\n", 
+                CERROR("NAK from %s (%s)\n",
                        libcfs_id2str(srcid),
                        ptllnd_ptlid2str(initiator));
 
                 if (plni->plni_dump_on_nak)
                         ptllnd_dump_debug(ni, srcid);
-                
+
                 if (plni->plni_abort_on_nak)
                         abort();
-                
+
+                plp = ptllnd_find_peer(ni, srcid, 0);
+                if (plp == NULL) {
+                        CERROR("Ignore NAK from %s: no peer\n", libcfs_id2str(srcid));
+                        return;
+                }
+                ptllnd_close_peer(plp, -EPROTO);
+                ptllnd_peer_decref(plp);
                 return;
         }
-        
+
         if (msg->ptlm_dstnid != ni->ni_nid ||
             msg->ptlm_dstpid != the_lnet.ln_pid) {
                 CERROR("Bad dstid %s (%s expected) from %s\n",
@@ -1428,7 +1474,7 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
                         __swab32s(&msg->ptlm_u.hello.kptlhm_max_msg_size);
                 }
                 break;
-                
+
         case PTLLND_MSG_TYPE_NOOP:
                 break;
 
@@ -1478,19 +1524,16 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
         if (plp->plp_sent_credits == 0) {
                 CERROR("%s[%d/%d+%d(%d)]: unexpected message\n",
                        libcfs_id2str(plp->plp_id),
-                       plp->plp_credits, plp->plp_outstanding_credits, 
+                       plp->plp_credits, plp->plp_outstanding_credits,
                        plp->plp_sent_credits,
                        plni->plni_peer_credits + plp->plp_lazy_credits);
                 return;
         }
         plp->plp_sent_credits--;
-        
+
         /* No check for credit overflow - the peer may post new buffers after
          * the startup handshake. */
-        if (msg->ptlm_credits > 0) {
-                plp->plp_credits += msg->ptlm_credits;
-                ptllnd_check_sends(plp);
-        }
+        plp->plp_credits += msg->ptlm_credits;
 
         /* All OK so far; assume the message is good... */
 
@@ -1520,6 +1563,9 @@ ptllnd_parse_request(lnet_ni_t *ni, ptl_process_id_t initiator,
                 break;
         }
 
+        if (msg->ptlm_credits > 0)
+                ptllnd_check_sends(plp);
+
         ptllnd_peer_decref(plp);
 }
 
@@ -1549,8 +1595,8 @@ ptllnd_buf_event (lnet_ni_t *ni, ptl_event_t *event)
                 /* Portals can't force message alignment - someone sending an
                  * odd-length message could misalign subsequent messages */
                 if ((event->mlength & 7) != 0) {
-                        CERROR("Message from %s has odd length %llu: "
-                               "probable version incompatibility\n",
+                        CERROR("Message from %s has odd length "LPU64
+                               " probable version incompatibility\n",
                                ptllnd_ptlid2str(event->initiator),
                                event->mlength);
                         LBUG();
@@ -1624,7 +1670,7 @@ ptllnd_tx_event (lnet_ni_t *ni, ptl_event_t *event)
         LASSERT (!isreq != !isbulk);            /* always one and only 1 match */
 
         PTLLND_HISTORY("%s[%d/%d+%d(%d)]: TX done %p %s%s",
-                       libcfs_id2str(tx->tx_peer->plp_id), 
+                       libcfs_id2str(tx->tx_peer->plp_id),
                        tx->tx_peer->plp_credits,
                        tx->tx_peer->plp_outstanding_credits,
                        tx->tx_peer->plp_sent_credits,
@@ -1688,8 +1734,8 @@ ptllnd_tx_event (lnet_ni_t *ni, ptl_event_t *event)
              PtlHandleIsEqual(tx->tx_reqmdh, PTL_INVALID_HANDLE))) {
                 if (error)
                         tx->tx_status = -EIO;
-                list_del(&tx->tx_list);
-                list_add_tail(&tx->tx_list, &plni->plni_zombie_txs);
+                cfs_list_del(&tx->tx_list);
+                cfs_list_add_tail(&tx->tx_list, &plni->plni_zombie_txs);
         }
 }
 
@@ -1697,18 +1743,19 @@ ptllnd_tx_t *
 ptllnd_find_timed_out_tx(ptllnd_peer_t *peer)
 {
         time_t            now = cfs_time_current_sec();
-        struct list_head *tmp;
+        ptllnd_tx_t *tx;
 
-        list_for_each(tmp, &peer->plp_txq) {
-                ptllnd_tx_t *tx = list_entry(tmp, ptllnd_tx_t, tx_list);
-                
+        cfs_list_for_each_entry (tx, &peer->plp_txq, tx_list) {
                 if (tx->tx_deadline < now)
                         return tx;
         }
-        
-        list_for_each(tmp, &peer->plp_activeq) {
-                ptllnd_tx_t *tx = list_entry(tmp, ptllnd_tx_t, tx_list);
-                
+
+        cfs_list_for_each_entry (tx, &peer->plp_noopq, tx_list) {
+                if (tx->tx_deadline < now)
+                        return tx;
+        }
+
+        cfs_list_for_each_entry (tx, &peer->plp_activeq, tx_list) {
                 if (tx->tx_deadline < now)
                         return tx;
         }
@@ -1720,11 +1767,16 @@ void
 ptllnd_check_peer(ptllnd_peer_t *peer)
 {
         ptllnd_tx_t *tx = ptllnd_find_timed_out_tx(peer);
-        
+
         if (tx == NULL)
                 return;
-        
-        CERROR("%s: timed out\n", libcfs_id2str(peer->plp_id));
+
+        CERROR("%s (sent %d recvd %d, credits %d/%d/%d/%d/%d): timed out %p %p\n",
+               libcfs_id2str(peer->plp_id), peer->plp_sent_hello, peer->plp_recvd_hello,
+               peer->plp_credits, peer->plp_outstanding_credits,
+               peer->plp_sent_credits, peer->plp_lazy_credits,
+               peer->plp_extra_lazy_credits, tx, tx->tx_lnetmsg);
+        ptllnd_debug_tx(tx);
         ptllnd_close_peer(peer, -ETIMEDOUT);
 }
 
@@ -1737,11 +1789,11 @@ ptllnd_watchdog (lnet_ni_t *ni, time_t now)
         int               chunk = plni->plni_peer_hash_size;
         int               interval = now - (plni->plni_watchdog_nextt - p);
         int               i;
-        struct list_head *hashlist;
-        struct list_head *tmp;
-        struct list_head *nxt;
+        cfs_list_t       *hashlist;
+        cfs_list_t       *tmp;
+        cfs_list_t       *nxt;
 
-        /* Time to check for RDMA timeouts on a few more peers: 
+        /* Time to check for RDMA timeouts on a few more peers:
          * I try to do checks every 'p' seconds on a proportion of the peer
          * table and I need to check every connection 'n' times within a
          * timeout interval, to ensure I detect a timeout on any connection
@@ -1757,11 +1809,12 @@ ptllnd_watchdog (lnet_ni_t *ni, time_t now)
 
         for (i = 0; i < chunk; i++) {
                 hashlist = &plni->plni_peer_hash[plni->plni_watchdog_peeridx];
-                
-                list_for_each_safe(tmp, nxt, hashlist) {
-                        ptllnd_check_peer(list_entry(tmp, ptllnd_peer_t, plp_list));
+
+                cfs_list_for_each_safe(tmp, nxt, hashlist) {
+                        ptllnd_check_peer(cfs_list_entry(tmp, ptllnd_peer_t,
+                                          plp_list));
                 }
-                
+
                 plni->plni_watchdog_peeridx = (plni->plni_watchdog_peeridx + 1) %
                                               plni->plni_peer_hash_size;
         }
@@ -1780,7 +1833,7 @@ ptllnd_wait (lnet_ni_t *ni, int milliseconds)
         struct timeval         then;
         struct timeval         now;
         struct timeval         deadline;
-        
+
         ptllnd_ni_t   *plni = ni->ni_data;
         ptllnd_tx_t   *tx;
         ptl_event_t    event;
@@ -1810,7 +1863,7 @@ ptllnd_wait (lnet_ni_t *ni, int milliseconds)
 
         for (;;) {
                 gettimeofday(&then, NULL);
-                
+
                 rc = PtlEQPoll(&plni->plni_eqh, 1, timeout, &event, &which);
 
                 gettimeofday(&now, NULL);
@@ -1831,7 +1884,7 @@ ptllnd_wait (lnet_ni_t *ni, int milliseconds)
                                 ptllnd_watchdog(ni, now.tv_sec);
                                 LASSERT (now.tv_sec < plni->plni_watchdog_nextt);
                         }
-                        
+
                         if (now.tv_sec > deadline.tv_sec || /* timeout expired */
                             (now.tv_sec == deadline.tv_sec &&
                              now.tv_usec >= deadline.tv_usec))
@@ -1847,7 +1900,7 @@ ptllnd_wait (lnet_ni_t *ni, int milliseconds)
 
                         continue;
                 }
-                
+
                 LASSERT (rc == PTL_OK || rc == PTL_EQ_DROPPED);
 
                 if (rc == PTL_EQ_DROPPED)
@@ -1871,10 +1924,10 @@ ptllnd_wait (lnet_ni_t *ni, int milliseconds)
                 }
         }
 
-        while (!list_empty(&plni->plni_zombie_txs)) {
-                tx = list_entry(plni->plni_zombie_txs.next,
+        while (!cfs_list_empty(&plni->plni_zombie_txs)) {
+                tx = cfs_list_entry(plni->plni_zombie_txs.next,
                                 ptllnd_tx_t, tx_list);
-                list_del_init(&tx->tx_list);
+                cfs_list_del_init(&tx->tx_list);
                 ptllnd_tx_done(tx);
         }