13287e96aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ace7f46bSManish Rangankar /* 3ace7f46bSManish Rangankar * QLogic iSCSI Offload Driver 4ace7f46bSManish Rangankar * Copyright (c) 2016 Cavium Inc. 5ace7f46bSManish Rangankar */ 6ace7f46bSManish Rangankar 7ace7f46bSManish Rangankar #include <linux/module.h> 8ace7f46bSManish Rangankar #include <linux/pci.h> 9ace7f46bSManish Rangankar #include <linux/kernel.h> 10ace7f46bSManish Rangankar #include <linux/if_arp.h> 11ace7f46bSManish Rangankar #include <scsi/iscsi_if.h> 12ace7f46bSManish Rangankar #include <linux/inet.h> 13ace7f46bSManish Rangankar #include <net/arp.h> 14ace7f46bSManish Rangankar #include <linux/list.h> 15ace7f46bSManish Rangankar #include <linux/kthread.h> 16ace7f46bSManish Rangankar #include <linux/mm.h> 17ace7f46bSManish Rangankar #include <linux/if_vlan.h> 18ace7f46bSManish Rangankar #include <linux/cpu.h> 19c57ec8fbSNilesh Javali #include <linux/iscsi_boot_sysfs.h> 20ace7f46bSManish Rangankar 21ace7f46bSManish Rangankar #include <scsi/scsi_cmnd.h> 22ace7f46bSManish Rangankar #include <scsi/scsi_device.h> 23ace7f46bSManish Rangankar #include <scsi/scsi_eh.h> 24ace7f46bSManish Rangankar #include <scsi/scsi_host.h> 25ace7f46bSManish Rangankar #include <scsi/scsi.h> 26ace7f46bSManish Rangankar 27ace7f46bSManish Rangankar #include "qedi.h" 28ace7f46bSManish Rangankar #include "qedi_gbl.h" 29ace7f46bSManish Rangankar #include "qedi_iscsi.h" 30ace7f46bSManish Rangankar 31c6bfa707SManish Rangankar static uint qedi_qed_debug; 32c6bfa707SManish Rangankar module_param(qedi_qed_debug, uint, 0644); 33c6bfa707SManish Rangankar MODULE_PARM_DESC(qedi_qed_debug, " QED debug level 0 (default)"); 34c6bfa707SManish Rangankar 35ace7f46bSManish Rangankar static uint qedi_fw_debug; 36ace7f46bSManish Rangankar module_param(qedi_fw_debug, uint, 0644); 37ace7f46bSManish Rangankar MODULE_PARM_DESC(qedi_fw_debug, " Firmware debug level 0(default) to 3"); 38ace7f46bSManish Rangankar 39ace7f46bSManish Rangankar uint qedi_dbg_log = QEDI_LOG_WARN | QEDI_LOG_SCSI_TM; 40ace7f46bSManish Rangankar module_param(qedi_dbg_log, uint, 0644); 41ace7f46bSManish Rangankar MODULE_PARM_DESC(qedi_dbg_log, " Default debug level"); 42ace7f46bSManish Rangankar 43ace7f46bSManish Rangankar uint qedi_io_tracing; 44ace7f46bSManish Rangankar module_param(qedi_io_tracing, uint, 0644); 45ace7f46bSManish Rangankar MODULE_PARM_DESC(qedi_io_tracing, 46ace7f46bSManish Rangankar " Enable logging of SCSI requests/completions into trace buffer. (default off)."); 47ace7f46bSManish Rangankar 4844578eceSJason Yan static uint qedi_ll2_buf_size = 0x400; 49dcceeeb7SNilesh Javali module_param(qedi_ll2_buf_size, uint, 0644); 50dcceeeb7SNilesh Javali MODULE_PARM_DESC(qedi_ll2_buf_size, 51dcceeeb7SNilesh Javali "parameter to set ping packet size, default - 0x400, Jumbo packets - 0x2400."); 52dcceeeb7SNilesh Javali 53f4ba4e55SManish Rangankar static uint qedi_flags_override; 54f4ba4e55SManish Rangankar module_param(qedi_flags_override, uint, 0644); 55f4ba4e55SManish Rangankar MODULE_PARM_DESC(qedi_flags_override, "Disable/Enable MFW error flags bits action."); 56f4ba4e55SManish Rangankar 57ace7f46bSManish Rangankar const struct qed_iscsi_ops *qedi_ops; 58ace7f46bSManish Rangankar static struct scsi_transport_template *qedi_scsi_transport; 59ace7f46bSManish Rangankar static struct pci_driver qedi_pci_driver; 60ace7f46bSManish Rangankar static DEFINE_PER_CPU(struct qedi_percpu_s, qedi_percpu); 61ace7f46bSManish Rangankar static LIST_HEAD(qedi_udev_list); 62ace7f46bSManish Rangankar /* Static function declaration */ 63ace7f46bSManish Rangankar static int qedi_alloc_global_queues(struct qedi_ctx *qedi); 64ace7f46bSManish Rangankar static void qedi_free_global_queues(struct qedi_ctx *qedi); 65ace7f46bSManish Rangankar static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid); 66ace7f46bSManish Rangankar static void qedi_reset_uio_rings(struct qedi_uio_dev *udev); 67ace7f46bSManish Rangankar static void qedi_ll2_free_skbs(struct qedi_ctx *qedi); 68534bbdf8SManish Rangankar static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi); 694b1068f5SManish Rangankar static void qedi_recovery_handler(struct work_struct *work); 70f4ba4e55SManish Rangankar static void qedi_schedule_hw_err_handler(void *dev, 71f4ba4e55SManish Rangankar enum qed_hw_err_type err_type); 72ace7f46bSManish Rangankar 73ace7f46bSManish Rangankar static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) 74ace7f46bSManish Rangankar { 75ace7f46bSManish Rangankar struct qedi_ctx *qedi; 76ace7f46bSManish Rangankar struct qedi_endpoint *qedi_ep; 77da090917STomer Tayar struct iscsi_eqe_data *data; 78ace7f46bSManish Rangankar int rval = 0; 79ace7f46bSManish Rangankar 80ace7f46bSManish Rangankar if (!context || !fw_handle) { 81ace7f46bSManish Rangankar QEDI_ERR(NULL, "Recv event with ctx NULL\n"); 82ace7f46bSManish Rangankar return -EINVAL; 83ace7f46bSManish Rangankar } 84ace7f46bSManish Rangankar 85ace7f46bSManish Rangankar qedi = (struct qedi_ctx *)context; 86ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 87ace7f46bSManish Rangankar "Recv Event %d fw_handle %p\n", fw_event_code, fw_handle); 88ace7f46bSManish Rangankar 89da090917STomer Tayar data = (struct iscsi_eqe_data *)fw_handle; 90ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 91da090917STomer Tayar "icid=0x%x conn_id=0x%x err-code=0x%x error-pdu-opcode-reserved=0x%x\n", 92da090917STomer Tayar data->icid, data->conn_id, data->error_code, 93da090917STomer Tayar data->error_pdu_opcode_reserved); 94ace7f46bSManish Rangankar 95da090917STomer Tayar qedi_ep = qedi->ep_tbl[data->icid]; 96ace7f46bSManish Rangankar 97ace7f46bSManish Rangankar if (!qedi_ep) { 98ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 99ace7f46bSManish Rangankar "Cannot process event, ep already disconnected, cid=0x%x\n", 100da090917STomer Tayar data->icid); 101ace7f46bSManish Rangankar WARN_ON(1); 102ace7f46bSManish Rangankar return -ENODEV; 103ace7f46bSManish Rangankar } 104ace7f46bSManish Rangankar 105ace7f46bSManish Rangankar switch (fw_event_code) { 106ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE: 107ace7f46bSManish Rangankar if (qedi_ep->state == EP_STATE_OFLDCONN_START) 108ace7f46bSManish Rangankar qedi_ep->state = EP_STATE_OFLDCONN_COMPL; 109ace7f46bSManish Rangankar 110ace7f46bSManish Rangankar wake_up_interruptible(&qedi_ep->tcp_ofld_wait); 111ace7f46bSManish Rangankar break; 112ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE: 113ace7f46bSManish Rangankar qedi_ep->state = EP_STATE_DISCONN_COMPL; 114ace7f46bSManish Rangankar wake_up_interruptible(&qedi_ep->tcp_ofld_wait); 115ace7f46bSManish Rangankar break; 116ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR: 117ace7f46bSManish Rangankar qedi_process_iscsi_error(qedi_ep, data); 118ace7f46bSManish Rangankar break; 119ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD: 120ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD: 121ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME: 122ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT: 123ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT: 124ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2: 125ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_TCP_CONN_ERROR: 126ace7f46bSManish Rangankar qedi_process_tcp_error(qedi_ep, data); 127ace7f46bSManish Rangankar break; 128ace7f46bSManish Rangankar default: 129ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Recv Unknown Event %u\n", 130ace7f46bSManish Rangankar fw_event_code); 131ace7f46bSManish Rangankar } 132ace7f46bSManish Rangankar 133ace7f46bSManish Rangankar return rval; 134ace7f46bSManish Rangankar } 135ace7f46bSManish Rangankar 136ace7f46bSManish Rangankar static int qedi_uio_open(struct uio_info *uinfo, struct inode *inode) 137ace7f46bSManish Rangankar { 138ace7f46bSManish Rangankar struct qedi_uio_dev *udev = uinfo->priv; 139ace7f46bSManish Rangankar struct qedi_ctx *qedi = udev->qedi; 140ace7f46bSManish Rangankar 141ace7f46bSManish Rangankar if (!capable(CAP_NET_ADMIN)) 142ace7f46bSManish Rangankar return -EPERM; 143ace7f46bSManish Rangankar 144ace7f46bSManish Rangankar if (udev->uio_dev != -1) 145ace7f46bSManish Rangankar return -EBUSY; 146ace7f46bSManish Rangankar 147ace7f46bSManish Rangankar rtnl_lock(); 148ace7f46bSManish Rangankar udev->uio_dev = iminor(inode); 149ace7f46bSManish Rangankar qedi_reset_uio_rings(udev); 150ace7f46bSManish Rangankar set_bit(UIO_DEV_OPENED, &qedi->flags); 151ace7f46bSManish Rangankar rtnl_unlock(); 152ace7f46bSManish Rangankar 153ace7f46bSManish Rangankar return 0; 154ace7f46bSManish Rangankar } 155ace7f46bSManish Rangankar 156ace7f46bSManish Rangankar static int qedi_uio_close(struct uio_info *uinfo, struct inode *inode) 157ace7f46bSManish Rangankar { 158ace7f46bSManish Rangankar struct qedi_uio_dev *udev = uinfo->priv; 159ace7f46bSManish Rangankar struct qedi_ctx *qedi = udev->qedi; 160ace7f46bSManish Rangankar 161ace7f46bSManish Rangankar udev->uio_dev = -1; 162ace7f46bSManish Rangankar clear_bit(UIO_DEV_OPENED, &qedi->flags); 163ace7f46bSManish Rangankar qedi_ll2_free_skbs(qedi); 164ace7f46bSManish Rangankar return 0; 165ace7f46bSManish Rangankar } 166ace7f46bSManish Rangankar 167ace7f46bSManish Rangankar static void __qedi_free_uio_rings(struct qedi_uio_dev *udev) 168ace7f46bSManish Rangankar { 1695e901d0bSArun Easi if (udev->uctrl) { 1705e901d0bSArun Easi free_page((unsigned long)udev->uctrl); 1715e901d0bSArun Easi udev->uctrl = NULL; 1725e901d0bSArun Easi } 1735e901d0bSArun Easi 174ace7f46bSManish Rangankar if (udev->ll2_ring) { 175ace7f46bSManish Rangankar free_page((unsigned long)udev->ll2_ring); 176ace7f46bSManish Rangankar udev->ll2_ring = NULL; 177ace7f46bSManish Rangankar } 178ace7f46bSManish Rangankar 179ace7f46bSManish Rangankar if (udev->ll2_buf) { 180ace7f46bSManish Rangankar free_pages((unsigned long)udev->ll2_buf, 2); 181ace7f46bSManish Rangankar udev->ll2_buf = NULL; 182ace7f46bSManish Rangankar } 183ace7f46bSManish Rangankar } 184ace7f46bSManish Rangankar 185ace7f46bSManish Rangankar static void __qedi_free_uio(struct qedi_uio_dev *udev) 186ace7f46bSManish Rangankar { 187ace7f46bSManish Rangankar uio_unregister_device(&udev->qedi_uinfo); 188ace7f46bSManish Rangankar 189ace7f46bSManish Rangankar __qedi_free_uio_rings(udev); 190ace7f46bSManish Rangankar 191ace7f46bSManish Rangankar pci_dev_put(udev->pdev); 192ace7f46bSManish Rangankar kfree(udev); 193ace7f46bSManish Rangankar } 194ace7f46bSManish Rangankar 195ace7f46bSManish Rangankar static void qedi_free_uio(struct qedi_uio_dev *udev) 196ace7f46bSManish Rangankar { 197ace7f46bSManish Rangankar if (!udev) 198ace7f46bSManish Rangankar return; 199ace7f46bSManish Rangankar 200ace7f46bSManish Rangankar list_del_init(&udev->list); 201ace7f46bSManish Rangankar __qedi_free_uio(udev); 202ace7f46bSManish Rangankar } 203ace7f46bSManish Rangankar 204ace7f46bSManish Rangankar static void qedi_reset_uio_rings(struct qedi_uio_dev *udev) 205ace7f46bSManish Rangankar { 206ace7f46bSManish Rangankar struct qedi_ctx *qedi = NULL; 207ace7f46bSManish Rangankar struct qedi_uio_ctrl *uctrl = NULL; 208ace7f46bSManish Rangankar 209ace7f46bSManish Rangankar qedi = udev->qedi; 210ace7f46bSManish Rangankar uctrl = udev->uctrl; 211ace7f46bSManish Rangankar 212ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 213ace7f46bSManish Rangankar uctrl->host_rx_cons = 0; 214ace7f46bSManish Rangankar uctrl->hw_rx_prod = 0; 215ace7f46bSManish Rangankar uctrl->hw_rx_bd_prod = 0; 216ace7f46bSManish Rangankar uctrl->host_rx_bd_cons = 0; 217ace7f46bSManish Rangankar 218ace7f46bSManish Rangankar memset(udev->ll2_ring, 0, udev->ll2_ring_size); 219ace7f46bSManish Rangankar memset(udev->ll2_buf, 0, udev->ll2_buf_size); 220ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 221ace7f46bSManish Rangankar } 222ace7f46bSManish Rangankar 223ace7f46bSManish Rangankar static int __qedi_alloc_uio_rings(struct qedi_uio_dev *udev) 224ace7f46bSManish Rangankar { 225ace7f46bSManish Rangankar int rc = 0; 226ace7f46bSManish Rangankar 227ace7f46bSManish Rangankar if (udev->ll2_ring || udev->ll2_buf) 228ace7f46bSManish Rangankar return rc; 229ace7f46bSManish Rangankar 2305e901d0bSArun Easi /* Memory for control area. */ 2315e901d0bSArun Easi udev->uctrl = (void *)get_zeroed_page(GFP_KERNEL); 2325e901d0bSArun Easi if (!udev->uctrl) 2335e901d0bSArun Easi return -ENOMEM; 2345e901d0bSArun Easi 235ace7f46bSManish Rangankar /* Allocating memory for LL2 ring */ 236ace7f46bSManish Rangankar udev->ll2_ring_size = QEDI_PAGE_SIZE; 237ace7f46bSManish Rangankar udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP); 238ace7f46bSManish Rangankar if (!udev->ll2_ring) { 239ace7f46bSManish Rangankar rc = -ENOMEM; 240ace7f46bSManish Rangankar goto exit_alloc_ring; 241ace7f46bSManish Rangankar } 242ace7f46bSManish Rangankar 243ace7f46bSManish Rangankar /* Allocating memory for Tx/Rx pkt buffer */ 244dcceeeb7SNilesh Javali udev->ll2_buf_size = TX_RX_RING * qedi_ll2_buf_size; 245ace7f46bSManish Rangankar udev->ll2_buf_size = QEDI_PAGE_ALIGN(udev->ll2_buf_size); 246ace7f46bSManish Rangankar udev->ll2_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP | 247ace7f46bSManish Rangankar __GFP_ZERO, 2); 248ace7f46bSManish Rangankar if (!udev->ll2_buf) { 249ace7f46bSManish Rangankar rc = -ENOMEM; 250ace7f46bSManish Rangankar goto exit_alloc_buf; 251ace7f46bSManish Rangankar } 252ace7f46bSManish Rangankar return rc; 253ace7f46bSManish Rangankar 254ace7f46bSManish Rangankar exit_alloc_buf: 255ace7f46bSManish Rangankar free_page((unsigned long)udev->ll2_ring); 256ace7f46bSManish Rangankar udev->ll2_ring = NULL; 257ace7f46bSManish Rangankar exit_alloc_ring: 258ace7f46bSManish Rangankar return rc; 259ace7f46bSManish Rangankar } 260ace7f46bSManish Rangankar 261ace7f46bSManish Rangankar static int qedi_alloc_uio_rings(struct qedi_ctx *qedi) 262ace7f46bSManish Rangankar { 263ace7f46bSManish Rangankar struct qedi_uio_dev *udev = NULL; 264ace7f46bSManish Rangankar int rc = 0; 265ace7f46bSManish Rangankar 266ace7f46bSManish Rangankar list_for_each_entry(udev, &qedi_udev_list, list) { 267ace7f46bSManish Rangankar if (udev->pdev == qedi->pdev) { 268ace7f46bSManish Rangankar udev->qedi = qedi; 269ace7f46bSManish Rangankar if (__qedi_alloc_uio_rings(udev)) { 270ace7f46bSManish Rangankar udev->qedi = NULL; 271ace7f46bSManish Rangankar return -ENOMEM; 272ace7f46bSManish Rangankar } 273ace7f46bSManish Rangankar qedi->udev = udev; 274ace7f46bSManish Rangankar return 0; 275ace7f46bSManish Rangankar } 276ace7f46bSManish Rangankar } 277ace7f46bSManish Rangankar 278ace7f46bSManish Rangankar udev = kzalloc(sizeof(*udev), GFP_KERNEL); 2798dc60252SColin Ian King if (!udev) 280ace7f46bSManish Rangankar goto err_udev; 281ace7f46bSManish Rangankar 282ace7f46bSManish Rangankar udev->uio_dev = -1; 283ace7f46bSManish Rangankar 284ace7f46bSManish Rangankar udev->qedi = qedi; 285ace7f46bSManish Rangankar udev->pdev = qedi->pdev; 286ace7f46bSManish Rangankar 287ace7f46bSManish Rangankar rc = __qedi_alloc_uio_rings(udev); 288ace7f46bSManish Rangankar if (rc) 2895e901d0bSArun Easi goto err_uctrl; 290ace7f46bSManish Rangankar 291ace7f46bSManish Rangankar list_add(&udev->list, &qedi_udev_list); 292ace7f46bSManish Rangankar 293ace7f46bSManish Rangankar pci_dev_get(udev->pdev); 294ace7f46bSManish Rangankar qedi->udev = udev; 295ace7f46bSManish Rangankar 296ace7f46bSManish Rangankar udev->tx_pkt = udev->ll2_buf; 297dcceeeb7SNilesh Javali udev->rx_pkt = udev->ll2_buf + qedi_ll2_buf_size; 298ace7f46bSManish Rangankar return 0; 299ace7f46bSManish Rangankar 300ace7f46bSManish Rangankar err_uctrl: 301ace7f46bSManish Rangankar kfree(udev); 302ace7f46bSManish Rangankar err_udev: 303ace7f46bSManish Rangankar return -ENOMEM; 304ace7f46bSManish Rangankar } 305ace7f46bSManish Rangankar 306ace7f46bSManish Rangankar static int qedi_init_uio(struct qedi_ctx *qedi) 307ace7f46bSManish Rangankar { 308ace7f46bSManish Rangankar struct qedi_uio_dev *udev = qedi->udev; 309ace7f46bSManish Rangankar struct uio_info *uinfo; 310ace7f46bSManish Rangankar int ret = 0; 311ace7f46bSManish Rangankar 312ace7f46bSManish Rangankar if (!udev) 313ace7f46bSManish Rangankar return -ENOMEM; 314ace7f46bSManish Rangankar 315ace7f46bSManish Rangankar uinfo = &udev->qedi_uinfo; 316ace7f46bSManish Rangankar 317ace7f46bSManish Rangankar uinfo->mem[0].addr = (unsigned long)udev->uctrl; 318ace7f46bSManish Rangankar uinfo->mem[0].size = sizeof(struct qedi_uio_ctrl); 319ace7f46bSManish Rangankar uinfo->mem[0].memtype = UIO_MEM_LOGICAL; 320ace7f46bSManish Rangankar 321ace7f46bSManish Rangankar uinfo->mem[1].addr = (unsigned long)udev->ll2_ring; 322ace7f46bSManish Rangankar uinfo->mem[1].size = udev->ll2_ring_size; 323ace7f46bSManish Rangankar uinfo->mem[1].memtype = UIO_MEM_LOGICAL; 324ace7f46bSManish Rangankar 325ace7f46bSManish Rangankar uinfo->mem[2].addr = (unsigned long)udev->ll2_buf; 326ace7f46bSManish Rangankar uinfo->mem[2].size = udev->ll2_buf_size; 327ace7f46bSManish Rangankar uinfo->mem[2].memtype = UIO_MEM_LOGICAL; 328ace7f46bSManish Rangankar 329ace7f46bSManish Rangankar uinfo->name = "qedi_uio"; 330ace7f46bSManish Rangankar uinfo->version = QEDI_MODULE_VERSION; 331ace7f46bSManish Rangankar uinfo->irq = UIO_IRQ_CUSTOM; 332ace7f46bSManish Rangankar 333ace7f46bSManish Rangankar uinfo->open = qedi_uio_open; 334ace7f46bSManish Rangankar uinfo->release = qedi_uio_close; 335ace7f46bSManish Rangankar 336ace7f46bSManish Rangankar if (udev->uio_dev == -1) { 337ace7f46bSManish Rangankar if (!uinfo->priv) { 338ace7f46bSManish Rangankar uinfo->priv = udev; 339ace7f46bSManish Rangankar 340ace7f46bSManish Rangankar ret = uio_register_device(&udev->pdev->dev, uinfo); 341ace7f46bSManish Rangankar if (ret) { 342ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 343ace7f46bSManish Rangankar "UIO registration failed\n"); 344ace7f46bSManish Rangankar } 345ace7f46bSManish Rangankar } 346ace7f46bSManish Rangankar } 347ace7f46bSManish Rangankar 348ace7f46bSManish Rangankar return ret; 349ace7f46bSManish Rangankar } 350ace7f46bSManish Rangankar 351ace7f46bSManish Rangankar static int qedi_alloc_and_init_sb(struct qedi_ctx *qedi, 352ace7f46bSManish Rangankar struct qed_sb_info *sb_info, u16 sb_id) 353ace7f46bSManish Rangankar { 35421dd79e8STomer Tayar struct status_block_e4 *sb_virt; 355ace7f46bSManish Rangankar dma_addr_t sb_phys; 356ace7f46bSManish Rangankar int ret; 357ace7f46bSManish Rangankar 358ace7f46bSManish Rangankar sb_virt = dma_alloc_coherent(&qedi->pdev->dev, 35921dd79e8STomer Tayar sizeof(struct status_block_e4), &sb_phys, 360ace7f46bSManish Rangankar GFP_KERNEL); 361ace7f46bSManish Rangankar if (!sb_virt) { 362ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 363ace7f46bSManish Rangankar "Status block allocation failed for id = %d.\n", 364ace7f46bSManish Rangankar sb_id); 365ace7f46bSManish Rangankar return -ENOMEM; 366ace7f46bSManish Rangankar } 367ace7f46bSManish Rangankar 368ace7f46bSManish Rangankar ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys, 369ace7f46bSManish Rangankar sb_id, QED_SB_TYPE_STORAGE); 370ace7f46bSManish Rangankar if (ret) { 371ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 372ace7f46bSManish Rangankar "Status block initialization failed for id = %d.\n", 373ace7f46bSManish Rangankar sb_id); 374ace7f46bSManish Rangankar return ret; 375ace7f46bSManish Rangankar } 376ace7f46bSManish Rangankar 377ace7f46bSManish Rangankar return 0; 378ace7f46bSManish Rangankar } 379ace7f46bSManish Rangankar 380ace7f46bSManish Rangankar static void qedi_free_sb(struct qedi_ctx *qedi) 381ace7f46bSManish Rangankar { 382ace7f46bSManish Rangankar struct qed_sb_info *sb_info; 383ace7f46bSManish Rangankar int id; 384ace7f46bSManish Rangankar 385ace7f46bSManish Rangankar for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 386ace7f46bSManish Rangankar sb_info = &qedi->sb_array[id]; 387ace7f46bSManish Rangankar if (sb_info->sb_virt) 388ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, 389ace7f46bSManish Rangankar sizeof(*sb_info->sb_virt), 390ace7f46bSManish Rangankar (void *)sb_info->sb_virt, 391ace7f46bSManish Rangankar sb_info->sb_phys); 392ace7f46bSManish Rangankar } 393ace7f46bSManish Rangankar } 394ace7f46bSManish Rangankar 395ace7f46bSManish Rangankar static void qedi_free_fp(struct qedi_ctx *qedi) 396ace7f46bSManish Rangankar { 397ace7f46bSManish Rangankar kfree(qedi->fp_array); 398ace7f46bSManish Rangankar kfree(qedi->sb_array); 399ace7f46bSManish Rangankar } 400ace7f46bSManish Rangankar 401ace7f46bSManish Rangankar static void qedi_destroy_fp(struct qedi_ctx *qedi) 402ace7f46bSManish Rangankar { 403ace7f46bSManish Rangankar qedi_free_sb(qedi); 404ace7f46bSManish Rangankar qedi_free_fp(qedi); 405ace7f46bSManish Rangankar } 406ace7f46bSManish Rangankar 407ace7f46bSManish Rangankar static int qedi_alloc_fp(struct qedi_ctx *qedi) 408ace7f46bSManish Rangankar { 409ace7f46bSManish Rangankar int ret = 0; 410ace7f46bSManish Rangankar 411ace7f46bSManish Rangankar qedi->fp_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), 412ace7f46bSManish Rangankar sizeof(struct qedi_fastpath), GFP_KERNEL); 413ace7f46bSManish Rangankar if (!qedi->fp_array) { 414ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 415ace7f46bSManish Rangankar "fastpath fp array allocation failed.\n"); 416ace7f46bSManish Rangankar return -ENOMEM; 417ace7f46bSManish Rangankar } 418ace7f46bSManish Rangankar 419ace7f46bSManish Rangankar qedi->sb_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), 420ace7f46bSManish Rangankar sizeof(struct qed_sb_info), GFP_KERNEL); 421ace7f46bSManish Rangankar if (!qedi->sb_array) { 422ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 423ace7f46bSManish Rangankar "fastpath sb array allocation failed.\n"); 424ace7f46bSManish Rangankar ret = -ENOMEM; 425ace7f46bSManish Rangankar goto free_fp; 426ace7f46bSManish Rangankar } 427ace7f46bSManish Rangankar 428ace7f46bSManish Rangankar return ret; 429ace7f46bSManish Rangankar 430ace7f46bSManish Rangankar free_fp: 431ace7f46bSManish Rangankar qedi_free_fp(qedi); 432ace7f46bSManish Rangankar return ret; 433ace7f46bSManish Rangankar } 434ace7f46bSManish Rangankar 435ace7f46bSManish Rangankar static void qedi_int_fp(struct qedi_ctx *qedi) 436ace7f46bSManish Rangankar { 437ace7f46bSManish Rangankar struct qedi_fastpath *fp; 438ace7f46bSManish Rangankar int id; 439ace7f46bSManish Rangankar 440ace7f46bSManish Rangankar memset(qedi->fp_array, 0, MIN_NUM_CPUS_MSIX(qedi) * 441ace7f46bSManish Rangankar sizeof(*qedi->fp_array)); 442ace7f46bSManish Rangankar memset(qedi->sb_array, 0, MIN_NUM_CPUS_MSIX(qedi) * 443ace7f46bSManish Rangankar sizeof(*qedi->sb_array)); 444ace7f46bSManish Rangankar 445ace7f46bSManish Rangankar for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 446ace7f46bSManish Rangankar fp = &qedi->fp_array[id]; 447ace7f46bSManish Rangankar fp->sb_info = &qedi->sb_array[id]; 448ace7f46bSManish Rangankar fp->sb_id = id; 449ace7f46bSManish Rangankar fp->qedi = qedi; 450ace7f46bSManish Rangankar snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", 451ace7f46bSManish Rangankar "qedi", id); 452ace7f46bSManish Rangankar 453ace7f46bSManish Rangankar /* fp_array[i] ---- irq cookie 454ace7f46bSManish Rangankar * So init data which is needed in int ctx 455ace7f46bSManish Rangankar */ 456ace7f46bSManish Rangankar } 457ace7f46bSManish Rangankar } 458ace7f46bSManish Rangankar 459ace7f46bSManish Rangankar static int qedi_prepare_fp(struct qedi_ctx *qedi) 460ace7f46bSManish Rangankar { 461ace7f46bSManish Rangankar struct qedi_fastpath *fp; 462ace7f46bSManish Rangankar int id, ret = 0; 463ace7f46bSManish Rangankar 464ace7f46bSManish Rangankar ret = qedi_alloc_fp(qedi); 465ace7f46bSManish Rangankar if (ret) 466ace7f46bSManish Rangankar goto err; 467ace7f46bSManish Rangankar 468ace7f46bSManish Rangankar qedi_int_fp(qedi); 469ace7f46bSManish Rangankar 470ace7f46bSManish Rangankar for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 471ace7f46bSManish Rangankar fp = &qedi->fp_array[id]; 472ace7f46bSManish Rangankar ret = qedi_alloc_and_init_sb(qedi, fp->sb_info, fp->sb_id); 473ace7f46bSManish Rangankar if (ret) { 474ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 475ace7f46bSManish Rangankar "SB allocation and initialization failed.\n"); 476ace7f46bSManish Rangankar ret = -EIO; 477ace7f46bSManish Rangankar goto err_init; 478ace7f46bSManish Rangankar } 479ace7f46bSManish Rangankar } 480ace7f46bSManish Rangankar 481ace7f46bSManish Rangankar return 0; 482ace7f46bSManish Rangankar 483ace7f46bSManish Rangankar err_init: 484ace7f46bSManish Rangankar qedi_free_sb(qedi); 485ace7f46bSManish Rangankar qedi_free_fp(qedi); 486ace7f46bSManish Rangankar err: 487ace7f46bSManish Rangankar return ret; 488ace7f46bSManish Rangankar } 489ace7f46bSManish Rangankar 490ace7f46bSManish Rangankar static int qedi_setup_cid_que(struct qedi_ctx *qedi) 491ace7f46bSManish Rangankar { 492ace7f46bSManish Rangankar int i; 493ace7f46bSManish Rangankar 494ace7f46bSManish Rangankar qedi->cid_que.cid_que_base = kmalloc_array(qedi->max_active_conns, 495ace7f46bSManish Rangankar sizeof(u32), GFP_KERNEL); 496ace7f46bSManish Rangankar if (!qedi->cid_que.cid_que_base) 497ace7f46bSManish Rangankar return -ENOMEM; 498ace7f46bSManish Rangankar 499ace7f46bSManish Rangankar qedi->cid_que.conn_cid_tbl = kmalloc_array(qedi->max_active_conns, 500ace7f46bSManish Rangankar sizeof(struct qedi_conn *), 501ace7f46bSManish Rangankar GFP_KERNEL); 502ace7f46bSManish Rangankar if (!qedi->cid_que.conn_cid_tbl) { 503ace7f46bSManish Rangankar kfree(qedi->cid_que.cid_que_base); 504ace7f46bSManish Rangankar qedi->cid_que.cid_que_base = NULL; 505ace7f46bSManish Rangankar return -ENOMEM; 506ace7f46bSManish Rangankar } 507ace7f46bSManish Rangankar 508ace7f46bSManish Rangankar qedi->cid_que.cid_que = (u32 *)qedi->cid_que.cid_que_base; 509ace7f46bSManish Rangankar qedi->cid_que.cid_q_prod_idx = 0; 510ace7f46bSManish Rangankar qedi->cid_que.cid_q_cons_idx = 0; 511ace7f46bSManish Rangankar qedi->cid_que.cid_q_max_idx = qedi->max_active_conns; 512ace7f46bSManish Rangankar qedi->cid_que.cid_free_cnt = qedi->max_active_conns; 513ace7f46bSManish Rangankar 514ace7f46bSManish Rangankar for (i = 0; i < qedi->max_active_conns; i++) { 515ace7f46bSManish Rangankar qedi->cid_que.cid_que[i] = i; 516ace7f46bSManish Rangankar qedi->cid_que.conn_cid_tbl[i] = NULL; 517ace7f46bSManish Rangankar } 518ace7f46bSManish Rangankar 519ace7f46bSManish Rangankar return 0; 520ace7f46bSManish Rangankar } 521ace7f46bSManish Rangankar 522ace7f46bSManish Rangankar static void qedi_release_cid_que(struct qedi_ctx *qedi) 523ace7f46bSManish Rangankar { 524ace7f46bSManish Rangankar kfree(qedi->cid_que.cid_que_base); 525ace7f46bSManish Rangankar qedi->cid_que.cid_que_base = NULL; 526ace7f46bSManish Rangankar 527ace7f46bSManish Rangankar kfree(qedi->cid_que.conn_cid_tbl); 528ace7f46bSManish Rangankar qedi->cid_que.conn_cid_tbl = NULL; 529ace7f46bSManish Rangankar } 530ace7f46bSManish Rangankar 531ace7f46bSManish Rangankar static int qedi_init_id_tbl(struct qedi_portid_tbl *id_tbl, u16 size, 532ace7f46bSManish Rangankar u16 start_id, u16 next) 533ace7f46bSManish Rangankar { 534ace7f46bSManish Rangankar id_tbl->start = start_id; 535ace7f46bSManish Rangankar id_tbl->max = size; 536ace7f46bSManish Rangankar id_tbl->next = next; 537ace7f46bSManish Rangankar spin_lock_init(&id_tbl->lock); 538915d9b71SDan Carpenter id_tbl->table = kcalloc(BITS_TO_LONGS(size), sizeof(long), GFP_KERNEL); 539ace7f46bSManish Rangankar if (!id_tbl->table) 540ace7f46bSManish Rangankar return -ENOMEM; 541ace7f46bSManish Rangankar 542ace7f46bSManish Rangankar return 0; 543ace7f46bSManish Rangankar } 544ace7f46bSManish Rangankar 545ace7f46bSManish Rangankar static void qedi_free_id_tbl(struct qedi_portid_tbl *id_tbl) 546ace7f46bSManish Rangankar { 547ace7f46bSManish Rangankar kfree(id_tbl->table); 548ace7f46bSManish Rangankar id_tbl->table = NULL; 549ace7f46bSManish Rangankar } 550ace7f46bSManish Rangankar 551ace7f46bSManish Rangankar int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id) 552ace7f46bSManish Rangankar { 553ace7f46bSManish Rangankar int ret = -1; 554ace7f46bSManish Rangankar 555ace7f46bSManish Rangankar id -= id_tbl->start; 556ace7f46bSManish Rangankar if (id >= id_tbl->max) 557ace7f46bSManish Rangankar return ret; 558ace7f46bSManish Rangankar 559ace7f46bSManish Rangankar spin_lock(&id_tbl->lock); 560ace7f46bSManish Rangankar if (!test_bit(id, id_tbl->table)) { 561ace7f46bSManish Rangankar set_bit(id, id_tbl->table); 562ace7f46bSManish Rangankar ret = 0; 563ace7f46bSManish Rangankar } 564ace7f46bSManish Rangankar spin_unlock(&id_tbl->lock); 565ace7f46bSManish Rangankar return ret; 566ace7f46bSManish Rangankar } 567ace7f46bSManish Rangankar 568ace7f46bSManish Rangankar u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl) 569ace7f46bSManish Rangankar { 570ace7f46bSManish Rangankar u16 id; 571ace7f46bSManish Rangankar 572ace7f46bSManish Rangankar spin_lock(&id_tbl->lock); 573ace7f46bSManish Rangankar id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next); 574ace7f46bSManish Rangankar if (id >= id_tbl->max) { 575ace7f46bSManish Rangankar id = QEDI_LOCAL_PORT_INVALID; 576ace7f46bSManish Rangankar if (id_tbl->next != 0) { 577ace7f46bSManish Rangankar id = find_first_zero_bit(id_tbl->table, id_tbl->next); 578ace7f46bSManish Rangankar if (id >= id_tbl->next) 579ace7f46bSManish Rangankar id = QEDI_LOCAL_PORT_INVALID; 580ace7f46bSManish Rangankar } 581ace7f46bSManish Rangankar } 582ace7f46bSManish Rangankar 583ace7f46bSManish Rangankar if (id < id_tbl->max) { 584ace7f46bSManish Rangankar set_bit(id, id_tbl->table); 585ace7f46bSManish Rangankar id_tbl->next = (id + 1) & (id_tbl->max - 1); 586ace7f46bSManish Rangankar id += id_tbl->start; 587ace7f46bSManish Rangankar } 588ace7f46bSManish Rangankar 589ace7f46bSManish Rangankar spin_unlock(&id_tbl->lock); 590ace7f46bSManish Rangankar 591ace7f46bSManish Rangankar return id; 592ace7f46bSManish Rangankar } 593ace7f46bSManish Rangankar 594ace7f46bSManish Rangankar void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id) 595ace7f46bSManish Rangankar { 596ace7f46bSManish Rangankar if (id == QEDI_LOCAL_PORT_INVALID) 597ace7f46bSManish Rangankar return; 598ace7f46bSManish Rangankar 599ace7f46bSManish Rangankar id -= id_tbl->start; 600ace7f46bSManish Rangankar if (id >= id_tbl->max) 601ace7f46bSManish Rangankar return; 602ace7f46bSManish Rangankar 603ace7f46bSManish Rangankar clear_bit(id, id_tbl->table); 604ace7f46bSManish Rangankar } 605ace7f46bSManish Rangankar 606ace7f46bSManish Rangankar static void qedi_cm_free_mem(struct qedi_ctx *qedi) 607ace7f46bSManish Rangankar { 608ace7f46bSManish Rangankar kfree(qedi->ep_tbl); 609ace7f46bSManish Rangankar qedi->ep_tbl = NULL; 610ace7f46bSManish Rangankar qedi_free_id_tbl(&qedi->lcl_port_tbl); 611ace7f46bSManish Rangankar } 612ace7f46bSManish Rangankar 613ace7f46bSManish Rangankar static int qedi_cm_alloc_mem(struct qedi_ctx *qedi) 614ace7f46bSManish Rangankar { 615ace7f46bSManish Rangankar u16 port_id; 616ace7f46bSManish Rangankar 617ace7f46bSManish Rangankar qedi->ep_tbl = kzalloc((qedi->max_active_conns * 618ace7f46bSManish Rangankar sizeof(struct qedi_endpoint *)), GFP_KERNEL); 619ace7f46bSManish Rangankar if (!qedi->ep_tbl) 620ace7f46bSManish Rangankar return -ENOMEM; 621ace7f46bSManish Rangankar port_id = prandom_u32() % QEDI_LOCAL_PORT_RANGE; 622ace7f46bSManish Rangankar if (qedi_init_id_tbl(&qedi->lcl_port_tbl, QEDI_LOCAL_PORT_RANGE, 623ace7f46bSManish Rangankar QEDI_LOCAL_PORT_MIN, port_id)) { 624ace7f46bSManish Rangankar qedi_cm_free_mem(qedi); 625ace7f46bSManish Rangankar return -ENOMEM; 626ace7f46bSManish Rangankar } 627ace7f46bSManish Rangankar 628ace7f46bSManish Rangankar return 0; 629ace7f46bSManish Rangankar } 630ace7f46bSManish Rangankar 631ace7f46bSManish Rangankar static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev) 632ace7f46bSManish Rangankar { 633ace7f46bSManish Rangankar struct Scsi_Host *shost; 634ace7f46bSManish Rangankar struct qedi_ctx *qedi = NULL; 635ace7f46bSManish Rangankar 636ace7f46bSManish Rangankar shost = iscsi_host_alloc(&qedi_host_template, 637ace7f46bSManish Rangankar sizeof(struct qedi_ctx), 0); 638ace7f46bSManish Rangankar if (!shost) { 639ace7f46bSManish Rangankar QEDI_ERR(NULL, "Could not allocate shost\n"); 640ace7f46bSManish Rangankar goto exit_setup_shost; 641ace7f46bSManish Rangankar } 642ace7f46bSManish Rangankar 643bdd4aad7SMike Christie shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA - 1; 644ace7f46bSManish Rangankar shost->max_channel = 0; 645ace7f46bSManish Rangankar shost->max_lun = ~0; 646ace7f46bSManish Rangankar shost->max_cmd_len = 16; 647ace7f46bSManish Rangankar shost->transportt = qedi_scsi_transport; 648ace7f46bSManish Rangankar 649ace7f46bSManish Rangankar qedi = iscsi_host_priv(shost); 650ace7f46bSManish Rangankar memset(qedi, 0, sizeof(*qedi)); 651ace7f46bSManish Rangankar qedi->shost = shost; 652ace7f46bSManish Rangankar qedi->dbg_ctx.host_no = shost->host_no; 653ace7f46bSManish Rangankar qedi->pdev = pdev; 654ace7f46bSManish Rangankar qedi->dbg_ctx.pdev = pdev; 655ace7f46bSManish Rangankar qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA; 656ace7f46bSManish Rangankar qedi->max_sqes = QEDI_SQ_SIZE; 657ace7f46bSManish Rangankar 658ace7f46bSManish Rangankar shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi); 659ace7f46bSManish Rangankar 660ace7f46bSManish Rangankar pci_set_drvdata(pdev, qedi); 661ace7f46bSManish Rangankar 662ace7f46bSManish Rangankar exit_setup_shost: 663ace7f46bSManish Rangankar return qedi; 664ace7f46bSManish Rangankar } 665ace7f46bSManish Rangankar 666ace7f46bSManish Rangankar static int qedi_ll2_rx(void *cookie, struct sk_buff *skb, u32 arg1, u32 arg2) 667ace7f46bSManish Rangankar { 668ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; 669ace7f46bSManish Rangankar struct skb_work_list *work; 670cdd3ff87SManish Rangankar struct ethhdr *eh; 671ace7f46bSManish Rangankar 672ace7f46bSManish Rangankar if (!qedi) { 673ace7f46bSManish Rangankar QEDI_ERR(NULL, "qedi is NULL\n"); 674ace7f46bSManish Rangankar return -1; 675ace7f46bSManish Rangankar } 676ace7f46bSManish Rangankar 677ace7f46bSManish Rangankar if (!test_bit(UIO_DEV_OPENED, &qedi->flags)) { 678ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UIO, 679ace7f46bSManish Rangankar "UIO DEV is not opened\n"); 680ace7f46bSManish Rangankar kfree_skb(skb); 681ace7f46bSManish Rangankar return 0; 682ace7f46bSManish Rangankar } 683ace7f46bSManish Rangankar 684cdd3ff87SManish Rangankar eh = (struct ethhdr *)skb->data; 685cdd3ff87SManish Rangankar /* Undo VLAN encapsulation */ 686cdd3ff87SManish Rangankar if (eh->h_proto == htons(ETH_P_8021Q)) { 687cdd3ff87SManish Rangankar memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); 688cdd3ff87SManish Rangankar eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); 689cdd3ff87SManish Rangankar skb_reset_mac_header(skb); 690cdd3ff87SManish Rangankar } 691cdd3ff87SManish Rangankar 692cdd3ff87SManish Rangankar /* Filter out non FIP/FCoE frames here to free them faster */ 693cdd3ff87SManish Rangankar if (eh->h_proto != htons(ETH_P_ARP) && 694cdd3ff87SManish Rangankar eh->h_proto != htons(ETH_P_IP) && 695cdd3ff87SManish Rangankar eh->h_proto != htons(ETH_P_IPV6)) { 696cdd3ff87SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 697cdd3ff87SManish Rangankar "Dropping frame ethertype [0x%x] len [0x%x].\n", 698cdd3ff87SManish Rangankar eh->h_proto, skb->len); 699cdd3ff87SManish Rangankar kfree_skb(skb); 700cdd3ff87SManish Rangankar return 0; 701cdd3ff87SManish Rangankar } 702cdd3ff87SManish Rangankar 703cdd3ff87SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 704cdd3ff87SManish Rangankar "Allowed frame ethertype [0x%x] len [0x%x].\n", 705cdd3ff87SManish Rangankar eh->h_proto, skb->len); 706cdd3ff87SManish Rangankar 707ace7f46bSManish Rangankar work = kzalloc(sizeof(*work), GFP_ATOMIC); 708ace7f46bSManish Rangankar if (!work) { 709ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 710ace7f46bSManish Rangankar "Could not allocate work so dropping frame.\n"); 711ace7f46bSManish Rangankar kfree_skb(skb); 712ace7f46bSManish Rangankar return 0; 713ace7f46bSManish Rangankar } 714ace7f46bSManish Rangankar 715ace7f46bSManish Rangankar INIT_LIST_HEAD(&work->list); 716ace7f46bSManish Rangankar work->skb = skb; 717ace7f46bSManish Rangankar 718ace7f46bSManish Rangankar if (skb_vlan_tag_present(skb)) 719ace7f46bSManish Rangankar work->vlan_id = skb_vlan_tag_get(skb); 720ace7f46bSManish Rangankar 721ace7f46bSManish Rangankar if (work->vlan_id) 722ace7f46bSManish Rangankar __vlan_insert_tag(work->skb, htons(ETH_P_8021Q), work->vlan_id); 723ace7f46bSManish Rangankar 724ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 725ace7f46bSManish Rangankar list_add_tail(&work->list, &qedi->ll2_skb_list); 726ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 7279632a6b4SManish Rangankar 728ace7f46bSManish Rangankar wake_up_process(qedi->ll2_recv_thread); 729ace7f46bSManish Rangankar 730ace7f46bSManish Rangankar return 0; 731ace7f46bSManish Rangankar } 732ace7f46bSManish Rangankar 733ace7f46bSManish Rangankar /* map this skb to iscsiuio mmaped region */ 734ace7f46bSManish Rangankar static int qedi_ll2_process_skb(struct qedi_ctx *qedi, struct sk_buff *skb, 735ace7f46bSManish Rangankar u16 vlan_id) 736ace7f46bSManish Rangankar { 737ace7f46bSManish Rangankar struct qedi_uio_dev *udev = NULL; 738ace7f46bSManish Rangankar struct qedi_uio_ctrl *uctrl = NULL; 739ace7f46bSManish Rangankar struct qedi_rx_bd rxbd; 740ace7f46bSManish Rangankar struct qedi_rx_bd *p_rxbd; 741ace7f46bSManish Rangankar u32 rx_bd_prod; 742ace7f46bSManish Rangankar void *pkt; 743ace7f46bSManish Rangankar int len = 0; 7449632a6b4SManish Rangankar u32 prod; 745ace7f46bSManish Rangankar 746ace7f46bSManish Rangankar if (!qedi) { 747ace7f46bSManish Rangankar QEDI_ERR(NULL, "qedi is NULL\n"); 748ace7f46bSManish Rangankar return -1; 749ace7f46bSManish Rangankar } 750ace7f46bSManish Rangankar 751ace7f46bSManish Rangankar udev = qedi->udev; 752ace7f46bSManish Rangankar uctrl = udev->uctrl; 7539632a6b4SManish Rangankar 7549632a6b4SManish Rangankar ++uctrl->hw_rx_prod_cnt; 7559632a6b4SManish Rangankar prod = (uctrl->hw_rx_prod + 1) % RX_RING; 7569632a6b4SManish Rangankar 7579632a6b4SManish Rangankar pkt = udev->rx_pkt + (prod * qedi_ll2_buf_size); 758dcceeeb7SNilesh Javali len = min_t(u32, skb->len, (u32)qedi_ll2_buf_size); 759ace7f46bSManish Rangankar memcpy(pkt, skb->data, len); 760ace7f46bSManish Rangankar 761ace7f46bSManish Rangankar memset(&rxbd, 0, sizeof(rxbd)); 7629632a6b4SManish Rangankar rxbd.rx_pkt_index = prod; 763ace7f46bSManish Rangankar rxbd.rx_pkt_len = len; 764ace7f46bSManish Rangankar rxbd.vlan_id = vlan_id; 765ace7f46bSManish Rangankar 766ace7f46bSManish Rangankar uctrl->hw_rx_bd_prod = (uctrl->hw_rx_bd_prod + 1) % QEDI_NUM_RX_BD; 767ace7f46bSManish Rangankar rx_bd_prod = uctrl->hw_rx_bd_prod; 768ace7f46bSManish Rangankar p_rxbd = (struct qedi_rx_bd *)udev->ll2_ring; 769ace7f46bSManish Rangankar p_rxbd += rx_bd_prod; 770ace7f46bSManish Rangankar 771ace7f46bSManish Rangankar memcpy(p_rxbd, &rxbd, sizeof(rxbd)); 772ace7f46bSManish Rangankar 7739632a6b4SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 7749632a6b4SManish Rangankar "hw_rx_prod [%d] prod [%d] hw_rx_bd_prod [%d] rx_pkt_idx [%d] rx_len [%d].\n", 7759632a6b4SManish Rangankar uctrl->hw_rx_prod, prod, uctrl->hw_rx_bd_prod, 7769632a6b4SManish Rangankar rxbd.rx_pkt_index, rxbd.rx_pkt_len); 7779632a6b4SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_LL2, 7789632a6b4SManish Rangankar "host_rx_cons [%d] hw_rx_bd_cons [%d].\n", 7799632a6b4SManish Rangankar uctrl->host_rx_cons, uctrl->host_rx_bd_cons); 7809632a6b4SManish Rangankar 7819632a6b4SManish Rangankar uctrl->hw_rx_prod = prod; 7829632a6b4SManish Rangankar 783ace7f46bSManish Rangankar /* notify the iscsiuio about new packet */ 784ace7f46bSManish Rangankar uio_event_notify(&udev->qedi_uinfo); 785ace7f46bSManish Rangankar 786ace7f46bSManish Rangankar return 0; 787ace7f46bSManish Rangankar } 788ace7f46bSManish Rangankar 789ace7f46bSManish Rangankar static void qedi_ll2_free_skbs(struct qedi_ctx *qedi) 790ace7f46bSManish Rangankar { 791ace7f46bSManish Rangankar struct skb_work_list *work, *work_tmp; 792ace7f46bSManish Rangankar 793ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 794ace7f46bSManish Rangankar list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, list) { 795ace7f46bSManish Rangankar list_del(&work->list); 796ace7f46bSManish Rangankar kfree_skb(work->skb); 797ace7f46bSManish Rangankar kfree(work); 798ace7f46bSManish Rangankar } 799ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 800ace7f46bSManish Rangankar } 801ace7f46bSManish Rangankar 802ace7f46bSManish Rangankar static int qedi_ll2_recv_thread(void *arg) 803ace7f46bSManish Rangankar { 804ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)arg; 805ace7f46bSManish Rangankar struct skb_work_list *work, *work_tmp; 806ace7f46bSManish Rangankar 807ace7f46bSManish Rangankar set_user_nice(current, -20); 808ace7f46bSManish Rangankar 809ace7f46bSManish Rangankar while (!kthread_should_stop()) { 810ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 811ace7f46bSManish Rangankar list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, 812ace7f46bSManish Rangankar list) { 813ace7f46bSManish Rangankar list_del(&work->list); 814ace7f46bSManish Rangankar qedi_ll2_process_skb(qedi, work->skb, work->vlan_id); 815ace7f46bSManish Rangankar kfree_skb(work->skb); 816ace7f46bSManish Rangankar kfree(work); 817ace7f46bSManish Rangankar } 818ace7f46bSManish Rangankar set_current_state(TASK_INTERRUPTIBLE); 819ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 820ace7f46bSManish Rangankar schedule(); 821ace7f46bSManish Rangankar } 822ace7f46bSManish Rangankar 823ace7f46bSManish Rangankar __set_current_state(TASK_RUNNING); 824ace7f46bSManish Rangankar return 0; 825ace7f46bSManish Rangankar } 826ace7f46bSManish Rangankar 827ace7f46bSManish Rangankar static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi) 828ace7f46bSManish Rangankar { 829ace7f46bSManish Rangankar u8 num_sq_pages; 830ace7f46bSManish Rangankar u32 log_page_size; 831ace7f46bSManish Rangankar int rval = 0; 832ace7f46bSManish Rangankar 833ace7f46bSManish Rangankar 834fa97c511SNilesh Javali num_sq_pages = (MAX_OUTSTANDING_TASKS_PER_CON * 8) / QEDI_PAGE_SIZE; 835ace7f46bSManish Rangankar 836ace7f46bSManish Rangankar qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi); 837ace7f46bSManish Rangankar 83842d7c10fSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 83942d7c10fSManish Rangankar "Number of CQ count is %d\n", qedi->num_queues); 84042d7c10fSManish Rangankar 841ace7f46bSManish Rangankar memset(&qedi->pf_params.iscsi_pf_params, 0, 842ace7f46bSManish Rangankar sizeof(qedi->pf_params.iscsi_pf_params)); 843ace7f46bSManish Rangankar 8447ae7ce0bSChristoph Hellwig qedi->p_cpuq = dma_alloc_coherent(&qedi->pdev->dev, 845ace7f46bSManish Rangankar qedi->num_queues * sizeof(struct qedi_glbl_q_params), 8467ae7ce0bSChristoph Hellwig &qedi->hw_p_cpuq, GFP_KERNEL); 847ace7f46bSManish Rangankar if (!qedi->p_cpuq) { 8487ae7ce0bSChristoph Hellwig QEDI_ERR(&qedi->dbg_ctx, "dma_alloc_coherent fail\n"); 849ace7f46bSManish Rangankar rval = -1; 850ace7f46bSManish Rangankar goto err_alloc_mem; 851ace7f46bSManish Rangankar } 852ace7f46bSManish Rangankar 853ace7f46bSManish Rangankar rval = qedi_alloc_global_queues(qedi); 854ace7f46bSManish Rangankar if (rval) { 855ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Global queue allocation failed.\n"); 856ace7f46bSManish Rangankar rval = -1; 857ace7f46bSManish Rangankar goto err_alloc_mem; 858ace7f46bSManish Rangankar } 859ace7f46bSManish Rangankar 860ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_cons = QEDI_MAX_ISCSI_CONNS_PER_HBA; 861ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_tasks = QEDI_MAX_ISCSI_TASK; 862ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.half_way_close_timeout = 10; 863ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_sq_pages_in_ring = num_sq_pages; 864ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_r2tq_pages_in_ring = num_sq_pages; 865ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_uhq_pages_in_ring = num_sq_pages; 866ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_queues = qedi->num_queues; 867ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.debug_mode = qedi_fw_debug; 868962ea1c0Smanish.rangankar@cavium.com qedi->pf_params.iscsi_pf_params.two_msl_timer = 4000; 8693d61a313SNilesh Javali qedi->pf_params.iscsi_pf_params.max_fin_rt = 2; 870ace7f46bSManish Rangankar 871ace7f46bSManish Rangankar for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) { 872fa97c511SNilesh Javali if ((1 << log_page_size) == QEDI_PAGE_SIZE) 873ace7f46bSManish Rangankar break; 874ace7f46bSManish Rangankar } 875ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.log_page_size = log_page_size; 876ace7f46bSManish Rangankar 877ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.glbl_q_params_addr = 878ace7f46bSManish Rangankar (u64)qedi->hw_p_cpuq; 879ace7f46bSManish Rangankar 880ace7f46bSManish Rangankar /* RQ BDQ initializations. 881ace7f46bSManish Rangankar * rq_num_entries: suggested value for Initiator is 16 (4KB RQ) 882ace7f46bSManish Rangankar * rqe_log_size: 8 for 256B RQE 883ace7f46bSManish Rangankar */ 884ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.rqe_log_size = 8; 885ace7f46bSManish Rangankar /* BDQ address and size */ 886ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.bdq_pbl_base_addr[BDQ_ID_RQ] = 887ace7f46bSManish Rangankar qedi->bdq_pbl_list_dma; 888ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.bdq_pbl_num_entries[BDQ_ID_RQ] = 889ace7f46bSManish Rangankar qedi->bdq_pbl_list_num_entries; 890ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.rq_buffer_size = QEDI_BDQ_BUF_SIZE; 891ace7f46bSManish Rangankar 892ace7f46bSManish Rangankar /* cq_num_entries: num_tasks + rq_num_entries */ 893ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.cq_num_entries = 2048; 894ace7f46bSManish Rangankar 895ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.gl_rq_pi = QEDI_PROTO_CQ_PROD_IDX; 896ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.gl_cmd_pi = 1; 897ace7f46bSManish Rangankar 898ace7f46bSManish Rangankar err_alloc_mem: 899ace7f46bSManish Rangankar return rval; 900ace7f46bSManish Rangankar } 901ace7f46bSManish Rangankar 902ace7f46bSManish Rangankar /* Free DMA coherent memory for array of queue pointers we pass to qed */ 903ace7f46bSManish Rangankar static void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi) 904ace7f46bSManish Rangankar { 905ace7f46bSManish Rangankar size_t size = 0; 906ace7f46bSManish Rangankar 907ace7f46bSManish Rangankar if (qedi->p_cpuq) { 908ace7f46bSManish Rangankar size = qedi->num_queues * sizeof(struct qedi_glbl_q_params); 9097ae7ce0bSChristoph Hellwig dma_free_coherent(&qedi->pdev->dev, size, qedi->p_cpuq, 910ace7f46bSManish Rangankar qedi->hw_p_cpuq); 911ace7f46bSManish Rangankar } 912ace7f46bSManish Rangankar 913ace7f46bSManish Rangankar qedi_free_global_queues(qedi); 914ace7f46bSManish Rangankar 915ace7f46bSManish Rangankar kfree(qedi->global_queues); 916ace7f46bSManish Rangankar } 917ace7f46bSManish Rangankar 918534bbdf8SManish Rangankar static void qedi_get_boot_tgt_info(struct nvm_iscsi_block *block, 919534bbdf8SManish Rangankar struct qedi_boot_target *tgt, u8 index) 920534bbdf8SManish Rangankar { 921534bbdf8SManish Rangankar u32 ipv6_en; 922534bbdf8SManish Rangankar 923534bbdf8SManish Rangankar ipv6_en = !!(block->generic.ctrl_flags & 924534bbdf8SManish Rangankar NVM_ISCSI_CFG_GEN_IPV6_ENABLED); 925534bbdf8SManish Rangankar 9262f1ea398SManish Rangankar snprintf(tgt->iscsi_name, sizeof(tgt->iscsi_name), "%s", 927534bbdf8SManish Rangankar block->target[index].target_name.byte); 928534bbdf8SManish Rangankar 929534bbdf8SManish Rangankar tgt->ipv6_en = ipv6_en; 930534bbdf8SManish Rangankar 931534bbdf8SManish Rangankar if (ipv6_en) 932534bbdf8SManish Rangankar snprintf(tgt->ip_addr, IPV6_LEN, "%pI6\n", 933534bbdf8SManish Rangankar block->target[index].ipv6_addr.byte); 934534bbdf8SManish Rangankar else 935534bbdf8SManish Rangankar snprintf(tgt->ip_addr, IPV4_LEN, "%pI4\n", 936534bbdf8SManish Rangankar block->target[index].ipv4_addr.byte); 937534bbdf8SManish Rangankar } 938534bbdf8SManish Rangankar 939534bbdf8SManish Rangankar static int qedi_find_boot_info(struct qedi_ctx *qedi, 940534bbdf8SManish Rangankar struct qed_mfw_tlv_iscsi *iscsi, 941534bbdf8SManish Rangankar struct nvm_iscsi_block *block) 942534bbdf8SManish Rangankar { 943534bbdf8SManish Rangankar struct qedi_boot_target *pri_tgt = NULL, *sec_tgt = NULL; 944534bbdf8SManish Rangankar u32 pri_ctrl_flags = 0, sec_ctrl_flags = 0, found = 0; 945534bbdf8SManish Rangankar struct iscsi_cls_session *cls_sess; 946534bbdf8SManish Rangankar struct iscsi_cls_conn *cls_conn; 947534bbdf8SManish Rangankar struct qedi_conn *qedi_conn; 948534bbdf8SManish Rangankar struct iscsi_session *sess; 949534bbdf8SManish Rangankar struct iscsi_conn *conn; 950534bbdf8SManish Rangankar char ep_ip_addr[64]; 951534bbdf8SManish Rangankar int i, ret = 0; 952534bbdf8SManish Rangankar 953534bbdf8SManish Rangankar pri_ctrl_flags = !!(block->target[0].ctrl_flags & 954534bbdf8SManish Rangankar NVM_ISCSI_CFG_TARGET_ENABLED); 955534bbdf8SManish Rangankar if (pri_ctrl_flags) { 956534bbdf8SManish Rangankar pri_tgt = kzalloc(sizeof(*pri_tgt), GFP_KERNEL); 957534bbdf8SManish Rangankar if (!pri_tgt) 958534bbdf8SManish Rangankar return -1; 959534bbdf8SManish Rangankar qedi_get_boot_tgt_info(block, pri_tgt, 0); 960534bbdf8SManish Rangankar } 961534bbdf8SManish Rangankar 962534bbdf8SManish Rangankar sec_ctrl_flags = !!(block->target[1].ctrl_flags & 963534bbdf8SManish Rangankar NVM_ISCSI_CFG_TARGET_ENABLED); 964534bbdf8SManish Rangankar if (sec_ctrl_flags) { 965534bbdf8SManish Rangankar sec_tgt = kzalloc(sizeof(*sec_tgt), GFP_KERNEL); 966534bbdf8SManish Rangankar if (!sec_tgt) { 967534bbdf8SManish Rangankar ret = -1; 968534bbdf8SManish Rangankar goto free_tgt; 969534bbdf8SManish Rangankar } 970534bbdf8SManish Rangankar qedi_get_boot_tgt_info(block, sec_tgt, 1); 971534bbdf8SManish Rangankar } 972534bbdf8SManish Rangankar 973534bbdf8SManish Rangankar for (i = 0; i < qedi->max_active_conns; i++) { 974534bbdf8SManish Rangankar qedi_conn = qedi_get_conn_from_id(qedi, i); 975534bbdf8SManish Rangankar if (!qedi_conn) 976534bbdf8SManish Rangankar continue; 977534bbdf8SManish Rangankar 978534bbdf8SManish Rangankar if (qedi_conn->ep->ip_type == TCP_IPV4) 979534bbdf8SManish Rangankar snprintf(ep_ip_addr, IPV4_LEN, "%pI4\n", 980534bbdf8SManish Rangankar qedi_conn->ep->dst_addr); 981534bbdf8SManish Rangankar else 982534bbdf8SManish Rangankar snprintf(ep_ip_addr, IPV6_LEN, "%pI6\n", 983534bbdf8SManish Rangankar qedi_conn->ep->dst_addr); 984534bbdf8SManish Rangankar 985534bbdf8SManish Rangankar cls_conn = qedi_conn->cls_conn; 986534bbdf8SManish Rangankar conn = cls_conn->dd_data; 987534bbdf8SManish Rangankar cls_sess = iscsi_conn_to_session(cls_conn); 988534bbdf8SManish Rangankar sess = cls_sess->dd_data; 989534bbdf8SManish Rangankar 990d5632b11SManish Rangankar if (!iscsi_is_session_online(cls_sess)) 991d5632b11SManish Rangankar continue; 992d5632b11SManish Rangankar 9931ac3549eSNilesh Javali if (!sess->targetname) 9941ac3549eSNilesh Javali continue; 9951ac3549eSNilesh Javali 996534bbdf8SManish Rangankar if (pri_ctrl_flags) { 997534bbdf8SManish Rangankar if (!strcmp(pri_tgt->iscsi_name, sess->targetname) && 998534bbdf8SManish Rangankar !strcmp(pri_tgt->ip_addr, ep_ip_addr)) { 999534bbdf8SManish Rangankar found = 1; 1000534bbdf8SManish Rangankar break; 1001534bbdf8SManish Rangankar } 1002534bbdf8SManish Rangankar } 1003534bbdf8SManish Rangankar 1004534bbdf8SManish Rangankar if (sec_ctrl_flags) { 1005534bbdf8SManish Rangankar if (!strcmp(sec_tgt->iscsi_name, sess->targetname) && 1006534bbdf8SManish Rangankar !strcmp(sec_tgt->ip_addr, ep_ip_addr)) { 1007534bbdf8SManish Rangankar found = 1; 1008534bbdf8SManish Rangankar break; 1009534bbdf8SManish Rangankar } 1010534bbdf8SManish Rangankar } 1011534bbdf8SManish Rangankar } 1012534bbdf8SManish Rangankar 1013534bbdf8SManish Rangankar if (found) { 1014534bbdf8SManish Rangankar if (conn->hdrdgst_en) { 1015534bbdf8SManish Rangankar iscsi->header_digest_set = true; 1016534bbdf8SManish Rangankar iscsi->header_digest = 1; 1017534bbdf8SManish Rangankar } 1018534bbdf8SManish Rangankar 1019534bbdf8SManish Rangankar if (conn->datadgst_en) { 1020534bbdf8SManish Rangankar iscsi->data_digest_set = true; 1021534bbdf8SManish Rangankar iscsi->data_digest = 1; 1022534bbdf8SManish Rangankar } 1023534bbdf8SManish Rangankar iscsi->boot_taget_portal_set = true; 1024534bbdf8SManish Rangankar iscsi->boot_taget_portal = sess->tpgt; 1025534bbdf8SManish Rangankar 1026534bbdf8SManish Rangankar } else { 1027534bbdf8SManish Rangankar ret = -1; 1028534bbdf8SManish Rangankar } 1029534bbdf8SManish Rangankar 1030534bbdf8SManish Rangankar if (sec_ctrl_flags) 1031534bbdf8SManish Rangankar kfree(sec_tgt); 1032534bbdf8SManish Rangankar free_tgt: 1033534bbdf8SManish Rangankar if (pri_ctrl_flags) 1034534bbdf8SManish Rangankar kfree(pri_tgt); 1035534bbdf8SManish Rangankar 1036534bbdf8SManish Rangankar return ret; 1037534bbdf8SManish Rangankar } 1038534bbdf8SManish Rangankar 1039269afb36SManish Rangankar static void qedi_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data) 1040269afb36SManish Rangankar { 1041269afb36SManish Rangankar struct qedi_ctx *qedi; 1042269afb36SManish Rangankar 1043269afb36SManish Rangankar if (!dev) { 1044269afb36SManish Rangankar QEDI_INFO(NULL, QEDI_LOG_EVT, 1045269afb36SManish Rangankar "dev is NULL so ignoring get_generic_tlv_data request.\n"); 1046269afb36SManish Rangankar return; 1047269afb36SManish Rangankar } 1048269afb36SManish Rangankar qedi = (struct qedi_ctx *)dev; 1049269afb36SManish Rangankar 1050269afb36SManish Rangankar memset(data, 0, sizeof(struct qed_generic_tlvs)); 1051269afb36SManish Rangankar ether_addr_copy(data->mac[0], qedi->mac); 1052269afb36SManish Rangankar } 1053269afb36SManish Rangankar 1054534bbdf8SManish Rangankar /* 1055534bbdf8SManish Rangankar * Protocol TLV handler 1056534bbdf8SManish Rangankar */ 1057534bbdf8SManish Rangankar static void qedi_get_protocol_tlv_data(void *dev, void *data) 1058534bbdf8SManish Rangankar { 1059534bbdf8SManish Rangankar struct qed_mfw_tlv_iscsi *iscsi = data; 1060534bbdf8SManish Rangankar struct qed_iscsi_stats *fw_iscsi_stats; 1061534bbdf8SManish Rangankar struct nvm_iscsi_block *block = NULL; 1062534bbdf8SManish Rangankar u32 chap_en = 0, mchap_en = 0; 1063534bbdf8SManish Rangankar struct qedi_ctx *qedi = dev; 1064534bbdf8SManish Rangankar int rval = 0; 1065534bbdf8SManish Rangankar 1066534bbdf8SManish Rangankar fw_iscsi_stats = kmalloc(sizeof(*fw_iscsi_stats), GFP_KERNEL); 1067534bbdf8SManish Rangankar if (!fw_iscsi_stats) { 1068534bbdf8SManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1069534bbdf8SManish Rangankar "Could not allocate memory for fw_iscsi_stats.\n"); 1070534bbdf8SManish Rangankar goto exit_get_data; 1071534bbdf8SManish Rangankar } 1072534bbdf8SManish Rangankar 1073534bbdf8SManish Rangankar mutex_lock(&qedi->stats_lock); 1074534bbdf8SManish Rangankar /* Query firmware for offload stats */ 1075534bbdf8SManish Rangankar qedi_ops->get_stats(qedi->cdev, fw_iscsi_stats); 1076534bbdf8SManish Rangankar mutex_unlock(&qedi->stats_lock); 1077534bbdf8SManish Rangankar 1078534bbdf8SManish Rangankar iscsi->rx_frames_set = true; 1079534bbdf8SManish Rangankar iscsi->rx_frames = fw_iscsi_stats->iscsi_rx_packet_cnt; 1080534bbdf8SManish Rangankar iscsi->rx_bytes_set = true; 1081534bbdf8SManish Rangankar iscsi->rx_bytes = fw_iscsi_stats->iscsi_rx_bytes_cnt; 1082534bbdf8SManish Rangankar iscsi->tx_frames_set = true; 1083534bbdf8SManish Rangankar iscsi->tx_frames = fw_iscsi_stats->iscsi_tx_packet_cnt; 1084534bbdf8SManish Rangankar iscsi->tx_bytes_set = true; 1085534bbdf8SManish Rangankar iscsi->tx_bytes = fw_iscsi_stats->iscsi_tx_bytes_cnt; 1086534bbdf8SManish Rangankar iscsi->frame_size_set = true; 1087534bbdf8SManish Rangankar iscsi->frame_size = qedi->ll2_mtu; 1088534bbdf8SManish Rangankar block = qedi_get_nvram_block(qedi); 1089534bbdf8SManish Rangankar if (block) { 1090534bbdf8SManish Rangankar chap_en = !!(block->generic.ctrl_flags & 1091534bbdf8SManish Rangankar NVM_ISCSI_CFG_GEN_CHAP_ENABLED); 1092534bbdf8SManish Rangankar mchap_en = !!(block->generic.ctrl_flags & 1093534bbdf8SManish Rangankar NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED); 1094534bbdf8SManish Rangankar 1095534bbdf8SManish Rangankar iscsi->auth_method_set = (chap_en || mchap_en) ? true : false; 1096534bbdf8SManish Rangankar iscsi->auth_method = 1; 1097534bbdf8SManish Rangankar if (chap_en) 1098534bbdf8SManish Rangankar iscsi->auth_method = 2; 1099534bbdf8SManish Rangankar if (mchap_en) 1100534bbdf8SManish Rangankar iscsi->auth_method = 3; 1101534bbdf8SManish Rangankar 1102534bbdf8SManish Rangankar iscsi->tx_desc_size_set = true; 1103534bbdf8SManish Rangankar iscsi->tx_desc_size = QEDI_SQ_SIZE; 1104534bbdf8SManish Rangankar iscsi->rx_desc_size_set = true; 1105534bbdf8SManish Rangankar iscsi->rx_desc_size = QEDI_CQ_SIZE; 1106534bbdf8SManish Rangankar 1107534bbdf8SManish Rangankar /* tpgt, hdr digest, data digest */ 1108534bbdf8SManish Rangankar rval = qedi_find_boot_info(qedi, iscsi, block); 1109534bbdf8SManish Rangankar if (rval) 1110534bbdf8SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1111534bbdf8SManish Rangankar "Boot target not set"); 1112534bbdf8SManish Rangankar } 1113534bbdf8SManish Rangankar 1114534bbdf8SManish Rangankar kfree(fw_iscsi_stats); 1115534bbdf8SManish Rangankar exit_get_data: 1116534bbdf8SManish Rangankar return; 1117534bbdf8SManish Rangankar } 1118534bbdf8SManish Rangankar 1119f4ba4e55SManish Rangankar void qedi_schedule_hw_err_handler(void *dev, 1120f4ba4e55SManish Rangankar enum qed_hw_err_type err_type) 1121f4ba4e55SManish Rangankar { 1122f4ba4e55SManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)dev; 1123f4ba4e55SManish Rangankar unsigned long override_flags = qedi_flags_override; 1124f4ba4e55SManish Rangankar 1125f4ba4e55SManish Rangankar if (override_flags && test_bit(QEDI_ERR_OVERRIDE_EN, &override_flags)) 1126f4ba4e55SManish Rangankar qedi->qedi_err_flags = qedi_flags_override; 1127f4ba4e55SManish Rangankar 1128f4ba4e55SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1129f4ba4e55SManish Rangankar "HW error handler scheduled, err=%d err_flags=0x%x\n", 1130f4ba4e55SManish Rangankar err_type, qedi->qedi_err_flags); 1131f4ba4e55SManish Rangankar 1132f4ba4e55SManish Rangankar switch (err_type) { 11337dc71ac8SManish Rangankar case QED_HW_ERR_FAN_FAIL: 11347dc71ac8SManish Rangankar schedule_delayed_work(&qedi->board_disable_work, 0); 11357dc71ac8SManish Rangankar break; 1136f4ba4e55SManish Rangankar case QED_HW_ERR_MFW_RESP_FAIL: 1137f4ba4e55SManish Rangankar case QED_HW_ERR_HW_ATTN: 1138f4ba4e55SManish Rangankar case QED_HW_ERR_DMAE_FAIL: 1139f4ba4e55SManish Rangankar case QED_HW_ERR_RAMROD_FAIL: 1140f4ba4e55SManish Rangankar case QED_HW_ERR_FW_ASSERT: 1141f4ba4e55SManish Rangankar /* Prevent HW attentions from being reasserted */ 1142f4ba4e55SManish Rangankar if (test_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags)) 1143f4ba4e55SManish Rangankar qedi_ops->common->attn_clr_enable(qedi->cdev, true); 1144f4ba4e55SManish Rangankar 1145f4ba4e55SManish Rangankar if (err_type == QED_HW_ERR_RAMROD_FAIL && 1146f4ba4e55SManish Rangankar test_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags)) 1147f4ba4e55SManish Rangankar qedi_ops->common->recovery_process(qedi->cdev); 1148f4ba4e55SManish Rangankar 1149f4ba4e55SManish Rangankar break; 1150f4ba4e55SManish Rangankar default: 1151f4ba4e55SManish Rangankar break; 1152f4ba4e55SManish Rangankar } 1153f4ba4e55SManish Rangankar } 1154f4ba4e55SManish Rangankar 11554b1068f5SManish Rangankar static void qedi_schedule_recovery_handler(void *dev) 11564b1068f5SManish Rangankar { 11574b1068f5SManish Rangankar struct qedi_ctx *qedi = dev; 11584b1068f5SManish Rangankar 11594b1068f5SManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Recovery handler scheduled.\n"); 11604b1068f5SManish Rangankar 11614b1068f5SManish Rangankar if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) 11624b1068f5SManish Rangankar return; 11634b1068f5SManish Rangankar 11644b1068f5SManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 11654b1068f5SManish Rangankar 11664b1068f5SManish Rangankar schedule_delayed_work(&qedi->recovery_work, 0); 11674b1068f5SManish Rangankar } 11684b1068f5SManish Rangankar 11694118879bSNilesh Javali static void qedi_set_conn_recovery(struct iscsi_cls_session *cls_session) 11704118879bSNilesh Javali { 11714118879bSNilesh Javali struct iscsi_session *session = cls_session->dd_data; 11724118879bSNilesh Javali struct iscsi_conn *conn = session->leadconn; 11734118879bSNilesh Javali struct qedi_conn *qedi_conn = conn->dd_data; 11744118879bSNilesh Javali 11754118879bSNilesh Javali qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); 11764118879bSNilesh Javali } 11774118879bSNilesh Javali 1178ace7f46bSManish Rangankar static void qedi_link_update(void *dev, struct qed_link_output *link) 1179ace7f46bSManish Rangankar { 1180ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)dev; 1181ace7f46bSManish Rangankar 1182ace7f46bSManish Rangankar if (link->link_up) { 1183ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "Link Up event.\n"); 1184ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_UP); 1185ace7f46bSManish Rangankar } else { 1186ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1187ace7f46bSManish Rangankar "Link Down event.\n"); 1188ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 11894118879bSNilesh Javali iscsi_host_for_each_session(qedi->shost, qedi_set_conn_recovery); 1190ace7f46bSManish Rangankar } 1191ace7f46bSManish Rangankar } 1192ace7f46bSManish Rangankar 1193ace7f46bSManish Rangankar static struct qed_iscsi_cb_ops qedi_cb_ops = { 1194ace7f46bSManish Rangankar { 1195ace7f46bSManish Rangankar .link_update = qedi_link_update, 11964b1068f5SManish Rangankar .schedule_recovery_handler = qedi_schedule_recovery_handler, 1197f4ba4e55SManish Rangankar .schedule_hw_err_handler = qedi_schedule_hw_err_handler, 1198534bbdf8SManish Rangankar .get_protocol_tlv_data = qedi_get_protocol_tlv_data, 1199269afb36SManish Rangankar .get_generic_tlv_data = qedi_get_generic_tlv_data, 1200ace7f46bSManish Rangankar } 1201ace7f46bSManish Rangankar }; 1202ace7f46bSManish Rangankar 1203ace7f46bSManish Rangankar static int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe, 1204ace7f46bSManish Rangankar u16 que_idx, struct qedi_percpu_s *p) 1205ace7f46bSManish Rangankar { 1206ace7f46bSManish Rangankar struct qedi_work *qedi_work; 1207ace7f46bSManish Rangankar struct qedi_conn *q_conn; 1208ace7f46bSManish Rangankar struct qedi_cmd *qedi_cmd; 1209ace7f46bSManish Rangankar u32 iscsi_cid; 1210ace7f46bSManish Rangankar int rc = 0; 1211ace7f46bSManish Rangankar 1212ace7f46bSManish Rangankar iscsi_cid = cqe->cqe_common.conn_id; 1213ace7f46bSManish Rangankar q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; 1214ace7f46bSManish Rangankar if (!q_conn) { 1215ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1216ace7f46bSManish Rangankar "Session no longer exists for cid=0x%x!!\n", 1217ace7f46bSManish Rangankar iscsi_cid); 1218ace7f46bSManish Rangankar return -1; 1219ace7f46bSManish Rangankar } 1220ace7f46bSManish Rangankar 1221ace7f46bSManish Rangankar switch (cqe->cqe_common.cqe_type) { 1222ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_SOLICITED: 1223ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE: 1224ace7f46bSManish Rangankar qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid); 1225ace7f46bSManish Rangankar if (!qedi_cmd) { 1226ace7f46bSManish Rangankar rc = -1; 1227ace7f46bSManish Rangankar break; 1228ace7f46bSManish Rangankar } 1229ace7f46bSManish Rangankar INIT_LIST_HEAD(&qedi_cmd->cqe_work.list); 1230ace7f46bSManish Rangankar qedi_cmd->cqe_work.qedi = qedi; 1231ace7f46bSManish Rangankar memcpy(&qedi_cmd->cqe_work.cqe, cqe, sizeof(union iscsi_cqe)); 1232ace7f46bSManish Rangankar qedi_cmd->cqe_work.que_idx = que_idx; 1233ace7f46bSManish Rangankar qedi_cmd->cqe_work.is_solicited = true; 1234ace7f46bSManish Rangankar list_add_tail(&qedi_cmd->cqe_work.list, &p->work_list); 1235ace7f46bSManish Rangankar break; 1236ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_UNSOLICITED: 1237ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_DUMMY: 1238ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_TASK_CLEANUP: 1239ace7f46bSManish Rangankar qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC); 1240ace7f46bSManish Rangankar if (!qedi_work) { 1241ace7f46bSManish Rangankar rc = -1; 1242ace7f46bSManish Rangankar break; 1243ace7f46bSManish Rangankar } 1244ace7f46bSManish Rangankar INIT_LIST_HEAD(&qedi_work->list); 1245ace7f46bSManish Rangankar qedi_work->qedi = qedi; 1246ace7f46bSManish Rangankar memcpy(&qedi_work->cqe, cqe, sizeof(union iscsi_cqe)); 1247ace7f46bSManish Rangankar qedi_work->que_idx = que_idx; 1248ace7f46bSManish Rangankar qedi_work->is_solicited = false; 1249ace7f46bSManish Rangankar list_add_tail(&qedi_work->list, &p->work_list); 1250ace7f46bSManish Rangankar break; 1251ace7f46bSManish Rangankar default: 1252ace7f46bSManish Rangankar rc = -1; 1253ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "FW Error cqe.\n"); 1254ace7f46bSManish Rangankar } 1255ace7f46bSManish Rangankar return rc; 1256ace7f46bSManish Rangankar } 1257ace7f46bSManish Rangankar 1258ace7f46bSManish Rangankar static bool qedi_process_completions(struct qedi_fastpath *fp) 1259ace7f46bSManish Rangankar { 1260ace7f46bSManish Rangankar struct qedi_ctx *qedi = fp->qedi; 1261ace7f46bSManish Rangankar struct qed_sb_info *sb_info = fp->sb_info; 126221dd79e8STomer Tayar struct status_block_e4 *sb = sb_info->sb_virt; 1263ace7f46bSManish Rangankar struct qedi_percpu_s *p = NULL; 1264ace7f46bSManish Rangankar struct global_queue *que; 1265ace7f46bSManish Rangankar u16 prod_idx; 1266ace7f46bSManish Rangankar unsigned long flags; 1267ace7f46bSManish Rangankar union iscsi_cqe *cqe; 1268ace7f46bSManish Rangankar int cpu; 1269ace7f46bSManish Rangankar int ret; 1270ace7f46bSManish Rangankar 1271ace7f46bSManish Rangankar /* Get the current firmware producer index */ 1272ace7f46bSManish Rangankar prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; 1273ace7f46bSManish Rangankar 1274ace7f46bSManish Rangankar if (prod_idx >= QEDI_CQ_SIZE) 1275ace7f46bSManish Rangankar prod_idx = prod_idx % QEDI_CQ_SIZE; 1276ace7f46bSManish Rangankar 1277ace7f46bSManish Rangankar que = qedi->global_queues[fp->sb_id]; 1278ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, 1279ace7f46bSManish Rangankar "Before: global queue=%p prod_idx=%d cons_idx=%d, sb_id=%d\n", 1280ace7f46bSManish Rangankar que, prod_idx, que->cq_cons_idx, fp->sb_id); 1281ace7f46bSManish Rangankar 1282ace7f46bSManish Rangankar qedi->intr_cpu = fp->sb_id; 1283ace7f46bSManish Rangankar cpu = smp_processor_id(); 1284ace7f46bSManish Rangankar p = &per_cpu(qedi_percpu, cpu); 1285ace7f46bSManish Rangankar 1286ace7f46bSManish Rangankar if (unlikely(!p->iothread)) 1287ace7f46bSManish Rangankar WARN_ON(1); 1288ace7f46bSManish Rangankar 1289ace7f46bSManish Rangankar spin_lock_irqsave(&p->p_work_lock, flags); 1290ace7f46bSManish Rangankar while (que->cq_cons_idx != prod_idx) { 1291ace7f46bSManish Rangankar cqe = &que->cq[que->cq_cons_idx]; 1292ace7f46bSManish Rangankar 1293ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, 1294ace7f46bSManish Rangankar "cqe=%p prod_idx=%d cons_idx=%d.\n", 1295ace7f46bSManish Rangankar cqe, prod_idx, que->cq_cons_idx); 1296ace7f46bSManish Rangankar 1297ace7f46bSManish Rangankar ret = qedi_queue_cqe(qedi, cqe, fp->sb_id, p); 1298ace7f46bSManish Rangankar if (ret) 1299a1a20ffdSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1300a1a20ffdSManish Rangankar "Dropping CQE 0x%x for cid=0x%x.\n", 1301a1a20ffdSManish Rangankar que->cq_cons_idx, cqe->cqe_common.conn_id); 1302ace7f46bSManish Rangankar 1303ace7f46bSManish Rangankar que->cq_cons_idx++; 1304ace7f46bSManish Rangankar if (que->cq_cons_idx == QEDI_CQ_SIZE) 1305ace7f46bSManish Rangankar que->cq_cons_idx = 0; 1306ace7f46bSManish Rangankar } 1307ace7f46bSManish Rangankar wake_up_process(p->iothread); 1308ace7f46bSManish Rangankar spin_unlock_irqrestore(&p->p_work_lock, flags); 1309ace7f46bSManish Rangankar 1310ace7f46bSManish Rangankar return true; 1311ace7f46bSManish Rangankar } 1312ace7f46bSManish Rangankar 1313ace7f46bSManish Rangankar static bool qedi_fp_has_work(struct qedi_fastpath *fp) 1314ace7f46bSManish Rangankar { 1315ace7f46bSManish Rangankar struct qedi_ctx *qedi = fp->qedi; 1316ace7f46bSManish Rangankar struct global_queue *que; 1317ace7f46bSManish Rangankar struct qed_sb_info *sb_info = fp->sb_info; 131821dd79e8STomer Tayar struct status_block_e4 *sb = sb_info->sb_virt; 1319ace7f46bSManish Rangankar u16 prod_idx; 1320ace7f46bSManish Rangankar 1321ace7f46bSManish Rangankar barrier(); 1322ace7f46bSManish Rangankar 1323ace7f46bSManish Rangankar /* Get the current firmware producer index */ 1324ace7f46bSManish Rangankar prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; 1325ace7f46bSManish Rangankar 1326ace7f46bSManish Rangankar /* Get the pointer to the global CQ this completion is on */ 1327ace7f46bSManish Rangankar que = qedi->global_queues[fp->sb_id]; 1328ace7f46bSManish Rangankar 1329ace7f46bSManish Rangankar /* prod idx wrap around uint16 */ 1330ace7f46bSManish Rangankar if (prod_idx >= QEDI_CQ_SIZE) 1331ace7f46bSManish Rangankar prod_idx = prod_idx % QEDI_CQ_SIZE; 1332ace7f46bSManish Rangankar 1333ace7f46bSManish Rangankar return (que->cq_cons_idx != prod_idx); 1334ace7f46bSManish Rangankar } 1335ace7f46bSManish Rangankar 1336ace7f46bSManish Rangankar /* MSI-X fastpath handler code */ 1337ace7f46bSManish Rangankar static irqreturn_t qedi_msix_handler(int irq, void *dev_id) 1338ace7f46bSManish Rangankar { 1339ace7f46bSManish Rangankar struct qedi_fastpath *fp = dev_id; 1340ace7f46bSManish Rangankar struct qedi_ctx *qedi = fp->qedi; 1341ace7f46bSManish Rangankar bool wake_io_thread = true; 1342ace7f46bSManish Rangankar 1343ace7f46bSManish Rangankar qed_sb_ack(fp->sb_info, IGU_INT_DISABLE, 0); 1344ace7f46bSManish Rangankar 1345ace7f46bSManish Rangankar process_again: 1346ace7f46bSManish Rangankar wake_io_thread = qedi_process_completions(fp); 1347ace7f46bSManish Rangankar if (wake_io_thread) { 1348ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 1349ace7f46bSManish Rangankar "process already running\n"); 1350ace7f46bSManish Rangankar } 1351ace7f46bSManish Rangankar 13529187745cSJason Yan if (!qedi_fp_has_work(fp)) 1353ace7f46bSManish Rangankar qed_sb_update_sb_idx(fp->sb_info); 1354ace7f46bSManish Rangankar 1355ace7f46bSManish Rangankar /* Check for more work */ 1356ace7f46bSManish Rangankar rmb(); 1357ace7f46bSManish Rangankar 13589187745cSJason Yan if (!qedi_fp_has_work(fp)) 1359ace7f46bSManish Rangankar qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1); 1360ace7f46bSManish Rangankar else 1361ace7f46bSManish Rangankar goto process_again; 1362ace7f46bSManish Rangankar 1363ace7f46bSManish Rangankar return IRQ_HANDLED; 1364ace7f46bSManish Rangankar } 1365ace7f46bSManish Rangankar 1366ace7f46bSManish Rangankar /* simd handler for MSI/INTa */ 1367ace7f46bSManish Rangankar static void qedi_simd_int_handler(void *cookie) 1368ace7f46bSManish Rangankar { 1369ace7f46bSManish Rangankar /* Cookie is qedi_ctx struct */ 1370ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; 1371ace7f46bSManish Rangankar 1372ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, "qedi=%p.\n", qedi); 1373ace7f46bSManish Rangankar } 1374ace7f46bSManish Rangankar 1375ace7f46bSManish Rangankar #define QEDI_SIMD_HANDLER_NUM 0 1376ace7f46bSManish Rangankar static void qedi_sync_free_irqs(struct qedi_ctx *qedi) 1377ace7f46bSManish Rangankar { 1378ace7f46bSManish Rangankar int i; 13792bfbc570SManish Rangankar u16 idx; 1380ace7f46bSManish Rangankar 1381ace7f46bSManish Rangankar if (qedi->int_info.msix_cnt) { 1382ace7f46bSManish Rangankar for (i = 0; i < qedi->int_info.used_cnt; i++) { 13832bfbc570SManish Rangankar idx = i * qedi->dev_info.common.num_hwfns + 13842bfbc570SManish Rangankar qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); 13852bfbc570SManish Rangankar 13862bfbc570SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 13872bfbc570SManish Rangankar "Freeing IRQ #%d vector_idx=%d.\n", i, idx); 13882bfbc570SManish Rangankar 13892bfbc570SManish Rangankar synchronize_irq(qedi->int_info.msix[idx].vector); 13902bfbc570SManish Rangankar irq_set_affinity_hint(qedi->int_info.msix[idx].vector, 1391ace7f46bSManish Rangankar NULL); 13922bfbc570SManish Rangankar free_irq(qedi->int_info.msix[idx].vector, 1393ace7f46bSManish Rangankar &qedi->fp_array[i]); 1394ace7f46bSManish Rangankar } 1395ace7f46bSManish Rangankar } else { 1396ace7f46bSManish Rangankar qedi_ops->common->simd_handler_clean(qedi->cdev, 1397ace7f46bSManish Rangankar QEDI_SIMD_HANDLER_NUM); 1398ace7f46bSManish Rangankar } 1399ace7f46bSManish Rangankar 1400ace7f46bSManish Rangankar qedi->int_info.used_cnt = 0; 1401ace7f46bSManish Rangankar qedi_ops->common->set_fp_int(qedi->cdev, 0); 1402ace7f46bSManish Rangankar } 1403ace7f46bSManish Rangankar 1404ace7f46bSManish Rangankar static int qedi_request_msix_irq(struct qedi_ctx *qedi) 1405ace7f46bSManish Rangankar { 1406ace7f46bSManish Rangankar int i, rc, cpu; 14072bfbc570SManish Rangankar u16 idx; 1408ace7f46bSManish Rangankar 1409ace7f46bSManish Rangankar cpu = cpumask_first(cpu_online_mask); 14103f8ad007SManish Rangankar for (i = 0; i < qedi->msix_count; i++) { 14112bfbc570SManish Rangankar idx = i * qedi->dev_info.common.num_hwfns + 14122bfbc570SManish Rangankar qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); 14132bfbc570SManish Rangankar 14142bfbc570SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 14152bfbc570SManish Rangankar "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", 14162bfbc570SManish Rangankar qedi->dev_info.common.num_hwfns, 14172bfbc570SManish Rangankar qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); 14182bfbc570SManish Rangankar 14192bfbc570SManish Rangankar rc = request_irq(qedi->int_info.msix[idx].vector, 1420ace7f46bSManish Rangankar qedi_msix_handler, 0, "qedi", 1421ace7f46bSManish Rangankar &qedi->fp_array[i]); 1422ace7f46bSManish Rangankar if (rc) { 1423ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); 1424ace7f46bSManish Rangankar qedi_sync_free_irqs(qedi); 1425ace7f46bSManish Rangankar return rc; 1426ace7f46bSManish Rangankar } 1427ace7f46bSManish Rangankar qedi->int_info.used_cnt++; 14282bfbc570SManish Rangankar rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector, 1429ace7f46bSManish Rangankar get_cpu_mask(cpu)); 1430ace7f46bSManish Rangankar cpu = cpumask_next(cpu, cpu_online_mask); 1431ace7f46bSManish Rangankar } 1432ace7f46bSManish Rangankar 1433ace7f46bSManish Rangankar return 0; 1434ace7f46bSManish Rangankar } 1435ace7f46bSManish Rangankar 1436ace7f46bSManish Rangankar static int qedi_setup_int(struct qedi_ctx *qedi) 1437ace7f46bSManish Rangankar { 1438ace7f46bSManish Rangankar int rc = 0; 1439ace7f46bSManish Rangankar 14403f8ad007SManish Rangankar rc = qedi_ops->common->set_fp_int(qedi->cdev, qedi->num_queues); 14413f8ad007SManish Rangankar if (rc < 0) 14423f8ad007SManish Rangankar goto exit_setup_int; 14433f8ad007SManish Rangankar 14443f8ad007SManish Rangankar qedi->msix_count = rc; 14453f8ad007SManish Rangankar 1446ace7f46bSManish Rangankar rc = qedi_ops->common->get_fp_int(qedi->cdev, &qedi->int_info); 1447ace7f46bSManish Rangankar if (rc) 1448ace7f46bSManish Rangankar goto exit_setup_int; 1449ace7f46bSManish Rangankar 1450ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 1451ace7f46bSManish Rangankar "Number of msix_cnt = 0x%x num of cpus = 0x%x\n", 1452ace7f46bSManish Rangankar qedi->int_info.msix_cnt, num_online_cpus()); 1453ace7f46bSManish Rangankar 1454ace7f46bSManish Rangankar if (qedi->int_info.msix_cnt) { 1455ace7f46bSManish Rangankar rc = qedi_request_msix_irq(qedi); 1456ace7f46bSManish Rangankar goto exit_setup_int; 1457ace7f46bSManish Rangankar } else { 1458ace7f46bSManish Rangankar qedi_ops->common->simd_handler_config(qedi->cdev, &qedi, 1459ace7f46bSManish Rangankar QEDI_SIMD_HANDLER_NUM, 1460ace7f46bSManish Rangankar qedi_simd_int_handler); 1461ace7f46bSManish Rangankar qedi->int_info.used_cnt = 1; 1462ace7f46bSManish Rangankar } 1463ace7f46bSManish Rangankar 1464ace7f46bSManish Rangankar exit_setup_int: 1465ace7f46bSManish Rangankar return rc; 1466ace7f46bSManish Rangankar } 1467ace7f46bSManish Rangankar 1468c57ec8fbSNilesh Javali static void qedi_free_nvm_iscsi_cfg(struct qedi_ctx *qedi) 1469c57ec8fbSNilesh Javali { 1470c77a2fa3SNilesh Javali if (qedi->iscsi_image) 1471c57ec8fbSNilesh Javali dma_free_coherent(&qedi->pdev->dev, 1472c77a2fa3SNilesh Javali sizeof(struct qedi_nvm_iscsi_image), 1473c77a2fa3SNilesh Javali qedi->iscsi_image, qedi->nvm_buf_dma); 1474c57ec8fbSNilesh Javali } 1475c57ec8fbSNilesh Javali 1476c57ec8fbSNilesh Javali static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi) 1477c57ec8fbSNilesh Javali { 1478750afb08SLuis Chamberlain qedi->iscsi_image = dma_alloc_coherent(&qedi->pdev->dev, 1479872e192fSColin Ian King sizeof(struct qedi_nvm_iscsi_image), 1480750afb08SLuis Chamberlain &qedi->nvm_buf_dma, GFP_KERNEL); 1481c77a2fa3SNilesh Javali if (!qedi->iscsi_image) { 1482c57ec8fbSNilesh Javali QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n"); 1483c57ec8fbSNilesh Javali return -ENOMEM; 1484c57ec8fbSNilesh Javali } 1485c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1486c77a2fa3SNilesh Javali "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_image, 1487c57ec8fbSNilesh Javali qedi->nvm_buf_dma); 1488c57ec8fbSNilesh Javali 1489c57ec8fbSNilesh Javali return 0; 1490c57ec8fbSNilesh Javali } 1491c57ec8fbSNilesh Javali 1492ace7f46bSManish Rangankar static void qedi_free_bdq(struct qedi_ctx *qedi) 1493ace7f46bSManish Rangankar { 1494ace7f46bSManish Rangankar int i; 1495ace7f46bSManish Rangankar 1496ace7f46bSManish Rangankar if (qedi->bdq_pbl_list) 1497fa97c511SNilesh Javali dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, 1498ace7f46bSManish Rangankar qedi->bdq_pbl_list, qedi->bdq_pbl_list_dma); 1499ace7f46bSManish Rangankar 1500ace7f46bSManish Rangankar if (qedi->bdq_pbl) 1501ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, qedi->bdq_pbl_mem_size, 1502ace7f46bSManish Rangankar qedi->bdq_pbl, qedi->bdq_pbl_dma); 1503ace7f46bSManish Rangankar 1504ace7f46bSManish Rangankar for (i = 0; i < QEDI_BDQ_NUM; i++) { 1505ace7f46bSManish Rangankar if (qedi->bdq[i].buf_addr) { 1506ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, QEDI_BDQ_BUF_SIZE, 1507ace7f46bSManish Rangankar qedi->bdq[i].buf_addr, 1508ace7f46bSManish Rangankar qedi->bdq[i].buf_dma); 1509ace7f46bSManish Rangankar } 1510ace7f46bSManish Rangankar } 1511ace7f46bSManish Rangankar } 1512ace7f46bSManish Rangankar 1513ace7f46bSManish Rangankar static void qedi_free_global_queues(struct qedi_ctx *qedi) 1514ace7f46bSManish Rangankar { 1515ace7f46bSManish Rangankar int i; 1516ace7f46bSManish Rangankar struct global_queue **gl = qedi->global_queues; 1517ace7f46bSManish Rangankar 1518ace7f46bSManish Rangankar for (i = 0; i < qedi->num_queues; i++) { 1519ace7f46bSManish Rangankar if (!gl[i]) 1520ace7f46bSManish Rangankar continue; 1521ace7f46bSManish Rangankar 1522ace7f46bSManish Rangankar if (gl[i]->cq) 1523ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_mem_size, 1524ace7f46bSManish Rangankar gl[i]->cq, gl[i]->cq_dma); 1525ace7f46bSManish Rangankar if (gl[i]->cq_pbl) 1526ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_pbl_size, 1527ace7f46bSManish Rangankar gl[i]->cq_pbl, gl[i]->cq_pbl_dma); 1528ace7f46bSManish Rangankar 1529ace7f46bSManish Rangankar kfree(gl[i]); 1530ace7f46bSManish Rangankar } 1531ace7f46bSManish Rangankar qedi_free_bdq(qedi); 1532c57ec8fbSNilesh Javali qedi_free_nvm_iscsi_cfg(qedi); 1533ace7f46bSManish Rangankar } 1534ace7f46bSManish Rangankar 1535ace7f46bSManish Rangankar static int qedi_alloc_bdq(struct qedi_ctx *qedi) 1536ace7f46bSManish Rangankar { 1537ace7f46bSManish Rangankar int i; 1538ace7f46bSManish Rangankar struct scsi_bd *pbl; 1539ace7f46bSManish Rangankar u64 *list; 1540ace7f46bSManish Rangankar dma_addr_t page; 1541ace7f46bSManish Rangankar 1542ace7f46bSManish Rangankar /* Alloc dma memory for BDQ buffers */ 1543ace7f46bSManish Rangankar for (i = 0; i < QEDI_BDQ_NUM; i++) { 1544ace7f46bSManish Rangankar qedi->bdq[i].buf_addr = 1545ace7f46bSManish Rangankar dma_alloc_coherent(&qedi->pdev->dev, 1546ace7f46bSManish Rangankar QEDI_BDQ_BUF_SIZE, 1547ace7f46bSManish Rangankar &qedi->bdq[i].buf_dma, 1548ace7f46bSManish Rangankar GFP_KERNEL); 1549ace7f46bSManish Rangankar if (!qedi->bdq[i].buf_addr) { 1550ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1551ace7f46bSManish Rangankar "Could not allocate BDQ buffer %d.\n", i); 1552ace7f46bSManish Rangankar return -ENOMEM; 1553ace7f46bSManish Rangankar } 1554ace7f46bSManish Rangankar } 1555ace7f46bSManish Rangankar 1556ace7f46bSManish Rangankar /* Alloc dma memory for BDQ page buffer list */ 1557ace7f46bSManish Rangankar qedi->bdq_pbl_mem_size = QEDI_BDQ_NUM * sizeof(struct scsi_bd); 1558fa97c511SNilesh Javali qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, QEDI_PAGE_SIZE); 1559ace7f46bSManish Rangankar qedi->rq_num_entries = qedi->bdq_pbl_mem_size / sizeof(struct scsi_bd); 1560ace7f46bSManish Rangankar 1561ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, "rq_num_entries = %d.\n", 1562ace7f46bSManish Rangankar qedi->rq_num_entries); 1563ace7f46bSManish Rangankar 1564ace7f46bSManish Rangankar qedi->bdq_pbl = dma_alloc_coherent(&qedi->pdev->dev, 1565ace7f46bSManish Rangankar qedi->bdq_pbl_mem_size, 1566ace7f46bSManish Rangankar &qedi->bdq_pbl_dma, GFP_KERNEL); 1567ace7f46bSManish Rangankar if (!qedi->bdq_pbl) { 1568ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Could not allocate BDQ PBL.\n"); 1569ace7f46bSManish Rangankar return -ENOMEM; 1570ace7f46bSManish Rangankar } 1571ace7f46bSManish Rangankar 1572ace7f46bSManish Rangankar /* 1573ace7f46bSManish Rangankar * Populate BDQ PBL with physical and virtual address of individual 1574ace7f46bSManish Rangankar * BDQ buffers 1575ace7f46bSManish Rangankar */ 1576ace7f46bSManish Rangankar pbl = (struct scsi_bd *)qedi->bdq_pbl; 1577ace7f46bSManish Rangankar for (i = 0; i < QEDI_BDQ_NUM; i++) { 1578ace7f46bSManish Rangankar pbl->address.hi = 1579ace7f46bSManish Rangankar cpu_to_le32(QEDI_U64_HI(qedi->bdq[i].buf_dma)); 1580ace7f46bSManish Rangankar pbl->address.lo = 1581ace7f46bSManish Rangankar cpu_to_le32(QEDI_U64_LO(qedi->bdq[i].buf_dma)); 1582ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1583ace7f46bSManish Rangankar "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx], idx [%d]\n", 1584ace7f46bSManish Rangankar pbl, pbl->address.hi, pbl->address.lo, i); 1585da090917STomer Tayar pbl->opaque.iscsi_opaque.reserved_zero[0] = 0; 1586da090917STomer Tayar pbl->opaque.iscsi_opaque.reserved_zero[1] = 0; 1587da090917STomer Tayar pbl->opaque.iscsi_opaque.reserved_zero[2] = 0; 1588da090917STomer Tayar pbl->opaque.iscsi_opaque.opaque = cpu_to_le16(i); 1589ace7f46bSManish Rangankar pbl++; 1590ace7f46bSManish Rangankar } 1591ace7f46bSManish Rangankar 1592ace7f46bSManish Rangankar /* Allocate list of PBL pages */ 1593750afb08SLuis Chamberlain qedi->bdq_pbl_list = dma_alloc_coherent(&qedi->pdev->dev, 1594fa97c511SNilesh Javali QEDI_PAGE_SIZE, 1595ace7f46bSManish Rangankar &qedi->bdq_pbl_list_dma, 1596ace7f46bSManish Rangankar GFP_KERNEL); 1597ace7f46bSManish Rangankar if (!qedi->bdq_pbl_list) { 1598ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1599ace7f46bSManish Rangankar "Could not allocate list of PBL pages.\n"); 1600ace7f46bSManish Rangankar return -ENOMEM; 1601ace7f46bSManish Rangankar } 1602ace7f46bSManish Rangankar 1603ace7f46bSManish Rangankar /* 1604ace7f46bSManish Rangankar * Now populate PBL list with pages that contain pointers to the 1605ace7f46bSManish Rangankar * individual buffers. 1606ace7f46bSManish Rangankar */ 1607fa97c511SNilesh Javali qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / 1608fa97c511SNilesh Javali QEDI_PAGE_SIZE; 1609ace7f46bSManish Rangankar list = (u64 *)qedi->bdq_pbl_list; 1610ace7f46bSManish Rangankar page = qedi->bdq_pbl_list_dma; 1611ace7f46bSManish Rangankar for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) { 1612ace7f46bSManish Rangankar *list = qedi->bdq_pbl_dma; 1613ace7f46bSManish Rangankar list++; 1614fa97c511SNilesh Javali page += QEDI_PAGE_SIZE; 1615ace7f46bSManish Rangankar } 1616ace7f46bSManish Rangankar 1617ace7f46bSManish Rangankar return 0; 1618ace7f46bSManish Rangankar } 1619ace7f46bSManish Rangankar 1620ace7f46bSManish Rangankar static int qedi_alloc_global_queues(struct qedi_ctx *qedi) 1621ace7f46bSManish Rangankar { 1622ace7f46bSManish Rangankar u32 *list; 1623ace7f46bSManish Rangankar int i; 1624ace7f46bSManish Rangankar int status = 0, rc; 1625ace7f46bSManish Rangankar u32 *pbl; 1626ace7f46bSManish Rangankar dma_addr_t page; 1627ace7f46bSManish Rangankar int num_pages; 1628ace7f46bSManish Rangankar 1629ace7f46bSManish Rangankar /* 1630ace7f46bSManish Rangankar * Number of global queues (CQ / RQ). This should 1631ace7f46bSManish Rangankar * be <= number of available MSIX vectors for the PF 1632ace7f46bSManish Rangankar */ 1633ace7f46bSManish Rangankar if (!qedi->num_queues) { 1634ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "No MSI-X vectors available!\n"); 1635ace7f46bSManish Rangankar return 1; 1636ace7f46bSManish Rangankar } 1637ace7f46bSManish Rangankar 1638ace7f46bSManish Rangankar /* Make sure we allocated the PBL that will contain the physical 1639ace7f46bSManish Rangankar * addresses of our queues 1640ace7f46bSManish Rangankar */ 1641ace7f46bSManish Rangankar if (!qedi->p_cpuq) { 1642ace7f46bSManish Rangankar status = 1; 1643ace7f46bSManish Rangankar goto mem_alloc_failure; 1644ace7f46bSManish Rangankar } 1645ace7f46bSManish Rangankar 1646ace7f46bSManish Rangankar qedi->global_queues = kzalloc((sizeof(struct global_queue *) * 1647ace7f46bSManish Rangankar qedi->num_queues), GFP_KERNEL); 1648ace7f46bSManish Rangankar if (!qedi->global_queues) { 1649ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1650ace7f46bSManish Rangankar "Unable to allocate global queues array ptr memory\n"); 1651ace7f46bSManish Rangankar return -ENOMEM; 1652ace7f46bSManish Rangankar } 1653ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 1654ace7f46bSManish Rangankar "qedi->global_queues=%p.\n", qedi->global_queues); 1655ace7f46bSManish Rangankar 1656ace7f46bSManish Rangankar /* Allocate DMA coherent buffers for BDQ */ 1657ace7f46bSManish Rangankar rc = qedi_alloc_bdq(qedi); 1658ace7f46bSManish Rangankar if (rc) 1659ace7f46bSManish Rangankar goto mem_alloc_failure; 1660ace7f46bSManish Rangankar 1661c57ec8fbSNilesh Javali /* Allocate DMA coherent buffers for NVM_ISCSI_CFG */ 1662c57ec8fbSNilesh Javali rc = qedi_alloc_nvm_iscsi_cfg(qedi); 1663c57ec8fbSNilesh Javali if (rc) 1664c57ec8fbSNilesh Javali goto mem_alloc_failure; 1665c57ec8fbSNilesh Javali 1666ace7f46bSManish Rangankar /* Allocate a CQ and an associated PBL for each MSI-X 1667ace7f46bSManish Rangankar * vector. 1668ace7f46bSManish Rangankar */ 1669ace7f46bSManish Rangankar for (i = 0; i < qedi->num_queues; i++) { 1670ace7f46bSManish Rangankar qedi->global_queues[i] = 1671ace7f46bSManish Rangankar kzalloc(sizeof(*qedi->global_queues[0]), 1672ace7f46bSManish Rangankar GFP_KERNEL); 1673ace7f46bSManish Rangankar if (!qedi->global_queues[i]) { 1674ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1675ace7f46bSManish Rangankar "Unable to allocation global queue %d.\n", i); 1676f6995383SJia-Ju Bai status = -ENOMEM; 1677ace7f46bSManish Rangankar goto mem_alloc_failure; 1678ace7f46bSManish Rangankar } 1679ace7f46bSManish Rangankar 1680ace7f46bSManish Rangankar qedi->global_queues[i]->cq_mem_size = 1681ace7f46bSManish Rangankar (QEDI_CQ_SIZE + 8) * sizeof(union iscsi_cqe); 1682ace7f46bSManish Rangankar qedi->global_queues[i]->cq_mem_size = 1683ace7f46bSManish Rangankar (qedi->global_queues[i]->cq_mem_size + 1684ace7f46bSManish Rangankar (QEDI_PAGE_SIZE - 1)); 1685ace7f46bSManish Rangankar 1686ace7f46bSManish Rangankar qedi->global_queues[i]->cq_pbl_size = 1687ace7f46bSManish Rangankar (qedi->global_queues[i]->cq_mem_size / 1688ace7f46bSManish Rangankar QEDI_PAGE_SIZE) * sizeof(void *); 1689ace7f46bSManish Rangankar qedi->global_queues[i]->cq_pbl_size = 1690ace7f46bSManish Rangankar (qedi->global_queues[i]->cq_pbl_size + 1691ace7f46bSManish Rangankar (QEDI_PAGE_SIZE - 1)); 1692ace7f46bSManish Rangankar 1693750afb08SLuis Chamberlain qedi->global_queues[i]->cq = dma_alloc_coherent(&qedi->pdev->dev, 1694ace7f46bSManish Rangankar qedi->global_queues[i]->cq_mem_size, 1695ace7f46bSManish Rangankar &qedi->global_queues[i]->cq_dma, 1696ace7f46bSManish Rangankar GFP_KERNEL); 1697ace7f46bSManish Rangankar 1698ace7f46bSManish Rangankar if (!qedi->global_queues[i]->cq) { 1699ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1700ace7f46bSManish Rangankar "Could not allocate cq.\n"); 1701ace7f46bSManish Rangankar status = -ENOMEM; 1702ace7f46bSManish Rangankar goto mem_alloc_failure; 1703ace7f46bSManish Rangankar } 1704750afb08SLuis Chamberlain qedi->global_queues[i]->cq_pbl = dma_alloc_coherent(&qedi->pdev->dev, 1705ace7f46bSManish Rangankar qedi->global_queues[i]->cq_pbl_size, 1706ace7f46bSManish Rangankar &qedi->global_queues[i]->cq_pbl_dma, 1707ace7f46bSManish Rangankar GFP_KERNEL); 1708ace7f46bSManish Rangankar 1709ace7f46bSManish Rangankar if (!qedi->global_queues[i]->cq_pbl) { 1710ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1711ace7f46bSManish Rangankar "Could not allocate cq PBL.\n"); 1712ace7f46bSManish Rangankar status = -ENOMEM; 1713ace7f46bSManish Rangankar goto mem_alloc_failure; 1714ace7f46bSManish Rangankar } 1715ace7f46bSManish Rangankar 1716ace7f46bSManish Rangankar /* Create PBL */ 1717ace7f46bSManish Rangankar num_pages = qedi->global_queues[i]->cq_mem_size / 1718ace7f46bSManish Rangankar QEDI_PAGE_SIZE; 1719ace7f46bSManish Rangankar page = qedi->global_queues[i]->cq_dma; 1720ace7f46bSManish Rangankar pbl = (u32 *)qedi->global_queues[i]->cq_pbl; 1721ace7f46bSManish Rangankar 1722ace7f46bSManish Rangankar while (num_pages--) { 1723ace7f46bSManish Rangankar *pbl = (u32)page; 1724ace7f46bSManish Rangankar pbl++; 1725ace7f46bSManish Rangankar *pbl = (u32)((u64)page >> 32); 1726ace7f46bSManish Rangankar pbl++; 1727ace7f46bSManish Rangankar page += QEDI_PAGE_SIZE; 1728ace7f46bSManish Rangankar } 1729ace7f46bSManish Rangankar } 1730ace7f46bSManish Rangankar 1731ace7f46bSManish Rangankar list = (u32 *)qedi->p_cpuq; 1732ace7f46bSManish Rangankar 1733ace7f46bSManish Rangankar /* 1734ace7f46bSManish Rangankar * The list is built as follows: CQ#0 PBL pointer, RQ#0 PBL pointer, 1735ace7f46bSManish Rangankar * CQ#1 PBL pointer, RQ#1 PBL pointer, etc. Each PBL pointer points 1736ace7f46bSManish Rangankar * to the physical address which contains an array of pointers to the 1737ace7f46bSManish Rangankar * physical addresses of the specific queue pages. 1738ace7f46bSManish Rangankar */ 1739ace7f46bSManish Rangankar for (i = 0; i < qedi->num_queues; i++) { 1740ace7f46bSManish Rangankar *list = (u32)qedi->global_queues[i]->cq_pbl_dma; 1741ace7f46bSManish Rangankar list++; 1742ace7f46bSManish Rangankar *list = (u32)((u64)qedi->global_queues[i]->cq_pbl_dma >> 32); 1743ace7f46bSManish Rangankar list++; 1744ace7f46bSManish Rangankar 1745ace7f46bSManish Rangankar *list = (u32)0; 1746ace7f46bSManish Rangankar list++; 1747ace7f46bSManish Rangankar *list = (u32)((u64)0 >> 32); 1748ace7f46bSManish Rangankar list++; 1749ace7f46bSManish Rangankar } 1750ace7f46bSManish Rangankar 1751ace7f46bSManish Rangankar return 0; 1752ace7f46bSManish Rangankar 1753ace7f46bSManish Rangankar mem_alloc_failure: 1754ace7f46bSManish Rangankar qedi_free_global_queues(qedi); 1755ace7f46bSManish Rangankar return status; 1756ace7f46bSManish Rangankar } 1757ace7f46bSManish Rangankar 1758ace7f46bSManish Rangankar int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) 1759ace7f46bSManish Rangankar { 1760ace7f46bSManish Rangankar int rval = 0; 1761ace7f46bSManish Rangankar u32 *pbl; 1762ace7f46bSManish Rangankar dma_addr_t page; 1763ace7f46bSManish Rangankar int num_pages; 1764ace7f46bSManish Rangankar 1765ace7f46bSManish Rangankar if (!ep) 1766ace7f46bSManish Rangankar return -EIO; 1767ace7f46bSManish Rangankar 1768ace7f46bSManish Rangankar /* Calculate appropriate queue and PBL sizes */ 1769ace7f46bSManish Rangankar ep->sq_mem_size = QEDI_SQ_SIZE * sizeof(struct iscsi_wqe); 1770ace7f46bSManish Rangankar ep->sq_mem_size += QEDI_PAGE_SIZE - 1; 1771ace7f46bSManish Rangankar 1772ace7f46bSManish Rangankar ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *); 1773ace7f46bSManish Rangankar ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE; 1774ace7f46bSManish Rangankar 1775750afb08SLuis Chamberlain ep->sq = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, 1776ace7f46bSManish Rangankar &ep->sq_dma, GFP_KERNEL); 1777ace7f46bSManish Rangankar if (!ep->sq) { 1778ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1779ace7f46bSManish Rangankar "Could not allocate send queue.\n"); 1780ace7f46bSManish Rangankar rval = -ENOMEM; 1781ace7f46bSManish Rangankar goto out; 1782ace7f46bSManish Rangankar } 1783750afb08SLuis Chamberlain ep->sq_pbl = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, 1784ace7f46bSManish Rangankar &ep->sq_pbl_dma, GFP_KERNEL); 1785ace7f46bSManish Rangankar if (!ep->sq_pbl) { 1786ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1787ace7f46bSManish Rangankar "Could not allocate send queue PBL.\n"); 1788ace7f46bSManish Rangankar rval = -ENOMEM; 1789ace7f46bSManish Rangankar goto out_free_sq; 1790ace7f46bSManish Rangankar } 1791ace7f46bSManish Rangankar 1792ace7f46bSManish Rangankar /* Create PBL */ 1793ace7f46bSManish Rangankar num_pages = ep->sq_mem_size / QEDI_PAGE_SIZE; 1794ace7f46bSManish Rangankar page = ep->sq_dma; 1795ace7f46bSManish Rangankar pbl = (u32 *)ep->sq_pbl; 1796ace7f46bSManish Rangankar 1797ace7f46bSManish Rangankar while (num_pages--) { 1798ace7f46bSManish Rangankar *pbl = (u32)page; 1799ace7f46bSManish Rangankar pbl++; 1800ace7f46bSManish Rangankar *pbl = (u32)((u64)page >> 32); 1801ace7f46bSManish Rangankar pbl++; 1802ace7f46bSManish Rangankar page += QEDI_PAGE_SIZE; 1803ace7f46bSManish Rangankar } 1804ace7f46bSManish Rangankar 1805ace7f46bSManish Rangankar return rval; 1806ace7f46bSManish Rangankar 1807ace7f46bSManish Rangankar out_free_sq: 1808ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, 1809ace7f46bSManish Rangankar ep->sq_dma); 1810ace7f46bSManish Rangankar out: 1811ace7f46bSManish Rangankar return rval; 1812ace7f46bSManish Rangankar } 1813ace7f46bSManish Rangankar 1814ace7f46bSManish Rangankar void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) 1815ace7f46bSManish Rangankar { 1816ace7f46bSManish Rangankar if (ep->sq_pbl) 1817ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, ep->sq_pbl_size, ep->sq_pbl, 1818ace7f46bSManish Rangankar ep->sq_pbl_dma); 1819ace7f46bSManish Rangankar if (ep->sq) 1820ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, 1821ace7f46bSManish Rangankar ep->sq_dma); 1822ace7f46bSManish Rangankar } 1823ace7f46bSManish Rangankar 1824ace7f46bSManish Rangankar int qedi_get_task_idx(struct qedi_ctx *qedi) 1825ace7f46bSManish Rangankar { 1826ace7f46bSManish Rangankar s16 tmp_idx; 1827ace7f46bSManish Rangankar 1828ace7f46bSManish Rangankar again: 1829ace7f46bSManish Rangankar tmp_idx = find_first_zero_bit(qedi->task_idx_map, 1830ace7f46bSManish Rangankar MAX_ISCSI_TASK_ENTRIES); 1831ace7f46bSManish Rangankar 1832ace7f46bSManish Rangankar if (tmp_idx >= MAX_ISCSI_TASK_ENTRIES) { 1833ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "FW task context pool is full.\n"); 1834ace7f46bSManish Rangankar tmp_idx = -1; 1835ace7f46bSManish Rangankar goto err_idx; 1836ace7f46bSManish Rangankar } 1837ace7f46bSManish Rangankar 1838ace7f46bSManish Rangankar if (test_and_set_bit(tmp_idx, qedi->task_idx_map)) 1839ace7f46bSManish Rangankar goto again; 1840ace7f46bSManish Rangankar 1841ace7f46bSManish Rangankar err_idx: 1842ace7f46bSManish Rangankar return tmp_idx; 1843ace7f46bSManish Rangankar } 1844ace7f46bSManish Rangankar 1845ace7f46bSManish Rangankar void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx) 1846ace7f46bSManish Rangankar { 184702d94e04SManish Rangankar if (!test_and_clear_bit(idx, qedi->task_idx_map)) 1848ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1849ace7f46bSManish Rangankar "FW task context, already cleared, tid=0x%x\n", idx); 1850ace7f46bSManish Rangankar } 1851ace7f46bSManish Rangankar 1852ace7f46bSManish Rangankar void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, 1853ace7f46bSManish Rangankar struct qedi_cmd *cmd) 1854ace7f46bSManish Rangankar { 1855ace7f46bSManish Rangankar qedi->itt_map[tid].itt = proto_itt; 1856ace7f46bSManish Rangankar qedi->itt_map[tid].p_cmd = cmd; 1857ace7f46bSManish Rangankar 1858ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1859ace7f46bSManish Rangankar "update itt map tid=0x%x, with proto itt=0x%x\n", tid, 1860ace7f46bSManish Rangankar qedi->itt_map[tid].itt); 1861ace7f46bSManish Rangankar } 1862ace7f46bSManish Rangankar 1863ace7f46bSManish Rangankar void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid) 1864ace7f46bSManish Rangankar { 1865ace7f46bSManish Rangankar u16 i; 1866ace7f46bSManish Rangankar 1867ace7f46bSManish Rangankar for (i = 0; i < MAX_ISCSI_TASK_ENTRIES; i++) { 1868ace7f46bSManish Rangankar if (qedi->itt_map[i].itt == itt) { 1869ace7f46bSManish Rangankar *tid = i; 1870ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1871ace7f46bSManish Rangankar "Ref itt=0x%x, found at tid=0x%x\n", 1872ace7f46bSManish Rangankar itt, *tid); 1873ace7f46bSManish Rangankar return; 1874ace7f46bSManish Rangankar } 1875ace7f46bSManish Rangankar } 1876ace7f46bSManish Rangankar 1877ace7f46bSManish Rangankar WARN_ON(1); 1878ace7f46bSManish Rangankar } 1879ace7f46bSManish Rangankar 1880ace7f46bSManish Rangankar void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt) 1881ace7f46bSManish Rangankar { 1882ace7f46bSManish Rangankar *proto_itt = qedi->itt_map[tid].itt; 1883ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1884ace7f46bSManish Rangankar "Get itt map tid [0x%x with proto itt[0x%x]", 1885ace7f46bSManish Rangankar tid, *proto_itt); 1886ace7f46bSManish Rangankar } 1887ace7f46bSManish Rangankar 1888ace7f46bSManish Rangankar struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) 1889ace7f46bSManish Rangankar { 1890ace7f46bSManish Rangankar struct qedi_cmd *cmd = NULL; 1891ace7f46bSManish Rangankar 1892fa2d9d6eSDan Carpenter if (tid >= MAX_ISCSI_TASK_ENTRIES) 1893ace7f46bSManish Rangankar return NULL; 1894ace7f46bSManish Rangankar 1895ace7f46bSManish Rangankar cmd = qedi->itt_map[tid].p_cmd; 1896ace7f46bSManish Rangankar if (cmd->task_id != tid) 1897ace7f46bSManish Rangankar return NULL; 1898ace7f46bSManish Rangankar 1899ace7f46bSManish Rangankar qedi->itt_map[tid].p_cmd = NULL; 1900ace7f46bSManish Rangankar 1901ace7f46bSManish Rangankar return cmd; 1902ace7f46bSManish Rangankar } 1903ace7f46bSManish Rangankar 1904ace7f46bSManish Rangankar static int qedi_alloc_itt(struct qedi_ctx *qedi) 1905ace7f46bSManish Rangankar { 1906ace7f46bSManish Rangankar qedi->itt_map = kcalloc(MAX_ISCSI_TASK_ENTRIES, 1907ace7f46bSManish Rangankar sizeof(struct qedi_itt_map), GFP_KERNEL); 1908ace7f46bSManish Rangankar if (!qedi->itt_map) { 1909ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1910ace7f46bSManish Rangankar "Unable to allocate itt map array memory\n"); 1911ace7f46bSManish Rangankar return -ENOMEM; 1912ace7f46bSManish Rangankar } 1913ace7f46bSManish Rangankar return 0; 1914ace7f46bSManish Rangankar } 1915ace7f46bSManish Rangankar 1916ace7f46bSManish Rangankar static void qedi_free_itt(struct qedi_ctx *qedi) 1917ace7f46bSManish Rangankar { 1918ace7f46bSManish Rangankar kfree(qedi->itt_map); 1919ace7f46bSManish Rangankar } 1920ace7f46bSManish Rangankar 1921ace7f46bSManish Rangankar static struct qed_ll2_cb_ops qedi_ll2_cb_ops = { 1922ace7f46bSManish Rangankar .rx_cb = qedi_ll2_rx, 1923ace7f46bSManish Rangankar .tx_cb = NULL, 1924ace7f46bSManish Rangankar }; 1925ace7f46bSManish Rangankar 1926ace7f46bSManish Rangankar static int qedi_percpu_io_thread(void *arg) 1927ace7f46bSManish Rangankar { 1928ace7f46bSManish Rangankar struct qedi_percpu_s *p = arg; 1929ace7f46bSManish Rangankar struct qedi_work *work, *tmp; 1930ace7f46bSManish Rangankar unsigned long flags; 1931ace7f46bSManish Rangankar LIST_HEAD(work_list); 1932ace7f46bSManish Rangankar 1933ace7f46bSManish Rangankar set_user_nice(current, -20); 1934ace7f46bSManish Rangankar 1935ace7f46bSManish Rangankar while (!kthread_should_stop()) { 1936ace7f46bSManish Rangankar spin_lock_irqsave(&p->p_work_lock, flags); 1937ace7f46bSManish Rangankar while (!list_empty(&p->work_list)) { 1938ace7f46bSManish Rangankar list_splice_init(&p->work_list, &work_list); 1939ace7f46bSManish Rangankar spin_unlock_irqrestore(&p->p_work_lock, flags); 1940ace7f46bSManish Rangankar 1941ace7f46bSManish Rangankar list_for_each_entry_safe(work, tmp, &work_list, list) { 1942ace7f46bSManish Rangankar list_del_init(&work->list); 1943ace7f46bSManish Rangankar qedi_fp_process_cqes(work); 1944ace7f46bSManish Rangankar if (!work->is_solicited) 1945ace7f46bSManish Rangankar kfree(work); 1946ace7f46bSManish Rangankar } 1947ace7f46bSManish Rangankar cond_resched(); 1948ace7f46bSManish Rangankar spin_lock_irqsave(&p->p_work_lock, flags); 1949ace7f46bSManish Rangankar } 1950ace7f46bSManish Rangankar set_current_state(TASK_INTERRUPTIBLE); 1951ace7f46bSManish Rangankar spin_unlock_irqrestore(&p->p_work_lock, flags); 1952ace7f46bSManish Rangankar schedule(); 1953ace7f46bSManish Rangankar } 1954ace7f46bSManish Rangankar __set_current_state(TASK_RUNNING); 1955ace7f46bSManish Rangankar 1956ace7f46bSManish Rangankar return 0; 1957ace7f46bSManish Rangankar } 1958ace7f46bSManish Rangankar 1959a98d1a0cSThomas Gleixner static int qedi_cpu_online(unsigned int cpu) 1960ace7f46bSManish Rangankar { 1961a98d1a0cSThomas Gleixner struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); 1962ace7f46bSManish Rangankar struct task_struct *thread; 1963ace7f46bSManish Rangankar 1964ace7f46bSManish Rangankar thread = kthread_create_on_node(qedi_percpu_io_thread, (void *)p, 1965ace7f46bSManish Rangankar cpu_to_node(cpu), 1966ace7f46bSManish Rangankar "qedi_thread/%d", cpu); 1967a98d1a0cSThomas Gleixner if (IS_ERR(thread)) 1968a98d1a0cSThomas Gleixner return PTR_ERR(thread); 1969a98d1a0cSThomas Gleixner 1970ace7f46bSManish Rangankar kthread_bind(thread, cpu); 1971ace7f46bSManish Rangankar p->iothread = thread; 1972ace7f46bSManish Rangankar wake_up_process(thread); 1973a98d1a0cSThomas Gleixner return 0; 1974ace7f46bSManish Rangankar } 1975ace7f46bSManish Rangankar 1976a98d1a0cSThomas Gleixner static int qedi_cpu_offline(unsigned int cpu) 1977ace7f46bSManish Rangankar { 1978a98d1a0cSThomas Gleixner struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); 1979ace7f46bSManish Rangankar struct qedi_work *work, *tmp; 1980a98d1a0cSThomas Gleixner struct task_struct *thread; 1981ace7f46bSManish Rangankar 1982ace7f46bSManish Rangankar spin_lock_bh(&p->p_work_lock); 1983ace7f46bSManish Rangankar thread = p->iothread; 1984ace7f46bSManish Rangankar p->iothread = NULL; 1985ace7f46bSManish Rangankar 1986ace7f46bSManish Rangankar list_for_each_entry_safe(work, tmp, &p->work_list, list) { 1987ace7f46bSManish Rangankar list_del_init(&work->list); 1988ace7f46bSManish Rangankar qedi_fp_process_cqes(work); 1989ace7f46bSManish Rangankar if (!work->is_solicited) 1990ace7f46bSManish Rangankar kfree(work); 1991ace7f46bSManish Rangankar } 1992ace7f46bSManish Rangankar 1993ace7f46bSManish Rangankar spin_unlock_bh(&p->p_work_lock); 1994ace7f46bSManish Rangankar if (thread) 1995ace7f46bSManish Rangankar kthread_stop(thread); 1996a98d1a0cSThomas Gleixner return 0; 1997ace7f46bSManish Rangankar } 1998ace7f46bSManish Rangankar 1999ace7f46bSManish Rangankar void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu) 2000ace7f46bSManish Rangankar { 2001ace7f46bSManish Rangankar struct qed_ll2_params params; 2002ace7f46bSManish Rangankar 2003ace7f46bSManish Rangankar qedi_recover_all_conns(qedi); 2004ace7f46bSManish Rangankar 2005ace7f46bSManish Rangankar qedi_ops->ll2->stop(qedi->cdev); 2006ace7f46bSManish Rangankar qedi_ll2_free_skbs(qedi); 2007ace7f46bSManish Rangankar 2008ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "old MTU %u, new MTU %u\n", 2009ace7f46bSManish Rangankar qedi->ll2_mtu, mtu); 2010ace7f46bSManish Rangankar memset(¶ms, 0, sizeof(params)); 2011ace7f46bSManish Rangankar qedi->ll2_mtu = mtu; 2012ace7f46bSManish Rangankar params.mtu = qedi->ll2_mtu + IPV6_HDR_LEN + TCP_HDR_LEN; 2013ace7f46bSManish Rangankar params.drop_ttl0_packets = 0; 2014ace7f46bSManish Rangankar params.rx_vlan_stripping = 1; 2015ace7f46bSManish Rangankar ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); 2016ace7f46bSManish Rangankar qedi_ops->ll2->start(qedi->cdev, ¶ms); 2017ace7f46bSManish Rangankar } 2018ace7f46bSManish Rangankar 20193db05fedSLee Jones /* 2020c57ec8fbSNilesh Javali * qedi_get_nvram_block: - Scan through the iSCSI NVRAM block (while accounting 2021c57ec8fbSNilesh Javali * for gaps) for the matching absolute-pf-id of the QEDI device. 2022c57ec8fbSNilesh Javali */ 2023c57ec8fbSNilesh Javali static struct nvm_iscsi_block * 2024c57ec8fbSNilesh Javali qedi_get_nvram_block(struct qedi_ctx *qedi) 2025c57ec8fbSNilesh Javali { 2026c57ec8fbSNilesh Javali int i; 2027c57ec8fbSNilesh Javali u8 pf; 2028c57ec8fbSNilesh Javali u32 flags; 2029c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 2030c57ec8fbSNilesh Javali 2031c57ec8fbSNilesh Javali pf = qedi->dev_info.common.abs_pf_id; 2032c77a2fa3SNilesh Javali block = &qedi->iscsi_image->iscsi_cfg.block[0]; 2033c57ec8fbSNilesh Javali for (i = 0; i < NUM_OF_ISCSI_PF_SUPPORTED; i++, block++) { 2034c57ec8fbSNilesh Javali flags = ((block->id) & NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK) >> 2035c57ec8fbSNilesh Javali NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET; 2036c57ec8fbSNilesh Javali if (flags & (NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY | 2037c57ec8fbSNilesh Javali NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED) && 2038c57ec8fbSNilesh Javali (pf == (block->id & NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK) 2039c57ec8fbSNilesh Javali >> NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET)) 2040c57ec8fbSNilesh Javali return block; 2041c57ec8fbSNilesh Javali } 2042c57ec8fbSNilesh Javali return NULL; 2043c57ec8fbSNilesh Javali } 2044c57ec8fbSNilesh Javali 2045c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) 2046c57ec8fbSNilesh Javali { 2047c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2048c57ec8fbSNilesh Javali struct nvm_iscsi_initiator *initiator; 2049c57ec8fbSNilesh Javali int rc = 1; 2050c57ec8fbSNilesh Javali u32 ipv6_en, dhcp_en, ip_len; 2051c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 2052c57ec8fbSNilesh Javali char *fmt, *ip, *sub, *gw; 2053c57ec8fbSNilesh Javali 2054c57ec8fbSNilesh Javali block = qedi_get_nvram_block(qedi); 2055c57ec8fbSNilesh Javali if (!block) 2056c57ec8fbSNilesh Javali return 0; 2057c57ec8fbSNilesh Javali 2058c57ec8fbSNilesh Javali initiator = &block->initiator; 2059c57ec8fbSNilesh Javali ipv6_en = block->generic.ctrl_flags & 2060c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_IPV6_ENABLED; 2061c57ec8fbSNilesh Javali dhcp_en = block->generic.ctrl_flags & 2062c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED; 2063c57ec8fbSNilesh Javali /* Static IP assignments. */ 2064c57ec8fbSNilesh Javali fmt = ipv6_en ? "%pI6\n" : "%pI4\n"; 2065c57ec8fbSNilesh Javali ip = ipv6_en ? initiator->ipv6.addr.byte : initiator->ipv4.addr.byte; 2066c57ec8fbSNilesh Javali ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN; 2067c57ec8fbSNilesh Javali sub = ipv6_en ? initiator->ipv6.subnet_mask.byte : 2068c57ec8fbSNilesh Javali initiator->ipv4.subnet_mask.byte; 2069c57ec8fbSNilesh Javali gw = ipv6_en ? initiator->ipv6.gateway.byte : 2070c57ec8fbSNilesh Javali initiator->ipv4.gateway.byte; 2071c57ec8fbSNilesh Javali /* DHCP IP adjustments. */ 2072c57ec8fbSNilesh Javali fmt = dhcp_en ? "%s\n" : fmt; 2073c57ec8fbSNilesh Javali if (dhcp_en) { 2074c57ec8fbSNilesh Javali ip = ipv6_en ? "0::0" : "0.0.0.0"; 2075c57ec8fbSNilesh Javali sub = ip; 2076c57ec8fbSNilesh Javali gw = ip; 2077c57ec8fbSNilesh Javali ip_len = ipv6_en ? 5 : 8; 2078c57ec8fbSNilesh Javali } 2079c57ec8fbSNilesh Javali 2080c57ec8fbSNilesh Javali switch (type) { 2081c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_IP_ADDR: 20822c08fe64SNilesh Javali rc = snprintf(buf, ip_len, fmt, ip); 2083c57ec8fbSNilesh Javali break; 2084c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_SUBNET_MASK: 20852c08fe64SNilesh Javali rc = snprintf(buf, ip_len, fmt, sub); 2086c57ec8fbSNilesh Javali break; 2087c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_GATEWAY: 20882c08fe64SNilesh Javali rc = snprintf(buf, ip_len, fmt, gw); 2089c57ec8fbSNilesh Javali break; 2090c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_FLAGS: 20912c08fe64SNilesh Javali rc = snprintf(buf, 3, "%hhd\n", 2092c57ec8fbSNilesh Javali SYSFS_FLAG_FW_SEL_BOOT); 2093c57ec8fbSNilesh Javali break; 2094c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_INDEX: 20952c08fe64SNilesh Javali rc = snprintf(buf, 3, "0\n"); 2096c57ec8fbSNilesh Javali break; 2097c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_MAC: 20982c08fe64SNilesh Javali rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN); 2099c57ec8fbSNilesh Javali break; 2100c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_VLAN: 21012c08fe64SNilesh Javali rc = snprintf(buf, 12, "%d\n", 2102c57ec8fbSNilesh Javali GET_FIELD2(initiator->generic_cont0, 2103c57ec8fbSNilesh Javali NVM_ISCSI_CFG_INITIATOR_VLAN)); 2104c57ec8fbSNilesh Javali break; 2105c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_ORIGIN: 2106c57ec8fbSNilesh Javali if (dhcp_en) 21072c08fe64SNilesh Javali rc = snprintf(buf, 3, "3\n"); 2108c57ec8fbSNilesh Javali break; 2109c57ec8fbSNilesh Javali default: 2110c57ec8fbSNilesh Javali rc = 0; 2111c57ec8fbSNilesh Javali break; 2112c57ec8fbSNilesh Javali } 2113c57ec8fbSNilesh Javali 2114c57ec8fbSNilesh Javali return rc; 2115c57ec8fbSNilesh Javali } 2116c57ec8fbSNilesh Javali 2117c57ec8fbSNilesh Javali static umode_t qedi_eth_get_attr_visibility(void *data, int type) 2118c57ec8fbSNilesh Javali { 2119c57ec8fbSNilesh Javali int rc = 1; 2120c57ec8fbSNilesh Javali 2121c57ec8fbSNilesh Javali switch (type) { 2122c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_FLAGS: 2123c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_MAC: 2124c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_INDEX: 2125c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_IP_ADDR: 2126c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_SUBNET_MASK: 2127c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_GATEWAY: 2128c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_ORIGIN: 2129c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_VLAN: 2130c57ec8fbSNilesh Javali rc = 0444; 2131c57ec8fbSNilesh Javali break; 2132c57ec8fbSNilesh Javali default: 2133c57ec8fbSNilesh Javali rc = 0; 2134c57ec8fbSNilesh Javali break; 2135c57ec8fbSNilesh Javali } 2136c57ec8fbSNilesh Javali return rc; 2137c57ec8fbSNilesh Javali } 2138c57ec8fbSNilesh Javali 2139c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) 2140c57ec8fbSNilesh Javali { 2141c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2142c57ec8fbSNilesh Javali struct nvm_iscsi_initiator *initiator; 2143c57ec8fbSNilesh Javali int rc; 2144c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 2145c57ec8fbSNilesh Javali 2146c57ec8fbSNilesh Javali block = qedi_get_nvram_block(qedi); 2147c57ec8fbSNilesh Javali if (!block) 2148c57ec8fbSNilesh Javali return 0; 2149c57ec8fbSNilesh Javali 2150c57ec8fbSNilesh Javali initiator = &block->initiator; 2151c57ec8fbSNilesh Javali 2152c57ec8fbSNilesh Javali switch (type) { 2153c57ec8fbSNilesh Javali case ISCSI_BOOT_INI_INITIATOR_NAME: 21542c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, 2155c57ec8fbSNilesh Javali initiator->initiator_name.byte); 2156c57ec8fbSNilesh Javali break; 2157c57ec8fbSNilesh Javali default: 2158c57ec8fbSNilesh Javali rc = 0; 2159c57ec8fbSNilesh Javali break; 2160c57ec8fbSNilesh Javali } 2161c57ec8fbSNilesh Javali return rc; 2162c57ec8fbSNilesh Javali } 2163c57ec8fbSNilesh Javali 2164c57ec8fbSNilesh Javali static umode_t qedi_ini_get_attr_visibility(void *data, int type) 2165c57ec8fbSNilesh Javali { 2166c57ec8fbSNilesh Javali int rc; 2167c57ec8fbSNilesh Javali 2168c57ec8fbSNilesh Javali switch (type) { 2169c57ec8fbSNilesh Javali case ISCSI_BOOT_INI_INITIATOR_NAME: 2170c57ec8fbSNilesh Javali rc = 0444; 2171c57ec8fbSNilesh Javali break; 2172c57ec8fbSNilesh Javali default: 2173c57ec8fbSNilesh Javali rc = 0; 2174c57ec8fbSNilesh Javali break; 2175c57ec8fbSNilesh Javali } 2176c57ec8fbSNilesh Javali return rc; 2177c57ec8fbSNilesh Javali } 2178c57ec8fbSNilesh Javali 2179c57ec8fbSNilesh Javali static ssize_t 2180c57ec8fbSNilesh Javali qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, 2181c57ec8fbSNilesh Javali char *buf, enum qedi_nvm_tgts idx) 2182c57ec8fbSNilesh Javali { 2183c57ec8fbSNilesh Javali int rc = 1; 2184c57ec8fbSNilesh Javali u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len; 2185c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 2186c57ec8fbSNilesh Javali char *chap_name, *chap_secret; 2187c57ec8fbSNilesh Javali char *mchap_name, *mchap_secret; 2188c57ec8fbSNilesh Javali 2189c57ec8fbSNilesh Javali block = qedi_get_nvram_block(qedi); 2190c57ec8fbSNilesh Javali if (!block) 2191c57ec8fbSNilesh Javali goto exit_show_tgt_info; 2192c57ec8fbSNilesh Javali 2193c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT, 2194c57ec8fbSNilesh Javali "Port:%d, tgt_idx:%d\n", 2195c57ec8fbSNilesh Javali GET_FIELD2(block->id, NVM_ISCSI_CFG_BLK_MAPPED_PF_ID), idx); 2196c57ec8fbSNilesh Javali 2197c57ec8fbSNilesh Javali ctrl_flags = block->target[idx].ctrl_flags & 2198c57ec8fbSNilesh Javali NVM_ISCSI_CFG_TARGET_ENABLED; 2199c57ec8fbSNilesh Javali 2200c57ec8fbSNilesh Javali if (!ctrl_flags) { 2201c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT, 2202c57ec8fbSNilesh Javali "Target disabled\n"); 2203c57ec8fbSNilesh Javali goto exit_show_tgt_info; 2204c57ec8fbSNilesh Javali } 2205c57ec8fbSNilesh Javali 2206c57ec8fbSNilesh Javali ipv6_en = block->generic.ctrl_flags & 2207c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_IPV6_ENABLED; 2208c57ec8fbSNilesh Javali ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN; 2209c57ec8fbSNilesh Javali chap_en = block->generic.ctrl_flags & 2210c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_CHAP_ENABLED; 2211c57ec8fbSNilesh Javali chap_name = chap_en ? block->initiator.chap_name.byte : NULL; 2212c57ec8fbSNilesh Javali chap_secret = chap_en ? block->initiator.chap_password.byte : NULL; 2213c57ec8fbSNilesh Javali 2214c57ec8fbSNilesh Javali mchap_en = block->generic.ctrl_flags & 2215c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED; 2216c57ec8fbSNilesh Javali mchap_name = mchap_en ? block->target[idx].chap_name.byte : NULL; 2217c57ec8fbSNilesh Javali mchap_secret = mchap_en ? block->target[idx].chap_password.byte : NULL; 2218c57ec8fbSNilesh Javali 2219c57ec8fbSNilesh Javali switch (type) { 2220c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NAME: 22212c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, 2222c57ec8fbSNilesh Javali block->target[idx].target_name.byte); 2223c57ec8fbSNilesh Javali break; 2224c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_IP_ADDR: 2225c57ec8fbSNilesh Javali if (ipv6_en) 22262c08fe64SNilesh Javali rc = snprintf(buf, ip_len, "%pI6\n", 2227c57ec8fbSNilesh Javali block->target[idx].ipv6_addr.byte); 2228c57ec8fbSNilesh Javali else 22292c08fe64SNilesh Javali rc = snprintf(buf, ip_len, "%pI4\n", 2230c57ec8fbSNilesh Javali block->target[idx].ipv4_addr.byte); 2231c57ec8fbSNilesh Javali break; 2232c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_PORT: 22332c08fe64SNilesh Javali rc = snprintf(buf, 12, "%d\n", 2234c57ec8fbSNilesh Javali GET_FIELD2(block->target[idx].generic_cont0, 2235c57ec8fbSNilesh Javali NVM_ISCSI_CFG_TARGET_TCP_PORT)); 2236c57ec8fbSNilesh Javali break; 2237c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_LUN: 22382c08fe64SNilesh Javali rc = snprintf(buf, 22, "%.*d\n", 2239c57ec8fbSNilesh Javali block->target[idx].lun.value[1], 2240c57ec8fbSNilesh Javali block->target[idx].lun.value[0]); 2241c57ec8fbSNilesh Javali break; 2242c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_NAME: 22432c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 2244c57ec8fbSNilesh Javali chap_name); 2245c57ec8fbSNilesh Javali break; 2246c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_SECRET: 2247d50c7986SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, 2248c57ec8fbSNilesh Javali chap_secret); 2249c57ec8fbSNilesh Javali break; 2250c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_NAME: 22512c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 2252c57ec8fbSNilesh Javali mchap_name); 2253c57ec8fbSNilesh Javali break; 2254c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 2255d50c7986SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, 2256c57ec8fbSNilesh Javali mchap_secret); 2257c57ec8fbSNilesh Javali break; 2258c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_FLAGS: 22592c08fe64SNilesh Javali rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); 2260c57ec8fbSNilesh Javali break; 2261c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NIC_ASSOC: 22622c08fe64SNilesh Javali rc = snprintf(buf, 3, "0\n"); 2263c57ec8fbSNilesh Javali break; 2264c57ec8fbSNilesh Javali default: 2265c57ec8fbSNilesh Javali rc = 0; 2266c57ec8fbSNilesh Javali break; 2267c57ec8fbSNilesh Javali } 2268c57ec8fbSNilesh Javali 2269c57ec8fbSNilesh Javali exit_show_tgt_info: 2270c57ec8fbSNilesh Javali return rc; 2271c57ec8fbSNilesh Javali } 2272c57ec8fbSNilesh Javali 2273c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_tgt_pri_info(void *data, int type, char *buf) 2274c57ec8fbSNilesh Javali { 2275c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2276c57ec8fbSNilesh Javali 2277c57ec8fbSNilesh Javali return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_PRI); 2278c57ec8fbSNilesh Javali } 2279c57ec8fbSNilesh Javali 2280c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_tgt_sec_info(void *data, int type, char *buf) 2281c57ec8fbSNilesh Javali { 2282c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2283c57ec8fbSNilesh Javali 2284c57ec8fbSNilesh Javali return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_SEC); 2285c57ec8fbSNilesh Javali } 2286c57ec8fbSNilesh Javali 2287c57ec8fbSNilesh Javali static umode_t qedi_tgt_get_attr_visibility(void *data, int type) 2288c57ec8fbSNilesh Javali { 2289c57ec8fbSNilesh Javali int rc; 2290c57ec8fbSNilesh Javali 2291c57ec8fbSNilesh Javali switch (type) { 2292c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NAME: 2293c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_IP_ADDR: 2294c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_PORT: 2295c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_LUN: 2296c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_NAME: 2297c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_SECRET: 2298c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_NAME: 2299c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 2300c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NIC_ASSOC: 2301c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_FLAGS: 2302c57ec8fbSNilesh Javali rc = 0444; 2303c57ec8fbSNilesh Javali break; 2304c57ec8fbSNilesh Javali default: 2305c57ec8fbSNilesh Javali rc = 0; 2306c57ec8fbSNilesh Javali break; 2307c57ec8fbSNilesh Javali } 2308c57ec8fbSNilesh Javali return rc; 2309c57ec8fbSNilesh Javali } 2310c57ec8fbSNilesh Javali 2311c57ec8fbSNilesh Javali static void qedi_boot_release(void *data) 2312c57ec8fbSNilesh Javali { 2313c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2314c57ec8fbSNilesh Javali 2315c57ec8fbSNilesh Javali scsi_host_put(qedi->shost); 2316c57ec8fbSNilesh Javali } 2317c57ec8fbSNilesh Javali 2318c57ec8fbSNilesh Javali static int qedi_get_boot_info(struct qedi_ctx *qedi) 2319c57ec8fbSNilesh Javali { 2320c57ec8fbSNilesh Javali int ret = 1; 2321c57ec8fbSNilesh Javali 2322c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 2323c57ec8fbSNilesh Javali "Get NVM iSCSI CFG image\n"); 2324c57ec8fbSNilesh Javali ret = qedi_ops->common->nvm_get_image(qedi->cdev, 2325c57ec8fbSNilesh Javali QED_NVM_IMAGE_ISCSI_CFG, 2326c77a2fa3SNilesh Javali (char *)qedi->iscsi_image, 2327872e192fSColin Ian King sizeof(struct qedi_nvm_iscsi_image)); 2328c57ec8fbSNilesh Javali if (ret) 2329c57ec8fbSNilesh Javali QEDI_ERR(&qedi->dbg_ctx, 2330c57ec8fbSNilesh Javali "Could not get NVM image. ret = %d\n", ret); 2331c57ec8fbSNilesh Javali 2332c57ec8fbSNilesh Javali return ret; 2333c57ec8fbSNilesh Javali } 2334c57ec8fbSNilesh Javali 2335c57ec8fbSNilesh Javali static int qedi_setup_boot_info(struct qedi_ctx *qedi) 2336c57ec8fbSNilesh Javali { 2337c57ec8fbSNilesh Javali struct iscsi_boot_kobj *boot_kobj; 2338c57ec8fbSNilesh Javali 2339c57ec8fbSNilesh Javali if (qedi_get_boot_info(qedi)) 2340c57ec8fbSNilesh Javali return -EPERM; 2341c57ec8fbSNilesh Javali 2342c57ec8fbSNilesh Javali qedi->boot_kset = iscsi_boot_create_host_kset(qedi->shost->host_no); 2343c57ec8fbSNilesh Javali if (!qedi->boot_kset) 2344c57ec8fbSNilesh Javali goto kset_free; 2345c57ec8fbSNilesh Javali 2346c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2347c57ec8fbSNilesh Javali goto kset_free; 2348c57ec8fbSNilesh Javali 2349c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 0, qedi, 2350c57ec8fbSNilesh Javali qedi_show_boot_tgt_pri_info, 2351c57ec8fbSNilesh Javali qedi_tgt_get_attr_visibility, 2352c57ec8fbSNilesh Javali qedi_boot_release); 2353c57ec8fbSNilesh Javali if (!boot_kobj) 2354c57ec8fbSNilesh Javali goto put_host; 2355c57ec8fbSNilesh Javali 2356c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2357c57ec8fbSNilesh Javali goto kset_free; 2358c57ec8fbSNilesh Javali 2359c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 1, qedi, 2360c57ec8fbSNilesh Javali qedi_show_boot_tgt_sec_info, 2361c57ec8fbSNilesh Javali qedi_tgt_get_attr_visibility, 2362c57ec8fbSNilesh Javali qedi_boot_release); 2363c57ec8fbSNilesh Javali if (!boot_kobj) 2364c57ec8fbSNilesh Javali goto put_host; 2365c57ec8fbSNilesh Javali 2366c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2367c57ec8fbSNilesh Javali goto kset_free; 2368c57ec8fbSNilesh Javali 2369c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_initiator(qedi->boot_kset, 0, qedi, 2370c57ec8fbSNilesh Javali qedi_show_boot_ini_info, 2371c57ec8fbSNilesh Javali qedi_ini_get_attr_visibility, 2372c57ec8fbSNilesh Javali qedi_boot_release); 2373c57ec8fbSNilesh Javali if (!boot_kobj) 2374c57ec8fbSNilesh Javali goto put_host; 2375c57ec8fbSNilesh Javali 2376c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2377c57ec8fbSNilesh Javali goto kset_free; 2378c57ec8fbSNilesh Javali 2379c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_ethernet(qedi->boot_kset, 0, qedi, 2380c57ec8fbSNilesh Javali qedi_show_boot_eth_info, 2381c57ec8fbSNilesh Javali qedi_eth_get_attr_visibility, 2382c57ec8fbSNilesh Javali qedi_boot_release); 2383c57ec8fbSNilesh Javali if (!boot_kobj) 2384c57ec8fbSNilesh Javali goto put_host; 2385c57ec8fbSNilesh Javali 2386c57ec8fbSNilesh Javali return 0; 2387c57ec8fbSNilesh Javali 2388c57ec8fbSNilesh Javali put_host: 2389c57ec8fbSNilesh Javali scsi_host_put(qedi->shost); 2390c57ec8fbSNilesh Javali kset_free: 2391c57ec8fbSNilesh Javali iscsi_boot_destroy_kset(qedi->boot_kset); 2392c57ec8fbSNilesh Javali return -ENOMEM; 2393c57ec8fbSNilesh Javali } 2394c57ec8fbSNilesh Javali 239596a766a7SManish Rangankar static pci_ers_result_t qedi_io_error_detected(struct pci_dev *pdev, 239696a766a7SManish Rangankar pci_channel_state_t state) 239796a766a7SManish Rangankar { 239896a766a7SManish Rangankar struct qedi_ctx *qedi = pci_get_drvdata(pdev); 239996a766a7SManish Rangankar 240096a766a7SManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "%s: PCI error detected [%d]\n", 240196a766a7SManish Rangankar __func__, state); 240296a766a7SManish Rangankar 240396a766a7SManish Rangankar if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags)) { 240496a766a7SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 240596a766a7SManish Rangankar "Recovery already in progress.\n"); 240696a766a7SManish Rangankar return PCI_ERS_RESULT_NONE; 240796a766a7SManish Rangankar } 240896a766a7SManish Rangankar 240996a766a7SManish Rangankar qedi_ops->common->recovery_process(qedi->cdev); 241096a766a7SManish Rangankar 241196a766a7SManish Rangankar return PCI_ERS_RESULT_CAN_RECOVER; 241296a766a7SManish Rangankar } 241396a766a7SManish Rangankar 2414ace7f46bSManish Rangankar static void __qedi_remove(struct pci_dev *pdev, int mode) 2415ace7f46bSManish Rangankar { 2416ace7f46bSManish Rangankar struct qedi_ctx *qedi = pci_get_drvdata(pdev); 2417a3440d0dSManish Rangankar int rval; 2418f4ba4e55SManish Rangankar u16 retry = 10; 2419ace7f46bSManish Rangankar 24204f93c4bfSManish Rangankar if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { 2421*d1f2ce77SMike Christie iscsi_host_remove(qedi->shost); 2422*d1f2ce77SMike Christie 2423ace7f46bSManish Rangankar if (qedi->tmf_thread) { 2424ace7f46bSManish Rangankar flush_workqueue(qedi->tmf_thread); 2425ace7f46bSManish Rangankar destroy_workqueue(qedi->tmf_thread); 2426ace7f46bSManish Rangankar qedi->tmf_thread = NULL; 2427ace7f46bSManish Rangankar } 2428ace7f46bSManish Rangankar 2429ace7f46bSManish Rangankar if (qedi->offload_thread) { 2430ace7f46bSManish Rangankar flush_workqueue(qedi->offload_thread); 2431ace7f46bSManish Rangankar destroy_workqueue(qedi->offload_thread); 2432ace7f46bSManish Rangankar qedi->offload_thread = NULL; 2433ace7f46bSManish Rangankar } 24344b1068f5SManish Rangankar } 2435ace7f46bSManish Rangankar 2436ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2437ace7f46bSManish Rangankar qedi_dbg_host_exit(&qedi->dbg_ctx); 2438ace7f46bSManish Rangankar #endif 2439ace7f46bSManish Rangankar if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) 2440ace7f46bSManish Rangankar qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); 2441ace7f46bSManish Rangankar 2442ace7f46bSManish Rangankar qedi_sync_free_irqs(qedi); 2443ace7f46bSManish Rangankar 2444ace7f46bSManish Rangankar if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { 2445f4ba4e55SManish Rangankar while (retry--) { 2446f4ba4e55SManish Rangankar rval = qedi_ops->stop(qedi->cdev); 2447f4ba4e55SManish Rangankar if (rval < 0) 2448f4ba4e55SManish Rangankar msleep(1000); 2449f4ba4e55SManish Rangankar else 2450f4ba4e55SManish Rangankar break; 2451f4ba4e55SManish Rangankar } 2452ace7f46bSManish Rangankar qedi_ops->ll2->stop(qedi->cdev); 2453ace7f46bSManish Rangankar } 2454ace7f46bSManish Rangankar 2455ace7f46bSManish Rangankar qedi_free_iscsi_pf_param(qedi); 2456ace7f46bSManish Rangankar 2457a3440d0dSManish Rangankar rval = qedi_ops->common->update_drv_state(qedi->cdev, false); 2458a3440d0dSManish Rangankar if (rval) 2459a3440d0dSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Failed to send drv state to MFW\n"); 2460a3440d0dSManish Rangankar 2461ace7f46bSManish Rangankar if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { 2462ace7f46bSManish Rangankar qedi_ops->common->slowpath_stop(qedi->cdev); 2463ace7f46bSManish Rangankar qedi_ops->common->remove(qedi->cdev); 2464ace7f46bSManish Rangankar } 2465ace7f46bSManish Rangankar 2466ace7f46bSManish Rangankar qedi_destroy_fp(qedi); 2467ace7f46bSManish Rangankar 24684f93c4bfSManish Rangankar if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) { 2469ace7f46bSManish Rangankar qedi_release_cid_que(qedi); 2470ace7f46bSManish Rangankar qedi_cm_free_mem(qedi); 2471ace7f46bSManish Rangankar qedi_free_uio(qedi->udev); 2472ace7f46bSManish Rangankar qedi_free_itt(qedi); 2473ace7f46bSManish Rangankar 2474ace7f46bSManish Rangankar if (qedi->ll2_recv_thread) { 2475ace7f46bSManish Rangankar kthread_stop(qedi->ll2_recv_thread); 2476ace7f46bSManish Rangankar qedi->ll2_recv_thread = NULL; 2477ace7f46bSManish Rangankar } 2478ace7f46bSManish Rangankar qedi_ll2_free_skbs(qedi); 2479c57ec8fbSNilesh Javali 2480c57ec8fbSNilesh Javali if (qedi->boot_kset) 2481c57ec8fbSNilesh Javali iscsi_boot_destroy_kset(qedi->boot_kset); 24824b1068f5SManish Rangankar 24834b1068f5SManish Rangankar iscsi_host_free(qedi->shost); 2484ace7f46bSManish Rangankar } 2485ace7f46bSManish Rangankar } 2486ace7f46bSManish Rangankar 24877dc71ac8SManish Rangankar static void qedi_board_disable_work(struct work_struct *work) 24887dc71ac8SManish Rangankar { 24897dc71ac8SManish Rangankar struct qedi_ctx *qedi = 24907dc71ac8SManish Rangankar container_of(work, struct qedi_ctx, 24917dc71ac8SManish Rangankar board_disable_work.work); 24927dc71ac8SManish Rangankar 24937dc71ac8SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 24947dc71ac8SManish Rangankar "Fan failure, Unloading firmware context.\n"); 24957dc71ac8SManish Rangankar 24967dc71ac8SManish Rangankar if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) 24977dc71ac8SManish Rangankar return; 24987dc71ac8SManish Rangankar 24997dc71ac8SManish Rangankar __qedi_remove(qedi->pdev, QEDI_MODE_SHUTDOWN); 25007dc71ac8SManish Rangankar } 25017dc71ac8SManish Rangankar 25024f93c4bfSManish Rangankar static void qedi_shutdown(struct pci_dev *pdev) 25034f93c4bfSManish Rangankar { 25044f93c4bfSManish Rangankar struct qedi_ctx *qedi = pci_get_drvdata(pdev); 25054f93c4bfSManish Rangankar 25064f93c4bfSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "%s: Shutdown qedi\n", __func__); 25074f93c4bfSManish Rangankar if (test_and_set_bit(QEDI_IN_SHUTDOWN, &qedi->flags)) 25084f93c4bfSManish Rangankar return; 25094f93c4bfSManish Rangankar __qedi_remove(pdev, QEDI_MODE_SHUTDOWN); 25104f93c4bfSManish Rangankar } 25114f93c4bfSManish Rangankar 2512ace7f46bSManish Rangankar static int __qedi_probe(struct pci_dev *pdev, int mode) 2513ace7f46bSManish Rangankar { 2514ace7f46bSManish Rangankar struct qedi_ctx *qedi; 2515ace7f46bSManish Rangankar struct qed_ll2_params params; 2516ace7f46bSManish Rangankar u8 dp_level = 0; 2517ace7f46bSManish Rangankar bool is_vf = false; 2518ace7f46bSManish Rangankar char host_buf[16]; 2519ace7f46bSManish Rangankar struct qed_link_params link_params; 2520ace7f46bSManish Rangankar struct qed_slowpath_params sp_params; 2521ace7f46bSManish Rangankar struct qed_probe_params qed_params; 2522ace7f46bSManish Rangankar void *task_start, *task_end; 2523ace7f46bSManish Rangankar int rc; 2524f4ba4e55SManish Rangankar u16 retry = 10; 2525ace7f46bSManish Rangankar 2526ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2527ace7f46bSManish Rangankar qedi = qedi_host_alloc(pdev); 2528ace7f46bSManish Rangankar if (!qedi) { 2529ace7f46bSManish Rangankar rc = -ENOMEM; 2530ace7f46bSManish Rangankar goto exit_probe; 2531ace7f46bSManish Rangankar } 2532ace7f46bSManish Rangankar } else { 2533ace7f46bSManish Rangankar qedi = pci_get_drvdata(pdev); 2534ace7f46bSManish Rangankar } 2535ace7f46bSManish Rangankar 2536f4ba4e55SManish Rangankar retry_probe: 2537f4ba4e55SManish Rangankar if (mode == QEDI_MODE_RECOVERY) 2538f4ba4e55SManish Rangankar msleep(2000); 2539f4ba4e55SManish Rangankar 2540ace7f46bSManish Rangankar memset(&qed_params, 0, sizeof(qed_params)); 2541ace7f46bSManish Rangankar qed_params.protocol = QED_PROTOCOL_ISCSI; 2542c6bfa707SManish Rangankar qed_params.dp_module = qedi_qed_debug; 2543ace7f46bSManish Rangankar qed_params.dp_level = dp_level; 2544ace7f46bSManish Rangankar qed_params.is_vf = is_vf; 2545ace7f46bSManish Rangankar qedi->cdev = qedi_ops->common->probe(pdev, &qed_params); 2546ace7f46bSManish Rangankar if (!qedi->cdev) { 2547f4ba4e55SManish Rangankar if (mode == QEDI_MODE_RECOVERY && retry) { 2548f4ba4e55SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 2549f4ba4e55SManish Rangankar "Retry %d initialize hardware\n", retry); 2550f4ba4e55SManish Rangankar retry--; 2551f4ba4e55SManish Rangankar goto retry_probe; 2552f4ba4e55SManish Rangankar } 2553f4ba4e55SManish Rangankar 2554ace7f46bSManish Rangankar rc = -ENODEV; 2555ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n"); 2556ace7f46bSManish Rangankar goto free_host; 2557ace7f46bSManish Rangankar } 2558ace7f46bSManish Rangankar 2559f4ba4e55SManish Rangankar set_bit(QEDI_ERR_ATTN_CLR_EN, &qedi->qedi_err_flags); 2560f4ba4e55SManish Rangankar set_bit(QEDI_ERR_IS_RECOVERABLE, &qedi->qedi_err_flags); 2561ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 2562ace7f46bSManish Rangankar 256342d7c10fSManish Rangankar rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); 256442d7c10fSManish Rangankar if (rc) 256542d7c10fSManish Rangankar goto free_host; 256642d7c10fSManish Rangankar 25672bfbc570SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 25682bfbc570SManish Rangankar "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", 25692bfbc570SManish Rangankar qedi->dev_info.common.num_hwfns, 25702bfbc570SManish Rangankar qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); 25712bfbc570SManish Rangankar 2572ace7f46bSManish Rangankar rc = qedi_set_iscsi_pf_param(qedi); 2573ace7f46bSManish Rangankar if (rc) { 2574ace7f46bSManish Rangankar rc = -ENOMEM; 2575ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2576ace7f46bSManish Rangankar "Set iSCSI pf param fail\n"); 2577ace7f46bSManish Rangankar goto free_host; 2578ace7f46bSManish Rangankar } 2579ace7f46bSManish Rangankar 2580ace7f46bSManish Rangankar qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); 2581ace7f46bSManish Rangankar 2582ace7f46bSManish Rangankar rc = qedi_prepare_fp(qedi); 2583ace7f46bSManish Rangankar if (rc) { 2584ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath.\n"); 2585ace7f46bSManish Rangankar goto free_pf_params; 2586ace7f46bSManish Rangankar } 2587ace7f46bSManish Rangankar 2588ace7f46bSManish Rangankar /* Start the Slowpath-process */ 2589ace7f46bSManish Rangankar memset(&sp_params, 0, sizeof(struct qed_slowpath_params)); 2590ace7f46bSManish Rangankar sp_params.int_mode = QED_INT_MODE_MSIX; 2591ace7f46bSManish Rangankar sp_params.drv_major = QEDI_DRIVER_MAJOR_VER; 2592ace7f46bSManish Rangankar sp_params.drv_minor = QEDI_DRIVER_MINOR_VER; 2593ace7f46bSManish Rangankar sp_params.drv_rev = QEDI_DRIVER_REV_VER; 2594ace7f46bSManish Rangankar sp_params.drv_eng = QEDI_DRIVER_ENG_VER; 2595ace7f46bSManish Rangankar strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); 2596ace7f46bSManish Rangankar rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params); 2597ace7f46bSManish Rangankar if (rc) { 2598ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n"); 2599ace7f46bSManish Rangankar goto stop_hw; 2600ace7f46bSManish Rangankar } 2601ace7f46bSManish Rangankar 2602ace7f46bSManish Rangankar /* update_pf_params needs to be called before and after slowpath 2603ace7f46bSManish Rangankar * start 2604ace7f46bSManish Rangankar */ 2605ace7f46bSManish Rangankar qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); 2606ace7f46bSManish Rangankar 2607d1a9ccc4SColin Ian King rc = qedi_setup_int(qedi); 2608ace7f46bSManish Rangankar if (rc) 2609ace7f46bSManish Rangankar goto stop_iscsi_func; 2610ace7f46bSManish Rangankar 2611ace7f46bSManish Rangankar qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); 2612ace7f46bSManish Rangankar 2613ace7f46bSManish Rangankar /* Learn information crucial for qedi to progress */ 2614ace7f46bSManish Rangankar rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); 2615ace7f46bSManish Rangankar if (rc) 2616ace7f46bSManish Rangankar goto stop_iscsi_func; 2617ace7f46bSManish Rangankar 2618ace7f46bSManish Rangankar /* Record BDQ producer doorbell addresses */ 2619ace7f46bSManish Rangankar qedi->bdq_primary_prod = qedi->dev_info.primary_dbq_rq_addr; 2620ace7f46bSManish Rangankar qedi->bdq_secondary_prod = qedi->dev_info.secondary_bdq_rq_addr; 2621ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 2622ace7f46bSManish Rangankar "BDQ primary_prod=%p secondary_prod=%p.\n", 2623ace7f46bSManish Rangankar qedi->bdq_primary_prod, 2624ace7f46bSManish Rangankar qedi->bdq_secondary_prod); 2625ace7f46bSManish Rangankar 2626ace7f46bSManish Rangankar /* 2627ace7f46bSManish Rangankar * We need to write the number of BDs in the BDQ we've preallocated so 2628ace7f46bSManish Rangankar * the f/w will do a prefetch and we'll get an unsolicited CQE when a 2629ace7f46bSManish Rangankar * packet arrives. 2630ace7f46bSManish Rangankar */ 2631ace7f46bSManish Rangankar qedi->bdq_prod_idx = QEDI_BDQ_NUM; 2632ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 2633ace7f46bSManish Rangankar "Writing %d to primary and secondary BDQ doorbell registers.\n", 2634ace7f46bSManish Rangankar qedi->bdq_prod_idx); 2635ace7f46bSManish Rangankar writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod); 2636e4020e08SLee Jones readw(qedi->bdq_primary_prod); 2637ace7f46bSManish Rangankar writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod); 2638e4020e08SLee Jones readw(qedi->bdq_secondary_prod); 2639ace7f46bSManish Rangankar 2640ace7f46bSManish Rangankar ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac); 2641ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n", 2642ace7f46bSManish Rangankar qedi->mac); 2643ace7f46bSManish Rangankar 26445a2e69afSManish Rangankar snprintf(host_buf, sizeof(host_buf), "host_%d", qedi->shost->host_no); 2645712c3cbfSMintz, Yuval qedi_ops->common->set_name(qedi->cdev, host_buf); 2646ace7f46bSManish Rangankar 2647ace7f46bSManish Rangankar qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); 2648ace7f46bSManish Rangankar 2649ace7f46bSManish Rangankar memset(¶ms, 0, sizeof(params)); 2650ace7f46bSManish Rangankar params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN; 2651ace7f46bSManish Rangankar qedi->ll2_mtu = DEF_PATH_MTU; 2652ace7f46bSManish Rangankar params.drop_ttl0_packets = 0; 2653ace7f46bSManish Rangankar params.rx_vlan_stripping = 1; 2654ace7f46bSManish Rangankar ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); 2655ace7f46bSManish Rangankar 2656ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2657ace7f46bSManish Rangankar /* set up rx path */ 2658ace7f46bSManish Rangankar INIT_LIST_HEAD(&qedi->ll2_skb_list); 2659ace7f46bSManish Rangankar spin_lock_init(&qedi->ll2_lock); 2660ace7f46bSManish Rangankar /* start qedi context */ 2661ace7f46bSManish Rangankar spin_lock_init(&qedi->hba_lock); 2662ace7f46bSManish Rangankar spin_lock_init(&qedi->task_idx_lock); 26633cc5746eSNilesh Javali mutex_init(&qedi->stats_lock); 2664ace7f46bSManish Rangankar } 2665ace7f46bSManish Rangankar qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi); 2666ace7f46bSManish Rangankar qedi_ops->ll2->start(qedi->cdev, ¶ms); 2667ace7f46bSManish Rangankar 2668ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2669ace7f46bSManish Rangankar qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread, 2670ace7f46bSManish Rangankar (void *)qedi, 2671ace7f46bSManish Rangankar "qedi_ll2_thread"); 2672ace7f46bSManish Rangankar } 2673ace7f46bSManish Rangankar 2674ace7f46bSManish Rangankar rc = qedi_ops->start(qedi->cdev, &qedi->tasks, 2675ace7f46bSManish Rangankar qedi, qedi_iscsi_event_cb); 2676ace7f46bSManish Rangankar if (rc) { 2677ace7f46bSManish Rangankar rc = -ENODEV; 2678ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot start iSCSI function\n"); 2679ace7f46bSManish Rangankar goto stop_slowpath; 2680ace7f46bSManish Rangankar } 2681ace7f46bSManish Rangankar 2682ace7f46bSManish Rangankar task_start = qedi_get_task_mem(&qedi->tasks, 0); 2683ace7f46bSManish Rangankar task_end = qedi_get_task_mem(&qedi->tasks, MAX_TID_BLOCKS_ISCSI - 1); 2684ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 2685ace7f46bSManish Rangankar "Task context start=%p, end=%p block_size=%u.\n", 2686ace7f46bSManish Rangankar task_start, task_end, qedi->tasks.size); 2687ace7f46bSManish Rangankar 2688ace7f46bSManish Rangankar memset(&link_params, 0, sizeof(link_params)); 2689ace7f46bSManish Rangankar link_params.link_up = true; 2690ace7f46bSManish Rangankar rc = qedi_ops->common->set_link(qedi->cdev, &link_params); 2691ace7f46bSManish Rangankar if (rc) { 2692ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, "Link set up failed.\n"); 2693ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 2694ace7f46bSManish Rangankar } 2695ace7f46bSManish Rangankar 2696ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2697779936faSArnd Bergmann qedi_dbg_host_init(&qedi->dbg_ctx, qedi_debugfs_ops, 2698779936faSArnd Bergmann qedi_dbg_fops); 2699ace7f46bSManish Rangankar #endif 2700ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 2701ace7f46bSManish Rangankar "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n", 2702ace7f46bSManish Rangankar QEDI_MODULE_VERSION, FW_MAJOR_VERSION, FW_MINOR_VERSION, 2703ace7f46bSManish Rangankar FW_REVISION_VERSION, FW_ENGINEERING_VERSION); 2704ace7f46bSManish Rangankar 2705ace7f46bSManish Rangankar if (mode == QEDI_MODE_NORMAL) { 2706ace7f46bSManish Rangankar if (iscsi_host_add(qedi->shost, &pdev->dev)) { 2707ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2708ace7f46bSManish Rangankar "Could not add iscsi host\n"); 2709ace7f46bSManish Rangankar rc = -ENOMEM; 2710ace7f46bSManish Rangankar goto remove_host; 2711ace7f46bSManish Rangankar } 2712ace7f46bSManish Rangankar 2713ace7f46bSManish Rangankar /* Allocate uio buffers */ 2714ace7f46bSManish Rangankar rc = qedi_alloc_uio_rings(qedi); 2715ace7f46bSManish Rangankar if (rc) { 2716ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2717ace7f46bSManish Rangankar "UIO alloc ring failed err=%d\n", rc); 2718ace7f46bSManish Rangankar goto remove_host; 2719ace7f46bSManish Rangankar } 2720ace7f46bSManish Rangankar 2721ace7f46bSManish Rangankar rc = qedi_init_uio(qedi); 2722ace7f46bSManish Rangankar if (rc) { 2723ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2724ace7f46bSManish Rangankar "UIO init failed, err=%d\n", rc); 2725ace7f46bSManish Rangankar goto free_uio; 2726ace7f46bSManish Rangankar } 2727ace7f46bSManish Rangankar 2728ace7f46bSManish Rangankar /* host the array on iscsi_conn */ 2729ace7f46bSManish Rangankar rc = qedi_setup_cid_que(qedi); 2730ace7f46bSManish Rangankar if (rc) { 2731ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2732ace7f46bSManish Rangankar "Could not setup cid que\n"); 2733ace7f46bSManish Rangankar goto free_uio; 2734ace7f46bSManish Rangankar } 2735ace7f46bSManish Rangankar 2736ace7f46bSManish Rangankar rc = qedi_cm_alloc_mem(qedi); 2737ace7f46bSManish Rangankar if (rc) { 2738ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2739ace7f46bSManish Rangankar "Could not alloc cm memory\n"); 2740ace7f46bSManish Rangankar goto free_cid_que; 2741ace7f46bSManish Rangankar } 2742ace7f46bSManish Rangankar 2743ace7f46bSManish Rangankar rc = qedi_alloc_itt(qedi); 2744ace7f46bSManish Rangankar if (rc) { 2745ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2746ace7f46bSManish Rangankar "Could not alloc itt memory\n"); 2747ace7f46bSManish Rangankar goto free_cid_que; 2748ace7f46bSManish Rangankar } 2749ace7f46bSManish Rangankar 2750ace7f46bSManish Rangankar sprintf(host_buf, "host_%d", qedi->shost->host_no); 2751ace7f46bSManish Rangankar qedi->tmf_thread = create_singlethread_workqueue(host_buf); 2752ace7f46bSManish Rangankar if (!qedi->tmf_thread) { 2753ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2754ace7f46bSManish Rangankar "Unable to start tmf thread!\n"); 2755ace7f46bSManish Rangankar rc = -ENODEV; 2756ace7f46bSManish Rangankar goto free_cid_que; 2757ace7f46bSManish Rangankar } 2758ace7f46bSManish Rangankar 2759ace7f46bSManish Rangankar sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no); 2760ace7f46bSManish Rangankar qedi->offload_thread = create_workqueue(host_buf); 2761ace7f46bSManish Rangankar if (!qedi->offload_thread) { 2762ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2763ace7f46bSManish Rangankar "Unable to start offload thread!\n"); 2764ace7f46bSManish Rangankar rc = -ENODEV; 276562eebd52SQinglang Miao goto free_tmf_thread; 2766ace7f46bSManish Rangankar } 2767ace7f46bSManish Rangankar 27684b1068f5SManish Rangankar INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler); 27697dc71ac8SManish Rangankar INIT_DELAYED_WORK(&qedi->board_disable_work, 27707dc71ac8SManish Rangankar qedi_board_disable_work); 27714b1068f5SManish Rangankar 2772ace7f46bSManish Rangankar /* F/w needs 1st task context memory entry for performance */ 2773ace7f46bSManish Rangankar set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map); 2774ace7f46bSManish Rangankar atomic_set(&qedi->num_offloads, 0); 2775c57ec8fbSNilesh Javali 2776c57ec8fbSNilesh Javali if (qedi_setup_boot_info(qedi)) 2777c57ec8fbSNilesh Javali QEDI_ERR(&qedi->dbg_ctx, 2778c57ec8fbSNilesh Javali "No iSCSI boot target configured\n"); 2779a3440d0dSManish Rangankar 2780a3440d0dSManish Rangankar rc = qedi_ops->common->update_drv_state(qedi->cdev, true); 2781a3440d0dSManish Rangankar if (rc) 2782a3440d0dSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2783a3440d0dSManish Rangankar "Failed to send drv state to MFW\n"); 2784a3440d0dSManish Rangankar 2785ace7f46bSManish Rangankar } 2786ace7f46bSManish Rangankar 2787ace7f46bSManish Rangankar return 0; 2788ace7f46bSManish Rangankar 278962eebd52SQinglang Miao free_tmf_thread: 279062eebd52SQinglang Miao destroy_workqueue(qedi->tmf_thread); 2791ace7f46bSManish Rangankar free_cid_que: 2792ace7f46bSManish Rangankar qedi_release_cid_que(qedi); 2793ace7f46bSManish Rangankar free_uio: 2794ace7f46bSManish Rangankar qedi_free_uio(qedi->udev); 2795ace7f46bSManish Rangankar remove_host: 2796ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2797ace7f46bSManish Rangankar qedi_dbg_host_exit(&qedi->dbg_ctx); 2798ace7f46bSManish Rangankar #endif 2799ace7f46bSManish Rangankar iscsi_host_remove(qedi->shost); 2800ace7f46bSManish Rangankar stop_iscsi_func: 2801ace7f46bSManish Rangankar qedi_ops->stop(qedi->cdev); 2802ace7f46bSManish Rangankar stop_slowpath: 2803ace7f46bSManish Rangankar qedi_ops->common->slowpath_stop(qedi->cdev); 2804ace7f46bSManish Rangankar stop_hw: 2805ace7f46bSManish Rangankar qedi_ops->common->remove(qedi->cdev); 2806ace7f46bSManish Rangankar free_pf_params: 2807ace7f46bSManish Rangankar qedi_free_iscsi_pf_param(qedi); 2808ace7f46bSManish Rangankar free_host: 2809ace7f46bSManish Rangankar iscsi_host_free(qedi->shost); 2810ace7f46bSManish Rangankar exit_probe: 2811ace7f46bSManish Rangankar return rc; 2812ace7f46bSManish Rangankar } 2813ace7f46bSManish Rangankar 28144b1068f5SManish Rangankar static void qedi_mark_conn_recovery(struct iscsi_cls_session *cls_session) 28154b1068f5SManish Rangankar { 28164b1068f5SManish Rangankar struct iscsi_session *session = cls_session->dd_data; 28174b1068f5SManish Rangankar struct iscsi_conn *conn = session->leadconn; 28184b1068f5SManish Rangankar struct qedi_conn *qedi_conn = conn->dd_data; 28194b1068f5SManish Rangankar 28204b1068f5SManish Rangankar iscsi_conn_failure(qedi_conn->cls_conn->dd_data, ISCSI_ERR_CONN_FAILED); 28214b1068f5SManish Rangankar } 28224b1068f5SManish Rangankar 28234b1068f5SManish Rangankar static void qedi_recovery_handler(struct work_struct *work) 28244b1068f5SManish Rangankar { 28254b1068f5SManish Rangankar struct qedi_ctx *qedi = 28264b1068f5SManish Rangankar container_of(work, struct qedi_ctx, recovery_work.work); 28274b1068f5SManish Rangankar 28284b1068f5SManish Rangankar iscsi_host_for_each_session(qedi->shost, qedi_mark_conn_recovery); 28294b1068f5SManish Rangankar 28304b1068f5SManish Rangankar /* Call common_ops->recovery_prolog to allow the MFW to quiesce 28314b1068f5SManish Rangankar * any PCI transactions. 28324b1068f5SManish Rangankar */ 28334b1068f5SManish Rangankar qedi_ops->common->recovery_prolog(qedi->cdev); 28344b1068f5SManish Rangankar 28354b1068f5SManish Rangankar __qedi_remove(qedi->pdev, QEDI_MODE_RECOVERY); 28364b1068f5SManish Rangankar __qedi_probe(qedi->pdev, QEDI_MODE_RECOVERY); 28374b1068f5SManish Rangankar clear_bit(QEDI_IN_RECOVERY, &qedi->flags); 28384b1068f5SManish Rangankar } 28394b1068f5SManish Rangankar 2840ace7f46bSManish Rangankar static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 2841ace7f46bSManish Rangankar { 2842ace7f46bSManish Rangankar return __qedi_probe(pdev, QEDI_MODE_NORMAL); 2843ace7f46bSManish Rangankar } 2844ace7f46bSManish Rangankar 2845ace7f46bSManish Rangankar static void qedi_remove(struct pci_dev *pdev) 2846ace7f46bSManish Rangankar { 2847ace7f46bSManish Rangankar __qedi_remove(pdev, QEDI_MODE_NORMAL); 2848ace7f46bSManish Rangankar } 2849ace7f46bSManish Rangankar 2850ace7f46bSManish Rangankar static struct pci_device_id qedi_pci_tbl[] = { 2851ace7f46bSManish Rangankar { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x165E) }, 285204688525SManish Rangankar { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x8084) }, 2853ace7f46bSManish Rangankar { 0 }, 2854ace7f46bSManish Rangankar }; 2855ace7f46bSManish Rangankar MODULE_DEVICE_TABLE(pci, qedi_pci_tbl); 2856ace7f46bSManish Rangankar 2857a98d1a0cSThomas Gleixner static enum cpuhp_state qedi_cpuhp_state; 2858a98d1a0cSThomas Gleixner 285996a766a7SManish Rangankar static struct pci_error_handlers qedi_err_handler = { 286096a766a7SManish Rangankar .error_detected = qedi_io_error_detected, 286196a766a7SManish Rangankar }; 286296a766a7SManish Rangankar 2863ace7f46bSManish Rangankar static struct pci_driver qedi_pci_driver = { 2864ace7f46bSManish Rangankar .name = QEDI_MODULE_NAME, 2865ace7f46bSManish Rangankar .id_table = qedi_pci_tbl, 2866ace7f46bSManish Rangankar .probe = qedi_probe, 2867ace7f46bSManish Rangankar .remove = qedi_remove, 28684f93c4bfSManish Rangankar .shutdown = qedi_shutdown, 286996a766a7SManish Rangankar .err_handler = &qedi_err_handler, 2870ace7f46bSManish Rangankar }; 2871ace7f46bSManish Rangankar 2872ace7f46bSManish Rangankar static int __init qedi_init(void) 2873ace7f46bSManish Rangankar { 2874ace7f46bSManish Rangankar struct qedi_percpu_s *p; 2875a98d1a0cSThomas Gleixner int cpu, rc = 0; 2876ace7f46bSManish Rangankar 2877ace7f46bSManish Rangankar qedi_ops = qed_get_iscsi_ops(); 2878ace7f46bSManish Rangankar if (!qedi_ops) { 2879ace7f46bSManish Rangankar QEDI_ERR(NULL, "Failed to get qed iSCSI operations\n"); 2880a98d1a0cSThomas Gleixner return -EINVAL; 2881ace7f46bSManish Rangankar } 2882ace7f46bSManish Rangankar 2883ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2884ace7f46bSManish Rangankar qedi_dbg_init("qedi"); 2885ace7f46bSManish Rangankar #endif 2886ace7f46bSManish Rangankar 2887ace7f46bSManish Rangankar qedi_scsi_transport = iscsi_register_transport(&qedi_iscsi_transport); 2888ace7f46bSManish Rangankar if (!qedi_scsi_transport) { 2889ace7f46bSManish Rangankar QEDI_ERR(NULL, "Could not register qedi transport"); 2890ace7f46bSManish Rangankar rc = -ENOMEM; 2891ace7f46bSManish Rangankar goto exit_qedi_init_1; 2892ace7f46bSManish Rangankar } 2893ace7f46bSManish Rangankar 2894ace7f46bSManish Rangankar for_each_possible_cpu(cpu) { 2895ace7f46bSManish Rangankar p = &per_cpu(qedi_percpu, cpu); 2896ace7f46bSManish Rangankar INIT_LIST_HEAD(&p->work_list); 2897ace7f46bSManish Rangankar spin_lock_init(&p->p_work_lock); 2898ace7f46bSManish Rangankar p->iothread = NULL; 2899ace7f46bSManish Rangankar } 2900ace7f46bSManish Rangankar 2901a98d1a0cSThomas Gleixner rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/qedi:online", 2902a98d1a0cSThomas Gleixner qedi_cpu_online, qedi_cpu_offline); 2903a98d1a0cSThomas Gleixner if (rc < 0) 2904a98d1a0cSThomas Gleixner goto exit_qedi_init_2; 2905a98d1a0cSThomas Gleixner qedi_cpuhp_state = rc; 2906ace7f46bSManish Rangankar 2907a98d1a0cSThomas Gleixner rc = pci_register_driver(&qedi_pci_driver); 2908a98d1a0cSThomas Gleixner if (rc) { 2909a98d1a0cSThomas Gleixner QEDI_ERR(NULL, "Failed to register driver\n"); 2910a98d1a0cSThomas Gleixner goto exit_qedi_hp; 2911a98d1a0cSThomas Gleixner } 2912ace7f46bSManish Rangankar 2913a98d1a0cSThomas Gleixner return 0; 2914a98d1a0cSThomas Gleixner 2915a98d1a0cSThomas Gleixner exit_qedi_hp: 2916a98d1a0cSThomas Gleixner cpuhp_remove_state(qedi_cpuhp_state); 2917ace7f46bSManish Rangankar exit_qedi_init_2: 2918ace7f46bSManish Rangankar iscsi_unregister_transport(&qedi_iscsi_transport); 2919ace7f46bSManish Rangankar exit_qedi_init_1: 2920ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2921ace7f46bSManish Rangankar qedi_dbg_exit(); 2922ace7f46bSManish Rangankar #endif 2923ace7f46bSManish Rangankar qed_put_iscsi_ops(); 2924ace7f46bSManish Rangankar return rc; 2925ace7f46bSManish Rangankar } 2926ace7f46bSManish Rangankar 2927ace7f46bSManish Rangankar static void __exit qedi_cleanup(void) 2928ace7f46bSManish Rangankar { 2929ace7f46bSManish Rangankar pci_unregister_driver(&qedi_pci_driver); 2930a98d1a0cSThomas Gleixner cpuhp_remove_state(qedi_cpuhp_state); 2931ace7f46bSManish Rangankar iscsi_unregister_transport(&qedi_iscsi_transport); 2932ace7f46bSManish Rangankar 2933ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2934ace7f46bSManish Rangankar qedi_dbg_exit(); 2935ace7f46bSManish Rangankar #endif 2936ace7f46bSManish Rangankar qed_put_iscsi_ops(); 2937ace7f46bSManish Rangankar } 2938ace7f46bSManish Rangankar 2939ace7f46bSManish Rangankar MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx iSCSI Module"); 2940ace7f46bSManish Rangankar MODULE_LICENSE("GPL"); 2941ace7f46bSManish Rangankar MODULE_AUTHOR("QLogic Corporation"); 2942ace7f46bSManish Rangankar MODULE_VERSION(QEDI_MODULE_VERSION); 2943ace7f46bSManish Rangankar module_init(qedi_init); 2944ace7f46bSManish Rangankar module_exit(qedi_cleanup); 2945