18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic iSCSI Offload Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2016 Cavium Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 118c2ecf20Sopenharmony_ci#include <scsi/iscsi_if.h> 128c2ecf20Sopenharmony_ci#include <linux/inet.h> 138c2ecf20Sopenharmony_ci#include <net/arp.h> 148c2ecf20Sopenharmony_ci#include <linux/list.h> 158c2ecf20Sopenharmony_ci#include <linux/kthread.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 188c2ecf20Sopenharmony_ci#include <linux/cpu.h> 198c2ecf20Sopenharmony_ci#include <linux/iscsi_boot_sysfs.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 228c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 238c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 248c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 258c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "qedi.h" 288c2ecf20Sopenharmony_ci#include "qedi_gbl.h" 298c2ecf20Sopenharmony_ci#include "qedi_iscsi.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic uint qedi_qed_debug; 328c2ecf20Sopenharmony_cimodule_param(qedi_qed_debug, uint, 0644); 338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qedi_qed_debug, " QED debug level 0 (default)"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic uint qedi_fw_debug; 368c2ecf20Sopenharmony_cimodule_param(qedi_fw_debug, uint, 0644); 378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qedi_fw_debug, " Firmware debug level 0(default) to 3"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ciuint qedi_dbg_log = QEDI_LOG_WARN | QEDI_LOG_SCSI_TM; 408c2ecf20Sopenharmony_cimodule_param(qedi_dbg_log, uint, 0644); 418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qedi_dbg_log, " Default debug level"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciuint qedi_io_tracing; 448c2ecf20Sopenharmony_cimodule_param(qedi_io_tracing, uint, 0644); 458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qedi_io_tracing, 468c2ecf20Sopenharmony_ci " Enable logging of SCSI requests/completions into trace buffer. (default off)."); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic uint qedi_ll2_buf_size = 0x400; 498c2ecf20Sopenharmony_cimodule_param(qedi_ll2_buf_size, uint, 0644); 508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qedi_ll2_buf_size, 518c2ecf20Sopenharmony_ci "parameter to set ping packet size, default - 0x400, Jumbo packets - 0x2400."); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic uint qedi_flags_override; 548c2ecf20Sopenharmony_cimodule_param(qedi_flags_override, uint, 0644); 558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(qedi_flags_override, "Disable/Enable MFW error flags bits action."); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciconst struct qed_iscsi_ops *qedi_ops; 588c2ecf20Sopenharmony_cistatic struct scsi_transport_template *qedi_scsi_transport; 598c2ecf20Sopenharmony_cistatic struct pci_driver qedi_pci_driver; 608c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct qedi_percpu_s, qedi_percpu); 618c2ecf20Sopenharmony_cistatic LIST_HEAD(qedi_udev_list); 628c2ecf20Sopenharmony_ci/* Static function declaration */ 638c2ecf20Sopenharmony_cistatic int qedi_alloc_global_queues(struct qedi_ctx *qedi); 648c2ecf20Sopenharmony_cistatic void qedi_free_global_queues(struct qedi_ctx *qedi); 658c2ecf20Sopenharmony_cistatic struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid); 668c2ecf20Sopenharmony_cistatic void qedi_reset_uio_rings(struct qedi_uio_dev *udev); 678c2ecf20Sopenharmony_cistatic void qedi_ll2_free_skbs(struct qedi_ctx *qedi); 688c2ecf20Sopenharmony_cistatic struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi); 698c2ecf20Sopenharmony_cistatic void qedi_recovery_handler(struct work_struct *work); 708c2ecf20Sopenharmony_cistatic void qedi_schedule_hw_err_handler(void *dev, 718c2ecf20Sopenharmony_ci enum qed_hw_err_type err_type); 728c2ecf20Sopenharmony_cistatic int qedi_suspend(struct pci_dev *pdev, pm_message_t state); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 778c2ecf20Sopenharmony_ci struct qedi_endpoint *qedi_ep; 788c2ecf20Sopenharmony_ci struct iscsi_eqe_data *data; 798c2ecf20Sopenharmony_ci int rval = 0; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!context || !fw_handle) { 828c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "Recv event with ctx NULL\n"); 838c2ecf20Sopenharmony_ci return -EINVAL; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci qedi = (struct qedi_ctx *)context; 878c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 888c2ecf20Sopenharmony_ci "Recv Event %d fw_handle %p\n", fw_event_code, fw_handle); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci data = (struct iscsi_eqe_data *)fw_handle; 918c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 928c2ecf20Sopenharmony_ci "icid=0x%x conn_id=0x%x err-code=0x%x error-pdu-opcode-reserved=0x%x\n", 938c2ecf20Sopenharmony_ci data->icid, data->conn_id, data->error_code, 948c2ecf20Sopenharmony_ci data->error_pdu_opcode_reserved); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci qedi_ep = qedi->ep_tbl[data->icid]; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!qedi_ep) { 998c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 1008c2ecf20Sopenharmony_ci "Cannot process event, ep already disconnected, cid=0x%x\n", 1018c2ecf20Sopenharmony_ci data->icid); 1028c2ecf20Sopenharmony_ci WARN_ON(1); 1038c2ecf20Sopenharmony_ci return -ENODEV; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci switch (fw_event_code) { 1078c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE: 1088c2ecf20Sopenharmony_ci if (qedi_ep->state == EP_STATE_OFLDCONN_START) 1098c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_OFLDCONN_COMPL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci wake_up_interruptible(&qedi_ep->tcp_ofld_wait); 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE: 1148c2ecf20Sopenharmony_ci qedi_ep->state = EP_STATE_DISCONN_COMPL; 1158c2ecf20Sopenharmony_ci wake_up_interruptible(&qedi_ep->tcp_ofld_wait); 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR: 1188c2ecf20Sopenharmony_ci qedi_process_iscsi_error(qedi_ep, data); 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD: 1218c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD: 1228c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME: 1238c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT: 1248c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT: 1258c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2: 1268c2ecf20Sopenharmony_ci case ISCSI_EVENT_TYPE_TCP_CONN_ERROR: 1278c2ecf20Sopenharmony_ci qedi_process_tcp_error(qedi_ep, data); 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci default: 1308c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Recv Unknown Event %u\n", 1318c2ecf20Sopenharmony_ci fw_event_code); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return rval; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int qedi_uio_open(struct uio_info *uinfo, struct inode *inode) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct qedi_uio_dev *udev = uinfo->priv; 1408c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = udev->qedi; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 1438c2ecf20Sopenharmony_ci return -EPERM; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (udev->uio_dev != -1) 1468c2ecf20Sopenharmony_ci return -EBUSY; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci rtnl_lock(); 1498c2ecf20Sopenharmony_ci udev->uio_dev = iminor(inode); 1508c2ecf20Sopenharmony_ci qedi_reset_uio_rings(udev); 1518c2ecf20Sopenharmony_ci set_bit(UIO_DEV_OPENED, &qedi->flags); 1528c2ecf20Sopenharmony_ci rtnl_unlock(); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int qedi_uio_close(struct uio_info *uinfo, struct inode *inode) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct qedi_uio_dev *udev = uinfo->priv; 1608c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = udev->qedi; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci udev->uio_dev = -1; 1638c2ecf20Sopenharmony_ci clear_bit(UIO_DEV_OPENED, &qedi->flags); 1648c2ecf20Sopenharmony_ci qedi_ll2_free_skbs(qedi); 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void __qedi_free_uio_rings(struct qedi_uio_dev *udev) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci if (udev->uctrl) { 1718c2ecf20Sopenharmony_ci free_page((unsigned long)udev->uctrl); 1728c2ecf20Sopenharmony_ci udev->uctrl = NULL; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (udev->ll2_ring) { 1768c2ecf20Sopenharmony_ci free_page((unsigned long)udev->ll2_ring); 1778c2ecf20Sopenharmony_ci udev->ll2_ring = NULL; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (udev->ll2_buf) { 1818c2ecf20Sopenharmony_ci free_pages((unsigned long)udev->ll2_buf, 2); 1828c2ecf20Sopenharmony_ci udev->ll2_buf = NULL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void __qedi_free_uio(struct qedi_uio_dev *udev) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci uio_unregister_device(&udev->qedi_uinfo); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci __qedi_free_uio_rings(udev); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci pci_dev_put(udev->pdev); 1938c2ecf20Sopenharmony_ci kfree(udev); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void qedi_free_uio(struct qedi_uio_dev *udev) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci if (!udev) 1998c2ecf20Sopenharmony_ci return; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci list_del_init(&udev->list); 2028c2ecf20Sopenharmony_ci __qedi_free_uio(udev); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void qedi_reset_uio_rings(struct qedi_uio_dev *udev) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = NULL; 2088c2ecf20Sopenharmony_ci struct qedi_uio_ctrl *uctrl = NULL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci qedi = udev->qedi; 2118c2ecf20Sopenharmony_ci uctrl = udev->uctrl; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci spin_lock_bh(&qedi->ll2_lock); 2148c2ecf20Sopenharmony_ci uctrl->host_rx_cons = 0; 2158c2ecf20Sopenharmony_ci uctrl->hw_rx_prod = 0; 2168c2ecf20Sopenharmony_ci uctrl->hw_rx_bd_prod = 0; 2178c2ecf20Sopenharmony_ci uctrl->host_rx_bd_cons = 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memset(udev->ll2_ring, 0, udev->ll2_ring_size); 2208c2ecf20Sopenharmony_ci memset(udev->ll2_buf, 0, udev->ll2_buf_size); 2218c2ecf20Sopenharmony_ci spin_unlock_bh(&qedi->ll2_lock); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int __qedi_alloc_uio_rings(struct qedi_uio_dev *udev) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci int rc = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (udev->ll2_ring || udev->ll2_buf) 2298c2ecf20Sopenharmony_ci return rc; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* Memory for control area. */ 2328c2ecf20Sopenharmony_ci udev->uctrl = (void *)get_zeroed_page(GFP_KERNEL); 2338c2ecf20Sopenharmony_ci if (!udev->uctrl) 2348c2ecf20Sopenharmony_ci return -ENOMEM; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Allocating memory for LL2 ring */ 2378c2ecf20Sopenharmony_ci udev->ll2_ring_size = QEDI_PAGE_SIZE; 2388c2ecf20Sopenharmony_ci udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP); 2398c2ecf20Sopenharmony_ci if (!udev->ll2_ring) { 2408c2ecf20Sopenharmony_ci rc = -ENOMEM; 2418c2ecf20Sopenharmony_ci goto exit_alloc_ring; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Allocating memory for Tx/Rx pkt buffer */ 2458c2ecf20Sopenharmony_ci udev->ll2_buf_size = TX_RX_RING * qedi_ll2_buf_size; 2468c2ecf20Sopenharmony_ci udev->ll2_buf_size = QEDI_PAGE_ALIGN(udev->ll2_buf_size); 2478c2ecf20Sopenharmony_ci udev->ll2_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP | 2488c2ecf20Sopenharmony_ci __GFP_ZERO, 2); 2498c2ecf20Sopenharmony_ci if (!udev->ll2_buf) { 2508c2ecf20Sopenharmony_ci rc = -ENOMEM; 2518c2ecf20Sopenharmony_ci goto exit_alloc_buf; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci return rc; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciexit_alloc_buf: 2568c2ecf20Sopenharmony_ci free_page((unsigned long)udev->ll2_ring); 2578c2ecf20Sopenharmony_ci udev->ll2_ring = NULL; 2588c2ecf20Sopenharmony_ciexit_alloc_ring: 2598c2ecf20Sopenharmony_ci return rc; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int qedi_alloc_uio_rings(struct qedi_ctx *qedi) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct qedi_uio_dev *udev = NULL; 2658c2ecf20Sopenharmony_ci int rc = 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci list_for_each_entry(udev, &qedi_udev_list, list) { 2688c2ecf20Sopenharmony_ci if (udev->pdev == qedi->pdev) { 2698c2ecf20Sopenharmony_ci udev->qedi = qedi; 2708c2ecf20Sopenharmony_ci if (__qedi_alloc_uio_rings(udev)) { 2718c2ecf20Sopenharmony_ci udev->qedi = NULL; 2728c2ecf20Sopenharmony_ci return -ENOMEM; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci qedi->udev = udev; 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci udev = kzalloc(sizeof(*udev), GFP_KERNEL); 2808c2ecf20Sopenharmony_ci if (!udev) { 2818c2ecf20Sopenharmony_ci rc = -ENOMEM; 2828c2ecf20Sopenharmony_ci goto err_udev; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci udev->uio_dev = -1; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci udev->qedi = qedi; 2888c2ecf20Sopenharmony_ci udev->pdev = qedi->pdev; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci rc = __qedi_alloc_uio_rings(udev); 2918c2ecf20Sopenharmony_ci if (rc) 2928c2ecf20Sopenharmony_ci goto err_uctrl; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci list_add(&udev->list, &qedi_udev_list); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci pci_dev_get(udev->pdev); 2978c2ecf20Sopenharmony_ci qedi->udev = udev; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci udev->tx_pkt = udev->ll2_buf; 3008c2ecf20Sopenharmony_ci udev->rx_pkt = udev->ll2_buf + qedi_ll2_buf_size; 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci err_uctrl: 3048c2ecf20Sopenharmony_ci kfree(udev); 3058c2ecf20Sopenharmony_ci err_udev: 3068c2ecf20Sopenharmony_ci return -ENOMEM; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int qedi_init_uio(struct qedi_ctx *qedi) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct qedi_uio_dev *udev = qedi->udev; 3128c2ecf20Sopenharmony_ci struct uio_info *uinfo; 3138c2ecf20Sopenharmony_ci int ret = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!udev) 3168c2ecf20Sopenharmony_ci return -ENOMEM; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci uinfo = &udev->qedi_uinfo; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci uinfo->mem[0].addr = (unsigned long)udev->uctrl; 3218c2ecf20Sopenharmony_ci uinfo->mem[0].size = sizeof(struct qedi_uio_ctrl); 3228c2ecf20Sopenharmony_ci uinfo->mem[0].memtype = UIO_MEM_LOGICAL; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci uinfo->mem[1].addr = (unsigned long)udev->ll2_ring; 3258c2ecf20Sopenharmony_ci uinfo->mem[1].size = udev->ll2_ring_size; 3268c2ecf20Sopenharmony_ci uinfo->mem[1].memtype = UIO_MEM_LOGICAL; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci uinfo->mem[2].addr = (unsigned long)udev->ll2_buf; 3298c2ecf20Sopenharmony_ci uinfo->mem[2].size = udev->ll2_buf_size; 3308c2ecf20Sopenharmony_ci uinfo->mem[2].memtype = UIO_MEM_LOGICAL; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci uinfo->name = "qedi_uio"; 3338c2ecf20Sopenharmony_ci uinfo->version = QEDI_MODULE_VERSION; 3348c2ecf20Sopenharmony_ci uinfo->irq = UIO_IRQ_CUSTOM; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci uinfo->open = qedi_uio_open; 3378c2ecf20Sopenharmony_ci uinfo->release = qedi_uio_close; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (udev->uio_dev == -1) { 3408c2ecf20Sopenharmony_ci if (!uinfo->priv) { 3418c2ecf20Sopenharmony_ci uinfo->priv = udev; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = uio_register_device(&udev->pdev->dev, uinfo); 3448c2ecf20Sopenharmony_ci if (ret) { 3458c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 3468c2ecf20Sopenharmony_ci "UIO registration failed\n"); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int qedi_alloc_and_init_sb(struct qedi_ctx *qedi, 3558c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info, u16 sb_id) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct status_block_e4 *sb_virt; 3588c2ecf20Sopenharmony_ci dma_addr_t sb_phys; 3598c2ecf20Sopenharmony_ci int ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci sb_virt = dma_alloc_coherent(&qedi->pdev->dev, 3628c2ecf20Sopenharmony_ci sizeof(struct status_block_e4), &sb_phys, 3638c2ecf20Sopenharmony_ci GFP_KERNEL); 3648c2ecf20Sopenharmony_ci if (!sb_virt) { 3658c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 3668c2ecf20Sopenharmony_ci "Status block allocation failed for id = %d.\n", 3678c2ecf20Sopenharmony_ci sb_id); 3688c2ecf20Sopenharmony_ci return -ENOMEM; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys, 3728c2ecf20Sopenharmony_ci sb_id, QED_SB_TYPE_STORAGE); 3738c2ecf20Sopenharmony_ci if (ret) { 3748c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 3758c2ecf20Sopenharmony_ci "Status block initialization failed for id = %d.\n", 3768c2ecf20Sopenharmony_ci sb_id); 3778c2ecf20Sopenharmony_ci return ret; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void qedi_free_sb(struct qedi_ctx *qedi) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info; 3868c2ecf20Sopenharmony_ci int id; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 3898c2ecf20Sopenharmony_ci sb_info = &qedi->sb_array[id]; 3908c2ecf20Sopenharmony_ci if (sb_info->sb_virt) 3918c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, 3928c2ecf20Sopenharmony_ci sizeof(*sb_info->sb_virt), 3938c2ecf20Sopenharmony_ci (void *)sb_info->sb_virt, 3948c2ecf20Sopenharmony_ci sb_info->sb_phys); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void qedi_free_fp(struct qedi_ctx *qedi) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci kfree(qedi->fp_array); 4018c2ecf20Sopenharmony_ci kfree(qedi->sb_array); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void qedi_destroy_fp(struct qedi_ctx *qedi) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci qedi_free_sb(qedi); 4078c2ecf20Sopenharmony_ci qedi_free_fp(qedi); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int qedi_alloc_fp(struct qedi_ctx *qedi) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci int ret = 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci qedi->fp_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), 4158c2ecf20Sopenharmony_ci sizeof(struct qedi_fastpath), GFP_KERNEL); 4168c2ecf20Sopenharmony_ci if (!qedi->fp_array) { 4178c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 4188c2ecf20Sopenharmony_ci "fastpath fp array allocation failed.\n"); 4198c2ecf20Sopenharmony_ci return -ENOMEM; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci qedi->sb_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), 4238c2ecf20Sopenharmony_ci sizeof(struct qed_sb_info), GFP_KERNEL); 4248c2ecf20Sopenharmony_ci if (!qedi->sb_array) { 4258c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 4268c2ecf20Sopenharmony_ci "fastpath sb array allocation failed.\n"); 4278c2ecf20Sopenharmony_ci ret = -ENOMEM; 4288c2ecf20Sopenharmony_ci goto free_fp; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cifree_fp: 4348c2ecf20Sopenharmony_ci qedi_free_fp(qedi); 4358c2ecf20Sopenharmony_ci return ret; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void qedi_int_fp(struct qedi_ctx *qedi) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct qedi_fastpath *fp; 4418c2ecf20Sopenharmony_ci int id; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci memset(qedi->fp_array, 0, MIN_NUM_CPUS_MSIX(qedi) * 4448c2ecf20Sopenharmony_ci sizeof(*qedi->fp_array)); 4458c2ecf20Sopenharmony_ci memset(qedi->sb_array, 0, MIN_NUM_CPUS_MSIX(qedi) * 4468c2ecf20Sopenharmony_ci sizeof(*qedi->sb_array)); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 4498c2ecf20Sopenharmony_ci fp = &qedi->fp_array[id]; 4508c2ecf20Sopenharmony_ci fp->sb_info = &qedi->sb_array[id]; 4518c2ecf20Sopenharmony_ci fp->sb_id = id; 4528c2ecf20Sopenharmony_ci fp->qedi = qedi; 4538c2ecf20Sopenharmony_ci snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", 4548c2ecf20Sopenharmony_ci "qedi", id); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* fp_array[i] ---- irq cookie 4578c2ecf20Sopenharmony_ci * So init data which is needed in int ctx 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int qedi_prepare_fp(struct qedi_ctx *qedi) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct qedi_fastpath *fp; 4658c2ecf20Sopenharmony_ci int id, ret = 0; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci ret = qedi_alloc_fp(qedi); 4688c2ecf20Sopenharmony_ci if (ret) 4698c2ecf20Sopenharmony_ci goto err; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci qedi_int_fp(qedi); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 4748c2ecf20Sopenharmony_ci fp = &qedi->fp_array[id]; 4758c2ecf20Sopenharmony_ci ret = qedi_alloc_and_init_sb(qedi, fp->sb_info, fp->sb_id); 4768c2ecf20Sopenharmony_ci if (ret) { 4778c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 4788c2ecf20Sopenharmony_ci "SB allocation and initialization failed.\n"); 4798c2ecf20Sopenharmony_ci ret = -EIO; 4808c2ecf20Sopenharmony_ci goto err_init; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cierr_init: 4878c2ecf20Sopenharmony_ci qedi_free_sb(qedi); 4888c2ecf20Sopenharmony_ci qedi_free_fp(qedi); 4898c2ecf20Sopenharmony_cierr: 4908c2ecf20Sopenharmony_ci return ret; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int qedi_setup_cid_que(struct qedi_ctx *qedi) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci int i; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci qedi->cid_que.cid_que_base = kmalloc_array(qedi->max_active_conns, 4988c2ecf20Sopenharmony_ci sizeof(u32), GFP_KERNEL); 4998c2ecf20Sopenharmony_ci if (!qedi->cid_que.cid_que_base) 5008c2ecf20Sopenharmony_ci return -ENOMEM; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci qedi->cid_que.conn_cid_tbl = kmalloc_array(qedi->max_active_conns, 5038c2ecf20Sopenharmony_ci sizeof(struct qedi_conn *), 5048c2ecf20Sopenharmony_ci GFP_KERNEL); 5058c2ecf20Sopenharmony_ci if (!qedi->cid_que.conn_cid_tbl) { 5068c2ecf20Sopenharmony_ci kfree(qedi->cid_que.cid_que_base); 5078c2ecf20Sopenharmony_ci qedi->cid_que.cid_que_base = NULL; 5088c2ecf20Sopenharmony_ci return -ENOMEM; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci qedi->cid_que.cid_que = (u32 *)qedi->cid_que.cid_que_base; 5128c2ecf20Sopenharmony_ci qedi->cid_que.cid_q_prod_idx = 0; 5138c2ecf20Sopenharmony_ci qedi->cid_que.cid_q_cons_idx = 0; 5148c2ecf20Sopenharmony_ci qedi->cid_que.cid_q_max_idx = qedi->max_active_conns; 5158c2ecf20Sopenharmony_ci qedi->cid_que.cid_free_cnt = qedi->max_active_conns; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci for (i = 0; i < qedi->max_active_conns; i++) { 5188c2ecf20Sopenharmony_ci qedi->cid_que.cid_que[i] = i; 5198c2ecf20Sopenharmony_ci qedi->cid_que.conn_cid_tbl[i] = NULL; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void qedi_release_cid_que(struct qedi_ctx *qedi) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci kfree(qedi->cid_que.cid_que_base); 5288c2ecf20Sopenharmony_ci qedi->cid_que.cid_que_base = NULL; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci kfree(qedi->cid_que.conn_cid_tbl); 5318c2ecf20Sopenharmony_ci qedi->cid_que.conn_cid_tbl = NULL; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int qedi_init_id_tbl(struct qedi_portid_tbl *id_tbl, u16 size, 5358c2ecf20Sopenharmony_ci u16 start_id, u16 next) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci id_tbl->start = start_id; 5388c2ecf20Sopenharmony_ci id_tbl->max = size; 5398c2ecf20Sopenharmony_ci id_tbl->next = next; 5408c2ecf20Sopenharmony_ci spin_lock_init(&id_tbl->lock); 5418c2ecf20Sopenharmony_ci id_tbl->table = kcalloc(BITS_TO_LONGS(size), sizeof(long), GFP_KERNEL); 5428c2ecf20Sopenharmony_ci if (!id_tbl->table) 5438c2ecf20Sopenharmony_ci return -ENOMEM; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void qedi_free_id_tbl(struct qedi_portid_tbl *id_tbl) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci kfree(id_tbl->table); 5518c2ecf20Sopenharmony_ci id_tbl->table = NULL; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ciint qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci int ret = -1; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci id -= id_tbl->start; 5598c2ecf20Sopenharmony_ci if (id >= id_tbl->max) 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci spin_lock(&id_tbl->lock); 5638c2ecf20Sopenharmony_ci if (!test_bit(id, id_tbl->table)) { 5648c2ecf20Sopenharmony_ci set_bit(id, id_tbl->table); 5658c2ecf20Sopenharmony_ci ret = 0; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci spin_unlock(&id_tbl->lock); 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ciu16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci u16 id; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci spin_lock(&id_tbl->lock); 5768c2ecf20Sopenharmony_ci id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next); 5778c2ecf20Sopenharmony_ci if (id >= id_tbl->max) { 5788c2ecf20Sopenharmony_ci id = QEDI_LOCAL_PORT_INVALID; 5798c2ecf20Sopenharmony_ci if (id_tbl->next != 0) { 5808c2ecf20Sopenharmony_ci id = find_first_zero_bit(id_tbl->table, id_tbl->next); 5818c2ecf20Sopenharmony_ci if (id >= id_tbl->next) 5828c2ecf20Sopenharmony_ci id = QEDI_LOCAL_PORT_INVALID; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (id < id_tbl->max) { 5878c2ecf20Sopenharmony_ci set_bit(id, id_tbl->table); 5888c2ecf20Sopenharmony_ci id_tbl->next = (id + 1) & (id_tbl->max - 1); 5898c2ecf20Sopenharmony_ci id += id_tbl->start; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci spin_unlock(&id_tbl->lock); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return id; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_civoid qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci if (id == QEDI_LOCAL_PORT_INVALID) 6008c2ecf20Sopenharmony_ci return; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci id -= id_tbl->start; 6038c2ecf20Sopenharmony_ci if (id >= id_tbl->max) 6048c2ecf20Sopenharmony_ci return; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci clear_bit(id, id_tbl->table); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic void qedi_cm_free_mem(struct qedi_ctx *qedi) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci kfree(qedi->ep_tbl); 6128c2ecf20Sopenharmony_ci qedi->ep_tbl = NULL; 6138c2ecf20Sopenharmony_ci qedi_free_id_tbl(&qedi->lcl_port_tbl); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int qedi_cm_alloc_mem(struct qedi_ctx *qedi) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci u16 port_id; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci qedi->ep_tbl = kzalloc((qedi->max_active_conns * 6218c2ecf20Sopenharmony_ci sizeof(struct qedi_endpoint *)), GFP_KERNEL); 6228c2ecf20Sopenharmony_ci if (!qedi->ep_tbl) 6238c2ecf20Sopenharmony_ci return -ENOMEM; 6248c2ecf20Sopenharmony_ci port_id = prandom_u32() % QEDI_LOCAL_PORT_RANGE; 6258c2ecf20Sopenharmony_ci if (qedi_init_id_tbl(&qedi->lcl_port_tbl, QEDI_LOCAL_PORT_RANGE, 6268c2ecf20Sopenharmony_ci QEDI_LOCAL_PORT_MIN, port_id)) { 6278c2ecf20Sopenharmony_ci qedi_cm_free_mem(qedi); 6288c2ecf20Sopenharmony_ci return -ENOMEM; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 6378c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = NULL; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci shost = iscsi_host_alloc(&qedi_host_template, 6408c2ecf20Sopenharmony_ci sizeof(struct qedi_ctx), 0); 6418c2ecf20Sopenharmony_ci if (!shost) { 6428c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "Could not allocate shost\n"); 6438c2ecf20Sopenharmony_ci goto exit_setup_shost; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA - 1; 6478c2ecf20Sopenharmony_ci shost->max_channel = 0; 6488c2ecf20Sopenharmony_ci shost->max_lun = ~0; 6498c2ecf20Sopenharmony_ci shost->max_cmd_len = 16; 6508c2ecf20Sopenharmony_ci shost->transportt = qedi_scsi_transport; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci qedi = iscsi_host_priv(shost); 6538c2ecf20Sopenharmony_ci memset(qedi, 0, sizeof(*qedi)); 6548c2ecf20Sopenharmony_ci qedi->shost = shost; 6558c2ecf20Sopenharmony_ci qedi->dbg_ctx.host_no = shost->host_no; 6568c2ecf20Sopenharmony_ci qedi->pdev = pdev; 6578c2ecf20Sopenharmony_ci qedi->dbg_ctx.pdev = pdev; 6588c2ecf20Sopenharmony_ci qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA; 6598c2ecf20Sopenharmony_ci qedi->max_sqes = QEDI_SQ_SIZE; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, qedi); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ciexit_setup_shost: 6668c2ecf20Sopenharmony_ci return qedi; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic int qedi_ll2_rx(void *cookie, struct sk_buff *skb, u32 arg1, u32 arg2) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; 6728c2ecf20Sopenharmony_ci struct skb_work_list *work; 6738c2ecf20Sopenharmony_ci struct ethhdr *eh; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (!qedi) { 6768c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "qedi is NULL\n"); 6778c2ecf20Sopenharmony_ci return -1; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!test_bit(UIO_DEV_OPENED, &qedi->flags)) { 6818c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UIO, 6828c2ecf20Sopenharmony_ci "UIO DEV is not opened\n"); 6838c2ecf20Sopenharmony_ci kfree_skb(skb); 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci eh = (struct ethhdr *)skb->data; 6888c2ecf20Sopenharmony_ci /* Undo VLAN encapsulation */ 6898c2ecf20Sopenharmony_ci if (eh->h_proto == htons(ETH_P_8021Q)) { 6908c2ecf20Sopenharmony_ci memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); 6918c2ecf20Sopenharmony_ci eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); 6928c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* Filter out non FIP/FCoE frames here to free them faster */ 6968c2ecf20Sopenharmony_ci if (eh->h_proto != htons(ETH_P_ARP) && 6978c2ecf20Sopenharmony_ci eh->h_proto != htons(ETH_P_IP) && 6988c2ecf20Sopenharmony_ci eh->h_proto != htons(ETH_P_IPV6)) { 6998c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 7008c2ecf20Sopenharmony_ci "Dropping frame ethertype [0x%x] len [0x%x].\n", 7018c2ecf20Sopenharmony_ci eh->h_proto, skb->len); 7028c2ecf20Sopenharmony_ci kfree_skb(skb); 7038c2ecf20Sopenharmony_ci return 0; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 7078c2ecf20Sopenharmony_ci "Allowed frame ethertype [0x%x] len [0x%x].\n", 7088c2ecf20Sopenharmony_ci eh->h_proto, skb->len); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_ATOMIC); 7118c2ecf20Sopenharmony_ci if (!work) { 7128c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 7138c2ecf20Sopenharmony_ci "Could not allocate work so dropping frame.\n"); 7148c2ecf20Sopenharmony_ci kfree_skb(skb); 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&work->list); 7198c2ecf20Sopenharmony_ci work->skb = skb; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) 7228c2ecf20Sopenharmony_ci work->vlan_id = skb_vlan_tag_get(skb); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (work->vlan_id) 7258c2ecf20Sopenharmony_ci __vlan_insert_tag(work->skb, htons(ETH_P_8021Q), work->vlan_id); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci spin_lock_bh(&qedi->ll2_lock); 7288c2ecf20Sopenharmony_ci list_add_tail(&work->list, &qedi->ll2_skb_list); 7298c2ecf20Sopenharmony_ci spin_unlock_bh(&qedi->ll2_lock); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci wake_up_process(qedi->ll2_recv_thread); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci/* map this skb to iscsiuio mmaped region */ 7378c2ecf20Sopenharmony_cistatic int qedi_ll2_process_skb(struct qedi_ctx *qedi, struct sk_buff *skb, 7388c2ecf20Sopenharmony_ci u16 vlan_id) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct qedi_uio_dev *udev = NULL; 7418c2ecf20Sopenharmony_ci struct qedi_uio_ctrl *uctrl = NULL; 7428c2ecf20Sopenharmony_ci struct qedi_rx_bd rxbd; 7438c2ecf20Sopenharmony_ci struct qedi_rx_bd *p_rxbd; 7448c2ecf20Sopenharmony_ci u32 rx_bd_prod; 7458c2ecf20Sopenharmony_ci void *pkt; 7468c2ecf20Sopenharmony_ci int len = 0; 7478c2ecf20Sopenharmony_ci u32 prod; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (!qedi) { 7508c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "qedi is NULL\n"); 7518c2ecf20Sopenharmony_ci return -1; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci udev = qedi->udev; 7558c2ecf20Sopenharmony_ci uctrl = udev->uctrl; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ++uctrl->hw_rx_prod_cnt; 7588c2ecf20Sopenharmony_ci prod = (uctrl->hw_rx_prod + 1) % RX_RING; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci pkt = udev->rx_pkt + (prod * qedi_ll2_buf_size); 7618c2ecf20Sopenharmony_ci len = min_t(u32, skb->len, (u32)qedi_ll2_buf_size); 7628c2ecf20Sopenharmony_ci memcpy(pkt, skb->data, len); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci memset(&rxbd, 0, sizeof(rxbd)); 7658c2ecf20Sopenharmony_ci rxbd.rx_pkt_index = prod; 7668c2ecf20Sopenharmony_ci rxbd.rx_pkt_len = len; 7678c2ecf20Sopenharmony_ci rxbd.vlan_id = vlan_id; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci uctrl->hw_rx_bd_prod = (uctrl->hw_rx_bd_prod + 1) % QEDI_NUM_RX_BD; 7708c2ecf20Sopenharmony_ci rx_bd_prod = uctrl->hw_rx_bd_prod; 7718c2ecf20Sopenharmony_ci p_rxbd = (struct qedi_rx_bd *)udev->ll2_ring; 7728c2ecf20Sopenharmony_ci p_rxbd += rx_bd_prod; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci memcpy(p_rxbd, &rxbd, sizeof(rxbd)); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 7778c2ecf20Sopenharmony_ci "hw_rx_prod [%d] prod [%d] hw_rx_bd_prod [%d] rx_pkt_idx [%d] rx_len [%d].\n", 7788c2ecf20Sopenharmony_ci uctrl->hw_rx_prod, prod, uctrl->hw_rx_bd_prod, 7798c2ecf20Sopenharmony_ci rxbd.rx_pkt_index, rxbd.rx_pkt_len); 7808c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 7818c2ecf20Sopenharmony_ci "host_rx_cons [%d] hw_rx_bd_cons [%d].\n", 7828c2ecf20Sopenharmony_ci uctrl->host_rx_cons, uctrl->host_rx_bd_cons); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci uctrl->hw_rx_prod = prod; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* notify the iscsiuio about new packet */ 7878c2ecf20Sopenharmony_ci uio_event_notify(&udev->qedi_uinfo); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic void qedi_ll2_free_skbs(struct qedi_ctx *qedi) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct skb_work_list *work, *work_tmp; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci spin_lock_bh(&qedi->ll2_lock); 7978c2ecf20Sopenharmony_ci list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, list) { 7988c2ecf20Sopenharmony_ci list_del(&work->list); 7998c2ecf20Sopenharmony_ci kfree_skb(work->skb); 8008c2ecf20Sopenharmony_ci kfree(work); 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci spin_unlock_bh(&qedi->ll2_lock); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic int qedi_ll2_recv_thread(void *arg) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = (struct qedi_ctx *)arg; 8088c2ecf20Sopenharmony_ci struct skb_work_list *work, *work_tmp; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci set_user_nice(current, -20); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 8138c2ecf20Sopenharmony_ci spin_lock_bh(&qedi->ll2_lock); 8148c2ecf20Sopenharmony_ci list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, 8158c2ecf20Sopenharmony_ci list) { 8168c2ecf20Sopenharmony_ci list_del(&work->list); 8178c2ecf20Sopenharmony_ci qedi_ll2_process_skb(qedi, work->skb, work->vlan_id); 8188c2ecf20Sopenharmony_ci kfree_skb(work->skb); 8198c2ecf20Sopenharmony_ci kfree(work); 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 8228c2ecf20Sopenharmony_ci spin_unlock_bh(&qedi->ll2_lock); 8238c2ecf20Sopenharmony_ci schedule(); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 8278c2ecf20Sopenharmony_ci return 0; 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci u8 num_sq_pages; 8338c2ecf20Sopenharmony_ci u32 log_page_size; 8348c2ecf20Sopenharmony_ci int rval = 0; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci num_sq_pages = (MAX_OUTSTANDING_TASKS_PER_CON * 8) / QEDI_PAGE_SIZE; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 8428c2ecf20Sopenharmony_ci "Number of CQ count is %d\n", qedi->num_queues); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci memset(&qedi->pf_params.iscsi_pf_params, 0, 8458c2ecf20Sopenharmony_ci sizeof(qedi->pf_params.iscsi_pf_params)); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci qedi->p_cpuq = dma_alloc_coherent(&qedi->pdev->dev, 8488c2ecf20Sopenharmony_ci qedi->num_queues * sizeof(struct qedi_glbl_q_params), 8498c2ecf20Sopenharmony_ci &qedi->hw_p_cpuq, GFP_KERNEL); 8508c2ecf20Sopenharmony_ci if (!qedi->p_cpuq) { 8518c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "dma_alloc_coherent fail\n"); 8528c2ecf20Sopenharmony_ci rval = -1; 8538c2ecf20Sopenharmony_ci goto err_alloc_mem; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci rval = qedi_alloc_global_queues(qedi); 8578c2ecf20Sopenharmony_ci if (rval) { 8588c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Global queue allocation failed.\n"); 8598c2ecf20Sopenharmony_ci rval = -1; 8608c2ecf20Sopenharmony_ci goto err_alloc_mem; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.num_cons = QEDI_MAX_ISCSI_CONNS_PER_HBA; 8648c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.num_tasks = QEDI_MAX_ISCSI_TASK; 8658c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.half_way_close_timeout = 10; 8668c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.num_sq_pages_in_ring = num_sq_pages; 8678c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.num_r2tq_pages_in_ring = num_sq_pages; 8688c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.num_uhq_pages_in_ring = num_sq_pages; 8698c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.num_queues = qedi->num_queues; 8708c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.debug_mode = qedi_fw_debug; 8718c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.two_msl_timer = 4000; 8728c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.max_fin_rt = 2; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) { 8758c2ecf20Sopenharmony_ci if ((1 << log_page_size) == QEDI_PAGE_SIZE) 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.log_page_size = log_page_size; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.glbl_q_params_addr = 8818c2ecf20Sopenharmony_ci (u64)qedi->hw_p_cpuq; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* RQ BDQ initializations. 8848c2ecf20Sopenharmony_ci * rq_num_entries: suggested value for Initiator is 16 (4KB RQ) 8858c2ecf20Sopenharmony_ci * rqe_log_size: 8 for 256B RQE 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.rqe_log_size = 8; 8888c2ecf20Sopenharmony_ci /* BDQ address and size */ 8898c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.bdq_pbl_base_addr[BDQ_ID_RQ] = 8908c2ecf20Sopenharmony_ci qedi->bdq_pbl_list_dma; 8918c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.bdq_pbl_num_entries[BDQ_ID_RQ] = 8928c2ecf20Sopenharmony_ci qedi->bdq_pbl_list_num_entries; 8938c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.rq_buffer_size = QEDI_BDQ_BUF_SIZE; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* cq_num_entries: num_tasks + rq_num_entries */ 8968c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.cq_num_entries = 2048; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.gl_rq_pi = QEDI_PROTO_CQ_PROD_IDX; 8998c2ecf20Sopenharmony_ci qedi->pf_params.iscsi_pf_params.gl_cmd_pi = 1; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cierr_alloc_mem: 9028c2ecf20Sopenharmony_ci return rval; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/* Free DMA coherent memory for array of queue pointers we pass to qed */ 9068c2ecf20Sopenharmony_cistatic void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci size_t size = 0; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (qedi->p_cpuq) { 9118c2ecf20Sopenharmony_ci size = qedi->num_queues * sizeof(struct qedi_glbl_q_params); 9128c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, size, qedi->p_cpuq, 9138c2ecf20Sopenharmony_ci qedi->hw_p_cpuq); 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci qedi_free_global_queues(qedi); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci kfree(qedi->global_queues); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic void qedi_get_boot_tgt_info(struct nvm_iscsi_block *block, 9228c2ecf20Sopenharmony_ci struct qedi_boot_target *tgt, u8 index) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci u32 ipv6_en; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci ipv6_en = !!(block->generic.ctrl_flags & 9278c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_IPV6_ENABLED); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci snprintf(tgt->iscsi_name, sizeof(tgt->iscsi_name), "%s", 9308c2ecf20Sopenharmony_ci block->target[index].target_name.byte); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci tgt->ipv6_en = ipv6_en; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (ipv6_en) 9358c2ecf20Sopenharmony_ci snprintf(tgt->ip_addr, IPV6_LEN, "%pI6\n", 9368c2ecf20Sopenharmony_ci block->target[index].ipv6_addr.byte); 9378c2ecf20Sopenharmony_ci else 9388c2ecf20Sopenharmony_ci snprintf(tgt->ip_addr, IPV4_LEN, "%pI4\n", 9398c2ecf20Sopenharmony_ci block->target[index].ipv4_addr.byte); 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic int qedi_find_boot_info(struct qedi_ctx *qedi, 9438c2ecf20Sopenharmony_ci struct qed_mfw_tlv_iscsi *iscsi, 9448c2ecf20Sopenharmony_ci struct nvm_iscsi_block *block) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct qedi_boot_target *pri_tgt = NULL, *sec_tgt = NULL; 9478c2ecf20Sopenharmony_ci u32 pri_ctrl_flags = 0, sec_ctrl_flags = 0, found = 0; 9488c2ecf20Sopenharmony_ci struct iscsi_cls_session *cls_sess; 9498c2ecf20Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 9508c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn; 9518c2ecf20Sopenharmony_ci struct iscsi_session *sess; 9528c2ecf20Sopenharmony_ci struct iscsi_conn *conn; 9538c2ecf20Sopenharmony_ci char ep_ip_addr[64]; 9548c2ecf20Sopenharmony_ci int i, ret = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci pri_ctrl_flags = !!(block->target[0].ctrl_flags & 9578c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_TARGET_ENABLED); 9588c2ecf20Sopenharmony_ci if (pri_ctrl_flags) { 9598c2ecf20Sopenharmony_ci pri_tgt = kzalloc(sizeof(*pri_tgt), GFP_KERNEL); 9608c2ecf20Sopenharmony_ci if (!pri_tgt) 9618c2ecf20Sopenharmony_ci return -1; 9628c2ecf20Sopenharmony_ci qedi_get_boot_tgt_info(block, pri_tgt, 0); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci sec_ctrl_flags = !!(block->target[1].ctrl_flags & 9668c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_TARGET_ENABLED); 9678c2ecf20Sopenharmony_ci if (sec_ctrl_flags) { 9688c2ecf20Sopenharmony_ci sec_tgt = kzalloc(sizeof(*sec_tgt), GFP_KERNEL); 9698c2ecf20Sopenharmony_ci if (!sec_tgt) { 9708c2ecf20Sopenharmony_ci ret = -1; 9718c2ecf20Sopenharmony_ci goto free_tgt; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci qedi_get_boot_tgt_info(block, sec_tgt, 1); 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci for (i = 0; i < qedi->max_active_conns; i++) { 9778c2ecf20Sopenharmony_ci qedi_conn = qedi_get_conn_from_id(qedi, i); 9788c2ecf20Sopenharmony_ci if (!qedi_conn) 9798c2ecf20Sopenharmony_ci continue; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (qedi_conn->ep->ip_type == TCP_IPV4) 9828c2ecf20Sopenharmony_ci snprintf(ep_ip_addr, IPV4_LEN, "%pI4\n", 9838c2ecf20Sopenharmony_ci qedi_conn->ep->dst_addr); 9848c2ecf20Sopenharmony_ci else 9858c2ecf20Sopenharmony_ci snprintf(ep_ip_addr, IPV6_LEN, "%pI6\n", 9868c2ecf20Sopenharmony_ci qedi_conn->ep->dst_addr); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci cls_conn = qedi_conn->cls_conn; 9898c2ecf20Sopenharmony_ci conn = cls_conn->dd_data; 9908c2ecf20Sopenharmony_ci cls_sess = iscsi_conn_to_session(cls_conn); 9918c2ecf20Sopenharmony_ci sess = cls_sess->dd_data; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (!iscsi_is_session_online(cls_sess)) 9948c2ecf20Sopenharmony_ci continue; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!sess->targetname) 9978c2ecf20Sopenharmony_ci continue; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (pri_ctrl_flags) { 10008c2ecf20Sopenharmony_ci if (!strcmp(pri_tgt->iscsi_name, sess->targetname) && 10018c2ecf20Sopenharmony_ci !strcmp(pri_tgt->ip_addr, ep_ip_addr)) { 10028c2ecf20Sopenharmony_ci found = 1; 10038c2ecf20Sopenharmony_ci break; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (sec_ctrl_flags) { 10088c2ecf20Sopenharmony_ci if (!strcmp(sec_tgt->iscsi_name, sess->targetname) && 10098c2ecf20Sopenharmony_ci !strcmp(sec_tgt->ip_addr, ep_ip_addr)) { 10108c2ecf20Sopenharmony_ci found = 1; 10118c2ecf20Sopenharmony_ci break; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (found) { 10178c2ecf20Sopenharmony_ci if (conn->hdrdgst_en) { 10188c2ecf20Sopenharmony_ci iscsi->header_digest_set = true; 10198c2ecf20Sopenharmony_ci iscsi->header_digest = 1; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (conn->datadgst_en) { 10238c2ecf20Sopenharmony_ci iscsi->data_digest_set = true; 10248c2ecf20Sopenharmony_ci iscsi->data_digest = 1; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci iscsi->boot_taget_portal_set = true; 10278c2ecf20Sopenharmony_ci iscsi->boot_taget_portal = sess->tpgt; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci } else { 10308c2ecf20Sopenharmony_ci ret = -1; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (sec_ctrl_flags) 10348c2ecf20Sopenharmony_ci kfree(sec_tgt); 10358c2ecf20Sopenharmony_cifree_tgt: 10368c2ecf20Sopenharmony_ci if (pri_ctrl_flags) 10378c2ecf20Sopenharmony_ci kfree(pri_tgt); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci return ret; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic void qedi_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (!dev) { 10478c2ecf20Sopenharmony_ci QEDI_INFO(NULL, QEDI_LOG_EVT, 10488c2ecf20Sopenharmony_ci "dev is NULL so ignoring get_generic_tlv_data request.\n"); 10498c2ecf20Sopenharmony_ci return; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci qedi = (struct qedi_ctx *)dev; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci memset(data, 0, sizeof(struct qed_generic_tlvs)); 10548c2ecf20Sopenharmony_ci ether_addr_copy(data->mac[0], qedi->mac); 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci/* 10588c2ecf20Sopenharmony_ci * Protocol TLV handler 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_cistatic void qedi_get_protocol_tlv_data(void *dev, void *data) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct qed_mfw_tlv_iscsi *iscsi = data; 10638c2ecf20Sopenharmony_ci struct qed_iscsi_stats *fw_iscsi_stats; 10648c2ecf20Sopenharmony_ci struct nvm_iscsi_block *block = NULL; 10658c2ecf20Sopenharmony_ci u32 chap_en = 0, mchap_en = 0; 10668c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = dev; 10678c2ecf20Sopenharmony_ci int rval = 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci fw_iscsi_stats = kmalloc(sizeof(*fw_iscsi_stats), GFP_KERNEL); 10708c2ecf20Sopenharmony_ci if (!fw_iscsi_stats) { 10718c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 10728c2ecf20Sopenharmony_ci "Could not allocate memory for fw_iscsi_stats.\n"); 10738c2ecf20Sopenharmony_ci goto exit_get_data; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci mutex_lock(&qedi->stats_lock); 10778c2ecf20Sopenharmony_ci /* Query firmware for offload stats */ 10788c2ecf20Sopenharmony_ci qedi_ops->get_stats(qedi->cdev, fw_iscsi_stats); 10798c2ecf20Sopenharmony_ci mutex_unlock(&qedi->stats_lock); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci iscsi->rx_frames_set = true; 10828c2ecf20Sopenharmony_ci iscsi->rx_frames = fw_iscsi_stats->iscsi_rx_packet_cnt; 10838c2ecf20Sopenharmony_ci iscsi->rx_bytes_set = true; 10848c2ecf20Sopenharmony_ci iscsi->rx_bytes = fw_iscsi_stats->iscsi_rx_bytes_cnt; 10858c2ecf20Sopenharmony_ci iscsi->tx_frames_set = true; 10868c2ecf20Sopenharmony_ci iscsi->tx_frames = fw_iscsi_stats->iscsi_tx_packet_cnt; 10878c2ecf20Sopenharmony_ci iscsi->tx_bytes_set = true; 10888c2ecf20Sopenharmony_ci iscsi->tx_bytes = fw_iscsi_stats->iscsi_tx_bytes_cnt; 10898c2ecf20Sopenharmony_ci iscsi->frame_size_set = true; 10908c2ecf20Sopenharmony_ci iscsi->frame_size = qedi->ll2_mtu; 10918c2ecf20Sopenharmony_ci block = qedi_get_nvram_block(qedi); 10928c2ecf20Sopenharmony_ci if (block) { 10938c2ecf20Sopenharmony_ci chap_en = !!(block->generic.ctrl_flags & 10948c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_CHAP_ENABLED); 10958c2ecf20Sopenharmony_ci mchap_en = !!(block->generic.ctrl_flags & 10968c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci iscsi->auth_method_set = (chap_en || mchap_en) ? true : false; 10998c2ecf20Sopenharmony_ci iscsi->auth_method = 1; 11008c2ecf20Sopenharmony_ci if (chap_en) 11018c2ecf20Sopenharmony_ci iscsi->auth_method = 2; 11028c2ecf20Sopenharmony_ci if (mchap_en) 11038c2ecf20Sopenharmony_ci iscsi->auth_method = 3; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci iscsi->tx_desc_size_set = true; 11068c2ecf20Sopenharmony_ci iscsi->tx_desc_size = QEDI_SQ_SIZE; 11078c2ecf20Sopenharmony_ci iscsi->rx_desc_size_set = true; 11088c2ecf20Sopenharmony_ci iscsi->rx_desc_size = QEDI_CQ_SIZE; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* tpgt, hdr digest, data digest */ 11118c2ecf20Sopenharmony_ci rval = qedi_find_boot_info(qedi, iscsi, block); 11128c2ecf20Sopenharmony_ci if (rval) 11138c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 11148c2ecf20Sopenharmony_ci "Boot target not set"); 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci kfree(fw_iscsi_stats); 11188c2ecf20Sopenharmony_ciexit_get_data: 11198c2ecf20Sopenharmony_ci return; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_civoid qedi_schedule_hw_err_handler(void *dev, 11238c2ecf20Sopenharmony_ci enum qed_hw_err_type err_type) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = (struct qedi_ctx *)dev; 11268c2ecf20Sopenharmony_ci unsigned long override_flags = qedi_flags_override; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (override_flags && test_bit(QEDI_ERR_OVERRIDE_EN, &override_flags)) 11298c2ecf20Sopenharmony_ci qedi->qedi_err_flags = qedi_flags_override; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 11328c2ecf20Sopenharmony_ci "HW error handler scheduled, err=%d err_flags=0x%x\n", 11338c2ecf20Sopenharmony_ci err_type, qedi->qedi_err_flags); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci switch (err_type) { 11368c2ecf20Sopenharmony_ci case QED_HW_ERR_FAN_FAIL: 11378c2ecf20Sopenharmony_ci schedule_delayed_work(&qedi->board_disable_work, 0); 11388c2ecf20Sopenharmony_ci break; 11398c2ecf20Sopenharmony_ci case QED_HW_ERR_MFW_RESP_FAIL: 11408c2ecf20Sopenharmony_ci case QED_HW_ERR_HW_ATTN: 11418c2ecf20Sopenharmony_ci case QED_HW_ERR_DMAE_FAIL: 11428c2ecf20Sopenharmony_ci case QED_HW_ERR_RAMROD_FAIL: 11438c2ecf20Sopenharmony_ci case QED_HW_ERR_FW_ASSERT: 11448c2ecf20Sopenharmony_ci /* Prevent HW attentions from being reasserted */ 11458c2ecf20Sopenharmony_ci if (test_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags)) 11468c2ecf20Sopenharmony_ci qedi_ops->common->attn_clr_enable(qedi->cdev, true); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (err_type == QED_HW_ERR_RAMROD_FAIL && 11498c2ecf20Sopenharmony_ci test_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags)) 11508c2ecf20Sopenharmony_ci qedi_ops->common->recovery_process(qedi->cdev); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci default: 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic void qedi_schedule_recovery_handler(void *dev) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = dev; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Recovery handler scheduled.\n"); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) 11658c2ecf20Sopenharmony_ci return; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci schedule_delayed_work(&qedi->recovery_work, 0); 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic void qedi_set_conn_recovery(struct iscsi_cls_session *cls_session) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct iscsi_session *session = cls_session->dd_data; 11758c2ecf20Sopenharmony_ci struct iscsi_conn *conn = session->leadconn; 11768c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic void qedi_link_update(void *dev, struct qed_link_output *link) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = (struct qedi_ctx *)dev; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (link->link_up) { 11868c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "Link Up event.\n"); 11878c2ecf20Sopenharmony_ci atomic_set(&qedi->link_state, QEDI_LINK_UP); 11888c2ecf20Sopenharmony_ci } else { 11898c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 11908c2ecf20Sopenharmony_ci "Link Down event.\n"); 11918c2ecf20Sopenharmony_ci atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 11928c2ecf20Sopenharmony_ci iscsi_host_for_each_session(qedi->shost, qedi_set_conn_recovery); 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic struct qed_iscsi_cb_ops qedi_cb_ops = { 11978c2ecf20Sopenharmony_ci { 11988c2ecf20Sopenharmony_ci .link_update = qedi_link_update, 11998c2ecf20Sopenharmony_ci .schedule_recovery_handler = qedi_schedule_recovery_handler, 12008c2ecf20Sopenharmony_ci .schedule_hw_err_handler = qedi_schedule_hw_err_handler, 12018c2ecf20Sopenharmony_ci .get_protocol_tlv_data = qedi_get_protocol_tlv_data, 12028c2ecf20Sopenharmony_ci .get_generic_tlv_data = qedi_get_generic_tlv_data, 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci}; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe, 12078c2ecf20Sopenharmony_ci u16 que_idx, struct qedi_percpu_s *p) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci struct qedi_work *qedi_work; 12108c2ecf20Sopenharmony_ci struct qedi_conn *q_conn; 12118c2ecf20Sopenharmony_ci struct qedi_cmd *qedi_cmd; 12128c2ecf20Sopenharmony_ci u32 iscsi_cid; 12138c2ecf20Sopenharmony_ci int rc = 0; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci iscsi_cid = cqe->cqe_common.conn_id; 12168c2ecf20Sopenharmony_ci q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; 12178c2ecf20Sopenharmony_ci if (!q_conn) { 12188c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 12198c2ecf20Sopenharmony_ci "Session no longer exists for cid=0x%x!!\n", 12208c2ecf20Sopenharmony_ci iscsi_cid); 12218c2ecf20Sopenharmony_ci return -1; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci switch (cqe->cqe_common.cqe_type) { 12258c2ecf20Sopenharmony_ci case ISCSI_CQE_TYPE_SOLICITED: 12268c2ecf20Sopenharmony_ci case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE: 12278c2ecf20Sopenharmony_ci qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid); 12288c2ecf20Sopenharmony_ci if (!qedi_cmd) { 12298c2ecf20Sopenharmony_ci rc = -1; 12308c2ecf20Sopenharmony_ci break; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qedi_cmd->cqe_work.list); 12338c2ecf20Sopenharmony_ci qedi_cmd->cqe_work.qedi = qedi; 12348c2ecf20Sopenharmony_ci memcpy(&qedi_cmd->cqe_work.cqe, cqe, sizeof(union iscsi_cqe)); 12358c2ecf20Sopenharmony_ci qedi_cmd->cqe_work.que_idx = que_idx; 12368c2ecf20Sopenharmony_ci qedi_cmd->cqe_work.is_solicited = true; 12378c2ecf20Sopenharmony_ci list_add_tail(&qedi_cmd->cqe_work.list, &p->work_list); 12388c2ecf20Sopenharmony_ci break; 12398c2ecf20Sopenharmony_ci case ISCSI_CQE_TYPE_UNSOLICITED: 12408c2ecf20Sopenharmony_ci case ISCSI_CQE_TYPE_DUMMY: 12418c2ecf20Sopenharmony_ci case ISCSI_CQE_TYPE_TASK_CLEANUP: 12428c2ecf20Sopenharmony_ci qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC); 12438c2ecf20Sopenharmony_ci if (!qedi_work) { 12448c2ecf20Sopenharmony_ci rc = -1; 12458c2ecf20Sopenharmony_ci break; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qedi_work->list); 12488c2ecf20Sopenharmony_ci qedi_work->qedi = qedi; 12498c2ecf20Sopenharmony_ci memcpy(&qedi_work->cqe, cqe, sizeof(union iscsi_cqe)); 12508c2ecf20Sopenharmony_ci qedi_work->que_idx = que_idx; 12518c2ecf20Sopenharmony_ci qedi_work->is_solicited = false; 12528c2ecf20Sopenharmony_ci list_add_tail(&qedi_work->list, &p->work_list); 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci default: 12558c2ecf20Sopenharmony_ci rc = -1; 12568c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "FW Error cqe.\n"); 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci return rc; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic bool qedi_process_completions(struct qedi_fastpath *fp) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = fp->qedi; 12648c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info = fp->sb_info; 12658c2ecf20Sopenharmony_ci struct status_block_e4 *sb = sb_info->sb_virt; 12668c2ecf20Sopenharmony_ci struct qedi_percpu_s *p = NULL; 12678c2ecf20Sopenharmony_ci struct global_queue *que; 12688c2ecf20Sopenharmony_ci u16 prod_idx; 12698c2ecf20Sopenharmony_ci unsigned long flags; 12708c2ecf20Sopenharmony_ci union iscsi_cqe *cqe; 12718c2ecf20Sopenharmony_ci int cpu; 12728c2ecf20Sopenharmony_ci int ret; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* Get the current firmware producer index */ 12758c2ecf20Sopenharmony_ci prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (prod_idx >= QEDI_CQ_SIZE) 12788c2ecf20Sopenharmony_ci prod_idx = prod_idx % QEDI_CQ_SIZE; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci que = qedi->global_queues[fp->sb_id]; 12818c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, 12828c2ecf20Sopenharmony_ci "Before: global queue=%p prod_idx=%d cons_idx=%d, sb_id=%d\n", 12838c2ecf20Sopenharmony_ci que, prod_idx, que->cq_cons_idx, fp->sb_id); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci qedi->intr_cpu = fp->sb_id; 12868c2ecf20Sopenharmony_ci cpu = smp_processor_id(); 12878c2ecf20Sopenharmony_ci p = &per_cpu(qedi_percpu, cpu); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (unlikely(!p->iothread)) 12908c2ecf20Sopenharmony_ci WARN_ON(1); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->p_work_lock, flags); 12938c2ecf20Sopenharmony_ci while (que->cq_cons_idx != prod_idx) { 12948c2ecf20Sopenharmony_ci cqe = &que->cq[que->cq_cons_idx]; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, 12978c2ecf20Sopenharmony_ci "cqe=%p prod_idx=%d cons_idx=%d.\n", 12988c2ecf20Sopenharmony_ci cqe, prod_idx, que->cq_cons_idx); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci ret = qedi_queue_cqe(qedi, cqe, fp->sb_id, p); 13018c2ecf20Sopenharmony_ci if (ret) 13028c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 13038c2ecf20Sopenharmony_ci "Dropping CQE 0x%x for cid=0x%x.\n", 13048c2ecf20Sopenharmony_ci que->cq_cons_idx, cqe->cqe_common.conn_id); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci que->cq_cons_idx++; 13078c2ecf20Sopenharmony_ci if (que->cq_cons_idx == QEDI_CQ_SIZE) 13088c2ecf20Sopenharmony_ci que->cq_cons_idx = 0; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci wake_up_process(p->iothread); 13118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->p_work_lock, flags); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci return true; 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic bool qedi_fp_has_work(struct qedi_fastpath *fp) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = fp->qedi; 13198c2ecf20Sopenharmony_ci struct global_queue *que; 13208c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info = fp->sb_info; 13218c2ecf20Sopenharmony_ci struct status_block_e4 *sb = sb_info->sb_virt; 13228c2ecf20Sopenharmony_ci u16 prod_idx; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci barrier(); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Get the current firmware producer index */ 13278c2ecf20Sopenharmony_ci prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci /* Get the pointer to the global CQ this completion is on */ 13308c2ecf20Sopenharmony_ci que = qedi->global_queues[fp->sb_id]; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* prod idx wrap around uint16 */ 13338c2ecf20Sopenharmony_ci if (prod_idx >= QEDI_CQ_SIZE) 13348c2ecf20Sopenharmony_ci prod_idx = prod_idx % QEDI_CQ_SIZE; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci return (que->cq_cons_idx != prod_idx); 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci/* MSI-X fastpath handler code */ 13408c2ecf20Sopenharmony_cistatic irqreturn_t qedi_msix_handler(int irq, void *dev_id) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct qedi_fastpath *fp = dev_id; 13438c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = fp->qedi; 13448c2ecf20Sopenharmony_ci bool wake_io_thread = true; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci qed_sb_ack(fp->sb_info, IGU_INT_DISABLE, 0); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ciprocess_again: 13498c2ecf20Sopenharmony_ci wake_io_thread = qedi_process_completions(fp); 13508c2ecf20Sopenharmony_ci if (wake_io_thread) { 13518c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 13528c2ecf20Sopenharmony_ci "process already running\n"); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (!qedi_fp_has_work(fp)) 13568c2ecf20Sopenharmony_ci qed_sb_update_sb_idx(fp->sb_info); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci /* Check for more work */ 13598c2ecf20Sopenharmony_ci rmb(); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (!qedi_fp_has_work(fp)) 13628c2ecf20Sopenharmony_ci qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1); 13638c2ecf20Sopenharmony_ci else 13648c2ecf20Sopenharmony_ci goto process_again; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci/* simd handler for MSI/INTa */ 13708c2ecf20Sopenharmony_cistatic void qedi_simd_int_handler(void *cookie) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci /* Cookie is qedi_ctx struct */ 13738c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, "qedi=%p.\n", qedi); 13768c2ecf20Sopenharmony_ci} 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci#define QEDI_SIMD_HANDLER_NUM 0 13798c2ecf20Sopenharmony_cistatic void qedi_sync_free_irqs(struct qedi_ctx *qedi) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci int i; 13828c2ecf20Sopenharmony_ci u16 idx; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (qedi->int_info.msix_cnt) { 13858c2ecf20Sopenharmony_ci for (i = 0; i < qedi->int_info.used_cnt; i++) { 13868c2ecf20Sopenharmony_ci idx = i * qedi->dev_info.common.num_hwfns + 13878c2ecf20Sopenharmony_ci qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 13908c2ecf20Sopenharmony_ci "Freeing IRQ #%d vector_idx=%d.\n", i, idx); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci synchronize_irq(qedi->int_info.msix[idx].vector); 13938c2ecf20Sopenharmony_ci irq_set_affinity_hint(qedi->int_info.msix[idx].vector, 13948c2ecf20Sopenharmony_ci NULL); 13958c2ecf20Sopenharmony_ci free_irq(qedi->int_info.msix[idx].vector, 13968c2ecf20Sopenharmony_ci &qedi->fp_array[i]); 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci } else { 13998c2ecf20Sopenharmony_ci qedi_ops->common->simd_handler_clean(qedi->cdev, 14008c2ecf20Sopenharmony_ci QEDI_SIMD_HANDLER_NUM); 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci qedi->int_info.used_cnt = 0; 14048c2ecf20Sopenharmony_ci qedi_ops->common->set_fp_int(qedi->cdev, 0); 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic int qedi_request_msix_irq(struct qedi_ctx *qedi) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci int i, rc, cpu; 14108c2ecf20Sopenharmony_ci u16 idx; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci cpu = cpumask_first(cpu_online_mask); 14138c2ecf20Sopenharmony_ci for (i = 0; i < qedi->msix_count; i++) { 14148c2ecf20Sopenharmony_ci idx = i * qedi->dev_info.common.num_hwfns + 14158c2ecf20Sopenharmony_ci qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 14188c2ecf20Sopenharmony_ci "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", 14198c2ecf20Sopenharmony_ci qedi->dev_info.common.num_hwfns, 14208c2ecf20Sopenharmony_ci qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci rc = request_irq(qedi->int_info.msix[idx].vector, 14238c2ecf20Sopenharmony_ci qedi_msix_handler, 0, "qedi", 14248c2ecf20Sopenharmony_ci &qedi->fp_array[i]); 14258c2ecf20Sopenharmony_ci if (rc) { 14268c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); 14278c2ecf20Sopenharmony_ci qedi_sync_free_irqs(qedi); 14288c2ecf20Sopenharmony_ci return rc; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci qedi->int_info.used_cnt++; 14318c2ecf20Sopenharmony_ci rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector, 14328c2ecf20Sopenharmony_ci get_cpu_mask(cpu)); 14338c2ecf20Sopenharmony_ci cpu = cpumask_next(cpu, cpu_online_mask); 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return 0; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic int qedi_setup_int(struct qedi_ctx *qedi) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci int rc = 0; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci rc = qedi_ops->common->set_fp_int(qedi->cdev, qedi->num_queues); 14448c2ecf20Sopenharmony_ci if (rc < 0) 14458c2ecf20Sopenharmony_ci goto exit_setup_int; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci qedi->msix_count = rc; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci rc = qedi_ops->common->get_fp_int(qedi->cdev, &qedi->int_info); 14508c2ecf20Sopenharmony_ci if (rc) 14518c2ecf20Sopenharmony_ci goto exit_setup_int; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 14548c2ecf20Sopenharmony_ci "Number of msix_cnt = 0x%x num of cpus = 0x%x\n", 14558c2ecf20Sopenharmony_ci qedi->int_info.msix_cnt, num_online_cpus()); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (qedi->int_info.msix_cnt) { 14588c2ecf20Sopenharmony_ci rc = qedi_request_msix_irq(qedi); 14598c2ecf20Sopenharmony_ci goto exit_setup_int; 14608c2ecf20Sopenharmony_ci } else { 14618c2ecf20Sopenharmony_ci qedi_ops->common->simd_handler_config(qedi->cdev, &qedi, 14628c2ecf20Sopenharmony_ci QEDI_SIMD_HANDLER_NUM, 14638c2ecf20Sopenharmony_ci qedi_simd_int_handler); 14648c2ecf20Sopenharmony_ci qedi->int_info.used_cnt = 1; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ciexit_setup_int: 14688c2ecf20Sopenharmony_ci return rc; 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic void qedi_free_nvm_iscsi_cfg(struct qedi_ctx *qedi) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci if (qedi->iscsi_image) 14748c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, 14758c2ecf20Sopenharmony_ci sizeof(struct qedi_nvm_iscsi_image), 14768c2ecf20Sopenharmony_ci qedi->iscsi_image, qedi->nvm_buf_dma); 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci qedi->iscsi_image = dma_alloc_coherent(&qedi->pdev->dev, 14828c2ecf20Sopenharmony_ci sizeof(struct qedi_nvm_iscsi_image), 14838c2ecf20Sopenharmony_ci &qedi->nvm_buf_dma, GFP_KERNEL); 14848c2ecf20Sopenharmony_ci if (!qedi->iscsi_image) { 14858c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n"); 14868c2ecf20Sopenharmony_ci return -ENOMEM; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 14898c2ecf20Sopenharmony_ci "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_image, 14908c2ecf20Sopenharmony_ci qedi->nvm_buf_dma); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return 0; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic void qedi_free_bdq(struct qedi_ctx *qedi) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci int i; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (qedi->bdq_pbl_list) 15008c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 15018c2ecf20Sopenharmony_ci qedi->bdq_pbl_list, qedi->bdq_pbl_list_dma); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if (qedi->bdq_pbl) 15048c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, qedi->bdq_pbl_mem_size, 15058c2ecf20Sopenharmony_ci qedi->bdq_pbl, qedi->bdq_pbl_dma); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci for (i = 0; i < QEDI_BDQ_NUM; i++) { 15088c2ecf20Sopenharmony_ci if (qedi->bdq[i].buf_addr) { 15098c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, QEDI_BDQ_BUF_SIZE, 15108c2ecf20Sopenharmony_ci qedi->bdq[i].buf_addr, 15118c2ecf20Sopenharmony_ci qedi->bdq[i].buf_dma); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_cistatic void qedi_free_global_queues(struct qedi_ctx *qedi) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci int i; 15198c2ecf20Sopenharmony_ci struct global_queue **gl = qedi->global_queues; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci for (i = 0; i < qedi->num_queues; i++) { 15228c2ecf20Sopenharmony_ci if (!gl[i]) 15238c2ecf20Sopenharmony_ci continue; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (gl[i]->cq) 15268c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_mem_size, 15278c2ecf20Sopenharmony_ci gl[i]->cq, gl[i]->cq_dma); 15288c2ecf20Sopenharmony_ci if (gl[i]->cq_pbl) 15298c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_pbl_size, 15308c2ecf20Sopenharmony_ci gl[i]->cq_pbl, gl[i]->cq_pbl_dma); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci kfree(gl[i]); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci qedi_free_bdq(qedi); 15358c2ecf20Sopenharmony_ci qedi_free_nvm_iscsi_cfg(qedi); 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic int qedi_alloc_bdq(struct qedi_ctx *qedi) 15398c2ecf20Sopenharmony_ci{ 15408c2ecf20Sopenharmony_ci int i; 15418c2ecf20Sopenharmony_ci struct scsi_bd *pbl; 15428c2ecf20Sopenharmony_ci u64 *list; 15438c2ecf20Sopenharmony_ci dma_addr_t page; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* Alloc dma memory for BDQ buffers */ 15468c2ecf20Sopenharmony_ci for (i = 0; i < QEDI_BDQ_NUM; i++) { 15478c2ecf20Sopenharmony_ci qedi->bdq[i].buf_addr = 15488c2ecf20Sopenharmony_ci dma_alloc_coherent(&qedi->pdev->dev, 15498c2ecf20Sopenharmony_ci QEDI_BDQ_BUF_SIZE, 15508c2ecf20Sopenharmony_ci &qedi->bdq[i].buf_dma, 15518c2ecf20Sopenharmony_ci GFP_KERNEL); 15528c2ecf20Sopenharmony_ci if (!qedi->bdq[i].buf_addr) { 15538c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 15548c2ecf20Sopenharmony_ci "Could not allocate BDQ buffer %d.\n", i); 15558c2ecf20Sopenharmony_ci return -ENOMEM; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci /* Alloc dma memory for BDQ page buffer list */ 15608c2ecf20Sopenharmony_ci qedi->bdq_pbl_mem_size = QEDI_BDQ_NUM * sizeof(struct scsi_bd); 15618c2ecf20Sopenharmony_ci qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, QEDI_PAGE_SIZE); 15628c2ecf20Sopenharmony_ci qedi->rq_num_entries = qedi->bdq_pbl_mem_size / sizeof(struct scsi_bd); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, "rq_num_entries = %d.\n", 15658c2ecf20Sopenharmony_ci qedi->rq_num_entries); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci qedi->bdq_pbl = dma_alloc_coherent(&qedi->pdev->dev, 15688c2ecf20Sopenharmony_ci qedi->bdq_pbl_mem_size, 15698c2ecf20Sopenharmony_ci &qedi->bdq_pbl_dma, GFP_KERNEL); 15708c2ecf20Sopenharmony_ci if (!qedi->bdq_pbl) { 15718c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Could not allocate BDQ PBL.\n"); 15728c2ecf20Sopenharmony_ci return -ENOMEM; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci /* 15768c2ecf20Sopenharmony_ci * Populate BDQ PBL with physical and virtual address of individual 15778c2ecf20Sopenharmony_ci * BDQ buffers 15788c2ecf20Sopenharmony_ci */ 15798c2ecf20Sopenharmony_ci pbl = (struct scsi_bd *)qedi->bdq_pbl; 15808c2ecf20Sopenharmony_ci for (i = 0; i < QEDI_BDQ_NUM; i++) { 15818c2ecf20Sopenharmony_ci pbl->address.hi = 15828c2ecf20Sopenharmony_ci cpu_to_le32(QEDI_U64_HI(qedi->bdq[i].buf_dma)); 15838c2ecf20Sopenharmony_ci pbl->address.lo = 15848c2ecf20Sopenharmony_ci cpu_to_le32(QEDI_U64_LO(qedi->bdq[i].buf_dma)); 15858c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 15868c2ecf20Sopenharmony_ci "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx], idx [%d]\n", 15878c2ecf20Sopenharmony_ci pbl, pbl->address.hi, pbl->address.lo, i); 15888c2ecf20Sopenharmony_ci pbl->opaque.iscsi_opaque.reserved_zero[0] = 0; 15898c2ecf20Sopenharmony_ci pbl->opaque.iscsi_opaque.reserved_zero[1] = 0; 15908c2ecf20Sopenharmony_ci pbl->opaque.iscsi_opaque.reserved_zero[2] = 0; 15918c2ecf20Sopenharmony_ci pbl->opaque.iscsi_opaque.opaque = cpu_to_le16(i); 15928c2ecf20Sopenharmony_ci pbl++; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* Allocate list of PBL pages */ 15968c2ecf20Sopenharmony_ci qedi->bdq_pbl_list = dma_alloc_coherent(&qedi->pdev->dev, 15978c2ecf20Sopenharmony_ci QEDI_PAGE_SIZE, 15988c2ecf20Sopenharmony_ci &qedi->bdq_pbl_list_dma, 15998c2ecf20Sopenharmony_ci GFP_KERNEL); 16008c2ecf20Sopenharmony_ci if (!qedi->bdq_pbl_list) { 16018c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 16028c2ecf20Sopenharmony_ci "Could not allocate list of PBL pages.\n"); 16038c2ecf20Sopenharmony_ci return -ENOMEM; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* 16078c2ecf20Sopenharmony_ci * Now populate PBL list with pages that contain pointers to the 16088c2ecf20Sopenharmony_ci * individual buffers. 16098c2ecf20Sopenharmony_ci */ 16108c2ecf20Sopenharmony_ci qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / 16118c2ecf20Sopenharmony_ci QEDI_PAGE_SIZE; 16128c2ecf20Sopenharmony_ci list = (u64 *)qedi->bdq_pbl_list; 16138c2ecf20Sopenharmony_ci page = qedi->bdq_pbl_list_dma; 16148c2ecf20Sopenharmony_ci for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) { 16158c2ecf20Sopenharmony_ci *list = qedi->bdq_pbl_dma; 16168c2ecf20Sopenharmony_ci list++; 16178c2ecf20Sopenharmony_ci page += QEDI_PAGE_SIZE; 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci return 0; 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic int qedi_alloc_global_queues(struct qedi_ctx *qedi) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci u32 *list; 16268c2ecf20Sopenharmony_ci int i; 16278c2ecf20Sopenharmony_ci int status; 16288c2ecf20Sopenharmony_ci u32 *pbl; 16298c2ecf20Sopenharmony_ci dma_addr_t page; 16308c2ecf20Sopenharmony_ci int num_pages; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* 16338c2ecf20Sopenharmony_ci * Number of global queues (CQ / RQ). This should 16348c2ecf20Sopenharmony_ci * be <= number of available MSIX vectors for the PF 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_ci if (!qedi->num_queues) { 16378c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "No MSI-X vectors available!\n"); 16388c2ecf20Sopenharmony_ci return -ENOMEM; 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci /* Make sure we allocated the PBL that will contain the physical 16428c2ecf20Sopenharmony_ci * addresses of our queues 16438c2ecf20Sopenharmony_ci */ 16448c2ecf20Sopenharmony_ci if (!qedi->p_cpuq) { 16458c2ecf20Sopenharmony_ci status = -EINVAL; 16468c2ecf20Sopenharmony_ci goto mem_alloc_failure; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci qedi->global_queues = kzalloc((sizeof(struct global_queue *) * 16508c2ecf20Sopenharmony_ci qedi->num_queues), GFP_KERNEL); 16518c2ecf20Sopenharmony_ci if (!qedi->global_queues) { 16528c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 16538c2ecf20Sopenharmony_ci "Unable to allocate global queues array ptr memory\n"); 16548c2ecf20Sopenharmony_ci return -ENOMEM; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 16578c2ecf20Sopenharmony_ci "qedi->global_queues=%p.\n", qedi->global_queues); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* Allocate DMA coherent buffers for BDQ */ 16608c2ecf20Sopenharmony_ci status = qedi_alloc_bdq(qedi); 16618c2ecf20Sopenharmony_ci if (status) 16628c2ecf20Sopenharmony_ci goto mem_alloc_failure; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* Allocate DMA coherent buffers for NVM_ISCSI_CFG */ 16658c2ecf20Sopenharmony_ci status = qedi_alloc_nvm_iscsi_cfg(qedi); 16668c2ecf20Sopenharmony_ci if (status) 16678c2ecf20Sopenharmony_ci goto mem_alloc_failure; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci /* Allocate a CQ and an associated PBL for each MSI-X 16708c2ecf20Sopenharmony_ci * vector. 16718c2ecf20Sopenharmony_ci */ 16728c2ecf20Sopenharmony_ci for (i = 0; i < qedi->num_queues; i++) { 16738c2ecf20Sopenharmony_ci qedi->global_queues[i] = 16748c2ecf20Sopenharmony_ci kzalloc(sizeof(*qedi->global_queues[0]), 16758c2ecf20Sopenharmony_ci GFP_KERNEL); 16768c2ecf20Sopenharmony_ci if (!qedi->global_queues[i]) { 16778c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 16788c2ecf20Sopenharmony_ci "Unable to allocation global queue %d.\n", i); 16798c2ecf20Sopenharmony_ci status = -ENOMEM; 16808c2ecf20Sopenharmony_ci goto mem_alloc_failure; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_mem_size = 16848c2ecf20Sopenharmony_ci (QEDI_CQ_SIZE + 8) * sizeof(union iscsi_cqe); 16858c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_mem_size = 16868c2ecf20Sopenharmony_ci (qedi->global_queues[i]->cq_mem_size + 16878c2ecf20Sopenharmony_ci (QEDI_PAGE_SIZE - 1)); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_pbl_size = 16908c2ecf20Sopenharmony_ci (qedi->global_queues[i]->cq_mem_size / 16918c2ecf20Sopenharmony_ci QEDI_PAGE_SIZE) * sizeof(void *); 16928c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_pbl_size = 16938c2ecf20Sopenharmony_ci (qedi->global_queues[i]->cq_pbl_size + 16948c2ecf20Sopenharmony_ci (QEDI_PAGE_SIZE - 1)); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq = dma_alloc_coherent(&qedi->pdev->dev, 16978c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_mem_size, 16988c2ecf20Sopenharmony_ci &qedi->global_queues[i]->cq_dma, 16998c2ecf20Sopenharmony_ci GFP_KERNEL); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci if (!qedi->global_queues[i]->cq) { 17028c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 17038c2ecf20Sopenharmony_ci "Could not allocate cq.\n"); 17048c2ecf20Sopenharmony_ci status = -ENOMEM; 17058c2ecf20Sopenharmony_ci goto mem_alloc_failure; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_pbl = dma_alloc_coherent(&qedi->pdev->dev, 17088c2ecf20Sopenharmony_ci qedi->global_queues[i]->cq_pbl_size, 17098c2ecf20Sopenharmony_ci &qedi->global_queues[i]->cq_pbl_dma, 17108c2ecf20Sopenharmony_ci GFP_KERNEL); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (!qedi->global_queues[i]->cq_pbl) { 17138c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 17148c2ecf20Sopenharmony_ci "Could not allocate cq PBL.\n"); 17158c2ecf20Sopenharmony_ci status = -ENOMEM; 17168c2ecf20Sopenharmony_ci goto mem_alloc_failure; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci /* Create PBL */ 17208c2ecf20Sopenharmony_ci num_pages = qedi->global_queues[i]->cq_mem_size / 17218c2ecf20Sopenharmony_ci QEDI_PAGE_SIZE; 17228c2ecf20Sopenharmony_ci page = qedi->global_queues[i]->cq_dma; 17238c2ecf20Sopenharmony_ci pbl = (u32 *)qedi->global_queues[i]->cq_pbl; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci while (num_pages--) { 17268c2ecf20Sopenharmony_ci *pbl = (u32)page; 17278c2ecf20Sopenharmony_ci pbl++; 17288c2ecf20Sopenharmony_ci *pbl = (u32)((u64)page >> 32); 17298c2ecf20Sopenharmony_ci pbl++; 17308c2ecf20Sopenharmony_ci page += QEDI_PAGE_SIZE; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci list = (u32 *)qedi->p_cpuq; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci /* 17378c2ecf20Sopenharmony_ci * The list is built as follows: CQ#0 PBL pointer, RQ#0 PBL pointer, 17388c2ecf20Sopenharmony_ci * CQ#1 PBL pointer, RQ#1 PBL pointer, etc. Each PBL pointer points 17398c2ecf20Sopenharmony_ci * to the physical address which contains an array of pointers to the 17408c2ecf20Sopenharmony_ci * physical addresses of the specific queue pages. 17418c2ecf20Sopenharmony_ci */ 17428c2ecf20Sopenharmony_ci for (i = 0; i < qedi->num_queues; i++) { 17438c2ecf20Sopenharmony_ci *list = (u32)qedi->global_queues[i]->cq_pbl_dma; 17448c2ecf20Sopenharmony_ci list++; 17458c2ecf20Sopenharmony_ci *list = (u32)((u64)qedi->global_queues[i]->cq_pbl_dma >> 32); 17468c2ecf20Sopenharmony_ci list++; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci *list = (u32)0; 17498c2ecf20Sopenharmony_ci list++; 17508c2ecf20Sopenharmony_ci *list = (u32)((u64)0 >> 32); 17518c2ecf20Sopenharmony_ci list++; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci return 0; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_cimem_alloc_failure: 17578c2ecf20Sopenharmony_ci qedi_free_global_queues(qedi); 17588c2ecf20Sopenharmony_ci return status; 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ciint qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci int rval = 0; 17648c2ecf20Sopenharmony_ci u32 *pbl; 17658c2ecf20Sopenharmony_ci dma_addr_t page; 17668c2ecf20Sopenharmony_ci int num_pages; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci if (!ep) 17698c2ecf20Sopenharmony_ci return -EIO; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* Calculate appropriate queue and PBL sizes */ 17728c2ecf20Sopenharmony_ci ep->sq_mem_size = QEDI_SQ_SIZE * sizeof(struct iscsi_wqe); 17738c2ecf20Sopenharmony_ci ep->sq_mem_size += QEDI_PAGE_SIZE - 1; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *); 17768c2ecf20Sopenharmony_ci ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci ep->sq = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, 17798c2ecf20Sopenharmony_ci &ep->sq_dma, GFP_KERNEL); 17808c2ecf20Sopenharmony_ci if (!ep->sq) { 17818c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 17828c2ecf20Sopenharmony_ci "Could not allocate send queue.\n"); 17838c2ecf20Sopenharmony_ci rval = -ENOMEM; 17848c2ecf20Sopenharmony_ci goto out; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci ep->sq_pbl = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, 17878c2ecf20Sopenharmony_ci &ep->sq_pbl_dma, GFP_KERNEL); 17888c2ecf20Sopenharmony_ci if (!ep->sq_pbl) { 17898c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, 17908c2ecf20Sopenharmony_ci "Could not allocate send queue PBL.\n"); 17918c2ecf20Sopenharmony_ci rval = -ENOMEM; 17928c2ecf20Sopenharmony_ci goto out_free_sq; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* Create PBL */ 17968c2ecf20Sopenharmony_ci num_pages = ep->sq_mem_size / QEDI_PAGE_SIZE; 17978c2ecf20Sopenharmony_ci page = ep->sq_dma; 17988c2ecf20Sopenharmony_ci pbl = (u32 *)ep->sq_pbl; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci while (num_pages--) { 18018c2ecf20Sopenharmony_ci *pbl = (u32)page; 18028c2ecf20Sopenharmony_ci pbl++; 18038c2ecf20Sopenharmony_ci *pbl = (u32)((u64)page >> 32); 18048c2ecf20Sopenharmony_ci pbl++; 18058c2ecf20Sopenharmony_ci page += QEDI_PAGE_SIZE; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci return rval; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ciout_free_sq: 18118c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, 18128c2ecf20Sopenharmony_ci ep->sq_dma); 18138c2ecf20Sopenharmony_ciout: 18148c2ecf20Sopenharmony_ci return rval; 18158c2ecf20Sopenharmony_ci} 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_civoid qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci if (ep->sq_pbl) 18208c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, ep->sq_pbl_size, ep->sq_pbl, 18218c2ecf20Sopenharmony_ci ep->sq_pbl_dma); 18228c2ecf20Sopenharmony_ci if (ep->sq) 18238c2ecf20Sopenharmony_ci dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, 18248c2ecf20Sopenharmony_ci ep->sq_dma); 18258c2ecf20Sopenharmony_ci} 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ciint qedi_get_task_idx(struct qedi_ctx *qedi) 18288c2ecf20Sopenharmony_ci{ 18298c2ecf20Sopenharmony_ci s16 tmp_idx; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ciagain: 18328c2ecf20Sopenharmony_ci tmp_idx = find_first_zero_bit(qedi->task_idx_map, 18338c2ecf20Sopenharmony_ci MAX_ISCSI_TASK_ENTRIES); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (tmp_idx >= MAX_ISCSI_TASK_ENTRIES) { 18368c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "FW task context pool is full.\n"); 18378c2ecf20Sopenharmony_ci tmp_idx = -1; 18388c2ecf20Sopenharmony_ci goto err_idx; 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (test_and_set_bit(tmp_idx, qedi->task_idx_map)) 18428c2ecf20Sopenharmony_ci goto again; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cierr_idx: 18458c2ecf20Sopenharmony_ci return tmp_idx; 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_civoid qedi_clear_task_idx(struct qedi_ctx *qedi, int idx) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci if (!test_and_clear_bit(idx, qedi->task_idx_map)) 18518c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 18528c2ecf20Sopenharmony_ci "FW task context, already cleared, tid=0x%x\n", idx); 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_civoid qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, 18568c2ecf20Sopenharmony_ci struct qedi_cmd *cmd) 18578c2ecf20Sopenharmony_ci{ 18588c2ecf20Sopenharmony_ci qedi->itt_map[tid].itt = proto_itt; 18598c2ecf20Sopenharmony_ci qedi->itt_map[tid].p_cmd = cmd; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 18628c2ecf20Sopenharmony_ci "update itt map tid=0x%x, with proto itt=0x%x\n", tid, 18638c2ecf20Sopenharmony_ci qedi->itt_map[tid].itt); 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_civoid qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci u16 i; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci for (i = 0; i < MAX_ISCSI_TASK_ENTRIES; i++) { 18718c2ecf20Sopenharmony_ci if (qedi->itt_map[i].itt == itt) { 18728c2ecf20Sopenharmony_ci *tid = i; 18738c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 18748c2ecf20Sopenharmony_ci "Ref itt=0x%x, found at tid=0x%x\n", 18758c2ecf20Sopenharmony_ci itt, *tid); 18768c2ecf20Sopenharmony_ci return; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci WARN_ON(1); 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_civoid qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt) 18848c2ecf20Sopenharmony_ci{ 18858c2ecf20Sopenharmony_ci *proto_itt = qedi->itt_map[tid].itt; 18868c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 18878c2ecf20Sopenharmony_ci "Get itt map tid [0x%x with proto itt[0x%x]", 18888c2ecf20Sopenharmony_ci tid, *proto_itt); 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistruct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci struct qedi_cmd *cmd = NULL; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (tid >= MAX_ISCSI_TASK_ENTRIES) 18968c2ecf20Sopenharmony_ci return NULL; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci cmd = qedi->itt_map[tid].p_cmd; 18998c2ecf20Sopenharmony_ci if (cmd->task_id != tid) 19008c2ecf20Sopenharmony_ci return NULL; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci qedi->itt_map[tid].p_cmd = NULL; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci return cmd; 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_cistatic int qedi_alloc_itt(struct qedi_ctx *qedi) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci qedi->itt_map = kcalloc(MAX_ISCSI_TASK_ENTRIES, 19108c2ecf20Sopenharmony_ci sizeof(struct qedi_itt_map), GFP_KERNEL); 19118c2ecf20Sopenharmony_ci if (!qedi->itt_map) { 19128c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 19138c2ecf20Sopenharmony_ci "Unable to allocate itt map array memory\n"); 19148c2ecf20Sopenharmony_ci return -ENOMEM; 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci return 0; 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistatic void qedi_free_itt(struct qedi_ctx *qedi) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci kfree(qedi->itt_map); 19228c2ecf20Sopenharmony_ci} 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic struct qed_ll2_cb_ops qedi_ll2_cb_ops = { 19258c2ecf20Sopenharmony_ci .rx_cb = qedi_ll2_rx, 19268c2ecf20Sopenharmony_ci .tx_cb = NULL, 19278c2ecf20Sopenharmony_ci}; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_cistatic int qedi_percpu_io_thread(void *arg) 19308c2ecf20Sopenharmony_ci{ 19318c2ecf20Sopenharmony_ci struct qedi_percpu_s *p = arg; 19328c2ecf20Sopenharmony_ci struct qedi_work *work, *tmp; 19338c2ecf20Sopenharmony_ci unsigned long flags; 19348c2ecf20Sopenharmony_ci LIST_HEAD(work_list); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci set_user_nice(current, -20); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 19398c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->p_work_lock, flags); 19408c2ecf20Sopenharmony_ci while (!list_empty(&p->work_list)) { 19418c2ecf20Sopenharmony_ci list_splice_init(&p->work_list, &work_list); 19428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->p_work_lock, flags); 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci list_for_each_entry_safe(work, tmp, &work_list, list) { 19458c2ecf20Sopenharmony_ci list_del_init(&work->list); 19468c2ecf20Sopenharmony_ci qedi_fp_process_cqes(work); 19478c2ecf20Sopenharmony_ci if (!work->is_solicited) 19488c2ecf20Sopenharmony_ci kfree(work); 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci cond_resched(); 19518c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->p_work_lock, flags); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 19548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->p_work_lock, flags); 19558c2ecf20Sopenharmony_ci schedule(); 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci return 0; 19608c2ecf20Sopenharmony_ci} 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_cistatic int qedi_cpu_online(unsigned int cpu) 19638c2ecf20Sopenharmony_ci{ 19648c2ecf20Sopenharmony_ci struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); 19658c2ecf20Sopenharmony_ci struct task_struct *thread; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci thread = kthread_create_on_node(qedi_percpu_io_thread, (void *)p, 19688c2ecf20Sopenharmony_ci cpu_to_node(cpu), 19698c2ecf20Sopenharmony_ci "qedi_thread/%d", cpu); 19708c2ecf20Sopenharmony_ci if (IS_ERR(thread)) 19718c2ecf20Sopenharmony_ci return PTR_ERR(thread); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci kthread_bind(thread, cpu); 19748c2ecf20Sopenharmony_ci p->iothread = thread; 19758c2ecf20Sopenharmony_ci wake_up_process(thread); 19768c2ecf20Sopenharmony_ci return 0; 19778c2ecf20Sopenharmony_ci} 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_cistatic int qedi_cpu_offline(unsigned int cpu) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); 19828c2ecf20Sopenharmony_ci struct qedi_work *work, *tmp; 19838c2ecf20Sopenharmony_ci struct task_struct *thread; 19848c2ecf20Sopenharmony_ci unsigned long flags; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->p_work_lock, flags); 19878c2ecf20Sopenharmony_ci thread = p->iothread; 19888c2ecf20Sopenharmony_ci p->iothread = NULL; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci list_for_each_entry_safe(work, tmp, &p->work_list, list) { 19918c2ecf20Sopenharmony_ci list_del_init(&work->list); 19928c2ecf20Sopenharmony_ci qedi_fp_process_cqes(work); 19938c2ecf20Sopenharmony_ci if (!work->is_solicited) 19948c2ecf20Sopenharmony_ci kfree(work); 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->p_work_lock, flags); 19988c2ecf20Sopenharmony_ci if (thread) 19998c2ecf20Sopenharmony_ci kthread_stop(thread); 20008c2ecf20Sopenharmony_ci return 0; 20018c2ecf20Sopenharmony_ci} 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_civoid qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu) 20048c2ecf20Sopenharmony_ci{ 20058c2ecf20Sopenharmony_ci struct qed_ll2_params params; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci qedi_recover_all_conns(qedi); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci qedi_ops->ll2->stop(qedi->cdev); 20108c2ecf20Sopenharmony_ci qedi_ll2_free_skbs(qedi); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "old MTU %u, new MTU %u\n", 20138c2ecf20Sopenharmony_ci qedi->ll2_mtu, mtu); 20148c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 20158c2ecf20Sopenharmony_ci qedi->ll2_mtu = mtu; 20168c2ecf20Sopenharmony_ci params.mtu = qedi->ll2_mtu + IPV6_HDR_LEN + TCP_HDR_LEN; 20178c2ecf20Sopenharmony_ci params.drop_ttl0_packets = 0; 20188c2ecf20Sopenharmony_ci params.rx_vlan_stripping = 1; 20198c2ecf20Sopenharmony_ci ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); 20208c2ecf20Sopenharmony_ci qedi_ops->ll2->start(qedi->cdev, ¶ms); 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci/* 20248c2ecf20Sopenharmony_ci * qedi_get_nvram_block: - Scan through the iSCSI NVRAM block (while accounting 20258c2ecf20Sopenharmony_ci * for gaps) for the matching absolute-pf-id of the QEDI device. 20268c2ecf20Sopenharmony_ci */ 20278c2ecf20Sopenharmony_cistatic struct nvm_iscsi_block * 20288c2ecf20Sopenharmony_ciqedi_get_nvram_block(struct qedi_ctx *qedi) 20298c2ecf20Sopenharmony_ci{ 20308c2ecf20Sopenharmony_ci int i; 20318c2ecf20Sopenharmony_ci u8 pf; 20328c2ecf20Sopenharmony_ci u32 flags; 20338c2ecf20Sopenharmony_ci struct nvm_iscsi_block *block; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci pf = qedi->dev_info.common.abs_pf_id; 20368c2ecf20Sopenharmony_ci block = &qedi->iscsi_image->iscsi_cfg.block[0]; 20378c2ecf20Sopenharmony_ci for (i = 0; i < NUM_OF_ISCSI_PF_SUPPORTED; i++, block++) { 20388c2ecf20Sopenharmony_ci flags = ((block->id) & NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK) >> 20398c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET; 20408c2ecf20Sopenharmony_ci if (flags & (NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY | 20418c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED) && 20428c2ecf20Sopenharmony_ci (pf == (block->id & NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK) 20438c2ecf20Sopenharmony_ci >> NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET)) 20448c2ecf20Sopenharmony_ci return block; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci return NULL; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_cistatic ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) 20508c2ecf20Sopenharmony_ci{ 20518c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = data; 20528c2ecf20Sopenharmony_ci struct nvm_iscsi_initiator *initiator; 20538c2ecf20Sopenharmony_ci int rc = 1; 20548c2ecf20Sopenharmony_ci u32 ipv6_en, dhcp_en, ip_len; 20558c2ecf20Sopenharmony_ci struct nvm_iscsi_block *block; 20568c2ecf20Sopenharmony_ci char *fmt, *ip, *sub, *gw; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci block = qedi_get_nvram_block(qedi); 20598c2ecf20Sopenharmony_ci if (!block) 20608c2ecf20Sopenharmony_ci return 0; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci initiator = &block->initiator; 20638c2ecf20Sopenharmony_ci ipv6_en = block->generic.ctrl_flags & 20648c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_IPV6_ENABLED; 20658c2ecf20Sopenharmony_ci dhcp_en = block->generic.ctrl_flags & 20668c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED; 20678c2ecf20Sopenharmony_ci /* Static IP assignments. */ 20688c2ecf20Sopenharmony_ci fmt = ipv6_en ? "%pI6\n" : "%pI4\n"; 20698c2ecf20Sopenharmony_ci ip = ipv6_en ? initiator->ipv6.addr.byte : initiator->ipv4.addr.byte; 20708c2ecf20Sopenharmony_ci ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN; 20718c2ecf20Sopenharmony_ci sub = ipv6_en ? initiator->ipv6.subnet_mask.byte : 20728c2ecf20Sopenharmony_ci initiator->ipv4.subnet_mask.byte; 20738c2ecf20Sopenharmony_ci gw = ipv6_en ? initiator->ipv6.gateway.byte : 20748c2ecf20Sopenharmony_ci initiator->ipv4.gateway.byte; 20758c2ecf20Sopenharmony_ci /* DHCP IP adjustments. */ 20768c2ecf20Sopenharmony_ci fmt = dhcp_en ? "%s\n" : fmt; 20778c2ecf20Sopenharmony_ci if (dhcp_en) { 20788c2ecf20Sopenharmony_ci ip = ipv6_en ? "0::0" : "0.0.0.0"; 20798c2ecf20Sopenharmony_ci sub = ip; 20808c2ecf20Sopenharmony_ci gw = ip; 20818c2ecf20Sopenharmony_ci ip_len = ipv6_en ? 5 : 8; 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci switch (type) { 20858c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_IP_ADDR: 20868c2ecf20Sopenharmony_ci rc = snprintf(buf, ip_len, fmt, ip); 20878c2ecf20Sopenharmony_ci break; 20888c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_SUBNET_MASK: 20898c2ecf20Sopenharmony_ci rc = snprintf(buf, ip_len, fmt, sub); 20908c2ecf20Sopenharmony_ci break; 20918c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_GATEWAY: 20928c2ecf20Sopenharmony_ci rc = snprintf(buf, ip_len, fmt, gw); 20938c2ecf20Sopenharmony_ci break; 20948c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_FLAGS: 20958c2ecf20Sopenharmony_ci rc = snprintf(buf, 3, "%hhd\n", 20968c2ecf20Sopenharmony_ci SYSFS_FLAG_FW_SEL_BOOT); 20978c2ecf20Sopenharmony_ci break; 20988c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_INDEX: 20998c2ecf20Sopenharmony_ci rc = snprintf(buf, 3, "0\n"); 21008c2ecf20Sopenharmony_ci break; 21018c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_MAC: 21028c2ecf20Sopenharmony_ci rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN); 21038c2ecf20Sopenharmony_ci break; 21048c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_VLAN: 21058c2ecf20Sopenharmony_ci rc = snprintf(buf, 12, "%d\n", 21068c2ecf20Sopenharmony_ci GET_FIELD2(initiator->generic_cont0, 21078c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_INITIATOR_VLAN)); 21088c2ecf20Sopenharmony_ci break; 21098c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_ORIGIN: 21108c2ecf20Sopenharmony_ci if (dhcp_en) 21118c2ecf20Sopenharmony_ci rc = snprintf(buf, 3, "3\n"); 21128c2ecf20Sopenharmony_ci break; 21138c2ecf20Sopenharmony_ci default: 21148c2ecf20Sopenharmony_ci rc = 0; 21158c2ecf20Sopenharmony_ci break; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci return rc; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_cistatic umode_t qedi_eth_get_attr_visibility(void *data, int type) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci int rc = 1; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci switch (type) { 21268c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_FLAGS: 21278c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_MAC: 21288c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_INDEX: 21298c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_IP_ADDR: 21308c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_SUBNET_MASK: 21318c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_GATEWAY: 21328c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_ORIGIN: 21338c2ecf20Sopenharmony_ci case ISCSI_BOOT_ETH_VLAN: 21348c2ecf20Sopenharmony_ci rc = 0444; 21358c2ecf20Sopenharmony_ci break; 21368c2ecf20Sopenharmony_ci default: 21378c2ecf20Sopenharmony_ci rc = 0; 21388c2ecf20Sopenharmony_ci break; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci return rc; 21418c2ecf20Sopenharmony_ci} 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_cistatic ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) 21448c2ecf20Sopenharmony_ci{ 21458c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = data; 21468c2ecf20Sopenharmony_ci struct nvm_iscsi_initiator *initiator; 21478c2ecf20Sopenharmony_ci int rc; 21488c2ecf20Sopenharmony_ci struct nvm_iscsi_block *block; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci block = qedi_get_nvram_block(qedi); 21518c2ecf20Sopenharmony_ci if (!block) 21528c2ecf20Sopenharmony_ci return 0; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci initiator = &block->initiator; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci switch (type) { 21578c2ecf20Sopenharmony_ci case ISCSI_BOOT_INI_INITIATOR_NAME: 21588c2ecf20Sopenharmony_ci rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, 21598c2ecf20Sopenharmony_ci initiator->initiator_name.byte); 21608c2ecf20Sopenharmony_ci break; 21618c2ecf20Sopenharmony_ci default: 21628c2ecf20Sopenharmony_ci rc = 0; 21638c2ecf20Sopenharmony_ci break; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci return rc; 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cistatic umode_t qedi_ini_get_attr_visibility(void *data, int type) 21698c2ecf20Sopenharmony_ci{ 21708c2ecf20Sopenharmony_ci int rc; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci switch (type) { 21738c2ecf20Sopenharmony_ci case ISCSI_BOOT_INI_INITIATOR_NAME: 21748c2ecf20Sopenharmony_ci rc = 0444; 21758c2ecf20Sopenharmony_ci break; 21768c2ecf20Sopenharmony_ci default: 21778c2ecf20Sopenharmony_ci rc = 0; 21788c2ecf20Sopenharmony_ci break; 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci return rc; 21818c2ecf20Sopenharmony_ci} 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_cistatic ssize_t 21848c2ecf20Sopenharmony_ciqedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, 21858c2ecf20Sopenharmony_ci char *buf, enum qedi_nvm_tgts idx) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci int rc = 1; 21888c2ecf20Sopenharmony_ci u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len; 21898c2ecf20Sopenharmony_ci struct nvm_iscsi_block *block; 21908c2ecf20Sopenharmony_ci char *chap_name, *chap_secret; 21918c2ecf20Sopenharmony_ci char *mchap_name, *mchap_secret; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci block = qedi_get_nvram_block(qedi); 21948c2ecf20Sopenharmony_ci if (!block) 21958c2ecf20Sopenharmony_ci goto exit_show_tgt_info; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT, 21988c2ecf20Sopenharmony_ci "Port:%d, tgt_idx:%d\n", 21998c2ecf20Sopenharmony_ci GET_FIELD2(block->id, NVM_ISCSI_CFG_BLK_MAPPED_PF_ID), idx); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci ctrl_flags = block->target[idx].ctrl_flags & 22028c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_TARGET_ENABLED; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci if (!ctrl_flags) { 22058c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT, 22068c2ecf20Sopenharmony_ci "Target disabled\n"); 22078c2ecf20Sopenharmony_ci goto exit_show_tgt_info; 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci ipv6_en = block->generic.ctrl_flags & 22118c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_IPV6_ENABLED; 22128c2ecf20Sopenharmony_ci ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN; 22138c2ecf20Sopenharmony_ci chap_en = block->generic.ctrl_flags & 22148c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_CHAP_ENABLED; 22158c2ecf20Sopenharmony_ci chap_name = chap_en ? block->initiator.chap_name.byte : NULL; 22168c2ecf20Sopenharmony_ci chap_secret = chap_en ? block->initiator.chap_password.byte : NULL; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci mchap_en = block->generic.ctrl_flags & 22198c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED; 22208c2ecf20Sopenharmony_ci mchap_name = mchap_en ? block->target[idx].chap_name.byte : NULL; 22218c2ecf20Sopenharmony_ci mchap_secret = mchap_en ? block->target[idx].chap_password.byte : NULL; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci switch (type) { 22248c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_NAME: 22258c2ecf20Sopenharmony_ci rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, 22268c2ecf20Sopenharmony_ci block->target[idx].target_name.byte); 22278c2ecf20Sopenharmony_ci break; 22288c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_IP_ADDR: 22298c2ecf20Sopenharmony_ci if (ipv6_en) 22308c2ecf20Sopenharmony_ci rc = snprintf(buf, ip_len, "%pI6\n", 22318c2ecf20Sopenharmony_ci block->target[idx].ipv6_addr.byte); 22328c2ecf20Sopenharmony_ci else 22338c2ecf20Sopenharmony_ci rc = snprintf(buf, ip_len, "%pI4\n", 22348c2ecf20Sopenharmony_ci block->target[idx].ipv4_addr.byte); 22358c2ecf20Sopenharmony_ci break; 22368c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_PORT: 22378c2ecf20Sopenharmony_ci rc = snprintf(buf, 12, "%d\n", 22388c2ecf20Sopenharmony_ci GET_FIELD2(block->target[idx].generic_cont0, 22398c2ecf20Sopenharmony_ci NVM_ISCSI_CFG_TARGET_TCP_PORT)); 22408c2ecf20Sopenharmony_ci break; 22418c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_LUN: 22428c2ecf20Sopenharmony_ci rc = snprintf(buf, 22, "%.*d\n", 22438c2ecf20Sopenharmony_ci block->target[idx].lun.value[1], 22448c2ecf20Sopenharmony_ci block->target[idx].lun.value[0]); 22458c2ecf20Sopenharmony_ci break; 22468c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_NAME: 22478c2ecf20Sopenharmony_ci rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 22488c2ecf20Sopenharmony_ci chap_name); 22498c2ecf20Sopenharmony_ci break; 22508c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_SECRET: 22518c2ecf20Sopenharmony_ci rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, 22528c2ecf20Sopenharmony_ci chap_secret); 22538c2ecf20Sopenharmony_ci break; 22548c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_NAME: 22558c2ecf20Sopenharmony_ci rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 22568c2ecf20Sopenharmony_ci mchap_name); 22578c2ecf20Sopenharmony_ci break; 22588c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 22598c2ecf20Sopenharmony_ci rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, 22608c2ecf20Sopenharmony_ci mchap_secret); 22618c2ecf20Sopenharmony_ci break; 22628c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_FLAGS: 22638c2ecf20Sopenharmony_ci rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); 22648c2ecf20Sopenharmony_ci break; 22658c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_NIC_ASSOC: 22668c2ecf20Sopenharmony_ci rc = snprintf(buf, 3, "0\n"); 22678c2ecf20Sopenharmony_ci break; 22688c2ecf20Sopenharmony_ci default: 22698c2ecf20Sopenharmony_ci rc = 0; 22708c2ecf20Sopenharmony_ci break; 22718c2ecf20Sopenharmony_ci } 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ciexit_show_tgt_info: 22748c2ecf20Sopenharmony_ci return rc; 22758c2ecf20Sopenharmony_ci} 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_cistatic ssize_t qedi_show_boot_tgt_pri_info(void *data, int type, char *buf) 22788c2ecf20Sopenharmony_ci{ 22798c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = data; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_PRI); 22828c2ecf20Sopenharmony_ci} 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_cistatic ssize_t qedi_show_boot_tgt_sec_info(void *data, int type, char *buf) 22858c2ecf20Sopenharmony_ci{ 22868c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = data; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_SEC); 22898c2ecf20Sopenharmony_ci} 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_cistatic umode_t qedi_tgt_get_attr_visibility(void *data, int type) 22928c2ecf20Sopenharmony_ci{ 22938c2ecf20Sopenharmony_ci int rc; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci switch (type) { 22968c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_NAME: 22978c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_IP_ADDR: 22988c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_PORT: 22998c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_LUN: 23008c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_NAME: 23018c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_CHAP_SECRET: 23028c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_NAME: 23038c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 23048c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_NIC_ASSOC: 23058c2ecf20Sopenharmony_ci case ISCSI_BOOT_TGT_FLAGS: 23068c2ecf20Sopenharmony_ci rc = 0444; 23078c2ecf20Sopenharmony_ci break; 23088c2ecf20Sopenharmony_ci default: 23098c2ecf20Sopenharmony_ci rc = 0; 23108c2ecf20Sopenharmony_ci break; 23118c2ecf20Sopenharmony_ci } 23128c2ecf20Sopenharmony_ci return rc; 23138c2ecf20Sopenharmony_ci} 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_cistatic void qedi_boot_release(void *data) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = data; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci scsi_host_put(qedi->shost); 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_cistatic int qedi_get_boot_info(struct qedi_ctx *qedi) 23238c2ecf20Sopenharmony_ci{ 23248c2ecf20Sopenharmony_ci int ret = 1; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 23278c2ecf20Sopenharmony_ci "Get NVM iSCSI CFG image\n"); 23288c2ecf20Sopenharmony_ci ret = qedi_ops->common->nvm_get_image(qedi->cdev, 23298c2ecf20Sopenharmony_ci QED_NVM_IMAGE_ISCSI_CFG, 23308c2ecf20Sopenharmony_ci (char *)qedi->iscsi_image, 23318c2ecf20Sopenharmony_ci sizeof(struct qedi_nvm_iscsi_image)); 23328c2ecf20Sopenharmony_ci if (ret) 23338c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 23348c2ecf20Sopenharmony_ci "Could not get NVM image. ret = %d\n", ret); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci return ret; 23378c2ecf20Sopenharmony_ci} 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_cistatic int qedi_setup_boot_info(struct qedi_ctx *qedi) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci struct iscsi_boot_kobj *boot_kobj; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci if (qedi_get_boot_info(qedi)) 23448c2ecf20Sopenharmony_ci return -EPERM; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci qedi->boot_kset = iscsi_boot_create_host_kset(qedi->shost->host_no); 23478c2ecf20Sopenharmony_ci if (!qedi->boot_kset) 23488c2ecf20Sopenharmony_ci goto kset_free; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (!scsi_host_get(qedi->shost)) 23518c2ecf20Sopenharmony_ci goto kset_free; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 0, qedi, 23548c2ecf20Sopenharmony_ci qedi_show_boot_tgt_pri_info, 23558c2ecf20Sopenharmony_ci qedi_tgt_get_attr_visibility, 23568c2ecf20Sopenharmony_ci qedi_boot_release); 23578c2ecf20Sopenharmony_ci if (!boot_kobj) 23588c2ecf20Sopenharmony_ci goto put_host; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci if (!scsi_host_get(qedi->shost)) 23618c2ecf20Sopenharmony_ci goto kset_free; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 1, qedi, 23648c2ecf20Sopenharmony_ci qedi_show_boot_tgt_sec_info, 23658c2ecf20Sopenharmony_ci qedi_tgt_get_attr_visibility, 23668c2ecf20Sopenharmony_ci qedi_boot_release); 23678c2ecf20Sopenharmony_ci if (!boot_kobj) 23688c2ecf20Sopenharmony_ci goto put_host; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci if (!scsi_host_get(qedi->shost)) 23718c2ecf20Sopenharmony_ci goto kset_free; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci boot_kobj = iscsi_boot_create_initiator(qedi->boot_kset, 0, qedi, 23748c2ecf20Sopenharmony_ci qedi_show_boot_ini_info, 23758c2ecf20Sopenharmony_ci qedi_ini_get_attr_visibility, 23768c2ecf20Sopenharmony_ci qedi_boot_release); 23778c2ecf20Sopenharmony_ci if (!boot_kobj) 23788c2ecf20Sopenharmony_ci goto put_host; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci if (!scsi_host_get(qedi->shost)) 23818c2ecf20Sopenharmony_ci goto kset_free; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci boot_kobj = iscsi_boot_create_ethernet(qedi->boot_kset, 0, qedi, 23848c2ecf20Sopenharmony_ci qedi_show_boot_eth_info, 23858c2ecf20Sopenharmony_ci qedi_eth_get_attr_visibility, 23868c2ecf20Sopenharmony_ci qedi_boot_release); 23878c2ecf20Sopenharmony_ci if (!boot_kobj) 23888c2ecf20Sopenharmony_ci goto put_host; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci return 0; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ciput_host: 23938c2ecf20Sopenharmony_ci scsi_host_put(qedi->shost); 23948c2ecf20Sopenharmony_cikset_free: 23958c2ecf20Sopenharmony_ci iscsi_boot_destroy_kset(qedi->boot_kset); 23968c2ecf20Sopenharmony_ci return -ENOMEM; 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_cistatic pci_ers_result_t qedi_io_error_detected(struct pci_dev *pdev, 24008c2ecf20Sopenharmony_ci pci_channel_state_t state) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = pci_get_drvdata(pdev); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "%s: PCI error detected [%d]\n", 24058c2ecf20Sopenharmony_ci __func__, state); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) { 24088c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 24098c2ecf20Sopenharmony_ci "Recovery already in progress.\n"); 24108c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NONE; 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci qedi_ops->common->recovery_process(qedi->cdev); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 24168c2ecf20Sopenharmony_ci} 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_cistatic void __qedi_remove(struct pci_dev *pdev, int mode) 24198c2ecf20Sopenharmony_ci{ 24208c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = pci_get_drvdata(pdev); 24218c2ecf20Sopenharmony_ci int rval; 24228c2ecf20Sopenharmony_ci u16 retry = 10; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (mode == QEDI_MODE_SHUTDOWN) 24258c2ecf20Sopenharmony_ci iscsi_host_for_each_session(qedi->shost, 24268c2ecf20Sopenharmony_ci qedi_clear_session_ctx); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { 24298c2ecf20Sopenharmony_ci if (qedi->tmf_thread) { 24308c2ecf20Sopenharmony_ci flush_workqueue(qedi->tmf_thread); 24318c2ecf20Sopenharmony_ci destroy_workqueue(qedi->tmf_thread); 24328c2ecf20Sopenharmony_ci qedi->tmf_thread = NULL; 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci if (qedi->offload_thread) { 24368c2ecf20Sopenharmony_ci flush_workqueue(qedi->offload_thread); 24378c2ecf20Sopenharmony_ci destroy_workqueue(qedi->offload_thread); 24388c2ecf20Sopenharmony_ci qedi->offload_thread = NULL; 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 24438c2ecf20Sopenharmony_ci qedi_dbg_host_exit(&qedi->dbg_ctx); 24448c2ecf20Sopenharmony_ci#endif 24458c2ecf20Sopenharmony_ci if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) 24468c2ecf20Sopenharmony_ci qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci qedi_sync_free_irqs(qedi); 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { 24518c2ecf20Sopenharmony_ci while (retry--) { 24528c2ecf20Sopenharmony_ci rval = qedi_ops->stop(qedi->cdev); 24538c2ecf20Sopenharmony_ci if (rval < 0) 24548c2ecf20Sopenharmony_ci msleep(1000); 24558c2ecf20Sopenharmony_ci else 24568c2ecf20Sopenharmony_ci break; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci qedi_ops->ll2->stop(qedi->cdev); 24598c2ecf20Sopenharmony_ci } 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&qedi->recovery_work); 24628c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&qedi->board_disable_work); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci qedi_free_iscsi_pf_param(qedi); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci rval = qedi_ops->common->update_drv_state(qedi->cdev, false); 24678c2ecf20Sopenharmony_ci if (rval) 24688c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Failed to send drv state to MFW\n"); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { 24718c2ecf20Sopenharmony_ci qedi_ops->common->slowpath_stop(qedi->cdev); 24728c2ecf20Sopenharmony_ci qedi_ops->common->remove(qedi->cdev); 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci qedi_destroy_fp(qedi); 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { 24788c2ecf20Sopenharmony_ci qedi_release_cid_que(qedi); 24798c2ecf20Sopenharmony_ci qedi_cm_free_mem(qedi); 24808c2ecf20Sopenharmony_ci qedi_free_uio(qedi->udev); 24818c2ecf20Sopenharmony_ci qedi_free_itt(qedi); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci if (qedi->ll2_recv_thread) { 24848c2ecf20Sopenharmony_ci kthread_stop(qedi->ll2_recv_thread); 24858c2ecf20Sopenharmony_ci qedi->ll2_recv_thread = NULL; 24868c2ecf20Sopenharmony_ci } 24878c2ecf20Sopenharmony_ci qedi_ll2_free_skbs(qedi); 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci if (qedi->boot_kset) 24908c2ecf20Sopenharmony_ci iscsi_boot_destroy_kset(qedi->boot_kset); 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci iscsi_host_remove(qedi->shost); 24938c2ecf20Sopenharmony_ci iscsi_host_free(qedi->shost); 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_cistatic void qedi_board_disable_work(struct work_struct *work) 24988c2ecf20Sopenharmony_ci{ 24998c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = 25008c2ecf20Sopenharmony_ci container_of(work, struct qedi_ctx, 25018c2ecf20Sopenharmony_ci board_disable_work.work); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 25048c2ecf20Sopenharmony_ci "Fan failure, Unloading firmware context.\n"); 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) 25078c2ecf20Sopenharmony_ci return; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci __qedi_remove(qedi->pdev, QEDI_MODE_SHUTDOWN); 25108c2ecf20Sopenharmony_ci} 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_cistatic void qedi_shutdown(struct pci_dev *pdev) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = pci_get_drvdata(pdev); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "%s: Shutdown qedi\n", __func__); 25178c2ecf20Sopenharmony_ci if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) 25188c2ecf20Sopenharmony_ci return; 25198c2ecf20Sopenharmony_ci __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); 25208c2ecf20Sopenharmony_ci} 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_cistatic int qedi_suspend(struct pci_dev *pdev, pm_message_t state) 25238c2ecf20Sopenharmony_ci{ 25248c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci if (!pdev) { 25278c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "pdev is NULL.\n"); 25288c2ecf20Sopenharmony_ci return -ENODEV; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci qedi = pci_get_drvdata(pdev); 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "%s: Device does not support suspend operation\n", __func__); 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci return -EPERM; 25368c2ecf20Sopenharmony_ci} 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_cistatic int __qedi_probe(struct pci_dev *pdev, int mode) 25398c2ecf20Sopenharmony_ci{ 25408c2ecf20Sopenharmony_ci struct qedi_ctx *qedi; 25418c2ecf20Sopenharmony_ci struct qed_ll2_params params; 25428c2ecf20Sopenharmony_ci u8 dp_level = 0; 25438c2ecf20Sopenharmony_ci bool is_vf = false; 25448c2ecf20Sopenharmony_ci char host_buf[16]; 25458c2ecf20Sopenharmony_ci struct qed_link_params link_params; 25468c2ecf20Sopenharmony_ci struct qed_slowpath_params sp_params; 25478c2ecf20Sopenharmony_ci struct qed_probe_params qed_params; 25488c2ecf20Sopenharmony_ci void *task_start, *task_end; 25498c2ecf20Sopenharmony_ci int rc; 25508c2ecf20Sopenharmony_ci u16 retry = 10; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci if (mode != QEDI_MODE_RECOVERY) { 25538c2ecf20Sopenharmony_ci qedi = qedi_host_alloc(pdev); 25548c2ecf20Sopenharmony_ci if (!qedi) { 25558c2ecf20Sopenharmony_ci rc = -ENOMEM; 25568c2ecf20Sopenharmony_ci goto exit_probe; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci } else { 25598c2ecf20Sopenharmony_ci qedi = pci_get_drvdata(pdev); 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ciretry_probe: 25638c2ecf20Sopenharmony_ci if (mode == QEDI_MODE_RECOVERY) 25648c2ecf20Sopenharmony_ci msleep(2000); 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci memset(&qed_params, 0, sizeof(qed_params)); 25678c2ecf20Sopenharmony_ci qed_params.protocol = QED_PROTOCOL_ISCSI; 25688c2ecf20Sopenharmony_ci qed_params.dp_module = qedi_qed_debug; 25698c2ecf20Sopenharmony_ci qed_params.dp_level = dp_level; 25708c2ecf20Sopenharmony_ci qed_params.is_vf = is_vf; 25718c2ecf20Sopenharmony_ci qedi->cdev = qedi_ops->common->probe(pdev, &qed_params); 25728c2ecf20Sopenharmony_ci if (!qedi->cdev) { 25738c2ecf20Sopenharmony_ci if (mode == QEDI_MODE_RECOVERY && retry) { 25748c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 25758c2ecf20Sopenharmony_ci "Retry %d initialize hardware\n", retry); 25768c2ecf20Sopenharmony_ci retry--; 25778c2ecf20Sopenharmony_ci goto retry_probe; 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci rc = -ENODEV; 25818c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n"); 25828c2ecf20Sopenharmony_ci goto free_host; 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci set_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags); 25868c2ecf20Sopenharmony_ci set_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags); 25878c2ecf20Sopenharmony_ci atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); 25908c2ecf20Sopenharmony_ci if (rc) 25918c2ecf20Sopenharmony_ci goto free_host; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 25948c2ecf20Sopenharmony_ci "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", 25958c2ecf20Sopenharmony_ci qedi->dev_info.common.num_hwfns, 25968c2ecf20Sopenharmony_ci qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci rc = qedi_set_iscsi_pf_param(qedi); 25998c2ecf20Sopenharmony_ci if (rc) { 26008c2ecf20Sopenharmony_ci rc = -ENOMEM; 26018c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 26028c2ecf20Sopenharmony_ci "Set iSCSI pf param fail\n"); 26038c2ecf20Sopenharmony_ci goto free_host; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci rc = qedi_prepare_fp(qedi); 26098c2ecf20Sopenharmony_ci if (rc) { 26108c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath.\n"); 26118c2ecf20Sopenharmony_ci goto free_pf_params; 26128c2ecf20Sopenharmony_ci } 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci /* Start the Slowpath-process */ 26158c2ecf20Sopenharmony_ci memset(&sp_params, 0, sizeof(struct qed_slowpath_params)); 26168c2ecf20Sopenharmony_ci sp_params.int_mode = QED_INT_MODE_MSIX; 26178c2ecf20Sopenharmony_ci sp_params.drv_major = QEDI_DRIVER_MAJOR_VER; 26188c2ecf20Sopenharmony_ci sp_params.drv_minor = QEDI_DRIVER_MINOR_VER; 26198c2ecf20Sopenharmony_ci sp_params.drv_rev = QEDI_DRIVER_REV_VER; 26208c2ecf20Sopenharmony_ci sp_params.drv_eng = QEDI_DRIVER_ENG_VER; 26218c2ecf20Sopenharmony_ci strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); 26228c2ecf20Sopenharmony_ci rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params); 26238c2ecf20Sopenharmony_ci if (rc) { 26248c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n"); 26258c2ecf20Sopenharmony_ci goto stop_hw; 26268c2ecf20Sopenharmony_ci } 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci /* update_pf_params needs to be called before and after slowpath 26298c2ecf20Sopenharmony_ci * start 26308c2ecf20Sopenharmony_ci */ 26318c2ecf20Sopenharmony_ci qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci rc = qedi_setup_int(qedi); 26348c2ecf20Sopenharmony_ci if (rc) 26358c2ecf20Sopenharmony_ci goto stop_iscsi_func; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci /* Learn information crucial for qedi to progress */ 26408c2ecf20Sopenharmony_ci rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); 26418c2ecf20Sopenharmony_ci if (rc) 26428c2ecf20Sopenharmony_ci goto stop_iscsi_func; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci /* Record BDQ producer doorbell addresses */ 26458c2ecf20Sopenharmony_ci qedi->bdq_primary_prod = qedi->dev_info.primary_dbq_rq_addr; 26468c2ecf20Sopenharmony_ci qedi->bdq_secondary_prod = qedi->dev_info.secondary_bdq_rq_addr; 26478c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 26488c2ecf20Sopenharmony_ci "BDQ primary_prod=%p secondary_prod=%p.\n", 26498c2ecf20Sopenharmony_ci qedi->bdq_primary_prod, 26508c2ecf20Sopenharmony_ci qedi->bdq_secondary_prod); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci /* 26538c2ecf20Sopenharmony_ci * We need to write the number of BDs in the BDQ we've preallocated so 26548c2ecf20Sopenharmony_ci * the f/w will do a prefetch and we'll get an unsolicited CQE when a 26558c2ecf20Sopenharmony_ci * packet arrives. 26568c2ecf20Sopenharmony_ci */ 26578c2ecf20Sopenharmony_ci qedi->bdq_prod_idx = QEDI_BDQ_NUM; 26588c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 26598c2ecf20Sopenharmony_ci "Writing %d to primary and secondary BDQ doorbell registers.\n", 26608c2ecf20Sopenharmony_ci qedi->bdq_prod_idx); 26618c2ecf20Sopenharmony_ci writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod); 26628c2ecf20Sopenharmony_ci readw(qedi->bdq_primary_prod); 26638c2ecf20Sopenharmony_ci writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod); 26648c2ecf20Sopenharmony_ci readw(qedi->bdq_secondary_prod); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac); 26678c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n", 26688c2ecf20Sopenharmony_ci qedi->mac); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci snprintf(host_buf, sizeof(host_buf), "host_%d", qedi->shost->host_no); 26718c2ecf20Sopenharmony_ci qedi_ops->common->set_name(qedi->cdev, host_buf); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 26768c2ecf20Sopenharmony_ci params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN; 26778c2ecf20Sopenharmony_ci qedi->ll2_mtu = DEF_PATH_MTU; 26788c2ecf20Sopenharmony_ci params.drop_ttl0_packets = 0; 26798c2ecf20Sopenharmony_ci params.rx_vlan_stripping = 1; 26808c2ecf20Sopenharmony_ci ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci if (mode != QEDI_MODE_RECOVERY) { 26838c2ecf20Sopenharmony_ci /* set up rx path */ 26848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qedi->ll2_skb_list); 26858c2ecf20Sopenharmony_ci spin_lock_init(&qedi->ll2_lock); 26868c2ecf20Sopenharmony_ci /* start qedi context */ 26878c2ecf20Sopenharmony_ci spin_lock_init(&qedi->hba_lock); 26888c2ecf20Sopenharmony_ci spin_lock_init(&qedi->task_idx_lock); 26898c2ecf20Sopenharmony_ci mutex_init(&qedi->stats_lock); 26908c2ecf20Sopenharmony_ci } 26918c2ecf20Sopenharmony_ci qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi); 26928c2ecf20Sopenharmony_ci qedi_ops->ll2->start(qedi->cdev, ¶ms); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci if (mode != QEDI_MODE_RECOVERY) { 26958c2ecf20Sopenharmony_ci qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread, 26968c2ecf20Sopenharmony_ci (void *)qedi, 26978c2ecf20Sopenharmony_ci "qedi_ll2_thread"); 26988c2ecf20Sopenharmony_ci } 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci rc = qedi_ops->start(qedi->cdev, &qedi->tasks, 27018c2ecf20Sopenharmony_ci qedi, qedi_iscsi_event_cb); 27028c2ecf20Sopenharmony_ci if (rc) { 27038c2ecf20Sopenharmony_ci rc = -ENODEV; 27048c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, "Cannot start iSCSI function\n"); 27058c2ecf20Sopenharmony_ci goto stop_slowpath; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci task_start = qedi_get_task_mem(&qedi->tasks, 0); 27098c2ecf20Sopenharmony_ci task_end = qedi_get_task_mem(&qedi->tasks, MAX_TID_BLOCKS_ISCSI - 1); 27108c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 27118c2ecf20Sopenharmony_ci "Task context start=%p, end=%p block_size=%u.\n", 27128c2ecf20Sopenharmony_ci task_start, task_end, qedi->tasks.size); 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 27158c2ecf20Sopenharmony_ci link_params.link_up = true; 27168c2ecf20Sopenharmony_ci rc = qedi_ops->common->set_link(qedi->cdev, &link_params); 27178c2ecf20Sopenharmony_ci if (rc) { 27188c2ecf20Sopenharmony_ci QEDI_WARN(&qedi->dbg_ctx, "Link set up failed.\n"); 27198c2ecf20Sopenharmony_ci atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 27238c2ecf20Sopenharmony_ci qedi_dbg_host_init(&qedi->dbg_ctx, qedi_debugfs_ops, 27248c2ecf20Sopenharmony_ci qedi_dbg_fops); 27258c2ecf20Sopenharmony_ci#endif 27268c2ecf20Sopenharmony_ci QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 27278c2ecf20Sopenharmony_ci "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n", 27288c2ecf20Sopenharmony_ci QEDI_MODULE_VERSION, FW_MAJOR_VERSION, FW_MINOR_VERSION, 27298c2ecf20Sopenharmony_ci FW_REVISION_VERSION, FW_ENGINEERING_VERSION); 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci if (mode == QEDI_MODE_NORMAL) { 27328c2ecf20Sopenharmony_ci if (iscsi_host_add(qedi->shost, &pdev->dev)) { 27338c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27348c2ecf20Sopenharmony_ci "Could not add iscsi host\n"); 27358c2ecf20Sopenharmony_ci rc = -ENOMEM; 27368c2ecf20Sopenharmony_ci goto remove_host; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci /* Allocate uio buffers */ 27408c2ecf20Sopenharmony_ci rc = qedi_alloc_uio_rings(qedi); 27418c2ecf20Sopenharmony_ci if (rc) { 27428c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27438c2ecf20Sopenharmony_ci "UIO alloc ring failed err=%d\n", rc); 27448c2ecf20Sopenharmony_ci goto remove_host; 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci rc = qedi_init_uio(qedi); 27488c2ecf20Sopenharmony_ci if (rc) { 27498c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27508c2ecf20Sopenharmony_ci "UIO init failed, err=%d\n", rc); 27518c2ecf20Sopenharmony_ci goto free_uio; 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci /* host the array on iscsi_conn */ 27558c2ecf20Sopenharmony_ci rc = qedi_setup_cid_que(qedi); 27568c2ecf20Sopenharmony_ci if (rc) { 27578c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27588c2ecf20Sopenharmony_ci "Could not setup cid que\n"); 27598c2ecf20Sopenharmony_ci goto free_uio; 27608c2ecf20Sopenharmony_ci } 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci rc = qedi_cm_alloc_mem(qedi); 27638c2ecf20Sopenharmony_ci if (rc) { 27648c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27658c2ecf20Sopenharmony_ci "Could not alloc cm memory\n"); 27668c2ecf20Sopenharmony_ci goto free_cid_que; 27678c2ecf20Sopenharmony_ci } 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci rc = qedi_alloc_itt(qedi); 27708c2ecf20Sopenharmony_ci if (rc) { 27718c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27728c2ecf20Sopenharmony_ci "Could not alloc itt memory\n"); 27738c2ecf20Sopenharmony_ci goto free_cid_que; 27748c2ecf20Sopenharmony_ci } 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci sprintf(host_buf, "host_%d", qedi->shost->host_no); 27778c2ecf20Sopenharmony_ci qedi->tmf_thread = create_singlethread_workqueue(host_buf); 27788c2ecf20Sopenharmony_ci if (!qedi->tmf_thread) { 27798c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27808c2ecf20Sopenharmony_ci "Unable to start tmf thread!\n"); 27818c2ecf20Sopenharmony_ci rc = -ENODEV; 27828c2ecf20Sopenharmony_ci goto free_cid_que; 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no); 27868c2ecf20Sopenharmony_ci qedi->offload_thread = create_workqueue(host_buf); 27878c2ecf20Sopenharmony_ci if (!qedi->offload_thread) { 27888c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 27898c2ecf20Sopenharmony_ci "Unable to start offload thread!\n"); 27908c2ecf20Sopenharmony_ci rc = -ENODEV; 27918c2ecf20Sopenharmony_ci goto free_tmf_thread; 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler); 27958c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&qedi->board_disable_work, 27968c2ecf20Sopenharmony_ci qedi_board_disable_work); 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci /* F/w needs 1st task context memory entry for performance */ 27998c2ecf20Sopenharmony_ci set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map); 28008c2ecf20Sopenharmony_ci atomic_set(&qedi->num_offloads, 0); 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci if (qedi_setup_boot_info(qedi)) 28038c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 28048c2ecf20Sopenharmony_ci "No iSCSI boot target configured\n"); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci rc = qedi_ops->common->update_drv_state(qedi->cdev, true); 28078c2ecf20Sopenharmony_ci if (rc) 28088c2ecf20Sopenharmony_ci QEDI_ERR(&qedi->dbg_ctx, 28098c2ecf20Sopenharmony_ci "Failed to send drv state to MFW\n"); 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci } 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci return 0; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_cifree_tmf_thread: 28168c2ecf20Sopenharmony_ci destroy_workqueue(qedi->tmf_thread); 28178c2ecf20Sopenharmony_cifree_cid_que: 28188c2ecf20Sopenharmony_ci qedi_release_cid_que(qedi); 28198c2ecf20Sopenharmony_cifree_uio: 28208c2ecf20Sopenharmony_ci qedi_free_uio(qedi->udev); 28218c2ecf20Sopenharmony_ciremove_host: 28228c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 28238c2ecf20Sopenharmony_ci qedi_dbg_host_exit(&qedi->dbg_ctx); 28248c2ecf20Sopenharmony_ci#endif 28258c2ecf20Sopenharmony_ci iscsi_host_remove(qedi->shost); 28268c2ecf20Sopenharmony_cistop_iscsi_func: 28278c2ecf20Sopenharmony_ci qedi_ops->stop(qedi->cdev); 28288c2ecf20Sopenharmony_cistop_slowpath: 28298c2ecf20Sopenharmony_ci qedi_ops->common->slowpath_stop(qedi->cdev); 28308c2ecf20Sopenharmony_cistop_hw: 28318c2ecf20Sopenharmony_ci qedi_ops->common->remove(qedi->cdev); 28328c2ecf20Sopenharmony_cifree_pf_params: 28338c2ecf20Sopenharmony_ci qedi_free_iscsi_pf_param(qedi); 28348c2ecf20Sopenharmony_cifree_host: 28358c2ecf20Sopenharmony_ci iscsi_host_free(qedi->shost); 28368c2ecf20Sopenharmony_ciexit_probe: 28378c2ecf20Sopenharmony_ci return rc; 28388c2ecf20Sopenharmony_ci} 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_cistatic void qedi_mark_conn_recovery(struct iscsi_cls_session *cls_session) 28418c2ecf20Sopenharmony_ci{ 28428c2ecf20Sopenharmony_ci struct iscsi_session *session = cls_session->dd_data; 28438c2ecf20Sopenharmony_ci struct iscsi_conn *conn = session->leadconn; 28448c2ecf20Sopenharmony_ci struct qedi_conn *qedi_conn = conn->dd_data; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci iscsi_conn_failure(qedi_conn->cls_conn->dd_data, ISCSI_ERR_CONN_FAILED); 28478c2ecf20Sopenharmony_ci} 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_cistatic void qedi_recovery_handler(struct work_struct *work) 28508c2ecf20Sopenharmony_ci{ 28518c2ecf20Sopenharmony_ci struct qedi_ctx *qedi = 28528c2ecf20Sopenharmony_ci container_of(work, struct qedi_ctx, recovery_work.work); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci iscsi_host_for_each_session(qedi->shost, qedi_mark_conn_recovery); 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci /* Call common_ops->recovery_prolog to allow the MFW to quiesce 28578c2ecf20Sopenharmony_ci * any PCI transactions. 28588c2ecf20Sopenharmony_ci */ 28598c2ecf20Sopenharmony_ci qedi_ops->common->recovery_prolog(qedi->cdev); 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci __qedi_remove(qedi->pdev, QEDI_MODE_RECOVERY); 28628c2ecf20Sopenharmony_ci __qedi_probe(qedi->pdev, QEDI_MODE_RECOVERY); 28638c2ecf20Sopenharmony_ci clear_bit(QEDI_IN_RECOVERY, &qedi->flags); 28648c2ecf20Sopenharmony_ci} 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_cistatic int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 28678c2ecf20Sopenharmony_ci{ 28688c2ecf20Sopenharmony_ci return __qedi_probe(pdev, QEDI_MODE_NORMAL); 28698c2ecf20Sopenharmony_ci} 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_cistatic void qedi_remove(struct pci_dev *pdev) 28728c2ecf20Sopenharmony_ci{ 28738c2ecf20Sopenharmony_ci __qedi_remove(pdev, QEDI_MODE_NORMAL); 28748c2ecf20Sopenharmony_ci} 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_cistatic struct pci_device_id qedi_pci_tbl[] = { 28778c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x165E) }, 28788c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x8084) }, 28798c2ecf20Sopenharmony_ci { 0 }, 28808c2ecf20Sopenharmony_ci}; 28818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qedi_pci_tbl); 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_cistatic enum cpuhp_state qedi_cpuhp_state; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_cistatic struct pci_error_handlers qedi_err_handler = { 28868c2ecf20Sopenharmony_ci .error_detected = qedi_io_error_detected, 28878c2ecf20Sopenharmony_ci}; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_cistatic struct pci_driver qedi_pci_driver = { 28908c2ecf20Sopenharmony_ci .name = QEDI_MODULE_NAME, 28918c2ecf20Sopenharmony_ci .id_table = qedi_pci_tbl, 28928c2ecf20Sopenharmony_ci .probe = qedi_probe, 28938c2ecf20Sopenharmony_ci .remove = qedi_remove, 28948c2ecf20Sopenharmony_ci .shutdown = qedi_shutdown, 28958c2ecf20Sopenharmony_ci .err_handler = &qedi_err_handler, 28968c2ecf20Sopenharmony_ci .suspend = qedi_suspend, 28978c2ecf20Sopenharmony_ci}; 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_cistatic int __init qedi_init(void) 29008c2ecf20Sopenharmony_ci{ 29018c2ecf20Sopenharmony_ci struct qedi_percpu_s *p; 29028c2ecf20Sopenharmony_ci int cpu, rc = 0; 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci qedi_ops = qed_get_iscsi_ops(); 29058c2ecf20Sopenharmony_ci if (!qedi_ops) { 29068c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "Failed to get qed iSCSI operations\n"); 29078c2ecf20Sopenharmony_ci return -EINVAL; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 29118c2ecf20Sopenharmony_ci qedi_dbg_init("qedi"); 29128c2ecf20Sopenharmony_ci#endif 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci qedi_scsi_transport = iscsi_register_transport(&qedi_iscsi_transport); 29158c2ecf20Sopenharmony_ci if (!qedi_scsi_transport) { 29168c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "Could not register qedi transport"); 29178c2ecf20Sopenharmony_ci rc = -ENOMEM; 29188c2ecf20Sopenharmony_ci goto exit_qedi_init_1; 29198c2ecf20Sopenharmony_ci } 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 29228c2ecf20Sopenharmony_ci p = &per_cpu(qedi_percpu, cpu); 29238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p->work_list); 29248c2ecf20Sopenharmony_ci spin_lock_init(&p->p_work_lock); 29258c2ecf20Sopenharmony_ci p->iothread = NULL; 29268c2ecf20Sopenharmony_ci } 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/qedi:online", 29298c2ecf20Sopenharmony_ci qedi_cpu_online, qedi_cpu_offline); 29308c2ecf20Sopenharmony_ci if (rc < 0) 29318c2ecf20Sopenharmony_ci goto exit_qedi_init_2; 29328c2ecf20Sopenharmony_ci qedi_cpuhp_state = rc; 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci rc = pci_register_driver(&qedi_pci_driver); 29358c2ecf20Sopenharmony_ci if (rc) { 29368c2ecf20Sopenharmony_ci QEDI_ERR(NULL, "Failed to register driver\n"); 29378c2ecf20Sopenharmony_ci goto exit_qedi_hp; 29388c2ecf20Sopenharmony_ci } 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci return 0; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ciexit_qedi_hp: 29438c2ecf20Sopenharmony_ci cpuhp_remove_state(qedi_cpuhp_state); 29448c2ecf20Sopenharmony_ciexit_qedi_init_2: 29458c2ecf20Sopenharmony_ci iscsi_unregister_transport(&qedi_iscsi_transport); 29468c2ecf20Sopenharmony_ciexit_qedi_init_1: 29478c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 29488c2ecf20Sopenharmony_ci qedi_dbg_exit(); 29498c2ecf20Sopenharmony_ci#endif 29508c2ecf20Sopenharmony_ci qed_put_iscsi_ops(); 29518c2ecf20Sopenharmony_ci return rc; 29528c2ecf20Sopenharmony_ci} 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_cistatic void __exit qedi_cleanup(void) 29558c2ecf20Sopenharmony_ci{ 29568c2ecf20Sopenharmony_ci pci_unregister_driver(&qedi_pci_driver); 29578c2ecf20Sopenharmony_ci cpuhp_remove_state(qedi_cpuhp_state); 29588c2ecf20Sopenharmony_ci iscsi_unregister_transport(&qedi_iscsi_transport); 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 29618c2ecf20Sopenharmony_ci qedi_dbg_exit(); 29628c2ecf20Sopenharmony_ci#endif 29638c2ecf20Sopenharmony_ci qed_put_iscsi_ops(); 29648c2ecf20Sopenharmony_ci} 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic FastLinQ 4xxxx iSCSI Module"); 29678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 29688c2ecf20Sopenharmony_ciMODULE_AUTHOR("QLogic Corporation"); 29698c2ecf20Sopenharmony_ciMODULE_VERSION(QEDI_MODULE_VERSION); 29708c2ecf20Sopenharmony_cimodule_init(qedi_init); 29718c2ecf20Sopenharmony_cimodule_exit(qedi_cleanup); 2972