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.
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.
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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
28 * Hermon Fibre Channel over IB routines
30 * Implements all the routines necessary for setting up, using, and
31 * (later) tearing down all the FCoIB state.
34 #include <sys/ib/adapters/hermon/hermon.h>
37 * hermon_fcoib_enable()
38 * Context: user or kernel context
41 hermon_fcoib_enable(hermon_state_t
*state
, int port
)
43 hermon_fcoib_t
*fcoib
;
44 hermon_hw_config_fc_basic_t config_fc_basic
;
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
;
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
;
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
);
64 status
= hermon_config_fc_cmd_post(state
, &config_fc_basic
, 1,
65 HERMON_HW_FC_CONF_BASIC
, 0, 0, HERMON_CMD_NOSLEEP_SPIN
);
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");
72 fcoib
->hfc_port_enabled
[port
] = 1;
73 state
->hs_fcoib_may_be_running
= B_TRUE
;
78 * hermon_fcoib_set_id()
79 * Context: user or kernel context
82 hermon_fcoib_set_id(hermon_state_t
*state
, int port
, uint32_t rfci_qpn
,
85 hermon_fcoib_t
*fcoib
;
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
);
95 if (fcoib
->hfc_port_enabled
[port
] == 0) {
96 if (hermon_fcoib_enable(state
, port
+ 1) != DDI_SUCCESS
) {
97 mutex_exit(&fcoib
->hfc_lock
);
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
;
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
);
115 mutex_exit(&fcoib
->hfc_lock
);
116 return (DDI_SUCCESS
);
120 * hermon_fcoib_get_id_idx()
121 * Context: user or kernel context
124 hermon_fcoib_get_id_idx(hermon_state_t
*state
, int port
, ibt_fc_attr_t
*fcp
)
126 hermon_fcoib_t
*fcoib
;
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
;
133 idx
= fcp
->fc_rfci_qpn
- fcoib
->hfc_rfci_base
[port
];
134 if (idx
< 0 || idx
>= fcoib
->hfc_rfci_qps_per_port
)
141 * hermon_fcoib_get_exch_base()
142 * Context: user or kernel context
145 hermon_fcoib_check_exch_base_off(hermon_state_t
*state
, int port
,
148 hermon_fcoib_t
*fcoib
;
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
;
155 exch_base_off
= fcp
->fc_exch_base_off
;
156 if (exch_base_off
>= fcoib
->hfc_fexch_qps_per_port
)
159 return (exch_base_off
);
163 * hermon_fcoib_qpnum_from_fexch()
164 * Context: user, kernel, or interrupt context
167 hermon_fcoib_is_fexch_qpn(hermon_state_t
*state
, uint_t qpnum
)
169 hermon_fcoib_t
*fcoib
;
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
);
177 * hermon_fcoib_qpnum_from_fexch()
178 * Context: user, kernel, or interrupt context
181 hermon_fcoib_qpnum_from_fexch(hermon_state_t
*state
, int port
,
184 hermon_fcoib_t
*fcoib
;
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
];
195 * hermon_fcoib_qpn_to_mkey
196 * Context: user or kernel context
199 hermon_fcoib_qpn_to_mkey(hermon_state_t
*state
, uint_t qpnum
)
202 hermon_fcoib_t
*fcoib
;
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);
211 return ((uint32_t)-1); /* cannot get here with valid qpnum argument */
215 * hermon_fcoib_fexch_relative_qpn()
216 * Context: user or kernel context
219 hermon_fcoib_fexch_relative_qpn(hermon_state_t
*state
, uint8_t port
,
223 ASSERT(port
< HERMON_MAX_PORTS
);
224 qp_indx
-= state
->hs_fcoib
.hfc_fexch_base
[port
];
229 * hermon_fcoib_fexch_mkey_init()
230 * Context: user or kernel context
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
)
240 hermon_fcoib_t
*fcoib
;
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
;
253 status
= hermon_mr_fexch_mpt_init(state
, pd
, mpt_indx
,
254 nummtt
, mtt_addr
, sleep
);
259 * hermon_fcoib_fexch_mkey_fini()
260 * Context: user or kernel context
263 hermon_fcoib_fexch_mkey_fini(hermon_state_t
*state
, hermon_pdhdl_t pd
,
264 uint32_t qpnum
, uint_t sleep
)
270 hermon_fcoib_t
*fcoib
;
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
)
278 return (IBT_INVALID_PARAM
);
280 /* qp_indx relative to FEXCH base */
281 mpt_indx
= qp_indx
+ fcoib
->hfc_mpt_base
[port
];
283 status
= hermon_mr_fexch_mpt_fini(state
, pd
, mpt_indx
, sleep
);
288 * hermon_fcoib_query_fc()
289 * Context: user or kernel context
292 hermon_fcoib_query_fc(hermon_state_t
*state
, hermon_fcoib_t
*fcoib
)
295 struct hermon_hw_query_fc_s query_fc
;
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
;
304 cmn_err(CE_CONT
, "!query_fc status 0x%x\n", status
);
308 * hermon_fcoib_init()
309 * Context: Only called from attach() path context
312 hermon_fcoib_init(hermon_state_t
*state
)
314 hermon_fcoib_t
*fcoib
;
318 uintptr_t vmemstart
= (uintptr_t)0x10000000;
320 /* used for fast checking for FCoIB during cqe_consume */
321 state
->hs_fcoib_may_be_running
= B_FALSE
;
323 if ((state
->hs_ibtfinfo
.hca_attr
->hca_flags2
& IBT_HCA2_FC
) == 0)
324 return (DDI_SUCCESS
);
326 fcoib
= &state
->hs_fcoib
;
327 bzero(fcoib
, sizeof (*fcoib
));
329 hermon_fcoib_query_fc(state
, fcoib
);
331 mutex_init(&fcoib
->hfc_lock
, NULL
, MUTEX_DRIVER
, NULL
);
332 mutex_enter(&fcoib
->hfc_lock
);
334 /* use a ROUND value that works on both 32 and 64-bit kernels */
335 fcoib
->hfc_vmemstart
= vmemstart
;
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
) >>
344 fcoib
->hfc_rfci_qps_per_port
=
345 1 << state
->hs_ibtfinfo
.hca_attr
->hca_rfci_max_log2_qp
;
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
);
356 * Only reserve MTTs for the Primary MPTs (first half of the
357 * range for each port).
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
);
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
);
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
);
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
);
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
;
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
);
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
);
411 mutex_exit(&fcoib
->hfc_lock
);
413 return (DDI_SUCCESS
);
418 * hermon_fcoib_fini()
419 * Context: Only called from attach() and/or detach() path contexts
422 hermon_fcoib_fini(hermon_state_t
*state
)
424 hermon_fcoib_t
*fcoib
;
428 if ((state
->hs_ibtfinfo
.hca_attr
->hca_flags2
& IBT_HCA2_FC
) == 0)
431 fcoib
= &state
->hs_fcoib
;
433 mutex_enter(&fcoib
->hfc_lock
);
435 numports
= fcoib
->hfc_nports
;
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
);
446 /* XXX --- should we issue HERMON_HW_FC_CONF_BASIC disable? */
447 fcoib
->hfc_port_enabled
[i
] = 0;
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
);
458 mutex_exit(&fcoib
->hfc_lock
);
459 mutex_destroy(&fcoib
->hfc_lock
);
461 bzero(fcoib
, sizeof (*fcoib
));