18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/kernel.h> 388c2ecf20Sopenharmony_ci#include <linux/module.h> 398c2ecf20Sopenharmony_ci#include <linux/init.h> 408c2ecf20Sopenharmony_ci#include <linux/pci.h> 418c2ecf20Sopenharmony_ci#include <linux/aer.h> 428c2ecf20Sopenharmony_ci#include <linux/mm.h> 438c2ecf20Sopenharmony_ci#include <linux/notifier.h> 448c2ecf20Sopenharmony_ci#include <linux/kdebug.h> 458c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 468c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 478c2ecf20Sopenharmony_ci#include <linux/string.h> 488c2ecf20Sopenharmony_ci#include <linux/export.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "csio_init.h" 518c2ecf20Sopenharmony_ci#include "csio_defs.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define CSIO_MIN_MEMPOOL_SZ 64 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic struct dentry *csio_debugfs_root; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct scsi_transport_template *csio_fcoe_transport; 588c2ecf20Sopenharmony_cistatic struct scsi_transport_template *csio_fcoe_transport_vport; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * debugfs support 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistatic ssize_t 648c2ecf20Sopenharmony_cicsio_mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci loff_t pos = *ppos; 678c2ecf20Sopenharmony_ci loff_t avail = file_inode(file)->i_size; 688c2ecf20Sopenharmony_ci unsigned int mem = (uintptr_t)file->private_data & 3; 698c2ecf20Sopenharmony_ci struct csio_hw *hw = file->private_data - mem; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (pos < 0) 728c2ecf20Sopenharmony_ci return -EINVAL; 738c2ecf20Sopenharmony_ci if (pos >= avail) 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci if (count > avail - pos) 768c2ecf20Sopenharmony_ci count = avail - pos; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci while (count) { 798c2ecf20Sopenharmony_ci size_t len; 808c2ecf20Sopenharmony_ci int ret, ofst; 818c2ecf20Sopenharmony_ci __be32 data[16]; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (mem == MEM_MC) 848c2ecf20Sopenharmony_ci ret = hw->chip_ops->chip_mc_read(hw, 0, pos, 858c2ecf20Sopenharmony_ci data, NULL); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci ret = hw->chip_ops->chip_edc_read(hw, mem, pos, 888c2ecf20Sopenharmony_ci data, NULL); 898c2ecf20Sopenharmony_ci if (ret) 908c2ecf20Sopenharmony_ci return ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ofst = pos % sizeof(data); 938c2ecf20Sopenharmony_ci len = min(count, sizeof(data) - ofst); 948c2ecf20Sopenharmony_ci if (copy_to_user(buf, (u8 *)data + ofst, len)) 958c2ecf20Sopenharmony_ci return -EFAULT; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci buf += len; 988c2ecf20Sopenharmony_ci pos += len; 998c2ecf20Sopenharmony_ci count -= len; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci count = pos - *ppos; 1028c2ecf20Sopenharmony_ci *ppos = pos; 1038c2ecf20Sopenharmony_ci return count; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic const struct file_operations csio_mem_debugfs_fops = { 1078c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1088c2ecf20Sopenharmony_ci .open = simple_open, 1098c2ecf20Sopenharmony_ci .read = csio_mem_read, 1108c2ecf20Sopenharmony_ci .llseek = default_llseek, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_civoid csio_add_debugfs_mem(struct csio_hw *hw, const char *name, 1148c2ecf20Sopenharmony_ci unsigned int idx, unsigned int size_mb) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci debugfs_create_file_size(name, S_IRUSR, hw->debugfs_root, 1178c2ecf20Sopenharmony_ci (void *)hw + idx, &csio_mem_debugfs_fops, 1188c2ecf20Sopenharmony_ci size_mb << 20); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int csio_setup_debugfs(struct csio_hw *hw) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int i; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(hw->debugfs_root)) 1268c2ecf20Sopenharmony_ci return -1; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A); 1298c2ecf20Sopenharmony_ci if (i & EDRAM0_ENABLE_F) 1308c2ecf20Sopenharmony_ci csio_add_debugfs_mem(hw, "edc0", MEM_EDC0, 5); 1318c2ecf20Sopenharmony_ci if (i & EDRAM1_ENABLE_F) 1328c2ecf20Sopenharmony_ci csio_add_debugfs_mem(hw, "edc1", MEM_EDC1, 5); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci hw->chip_ops->chip_dfs_create_ext_mem(hw); 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * csio_dfs_create - Creates and sets up per-hw debugfs. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_cistatic int 1438c2ecf20Sopenharmony_cicsio_dfs_create(struct csio_hw *hw) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci if (csio_debugfs_root) { 1468c2ecf20Sopenharmony_ci hw->debugfs_root = debugfs_create_dir(pci_name(hw->pdev), 1478c2ecf20Sopenharmony_ci csio_debugfs_root); 1488c2ecf20Sopenharmony_ci csio_setup_debugfs(hw); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * csio_dfs_destroy - Destroys per-hw debugfs. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic void 1588c2ecf20Sopenharmony_cicsio_dfs_destroy(struct csio_hw *hw) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci debugfs_remove_recursive(hw->debugfs_root); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * csio_dfs_init - Debug filesystem initialization for the module. 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic void 1688c2ecf20Sopenharmony_cicsio_dfs_init(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci csio_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 1748c2ecf20Sopenharmony_ci * csio_dfs_exit - debugfs cleanup for the module. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistatic void 1778c2ecf20Sopenharmony_cicsio_dfs_exit(void) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci debugfs_remove(csio_debugfs_root); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * csio_pci_init - PCI initialization. 1848c2ecf20Sopenharmony_ci * @pdev: PCI device. 1858c2ecf20Sopenharmony_ci * @bars: Bitmask of bars to be requested. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Initializes the PCI function by enabling MMIO, setting bus 1888c2ecf20Sopenharmony_ci * mastership and setting DMA mask. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistatic int 1918c2ecf20Sopenharmony_cicsio_pci_init(struct pci_dev *pdev, int *bars) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int rv = -ENODEV; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci *bars = pci_select_bars(pdev, IORESOURCE_MEM); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (pci_enable_device_mem(pdev)) 1988c2ecf20Sopenharmony_ci goto err; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (pci_request_selected_regions(pdev, *bars, KBUILD_MODNAME)) 2018c2ecf20Sopenharmony_ci goto err_disable_device; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci pci_set_master(pdev); 2048c2ecf20Sopenharmony_ci pci_try_set_mwi(pdev); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 2078c2ecf20Sopenharmony_ci if (rv) 2088c2ecf20Sopenharmony_ci rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 2098c2ecf20Sopenharmony_ci if (rv) { 2108c2ecf20Sopenharmony_ci rv = -ENODEV; 2118c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No suitable DMA available.\n"); 2128c2ecf20Sopenharmony_ci goto err_release_regions; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cierr_release_regions: 2188c2ecf20Sopenharmony_ci pci_release_selected_regions(pdev, *bars); 2198c2ecf20Sopenharmony_cierr_disable_device: 2208c2ecf20Sopenharmony_ci pci_disable_device(pdev); 2218c2ecf20Sopenharmony_cierr: 2228c2ecf20Sopenharmony_ci return rv; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * csio_pci_exit - PCI unitialization. 2288c2ecf20Sopenharmony_ci * @pdev: PCI device. 2298c2ecf20Sopenharmony_ci * @bars: Bars to be released. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistatic void 2338c2ecf20Sopenharmony_cicsio_pci_exit(struct pci_dev *pdev, int *bars) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci pci_release_selected_regions(pdev, *bars); 2368c2ecf20Sopenharmony_ci pci_disable_device(pdev); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * csio_hw_init_workers - Initialize the HW module's worker threads. 2418c2ecf20Sopenharmony_ci * @hw: HW module. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic void 2458c2ecf20Sopenharmony_cicsio_hw_init_workers(struct csio_hw *hw) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci INIT_WORK(&hw->evtq_work, csio_evtq_worker); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void 2518c2ecf20Sopenharmony_cicsio_hw_exit_workers(struct csio_hw *hw) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci cancel_work_sync(&hw->evtq_work); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int 2578c2ecf20Sopenharmony_cicsio_create_queues(struct csio_hw *hw) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci int i, j; 2608c2ecf20Sopenharmony_ci struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw); 2618c2ecf20Sopenharmony_ci int rv; 2628c2ecf20Sopenharmony_ci struct csio_scsi_cpu_info *info; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (hw->flags & CSIO_HWF_Q_FW_ALLOCED) 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (hw->intr_mode != CSIO_IM_MSIX) { 2688c2ecf20Sopenharmony_ci rv = csio_wr_iq_create(hw, NULL, hw->intr_iq_idx, 2698c2ecf20Sopenharmony_ci 0, hw->pport[0].portid, false, NULL); 2708c2ecf20Sopenharmony_ci if (rv != 0) { 2718c2ecf20Sopenharmony_ci csio_err(hw, " Forward Interrupt IQ failed!: %d\n", rv); 2728c2ecf20Sopenharmony_ci return rv; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* FW event queue */ 2778c2ecf20Sopenharmony_ci rv = csio_wr_iq_create(hw, NULL, hw->fwevt_iq_idx, 2788c2ecf20Sopenharmony_ci csio_get_fwevt_intr_idx(hw), 2798c2ecf20Sopenharmony_ci hw->pport[0].portid, true, NULL); 2808c2ecf20Sopenharmony_ci if (rv != 0) { 2818c2ecf20Sopenharmony_ci csio_err(hw, "FW event IQ config failed!: %d\n", rv); 2828c2ecf20Sopenharmony_ci return rv; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Create mgmt queue */ 2868c2ecf20Sopenharmony_ci rv = csio_wr_eq_create(hw, NULL, mgmtm->eq_idx, 2878c2ecf20Sopenharmony_ci mgmtm->iq_idx, hw->pport[0].portid, NULL); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (rv != 0) { 2908c2ecf20Sopenharmony_ci csio_err(hw, "Mgmt EQ create failed!: %d\n", rv); 2918c2ecf20Sopenharmony_ci goto err; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Create SCSI queues */ 2958c2ecf20Sopenharmony_ci for (i = 0; i < hw->num_pports; i++) { 2968c2ecf20Sopenharmony_ci info = &hw->scsi_cpu_info[i]; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci for (j = 0; j < info->max_cpus; j++) { 2998c2ecf20Sopenharmony_ci struct csio_scsi_qset *sqset = &hw->sqset[i][j]; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci rv = csio_wr_iq_create(hw, NULL, sqset->iq_idx, 3028c2ecf20Sopenharmony_ci sqset->intr_idx, i, false, NULL); 3038c2ecf20Sopenharmony_ci if (rv != 0) { 3048c2ecf20Sopenharmony_ci csio_err(hw, 3058c2ecf20Sopenharmony_ci "SCSI module IQ config failed [%d][%d]:%d\n", 3068c2ecf20Sopenharmony_ci i, j, rv); 3078c2ecf20Sopenharmony_ci goto err; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci rv = csio_wr_eq_create(hw, NULL, sqset->eq_idx, 3108c2ecf20Sopenharmony_ci sqset->iq_idx, i, NULL); 3118c2ecf20Sopenharmony_ci if (rv != 0) { 3128c2ecf20Sopenharmony_ci csio_err(hw, 3138c2ecf20Sopenharmony_ci "SCSI module EQ config failed [%d][%d]:%d\n", 3148c2ecf20Sopenharmony_ci i, j, rv); 3158c2ecf20Sopenharmony_ci goto err; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } /* for all CPUs */ 3188c2ecf20Sopenharmony_ci } /* For all ports */ 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci hw->flags |= CSIO_HWF_Q_FW_ALLOCED; 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_cierr: 3238c2ecf20Sopenharmony_ci csio_wr_destroy_queues(hw, true); 3248c2ecf20Sopenharmony_ci return -EINVAL; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/* 3288c2ecf20Sopenharmony_ci * csio_config_queues - Configure the DMA queues. 3298c2ecf20Sopenharmony_ci * @hw: HW module. 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * Allocates memory for queues are registers them with FW. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ciint 3348c2ecf20Sopenharmony_cicsio_config_queues(struct csio_hw *hw) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int i, j, idx, k = 0; 3378c2ecf20Sopenharmony_ci int rv; 3388c2ecf20Sopenharmony_ci struct csio_scsi_qset *sqset; 3398c2ecf20Sopenharmony_ci struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw); 3408c2ecf20Sopenharmony_ci struct csio_scsi_qset *orig; 3418c2ecf20Sopenharmony_ci struct csio_scsi_cpu_info *info; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (hw->flags & CSIO_HWF_Q_MEM_ALLOCED) 3448c2ecf20Sopenharmony_ci return csio_create_queues(hw); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Calculate number of SCSI queues for MSIX we would like */ 3478c2ecf20Sopenharmony_ci hw->num_scsi_msix_cpus = num_online_cpus(); 3488c2ecf20Sopenharmony_ci hw->num_sqsets = num_online_cpus() * hw->num_pports; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (hw->num_sqsets > CSIO_MAX_SCSI_QSETS) { 3518c2ecf20Sopenharmony_ci hw->num_sqsets = CSIO_MAX_SCSI_QSETS; 3528c2ecf20Sopenharmony_ci hw->num_scsi_msix_cpus = CSIO_MAX_SCSI_CPU; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Initialize max_cpus, may get reduced during msix allocations */ 3568c2ecf20Sopenharmony_ci for (i = 0; i < hw->num_pports; i++) 3578c2ecf20Sopenharmony_ci hw->scsi_cpu_info[i].max_cpus = hw->num_scsi_msix_cpus; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci csio_dbg(hw, "nsqsets:%d scpus:%d\n", 3608c2ecf20Sopenharmony_ci hw->num_sqsets, hw->num_scsi_msix_cpus); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci csio_intr_enable(hw); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (hw->intr_mode != CSIO_IM_MSIX) { 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Allocate Forward interrupt iq. */ 3678c2ecf20Sopenharmony_ci hw->intr_iq_idx = csio_wr_alloc_q(hw, CSIO_INTR_IQSIZE, 3688c2ecf20Sopenharmony_ci CSIO_INTR_WRSIZE, CSIO_INGRESS, 3698c2ecf20Sopenharmony_ci (void *)hw, 0, 0, NULL); 3708c2ecf20Sopenharmony_ci if (hw->intr_iq_idx == -1) { 3718c2ecf20Sopenharmony_ci csio_err(hw, 3728c2ecf20Sopenharmony_ci "Forward interrupt queue creation failed\n"); 3738c2ecf20Sopenharmony_ci goto intr_disable; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Allocate the FW evt queue */ 3788c2ecf20Sopenharmony_ci hw->fwevt_iq_idx = csio_wr_alloc_q(hw, CSIO_FWEVT_IQSIZE, 3798c2ecf20Sopenharmony_ci CSIO_FWEVT_WRSIZE, 3808c2ecf20Sopenharmony_ci CSIO_INGRESS, (void *)hw, 3818c2ecf20Sopenharmony_ci CSIO_FWEVT_FLBUFS, 0, 3828c2ecf20Sopenharmony_ci csio_fwevt_intx_handler); 3838c2ecf20Sopenharmony_ci if (hw->fwevt_iq_idx == -1) { 3848c2ecf20Sopenharmony_ci csio_err(hw, "FW evt queue creation failed\n"); 3858c2ecf20Sopenharmony_ci goto intr_disable; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Allocate the mgmt queue */ 3898c2ecf20Sopenharmony_ci mgmtm->eq_idx = csio_wr_alloc_q(hw, CSIO_MGMT_EQSIZE, 3908c2ecf20Sopenharmony_ci CSIO_MGMT_EQ_WRSIZE, 3918c2ecf20Sopenharmony_ci CSIO_EGRESS, (void *)hw, 0, 0, NULL); 3928c2ecf20Sopenharmony_ci if (mgmtm->eq_idx == -1) { 3938c2ecf20Sopenharmony_ci csio_err(hw, "Failed to alloc egress queue for mgmt module\n"); 3948c2ecf20Sopenharmony_ci goto intr_disable; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Use FW IQ for MGMT req completion */ 3988c2ecf20Sopenharmony_ci mgmtm->iq_idx = hw->fwevt_iq_idx; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Allocate SCSI queues */ 4018c2ecf20Sopenharmony_ci for (i = 0; i < hw->num_pports; i++) { 4028c2ecf20Sopenharmony_ci info = &hw->scsi_cpu_info[i]; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci for (j = 0; j < hw->num_scsi_msix_cpus; j++) { 4058c2ecf20Sopenharmony_ci sqset = &hw->sqset[i][j]; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (j >= info->max_cpus) { 4088c2ecf20Sopenharmony_ci k = j % info->max_cpus; 4098c2ecf20Sopenharmony_ci orig = &hw->sqset[i][k]; 4108c2ecf20Sopenharmony_ci sqset->eq_idx = orig->eq_idx; 4118c2ecf20Sopenharmony_ci sqset->iq_idx = orig->iq_idx; 4128c2ecf20Sopenharmony_ci continue; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci idx = csio_wr_alloc_q(hw, csio_scsi_eqsize, 0, 4168c2ecf20Sopenharmony_ci CSIO_EGRESS, (void *)hw, 0, 0, 4178c2ecf20Sopenharmony_ci NULL); 4188c2ecf20Sopenharmony_ci if (idx == -1) { 4198c2ecf20Sopenharmony_ci csio_err(hw, "EQ creation failed for idx:%d\n", 4208c2ecf20Sopenharmony_ci idx); 4218c2ecf20Sopenharmony_ci goto intr_disable; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci sqset->eq_idx = idx; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci idx = csio_wr_alloc_q(hw, CSIO_SCSI_IQSIZE, 4278c2ecf20Sopenharmony_ci CSIO_SCSI_IQ_WRSZ, CSIO_INGRESS, 4288c2ecf20Sopenharmony_ci (void *)hw, 0, 0, 4298c2ecf20Sopenharmony_ci csio_scsi_intx_handler); 4308c2ecf20Sopenharmony_ci if (idx == -1) { 4318c2ecf20Sopenharmony_ci csio_err(hw, "IQ creation failed for idx:%d\n", 4328c2ecf20Sopenharmony_ci idx); 4338c2ecf20Sopenharmony_ci goto intr_disable; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci sqset->iq_idx = idx; 4368c2ecf20Sopenharmony_ci } /* for all CPUs */ 4378c2ecf20Sopenharmony_ci } /* For all ports */ 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci hw->flags |= CSIO_HWF_Q_MEM_ALLOCED; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci rv = csio_create_queues(hw); 4428c2ecf20Sopenharmony_ci if (rv != 0) 4438c2ecf20Sopenharmony_ci goto intr_disable; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* 4468c2ecf20Sopenharmony_ci * Now request IRQs for the vectors. In the event of a failure, 4478c2ecf20Sopenharmony_ci * cleanup is handled internally by this function. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci rv = csio_request_irqs(hw); 4508c2ecf20Sopenharmony_ci if (rv != 0) 4518c2ecf20Sopenharmony_ci return -EINVAL; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ciintr_disable: 4568c2ecf20Sopenharmony_ci csio_intr_disable(hw, false); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int 4628c2ecf20Sopenharmony_cicsio_resource_alloc(struct csio_hw *hw) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct csio_wrm *wrm = csio_hw_to_wrm(hw); 4658c2ecf20Sopenharmony_ci int rv = -ENOMEM; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci wrm->num_q = ((CSIO_MAX_SCSI_QSETS * 2) + CSIO_HW_NIQ + 4688c2ecf20Sopenharmony_ci CSIO_HW_NEQ + CSIO_HW_NFLQ + CSIO_HW_NINTXQ); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci hw->mb_mempool = mempool_create_kmalloc_pool(CSIO_MIN_MEMPOOL_SZ, 4718c2ecf20Sopenharmony_ci sizeof(struct csio_mb)); 4728c2ecf20Sopenharmony_ci if (!hw->mb_mempool) 4738c2ecf20Sopenharmony_ci goto err; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci hw->rnode_mempool = mempool_create_kmalloc_pool(CSIO_MIN_MEMPOOL_SZ, 4768c2ecf20Sopenharmony_ci sizeof(struct csio_rnode)); 4778c2ecf20Sopenharmony_ci if (!hw->rnode_mempool) 4788c2ecf20Sopenharmony_ci goto err_free_mb_mempool; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci hw->scsi_dma_pool = dma_pool_create("csio_scsi_dma_pool", 4818c2ecf20Sopenharmony_ci &hw->pdev->dev, CSIO_SCSI_RSP_LEN, 4828c2ecf20Sopenharmony_ci 8, 0); 4838c2ecf20Sopenharmony_ci if (!hw->scsi_dma_pool) 4848c2ecf20Sopenharmony_ci goto err_free_rn_pool; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cierr_free_rn_pool: 4898c2ecf20Sopenharmony_ci mempool_destroy(hw->rnode_mempool); 4908c2ecf20Sopenharmony_ci hw->rnode_mempool = NULL; 4918c2ecf20Sopenharmony_cierr_free_mb_mempool: 4928c2ecf20Sopenharmony_ci mempool_destroy(hw->mb_mempool); 4938c2ecf20Sopenharmony_ci hw->mb_mempool = NULL; 4948c2ecf20Sopenharmony_cierr: 4958c2ecf20Sopenharmony_ci return rv; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic void 4998c2ecf20Sopenharmony_cicsio_resource_free(struct csio_hw *hw) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci dma_pool_destroy(hw->scsi_dma_pool); 5028c2ecf20Sopenharmony_ci hw->scsi_dma_pool = NULL; 5038c2ecf20Sopenharmony_ci mempool_destroy(hw->rnode_mempool); 5048c2ecf20Sopenharmony_ci hw->rnode_mempool = NULL; 5058c2ecf20Sopenharmony_ci mempool_destroy(hw->mb_mempool); 5068c2ecf20Sopenharmony_ci hw->mb_mempool = NULL; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/* 5108c2ecf20Sopenharmony_ci * csio_hw_alloc - Allocate and initialize the HW module. 5118c2ecf20Sopenharmony_ci * @pdev: PCI device. 5128c2ecf20Sopenharmony_ci * 5138c2ecf20Sopenharmony_ci * Allocates HW structure, DMA, memory resources, maps BARS to 5148c2ecf20Sopenharmony_ci * host memory and initializes HW module. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_cistatic struct csio_hw *csio_hw_alloc(struct pci_dev *pdev) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct csio_hw *hw; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci hw = kzalloc(sizeof(struct csio_hw), GFP_KERNEL); 5218c2ecf20Sopenharmony_ci if (!hw) 5228c2ecf20Sopenharmony_ci goto err; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci hw->pdev = pdev; 5258c2ecf20Sopenharmony_ci strncpy(hw->drv_version, CSIO_DRV_VERSION, 32); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* memory pool/DMA pool allocation */ 5288c2ecf20Sopenharmony_ci if (csio_resource_alloc(hw)) 5298c2ecf20Sopenharmony_ci goto err_free_hw; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Get the start address of registers from BAR 0 */ 5328c2ecf20Sopenharmony_ci hw->regstart = ioremap(pci_resource_start(pdev, 0), 5338c2ecf20Sopenharmony_ci pci_resource_len(pdev, 0)); 5348c2ecf20Sopenharmony_ci if (!hw->regstart) { 5358c2ecf20Sopenharmony_ci csio_err(hw, "Could not map BAR 0, regstart = %p\n", 5368c2ecf20Sopenharmony_ci hw->regstart); 5378c2ecf20Sopenharmony_ci goto err_resource_free; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci csio_hw_init_workers(hw); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (csio_hw_init(hw)) 5438c2ecf20Sopenharmony_ci goto err_unmap_bar; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci csio_dfs_create(hw); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci csio_dbg(hw, "hw:%p\n", hw); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return hw; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cierr_unmap_bar: 5528c2ecf20Sopenharmony_ci csio_hw_exit_workers(hw); 5538c2ecf20Sopenharmony_ci iounmap(hw->regstart); 5548c2ecf20Sopenharmony_cierr_resource_free: 5558c2ecf20Sopenharmony_ci csio_resource_free(hw); 5568c2ecf20Sopenharmony_cierr_free_hw: 5578c2ecf20Sopenharmony_ci kfree(hw); 5588c2ecf20Sopenharmony_cierr: 5598c2ecf20Sopenharmony_ci return NULL; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/* 5638c2ecf20Sopenharmony_ci * csio_hw_free - Uninitialize and free the HW module. 5648c2ecf20Sopenharmony_ci * @hw: The HW module 5658c2ecf20Sopenharmony_ci * 5668c2ecf20Sopenharmony_ci * Disable interrupts, uninit the HW module, free resources, free hw. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_cistatic void 5698c2ecf20Sopenharmony_cicsio_hw_free(struct csio_hw *hw) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci csio_intr_disable(hw, true); 5728c2ecf20Sopenharmony_ci csio_hw_exit_workers(hw); 5738c2ecf20Sopenharmony_ci csio_hw_exit(hw); 5748c2ecf20Sopenharmony_ci iounmap(hw->regstart); 5758c2ecf20Sopenharmony_ci csio_dfs_destroy(hw); 5768c2ecf20Sopenharmony_ci csio_resource_free(hw); 5778c2ecf20Sopenharmony_ci kfree(hw); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/** 5818c2ecf20Sopenharmony_ci * csio_shost_init - Create and initialize the lnode module. 5828c2ecf20Sopenharmony_ci * @hw: The HW module. 5838c2ecf20Sopenharmony_ci * @dev: The device associated with this invocation. 5848c2ecf20Sopenharmony_ci * @probe: Called from probe context or not? 5858c2ecf20Sopenharmony_ci * @pln: Parent lnode if any. 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * Allocates lnode structure via scsi_host_alloc, initializes 5888c2ecf20Sopenharmony_ci * shost, initializes lnode module and registers with SCSI ML 5898c2ecf20Sopenharmony_ci * via scsi_host_add. This function is shared between physical and 5908c2ecf20Sopenharmony_ci * virtual node ports. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_cistruct csio_lnode * 5938c2ecf20Sopenharmony_cicsio_shost_init(struct csio_hw *hw, struct device *dev, 5948c2ecf20Sopenharmony_ci bool probe, struct csio_lnode *pln) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct Scsi_Host *shost = NULL; 5978c2ecf20Sopenharmony_ci struct csio_lnode *ln; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci csio_fcoe_shost_template.cmd_per_lun = csio_lun_qdepth; 6008c2ecf20Sopenharmony_ci csio_fcoe_shost_vport_template.cmd_per_lun = csio_lun_qdepth; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* 6038c2ecf20Sopenharmony_ci * hw->pdev is the physical port's PCI dev structure, 6048c2ecf20Sopenharmony_ci * which will be different from the NPIV dev structure. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci if (dev == &hw->pdev->dev) 6078c2ecf20Sopenharmony_ci shost = scsi_host_alloc( 6088c2ecf20Sopenharmony_ci &csio_fcoe_shost_template, 6098c2ecf20Sopenharmony_ci sizeof(struct csio_lnode)); 6108c2ecf20Sopenharmony_ci else 6118c2ecf20Sopenharmony_ci shost = scsi_host_alloc( 6128c2ecf20Sopenharmony_ci &csio_fcoe_shost_vport_template, 6138c2ecf20Sopenharmony_ci sizeof(struct csio_lnode)); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (!shost) 6168c2ecf20Sopenharmony_ci goto err; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci ln = shost_priv(shost); 6198c2ecf20Sopenharmony_ci memset(ln, 0, sizeof(struct csio_lnode)); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Link common lnode to this lnode */ 6228c2ecf20Sopenharmony_ci ln->dev_num = (shost->host_no << 16); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci shost->can_queue = CSIO_MAX_QUEUE; 6258c2ecf20Sopenharmony_ci shost->this_id = -1; 6268c2ecf20Sopenharmony_ci shost->unique_id = shost->host_no; 6278c2ecf20Sopenharmony_ci shost->max_cmd_len = 16; /* Max CDB length supported */ 6288c2ecf20Sopenharmony_ci shost->max_id = min_t(uint32_t, csio_fcoe_rnodes, 6298c2ecf20Sopenharmony_ci hw->fres_info.max_ssns); 6308c2ecf20Sopenharmony_ci shost->max_lun = CSIO_MAX_LUN; 6318c2ecf20Sopenharmony_ci if (dev == &hw->pdev->dev) 6328c2ecf20Sopenharmony_ci shost->transportt = csio_fcoe_transport; 6338c2ecf20Sopenharmony_ci else 6348c2ecf20Sopenharmony_ci shost->transportt = csio_fcoe_transport_vport; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* root lnode */ 6378c2ecf20Sopenharmony_ci if (!hw->rln) 6388c2ecf20Sopenharmony_ci hw->rln = ln; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Other initialization here: Common, Transport specific */ 6418c2ecf20Sopenharmony_ci if (csio_lnode_init(ln, hw, pln)) 6428c2ecf20Sopenharmony_ci goto err_shost_put; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (scsi_add_host_with_dma(shost, dev, &hw->pdev->dev)) 6458c2ecf20Sopenharmony_ci goto err_lnode_exit; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return ln; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cierr_lnode_exit: 6508c2ecf20Sopenharmony_ci csio_lnode_exit(ln); 6518c2ecf20Sopenharmony_cierr_shost_put: 6528c2ecf20Sopenharmony_ci scsi_host_put(shost); 6538c2ecf20Sopenharmony_cierr: 6548c2ecf20Sopenharmony_ci return NULL; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci/** 6588c2ecf20Sopenharmony_ci * csio_shost_exit - De-instantiate the shost. 6598c2ecf20Sopenharmony_ci * @ln: The lnode module corresponding to the shost. 6608c2ecf20Sopenharmony_ci * 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_civoid 6638c2ecf20Sopenharmony_cicsio_shost_exit(struct csio_lnode *ln) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct Scsi_Host *shost = csio_ln_to_shost(ln); 6668c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Inform transport */ 6698c2ecf20Sopenharmony_ci fc_remove_host(shost); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Inform SCSI ML */ 6728c2ecf20Sopenharmony_ci scsi_remove_host(shost); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Flush all the events, so that any rnode removal events 6758c2ecf20Sopenharmony_ci * already queued are all handled, before we remove the lnode. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 6788c2ecf20Sopenharmony_ci csio_evtq_flush(hw); 6798c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci csio_lnode_exit(ln); 6828c2ecf20Sopenharmony_ci scsi_host_put(shost); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistruct csio_lnode * 6868c2ecf20Sopenharmony_cicsio_lnode_alloc(struct csio_hw *hw) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci return csio_shost_init(hw, &hw->pdev->dev, false, NULL); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_civoid 6928c2ecf20Sopenharmony_cicsio_lnodes_block_request(struct csio_hw *hw) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 6958c2ecf20Sopenharmony_ci struct csio_lnode *sln; 6968c2ecf20Sopenharmony_ci struct csio_lnode *ln; 6978c2ecf20Sopenharmony_ci struct list_head *cur_ln, *cur_cln; 6988c2ecf20Sopenharmony_ci struct csio_lnode **lnode_list; 6998c2ecf20Sopenharmony_ci int cur_cnt = 0, ii; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci lnode_list = kzalloc((sizeof(struct csio_lnode *) * hw->num_lns), 7028c2ecf20Sopenharmony_ci GFP_KERNEL); 7038c2ecf20Sopenharmony_ci if (!lnode_list) { 7048c2ecf20Sopenharmony_ci csio_err(hw, "Failed to allocate lnodes_list"); 7058c2ecf20Sopenharmony_ci return; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 7098c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 7108c2ecf20Sopenharmony_ci list_for_each(cur_ln, &hw->sln_head) { 7118c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) cur_ln; 7128c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = sln; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 7158c2ecf20Sopenharmony_ci list_for_each(cur_cln, &sln->cln_head) 7168c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = (struct csio_lnode *) cur_cln; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci for (ii = 0; ii < cur_cnt; ii++) { 7218c2ecf20Sopenharmony_ci csio_dbg(hw, "Blocking IOs on lnode: %p\n", lnode_list[ii]); 7228c2ecf20Sopenharmony_ci ln = lnode_list[ii]; 7238c2ecf20Sopenharmony_ci shost = csio_ln_to_shost(ln); 7248c2ecf20Sopenharmony_ci scsi_block_requests(shost); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci kfree(lnode_list); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_civoid 7318c2ecf20Sopenharmony_cicsio_lnodes_unblock_request(struct csio_hw *hw) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct csio_lnode *ln; 7348c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 7358c2ecf20Sopenharmony_ci struct csio_lnode *sln; 7368c2ecf20Sopenharmony_ci struct list_head *cur_ln, *cur_cln; 7378c2ecf20Sopenharmony_ci struct csio_lnode **lnode_list; 7388c2ecf20Sopenharmony_ci int cur_cnt = 0, ii; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci lnode_list = kzalloc((sizeof(struct csio_lnode *) * hw->num_lns), 7418c2ecf20Sopenharmony_ci GFP_KERNEL); 7428c2ecf20Sopenharmony_ci if (!lnode_list) { 7438c2ecf20Sopenharmony_ci csio_err(hw, "Failed to allocate lnodes_list"); 7448c2ecf20Sopenharmony_ci return; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 7488c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 7498c2ecf20Sopenharmony_ci list_for_each(cur_ln, &hw->sln_head) { 7508c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) cur_ln; 7518c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = sln; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 7548c2ecf20Sopenharmony_ci list_for_each(cur_cln, &sln->cln_head) 7558c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = (struct csio_lnode *) cur_cln; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci for (ii = 0; ii < cur_cnt; ii++) { 7608c2ecf20Sopenharmony_ci csio_dbg(hw, "unblocking IOs on lnode: %p\n", lnode_list[ii]); 7618c2ecf20Sopenharmony_ci ln = lnode_list[ii]; 7628c2ecf20Sopenharmony_ci shost = csio_ln_to_shost(ln); 7638c2ecf20Sopenharmony_ci scsi_unblock_requests(shost); 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci kfree(lnode_list); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_civoid 7698c2ecf20Sopenharmony_cicsio_lnodes_block_by_port(struct csio_hw *hw, uint8_t portid) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct csio_lnode *ln; 7728c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 7738c2ecf20Sopenharmony_ci struct csio_lnode *sln; 7748c2ecf20Sopenharmony_ci struct list_head *cur_ln, *cur_cln; 7758c2ecf20Sopenharmony_ci struct csio_lnode **lnode_list; 7768c2ecf20Sopenharmony_ci int cur_cnt = 0, ii; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci lnode_list = kzalloc((sizeof(struct csio_lnode *) * hw->num_lns), 7798c2ecf20Sopenharmony_ci GFP_KERNEL); 7808c2ecf20Sopenharmony_ci if (!lnode_list) { 7818c2ecf20Sopenharmony_ci csio_err(hw, "Failed to allocate lnodes_list"); 7828c2ecf20Sopenharmony_ci return; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 7868c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 7878c2ecf20Sopenharmony_ci list_for_each(cur_ln, &hw->sln_head) { 7888c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) cur_ln; 7898c2ecf20Sopenharmony_ci if (sln->portid != portid) 7908c2ecf20Sopenharmony_ci continue; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = sln; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 7958c2ecf20Sopenharmony_ci list_for_each(cur_cln, &sln->cln_head) 7968c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = (struct csio_lnode *) cur_cln; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci for (ii = 0; ii < cur_cnt; ii++) { 8018c2ecf20Sopenharmony_ci csio_dbg(hw, "Blocking IOs on lnode: %p\n", lnode_list[ii]); 8028c2ecf20Sopenharmony_ci ln = lnode_list[ii]; 8038c2ecf20Sopenharmony_ci shost = csio_ln_to_shost(ln); 8048c2ecf20Sopenharmony_ci scsi_block_requests(shost); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci kfree(lnode_list); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_civoid 8108c2ecf20Sopenharmony_cicsio_lnodes_unblock_by_port(struct csio_hw *hw, uint8_t portid) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct csio_lnode *ln; 8138c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 8148c2ecf20Sopenharmony_ci struct csio_lnode *sln; 8158c2ecf20Sopenharmony_ci struct list_head *cur_ln, *cur_cln; 8168c2ecf20Sopenharmony_ci struct csio_lnode **lnode_list; 8178c2ecf20Sopenharmony_ci int cur_cnt = 0, ii; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci lnode_list = kzalloc((sizeof(struct csio_lnode *) * hw->num_lns), 8208c2ecf20Sopenharmony_ci GFP_KERNEL); 8218c2ecf20Sopenharmony_ci if (!lnode_list) { 8228c2ecf20Sopenharmony_ci csio_err(hw, "Failed to allocate lnodes_list"); 8238c2ecf20Sopenharmony_ci return; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 8278c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 8288c2ecf20Sopenharmony_ci list_for_each(cur_ln, &hw->sln_head) { 8298c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) cur_ln; 8308c2ecf20Sopenharmony_ci if (sln->portid != portid) 8318c2ecf20Sopenharmony_ci continue; 8328c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = sln; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 8358c2ecf20Sopenharmony_ci list_for_each(cur_cln, &sln->cln_head) 8368c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = (struct csio_lnode *) cur_cln; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci for (ii = 0; ii < cur_cnt; ii++) { 8418c2ecf20Sopenharmony_ci csio_dbg(hw, "unblocking IOs on lnode: %p\n", lnode_list[ii]); 8428c2ecf20Sopenharmony_ci ln = lnode_list[ii]; 8438c2ecf20Sopenharmony_ci shost = csio_ln_to_shost(ln); 8448c2ecf20Sopenharmony_ci scsi_unblock_requests(shost); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci kfree(lnode_list); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_civoid 8508c2ecf20Sopenharmony_cicsio_lnodes_exit(struct csio_hw *hw, bool npiv) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct csio_lnode *sln; 8538c2ecf20Sopenharmony_ci struct csio_lnode *ln; 8548c2ecf20Sopenharmony_ci struct list_head *cur_ln, *cur_cln; 8558c2ecf20Sopenharmony_ci struct csio_lnode **lnode_list; 8568c2ecf20Sopenharmony_ci int cur_cnt = 0, ii; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci lnode_list = kzalloc((sizeof(struct csio_lnode *) * hw->num_lns), 8598c2ecf20Sopenharmony_ci GFP_KERNEL); 8608c2ecf20Sopenharmony_ci if (!lnode_list) { 8618c2ecf20Sopenharmony_ci csio_err(hw, "lnodes_exit: Failed to allocate lnodes_list.\n"); 8628c2ecf20Sopenharmony_ci return; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci /* Get all child lnodes(NPIV ports) */ 8668c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 8678c2ecf20Sopenharmony_ci list_for_each(cur_ln, &hw->sln_head) { 8688c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) cur_ln; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 8718c2ecf20Sopenharmony_ci list_for_each(cur_cln, &sln->cln_head) 8728c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = (struct csio_lnode *) cur_cln; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Delete NPIV lnodes */ 8778c2ecf20Sopenharmony_ci for (ii = 0; ii < cur_cnt; ii++) { 8788c2ecf20Sopenharmony_ci csio_dbg(hw, "Deleting child lnode: %p\n", lnode_list[ii]); 8798c2ecf20Sopenharmony_ci ln = lnode_list[ii]; 8808c2ecf20Sopenharmony_ci fc_vport_terminate(ln->fc_vport); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* Delete only npiv lnodes */ 8848c2ecf20Sopenharmony_ci if (npiv) 8858c2ecf20Sopenharmony_ci goto free_lnodes; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci cur_cnt = 0; 8888c2ecf20Sopenharmony_ci /* Get all physical lnodes */ 8898c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 8908c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 8918c2ecf20Sopenharmony_ci list_for_each(cur_ln, &hw->sln_head) { 8928c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) cur_ln; 8938c2ecf20Sopenharmony_ci lnode_list[cur_cnt++] = sln; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Delete physical lnodes */ 8988c2ecf20Sopenharmony_ci for (ii = 0; ii < cur_cnt; ii++) { 8998c2ecf20Sopenharmony_ci csio_dbg(hw, "Deleting parent lnode: %p\n", lnode_list[ii]); 9008c2ecf20Sopenharmony_ci csio_shost_exit(lnode_list[ii]); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cifree_lnodes: 9048c2ecf20Sopenharmony_ci kfree(lnode_list); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/* 9088c2ecf20Sopenharmony_ci * csio_lnode_init_post: Set lnode attributes after starting HW. 9098c2ecf20Sopenharmony_ci * @ln: lnode. 9108c2ecf20Sopenharmony_ci * 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_cistatic void 9138c2ecf20Sopenharmony_cicsio_lnode_init_post(struct csio_lnode *ln) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci struct Scsi_Host *shost = csio_ln_to_shost(ln); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci csio_fchost_attr_init(ln); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci scsi_scan_host(shost); 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/* 9238c2ecf20Sopenharmony_ci * csio_probe_one - Instantiate this function. 9248c2ecf20Sopenharmony_ci * @pdev: PCI device 9258c2ecf20Sopenharmony_ci * @id: Device ID 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * This is the .probe() callback of the driver. This function: 9288c2ecf20Sopenharmony_ci * - Initializes the PCI function by enabling MMIO, setting bus 9298c2ecf20Sopenharmony_ci * mastership and setting DMA mask. 9308c2ecf20Sopenharmony_ci * - Allocates HW structure, DMA, memory resources, maps BARS to 9318c2ecf20Sopenharmony_ci * host memory and initializes HW module. 9328c2ecf20Sopenharmony_ci * - Allocates lnode structure via scsi_host_alloc, initializes 9338c2ecf20Sopenharmony_ci * shost, initialized lnode module and registers with SCSI ML 9348c2ecf20Sopenharmony_ci * via scsi_host_add. 9358c2ecf20Sopenharmony_ci * - Enables interrupts, and starts the chip by kicking off the 9368c2ecf20Sopenharmony_ci * HW state machine. 9378c2ecf20Sopenharmony_ci * - Once hardware is ready, initiated scan of the host via 9388c2ecf20Sopenharmony_ci * scsi_scan_host. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_cistatic int csio_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci int rv; 9438c2ecf20Sopenharmony_ci int bars; 9448c2ecf20Sopenharmony_ci int i; 9458c2ecf20Sopenharmony_ci struct csio_hw *hw; 9468c2ecf20Sopenharmony_ci struct csio_lnode *ln; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* probe only T5 and T6 cards */ 9498c2ecf20Sopenharmony_ci if (!csio_is_t5((pdev->device & CSIO_HW_CHIP_MASK)) && 9508c2ecf20Sopenharmony_ci !csio_is_t6((pdev->device & CSIO_HW_CHIP_MASK))) 9518c2ecf20Sopenharmony_ci return -ENODEV; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci rv = csio_pci_init(pdev, &bars); 9548c2ecf20Sopenharmony_ci if (rv) 9558c2ecf20Sopenharmony_ci goto err; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci hw = csio_hw_alloc(pdev); 9588c2ecf20Sopenharmony_ci if (!hw) { 9598c2ecf20Sopenharmony_ci rv = -ENODEV; 9608c2ecf20Sopenharmony_ci goto err_pci_exit; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (!pcie_relaxed_ordering_enabled(pdev)) 9648c2ecf20Sopenharmony_ci hw->flags |= CSIO_HWF_ROOT_NO_RELAXED_ORDERING; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, hw); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci rv = csio_hw_start(hw); 9698c2ecf20Sopenharmony_ci if (rv) { 9708c2ecf20Sopenharmony_ci if (rv == -EINVAL) { 9718c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 9728c2ecf20Sopenharmony_ci "Failed to start FW, continuing in debug mode.\n"); 9738c2ecf20Sopenharmony_ci return 0; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci goto err_lnode_exit; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci sprintf(hw->fwrev_str, "%u.%u.%u.%u\n", 9798c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(hw->fwrev), 9808c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(hw->fwrev), 9818c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(hw->fwrev), 9828c2ecf20Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(hw->fwrev)); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci for (i = 0; i < hw->num_pports; i++) { 9858c2ecf20Sopenharmony_ci ln = csio_shost_init(hw, &pdev->dev, true, NULL); 9868c2ecf20Sopenharmony_ci if (!ln) { 9878c2ecf20Sopenharmony_ci rv = -ENODEV; 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci /* Initialize portid */ 9918c2ecf20Sopenharmony_ci ln->portid = hw->pport[i].portid; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 9948c2ecf20Sopenharmony_ci if (csio_lnode_start(ln) != 0) 9958c2ecf20Sopenharmony_ci rv = -ENODEV; 9968c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (rv) 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci csio_lnode_init_post(ln); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (rv) 10058c2ecf20Sopenharmony_ci goto err_lnode_exit; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return 0; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cierr_lnode_exit: 10108c2ecf20Sopenharmony_ci csio_lnodes_block_request(hw); 10118c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 10128c2ecf20Sopenharmony_ci csio_hw_stop(hw); 10138c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 10148c2ecf20Sopenharmony_ci csio_lnodes_unblock_request(hw); 10158c2ecf20Sopenharmony_ci csio_lnodes_exit(hw, 0); 10168c2ecf20Sopenharmony_ci csio_hw_free(hw); 10178c2ecf20Sopenharmony_cierr_pci_exit: 10188c2ecf20Sopenharmony_ci csio_pci_exit(pdev, &bars); 10198c2ecf20Sopenharmony_cierr: 10208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "probe of device failed: %d\n", rv); 10218c2ecf20Sopenharmony_ci return rv; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci/* 10258c2ecf20Sopenharmony_ci * csio_remove_one - Remove one instance of the driver at this PCI function. 10268c2ecf20Sopenharmony_ci * @pdev: PCI device 10278c2ecf20Sopenharmony_ci * 10288c2ecf20Sopenharmony_ci * Used during hotplug operation. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_cistatic void csio_remove_one(struct pci_dev *pdev) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct csio_hw *hw = pci_get_drvdata(pdev); 10338c2ecf20Sopenharmony_ci int bars = pci_select_bars(pdev, IORESOURCE_MEM); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci csio_lnodes_block_request(hw); 10368c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Stops lnode, Rnode s/m 10398c2ecf20Sopenharmony_ci * Quiesce IOs. 10408c2ecf20Sopenharmony_ci * All sessions with remote ports are unregistered. 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_ci csio_hw_stop(hw); 10438c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 10448c2ecf20Sopenharmony_ci csio_lnodes_unblock_request(hw); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci csio_lnodes_exit(hw, 0); 10478c2ecf20Sopenharmony_ci csio_hw_free(hw); 10488c2ecf20Sopenharmony_ci csio_pci_exit(pdev, &bars); 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci/* 10528c2ecf20Sopenharmony_ci * csio_pci_error_detected - PCI error was detected 10538c2ecf20Sopenharmony_ci * @pdev: PCI device 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_cistatic pci_ers_result_t 10578c2ecf20Sopenharmony_cicsio_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci struct csio_hw *hw = pci_get_drvdata(pdev); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci csio_lnodes_block_request(hw); 10628c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Post PCI error detected evt to HW s/m 10658c2ecf20Sopenharmony_ci * HW s/m handles this evt by quiescing IOs, unregisters rports 10668c2ecf20Sopenharmony_ci * and finally takes the device to offline. 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci csio_post_event(&hw->sm, CSIO_HWE_PCIERR_DETECTED); 10698c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 10708c2ecf20Sopenharmony_ci csio_lnodes_unblock_request(hw); 10718c2ecf20Sopenharmony_ci csio_lnodes_exit(hw, 0); 10728c2ecf20Sopenharmony_ci csio_intr_disable(hw, true); 10738c2ecf20Sopenharmony_ci pci_disable_device(pdev); 10748c2ecf20Sopenharmony_ci return state == pci_channel_io_perm_failure ? 10758c2ecf20Sopenharmony_ci PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci/* 10798c2ecf20Sopenharmony_ci * csio_pci_slot_reset - PCI slot has been reset. 10808c2ecf20Sopenharmony_ci * @pdev: PCI device 10818c2ecf20Sopenharmony_ci * 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_cistatic pci_ers_result_t 10848c2ecf20Sopenharmony_cicsio_pci_slot_reset(struct pci_dev *pdev) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct csio_hw *hw = pci_get_drvdata(pdev); 10878c2ecf20Sopenharmony_ci int ready; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 10908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot re-enable device in slot reset\n"); 10918c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci pci_set_master(pdev); 10958c2ecf20Sopenharmony_ci pci_restore_state(pdev); 10968c2ecf20Sopenharmony_ci pci_save_state(pdev); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* Bring HW s/m to ready state. 10998c2ecf20Sopenharmony_ci * but don't resume IOs. 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 11028c2ecf20Sopenharmony_ci csio_post_event(&hw->sm, CSIO_HWE_PCIERR_SLOT_RESET); 11038c2ecf20Sopenharmony_ci ready = csio_is_hw_ready(hw); 11048c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (ready) { 11078c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 11088c2ecf20Sopenharmony_ci } else { 11098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't initialize HW when in slot reset\n"); 11108c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci/* 11158c2ecf20Sopenharmony_ci * csio_pci_resume - Resume normal operations 11168c2ecf20Sopenharmony_ci * @pdev: PCI device 11178c2ecf20Sopenharmony_ci * 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_cistatic void 11208c2ecf20Sopenharmony_cicsio_pci_resume(struct pci_dev *pdev) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct csio_hw *hw = pci_get_drvdata(pdev); 11238c2ecf20Sopenharmony_ci struct csio_lnode *ln; 11248c2ecf20Sopenharmony_ci int rv = 0; 11258c2ecf20Sopenharmony_ci int i; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci /* Bring the LINK UP and Resume IO */ 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci for (i = 0; i < hw->num_pports; i++) { 11308c2ecf20Sopenharmony_ci ln = csio_shost_init(hw, &pdev->dev, true, NULL); 11318c2ecf20Sopenharmony_ci if (!ln) { 11328c2ecf20Sopenharmony_ci rv = -ENODEV; 11338c2ecf20Sopenharmony_ci break; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci /* Initialize portid */ 11368c2ecf20Sopenharmony_ci ln->portid = hw->pport[i].portid; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 11398c2ecf20Sopenharmony_ci if (csio_lnode_start(ln) != 0) 11408c2ecf20Sopenharmony_ci rv = -ENODEV; 11418c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (rv) 11448c2ecf20Sopenharmony_ci break; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci csio_lnode_init_post(ln); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (rv) 11508c2ecf20Sopenharmony_ci goto err_resume_exit; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cierr_resume_exit: 11558c2ecf20Sopenharmony_ci csio_lnodes_block_request(hw); 11568c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 11578c2ecf20Sopenharmony_ci csio_hw_stop(hw); 11588c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 11598c2ecf20Sopenharmony_ci csio_lnodes_unblock_request(hw); 11608c2ecf20Sopenharmony_ci csio_lnodes_exit(hw, 0); 11618c2ecf20Sopenharmony_ci csio_hw_free(hw); 11628c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "resume of device failed: %d\n", rv); 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic struct pci_error_handlers csio_err_handler = { 11668c2ecf20Sopenharmony_ci .error_detected = csio_pci_error_detected, 11678c2ecf20Sopenharmony_ci .slot_reset = csio_pci_slot_reset, 11688c2ecf20Sopenharmony_ci .resume = csio_pci_resume, 11698c2ecf20Sopenharmony_ci}; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci/* 11728c2ecf20Sopenharmony_ci * Macros needed to support the PCI Device ID Table ... 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \ 11758c2ecf20Sopenharmony_ci static const struct pci_device_id csio_pci_tbl[] = { 11768c2ecf20Sopenharmony_ci/* Define for FCoE uses PF6 */ 11778c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION 0x6 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci#define CH_PCI_ID_TABLE_ENTRY(devid) \ 11808c2ecf20Sopenharmony_ci { PCI_VDEVICE(CHELSIO, (devid)), 0 } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_END { 0, } } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci#include "t4_pci_id_tbl.h" 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic struct pci_driver csio_pci_driver = { 11878c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 11888c2ecf20Sopenharmony_ci .driver = { 11898c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11908c2ecf20Sopenharmony_ci }, 11918c2ecf20Sopenharmony_ci .id_table = csio_pci_tbl, 11928c2ecf20Sopenharmony_ci .probe = csio_probe_one, 11938c2ecf20Sopenharmony_ci .remove = csio_remove_one, 11948c2ecf20Sopenharmony_ci .err_handler = &csio_err_handler, 11958c2ecf20Sopenharmony_ci}; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci/* 11988c2ecf20Sopenharmony_ci * csio_init - Chelsio storage driver initialization function. 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci */ 12018c2ecf20Sopenharmony_cistatic int __init 12028c2ecf20Sopenharmony_cicsio_init(void) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci int rv = -ENOMEM; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci pr_info("%s %s\n", CSIO_DRV_DESC, CSIO_DRV_VERSION); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci csio_dfs_init(); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci csio_fcoe_transport = fc_attach_transport(&csio_fc_transport_funcs); 12118c2ecf20Sopenharmony_ci if (!csio_fcoe_transport) 12128c2ecf20Sopenharmony_ci goto err; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci csio_fcoe_transport_vport = 12158c2ecf20Sopenharmony_ci fc_attach_transport(&csio_fc_transport_vport_funcs); 12168c2ecf20Sopenharmony_ci if (!csio_fcoe_transport_vport) 12178c2ecf20Sopenharmony_ci goto err_vport; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci rv = pci_register_driver(&csio_pci_driver); 12208c2ecf20Sopenharmony_ci if (rv) 12218c2ecf20Sopenharmony_ci goto err_pci; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci return 0; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cierr_pci: 12268c2ecf20Sopenharmony_ci fc_release_transport(csio_fcoe_transport_vport); 12278c2ecf20Sopenharmony_cierr_vport: 12288c2ecf20Sopenharmony_ci fc_release_transport(csio_fcoe_transport); 12298c2ecf20Sopenharmony_cierr: 12308c2ecf20Sopenharmony_ci csio_dfs_exit(); 12318c2ecf20Sopenharmony_ci return rv; 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci/* 12358c2ecf20Sopenharmony_ci * csio_exit - Chelsio storage driver uninitialization . 12368c2ecf20Sopenharmony_ci * 12378c2ecf20Sopenharmony_ci * Function that gets called in the unload path. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_cistatic void __exit 12408c2ecf20Sopenharmony_cicsio_exit(void) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci pci_unregister_driver(&csio_pci_driver); 12438c2ecf20Sopenharmony_ci csio_dfs_exit(); 12448c2ecf20Sopenharmony_ci fc_release_transport(csio_fcoe_transport_vport); 12458c2ecf20Sopenharmony_ci fc_release_transport(csio_fcoe_transport); 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cimodule_init(csio_init); 12498c2ecf20Sopenharmony_cimodule_exit(csio_exit); 12508c2ecf20Sopenharmony_ciMODULE_AUTHOR(CSIO_DRV_AUTHOR); 12518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(CSIO_DRV_DESC); 12528c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 12538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, csio_pci_tbl); 12548c2ecf20Sopenharmony_ciMODULE_VERSION(CSIO_DRV_VERSION); 12558c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_FNAME_T5); 12568c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_FNAME_T6); 12578c2ecf20Sopenharmony_ciMODULE_SOFTDEP("pre: cxgb4"); 1258