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/kmem.h> 28 #include <sys/conf.h> 29 #include <sys/ddi.h> 30 #include <sys/sunddi.h> 31 #include <sys/ksynch.h> 32 33 #include <sys/ib/clients/eoib/eib_impl.h> 34 35 /* 36 * Declarations private to this file 37 */ 38 static int eib_adm_setup_cq(eib_t *); 39 static int eib_adm_setup_ud_channel(eib_t *); 40 static void eib_adm_comp_intr(ibt_cq_hdl_t, void *); 41 static void eib_adm_rx_comp(eib_t *, eib_wqe_t *); 42 static void eib_adm_tx_comp(eib_t *, eib_wqe_t *); 43 static void eib_adm_err_comp(eib_t *, eib_wqe_t *, ibt_wc_t *); 44 static void eib_rb_adm_setup_cq(eib_t *); 45 static void eib_rb_adm_setup_ud_channel(eib_t *); 46 47 int 48 eib_adm_setup_qp(eib_t *ss, int *err) 49 { 50 eib_chan_t *chan; 51 ibt_status_t ret; 52 uint16_t pkey_ix; 53 54 /* 55 * Verify pkey 56 */ 57 ret = ibt_pkey2index(ss->ei_hca_hdl, ss->ei_props->ep_port_num, 58 EIB_ADMIN_PKEY, &pkey_ix); 59 if (ret != IBT_SUCCESS) { 60 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_qp: " 61 "ibt_pkey2index() failed, port_num=0x%x, " 62 "pkey=0x%x, ret=%d", ss->ei_props->ep_port_num, 63 EIB_ADMIN_PKEY, ret); 64 *err = ENONET; 65 goto adm_setup_qp_fail; 66 } 67 68 /* 69 * Allocate a eib_chan_t to store stuff about admin qp and 70 * initialize some basic stuff 71 */ 72 ss->ei_admin_chan = eib_chan_init(); 73 74 chan = ss->ei_admin_chan; 75 chan->ch_pkey = EIB_ADMIN_PKEY; 76 chan->ch_pkey_ix = pkey_ix; 77 chan->ch_vnic_inst = -1; 78 79 /* 80 * Setup a combined CQ and completion handler 81 */ 82 if (eib_adm_setup_cq(ss) != EIB_E_SUCCESS) { 83 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_qp: " 84 "eib_adm_setup_cq() failed"); 85 *err = ENOMEM; 86 goto adm_setup_qp_fail; 87 } 88 89 /* 90 * Setup UD channel 91 */ 92 if (eib_adm_setup_ud_channel(ss) != EIB_E_SUCCESS) { 93 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_qp: " 94 "eib_adm_setup_ud_channel() failed"); 95 *err = ENOMEM; 96 goto adm_setup_qp_fail; 97 } 98 99 /* 100 * Post initial set of rx buffers to the HCA 101 */ 102 if (eib_chan_post_rx(ss, chan, NULL) != EIB_E_SUCCESS) { 103 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_qp: " 104 "eib_chan_post_rx() failed"); 105 *err = ENOMEM; 106 goto adm_setup_qp_fail; 107 } 108 109 return (EIB_E_SUCCESS); 110 111 adm_setup_qp_fail: 112 eib_rb_adm_setup_qp(ss); 113 return (EIB_E_FAILURE); 114 } 115 116 /*ARGSUSED*/ 117 uint_t 118 eib_adm_comp_handler(caddr_t arg1, caddr_t arg2) 119 { 120 eib_t *ss = (eib_t *)(void *)arg1; 121 eib_chan_t *chan = ss->ei_admin_chan; 122 ibt_wc_t *wc; 123 eib_wqe_t *wqe; 124 ibt_status_t ret; 125 uint_t polled; 126 int i; 127 128 /* 129 * Re-arm the notification callback before we start polling 130 * the completion queue. There's nothing much we can do if the 131 * enable_cq_notify fails - we issue a warning and move on. 132 */ 133 ret = ibt_enable_cq_notify(chan->ch_cq_hdl, IBT_NEXT_COMPLETION); 134 if (ret != IBT_SUCCESS) { 135 EIB_DPRINTF_WARN(ss->ei_instance, "eib_adm_comp_handler: " 136 "ibt_enable_cq_notify() failed, ret=%d", ret); 137 } 138 139 /* 140 * Handle tx and rx completions 141 */ 142 while ((ret = ibt_poll_cq(chan->ch_cq_hdl, chan->ch_wc, chan->ch_cq_sz, 143 &polled)) == IBT_SUCCESS) { 144 for (wc = chan->ch_wc, i = 0; i < polled; i++, wc++) { 145 wqe = (eib_wqe_t *)(uintptr_t)wc->wc_id; 146 if (wc->wc_status != IBT_WC_SUCCESS) { 147 eib_adm_err_comp(ss, wqe, wc); 148 } else if (EIB_WQE_TYPE(wqe->qe_info) == EIB_WQE_RX) { 149 eib_adm_rx_comp(ss, wqe); 150 } else { 151 eib_adm_tx_comp(ss, wqe); 152 } 153 } 154 } 155 156 return (DDI_INTR_CLAIMED); 157 } 158 159 void 160 eib_rb_adm_setup_qp(eib_t *ss) 161 { 162 eib_rb_adm_setup_ud_channel(ss); 163 164 eib_rb_adm_setup_cq(ss); 165 166 eib_chan_fini(ss->ei_admin_chan); 167 ss->ei_admin_chan = NULL; 168 } 169 170 static int 171 eib_adm_setup_cq(eib_t *ss) 172 { 173 eib_chan_t *chan = ss->ei_admin_chan; 174 ibt_cq_attr_t cq_attr; 175 ibt_status_t ret; 176 uint_t sz; 177 int rv; 178 179 /* 180 * Allocate the admin completion queue for sending vnic logins and 181 * logouts and receiving vnic login acks. 182 */ 183 cq_attr.cq_sched = NULL; 184 cq_attr.cq_flags = IBT_CQ_NO_FLAGS; 185 if (ss->ei_hca_attrs->hca_max_cq_sz < EIB_ADMIN_CQ_SIZE) 186 cq_attr.cq_size = ss->ei_hca_attrs->hca_max_cq_sz; 187 else 188 cq_attr.cq_size = EIB_ADMIN_CQ_SIZE; 189 190 ret = ibt_alloc_cq(ss->ei_hca_hdl, &cq_attr, &chan->ch_cq_hdl, &sz); 191 if (ret != IBT_SUCCESS) { 192 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_cq: " 193 "ibt_alloc_cq(cq_sz=0x%lx) failed, ret=%d", 194 cq_attr.cq_size, ret); 195 goto adm_setup_cq_fail; 196 } 197 198 /* 199 * Set up other parameters for collecting completion information 200 */ 201 chan->ch_cq_sz = sz; 202 chan->ch_wc = kmem_zalloc(sizeof (ibt_wc_t) * sz, KM_SLEEP); 203 204 /* 205 * Allocate soft interrupt for the admin channel cq handler and 206 * set up the handler as well. 207 */ 208 if ((rv = ddi_intr_add_softint(ss->ei_dip, &ss->ei_admin_si_hdl, 209 EIB_SOFTPRI_ADM, eib_adm_comp_handler, ss)) != DDI_SUCCESS) { 210 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_cq: " 211 "ddi_intr_add_softint() failed for adm qp, ret=%d", rv); 212 goto adm_setup_cq_fail; 213 } 214 215 /* 216 * Now, set up the admin completion queue handler. 217 */ 218 ibt_set_cq_handler(chan->ch_cq_hdl, eib_adm_comp_intr, ss); 219 220 ret = ibt_enable_cq_notify(chan->ch_cq_hdl, IBT_NEXT_COMPLETION); 221 if (ret != IBT_SUCCESS) { 222 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_cq: " 223 "ibt_enable_cq_notify() failed, ret=%d", ret); 224 goto adm_setup_cq_fail; 225 } 226 227 return (EIB_E_SUCCESS); 228 229 adm_setup_cq_fail: 230 eib_rb_adm_setup_cq(ss); 231 return (EIB_E_FAILURE); 232 } 233 234 static int 235 eib_adm_setup_ud_channel(eib_t *ss) 236 { 237 eib_chan_t *chan = ss->ei_admin_chan; 238 ibt_ud_chan_alloc_args_t alloc_attr; 239 ibt_ud_chan_query_attr_t query_attr; 240 ibt_status_t ret; 241 242 bzero(&alloc_attr, sizeof (ibt_ud_chan_alloc_args_t)); 243 bzero(&query_attr, sizeof (ibt_ud_chan_query_attr_t)); 244 245 alloc_attr.ud_flags = IBT_ALL_SIGNALED; 246 alloc_attr.ud_hca_port_num = ss->ei_props->ep_port_num; 247 alloc_attr.ud_pkey_ix = chan->ch_pkey_ix; 248 alloc_attr.ud_sizes.cs_sq = EIB_ADMIN_MAX_SWQE; 249 alloc_attr.ud_sizes.cs_rq = EIB_ADMIN_MAX_RWQE; 250 alloc_attr.ud_sizes.cs_sq_sgl = 1; 251 alloc_attr.ud_sizes.cs_rq_sgl = 1; 252 alloc_attr.ud_sizes.cs_inline = 0; 253 254 alloc_attr.ud_qkey = EIB_FIP_QKEY; 255 alloc_attr.ud_scq = chan->ch_cq_hdl; 256 alloc_attr.ud_rcq = chan->ch_cq_hdl; 257 alloc_attr.ud_pd = ss->ei_pd_hdl; 258 259 ret = ibt_alloc_ud_channel(ss->ei_hca_hdl, IBT_ACHAN_NO_FLAGS, 260 &alloc_attr, &chan->ch_chan, NULL); 261 if (ret != IBT_SUCCESS) { 262 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_ud_channel: " 263 "ibt_alloc_ud_channel(port=0x%x, pkey_ix=0x%x) " 264 "failed, ret=%d", alloc_attr.ud_hca_port_num, 265 chan->ch_pkey_ix, ret); 266 goto adm_setup_ud_channel_fail; 267 } 268 269 ret = ibt_query_ud_channel(chan->ch_chan, &query_attr); 270 if (ret != IBT_SUCCESS) { 271 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_setup_ud_channel: " 272 "ibt_query_ud_channel() failed, ret=%d", ret); 273 goto adm_setup_ud_channel_fail; 274 } 275 276 chan->ch_qpn = query_attr.ud_qpn; 277 chan->ch_max_swqes = query_attr.ud_chan_sizes.cs_sq; 278 chan->ch_max_rwqes = query_attr.ud_chan_sizes.cs_rq; 279 chan->ch_lwm_rwqes = chan->ch_max_rwqes >> 2; 280 chan->ch_rwqe_bktsz = chan->ch_max_rwqes; 281 chan->ch_ip_hdr_align = 0; 282 chan->ch_alloc_mp = B_FALSE; 283 chan->ch_tear_down = B_FALSE; 284 285 return (EIB_E_SUCCESS); 286 287 adm_setup_ud_channel_fail: 288 eib_rb_adm_setup_ud_channel(ss); 289 return (EIB_E_FAILURE); 290 } 291 292 static void 293 eib_adm_comp_intr(ibt_cq_hdl_t cq_hdl, void *arg) 294 { 295 eib_t *ss = arg; 296 eib_chan_t *chan = ss->ei_admin_chan; 297 298 if (cq_hdl != chan->ch_cq_hdl) { 299 EIB_DPRINTF_DEBUG(ss->ei_instance, "eib_adm_comp_intr: " 300 "cq_hdl(0x%llx) != chan->ch_cq_hdl(0x%llx), " 301 "ignoring completion", cq_hdl, chan->ch_cq_hdl); 302 return; 303 } 304 305 ASSERT(ss->ei_admin_si_hdl != NULL); 306 307 (void) ddi_intr_trigger_softint(ss->ei_admin_si_hdl, NULL); 308 } 309 310 static void 311 eib_adm_rx_comp(eib_t *ss, eib_wqe_t *wqe) 312 { 313 eib_chan_t *chan = ss->ei_admin_chan; 314 eib_login_data_t ld; 315 uint8_t *pkt = (uint8_t *)(uintptr_t)(wqe->qe_sgl.ds_va); 316 ibt_status_t ret; 317 318 /* 319 * Skip the GRH and parse the login ack message in the packet 320 */ 321 if (eib_fip_parse_login_ack(ss, pkt + EIB_GRH_SZ, &ld) == EIB_E_SUCCESS) 322 eib_vnic_login_ack(ss, &ld); 323 324 /* 325 * Try to repost the rwqe. For admin channel, we can take the shortcut 326 * and not go through eib_chan_post_recv(), since we know that the 327 * qe_info flag, qe_chan and qe_vinst are all already set correctly; we 328 * just took this out of the rx queue, so the ch_rx_posted will be ok 329 * if we just posted it back. And there are no mblk allocation or 330 * buffer alignment restrictions for this channel as well. 331 */ 332 if (chan->ch_tear_down) { 333 eib_rsrc_return_rwqe(ss, wqe, chan); 334 } else { 335 ret = ibt_post_recv(chan->ch_chan, &(wqe->qe_wr.recv), 1, NULL); 336 if (ret != IBT_SUCCESS) { 337 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_rx_comp: " 338 "ibt_post_recv() failed, ret=%d", ret); 339 eib_rsrc_return_rwqe(ss, wqe, chan); 340 } 341 } 342 } 343 344 static void 345 eib_adm_tx_comp(eib_t *ss, eib_wqe_t *wqe) 346 { 347 eib_rsrc_return_swqe(ss, wqe, ss->ei_admin_chan); 348 } 349 350 /*ARGSUSED*/ 351 static void 352 eib_adm_err_comp(eib_t *ss, eib_wqe_t *wqe, ibt_wc_t *wc) 353 { 354 /* 355 * Currently, all we do is report 356 */ 357 switch (wc->wc_status) { 358 case IBT_WC_WR_FLUSHED_ERR: 359 break; 360 361 case IBT_WC_LOCAL_CHAN_OP_ERR: 362 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_err_comp: " 363 "IBT_WC_LOCAL_CHAN_OP_ERR seen, wqe_info=0x%lx ", 364 wqe->qe_info); 365 break; 366 367 case IBT_WC_LOCAL_PROTECT_ERR: 368 EIB_DPRINTF_ERR(ss->ei_instance, "eib_adm_err_comp: " 369 "IBT_WC_LOCAL_PROTECT_ERR seen, wqe_info=0x%lx ", 370 wqe->qe_info); 371 break; 372 } 373 374 /* 375 * When a wc indicates error, we do not attempt to repost but 376 * simply return it to the wqe pool. 377 */ 378 if (EIB_WQE_TYPE(wqe->qe_info) == EIB_WQE_RX) 379 eib_rsrc_return_rwqe(ss, wqe, ss->ei_admin_chan); 380 else 381 eib_rsrc_return_swqe(ss, wqe, ss->ei_admin_chan); 382 } 383 384 static void 385 eib_rb_adm_setup_cq(eib_t *ss) 386 { 387 eib_chan_t *chan = ss->ei_admin_chan; 388 ibt_status_t ret; 389 390 if (chan == NULL) 391 return; 392 393 /* 394 * Reset any completion handler we may have set up 395 */ 396 if (chan->ch_cq_hdl) 397 ibt_set_cq_handler(chan->ch_cq_hdl, NULL, NULL); 398 399 /* 400 * Remove any softint we may have allocated for the admin cq 401 */ 402 if (ss->ei_admin_si_hdl) { 403 (void) ddi_intr_remove_softint(ss->ei_admin_si_hdl); 404 ss->ei_admin_si_hdl = NULL; 405 } 406 407 /* 408 * Release any work completion buffers we may have allocated 409 */ 410 if (chan->ch_wc && chan->ch_cq_sz) 411 kmem_free(chan->ch_wc, sizeof (ibt_wc_t) * chan->ch_cq_sz); 412 413 chan->ch_cq_sz = 0; 414 chan->ch_wc = NULL; 415 416 /* 417 * Free any completion queue we may have allocated 418 */ 419 if (chan->ch_cq_hdl) { 420 ret = ibt_free_cq(chan->ch_cq_hdl); 421 if (ret != IBT_SUCCESS) { 422 EIB_DPRINTF_WARN(ss->ei_instance, 423 "eib_rb_adm_setup_cq: " 424 "ibt_free_cq() failed, ret=%d", ret); 425 } 426 chan->ch_cq_hdl = NULL; 427 } 428 } 429 430 static void 431 eib_rb_adm_setup_ud_channel(eib_t *ss) 432 { 433 eib_chan_t *chan = ss->ei_admin_chan; 434 ibt_status_t ret; 435 436 if (chan == NULL) 437 return; 438 439 if (chan->ch_chan) { 440 /* 441 * We're trying to tear down this UD channel. Make sure that 442 * we don't attempt to refill (repost) at any point from now on. 443 */ 444 chan->ch_tear_down = B_TRUE; 445 if ((ret = ibt_flush_channel(chan->ch_chan)) != IBT_SUCCESS) { 446 EIB_DPRINTF_WARN(ss->ei_instance, 447 "eib_rb_adm_setup_ud_channel: " 448 "ibt_flush_channel() failed, ret=%d", ret); 449 } 450 451 /* 452 * Wait until all posted tx wqes on this channel are back with 453 * the wqe pool. 454 */ 455 mutex_enter(&chan->ch_tx_lock); 456 while (chan->ch_tx_posted > 0) 457 cv_wait(&chan->ch_tx_cv, &chan->ch_tx_lock); 458 mutex_exit(&chan->ch_tx_lock); 459 460 /* 461 * Wait until all posted rx wqes on this channel are back with 462 * the wqe pool. 463 */ 464 mutex_enter(&chan->ch_rx_lock); 465 while (chan->ch_rx_posted > 0) 466 cv_wait(&chan->ch_rx_cv, &chan->ch_rx_lock); 467 mutex_exit(&chan->ch_rx_lock); 468 469 /* 470 * Now we're ready to free this channel 471 */ 472 if ((ret = ibt_free_channel(chan->ch_chan)) != IBT_SUCCESS) { 473 EIB_DPRINTF_WARN(ss->ei_instance, 474 "eib_rb_adm_setup_ud_channel: " 475 "ibt_free_channel() failed, ret=%d", ret); 476 } 477 478 chan->ch_alloc_mp = B_FALSE; 479 chan->ch_ip_hdr_align = 0; 480 chan->ch_rwqe_bktsz = 0; 481 chan->ch_lwm_rwqes = 0; 482 chan->ch_max_rwqes = 0; 483 chan->ch_max_swqes = 0; 484 chan->ch_qpn = 0; 485 chan->ch_chan = NULL; 486 } 487 } 488