1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27*0Sstevel@tonic-gate /* All Rights Reserved */ 28*0Sstevel@tonic-gate /* 29*0Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 30*0Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of 31*0Sstevel@tonic-gate * California. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #include <sys/param.h> 37*0Sstevel@tonic-gate #include <sys/types.h> 38*0Sstevel@tonic-gate #include <sys/user.h> 39*0Sstevel@tonic-gate #include <sys/systm.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <sys/errno.h> 42*0Sstevel@tonic-gate #include <sys/kmem.h> 43*0Sstevel@tonic-gate #include <sys/debug.h> 44*0Sstevel@tonic-gate #include <sys/systm.h> 45*0Sstevel@tonic-gate #include <sys/kstat.h> 46*0Sstevel@tonic-gate #include <sys/t_lock.h> 47*0Sstevel@tonic-gate #include <sys/ddi.h> 48*0Sstevel@tonic-gate #include <sys/cmn_err.h> 49*0Sstevel@tonic-gate #include <sys/time.h> 50*0Sstevel@tonic-gate #include <sys/isa_defs.h> 51*0Sstevel@tonic-gate #include <sys/zone.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <rpc/types.h> 54*0Sstevel@tonic-gate #include <rpc/xdr.h> 55*0Sstevel@tonic-gate #include <rpc/auth.h> 56*0Sstevel@tonic-gate #include <rpc/clnt.h> 57*0Sstevel@tonic-gate #include <rpc/rpc_msg.h> 58*0Sstevel@tonic-gate #include <rpc/rpc_rdma.h> 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate static enum clnt_stat clnt_rdma_kcallit(CLIENT *, rpcproc_t, xdrproc_t, 62*0Sstevel@tonic-gate caddr_t, xdrproc_t, caddr_t, struct timeval); 63*0Sstevel@tonic-gate static void clnt_rdma_kabort(CLIENT *); 64*0Sstevel@tonic-gate static void clnt_rdma_kerror(CLIENT *, struct rpc_err *); 65*0Sstevel@tonic-gate static bool_t clnt_rdma_kfreeres(CLIENT *, xdrproc_t, caddr_t); 66*0Sstevel@tonic-gate static void clnt_rdma_kdestroy(CLIENT *); 67*0Sstevel@tonic-gate static bool_t clnt_rdma_kcontrol(CLIENT *, int, char *); 68*0Sstevel@tonic-gate static int clnt_rdma_ksettimers(CLIENT *, struct rpc_timers *, 69*0Sstevel@tonic-gate struct rpc_timers *, int, void(*)(int, int, caddr_t), caddr_t, uint32_t); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * Operations vector for RDMA based RPC 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate static struct clnt_ops rdma_clnt_ops = { 75*0Sstevel@tonic-gate clnt_rdma_kcallit, /* do rpc call */ 76*0Sstevel@tonic-gate clnt_rdma_kabort, /* abort call */ 77*0Sstevel@tonic-gate clnt_rdma_kerror, /* return error status */ 78*0Sstevel@tonic-gate clnt_rdma_kfreeres, /* free results */ 79*0Sstevel@tonic-gate clnt_rdma_kdestroy, /* destroy rpc handle */ 80*0Sstevel@tonic-gate clnt_rdma_kcontrol, /* the ioctl() of rpc */ 81*0Sstevel@tonic-gate clnt_rdma_ksettimers, /* set retry timers */ 82*0Sstevel@tonic-gate }; 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate /* 85*0Sstevel@tonic-gate * The size of the preserialized RPC header information. 86*0Sstevel@tonic-gate */ 87*0Sstevel@tonic-gate #define CKU_HDRSIZE 20 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate /* 90*0Sstevel@tonic-gate * Per RPC RDMA endpoint details 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate typedef struct cku_private { 93*0Sstevel@tonic-gate CLIENT cku_client; /* client handle */ 94*0Sstevel@tonic-gate rdma_mod_t *cku_rd_mod; /* underlying RDMA mod */ 95*0Sstevel@tonic-gate void *cku_rd_handle; /* underlying RDMA device */ 96*0Sstevel@tonic-gate struct netbuf cku_addr; /* remote netbuf address */ 97*0Sstevel@tonic-gate int cku_addrfmly; /* for finding addr_type */ 98*0Sstevel@tonic-gate struct rpc_err cku_err; /* error status */ 99*0Sstevel@tonic-gate struct cred *cku_cred; /* credentials */ 100*0Sstevel@tonic-gate XDR cku_outxdr; /* xdr stream for output */ 101*0Sstevel@tonic-gate uint32_t cku_outsz; 102*0Sstevel@tonic-gate XDR cku_inxdr; /* xdr stream for input */ 103*0Sstevel@tonic-gate char cku_rpchdr[CKU_HDRSIZE+4]; /* rpc header */ 104*0Sstevel@tonic-gate uint32_t cku_xid; /* current XID */ 105*0Sstevel@tonic-gate } cku_private_t; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate #define CLNT_RDMA_DELAY 10 /* secs to delay after a connection failure */ 108*0Sstevel@tonic-gate static int clnt_rdma_min_delay = CLNT_RDMA_DELAY; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate struct { 111*0Sstevel@tonic-gate kstat_named_t rccalls; 112*0Sstevel@tonic-gate kstat_named_t rcbadcalls; 113*0Sstevel@tonic-gate kstat_named_t rcbadxids; 114*0Sstevel@tonic-gate kstat_named_t rctimeouts; 115*0Sstevel@tonic-gate kstat_named_t rcnewcreds; 116*0Sstevel@tonic-gate kstat_named_t rcbadverfs; 117*0Sstevel@tonic-gate kstat_named_t rctimers; 118*0Sstevel@tonic-gate kstat_named_t rccantconn; 119*0Sstevel@tonic-gate kstat_named_t rcnomem; 120*0Sstevel@tonic-gate kstat_named_t rcintrs; 121*0Sstevel@tonic-gate kstat_named_t rclongrpcs; 122*0Sstevel@tonic-gate } rdmarcstat = { 123*0Sstevel@tonic-gate { "calls", KSTAT_DATA_UINT64 }, 124*0Sstevel@tonic-gate { "badcalls", KSTAT_DATA_UINT64 }, 125*0Sstevel@tonic-gate { "badxids", KSTAT_DATA_UINT64 }, 126*0Sstevel@tonic-gate { "timeouts", KSTAT_DATA_UINT64 }, 127*0Sstevel@tonic-gate { "newcreds", KSTAT_DATA_UINT64 }, 128*0Sstevel@tonic-gate { "badverfs", KSTAT_DATA_UINT64 }, 129*0Sstevel@tonic-gate { "timers", KSTAT_DATA_UINT64 }, 130*0Sstevel@tonic-gate { "cantconn", KSTAT_DATA_UINT64 }, 131*0Sstevel@tonic-gate { "nomem", KSTAT_DATA_UINT64 }, 132*0Sstevel@tonic-gate { "interrupts", KSTAT_DATA_UINT64 }, 133*0Sstevel@tonic-gate { "longrpc", KSTAT_DATA_UINT64 } 134*0Sstevel@tonic-gate }; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate kstat_named_t *rdmarcstat_ptr = (kstat_named_t *)&rdmarcstat; 137*0Sstevel@tonic-gate uint_t rdmarcstat_ndata = sizeof (rdmarcstat) / sizeof (kstat_named_t); 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate #ifdef DEBUG 140*0Sstevel@tonic-gate int rdma_clnt_debug = 0; 141*0Sstevel@tonic-gate #endif 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate #ifdef accurate_stats 144*0Sstevel@tonic-gate extern kmutex_t rdmarcstat_lock; /* mutex for rcstat updates */ 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate #define RCSTAT_INCR(x) \ 147*0Sstevel@tonic-gate mutex_enter(&rdmarcstat_lock); \ 148*0Sstevel@tonic-gate rdmarcstat.x.value.ui64++; \ 149*0Sstevel@tonic-gate mutex_exit(&rdmarcstat_lock); 150*0Sstevel@tonic-gate #else 151*0Sstevel@tonic-gate #define RCSTAT_INCR(x) \ 152*0Sstevel@tonic-gate rdmarcstat.x.value.ui64++; 153*0Sstevel@tonic-gate #endif 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate #define ptoh(p) (&((p)->cku_client)) 156*0Sstevel@tonic-gate #define htop(h) ((cku_private_t *)((h)->cl_private)) 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate int 159*0Sstevel@tonic-gate clnt_rdma_kcreate(char *proto, void *handle, struct netbuf *raddr, int family, 160*0Sstevel@tonic-gate rpcprog_t pgm, rpcvers_t vers, struct cred *cred, CLIENT **cl) 161*0Sstevel@tonic-gate { 162*0Sstevel@tonic-gate CLIENT *h; 163*0Sstevel@tonic-gate struct cku_private *p; 164*0Sstevel@tonic-gate struct rpc_msg call_msg; 165*0Sstevel@tonic-gate rdma_registry_t *rp; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate ASSERT(INGLOBALZONE(curproc)); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if (cl == NULL) 170*0Sstevel@tonic-gate return (EINVAL); 171*0Sstevel@tonic-gate *cl = NULL; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate p = kmem_zalloc(sizeof (*p), KM_SLEEP); 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* 176*0Sstevel@tonic-gate * Find underlying RDMATF plugin 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate rw_enter(&rdma_lock, RW_READER); 179*0Sstevel@tonic-gate rp = rdma_mod_head; 180*0Sstevel@tonic-gate while (rp != NULL) { 181*0Sstevel@tonic-gate if (strcmp(rp->r_mod->rdma_api, proto)) 182*0Sstevel@tonic-gate rp = rp->r_next; 183*0Sstevel@tonic-gate else { 184*0Sstevel@tonic-gate p->cku_rd_mod = rp->r_mod; 185*0Sstevel@tonic-gate p->cku_rd_handle = handle; 186*0Sstevel@tonic-gate break; 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate rw_exit(&rdma_lock); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate if (p->cku_rd_mod == NULL) { 192*0Sstevel@tonic-gate /* 193*0Sstevel@tonic-gate * Should not happen. 194*0Sstevel@tonic-gate * No matching RDMATF plugin. 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate kmem_free(p, sizeof (struct cku_private)); 197*0Sstevel@tonic-gate return (EINVAL); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate h = ptoh(p); 201*0Sstevel@tonic-gate h->cl_ops = &rdma_clnt_ops; 202*0Sstevel@tonic-gate h->cl_private = (caddr_t)p; 203*0Sstevel@tonic-gate h->cl_auth = authkern_create(); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* call message, just used to pre-serialize below */ 206*0Sstevel@tonic-gate call_msg.rm_xid = 0; 207*0Sstevel@tonic-gate call_msg.rm_direction = CALL; 208*0Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 209*0Sstevel@tonic-gate call_msg.rm_call.cb_prog = pgm; 210*0Sstevel@tonic-gate call_msg.rm_call.cb_vers = vers; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, CKU_HDRSIZE, XDR_ENCODE); 213*0Sstevel@tonic-gate /* pre-serialize call message header */ 214*0Sstevel@tonic-gate if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) { 215*0Sstevel@tonic-gate XDR_DESTROY(&p->cku_outxdr); 216*0Sstevel@tonic-gate auth_destroy(h->cl_auth); 217*0Sstevel@tonic-gate kmem_free(p, sizeof (struct cku_private)); 218*0Sstevel@tonic-gate return (EINVAL); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * Set up the rpc information 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate p->cku_cred = cred; 225*0Sstevel@tonic-gate p->cku_addr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP); 226*0Sstevel@tonic-gate p->cku_addr.maxlen = raddr->maxlen; 227*0Sstevel@tonic-gate p->cku_addr.len = raddr->len; 228*0Sstevel@tonic-gate bcopy(raddr->buf, p->cku_addr.buf, raddr->len); 229*0Sstevel@tonic-gate p->cku_addrfmly = family; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate *cl = h; 232*0Sstevel@tonic-gate return (0); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate static void 236*0Sstevel@tonic-gate clnt_rdma_kdestroy(CLIENT *h) 237*0Sstevel@tonic-gate { 238*0Sstevel@tonic-gate struct cku_private *p = htop(h); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate kmem_free(p->cku_addr.buf, p->cku_addr.maxlen); 241*0Sstevel@tonic-gate kmem_free(p, sizeof (*p)); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate void 245*0Sstevel@tonic-gate clnt_rdma_kinit(CLIENT *h, char *proto, void *handle, struct netbuf *raddr, 246*0Sstevel@tonic-gate struct cred *cred) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate struct cku_private *p = htop(h); 249*0Sstevel@tonic-gate rdma_registry_t *rp; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate ASSERT(INGLOBALZONE(curproc)); 252*0Sstevel@tonic-gate /* 253*0Sstevel@tonic-gate * Find underlying RDMATF plugin 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate p->cku_rd_mod = NULL; 256*0Sstevel@tonic-gate rw_enter(&rdma_lock, RW_READER); 257*0Sstevel@tonic-gate rp = rdma_mod_head; 258*0Sstevel@tonic-gate while (rp != NULL) { 259*0Sstevel@tonic-gate if (strcmp(rp->r_mod->rdma_api, proto)) 260*0Sstevel@tonic-gate rp = rp->r_next; 261*0Sstevel@tonic-gate else { 262*0Sstevel@tonic-gate p->cku_rd_mod = rp->r_mod; 263*0Sstevel@tonic-gate p->cku_rd_handle = handle; 264*0Sstevel@tonic-gate break; 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate rw_exit(&rdma_lock); 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * Set up the rpc information 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate p->cku_cred = cred; 274*0Sstevel@tonic-gate p->cku_xid = 0; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate if (p->cku_addr.maxlen < raddr->len) { 277*0Sstevel@tonic-gate if (p->cku_addr.maxlen != 0 && p->cku_addr.buf != NULL) 278*0Sstevel@tonic-gate kmem_free(p->cku_addr.buf, p->cku_addr.maxlen); 279*0Sstevel@tonic-gate p->cku_addr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP); 280*0Sstevel@tonic-gate p->cku_addr.maxlen = raddr->maxlen; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate p->cku_addr.len = raddr->len; 284*0Sstevel@tonic-gate bcopy(raddr->buf, p->cku_addr.buf, raddr->len); 285*0Sstevel@tonic-gate h->cl_ops = &rdma_clnt_ops; 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate /* ARGSUSED */ 289*0Sstevel@tonic-gate static enum clnt_stat 290*0Sstevel@tonic-gate clnt_rdma_kcallit(CLIENT *h, rpcproc_t procnum, xdrproc_t xdr_args, 291*0Sstevel@tonic-gate caddr_t argsp, xdrproc_t xdr_results, caddr_t resultsp, struct timeval wait) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate cku_private_t *p = htop(h); 294*0Sstevel@tonic-gate int status; 295*0Sstevel@tonic-gate XDR *xdrs; 296*0Sstevel@tonic-gate XDR *cxdrp = NULL, callxdr; /* for xdrrdma encoding the RPC call */ 297*0Sstevel@tonic-gate XDR *rxdrp = NULL, replxdr; /* for xdrrdma decoding the RPC reply */ 298*0Sstevel@tonic-gate struct rpc_msg reply_msg; 299*0Sstevel@tonic-gate struct clist *sendlist, *recvlist = NULL; 300*0Sstevel@tonic-gate struct clist *cl = NULL, *cle = NULL; 301*0Sstevel@tonic-gate uint_t vers, op; 302*0Sstevel@tonic-gate uint_t off; 303*0Sstevel@tonic-gate uint32_t xid; 304*0Sstevel@tonic-gate CONN *conn = NULL; 305*0Sstevel@tonic-gate rdma_buf_t clmsg, rpcmsg, longmsg, rpcreply; 306*0Sstevel@tonic-gate int msglen; 307*0Sstevel@tonic-gate clock_t ticks; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate RCSTAT_INCR(rccalls); 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * Get unique xid 312*0Sstevel@tonic-gate */ 313*0Sstevel@tonic-gate if (p->cku_xid == 0) 314*0Sstevel@tonic-gate p->cku_xid = alloc_xid(); 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate status = RDMA_GET_CONN(p->cku_rd_mod->rdma_ops, &p->cku_addr, 317*0Sstevel@tonic-gate p->cku_addrfmly, p->cku_rd_handle, &conn); 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if (conn == NULL) { 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * Connect failed to server. Could be because of one 322*0Sstevel@tonic-gate * of several things. In some cases we don't want 323*0Sstevel@tonic-gate * the caller to retry immediately - delay before 324*0Sstevel@tonic-gate * returning to caller. 325*0Sstevel@tonic-gate */ 326*0Sstevel@tonic-gate switch (status) { 327*0Sstevel@tonic-gate case RDMA_TIMEDOUT: 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * Already timed out. No need to delay 330*0Sstevel@tonic-gate * some more. 331*0Sstevel@tonic-gate */ 332*0Sstevel@tonic-gate p->cku_err.re_status = RPC_TIMEDOUT; 333*0Sstevel@tonic-gate p->cku_err.re_errno = ETIMEDOUT; 334*0Sstevel@tonic-gate break; 335*0Sstevel@tonic-gate case RDMA_INTR: 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * Failed because of an signal. Very likely 338*0Sstevel@tonic-gate * the caller will not retry. 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate p->cku_err.re_status = RPC_INTR; 341*0Sstevel@tonic-gate p->cku_err.re_errno = EINTR; 342*0Sstevel@tonic-gate break; 343*0Sstevel@tonic-gate default: 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * All other failures - server down or service 346*0Sstevel@tonic-gate * down or temporary resource failure. Delay before 347*0Sstevel@tonic-gate * returning to caller. 348*0Sstevel@tonic-gate */ 349*0Sstevel@tonic-gate ticks = clnt_rdma_min_delay * drv_usectohz(1000000); 350*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTCONNECT; 351*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate if (h->cl_nosignal == TRUE) { 354*0Sstevel@tonic-gate delay(ticks); 355*0Sstevel@tonic-gate } else { 356*0Sstevel@tonic-gate if (delay_sig(ticks) == EINTR) { 357*0Sstevel@tonic-gate p->cku_err.re_status = RPC_INTR; 358*0Sstevel@tonic-gate p->cku_err.re_errno = EINTR; 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate break; 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate return (p->cku_err.re_status); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * Get the size of the rpc call message. Need this 368*0Sstevel@tonic-gate * to determine if the rpc call message will fit in 369*0Sstevel@tonic-gate * the pre-allocated RDMA buffers. If the rpc call 370*0Sstevel@tonic-gate * message length is greater that the pre-allocated 371*0Sstevel@tonic-gate * buffers then, it is a Long RPC. A one time use 372*0Sstevel@tonic-gate * buffer is allocated and registered for the Long 373*0Sstevel@tonic-gate * RPC call. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate xdrs = &callxdr; 376*0Sstevel@tonic-gate msglen = CKU_HDRSIZE + BYTES_PER_XDR_UNIT; 377*0Sstevel@tonic-gate if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 378*0Sstevel@tonic-gate msglen += xdrrdma_authsize(h->cl_auth, p->cku_cred, 379*0Sstevel@tonic-gate rdma_minchunk); 380*0Sstevel@tonic-gate msglen += xdrrdma_sizeof(xdr_args, argsp, rdma_minchunk); 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate if (msglen > RPC_MSG_SZ) { 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * Long RPC. Allocate one time use custom buffer. 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate rpcmsg.type = CHUNK_BUFFER; 388*0Sstevel@tonic-gate rpcmsg.addr = kmem_zalloc(msglen, KM_SLEEP); 389*0Sstevel@tonic-gate cle = kmem_zalloc(sizeof (*cle), KM_SLEEP); 390*0Sstevel@tonic-gate cle->c_xdroff = 0; 391*0Sstevel@tonic-gate cle->c_len = rpcmsg.len = msglen; 392*0Sstevel@tonic-gate cle->c_saddr = (uint64)(uintptr_t)rpcmsg.addr; 393*0Sstevel@tonic-gate cle->c_next = NULL; 394*0Sstevel@tonic-gate xdrrdma_create(xdrs, rpcmsg.addr, msglen, 395*0Sstevel@tonic-gate rdma_minchunk, cle, XDR_ENCODE, NULL); 396*0Sstevel@tonic-gate cxdrp = xdrs; 397*0Sstevel@tonic-gate op = RDMA_NOMSG; 398*0Sstevel@tonic-gate } else { 399*0Sstevel@tonic-gate /* 400*0Sstevel@tonic-gate * Get a pre-allocated buffer for rpc call 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate rpcmsg.type = SEND_BUFFER; 403*0Sstevel@tonic-gate if (RDMA_BUF_ALLOC(conn, &rpcmsg)) { 404*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 405*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 406*0Sstevel@tonic-gate RCSTAT_INCR(rcnomem); 407*0Sstevel@tonic-gate cmn_err(CE_WARN, 408*0Sstevel@tonic-gate "clnt_rdma_kcallit: no buffers!"); 409*0Sstevel@tonic-gate goto done; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate xdrrdma_create(xdrs, rpcmsg.addr, rpcmsg.len, 412*0Sstevel@tonic-gate rdma_minchunk, NULL, XDR_ENCODE, NULL); 413*0Sstevel@tonic-gate cxdrp = xdrs; 414*0Sstevel@tonic-gate op = RDMA_MSG; 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate } else { 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * For RPCSEC_GSS since we cannot accurately presize the 419*0Sstevel@tonic-gate * buffer required for encoding, we assume that its going 420*0Sstevel@tonic-gate * to be a Long RPC to start with. We also create the 421*0Sstevel@tonic-gate * the XDR stream with min_chunk set to 0 which instructs 422*0Sstevel@tonic-gate * the XDR layer to not chunk the incoming byte stream. 423*0Sstevel@tonic-gate */ 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate msglen += 2 * MAX_AUTH_BYTES + 2 * sizeof (struct opaque_auth); 426*0Sstevel@tonic-gate msglen += xdr_sizeof(xdr_args, argsp); 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Long RPC. Allocate one time use custom buffer. 430*0Sstevel@tonic-gate */ 431*0Sstevel@tonic-gate longmsg.type = CHUNK_BUFFER; 432*0Sstevel@tonic-gate longmsg.addr = kmem_zalloc(msglen, KM_SLEEP); 433*0Sstevel@tonic-gate cle = kmem_zalloc(sizeof (*cle), KM_SLEEP); 434*0Sstevel@tonic-gate cle->c_xdroff = 0; 435*0Sstevel@tonic-gate cle->c_len = longmsg.len = msglen; 436*0Sstevel@tonic-gate cle->c_saddr = (uint64)(uintptr_t)longmsg.addr; 437*0Sstevel@tonic-gate cle->c_next = NULL; 438*0Sstevel@tonic-gate xdrrdma_create(xdrs, longmsg.addr, msglen, 0, cle, 439*0Sstevel@tonic-gate XDR_ENCODE, NULL); 440*0Sstevel@tonic-gate cxdrp = xdrs; 441*0Sstevel@tonic-gate op = RDMA_NOMSG; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 445*0Sstevel@tonic-gate /* 446*0Sstevel@tonic-gate * Copy in the preserialized RPC header 447*0Sstevel@tonic-gate * information. 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate bcopy(p->cku_rpchdr, rpcmsg.addr, CKU_HDRSIZE); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate /* 452*0Sstevel@tonic-gate * transaction id is the 1st thing in the output 453*0Sstevel@tonic-gate * buffer. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate /* LINTED pointer alignment */ 456*0Sstevel@tonic-gate (*(uint32_t *)(rpcmsg.addr)) = p->cku_xid; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* Skip the preserialized stuff. */ 459*0Sstevel@tonic-gate XDR_SETPOS(xdrs, CKU_HDRSIZE); 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* Serialize dynamic stuff into the output buffer. */ 462*0Sstevel@tonic-gate if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) || 463*0Sstevel@tonic-gate (!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) || 464*0Sstevel@tonic-gate (!(*xdr_args)(xdrs, argsp))) { 465*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 466*0Sstevel@tonic-gate if (cle) 467*0Sstevel@tonic-gate clist_free(cle); 468*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTENCODEARGS; 469*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 470*0Sstevel@tonic-gate cmn_err(CE_WARN, 471*0Sstevel@tonic-gate "clnt_rdma_kcallit: XDR_PUTINT32/AUTH_MARSHAL/xdr_args failed"); 472*0Sstevel@tonic-gate goto done; 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate p->cku_outsz = XDR_GETPOS(xdrs); 475*0Sstevel@tonic-gate } else { 476*0Sstevel@tonic-gate uint32_t *uproc = (uint32_t *)&p->cku_rpchdr[CKU_HDRSIZE]; 477*0Sstevel@tonic-gate IXDR_PUT_U_INT32(uproc, procnum); 478*0Sstevel@tonic-gate (*(uint32_t *)(&p->cku_rpchdr[0])) = p->cku_xid; 479*0Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate /* Serialize the procedure number and the arguments. */ 482*0Sstevel@tonic-gate if (!AUTH_WRAP(h->cl_auth, (caddr_t)p->cku_rpchdr, 483*0Sstevel@tonic-gate CKU_HDRSIZE+4, xdrs, xdr_args, argsp)) { 484*0Sstevel@tonic-gate if (longmsg.addr != xdrs->x_base) { 485*0Sstevel@tonic-gate longmsg.addr = xdrs->x_base; 486*0Sstevel@tonic-gate longmsg.len = xdr_getbufsize(xdrs); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate rdma_buf_free(conn, &longmsg); 489*0Sstevel@tonic-gate clist_free(cle); 490*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTENCODEARGS; 491*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 492*0Sstevel@tonic-gate cmn_err(CE_WARN, 493*0Sstevel@tonic-gate "clnt_rdma_kcallit: AUTH_WRAP failed"); 494*0Sstevel@tonic-gate goto done; 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate /* 497*0Sstevel@tonic-gate * If we had to allocate a new buffer while encoding 498*0Sstevel@tonic-gate * then update the addr and len. 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate if (longmsg.addr != xdrs->x_base) { 501*0Sstevel@tonic-gate longmsg.addr = xdrs->x_base; 502*0Sstevel@tonic-gate longmsg.len = xdr_getbufsize(xdrs); 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate /* 506*0Sstevel@tonic-gate * If it so happens that the encoded message is after all 507*0Sstevel@tonic-gate * not long enough to be a Long RPC then allocate a 508*0Sstevel@tonic-gate * SEND_BUFFER and copy the encoded message into it. 509*0Sstevel@tonic-gate */ 510*0Sstevel@tonic-gate p->cku_outsz = XDR_GETPOS(xdrs); 511*0Sstevel@tonic-gate if (p->cku_outsz > RPC_MSG_SZ) { 512*0Sstevel@tonic-gate rpcmsg.type = CHUNK_BUFFER; 513*0Sstevel@tonic-gate rpcmsg.addr = longmsg.addr; 514*0Sstevel@tonic-gate rpcmsg.len = longmsg.len; 515*0Sstevel@tonic-gate } else { 516*0Sstevel@tonic-gate clist_free(cle); 517*0Sstevel@tonic-gate XDR_DESTROY(cxdrp); 518*0Sstevel@tonic-gate cxdrp = NULL; 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * Get a pre-allocated buffer for rpc call 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate rpcmsg.type = SEND_BUFFER; 523*0Sstevel@tonic-gate if (RDMA_BUF_ALLOC(conn, &rpcmsg)) { 524*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 525*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 526*0Sstevel@tonic-gate RCSTAT_INCR(rcnomem); 527*0Sstevel@tonic-gate cmn_err(CE_WARN, 528*0Sstevel@tonic-gate "clnt_rdma_kcallit: no buffers!"); 529*0Sstevel@tonic-gate rdma_buf_free(conn, &longmsg); 530*0Sstevel@tonic-gate goto done; 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate bcopy(longmsg.addr, rpcmsg.addr, p->cku_outsz); 533*0Sstevel@tonic-gate xdrrdma_create(xdrs, rpcmsg.addr, p->cku_outsz, 0, 534*0Sstevel@tonic-gate NULL, XDR_ENCODE, NULL); 535*0Sstevel@tonic-gate cxdrp = xdrs; 536*0Sstevel@tonic-gate rdma_buf_free(conn, &longmsg); 537*0Sstevel@tonic-gate op = RDMA_MSG; 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate cl = xdrrdma_clist(xdrs); 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * Update the chunk size information for the Long RPC msg. 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate if (cl && op == RDMA_NOMSG) 547*0Sstevel@tonic-gate cl->c_len = p->cku_outsz; 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* 550*0Sstevel@tonic-gate * Set up the RDMA chunk message 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate vers = RPCRDMA_VERS; 553*0Sstevel@tonic-gate clmsg.type = SEND_BUFFER; 554*0Sstevel@tonic-gate if (RDMA_BUF_ALLOC(conn, &clmsg)) { 555*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 556*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 557*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 558*0Sstevel@tonic-gate RCSTAT_INCR(rcnomem); 559*0Sstevel@tonic-gate cmn_err(CE_WARN, "clnt_rdma_kcallit: no free buffers!!"); 560*0Sstevel@tonic-gate goto done; 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate xdrs = &p->cku_outxdr; 563*0Sstevel@tonic-gate xdrmem_create(xdrs, clmsg.addr, clmsg.len, XDR_ENCODE); 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * Treat xid as opaque (xid is the first entity 566*0Sstevel@tonic-gate * in the rpc rdma message). 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate (*(uint32_t *)clmsg.addr) = p->cku_xid; 569*0Sstevel@tonic-gate /* Skip xid and set the xdr position accordingly. */ 570*0Sstevel@tonic-gate XDR_SETPOS(xdrs, sizeof (uint32_t)); 571*0Sstevel@tonic-gate (void) xdr_u_int(xdrs, &vers); 572*0Sstevel@tonic-gate (void) xdr_u_int(xdrs, &op); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate /* 575*0Sstevel@tonic-gate * Now XDR the chunk list 576*0Sstevel@tonic-gate */ 577*0Sstevel@tonic-gate if (cl != NULL) { 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate /* 580*0Sstevel@tonic-gate * Register the chunks in the list 581*0Sstevel@tonic-gate */ 582*0Sstevel@tonic-gate status = clist_register(conn, cl, 1); 583*0Sstevel@tonic-gate if (status != RDMA_SUCCESS) { 584*0Sstevel@tonic-gate cmn_err(CE_WARN, 585*0Sstevel@tonic-gate "clnt_rdma_kcallit: clist register failed"); 586*0Sstevel@tonic-gate rdma_buf_free(conn, &clmsg); 587*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 588*0Sstevel@tonic-gate clist_free(cl); 589*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 590*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 591*0Sstevel@tonic-gate goto done; 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate (void) xdr_do_clist(xdrs, &cl); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate /* 598*0Sstevel@tonic-gate * Start with the RDMA header and clist (if any) 599*0Sstevel@tonic-gate */ 600*0Sstevel@tonic-gate sendlist = NULL; 601*0Sstevel@tonic-gate clist_add(&sendlist, 0, XDR_GETPOS(xdrs), &clmsg.handle, 602*0Sstevel@tonic-gate clmsg.addr, NULL, NULL); 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate /* 605*0Sstevel@tonic-gate * Put the RPC call message in the send list if small RPC 606*0Sstevel@tonic-gate */ 607*0Sstevel@tonic-gate if (op == RDMA_MSG) { 608*0Sstevel@tonic-gate clist_add(&sendlist, 0, p->cku_outsz, &rpcmsg.handle, 609*0Sstevel@tonic-gate rpcmsg.addr, NULL, NULL); 610*0Sstevel@tonic-gate } else { 611*0Sstevel@tonic-gate /* Long RPC already in chunk list */ 612*0Sstevel@tonic-gate RCSTAT_INCR(rclongrpcs); 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate /* 616*0Sstevel@tonic-gate * Set up a reply buffer ready for the reply 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate status = rdma_clnt_postrecv(conn, p->cku_xid); 619*0Sstevel@tonic-gate if (status != RDMA_SUCCESS) { 620*0Sstevel@tonic-gate rdma_buf_free(conn, &clmsg); 621*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 622*0Sstevel@tonic-gate if (cl) { 623*0Sstevel@tonic-gate (void) clist_deregister(conn, cl, 1); 624*0Sstevel@tonic-gate clist_free(cl); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate clist_free(sendlist); 627*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 628*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 629*0Sstevel@tonic-gate goto done; 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate /* 632*0Sstevel@tonic-gate * sync the memory for dma 633*0Sstevel@tonic-gate */ 634*0Sstevel@tonic-gate if (cl != NULL) { 635*0Sstevel@tonic-gate status = clist_syncmem(conn, cl, 1); 636*0Sstevel@tonic-gate if (status != RDMA_SUCCESS) { 637*0Sstevel@tonic-gate rdma_buf_free(conn, &clmsg); 638*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 639*0Sstevel@tonic-gate (void) clist_deregister(conn, cl, 1); 640*0Sstevel@tonic-gate clist_free(cl); 641*0Sstevel@tonic-gate clist_free(sendlist); 642*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 643*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 644*0Sstevel@tonic-gate goto done; 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * Send the call message to the server 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate status = RDMA_SEND(conn, sendlist, p->cku_xid); 652*0Sstevel@tonic-gate if (status != RDMA_SUCCESS) { 653*0Sstevel@tonic-gate if (cl) { 654*0Sstevel@tonic-gate (void) clist_deregister(conn, cl, 1); 655*0Sstevel@tonic-gate clist_free(cl); 656*0Sstevel@tonic-gate /* 657*0Sstevel@tonic-gate * If this was a long RPC message, need 658*0Sstevel@tonic-gate * to free that buffer. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate if (rpcmsg.type == CHUNK_BUFFER) 661*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate clist_free(sendlist); 664*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 665*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 666*0Sstevel@tonic-gate goto done; 667*0Sstevel@tonic-gate } else { 668*0Sstevel@tonic-gate /* 669*0Sstevel@tonic-gate * RDMA plugin now owns the send msg buffers. 670*0Sstevel@tonic-gate * Clear them out and don't free them here. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate clmsg.addr = NULL; 673*0Sstevel@tonic-gate if (rpcmsg.type == SEND_BUFFER) 674*0Sstevel@tonic-gate rpcmsg.addr = NULL; 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate clist_free(sendlist); 677*0Sstevel@tonic-gate #ifdef DEBUG 678*0Sstevel@tonic-gate if (rdma_clnt_debug) { 679*0Sstevel@tonic-gate printf("clnt_rdma_kcallit: send request xid %u\n", p->cku_xid); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate #endif 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Recv rpc reply 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate status = RDMA_RECV(conn, &recvlist, p->cku_xid); 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* 689*0Sstevel@tonic-gate * Deregister chunks sent. Do this only after the reply 690*0Sstevel@tonic-gate * is received as that is a sure indication that the 691*0Sstevel@tonic-gate * remote end has completed RDMA of the chunks. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate if (cl != NULL) { 694*0Sstevel@tonic-gate /* 695*0Sstevel@tonic-gate * Deregister the chunks 696*0Sstevel@tonic-gate */ 697*0Sstevel@tonic-gate (void) clist_deregister(conn, cl, 1); 698*0Sstevel@tonic-gate clist_free(cl); 699*0Sstevel@tonic-gate /* 700*0Sstevel@tonic-gate * If long RPC free chunk 701*0Sstevel@tonic-gate */ 702*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcmsg); 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * Now check recv status 707*0Sstevel@tonic-gate */ 708*0Sstevel@tonic-gate if (status != 0) { 709*0Sstevel@tonic-gate #ifdef DEBUG 710*0Sstevel@tonic-gate if (rdma_clnt_debug) 711*0Sstevel@tonic-gate cmn_err(CE_NOTE, 712*0Sstevel@tonic-gate "clnt_rdma_kcallit: reply failed %u status %d", 713*0Sstevel@tonic-gate p->cku_xid, status); 714*0Sstevel@tonic-gate #endif 715*0Sstevel@tonic-gate if (status == RDMA_INTR) { 716*0Sstevel@tonic-gate p->cku_err.re_status = RPC_INTR; 717*0Sstevel@tonic-gate p->cku_err.re_errno = EINTR; 718*0Sstevel@tonic-gate RCSTAT_INCR(rcintrs); 719*0Sstevel@tonic-gate } else if (status == RPC_TIMEDOUT) { 720*0Sstevel@tonic-gate p->cku_err.re_status = RPC_TIMEDOUT; 721*0Sstevel@tonic-gate p->cku_err.re_errno = ETIMEDOUT; 722*0Sstevel@tonic-gate RCSTAT_INCR(rctimeouts); 723*0Sstevel@tonic-gate } else { 724*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTRECV; 725*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate goto done; 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate #ifdef DEBUG 730*0Sstevel@tonic-gate if (rdma_clnt_debug) 731*0Sstevel@tonic-gate printf("clnt_rdma_kcallit: got response xid %u\n", p->cku_xid); 732*0Sstevel@tonic-gate #endif 733*0Sstevel@tonic-gate /* 734*0Sstevel@tonic-gate * Process the reply message. 735*0Sstevel@tonic-gate * 736*0Sstevel@tonic-gate * First the chunk list (if any) 737*0Sstevel@tonic-gate */ 738*0Sstevel@tonic-gate xdrs = &(p->cku_inxdr); 739*0Sstevel@tonic-gate xdrmem_create(xdrs, (caddr_t)(uintptr_t)recvlist->c_saddr, 740*0Sstevel@tonic-gate recvlist->c_len, XDR_DECODE); 741*0Sstevel@tonic-gate /* 742*0Sstevel@tonic-gate * Treat xid as opaque (xid is the first entity 743*0Sstevel@tonic-gate * in the rpc rdma message). 744*0Sstevel@tonic-gate */ 745*0Sstevel@tonic-gate xid = *(uint32_t *)recvlist->c_saddr; 746*0Sstevel@tonic-gate /* Skip xid and set the xdr position accordingly. */ 747*0Sstevel@tonic-gate XDR_SETPOS(xdrs, sizeof (uint32_t)); 748*0Sstevel@tonic-gate (void) xdr_u_int(xdrs, &vers); 749*0Sstevel@tonic-gate (void) xdr_u_int(xdrs, &op); 750*0Sstevel@tonic-gate (void) xdr_do_clist(xdrs, &cl); 751*0Sstevel@tonic-gate off = xdr_getpos(xdrs); 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate /* 754*0Sstevel@tonic-gate * Now the RPC reply message itself. If the reply 755*0Sstevel@tonic-gate * came as a chunk item, then RDMA the reply over. 756*0Sstevel@tonic-gate */ 757*0Sstevel@tonic-gate xdrs = &replxdr; 758*0Sstevel@tonic-gate if (cl && op == RDMA_NOMSG) { 759*0Sstevel@tonic-gate struct clist *cle = cl; 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate rpcreply.type = CHUNK_BUFFER; 762*0Sstevel@tonic-gate rpcreply.addr = kmem_alloc(cle->c_len, KM_SLEEP); 763*0Sstevel@tonic-gate rpcreply.len = cle->c_len; 764*0Sstevel@tonic-gate cle->c_daddr = (uint64)(uintptr_t)rpcreply.addr; 765*0Sstevel@tonic-gate cl = cl->c_next; 766*0Sstevel@tonic-gate cle->c_next = NULL; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate /* 769*0Sstevel@tonic-gate * Register the rpc reply chunk destination 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate status = clist_register(conn, cle, 0); 772*0Sstevel@tonic-gate if (status) { 773*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcreply); 774*0Sstevel@tonic-gate clist_free(cle); 775*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES; 776*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 777*0Sstevel@tonic-gate cmn_err(CE_WARN, 778*0Sstevel@tonic-gate "clnt_rdma_kcallit: clist_register failed"); 779*0Sstevel@tonic-gate goto rdma_done; 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate /* 783*0Sstevel@tonic-gate * Now read rpc reply in 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate #ifdef DEBUG 786*0Sstevel@tonic-gate if (rdma_clnt_debug) 787*0Sstevel@tonic-gate printf("clnt_rdma_kcallit: read chunk, len %d, xid %u, \ 788*0Sstevel@tonic-gate reply xid %u\n", cle->c_len, p->cku_xid, xid); 789*0Sstevel@tonic-gate #endif 790*0Sstevel@tonic-gate status = RDMA_READ(conn, cle, WAIT); 791*0Sstevel@tonic-gate if (status) { 792*0Sstevel@tonic-gate (void) clist_deregister(conn, cle, 0); 793*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcreply); 794*0Sstevel@tonic-gate clist_free(cle); 795*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES; 796*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 797*0Sstevel@tonic-gate cmn_err(CE_WARN, 798*0Sstevel@tonic-gate "clnt_rdma_kcallit: RDMA_READ failed"); 799*0Sstevel@tonic-gate goto rdma_done; 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate /* 803*0Sstevel@tonic-gate * sync the memory for dma 804*0Sstevel@tonic-gate */ 805*0Sstevel@tonic-gate status = clist_syncmem(conn, cle, 0); 806*0Sstevel@tonic-gate if (status != RDMA_SUCCESS) { 807*0Sstevel@tonic-gate (void) clist_deregister(conn, cle, 0); 808*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcreply); 809*0Sstevel@tonic-gate clist_free(cle); 810*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES; 811*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 812*0Sstevel@tonic-gate goto rdma_done; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate /* 816*0Sstevel@tonic-gate * Deregister the Long RPC chunk 817*0Sstevel@tonic-gate */ 818*0Sstevel@tonic-gate (void) clist_deregister(conn, cle, 0); 819*0Sstevel@tonic-gate clist_free(cle); 820*0Sstevel@tonic-gate xdrrdma_create(xdrs, rpcreply.addr, rpcreply.len, 0, cl, 821*0Sstevel@tonic-gate XDR_DECODE, conn); 822*0Sstevel@tonic-gate rxdrp = xdrs; 823*0Sstevel@tonic-gate } else { 824*0Sstevel@tonic-gate rpcreply.addr = NULL; 825*0Sstevel@tonic-gate xdrrdma_create(xdrs, 826*0Sstevel@tonic-gate (caddr_t)(uintptr_t)(recvlist->c_saddr + off), 827*0Sstevel@tonic-gate recvlist->c_len - off, 0, cl, XDR_DECODE, conn); 828*0Sstevel@tonic-gate rxdrp = xdrs; 829*0Sstevel@tonic-gate } 830*0Sstevel@tonic-gate 831*0Sstevel@tonic-gate reply_msg.rm_direction = REPLY; 832*0Sstevel@tonic-gate reply_msg.rm_reply.rp_stat = MSG_ACCEPTED; 833*0Sstevel@tonic-gate reply_msg.acpted_rply.ar_stat = SUCCESS; 834*0Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth; 835*0Sstevel@tonic-gate /* 836*0Sstevel@tonic-gate * xdr_results will be done in AUTH_UNWRAP. 837*0Sstevel@tonic-gate */ 838*0Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = NULL; 839*0Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xdr_void; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate /* 842*0Sstevel@tonic-gate * Decode and validate the response. 843*0Sstevel@tonic-gate */ 844*0Sstevel@tonic-gate if (xdr_replymsg(xdrs, &reply_msg)) { 845*0Sstevel@tonic-gate enum clnt_stat re_status; 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate _seterr_reply(&reply_msg, &(p->cku_err)); 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate re_status = p->cku_err.re_status; 850*0Sstevel@tonic-gate if (re_status == RPC_SUCCESS) { 851*0Sstevel@tonic-gate /* 852*0Sstevel@tonic-gate * Reply is good, check auth. 853*0Sstevel@tonic-gate */ 854*0Sstevel@tonic-gate if (!AUTH_VALIDATE(h->cl_auth, 855*0Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) { 856*0Sstevel@tonic-gate p->cku_err.re_status = RPC_AUTHERROR; 857*0Sstevel@tonic-gate p->cku_err.re_why = AUTH_INVALIDRESP; 858*0Sstevel@tonic-gate RCSTAT_INCR(rcbadverfs); 859*0Sstevel@tonic-gate cmn_err(CE_WARN, 860*0Sstevel@tonic-gate "clnt_rdma_kcallit: AUTH_VALIDATE failed"); 861*0Sstevel@tonic-gate } else if (!AUTH_UNWRAP(h->cl_auth, xdrs, 862*0Sstevel@tonic-gate xdr_results, resultsp)) { 863*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES; 864*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 865*0Sstevel@tonic-gate cmn_err(CE_WARN, 866*0Sstevel@tonic-gate "clnt_rdma_kcallit: AUTH_UNWRAP failed"); 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate } else { 869*0Sstevel@tonic-gate /* set errno in case we can't recover */ 870*0Sstevel@tonic-gate if (re_status != RPC_VERSMISMATCH && 871*0Sstevel@tonic-gate re_status != RPC_AUTHERROR && 872*0Sstevel@tonic-gate re_status != RPC_PROGVERSMISMATCH) 873*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate if (re_status == RPC_AUTHERROR) { 876*0Sstevel@tonic-gate /* 877*0Sstevel@tonic-gate * Map recoverable and unrecoverable 878*0Sstevel@tonic-gate * authentication errors to appropriate 879*0Sstevel@tonic-gate * errno 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate switch (p->cku_err.re_why) { 882*0Sstevel@tonic-gate case AUTH_BADCRED: 883*0Sstevel@tonic-gate case AUTH_BADVERF: 884*0Sstevel@tonic-gate case AUTH_INVALIDRESP: 885*0Sstevel@tonic-gate case AUTH_TOOWEAK: 886*0Sstevel@tonic-gate case AUTH_FAILED: 887*0Sstevel@tonic-gate case RPCSEC_GSS_NOCRED: 888*0Sstevel@tonic-gate case RPCSEC_GSS_FAILED: 889*0Sstevel@tonic-gate p->cku_err.re_errno = EACCES; 890*0Sstevel@tonic-gate break; 891*0Sstevel@tonic-gate case AUTH_REJECTEDCRED: 892*0Sstevel@tonic-gate case AUTH_REJECTEDVERF: 893*0Sstevel@tonic-gate default: 894*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 895*0Sstevel@tonic-gate break; 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate RPCLOG(1, "clnt_rdma_kcallit : " 898*0Sstevel@tonic-gate "authentication failed with " 899*0Sstevel@tonic-gate "RPC_AUTHERROR of type %d\n", 900*0Sstevel@tonic-gate p->cku_err.re_why); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate cmn_err(CE_WARN, 903*0Sstevel@tonic-gate "clnt_rdma_kcallit: RPC failed"); 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate } else { 907*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES; 908*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 909*0Sstevel@tonic-gate cmn_err(CE_WARN, "clnt_rdma_kcallit: xdr_replymsg failed"); 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate /* 913*0Sstevel@tonic-gate * If rpc reply is in a chunk, free it now. 914*0Sstevel@tonic-gate */ 915*0Sstevel@tonic-gate if (rpcreply.addr != NULL) 916*0Sstevel@tonic-gate rdma_buf_free(conn, &rpcreply); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate rdma_done: 919*0Sstevel@tonic-gate if ((cl != NULL) || (op == RDMA_NOMSG)) { 920*0Sstevel@tonic-gate rdma_buf_t donemsg; 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate /* 923*0Sstevel@tonic-gate * Free the list holding the chunk info 924*0Sstevel@tonic-gate */ 925*0Sstevel@tonic-gate if (cl) { 926*0Sstevel@tonic-gate clist_free(cl); 927*0Sstevel@tonic-gate cl = NULL; 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate /* 931*0Sstevel@tonic-gate * Tell the server that the reads are done 932*0Sstevel@tonic-gate */ 933*0Sstevel@tonic-gate donemsg.type = SEND_BUFFER; 934*0Sstevel@tonic-gate if (RDMA_BUF_ALLOC(conn, &donemsg)) { 935*0Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTSEND; 936*0Sstevel@tonic-gate p->cku_err.re_errno = EIO; 937*0Sstevel@tonic-gate RCSTAT_INCR(rcnomem); 938*0Sstevel@tonic-gate cmn_err(CE_WARN, "clnt_rdma_kcallit: no free buffer"); 939*0Sstevel@tonic-gate goto done; 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate xdrs = &p->cku_outxdr; 942*0Sstevel@tonic-gate xdrmem_create(xdrs, donemsg.addr, donemsg.len, XDR_ENCODE); 943*0Sstevel@tonic-gate vers = RPCRDMA_VERS; 944*0Sstevel@tonic-gate op = RDMA_DONE; 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate /* 947*0Sstevel@tonic-gate * Treat xid as opaque (xid is the first entity 948*0Sstevel@tonic-gate * in the rpc rdma message). 949*0Sstevel@tonic-gate */ 950*0Sstevel@tonic-gate (*(uint32_t *)donemsg.addr) = p->cku_xid; 951*0Sstevel@tonic-gate /* Skip xid and set the xdr position accordingly. */ 952*0Sstevel@tonic-gate XDR_SETPOS(xdrs, sizeof (uint32_t)); 953*0Sstevel@tonic-gate if (!xdr_u_int(xdrs, &vers) || 954*0Sstevel@tonic-gate !xdr_u_int(xdrs, &op)) { 955*0Sstevel@tonic-gate cmn_err(CE_WARN, 956*0Sstevel@tonic-gate "clnt_rdma_kcallit: xdr_u_int failed"); 957*0Sstevel@tonic-gate rdma_buf_free(conn, &donemsg); 958*0Sstevel@tonic-gate goto done; 959*0Sstevel@tonic-gate } 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate sendlist = NULL; 962*0Sstevel@tonic-gate clist_add(&sendlist, 0, XDR_GETPOS(xdrs), &donemsg.handle, 963*0Sstevel@tonic-gate donemsg.addr, NULL, NULL); 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate status = RDMA_SEND(conn, sendlist, p->cku_xid); 966*0Sstevel@tonic-gate if (status != RDMA_SUCCESS) { 967*0Sstevel@tonic-gate cmn_err(CE_WARN, 968*0Sstevel@tonic-gate "clnt_rdma_kcallit: RDMA_SEND failed xid %u", 969*0Sstevel@tonic-gate p->cku_xid); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate #ifdef DEBUG 972*0Sstevel@tonic-gate else { 973*0Sstevel@tonic-gate if (rdma_clnt_debug) 974*0Sstevel@tonic-gate printf("clnt_rdma_kcallit: sent RDMA_DONE xid %u\n", 975*0Sstevel@tonic-gate p->cku_xid); 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate #endif 978*0Sstevel@tonic-gate clist_free(sendlist); 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate done: 982*0Sstevel@tonic-gate if (cxdrp) 983*0Sstevel@tonic-gate XDR_DESTROY(cxdrp); 984*0Sstevel@tonic-gate if (rxdrp) { 985*0Sstevel@tonic-gate (void) xdr_rpc_free_verifier(rxdrp, &reply_msg); 986*0Sstevel@tonic-gate XDR_DESTROY(rxdrp); 987*0Sstevel@tonic-gate } 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate if (recvlist) { 990*0Sstevel@tonic-gate rdma_buf_t recvmsg; 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate recvmsg.addr = (caddr_t)(uintptr_t)recvlist->c_saddr; 993*0Sstevel@tonic-gate recvmsg.type = RECV_BUFFER; 994*0Sstevel@tonic-gate RDMA_BUF_FREE(conn, &recvmsg); 995*0Sstevel@tonic-gate clist_free(recvlist); 996*0Sstevel@tonic-gate } 997*0Sstevel@tonic-gate RDMA_REL_CONN(conn); 998*0Sstevel@tonic-gate if (p->cku_err.re_status != RPC_SUCCESS) { 999*0Sstevel@tonic-gate RCSTAT_INCR(rcbadcalls); 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate return (p->cku_err.re_status); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate /* ARGSUSED */ 1005*0Sstevel@tonic-gate static void 1006*0Sstevel@tonic-gate clnt_rdma_kabort(CLIENT *h) 1007*0Sstevel@tonic-gate { 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate static void 1011*0Sstevel@tonic-gate clnt_rdma_kerror(CLIENT *h, struct rpc_err *err) 1012*0Sstevel@tonic-gate { 1013*0Sstevel@tonic-gate struct cku_private *p = htop(h); 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate *err = p->cku_err; 1016*0Sstevel@tonic-gate } 1017*0Sstevel@tonic-gate 1018*0Sstevel@tonic-gate static bool_t 1019*0Sstevel@tonic-gate clnt_rdma_kfreeres(CLIENT *h, xdrproc_t xdr_res, caddr_t res_ptr) 1020*0Sstevel@tonic-gate { 1021*0Sstevel@tonic-gate struct cku_private *p = htop(h); 1022*0Sstevel@tonic-gate XDR *xdrs; 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate xdrs = &(p->cku_outxdr); 1025*0Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 1026*0Sstevel@tonic-gate return ((*xdr_res)(xdrs, res_ptr)); 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* ARGSUSED */ 1030*0Sstevel@tonic-gate static bool_t 1031*0Sstevel@tonic-gate clnt_rdma_kcontrol(CLIENT *h, int cmd, char *arg) 1032*0Sstevel@tonic-gate { 1033*0Sstevel@tonic-gate return (TRUE); 1034*0Sstevel@tonic-gate } 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate /* ARGSUSED */ 1037*0Sstevel@tonic-gate static int 1038*0Sstevel@tonic-gate clnt_rdma_ksettimers(CLIENT *h, struct rpc_timers *t, struct rpc_timers *all, 1039*0Sstevel@tonic-gate int minimum, void(*feedback)(int, int, caddr_t), caddr_t arg, 1040*0Sstevel@tonic-gate uint32_t xid) 1041*0Sstevel@tonic-gate { 1042*0Sstevel@tonic-gate RCSTAT_INCR(rctimers); 1043*0Sstevel@tonic-gate return (0); 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate int 1047*0Sstevel@tonic-gate rdma_reachable(int addr_type, struct netbuf *addr, struct knetconfig **knconf) 1048*0Sstevel@tonic-gate { 1049*0Sstevel@tonic-gate rdma_registry_t *rp; 1050*0Sstevel@tonic-gate void *handle = NULL; 1051*0Sstevel@tonic-gate struct knetconfig *knc; 1052*0Sstevel@tonic-gate char *pf, *p; 1053*0Sstevel@tonic-gate rdma_stat status; 1054*0Sstevel@tonic-gate int error = 0; 1055*0Sstevel@tonic-gate 1056*0Sstevel@tonic-gate if (!INGLOBALZONE(curproc)) 1057*0Sstevel@tonic-gate return (-1); 1058*0Sstevel@tonic-gate /* 1059*0Sstevel@tonic-gate * modload the RDMA plugins if not already done. 1060*0Sstevel@tonic-gate */ 1061*0Sstevel@tonic-gate if (!rdma_modloaded) { 1062*0Sstevel@tonic-gate mutex_enter(&rdma_modload_lock); 1063*0Sstevel@tonic-gate if (!rdma_modloaded) { 1064*0Sstevel@tonic-gate error = rdma_modload(); 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate mutex_exit(&rdma_modload_lock); 1067*0Sstevel@tonic-gate if (error) 1068*0Sstevel@tonic-gate return (-1); 1069*0Sstevel@tonic-gate } 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate if (!rdma_dev_available) 1072*0Sstevel@tonic-gate return (-1); 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate rw_enter(&rdma_lock, RW_READER); 1075*0Sstevel@tonic-gate rp = rdma_mod_head; 1076*0Sstevel@tonic-gate while (rp != NULL) { 1077*0Sstevel@tonic-gate status = RDMA_REACHABLE(rp->r_mod->rdma_ops, addr_type, addr, 1078*0Sstevel@tonic-gate &handle); 1079*0Sstevel@tonic-gate if (status == RDMA_SUCCESS) { 1080*0Sstevel@tonic-gate knc = kmem_zalloc(sizeof (struct knetconfig), 1081*0Sstevel@tonic-gate KM_SLEEP); 1082*0Sstevel@tonic-gate knc->knc_semantics = NC_TPI_RDMA; 1083*0Sstevel@tonic-gate pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 1084*0Sstevel@tonic-gate p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 1085*0Sstevel@tonic-gate if (addr_type == AF_INET) 1086*0Sstevel@tonic-gate (void) strncpy(pf, NC_INET, KNC_STRSIZE); 1087*0Sstevel@tonic-gate else if (addr_type == AF_INET6) 1088*0Sstevel@tonic-gate (void) strncpy(pf, NC_INET6, KNC_STRSIZE); 1089*0Sstevel@tonic-gate pf[KNC_STRSIZE - 1] = '\0'; 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate (void) strncpy(p, rp->r_mod->rdma_api, KNC_STRSIZE); 1092*0Sstevel@tonic-gate p[KNC_STRSIZE - 1] = '\0'; 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate knc->knc_protofmly = pf; 1095*0Sstevel@tonic-gate knc->knc_proto = p; 1096*0Sstevel@tonic-gate knc->knc_rdev = (dev_t)handle; 1097*0Sstevel@tonic-gate *knconf = knc; 1098*0Sstevel@tonic-gate rw_exit(&rdma_lock); 1099*0Sstevel@tonic-gate return (0); 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate rp = rp->r_next; 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate rw_exit(&rdma_lock); 1104*0Sstevel@tonic-gate return (-1); 1105*0Sstevel@tonic-gate } 1106