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 #ifndef _SYS_IB_EOIB_ENX_IMPL_H
27 #define _SYS_IB_EOIB_ENX_IMPL_H
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/varargs.h>
36 #include <sys/ib/ibtl/ibti.h>
37 #include <sys/ib/ibtl/ibvti.h>
38 #include <sys/ib/ib_pkt_hdrs.h>
39 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
40 #include <sys/ib/mgt/sm_attr.h>
41
42 #include <sys/ib/clients/eoib/fip.h>
43 #include <sys/ib/clients/eoib/eib.h>
44
45 /*
46 * Driver specific constants
47 */
48 #define ENX_E_SUCCESS 0
49 #define ENX_E_FAILURE -1
50 #define ENX_MAX_LINE 128
51 #define ENX_GRH_SZ (sizeof (ib_grh_t))
52
53 /*
54 * Debug messages
55 */
56 #define ENX_MSGS_CRIT 0x01
57 #define ENX_MSGS_ERR 0x02
58 #define ENX_MSGS_WARN 0x04
59 #define ENX_MSGS_DEBUG 0x08
60 #define ENX_MSGS_ARGS 0x10
61 #define ENX_MSGS_VERBOSE 0x20
62 #define ENX_MSGS_DEFAULT (ENX_MSGS_CRIT | ENX_MSGS_ERR | ENX_MSGS_WARN)
63
64 #define ENX_LOGSZ_DEFAULT 0x20000
65
66 #define ENX_DPRINTF_CRIT eibnx_dprintf_crit
67 #define ENX_DPRINTF_ERR eibnx_dprintf_err
68 #define ENX_DPRINTF_WARN eibnx_dprintf_warn
69 #ifdef ENX_DEBUG
70 #define ENX_DPRINTF_DEBUG eibnx_dprintf_debug
71 #define ENX_DPRINTF_ARGS eibnx_dprintf_args
72 #define ENX_DPRINTF_VERBOSE eibnx_dprintf_verbose
73 #else
74 #define ENX_DPRINTF_DEBUG 0 &&
75 #define ENX_DPRINTF_ARGS 0 &&
76 #define ENX_DPRINTF_VERBOSE 0 &&
77 #endif
78
79 /*
80 * EoIB Nexus service threads
81 */
82 #define ENX_PORT_MONITOR "eibnx_port_%d_monitor"
83 #define ENX_NODE_CREATOR "eibnx_node_creator"
84
85 /*
86 * Default period (us) for unicast solicitations to discovered gateways.
87 * EoIB specification requires that hosts send solicitation atleast every
88 * 4 * GW_ADV_PERIOD.
89 */
90 #define ENX_DFL_SOLICIT_PERIOD_USEC 32000000
91
92 /*
93 * Portinfo list per HCA
94 */
95 typedef struct eibnx_port_s {
96 struct eibnx_port_s *po_next;
97 ibt_hca_portinfo_t *po_pi;
98 uint_t po_pi_size;
99 } eibnx_port_t;
100
101 /*
102 * HCA details
103 */
104 typedef struct eibnx_hca_s {
105 struct eibnx_hca_s *hc_next;
106 ib_guid_t hc_guid;
107 ibt_hca_hdl_t hc_hdl;
108 ibt_pd_hdl_t hc_pd;
109 eibnx_port_t *hc_port;
110 } eibnx_hca_t;
111
112 /*
113 * The port_monitor thread in EoIB nexus driver only sends two types of
114 * packets: multicast solicitation the first time around, and periodic
115 * unicast solicitations later to gateways that have been discovered. So
116 * we need a couple of send wqes for the multicast solicitation and
117 * probably as many send wqes as the number of gateways that may be
118 * discovered from each port, for sending the unicast solicitations.
119 * For unicast solicitations though, the UD destination needs to be set
120 * up at the time we receive the advertisement from the gateway, using
121 * ibt_modify_reply_ud_dest(), so we'll assign one send wqe for each
122 * gateway that we discover. This means that we need to acquire these
123 * send wqe entries during rx processing in the completion handler, which
124 * means we must avoid sleeping in trying to acquire the swqe. Therefore,
125 * we'll pre-allocate these unicast solication send wqes to be atleast
126 * twice the number of recv wqes.
127 *
128 * The receive packets expected by the EoIB nexus driver are the multicast
129 * and unicast messages on the SOLICIT and ADVERTISE groups. These
130 * shouldn't be too many, and should be tuned as we gain experience on
131 * the traffic pattern. We'll start with 16.
132 */
133 #define ENX_NUM_SWQE 46
134 #define ENX_NUM_RWQE 16
135 #define ENX_CQ_SIZE (ENX_NUM_SWQE + ENX_NUM_RWQE + 2)
136
137 /*
138 * qe_type values
139 */
140 #define ENX_QETYP_RWQE 0x1
141 #define ENX_QETYP_SWQE 0x2
142
143 /*
144 * qe_flags bitmasks (protected by qe_lock). None of the
145 * flag values may be zero.
146 */
147 #define ENX_QEFL_INUSE 0x01
148 #define ENX_QEFL_POSTED 0x02
149 #define ENX_QEFL_RELONCOMP 0x04
150
151 /*
152 * Recv and send workq entries
153 */
154 typedef struct eibnx_wqe_s {
155 uint_t qe_type;
156 uint_t qe_bufsz;
157 ibt_wr_ds_t qe_sgl;
158 ibt_all_wr_t qe_wr;
159 kmutex_t qe_lock;
160 uint_t qe_flags;
161 } eibnx_wqe_t;
162
163 /*
164 * Tx descriptor
165 */
166 typedef struct eibnx_tx_s {
167 ib_vaddr_t tx_vaddr;
168 ibt_mr_hdl_t tx_mr;
169 ibt_lkey_t tx_lkey;
170 eibnx_wqe_t tx_wqe[ENX_NUM_SWQE];
171 } eibnx_tx_t;
172
173 /*
174 * Rx descriptor
175 */
176 typedef struct eibnx_rx_s {
177 ib_vaddr_t rx_vaddr;
178 ibt_mr_hdl_t rx_mr;
179 ibt_lkey_t rx_lkey;
180 eibnx_wqe_t rx_wqe[ENX_NUM_RWQE];
181 } eibnx_rx_t;
182
183 /*
184 * Details about the address of each gateway we discover.
185 */
186 typedef struct eibnx_gw_addr_s {
187 ibt_adds_vect_t *ga_vect;
188 ib_gid_t ga_gid;
189 ib_qpn_t ga_qpn;
190 ib_qkey_t ga_qkey;
191 ib_pkey_t ga_pkey;
192 } eibnx_gw_addr_t;
193
194 /*
195 * States for each GW
196 */
197 #define ENX_GW_STATE_UNAVAILABLE 1 /* GW nackd availability */
198 #define ENX_GW_STATE_AVAILABLE 2 /* GW mcasted availability */
199 #define ENX_GW_STATE_READY_TO_LOGIN 3 /* GW ucasted availability */
200
201 typedef struct eibnx_gw_info_s {
202 struct eibnx_gw_info_s *gw_next;
203 eibnx_wqe_t *gw_swqe;
204 uint_t gw_state;
205
206 kmutex_t gw_adv_lock;
207 uint_t gw_adv_flag;
208 int64_t gw_adv_last_lbolt;
209 int64_t gw_adv_timeout_ticks;
210
211 eibnx_gw_addr_t gw_addr;
212
213 ib_guid_t gw_system_guid;
214 ib_guid_t gw_guid;
215
216 uint32_t gw_adv_period;
217 uint32_t gw_ka_period;
218 uint32_t gw_vnic_ka_period;
219 ib_qpn_t gw_ctrl_qpn;
220
221 ib_lid_t gw_lid;
222 uint16_t gw_portid;
223 uint16_t gw_num_net_vnics;
224
225 uint8_t gw_is_host_adm_vnics;
226 uint8_t gw_sl;
227 uint8_t gw_n_rss_qpn;
228 uint8_t gw_flag_ucast_advt;
229 uint8_t gw_flag_available;
230
231 uint8_t gw_system_name[EIB_GW_SYSNAME_LEN];
232 uint8_t gw_port_name[EIB_GW_PORTNAME_LEN];
233 uint8_t gw_vendor_id[EIB_GW_VENDOR_LEN];
234 } eibnx_gw_info_t;
235
236 /*
237 * Values for gw_adv_flag (non-zero only)
238 */
239 #define ENX_GW_DEAD 1
240 #define ENX_GW_ALIVE 2
241 #define ENX_GW_AWARE 3
242
243 /*
244 * Currently, we only expect the advertisement type of packets
245 * from the gw. But we do get login acks from the gateway also
246 * here in the nexus, so we'll need an identifier for that.
247 */
248 typedef enum {
249 FIP_GW_ADVERTISE_MCAST = 0,
250 FIP_GW_ADVERTISE_UCAST,
251 FIP_VNIC_LOGIN_ACK
252 } eibnx_gw_pkt_type_t;
253
254 /*
255 * Currently, the only gw response handled by the eibnx driver
256 * are the ucast/mcast advertisements. Information collected from
257 * both these responses may be packed into a eibnx_gw_info_t.
258 * In the future, if we decide to handle other types of responses
259 * from the gw, we could simply add the new types to the union.
260 */
261 typedef struct eibnx_gw_msg_s {
262 eibnx_gw_pkt_type_t gm_type;
263 union {
264 eibnx_gw_info_t gm_info;
265 } u;
266 } eibnx_gw_msg_t;
267
268 /*
269 * List to hold the devinfo nodes of eoib instances
270 */
271 typedef struct eibnx_child_s {
272 struct eibnx_child_s *ch_next;
273 dev_info_t *ch_dip;
274 eibnx_gw_info_t *ch_gwi;
275 char *ch_node_name;
276 } eibnx_child_t;
277
278 /*
279 * Event bitmasks for the port-monitor to wait on. None of these flags
280 * may be zero.
281 */
282 #define ENX_EVENT_LINK_UP 0x01
283 #define ENX_EVENT_MCGS_AVAILABLE 0x02
284 #define ENX_EVENT_TIMED_OUT 0x04
285 #define ENX_EVENT_DIE 0x08
286 #define ENX_EVENT_COMPLETION 0x10
287
288 /*
289 * MCG Query/Join status
290 */
291 #define ENX_MCGS_FOUND 0x1
292 #define ENX_MCGS_JOINED 0x2
293
294 /*
295 * Information that each port-monitor thread cares about
296 */
297 typedef struct eibnx_thr_info_s {
298 struct eibnx_thr_info_s *ti_next;
299 uint_t ti_progress;
300
301 /*
302 * Our kernel thread id
303 */
304 kt_did_t ti_kt_did;
305
306 /*
307 * HCA, port and protection domain information
308 */
309 ib_guid_t ti_hca_guid;
310 ibt_hca_hdl_t ti_hca;
311 ibt_pd_hdl_t ti_pd;
312 ibt_hca_portinfo_t *ti_pi;
313 char *ti_ident;
314
315 /*
316 * Well-known multicast groups for solicitations
317 * and advertisements.
318 */
319 kmutex_t ti_mcg_lock;
320 uint_t ti_mcg_status;
321 ibt_mcg_info_t *ti_advertise_mcg;
322 ibt_mcg_info_t *ti_solicit_mcg;
323 uint_t ti_mcast_done;
324
325 /*
326 * Completion queue stuff
327 */
328 ibt_cq_hdl_t ti_cq_hdl;
329 uint_t ti_cq_sz;
330 ibt_wc_t *ti_wc;
331 ddi_softint_handle_t ti_softint_hdl;
332
333 /*
334 * Channel related
335 */
336 ibt_channel_hdl_t ti_chan;
337 ib_qpn_t ti_qpn;
338
339 /*
340 * Transmit/Receive stuff
341 */
342 eibnx_tx_t ti_snd;
343 eibnx_rx_t ti_rcv;
344
345 /*
346 * GW related stuff
347 */
348 kmutex_t ti_gw_lock;
349 eibnx_gw_info_t *ti_gw;
350
351 /*
352 * Devinfo nodes for the eoib children
353 */
354 kmutex_t ti_child_lock;
355 eibnx_child_t *ti_child;
356
357 /*
358 * Events that we wait on and/or handle
359 */
360 kmutex_t ti_event_lock;
361 kcondvar_t ti_event_cv;
362 uint_t ti_event;
363 } eibnx_thr_info_t;
364
365 /*
366 * Workq entry for creation of eoib nodes
367 */
368 typedef struct eibnx_nodeq_s {
369 struct eibnx_nodeq_s *nc_next;
370 eibnx_thr_info_t *nc_info;
371 eibnx_gw_info_t *nc_gwi;
372 } eibnx_nodeq_t;
373
374 /*
375 * Bus config status flags. The in-prog is protected by
376 * nx_lock, and the rest of the flags (currently only
377 * buscfg-complete) is protected by the in-prog bit itself.
378 */
379 #define NX_FL_BUSOP_INPROG 0x1
380 #define NX_FL_BUSCFG_COMPLETE 0x2
381 #define NX_FL_BUSOP_MASK 0x3
382
383 /*
384 * EoIB nexus per-instance state
385 */
386 typedef struct eibnx_s {
387 dev_info_t *nx_dip;
388 ibt_clnt_hdl_t nx_ibt_hdl;
389
390 kmutex_t nx_lock;
391 eibnx_hca_t *nx_hca;
392 eibnx_thr_info_t *nx_thr_info;
393 boolean_t nx_monitors_up;
394
395 kmutex_t nx_nodeq_lock;
396 kcondvar_t nx_nodeq_cv;
397 eibnx_nodeq_t *nx_nodeq;
398 kt_did_t nx_nodeq_kt_did;
399 uint_t nx_nodeq_thr_die;
400
401 kmutex_t nx_busop_lock;
402 kcondvar_t nx_busop_cv;
403 uint_t nx_busop_flags;
404 } eibnx_t;
405
406
407 /*
408 * Event tags for EoIB Nexus events delivered to EoIB instances
409 */
410 #define ENX_EVENT_TAG_GW_INFO_UPDATE 0
411 #define ENX_EVENT_TAG_GW_AVAILABLE 1
412 #define ENX_EVENT_TAG_LOGIN_ACK 2
413
414 /*
415 * FUNCTION PROTOTYPES FOR CROSS-FILE LINKAGE
416 */
417
418 /*
419 * Threads and Event Handlers
420 */
421 void eibnx_port_monitor(eibnx_thr_info_t *);
422 void eibnx_subnet_notices_handler(void *, ib_gid_t, ibt_subnet_event_code_t,
423 ibt_subnet_event_t *);
424 void eibnx_async_handler(void *, ibt_hca_hdl_t, ibt_async_code_t,
425 ibt_async_event_t *);
426 boolean_t eibnx_is_gw_dead(eibnx_gw_info_t *);
427 void eibnx_create_eoib_node(void);
428 void eibnx_comp_intr(ibt_cq_hdl_t, void *);
429 uint_t eibnx_comp_handler(caddr_t, caddr_t);
430
431 /*
432 * IBT related functions
433 */
434 int eibnx_ibt_init(eibnx_t *);
435 int eibnx_find_mgroups(eibnx_thr_info_t *);
436 int eibnx_setup_cq(eibnx_thr_info_t *);
437 int eibnx_setup_ud_channel(eibnx_thr_info_t *);
438 int eibnx_setup_bufs(eibnx_thr_info_t *);
439 int eibnx_setup_cq_handler(eibnx_thr_info_t *);
440 int eibnx_join_mcgs(eibnx_thr_info_t *);
441 int eibnx_rejoin_mcgs(eibnx_thr_info_t *);
442 int eibnx_ibt_fini(eibnx_t *);
443
444 void eibnx_rb_find_mgroups(eibnx_thr_info_t *);
445 void eibnx_rb_setup_cq(eibnx_thr_info_t *);
446 void eibnx_rb_setup_ud_channel(eibnx_thr_info_t *);
447 void eibnx_rb_setup_bufs(eibnx_thr_info_t *);
448 void eibnx_rb_setup_cq_handler(eibnx_thr_info_t *);
449 void eibnx_rb_join_mcgs(eibnx_thr_info_t *);
450
451 eibnx_hca_t *eibnx_prepare_hca(ib_guid_t);
452 int eibnx_cleanup_hca(eibnx_hca_t *);
453
454 /*
455 * FIP packetizing related functions
456 */
457 int eibnx_fip_solicit_mcast(eibnx_thr_info_t *);
458 int eibnx_fip_solicit_ucast(eibnx_thr_info_t *, clock_t *);
459 int eibnx_fip_parse_pkt(uint8_t *, eibnx_gw_msg_t *);
460
461 /*
462 * Queue and List related routines
463 */
464 eibnx_wqe_t *eibnx_acquire_swqe(eibnx_thr_info_t *, int);
465 void eibnx_return_swqe(eibnx_wqe_t *);
466 void eibnx_return_rwqe(eibnx_thr_info_t *, eibnx_wqe_t *);
467 void eibnx_release_swqe(eibnx_wqe_t *);
468
469 void eibnx_enqueue_child(eibnx_thr_info_t *, eibnx_gw_info_t *, char *,
470 dev_info_t *);
471 int eibnx_update_child(eibnx_thr_info_t *, eibnx_gw_info_t *, dev_info_t *);
472 dev_info_t *eibnx_find_child_dip_by_inst(eibnx_thr_info_t *, int);
473 dev_info_t *eibnx_find_child_dip_by_gw(eibnx_thr_info_t *, uint16_t);
474
475 eibnx_gw_info_t *eibnx_find_gw_in_gwlist(eibnx_thr_info_t *, eibnx_gw_info_t *);
476 eibnx_gw_info_t *eibnx_add_gw_to_gwlist(eibnx_thr_info_t *, eibnx_gw_info_t *,
477 ibt_wc_t *, uint8_t *);
478 void eibnx_replace_gw_in_gwlist(eibnx_thr_info_t *, eibnx_gw_info_t *,
479 eibnx_gw_info_t *, ibt_wc_t *, uint8_t *, boolean_t *);
480 void eibnx_queue_for_creation(eibnx_thr_info_t *, eibnx_gw_info_t *);
481
482 /*
483 * Logging and Error reporting routines
484 */
485 void eibnx_debug_init(void);
486 void eibnx_debug_fini(void);
487 void eibnx_dprintf_crit(const char *fmt, ...);
488 void eibnx_dprintf_err(const char *fmt, ...);
489 void eibnx_dprintf_warn(const char *fmt, ...);
490 #ifdef ENX_DEBUG
491 void eibnx_dprintf_debug(const char *fmt, ...);
492 void eibnx_dprintf_args(const char *fmt, ...);
493 void eibnx_dprintf_verbose(const char *fmt, ...);
494 #endif
495
496 /*
497 * Miscellaneous
498 */
499 void eibnx_cleanup_port_nodes(eibnx_thr_info_t *);
500 void eibnx_create_node_props(dev_info_t *, eibnx_thr_info_t *,
501 eibnx_gw_info_t *);
502 int eibnx_name_child(dev_info_t *, char *, size_t);
503 void eibnx_busop_inprog_enter(eibnx_t *);
504 void eibnx_busop_inprog_exit(eibnx_t *);
505 eibnx_thr_info_t *eibnx_start_port_monitor(eibnx_hca_t *, eibnx_port_t *);
506 void eibnx_stop_port_monitor(eibnx_thr_info_t *);
507 void eibnx_terminate_monitors(void);
508 int eibnx_configure_node(eibnx_thr_info_t *, eibnx_gw_info_t *, dev_info_t **);
509 int eibnx_unconfigure_node(eibnx_thr_info_t *, eibnx_gw_info_t *);
510 int eibnx_locate_node_name(char *, eibnx_thr_info_t **, eibnx_gw_info_t **);
511 int eibnx_locate_unconfigured_node(eibnx_thr_info_t **, eibnx_gw_info_t **);
512
513 /*
514 * Devctl cbops (currently dummy)
515 */
516 int eibnx_devctl_open(dev_t *, int, int, cred_t *);
517 int eibnx_devctl_close(dev_t, int, int, cred_t *);
518 int eibnx_devctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
519
520 /*
521 * External variable references
522 */
523 extern pri_t minclsyspri;
524 extern eibnx_t *enx_global_ss;
525 extern ib_gid_t enx_solicit_mgid;
526 extern ib_gid_t enx_advertise_mgid;
527
528 #ifdef __cplusplus
529 }
530 #endif
531
532 #endif /* _SYS_IB_EOIB_ENX_IMPL_H */