11bdd6c0eSSue Gleeson /*
21bdd6c0eSSue Gleeson  * CDDL HEADER START
31bdd6c0eSSue Gleeson  *
41bdd6c0eSSue Gleeson  * The contents of this file are subject to the terms of the
51bdd6c0eSSue Gleeson  * Common Development and Distribution License (the "License").
61bdd6c0eSSue Gleeson  * You may not use this file except in compliance with the License.
71bdd6c0eSSue Gleeson  *
81bdd6c0eSSue Gleeson  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91bdd6c0eSSue Gleeson  * or http://www.opensolaris.org/os/licensing.
101bdd6c0eSSue Gleeson  * See the License for the specific language governing permissions
111bdd6c0eSSue Gleeson  * and limitations under the License.
121bdd6c0eSSue Gleeson  *
131bdd6c0eSSue Gleeson  * When distributing Covered Code, include this CDDL HEADER in each
141bdd6c0eSSue Gleeson  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151bdd6c0eSSue Gleeson  * If applicable, add the following below this CDDL HEADER, with the
161bdd6c0eSSue Gleeson  * fields enclosed by brackets "[]" replaced with your own identifying
171bdd6c0eSSue Gleeson  * information: Portions Copyright [yyyy] [name of copyright owner]
181bdd6c0eSSue Gleeson  *
191bdd6c0eSSue Gleeson  * CDDL HEADER END
201bdd6c0eSSue Gleeson  */
211bdd6c0eSSue Gleeson 
221bdd6c0eSSue Gleeson /*
23c3a558e7SSue Gleeson  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
241bdd6c0eSSue Gleeson  */
251bdd6c0eSSue Gleeson 
261bdd6c0eSSue Gleeson /*
271bdd6c0eSSue Gleeson  * I/O Controller functions for the Solaris COMSTAR SCSI RDMA Protocol
281bdd6c0eSSue Gleeson  * Target (SRPT) port provider.
291bdd6c0eSSue Gleeson  */
301bdd6c0eSSue Gleeson 
311bdd6c0eSSue Gleeson #include <sys/types.h>
321bdd6c0eSSue Gleeson #include <sys/ddi.h>
331bdd6c0eSSue Gleeson #include <sys/types.h>
341bdd6c0eSSue Gleeson #include <sys/sunddi.h>
351bdd6c0eSSue Gleeson #include <sys/atomic.h>
361bdd6c0eSSue Gleeson #include <sys/sysmacros.h>
371bdd6c0eSSue Gleeson #include <sys/ib/ibtl/ibti.h>
38191c289bSCharles Ting #include <sys/sdt.h>
391bdd6c0eSSue Gleeson 
401bdd6c0eSSue Gleeson #include "srp.h"
411bdd6c0eSSue Gleeson #include "srpt_impl.h"
421bdd6c0eSSue Gleeson #include "srpt_ioc.h"
431bdd6c0eSSue Gleeson #include "srpt_stp.h"
441bdd6c0eSSue Gleeson #include "srpt_ch.h"
45c3a558e7SSue Gleeson #include "srpt_common.h"
461bdd6c0eSSue Gleeson 
471bdd6c0eSSue Gleeson /*
481bdd6c0eSSue Gleeson  * srpt_ioc_srq_size - Tunable parameter that specifies the number
491bdd6c0eSSue Gleeson  * of receive WQ entries that can be posted to the IOC shared
501bdd6c0eSSue Gleeson  * receive queue.
511bdd6c0eSSue Gleeson  */
52c3a558e7SSue Gleeson uint32_t		srpt_ioc_srq_size = SRPT_DEFAULT_IOC_SRQ_SIZE;
53c3a558e7SSue Gleeson extern uint16_t		srpt_send_msg_depth;
54c3a558e7SSue Gleeson extern uint32_t		srpt_iu_size;
55c3a558e7SSue Gleeson extern boolean_t	srpt_enable_by_default;
561bdd6c0eSSue Gleeson 
571bdd6c0eSSue Gleeson /* IOC profile capabilities mask must be big-endian */
581bdd6c0eSSue Gleeson typedef struct srpt_ioc_opcap_bits_s {
591bdd6c0eSSue Gleeson #if	defined(_BIT_FIELDS_LTOH)
601bdd6c0eSSue Gleeson 	uint8_t		af:1,
611bdd6c0eSSue Gleeson 			at:1,
621bdd6c0eSSue Gleeson 			wf:1,
631bdd6c0eSSue Gleeson 			wt:1,
641bdd6c0eSSue Gleeson 			rf:1,
651bdd6c0eSSue Gleeson 			rt:1,
661bdd6c0eSSue Gleeson 			sf:1,
671bdd6c0eSSue Gleeson 			st:1;
681bdd6c0eSSue Gleeson #elif	defined(_BIT_FIELDS_HTOL)
691bdd6c0eSSue Gleeson 	uint8_t		st:1,
701bdd6c0eSSue Gleeson 			sf:1,
711bdd6c0eSSue Gleeson 			rt:1,
721bdd6c0eSSue Gleeson 			rf:1,
731bdd6c0eSSue Gleeson 			wt:1,
741bdd6c0eSSue Gleeson 			wf:1,
751bdd6c0eSSue Gleeson 			at:1,
761bdd6c0eSSue Gleeson 			af:1;
771bdd6c0eSSue Gleeson #else
781bdd6c0eSSue Gleeson #error	One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
791bdd6c0eSSue Gleeson #endif
801bdd6c0eSSue Gleeson } srpt_ioc_opcap_bits_t;
811bdd6c0eSSue Gleeson 
821bdd6c0eSSue Gleeson typedef union {
831bdd6c0eSSue Gleeson 	srpt_ioc_opcap_bits_t	bits;
841bdd6c0eSSue Gleeson 	uint8_t			mask;
851bdd6c0eSSue Gleeson } srpt_ioc_opcap_mask_t;
861bdd6c0eSSue Gleeson 
871bdd6c0eSSue Gleeson /*
881bdd6c0eSSue Gleeson  * vmem arena variables - values derived from iSER
891bdd6c0eSSue Gleeson  */
901bdd6c0eSSue Gleeson #define	SRPT_MR_QUANTSIZE	0x400			/* 1K */
911bdd6c0eSSue Gleeson #define	SRPT_MIN_CHUNKSIZE	0x100000		/* 1MB */
921bdd6c0eSSue Gleeson 
931bdd6c0eSSue Gleeson /* use less memory on 32-bit kernels as it's much more constrained */
941bdd6c0eSSue Gleeson #ifdef _LP64
951bdd6c0eSSue Gleeson #define	SRPT_BUF_MR_CHUNKSIZE	0x1000000		/* 16MB */
961bdd6c0eSSue Gleeson #define	SRPT_BUF_POOL_MAX	0x40000000		/* 1GB */
971bdd6c0eSSue Gleeson #else
981bdd6c0eSSue Gleeson #define	SRPT_BUF_MR_CHUNKSIZE	0x400000		/* 4MB */
991bdd6c0eSSue Gleeson #define	SRPT_BUF_POOL_MAX	0x4000000		/* 64MB */
1001bdd6c0eSSue Gleeson #endif
1011bdd6c0eSSue Gleeson 
1021bdd6c0eSSue Gleeson static ibt_mr_flags_t	srpt_dbuf_mr_flags =
1031bdd6c0eSSue Gleeson     IBT_MR_ENABLE_LOCAL_WRITE | IBT_MR_ENABLE_REMOTE_WRITE |
1041bdd6c0eSSue Gleeson     IBT_MR_ENABLE_REMOTE_READ;
1051bdd6c0eSSue Gleeson 
1061bdd6c0eSSue Gleeson void srpt_ioc_ib_async_hdlr(void *clnt, ibt_hca_hdl_t hdl,
1071bdd6c0eSSue Gleeson 	ibt_async_code_t code, ibt_async_event_t *event);
1081bdd6c0eSSue Gleeson 
1091bdd6c0eSSue Gleeson static struct ibt_clnt_modinfo_s srpt_ibt_modinfo = {
1101bdd6c0eSSue Gleeson 	IBTI_V_CURR,
1111bdd6c0eSSue Gleeson 	IBT_STORAGE_DEV,
1121bdd6c0eSSue Gleeson 	srpt_ioc_ib_async_hdlr,
1131bdd6c0eSSue Gleeson 	NULL,
1141bdd6c0eSSue Gleeson 	"srpt"
1151bdd6c0eSSue Gleeson };
1161bdd6c0eSSue Gleeson 
1171bdd6c0eSSue Gleeson static srpt_ioc_t *srpt_ioc_init(ib_guid_t guid);
1181bdd6c0eSSue Gleeson static void srpt_ioc_fini(srpt_ioc_t *ioc);
119c3a558e7SSue Gleeson static boolean_t srpt_check_hca_cfg_enabled(ib_guid_t hca_guid);
1201bdd6c0eSSue Gleeson 
1211bdd6c0eSSue Gleeson static srpt_vmem_pool_t *srpt_vmem_create(const char *name, srpt_ioc_t *ioc,
1221bdd6c0eSSue Gleeson     ib_memlen_t chunksize, uint64_t maxsize, ibt_mr_flags_t flags);
1231bdd6c0eSSue Gleeson static void *srpt_vmem_alloc(srpt_vmem_pool_t *vm_pool, size_t size);
1241bdd6c0eSSue Gleeson static int srpt_vmem_mr_compare(const void *a, const void *b);
1251bdd6c0eSSue Gleeson static srpt_mr_t *srpt_vmem_chunk_alloc(srpt_vmem_pool_t *ioc,
1261bdd6c0eSSue Gleeson     ib_memlen_t chunksize);
1271bdd6c0eSSue Gleeson static void srpt_vmem_destroy(srpt_vmem_pool_t *vm_pool);
1281bdd6c0eSSue Gleeson static void srpt_vmem_free(srpt_vmem_pool_t *vm_pool, void *vaddr, size_t size);
1291bdd6c0eSSue Gleeson static srpt_mr_t *srpt_reg_mem(srpt_vmem_pool_t *vm_pool, ib_vaddr_t vaddr,
1301bdd6c0eSSue Gleeson     ib_memlen_t len);
1311bdd6c0eSSue Gleeson static void srpt_vmem_chunk_free(srpt_vmem_pool_t *vm_pool, srpt_mr_t *mr);
1321bdd6c0eSSue Gleeson static void srpt_dereg_mem(srpt_ioc_t *ioc, srpt_mr_t *mr);
1331bdd6c0eSSue Gleeson static int srpt_vmem_mr(srpt_vmem_pool_t *vm_pool, void *vaddr, size_t size,
1341bdd6c0eSSue Gleeson     srpt_mr_t *mr);
1351bdd6c0eSSue Gleeson 
1361bdd6c0eSSue Gleeson /*
1371bdd6c0eSSue Gleeson  * srpt_ioc_attach() - I/O Controller attach
1381bdd6c0eSSue Gleeson  *
1391bdd6c0eSSue Gleeson  * Attach to IBTF and initialize I/O controllers. The srpt_ctxt->sc_rwlock
1401bdd6c0eSSue Gleeson  * should be held outside of this call.
1411bdd6c0eSSue Gleeson  */
1421bdd6c0eSSue Gleeson int
srpt_ioc_attach()1431bdd6c0eSSue Gleeson srpt_ioc_attach()
1441bdd6c0eSSue Gleeson {
1451bdd6c0eSSue Gleeson 	int		status;
1461bdd6c0eSSue Gleeson 	int		hca_cnt;
1471bdd6c0eSSue Gleeson 	int		hca_ndx;
1481bdd6c0eSSue Gleeson 	ib_guid_t	*guid;
1491bdd6c0eSSue Gleeson 
1501bdd6c0eSSue Gleeson 	ASSERT(srpt_ctxt != NULL);
1511bdd6c0eSSue Gleeson 
1521bdd6c0eSSue Gleeson 	/*
1531bdd6c0eSSue Gleeson 	 * Attach to IBTF and initialize a list of IB devices.  Each
1541bdd6c0eSSue Gleeson 	 * HCA will be represented by an I/O Controller.
1551bdd6c0eSSue Gleeson 	 */
1561bdd6c0eSSue Gleeson 	status = ibt_attach(&srpt_ibt_modinfo, srpt_ctxt->sc_dip,
1571bdd6c0eSSue Gleeson 	    srpt_ctxt,  &srpt_ctxt->sc_ibt_hdl);
1581bdd6c0eSSue Gleeson 	if (status != DDI_SUCCESS) {
1591bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_attach, ibt_attach failed (0x%x)",
1601bdd6c0eSSue Gleeson 		    status);
1611bdd6c0eSSue Gleeson 		return (DDI_FAILURE);
1621bdd6c0eSSue Gleeson 	}
1631bdd6c0eSSue Gleeson 
1641bdd6c0eSSue Gleeson 	hca_cnt = ibt_get_hca_list(&guid);
1651bdd6c0eSSue Gleeson 	if (hca_cnt < 1) {
166168665f7SSue Gleeson 		/*
167168665f7SSue Gleeson 		 * not a fatal error.  Service will be up and
168168665f7SSue Gleeson 		 * waiting for ATTACH events.
169168665f7SSue Gleeson 		 */
1701bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_attach, no HCA found");
171168665f7SSue Gleeson 		return (DDI_SUCCESS);
1721bdd6c0eSSue Gleeson 	}
1731bdd6c0eSSue Gleeson 
1741bdd6c0eSSue Gleeson 	for (hca_ndx = 0; hca_ndx < hca_cnt; hca_ndx++) {
175c3a558e7SSue Gleeson 		SRPT_DPRINTF_L2("ioc_attach, attaching HCA %016llx",
176c3a558e7SSue Gleeson 		    (u_longlong_t)guid[hca_ndx]);
177c3a558e7SSue Gleeson 		srpt_ioc_attach_hca(guid[hca_ndx], B_FALSE);
1781bdd6c0eSSue Gleeson 	}
1791bdd6c0eSSue Gleeson 
1801bdd6c0eSSue Gleeson 	ibt_free_hca_list(guid, hca_cnt);
1811bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("ioc_attach, added %d I/O Controller(s)",
1821bdd6c0eSSue Gleeson 	    srpt_ctxt->sc_num_iocs);
1831bdd6c0eSSue Gleeson 	return (DDI_SUCCESS);
1841bdd6c0eSSue Gleeson }
1851bdd6c0eSSue Gleeson 
186c3a558e7SSue Gleeson /*
187c3a558e7SSue Gleeson  * Initialize I/O Controllers.  sprt_ctxt->sc_rwlock must be locked by the
188c3a558e7SSue Gleeson  * caller.
189c3a558e7SSue Gleeson  *
190c3a558e7SSue Gleeson  * 'checked' indicates no need to lookup the hca in the HCA configuration
191c3a558e7SSue Gleeson  * list.
192c3a558e7SSue Gleeson  */
193c3a558e7SSue Gleeson void
srpt_ioc_attach_hca(ib_guid_t hca_guid,boolean_t checked)194c3a558e7SSue Gleeson srpt_ioc_attach_hca(ib_guid_t hca_guid, boolean_t checked)
195c3a558e7SSue Gleeson {
196c3a558e7SSue Gleeson 	boolean_t	enable_hca = B_TRUE;
197c3a558e7SSue Gleeson 	srpt_ioc_t	*ioc;
198c3a558e7SSue Gleeson 
199c3a558e7SSue Gleeson 	if (!checked) {
200c3a558e7SSue Gleeson 		enable_hca = srpt_check_hca_cfg_enabled(hca_guid);
201c3a558e7SSue Gleeson 
202c3a558e7SSue Gleeson 		if (!enable_hca) {
203c3a558e7SSue Gleeson 			/* nothing to do */
204c3a558e7SSue Gleeson 			SRPT_DPRINTF_L2(
205c3a558e7SSue Gleeson 			    "ioc_attach_hca, HCA %016llx disabled "
206c3a558e7SSue Gleeson 			    "by srpt config",
207c3a558e7SSue Gleeson 			    (u_longlong_t)hca_guid);
208c3a558e7SSue Gleeson 			return;
209c3a558e7SSue Gleeson 		}
210c3a558e7SSue Gleeson 	}
211c3a558e7SSue Gleeson 
212c3a558e7SSue Gleeson 	SRPT_DPRINTF_L2("ioc_attach_hca, adding I/O"
213c3a558e7SSue Gleeson 	    " Controller (%016llx)", (u_longlong_t)hca_guid);
214c3a558e7SSue Gleeson 
215c3a558e7SSue Gleeson 	ioc = srpt_ioc_init(hca_guid);
216c3a558e7SSue Gleeson 	if (ioc == NULL) {
217c3a558e7SSue Gleeson 		/*
218c3a558e7SSue Gleeson 		 * IOC already exists or an error occurred.  Already
219c3a558e7SSue Gleeson 		 * logged by srpt_ioc_init()
220c3a558e7SSue Gleeson 		 */
221c3a558e7SSue Gleeson 		return;
222c3a558e7SSue Gleeson 	}
223c3a558e7SSue Gleeson 
224c3a558e7SSue Gleeson 	/*
225c3a558e7SSue Gleeson 	 * Create the COMSTAR SRP Target for this IOC.  If this fails,
226c3a558e7SSue Gleeson 	 * remove the IOC.
227c3a558e7SSue Gleeson 	 */
228c3a558e7SSue Gleeson 	rw_enter(&ioc->ioc_rwlock, RW_WRITER);
229c3a558e7SSue Gleeson 	ioc->ioc_tgt_port = srpt_stp_alloc_port(ioc, ioc->ioc_guid);
230c3a558e7SSue Gleeson 	if (ioc->ioc_tgt_port == NULL) {
231c3a558e7SSue Gleeson 		SRPT_DPRINTF_L1("ioc_attach_hca: alloc SCSI"
232c3a558e7SSue Gleeson 		    " Target Port error on GUID(%016llx)",
233c3a558e7SSue Gleeson 		    (u_longlong_t)ioc->ioc_guid);
234c3a558e7SSue Gleeson 		rw_exit(&ioc->ioc_rwlock);
235c3a558e7SSue Gleeson 		srpt_ioc_fini(ioc);
236c3a558e7SSue Gleeson 		return;
237c3a558e7SSue Gleeson 	}
238c3a558e7SSue Gleeson 	rw_exit(&ioc->ioc_rwlock);
239c3a558e7SSue Gleeson 
240c3a558e7SSue Gleeson 	/*
241c3a558e7SSue Gleeson 	 * New HCA added with default SCSI Target Port, SRP service
242c3a558e7SSue Gleeson 	 * will be started when SCSI Target Port is brought
243c3a558e7SSue Gleeson 	 * on-line by STMF.
244c3a558e7SSue Gleeson 	 */
245c3a558e7SSue Gleeson 	list_insert_tail(&srpt_ctxt->sc_ioc_list, ioc);
246c3a558e7SSue Gleeson 	SRPT_DPRINTF_L2("ioc_attach_hca, I/O Controller ibt HCA hdl (%p)",
247c3a558e7SSue Gleeson 	    (void *)ioc->ioc_ibt_hdl);
248c3a558e7SSue Gleeson 
249c3a558e7SSue Gleeson 	srpt_ctxt->sc_num_iocs++;
250c3a558e7SSue Gleeson }
251c3a558e7SSue Gleeson 
252c3a558e7SSue Gleeson /*
253c3a558e7SSue Gleeson  * srpt_check_hca_cfg_enabled()
254c3a558e7SSue Gleeson  *
255c3a558e7SSue Gleeson  * Function to check the configuration for the enabled status of a given
256c3a558e7SSue Gleeson  * HCA.  Returns B_TRUE if SRPT services should be activated for this HCA,
257c3a558e7SSue Gleeson  * B_FALSE if it should be disabled.
258c3a558e7SSue Gleeson  */
259c3a558e7SSue Gleeson static boolean_t
srpt_check_hca_cfg_enabled(ib_guid_t hca_guid)260c3a558e7SSue Gleeson srpt_check_hca_cfg_enabled(ib_guid_t hca_guid)
261c3a558e7SSue Gleeson {
262c3a558e7SSue Gleeson 	int		status;
263c3a558e7SSue Gleeson 	char		buf[32];
264c3a558e7SSue Gleeson 	nvlist_t	*hcanv;
265c3a558e7SSue Gleeson 	boolean_t	enable_hca;
266c3a558e7SSue Gleeson 
267c3a558e7SSue Gleeson 	enable_hca = srpt_enable_by_default;
268c3a558e7SSue Gleeson 
269c3a558e7SSue Gleeson 	SRPT_FORMAT_HCAKEY(buf, sizeof (buf), (u_longlong_t)hca_guid);
270c3a558e7SSue Gleeson 
271c3a558e7SSue Gleeson 	if (srpt_ctxt->sc_cfg_hca_nv != NULL) {
272c3a558e7SSue Gleeson 		status = nvlist_lookup_nvlist(srpt_ctxt->sc_cfg_hca_nv,
273c3a558e7SSue Gleeson 		    buf, &hcanv);
274c3a558e7SSue Gleeson 		if (status == 0) {
275c3a558e7SSue Gleeson 			SRPT_DPRINTF_L3("check_hca_cfg, found guid %s",  buf);
276c3a558e7SSue Gleeson 			(void) nvlist_lookup_boolean_value(hcanv,
277c3a558e7SSue Gleeson 			    SRPT_PROP_ENABLED, &enable_hca);
278c3a558e7SSue Gleeson 		} else {
279c3a558e7SSue Gleeson 			SRPT_DPRINTF_L3("check_hca_cfg, did not find guid %s",
280c3a558e7SSue Gleeson 			    buf);
281c3a558e7SSue Gleeson 		}
282c3a558e7SSue Gleeson 	}
283c3a558e7SSue Gleeson 
284c3a558e7SSue Gleeson 	return (enable_hca);
285c3a558e7SSue Gleeson }
286c3a558e7SSue Gleeson 
287c3a558e7SSue Gleeson /*
288c3a558e7SSue Gleeson  * srpt_ioc_update()
289c3a558e7SSue Gleeson  *
290c3a558e7SSue Gleeson  * Using the configuration nvlist, enables or disables SRP services
291c3a558e7SSue Gleeson  * the provided HCAs.  srpt_ctxt->sc_rwlock should be held outside of this call.
292c3a558e7SSue Gleeson  */
293c3a558e7SSue Gleeson void
srpt_ioc_update(void)294c3a558e7SSue Gleeson srpt_ioc_update(void)
295c3a558e7SSue Gleeson {
296c3a558e7SSue Gleeson 	boolean_t	enabled;
297c3a558e7SSue Gleeson 	nvpair_t	*nvp = NULL;
298c3a558e7SSue Gleeson 	uint64_t	hca_guid;
299c3a558e7SSue Gleeson 	nvlist_t	*nvl;
300c3a558e7SSue Gleeson 	nvlist_t	*cfg = srpt_ctxt->sc_cfg_hca_nv;
301c3a558e7SSue Gleeson 
302c3a558e7SSue Gleeson 	if (cfg == NULL) {
303c3a558e7SSue Gleeson 		SRPT_DPRINTF_L2("ioc_update, no configuration data");
304c3a558e7SSue Gleeson 		return;
305c3a558e7SSue Gleeson 	}
306c3a558e7SSue Gleeson 
307c3a558e7SSue Gleeson 	while ((nvp = nvlist_next_nvpair(cfg, nvp)) != NULL) {
308c3a558e7SSue Gleeson 		enabled = srpt_enable_by_default;
309c3a558e7SSue Gleeson 
310c3a558e7SSue Gleeson 		if ((nvpair_value_nvlist(nvp, &nvl)) != 0) {
311c3a558e7SSue Gleeson 			SRPT_DPRINTF_L2("ioc_update, did not find an nvlist");
312c3a558e7SSue Gleeson 			continue;
313c3a558e7SSue Gleeson 		}
314c3a558e7SSue Gleeson 
315c3a558e7SSue Gleeson 		if ((nvlist_lookup_uint64(nvl, SRPT_PROP_GUID, &hca_guid))
316c3a558e7SSue Gleeson 		    != 0) {
317c3a558e7SSue Gleeson 			SRPT_DPRINTF_L2("ioc_update, did not find a guid");
318c3a558e7SSue Gleeson 			continue;
319c3a558e7SSue Gleeson 		}
320c3a558e7SSue Gleeson 
321c3a558e7SSue Gleeson 		(void) nvlist_lookup_boolean_value(nvl, SRPT_PROP_ENABLED,
322c3a558e7SSue Gleeson 		    &enabled);
323c3a558e7SSue Gleeson 
324c3a558e7SSue Gleeson 		if (enabled) {
325c3a558e7SSue Gleeson 			SRPT_DPRINTF_L2("ioc_update, enabling guid %016llx",
326c3a558e7SSue Gleeson 			    (u_longlong_t)hca_guid);
327c3a558e7SSue Gleeson 			srpt_ioc_attach_hca(hca_guid, B_TRUE);
328c3a558e7SSue Gleeson 		} else {
329c3a558e7SSue Gleeson 			SRPT_DPRINTF_L2("ioc_update, disabling guid %016llx",
330c3a558e7SSue Gleeson 			    (u_longlong_t)hca_guid);
331c3a558e7SSue Gleeson 			srpt_ioc_detach_hca(hca_guid);
332c3a558e7SSue Gleeson 		}
333c3a558e7SSue Gleeson 	}
334c3a558e7SSue Gleeson }
335c3a558e7SSue Gleeson 
3361bdd6c0eSSue Gleeson /*
3371bdd6c0eSSue Gleeson  * srpt_ioc_detach() - I/O Controller detach
3381bdd6c0eSSue Gleeson  *
3391bdd6c0eSSue Gleeson  * srpt_ctxt->sc_rwlock should be held outside of this call.
3401bdd6c0eSSue Gleeson  */
3411bdd6c0eSSue Gleeson void
srpt_ioc_detach()3421bdd6c0eSSue Gleeson srpt_ioc_detach()
3431bdd6c0eSSue Gleeson {
3441bdd6c0eSSue Gleeson 	srpt_ioc_t	*ioc;
3451bdd6c0eSSue Gleeson 
346c3a558e7SSue Gleeson 	/*
347c3a558e7SSue Gleeson 	 * All SRP targets must be destroyed before calling this
348c3a558e7SSue Gleeson 	 * function.
349c3a558e7SSue Gleeson 	 */
3501bdd6c0eSSue Gleeson 	while ((ioc = list_head(&srpt_ctxt->sc_ioc_list)) != NULL) {
3511bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_detach, removing I/O Controller(%p)"
3521bdd6c0eSSue Gleeson 		    " (%016llx), ibt_hdl(%p)",
3531bdd6c0eSSue Gleeson 		    (void *)ioc,
3541bdd6c0eSSue Gleeson 		    ioc ? (u_longlong_t)ioc->ioc_guid : 0x0ll,
3551bdd6c0eSSue Gleeson 		    (void *)ioc->ioc_ibt_hdl);
356c3a558e7SSue Gleeson 
357c3a558e7SSue Gleeson 		list_remove(&srpt_ctxt->sc_ioc_list, ioc);
3581bdd6c0eSSue Gleeson 		srpt_ioc_fini(ioc);
359c3a558e7SSue Gleeson 		srpt_ctxt->sc_num_iocs--;
3601bdd6c0eSSue Gleeson 	}
3611bdd6c0eSSue Gleeson 
3621bdd6c0eSSue Gleeson 	srpt_ctxt->sc_ibt_hdl = NULL;
3631bdd6c0eSSue Gleeson }
3641bdd6c0eSSue Gleeson 
365c3a558e7SSue Gleeson /*
366c3a558e7SSue Gleeson  * srpt_ioc_detach_hca()
367c3a558e7SSue Gleeson  *
368c3a558e7SSue Gleeson  * Stop SRP Target services on this HCA
369c3a558e7SSue Gleeson  *
370c3a558e7SSue Gleeson  * Note that this is not entirely synchronous with srpt_ioc_attach_hca()
371c3a558e7SSue Gleeson  * in that we don't need to check the configuration to know whether to
372c3a558e7SSue Gleeson  * disable an HCA.  We get here either because the IB framework has told
373c3a558e7SSue Gleeson  * us the HCA has been detached, or because the administrator has explicitly
374c3a558e7SSue Gleeson  * disabled this HCA.
375c3a558e7SSue Gleeson  *
376c3a558e7SSue Gleeson  * Must be called with srpt_ctxt->sc_rwlock locked as RW_WRITER.
377c3a558e7SSue Gleeson  */
378c3a558e7SSue Gleeson void
srpt_ioc_detach_hca(ib_guid_t hca_guid)379c3a558e7SSue Gleeson srpt_ioc_detach_hca(ib_guid_t hca_guid)
380c3a558e7SSue Gleeson {
381c3a558e7SSue Gleeson 	srpt_ioc_t		*ioc;
382c3a558e7SSue Gleeson 	srpt_target_port_t	*tgt;
383c3a558e7SSue Gleeson 	stmf_status_t		stmf_status = STMF_SUCCESS;
384c3a558e7SSue Gleeson 
385c3a558e7SSue Gleeson 	ioc = srpt_ioc_get_locked(hca_guid);
386c3a558e7SSue Gleeson 	if (ioc == NULL) {
387c3a558e7SSue Gleeson 		/* doesn't exist, nothing to do */
388c3a558e7SSue Gleeson 		return;
389c3a558e7SSue Gleeson 	}
390c3a558e7SSue Gleeson 
391c3a558e7SSue Gleeson 	rw_enter(&ioc->ioc_rwlock, RW_WRITER);
392c3a558e7SSue Gleeson 	tgt = ioc->ioc_tgt_port;
393c3a558e7SSue Gleeson 
394c3a558e7SSue Gleeson 	if (tgt != NULL) {
395c3a558e7SSue Gleeson 		stmf_status = srpt_stp_destroy_port(tgt);
396c3a558e7SSue Gleeson 		if (stmf_status == STMF_SUCCESS) {
397c3a558e7SSue Gleeson 			ioc->ioc_tgt_port = NULL;
398c3a558e7SSue Gleeson 			(void) srpt_stp_free_port(tgt);
399c3a558e7SSue Gleeson 		}
400c3a558e7SSue Gleeson 	}
401c3a558e7SSue Gleeson 
402c3a558e7SSue Gleeson 	rw_exit(&ioc->ioc_rwlock);
403c3a558e7SSue Gleeson 
404c3a558e7SSue Gleeson 	if (stmf_status != STMF_SUCCESS) {
405c3a558e7SSue Gleeson 		/* should never happen */
406c3a558e7SSue Gleeson 		return;
407c3a558e7SSue Gleeson 	}
408c3a558e7SSue Gleeson 
409c3a558e7SSue Gleeson 	list_remove(&srpt_ctxt->sc_ioc_list, ioc);
410c3a558e7SSue Gleeson 	srpt_ctxt->sc_num_iocs--;
411c3a558e7SSue Gleeson 
412c3a558e7SSue Gleeson 	srpt_ioc_fini(ioc);
413c3a558e7SSue Gleeson 	SRPT_DPRINTF_L2("ioc_detach_hca, HCA %016llx detached",
414c3a558e7SSue Gleeson 	    (u_longlong_t)hca_guid);
415c3a558e7SSue Gleeson }
416c3a558e7SSue Gleeson 
4171bdd6c0eSSue Gleeson /*
4181bdd6c0eSSue Gleeson  * srpt_ioc_init() - I/O Controller initialization
4191bdd6c0eSSue Gleeson  *
4201bdd6c0eSSue Gleeson  * Requires srpt_ctxt->rw_lock be held outside of call.
4211bdd6c0eSSue Gleeson  */
4221bdd6c0eSSue Gleeson static srpt_ioc_t *
srpt_ioc_init(ib_guid_t guid)4231bdd6c0eSSue Gleeson srpt_ioc_init(ib_guid_t guid)
4241bdd6c0eSSue Gleeson {
4251bdd6c0eSSue Gleeson 	ibt_status_t		status;
4261bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
4271bdd6c0eSSue Gleeson 	ibt_hca_attr_t		hca_attr;
4281bdd6c0eSSue Gleeson 	uint_t			iu_ndx;
4291bdd6c0eSSue Gleeson 	uint_t			err_ndx;
4301bdd6c0eSSue Gleeson 	ibt_mr_attr_t		mr_attr;
4311bdd6c0eSSue Gleeson 	ibt_mr_desc_t		mr_desc;
4321bdd6c0eSSue Gleeson 	srpt_iu_t		*iu;
4331bdd6c0eSSue Gleeson 	ibt_srq_sizes_t		srq_attr;
4341bdd6c0eSSue Gleeson 	char			namebuf[32];
4351bdd6c0eSSue Gleeson 	size_t			iu_offset;
436989ca640SSue Gleeson 	uint_t			srq_sz;
4371bdd6c0eSSue Gleeson 
4381bdd6c0eSSue Gleeson 	status = ibt_query_hca_byguid(guid, &hca_attr);
4391bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
4401bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, HCA query error (%d)",
4411bdd6c0eSSue Gleeson 		    status);
4421bdd6c0eSSue Gleeson 		return (NULL);
4431bdd6c0eSSue Gleeson 	}
4441bdd6c0eSSue Gleeson 
4451bdd6c0eSSue Gleeson 	ioc = srpt_ioc_get_locked(guid);
4461bdd6c0eSSue Gleeson 	if (ioc != NULL) {
447c3a558e7SSue Gleeson 		SRPT_DPRINTF_L2("ioc_init, HCA already exists");
4481bdd6c0eSSue Gleeson 		return (NULL);
4491bdd6c0eSSue Gleeson 	}
4501bdd6c0eSSue Gleeson 
4511bdd6c0eSSue Gleeson 	ioc = kmem_zalloc(sizeof (srpt_ioc_t), KM_SLEEP);
4521bdd6c0eSSue Gleeson 
4531bdd6c0eSSue Gleeson 	rw_init(&ioc->ioc_rwlock, NULL, RW_DRIVER, NULL);
4541bdd6c0eSSue Gleeson 	rw_enter(&ioc->ioc_rwlock, RW_WRITER);
4551bdd6c0eSSue Gleeson 
4561bdd6c0eSSue Gleeson 	bcopy(&hca_attr, &ioc->ioc_attr, sizeof (ibt_hca_attr_t));
4571bdd6c0eSSue Gleeson 
4581bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("ioc_init, HCA max mr=%d, mrlen=%lld",
4591bdd6c0eSSue Gleeson 	    hca_attr.hca_max_memr, (u_longlong_t)hca_attr.hca_max_memr_len);
4601bdd6c0eSSue Gleeson 	ioc->ioc_guid   = guid;
4611bdd6c0eSSue Gleeson 
4621bdd6c0eSSue Gleeson 	status = ibt_open_hca(srpt_ctxt->sc_ibt_hdl, guid, &ioc->ioc_ibt_hdl);
4631bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
4641bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, IBT open failed (%d)", status);
4651bdd6c0eSSue Gleeson 		goto hca_open_err;
4661bdd6c0eSSue Gleeson 	}
4671bdd6c0eSSue Gleeson 
4681bdd6c0eSSue Gleeson 	status = ibt_alloc_pd(ioc->ioc_ibt_hdl, IBT_PD_NO_FLAGS,
4691bdd6c0eSSue Gleeson 	    &ioc->ioc_pd_hdl);
4701bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
4711bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, IBT create PD failed (%d)", status);
4721bdd6c0eSSue Gleeson 		goto pd_alloc_err;
4731bdd6c0eSSue Gleeson 	}
4741bdd6c0eSSue Gleeson 
4751bdd6c0eSSue Gleeson 	/*
4761bdd6c0eSSue Gleeson 	 * We require hardware support for SRQs.  We use a common SRQ to
4771bdd6c0eSSue Gleeson 	 * reduce channel memory consumption.
4781bdd6c0eSSue Gleeson 	 */
4791bdd6c0eSSue Gleeson 	if ((ioc->ioc_attr.hca_flags & IBT_HCA_SRQ) == 0) {
480989ca640SSue Gleeson 		SRPT_DPRINTF_L0(
481989ca640SSue Gleeson 		    "ioc_init, no SRQ capability, HCA not supported");
4821bdd6c0eSSue Gleeson 		goto srq_alloc_err;
4831bdd6c0eSSue Gleeson 	}
4841bdd6c0eSSue Gleeson 
4851bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("ioc_init, Using shared receive queues, max srq work"
4861bdd6c0eSSue Gleeson 	    " queue size(%d), def size = %d", ioc->ioc_attr.hca_max_srqs_sz,
4871bdd6c0eSSue Gleeson 	    srpt_ioc_srq_size);
488989ca640SSue Gleeson 	srq_sz = srq_attr.srq_wr_sz = min(srpt_ioc_srq_size,
489989ca640SSue Gleeson 	    ioc->ioc_attr.hca_max_srqs_sz) - 1;
4901bdd6c0eSSue Gleeson 	srq_attr.srq_sgl_sz = 1;
4911bdd6c0eSSue Gleeson 
4921bdd6c0eSSue Gleeson 	status = ibt_alloc_srq(ioc->ioc_ibt_hdl, IBT_SRQ_NO_FLAGS,
4931bdd6c0eSSue Gleeson 	    ioc->ioc_pd_hdl, &srq_attr, &ioc->ioc_srq_hdl,
4941bdd6c0eSSue Gleeson 	    &ioc->ioc_srq_attr);
4951bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
4961bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, IBT create SRQ failed(%d)", status);
4971bdd6c0eSSue Gleeson 		goto srq_alloc_err;
4981bdd6c0eSSue Gleeson 	}
4991bdd6c0eSSue Gleeson 
500989ca640SSue Gleeson 	SRPT_DPRINTF_L2("ioc_init, Using SRQ size(%d), MAX SG size(%d)",
501989ca640SSue Gleeson 	    srq_sz, 1);
5021bdd6c0eSSue Gleeson 
5031bdd6c0eSSue Gleeson 	ibt_set_srq_private(ioc->ioc_srq_hdl, ioc);
5041bdd6c0eSSue Gleeson 
5051bdd6c0eSSue Gleeson 	/*
5061bdd6c0eSSue Gleeson 	 * Allocate a pool of SRP IU message buffers and post them to
5071bdd6c0eSSue Gleeson 	 * the I/O Controller SRQ.  We let the SRQ manage the free IU
5081bdd6c0eSSue Gleeson 	 * messages.
5091bdd6c0eSSue Gleeson 	 */
510989ca640SSue Gleeson 	ioc->ioc_num_iu_entries = srq_sz;
5111bdd6c0eSSue Gleeson 
5121bdd6c0eSSue Gleeson 	ioc->ioc_iu_pool = kmem_zalloc(sizeof (srpt_iu_t) *
5131bdd6c0eSSue Gleeson 	    ioc->ioc_num_iu_entries, KM_SLEEP);
5141bdd6c0eSSue Gleeson 
515989ca640SSue Gleeson 	ioc->ioc_iu_bufs = kmem_alloc(srpt_iu_size *
5161bdd6c0eSSue Gleeson 	    ioc->ioc_num_iu_entries, KM_SLEEP);
5171bdd6c0eSSue Gleeson 
5181bdd6c0eSSue Gleeson 	if ((ioc->ioc_iu_pool == NULL) || (ioc->ioc_iu_bufs == NULL)) {
5191bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, failed to allocate SRQ IUs");
5201bdd6c0eSSue Gleeson 		goto srq_iu_alloc_err;
5211bdd6c0eSSue Gleeson 	}
5221bdd6c0eSSue Gleeson 
5231bdd6c0eSSue Gleeson 	mr_attr.mr_vaddr = (ib_vaddr_t)(uintptr_t)ioc->ioc_iu_bufs;
524989ca640SSue Gleeson 	mr_attr.mr_len   = srpt_iu_size * ioc->ioc_num_iu_entries;
5251bdd6c0eSSue Gleeson 	mr_attr.mr_as    = NULL;
5261bdd6c0eSSue Gleeson 	mr_attr.mr_flags = IBT_MR_ENABLE_LOCAL_WRITE;
5271bdd6c0eSSue Gleeson 
5281bdd6c0eSSue Gleeson 	status = ibt_register_mr(ioc->ioc_ibt_hdl, ioc->ioc_pd_hdl,
5291bdd6c0eSSue Gleeson 	    &mr_attr, &ioc->ioc_iu_mr_hdl, &mr_desc);
5301bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
5311bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, IU buffer pool MR err(%d)",
5321bdd6c0eSSue Gleeson 		    status);
5331bdd6c0eSSue Gleeson 		goto srq_iu_alloc_err;
5341bdd6c0eSSue Gleeson 	}
5351bdd6c0eSSue Gleeson 
5361bdd6c0eSSue Gleeson 	for (iu_ndx = 0, iu = ioc->ioc_iu_pool; iu_ndx <
5371bdd6c0eSSue Gleeson 	    ioc->ioc_num_iu_entries; iu_ndx++, iu++) {
5381bdd6c0eSSue Gleeson 
539989ca640SSue Gleeson 		iu_offset = (iu_ndx * srpt_iu_size);
5401bdd6c0eSSue Gleeson 		iu->iu_buf = (void *)((uintptr_t)ioc->ioc_iu_bufs + iu_offset);
5411bdd6c0eSSue Gleeson 
5421bdd6c0eSSue Gleeson 		mutex_init(&iu->iu_lock, NULL, MUTEX_DRIVER, NULL);
5431bdd6c0eSSue Gleeson 
5441bdd6c0eSSue Gleeson 		iu->iu_sge.ds_va  = mr_desc.md_vaddr + iu_offset;
5451bdd6c0eSSue Gleeson 		iu->iu_sge.ds_key = mr_desc.md_lkey;
546989ca640SSue Gleeson 		iu->iu_sge.ds_len = srpt_iu_size;
5471bdd6c0eSSue Gleeson 		iu->iu_ioc	  = ioc;
5481bdd6c0eSSue Gleeson 		iu->iu_pool_ndx   = iu_ndx;
5491bdd6c0eSSue Gleeson 
5501bdd6c0eSSue Gleeson 		status = srpt_ioc_post_recv_iu(ioc, &ioc->ioc_iu_pool[iu_ndx]);
5511bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
5521bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("ioc_init, SRQ IU post err(%d)",
5531bdd6c0eSSue Gleeson 			    status);
5541bdd6c0eSSue Gleeson 			goto srq_iu_post_err;
5551bdd6c0eSSue Gleeson 		}
5561bdd6c0eSSue Gleeson 	}
5571bdd6c0eSSue Gleeson 
5581bdd6c0eSSue Gleeson 	/*
5591bdd6c0eSSue Gleeson 	 * Initialize the dbuf vmem arena
5601bdd6c0eSSue Gleeson 	 */
5611bdd6c0eSSue Gleeson 	(void) snprintf(namebuf, sizeof (namebuf),
5621bdd6c0eSSue Gleeson 	    "srpt_buf_pool_%16llX", (u_longlong_t)guid);
5631bdd6c0eSSue Gleeson 	ioc->ioc_dbuf_pool = srpt_vmem_create(namebuf, ioc,
5641bdd6c0eSSue Gleeson 	    SRPT_BUF_MR_CHUNKSIZE, SRPT_BUF_POOL_MAX, srpt_dbuf_mr_flags);
5651bdd6c0eSSue Gleeson 
5661bdd6c0eSSue Gleeson 	if (ioc->ioc_dbuf_pool == NULL) {
5671bdd6c0eSSue Gleeson 		goto stmf_db_alloc_err;
5681bdd6c0eSSue Gleeson 	}
5691bdd6c0eSSue Gleeson 
5701bdd6c0eSSue Gleeson 	/*
5711bdd6c0eSSue Gleeson 	 * Allocate the I/O Controller STMF data buffer allocator.  The
5721bdd6c0eSSue Gleeson 	 * data store will span all targets associated with this IOC.
5731bdd6c0eSSue Gleeson 	 */
5741bdd6c0eSSue Gleeson 	ioc->ioc_stmf_ds = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0);
5751bdd6c0eSSue Gleeson 	if (ioc->ioc_stmf_ds == NULL) {
5761bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_attach, STMF DBUF alloc failure for IOC");
5771bdd6c0eSSue Gleeson 		goto stmf_db_alloc_err;
5781bdd6c0eSSue Gleeson 	}
5791bdd6c0eSSue Gleeson 	ioc->ioc_stmf_ds->ds_alloc_data_buf = &srpt_ioc_ds_alloc_dbuf;
5801bdd6c0eSSue Gleeson 	ioc->ioc_stmf_ds->ds_free_data_buf  = &srpt_ioc_ds_free_dbuf;
5811bdd6c0eSSue Gleeson 	ioc->ioc_stmf_ds->ds_port_private   = ioc;
5821bdd6c0eSSue Gleeson 
5831bdd6c0eSSue Gleeson 	rw_exit(&ioc->ioc_rwlock);
5841bdd6c0eSSue Gleeson 	return (ioc);
5851bdd6c0eSSue Gleeson 
5861bdd6c0eSSue Gleeson stmf_db_alloc_err:
5871bdd6c0eSSue Gleeson 	if (ioc->ioc_dbuf_pool != NULL) {
5881bdd6c0eSSue Gleeson 		srpt_vmem_destroy(ioc->ioc_dbuf_pool);
5891bdd6c0eSSue Gleeson 	}
5901bdd6c0eSSue Gleeson 
5911bdd6c0eSSue Gleeson srq_iu_post_err:
5921bdd6c0eSSue Gleeson 	if (ioc->ioc_iu_mr_hdl != NULL) {
5931bdd6c0eSSue Gleeson 		status = ibt_deregister_mr(ioc->ioc_ibt_hdl,
5941bdd6c0eSSue Gleeson 		    ioc->ioc_iu_mr_hdl);
5951bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
5961bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("ioc_init, error deregistering"
5971bdd6c0eSSue Gleeson 			    " memory region (%d)", status);
5981bdd6c0eSSue Gleeson 		}
5991bdd6c0eSSue Gleeson 	}
6001bdd6c0eSSue Gleeson 	for (err_ndx = 0, iu = ioc->ioc_iu_pool; err_ndx < iu_ndx;
6011bdd6c0eSSue Gleeson 	    err_ndx++, iu++) {
6021bdd6c0eSSue Gleeson 		mutex_destroy(&iu->iu_lock);
6031bdd6c0eSSue Gleeson 	}
6041bdd6c0eSSue Gleeson 
6051bdd6c0eSSue Gleeson srq_iu_alloc_err:
6061bdd6c0eSSue Gleeson 	if (ioc->ioc_iu_bufs != NULL) {
607989ca640SSue Gleeson 		kmem_free(ioc->ioc_iu_bufs, srpt_iu_size *
6081bdd6c0eSSue Gleeson 		    ioc->ioc_num_iu_entries);
6091bdd6c0eSSue Gleeson 	}
6101bdd6c0eSSue Gleeson 	if (ioc->ioc_iu_pool != NULL) {
6111bdd6c0eSSue Gleeson 		kmem_free(ioc->ioc_iu_pool,
6121bdd6c0eSSue Gleeson 		    sizeof (srpt_iu_t) * ioc->ioc_num_iu_entries);
6131bdd6c0eSSue Gleeson 	}
6141bdd6c0eSSue Gleeson 	if (ioc->ioc_srq_hdl != NULL) {
6151bdd6c0eSSue Gleeson 		status = ibt_free_srq(ioc->ioc_srq_hdl);
6161bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
6171bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("ioc_init, error freeing SRQ (%d)",
6181bdd6c0eSSue Gleeson 			    status);
6191bdd6c0eSSue Gleeson 		}
6201bdd6c0eSSue Gleeson 
6211bdd6c0eSSue Gleeson 	}
6221bdd6c0eSSue Gleeson 
6231bdd6c0eSSue Gleeson srq_alloc_err:
6241bdd6c0eSSue Gleeson 	status = ibt_free_pd(ioc->ioc_ibt_hdl, ioc->ioc_pd_hdl);
6251bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
6261bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, free PD error (%d)", status);
6271bdd6c0eSSue Gleeson 	}
6281bdd6c0eSSue Gleeson 
6291bdd6c0eSSue Gleeson pd_alloc_err:
6301bdd6c0eSSue Gleeson 	status = ibt_close_hca(ioc->ioc_ibt_hdl);
6311bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
6321bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_init, close ioc error (%d)", status);
6331bdd6c0eSSue Gleeson 	}
6341bdd6c0eSSue Gleeson 
6351bdd6c0eSSue Gleeson hca_open_err:
6361bdd6c0eSSue Gleeson 	rw_exit(&ioc->ioc_rwlock);
6371bdd6c0eSSue Gleeson 	rw_destroy(&ioc->ioc_rwlock);
6381bdd6c0eSSue Gleeson 	kmem_free(ioc, sizeof (*ioc));
6391bdd6c0eSSue Gleeson 	return (NULL);
6401bdd6c0eSSue Gleeson }
6411bdd6c0eSSue Gleeson 
6421bdd6c0eSSue Gleeson /*
6431bdd6c0eSSue Gleeson  * srpt_ioc_fini() - I/O Controller Cleanup
6441bdd6c0eSSue Gleeson  *
6451bdd6c0eSSue Gleeson  * Requires srpt_ctxt->sc_rwlock be held outside of call.
6461bdd6c0eSSue Gleeson  */
6471bdd6c0eSSue Gleeson static void
srpt_ioc_fini(srpt_ioc_t * ioc)6481bdd6c0eSSue Gleeson srpt_ioc_fini(srpt_ioc_t *ioc)
6491bdd6c0eSSue Gleeson {
6501bdd6c0eSSue Gleeson 	int		status;
6511bdd6c0eSSue Gleeson 	int		ndx;
6521bdd6c0eSSue Gleeson 
6531bdd6c0eSSue Gleeson 	/*
6541bdd6c0eSSue Gleeson 	 * Note driver flows will have already taken all SRP
6551bdd6c0eSSue Gleeson 	 * services running on the I/O Controller off-line.
6561bdd6c0eSSue Gleeson 	 */
657*b1d7ec75SPeter Cudhea - Oracle Corporation - Burlington, MA United States 	ASSERT(ioc->ioc_tgt_port == NULL);
6581bdd6c0eSSue Gleeson 	rw_enter(&ioc->ioc_rwlock, RW_WRITER);
6591bdd6c0eSSue Gleeson 	if (ioc->ioc_ibt_hdl != NULL) {
6601bdd6c0eSSue Gleeson 		if (ioc->ioc_stmf_ds != NULL) {
6611bdd6c0eSSue Gleeson 			stmf_free(ioc->ioc_stmf_ds);
6621bdd6c0eSSue Gleeson 		}
6631bdd6c0eSSue Gleeson 
6641bdd6c0eSSue Gleeson 		if (ioc->ioc_srq_hdl != NULL) {
6651bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L4("ioc_fini, freeing SRQ");
6661bdd6c0eSSue Gleeson 			status = ibt_free_srq(ioc->ioc_srq_hdl);
6671bdd6c0eSSue Gleeson 			if (status != IBT_SUCCESS) {
6681bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L1("ioc_fini, free SRQ"
6691bdd6c0eSSue Gleeson 				    " error (%d)", status);
6701bdd6c0eSSue Gleeson 			}
6711bdd6c0eSSue Gleeson 		}
6721bdd6c0eSSue Gleeson 
6731bdd6c0eSSue Gleeson 		if (ioc->ioc_iu_mr_hdl != NULL) {
6741bdd6c0eSSue Gleeson 			status = ibt_deregister_mr(
6751bdd6c0eSSue Gleeson 			    ioc->ioc_ibt_hdl, ioc->ioc_iu_mr_hdl);
6761bdd6c0eSSue Gleeson 			if (status != IBT_SUCCESS) {
6771bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L1("ioc_fini, error deregistering"
6781bdd6c0eSSue Gleeson 				    " memory region (%d)", status);
6791bdd6c0eSSue Gleeson 			}
6801bdd6c0eSSue Gleeson 		}
6811bdd6c0eSSue Gleeson 
6821bdd6c0eSSue Gleeson 		if (ioc->ioc_iu_bufs != NULL) {
683989ca640SSue Gleeson 			kmem_free(ioc->ioc_iu_bufs, srpt_iu_size *
6841bdd6c0eSSue Gleeson 			    ioc->ioc_num_iu_entries);
6851bdd6c0eSSue Gleeson 		}
6861bdd6c0eSSue Gleeson 
6871bdd6c0eSSue Gleeson 		if (ioc->ioc_iu_pool != NULL) {
6881bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L4("ioc_fini, freeing IU entries");
6891bdd6c0eSSue Gleeson 			for (ndx = 0; ndx < ioc->ioc_num_iu_entries; ndx++) {
6901bdd6c0eSSue Gleeson 				mutex_destroy(&ioc->ioc_iu_pool[ndx].iu_lock);
6911bdd6c0eSSue Gleeson 			}
6921bdd6c0eSSue Gleeson 
6931bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L4("ioc_fini, free IU pool struct");
6941bdd6c0eSSue Gleeson 			kmem_free(ioc->ioc_iu_pool,
6951bdd6c0eSSue Gleeson 			    sizeof (srpt_iu_t) * (ioc->ioc_num_iu_entries));
6961bdd6c0eSSue Gleeson 			ioc->ioc_iu_pool = NULL;
6971bdd6c0eSSue Gleeson 			ioc->ioc_num_iu_entries = 0;
6981bdd6c0eSSue Gleeson 		}
6991bdd6c0eSSue Gleeson 
7001bdd6c0eSSue Gleeson 		if (ioc->ioc_dbuf_pool != NULL) {
7011bdd6c0eSSue Gleeson 			srpt_vmem_destroy(ioc->ioc_dbuf_pool);
7021bdd6c0eSSue Gleeson 		}
7031bdd6c0eSSue Gleeson 
7041bdd6c0eSSue Gleeson 		if (ioc->ioc_pd_hdl != NULL) {
7051bdd6c0eSSue Gleeson 			status = ibt_free_pd(ioc->ioc_ibt_hdl,
7061bdd6c0eSSue Gleeson 			    ioc->ioc_pd_hdl);
7071bdd6c0eSSue Gleeson 			if (status != IBT_SUCCESS) {
7081bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L1("ioc_fini, free PD"
7091bdd6c0eSSue Gleeson 				    " error (%d)", status);
7101bdd6c0eSSue Gleeson 			}
7111bdd6c0eSSue Gleeson 		}
7121bdd6c0eSSue Gleeson 
7131bdd6c0eSSue Gleeson 		status = ibt_close_hca(ioc->ioc_ibt_hdl);
7141bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
7151bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1(
7161bdd6c0eSSue Gleeson 			    "ioc_fini, close ioc error (%d)", status);
7171bdd6c0eSSue Gleeson 		}
7181bdd6c0eSSue Gleeson 	}
7191bdd6c0eSSue Gleeson 	rw_exit(&ioc->ioc_rwlock);
7201bdd6c0eSSue Gleeson 	rw_destroy(&ioc->ioc_rwlock);
7211bdd6c0eSSue Gleeson 	kmem_free(ioc, sizeof (srpt_ioc_t));
7221bdd6c0eSSue Gleeson }
7231bdd6c0eSSue Gleeson 
7241bdd6c0eSSue Gleeson /*
7251bdd6c0eSSue Gleeson  * srpt_ioc_port_active() - I/O Controller port active
7261bdd6c0eSSue Gleeson  */
7271bdd6c0eSSue Gleeson static void
srpt_ioc_port_active(ibt_async_event_t * event)7281bdd6c0eSSue Gleeson srpt_ioc_port_active(ibt_async_event_t *event)
7291bdd6c0eSSue Gleeson {
7301bdd6c0eSSue Gleeson 	ibt_status_t		status;
7311bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
7323baa0db4SSue Gleeson 	srpt_target_port_t	*tgt = NULL;
7333baa0db4SSue Gleeson 	boolean_t		online_target = B_FALSE;
7343baa0db4SSue Gleeson 	stmf_change_status_t	cstatus;
7351bdd6c0eSSue Gleeson 
7361bdd6c0eSSue Gleeson 	ASSERT(event != NULL);
7371bdd6c0eSSue Gleeson 
7381bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("ioc_port_active event handler, invoked");
7391bdd6c0eSSue Gleeson 
7401bdd6c0eSSue Gleeson 	/*
7411bdd6c0eSSue Gleeson 	 * Find the HCA in question and if the HCA has completed
7421bdd6c0eSSue Gleeson 	 * initialization, and the SRP Target service for the
7431bdd6c0eSSue Gleeson 	 * the I/O Controller exists, then bind this port.
7441bdd6c0eSSue Gleeson 	 */
7451bdd6c0eSSue Gleeson 	ioc = srpt_ioc_get(event->ev_hca_guid);
7461bdd6c0eSSue Gleeson 
7471bdd6c0eSSue Gleeson 	if (ioc == NULL) {
7481bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_port_active, I/O Controller not"
7491bdd6c0eSSue Gleeson 		    " active");
7501bdd6c0eSSue Gleeson 		return;
7511bdd6c0eSSue Gleeson 	}
7521bdd6c0eSSue Gleeson 
7533baa0db4SSue Gleeson 	tgt = ioc->ioc_tgt_port;
7543baa0db4SSue Gleeson 	if (tgt == NULL) {
7551bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_port_active, no I/O Controller target"
7561bdd6c0eSSue Gleeson 		    " undefined");
7571bdd6c0eSSue Gleeson 		return;
7581bdd6c0eSSue Gleeson 	}
7591bdd6c0eSSue Gleeson 
7601bdd6c0eSSue Gleeson 
7611bdd6c0eSSue Gleeson 	/*
7621bdd6c0eSSue Gleeson 	 * We take the target lock here to serialize this operation
7631bdd6c0eSSue Gleeson 	 * with any STMF initiated target state transitions.  If
7641bdd6c0eSSue Gleeson 	 * SRP is off-line then the service handle is NULL.
7651bdd6c0eSSue Gleeson 	 */
7663baa0db4SSue Gleeson 	mutex_enter(&tgt->tp_lock);
7671bdd6c0eSSue Gleeson 
7683baa0db4SSue Gleeson 	if (tgt->tp_ibt_svc_hdl != NULL) {
7693baa0db4SSue Gleeson 		status = srpt_ioc_svc_bind(tgt, event->ev_port);
7703baa0db4SSue Gleeson 		if ((status != IBT_SUCCESS) &&
7713baa0db4SSue Gleeson 		    (status != IBT_HCA_PORT_NOT_ACTIVE)) {
7721bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("ioc_port_active, bind failed (%d)",
7731bdd6c0eSSue Gleeson 			    status);
7741bdd6c0eSSue Gleeson 		}
7753baa0db4SSue Gleeson 	} else {
7763baa0db4SSue Gleeson 		/* if we were offline because of no ports, try onlining now */
7773baa0db4SSue Gleeson 		if ((tgt->tp_num_active_ports == 0) &&
7783baa0db4SSue Gleeson 		    (tgt->tp_requested_state != tgt->tp_state) &&
7793baa0db4SSue Gleeson 		    (tgt->tp_requested_state == SRPT_TGT_STATE_ONLINE)) {
7803baa0db4SSue Gleeson 			online_target = B_TRUE;
7813baa0db4SSue Gleeson 			cstatus.st_completion_status = STMF_SUCCESS;
7823baa0db4SSue Gleeson 			cstatus.st_additional_info = "port active";
7833baa0db4SSue Gleeson 		}
7843baa0db4SSue Gleeson 	}
7853baa0db4SSue Gleeson 
7863baa0db4SSue Gleeson 	mutex_exit(&tgt->tp_lock);
7873baa0db4SSue Gleeson 
7883baa0db4SSue Gleeson 	if (online_target) {
7893baa0db4SSue Gleeson 		stmf_status_t	ret;
7903baa0db4SSue Gleeson 
7913baa0db4SSue Gleeson 		ret = stmf_ctl(STMF_CMD_LPORT_ONLINE, tgt->tp_lport, &cstatus);
7923baa0db4SSue Gleeson 
7933baa0db4SSue Gleeson 		if (ret == STMF_SUCCESS) {
7943baa0db4SSue Gleeson 			SRPT_DPRINTF_L1("ioc_port_active, port %d active, "
7953baa0db4SSue Gleeson 			    "target %016llx online requested", event->ev_port,
7963baa0db4SSue Gleeson 			    (u_longlong_t)ioc->ioc_guid);
7973baa0db4SSue Gleeson 		} else if (ret != STMF_ALREADY) {
7983baa0db4SSue Gleeson 			SRPT_DPRINTF_L1("ioc_port_active, port %d active, "
7993baa0db4SSue Gleeson 			    "target %016llx failed online request: %d",
8003baa0db4SSue Gleeson 			    event->ev_port, (u_longlong_t)ioc->ioc_guid,
8013baa0db4SSue Gleeson 			    (int)ret);
8023baa0db4SSue Gleeson 		}
8031bdd6c0eSSue Gleeson 	}
8041bdd6c0eSSue Gleeson }
8051bdd6c0eSSue Gleeson 
8061bdd6c0eSSue Gleeson /*
8071bdd6c0eSSue Gleeson  * srpt_ioc_port_down()
8081bdd6c0eSSue Gleeson  */
8091bdd6c0eSSue Gleeson static void
srpt_ioc_port_down(ibt_async_event_t * event)8101bdd6c0eSSue Gleeson srpt_ioc_port_down(ibt_async_event_t *event)
8111bdd6c0eSSue Gleeson {
8121bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
8131bdd6c0eSSue Gleeson 	srpt_target_port_t	*tgt;
8141bdd6c0eSSue Gleeson 	srpt_channel_t		*ch;
8151bdd6c0eSSue Gleeson 	srpt_channel_t		*next_ch;
8163baa0db4SSue Gleeson 	boolean_t		offline_target = B_FALSE;
8173baa0db4SSue Gleeson 	stmf_change_status_t	cstatus;
8181bdd6c0eSSue Gleeson 
8191bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("ioc_port_down event handler, invoked");
8201bdd6c0eSSue Gleeson 
8211bdd6c0eSSue Gleeson 	/*
8221bdd6c0eSSue Gleeson 	 * Find the HCA in question and if the HCA has completed
8231bdd6c0eSSue Gleeson 	 * initialization, and the SRP Target service for the
8241bdd6c0eSSue Gleeson 	 * the I/O Controller exists, then logout initiators
8251bdd6c0eSSue Gleeson 	 * through this port.
8261bdd6c0eSSue Gleeson 	 */
8271bdd6c0eSSue Gleeson 	ioc = srpt_ioc_get(event->ev_hca_guid);
8281bdd6c0eSSue Gleeson 
8291bdd6c0eSSue Gleeson 	if (ioc == NULL) {
8301bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_port_down, I/O Controller not"
8311bdd6c0eSSue Gleeson 		    " active");
8321bdd6c0eSSue Gleeson 		return;
8331bdd6c0eSSue Gleeson 	}
8341bdd6c0eSSue Gleeson 
8351bdd6c0eSSue Gleeson 	/*
8361bdd6c0eSSue Gleeson 	 * We only have one target now, but we could go through all
8371bdd6c0eSSue Gleeson 	 * SCSI target ports if more are added.
8381bdd6c0eSSue Gleeson 	 */
8391bdd6c0eSSue Gleeson 	tgt = ioc->ioc_tgt_port;
8401bdd6c0eSSue Gleeson 	if (tgt == NULL) {
8411bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_port_down, no I/O Controller target"
8421bdd6c0eSSue Gleeson 		    " undefined");
8431bdd6c0eSSue Gleeson 		return;
8441bdd6c0eSSue Gleeson 	}
8451bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_lock);
8461bdd6c0eSSue Gleeson 
8471bdd6c0eSSue Gleeson 	/*
8481bdd6c0eSSue Gleeson 	 * For all channel's logged in through this port, initiate a
8491bdd6c0eSSue Gleeson 	 * disconnect.
8501bdd6c0eSSue Gleeson 	 */
8511bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_ch_list_lock);
8521bdd6c0eSSue Gleeson 	ch = list_head(&tgt->tp_ch_list);
8531bdd6c0eSSue Gleeson 	while (ch != NULL) {
8541bdd6c0eSSue Gleeson 		next_ch = list_next(&tgt->tp_ch_list, ch);
8551bdd6c0eSSue Gleeson 		if (ch->ch_session && (ch->ch_session->ss_hw_port ==
8561bdd6c0eSSue Gleeson 		    event->ev_port)) {
8571bdd6c0eSSue Gleeson 			srpt_ch_disconnect(ch);
8581bdd6c0eSSue Gleeson 		}
8591bdd6c0eSSue Gleeson 		ch = next_ch;
8601bdd6c0eSSue Gleeson 	}
8611bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_ch_list_lock);
8621bdd6c0eSSue Gleeson 
8633baa0db4SSue Gleeson 	tgt->tp_num_active_ports--;
8643baa0db4SSue Gleeson 
8653baa0db4SSue Gleeson 	/* if we have no active ports, take the target offline */
8663baa0db4SSue Gleeson 	if ((tgt->tp_num_active_ports == 0) &&
8673baa0db4SSue Gleeson 	    (tgt->tp_state == SRPT_TGT_STATE_ONLINE)) {
8683baa0db4SSue Gleeson 		cstatus.st_completion_status = STMF_SUCCESS;
8693baa0db4SSue Gleeson 		cstatus.st_additional_info = "no ports active";
8703baa0db4SSue Gleeson 		offline_target = B_TRUE;
8713baa0db4SSue Gleeson 	}
8723baa0db4SSue Gleeson 
8731bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_lock);
8743baa0db4SSue Gleeson 
8753baa0db4SSue Gleeson 	if (offline_target) {
8763baa0db4SSue Gleeson 		stmf_status_t	ret;
8773baa0db4SSue Gleeson 
8783baa0db4SSue Gleeson 		ret = stmf_ctl(STMF_CMD_LPORT_OFFLINE, tgt->tp_lport, &cstatus);
8793baa0db4SSue Gleeson 
8803baa0db4SSue Gleeson 		if (ret == STMF_SUCCESS) {
8813baa0db4SSue Gleeson 			SRPT_DPRINTF_L1("ioc_port_down, port %d down, target "
8823baa0db4SSue Gleeson 			    "%016llx offline requested", event->ev_port,
8833baa0db4SSue Gleeson 			    (u_longlong_t)ioc->ioc_guid);
8843baa0db4SSue Gleeson 		} else if (ret != STMF_ALREADY) {
8853baa0db4SSue Gleeson 			SRPT_DPRINTF_L1("ioc_port_down, port %d down, target "
8863baa0db4SSue Gleeson 			    "%016llx failed offline request: %d",
8873baa0db4SSue Gleeson 			    event->ev_port,
8883baa0db4SSue Gleeson 			    (u_longlong_t)ioc->ioc_guid, (int)ret);
8893baa0db4SSue Gleeson 		}
8903baa0db4SSue Gleeson 	}
8911bdd6c0eSSue Gleeson }
8921bdd6c0eSSue Gleeson 
8931bdd6c0eSSue Gleeson /*
8941bdd6c0eSSue Gleeson  * srpt_ioc_ib_async_hdlr - I/O Controller IB asynchronous events
8951bdd6c0eSSue Gleeson  */
8961bdd6c0eSSue Gleeson /* ARGSUSED */
8971bdd6c0eSSue Gleeson void
srpt_ioc_ib_async_hdlr(void * clnt,ibt_hca_hdl_t hdl,ibt_async_code_t code,ibt_async_event_t * event)8981bdd6c0eSSue Gleeson srpt_ioc_ib_async_hdlr(void *clnt, ibt_hca_hdl_t hdl,
8991bdd6c0eSSue Gleeson 	ibt_async_code_t code, ibt_async_event_t *event)
9001bdd6c0eSSue Gleeson {
9011bdd6c0eSSue Gleeson 	srpt_channel_t		*ch;
9021bdd6c0eSSue Gleeson 
9031bdd6c0eSSue Gleeson 	switch (code) {
9041bdd6c0eSSue Gleeson 	case IBT_EVENT_PORT_UP:
9051bdd6c0eSSue Gleeson 		srpt_ioc_port_active(event);
9061bdd6c0eSSue Gleeson 		break;
9071bdd6c0eSSue Gleeson 
9081bdd6c0eSSue Gleeson 	case IBT_ERROR_PORT_DOWN:
9091bdd6c0eSSue Gleeson 		srpt_ioc_port_down(event);
9101bdd6c0eSSue Gleeson 		break;
9111bdd6c0eSSue Gleeson 
9121bdd6c0eSSue Gleeson 	case IBT_HCA_ATTACH_EVENT:
913c3a558e7SSue Gleeson 		SRPT_DPRINTF_L2(
914c3a558e7SSue Gleeson 		    "ib_async_hdlr, received attach event for HCA 0x%016llx",
915c3a558e7SSue Gleeson 		    (u_longlong_t)event->ev_hca_guid);
9161bdd6c0eSSue Gleeson 
917c3a558e7SSue Gleeson 		rw_enter(&srpt_ctxt->sc_rwlock, RW_WRITER);
918c3a558e7SSue Gleeson 		srpt_ioc_attach_hca(event->ev_hca_guid, B_FALSE);
9191bdd6c0eSSue Gleeson 		rw_exit(&srpt_ctxt->sc_rwlock);
920c3a558e7SSue Gleeson 
9211bdd6c0eSSue Gleeson 		break;
9221bdd6c0eSSue Gleeson 
9231bdd6c0eSSue Gleeson 	case IBT_HCA_DETACH_EVENT:
9241bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1(
925c3a558e7SSue Gleeson 		    "ioc_iob_async_hdlr, received HCA_DETACH_EVENT for "
926c3a558e7SSue Gleeson 		    "HCA 0x%016llx",
927c3a558e7SSue Gleeson 		    (u_longlong_t)event->ev_hca_guid);
928c3a558e7SSue Gleeson 
929c3a558e7SSue Gleeson 		rw_enter(&srpt_ctxt->sc_rwlock, RW_WRITER);
930c3a558e7SSue Gleeson 		srpt_ioc_detach_hca(event->ev_hca_guid);
931c3a558e7SSue Gleeson 		rw_exit(&srpt_ctxt->sc_rwlock);
932c3a558e7SSue Gleeson 
9331bdd6c0eSSue Gleeson 		break;
9341bdd6c0eSSue Gleeson 
9351bdd6c0eSSue Gleeson 	case IBT_EVENT_EMPTY_CHAN:
9361bdd6c0eSSue Gleeson 		/* Channel in ERROR state is now empty */
9371bdd6c0eSSue Gleeson 		ch = (srpt_channel_t *)ibt_get_chan_private(event->ev_chan_hdl);
9381bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3(
9391bdd6c0eSSue Gleeson 		    "ioc_iob_async_hdlr, received empty channel error on %p",
9401bdd6c0eSSue Gleeson 		    (void *)ch);
9411bdd6c0eSSue Gleeson 		break;
9421bdd6c0eSSue Gleeson 
9431bdd6c0eSSue Gleeson 	default:
9441bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_ib_async_hdlr, event not "
9451bdd6c0eSSue Gleeson 		    "handled (%d)", code);
9461bdd6c0eSSue Gleeson 		break;
9471bdd6c0eSSue Gleeson 	}
9481bdd6c0eSSue Gleeson }
9491bdd6c0eSSue Gleeson 
9501bdd6c0eSSue Gleeson /*
9511bdd6c0eSSue Gleeson  * srpt_ioc_svc_bind()
9521bdd6c0eSSue Gleeson  */
9531bdd6c0eSSue Gleeson ibt_status_t
srpt_ioc_svc_bind(srpt_target_port_t * tgt,uint_t portnum)9541bdd6c0eSSue Gleeson srpt_ioc_svc_bind(srpt_target_port_t *tgt, uint_t portnum)
9551bdd6c0eSSue Gleeson {
9561bdd6c0eSSue Gleeson 	ibt_status_t		status;
9571bdd6c0eSSue Gleeson 	srpt_hw_port_t		*port;
9581bdd6c0eSSue Gleeson 	ibt_hca_portinfo_t	*portinfo;
9591bdd6c0eSSue Gleeson 	uint_t			qportinfo_sz;
9601bdd6c0eSSue Gleeson 	uint_t			qportnum;
9611bdd6c0eSSue Gleeson 	ib_gid_t		new_gid;
9621bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
963191c289bSCharles Ting 	srpt_session_t		sess;
9641bdd6c0eSSue Gleeson 
9651bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
9661bdd6c0eSSue Gleeson 	ASSERT(tgt->tp_ioc != NULL);
9671bdd6c0eSSue Gleeson 	ioc = tgt->tp_ioc;
9681bdd6c0eSSue Gleeson 
9691bdd6c0eSSue Gleeson 	if (tgt->tp_ibt_svc_hdl == NULL) {
9701bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_bind, NULL SCSI target port"
9711bdd6c0eSSue Gleeson 		    " service");
9721bdd6c0eSSue Gleeson 		return (IBT_INVALID_PARAM);
9731bdd6c0eSSue Gleeson 	}
9741bdd6c0eSSue Gleeson 
9751bdd6c0eSSue Gleeson 	if (portnum == 0 || portnum > tgt->tp_nports) {
9761bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_bind, bad port (%d)", portnum);
9771bdd6c0eSSue Gleeson 		return (IBT_INVALID_PARAM);
9781bdd6c0eSSue Gleeson 	}
9791bdd6c0eSSue Gleeson 	status = ibt_query_hca_ports(ioc->ioc_ibt_hdl, portnum,
9801bdd6c0eSSue Gleeson 	    &portinfo, &qportnum, &qportinfo_sz);
9811bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
9821bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("ioc_svc_bind, query port error (%d)",
9831bdd6c0eSSue Gleeson 		    portnum);
9841bdd6c0eSSue Gleeson 		return (IBT_INVALID_PARAM);
9851bdd6c0eSSue Gleeson 	}
9861bdd6c0eSSue Gleeson 
9871bdd6c0eSSue Gleeson 	ASSERT(portinfo != NULL);
9881bdd6c0eSSue Gleeson 
9891bdd6c0eSSue Gleeson 	/*
9901bdd6c0eSSue Gleeson 	 * If port is not active do nothing, caller should attempt to bind
9911bdd6c0eSSue Gleeson 	 * after the port goes active.
9921bdd6c0eSSue Gleeson 	 */
9931bdd6c0eSSue Gleeson 	if (portinfo->p_linkstate != IBT_PORT_ACTIVE) {
9941bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_bind, port %d not in active state",
9951bdd6c0eSSue Gleeson 		    portnum);
9961bdd6c0eSSue Gleeson 		ibt_free_portinfo(portinfo, qportinfo_sz);
9971bdd6c0eSSue Gleeson 		return (IBT_HCA_PORT_NOT_ACTIVE);
9981bdd6c0eSSue Gleeson 	}
9991bdd6c0eSSue Gleeson 
10001bdd6c0eSSue Gleeson 	port    = &tgt->tp_hw_port[portnum-1];
10011bdd6c0eSSue Gleeson 	new_gid = portinfo->p_sgid_tbl[0];
10021bdd6c0eSSue Gleeson 	ibt_free_portinfo(portinfo, qportinfo_sz);
10031bdd6c0eSSue Gleeson 
10041bdd6c0eSSue Gleeson 	/*
10051bdd6c0eSSue Gleeson 	 * If previously bound and the port GID has changed,
1006285c05bcSSue Gleeson 	 * unbind the old GID.
10071bdd6c0eSSue Gleeson 	 */
10081bdd6c0eSSue Gleeson 	if (port->hwp_bind_hdl != NULL) {
10091bdd6c0eSSue Gleeson 		if (new_gid.gid_guid != port->hwp_gid.gid_guid ||
10101bdd6c0eSSue Gleeson 		    new_gid.gid_prefix != port->hwp_gid.gid_prefix) {
10111bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("ioc_svc_bind, unregister current"
10121bdd6c0eSSue Gleeson 			    " bind");
1013aedf2b3bSsrivijitha dugganapalli 			(void) ibt_unbind_service(tgt->tp_ibt_svc_hdl,
10141bdd6c0eSSue Gleeson 			    port->hwp_bind_hdl);
10151bdd6c0eSSue Gleeson 			port->hwp_bind_hdl = NULL;
1016285c05bcSSue Gleeson 		} else {
1017285c05bcSSue Gleeson 			SRPT_DPRINTF_L2("ioc_svc_bind, port %d already bound",
1018285c05bcSSue Gleeson 			    portnum);
10191bdd6c0eSSue Gleeson 		}
10201bdd6c0eSSue Gleeson 	}
10211bdd6c0eSSue Gleeson 
1022285c05bcSSue Gleeson 	/* bind the new port GID */
1023285c05bcSSue Gleeson 	if (port->hwp_bind_hdl == NULL) {
1024285c05bcSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_bind, bind service, %016llx:%016llx",
1025285c05bcSSue Gleeson 		    (u_longlong_t)new_gid.gid_prefix,
1026285c05bcSSue Gleeson 		    (u_longlong_t)new_gid.gid_guid);
1027285c05bcSSue Gleeson 
1028285c05bcSSue Gleeson 		/*
1029285c05bcSSue Gleeson 		 * Pass SCSI Target Port as CM private data, the target will
1030285c05bcSSue Gleeson 		 * always exist while this service is bound.
1031285c05bcSSue Gleeson 		 */
1032285c05bcSSue Gleeson 		status = ibt_bind_service(tgt->tp_ibt_svc_hdl, new_gid, NULL,
1033285c05bcSSue Gleeson 		    tgt, &port->hwp_bind_hdl);
1034285c05bcSSue Gleeson 		if (status != IBT_SUCCESS && status != IBT_CM_SERVICE_EXISTS) {
1035285c05bcSSue Gleeson 			SRPT_DPRINTF_L1("ioc_svc_bind, bind error (%d)",
1036285c05bcSSue Gleeson 			    status);
1037285c05bcSSue Gleeson 			return (status);
1038285c05bcSSue Gleeson 		}
1039285c05bcSSue Gleeson 		port->hwp_gid.gid_prefix = new_gid.gid_prefix;
1040285c05bcSSue Gleeson 		port->hwp_gid.gid_guid = new_gid.gid_guid;
10411bdd6c0eSSue Gleeson 	}
1042285c05bcSSue Gleeson 
1043285c05bcSSue Gleeson 	/* port is now active */
10443baa0db4SSue Gleeson 	tgt->tp_num_active_ports++;
1045191c289bSCharles Ting 
1046191c289bSCharles Ting 	/* setting up a transient structure for the dtrace probe. */
1047191c289bSCharles Ting 	bzero(&sess, sizeof (srpt_session_t));
1048191c289bSCharles Ting 	ALIAS_STR(sess.ss_t_gid, new_gid.gid_prefix, new_gid.gid_guid);
1049191c289bSCharles Ting 	EUI_STR(sess.ss_t_name, tgt->tp_ibt_svc_id);
1050191c289bSCharles Ting 
1051191c289bSCharles Ting 	DTRACE_SRP_1(service__up, srpt_session_t, &sess);
10521bdd6c0eSSue Gleeson 
10531bdd6c0eSSue Gleeson 	return (IBT_SUCCESS);
10541bdd6c0eSSue Gleeson }
10551bdd6c0eSSue Gleeson 
10561bdd6c0eSSue Gleeson /*
10571bdd6c0eSSue Gleeson  * srpt_ioc_svc_unbind()
10581bdd6c0eSSue Gleeson  */
10591bdd6c0eSSue Gleeson void
srpt_ioc_svc_unbind(srpt_target_port_t * tgt,uint_t portnum)10601bdd6c0eSSue Gleeson srpt_ioc_svc_unbind(srpt_target_port_t *tgt, uint_t portnum)
10611bdd6c0eSSue Gleeson {
10621bdd6c0eSSue Gleeson 	srpt_hw_port_t		*port;
1063191c289bSCharles Ting 	srpt_session_t		sess;
10643baa0db4SSue Gleeson 	ibt_status_t		ret;
10651bdd6c0eSSue Gleeson 
10661bdd6c0eSSue Gleeson 	if (tgt == NULL) {
10671bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_unbind, SCSI target does not exist");
10681bdd6c0eSSue Gleeson 		return;
10691bdd6c0eSSue Gleeson 	}
10701bdd6c0eSSue Gleeson 
10711bdd6c0eSSue Gleeson 	if (portnum == 0 || portnum > tgt->tp_nports) {
10721bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_unbind, bad port (%d)", portnum);
10731bdd6c0eSSue Gleeson 		return;
10741bdd6c0eSSue Gleeson 	}
10751bdd6c0eSSue Gleeson 	port = &tgt->tp_hw_port[portnum-1];
10761bdd6c0eSSue Gleeson 
1077191c289bSCharles Ting 	/* setting up a transient structure for the dtrace probe. */
1078191c289bSCharles Ting 	bzero(&sess, sizeof (srpt_session_t));
1079191c289bSCharles Ting 	ALIAS_STR(sess.ss_t_gid, port->hwp_gid.gid_prefix,
1080191c289bSCharles Ting 	    port->hwp_gid.gid_guid);
1081191c289bSCharles Ting 	EUI_STR(sess.ss_t_name, tgt->tp_ibt_svc_id);
1082191c289bSCharles Ting 
1083191c289bSCharles Ting 	DTRACE_SRP_1(service__down, srpt_session_t, &sess);
1084191c289bSCharles Ting 
10851bdd6c0eSSue Gleeson 	if (tgt->tp_ibt_svc_hdl != NULL && port->hwp_bind_hdl != NULL) {
10861bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_unbind, unregister current bind");
10873baa0db4SSue Gleeson 		ret = ibt_unbind_service(tgt->tp_ibt_svc_hdl,
1088aedf2b3bSsrivijitha dugganapalli 		    port->hwp_bind_hdl);
10893baa0db4SSue Gleeson 		if (ret != IBT_SUCCESS) {
10903baa0db4SSue Gleeson 			SRPT_DPRINTF_L1(
10913baa0db4SSue Gleeson 			    "ioc_svc_unbind, unregister port %d failed: %d",
10923baa0db4SSue Gleeson 			    portnum, ret);
10933baa0db4SSue Gleeson 		} else {
10943baa0db4SSue Gleeson 			port->hwp_bind_hdl = NULL;
10953baa0db4SSue Gleeson 			port->hwp_gid.gid_prefix = 0;
10963baa0db4SSue Gleeson 			port->hwp_gid.gid_guid = 0;
10973baa0db4SSue Gleeson 		}
10981bdd6c0eSSue Gleeson 	}
10991bdd6c0eSSue Gleeson }
11001bdd6c0eSSue Gleeson 
11011bdd6c0eSSue Gleeson /*
11021bdd6c0eSSue Gleeson  * srpt_ioc_svc_unbind_all()
11031bdd6c0eSSue Gleeson  */
11041bdd6c0eSSue Gleeson void
srpt_ioc_svc_unbind_all(srpt_target_port_t * tgt)11051bdd6c0eSSue Gleeson srpt_ioc_svc_unbind_all(srpt_target_port_t *tgt)
11061bdd6c0eSSue Gleeson {
11071bdd6c0eSSue Gleeson 	uint_t		portnum;
11081bdd6c0eSSue Gleeson 
11091bdd6c0eSSue Gleeson 	if (tgt == NULL) {
11101bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_svc_unbind_all, NULL SCSI target port"
11111bdd6c0eSSue Gleeson 		    " specified");
11121bdd6c0eSSue Gleeson 		return;
11131bdd6c0eSSue Gleeson 	}
11141bdd6c0eSSue Gleeson 	for (portnum = 1; portnum <= tgt->tp_nports; portnum++) {
11151bdd6c0eSSue Gleeson 		srpt_ioc_svc_unbind(tgt, portnum);
11161bdd6c0eSSue Gleeson 	}
11171bdd6c0eSSue Gleeson }
11181bdd6c0eSSue Gleeson 
11191bdd6c0eSSue Gleeson /*
11201bdd6c0eSSue Gleeson  * srpt_ioc_get_locked()
11211bdd6c0eSSue Gleeson  *
11221bdd6c0eSSue Gleeson  * Requires srpt_ctxt->rw_lock be held outside of call.
11231bdd6c0eSSue Gleeson  */
11241bdd6c0eSSue Gleeson srpt_ioc_t *
srpt_ioc_get_locked(ib_guid_t guid)11251bdd6c0eSSue Gleeson srpt_ioc_get_locked(ib_guid_t guid)
11261bdd6c0eSSue Gleeson {
11271bdd6c0eSSue Gleeson 	srpt_ioc_t	*ioc;
11281bdd6c0eSSue Gleeson 
11291bdd6c0eSSue Gleeson 	ioc = list_head(&srpt_ctxt->sc_ioc_list);
11301bdd6c0eSSue Gleeson 	while (ioc != NULL) {
11311bdd6c0eSSue Gleeson 		if (ioc->ioc_guid == guid) {
11321bdd6c0eSSue Gleeson 			break;
11331bdd6c0eSSue Gleeson 		}
11341bdd6c0eSSue Gleeson 		ioc = list_next(&srpt_ctxt->sc_ioc_list, ioc);
11351bdd6c0eSSue Gleeson 	}
11361bdd6c0eSSue Gleeson 	return (ioc);
11371bdd6c0eSSue Gleeson }
11381bdd6c0eSSue Gleeson 
11391bdd6c0eSSue Gleeson /*
11401bdd6c0eSSue Gleeson  * srpt_ioc_get()
11411bdd6c0eSSue Gleeson  */
11421bdd6c0eSSue Gleeson srpt_ioc_t *
srpt_ioc_get(ib_guid_t guid)11431bdd6c0eSSue Gleeson srpt_ioc_get(ib_guid_t guid)
11441bdd6c0eSSue Gleeson {
11451bdd6c0eSSue Gleeson 	srpt_ioc_t	*ioc;
11461bdd6c0eSSue Gleeson 
11471bdd6c0eSSue Gleeson 	rw_enter(&srpt_ctxt->sc_rwlock, RW_READER);
11481bdd6c0eSSue Gleeson 	ioc = srpt_ioc_get_locked(guid);
11491bdd6c0eSSue Gleeson 	rw_exit(&srpt_ctxt->sc_rwlock);
11501bdd6c0eSSue Gleeson 	return (ioc);
11511bdd6c0eSSue Gleeson }
11521bdd6c0eSSue Gleeson 
11531bdd6c0eSSue Gleeson /*
11541bdd6c0eSSue Gleeson  * srpt_ioc_post_recv_iu()
11551bdd6c0eSSue Gleeson  */
11561bdd6c0eSSue Gleeson ibt_status_t
srpt_ioc_post_recv_iu(srpt_ioc_t * ioc,srpt_iu_t * iu)11571bdd6c0eSSue Gleeson srpt_ioc_post_recv_iu(srpt_ioc_t *ioc, srpt_iu_t *iu)
11581bdd6c0eSSue Gleeson {
11591bdd6c0eSSue Gleeson 	ibt_status_t		status;
11601bdd6c0eSSue Gleeson 	ibt_recv_wr_t		wr;
11611bdd6c0eSSue Gleeson 	uint_t			posted;
11621bdd6c0eSSue Gleeson 
11631bdd6c0eSSue Gleeson 	ASSERT(ioc != NULL);
11641bdd6c0eSSue Gleeson 	ASSERT(iu != NULL);
11651bdd6c0eSSue Gleeson 
11661bdd6c0eSSue Gleeson 	wr.wr_id  = (ibt_wrid_t)(uintptr_t)iu;
11671bdd6c0eSSue Gleeson 	wr.wr_nds = 1;
11681bdd6c0eSSue Gleeson 	wr.wr_sgl = &iu->iu_sge;
11691bdd6c0eSSue Gleeson 	posted    = 0;
11701bdd6c0eSSue Gleeson 
11711bdd6c0eSSue Gleeson 	status = ibt_post_srq(ioc->ioc_srq_hdl, &wr, 1, &posted);
11721bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
11731bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_post_recv_iu, post error (%d)",
11741bdd6c0eSSue Gleeson 		    status);
11751bdd6c0eSSue Gleeson 	}
11761bdd6c0eSSue Gleeson 	return (status);
11771bdd6c0eSSue Gleeson }
11781bdd6c0eSSue Gleeson 
11791bdd6c0eSSue Gleeson /*
11801bdd6c0eSSue Gleeson  * srpt_ioc_repost_recv_iu()
11811bdd6c0eSSue Gleeson  */
11821bdd6c0eSSue Gleeson void
srpt_ioc_repost_recv_iu(srpt_ioc_t * ioc,srpt_iu_t * iu)11831bdd6c0eSSue Gleeson srpt_ioc_repost_recv_iu(srpt_ioc_t *ioc, srpt_iu_t *iu)
11841bdd6c0eSSue Gleeson {
11851bdd6c0eSSue Gleeson 	srpt_channel_t		*ch;
11861bdd6c0eSSue Gleeson 	ibt_status_t		status;
11871bdd6c0eSSue Gleeson 
11881bdd6c0eSSue Gleeson 	ASSERT(iu != NULL);
11891bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&iu->iu_lock));
11901bdd6c0eSSue Gleeson 
11911bdd6c0eSSue Gleeson 	/*
11921bdd6c0eSSue Gleeson 	 * Some additional sanity checks while in debug state, all STMF
11931bdd6c0eSSue Gleeson 	 * related task activities should be complete prior to returning
11941bdd6c0eSSue Gleeson 	 * this IU to the available pool.
11951bdd6c0eSSue Gleeson 	 */
11961bdd6c0eSSue Gleeson 	ASSERT(iu->iu_stmf_task == NULL);
11971bdd6c0eSSue Gleeson 	ASSERT(iu->iu_sq_posted_cnt == 0);
11981bdd6c0eSSue Gleeson 
11991bdd6c0eSSue Gleeson 	ch = iu->iu_ch;
12001bdd6c0eSSue Gleeson 	iu->iu_ch = NULL;
12011bdd6c0eSSue Gleeson 	iu->iu_num_rdescs = 0;
12021bdd6c0eSSue Gleeson 	iu->iu_rdescs = NULL;
12031bdd6c0eSSue Gleeson 	iu->iu_tot_xfer_len = 0;
12041bdd6c0eSSue Gleeson 	iu->iu_tag = 0;
12051bdd6c0eSSue Gleeson 	iu->iu_flags = 0;
12061bdd6c0eSSue Gleeson 	iu->iu_sq_posted_cnt = 0;
12071bdd6c0eSSue Gleeson 
12081bdd6c0eSSue Gleeson 	status = srpt_ioc_post_recv_iu(ioc, iu);
12091bdd6c0eSSue Gleeson 
12101bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
12111bdd6c0eSSue Gleeson 		/*
12121bdd6c0eSSue Gleeson 		 * Very bad, we should initiate a shutdown of the I/O
12131bdd6c0eSSue Gleeson 		 * Controller here, off-lining any targets associated
12141bdd6c0eSSue Gleeson 		 * with this I/O Controller (and therefore disconnecting
12151bdd6c0eSSue Gleeson 		 * any logins that remain).
12161bdd6c0eSSue Gleeson 		 *
12171bdd6c0eSSue Gleeson 		 * In practice this should never happen so we put
12181bdd6c0eSSue Gleeson 		 * the code near the bottom of the implementation list.
12191bdd6c0eSSue Gleeson 		 */
12201bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L0("ioc_repost_recv_iu, error RX IU (%d)",
12211bdd6c0eSSue Gleeson 		    status);
12221bdd6c0eSSue Gleeson 		ASSERT(0);
12231bdd6c0eSSue Gleeson 	} else if (ch != NULL) {
12241bdd6c0eSSue Gleeson 		atomic_inc_32(&ch->ch_req_lim_delta);
12251bdd6c0eSSue Gleeson 	}
12261bdd6c0eSSue Gleeson }
12271bdd6c0eSSue Gleeson 
12281bdd6c0eSSue Gleeson /*
12291bdd6c0eSSue Gleeson  * srpt_ioc_init_profile()
12301bdd6c0eSSue Gleeson  *
12311bdd6c0eSSue Gleeson  * SRP I/O Controller serialization lock must be held when this
12321bdd6c0eSSue Gleeson  * routine is invoked.
12331bdd6c0eSSue Gleeson  */
12341bdd6c0eSSue Gleeson void
srpt_ioc_init_profile(srpt_ioc_t * ioc)12351bdd6c0eSSue Gleeson srpt_ioc_init_profile(srpt_ioc_t *ioc)
12361bdd6c0eSSue Gleeson {
12371bdd6c0eSSue Gleeson 	srpt_ioc_opcap_mask_t		capmask = {0};
12381bdd6c0eSSue Gleeson 
12391bdd6c0eSSue Gleeson 	ASSERT(ioc != NULL);
12401bdd6c0eSSue Gleeson 
12411bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_guid = h2b64(ioc->ioc_guid);
12421bdd6c0eSSue Gleeson 	(void) memcpy(ioc->ioc_profile.ioc_id_string,
12431bdd6c0eSSue Gleeson 	    "Solaris SRP Target 0.9a", 23);
12441bdd6c0eSSue Gleeson 
12451bdd6c0eSSue Gleeson 	/*
12461bdd6c0eSSue Gleeson 	 * Note vendor ID and subsystem ID are 24 bit values.  Low order
12471bdd6c0eSSue Gleeson 	 * 8 bits in vendor ID field is slot and is initialized to zero.
12481bdd6c0eSSue Gleeson 	 * Low order 8 bits of subsystem ID is a reserved field and
12491bdd6c0eSSue Gleeson 	 * initialized to zero.
12501bdd6c0eSSue Gleeson 	 */
12511bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_vendorid =
12521bdd6c0eSSue Gleeson 	    h2b32((uint32_t)(ioc->ioc_attr.hca_vendor_id << 8));
12531bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_deviceid =
12541bdd6c0eSSue Gleeson 	    h2b32((uint32_t)ioc->ioc_attr.hca_device_id);
12551bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_device_ver =
12561bdd6c0eSSue Gleeson 	    h2b16((uint16_t)ioc->ioc_attr.hca_version_id);
12571bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_subsys_vendorid =
12581bdd6c0eSSue Gleeson 	    h2b32((uint32_t)(ioc->ioc_attr.hca_vendor_id << 8));
12591bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_subsys_id = h2b32(0);
12601bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_io_class = h2b16(SRP_REV_16A_IO_CLASS);
12611bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_io_subclass = h2b16(SRP_IO_SUBCLASS);
12621bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_protocol = h2b16(SRP_PROTOCOL);
12631bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_protocol_ver = h2b16(SRP_PROTOCOL_VERSION);
12641bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_send_msg_qdepth = h2b16(srpt_send_msg_depth);
12651bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_rdma_read_qdepth =
12661bdd6c0eSSue Gleeson 	    ioc->ioc_attr.hca_max_rdma_out_chan;
1267989ca640SSue Gleeson 	ioc->ioc_profile.ioc_send_msg_sz = h2b32(srpt_iu_size);
12681bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_rdma_xfer_sz = h2b32(SRPT_DEFAULT_MAX_RDMA_SIZE);
12691bdd6c0eSSue Gleeson 
12701bdd6c0eSSue Gleeson 	capmask.bits.st = 1;	/* Messages can be sent to IOC */
12711bdd6c0eSSue Gleeson 	capmask.bits.sf = 1;	/* Messages can be sent from IOC */
12721bdd6c0eSSue Gleeson 	capmask.bits.rf = 1;	/* RDMA Reads can be sent from IOC */
12731bdd6c0eSSue Gleeson 	capmask.bits.wf = 1;	/* RDMA Writes can be sent from IOC */
12741bdd6c0eSSue Gleeson 	ioc->ioc_profile.ioc_ctrl_opcap_mask = capmask.mask;
12751bdd6c0eSSue Gleeson 
12761bdd6c0eSSue Gleeson 	/*
12771bdd6c0eSSue Gleeson 	 * We currently only have one target, but if we had a list we would
12781bdd6c0eSSue Gleeson 	 * go through that list and only count those that are ONLINE when
12791bdd6c0eSSue Gleeson 	 * setting the services count and entries.
12801bdd6c0eSSue Gleeson 	 */
12811bdd6c0eSSue Gleeson 	if (ioc->ioc_tgt_port->tp_srp_enabled) {
12821bdd6c0eSSue Gleeson 		ioc->ioc_profile.ioc_service_entries = 1;
12831bdd6c0eSSue Gleeson 		ioc->ioc_svc.srv_id = h2b64(ioc->ioc_guid);
12841bdd6c0eSSue Gleeson 		(void) snprintf((char *)ioc->ioc_svc.srv_name,
12851bdd6c0eSSue Gleeson 		    IB_DM_MAX_SVC_NAME_LEN, "SRP.T10:%016llx",
12861bdd6c0eSSue Gleeson 		    (u_longlong_t)ioc->ioc_guid);
12871bdd6c0eSSue Gleeson 	} else {
12881bdd6c0eSSue Gleeson 		ioc->ioc_profile.ioc_service_entries = 0;
12891bdd6c0eSSue Gleeson 		ioc->ioc_svc.srv_id = 0;
12901bdd6c0eSSue Gleeson 	}
12911bdd6c0eSSue Gleeson }
12921bdd6c0eSSue Gleeson 
12931bdd6c0eSSue Gleeson /*
12941bdd6c0eSSue Gleeson  * srpt_ioc_ds_alloc_dbuf()
12951bdd6c0eSSue Gleeson  */
12961bdd6c0eSSue Gleeson /* ARGSUSED */
12971bdd6c0eSSue Gleeson stmf_data_buf_t *
srpt_ioc_ds_alloc_dbuf(struct scsi_task * task,uint32_t size,uint32_t * pminsize,uint32_t flags)12981bdd6c0eSSue Gleeson srpt_ioc_ds_alloc_dbuf(struct scsi_task *task, uint32_t size,
12991bdd6c0eSSue Gleeson 	uint32_t *pminsize, uint32_t flags)
13001bdd6c0eSSue Gleeson {
13011bdd6c0eSSue Gleeson 	srpt_iu_t		*iu;
13021bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
13031bdd6c0eSSue Gleeson 	srpt_ds_dbuf_t		*dbuf;
13041bdd6c0eSSue Gleeson 	stmf_data_buf_t		*stmf_dbuf;
13051bdd6c0eSSue Gleeson 	void			*buf;
13061bdd6c0eSSue Gleeson 	srpt_mr_t		mr;
13071bdd6c0eSSue Gleeson 
13081bdd6c0eSSue Gleeson 	ASSERT(task != NULL);
13091bdd6c0eSSue Gleeson 	iu  = task->task_port_private;
13101bdd6c0eSSue Gleeson 	ioc = iu->iu_ioc;
13111bdd6c0eSSue Gleeson 
13121bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("ioc_ds_alloc_dbuf, invoked ioc(%p)"
13131bdd6c0eSSue Gleeson 	    " size(%d), flags(%x)",
13141bdd6c0eSSue Gleeson 	    (void *)ioc, size, flags);
13151bdd6c0eSSue Gleeson 
13161bdd6c0eSSue Gleeson 	buf = srpt_vmem_alloc(ioc->ioc_dbuf_pool, size);
13171bdd6c0eSSue Gleeson 	if (buf == NULL) {
13181bdd6c0eSSue Gleeson 		return (NULL);
13191bdd6c0eSSue Gleeson 	}
13201bdd6c0eSSue Gleeson 
13211bdd6c0eSSue Gleeson 	if (srpt_vmem_mr(ioc->ioc_dbuf_pool, buf, size, &mr) != 0) {
13221bdd6c0eSSue Gleeson 		goto stmf_alloc_err;
13231bdd6c0eSSue Gleeson 	}
13241bdd6c0eSSue Gleeson 
13251bdd6c0eSSue Gleeson 	stmf_dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, sizeof (srpt_ds_dbuf_t),
13261bdd6c0eSSue Gleeson 	    0);
13271bdd6c0eSSue Gleeson 	if (stmf_dbuf == NULL) {
13281bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("ioc_ds_alloc_dbuf, stmf_alloc failed");
13291bdd6c0eSSue Gleeson 		goto stmf_alloc_err;
13301bdd6c0eSSue Gleeson 	}
13311bdd6c0eSSue Gleeson 
13321bdd6c0eSSue Gleeson 	dbuf = stmf_dbuf->db_port_private;
13331bdd6c0eSSue Gleeson 	dbuf->db_stmf_buf = stmf_dbuf;
13341bdd6c0eSSue Gleeson 	dbuf->db_mr_hdl = mr.mr_hdl;
13351bdd6c0eSSue Gleeson 	dbuf->db_ioc = ioc;
13361bdd6c0eSSue Gleeson 	dbuf->db_sge.ds_va = mr.mr_va;
13371bdd6c0eSSue Gleeson 	dbuf->db_sge.ds_key = mr.mr_lkey;
13381bdd6c0eSSue Gleeson 	dbuf->db_sge.ds_len = size;
13391bdd6c0eSSue Gleeson 
13401bdd6c0eSSue Gleeson 	stmf_dbuf->db_buf_size = size;
13411bdd6c0eSSue Gleeson 	stmf_dbuf->db_data_size = size;
13421bdd6c0eSSue Gleeson 	stmf_dbuf->db_relative_offset = 0;
13431bdd6c0eSSue Gleeson 	stmf_dbuf->db_flags = 0;
13441bdd6c0eSSue Gleeson 	stmf_dbuf->db_xfer_status = 0;
13451bdd6c0eSSue Gleeson 	stmf_dbuf->db_sglist_length = 1;
13461bdd6c0eSSue Gleeson 	stmf_dbuf->db_sglist[0].seg_addr = buf;
13471bdd6c0eSSue Gleeson 	stmf_dbuf->db_sglist[0].seg_length = size;
13481bdd6c0eSSue Gleeson 
13491bdd6c0eSSue Gleeson 	return (stmf_dbuf);
13501bdd6c0eSSue Gleeson 
13511bdd6c0eSSue Gleeson buf_mr_err:
13521bdd6c0eSSue Gleeson 	stmf_free(stmf_dbuf);
13531bdd6c0eSSue Gleeson 
13541bdd6c0eSSue Gleeson stmf_alloc_err:
13551bdd6c0eSSue Gleeson 	srpt_vmem_free(ioc->ioc_dbuf_pool, buf, size);
13561bdd6c0eSSue Gleeson 
13571bdd6c0eSSue Gleeson 	return (NULL);
13581bdd6c0eSSue Gleeson }
13591bdd6c0eSSue Gleeson 
13601bdd6c0eSSue Gleeson void
srpt_ioc_ds_free_dbuf(struct stmf_dbuf_store * ds,stmf_data_buf_t * dbuf)13611bdd6c0eSSue Gleeson srpt_ioc_ds_free_dbuf(struct stmf_dbuf_store *ds,
13621bdd6c0eSSue Gleeson 	stmf_data_buf_t *dbuf)
13631bdd6c0eSSue Gleeson {
13641bdd6c0eSSue Gleeson 	srpt_ioc_t	*ioc;
13651bdd6c0eSSue Gleeson 
13661bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("ioc_ds_free_dbuf, invoked buf (%p)",
13671bdd6c0eSSue Gleeson 	    (void *)dbuf);
13681bdd6c0eSSue Gleeson 	ioc = ds->ds_port_private;
13691bdd6c0eSSue Gleeson 
13701bdd6c0eSSue Gleeson 	srpt_vmem_free(ioc->ioc_dbuf_pool, dbuf->db_sglist[0].seg_addr,
13711bdd6c0eSSue Gleeson 	    dbuf->db_buf_size);
13721bdd6c0eSSue Gleeson 	stmf_free(dbuf);
13731bdd6c0eSSue Gleeson }
13741bdd6c0eSSue Gleeson 
13751bdd6c0eSSue Gleeson /* Memory arena routines */
13761bdd6c0eSSue Gleeson 
13771bdd6c0eSSue Gleeson static srpt_vmem_pool_t *
srpt_vmem_create(const char * name,srpt_ioc_t * ioc,ib_memlen_t chunksize,uint64_t maxsize,ibt_mr_flags_t flags)13781bdd6c0eSSue Gleeson srpt_vmem_create(const char *name, srpt_ioc_t *ioc, ib_memlen_t chunksize,
13791bdd6c0eSSue Gleeson     uint64_t maxsize, ibt_mr_flags_t flags)
13801bdd6c0eSSue Gleeson {
13811bdd6c0eSSue Gleeson 	srpt_mr_t		*chunk;
13821bdd6c0eSSue Gleeson 	srpt_vmem_pool_t	*result;
13831bdd6c0eSSue Gleeson 
13841bdd6c0eSSue Gleeson 	ASSERT(chunksize <= maxsize);
13851bdd6c0eSSue Gleeson 
13861bdd6c0eSSue Gleeson 	result = kmem_zalloc(sizeof (srpt_vmem_pool_t), KM_SLEEP);
13871bdd6c0eSSue Gleeson 
13881bdd6c0eSSue Gleeson 	result->svp_ioc = ioc;
13891bdd6c0eSSue Gleeson 	result->svp_chunksize = chunksize;
13901bdd6c0eSSue Gleeson 	result->svp_max_size = maxsize;
13911bdd6c0eSSue Gleeson 	result->svp_flags = flags;
13921bdd6c0eSSue Gleeson 
13931bdd6c0eSSue Gleeson 	rw_init(&result->svp_lock, NULL, RW_DRIVER, NULL);
13941bdd6c0eSSue Gleeson 	avl_create(&result->svp_mr_list, srpt_vmem_mr_compare,
13951bdd6c0eSSue Gleeson 	    sizeof (srpt_mr_t), offsetof(srpt_mr_t, mr_avl));
13961bdd6c0eSSue Gleeson 
13971bdd6c0eSSue Gleeson 	chunk = srpt_vmem_chunk_alloc(result, chunksize);
13981bdd6c0eSSue Gleeson 
13991bdd6c0eSSue Gleeson 	avl_add(&result->svp_mr_list, chunk);
14001bdd6c0eSSue Gleeson 	result->svp_total_size = chunksize;
14011bdd6c0eSSue Gleeson 
14021bdd6c0eSSue Gleeson 	result->svp_vmem = vmem_create(name,
14031bdd6c0eSSue Gleeson 	    (void*)(uintptr_t)chunk->mr_va,
14041bdd6c0eSSue Gleeson 	    (size_t)chunk->mr_len, SRPT_MR_QUANTSIZE,
14051bdd6c0eSSue Gleeson 	    NULL, NULL, NULL, 0, VM_SLEEP);
14061bdd6c0eSSue Gleeson 
14071bdd6c0eSSue Gleeson 	return (result);
14081bdd6c0eSSue Gleeson }
14091bdd6c0eSSue Gleeson 
14101bdd6c0eSSue Gleeson static void
srpt_vmem_destroy(srpt_vmem_pool_t * vm_pool)14111bdd6c0eSSue Gleeson srpt_vmem_destroy(srpt_vmem_pool_t *vm_pool)
14121bdd6c0eSSue Gleeson {
14131bdd6c0eSSue Gleeson 	srpt_mr_t		*chunk;
14141bdd6c0eSSue Gleeson 	srpt_mr_t		*next;
14151bdd6c0eSSue Gleeson 
14161bdd6c0eSSue Gleeson 	rw_enter(&vm_pool->svp_lock, RW_WRITER);
14171bdd6c0eSSue Gleeson 	vmem_destroy(vm_pool->svp_vmem);
14181bdd6c0eSSue Gleeson 
14191bdd6c0eSSue Gleeson 	chunk = avl_first(&vm_pool->svp_mr_list);
14201bdd6c0eSSue Gleeson 
14211bdd6c0eSSue Gleeson 	while (chunk != NULL) {
14221bdd6c0eSSue Gleeson 		next = AVL_NEXT(&vm_pool->svp_mr_list, chunk);
14231bdd6c0eSSue Gleeson 		avl_remove(&vm_pool->svp_mr_list, chunk);
14241bdd6c0eSSue Gleeson 		srpt_vmem_chunk_free(vm_pool, chunk);
14251bdd6c0eSSue Gleeson 		chunk = next;
14261bdd6c0eSSue Gleeson 	}
14271bdd6c0eSSue Gleeson 
14281bdd6c0eSSue Gleeson 	avl_destroy(&vm_pool->svp_mr_list);
14291bdd6c0eSSue Gleeson 
14301bdd6c0eSSue Gleeson 	rw_exit(&vm_pool->svp_lock);
14311bdd6c0eSSue Gleeson 	rw_destroy(&vm_pool->svp_lock);
14321bdd6c0eSSue Gleeson 
14331bdd6c0eSSue Gleeson 	kmem_free(vm_pool, sizeof (srpt_vmem_pool_t));
14341bdd6c0eSSue Gleeson }
14351bdd6c0eSSue Gleeson 
14361bdd6c0eSSue Gleeson static void *
srpt_vmem_alloc(srpt_vmem_pool_t * vm_pool,size_t size)14371bdd6c0eSSue Gleeson srpt_vmem_alloc(srpt_vmem_pool_t *vm_pool, size_t size)
14381bdd6c0eSSue Gleeson {
14391bdd6c0eSSue Gleeson 	void		*result;
14401bdd6c0eSSue Gleeson 	srpt_mr_t	*next;
14411bdd6c0eSSue Gleeson 	ib_memlen_t	chunklen;
14421bdd6c0eSSue Gleeson 
14431bdd6c0eSSue Gleeson 	ASSERT(vm_pool != NULL);
14441bdd6c0eSSue Gleeson 
14451bdd6c0eSSue Gleeson 	result = vmem_alloc(vm_pool->svp_vmem, size,
14461bdd6c0eSSue Gleeson 	    VM_NOSLEEP | VM_FIRSTFIT);
14471bdd6c0eSSue Gleeson 
14481bdd6c0eSSue Gleeson 	if (result != NULL) {
14491bdd6c0eSSue Gleeson 		/* memory successfully allocated */
14501bdd6c0eSSue Gleeson 		return (result);
14511bdd6c0eSSue Gleeson 	}
14521bdd6c0eSSue Gleeson 
14531bdd6c0eSSue Gleeson 	/* need more vmem */
14541bdd6c0eSSue Gleeson 	rw_enter(&vm_pool->svp_lock, RW_WRITER);
14551bdd6c0eSSue Gleeson 	chunklen = vm_pool->svp_chunksize;
14561bdd6c0eSSue Gleeson 
14571bdd6c0eSSue Gleeson 	if (vm_pool->svp_total_size >= vm_pool->svp_max_size) {
14581bdd6c0eSSue Gleeson 		/* no more room to alloc */
14591bdd6c0eSSue Gleeson 		rw_exit(&vm_pool->svp_lock);
14601bdd6c0eSSue Gleeson 		return (NULL);
14611bdd6c0eSSue Gleeson 	}
14621bdd6c0eSSue Gleeson 
14631bdd6c0eSSue Gleeson 	if ((vm_pool->svp_total_size + chunklen) > vm_pool->svp_max_size) {
14641bdd6c0eSSue Gleeson 		chunklen = vm_pool->svp_max_size - vm_pool->svp_total_size;
14651bdd6c0eSSue Gleeson 	}
14661bdd6c0eSSue Gleeson 
14671bdd6c0eSSue Gleeson 	next = srpt_vmem_chunk_alloc(vm_pool, chunklen);
14681bdd6c0eSSue Gleeson 	if (next != NULL) {
14691bdd6c0eSSue Gleeson 		/*
14701bdd6c0eSSue Gleeson 		 * Note that the size of the chunk we got
14711bdd6c0eSSue Gleeson 		 * may not be the size we requested.  Use the
14721bdd6c0eSSue Gleeson 		 * length returned in the chunk itself.
14731bdd6c0eSSue Gleeson 		 */
14741bdd6c0eSSue Gleeson 		if (vmem_add(vm_pool->svp_vmem, (void*)(uintptr_t)next->mr_va,
14751bdd6c0eSSue Gleeson 		    next->mr_len, VM_NOSLEEP) == NULL) {
14761bdd6c0eSSue Gleeson 			srpt_vmem_chunk_free(vm_pool, next);
14771bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("vmem_add failed");
14781bdd6c0eSSue Gleeson 		} else {
14791bdd6c0eSSue Gleeson 			vm_pool->svp_total_size += next->mr_len;
14801bdd6c0eSSue Gleeson 			avl_add(&vm_pool->svp_mr_list, next);
14811bdd6c0eSSue Gleeson 		}
14821bdd6c0eSSue Gleeson 	}
14831bdd6c0eSSue Gleeson 
14841bdd6c0eSSue Gleeson 	rw_exit(&vm_pool->svp_lock);
14851bdd6c0eSSue Gleeson 
14861bdd6c0eSSue Gleeson 	result = vmem_alloc(vm_pool->svp_vmem, size, VM_NOSLEEP | VM_FIRSTFIT);
14871bdd6c0eSSue Gleeson 
14881bdd6c0eSSue Gleeson 	return (result);
14891bdd6c0eSSue Gleeson }
14901bdd6c0eSSue Gleeson 
14911bdd6c0eSSue Gleeson static void
srpt_vmem_free(srpt_vmem_pool_t * vm_pool,void * vaddr,size_t size)14921bdd6c0eSSue Gleeson srpt_vmem_free(srpt_vmem_pool_t *vm_pool, void *vaddr, size_t size)
14931bdd6c0eSSue Gleeson {
14941bdd6c0eSSue Gleeson 	vmem_free(vm_pool->svp_vmem, vaddr, size);
14951bdd6c0eSSue Gleeson }
14961bdd6c0eSSue Gleeson 
14971bdd6c0eSSue Gleeson static int
srpt_vmem_mr(srpt_vmem_pool_t * vm_pool,void * vaddr,size_t size,srpt_mr_t * mr)14981bdd6c0eSSue Gleeson srpt_vmem_mr(srpt_vmem_pool_t *vm_pool, void *vaddr, size_t size,
14991bdd6c0eSSue Gleeson     srpt_mr_t *mr)
15001bdd6c0eSSue Gleeson {
15011bdd6c0eSSue Gleeson 	avl_index_t		where;
15021bdd6c0eSSue Gleeson 	ib_vaddr_t		mrva = (ib_vaddr_t)(uintptr_t)vaddr;
15031bdd6c0eSSue Gleeson 	srpt_mr_t		chunk;
15041bdd6c0eSSue Gleeson 	srpt_mr_t		*nearest;
15051bdd6c0eSSue Gleeson 	ib_vaddr_t		chunk_end;
15061bdd6c0eSSue Gleeson 	int			status = DDI_FAILURE;
15071bdd6c0eSSue Gleeson 
15081bdd6c0eSSue Gleeson 	rw_enter(&vm_pool->svp_lock, RW_READER);
15091bdd6c0eSSue Gleeson 
15101bdd6c0eSSue Gleeson 	chunk.mr_va = mrva;
15111bdd6c0eSSue Gleeson 	nearest = avl_find(&vm_pool->svp_mr_list, &chunk, &where);
15121bdd6c0eSSue Gleeson 
15131bdd6c0eSSue Gleeson 	if (nearest == NULL) {
15141bdd6c0eSSue Gleeson 		nearest = avl_nearest(&vm_pool->svp_mr_list, where,
15151bdd6c0eSSue Gleeson 		    AVL_BEFORE);
15161bdd6c0eSSue Gleeson 	}
15171bdd6c0eSSue Gleeson 
15181bdd6c0eSSue Gleeson 	if (nearest != NULL) {
15191bdd6c0eSSue Gleeson 		/* Verify this chunk contains the specified address range */
15201bdd6c0eSSue Gleeson 		ASSERT(nearest->mr_va <= mrva);
15211bdd6c0eSSue Gleeson 
15221bdd6c0eSSue Gleeson 		chunk_end = nearest->mr_va + nearest->mr_len;
15231bdd6c0eSSue Gleeson 		if (chunk_end >= mrva + size) {
15241bdd6c0eSSue Gleeson 			mr->mr_hdl = nearest->mr_hdl;
15251bdd6c0eSSue Gleeson 			mr->mr_va = mrva;
15261bdd6c0eSSue Gleeson 			mr->mr_len = size;
15271bdd6c0eSSue Gleeson 			mr->mr_lkey = nearest->mr_lkey;
15281bdd6c0eSSue Gleeson 			mr->mr_rkey = nearest->mr_rkey;
15291bdd6c0eSSue Gleeson 			status = DDI_SUCCESS;
15301bdd6c0eSSue Gleeson 		}
15311bdd6c0eSSue Gleeson 	}
15321bdd6c0eSSue Gleeson 
15331bdd6c0eSSue Gleeson 	rw_exit(&vm_pool->svp_lock);
15341bdd6c0eSSue Gleeson 	return (status);
15351bdd6c0eSSue Gleeson }
15361bdd6c0eSSue Gleeson 
15371bdd6c0eSSue Gleeson static srpt_mr_t *
srpt_vmem_chunk_alloc(srpt_vmem_pool_t * vm_pool,ib_memlen_t chunksize)15381bdd6c0eSSue Gleeson srpt_vmem_chunk_alloc(srpt_vmem_pool_t *vm_pool, ib_memlen_t chunksize)
15391bdd6c0eSSue Gleeson {
15401bdd6c0eSSue Gleeson 	void			*chunk = NULL;
15411bdd6c0eSSue Gleeson 	srpt_mr_t		*result = NULL;
15421bdd6c0eSSue Gleeson 
15431bdd6c0eSSue Gleeson 	while ((chunk == NULL) && (chunksize >= SRPT_MIN_CHUNKSIZE)) {
15441bdd6c0eSSue Gleeson 		chunk = kmem_alloc(chunksize, KM_NOSLEEP);
15451bdd6c0eSSue Gleeson 		if (chunk == NULL) {
15461bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("srpt_vmem_chunk_alloc: "
15471bdd6c0eSSue Gleeson 			    "failed to alloc chunk of %d, trying %d",
15481bdd6c0eSSue Gleeson 			    (int)chunksize, (int)chunksize/2);
15491bdd6c0eSSue Gleeson 			chunksize /= 2;
15501bdd6c0eSSue Gleeson 		}
15511bdd6c0eSSue Gleeson 	}
15521bdd6c0eSSue Gleeson 
15531bdd6c0eSSue Gleeson 	if (chunk != NULL) {
15541bdd6c0eSSue Gleeson 		result = srpt_reg_mem(vm_pool, (ib_vaddr_t)(uintptr_t)chunk,
15551bdd6c0eSSue Gleeson 		    chunksize);
15561bdd6c0eSSue Gleeson 		if (result == NULL) {
15571bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("srpt_vmem_chunk_alloc: "
15581bdd6c0eSSue Gleeson 			    "chunk registration failed");
15591bdd6c0eSSue Gleeson 			kmem_free(chunk, chunksize);
15601bdd6c0eSSue Gleeson 		}
15611bdd6c0eSSue Gleeson 	}
15621bdd6c0eSSue Gleeson 
15631bdd6c0eSSue Gleeson 	return (result);
15641bdd6c0eSSue Gleeson }
15651bdd6c0eSSue Gleeson 
15661bdd6c0eSSue Gleeson static void
srpt_vmem_chunk_free(srpt_vmem_pool_t * vm_pool,srpt_mr_t * mr)15671bdd6c0eSSue Gleeson srpt_vmem_chunk_free(srpt_vmem_pool_t *vm_pool, srpt_mr_t *mr)
15681bdd6c0eSSue Gleeson {
15691bdd6c0eSSue Gleeson 	void			*chunk = (void *)(uintptr_t)mr->mr_va;
15701bdd6c0eSSue Gleeson 	ib_memlen_t		chunksize = mr->mr_len;
15711bdd6c0eSSue Gleeson 
15721bdd6c0eSSue Gleeson 	srpt_dereg_mem(vm_pool->svp_ioc, mr);
15731bdd6c0eSSue Gleeson 	kmem_free(chunk, chunksize);
15741bdd6c0eSSue Gleeson }
15751bdd6c0eSSue Gleeson 
15761bdd6c0eSSue Gleeson static srpt_mr_t *
srpt_reg_mem(srpt_vmem_pool_t * vm_pool,ib_vaddr_t vaddr,ib_memlen_t len)15771bdd6c0eSSue Gleeson srpt_reg_mem(srpt_vmem_pool_t *vm_pool, ib_vaddr_t vaddr, ib_memlen_t len)
15781bdd6c0eSSue Gleeson {
15791bdd6c0eSSue Gleeson 	srpt_mr_t		*result = NULL;
15801bdd6c0eSSue Gleeson 	ibt_mr_attr_t		mr_attr;
15811bdd6c0eSSue Gleeson 	ibt_mr_desc_t		mr_desc;
15821bdd6c0eSSue Gleeson 	ibt_status_t		status;
15831bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc = vm_pool->svp_ioc;
15841bdd6c0eSSue Gleeson 
15851bdd6c0eSSue Gleeson 	result = kmem_zalloc(sizeof (srpt_mr_t), KM_NOSLEEP);
15861bdd6c0eSSue Gleeson 	if (result == NULL) {
15871bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("srpt_reg_mem: failed to allocate");
15881bdd6c0eSSue Gleeson 		return (NULL);
15891bdd6c0eSSue Gleeson 	}
15901bdd6c0eSSue Gleeson 
15911bdd6c0eSSue Gleeson 	bzero(&mr_attr, sizeof (ibt_mr_attr_t));
15921bdd6c0eSSue Gleeson 	bzero(&mr_desc, sizeof (ibt_mr_desc_t));
15931bdd6c0eSSue Gleeson 
15941bdd6c0eSSue Gleeson 	mr_attr.mr_vaddr = vaddr;
15951bdd6c0eSSue Gleeson 	mr_attr.mr_len = len;
15961bdd6c0eSSue Gleeson 	mr_attr.mr_as = NULL;
15971bdd6c0eSSue Gleeson 	mr_attr.mr_flags = vm_pool->svp_flags;
15981bdd6c0eSSue Gleeson 
15991bdd6c0eSSue Gleeson 	status = ibt_register_mr(ioc->ioc_ibt_hdl, ioc->ioc_pd_hdl,
16001bdd6c0eSSue Gleeson 	    &mr_attr, &result->mr_hdl, &mr_desc);
16011bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
16021bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("srpt_reg_mem: ibt_register_mr "
16031bdd6c0eSSue Gleeson 		    "failed %d", status);
16041bdd6c0eSSue Gleeson 		kmem_free(result, sizeof (srpt_mr_t));
16051bdd6c0eSSue Gleeson 		return (NULL);
16061bdd6c0eSSue Gleeson 	}
16071bdd6c0eSSue Gleeson 
16081bdd6c0eSSue Gleeson 	result->mr_va = mr_attr.mr_vaddr;
16091bdd6c0eSSue Gleeson 	result->mr_len = mr_attr.mr_len;
16101bdd6c0eSSue Gleeson 	result->mr_lkey = mr_desc.md_lkey;
16111bdd6c0eSSue Gleeson 	result->mr_rkey = mr_desc.md_rkey;
16121bdd6c0eSSue Gleeson 
16131bdd6c0eSSue Gleeson 	return (result);
16141bdd6c0eSSue Gleeson }
16151bdd6c0eSSue Gleeson 
16161bdd6c0eSSue Gleeson static void
srpt_dereg_mem(srpt_ioc_t * ioc,srpt_mr_t * mr)16171bdd6c0eSSue Gleeson srpt_dereg_mem(srpt_ioc_t *ioc, srpt_mr_t *mr)
16181bdd6c0eSSue Gleeson {
16191bdd6c0eSSue Gleeson 	ibt_status_t		status;
16201bdd6c0eSSue Gleeson 
16211bdd6c0eSSue Gleeson 	status = ibt_deregister_mr(ioc->ioc_ibt_hdl, mr->mr_hdl);
16221bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
1623c3a558e7SSue Gleeson 		SRPT_DPRINTF_L1("srpt_dereg_mem, error deregistering MR (%d)",
16241bdd6c0eSSue Gleeson 		    status);
16251bdd6c0eSSue Gleeson 	}
16261bdd6c0eSSue Gleeson 	kmem_free(mr, sizeof (srpt_mr_t));
16271bdd6c0eSSue Gleeson }
16281bdd6c0eSSue Gleeson 
16291bdd6c0eSSue Gleeson static int
srpt_vmem_mr_compare(const void * a,const void * b)16301bdd6c0eSSue Gleeson srpt_vmem_mr_compare(const void *a, const void *b)
16311bdd6c0eSSue Gleeson {
16321bdd6c0eSSue Gleeson 	srpt_mr_t		*mr1 = (srpt_mr_t *)a;
16331bdd6c0eSSue Gleeson 	srpt_mr_t		*mr2 = (srpt_mr_t *)b;
16341bdd6c0eSSue Gleeson 
16351bdd6c0eSSue Gleeson 	/* sort and match by virtual address */
16361bdd6c0eSSue Gleeson 	if (mr1->mr_va < mr2->mr_va) {
16371bdd6c0eSSue Gleeson 		return (-1);
16381bdd6c0eSSue Gleeson 	} else if (mr1->mr_va > mr2->mr_va) {
16391bdd6c0eSSue Gleeson 		return (1);
16401bdd6c0eSSue Gleeson 	}
16411bdd6c0eSSue Gleeson 
16421bdd6c0eSSue Gleeson 	return (0);
16431bdd6c0eSSue Gleeson }
1644