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 #include <sys/types.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/ksynch.h>
30 #include <sys/byteorder.h>
31
32 #include <sys/ib/clients/eoib/enx_impl.h>
33
34 const char fip_vendor_mellanox[] = {
35 0x4d, 0x65, 0x6c, 0x6c, 0x61, 0x6e, 0x6f, 0x78
36 };
37
38 /*
39 * HW/FW workaround
40 *
41 * Verification of descriptor list length in the received packets is
42 * disabled, since experimentation shows that BX does not set the desc
43 * list length correctly.
44 */
45 int enx_wa_no_desc_list_len = 1;
46
47 /*
48 * Static function declarations
49 */
50 static int eibnx_fip_make_solicit_pkt(eibnx_thr_info_t *, eibnx_wqe_t *);
51 static int eibnx_fip_send_solicit_pkt(eibnx_thr_info_t *, eibnx_wqe_t *,
52 eibnx_gw_addr_t *);
53 static int eibnx_fip_parse_advt_pkt(uint8_t *, eibnx_gw_msg_t *);
54 static void eibnx_rb_fip_make_solicit_pkt(eibnx_wqe_t *);
55
56 /*
57 * Prepare and send a solicit multicast packet to the All-EoIB-GWs-GID
58 */
59 int
eibnx_fip_solicit_mcast(eibnx_thr_info_t * info)60 eibnx_fip_solicit_mcast(eibnx_thr_info_t *info)
61 {
62 eibnx_wqe_t *swqe;
63 int ret;
64
65 if ((swqe = eibnx_acquire_swqe(info, KM_SLEEP)) == NULL)
66 return (ENX_E_FAILURE);
67
68 ret = eibnx_fip_make_solicit_pkt(info, swqe);
69 if (ret != ENX_E_SUCCESS) {
70 eibnx_release_swqe(swqe);
71 return (ENX_E_FAILURE);
72 }
73
74 ret = eibnx_fip_send_solicit_pkt(info, swqe, NULL);
75 if (ret != ENX_E_SUCCESS) {
76 eibnx_rb_fip_make_solicit_pkt(swqe);
77 eibnx_release_swqe(swqe);
78 return (ENX_E_FAILURE);
79 }
80
81 return (ENX_E_SUCCESS);
82 }
83
84 /*
85 * Go through the list of already discovered gateways and send
86 * a unicast solicitation to each gateway. This is required by
87 * the EoIB specification ostensibly to receive updated
88 * advertisements.
89 */
90 int
eibnx_fip_solicit_ucast(eibnx_thr_info_t * info,clock_t * solicit_period_ticks)91 eibnx_fip_solicit_ucast(eibnx_thr_info_t *info, clock_t *solicit_period_ticks)
92 {
93 eibnx_gw_info_t *gw;
94 eibnx_wqe_t *swqe;
95 clock_t min_solicit_period_msec;
96 int ret;
97
98 /*
99 * We want to read the gwlist and send a unicast to each
100 * destination. Now, the only places where the gw list pointers
101 * are updated are when we're adding a new gw item to the list
102 * and when the list is being torn down and freed.
103 *
104 * Since new GWs are always inserted at the head of the list,
105 * we're guaranteed that any tail subchain of the list will
106 * not change by the addition of a new gw item coming into
107 * the list.
108 *
109 * Also, since the gw list is torn down only by the port-monitor
110 * thread (i.e. ourselves), we are also protected against the
111 * list itself going away while we're here.
112 *
113 * Given these two constraints, we can safely read the list
114 * of gateways without the gw list lock in this routine.
115 */
116 min_solicit_period_msec = drv_hztousec(*solicit_period_ticks) / 1000;
117 for (gw = info->ti_gw; gw; gw = gw->gw_next) {
118
119 if (eibnx_is_gw_dead(gw))
120 continue;
121
122 swqe = gw->gw_swqe;
123 ASSERT(swqe != NULL);
124
125 mutex_enter(&swqe->qe_lock);
126 if (swqe->qe_type != ENX_QETYP_SWQE) {
127 ENX_DPRINTF_DEBUG("eibnx_fip_solicit_ucast: "
128 "gw wqe type (0x%lx) indicates this is not an "
129 "swqe!, cannot send solicitation to gw",
130 swqe->qe_type);
131 mutex_exit(&swqe->qe_lock);
132 continue;
133 } else if ((swqe->qe_flags & ENX_QEFL_INUSE) !=
134 ENX_QEFL_INUSE) {
135 ENX_DPRINTF_DEBUG("eibnx_fip_solicit_ucast: "
136 "gw swqe flags (0x%lx) indicate swqe is free!, "
137 "cannot send solicitation to gw", swqe->qe_flags);
138 mutex_exit(&swqe->qe_lock);
139 continue;
140 } else if ((swqe->qe_flags & ENX_QEFL_POSTED) ==
141 ENX_QEFL_POSTED) {
142 ENX_DPRINTF_DEBUG("eibnx_fip_solicit_ucast: gw swqe "
143 "flags (0x%lx) indicate swqe is still with HCA!, "
144 "cannot send solicitation to gw", swqe->qe_flags);
145 mutex_exit(&swqe->qe_lock);
146 continue;
147 }
148 mutex_exit(&swqe->qe_lock);
149
150 /*
151 * EoIB spec requires that each host send solicitation
152 * to discovered gateways atleast every 4 * GW_ADV_PERIOD.
153 * We make sure we send a solicitation to all gateways
154 * every 4 * GW_ADV_PERIOD of the smallest value of
155 * GW_ADV_PERIOD that we have in our gw list.
156 */
157 if ((gw->gw_adv_period * 4) < min_solicit_period_msec)
158 min_solicit_period_msec = gw->gw_adv_period * 4;
159
160 ret = eibnx_fip_make_solicit_pkt(info, swqe);
161 if (ret != ENX_E_SUCCESS)
162 continue;
163
164 ret = eibnx_fip_send_solicit_pkt(info, swqe, &gw->gw_addr);
165 if (ret != ENX_E_SUCCESS)
166 eibnx_rb_fip_make_solicit_pkt(swqe);
167 }
168
169 *solicit_period_ticks = drv_usectohz(min_solicit_period_msec * 1000);
170
171 return (ENX_E_SUCCESS);
172 }
173
174 /*
175 * Given a send wqe and an eibnx_thr_info_t pointer, fill in the
176 * send buffer with a solicit packet in the network byte order.
177 */
178 static int
eibnx_fip_make_solicit_pkt(eibnx_thr_info_t * info,eibnx_wqe_t * swqe)179 eibnx_fip_make_solicit_pkt(eibnx_thr_info_t *info, eibnx_wqe_t *swqe)
180 {
181 fip_solicit_t *solicit;
182 fip_proto_t *proto;
183 fip_basic_hdr_t *hdr;
184 fip_desc_iba_t *iba;
185 ib_gid_t port_gid;
186 ib_guid_t port_guid;
187
188 uint8_t *pkt = (uint8_t *)(uintptr_t)(swqe->qe_sgl.ds_va);
189 uint_t pktsz = swqe->qe_sgl.ds_len;
190 uint_t solicit_sz = sizeof (fip_solicit_t);
191
192 if (pktsz < solicit_sz) {
193 ENX_DPRINTF_ERR("swqe bufsize too small for pkt, "
194 "pktsz=%x < expsz=%x", pktsz, solicit_sz);
195 return (ENX_E_FAILURE);
196 }
197
198 /*
199 * Lint complains that there may be an alignment issue here,
200 * but we know that the "pkt" is atleast double-word aligned,
201 * so it's ok.
202 */
203 solicit = (fip_solicit_t *)pkt;
204
205 /*
206 * Fill in the FIP protocol version
207 */
208 proto = &solicit->sl_proto_version;
209 proto->pr_version = FIP_PROTO_VERSION;
210
211 /*
212 * Fill in the basic header
213 */
214 hdr = &solicit->sl_fip_hdr;
215 hdr->hd_opcode = htons(FIP_OPCODE_EOIB);
216 hdr->hd_subcode = FIP_SUBCODE_H_SOLICIT;
217 hdr->hd_desc_list_len = htons((solicit_sz >> 2) - 2);
218 hdr->hd_flags = 0;
219 hdr->hd_type = FIP_DESC_TYPE_VENDOR_ID;
220 hdr->hd_len = FIP_DESC_LEN_VENDOR_ID;
221 bcopy(fip_vendor_mellanox, hdr->hd_vendor_id, FIP_VENDOR_LEN);
222
223 /*
224 * Fill in the Infiniband Address descriptor
225 */
226 iba = &solicit->sl_iba;
227 iba->ia_type = FIP_DESC_TYPE_IBA;
228 iba->ia_len = FIP_DESC_LEN_IBA;
229 bcopy(fip_vendor_mellanox, iba->ia_vendor_id, FIP_VENDOR_LEN);
230 iba->ia_qpn = htonl(info->ti_qpn);
231 iba->ia_sl_portid = 0;
232 iba->ia_lid = htons(info->ti_pi->p_base_lid);
233 port_gid = info->ti_pi->p_sgid_tbl[0];
234 port_guid = htonll(port_gid.gid_guid);
235 bcopy(&port_guid, iba->ia_guid, FIP_GUID_LEN);
236
237 /*
238 * Adjust the ds_len in the sgl to indicate the size of the
239 * solicit pkt before returning
240 */
241 swqe->qe_sgl.ds_len = solicit_sz;
242
243 return (ENX_E_SUCCESS);
244 }
245
246 static int
eibnx_setup_ud_dest(eibnx_thr_info_t * info,eibnx_wqe_t * swqe,eibnx_gw_addr_t * gw_addr)247 eibnx_setup_ud_dest(eibnx_thr_info_t *info, eibnx_wqe_t *swqe,
248 eibnx_gw_addr_t *gw_addr)
249 {
250 eibnx_t *ss = enx_global_ss;
251 ibt_path_attr_t attr;
252 ibt_path_info_t path;
253 ibt_status_t ret;
254
255 /*
256 * If this a multicast send, we'll have the gateway address NULL,
257 * and we'll need to modify the UD destination to send to the
258 * solicit mcg.
259 */
260 if (gw_addr == NULL) {
261 ret = ibt_modify_ud_dest(swqe->qe_wr.send.wr.ud.udwr_dest,
262 info->ti_solicit_mcg->mc_qkey, IB_MC_QPN,
263 &info->ti_solicit_mcg->mc_adds_vect);
264 if (ret != IBT_SUCCESS) {
265 ENX_DPRINTF_ERR("ibt_modify_ud_dest() failed with "
266 "ret=%d, qkey=%x, qpn=%x", ret,
267 info->ti_solicit_mcg->mc_qkey, IB_MC_QPN);
268 return (ENX_E_FAILURE);
269 }
270
271 return (ENX_E_SUCCESS);
272 }
273
274 /*
275 * If this is a unicast send, but we already have the gw address
276 * vector, the ud destination handle has already been set up for
277 * this gateway, so we can return.
278 */
279 if (gw_addr->ga_vect)
280 return (ENX_E_SUCCESS);
281
282 /*
283 * Get the reversible path information for this gateway
284 */
285 bzero(&attr, sizeof (ibt_path_info_t));
286 attr.pa_dgids = &gw_addr->ga_gid;
287 attr.pa_num_dgids = 1;
288 attr.pa_sgid = info->ti_pi->p_sgid_tbl[0];
289 attr.pa_pkey = gw_addr->ga_pkey;
290
291 bzero(&path, sizeof (ibt_path_info_t));
292 ret = ibt_get_paths(ss->nx_ibt_hdl, IBT_PATH_PKEY,
293 &attr, 1, &path, NULL);
294 if ((ret != IBT_SUCCESS) || (path.pi_hca_guid == 0)) {
295 ENX_DPRINTF_ERR("ibt_get_paths() failed with "
296 "ret=%d, gid_prefix=%llx, gid_guid=%llx", ret,
297 gw_addr->ga_gid.gid_prefix, gw_addr->ga_gid.gid_guid);
298 return (ENX_E_FAILURE);
299 }
300
301 /*
302 * And save the address vector
303 */
304 gw_addr->ga_vect = kmem_zalloc(sizeof (ibt_adds_vect_t), KM_SLEEP);
305 bcopy(&path.pi_prim_cep_path.cep_adds_vect, gw_addr->ga_vect,
306 sizeof (ibt_adds_vect_t));
307
308 /*
309 * Modify the UD destination handle on this swqe entry to address
310 * this gateway
311 */
312 ret = ibt_modify_ud_dest(swqe->qe_wr.send.wr.ud.udwr_dest,
313 gw_addr->ga_qkey, gw_addr->ga_qpn, gw_addr->ga_vect);
314 if (ret != IBT_SUCCESS) {
315 ENX_DPRINTF_ERR("ibt_modify_ud_dest() failed with "
316 "ret=%d, qkey=%x, qpn=%x", ret, gw_addr->ga_qkey,
317 gw_addr->ga_qpn);
318 kmem_free(gw_addr->ga_vect, sizeof (ibt_adds_vect_t));
319 gw_addr->ga_vect = NULL;
320 return (ENX_E_FAILURE);
321 }
322
323 return (ENX_E_SUCCESS);
324 }
325
326 /*
327 * Send a solicit packet to the appropriate destination: if the
328 * destination gw addr is specified, send a unicast message to it;
329 * if not, send a multicast using the solicit mcg address.
330 */
331 static int
eibnx_fip_send_solicit_pkt(eibnx_thr_info_t * info,eibnx_wqe_t * swqe,eibnx_gw_addr_t * gw_addr)332 eibnx_fip_send_solicit_pkt(eibnx_thr_info_t *info, eibnx_wqe_t *swqe,
333 eibnx_gw_addr_t *gw_addr)
334 {
335 ibt_status_t ret;
336
337 if (eibnx_setup_ud_dest(info, swqe, gw_addr) != ENX_E_SUCCESS)
338 return (ENX_E_FAILURE);
339
340 mutex_enter(&swqe->qe_lock);
341
342 /*
343 * Note that if the post send fails, we don't really need to undo
344 * anything we did in setting up the ud destination; we can always
345 * use it for the next time.
346 */
347 ret = ibt_post_send(info->ti_chan, &(swqe->qe_wr.send), 1, NULL);
348 if (ret != IBT_SUCCESS) {
349 mutex_exit(&swqe->qe_lock);
350 ENX_DPRINTF_ERR("ibt_post_send() failed for solicit, "
351 "ret=%d", ret);
352 return (ENX_E_FAILURE);
353 }
354
355 /*
356 * Set the 'posted' flag for the send wqe. If this is an unicast
357 * send, the wqe is attached to a specific gw entry and we should
358 * not release the wqe back to the pool on the send completion.
359 */
360 swqe->qe_flags |= ENX_QEFL_POSTED;
361 if (gw_addr == NULL) {
362 swqe->qe_flags |= ENX_QEFL_RELONCOMP;
363 info->ti_mcast_done = 1;
364 }
365
366 mutex_exit(&swqe->qe_lock);
367
368 return (ENX_E_SUCCESS);
369 }
370
371 /*
372 * Parse a received packet from the gateway into the
373 * eibnx_gw_msg_t argument. Note that at this point, this
374 * driver only expects to receive advertisements from the
375 * GW, nothing else.
376 */
377 int
eibnx_fip_parse_pkt(uint8_t * pkt,eibnx_gw_msg_t * msg)378 eibnx_fip_parse_pkt(uint8_t *pkt, eibnx_gw_msg_t *msg)
379 {
380 fip_basic_hdr_t *hdr;
381 uint16_t opcode;
382 uint8_t subcode;
383 int ret = ENX_E_FAILURE;
384
385 /*
386 * Lint complains about potential alignment problem here,
387 * but the fip_* structures are all packed and each of them
388 * is aligned on a word boundary, so we're ok.
389 */
390 hdr = (fip_basic_hdr_t *)(pkt + sizeof (fip_proto_t));
391
392 /*
393 * Verify that the opcode is EoIB
394 */
395 if ((opcode = ntohs(hdr->hd_opcode)) != FIP_OPCODE_EOIB) {
396 ENX_DPRINTF_WARN("unsupported opcode (%x) found in "
397 "gw advertisement, ignoring", opcode);
398 return (ENX_E_FAILURE);
399 }
400
401 /*
402 * We only handle GW advertisements in the eibnx driver code. However,
403 * the BridgeX gateway software currently sends login acknowledgements
404 * to the one who did the solicitation instead of the one who actually
405 * made the login request, so we need to do something about this as
406 * well.
407 */
408 subcode = hdr->hd_subcode;
409 switch (subcode) {
410 case FIP_SUBCODE_G_ADVERTISE:
411 ret = eibnx_fip_parse_advt_pkt(pkt, msg);
412 break;
413
414 case FIP_SUBCODE_G_VNIC_LOGIN_ACK:
415 msg->gm_type = FIP_VNIC_LOGIN_ACK;
416 ret = ENX_E_SUCCESS;
417 break;
418
419 default:
420 ENX_DPRINTF_WARN("unsupported subcode (%x) found in "
421 "gw advertisement, ignoring", subcode);
422 ret = ENX_E_FAILURE;
423 break;
424 }
425
426 return (ret);
427 }
428
429 /*
430 * Parse and validate a packet known to be an advertisement from
431 * the GW.
432 */
433 static int
eibnx_fip_parse_advt_pkt(uint8_t * pkt,eibnx_gw_msg_t * msg)434 eibnx_fip_parse_advt_pkt(uint8_t *pkt, eibnx_gw_msg_t *msg)
435 {
436 fip_advertise_t *advertise;
437 fip_basic_hdr_t *hdr;
438 fip_desc_iba_t *desc_iba;
439 fip_desc_gwinfo_t *desc_gwinfo;
440 fip_desc_gwid_t *desc_gwid;
441 fip_desc_keepalive_t *desc_ka;
442 eibnx_gw_info_t *gwi;
443 ib_guid_t guid;
444 uint16_t rss_qpn_num_net_vnics;
445 uint16_t sl_portid;
446 uint16_t flags;
447
448 /*
449 * Lint complains about potential alignment problem here,
450 * but we know that "pkt" is always atleast double-word
451 * aligned when it's passed to us, so we're ok.
452 */
453 advertise = (fip_advertise_t *)pkt;
454
455 /*
456 * Verify if the descriptor list length in the received
457 * packet is valid. Currently disabled.
458 *
459 * Experimentation shows that BX doesn't set the desc list
460 * length correctly, so we also simply ignore it and move
461 * on. If and when BX fixes this problem, we'll need to
462 * enable the warning+failure below.
463 */
464 hdr = &(advertise->ad_fip_header);
465 if (!enx_wa_no_desc_list_len) {
466 uint_t pkt_data_sz;
467
468 pkt_data_sz = (ntohs(hdr->hd_desc_list_len) + 2) << 2;
469 if (pkt_data_sz < sizeof (fip_advertise_t)) {
470 ENX_DPRINTF_WARN("advertisement from gw too small; "
471 "expected %x, got %x", sizeof (fip_advertise_t),
472 pkt_data_sz);
473 return (ENX_E_FAILURE);
474 }
475 }
476
477 /*
478 * Validate all the header and descriptor types and lengths
479 */
480
481 if (hdr->hd_type != FIP_DESC_TYPE_VENDOR_ID ||
482 hdr->hd_len != FIP_DESC_LEN_VENDOR_ID) {
483 ENX_DPRINTF_WARN("invalid type/len in fip basic header; "
484 "expected (%x,%x), got (%x,%x)", FIP_DESC_TYPE_VENDOR_ID,
485 FIP_DESC_LEN_VENDOR_ID, hdr->hd_type, hdr->hd_len);
486 return (ENX_E_FAILURE);
487 }
488
489 desc_iba = &(advertise->ad_iba);
490 if (desc_iba->ia_type != FIP_DESC_TYPE_IBA ||
491 desc_iba->ia_len != FIP_DESC_LEN_IBA) {
492 ENX_DPRINTF_WARN("invalid type/len in fip iba desc; "
493 "expected (%x,%x), got (%x,%x)", FIP_DESC_TYPE_IBA,
494 FIP_DESC_LEN_IBA, desc_iba->ia_type, desc_iba->ia_len);
495 return (ENX_E_FAILURE);
496 }
497
498 desc_gwinfo = &(advertise->ad_gwinfo);
499 if (desc_gwinfo->gi_type != FIP_DESC_TYPE_EOIB_GW_INFO ||
500 desc_gwinfo->gi_len != FIP_DESC_LEN_EOIB_GW_INFO) {
501 ENX_DPRINTF_WARN("invalid type/len in fip gwinfo desc; "
502 "expected (%x,%x), got (%x,%x)",
503 FIP_DESC_TYPE_EOIB_GW_INFO, FIP_DESC_LEN_EOIB_GW_INFO,
504 desc_gwinfo->gi_type, desc_gwinfo->gi_len);
505 return (ENX_E_FAILURE);
506 }
507
508 desc_gwid = &(advertise->ad_gwid);
509 if (desc_gwid->id_type != FIP_DESC_TYPE_GW_ID ||
510 desc_gwid->id_len != FIP_DESC_LEN_GW_ID) {
511 ENX_DPRINTF_WARN("invalid type/len in fip gwid desc; "
512 "expected (%x,%x), got (%x,%x)",
513 FIP_DESC_TYPE_GW_ID, FIP_DESC_LEN_GW_ID,
514 desc_gwid->id_type, desc_gwid->id_len);
515 return (ENX_E_FAILURE);
516 }
517
518 desc_ka = &(advertise->ad_keep_alive);
519 if (desc_ka->ka_type != FIP_DESC_TYPE_KEEP_ALIVE ||
520 desc_ka->ka_len != FIP_DESC_LEN_KEEP_ALIVE) {
521 ENX_DPRINTF_WARN("invalid type/len in fip ka desc; "
522 "expected (%x,%x), got (%x,%x)",
523 FIP_DESC_TYPE_KEEP_ALIVE, FIP_DESC_LEN_KEEP_ALIVE,
524 desc_ka->ka_type, desc_ka->ka_len);
525 return (ENX_E_FAILURE);
526 }
527
528 /*
529 * Record if the gw is available for login ('A' bit in the header)
530 */
531 flags = ntohs(hdr->hd_flags);
532 gwi = &(msg->u.gm_info);
533 gwi->gw_flag_available = (flags & FIP_BHFLAG_GWAVAIL) ? 1 : 0;
534
535 /*
536 * Record if this was in response to a solicit request (unicast
537 * advertisement) or not ('S' bit in the header)
538 */
539 gwi->gw_flag_ucast_advt = (flags & FIP_BHFLAG_SLCTMSG) ? 1 : 0;
540 msg->gm_type = (gwi->gw_flag_ucast_advt) ?
541 FIP_GW_ADVERTISE_UCAST : FIP_GW_ADVERTISE_MCAST;
542
543 /*
544 * Record all info from the Infiniband Address descriptor
545 */
546 gwi->gw_ctrl_qpn = (ntohl(desc_iba->ia_qpn) & FIP_IBA_QPN_MASK);
547
548 sl_portid = ntohs(desc_iba->ia_sl_portid);
549 gwi->gw_portid = (sl_portid & FIP_IBA_PORTID_MASK);
550 gwi->gw_sl = ((sl_portid & FIP_IBA_SL_MASK) >> FIP_IBA_SL_SHIFT);
551
552 gwi->gw_lid = ntohs(desc_iba->ia_lid);
553
554 bcopy(desc_iba->ia_guid, &guid, sizeof (ib_guid_t));
555 gwi->gw_guid = ntohll(guid);
556
557 /*
558 * Record all info from the EoIB GW Information descriptor
559 */
560 if (desc_gwinfo->gi_flags & FIP_GWI_HOST_ADMIND_VNICS_MASK)
561 gwi->gw_is_host_adm_vnics = 1;
562 else
563 gwi->gw_is_host_adm_vnics = 0;
564
565 rss_qpn_num_net_vnics = ntohs(desc_gwinfo->gi_rss_qpn_num_net_vnics);
566 gwi->gw_num_net_vnics = (rss_qpn_num_net_vnics &
567 FIP_GWI_NUM_NET_VNICS_MASK);
568 gwi->gw_n_rss_qpn = ((rss_qpn_num_net_vnics &
569 FIP_GWI_RSS_QPN_MASK) >> FIP_GWI_RSS_QPN_SHIFT);
570 bcopy(desc_gwinfo->gi_vendor_id, gwi->gw_vendor_id, FIP_VENDOR_LEN);
571 (gwi->gw_vendor_id)[FIP_VENDOR_LEN] = '\0';
572
573 /*
574 * Record all info from the Gateway Identifier descriptor
575 */
576 bcopy(desc_gwid->id_guid, &guid, sizeof (ib_guid_t));
577 gwi->gw_system_guid = ntohll(guid);
578 bcopy(desc_gwid->id_sysname, gwi->gw_system_name, FIP_SYSNAME_LEN);
579 (gwi->gw_system_name)[FIP_SYSNAME_LEN] = '\0';
580 bcopy(desc_gwid->id_portname, gwi->gw_port_name, FIP_PORTNAME_LEN);
581 (gwi->gw_port_name)[FIP_PORTNAME_LEN] = '\0';
582
583 /*
584 * Record all info from the Keep Alive descriptor
585 */
586 gwi->gw_adv_period = ntohl(desc_ka->ka_gw_adv_period);
587 gwi->gw_ka_period = ntohl(desc_ka->ka_gw_ka_period);
588 gwi->gw_vnic_ka_period = ntohl(desc_ka->ka_vnic_ka_period);
589
590 gwi->gw_next = NULL;
591
592 return (ENX_E_SUCCESS);
593 }
594
595 /*
596 * Rollback whatever we did for making a solicit packet
597 */
598 static void
eibnx_rb_fip_make_solicit_pkt(eibnx_wqe_t * swqe)599 eibnx_rb_fip_make_solicit_pkt(eibnx_wqe_t *swqe)
600 {
601 uint8_t *pkt = (uint8_t *)(uintptr_t)(swqe->qe_sgl.ds_va);
602
603 bzero(pkt, sizeof (fip_solicit_t));
604 swqe->qe_sgl.ds_len = swqe->qe_bufsz;
605 }
606