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) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Infiniband Device Management Agent for IB storage. 28 */ 29 30 #include <sys/conf.h> 31 #include <sys/file.h> 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/modctl.h> 35 #include <sys/priv.h> 36 #include <sys/sysmacros.h> 37 38 #include <sys/ib/ibtl/ibti.h> /* IB public interfaces */ 39 40 #include <sys/ib/mgt/ibdma/ibdma.h> 41 #include <sys/ib/mgt/ibdma/ibdma_impl.h> 42 43 /* 44 * NOTE: The IB Device Management Agent function, like other IB 45 * managers and agents is best implemented as a kernel misc. 46 * module. 47 * Eventually we could modify IBT_DM_AGENT so that we don't need to 48 * open each HCA to receive asynchronous events. 49 */ 50 51 #define IBDMA_NAME_VERSION "IB Device Management Agent" 52 53 extern struct mod_ops mod_miscops; 54 55 static void ibdma_ibt_async_handler(void *clnt, ibt_hca_hdl_t hdl, 56 ibt_async_code_t code, ibt_async_event_t *event); 57 58 static void ibdma_mad_recv_cb(ibmf_handle_t ibmf_hdl, 59 ibmf_msg_t *msgp, void *args); 60 static void ibdma_create_resp_mad(ibmf_msg_t *msgp); 61 62 /* 63 * Misc. kernel module for now. 64 */ 65 static struct modlmisc modlmisc = { 66 &mod_miscops, 67 IBDMA_NAME_VERSION 68 }; 69 70 static struct modlinkage modlinkage = { 71 MODREV_1, { (void *)&modlmisc, NULL } 72 }; 73 74 static ibt_clnt_modinfo_t ibdma_ibt_modinfo = { 75 IBTI_V_CURR, 76 IBT_DM_AGENT, 77 ibdma_ibt_async_handler, 78 NULL, 79 "ibdma" 80 }; 81 82 /* 83 * Module global state allocated at init(). 84 */ 85 static ibdma_mod_state_t *ibdma = NULL; 86 87 /* 88 * Init/Fini handlers and IBTL HCA management prototypes. 89 */ 90 static int ibdma_init(); 91 static int ibdma_fini(); 92 static int ibdma_ibt_init(); 93 static void ibdma_ibt_fini(); 94 static ibdma_hca_t *ibdma_hca_init(ib_guid_t guid); 95 static void ibdma_hca_fini(ibdma_hca_t *hca); 96 static ibdma_hca_t *ibdma_find_hca(ib_guid_t guid); 97 98 /* 99 * DevMgmt Agent MAD attribute handlers prototypes. 100 */ 101 static void ibdma_get_class_portinfo(ibmf_msg_t *msg); 102 static void ibdma_get_io_unitinfo(ibdma_hca_t *hca, ibmf_msg_t *msg); 103 static void ibdma_get_ioc_profile(ibdma_hca_t *hca, ibmf_msg_t *msg); 104 static void ibdma_get_ioc_services(ibdma_hca_t *hca, ibmf_msg_t *msg); 105 106 /* 107 * _init() 108 */ 109 int 110 _init(void) 111 { 112 int status; 113 114 ASSERT(ibdma == NULL); 115 116 ibdma = kmem_zalloc(sizeof (*ibdma), KM_SLEEP); 117 ASSERT(ibdma != NULL); 118 119 status = ibdma_init(); 120 if (status != DDI_SUCCESS) { 121 kmem_free(ibdma, sizeof (*ibdma)); 122 ibdma = NULL; 123 return (status); 124 } 125 126 status = mod_install(&modlinkage); 127 if (status != DDI_SUCCESS) { 128 cmn_err(CE_NOTE, "_init, mod_install error (%d)", status); 129 (void) ibdma_fini(); 130 kmem_free(ibdma, sizeof (*ibdma)); 131 ibdma = NULL; 132 } 133 return (status); 134 } 135 136 /* 137 * _info() 138 */ 139 int 140 _info(struct modinfo *modinfop) 141 { 142 return (mod_info(&modlinkage, modinfop)); 143 } 144 145 /* 146 * _fini() 147 */ 148 int 149 _fini(void) 150 { 151 int status; 152 int slot; 153 ibdma_hca_t *hca; 154 155 status = mod_remove(&modlinkage); 156 if (status != DDI_SUCCESS) { 157 cmn_err(CE_NOTE, "_fini, mod_remove error (%d)", status); 158 return (status); 159 } 160 161 /* 162 * Sanity check to see if anyone is not cleaning 163 * up appropriately. 164 */ 165 mutex_enter(&ibdma->ms_hca_list_lock); 166 hca = list_head(&ibdma->ms_hca_list); 167 while (hca != NULL) { 168 for (slot = 0; slot < IBDMA_MAX_IOC; slot++) { 169 if (hca->ih_ioc[slot].ii_inuse) { 170 cmn_err(CE_NOTE, "_fini, IOC %d still attached" 171 " for (0x%0llx)", slot+1, 172 (u_longlong_t)hca->ih_iou_guid); 173 } 174 } 175 hca = list_next(&ibdma->ms_hca_list, hca); 176 } 177 mutex_exit(&ibdma->ms_hca_list_lock); 178 179 (void) ibdma_fini(); 180 kmem_free(ibdma, sizeof (*ibdma)); 181 return (status); 182 } 183 184 /* 185 * ibdma_init() 186 * 187 * Initialize I/O Unit structure, generate initial HCA list and register 188 * it port with the IBMF. 189 */ 190 static int 191 ibdma_init() 192 { 193 int status; 194 195 /* 196 * Global lock and I/O Unit initialization. 197 */ 198 mutex_init(&ibdma->ms_hca_list_lock, NULL, MUTEX_DRIVER, NULL); 199 200 /* 201 * Discover IB hardware and setup for device management agent 202 * support. 203 */ 204 status = ibdma_ibt_init(); 205 if (status != DDI_SUCCESS) { 206 cmn_err(CE_NOTE, "ibdma_init, ibt_attach failed (%d)", 207 status); 208 mutex_destroy(&ibdma->ms_hca_list_lock); 209 return (status); 210 } 211 212 return (status); 213 } 214 215 /* 216 * ibdma_fini() 217 * 218 * Release resource if we are no longer in use. 219 */ 220 static int 221 ibdma_fini() 222 { 223 ibdma_ibt_fini(); 224 mutex_destroy(&ibdma->ms_hca_list_lock); 225 return (DDI_SUCCESS); 226 } 227 228 /* 229 * ibdma_ibt_async_handler() 230 */ 231 /* ARGSUSED */ 232 static void 233 ibdma_ibt_async_handler(void *clnt, ibt_hca_hdl_t hdl, 234 ibt_async_code_t code, ibt_async_event_t *event) 235 { 236 ibdma_hca_t *hca; 237 238 switch (code) { 239 240 case IBT_EVENT_PORT_UP: 241 case IBT_ERROR_PORT_DOWN: 242 case IBT_PORT_CHANGE_EVENT: 243 case IBT_CLNT_REREG_EVENT: 244 break; 245 246 case IBT_HCA_ATTACH_EVENT: 247 mutex_enter(&ibdma->ms_hca_list_lock); 248 hca = ibdma_hca_init(event->ev_hca_guid); 249 if (hca != NULL) { 250 list_insert_tail(&ibdma->ms_hca_list, hca); 251 cmn_err(CE_NOTE, "hca ibt hdl (%p)", 252 (void *)hca->ih_ibt_hdl); 253 ibdma->ms_num_hcas++; 254 } 255 mutex_exit(&ibdma->ms_hca_list_lock); 256 break; 257 258 case IBT_HCA_DETACH_EVENT: 259 mutex_enter(&ibdma->ms_hca_list_lock); 260 hca = ibdma_find_hca(event->ev_hca_guid); 261 if (hca != NULL) { 262 list_remove(&ibdma->ms_hca_list, hca); 263 cmn_err(CE_NOTE, "removing hca (%p) (0x%llx)", 264 (void *)hca, hca ? 265 (u_longlong_t)hca->ih_iou_guid : 0x0ll); 266 ibdma_hca_fini(hca); 267 } 268 mutex_exit(&ibdma->ms_hca_list_lock); 269 break; 270 271 default: 272 #ifdef DEBUG 273 cmn_err(CE_NOTE, "ibt_async_handler, unhandled event(%d)", 274 code); 275 #endif 276 break; 277 } 278 279 } 280 281 /* 282 * ibdma_ibt_init() 283 */ 284 static int 285 ibdma_ibt_init() 286 { 287 int status; 288 int hca_cnt; 289 int hca_ndx; 290 ib_guid_t *guid; 291 ibdma_hca_t *hca; 292 293 /* 294 * Attach to IBTF and get HCA list. 295 */ 296 status = ibt_attach(&ibdma_ibt_modinfo, NULL, 297 ibdma, &ibdma->ms_ibt_hdl); 298 if (status != DDI_SUCCESS) { 299 cmn_err(CE_NOTE, "ibt_init, ibt_attach failed (%d)", 300 status); 301 return (status); 302 } 303 304 list_create(&ibdma->ms_hca_list, sizeof (ibdma_hca_t), 305 offsetof(ibdma_hca_t, ih_node)); 306 307 hca_cnt = ibt_get_hca_list(&guid); 308 if (hca_cnt < 1) { 309 #ifdef DEBUG_IBDMA 310 cmn_err(CE_NOTE, "ibt_init, no HCA(s) found"); 311 #endif 312 /* not an error if no HCAs, but nothing more to do here */ 313 return (DDI_SUCCESS); 314 } 315 316 mutex_enter(&ibdma->ms_hca_list_lock); 317 318 for (hca_ndx = 0; hca_ndx < hca_cnt; hca_ndx++) { 319 #ifdef DEBUG_IBDMA 320 cmn_err(CE_NOTE, "adding hca GUID(0x%llx)", 321 (u_longlong_t)guid[hca_ndx]); 322 #endif 323 324 hca = ibdma_hca_init(guid[hca_ndx]); 325 if (hca == NULL) { 326 cmn_err(CE_NOTE, "ibt_init, hca_init GUID(0x%llx)" 327 " failed", (u_longlong_t)guid[hca_ndx]); 328 continue; 329 } 330 list_insert_tail(&ibdma->ms_hca_list, hca); 331 ibdma->ms_num_hcas++; 332 } 333 334 mutex_exit(&ibdma->ms_hca_list_lock); 335 336 ibt_free_hca_list(guid, hca_cnt); 337 #ifdef DEBUG_IBDMA 338 cmn_err(CE_NOTE, "Added %d HCA(s)", 339 ibdma->ms_num_hcas); 340 #endif 341 return (DDI_SUCCESS); 342 } 343 344 /* 345 * ibdma_ibt_fini() 346 */ 347 static void 348 ibdma_ibt_fini() 349 { 350 ibdma_hca_t *hca; 351 ibdma_hca_t *next; 352 353 mutex_enter(&ibdma->ms_hca_list_lock); 354 hca = list_head(&ibdma->ms_hca_list); 355 while (hca != NULL) { 356 next = list_next(&ibdma->ms_hca_list, hca); 357 list_remove(&ibdma->ms_hca_list, hca); 358 #ifdef DEBUG_IBDMA 359 cmn_err(CE_NOTE, "removing hca (%p) (0x%llx)", 360 (void *)hca, hca ? 361 (u_longlong_t)hca->ih_iou_guid : 0x0ll); 362 cmn_err(CE_NOTE, "hca ibt hdl (%p)", 363 (void *)hca->ih_ibt_hdl); 364 #endif 365 ibdma_hca_fini(hca); 366 hca = next; 367 } 368 list_destroy(&ibdma->ms_hca_list); 369 370 (void) ibt_detach(ibdma->ms_ibt_hdl); 371 ibdma->ms_ibt_hdl = NULL; 372 ibdma->ms_num_hcas = 0; 373 mutex_exit(&ibdma->ms_hca_list_lock); 374 } 375 376 /* 377 * ibdma_find_hca() 378 */ 379 static ibdma_hca_t * 380 ibdma_find_hca(ib_guid_t guid) 381 { 382 ibdma_hca_t *hca; 383 384 ASSERT(mutex_owned(&ibdma->ms_hca_list_lock)); 385 386 hca = list_head(&ibdma->ms_hca_list); 387 while (hca != NULL) { 388 if (hca->ih_iou_guid == guid) { 389 break; 390 } 391 hca = list_next(&ibdma->ms_hca_list, hca); 392 } 393 return (hca); 394 } 395 396 /* 397 * ibdma_hca_init() 398 */ 399 static ibdma_hca_t * 400 ibdma_hca_init(ib_guid_t guid) 401 { 402 ibt_status_t status; 403 ibdma_hca_t *hca; 404 ibdma_port_t *port; 405 ibt_hca_attr_t hca_attr; 406 int ndx; 407 408 ASSERT(mutex_owned(&ibdma->ms_hca_list_lock)); 409 410 status = ibt_query_hca_byguid(guid, &hca_attr); 411 if (status != IBT_SUCCESS) { 412 cmn_err(CE_NOTE, "hca_init HCA query error (%d)", 413 status); 414 return (NULL); 415 } 416 417 if (ibdma_find_hca(guid) != NULL) { 418 #ifdef DEBUG_IBDMA 419 cmn_err(CE_NOTE, "hca_init HCA already exists"); 420 #endif 421 return (NULL); 422 } 423 424 hca = kmem_zalloc(sizeof (ibdma_hca_t) + 425 (hca_attr.hca_nports-1)*sizeof (ibdma_port_t), KM_SLEEP); 426 ASSERT(hca != NULL); 427 428 hca->ih_nports = hca_attr.hca_nports; 429 430 rw_init(&hca->ih_iou_rwlock, NULL, RW_DRIVER, NULL); 431 rw_enter(&hca->ih_iou_rwlock, RW_WRITER); 432 hca->ih_iou_guid = guid; 433 hca->ih_iou.iou_changeid = h2b16(1); 434 hca->ih_iou.iou_num_ctrl_slots = IBDMA_MAX_IOC; 435 hca->ih_iou.iou_flag = IB_DM_IOU_OPTIONROM_ABSENT; 436 437 list_create(&hca->ih_hdl_list, sizeof (ibdma_hdl_impl_t), 438 offsetof(ibdma_hdl_impl_t, ih_node)); 439 rw_exit(&hca->ih_iou_rwlock); 440 441 /* 442 * It would be better to not open, but IBTL is setup to only allow 443 * certain managers to get async call backs if not open. 444 */ 445 status = ibt_open_hca(ibdma->ms_ibt_hdl, guid, &hca->ih_ibt_hdl); 446 if (status != IBT_SUCCESS) { 447 cmn_err(CE_NOTE, "hca_init() IBT open failed (%d)", 448 status); 449 450 list_destroy(&hca->ih_hdl_list); 451 rw_destroy(&hca->ih_iou_rwlock); 452 kmem_free(hca, sizeof (ibdma_hca_t) + 453 (hca_attr.hca_nports-1)*sizeof (ibdma_port_t)); 454 return (NULL); 455 } 456 457 /* 458 * Register with the IB Management Framework and setup MAD call-back. 459 */ 460 for (ndx = 0; ndx < hca->ih_nports; ndx++) { 461 port = &hca->ih_port[ndx]; 462 port->ip_hcap = hca; 463 port->ip_ibmf_reg.ir_ci_guid = hca->ih_iou_guid; 464 port->ip_ibmf_reg.ir_port_num = ndx + 1; 465 port->ip_ibmf_reg.ir_client_class = DEV_MGT_AGENT; 466 467 status = ibmf_register(&port->ip_ibmf_reg, IBMF_VERSION, 468 0, NULL, NULL, &port->ip_ibmf_hdl, &port->ip_ibmf_caps); 469 if (status != IBMF_SUCCESS) { 470 cmn_err(CE_NOTE, "hca_init, IBMF register failed (%d)", 471 status); 472 port->ip_ibmf_hdl = NULL; 473 ibdma_hca_fini(hca); 474 return (NULL); 475 } 476 477 status = ibmf_setup_async_cb(port->ip_ibmf_hdl, 478 IBMF_QP_HANDLE_DEFAULT, ibdma_mad_recv_cb, port, 0); 479 if (status != IBMF_SUCCESS) { 480 cmn_err(CE_NOTE, "hca_init, IBMF cb setup failed (%d)", 481 status); 482 ibdma_hca_fini(hca); 483 return (NULL); 484 } 485 486 status = ibt_modify_port_byguid(hca->ih_iou_guid, 487 ndx+1, IBT_PORT_SET_DEVMGT, 0); 488 if (status != IBT_SUCCESS) { 489 cmn_err(CE_NOTE, "hca_init, IBT modify port caps" 490 " error (%d)", status); 491 ibdma_hca_fini(hca); 492 return (NULL); 493 } 494 } 495 return (hca); 496 } 497 498 /* 499 * ibdma_hca_fini() 500 */ 501 static void 502 ibdma_hca_fini(ibdma_hca_t *hca) 503 { 504 int status; 505 int ndx; 506 ibdma_port_t *port; 507 ibdma_hdl_impl_t *hdl; 508 ibdma_hdl_impl_t *hdl_next; 509 510 ASSERT(mutex_owned(&ibdma->ms_hca_list_lock)); 511 ASSERT(hca != NULL); 512 513 rw_enter(&hca->ih_iou_rwlock, RW_WRITER); 514 515 /* 516 * All handles should have been de-registered, but release 517 * any that are outstanding. 518 */ 519 hdl = list_head(&hca->ih_hdl_list); 520 while (hdl != NULL) { 521 hdl_next = list_next(&hca->ih_hdl_list, hdl); 522 list_remove(&hca->ih_hdl_list, hdl); 523 cmn_err(CE_NOTE, "hca_fini, unexpected ibdma user handle" 524 " exists"); 525 kmem_free(hdl, sizeof (*hdl)); 526 hdl = hdl_next; 527 } 528 list_destroy(&hca->ih_hdl_list); 529 530 /* 531 * Un-register with the IBMF. 532 */ 533 for (ndx = 0; ndx < hca->ih_nports; ndx++) { 534 port = &hca->ih_port[ndx]; 535 port->ip_hcap = NULL; 536 537 status = ibt_modify_port_byguid(hca->ih_iou_guid, 538 ndx+1, IBT_PORT_RESET_DEVMGT, 0); 539 if (status != IBT_SUCCESS) 540 cmn_err(CE_NOTE, "hca_fini, IBT modify port caps" 541 " error (%d)", status); 542 543 if (port->ip_ibmf_hdl == NULL) 544 continue; 545 546 status = ibmf_tear_down_async_cb(port->ip_ibmf_hdl, 547 IBMF_QP_HANDLE_DEFAULT, 0); 548 if (status != IBMF_SUCCESS) 549 cmn_err(CE_NOTE, "hca_fini, IBMF tear down cb" 550 " error (%d)", status); 551 552 status = ibmf_unregister(&port->ip_ibmf_hdl, 0); 553 if (status != IBMF_SUCCESS) 554 cmn_err(CE_NOTE, "hca_fini, IBMF un-register" 555 " error (%d)", status); 556 port->ip_ibmf_hdl = NULL; 557 } 558 559 status = ibt_close_hca(hca->ih_ibt_hdl); 560 if (status != IBT_SUCCESS) 561 cmn_err(CE_NOTE, "hca_fini close error (%d)", status); 562 563 rw_exit(&hca->ih_iou_rwlock); 564 rw_destroy(&hca->ih_iou_rwlock); 565 kmem_free(hca, sizeof (ibdma_hca_t) + 566 (hca->ih_nports-1) * sizeof (ibdma_port_t)); 567 } 568 569 /* DM IBMF MAD handlers */ 570 /* 571 * ibdma_create_resp_mad() 572 */ 573 static void 574 ibdma_create_resp_mad(ibmf_msg_t *msgp) 575 { 576 /* 577 * Allocate send buffer fix up hdr for response. 578 */ 579 msgp->im_msgbufs_send.im_bufs_mad_hdr = 580 kmem_zalloc(IBDMA_MAD_SIZE, KM_SLEEP); 581 582 msgp->im_msgbufs_send.im_bufs_cl_hdr = (uchar_t *) 583 msgp->im_msgbufs_send.im_bufs_mad_hdr + sizeof (ib_mad_hdr_t); 584 msgp->im_msgbufs_send.im_bufs_cl_hdr_len = IBDMA_DM_MAD_HDR_SIZE; 585 msgp->im_msgbufs_send.im_bufs_cl_data = 586 ((char *)msgp->im_msgbufs_send.im_bufs_cl_hdr + 587 IBDMA_DM_MAD_HDR_SIZE); 588 msgp->im_msgbufs_send.im_bufs_cl_data_len = 589 IBDMA_MAD_SIZE - sizeof (ib_mad_hdr_t) - IBDMA_DM_MAD_HDR_SIZE; 590 (void) memcpy(msgp->im_msgbufs_send.im_bufs_mad_hdr, 591 msgp->im_msgbufs_recv.im_bufs_mad_hdr, IBDMA_MAD_SIZE); 592 593 /* 594 * We may want to support a GRH since this is a GMP; not 595 * required for current SRP device manager platforms. 596 */ 597 #if 0 598 if (msgp->im_msg_flags & IBMF_MSG_FLAGS_GLOBAL_ADDRESS) { 599 ib_gid_t temp = msgp->im_global_addr.ig_recver_gid; 600 601 msgp->im_global_addr.ig_recver_gid = 602 msgp->im_global_addr.ig_sender_gid; 603 msgp->im_global_addr.ig_sender_gid = temp; 604 } 605 #endif 606 } 607 608 /* 609 * ibdma_mad_send_cb() 610 */ 611 /* ARGSUSED */ 612 static void 613 ibdma_mad_send_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msgp, void *arg) 614 { 615 /* 616 * Just free the buffers and release the message. 617 */ 618 if (msgp->im_msgbufs_send.im_bufs_mad_hdr != NULL) { 619 kmem_free(msgp->im_msgbufs_send.im_bufs_mad_hdr, 620 IBDMA_MAD_SIZE); 621 msgp->im_msgbufs_send.im_bufs_mad_hdr = NULL; 622 } 623 if (ibmf_free_msg(ibmf_hdl, &msgp) != IBMF_SUCCESS) { 624 cmn_err(CE_NOTE, "mad_send_cb, IBMF message free error"); 625 } 626 } 627 628 /* 629 * ibdma_mad_recv_cb() 630 */ 631 static void 632 ibdma_mad_recv_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msgp, void *args) 633 { 634 int status; 635 ib_mad_hdr_t *in_mad; 636 ib_mad_hdr_t *out_mad; 637 ibdma_port_t *port = args; 638 639 ASSERT(msgp != NULL); 640 ASSERT(port != NULL); 641 642 if (msgp->im_msg_status != IBMF_SUCCESS) { 643 cmn_err(CE_NOTE, "mad_recv_cb, bad MAD receive status (%d)", 644 msgp->im_msg_status); 645 goto drop; 646 } 647 648 in_mad = msgp->im_msgbufs_recv.im_bufs_mad_hdr; 649 650 if (in_mad->MgmtClass != MAD_MGMT_CLASS_DEV_MGT) { 651 #ifdef DEBUG_IBDMA 652 cmn_err(CE_NOTE, "mad_recv_cb, MAD not of Dev Mgmt Class"); 653 #endif 654 goto drop; 655 } 656 657 ibdma_create_resp_mad(msgp); 658 out_mad = msgp->im_msgbufs_send.im_bufs_mad_hdr; 659 660 out_mad->R_Method = IB_DM_DEVMGT_METHOD_GET_RESP; 661 out_mad->Status = 0; 662 663 if (in_mad->R_Method == MAD_METHOD_SET) { 664 #ifdef DEBUG_IBDMA 665 cmn_err(CE_NOTE, "mad_recv_cb, no attributes supported" 666 " for set"); 667 #endif 668 out_mad->Status = MAD_STATUS_UNSUPP_METHOD_ATTR; 669 goto send_resp; 670 } 671 672 if (in_mad->R_Method != MAD_METHOD_GET) { 673 #ifdef DEBUG_IBDMA 674 cmn_err(CE_NOTE, "mad_recv_cb, no attributes supported" 675 " for set"); 676 #endif 677 out_mad->Status = MAD_STATUS_UNSUPP_METHOD; 678 goto send_resp; 679 } 680 681 /* 682 * Process a GET method. 683 */ 684 switch (b2h16(in_mad->AttributeID)) { 685 686 case IB_DM_ATTR_CLASSPORTINFO: 687 ibdma_get_class_portinfo(msgp); 688 break; 689 690 case IB_DM_ATTR_IO_UNITINFO: 691 ibdma_get_io_unitinfo(port->ip_hcap, msgp); 692 break; 693 694 case IB_DM_ATTR_IOC_CTRL_PROFILE: 695 ibdma_get_ioc_profile(port->ip_hcap, msgp); 696 break; 697 698 case IB_DM_ATTR_SERVICE_ENTRIES: 699 ibdma_get_ioc_services(port->ip_hcap, msgp); 700 break; 701 702 default: 703 out_mad->Status = MAD_STATUS_UNSUPP_METHOD_ATTR; 704 break; 705 } 706 707 send_resp: 708 status = ibmf_msg_transport(ibmf_hdl, IBMF_QP_HANDLE_DEFAULT, 709 msgp, NULL, ibdma_mad_send_cb, NULL, 0); 710 if (status != IBMF_SUCCESS) { 711 cmn_err(CE_NOTE, "mad_recv_cb, send error (%d)", status); 712 ibdma_mad_send_cb(ibmf_hdl, msgp, NULL); 713 } 714 return; 715 716 drop: 717 status = ibmf_free_msg(ibmf_hdl, &msgp); 718 if (status != IBMF_SUCCESS) { 719 cmn_err(CE_NOTE, "mad_recv_cb, error dropping (%d)", 720 status); 721 } 722 } 723 724 /* 725 * ibdma_get_class_portinfo() 726 */ 727 static void 728 ibdma_get_class_portinfo(ibmf_msg_t *msg) 729 { 730 ib_mad_classportinfo_t *cpip; 731 732 cpip = (ib_mad_classportinfo_t *)msg->im_msgbufs_send.im_bufs_cl_data; 733 bzero(cpip, sizeof (*cpip)); 734 cpip->BaseVersion = MAD_CLASS_BASE_VERS_1; 735 cpip->ClassVersion = IB_DM_CLASS_VERSION_1; 736 cpip->RespTimeValue = h2b32(IBDMA_DM_RESP_TIME); 737 } 738 739 /* 740 * ibdma_get_io_unitinfo() 741 */ 742 static void 743 ibdma_get_io_unitinfo(ibdma_hca_t *hca, ibmf_msg_t *msg) 744 { 745 ib_dm_io_unitinfo_t *uip; 746 747 uip = (ib_dm_io_unitinfo_t *)msg->im_msgbufs_send.im_bufs_cl_data; 748 rw_enter(&hca->ih_iou_rwlock, RW_READER); 749 bcopy(&hca->ih_iou, uip, sizeof (ib_dm_io_unitinfo_t)); 750 rw_exit(&hca->ih_iou_rwlock); 751 } 752 753 /* 754 * ibdma_get_ioc_profile() 755 */ 756 static void 757 ibdma_get_ioc_profile(ibdma_hca_t *hca, ibmf_msg_t *msg) 758 { 759 ib_dm_ioc_ctrl_profile_t *iocp; 760 uint32_t slot; 761 762 ASSERT(msg != NULL); 763 764 slot = b2h32(msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeModifier); 765 iocp = (ib_dm_ioc_ctrl_profile_t *) 766 msg->im_msgbufs_send.im_bufs_cl_data; 767 if (slot == 0 || slot > IBDMA_MAX_IOC) { 768 msg->im_msgbufs_send.im_bufs_mad_hdr->Status = 769 MAD_STATUS_INVALID_FIELD; 770 return; 771 } 772 773 slot--; 774 rw_enter(&hca->ih_iou_rwlock, RW_READER); 775 if (ibdma_get_ioc_state(hca, slot) == IBDMA_IOC_PRESENT) { 776 bcopy(&hca->ih_ioc[slot].ii_profile, iocp, 777 sizeof (ib_dm_ioc_ctrl_profile_t)); 778 } else { 779 msg->im_msgbufs_send.im_bufs_mad_hdr->Status = 780 IB_DM_DEVMGT_MAD_STAT_NORESP; 781 } 782 rw_exit(&hca->ih_iou_rwlock); 783 } 784 785 /* 786 * ibdma_get_ioc_services() 787 */ 788 static void 789 ibdma_get_ioc_services(ibdma_hca_t *hca, ibmf_msg_t *msg) 790 { 791 ib_dm_srv_t *to_svcp; 792 ib_dm_srv_t *from_svcp; 793 uint32_t slot; 794 uint8_t hi; 795 uint8_t low; 796 797 ASSERT(msg != NULL); 798 799 slot = b2h32(msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeModifier); 800 hi = (slot >> 8) & 0x00FF; 801 low = slot & 0x00FF; 802 slot = (slot >> 16) & 0x0FFFF; 803 if (slot == 0 || slot > IBDMA_MAX_IOC) { 804 msg->im_msgbufs_send.im_bufs_mad_hdr->Status = 805 MAD_STATUS_INVALID_FIELD; 806 return; 807 } 808 809 slot--; 810 811 rw_enter(&hca->ih_iou_rwlock, RW_READER); 812 if (ibdma_get_ioc_state(hca, slot) != IBDMA_IOC_PRESENT) { 813 msg->im_msgbufs_send.im_bufs_mad_hdr->Status = 814 IB_DM_DEVMGT_MAD_STAT_NORESP; 815 rw_exit(&hca->ih_iou_rwlock); 816 return; 817 } 818 819 if ((low > hi) || (hi - low > 4)) { 820 msg->im_msgbufs_send.im_bufs_mad_hdr->Status = 821 MAD_STATUS_INVALID_FIELD; 822 rw_exit(&hca->ih_iou_rwlock); 823 return; 824 } 825 826 if (hi > hca->ih_ioc[slot].ii_profile.ioc_service_entries) { 827 msg->im_msgbufs_send.im_bufs_mad_hdr->Status = 828 MAD_STATUS_INVALID_FIELD; 829 rw_exit(&hca->ih_iou_rwlock); 830 return; 831 } 832 833 to_svcp = (ib_dm_srv_t *)msg->im_msgbufs_send.im_bufs_cl_data; 834 from_svcp = hca->ih_ioc[slot].ii_srvcs + low; 835 bcopy(from_svcp, to_svcp, sizeof (ib_dm_srv_t) * (hi - low + 1)); 836 rw_exit(&hca->ih_iou_rwlock); 837 } 838 839 840 /* 841 * Client API internal helpers 842 */ 843 844 /* 845 * ibdma_hdl_to_ioc() 846 */ 847 ibdma_hdl_impl_t * 848 ibdma_get_hdl_impl(ibdma_hdl_t hdl) 849 { 850 ibdma_hca_t *hca; 851 ibdma_hdl_impl_t *hdl_tmp = hdl; 852 ibdma_hdl_impl_t *hdl_impl; 853 854 ASSERT(mutex_owned(&ibdma->ms_hca_list_lock)); 855 856 if (hdl_tmp == NULL) { 857 cmn_err(CE_NOTE, "get_hdl_impl, NULL handle"); 858 return (NULL); 859 } 860 861 hca = ibdma_find_hca(hdl_tmp->ih_iou_guid); 862 if (hca == NULL) { 863 cmn_err(CE_NOTE, "get_hdl_impl, invalid handle, bad IOU"); 864 return (NULL); 865 } 866 867 hdl_impl = list_head(&hca->ih_hdl_list); 868 while (hdl_impl != NULL) { 869 if (hdl_impl == hdl_tmp) { 870 break; 871 } 872 hdl_impl = list_next(&hca->ih_hdl_list, hdl_impl); 873 } 874 return (hdl_impl); 875 } 876 877 /* 878 * ibdma_set_ioc_state() 879 * 880 * slot should be 0 based (not DM 1 based slot). 881 * 882 * I/O Unit write lock should be held outside of this function. 883 */ 884 static void 885 ibdma_set_ioc_state(ibdma_hca_t *hca, int slot, ibdma_ioc_state_t state) 886 { 887 uint8_t cur; 888 uint16_t id; 889 890 cur = hca->ih_iou.iou_ctrl_list[slot >> 1]; 891 if (slot & 1) { 892 cur = (cur & 0xF0) | state; 893 } else { 894 cur = (cur & 0x0F) | (state << 4); 895 } 896 hca->ih_iou.iou_ctrl_list[slot >> 1] = cur; 897 id = b2h16(hca->ih_iou.iou_changeid); 898 id++; 899 hca->ih_iou.iou_changeid = h2b16(id); 900 #ifdef DEBUG_IBDMA 901 cmn_err(CE_NOTE, "set_ioc_state, slot offset(%d), value(%d)", 902 slot, hca->ih_iou.iou_ctrl_list[slot >> 1]); 903 #endif 904 } 905 906 /* 907 * ibdma_get_ioc_state() 908 * 909 * slot should be 0 based (not DM 1 based slot). 910 * 911 * I/O Unit read lock should be held outside of this function. 912 */ 913 static ibdma_ioc_state_t 914 ibdma_get_ioc_state(ibdma_hca_t *hca, int slot) 915 { 916 uint8_t cur; 917 918 if (slot >= IBDMA_MAX_IOC) 919 return (0xFF); 920 921 cur = hca->ih_iou.iou_ctrl_list[slot >> 1]; 922 cur = slot & 1 ? cur & 0x0F : cur >> 4; 923 return (cur); 924 } 925 926 /* CLIENT API Implementation */ 927 /* 928 * ibdma_ioc_register() 929 * 930 */ 931 ibdma_hdl_t 932 ibdma_ioc_register(ib_guid_t iou_guid, ib_dm_ioc_ctrl_profile_t *profile, 933 ib_dm_srv_t *services) 934 { 935 int free_slot = -1; 936 int svc_entries; 937 int slot; 938 ibdma_hca_t *hca; 939 ibdma_hdl_impl_t *hdl; 940 941 if (profile == NULL || services == NULL) { 942 cmn_err(CE_NOTE, "ioc_register, bad parameter"); 943 return (NULL); 944 } 945 946 svc_entries = profile->ioc_service_entries; 947 if (svc_entries == 0) { 948 cmn_err(CE_NOTE, "ioc_register, bad profile no service"); 949 return (NULL); 950 } 951 952 /* 953 * Find the associated I/O Unit. 954 */ 955 mutex_enter(&ibdma->ms_hca_list_lock); 956 hca = ibdma_find_hca(iou_guid); 957 if (hca == NULL) { 958 mutex_exit(&ibdma->ms_hca_list_lock); 959 cmn_err(CE_NOTE, "ioc_register, bad I/O Unit GUID (0x%llx)", 960 (u_longlong_t)iou_guid); 961 return (NULL); 962 } 963 964 rw_enter(&hca->ih_iou_rwlock, RW_WRITER); 965 for (slot = 0; slot < IBDMA_MAX_IOC; slot++) { 966 if (hca->ih_ioc[slot].ii_inuse == 0) { 967 if (free_slot == -1) { 968 free_slot = slot; 969 } 970 continue; 971 } 972 973 if (profile->ioc_guid == 974 hca->ih_ioc[slot].ii_profile.ioc_guid) { 975 rw_exit(&hca->ih_iou_rwlock); 976 mutex_exit(&ibdma->ms_hca_list_lock); 977 #ifdef DEBUG_IBDMA 978 cmn_err(CE_NOTE, "ioc_register, IOC previously" 979 " registered"); 980 #endif 981 return (NULL); 982 } 983 } 984 985 if (free_slot < 0) { 986 rw_exit(&hca->ih_iou_rwlock); 987 cmn_err(CE_NOTE, "ioc_register, error - I/O Unit full"); 988 return (NULL); 989 } 990 #ifdef DEBUG_IBDMA 991 cmn_err(CE_NOTE, "ibdma_ioc_register, assigned to 0 based slot (%d)", 992 free_slot); 993 #endif 994 995 hca->ih_ioc[free_slot].ii_inuse = 1; 996 hca->ih_ioc[free_slot].ii_slot = free_slot; 997 hca->ih_ioc[free_slot].ii_hcap = hca; 998 999 /* 1000 * Allocate local copy of profile and services. 1001 */ 1002 hca->ih_ioc[free_slot].ii_srvcs = 1003 kmem_zalloc(sizeof (ib_dm_srv_t) * svc_entries, KM_SLEEP); 1004 bcopy(profile, &hca->ih_ioc[free_slot].ii_profile, 1005 sizeof (ib_dm_ioc_ctrl_profile_t)); 1006 bcopy(services, hca->ih_ioc[free_slot].ii_srvcs, 1007 sizeof (ib_dm_srv_t) * svc_entries); 1008 1009 /* 1010 * Update the profile copy with the I/O controller slot assigned. 1011 * The slot occupies the lower 8 biths of the vendor ID/slot 32bit 1012 * field. 1013 */ 1014 profile->ioc_vendorid |= h2b32(free_slot); 1015 1016 ibdma_set_ioc_state(hca, free_slot, IBDMA_IOC_PRESENT); 1017 1018 hdl = kmem_alloc(sizeof (*hdl), KM_SLEEP); 1019 hdl->ih_iou_guid = hca->ih_iou_guid; 1020 hdl->ih_ioc_ndx = (uint8_t)free_slot; 1021 list_insert_tail(&hca->ih_hdl_list, hdl); 1022 1023 rw_exit(&hca->ih_iou_rwlock); 1024 mutex_exit(&ibdma->ms_hca_list_lock); 1025 1026 return ((ibdma_hdl_t)hdl); 1027 } 1028 1029 /* 1030 * ibdma_ioc_unregister() 1031 * 1032 */ 1033 ibdma_status_t 1034 ibdma_ioc_unregister(ibdma_hdl_t hdl) 1035 { 1036 ibdma_ioc_t *ioc; 1037 ibdma_hca_t *hca; 1038 int slot; 1039 ibdma_hdl_impl_t *hdl_tmp = hdl; 1040 ibdma_hdl_impl_t *hdl_impl; 1041 1042 if (hdl == NULL) { 1043 cmn_err(CE_NOTE, "ioc_unregister, NULL handle"); 1044 return (IBDMA_BAD_PARAM); 1045 } 1046 1047 mutex_enter(&ibdma->ms_hca_list_lock); 1048 hca = ibdma_find_hca(hdl_tmp->ih_iou_guid); 1049 if (hca == NULL) { 1050 cmn_err(CE_NOTE, "ioc_unregsiter, invalid handle, IOU" 1051 " not found"); 1052 mutex_exit(&ibdma->ms_hca_list_lock); 1053 return (IBDMA_BAD_PARAM); 1054 } 1055 1056 hdl_impl = list_head(&hca->ih_hdl_list); 1057 while (hdl_impl != NULL) { 1058 if (hdl_impl == hdl_tmp) { 1059 break; 1060 } 1061 hdl_impl = list_next(&hca->ih_hdl_list, hdl_impl); 1062 } 1063 1064 if (hdl_impl == NULL) { 1065 cmn_err(CE_NOTE, "ioc_unregsiter, invalid handle, not found"); 1066 mutex_exit(&ibdma->ms_hca_list_lock); 1067 return (IBDMA_BAD_PARAM); 1068 } 1069 1070 list_remove(&hca->ih_hdl_list, hdl_impl); 1071 1072 if (hdl_impl->ih_ioc_ndx >= IBDMA_MAX_IOC) { 1073 cmn_err(CE_NOTE, "ioc_unregister, corrupted handle"); 1074 kmem_free(hdl_impl, sizeof (*hdl_impl)); 1075 mutex_exit(&ibdma->ms_hca_list_lock); 1076 return (IBDMA_BAD_PARAM); 1077 } 1078 ioc = &hca->ih_ioc[hdl_impl->ih_ioc_ndx]; 1079 kmem_free(hdl_impl, sizeof (*hdl_impl)); 1080 1081 if (ioc->ii_slot > IBDMA_MAX_IOC) { 1082 cmn_err(CE_NOTE, "ioc_unregister, IOC corrupted, bad" 1083 " slot in IOC"); 1084 mutex_exit(&ibdma->ms_hca_list_lock); 1085 return (IBDMA_BAD_PARAM); 1086 } 1087 1088 rw_enter(&ioc->ii_hcap->ih_iou_rwlock, RW_WRITER); 1089 if (ioc->ii_inuse == 0) { 1090 rw_exit(&ioc->ii_hcap->ih_iou_rwlock); 1091 mutex_exit(&ibdma->ms_hca_list_lock); 1092 cmn_err(CE_NOTE, "ioc_unregister, slot not in use (%d)", 1093 ioc->ii_slot+1); 1094 return (IBDMA_BAD_PARAM); 1095 } 1096 1097 ASSERT(ioc->ii_srvcs != NULL); 1098 1099 slot = ioc->ii_slot; 1100 hca = ioc->ii_hcap; 1101 kmem_free(ioc->ii_srvcs, sizeof (ib_dm_srv_t) * 1102 ioc->ii_profile.ioc_service_entries); 1103 bzero(ioc, sizeof (ibdma_ioc_t)); 1104 ibdma_set_ioc_state(hca, slot, IBDMA_IOC_NOT_INSTALLED); 1105 1106 rw_exit(&hca->ih_iou_rwlock); 1107 mutex_exit(&ibdma->ms_hca_list_lock); 1108 1109 return (IBDMA_SUCCESS); 1110 } 1111 1112 /* 1113 * ibdma_ioc_update() 1114 * 1115 */ 1116 ibdma_status_t 1117 ibdma_ioc_update(ibdma_hdl_t hdl, ib_dm_ioc_ctrl_profile_t *profile, 1118 ib_dm_srv_t *services) 1119 { 1120 ibdma_ioc_t *ioc; 1121 ibdma_hca_t *hca; 1122 ibdma_hdl_impl_t *hdl_tmp = hdl; 1123 ibdma_hdl_impl_t *hdl_impl; 1124 1125 if (hdl == NULL) { 1126 cmn_err(CE_NOTE, "ioc_update, NULL handle"); 1127 return (IBDMA_BAD_PARAM); 1128 } 1129 1130 if (profile == NULL || services == NULL) { 1131 cmn_err(CE_NOTE, "ioc_update, NULL parameter"); 1132 return (IBDMA_BAD_PARAM); 1133 } 1134 1135 mutex_enter(&ibdma->ms_hca_list_lock); 1136 hca = ibdma_find_hca(hdl_tmp->ih_iou_guid); 1137 if (hca == NULL) { 1138 cmn_err(CE_NOTE, "ioc_update, invalid handle, IOU not found"); 1139 mutex_exit(&ibdma->ms_hca_list_lock); 1140 return (IBDMA_BAD_PARAM); 1141 } 1142 1143 hdl_impl = list_head(&hca->ih_hdl_list); 1144 while (hdl_impl != NULL) { 1145 if (hdl_impl == hdl_tmp) { 1146 break; 1147 } 1148 hdl_impl = list_next(&hca->ih_hdl_list, hdl_impl); 1149 } 1150 1151 if (hdl_impl == NULL) { 1152 cmn_err(CE_NOTE, "ioc_update, invalid handle, not found"); 1153 mutex_exit(&ibdma->ms_hca_list_lock); 1154 return (IBDMA_BAD_PARAM); 1155 } 1156 1157 if (hdl_impl->ih_ioc_ndx >= IBDMA_MAX_IOC) { 1158 cmn_err(CE_NOTE, "ioc_update, corrupted handle"); 1159 mutex_exit(&ibdma->ms_hca_list_lock); 1160 return (IBDMA_BAD_PARAM); 1161 } 1162 ioc = &hca->ih_ioc[hdl_impl->ih_ioc_ndx]; 1163 1164 if (ioc->ii_slot >= IBDMA_MAX_IOC || ioc->ii_hcap == NULL) { 1165 cmn_err(CE_NOTE, "ioc_update, bad handle (%p)", 1166 (void *)hdl); 1167 mutex_exit(&ibdma->ms_hca_list_lock); 1168 return (IBDMA_BAD_PARAM); 1169 } 1170 1171 rw_enter(&ioc->ii_hcap->ih_iou_rwlock, RW_WRITER); 1172 if (ioc->ii_inuse == 0) { 1173 rw_exit(&ioc->ii_hcap->ih_iou_rwlock); 1174 mutex_exit(&ibdma->ms_hca_list_lock); 1175 cmn_err(CE_NOTE, "ioc_udate slot not in use (%d)", 1176 ioc->ii_slot+1); 1177 return (IBDMA_BAD_PARAM); 1178 } 1179 1180 ASSERT(ioc->ii_srvcs != NULL); 1181 1182 kmem_free(ioc->ii_srvcs, ioc->ii_profile.ioc_service_entries * 1183 sizeof (ib_dm_srv_t)); 1184 ioc->ii_srvcs = kmem_zalloc(profile->ioc_service_entries * 1185 sizeof (ib_dm_srv_t), KM_SLEEP); 1186 1187 bcopy(profile, &ioc->ii_profile, sizeof (ib_dm_ioc_ctrl_profile_t)); 1188 bcopy(services, ioc->ii_srvcs, sizeof (ib_dm_srv_t) * 1189 profile->ioc_service_entries); 1190 /* 1191 * Update the profile copy with the I/O controller slot assigned. 1192 * The slot occupies the lower 8 biths of the vendor ID/slot 32bit 1193 * field. 1194 */ 1195 profile->ioc_vendorid |= h2b32(ioc->ii_slot); 1196 ibdma_set_ioc_state(ioc->ii_hcap, ioc->ii_slot, IBDMA_IOC_PRESENT); 1197 rw_exit(&ioc->ii_hcap->ih_iou_rwlock); 1198 mutex_exit(&ibdma->ms_hca_list_lock); 1199 1200 return (IBDMA_SUCCESS); 1201 }