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 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * hermon_fcoib.c
28  *    Hermon Fibre Channel over IB routines
29  *
30  *    Implements all the routines necessary for setting up, using, and
31  *    (later) tearing down all the FCoIB state.
32  */
33 
34 #include <sys/ib/adapters/hermon/hermon.h>
35 
36 /*
37  * hermon_fcoib_enable()
38  *    Context: user or kernel context
39  */
40 static int
hermon_fcoib_enable(hermon_state_t * state,int port)41 hermon_fcoib_enable(hermon_state_t *state, int port)
42 {
43 	hermon_fcoib_t	*fcoib;
44 	hermon_hw_config_fc_basic_t config_fc_basic;
45 	int		status;
46 
47 	port--;		/* passed in as 1 or 2, used as 0 or 1 */
48 	ASSERT(port >= 0 && port < HERMON_MAX_PORTS);
49 	fcoib = &state->hs_fcoib;
50 
51 	/* Configure FCoIB on the port */
52 	bzero(&config_fc_basic, sizeof (config_fc_basic));
53 	config_fc_basic.fexch_base_hi = fcoib->hfc_fexch_base[port] >> 16;
54 	config_fc_basic.fx_base_mpt_hi = fcoib->hfc_mpt_base[port] >> 17;
55 	config_fc_basic.fx_base_mpt_lo = 0;
56 	config_fc_basic.log2_num_rfci =
57 	    state->hs_ibtfinfo.hca_attr->hca_rfci_max_log2_qp;
58 	config_fc_basic.rfci_base = fcoib->hfc_rfci_qps_per_port * port +
59 	    fcoib->hfc_rfci_rsrc->hr_indx;
60 #if 1
61 	status = hermon_config_fc_cmd_post(state, &config_fc_basic, 1,
62 	    HERMON_HW_FC_CONF_BASIC, 0, port + 1, HERMON_CMD_NOSLEEP_SPIN);
63 #else
64 	status = hermon_config_fc_cmd_post(state, &config_fc_basic, 1,
65 	    HERMON_HW_FC_CONF_BASIC, 0, 0, HERMON_CMD_NOSLEEP_SPIN);
66 #endif
67 	if (status != HERMON_CMD_SUCCESS) {
68 		cmn_err(CE_CONT, "fcoib_enable failed: status 0x%x\n", status);
69 		HERMON_WARNING(state, "fcoib_enable failed");
70 		return (DDI_FAILURE);
71 	}
72 	fcoib->hfc_port_enabled[port] = 1;
73 	state->hs_fcoib_may_be_running = B_TRUE;
74 	return (DDI_SUCCESS);
75 }
76 
77 /*
78  * hermon_fcoib_set_id()
79  *    Context: user or kernel context
80  */
81 int
hermon_fcoib_set_id(hermon_state_t * state,int port,uint32_t rfci_qpn,uint32_t src_id)82 hermon_fcoib_set_id(hermon_state_t *state, int port, uint32_t rfci_qpn,
83     uint32_t src_id)
84 {
85 	hermon_fcoib_t	*fcoib;
86 	int		status;
87 	int		offset;
88 	uint32_t	*n_port_ids;
89 
90 	port--;		/* passed in as 1 or 2, used as 0 or 1 */
91 	ASSERT(port >= 0 && port < HERMON_MAX_PORTS);
92 	fcoib = &state->hs_fcoib;
93 	mutex_enter(&fcoib->hfc_lock);
94 
95 	if (fcoib->hfc_port_enabled[port] == 0) {
96 		if (hermon_fcoib_enable(state, port + 1) != DDI_SUCCESS) {
97 			mutex_exit(&fcoib->hfc_lock);
98 			return (DDI_FAILURE);
99 		}
100 	}
101 
102 	n_port_ids = fcoib->hfc_n_port_ids[port];
103 	offset = rfci_qpn - fcoib->hfc_rfci_base[port];
104 	ASSERT(offset >= 0 && offset < fcoib->hfc_rfci_qps_per_port);
105 	n_port_ids[offset] = src_id;
106 
107 	status = hermon_config_fc_cmd_post(state, n_port_ids, 1,
108 	    HERMON_HW_FC_CONF_NPORT, fcoib->hfc_rfci_qps_per_port,
109 	    port + 1, HERMON_CMD_NOSLEEP_SPIN);
110 	if (status != HERMON_CMD_SUCCESS) {
111 		HERMON_WARNING(state, "fcoib_set_id failed");
112 		mutex_exit(&fcoib->hfc_lock);
113 		return (DDI_FAILURE);
114 	}
115 	mutex_exit(&fcoib->hfc_lock);
116 	return (DDI_SUCCESS);
117 }
118 
119 /*
120  * hermon_fcoib_get_id_idx()
121  *    Context: user or kernel context
122  */
123 int
hermon_fcoib_get_id_idx(hermon_state_t * state,int port,ibt_fc_attr_t * fcp)124 hermon_fcoib_get_id_idx(hermon_state_t *state, int port, ibt_fc_attr_t *fcp)
125 {
126 	hermon_fcoib_t	*fcoib;
127 	int		idx;
128 
129 	port--;		/* passed in as 1 or 2, used as 0 or 1 */
130 	ASSERT(port >= 0 && port < HERMON_MAX_PORTS);
131 	fcoib = &state->hs_fcoib;
132 
133 	idx = fcp->fc_rfci_qpn - fcoib->hfc_rfci_base[port];
134 	if (idx < 0 || idx >= fcoib->hfc_rfci_qps_per_port)
135 		idx = -1;
136 
137 	return (idx);
138 }
139 
140 /*
141  * hermon_fcoib_get_exch_base()
142  *    Context: user or kernel context
143  */
144 int
hermon_fcoib_check_exch_base_off(hermon_state_t * state,int port,ibt_fc_attr_t * fcp)145 hermon_fcoib_check_exch_base_off(hermon_state_t *state, int port,
146     ibt_fc_attr_t *fcp)
147 {
148 	hermon_fcoib_t	*fcoib;
149 	int		exch_base_off;
150 
151 	port--;		/* passed in as 1 or 2, used as 0 or 1 */
152 	ASSERT(port >= 0 && port < HERMON_MAX_PORTS);
153 	fcoib = &state->hs_fcoib;
154 
155 	exch_base_off = fcp->fc_exch_base_off;
156 	if (exch_base_off >= fcoib->hfc_fexch_qps_per_port)
157 		exch_base_off = -1;
158 
159 	return (exch_base_off);
160 }
161 
162 /*
163  * hermon_fcoib_qpnum_from_fexch()
164  *    Context: user, kernel, or interrupt context
165  */
166 int
hermon_fcoib_is_fexch_qpn(hermon_state_t * state,uint_t qpnum)167 hermon_fcoib_is_fexch_qpn(hermon_state_t *state, uint_t qpnum)
168 {
169 	hermon_fcoib_t	*fcoib;
170 
171 	fcoib = &state->hs_fcoib;
172 	qpnum -= fcoib->hfc_fexch_rsrc->hr_indx;
173 	return (qpnum < fcoib->hfc_nports * fcoib->hfc_fexch_qps_per_port);
174 }
175 
176 /*
177  * hermon_fcoib_qpnum_from_fexch()
178  *    Context: user, kernel, or interrupt context
179  */
180 uint_t
hermon_fcoib_qpnum_from_fexch(hermon_state_t * state,int port,uint16_t fexch)181 hermon_fcoib_qpnum_from_fexch(hermon_state_t *state, int port,
182     uint16_t fexch)
183 {
184 	hermon_fcoib_t	*fcoib;
185 	uint_t		qpnum;
186 
187 	port--;		/* passed in as 1 or 2, used as 0 or 1 */
188 	ASSERT(port >= 0 && port < HERMON_MAX_PORTS);
189 	fcoib = &state->hs_fcoib;
190 	qpnum = fexch + fcoib->hfc_fexch_base[port];
191 	return (qpnum);
192 }
193 
194 /*
195  * hermon_fcoib_qpn_to_mkey
196  *    Context: user or kernel context
197  */
198 uint32_t
hermon_fcoib_qpn_to_mkey(hermon_state_t * state,uint_t qpnum)199 hermon_fcoib_qpn_to_mkey(hermon_state_t *state, uint_t qpnum)
200 {
201 	int		i;
202 	hermon_fcoib_t	*fcoib;
203 	uint32_t	qp_indx;
204 
205 	fcoib = &state->hs_fcoib;
206 	for (i = 0; i < fcoib->hfc_nports; i++) {
207 		qp_indx = qpnum - fcoib->hfc_fexch_base[i];
208 		if (qp_indx < fcoib->hfc_fexch_qps_per_port)
209 			return ((qp_indx + fcoib->hfc_mpt_base[i]) << 8);
210 	}
211 	return ((uint32_t)-1);	/* cannot get here with valid qpnum argument */
212 }
213 
214 /*
215  * hermon_fcoib_fexch_relative_qpn()
216  *    Context: user or kernel context
217  */
218 uint32_t
hermon_fcoib_fexch_relative_qpn(hermon_state_t * state,uint8_t port,uint32_t qp_indx)219 hermon_fcoib_fexch_relative_qpn(hermon_state_t *state, uint8_t port,
220     uint32_t qp_indx)
221 {
222 	port--;
223 	ASSERT(port < HERMON_MAX_PORTS);
224 	qp_indx -= state->hs_fcoib.hfc_fexch_base[port];
225 	return (qp_indx);
226 }
227 
228 /*
229  * hermon_fcoib_fexch_mkey_init()
230  *    Context: user or kernel context
231  */
232 int
hermon_fcoib_fexch_mkey_init(hermon_state_t * state,hermon_pdhdl_t pd,uint8_t port,uint32_t qp_indx,uint_t sleep)233 hermon_fcoib_fexch_mkey_init(hermon_state_t *state, hermon_pdhdl_t pd,
234     uint8_t port, uint32_t qp_indx, uint_t sleep)
235 {
236 	int		status;
237 	uint32_t	mpt_indx;
238 	uint_t		nummtt;
239 	uint64_t	mtt_addr;
240 	hermon_fcoib_t	*fcoib;
241 
242 	port--;
243 	ASSERT(port < HERMON_MAX_PORTS);
244 	fcoib = &state->hs_fcoib;
245 	qp_indx -= fcoib->hfc_fexch_base[port];	/* relative to FEXCH base */
246 	if (qp_indx > fcoib->hfc_fexch_qps_per_port)
247 		return (IBT_INVALID_PARAM);
248 	mpt_indx = qp_indx + fcoib->hfc_mpt_base[port];
249 	nummtt = fcoib->hfc_mtts_per_mpt;
250 	mtt_addr = ((uint64_t)qp_indx * nummtt + fcoib->hfc_mtt_base[port]) <<
251 	    HERMON_MTT_SIZE_SHIFT;
252 
253 	status = hermon_mr_fexch_mpt_init(state, pd, mpt_indx,
254 	    nummtt, mtt_addr, sleep);
255 	return (status);
256 }
257 
258 /*
259  * hermon_fcoib_fexch_mkey_fini()
260  *    Context: user or kernel context
261  */
262 int
hermon_fcoib_fexch_mkey_fini(hermon_state_t * state,hermon_pdhdl_t pd,uint32_t qpnum,uint_t sleep)263 hermon_fcoib_fexch_mkey_fini(hermon_state_t *state, hermon_pdhdl_t pd,
264     uint32_t qpnum, uint_t sleep)
265 {
266 	int		status;
267 	uint8_t		port;
268 	uint32_t	qp_indx;
269 	uint32_t	mpt_indx;
270 	hermon_fcoib_t	*fcoib;
271 
272 	fcoib = &state->hs_fcoib;
273 	for (port = 0; port < fcoib->hfc_nports; port++) {
274 		qp_indx = qpnum - fcoib->hfc_fexch_base[port];
275 		if (qp_indx < fcoib->hfc_fexch_qps_per_port)
276 			goto found;
277 	}
278 	return (IBT_INVALID_PARAM);
279 found:
280 	/* qp_indx relative to FEXCH base */
281 	mpt_indx = qp_indx + fcoib->hfc_mpt_base[port];
282 
283 	status = hermon_mr_fexch_mpt_fini(state, pd, mpt_indx, sleep);
284 	return (status);
285 }
286 
287 /*
288  * hermon_fcoib_query_fc()
289  *    Context: user or kernel context
290  */
291 void
hermon_fcoib_query_fc(hermon_state_t * state,hermon_fcoib_t * fcoib)292 hermon_fcoib_query_fc(hermon_state_t *state, hermon_fcoib_t *fcoib)
293 {
294 	int status;
295 	struct hermon_hw_query_fc_s query_fc;
296 
297 	status = hermon_cmn_query_cmd_post(state, QUERY_FC, 0, 0, &query_fc,
298 	    sizeof (query_fc), HERMON_CMD_NOSLEEP_SPIN);
299 	if (status == HERMON_CMD_SUCCESS) {
300 		fcoib->hfc_log2_max_port_ids_queried = query_fc.log2_max_nports;
301 		fcoib->hfc_log2_max_fexch_queried = query_fc.log2_max_fexch;
302 		fcoib->hfc_log2_max_rfci_queried = query_fc.log2_max_rfci;
303 	} else
304 		cmn_err(CE_CONT, "!query_fc status 0x%x\n", status);
305 }
306 
307 /*
308  * hermon_fcoib_init()
309  *    Context: Only called from attach() path context
310  */
311 int
hermon_fcoib_init(hermon_state_t * state)312 hermon_fcoib_init(hermon_state_t *state)
313 {
314 	hermon_fcoib_t	*fcoib;
315 	uint_t		numports;
316 	char		string[128];
317 	int		i;
318 	uintptr_t	vmemstart = (uintptr_t)0x10000000;
319 
320 	/* used for fast checking for FCoIB during cqe_consume */
321 	state->hs_fcoib_may_be_running = B_FALSE;
322 
323 	if ((state->hs_ibtfinfo.hca_attr->hca_flags2 & IBT_HCA2_FC) == 0)
324 		return (DDI_SUCCESS);
325 
326 	fcoib = &state->hs_fcoib;
327 	bzero(fcoib, sizeof (*fcoib));
328 
329 	hermon_fcoib_query_fc(state, fcoib);
330 
331 	mutex_init(&fcoib->hfc_lock, NULL, MUTEX_DRIVER, NULL);
332 	mutex_enter(&fcoib->hfc_lock);
333 
334 	/* use a ROUND value that works on both 32 and 64-bit kernels */
335 	fcoib->hfc_vmemstart = vmemstart;
336 
337 	fcoib->hfc_nports = numports = state->hs_cfg_profile->cp_num_ports;
338 	fcoib->hfc_fexch_qps_per_port =
339 	    1 << state->hs_ibtfinfo.hca_attr->hca_fexch_max_log2_qp;
340 	fcoib->hfc_mpts_per_port = fcoib->hfc_fexch_qps_per_port * 2;
341 	fcoib->hfc_mtts_per_mpt =
342 	    (1 << state->hs_ibtfinfo.hca_attr->hca_fexch_max_log2_mem) >>
343 	    PAGESHIFT;
344 	fcoib->hfc_rfci_qps_per_port =
345 	    1 << state->hs_ibtfinfo.hca_attr->hca_rfci_max_log2_qp;
346 
347 	if (hermon_rsrc_reserve(state, HERMON_DMPT, numports *
348 	    fcoib->hfc_mpts_per_port, HERMON_SLEEP,
349 	    &fcoib->hfc_mpt_rsrc) != DDI_SUCCESS) {
350 		mutex_exit(&fcoib->hfc_lock);
351 		hermon_fcoib_fini(state);
352 		return (DDI_FAILURE);
353 	}
354 
355 	/*
356 	 * Only reserve MTTs for the Primary MPTs (first half of the
357 	 * range for each port).
358 	 */
359 	if (hermon_rsrc_reserve(state, HERMON_MTT, numports *
360 	    fcoib->hfc_mpts_per_port * fcoib->hfc_mtts_per_mpt / 2,
361 	    HERMON_SLEEP, &fcoib->hfc_mtt_rsrc) != DDI_SUCCESS) {
362 		mutex_exit(&fcoib->hfc_lock);
363 		hermon_fcoib_fini(state);
364 		return (DDI_FAILURE);
365 	}
366 	if (hermon_rsrc_reserve(state, HERMON_QPC, numports *
367 	    fcoib->hfc_fexch_qps_per_port, HERMON_SLEEP,
368 	    &fcoib->hfc_fexch_rsrc) != DDI_SUCCESS) {
369 		mutex_exit(&fcoib->hfc_lock);
370 		hermon_fcoib_fini(state);
371 		return (DDI_FAILURE);
372 	}
373 	if (hermon_rsrc_reserve(state, HERMON_QPC, numports *
374 	    fcoib->hfc_rfci_qps_per_port, HERMON_SLEEP,
375 	    &fcoib->hfc_rfci_rsrc) != DDI_SUCCESS) {
376 		mutex_exit(&fcoib->hfc_lock);
377 		hermon_fcoib_fini(state);
378 		return (DDI_FAILURE);
379 	}
380 
381 	for (i = 0; i < numports; i++) {
382 		fcoib->hfc_port_enabled[i] = 0;
383 		fcoib->hfc_n_port_ids[i] = kmem_zalloc(sizeof (uint32_t) *
384 		    fcoib->hfc_rfci_qps_per_port, KM_SLEEP);
385 
386 		fcoib->hfc_mpt_base[i] = i * fcoib->hfc_mpts_per_port +
387 		    fcoib->hfc_mpt_rsrc->hr_indx;
388 		/* "/ 2" is for Secondary MKEYs never used on Client side */
389 		fcoib->hfc_mtt_base[i] = (i * fcoib->hfc_mpts_per_port *
390 		    fcoib->hfc_mtts_per_mpt / 2) + fcoib->hfc_mtt_rsrc->hr_indx;
391 		fcoib->hfc_fexch_base[i] = i * fcoib->hfc_fexch_qps_per_port +
392 		    fcoib->hfc_fexch_rsrc->hr_indx;
393 		fcoib->hfc_rfci_base[i] = i * fcoib->hfc_rfci_qps_per_port +
394 		    fcoib->hfc_rfci_rsrc->hr_indx;
395 
396 		/* init FEXCH QP rsrc pool */
397 		(void) sprintf(string, "hermon%d_port%d_fexch_vmem",
398 		    state->hs_instance, i + 1);
399 		fcoib->hfc_fexch_vmemp[i] = vmem_create(string,
400 		    (void *)vmemstart, fcoib->hfc_fexch_qps_per_port,
401 		    1, NULL, NULL, NULL, 0, VM_SLEEP);
402 
403 		/* init RFCI QP rsrc pool */
404 		(void) sprintf(string, "hermon%d_port%d_rfci_vmem",
405 		    state->hs_instance, i + 1);
406 		fcoib->hfc_rfci_vmemp[i] = vmem_create(string,
407 		    (void *)vmemstart, fcoib->hfc_rfci_qps_per_port,
408 		    1, NULL, NULL, NULL, 0, VM_SLEEP);
409 	}
410 
411 	mutex_exit(&fcoib->hfc_lock);
412 
413 	return (DDI_SUCCESS);
414 }
415 
416 
417 /*
418  * hermon_fcoib_fini()
419  *    Context: Only called from attach() and/or detach() path contexts
420  */
421 void
hermon_fcoib_fini(hermon_state_t * state)422 hermon_fcoib_fini(hermon_state_t *state)
423 {
424 	hermon_fcoib_t	*fcoib;
425 	uint_t		numports;
426 	int		i;
427 
428 	if ((state->hs_ibtfinfo.hca_attr->hca_flags2 & IBT_HCA2_FC) == 0)
429 		return;
430 
431 	fcoib = &state->hs_fcoib;
432 
433 	mutex_enter(&fcoib->hfc_lock);
434 
435 	numports = fcoib->hfc_nports;
436 
437 	for (i = 0; i < numports; i++) {
438 		if (fcoib->hfc_rfci_vmemp[i])
439 			vmem_destroy(fcoib->hfc_rfci_vmemp[i]);
440 		if (fcoib->hfc_fexch_vmemp[i])
441 			vmem_destroy(fcoib->hfc_fexch_vmemp[i]);
442 		if (fcoib->hfc_n_port_ids[i])
443 			kmem_free(fcoib->hfc_n_port_ids[i], sizeof (uint32_t) *
444 			    fcoib->hfc_rfci_qps_per_port);
445 
446 		/* XXX --- should we issue HERMON_HW_FC_CONF_BASIC disable? */
447 		fcoib->hfc_port_enabled[i] = 0;
448 	}
449 	if (fcoib->hfc_rfci_rsrc)
450 		hermon_rsrc_free(state, &fcoib->hfc_rfci_rsrc);
451 	if (fcoib->hfc_fexch_rsrc)
452 		hermon_rsrc_free(state, &fcoib->hfc_fexch_rsrc);
453 	if (fcoib->hfc_mpt_rsrc)
454 		hermon_rsrc_free(state, &fcoib->hfc_mpt_rsrc);
455 	if (fcoib->hfc_mtt_rsrc)
456 		hermon_rsrc_free(state, &fcoib->hfc_mtt_rsrc);
457 
458 	mutex_exit(&fcoib->hfc_lock);
459 	mutex_destroy(&fcoib->hfc_lock);
460 
461 	bzero(fcoib, sizeof (*fcoib));
462 }
463