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_SETUP_INTR 0x4 39 #define ATTACH_LOCK_INIT 0x8 40 #define ATTACH_PCI_INIT 0x10 41 #define ATTACH_BOOTSTRAP_INIT 0x20 42 #define ATTACH_HW_INIT 0x40 43 #define ATTACH_ADD_HANDLERS 0x80 44 #define ATTACH_STAT_INIT 0x100 45 #define ATTACH_MAC_REG 0x200 46 47 /* ---[ globals and externs ]-------------------------------------------- */ 48 const char oce_ident_string[] = OCE_IDENT_STRING; 49 const char oce_mod_name[] = OCE_MOD_NAME; 50 static const char oce_desc_string[] = OCE_DESC_STRING; 51 52 char oce_version[] = OCE_REVISION; 53 54 /* driver properties */ 55 static const char mtu_prop_name[] = "oce_default_mtu"; 56 static const char tx_ring_size_name[] = "oce_tx_ring_size"; 57 static const char bcopy_limit_name[] = "oce_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 int oce_reset_fun(struct oce_dev *dev); 73 74 static struct cb_ops oce_cb_ops = { 75 nulldev, /* cb_open */ 76 nulldev, /* cb_close */ 77 nodev, /* cb_strategy */ 78 nodev, /* cb_print */ 79 nodev, /* cb_dump */ 80 nodev, /* cb_read */ 81 nodev, /* cb_write */ 82 nodev, /* cb_ioctl */ 83 nodev, /* cb_devmap */ 84 nodev, /* cb_mmap */ 85 nodev, /* cb_segmap */ 86 nochpoll, /* cb_chpoll */ 87 ddi_prop_op, /* cb_prop_op */ 88 NULL, /* cb_stream */ 89 D_MP, /* cb_flag */ 90 CB_REV, /* cb_rev */ 91 nodev, /* cb_aread */ 92 nodev /* cb_awrite */ 93 }; 94 95 static struct dev_ops oce_dev_ops = { 96 DEVO_REV, /* devo_rev */ 97 0, /* devo_refcnt */ 98 NULL, /* devo_getinfo */ 99 NULL, /* devo_identify */ 100 nulldev, /* devo_probe */ 101 oce_attach, /* devo_attach */ 102 oce_detach, /* devo_detach */ 103 nodev, /* devo_reset */ 104 &oce_cb_ops, /* devo_cb_ops */ 105 NULL, /* devo_bus_ops */ 106 nodev, /* devo_power */ 107 oce_quiesce /* devo_quiesce */ 108 }; 109 110 static struct modldrv oce_drv = { 111 &mod_driverops, /* Type of module. This one is a driver */ 112 (char *)oce_ident_string, /* Description string */ 113 &oce_dev_ops, /* driver ops */ 114 }; 115 116 static struct modlinkage oce_mod_linkage = { 117 MODREV_1, &oce_drv, NULL 118 }; 119 120 #define OCE_M_CB_FLAGS (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 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 oce_m_ioctl, /* mc_ioctl */ 131 oce_m_getcap, /* mc_getcapab */ 132 NULL, /* open */ 133 NULL, /* close */ 134 oce_m_setprop, /* set properties */ 135 oce_m_getprop /* get properties */ 136 }; 137 138 extern mac_priv_prop_t oce_priv_props[]; 139 extern uint32_t oce_num_props; 140 141 /* Module Init */ 142 int 143 _info(struct modinfo *modinfop) 144 { 145 return (mod_info(&oce_mod_linkage, modinfop)); 146 } /* _info */ 147 148 int 149 _init(void) 150 { 151 int ret = 0; 152 153 /* install the module */ 154 mac_init_ops(&oce_dev_ops, "oce"); 155 156 ret = mod_install(&oce_mod_linkage); 157 if (ret) { 158 cmn_err(CE_WARN, "mod_install failed rval=%x", ret); 159 } 160 161 return (ret); 162 } /* _init */ 163 164 165 int 166 _fini(void) 167 { 168 int ret = 0; 169 /* remove the module */ 170 ret = mod_remove(&oce_mod_linkage); 171 if (ret != 0) { 172 return (ret); 173 } 174 175 mac_fini_ops(&oce_dev_ops); 176 177 return (ret); 178 } /* _fini */ 179 180 181 static int 182 oce_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 183 { 184 int ret = 0; 185 int intr_types; 186 struct oce_dev *dev = NULL; 187 mac_register_t *mac; 188 struct mac_address_format mac_addr; 189 190 switch (cmd) { 191 case DDI_RESUME: 192 return (oce_resume(dip)); 193 default: 194 return (DDI_FAILURE); 195 196 case DDI_ATTACH: 197 break; 198 } 199 oce_log(dev, CE_CONT, MOD_CONFIG, "!%s, %s", 200 oce_desc_string, oce_version); 201 202 203 /* get supported intr types */ 204 ret = ddi_intr_get_supported_types(dip, &intr_types); 205 if (ret != DDI_SUCCESS) { 206 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 207 "Failed to retrieve intr types "); 208 return (DDI_FAILURE); 209 } 210 211 /* allocate dev */ 212 dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP); 213 214 /* populate the dev structure */ 215 dev->dip = dip; 216 dev->dev_id = ddi_get_instance(dip); 217 dev->intr_types = intr_types; 218 dev->suspended = B_FALSE; 219 220 /* get the parameters */ 221 oce_get_params(dev); 222 223 /* 224 * set the ddi driver private data pointer. This is 225 * sent to all mac callback entry points 226 */ 227 ddi_set_driver_private(dip, dev); 228 229 dev->attach_state |= ATTACH_DEV_INIT; 230 231 oce_fm_init(dev); 232 dev->attach_state |= ATTACH_FM_INIT; 233 234 ret = oce_setup_intr(dev); 235 if (ret != DDI_SUCCESS) { 236 oce_log(dev, CE_WARN, MOD_CONFIG, 237 "Interrupt setup failed with %d", ret); 238 goto attach_fail; 239 } 240 dev->attach_state |= ATTACH_SETUP_INTR; 241 242 /* initialize locks */ 243 oce_init_locks(dev); 244 dev->attach_state |= ATTACH_LOCK_INIT; 245 246 /* setup PCI bars */ 247 ret = oce_pci_init(dev); 248 if (ret != DDI_SUCCESS) { 249 oce_log(dev, CE_WARN, MOD_CONFIG, 250 "PCI initialization failed with %d", ret); 251 goto attach_fail; 252 } 253 dev->attach_state |= ATTACH_PCI_INIT; 254 255 /* check if reset if required */ 256 if (oce_is_reset_pci(dev)) { 257 ret = oce_pci_soft_reset(dev); 258 if (ret) { 259 oce_log(dev, CE_WARN, MOD_CONFIG, 260 "Device Reset failed: %d", ret); 261 goto attach_fail; 262 } 263 } 264 265 /* create bootstrap mailbox */ 266 dev->bmbx = oce_alloc_dma_buffer(dev, 267 sizeof (struct oce_bmbx), DDI_DMA_CONSISTENT); 268 if (dev->bmbx == NULL) { 269 oce_log(dev, CE_WARN, MOD_CONFIG, 270 "Failed to allocate bmbx: size = %u", 271 (uint32_t)sizeof (struct oce_bmbx)); 272 goto attach_fail; 273 } 274 dev->attach_state |= ATTACH_BOOTSTRAP_INIT; 275 276 /* initialize the BMBX */ 277 ret = oce_mbox_init(dev); 278 if (ret != 0) { 279 oce_log(dev, CE_WARN, MOD_CONFIG, 280 "Mailbox initialization Failed with %d", ret); 281 goto attach_fail; 282 } 283 284 /* read the firmware version */ 285 ret = oce_get_fw_version(dev); 286 if (ret != 0) { 287 oce_log(dev, CE_WARN, MOD_CONFIG, 288 "Firmaware version read failed with %d", ret); 289 goto attach_fail; 290 } 291 292 /* read the fw config */ 293 ret = oce_get_fw_config(dev); 294 if (ret != 0) { 295 oce_log(dev, CE_WARN, MOD_CONFIG, 296 "Firmware configuration read failed with %d", ret); 297 goto attach_fail; 298 } 299 300 /* read the MAC address */ 301 ret = oce_read_mac_addr(dev, dev->if_id, 1, 302 MAC_ADDRESS_TYPE_NETWORK, &mac_addr); 303 if (ret != 0) { 304 oce_log(dev, CE_WARN, MOD_CONFIG, 305 "MAC address read failed with %d", ret); 306 goto attach_fail; 307 } 308 bcopy(&mac_addr.mac_addr[0], &dev->mac_addr[0], ETHERADDRL); 309 310 ret = oce_stat_init(dev); 311 if (ret != DDI_SUCCESS) { 312 oce_log(dev, CE_WARN, MOD_CONFIG, 313 "kstat setup Failed with %d", ret); 314 goto attach_fail; 315 } 316 dev->attach_state |= ATTACH_STAT_INIT; 317 318 /* mac_register_t */ 319 oce_log(dev, CE_NOTE, MOD_CONFIG, 320 "MAC_VERSION = 0x%x", MAC_VERSION); 321 mac = mac_alloc(MAC_VERSION); 322 if (mac == NULL) { 323 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 324 "MAC allocation Failed"); 325 goto attach_fail; 326 } 327 /* 328 * fill the mac structure before calling mac_register 329 */ 330 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 331 mac->m_driver = dev; 332 mac->m_dip = dip; 333 mac->m_src_addr = dev->mac_addr; 334 mac->m_callbacks = &oce_mac_cb; 335 mac->m_min_sdu = 0; 336 mac->m_max_sdu = dev->mtu; 337 mac->m_margin = VLAN_TAGSZ; 338 mac->m_priv_props = oce_priv_props; 339 mac->m_priv_prop_count = oce_num_props; 340 341 oce_log(dev, CE_NOTE, MOD_CONFIG, 342 "Driver Private structure = 0x%p", (void *)dev); 343 344 /* now register with GLDv3 */ 345 ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle); 346 /* regardless of the status, free mac_register */ 347 mac_free(mac); 348 mac = NULL; 349 if (ret != DDI_SUCCESS) { 350 oce_log(dev, CE_WARN, MOD_CONFIG, 351 "MAC registration failed :0x%x", ret); 352 goto attach_fail; 353 354 } 355 356 /* correct link status only after start */ 357 mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN); 358 359 dev->attach_state |= ATTACH_MAC_REG; 360 dev->state |= STATE_INIT; 361 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s", 362 "ATTACH SUCCESS"); 363 364 return (DDI_SUCCESS); 365 366 attach_fail: 367 oce_unconfigure(dev); 368 return (DDI_FAILURE); 369 } /* oce_attach */ 370 371 static int 372 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 373 { 374 struct oce_dev *dev = ddi_get_driver_private(dip); 375 376 ASSERT(dev != NULL); 377 378 oce_log(dev, CE_NOTE, MOD_CONFIG, 379 "Detaching driver: cmd = 0x%x", cmd); 380 381 switch (cmd) { 382 case DDI_DETACH: 383 oce_unconfigure(dev); 384 break; 385 386 case DDI_SUSPEND: 387 return (oce_suspend(dip)); 388 389 default: 390 return (DDI_FAILURE); 391 } /* switch cmd */ 392 return (DDI_SUCCESS); 393 } /* oce_detach */ 394 395 static int 396 oce_quiesce(dev_info_t *dip) 397 { 398 int ret = DDI_SUCCESS; 399 struct oce_dev *dev = ddi_get_driver_private(dip); 400 401 if (dev == NULL) { 402 return (DDI_FAILURE); 403 } 404 if (dev->suspended) { 405 return (DDI_SUCCESS); 406 } 407 408 oce_di(dev); 409 410 ret = oce_reset_fun(dev); 411 412 return (ret); 413 } 414 415 static int 416 oce_suspend(dev_info_t *dip) 417 { 418 struct oce_dev *dev = ddi_get_driver_private(dip); 419 420 mutex_enter(&dev->dev_lock); 421 /* Suspend the card */ 422 dev->suspended = B_TRUE; 423 /* stop the adapter */ 424 if (dev->state & STATE_MAC_STARTED) { 425 oce_stop(dev); 426 } 427 dev->state &= ~STATE_MAC_STARTED; 428 mutex_exit(&dev->dev_lock); 429 return (DDI_SUCCESS); 430 } /* oce_suspend */ 431 432 static int 433 oce_resume(dev_info_t *dip) 434 { 435 struct oce_dev *dev; 436 int ret; 437 438 /* get the dev pointer from dip */ 439 dev = ddi_get_driver_private(dip); 440 mutex_enter(&dev->dev_lock); 441 if (!dev->suspended) { 442 mutex_exit(&dev->dev_lock); 443 return (DDI_SUCCESS); 444 } 445 if (dev->state & STATE_MAC_STARTED) { 446 ret = oce_start(dev); 447 if (ret != DDI_SUCCESS) { 448 mutex_exit(&dev->dev_lock); 449 return (DDI_FAILURE); 450 } 451 } 452 dev->suspended = B_FALSE; 453 dev->state |= STATE_MAC_STARTED; 454 mutex_exit(&dev->dev_lock); 455 return (ret); 456 } /* oce_resume */ 457 458 static void 459 oce_init_locks(struct oce_dev *dev) 460 { 461 /* initialize locks */ 462 mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER, 463 DDI_INTR_PRI(dev->intr_pri)); 464 mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER, 465 DDI_INTR_PRI(dev->intr_pri)); 466 } /* oce_init_locks */ 467 468 static void 469 oce_destroy_locks(struct oce_dev *dev) 470 { 471 mutex_destroy(&dev->dev_lock); 472 mutex_destroy(&dev->bmbx_lock); 473 } /* oce_destroy_locks */ 474 475 static void 476 oce_unconfigure(struct oce_dev *dev) 477 { 478 uint32_t state = dev->attach_state; 479 480 if (state & ATTACH_MAC_REG) { 481 (void) mac_unregister(dev->mac_handle); 482 } 483 if (state & ATTACH_STAT_INIT) { 484 oce_stat_fini(dev); 485 } 486 if (state & ATTACH_BOOTSTRAP_INIT) { 487 oce_free_dma_buffer(dev, dev->bmbx); 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_SETUP_INTR) { 496 (void) oce_teardown_intr(dev); 497 } 498 if (state & ATTACH_FM_INIT) { 499 oce_fm_fini(dev); 500 } 501 if (state & ATTACH_DEV_INIT) { 502 ddi_set_driver_private(dev->dip, NULL); 503 kmem_free(dev, sizeof (struct oce_dev)); 504 } 505 } /* oce_unconfigure */ 506 507 static void 508 oce_get_params(struct oce_dev *dev) 509 { 510 uint32_t log_level; 511 uint16_t mod_mask; 512 uint16_t severity; 513 514 /* non tunables */ 515 dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE; 516 dev->flow_control = OCE_DEFAULT_FLOW_CONTROL; 517 518 /* configurable parameters */ 519 520 /* restrict MTU to 1500 and 9000 only */ 521 dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 522 DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU); 523 if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU) 524 dev->mtu = OCE_MIN_MTU; 525 526 dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 527 DDI_PROP_DONTPASS, (char *)tx_ring_size_name, 528 OCE_DEFAULT_TX_RING_SIZE); 529 530 dev->bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 531 DDI_PROP_DONTPASS, (char *)bcopy_limit_name, 532 OCE_DEFAULT_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, 0); 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