162306a36Sopenharmony_ci/* bnx2i.c: QLogic NetXtreme II iSCSI driver. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright (c) 2006 - 2013 Broadcom Corporation 462306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Mike Christie 662306a36Sopenharmony_ci * Copyright (c) 2014, QLogic Corporation 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 962306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1062306a36Sopenharmony_ci * the Free Software Foundation. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) 1362306a36Sopenharmony_ci * Previously Maintained by: Eddie Wai (eddie.wai@broadcom.com) 1462306a36Sopenharmony_ci * Maintained by: QLogic-Storage-Upstream@qlogic.com 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "bnx2i.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); 2062306a36Sopenharmony_cistatic u32 adapter_count; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define DRV_MODULE_NAME "bnx2i" 2362306a36Sopenharmony_ci#define DRV_MODULE_VERSION "2.7.10.1" 2462306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "Jul 16, 2014" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic char version[] = 2762306a36Sopenharmony_ci "QLogic NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ 2862306a36Sopenharmony_ci " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciMODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com> and " 3262306a36Sopenharmony_ci "Eddie Wai <eddie.wai@broadcom.com>"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic NetXtreme II BCM5706/5708/5709/57710/57711/57712" 3562306a36Sopenharmony_ci "/57800/57810/57840 iSCSI Driver"); 3662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3762306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic DEFINE_MUTEX(bnx2i_dev_lock); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciunsigned int event_coal_min = 24; 4262306a36Sopenharmony_cimodule_param(event_coal_min, int, 0664); 4362306a36Sopenharmony_ciMODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciunsigned int event_coal_div = 2; 4662306a36Sopenharmony_cimodule_param(event_coal_div, int, 0664); 4762306a36Sopenharmony_ciMODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciunsigned int en_tcp_dack = 1; 5062306a36Sopenharmony_cimodule_param(en_tcp_dack, int, 0664); 5162306a36Sopenharmony_ciMODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciunsigned int error_mask1 = 0x00; 5462306a36Sopenharmony_cimodule_param(error_mask1, uint, 0664); 5562306a36Sopenharmony_ciMODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1"); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciunsigned int error_mask2 = 0x00; 5862306a36Sopenharmony_cimodule_param(error_mask2, uint, 0664); 5962306a36Sopenharmony_ciMODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2"); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciunsigned int sq_size; 6262306a36Sopenharmony_cimodule_param(sq_size, int, 0664); 6362306a36Sopenharmony_ciMODULE_PARM_DESC(sq_size, "Configure SQ size"); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciunsigned int rq_size = BNX2I_RQ_WQES_DEFAULT; 6662306a36Sopenharmony_cimodule_param(rq_size, int, 0664); 6762306a36Sopenharmony_ciMODULE_PARM_DESC(rq_size, "Configure RQ size"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciu64 iscsi_error_mask = 0x00; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciDEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** 7462306a36Sopenharmony_ci * bnx2i_identify_device - identifies NetXtreme II device type 7562306a36Sopenharmony_ci * @hba: Adapter structure pointer 7662306a36Sopenharmony_ci * @dev: Corresponding cnic device 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * This function identifies the NX2 device type and sets appropriate 7962306a36Sopenharmony_ci * queue mailbox register access method, 5709 requires driver to 8062306a36Sopenharmony_ci * access MBOX regs using *bin* mode 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_civoid bnx2i_identify_device(struct bnx2i_hba *hba, struct cnic_dev *dev) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci hba->cnic_dev_type = 0; 8562306a36Sopenharmony_ci if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { 8662306a36Sopenharmony_ci if (hba->pci_did == PCI_DEVICE_ID_NX2_5706 || 8762306a36Sopenharmony_ci hba->pci_did == PCI_DEVICE_ID_NX2_5706S) { 8862306a36Sopenharmony_ci set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type); 8962306a36Sopenharmony_ci } else if (hba->pci_did == PCI_DEVICE_ID_NX2_5708 || 9062306a36Sopenharmony_ci hba->pci_did == PCI_DEVICE_ID_NX2_5708S) { 9162306a36Sopenharmony_ci set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type); 9262306a36Sopenharmony_ci } else if (hba->pci_did == PCI_DEVICE_ID_NX2_5709 || 9362306a36Sopenharmony_ci hba->pci_did == PCI_DEVICE_ID_NX2_5709S) { 9462306a36Sopenharmony_ci set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type); 9562306a36Sopenharmony_ci hba->mail_queue_access = BNX2I_MQ_BIN_MODE; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { 9862306a36Sopenharmony_ci set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type); 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n", 10162306a36Sopenharmony_ci hba->pci_did); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/** 10762306a36Sopenharmony_ci * get_adapter_list_head - returns head of adapter list 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistruct bnx2i_hba *get_adapter_list_head(void) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct bnx2i_hba *hba = NULL; 11262306a36Sopenharmony_ci struct bnx2i_hba *tmp_hba; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (!adapter_count) 11562306a36Sopenharmony_ci goto hba_not_found; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci mutex_lock(&bnx2i_dev_lock); 11862306a36Sopenharmony_ci list_for_each_entry(tmp_hba, &adapter_list, link) { 11962306a36Sopenharmony_ci if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) { 12062306a36Sopenharmony_ci hba = tmp_hba; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci mutex_unlock(&bnx2i_dev_lock); 12562306a36Sopenharmony_cihba_not_found: 12662306a36Sopenharmony_ci return hba; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/** 13162306a36Sopenharmony_ci * bnx2i_find_hba_for_cnic - maps cnic device instance to bnx2i adapter instance 13262306a36Sopenharmony_ci * @cnic: pointer to cnic device instance 13362306a36Sopenharmony_ci * 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistruct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct bnx2i_hba *hba, *temp; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci mutex_lock(&bnx2i_dev_lock); 14062306a36Sopenharmony_ci list_for_each_entry_safe(hba, temp, &adapter_list, link) { 14162306a36Sopenharmony_ci if (hba->cnic == cnic) { 14262306a36Sopenharmony_ci mutex_unlock(&bnx2i_dev_lock); 14362306a36Sopenharmony_ci return hba; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci mutex_unlock(&bnx2i_dev_lock); 14762306a36Sopenharmony_ci return NULL; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/** 15262306a36Sopenharmony_ci * bnx2i_start - cnic callback to initialize & start adapter instance 15362306a36Sopenharmony_ci * @handle: transparent handle pointing to adapter structure 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * This function maps adapter structure to pcidev structure and initiates 15662306a36Sopenharmony_ci * firmware handshake to enable/initialize on chip iscsi components 15762306a36Sopenharmony_ci * This bnx2i - cnic interface api callback is issued after following 15862306a36Sopenharmony_ci * 2 conditions are met - 15962306a36Sopenharmony_ci * a) underlying network interface is up (marked by event 'NETDEV_UP' 16062306a36Sopenharmony_ci * from netdev 16162306a36Sopenharmony_ci * b) bnx2i adapter instance is registered 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_civoid bnx2i_start(void *handle) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci#define BNX2I_INIT_POLL_TIME (1000 / HZ) 16662306a36Sopenharmony_ci struct bnx2i_hba *hba = handle; 16762306a36Sopenharmony_ci int i = HZ; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* On some bnx2x devices, it is possible that iSCSI is no 17062306a36Sopenharmony_ci * longer supported after firmware is downloaded. In that 17162306a36Sopenharmony_ci * case, the iscsi_init_msg will return failure. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci bnx2i_send_fw_iscsi_init_msg(hba); 17562306a36Sopenharmony_ci while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && 17662306a36Sopenharmony_ci !test_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state) && i--) 17762306a36Sopenharmony_ci msleep(BNX2I_INIT_POLL_TIME); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/** 18262306a36Sopenharmony_ci * bnx2i_chip_cleanup - local routine to handle chip cleanup 18362306a36Sopenharmony_ci * @hba: Adapter instance to register 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * Driver checks if adapter still has any active connections before 18662306a36Sopenharmony_ci * executing the cleanup process 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_cistatic void bnx2i_chip_cleanup(struct bnx2i_hba *hba) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct bnx2i_endpoint *bnx2i_ep; 19162306a36Sopenharmony_ci struct list_head *pos, *tmp; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (hba->ofld_conns_active) { 19462306a36Sopenharmony_ci /* Stage to force the disconnection 19562306a36Sopenharmony_ci * This is the case where the daemon is either slow or 19662306a36Sopenharmony_ci * not present 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci printk(KERN_ALERT "bnx2i: (%s) chip cleanup for %d active " 19962306a36Sopenharmony_ci "connections\n", hba->netdev->name, 20062306a36Sopenharmony_ci hba->ofld_conns_active); 20162306a36Sopenharmony_ci mutex_lock(&hba->net_dev_lock); 20262306a36Sopenharmony_ci list_for_each_safe(pos, tmp, &hba->ep_active_list) { 20362306a36Sopenharmony_ci bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link); 20462306a36Sopenharmony_ci /* Clean up the chip only */ 20562306a36Sopenharmony_ci bnx2i_hw_ep_disconnect(bnx2i_ep); 20662306a36Sopenharmony_ci bnx2i_ep->cm_sk = NULL; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci mutex_unlock(&hba->net_dev_lock); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/** 21462306a36Sopenharmony_ci * bnx2i_stop - cnic callback to shutdown adapter instance 21562306a36Sopenharmony_ci * @handle: transparent handle pointing to adapter structure 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * driver checks if adapter is already in shutdown mode, if not start 21862306a36Sopenharmony_ci * the shutdown process 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_civoid bnx2i_stop(void *handle) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct bnx2i_hba *hba = handle; 22362306a36Sopenharmony_ci int conns_active; 22462306a36Sopenharmony_ci int wait_delay = 1 * HZ; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* check if cleanup happened in GOING_DOWN context */ 22762306a36Sopenharmony_ci if (!test_and_set_bit(ADAPTER_STATE_GOING_DOWN, 22862306a36Sopenharmony_ci &hba->adapter_state)) { 22962306a36Sopenharmony_ci iscsi_host_for_each_session(hba->shost, 23062306a36Sopenharmony_ci bnx2i_drop_session); 23162306a36Sopenharmony_ci wait_delay = hba->hba_shutdown_tmo; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci /* Wait for inflight offload connection tasks to complete before 23462306a36Sopenharmony_ci * proceeding. Forcefully terminate all connection recovery in 23562306a36Sopenharmony_ci * progress at the earliest, either in bind(), send_pdu(LOGIN), 23662306a36Sopenharmony_ci * or conn_start() 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci wait_event_interruptible_timeout(hba->eh_wait, 23962306a36Sopenharmony_ci (list_empty(&hba->ep_ofld_list) && 24062306a36Sopenharmony_ci list_empty(&hba->ep_destroy_list)), 24162306a36Sopenharmony_ci 2 * HZ); 24262306a36Sopenharmony_ci /* Wait for all endpoints to be torn down, Chip will be reset once 24362306a36Sopenharmony_ci * control returns to network driver. So it is required to cleanup and 24462306a36Sopenharmony_ci * release all connection resources before returning from this routine. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci while (hba->ofld_conns_active) { 24762306a36Sopenharmony_ci conns_active = hba->ofld_conns_active; 24862306a36Sopenharmony_ci wait_event_interruptible_timeout(hba->eh_wait, 24962306a36Sopenharmony_ci (hba->ofld_conns_active != conns_active), 25062306a36Sopenharmony_ci wait_delay); 25162306a36Sopenharmony_ci if (hba->ofld_conns_active == conns_active) 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci bnx2i_chip_cleanup(hba); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* This flag should be cleared last so that ep_disconnect() gracefully 25762306a36Sopenharmony_ci * cleans up connection context 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); 26062306a36Sopenharmony_ci clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * bnx2i_init_one - initialize an adapter instance and allocate memory resources 26662306a36Sopenharmony_ci * @hba: bnx2i adapter instance 26762306a36Sopenharmony_ci * @cnic: cnic device handle 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Global resource lock is held during critical sections below. This routine is 27062306a36Sopenharmony_ci * called from either cnic_register_driver() or device hot plug context and 27162306a36Sopenharmony_ci * and does majority of device specific initialization 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_cistatic int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int rc; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci mutex_lock(&bnx2i_dev_lock); 27862306a36Sopenharmony_ci if (!cnic->max_iscsi_conn) { 27962306a36Sopenharmony_ci printk(KERN_ALERT "bnx2i: dev %s does not support " 28062306a36Sopenharmony_ci "iSCSI\n", hba->netdev->name); 28162306a36Sopenharmony_ci rc = -EOPNOTSUPP; 28262306a36Sopenharmony_ci goto out; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci hba->cnic = cnic; 28662306a36Sopenharmony_ci rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); 28762306a36Sopenharmony_ci if (!rc) { 28862306a36Sopenharmony_ci hba->age++; 28962306a36Sopenharmony_ci set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); 29062306a36Sopenharmony_ci list_add_tail(&hba->link, &adapter_list); 29162306a36Sopenharmony_ci adapter_count++; 29262306a36Sopenharmony_ci } else if (rc == -EBUSY) /* duplicate registration */ 29362306a36Sopenharmony_ci printk(KERN_ALERT "bnx2i, duplicate registration" 29462306a36Sopenharmony_ci "hba=%p, cnic=%p\n", hba, cnic); 29562306a36Sopenharmony_ci else if (rc == -EAGAIN) 29662306a36Sopenharmony_ci printk(KERN_ERR "bnx2i, driver not registered\n"); 29762306a36Sopenharmony_ci else if (rc == -EINVAL) 29862306a36Sopenharmony_ci printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI); 29962306a36Sopenharmony_ci else 30062306a36Sopenharmony_ci printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ciout: 30362306a36Sopenharmony_ci mutex_unlock(&bnx2i_dev_lock); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return rc; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/** 31062306a36Sopenharmony_ci * bnx2i_ulp_init - initialize an adapter instance 31162306a36Sopenharmony_ci * @dev: cnic device handle 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * Called from cnic_register_driver() context to initialize all enumerated 31462306a36Sopenharmony_ci * cnic devices. This routine allocate adapter structure and other 31562306a36Sopenharmony_ci * device specific resources. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_civoid bnx2i_ulp_init(struct cnic_dev *dev) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct bnx2i_hba *hba; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Allocate a HBA structure for this device */ 32262306a36Sopenharmony_ci hba = bnx2i_alloc_hba(dev); 32362306a36Sopenharmony_ci if (!hba) { 32462306a36Sopenharmony_ci printk(KERN_ERR "bnx2i init: hba initialization failed\n"); 32562306a36Sopenharmony_ci return; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Get PCI related information and update hba struct members */ 32962306a36Sopenharmony_ci clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); 33062306a36Sopenharmony_ci if (bnx2i_init_one(hba, dev)) { 33162306a36Sopenharmony_ci printk(KERN_ERR "bnx2i - hba %p init failed\n", hba); 33262306a36Sopenharmony_ci bnx2i_free_hba(hba); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/** 33862306a36Sopenharmony_ci * bnx2i_ulp_exit - shuts down adapter instance and frees all resources 33962306a36Sopenharmony_ci * @dev: cnic device handle 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_civoid bnx2i_ulp_exit(struct cnic_dev *dev) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct bnx2i_hba *hba; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci hba = bnx2i_find_hba_for_cnic(dev); 34762306a36Sopenharmony_ci if (!hba) { 34862306a36Sopenharmony_ci printk(KERN_INFO "bnx2i_ulp_exit: hba not " 34962306a36Sopenharmony_ci "found, dev 0x%p\n", dev); 35062306a36Sopenharmony_ci return; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci mutex_lock(&bnx2i_dev_lock); 35362306a36Sopenharmony_ci list_del_init(&hba->link); 35462306a36Sopenharmony_ci adapter_count--; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { 35762306a36Sopenharmony_ci hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); 35862306a36Sopenharmony_ci clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci mutex_unlock(&bnx2i_dev_lock); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci bnx2i_free_hba(hba); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/** 36762306a36Sopenharmony_ci * bnx2i_get_stats - Retrieve various statistic from iSCSI offload 36862306a36Sopenharmony_ci * @handle: bnx2i_hba 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * function callback exported via bnx2i - cnic driver interface to 37162306a36Sopenharmony_ci * retrieve various iSCSI offload related statistics. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ciint bnx2i_get_stats(void *handle) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct bnx2i_hba *hba = handle; 37662306a36Sopenharmony_ci struct iscsi_stats_info *stats; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!hba) 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci stats = (struct iscsi_stats_info *)hba->cnic->stats_addr; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (!stats) 38462306a36Sopenharmony_ci return -ENOMEM; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci strscpy(stats->version, DRV_MODULE_VERSION, sizeof(stats->version)); 38762306a36Sopenharmony_ci memcpy(stats->mac_add1 + 2, hba->cnic->mac_addr, ETH_ALEN); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci stats->max_frame_size = hba->netdev->mtu; 39062306a36Sopenharmony_ci stats->txq_size = hba->max_sqes; 39162306a36Sopenharmony_ci stats->rxq_size = hba->max_cqes; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci stats->txq_avg_depth = 0; 39462306a36Sopenharmony_ci stats->rxq_avg_depth = 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci GET_STATS_64(hba, stats, rx_pdus); 39762306a36Sopenharmony_ci GET_STATS_64(hba, stats, rx_bytes); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci GET_STATS_64(hba, stats, tx_pdus); 40062306a36Sopenharmony_ci GET_STATS_64(hba, stats, tx_bytes); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/** 40762306a36Sopenharmony_ci * bnx2i_cpu_online - Create a receive thread for an online CPU 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci * @cpu: cpu index for the online cpu 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_cistatic int bnx2i_cpu_online(unsigned int cpu) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct bnx2i_percpu_s *p; 41462306a36Sopenharmony_ci struct task_struct *thread; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci p = &per_cpu(bnx2i_percpu, cpu); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci thread = kthread_create_on_node(bnx2i_percpu_io_thread, (void *)p, 41962306a36Sopenharmony_ci cpu_to_node(cpu), 42062306a36Sopenharmony_ci "bnx2i_thread/%d", cpu); 42162306a36Sopenharmony_ci if (IS_ERR(thread)) 42262306a36Sopenharmony_ci return PTR_ERR(thread); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* bind thread to the cpu */ 42562306a36Sopenharmony_ci kthread_bind(thread, cpu); 42662306a36Sopenharmony_ci p->iothread = thread; 42762306a36Sopenharmony_ci wake_up_process(thread); 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int bnx2i_cpu_offline(unsigned int cpu) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct bnx2i_percpu_s *p; 43462306a36Sopenharmony_ci struct task_struct *thread; 43562306a36Sopenharmony_ci struct bnx2i_work *work, *tmp; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Prevent any new work from being queued for this CPU */ 43862306a36Sopenharmony_ci p = &per_cpu(bnx2i_percpu, cpu); 43962306a36Sopenharmony_ci spin_lock_bh(&p->p_work_lock); 44062306a36Sopenharmony_ci thread = p->iothread; 44162306a36Sopenharmony_ci p->iothread = NULL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Free all work in the list */ 44462306a36Sopenharmony_ci list_for_each_entry_safe(work, tmp, &p->work_list, list) { 44562306a36Sopenharmony_ci list_del_init(&work->list); 44662306a36Sopenharmony_ci bnx2i_process_scsi_cmd_resp(work->session, 44762306a36Sopenharmony_ci work->bnx2i_conn, &work->cqe); 44862306a36Sopenharmony_ci kfree(work); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci spin_unlock_bh(&p->p_work_lock); 45262306a36Sopenharmony_ci if (thread) 45362306a36Sopenharmony_ci kthread_stop(thread); 45462306a36Sopenharmony_ci return 0; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic enum cpuhp_state bnx2i_online_state; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/** 46062306a36Sopenharmony_ci * bnx2i_mod_init - module init entry point 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * initialize any driver wide global data structures such as endpoint pool, 46362306a36Sopenharmony_ci * tcp port manager/queue, sysfs. finally driver will register itself 46462306a36Sopenharmony_ci * with the cnic module 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_cistatic int __init bnx2i_mod_init(void) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci int err; 46962306a36Sopenharmony_ci unsigned cpu = 0; 47062306a36Sopenharmony_ci struct bnx2i_percpu_s *p; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci printk(KERN_INFO "%s", version); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (sq_size && !is_power_of_2(sq_size)) 47562306a36Sopenharmony_ci sq_size = roundup_pow_of_two(sq_size); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci bnx2i_scsi_xport_template = 47862306a36Sopenharmony_ci iscsi_register_transport(&bnx2i_iscsi_transport); 47962306a36Sopenharmony_ci if (!bnx2i_scsi_xport_template) { 48062306a36Sopenharmony_ci printk(KERN_ERR "Could not register bnx2i transport.\n"); 48162306a36Sopenharmony_ci err = -ENOMEM; 48262306a36Sopenharmony_ci goto out; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb); 48662306a36Sopenharmony_ci if (err) { 48762306a36Sopenharmony_ci printk(KERN_ERR "Could not register bnx2i cnic driver.\n"); 48862306a36Sopenharmony_ci goto unreg_xport; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Create percpu kernel threads to handle iSCSI I/O completions */ 49262306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 49362306a36Sopenharmony_ci p = &per_cpu(bnx2i_percpu, cpu); 49462306a36Sopenharmony_ci INIT_LIST_HEAD(&p->work_list); 49562306a36Sopenharmony_ci spin_lock_init(&p->p_work_lock); 49662306a36Sopenharmony_ci p->iothread = NULL; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/bnx2i:online", 50062306a36Sopenharmony_ci bnx2i_cpu_online, bnx2i_cpu_offline); 50162306a36Sopenharmony_ci if (err < 0) 50262306a36Sopenharmony_ci goto unreg_driver; 50362306a36Sopenharmony_ci bnx2i_online_state = err; 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ciunreg_driver: 50762306a36Sopenharmony_ci cnic_unregister_driver(CNIC_ULP_ISCSI); 50862306a36Sopenharmony_ciunreg_xport: 50962306a36Sopenharmony_ci iscsi_unregister_transport(&bnx2i_iscsi_transport); 51062306a36Sopenharmony_ciout: 51162306a36Sopenharmony_ci return err; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/** 51662306a36Sopenharmony_ci * bnx2i_mod_exit - module cleanup/exit entry point 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * Global resource lock and host adapter lock is held during critical sections 51962306a36Sopenharmony_ci * in this function. Driver will browse through the adapter list, cleans-up 52062306a36Sopenharmony_ci * each instance, unregisters iscsi transport name and finally driver will 52162306a36Sopenharmony_ci * unregister itself with the cnic module 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic void __exit bnx2i_mod_exit(void) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct bnx2i_hba *hba; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci mutex_lock(&bnx2i_dev_lock); 52862306a36Sopenharmony_ci while (!list_empty(&adapter_list)) { 52962306a36Sopenharmony_ci hba = list_entry(adapter_list.next, struct bnx2i_hba, link); 53062306a36Sopenharmony_ci list_del(&hba->link); 53162306a36Sopenharmony_ci adapter_count--; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { 53462306a36Sopenharmony_ci bnx2i_chip_cleanup(hba); 53562306a36Sopenharmony_ci hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); 53662306a36Sopenharmony_ci clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci bnx2i_free_hba(hba); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci mutex_unlock(&bnx2i_dev_lock); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci cpuhp_remove_state(bnx2i_online_state); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci iscsi_unregister_transport(&bnx2i_iscsi_transport); 54662306a36Sopenharmony_ci cnic_unregister_driver(CNIC_ULP_ISCSI); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cimodule_init(bnx2i_mod_init); 55062306a36Sopenharmony_cimodule_exit(bnx2i_mod_exit); 551