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 2009 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Source file containing the implementation of the driver entry points 29 * and related helper functions 30 */ 31 32 #include <oce_impl.h> 33 #include <oce_stat.h> 34 #include <oce_ioctl.h> 35 36 #define ATTACH_DEV_INIT 0x1 37 #define ATTACH_FM_INIT 0x2 38 #define ATTACH_LOCK_INIT 0x4 39 #define ATTACH_PCI_INIT 0x8 40 #define ATTACH_HW_INIT 0x10 41 #define ATTACH_SETUP_TXRX 0x20 42 #define ATTACH_SETUP_ADAP 0x40 43 #define ATTACH_STAT_INIT 0x100 44 #define ATTACH_MAC_REG 0x200 45 46 /* ---[ globals and externs ]-------------------------------------------- */ 47 const char oce_ident_string[] = OCE_IDENT_STRING; 48 const char oce_mod_name[] = OCE_MOD_NAME; 49 static const char oce_desc_string[] = OCE_DESC_STRING; 50 51 char oce_version[] = OCE_REVISION; 52 53 /* driver properties */ 54 static const char mtu_prop_name[] = "oce_default_mtu"; 55 static const char tx_ring_size_name[] = "oce_tx_ring_size"; 56 static const char tx_bcopy_limit_name[] = "oce_tx_bcopy_limit"; 57 static const char rx_bcopy_limit_name[] = "oce_rx_bcopy_limit"; 58 static const char fm_cap_name[] = "oce_fm_capability"; 59 static const char log_level_name[] = "oce_log_level"; 60 static const char lso_capable_name[] = "oce_lso_capable"; 61 62 /* --[ static function prototypes here ]------------------------------- */ 63 static int oce_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd); 64 static int oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 65 static int oce_quiesce(dev_info_t *dip); 66 static int oce_suspend(dev_info_t *dip); 67 static int oce_resume(dev_info_t *dip); 68 static void oce_unconfigure(struct oce_dev *dev); 69 static void oce_init_locks(struct oce_dev *dev); 70 static void oce_destroy_locks(struct oce_dev *dev); 71 static void oce_get_params(struct oce_dev *dev); 72 73 static struct cb_ops oce_cb_ops = { 74 nulldev, /* cb_open */ 75 nulldev, /* cb_close */ 76 nodev, /* cb_strategy */ 77 nodev, /* cb_print */ 78 nodev, /* cb_dump */ 79 nodev, /* cb_read */ 80 nodev, /* cb_write */ 81 nodev, /* cb_ioctl */ 82 nodev, /* cb_devmap */ 83 nodev, /* cb_mmap */ 84 nodev, /* cb_segmap */ 85 nochpoll, /* cb_chpoll */ 86 ddi_prop_op, /* cb_prop_op */ 87 NULL, /* cb_stream */ 88 D_MP, /* cb_flag */ 89 CB_REV, /* cb_rev */ 90 nodev, /* cb_aread */ 91 nodev /* cb_awrite */ 92 }; 93 94 static struct dev_ops oce_dev_ops = { 95 DEVO_REV, /* devo_rev */ 96 0, /* devo_refcnt */ 97 NULL, /* devo_getinfo */ 98 NULL, /* devo_identify */ 99 nulldev, /* devo_probe */ 100 oce_attach, /* devo_attach */ 101 oce_detach, /* devo_detach */ 102 nodev, /* devo_reset */ 103 &oce_cb_ops, /* devo_cb_ops */ 104 NULL, /* devo_bus_ops */ 105 nodev, /* devo_power */ 106 oce_quiesce /* devo_quiesce */ 107 }; 108 109 static struct modldrv oce_drv = { 110 &mod_driverops, /* Type of module. This one is a driver */ 111 (char *)oce_ident_string, /* Description string */ 112 &oce_dev_ops, /* driver ops */ 113 }; 114 115 static struct modlinkage oce_mod_linkage = { 116 MODREV_1, &oce_drv, NULL 117 }; 118 119 #define OCE_M_CB_FLAGS (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 120 static mac_callbacks_t oce_mac_cb = { 121 OCE_M_CB_FLAGS, /* mc_callbacks */ 122 oce_m_stat, /* mc_getstat */ 123 oce_m_start, /* mc_start */ 124 oce_m_stop, /* mc_stop */ 125 oce_m_promiscuous, /* mc_setpromisc */ 126 oce_m_multicast, /* mc_multicast */ 127 oce_m_unicast, /* mc_unicast */ 128 oce_m_send, /* mc_tx */ 129 oce_m_ioctl, /* mc_ioctl */ 130 oce_m_getcap, /* mc_getcapab */ 131 NULL, /* open */ 132 NULL, /* close */ 133 oce_m_setprop, /* set properties */ 134 oce_m_getprop /* get properties */ 135 }; 136 137 extern mac_priv_prop_t oce_priv_props[]; 138 extern uint32_t oce_num_props; 139 140 /* Module Init */ 141 int 142 _info(struct modinfo *modinfop) 143 { 144 return (mod_info(&oce_mod_linkage, modinfop)); 145 } /* _info */ 146 147 int 148 _init(void) 149 { 150 int ret = 0; 151 152 /* install the module */ 153 mac_init_ops(&oce_dev_ops, "oce"); 154 155 ret = mod_install(&oce_mod_linkage); 156 if (ret) { 157 cmn_err(CE_WARN, "mod_install failed rval=%x", ret); 158 } 159 160 return (ret); 161 } /* _init */ 162 163 164 int 165 _fini(void) 166 { 167 int ret = 0; 168 /* remove the module */ 169 ret = mod_remove(&oce_mod_linkage); 170 if (ret != 0) { 171 return (ret); 172 } 173 174 mac_fini_ops(&oce_dev_ops); 175 176 return (ret); 177 } /* _fini */ 178 179 180 static int 181 oce_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 182 { 183 int ret = 0; 184 struct oce_dev *dev = NULL; 185 mac_register_t *mac; 186 187 switch (cmd) { 188 case DDI_RESUME: 189 return (oce_resume(dip)); 190 default: 191 return (DDI_FAILURE); 192 193 case DDI_ATTACH: 194 break; 195 } 196 oce_log(dev, CE_CONT, MOD_CONFIG, "!%s, %s", 197 oce_desc_string, oce_version); 198 199 /* allocate dev */ 200 dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP); 201 202 /* populate the dev structure */ 203 dev->dip = dip; 204 dev->dev_id = ddi_get_instance(dip); 205 dev->suspended = B_FALSE; 206 207 /* get the parameters */ 208 oce_get_params(dev); 209 210 /* 211 * set the ddi driver private data pointer. This is 212 * sent to all mac callback entry points 213 */ 214 ddi_set_driver_private(dip, dev); 215 216 dev->attach_state |= ATTACH_DEV_INIT; 217 218 oce_fm_init(dev); 219 dev->attach_state |= ATTACH_FM_INIT; 220 ret = oce_setup_intr(dev); 221 if (ret != DDI_SUCCESS) { 222 oce_log(dev, CE_WARN, MOD_CONFIG, 223 "Interrupt setup failed with %d", ret); 224 goto attach_fail; 225 226 } 227 228 /* initialize locks */ 229 oce_init_locks(dev); 230 dev->attach_state |= ATTACH_LOCK_INIT; 231 232 /* setup PCI bars */ 233 ret = oce_pci_init(dev); 234 if (ret != DDI_SUCCESS) { 235 oce_log(dev, CE_WARN, MOD_CONFIG, 236 "PCI initialization failed with %d", ret); 237 goto attach_fail; 238 } 239 dev->attach_state |= ATTACH_PCI_INIT; 240 241 /* HW init */ 242 ret = oce_hw_init(dev); 243 if (ret != DDI_SUCCESS) { 244 oce_log(dev, CE_WARN, MOD_CONFIG, 245 "HW initialization failed with %d", ret); 246 goto attach_fail; 247 } 248 dev->attach_state |= ATTACH_HW_INIT; 249 250 ret = oce_init_txrx(dev); 251 if (ret != DDI_SUCCESS) { 252 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 253 "Failed to init rings"); 254 goto attach_fail; 255 } 256 dev->attach_state |= ATTACH_SETUP_TXRX; 257 258 ret = oce_setup_adapter(dev); 259 if (ret != DDI_SUCCESS) { 260 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 261 "Failed to setup adapter"); 262 goto attach_fail; 263 } 264 dev->attach_state |= ATTACH_SETUP_ADAP; 265 266 267 ret = oce_stat_init(dev); 268 if (ret != DDI_SUCCESS) { 269 oce_log(dev, CE_WARN, MOD_CONFIG, 270 "kstat setup Failed with %d", ret); 271 goto attach_fail; 272 } 273 dev->attach_state |= ATTACH_STAT_INIT; 274 275 /* mac_register_t */ 276 oce_log(dev, CE_NOTE, MOD_CONFIG, 277 "MAC_VERSION = 0x%x", MAC_VERSION); 278 mac = mac_alloc(MAC_VERSION); 279 if (mac == NULL) { 280 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 281 "MAC allocation Failed"); 282 goto attach_fail; 283 } 284 /* 285 * fill the mac structure before calling mac_register 286 */ 287 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 288 mac->m_driver = dev; 289 mac->m_dip = dip; 290 mac->m_src_addr = dev->mac_addr; 291 mac->m_callbacks = &oce_mac_cb; 292 mac->m_min_sdu = 0; 293 mac->m_max_sdu = dev->mtu; 294 mac->m_margin = VLAN_TAGSZ; 295 mac->m_priv_props = oce_priv_props; 296 mac->m_priv_prop_count = oce_num_props; 297 298 oce_log(dev, CE_NOTE, MOD_CONFIG, 299 "Driver Private structure = 0x%p", (void *)dev); 300 301 /* now register with GLDv3 */ 302 ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle); 303 /* regardless of the status, free mac_register */ 304 mac_free(mac); 305 mac = NULL; 306 if (ret != DDI_SUCCESS) { 307 oce_log(dev, CE_WARN, MOD_CONFIG, 308 "MAC registration failed :0x%x", ret); 309 goto attach_fail; 310 311 } 312 313 /* correct link status only after start */ 314 mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN); 315 316 dev->attach_state |= ATTACH_MAC_REG; 317 dev->state |= STATE_INIT; 318 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", 319 "ATTACH SUCCESS"); 320 321 return (DDI_SUCCESS); 322 323 attach_fail: 324 oce_unconfigure(dev); 325 return (DDI_FAILURE); 326 } /* oce_attach */ 327 328 static int 329 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 330 { 331 struct oce_dev *dev; 332 int pcnt = 0; 333 334 dev = ddi_get_driver_private(dip); 335 if (dev == NULL) { 336 return (DDI_FAILURE); 337 } 338 oce_log(dev, CE_NOTE, MOD_CONFIG, 339 "Detaching driver: cmd = 0x%x", cmd); 340 341 switch (cmd) { 342 default: 343 return (DDI_FAILURE); 344 case DDI_SUSPEND: 345 return (oce_suspend(dip)); 346 case DDI_DETACH: 347 break; 348 } /* switch cmd */ 349 350 /* Fail detach if MAC unregister is unsuccessfule */ 351 if (mac_unregister(dev->mac_handle) != 0) { 352 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 353 "Failed to unregister MAC "); 354 return (DDI_FAILURE); 355 } 356 dev->attach_state &= ~ATTACH_MAC_REG; 357 358 /* check if the detach is called with out stopping */ 359 DEV_LOCK(dev); 360 if (dev->state & STATE_MAC_STARTED) { 361 dev->state &= ~STATE_MAC_STARTED; 362 oce_stop(dev); 363 DEV_UNLOCK(dev); 364 } else 365 DEV_UNLOCK(dev); 366 367 /* 368 * Wait for Packets sent up to be freed 369 */ 370 if ((pcnt = oce_rx_pending(dev)) != 0) { 371 oce_log(dev, CE_WARN, MOD_CONFIG, 372 "%d Pending Buffers Detach failed", pcnt); 373 return (DDI_FAILURE); 374 } 375 oce_unconfigure(dev); 376 377 return (DDI_SUCCESS); 378 } /* oce_detach */ 379 380 static int 381 oce_quiesce(dev_info_t *dip) 382 { 383 int ret = DDI_SUCCESS; 384 struct oce_dev *dev = ddi_get_driver_private(dip); 385 386 if (dev == NULL) { 387 return (DDI_FAILURE); 388 } 389 if (dev->suspended) { 390 return (DDI_SUCCESS); 391 } 392 393 oce_chip_di(dev); 394 395 ret = oce_reset_fun(dev); 396 397 return (ret); 398 } 399 400 static int 401 oce_suspend(dev_info_t *dip) 402 { 403 struct oce_dev *dev = ddi_get_driver_private(dip); 404 405 mutex_enter(&dev->dev_lock); 406 /* Suspend the card */ 407 dev->suspended = B_TRUE; 408 /* stop the adapter */ 409 if (dev->state & STATE_MAC_STARTED) { 410 oce_stop(dev); 411 oce_unsetup_adapter(dev); 412 } 413 dev->state &= ~STATE_MAC_STARTED; 414 mutex_exit(&dev->dev_lock); 415 return (DDI_SUCCESS); 416 } /* oce_suspend */ 417 418 static int 419 oce_resume(dev_info_t *dip) 420 { 421 struct oce_dev *dev; 422 int ret; 423 424 /* get the dev pointer from dip */ 425 dev = ddi_get_driver_private(dip); 426 mutex_enter(&dev->dev_lock); 427 if (!dev->suspended) { 428 mutex_exit(&dev->dev_lock); 429 return (DDI_SUCCESS); 430 } 431 if (dev->state & STATE_MAC_STARTED) { 432 ret = oce_setup_adapter(dev); 433 if (ret != DDI_SUCCESS) { 434 mutex_exit(&dev->dev_lock); 435 return (DDI_FAILURE); 436 } 437 ret = oce_start(dev); 438 if (ret != DDI_SUCCESS) { 439 mutex_exit(&dev->dev_lock); 440 return (DDI_FAILURE); 441 } 442 } 443 dev->suspended = B_FALSE; 444 dev->state |= STATE_MAC_STARTED; 445 mutex_exit(&dev->dev_lock); 446 return (ret); 447 } /* oce_resume */ 448 449 static void 450 oce_init_locks(struct oce_dev *dev) 451 { 452 /* initialize locks */ 453 mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER, 454 DDI_INTR_PRI(dev->intr_pri)); 455 mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER, 456 DDI_INTR_PRI(dev->intr_pri)); 457 } /* oce_init_locks */ 458 459 static void 460 oce_destroy_locks(struct oce_dev *dev) 461 { 462 mutex_destroy(&dev->dev_lock); 463 mutex_destroy(&dev->bmbx_lock); 464 } /* oce_destroy_locks */ 465 466 static void 467 oce_unconfigure(struct oce_dev *dev) 468 { 469 uint32_t state = dev->attach_state; 470 471 if (state & ATTACH_MAC_REG) { 472 (void) mac_unregister(dev->mac_handle); 473 } 474 if (state & ATTACH_STAT_INIT) { 475 oce_stat_fini(dev); 476 } 477 if (state & ATTACH_SETUP_ADAP) { 478 oce_unsetup_adapter(dev); 479 } 480 481 if (state & ATTACH_SETUP_TXRX) { 482 oce_fini_txrx(dev); 483 } 484 485 if (state & ATTACH_HW_INIT) { 486 oce_hw_fini(dev); 487 } 488 if (state & ATTACH_PCI_INIT) { 489 oce_pci_fini(dev); 490 } 491 if (state & ATTACH_LOCK_INIT) { 492 oce_destroy_locks(dev); 493 } 494 if (state & ATTACH_FM_INIT) { 495 oce_fm_fini(dev); 496 } 497 if (state & ATTACH_DEV_INIT) { 498 ddi_set_driver_private(dev->dip, NULL); 499 kmem_free(dev, sizeof (struct oce_dev)); 500 } 501 } /* oce_unconfigure */ 502 503 static void 504 oce_get_params(struct oce_dev *dev) 505 { 506 uint32_t log_level; 507 uint16_t mod_mask; 508 uint16_t severity; 509 510 /* non tunables */ 511 dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE; 512 dev->flow_control = OCE_DEFAULT_FLOW_CONTROL; 513 514 /* configurable parameters */ 515 516 /* restrict MTU to 1500 and 9000 only */ 517 dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 518 DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU); 519 if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU) 520 dev->mtu = OCE_MIN_MTU; 521 522 dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 523 DDI_PROP_DONTPASS, (char *)tx_ring_size_name, 524 OCE_DEFAULT_TX_RING_SIZE); 525 526 dev->tx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 527 DDI_PROP_DONTPASS, (char *)tx_bcopy_limit_name, 528 OCE_DEFAULT_TX_BCOPY_LIMIT); 529 dev->rx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 530 DDI_PROP_DONTPASS, (char *)rx_bcopy_limit_name, 531 OCE_DEFAULT_RX_BCOPY_LIMIT); 532 533 dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 534 DDI_PROP_DONTPASS, (char *)lso_capable_name, 1); 535 536 dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 537 DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY); 538 539 log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 540 DDI_PROP_DONTPASS, (char *)log_level_name, 541 OCE_DEFAULT_LOG_SETTINGS); 542 severity = (uint16_t)(log_level & 0xffff); 543 mod_mask = (uint16_t)(log_level >> 16); 544 if (mod_mask > MOD_ISR) { 545 mod_mask = 0; 546 } 547 if (severity > CE_IGNORE) { 548 severity = 0; 549 } 550 551 dev->mod_mask = mod_mask; 552 dev->severity = severity; 553 } /* oce_get_params */ 554