+void
+kqswnal_print_eiov (int how, char *str, int n, EP_IOVEC *iov)
+{
+ int i;
+
+ CDEBUG (how, "%s: %d\n", str, n);
+ for (i = 0; i < n; i++) {
+ CDEBUG (how, " %08x for %d\n", iov[i].Base, iov[i].Len);
+ }
+}
+
+int
+kqswnal_eiovs2datav (int ndv, EP_DATAVEC *dv,
+ int nsrc, EP_IOVEC *src,
+ int ndst, EP_IOVEC *dst)
+{
+ int count;
+ int nob;
+
+ LASSERT (ndv > 0);
+ LASSERT (nsrc > 0);
+ LASSERT (ndst > 0);
+
+ for (count = 0; count < ndv; count++, dv++) {
+
+ if (nsrc == 0 || ndst == 0) {
+ if (nsrc != ndst) {
+ /* For now I'll barf on any left over entries */
+ CERROR ("mismatched src and dst iovs\n");
+ return (-EINVAL);
+ }
+ return (count);
+ }
+
+ nob = (src->Len < dst->Len) ? src->Len : dst->Len;
+ dv->Len = nob;
+ dv->Source = src->Base;
+ dv->Dest = dst->Base;
+
+ if (nob >= src->Len) {
+ src++;
+ nsrc--;
+ } else {
+ src->Len -= nob;
+ src->Base += nob;
+ }
+
+ if (nob >= dst->Len) {
+ dst++;
+ ndst--;
+ } else {
+ src->Len -= nob;
+ src->Base += nob;
+ }
+ }
+
+ CERROR ("DATAVEC too small\n");
+ return (-E2BIG);
+}
+
+int
+kqswnal_dma_reply (kqswnal_tx_t *ktx, int nfrag,
+ struct iovec *iov, ptl_kiov_t *kiov, int nob)
+{
+ kqswnal_rx_t *krx = (kqswnal_rx_t *)ktx->ktx_args[0];
+ char *buffer = (char *)page_address(krx->krx_pages[0]);
+ kqswnal_remotemd_t *rmd = (kqswnal_remotemd_t *)(buffer + KQSW_HDR_SIZE);
+ EP_IOVEC eiov[EP_MAXFRAG];
+ EP_STATUSBLK blk;
+ int rc;
+
+ LASSERT (ep_rxd_isrpc(krx->krx_rxd) && !krx->krx_rpc_completed);
+ LASSERT ((iov == NULL) != (kiov == NULL));
+
+ /* see .*_pack_k?iov comment regarding endian-ness */
+ if (buffer + krx->krx_nob < (char *)(rmd + 1)) {
+ /* msg too small to discover rmd size */
+ CERROR ("Incoming message [%d] too small for RMD (%d needed)\n",
+ krx->krx_nob, (int)(((char *)(rmd + 1)) - buffer));
+ return (-EINVAL);
+ }
+
+ if (buffer + krx->krx_nob < (char *)&rmd->kqrmd_eiov[rmd->kqrmd_neiov]) {
+ /* rmd doesn't fit in the incoming message */
+ CERROR ("Incoming message [%d] too small for RMD[%d] (%d needed)\n",
+ krx->krx_nob, rmd->kqrmd_neiov,
+ (int)(((char *)&rmd->kqrmd_eiov[rmd->kqrmd_neiov]) - buffer));
+ return (-EINVAL);
+ }
+
+ /* Ghastly hack part 1, uses the existing procedures to map the source data... */
+ ktx->ktx_nfrag = 0;
+ if (kiov != NULL)
+ rc = kqswnal_map_tx_kiov (ktx, nob, nfrag, kiov);
+ else
+ rc = kqswnal_map_tx_iov (ktx, nob, nfrag, iov);
+
+ if (rc != 0) {
+ CERROR ("Can't map source data: %d\n", rc);
+ return (rc);
+ }
+
+ /* Ghastly hack part 2, copy out eiov so we can create the datav; Ugghh... */
+ memcpy (eiov, ktx->ktx_frags.iov, ktx->ktx_nfrag * sizeof (eiov[0]));
+
+ rc = kqswnal_eiovs2datav (EP_MAXFRAG, ktx->ktx_frags.datav,
+ ktx->ktx_nfrag, eiov,
+ rmd->kqrmd_neiov, rmd->kqrmd_eiov);
+ if (rc < 0) {
+ CERROR ("Can't create datavec: %d\n", rc);
+ return (rc);
+ }
+ ktx->ktx_nfrag = rc;
+
+ memset (&blk, 0, sizeof (blk)); /* zero blk.Status */
+
+ /* Our caller will start to race with kqswnal_rpc_complete... */
+ LASSERT (atomic_read (&krx->krx_refcount) == 1);
+ atomic_set (&krx->krx_refcount, 2);
+
+ rc = ep_complete_rpc (krx->krx_rxd, kqswnal_reply_complete, ktx,
+ &blk, ktx->ktx_frags.datav, ktx->ktx_nfrag);
+ if (rc == ESUCCESS)
+ return (0);
+
+ /* reset refcount back to 1: we're not going to be racing with
+ * kqswnal_rely_complete. */
+ atomic_set (&krx->krx_refcount, 1);
+ return (-ECONNABORTED);
+}
+