xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c (revision 6db9d0a6a95a320cf284a92628509b477c79f7d9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/stropts.h>
32 #include <sys/stream.h>
33 #include <sys/strsun.h>
34 #include <sys/strsubr.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <net/if_arp.h>
38 #include <sys/file.h>
39 #include <sys/sockio.h>
40 #include <sys/pathname.h>
41 #include <inet/arp.h>
42 #include <sys/modctl.h>
43 
44 #include <sys/ib/mgt/ibcm/ibcm_arp.h>
45 
46 #include <sys/kstr.h>
47 #include <sys/tiuser.h>
48 #include <sys/t_kuser.h>
49 
50 extern char cmlog[];
51 
52 extern int ibcm_arp_pr_lookup(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr,
53     ibt_ip_addr_t *src_addr, uint8_t localroute, uint32_t bound_dev_if,
54     ibcm_arp_pr_comp_func_t func);
55 extern void ibcm_arp_pr_arp_ack(mblk_t *mp);
56 extern void ibcm_arp_prwqn_delete(ibcm_arp_prwqn_t *wqnp);
57 
58 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", datab))
59 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibt_ip_addr_s))
60 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_ip_t))
61 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_ibd_insts_t))
62 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_prwqn_t))
63 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", iocblk))
64 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", msgb))
65 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", queue))
66 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", sockaddr_in))
67 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", sockaddr_in6))
68 
69 /*
70  * ibcm_arp_get_ibaddr_cb
71  */
72 static int
73 ibcm_arp_get_ibaddr_cb(void *arg, int status)
74 {
75 	ibcm_arp_prwqn_t	*wqnp = (ibcm_arp_prwqn_t *)arg;
76 	ibcm_arp_streams_t	*ib_s = (ibcm_arp_streams_t *)wqnp->arg;
77 
78 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr_cb(ib_s: %p wqnp: %p)",
79 	    ib_s, wqnp);
80 
81 	mutex_enter(&ib_s->lock);
82 	ib_s->status = status;
83 	ib_s->done = B_TRUE;
84 
85 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr_cb: SGID %llX:%llX "
86 	    "DGID: %llX:%llX", wqnp->sgid.gid_prefix, wqnp->sgid.gid_guid,
87 	    wqnp->dgid.gid_prefix, wqnp->dgid.gid_guid);
88 
89 	/* lock is held by the caller. */
90 	cv_signal(&ib_s->cv);
91 	mutex_exit(&ib_s->lock);
92 	return (0);
93 }
94 
95 /*
96  * Lower read service procedure (messages coming back from arp/ip).
97  * Process messages based on queue type.
98  */
99 static int
100 ibcm_arp_lrsrv(queue_t *q)
101 {
102 	mblk_t *mp;
103 	ibcm_arp_streams_t *ib_s = q->q_ptr;
104 
105 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lrsrv(%p, ibd_s: 0x%p)", q, ib_s);
106 
107 	if (WR(q) == ib_s->arpqueue) {
108 		while (mp = getq(q)) {
109 			ibcm_arp_pr_arp_ack(mp);
110 		}
111 	}
112 
113 	return (0);
114 }
115 
116 /*
117  * Lower write service procedure.
118  * Used when lower streams are flow controlled.
119  */
120 static int
121 ibcm_arp_lwsrv(queue_t *q)
122 {
123 	mblk_t *mp;
124 
125 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lwsrv(%p)", q);
126 
127 	while (mp = getq(q)) {
128 		if (canputnext(q)) {
129 			putnext(q, mp);
130 		} else {
131 			(void) putbq(q, mp);
132 			qenable(q);
133 			break;
134 		}
135 	}
136 
137 	return (0);
138 }
139 
140 /*
141  * Lower read put procedure. Arp/ip messages come here.
142  */
143 static int
144 ibcm_arp_lrput(queue_t *q, mblk_t *mp)
145 {
146 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lrput(0x%p, db_type: %d)",
147 	    q, DB_TYPE(mp));
148 
149 	switch (DB_TYPE(mp)) {
150 		case M_FLUSH:
151 			/*
152 			 * Turn around
153 			 */
154 			if (*mp->b_rptr & FLUSHW) {
155 				*mp->b_rptr &= ~FLUSHR;
156 				qreply(q, mp);
157 				return (0);
158 			}
159 			freemsg(mp);
160 			break;
161 		case M_IOCACK:
162 		case M_IOCNAK:
163 		case M_DATA:
164 			/*
165 			 * This could be in interrupt context.
166 			 * Some of the ibt calls cannot be called in
167 			 * interrupt context, so
168 			 * put it in the queue and the message will be
169 			 * processed by service proccedure
170 			 */
171 			(void) putq(q, mp);
172 			qenable(q);
173 			break;
174 		default:
175 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_lrput: "
176 			    "got unknown msg <0x%x>\n", mp->b_datap->db_type);
177 			ASSERT(0);
178 			break;
179 	}
180 
181 	return (0);
182 }
183 
184 /*
185  * Streams write queue module info
186  */
187 static struct module_info ibcm_arp_winfo = {
188 	0,		/* module ID number */
189 	"ibcm",		/* module name */
190 	0,		/* min packet size */
191 	INFPSZ,
192 	49152,		/* STREAM queue high water mark -- 49152 */
193 	12		/* STREAM queue low water mark -- 12 */
194 };
195 
196 /*
197  * Streams lower write queue, for ibcm/ip requests.
198  */
199 static struct qinit ibcm_arp_lwinit = {
200 	NULL,		/* qi_putp */
201 	ibcm_arp_lwsrv,	/* qi_srvp */
202 	NULL,		/* qi_qopen */
203 	NULL,		/* qi_qclose */
204 	NULL,		/* qi_qadmin */
205 	&ibcm_arp_winfo,	/* module info */
206 	NULL,		/* module statistics struct */
207 	NULL,
208 	NULL,
209 	STRUIOT_NONE	/* stream uio type is standard uiomove() */
210 };
211 
212 /*
213  * Streams lower read queue: read reply messages from ibcm/ip.
214  */
215 static struct qinit ibcm_arp_lrinit = {
216 	ibcm_arp_lrput,	/* qi_putp */
217 	ibcm_arp_lrsrv,	/* qi_srvp */
218 	NULL,		/* qi_qopen */
219 	NULL,		/* qi_qclose */
220 	NULL,		/* qi_qadmin */
221 	&ibcm_arp_winfo,	/* module info */
222 	NULL,		/* module statistics struct */
223 	NULL,
224 	NULL,
225 	STRUIOT_NONE /* stream uio type is standard uiomove() */
226 };
227 
228 
229 static int
230 ibcm_arp_link_driver(ibcm_arp_streams_t *ib_s, char *path, queue_t **q,
231     vnode_t **dev_vp)
232 {
233 	struct stdata *dev_stp;
234 	vnode_t *vp;
235 	int error;
236 	queue_t *rq;
237 
238 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_link_driver: Enter: %s", path);
239 
240 	/* open the driver from inside the kernel */
241 	error = vn_open(path, UIO_SYSSPACE, FREAD|FWRITE, 0, &vp,
242 	    0, NULL);
243 	if (error) {
244 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_link_driver: "
245 		    "vn_open('%s') failed\n", path);
246 		return (error);
247 	}
248 	*dev_vp = vp;
249 
250 	dev_stp = vp->v_stream;
251 	*q = dev_stp->sd_wrq;
252 
253 	VN_HOLD(vp);
254 
255 	rq = RD(dev_stp->sd_wrq);
256 	RD(rq)->q_ptr = WR(rq)->q_ptr = ib_s;
257 	setq(rq, &ibcm_arp_lrinit, &ibcm_arp_lwinit, NULL, QMTSAFE,
258 	    SQ_CI|SQ_CO, B_FALSE);
259 
260 	return (0);
261 }
262 
263 extern struct qinit strdata;
264 extern struct qinit stwdata;
265 
266 /*
267  * Unlink ip, ibcm, icmp6 drivers
268  */
269 /* ARGSUSED */
270 static int
271 ibcm_arp_unlink_driver(queue_t **q, vnode_t **dev_vp)
272 {
273 	vnode_t *vp = *dev_vp;
274 	struct stdata *dev_stp = vp->v_stream;
275 	queue_t *wrq, *rq;
276 	int	rc;
277 
278 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_unlink_driver: Enter: 0x%p", q);
279 
280 	wrq = dev_stp->sd_wrq;
281 	rq = RD(wrq);
282 
283 	disable_svc(rq);
284 	wait_svc(rq);
285 	flushq(rq, FLUSHALL);
286 	flushq(WR(rq), FLUSHALL);
287 
288 	rq->q_ptr = wrq->q_ptr = dev_stp;
289 
290 	setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_TRUE);
291 
292 	if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL)) != 0) {
293 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_unlink_driver: VOP_CLOSE "
294 		    "failed %d\n", rc);
295 	}
296 	VN_RELE(vp);
297 
298 	return (0);
299 }
300 
301 static int
302 ibcm_arp_unlink_drivers(ibcm_arp_streams_t *ib_s)
303 {
304 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_unlink_drivers(%p)", ib_s);
305 
306 	if (ib_s->arpqueue) {
307 		(void) ibcm_arp_unlink_driver(&ib_s->arpqueue, &ib_s->arp_vp);
308 	}
309 
310 	return (0);
311 }
312 
313 /*
314  * Link ip, ibtl drivers below ibtl
315  */
316 static int
317 ibcm_arp_link_drivers(ibcm_arp_streams_t *ib_s)
318 {
319 	int	rc;
320 
321 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_link_drivers(%p)", ib_s);
322 
323 	if ((rc = ibcm_arp_link_driver(ib_s, "/dev/arp", &ib_s->arpqueue,
324 	    &ib_s->arp_vp)) != 0) {
325 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_link_drivers: "
326 		    "ibcm_arp_link_driver failed: %d\n", rc);
327 		return (rc);
328 	}
329 
330 	return (0);
331 }
332 
333 ibt_status_t
334 ibcm_arp_get_ibaddr(ipaddr_t srcip, ipaddr_t destip, ib_gid_t *sgid,
335     ib_gid_t *dgid)
336 {
337 	ibcm_arp_streams_t	*ib_s;
338 	ibt_ip_addr_t		srcaddr, destaddr;
339 	int			ret = 0;
340 
341 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr(%lX, %lX, %p, %p)",
342 	    htonl(srcip), htonl(destip), sgid, dgid);
343 
344 	ib_s = (ibcm_arp_streams_t *)kmem_zalloc(sizeof (ibcm_arp_streams_t),
345 	    KM_SLEEP);
346 
347 	mutex_init(&ib_s->lock, NULL, MUTEX_DEFAULT, NULL);
348 	cv_init(&ib_s->cv, NULL, CV_DRIVER, NULL);
349 
350 	ret = ibcm_arp_link_drivers(ib_s);
351 	if (ret != 0) {
352 		IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: "
353 		    "ibcm_arp_link_drivers failed %d", ret);
354 		goto arp_ibaddr_error;
355 	}
356 
357 	bzero(&destaddr, sizeof (ibt_ip_addr_t));
358 	bzero(&srcaddr, sizeof (ibt_ip_addr_t));
359 
360 	mutex_enter(&ib_s->lock);
361 	ib_s->done = B_FALSE;
362 	mutex_exit(&ib_s->lock);
363 
364 	destaddr.family = AF_INET_OFFLOAD;
365 	destaddr.un.ip4addr = htonl(destip);
366 	srcaddr.family = AF_INET_OFFLOAD;
367 	srcaddr.un.ip4addr = htonl(srcip);
368 
369 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: SrcIP %lX, DstIP %lX",
370 	    srcaddr.un.ip4addr, destaddr.un.ip4addr);
371 	ret = ibcm_arp_pr_lookup(ib_s, &destaddr, &srcaddr, 0, NULL,
372 	    ibcm_arp_get_ibaddr_cb);
373 
374 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: ibcm_arp_pr_lookup "
375 	    "returned: %d", ret);
376 	if (ret == 0) {
377 		mutex_enter(&ib_s->lock);
378 		while (ib_s->done != B_TRUE)
379 			cv_wait(&ib_s->cv, &ib_s->lock);
380 		mutex_exit(&ib_s->lock);
381 	}
382 
383 	(void) ibcm_arp_unlink_drivers(ib_s);
384 	mutex_enter(&ib_s->lock);
385 	ret = ib_s->status;
386 	if (ret == 0) {
387 		ibcm_arp_prwqn_t *wqnp = ib_s->wqnp;
388 		if (sgid)
389 			*sgid = ib_s->wqnp->sgid;
390 		if (dgid)
391 			*dgid = ib_s->wqnp->dgid;
392 
393 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr: SGID: %llX:%llX"
394 		    " DGID: %llX:%llX",
395 		    ib_s->wqnp->sgid.gid_prefix, ib_s->wqnp->sgid.gid_guid,
396 		    ib_s->wqnp->dgid.gid_prefix, ib_s->wqnp->dgid.gid_guid);
397 
398 		mutex_exit(&ib_s->lock);
399 		ibcm_arp_prwqn_delete(wqnp);
400 		mutex_enter(&ib_s->lock);
401 	}
402 	mutex_exit(&ib_s->lock);
403 
404 arp_ibaddr_error:
405 
406 	mutex_destroy(&ib_s->lock);
407 	cv_destroy(&ib_s->cv);
408 	kmem_free(ib_s, sizeof (ibcm_arp_streams_t));
409 
410 	if (ret)
411 		return (IBT_FAILURE);
412 	else
413 		return (IBT_SUCCESS);
414 }
415 
416 
417 /*
418  * Routine to get list of "local" IP-ADDR to GID/P_KEY mapping information.
419  * Optionally, if "gid" and/or "p_key" info are specified, then retrieve the
420  * IP-ADDR info for that attribute only.
421  */
422 
423 static ibcm_arp_ip_t *
424 ibcm_arp_ibd_gid2mac(ib_gid_t *gid, ib_pkey_t pkey, ibcm_arp_ibd_insts_t *ibdp)
425 {
426 	ibcm_arp_ip_t		*ipp;
427 	int			i;
428 
429 	for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt;
430 	    i++, ipp++) {
431 		if ((ipp->ip_port_gid.gid_prefix == gid->gid_prefix) &&
432 		    (ipp->ip_port_gid.gid_guid == gid->gid_guid)) {
433 			if (pkey) {
434 				if (ipp->ip_pkey == pkey)
435 					return (ipp);
436 				else
437 					continue;
438 			}
439 			return (ipp);
440 		}
441 	}
442 	return (NULL);
443 }
444 
445 static ibt_status_t
446 ibcm_arp_ibd_mac2gid(ibcm_arp_ibd_insts_t *ibdp, ipaddr_t srcip,
447     ib_gid_t *sgid)
448 {
449 	ibcm_arp_ip_t		*ipp;
450 	int			i;
451 
452 	for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt;
453 	    i++, ipp++) {
454 
455 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: Is %lX == %lX "
456 		    "GID %llX:%llX", srcip, ipp->ip_cm_sin.sin_addr,
457 		    ipp->ip_port_gid.gid_prefix, ipp->ip_port_gid.gid_guid);
458 
459 		if (bcmp(&srcip, &ipp->ip_cm_sin.sin_addr, sizeof (in_addr_t))
460 		    == 0) {
461 			*sgid = ipp->ip_port_gid;
462 
463 			IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: Found "
464 			    "GID %llX:%llX", sgid->gid_prefix, sgid->gid_guid);
465 			return (IBT_SUCCESS);
466 		}
467 	}
468 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Matching SRC info "
469 	    "NOT Found");
470 	return (IBT_SRC_IP_NOT_FOUND);
471 }
472 
473 static int
474 ibcm_arp_get_ibd_insts_cb(dev_info_t *dip, void *arg)
475 {
476 	ibcm_arp_ibd_insts_t *ibds = (ibcm_arp_ibd_insts_t *)arg;
477 	ibcm_arp_ip_t	*ipp;
478 	ib_pkey_t	pkey;
479 	uint8_t		port;
480 	ib_guid_t	hca_guid;
481 	ib_gid_t	port_gid;
482 
483 	if (i_ddi_devi_attached(dip) &&
484 	    (strcmp(ddi_node_name(dip), "ibport") == 0) &&
485 	    (strstr(ddi_get_name_addr(dip), "ipib") != NULL)) {
486 
487 		if (ibds->ibcm_arp_ibd_cnt >= ibds->ibcm_arp_ibd_alloc) {
488 			ibcm_arp_ip_t	*tmp = NULL;
489 			uint8_t		new_count;
490 
491 			new_count = ibds->ibcm_arp_ibd_alloc +
492 			    IBCM_ARP_IBD_INSTANCES;
493 
494 			tmp = (ibcm_arp_ip_t *)kmem_zalloc(
495 			    new_count * sizeof (ibcm_arp_ip_t), KM_SLEEP);
496 			bcopy(ibds->ibcm_arp_ip, tmp,
497 			    ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t));
498 			kmem_free(ibds->ibcm_arp_ip,
499 			    ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t));
500 			ibds->ibcm_arp_ibd_alloc = new_count;
501 			ibds->ibcm_arp_ip = tmp;
502 		}
503 
504 		if (((hca_guid = ddi_prop_get_int64(DDI_DEV_T_ANY, dip, 0,
505 		    "hca-guid", 0)) == 0) ||
506 		    ((port = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
507 		    "port-number", 0)) == 0) ||
508 		    (ibt_get_port_state_byguid(hca_guid, port, &port_gid,
509 		    NULL) != IBT_SUCCESS) ||
510 		    ((pkey = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
511 		    "port-pkey", IB_PKEY_INVALID_LIMITED)) <=
512 		    IB_PKEY_INVALID_FULL)) {
513 			return (DDI_WALK_CONTINUE);
514 		}
515 
516 		ipp = &ibds->ibcm_arp_ip[ibds->ibcm_arp_ibd_cnt];
517 		ipp->ip_inst = ddi_get_instance(dip);
518 		ipp->ip_pkey = pkey;
519 		ipp->ip_hca_guid = hca_guid;
520 		ipp->ip_port_gid = port_gid;
521 		ibds->ibcm_arp_ibd_cnt++;
522 	}
523 	return (DDI_WALK_CONTINUE);
524 }
525 
526 static void
527 ibcm_arp_get_ibd_insts(ibcm_arp_ibd_insts_t *ibds)
528 {
529 	ddi_walk_devs(ddi_root_node(), ibcm_arp_get_ibd_insts_cb, ibds);
530 }
531 
532 /*
533  * Return ibd interfaces and ibd instances.
534  */
535 static int
536 ibcm_arp_get_ibd_ipaddr(ibcm_arp_ibd_insts_t *ibds)
537 {
538 	TIUSER			*tiptr;
539 	vnode_t			*kvp;
540 	vnode_t			*vp = NULL;
541 	struct strioctl		iocb;
542 	struct lifreq		lif_req;
543 	int			k, ip_cnt;
544 	ibcm_arp_ip_t		*ipp;
545 
546 	if (lookupname("/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &kvp) == 0) {
547 		if (t_kopen((file_t *)NULL, kvp->v_rdev, FREAD|FWRITE,
548 		    &tiptr, CRED()) == 0) {
549 			vp = tiptr->fp->f_vnode;
550 		} else {
551 			VN_RELE(kvp);
552 		}
553 	}
554 
555 	if (vp == NULL)
556 		return (-1);
557 
558 	/* Get ibd ip's */
559 	ip_cnt = 0;
560 	for (k = 0, ipp = ibds->ibcm_arp_ip; k < ibds->ibcm_arp_ibd_cnt;
561 	    k++, ipp++) {
562 
563 		(void) bzero((void *)&lif_req, sizeof (struct lifreq));
564 		(void) snprintf(lif_req.lifr_name, sizeof (lif_req.lifr_name),
565 		    "%s%d", IBCM_ARP_IBD_NAME, ipp->ip_inst);
566 
567 		(void) bzero((void *)&iocb, sizeof (struct strioctl));
568 		iocb.ic_cmd = SIOCGLIFADDR;
569 		iocb.ic_timout = 0;
570 		iocb.ic_len = sizeof (struct lifreq);
571 		iocb.ic_dp = (caddr_t)&lif_req;
572 
573 		if (kstr_ioctl(vp, I_STR, (intptr_t)&iocb) == 0) {
574 			ipp->ip_inet_family = AF_INET;
575 			bcopy(&lif_req.lifr_addr, &ipp->ip_cm_sin,
576 			    sizeof (struct sockaddr_in));
577 			ip_cnt++;
578 			continue;
579 		}
580 	}
581 
582 	(void) t_kclose(tiptr, 0);
583 	VN_RELE(kvp);
584 
585 	if (ip_cnt == 0)
586 		return (-1);
587 	else
588 		return (0);
589 }
590 
591 ibt_status_t
592 ibcm_arp_get_ibds(ibcm_arp_ibd_insts_t *ibdp)
593 {
594 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds(%p)", ibdp);
595 
596 	ibcm_arp_get_ibd_insts(ibdp);
597 
598 	IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibds: Found %d ibd instances",
599 	    ibdp->ibcm_arp_ibd_cnt);
600 
601 	if (ibdp->ibcm_arp_ibd_cnt == 0)
602 		return (IBT_SRC_IP_NOT_FOUND);
603 
604 	/* Get the IP addresses of active ports. */
605 	if (ibcm_arp_get_ibd_ipaddr(ibdp) != 0) {
606 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: failed to get "
607 		    "ibd instance: IBT_SRC_IP_NOT_FOUND");
608 		return (IBT_SRC_IP_NOT_FOUND);
609 	}
610 
611 	return (IBT_SUCCESS);
612 }
613 
614 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibtl_cm_port_list_t))
615 
616 ibt_status_t
617 ibcm_arp_get_srcip_plist(ibt_ip_path_attr_t *ipattr, ibt_path_flags_t flags,
618     ibtl_cm_port_list_t **port_list_p)
619 {
620 	ibt_path_attr_t		attr;
621 	ibt_status_t		ret;
622 	ibcm_arp_ibd_insts_t	ibds;
623 	ibcm_arp_ip_t		*ipp;
624 	ibtl_cm_port_list_t	*plistp;
625 	ib_gid_t		sgid;
626 
627 	IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist(%p, %llX)",
628 	    ipattr, flags);
629 
630 	sgid.gid_prefix = sgid.gid_guid = 0;
631 	bzero(&ibds, sizeof (ibcm_arp_ibd_insts_t));
632 	ibds.ibcm_arp_ibd_alloc = IBCM_ARP_IBD_INSTANCES;
633 	ibds.ibcm_arp_ibd_cnt = 0;
634 	ibds.ibcm_arp_ip = (ibcm_arp_ip_t *)kmem_zalloc(
635 	    ibds.ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t), KM_SLEEP);
636 
637 	ret = ibcm_arp_get_ibds(&ibds);
638 	if (ret != IBT_SUCCESS) {
639 		IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: "
640 		    "ibcm_arp_get_ibds failed : 0x%x", ret);
641 		goto srcip_plist_end;
642 	}
643 
644 	if (ipattr->ipa_src_ip.family != AF_UNSPEC) {
645 		ret = ibcm_arp_ibd_mac2gid(&ibds,
646 		    htonl(ipattr->ipa_src_ip.un.ip4addr), &sgid);
647 		if (ret != IBT_SUCCESS) {
648 			IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: "
649 			    "SGID for the specified SRCIP Not found %X", ret);
650 			goto srcip_plist_end;
651 		}
652 		IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: SGID "
653 		    "%llX:%llX", sgid.gid_prefix, sgid.gid_guid);
654 	}
655 
656 	bzero(&attr, sizeof (ibt_path_attr_t));
657 	attr.pa_hca_guid = ipattr->ipa_hca_guid;
658 	attr.pa_hca_port_num = ipattr->ipa_hca_port_num;
659 	attr.pa_sgid = sgid;
660 	bcopy(&ipattr->ipa_mtu,  &attr.pa_mtu, sizeof (ibt_mtu_req_t));
661 	bcopy(&ipattr->ipa_srate,  &attr.pa_srate, sizeof (ibt_srate_req_t));
662 	bcopy(&ipattr->ipa_pkt_lt,  &attr.pa_pkt_lt, sizeof (ibt_pkt_lt_req_t));
663 
664 	ret = ibtl_cm_get_active_plist(&attr, flags, port_list_p);
665 	if (ret == IBT_SUCCESS) {
666 		int		i;
667 		uint8_t		cnt;
668 
669 		plistp = port_list_p[0];
670 		cnt = plistp->p_count;
671 		for (i = 0; i < cnt; i++, plistp++) {
672 			ipp = ibcm_arp_ibd_gid2mac(&plistp->p_sgid, 0, &ibds);
673 			if (ipp == NULL)
674 				plistp->p_src_ip.family = AF_UNSPEC;
675 			else {
676 				IBTF_DPRINTF_L4(cmlog,
677 				    "ibcm_arp_get_srcip_plist: GID %llX:%llX",
678 				    plistp->p_sgid.gid_prefix,
679 				    plistp->p_sgid.gid_guid);
680 				if (ipp->ip_inet_family == AF_INET) {
681 					plistp->p_src_ip.family = AF_INET;
682 					bcopy(&ipp->ip_cm_sin.sin_addr,
683 					    &plistp->p_src_ip.un.ip4addr,
684 					    sizeof (in_addr_t));
685 
686 					IBTF_DPRINTF_L4(cmlog,
687 					    "ibcm_arp_get_srcip_plist: SrcIP: "
688 					    "%lX", plistp->p_src_ip.un.ip4addr);
689 				} else if (ipp->ip_inet_family == AF_INET6) {
690 					plistp->p_src_ip.family = AF_INET6;
691 					bcopy(&ipp->ip_cm_sin6.sin6_addr,
692 					    &plistp->p_src_ip.un.ip6addr,
693 					    sizeof (in6_addr_t));
694 				}
695 			}
696 		}
697 	}
698 
699 srcip_plist_end:
700 	if (ibds.ibcm_arp_ip)
701 		kmem_free(ibds.ibcm_arp_ip, ibds.ibcm_arp_ibd_alloc *
702 		    sizeof (ibcm_arp_ip_t));
703 
704 	return (ret);
705 }
706 /* Routines for warlock */
707 
708 /* ARGSUSED */
709 static int
710 ibcm_arp_dummy_ibaddr_hdl(void *arg, int status)
711 {
712 	ibcm_arp_prwqn_t		dummy_wqn1;
713 	ibcm_arp_prwqn_t		dummy_wqn2;
714 
715 	dummy_wqn1.func = ibcm_arp_get_ibaddr_cb;
716 	dummy_wqn2.func = ibcm_arp_dummy_ibaddr_hdl;
717 
718 	IBTF_DPRINTF_L5(cmlog, "ibcm_arp_dummy_ibaddr_hdl: "
719 	    "dummy_wqn1.func %p %p", dummy_wqn1.func, dummy_wqn2.func);
720 
721 	return (0);
722 }
723