+/*
+ * Allocation logic common to kfilnd_tn_alloc() and kfilnd_tn_alloc_for_hello().
+ * @ep: The KFI LND endpoint to associate with the transaction.
+ * @kp: The kfilnd peer to associate with the transaction.
+ * See kfilnd_tn_alloc() for a description of the other fields
+ * Note: Caller must have a reference on @kp
+ */
+static struct kfilnd_transaction *kfilnd_tn_alloc_common(struct kfilnd_ep *ep,
+ struct kfilnd_peer *kp,
+ bool alloc_msg,
+ bool is_initiator,
+ u16 key)
+{
+ struct kfilnd_transaction *tn;
+ int rc;
+ ktime_t tn_alloc_ts;
+
+ tn_alloc_ts = ktime_get();
+
+ tn = kmem_cache_zalloc(tn_cache, GFP_KERNEL);
+ if (!tn) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ if (alloc_msg) {
+ tn->tn_tx_msg.msg = kmem_cache_alloc(imm_buf_cache, GFP_KERNEL);
+ if (!tn->tn_tx_msg.msg) {
+ rc = -ENOMEM;
+ goto err_free_tn;
+ }
+ }
+
+ tn->tn_mr_key = key;
+
+ tn->tn_kp = kp;
+
+ mutex_init(&tn->tn_lock);
+ tn->tn_ep = ep;
+ tn->tn_response_rx = ep->end_context_id;
+ tn->tn_state = TN_STATE_IDLE;
+ tn->hstatus = LNET_MSG_STATUS_OK;
+ tn->deadline = ktime_get_seconds() + lnet_get_lnd_timeout();
+ tn->tn_replay_deadline = ktime_sub(tn->deadline,
+ (lnet_get_lnd_timeout() / 2));
+ tn->is_initiator = is_initiator;
+ INIT_WORK(&tn->timeout_work, kfilnd_tn_timeout_work);
+
+ /* Add the transaction to an endpoint. This is like
+ * incrementing a ref counter.
+ */
+ spin_lock(&ep->tn_list_lock);
+ list_add_tail(&tn->tn_entry, &ep->tn_list);
+ spin_unlock(&ep->tn_list_lock);
+
+ tn->tn_alloc_ts = tn_alloc_ts;
+ tn->tn_state_ts = ktime_get();
+
+ KFILND_EP_DEBUG(ep, "Transaction ID %u allocated", tn->tn_mr_key);
+
+ return tn;
+
+err_free_tn:
+ if (tn->tn_tx_msg.msg)
+ kmem_cache_free(imm_buf_cache, tn->tn_tx_msg.msg);
+ kmem_cache_free(tn_cache, tn);
+err:
+ return ERR_PTR(rc);
+}
+
+static struct kfilnd_ep *kfilnd_dev_to_ep(struct kfilnd_dev *dev, int cpt)
+{
+ struct kfilnd_ep *ep;
+
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ ep = dev->cpt_to_endpoint[cpt];
+ if (!ep) {
+ CWARN("%s used invalid cpt=%d\n",
+ libcfs_nidstr(&dev->kfd_ni->ni_nid), cpt);
+ ep = dev->kfd_endpoints[0];
+ }
+
+ return ep;
+}
+