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 MC_PROPINFO) 121 static mac_callbacks_t oce_mac_cb = { 122 OCE_M_CB_FLAGS, /* mc_callbacks */ 123 oce_m_stat, /* mc_getstat */ 124 oce_m_start, /* mc_start */ 125 oce_m_stop, /* mc_stop */ 126 oce_m_promiscuous, /* mc_setpromisc */ 127 oce_m_multicast, /* mc_multicast */ 128 oce_m_unicast, /* mc_unicast */ 129 oce_m_send, /* mc_tx */ 130 NULL, 131 oce_m_ioctl, /* mc_ioctl */ 132 oce_m_getcap, /* mc_getcapab */ 133 NULL, /* open */ 134 NULL, /* close */ 135 oce_m_setprop, /* set properties */ 136 oce_m_getprop, /* get properties */ 137 oce_m_propinfo /* properties info */ 138 }; 139 140 extern char *oce_priv_props[]; 141 142 /* Module Init */ 143 int 144 _info(struct modinfo *modinfop) 145 { 146 return (mod_info(&oce_mod_linkage, modinfop)); 147 } /* _info */ 148 149 int 150 _init(void) 151 { 152 int ret = 0; 153 154 /* install the module */ 155 mac_init_ops(&oce_dev_ops, "oce"); 156 157 ret = mod_install(&oce_mod_linkage); 158 if (ret) { 159 cmn_err(CE_WARN, "mod_install failed rval=%x", ret); 160 } 161 162 return (ret); 163 } /* _init */ 164 165 166 int 167 _fini(void) 168 { 169 int ret = 0; 170 /* remove the module */ 171 ret = mod_remove(&oce_mod_linkage); 172 if (ret != 0) { 173 return (ret); 174 } 175 176 mac_fini_ops(&oce_dev_ops); 177 178 return (ret); 179 } /* _fini */ 180 181 182 static int 183 oce_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 184 { 185 int ret = 0; 186 struct oce_dev *dev = NULL; 187 mac_register_t *mac; 188 189 switch (cmd) { 190 case DDI_RESUME: 191 return (oce_resume(dip)); 192 default: 193 return (DDI_FAILURE); 194 195 case DDI_ATTACH: 196 break; 197 } 198 oce_log(dev, CE_CONT, MOD_CONFIG, "!%s, %s", 199 oce_desc_string, oce_version); 200 201 /* allocate dev */ 202 dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP); 203 204 /* populate the dev structure */ 205 dev->dip = dip; 206 dev->dev_id = ddi_get_instance(dip); 207 dev->suspended = B_FALSE; 208 209 /* get the parameters */ 210 oce_get_params(dev); 211 212 /* 213 * set the ddi driver private data pointer. This is 214 * sent to all mac callback entry points 215 */ 216 ddi_set_driver_private(dip, dev); 217 218 dev->attach_state |= ATTACH_DEV_INIT; 219 220 oce_fm_init(dev); 221 dev->attach_state |= ATTACH_FM_INIT; 222 ret = oce_setup_intr(dev); 223 if (ret != DDI_SUCCESS) { 224 oce_log(dev, CE_WARN, MOD_CONFIG, 225 "Interrupt setup failed with %d", ret); 226 goto attach_fail; 227 228 } 229 230 /* initialize locks */ 231 oce_init_locks(dev); 232 dev->attach_state |= ATTACH_LOCK_INIT; 233 234 /* setup PCI bars */ 235 ret = oce_pci_init(dev); 236 if (ret != DDI_SUCCESS) { 237 oce_log(dev, CE_WARN, MOD_CONFIG, 238 "PCI initialization failed with %d", ret); 239 goto attach_fail; 240 } 241 dev->attach_state |= ATTACH_PCI_INIT; 242 243 /* HW init */ 244 ret = oce_hw_init(dev); 245 if (ret != DDI_SUCCESS) { 246 oce_log(dev, CE_WARN, MOD_CONFIG, 247 "HW initialization failed with %d", ret); 248 goto attach_fail; 249 } 250 dev->attach_state |= ATTACH_HW_INIT; 251 252 ret = oce_init_txrx(dev); 253 if (ret != DDI_SUCCESS) { 254 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 255 "Failed to init rings"); 256 goto attach_fail; 257 } 258 dev->attach_state |= ATTACH_SETUP_TXRX; 259 260 ret = oce_setup_adapter(dev); 261 if (ret != DDI_SUCCESS) { 262 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 263 "Failed to setup adapter"); 264 goto attach_fail; 265 } 266 dev->attach_state |= ATTACH_SETUP_ADAP; 267 268 269 ret = oce_stat_init(dev); 270 if (ret != DDI_SUCCESS) { 271 oce_log(dev, CE_WARN, MOD_CONFIG, 272 "kstat setup Failed with %d", ret); 273 goto attach_fail; 274 } 275 dev->attach_state |= ATTACH_STAT_INIT; 276 277 /* mac_register_t */ 278 oce_log(dev, CE_NOTE, MOD_CONFIG, 279 "MAC_VERSION = 0x%x", MAC_VERSION); 280 mac = mac_alloc(MAC_VERSION); 281 if (mac == NULL) { 282 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 283 "MAC allocation Failed"); 284 goto attach_fail; 285 } 286 /* 287 * fill the mac structure before calling mac_register 288 */ 289 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 290 mac->m_driver = dev; 291 mac->m_dip = dip; 292 mac->m_src_addr = dev->mac_addr; 293 mac->m_callbacks = &oce_mac_cb; 294 mac->m_min_sdu = 0; 295 mac->m_max_sdu = dev->mtu; 296 mac->m_margin = VLAN_TAGSZ; 297 mac->m_priv_props = oce_priv_props; 298 299 oce_log(dev, CE_NOTE, MOD_CONFIG, 300 "Driver Private structure = 0x%p", (void *)dev); 301 302 /* now register with GLDv3 */ 303 ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle); 304 /* regardless of the status, free mac_register */ 305 mac_free(mac); 306 mac = NULL; 307 if (ret != DDI_SUCCESS) { 308 oce_log(dev, CE_WARN, MOD_CONFIG, 309 "MAC registration failed :0x%x", ret); 310 goto attach_fail; 311 312 } 313 314 /* correct link status only after start */ 315 mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN); 316 317 dev->attach_state |= ATTACH_MAC_REG; 318 dev->state |= STATE_INIT; 319 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", 320 "ATTACH SUCCESS"); 321 322 return (DDI_SUCCESS); 323 324 attach_fail: 325 oce_unconfigure(dev); 326 return (DDI_FAILURE); 327 } /* oce_attach */ 328 329 static int 330 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 331 { 332 struct oce_dev *dev; 333 int pcnt = 0; 334 335 dev = ddi_get_driver_private(dip); 336 if (dev == NULL) { 337 return (DDI_FAILURE); 338 } 339 oce_log(dev, CE_NOTE, MOD_CONFIG, 340 "Detaching driver: cmd = 0x%x", cmd); 341 342 switch (cmd) { 343 default: 344 return (DDI_FAILURE); 345 case DDI_SUSPEND: 346 return (oce_suspend(dip)); 347 case DDI_DETACH: 348 break; 349 } /* switch cmd */ 350 351 /* Fail detach if MAC unregister is unsuccessfule */ 352 if (mac_unregister(dev->mac_handle) != 0) { 353 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 354 "Failed to unregister MAC "); 355 return (DDI_FAILURE); 356 } 357 dev->attach_state &= ~ATTACH_MAC_REG; 358 359 /* check if the detach is called with out stopping */ 360 DEV_LOCK(dev); 361 if (dev->state & STATE_MAC_STARTED) { 362 dev->state &= ~STATE_MAC_STARTED; 363 oce_stop(dev); 364 DEV_UNLOCK(dev); 365 } else 366 DEV_UNLOCK(dev); 367 368 /* 369 * Wait for Packets sent up to be freed 370 */ 371 if ((pcnt = oce_rx_pending(dev)) != 0) { 372 oce_log(dev, CE_WARN, MOD_CONFIG, 373 "%d Pending Buffers Detach failed", pcnt); 374 return (DDI_FAILURE); 375 } 376 oce_unconfigure(dev); 377 378 return (DDI_SUCCESS); 379 } /* oce_detach */ 380 381 static int 382 oce_quiesce(dev_info_t *dip) 383 { 384 int ret = DDI_SUCCESS; 385 struct oce_dev *dev = ddi_get_driver_private(dip); 386 387 if (dev == NULL) { 388 return (DDI_FAILURE); 389 } 390 if (dev->suspended) { 391 return (DDI_SUCCESS); 392 } 393 394 oce_chip_di(dev); 395 396 ret = oce_reset_fun(dev); 397 398 return (ret); 399 } 400 401 static int 402 oce_suspend(dev_info_t *dip) 403 { 404 struct oce_dev *dev = ddi_get_driver_private(dip); 405 406 mutex_enter(&dev->dev_lock); 407 /* Suspend the card */ 408 dev->suspended = B_TRUE; 409 /* stop the adapter */ 410 if (dev->state & STATE_MAC_STARTED) { 411 oce_stop(dev); 412 oce_unsetup_adapter(dev); 413 } 414 dev->state &= ~STATE_MAC_STARTED; 415 mutex_exit(&dev->dev_lock); 416 return (DDI_SUCCESS); 417 } /* oce_suspend */ 418 419 static int 420 oce_resume(dev_info_t *dip) 421 { 422 struct oce_dev *dev; 423 int ret; 424 425 /* get the dev pointer from dip */ 426 dev = ddi_get_driver_private(dip); 427 mutex_enter(&dev->dev_lock); 428 if (!dev->suspended) { 429 mutex_exit(&dev->dev_lock); 430 return (DDI_SUCCESS); 431 } 432 if (dev->state & STATE_MAC_STARTED) { 433 ret = oce_setup_adapter(dev); 434 if (ret != DDI_SUCCESS) { 435 mutex_exit(&dev->dev_lock); 436 return (DDI_FAILURE); 437 } 438 ret = oce_start(dev); 439 if (ret != DDI_SUCCESS) { 440 mutex_exit(&dev->dev_lock); 441 return (DDI_FAILURE); 442 } 443 } 444 dev->suspended = B_FALSE; 445 dev->state |= STATE_MAC_STARTED; 446 mutex_exit(&dev->dev_lock); 447 return (ret); 448 } /* oce_resume */ 449 450 static void 451 oce_init_locks(struct oce_dev *dev) 452 { 453 /* initialize locks */ 454 mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER, 455 DDI_INTR_PRI(dev->intr_pri)); 456 mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER, 457 DDI_INTR_PRI(dev->intr_pri)); 458 } /* oce_init_locks */ 459 460 static void 461 oce_destroy_locks(struct oce_dev *dev) 462 { 463 mutex_destroy(&dev->dev_lock); 464 mutex_destroy(&dev->bmbx_lock); 465 } /* oce_destroy_locks */ 466 467 static void 468 oce_unconfigure(struct oce_dev *dev) 469 { 470 uint32_t state = dev->attach_state; 471 472 if (state & ATTACH_MAC_REG) { 473 (void) mac_unregister(dev->mac_handle); 474 } 475 if (state & ATTACH_STAT_INIT) { 476 oce_stat_fini(dev); 477 } 478 if (state & ATTACH_SETUP_ADAP) { 479 oce_unsetup_adapter(dev); 480 } 481 482 if (state & ATTACH_SETUP_TXRX) { 483 oce_fini_txrx(dev); 484 } 485 486 if (state & ATTACH_HW_INIT) { 487 oce_hw_fini(dev); 488 } 489 if (state & ATTACH_PCI_INIT) { 490 oce_pci_fini(dev); 491 } 492 if (state & ATTACH_LOCK_INIT) { 493 oce_destroy_locks(dev); 494 } 495 if (state & ATTACH_FM_INIT) { 496 oce_fm_fini(dev); 497 } 498 if (state & ATTACH_DEV_INIT) { 499 ddi_set_driver_private(dev->dip, NULL); 500 kmem_free(dev, sizeof (struct oce_dev)); 501 } 502 } /* oce_unconfigure */ 503 504 static void 505 oce_get_params(struct oce_dev *dev) 506 { 507 uint32_t log_level; 508 uint16_t mod_mask; 509 uint16_t severity; 510 511 /* non tunables */ 512 dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE; 513 dev->flow_control = OCE_DEFAULT_FLOW_CONTROL; 514 515 /* configurable parameters */ 516 517 /* restrict MTU to 1500 and 9000 only */ 518 dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 519 DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU); 520 if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU) 521 dev->mtu = OCE_MIN_MTU; 522 523 dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 524 DDI_PROP_DONTPASS, (char *)tx_ring_size_name, 525 OCE_DEFAULT_TX_RING_SIZE); 526 527 dev->tx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 528 DDI_PROP_DONTPASS, (char *)tx_bcopy_limit_name, 529 OCE_DEFAULT_TX_BCOPY_LIMIT); 530 dev->rx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 531 DDI_PROP_DONTPASS, (char *)rx_bcopy_limit_name, 532 OCE_DEFAULT_RX_BCOPY_LIMIT); 533 534 dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 535 DDI_PROP_DONTPASS, (char *)lso_capable_name, 1); 536 537 dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 538 DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY); 539 540 log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 541 DDI_PROP_DONTPASS, (char *)log_level_name, 542 OCE_DEFAULT_LOG_SETTINGS); 543 severity = (uint16_t)(log_level & 0xffff); 544 mod_mask = (uint16_t)(log_level >> 16); 545 if (mod_mask > MOD_ISR) { 546 mod_mask = 0; 547 } 548 if (severity > CE_IGNORE) { 549 severity = 0; 550 } 551 552 dev->mod_mask = mod_mask; 553 dev->severity = severity; 554 } /* oce_get_params */ 555