1ace7f46bSManish Rangankar /* 2ace7f46bSManish Rangankar * QLogic iSCSI Offload Driver 3ace7f46bSManish Rangankar * Copyright (c) 2016 Cavium Inc. 4ace7f46bSManish Rangankar * 5ace7f46bSManish Rangankar * This software is available under the terms of the GNU General Public License 6ace7f46bSManish Rangankar * (GPL) Version 2, available from the file COPYING in the main directory of 7ace7f46bSManish Rangankar * this source tree. 8ace7f46bSManish Rangankar */ 9ace7f46bSManish Rangankar 10ace7f46bSManish Rangankar #include <linux/module.h> 11ace7f46bSManish Rangankar #include <linux/pci.h> 12ace7f46bSManish Rangankar #include <linux/kernel.h> 13ace7f46bSManish Rangankar #include <linux/if_arp.h> 14ace7f46bSManish Rangankar #include <scsi/iscsi_if.h> 15ace7f46bSManish Rangankar #include <linux/inet.h> 16ace7f46bSManish Rangankar #include <net/arp.h> 17ace7f46bSManish Rangankar #include <linux/list.h> 18ace7f46bSManish Rangankar #include <linux/kthread.h> 19ace7f46bSManish Rangankar #include <linux/mm.h> 20ace7f46bSManish Rangankar #include <linux/if_vlan.h> 21ace7f46bSManish Rangankar #include <linux/cpu.h> 22c57ec8fbSNilesh Javali #include <linux/iscsi_boot_sysfs.h> 23ace7f46bSManish Rangankar 24ace7f46bSManish Rangankar #include <scsi/scsi_cmnd.h> 25ace7f46bSManish Rangankar #include <scsi/scsi_device.h> 26ace7f46bSManish Rangankar #include <scsi/scsi_eh.h> 27ace7f46bSManish Rangankar #include <scsi/scsi_host.h> 28ace7f46bSManish Rangankar #include <scsi/scsi.h> 29ace7f46bSManish Rangankar 30ace7f46bSManish Rangankar #include "qedi.h" 31ace7f46bSManish Rangankar #include "qedi_gbl.h" 32ace7f46bSManish Rangankar #include "qedi_iscsi.h" 33ace7f46bSManish Rangankar 34ace7f46bSManish Rangankar static uint qedi_fw_debug; 35ace7f46bSManish Rangankar module_param(qedi_fw_debug, uint, 0644); 36ace7f46bSManish Rangankar MODULE_PARM_DESC(qedi_fw_debug, " Firmware debug level 0(default) to 3"); 37ace7f46bSManish Rangankar 38ace7f46bSManish Rangankar uint qedi_dbg_log = QEDI_LOG_WARN | QEDI_LOG_SCSI_TM; 39ace7f46bSManish Rangankar module_param(qedi_dbg_log, uint, 0644); 40ace7f46bSManish Rangankar MODULE_PARM_DESC(qedi_dbg_log, " Default debug level"); 41ace7f46bSManish Rangankar 42ace7f46bSManish Rangankar uint qedi_io_tracing; 43ace7f46bSManish Rangankar module_param(qedi_io_tracing, uint, 0644); 44ace7f46bSManish Rangankar MODULE_PARM_DESC(qedi_io_tracing, 45ace7f46bSManish Rangankar " Enable logging of SCSI requests/completions into trace buffer. (default off)."); 46ace7f46bSManish Rangankar 47ace7f46bSManish Rangankar const struct qed_iscsi_ops *qedi_ops; 48ace7f46bSManish Rangankar static struct scsi_transport_template *qedi_scsi_transport; 49ace7f46bSManish Rangankar static struct pci_driver qedi_pci_driver; 50ace7f46bSManish Rangankar static DEFINE_PER_CPU(struct qedi_percpu_s, qedi_percpu); 51ace7f46bSManish Rangankar static LIST_HEAD(qedi_udev_list); 52ace7f46bSManish Rangankar /* Static function declaration */ 53ace7f46bSManish Rangankar static int qedi_alloc_global_queues(struct qedi_ctx *qedi); 54ace7f46bSManish Rangankar static void qedi_free_global_queues(struct qedi_ctx *qedi); 55ace7f46bSManish Rangankar static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid); 56ace7f46bSManish Rangankar static void qedi_reset_uio_rings(struct qedi_uio_dev *udev); 57ace7f46bSManish Rangankar static void qedi_ll2_free_skbs(struct qedi_ctx *qedi); 58534bbdf8SManish Rangankar static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi); 59ace7f46bSManish Rangankar 60ace7f46bSManish Rangankar static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) 61ace7f46bSManish Rangankar { 62ace7f46bSManish Rangankar struct qedi_ctx *qedi; 63ace7f46bSManish Rangankar struct qedi_endpoint *qedi_ep; 64da090917STomer Tayar struct iscsi_eqe_data *data; 65ace7f46bSManish Rangankar int rval = 0; 66ace7f46bSManish Rangankar 67ace7f46bSManish Rangankar if (!context || !fw_handle) { 68ace7f46bSManish Rangankar QEDI_ERR(NULL, "Recv event with ctx NULL\n"); 69ace7f46bSManish Rangankar return -EINVAL; 70ace7f46bSManish Rangankar } 71ace7f46bSManish Rangankar 72ace7f46bSManish Rangankar qedi = (struct qedi_ctx *)context; 73ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 74ace7f46bSManish Rangankar "Recv Event %d fw_handle %p\n", fw_event_code, fw_handle); 75ace7f46bSManish Rangankar 76da090917STomer Tayar data = (struct iscsi_eqe_data *)fw_handle; 77ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 78da090917STomer Tayar "icid=0x%x conn_id=0x%x err-code=0x%x error-pdu-opcode-reserved=0x%x\n", 79da090917STomer Tayar data->icid, data->conn_id, data->error_code, 80da090917STomer Tayar data->error_pdu_opcode_reserved); 81ace7f46bSManish Rangankar 82da090917STomer Tayar qedi_ep = qedi->ep_tbl[data->icid]; 83ace7f46bSManish Rangankar 84ace7f46bSManish Rangankar if (!qedi_ep) { 85ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 86ace7f46bSManish Rangankar "Cannot process event, ep already disconnected, cid=0x%x\n", 87da090917STomer Tayar data->icid); 88ace7f46bSManish Rangankar WARN_ON(1); 89ace7f46bSManish Rangankar return -ENODEV; 90ace7f46bSManish Rangankar } 91ace7f46bSManish Rangankar 92ace7f46bSManish Rangankar switch (fw_event_code) { 93ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE: 94ace7f46bSManish Rangankar if (qedi_ep->state == EP_STATE_OFLDCONN_START) 95ace7f46bSManish Rangankar qedi_ep->state = EP_STATE_OFLDCONN_COMPL; 96ace7f46bSManish Rangankar 97ace7f46bSManish Rangankar wake_up_interruptible(&qedi_ep->tcp_ofld_wait); 98ace7f46bSManish Rangankar break; 99ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE: 100ace7f46bSManish Rangankar qedi_ep->state = EP_STATE_DISCONN_COMPL; 101ace7f46bSManish Rangankar wake_up_interruptible(&qedi_ep->tcp_ofld_wait); 102ace7f46bSManish Rangankar break; 103ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR: 104ace7f46bSManish Rangankar qedi_process_iscsi_error(qedi_ep, data); 105ace7f46bSManish Rangankar break; 106ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD: 107ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD: 108ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME: 109ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT: 110ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT: 111ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2: 112ace7f46bSManish Rangankar case ISCSI_EVENT_TYPE_TCP_CONN_ERROR: 113ace7f46bSManish Rangankar qedi_process_tcp_error(qedi_ep, data); 114ace7f46bSManish Rangankar break; 115ace7f46bSManish Rangankar default: 116ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Recv Unknown Event %u\n", 117ace7f46bSManish Rangankar fw_event_code); 118ace7f46bSManish Rangankar } 119ace7f46bSManish Rangankar 120ace7f46bSManish Rangankar return rval; 121ace7f46bSManish Rangankar } 122ace7f46bSManish Rangankar 123ace7f46bSManish Rangankar static int qedi_uio_open(struct uio_info *uinfo, struct inode *inode) 124ace7f46bSManish Rangankar { 125ace7f46bSManish Rangankar struct qedi_uio_dev *udev = uinfo->priv; 126ace7f46bSManish Rangankar struct qedi_ctx *qedi = udev->qedi; 127ace7f46bSManish Rangankar 128ace7f46bSManish Rangankar if (!capable(CAP_NET_ADMIN)) 129ace7f46bSManish Rangankar return -EPERM; 130ace7f46bSManish Rangankar 131ace7f46bSManish Rangankar if (udev->uio_dev != -1) 132ace7f46bSManish Rangankar return -EBUSY; 133ace7f46bSManish Rangankar 134ace7f46bSManish Rangankar rtnl_lock(); 135ace7f46bSManish Rangankar udev->uio_dev = iminor(inode); 136ace7f46bSManish Rangankar qedi_reset_uio_rings(udev); 137ace7f46bSManish Rangankar set_bit(UIO_DEV_OPENED, &qedi->flags); 138ace7f46bSManish Rangankar rtnl_unlock(); 139ace7f46bSManish Rangankar 140ace7f46bSManish Rangankar return 0; 141ace7f46bSManish Rangankar } 142ace7f46bSManish Rangankar 143ace7f46bSManish Rangankar static int qedi_uio_close(struct uio_info *uinfo, struct inode *inode) 144ace7f46bSManish Rangankar { 145ace7f46bSManish Rangankar struct qedi_uio_dev *udev = uinfo->priv; 146ace7f46bSManish Rangankar struct qedi_ctx *qedi = udev->qedi; 147ace7f46bSManish Rangankar 148ace7f46bSManish Rangankar udev->uio_dev = -1; 149ace7f46bSManish Rangankar clear_bit(UIO_DEV_OPENED, &qedi->flags); 150ace7f46bSManish Rangankar qedi_ll2_free_skbs(qedi); 151ace7f46bSManish Rangankar return 0; 152ace7f46bSManish Rangankar } 153ace7f46bSManish Rangankar 154ace7f46bSManish Rangankar static void __qedi_free_uio_rings(struct qedi_uio_dev *udev) 155ace7f46bSManish Rangankar { 1565e901d0bSArun Easi if (udev->uctrl) { 1575e901d0bSArun Easi free_page((unsigned long)udev->uctrl); 1585e901d0bSArun Easi udev->uctrl = NULL; 1595e901d0bSArun Easi } 1605e901d0bSArun Easi 161ace7f46bSManish Rangankar if (udev->ll2_ring) { 162ace7f46bSManish Rangankar free_page((unsigned long)udev->ll2_ring); 163ace7f46bSManish Rangankar udev->ll2_ring = NULL; 164ace7f46bSManish Rangankar } 165ace7f46bSManish Rangankar 166ace7f46bSManish Rangankar if (udev->ll2_buf) { 167ace7f46bSManish Rangankar free_pages((unsigned long)udev->ll2_buf, 2); 168ace7f46bSManish Rangankar udev->ll2_buf = NULL; 169ace7f46bSManish Rangankar } 170ace7f46bSManish Rangankar } 171ace7f46bSManish Rangankar 172ace7f46bSManish Rangankar static void __qedi_free_uio(struct qedi_uio_dev *udev) 173ace7f46bSManish Rangankar { 174ace7f46bSManish Rangankar uio_unregister_device(&udev->qedi_uinfo); 175ace7f46bSManish Rangankar 176ace7f46bSManish Rangankar __qedi_free_uio_rings(udev); 177ace7f46bSManish Rangankar 178ace7f46bSManish Rangankar pci_dev_put(udev->pdev); 179ace7f46bSManish Rangankar kfree(udev); 180ace7f46bSManish Rangankar } 181ace7f46bSManish Rangankar 182ace7f46bSManish Rangankar static void qedi_free_uio(struct qedi_uio_dev *udev) 183ace7f46bSManish Rangankar { 184ace7f46bSManish Rangankar if (!udev) 185ace7f46bSManish Rangankar return; 186ace7f46bSManish Rangankar 187ace7f46bSManish Rangankar list_del_init(&udev->list); 188ace7f46bSManish Rangankar __qedi_free_uio(udev); 189ace7f46bSManish Rangankar } 190ace7f46bSManish Rangankar 191ace7f46bSManish Rangankar static void qedi_reset_uio_rings(struct qedi_uio_dev *udev) 192ace7f46bSManish Rangankar { 193ace7f46bSManish Rangankar struct qedi_ctx *qedi = NULL; 194ace7f46bSManish Rangankar struct qedi_uio_ctrl *uctrl = NULL; 195ace7f46bSManish Rangankar 196ace7f46bSManish Rangankar qedi = udev->qedi; 197ace7f46bSManish Rangankar uctrl = udev->uctrl; 198ace7f46bSManish Rangankar 199ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 200ace7f46bSManish Rangankar uctrl->host_rx_cons = 0; 201ace7f46bSManish Rangankar uctrl->hw_rx_prod = 0; 202ace7f46bSManish Rangankar uctrl->hw_rx_bd_prod = 0; 203ace7f46bSManish Rangankar uctrl->host_rx_bd_cons = 0; 204ace7f46bSManish Rangankar 205ace7f46bSManish Rangankar memset(udev->ll2_ring, 0, udev->ll2_ring_size); 206ace7f46bSManish Rangankar memset(udev->ll2_buf, 0, udev->ll2_buf_size); 207ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 208ace7f46bSManish Rangankar } 209ace7f46bSManish Rangankar 210ace7f46bSManish Rangankar static int __qedi_alloc_uio_rings(struct qedi_uio_dev *udev) 211ace7f46bSManish Rangankar { 212ace7f46bSManish Rangankar int rc = 0; 213ace7f46bSManish Rangankar 214ace7f46bSManish Rangankar if (udev->ll2_ring || udev->ll2_buf) 215ace7f46bSManish Rangankar return rc; 216ace7f46bSManish Rangankar 2175e901d0bSArun Easi /* Memory for control area. */ 2185e901d0bSArun Easi udev->uctrl = (void *)get_zeroed_page(GFP_KERNEL); 2195e901d0bSArun Easi if (!udev->uctrl) 2205e901d0bSArun Easi return -ENOMEM; 2215e901d0bSArun Easi 222ace7f46bSManish Rangankar /* Allocating memory for LL2 ring */ 223ace7f46bSManish Rangankar udev->ll2_ring_size = QEDI_PAGE_SIZE; 224ace7f46bSManish Rangankar udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP); 225ace7f46bSManish Rangankar if (!udev->ll2_ring) { 226ace7f46bSManish Rangankar rc = -ENOMEM; 227ace7f46bSManish Rangankar goto exit_alloc_ring; 228ace7f46bSManish Rangankar } 229ace7f46bSManish Rangankar 230ace7f46bSManish Rangankar /* Allocating memory for Tx/Rx pkt buffer */ 231ace7f46bSManish Rangankar udev->ll2_buf_size = TX_RX_RING * LL2_SINGLE_BUF_SIZE; 232ace7f46bSManish Rangankar udev->ll2_buf_size = QEDI_PAGE_ALIGN(udev->ll2_buf_size); 233ace7f46bSManish Rangankar udev->ll2_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP | 234ace7f46bSManish Rangankar __GFP_ZERO, 2); 235ace7f46bSManish Rangankar if (!udev->ll2_buf) { 236ace7f46bSManish Rangankar rc = -ENOMEM; 237ace7f46bSManish Rangankar goto exit_alloc_buf; 238ace7f46bSManish Rangankar } 239ace7f46bSManish Rangankar return rc; 240ace7f46bSManish Rangankar 241ace7f46bSManish Rangankar exit_alloc_buf: 242ace7f46bSManish Rangankar free_page((unsigned long)udev->ll2_ring); 243ace7f46bSManish Rangankar udev->ll2_ring = NULL; 244ace7f46bSManish Rangankar exit_alloc_ring: 245ace7f46bSManish Rangankar return rc; 246ace7f46bSManish Rangankar } 247ace7f46bSManish Rangankar 248ace7f46bSManish Rangankar static int qedi_alloc_uio_rings(struct qedi_ctx *qedi) 249ace7f46bSManish Rangankar { 250ace7f46bSManish Rangankar struct qedi_uio_dev *udev = NULL; 251ace7f46bSManish Rangankar int rc = 0; 252ace7f46bSManish Rangankar 253ace7f46bSManish Rangankar list_for_each_entry(udev, &qedi_udev_list, list) { 254ace7f46bSManish Rangankar if (udev->pdev == qedi->pdev) { 255ace7f46bSManish Rangankar udev->qedi = qedi; 256ace7f46bSManish Rangankar if (__qedi_alloc_uio_rings(udev)) { 257ace7f46bSManish Rangankar udev->qedi = NULL; 258ace7f46bSManish Rangankar return -ENOMEM; 259ace7f46bSManish Rangankar } 260ace7f46bSManish Rangankar qedi->udev = udev; 261ace7f46bSManish Rangankar return 0; 262ace7f46bSManish Rangankar } 263ace7f46bSManish Rangankar } 264ace7f46bSManish Rangankar 265ace7f46bSManish Rangankar udev = kzalloc(sizeof(*udev), GFP_KERNEL); 266ace7f46bSManish Rangankar if (!udev) { 267ace7f46bSManish Rangankar rc = -ENOMEM; 268ace7f46bSManish Rangankar goto err_udev; 269ace7f46bSManish Rangankar } 270ace7f46bSManish Rangankar 271ace7f46bSManish Rangankar udev->uio_dev = -1; 272ace7f46bSManish Rangankar 273ace7f46bSManish Rangankar udev->qedi = qedi; 274ace7f46bSManish Rangankar udev->pdev = qedi->pdev; 275ace7f46bSManish Rangankar 276ace7f46bSManish Rangankar rc = __qedi_alloc_uio_rings(udev); 277ace7f46bSManish Rangankar if (rc) 2785e901d0bSArun Easi goto err_uctrl; 279ace7f46bSManish Rangankar 280ace7f46bSManish Rangankar list_add(&udev->list, &qedi_udev_list); 281ace7f46bSManish Rangankar 282ace7f46bSManish Rangankar pci_dev_get(udev->pdev); 283ace7f46bSManish Rangankar qedi->udev = udev; 284ace7f46bSManish Rangankar 285ace7f46bSManish Rangankar udev->tx_pkt = udev->ll2_buf; 286ace7f46bSManish Rangankar udev->rx_pkt = udev->ll2_buf + LL2_SINGLE_BUF_SIZE; 287ace7f46bSManish Rangankar return 0; 288ace7f46bSManish Rangankar 289ace7f46bSManish Rangankar err_uctrl: 290ace7f46bSManish Rangankar kfree(udev); 291ace7f46bSManish Rangankar err_udev: 292ace7f46bSManish Rangankar return -ENOMEM; 293ace7f46bSManish Rangankar } 294ace7f46bSManish Rangankar 295ace7f46bSManish Rangankar static int qedi_init_uio(struct qedi_ctx *qedi) 296ace7f46bSManish Rangankar { 297ace7f46bSManish Rangankar struct qedi_uio_dev *udev = qedi->udev; 298ace7f46bSManish Rangankar struct uio_info *uinfo; 299ace7f46bSManish Rangankar int ret = 0; 300ace7f46bSManish Rangankar 301ace7f46bSManish Rangankar if (!udev) 302ace7f46bSManish Rangankar return -ENOMEM; 303ace7f46bSManish Rangankar 304ace7f46bSManish Rangankar uinfo = &udev->qedi_uinfo; 305ace7f46bSManish Rangankar 306ace7f46bSManish Rangankar uinfo->mem[0].addr = (unsigned long)udev->uctrl; 307ace7f46bSManish Rangankar uinfo->mem[0].size = sizeof(struct qedi_uio_ctrl); 308ace7f46bSManish Rangankar uinfo->mem[0].memtype = UIO_MEM_LOGICAL; 309ace7f46bSManish Rangankar 310ace7f46bSManish Rangankar uinfo->mem[1].addr = (unsigned long)udev->ll2_ring; 311ace7f46bSManish Rangankar uinfo->mem[1].size = udev->ll2_ring_size; 312ace7f46bSManish Rangankar uinfo->mem[1].memtype = UIO_MEM_LOGICAL; 313ace7f46bSManish Rangankar 314ace7f46bSManish Rangankar uinfo->mem[2].addr = (unsigned long)udev->ll2_buf; 315ace7f46bSManish Rangankar uinfo->mem[2].size = udev->ll2_buf_size; 316ace7f46bSManish Rangankar uinfo->mem[2].memtype = UIO_MEM_LOGICAL; 317ace7f46bSManish Rangankar 318ace7f46bSManish Rangankar uinfo->name = "qedi_uio"; 319ace7f46bSManish Rangankar uinfo->version = QEDI_MODULE_VERSION; 320ace7f46bSManish Rangankar uinfo->irq = UIO_IRQ_CUSTOM; 321ace7f46bSManish Rangankar 322ace7f46bSManish Rangankar uinfo->open = qedi_uio_open; 323ace7f46bSManish Rangankar uinfo->release = qedi_uio_close; 324ace7f46bSManish Rangankar 325ace7f46bSManish Rangankar if (udev->uio_dev == -1) { 326ace7f46bSManish Rangankar if (!uinfo->priv) { 327ace7f46bSManish Rangankar uinfo->priv = udev; 328ace7f46bSManish Rangankar 329ace7f46bSManish Rangankar ret = uio_register_device(&udev->pdev->dev, uinfo); 330ace7f46bSManish Rangankar if (ret) { 331ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 332ace7f46bSManish Rangankar "UIO registration failed\n"); 333ace7f46bSManish Rangankar } 334ace7f46bSManish Rangankar } 335ace7f46bSManish Rangankar } 336ace7f46bSManish Rangankar 337ace7f46bSManish Rangankar return ret; 338ace7f46bSManish Rangankar } 339ace7f46bSManish Rangankar 340ace7f46bSManish Rangankar static int qedi_alloc_and_init_sb(struct qedi_ctx *qedi, 341ace7f46bSManish Rangankar struct qed_sb_info *sb_info, u16 sb_id) 342ace7f46bSManish Rangankar { 34321dd79e8STomer Tayar struct status_block_e4 *sb_virt; 344ace7f46bSManish Rangankar dma_addr_t sb_phys; 345ace7f46bSManish Rangankar int ret; 346ace7f46bSManish Rangankar 347ace7f46bSManish Rangankar sb_virt = dma_alloc_coherent(&qedi->pdev->dev, 34821dd79e8STomer Tayar sizeof(struct status_block_e4), &sb_phys, 349ace7f46bSManish Rangankar GFP_KERNEL); 350ace7f46bSManish Rangankar if (!sb_virt) { 351ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 352ace7f46bSManish Rangankar "Status block allocation failed for id = %d.\n", 353ace7f46bSManish Rangankar sb_id); 354ace7f46bSManish Rangankar return -ENOMEM; 355ace7f46bSManish Rangankar } 356ace7f46bSManish Rangankar 357ace7f46bSManish Rangankar ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys, 358ace7f46bSManish Rangankar sb_id, QED_SB_TYPE_STORAGE); 359ace7f46bSManish Rangankar if (ret) { 360ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 361ace7f46bSManish Rangankar "Status block initialization failed for id = %d.\n", 362ace7f46bSManish Rangankar sb_id); 363ace7f46bSManish Rangankar return ret; 364ace7f46bSManish Rangankar } 365ace7f46bSManish Rangankar 366ace7f46bSManish Rangankar return 0; 367ace7f46bSManish Rangankar } 368ace7f46bSManish Rangankar 369ace7f46bSManish Rangankar static void qedi_free_sb(struct qedi_ctx *qedi) 370ace7f46bSManish Rangankar { 371ace7f46bSManish Rangankar struct qed_sb_info *sb_info; 372ace7f46bSManish Rangankar int id; 373ace7f46bSManish Rangankar 374ace7f46bSManish Rangankar for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 375ace7f46bSManish Rangankar sb_info = &qedi->sb_array[id]; 376ace7f46bSManish Rangankar if (sb_info->sb_virt) 377ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, 378ace7f46bSManish Rangankar sizeof(*sb_info->sb_virt), 379ace7f46bSManish Rangankar (void *)sb_info->sb_virt, 380ace7f46bSManish Rangankar sb_info->sb_phys); 381ace7f46bSManish Rangankar } 382ace7f46bSManish Rangankar } 383ace7f46bSManish Rangankar 384ace7f46bSManish Rangankar static void qedi_free_fp(struct qedi_ctx *qedi) 385ace7f46bSManish Rangankar { 386ace7f46bSManish Rangankar kfree(qedi->fp_array); 387ace7f46bSManish Rangankar kfree(qedi->sb_array); 388ace7f46bSManish Rangankar } 389ace7f46bSManish Rangankar 390ace7f46bSManish Rangankar static void qedi_destroy_fp(struct qedi_ctx *qedi) 391ace7f46bSManish Rangankar { 392ace7f46bSManish Rangankar qedi_free_sb(qedi); 393ace7f46bSManish Rangankar qedi_free_fp(qedi); 394ace7f46bSManish Rangankar } 395ace7f46bSManish Rangankar 396ace7f46bSManish Rangankar static int qedi_alloc_fp(struct qedi_ctx *qedi) 397ace7f46bSManish Rangankar { 398ace7f46bSManish Rangankar int ret = 0; 399ace7f46bSManish Rangankar 400ace7f46bSManish Rangankar qedi->fp_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), 401ace7f46bSManish Rangankar sizeof(struct qedi_fastpath), GFP_KERNEL); 402ace7f46bSManish Rangankar if (!qedi->fp_array) { 403ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 404ace7f46bSManish Rangankar "fastpath fp array allocation failed.\n"); 405ace7f46bSManish Rangankar return -ENOMEM; 406ace7f46bSManish Rangankar } 407ace7f46bSManish Rangankar 408ace7f46bSManish Rangankar qedi->sb_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), 409ace7f46bSManish Rangankar sizeof(struct qed_sb_info), GFP_KERNEL); 410ace7f46bSManish Rangankar if (!qedi->sb_array) { 411ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 412ace7f46bSManish Rangankar "fastpath sb array allocation failed.\n"); 413ace7f46bSManish Rangankar ret = -ENOMEM; 414ace7f46bSManish Rangankar goto free_fp; 415ace7f46bSManish Rangankar } 416ace7f46bSManish Rangankar 417ace7f46bSManish Rangankar return ret; 418ace7f46bSManish Rangankar 419ace7f46bSManish Rangankar free_fp: 420ace7f46bSManish Rangankar qedi_free_fp(qedi); 421ace7f46bSManish Rangankar return ret; 422ace7f46bSManish Rangankar } 423ace7f46bSManish Rangankar 424ace7f46bSManish Rangankar static void qedi_int_fp(struct qedi_ctx *qedi) 425ace7f46bSManish Rangankar { 426ace7f46bSManish Rangankar struct qedi_fastpath *fp; 427ace7f46bSManish Rangankar int id; 428ace7f46bSManish Rangankar 429ace7f46bSManish Rangankar memset(qedi->fp_array, 0, MIN_NUM_CPUS_MSIX(qedi) * 430ace7f46bSManish Rangankar sizeof(*qedi->fp_array)); 431ace7f46bSManish Rangankar memset(qedi->sb_array, 0, MIN_NUM_CPUS_MSIX(qedi) * 432ace7f46bSManish Rangankar sizeof(*qedi->sb_array)); 433ace7f46bSManish Rangankar 434ace7f46bSManish Rangankar for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 435ace7f46bSManish Rangankar fp = &qedi->fp_array[id]; 436ace7f46bSManish Rangankar fp->sb_info = &qedi->sb_array[id]; 437ace7f46bSManish Rangankar fp->sb_id = id; 438ace7f46bSManish Rangankar fp->qedi = qedi; 439ace7f46bSManish Rangankar snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", 440ace7f46bSManish Rangankar "qedi", id); 441ace7f46bSManish Rangankar 442ace7f46bSManish Rangankar /* fp_array[i] ---- irq cookie 443ace7f46bSManish Rangankar * So init data which is needed in int ctx 444ace7f46bSManish Rangankar */ 445ace7f46bSManish Rangankar } 446ace7f46bSManish Rangankar } 447ace7f46bSManish Rangankar 448ace7f46bSManish Rangankar static int qedi_prepare_fp(struct qedi_ctx *qedi) 449ace7f46bSManish Rangankar { 450ace7f46bSManish Rangankar struct qedi_fastpath *fp; 451ace7f46bSManish Rangankar int id, ret = 0; 452ace7f46bSManish Rangankar 453ace7f46bSManish Rangankar ret = qedi_alloc_fp(qedi); 454ace7f46bSManish Rangankar if (ret) 455ace7f46bSManish Rangankar goto err; 456ace7f46bSManish Rangankar 457ace7f46bSManish Rangankar qedi_int_fp(qedi); 458ace7f46bSManish Rangankar 459ace7f46bSManish Rangankar for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { 460ace7f46bSManish Rangankar fp = &qedi->fp_array[id]; 461ace7f46bSManish Rangankar ret = qedi_alloc_and_init_sb(qedi, fp->sb_info, fp->sb_id); 462ace7f46bSManish Rangankar if (ret) { 463ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 464ace7f46bSManish Rangankar "SB allocation and initialization failed.\n"); 465ace7f46bSManish Rangankar ret = -EIO; 466ace7f46bSManish Rangankar goto err_init; 467ace7f46bSManish Rangankar } 468ace7f46bSManish Rangankar } 469ace7f46bSManish Rangankar 470ace7f46bSManish Rangankar return 0; 471ace7f46bSManish Rangankar 472ace7f46bSManish Rangankar err_init: 473ace7f46bSManish Rangankar qedi_free_sb(qedi); 474ace7f46bSManish Rangankar qedi_free_fp(qedi); 475ace7f46bSManish Rangankar err: 476ace7f46bSManish Rangankar return ret; 477ace7f46bSManish Rangankar } 478ace7f46bSManish Rangankar 479ace7f46bSManish Rangankar static int qedi_setup_cid_que(struct qedi_ctx *qedi) 480ace7f46bSManish Rangankar { 481ace7f46bSManish Rangankar int i; 482ace7f46bSManish Rangankar 483ace7f46bSManish Rangankar qedi->cid_que.cid_que_base = kmalloc_array(qedi->max_active_conns, 484ace7f46bSManish Rangankar sizeof(u32), GFP_KERNEL); 485ace7f46bSManish Rangankar if (!qedi->cid_que.cid_que_base) 486ace7f46bSManish Rangankar return -ENOMEM; 487ace7f46bSManish Rangankar 488ace7f46bSManish Rangankar qedi->cid_que.conn_cid_tbl = kmalloc_array(qedi->max_active_conns, 489ace7f46bSManish Rangankar sizeof(struct qedi_conn *), 490ace7f46bSManish Rangankar GFP_KERNEL); 491ace7f46bSManish Rangankar if (!qedi->cid_que.conn_cid_tbl) { 492ace7f46bSManish Rangankar kfree(qedi->cid_que.cid_que_base); 493ace7f46bSManish Rangankar qedi->cid_que.cid_que_base = NULL; 494ace7f46bSManish Rangankar return -ENOMEM; 495ace7f46bSManish Rangankar } 496ace7f46bSManish Rangankar 497ace7f46bSManish Rangankar qedi->cid_que.cid_que = (u32 *)qedi->cid_que.cid_que_base; 498ace7f46bSManish Rangankar qedi->cid_que.cid_q_prod_idx = 0; 499ace7f46bSManish Rangankar qedi->cid_que.cid_q_cons_idx = 0; 500ace7f46bSManish Rangankar qedi->cid_que.cid_q_max_idx = qedi->max_active_conns; 501ace7f46bSManish Rangankar qedi->cid_que.cid_free_cnt = qedi->max_active_conns; 502ace7f46bSManish Rangankar 503ace7f46bSManish Rangankar for (i = 0; i < qedi->max_active_conns; i++) { 504ace7f46bSManish Rangankar qedi->cid_que.cid_que[i] = i; 505ace7f46bSManish Rangankar qedi->cid_que.conn_cid_tbl[i] = NULL; 506ace7f46bSManish Rangankar } 507ace7f46bSManish Rangankar 508ace7f46bSManish Rangankar return 0; 509ace7f46bSManish Rangankar } 510ace7f46bSManish Rangankar 511ace7f46bSManish Rangankar static void qedi_release_cid_que(struct qedi_ctx *qedi) 512ace7f46bSManish Rangankar { 513ace7f46bSManish Rangankar kfree(qedi->cid_que.cid_que_base); 514ace7f46bSManish Rangankar qedi->cid_que.cid_que_base = NULL; 515ace7f46bSManish Rangankar 516ace7f46bSManish Rangankar kfree(qedi->cid_que.conn_cid_tbl); 517ace7f46bSManish Rangankar qedi->cid_que.conn_cid_tbl = NULL; 518ace7f46bSManish Rangankar } 519ace7f46bSManish Rangankar 520ace7f46bSManish Rangankar static int qedi_init_id_tbl(struct qedi_portid_tbl *id_tbl, u16 size, 521ace7f46bSManish Rangankar u16 start_id, u16 next) 522ace7f46bSManish Rangankar { 523ace7f46bSManish Rangankar id_tbl->start = start_id; 524ace7f46bSManish Rangankar id_tbl->max = size; 525ace7f46bSManish Rangankar id_tbl->next = next; 526ace7f46bSManish Rangankar spin_lock_init(&id_tbl->lock); 527*915d9b71SDan Carpenter id_tbl->table = kcalloc(BITS_TO_LONGS(size), sizeof(long), GFP_KERNEL); 528ace7f46bSManish Rangankar if (!id_tbl->table) 529ace7f46bSManish Rangankar return -ENOMEM; 530ace7f46bSManish Rangankar 531ace7f46bSManish Rangankar return 0; 532ace7f46bSManish Rangankar } 533ace7f46bSManish Rangankar 534ace7f46bSManish Rangankar static void qedi_free_id_tbl(struct qedi_portid_tbl *id_tbl) 535ace7f46bSManish Rangankar { 536ace7f46bSManish Rangankar kfree(id_tbl->table); 537ace7f46bSManish Rangankar id_tbl->table = NULL; 538ace7f46bSManish Rangankar } 539ace7f46bSManish Rangankar 540ace7f46bSManish Rangankar int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id) 541ace7f46bSManish Rangankar { 542ace7f46bSManish Rangankar int ret = -1; 543ace7f46bSManish Rangankar 544ace7f46bSManish Rangankar id -= id_tbl->start; 545ace7f46bSManish Rangankar if (id >= id_tbl->max) 546ace7f46bSManish Rangankar return ret; 547ace7f46bSManish Rangankar 548ace7f46bSManish Rangankar spin_lock(&id_tbl->lock); 549ace7f46bSManish Rangankar if (!test_bit(id, id_tbl->table)) { 550ace7f46bSManish Rangankar set_bit(id, id_tbl->table); 551ace7f46bSManish Rangankar ret = 0; 552ace7f46bSManish Rangankar } 553ace7f46bSManish Rangankar spin_unlock(&id_tbl->lock); 554ace7f46bSManish Rangankar return ret; 555ace7f46bSManish Rangankar } 556ace7f46bSManish Rangankar 557ace7f46bSManish Rangankar u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl) 558ace7f46bSManish Rangankar { 559ace7f46bSManish Rangankar u16 id; 560ace7f46bSManish Rangankar 561ace7f46bSManish Rangankar spin_lock(&id_tbl->lock); 562ace7f46bSManish Rangankar id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next); 563ace7f46bSManish Rangankar if (id >= id_tbl->max) { 564ace7f46bSManish Rangankar id = QEDI_LOCAL_PORT_INVALID; 565ace7f46bSManish Rangankar if (id_tbl->next != 0) { 566ace7f46bSManish Rangankar id = find_first_zero_bit(id_tbl->table, id_tbl->next); 567ace7f46bSManish Rangankar if (id >= id_tbl->next) 568ace7f46bSManish Rangankar id = QEDI_LOCAL_PORT_INVALID; 569ace7f46bSManish Rangankar } 570ace7f46bSManish Rangankar } 571ace7f46bSManish Rangankar 572ace7f46bSManish Rangankar if (id < id_tbl->max) { 573ace7f46bSManish Rangankar set_bit(id, id_tbl->table); 574ace7f46bSManish Rangankar id_tbl->next = (id + 1) & (id_tbl->max - 1); 575ace7f46bSManish Rangankar id += id_tbl->start; 576ace7f46bSManish Rangankar } 577ace7f46bSManish Rangankar 578ace7f46bSManish Rangankar spin_unlock(&id_tbl->lock); 579ace7f46bSManish Rangankar 580ace7f46bSManish Rangankar return id; 581ace7f46bSManish Rangankar } 582ace7f46bSManish Rangankar 583ace7f46bSManish Rangankar void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id) 584ace7f46bSManish Rangankar { 585ace7f46bSManish Rangankar if (id == QEDI_LOCAL_PORT_INVALID) 586ace7f46bSManish Rangankar return; 587ace7f46bSManish Rangankar 588ace7f46bSManish Rangankar id -= id_tbl->start; 589ace7f46bSManish Rangankar if (id >= id_tbl->max) 590ace7f46bSManish Rangankar return; 591ace7f46bSManish Rangankar 592ace7f46bSManish Rangankar clear_bit(id, id_tbl->table); 593ace7f46bSManish Rangankar } 594ace7f46bSManish Rangankar 595ace7f46bSManish Rangankar static void qedi_cm_free_mem(struct qedi_ctx *qedi) 596ace7f46bSManish Rangankar { 597ace7f46bSManish Rangankar kfree(qedi->ep_tbl); 598ace7f46bSManish Rangankar qedi->ep_tbl = NULL; 599ace7f46bSManish Rangankar qedi_free_id_tbl(&qedi->lcl_port_tbl); 600ace7f46bSManish Rangankar } 601ace7f46bSManish Rangankar 602ace7f46bSManish Rangankar static int qedi_cm_alloc_mem(struct qedi_ctx *qedi) 603ace7f46bSManish Rangankar { 604ace7f46bSManish Rangankar u16 port_id; 605ace7f46bSManish Rangankar 606ace7f46bSManish Rangankar qedi->ep_tbl = kzalloc((qedi->max_active_conns * 607ace7f46bSManish Rangankar sizeof(struct qedi_endpoint *)), GFP_KERNEL); 608ace7f46bSManish Rangankar if (!qedi->ep_tbl) 609ace7f46bSManish Rangankar return -ENOMEM; 610ace7f46bSManish Rangankar port_id = prandom_u32() % QEDI_LOCAL_PORT_RANGE; 611ace7f46bSManish Rangankar if (qedi_init_id_tbl(&qedi->lcl_port_tbl, QEDI_LOCAL_PORT_RANGE, 612ace7f46bSManish Rangankar QEDI_LOCAL_PORT_MIN, port_id)) { 613ace7f46bSManish Rangankar qedi_cm_free_mem(qedi); 614ace7f46bSManish Rangankar return -ENOMEM; 615ace7f46bSManish Rangankar } 616ace7f46bSManish Rangankar 617ace7f46bSManish Rangankar return 0; 618ace7f46bSManish Rangankar } 619ace7f46bSManish Rangankar 620ace7f46bSManish Rangankar static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev) 621ace7f46bSManish Rangankar { 622ace7f46bSManish Rangankar struct Scsi_Host *shost; 623ace7f46bSManish Rangankar struct qedi_ctx *qedi = NULL; 624ace7f46bSManish Rangankar 625ace7f46bSManish Rangankar shost = iscsi_host_alloc(&qedi_host_template, 626ace7f46bSManish Rangankar sizeof(struct qedi_ctx), 0); 627ace7f46bSManish Rangankar if (!shost) { 628ace7f46bSManish Rangankar QEDI_ERR(NULL, "Could not allocate shost\n"); 629ace7f46bSManish Rangankar goto exit_setup_shost; 630ace7f46bSManish Rangankar } 631ace7f46bSManish Rangankar 632ace7f46bSManish Rangankar shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA; 633ace7f46bSManish Rangankar shost->max_channel = 0; 634ace7f46bSManish Rangankar shost->max_lun = ~0; 635ace7f46bSManish Rangankar shost->max_cmd_len = 16; 636ace7f46bSManish Rangankar shost->transportt = qedi_scsi_transport; 637ace7f46bSManish Rangankar 638ace7f46bSManish Rangankar qedi = iscsi_host_priv(shost); 639ace7f46bSManish Rangankar memset(qedi, 0, sizeof(*qedi)); 640ace7f46bSManish Rangankar qedi->shost = shost; 641ace7f46bSManish Rangankar qedi->dbg_ctx.host_no = shost->host_no; 642ace7f46bSManish Rangankar qedi->pdev = pdev; 643ace7f46bSManish Rangankar qedi->dbg_ctx.pdev = pdev; 644ace7f46bSManish Rangankar qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA; 645ace7f46bSManish Rangankar qedi->max_sqes = QEDI_SQ_SIZE; 646ace7f46bSManish Rangankar 647ace7f46bSManish Rangankar if (shost_use_blk_mq(shost)) 648ace7f46bSManish Rangankar shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi); 649ace7f46bSManish Rangankar 650ace7f46bSManish Rangankar pci_set_drvdata(pdev, qedi); 651ace7f46bSManish Rangankar 652ace7f46bSManish Rangankar exit_setup_shost: 653ace7f46bSManish Rangankar return qedi; 654ace7f46bSManish Rangankar } 655ace7f46bSManish Rangankar 656ace7f46bSManish Rangankar static int qedi_ll2_rx(void *cookie, struct sk_buff *skb, u32 arg1, u32 arg2) 657ace7f46bSManish Rangankar { 658ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; 659ace7f46bSManish Rangankar struct qedi_uio_dev *udev; 660ace7f46bSManish Rangankar struct qedi_uio_ctrl *uctrl; 661ace7f46bSManish Rangankar struct skb_work_list *work; 662ace7f46bSManish Rangankar u32 prod; 663ace7f46bSManish Rangankar 664ace7f46bSManish Rangankar if (!qedi) { 665ace7f46bSManish Rangankar QEDI_ERR(NULL, "qedi is NULL\n"); 666ace7f46bSManish Rangankar return -1; 667ace7f46bSManish Rangankar } 668ace7f46bSManish Rangankar 669ace7f46bSManish Rangankar if (!test_bit(UIO_DEV_OPENED, &qedi->flags)) { 670ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UIO, 671ace7f46bSManish Rangankar "UIO DEV is not opened\n"); 672ace7f46bSManish Rangankar kfree_skb(skb); 673ace7f46bSManish Rangankar return 0; 674ace7f46bSManish Rangankar } 675ace7f46bSManish Rangankar 676ace7f46bSManish Rangankar udev = qedi->udev; 677ace7f46bSManish Rangankar uctrl = udev->uctrl; 678ace7f46bSManish Rangankar 679ace7f46bSManish Rangankar work = kzalloc(sizeof(*work), GFP_ATOMIC); 680ace7f46bSManish Rangankar if (!work) { 681ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 682ace7f46bSManish Rangankar "Could not allocate work so dropping frame.\n"); 683ace7f46bSManish Rangankar kfree_skb(skb); 684ace7f46bSManish Rangankar return 0; 685ace7f46bSManish Rangankar } 686ace7f46bSManish Rangankar 687ace7f46bSManish Rangankar INIT_LIST_HEAD(&work->list); 688ace7f46bSManish Rangankar work->skb = skb; 689ace7f46bSManish Rangankar 690ace7f46bSManish Rangankar if (skb_vlan_tag_present(skb)) 691ace7f46bSManish Rangankar work->vlan_id = skb_vlan_tag_get(skb); 692ace7f46bSManish Rangankar 693ace7f46bSManish Rangankar if (work->vlan_id) 694ace7f46bSManish Rangankar __vlan_insert_tag(work->skb, htons(ETH_P_8021Q), work->vlan_id); 695ace7f46bSManish Rangankar 696ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 697ace7f46bSManish Rangankar list_add_tail(&work->list, &qedi->ll2_skb_list); 698ace7f46bSManish Rangankar 699ace7f46bSManish Rangankar ++uctrl->hw_rx_prod_cnt; 700ace7f46bSManish Rangankar prod = (uctrl->hw_rx_prod + 1) % RX_RING; 701ace7f46bSManish Rangankar if (prod != uctrl->host_rx_cons) { 702ace7f46bSManish Rangankar uctrl->hw_rx_prod = prod; 703ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 704ace7f46bSManish Rangankar wake_up_process(qedi->ll2_recv_thread); 705ace7f46bSManish Rangankar return 0; 706ace7f46bSManish Rangankar } 707ace7f46bSManish Rangankar 708ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 709ace7f46bSManish Rangankar return 0; 710ace7f46bSManish Rangankar } 711ace7f46bSManish Rangankar 712ace7f46bSManish Rangankar /* map this skb to iscsiuio mmaped region */ 713ace7f46bSManish Rangankar static int qedi_ll2_process_skb(struct qedi_ctx *qedi, struct sk_buff *skb, 714ace7f46bSManish Rangankar u16 vlan_id) 715ace7f46bSManish Rangankar { 716ace7f46bSManish Rangankar struct qedi_uio_dev *udev = NULL; 717ace7f46bSManish Rangankar struct qedi_uio_ctrl *uctrl = NULL; 718ace7f46bSManish Rangankar struct qedi_rx_bd rxbd; 719ace7f46bSManish Rangankar struct qedi_rx_bd *p_rxbd; 720ace7f46bSManish Rangankar u32 rx_bd_prod; 721ace7f46bSManish Rangankar void *pkt; 722ace7f46bSManish Rangankar int len = 0; 723ace7f46bSManish Rangankar 724ace7f46bSManish Rangankar if (!qedi) { 725ace7f46bSManish Rangankar QEDI_ERR(NULL, "qedi is NULL\n"); 726ace7f46bSManish Rangankar return -1; 727ace7f46bSManish Rangankar } 728ace7f46bSManish Rangankar 729ace7f46bSManish Rangankar udev = qedi->udev; 730ace7f46bSManish Rangankar uctrl = udev->uctrl; 731ace7f46bSManish Rangankar pkt = udev->rx_pkt + (uctrl->hw_rx_prod * LL2_SINGLE_BUF_SIZE); 732ace7f46bSManish Rangankar len = min_t(u32, skb->len, (u32)LL2_SINGLE_BUF_SIZE); 733ace7f46bSManish Rangankar memcpy(pkt, skb->data, len); 734ace7f46bSManish Rangankar 735ace7f46bSManish Rangankar memset(&rxbd, 0, sizeof(rxbd)); 736ace7f46bSManish Rangankar rxbd.rx_pkt_index = uctrl->hw_rx_prod; 737ace7f46bSManish Rangankar rxbd.rx_pkt_len = len; 738ace7f46bSManish Rangankar rxbd.vlan_id = vlan_id; 739ace7f46bSManish Rangankar 740ace7f46bSManish Rangankar uctrl->hw_rx_bd_prod = (uctrl->hw_rx_bd_prod + 1) % QEDI_NUM_RX_BD; 741ace7f46bSManish Rangankar rx_bd_prod = uctrl->hw_rx_bd_prod; 742ace7f46bSManish Rangankar p_rxbd = (struct qedi_rx_bd *)udev->ll2_ring; 743ace7f46bSManish Rangankar p_rxbd += rx_bd_prod; 744ace7f46bSManish Rangankar 745ace7f46bSManish Rangankar memcpy(p_rxbd, &rxbd, sizeof(rxbd)); 746ace7f46bSManish Rangankar 747ace7f46bSManish Rangankar /* notify the iscsiuio about new packet */ 748ace7f46bSManish Rangankar uio_event_notify(&udev->qedi_uinfo); 749ace7f46bSManish Rangankar 750ace7f46bSManish Rangankar return 0; 751ace7f46bSManish Rangankar } 752ace7f46bSManish Rangankar 753ace7f46bSManish Rangankar static void qedi_ll2_free_skbs(struct qedi_ctx *qedi) 754ace7f46bSManish Rangankar { 755ace7f46bSManish Rangankar struct skb_work_list *work, *work_tmp; 756ace7f46bSManish Rangankar 757ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 758ace7f46bSManish Rangankar list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, list) { 759ace7f46bSManish Rangankar list_del(&work->list); 760ace7f46bSManish Rangankar if (work->skb) 761ace7f46bSManish Rangankar kfree_skb(work->skb); 762ace7f46bSManish Rangankar kfree(work); 763ace7f46bSManish Rangankar } 764ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 765ace7f46bSManish Rangankar } 766ace7f46bSManish Rangankar 767ace7f46bSManish Rangankar static int qedi_ll2_recv_thread(void *arg) 768ace7f46bSManish Rangankar { 769ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)arg; 770ace7f46bSManish Rangankar struct skb_work_list *work, *work_tmp; 771ace7f46bSManish Rangankar 772ace7f46bSManish Rangankar set_user_nice(current, -20); 773ace7f46bSManish Rangankar 774ace7f46bSManish Rangankar while (!kthread_should_stop()) { 775ace7f46bSManish Rangankar spin_lock_bh(&qedi->ll2_lock); 776ace7f46bSManish Rangankar list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, 777ace7f46bSManish Rangankar list) { 778ace7f46bSManish Rangankar list_del(&work->list); 779ace7f46bSManish Rangankar qedi_ll2_process_skb(qedi, work->skb, work->vlan_id); 780ace7f46bSManish Rangankar kfree_skb(work->skb); 781ace7f46bSManish Rangankar kfree(work); 782ace7f46bSManish Rangankar } 783ace7f46bSManish Rangankar set_current_state(TASK_INTERRUPTIBLE); 784ace7f46bSManish Rangankar spin_unlock_bh(&qedi->ll2_lock); 785ace7f46bSManish Rangankar schedule(); 786ace7f46bSManish Rangankar } 787ace7f46bSManish Rangankar 788ace7f46bSManish Rangankar __set_current_state(TASK_RUNNING); 789ace7f46bSManish Rangankar return 0; 790ace7f46bSManish Rangankar } 791ace7f46bSManish Rangankar 792ace7f46bSManish Rangankar static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi) 793ace7f46bSManish Rangankar { 794ace7f46bSManish Rangankar u8 num_sq_pages; 795ace7f46bSManish Rangankar u32 log_page_size; 796ace7f46bSManish Rangankar int rval = 0; 797ace7f46bSManish Rangankar 798ace7f46bSManish Rangankar 799ace7f46bSManish Rangankar num_sq_pages = (MAX_OUSTANDING_TASKS_PER_CON * 8) / PAGE_SIZE; 800ace7f46bSManish Rangankar 801ace7f46bSManish Rangankar qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi); 802ace7f46bSManish Rangankar 80342d7c10fSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 80442d7c10fSManish Rangankar "Number of CQ count is %d\n", qedi->num_queues); 80542d7c10fSManish Rangankar 806ace7f46bSManish Rangankar memset(&qedi->pf_params.iscsi_pf_params, 0, 807ace7f46bSManish Rangankar sizeof(qedi->pf_params.iscsi_pf_params)); 808ace7f46bSManish Rangankar 809ace7f46bSManish Rangankar qedi->p_cpuq = pci_alloc_consistent(qedi->pdev, 810ace7f46bSManish Rangankar qedi->num_queues * sizeof(struct qedi_glbl_q_params), 811ace7f46bSManish Rangankar &qedi->hw_p_cpuq); 812ace7f46bSManish Rangankar if (!qedi->p_cpuq) { 813ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n"); 814ace7f46bSManish Rangankar rval = -1; 815ace7f46bSManish Rangankar goto err_alloc_mem; 816ace7f46bSManish Rangankar } 817ace7f46bSManish Rangankar 818ace7f46bSManish Rangankar rval = qedi_alloc_global_queues(qedi); 819ace7f46bSManish Rangankar if (rval) { 820ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Global queue allocation failed.\n"); 821ace7f46bSManish Rangankar rval = -1; 822ace7f46bSManish Rangankar goto err_alloc_mem; 823ace7f46bSManish Rangankar } 824ace7f46bSManish Rangankar 825ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_cons = QEDI_MAX_ISCSI_CONNS_PER_HBA; 826ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_tasks = QEDI_MAX_ISCSI_TASK; 827ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.half_way_close_timeout = 10; 828ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_sq_pages_in_ring = num_sq_pages; 829ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_r2tq_pages_in_ring = num_sq_pages; 830ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_uhq_pages_in_ring = num_sq_pages; 831ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.num_queues = qedi->num_queues; 832ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.debug_mode = qedi_fw_debug; 833962ea1c0Smanish.rangankar@cavium.com qedi->pf_params.iscsi_pf_params.two_msl_timer = 4000; 8343d61a313SNilesh Javali qedi->pf_params.iscsi_pf_params.max_fin_rt = 2; 835ace7f46bSManish Rangankar 836ace7f46bSManish Rangankar for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) { 837ace7f46bSManish Rangankar if ((1 << log_page_size) == PAGE_SIZE) 838ace7f46bSManish Rangankar break; 839ace7f46bSManish Rangankar } 840ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.log_page_size = log_page_size; 841ace7f46bSManish Rangankar 842ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.glbl_q_params_addr = 843ace7f46bSManish Rangankar (u64)qedi->hw_p_cpuq; 844ace7f46bSManish Rangankar 845ace7f46bSManish Rangankar /* RQ BDQ initializations. 846ace7f46bSManish Rangankar * rq_num_entries: suggested value for Initiator is 16 (4KB RQ) 847ace7f46bSManish Rangankar * rqe_log_size: 8 for 256B RQE 848ace7f46bSManish Rangankar */ 849ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.rqe_log_size = 8; 850ace7f46bSManish Rangankar /* BDQ address and size */ 851ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.bdq_pbl_base_addr[BDQ_ID_RQ] = 852ace7f46bSManish Rangankar qedi->bdq_pbl_list_dma; 853ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.bdq_pbl_num_entries[BDQ_ID_RQ] = 854ace7f46bSManish Rangankar qedi->bdq_pbl_list_num_entries; 855ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.rq_buffer_size = QEDI_BDQ_BUF_SIZE; 856ace7f46bSManish Rangankar 857ace7f46bSManish Rangankar /* cq_num_entries: num_tasks + rq_num_entries */ 858ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.cq_num_entries = 2048; 859ace7f46bSManish Rangankar 860ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.gl_rq_pi = QEDI_PROTO_CQ_PROD_IDX; 861ace7f46bSManish Rangankar qedi->pf_params.iscsi_pf_params.gl_cmd_pi = 1; 862ace7f46bSManish Rangankar 863ace7f46bSManish Rangankar err_alloc_mem: 864ace7f46bSManish Rangankar return rval; 865ace7f46bSManish Rangankar } 866ace7f46bSManish Rangankar 867ace7f46bSManish Rangankar /* Free DMA coherent memory for array of queue pointers we pass to qed */ 868ace7f46bSManish Rangankar static void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi) 869ace7f46bSManish Rangankar { 870ace7f46bSManish Rangankar size_t size = 0; 871ace7f46bSManish Rangankar 872ace7f46bSManish Rangankar if (qedi->p_cpuq) { 873ace7f46bSManish Rangankar size = qedi->num_queues * sizeof(struct qedi_glbl_q_params); 874ace7f46bSManish Rangankar pci_free_consistent(qedi->pdev, size, qedi->p_cpuq, 875ace7f46bSManish Rangankar qedi->hw_p_cpuq); 876ace7f46bSManish Rangankar } 877ace7f46bSManish Rangankar 878ace7f46bSManish Rangankar qedi_free_global_queues(qedi); 879ace7f46bSManish Rangankar 880ace7f46bSManish Rangankar kfree(qedi->global_queues); 881ace7f46bSManish Rangankar } 882ace7f46bSManish Rangankar 883534bbdf8SManish Rangankar static void qedi_get_boot_tgt_info(struct nvm_iscsi_block *block, 884534bbdf8SManish Rangankar struct qedi_boot_target *tgt, u8 index) 885534bbdf8SManish Rangankar { 886534bbdf8SManish Rangankar u32 ipv6_en; 887534bbdf8SManish Rangankar 888534bbdf8SManish Rangankar ipv6_en = !!(block->generic.ctrl_flags & 889534bbdf8SManish Rangankar NVM_ISCSI_CFG_GEN_IPV6_ENABLED); 890534bbdf8SManish Rangankar 891534bbdf8SManish Rangankar snprintf(tgt->iscsi_name, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n", 892534bbdf8SManish Rangankar block->target[index].target_name.byte); 893534bbdf8SManish Rangankar 894534bbdf8SManish Rangankar tgt->ipv6_en = ipv6_en; 895534bbdf8SManish Rangankar 896534bbdf8SManish Rangankar if (ipv6_en) 897534bbdf8SManish Rangankar snprintf(tgt->ip_addr, IPV6_LEN, "%pI6\n", 898534bbdf8SManish Rangankar block->target[index].ipv6_addr.byte); 899534bbdf8SManish Rangankar else 900534bbdf8SManish Rangankar snprintf(tgt->ip_addr, IPV4_LEN, "%pI4\n", 901534bbdf8SManish Rangankar block->target[index].ipv4_addr.byte); 902534bbdf8SManish Rangankar } 903534bbdf8SManish Rangankar 904534bbdf8SManish Rangankar static int qedi_find_boot_info(struct qedi_ctx *qedi, 905534bbdf8SManish Rangankar struct qed_mfw_tlv_iscsi *iscsi, 906534bbdf8SManish Rangankar struct nvm_iscsi_block *block) 907534bbdf8SManish Rangankar { 908534bbdf8SManish Rangankar struct qedi_boot_target *pri_tgt = NULL, *sec_tgt = NULL; 909534bbdf8SManish Rangankar u32 pri_ctrl_flags = 0, sec_ctrl_flags = 0, found = 0; 910534bbdf8SManish Rangankar struct iscsi_cls_session *cls_sess; 911534bbdf8SManish Rangankar struct iscsi_cls_conn *cls_conn; 912534bbdf8SManish Rangankar struct qedi_conn *qedi_conn; 913534bbdf8SManish Rangankar struct iscsi_session *sess; 914534bbdf8SManish Rangankar struct iscsi_conn *conn; 915534bbdf8SManish Rangankar char ep_ip_addr[64]; 916534bbdf8SManish Rangankar int i, ret = 0; 917534bbdf8SManish Rangankar 918534bbdf8SManish Rangankar pri_ctrl_flags = !!(block->target[0].ctrl_flags & 919534bbdf8SManish Rangankar NVM_ISCSI_CFG_TARGET_ENABLED); 920534bbdf8SManish Rangankar if (pri_ctrl_flags) { 921534bbdf8SManish Rangankar pri_tgt = kzalloc(sizeof(*pri_tgt), GFP_KERNEL); 922534bbdf8SManish Rangankar if (!pri_tgt) 923534bbdf8SManish Rangankar return -1; 924534bbdf8SManish Rangankar qedi_get_boot_tgt_info(block, pri_tgt, 0); 925534bbdf8SManish Rangankar } 926534bbdf8SManish Rangankar 927534bbdf8SManish Rangankar sec_ctrl_flags = !!(block->target[1].ctrl_flags & 928534bbdf8SManish Rangankar NVM_ISCSI_CFG_TARGET_ENABLED); 929534bbdf8SManish Rangankar if (sec_ctrl_flags) { 930534bbdf8SManish Rangankar sec_tgt = kzalloc(sizeof(*sec_tgt), GFP_KERNEL); 931534bbdf8SManish Rangankar if (!sec_tgt) { 932534bbdf8SManish Rangankar ret = -1; 933534bbdf8SManish Rangankar goto free_tgt; 934534bbdf8SManish Rangankar } 935534bbdf8SManish Rangankar qedi_get_boot_tgt_info(block, sec_tgt, 1); 936534bbdf8SManish Rangankar } 937534bbdf8SManish Rangankar 938534bbdf8SManish Rangankar for (i = 0; i < qedi->max_active_conns; i++) { 939534bbdf8SManish Rangankar qedi_conn = qedi_get_conn_from_id(qedi, i); 940534bbdf8SManish Rangankar if (!qedi_conn) 941534bbdf8SManish Rangankar continue; 942534bbdf8SManish Rangankar 943534bbdf8SManish Rangankar if (qedi_conn->ep->ip_type == TCP_IPV4) 944534bbdf8SManish Rangankar snprintf(ep_ip_addr, IPV4_LEN, "%pI4\n", 945534bbdf8SManish Rangankar qedi_conn->ep->dst_addr); 946534bbdf8SManish Rangankar else 947534bbdf8SManish Rangankar snprintf(ep_ip_addr, IPV6_LEN, "%pI6\n", 948534bbdf8SManish Rangankar qedi_conn->ep->dst_addr); 949534bbdf8SManish Rangankar 950534bbdf8SManish Rangankar cls_conn = qedi_conn->cls_conn; 951534bbdf8SManish Rangankar conn = cls_conn->dd_data; 952534bbdf8SManish Rangankar cls_sess = iscsi_conn_to_session(cls_conn); 953534bbdf8SManish Rangankar sess = cls_sess->dd_data; 954534bbdf8SManish Rangankar 955534bbdf8SManish Rangankar if (pri_ctrl_flags) { 956534bbdf8SManish Rangankar if (!strcmp(pri_tgt->iscsi_name, sess->targetname) && 957534bbdf8SManish Rangankar !strcmp(pri_tgt->ip_addr, ep_ip_addr)) { 958534bbdf8SManish Rangankar found = 1; 959534bbdf8SManish Rangankar break; 960534bbdf8SManish Rangankar } 961534bbdf8SManish Rangankar } 962534bbdf8SManish Rangankar 963534bbdf8SManish Rangankar if (sec_ctrl_flags) { 964534bbdf8SManish Rangankar if (!strcmp(sec_tgt->iscsi_name, sess->targetname) && 965534bbdf8SManish Rangankar !strcmp(sec_tgt->ip_addr, ep_ip_addr)) { 966534bbdf8SManish Rangankar found = 1; 967534bbdf8SManish Rangankar break; 968534bbdf8SManish Rangankar } 969534bbdf8SManish Rangankar } 970534bbdf8SManish Rangankar } 971534bbdf8SManish Rangankar 972534bbdf8SManish Rangankar if (found) { 973534bbdf8SManish Rangankar if (conn->hdrdgst_en) { 974534bbdf8SManish Rangankar iscsi->header_digest_set = true; 975534bbdf8SManish Rangankar iscsi->header_digest = 1; 976534bbdf8SManish Rangankar } 977534bbdf8SManish Rangankar 978534bbdf8SManish Rangankar if (conn->datadgst_en) { 979534bbdf8SManish Rangankar iscsi->data_digest_set = true; 980534bbdf8SManish Rangankar iscsi->data_digest = 1; 981534bbdf8SManish Rangankar } 982534bbdf8SManish Rangankar iscsi->boot_taget_portal_set = true; 983534bbdf8SManish Rangankar iscsi->boot_taget_portal = sess->tpgt; 984534bbdf8SManish Rangankar 985534bbdf8SManish Rangankar } else { 986534bbdf8SManish Rangankar ret = -1; 987534bbdf8SManish Rangankar } 988534bbdf8SManish Rangankar 989534bbdf8SManish Rangankar if (sec_ctrl_flags) 990534bbdf8SManish Rangankar kfree(sec_tgt); 991534bbdf8SManish Rangankar free_tgt: 992534bbdf8SManish Rangankar if (pri_ctrl_flags) 993534bbdf8SManish Rangankar kfree(pri_tgt); 994534bbdf8SManish Rangankar 995534bbdf8SManish Rangankar return ret; 996534bbdf8SManish Rangankar } 997534bbdf8SManish Rangankar 998269afb36SManish Rangankar static void qedi_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data) 999269afb36SManish Rangankar { 1000269afb36SManish Rangankar struct qedi_ctx *qedi; 1001269afb36SManish Rangankar 1002269afb36SManish Rangankar if (!dev) { 1003269afb36SManish Rangankar QEDI_INFO(NULL, QEDI_LOG_EVT, 1004269afb36SManish Rangankar "dev is NULL so ignoring get_generic_tlv_data request.\n"); 1005269afb36SManish Rangankar return; 1006269afb36SManish Rangankar } 1007269afb36SManish Rangankar qedi = (struct qedi_ctx *)dev; 1008269afb36SManish Rangankar 1009269afb36SManish Rangankar memset(data, 0, sizeof(struct qed_generic_tlvs)); 1010269afb36SManish Rangankar ether_addr_copy(data->mac[0], qedi->mac); 1011269afb36SManish Rangankar } 1012269afb36SManish Rangankar 1013534bbdf8SManish Rangankar /* 1014534bbdf8SManish Rangankar * Protocol TLV handler 1015534bbdf8SManish Rangankar */ 1016534bbdf8SManish Rangankar static void qedi_get_protocol_tlv_data(void *dev, void *data) 1017534bbdf8SManish Rangankar { 1018534bbdf8SManish Rangankar struct qed_mfw_tlv_iscsi *iscsi = data; 1019534bbdf8SManish Rangankar struct qed_iscsi_stats *fw_iscsi_stats; 1020534bbdf8SManish Rangankar struct nvm_iscsi_block *block = NULL; 1021534bbdf8SManish Rangankar u32 chap_en = 0, mchap_en = 0; 1022534bbdf8SManish Rangankar struct qedi_ctx *qedi = dev; 1023534bbdf8SManish Rangankar int rval = 0; 1024534bbdf8SManish Rangankar 1025534bbdf8SManish Rangankar fw_iscsi_stats = kmalloc(sizeof(*fw_iscsi_stats), GFP_KERNEL); 1026534bbdf8SManish Rangankar if (!fw_iscsi_stats) { 1027534bbdf8SManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1028534bbdf8SManish Rangankar "Could not allocate memory for fw_iscsi_stats.\n"); 1029534bbdf8SManish Rangankar goto exit_get_data; 1030534bbdf8SManish Rangankar } 1031534bbdf8SManish Rangankar 1032534bbdf8SManish Rangankar mutex_lock(&qedi->stats_lock); 1033534bbdf8SManish Rangankar /* Query firmware for offload stats */ 1034534bbdf8SManish Rangankar qedi_ops->get_stats(qedi->cdev, fw_iscsi_stats); 1035534bbdf8SManish Rangankar mutex_unlock(&qedi->stats_lock); 1036534bbdf8SManish Rangankar 1037534bbdf8SManish Rangankar iscsi->rx_frames_set = true; 1038534bbdf8SManish Rangankar iscsi->rx_frames = fw_iscsi_stats->iscsi_rx_packet_cnt; 1039534bbdf8SManish Rangankar iscsi->rx_bytes_set = true; 1040534bbdf8SManish Rangankar iscsi->rx_bytes = fw_iscsi_stats->iscsi_rx_bytes_cnt; 1041534bbdf8SManish Rangankar iscsi->tx_frames_set = true; 1042534bbdf8SManish Rangankar iscsi->tx_frames = fw_iscsi_stats->iscsi_tx_packet_cnt; 1043534bbdf8SManish Rangankar iscsi->tx_bytes_set = true; 1044534bbdf8SManish Rangankar iscsi->tx_bytes = fw_iscsi_stats->iscsi_tx_bytes_cnt; 1045534bbdf8SManish Rangankar iscsi->frame_size_set = true; 1046534bbdf8SManish Rangankar iscsi->frame_size = qedi->ll2_mtu; 1047534bbdf8SManish Rangankar block = qedi_get_nvram_block(qedi); 1048534bbdf8SManish Rangankar if (block) { 1049534bbdf8SManish Rangankar chap_en = !!(block->generic.ctrl_flags & 1050534bbdf8SManish Rangankar NVM_ISCSI_CFG_GEN_CHAP_ENABLED); 1051534bbdf8SManish Rangankar mchap_en = !!(block->generic.ctrl_flags & 1052534bbdf8SManish Rangankar NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED); 1053534bbdf8SManish Rangankar 1054534bbdf8SManish Rangankar iscsi->auth_method_set = (chap_en || mchap_en) ? true : false; 1055534bbdf8SManish Rangankar iscsi->auth_method = 1; 1056534bbdf8SManish Rangankar if (chap_en) 1057534bbdf8SManish Rangankar iscsi->auth_method = 2; 1058534bbdf8SManish Rangankar if (mchap_en) 1059534bbdf8SManish Rangankar iscsi->auth_method = 3; 1060534bbdf8SManish Rangankar 1061534bbdf8SManish Rangankar iscsi->tx_desc_size_set = true; 1062534bbdf8SManish Rangankar iscsi->tx_desc_size = QEDI_SQ_SIZE; 1063534bbdf8SManish Rangankar iscsi->rx_desc_size_set = true; 1064534bbdf8SManish Rangankar iscsi->rx_desc_size = QEDI_CQ_SIZE; 1065534bbdf8SManish Rangankar 1066534bbdf8SManish Rangankar /* tpgt, hdr digest, data digest */ 1067534bbdf8SManish Rangankar rval = qedi_find_boot_info(qedi, iscsi, block); 1068534bbdf8SManish Rangankar if (rval) 1069534bbdf8SManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1070534bbdf8SManish Rangankar "Boot target not set"); 1071534bbdf8SManish Rangankar } 1072534bbdf8SManish Rangankar 1073534bbdf8SManish Rangankar kfree(fw_iscsi_stats); 1074534bbdf8SManish Rangankar exit_get_data: 1075534bbdf8SManish Rangankar return; 1076534bbdf8SManish Rangankar } 1077534bbdf8SManish Rangankar 1078ace7f46bSManish Rangankar static void qedi_link_update(void *dev, struct qed_link_output *link) 1079ace7f46bSManish Rangankar { 1080ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)dev; 1081ace7f46bSManish Rangankar 1082ace7f46bSManish Rangankar if (link->link_up) { 1083ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "Link Up event.\n"); 1084ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_UP); 1085ace7f46bSManish Rangankar } else { 1086ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1087ace7f46bSManish Rangankar "Link Down event.\n"); 1088ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 1089ace7f46bSManish Rangankar } 1090ace7f46bSManish Rangankar } 1091ace7f46bSManish Rangankar 1092ace7f46bSManish Rangankar static struct qed_iscsi_cb_ops qedi_cb_ops = { 1093ace7f46bSManish Rangankar { 1094ace7f46bSManish Rangankar .link_update = qedi_link_update, 1095534bbdf8SManish Rangankar .get_protocol_tlv_data = qedi_get_protocol_tlv_data, 1096269afb36SManish Rangankar .get_generic_tlv_data = qedi_get_generic_tlv_data, 1097ace7f46bSManish Rangankar } 1098ace7f46bSManish Rangankar }; 1099ace7f46bSManish Rangankar 1100ace7f46bSManish Rangankar static int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe, 1101ace7f46bSManish Rangankar u16 que_idx, struct qedi_percpu_s *p) 1102ace7f46bSManish Rangankar { 1103ace7f46bSManish Rangankar struct qedi_work *qedi_work; 1104ace7f46bSManish Rangankar struct qedi_conn *q_conn; 1105ace7f46bSManish Rangankar struct iscsi_conn *conn; 1106ace7f46bSManish Rangankar struct qedi_cmd *qedi_cmd; 1107ace7f46bSManish Rangankar u32 iscsi_cid; 1108ace7f46bSManish Rangankar int rc = 0; 1109ace7f46bSManish Rangankar 1110ace7f46bSManish Rangankar iscsi_cid = cqe->cqe_common.conn_id; 1111ace7f46bSManish Rangankar q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; 1112ace7f46bSManish Rangankar if (!q_conn) { 1113ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1114ace7f46bSManish Rangankar "Session no longer exists for cid=0x%x!!\n", 1115ace7f46bSManish Rangankar iscsi_cid); 1116ace7f46bSManish Rangankar return -1; 1117ace7f46bSManish Rangankar } 1118ace7f46bSManish Rangankar conn = q_conn->cls_conn->dd_data; 1119ace7f46bSManish Rangankar 1120ace7f46bSManish Rangankar switch (cqe->cqe_common.cqe_type) { 1121ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_SOLICITED: 1122ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE: 1123ace7f46bSManish Rangankar qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid); 1124ace7f46bSManish Rangankar if (!qedi_cmd) { 1125ace7f46bSManish Rangankar rc = -1; 1126ace7f46bSManish Rangankar break; 1127ace7f46bSManish Rangankar } 1128ace7f46bSManish Rangankar INIT_LIST_HEAD(&qedi_cmd->cqe_work.list); 1129ace7f46bSManish Rangankar qedi_cmd->cqe_work.qedi = qedi; 1130ace7f46bSManish Rangankar memcpy(&qedi_cmd->cqe_work.cqe, cqe, sizeof(union iscsi_cqe)); 1131ace7f46bSManish Rangankar qedi_cmd->cqe_work.que_idx = que_idx; 1132ace7f46bSManish Rangankar qedi_cmd->cqe_work.is_solicited = true; 1133ace7f46bSManish Rangankar list_add_tail(&qedi_cmd->cqe_work.list, &p->work_list); 1134ace7f46bSManish Rangankar break; 1135ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_UNSOLICITED: 1136ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_DUMMY: 1137ace7f46bSManish Rangankar case ISCSI_CQE_TYPE_TASK_CLEANUP: 1138ace7f46bSManish Rangankar qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC); 1139ace7f46bSManish Rangankar if (!qedi_work) { 1140ace7f46bSManish Rangankar rc = -1; 1141ace7f46bSManish Rangankar break; 1142ace7f46bSManish Rangankar } 1143ace7f46bSManish Rangankar INIT_LIST_HEAD(&qedi_work->list); 1144ace7f46bSManish Rangankar qedi_work->qedi = qedi; 1145ace7f46bSManish Rangankar memcpy(&qedi_work->cqe, cqe, sizeof(union iscsi_cqe)); 1146ace7f46bSManish Rangankar qedi_work->que_idx = que_idx; 1147ace7f46bSManish Rangankar qedi_work->is_solicited = false; 1148ace7f46bSManish Rangankar list_add_tail(&qedi_work->list, &p->work_list); 1149ace7f46bSManish Rangankar break; 1150ace7f46bSManish Rangankar default: 1151ace7f46bSManish Rangankar rc = -1; 1152ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "FW Error cqe.\n"); 1153ace7f46bSManish Rangankar } 1154ace7f46bSManish Rangankar return rc; 1155ace7f46bSManish Rangankar } 1156ace7f46bSManish Rangankar 1157ace7f46bSManish Rangankar static bool qedi_process_completions(struct qedi_fastpath *fp) 1158ace7f46bSManish Rangankar { 1159ace7f46bSManish Rangankar struct qedi_ctx *qedi = fp->qedi; 1160ace7f46bSManish Rangankar struct qed_sb_info *sb_info = fp->sb_info; 116121dd79e8STomer Tayar struct status_block_e4 *sb = sb_info->sb_virt; 1162ace7f46bSManish Rangankar struct qedi_percpu_s *p = NULL; 1163ace7f46bSManish Rangankar struct global_queue *que; 1164ace7f46bSManish Rangankar u16 prod_idx; 1165ace7f46bSManish Rangankar unsigned long flags; 1166ace7f46bSManish Rangankar union iscsi_cqe *cqe; 1167ace7f46bSManish Rangankar int cpu; 1168ace7f46bSManish Rangankar int ret; 1169ace7f46bSManish Rangankar 1170ace7f46bSManish Rangankar /* Get the current firmware producer index */ 1171ace7f46bSManish Rangankar prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; 1172ace7f46bSManish Rangankar 1173ace7f46bSManish Rangankar if (prod_idx >= QEDI_CQ_SIZE) 1174ace7f46bSManish Rangankar prod_idx = prod_idx % QEDI_CQ_SIZE; 1175ace7f46bSManish Rangankar 1176ace7f46bSManish Rangankar que = qedi->global_queues[fp->sb_id]; 1177ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, 1178ace7f46bSManish Rangankar "Before: global queue=%p prod_idx=%d cons_idx=%d, sb_id=%d\n", 1179ace7f46bSManish Rangankar que, prod_idx, que->cq_cons_idx, fp->sb_id); 1180ace7f46bSManish Rangankar 1181ace7f46bSManish Rangankar qedi->intr_cpu = fp->sb_id; 1182ace7f46bSManish Rangankar cpu = smp_processor_id(); 1183ace7f46bSManish Rangankar p = &per_cpu(qedi_percpu, cpu); 1184ace7f46bSManish Rangankar 1185ace7f46bSManish Rangankar if (unlikely(!p->iothread)) 1186ace7f46bSManish Rangankar WARN_ON(1); 1187ace7f46bSManish Rangankar 1188ace7f46bSManish Rangankar spin_lock_irqsave(&p->p_work_lock, flags); 1189ace7f46bSManish Rangankar while (que->cq_cons_idx != prod_idx) { 1190ace7f46bSManish Rangankar cqe = &que->cq[que->cq_cons_idx]; 1191ace7f46bSManish Rangankar 1192ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, 1193ace7f46bSManish Rangankar "cqe=%p prod_idx=%d cons_idx=%d.\n", 1194ace7f46bSManish Rangankar cqe, prod_idx, que->cq_cons_idx); 1195ace7f46bSManish Rangankar 1196ace7f46bSManish Rangankar ret = qedi_queue_cqe(qedi, cqe, fp->sb_id, p); 1197ace7f46bSManish Rangankar if (ret) 1198a1a20ffdSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1199a1a20ffdSManish Rangankar "Dropping CQE 0x%x for cid=0x%x.\n", 1200a1a20ffdSManish Rangankar que->cq_cons_idx, cqe->cqe_common.conn_id); 1201ace7f46bSManish Rangankar 1202ace7f46bSManish Rangankar que->cq_cons_idx++; 1203ace7f46bSManish Rangankar if (que->cq_cons_idx == QEDI_CQ_SIZE) 1204ace7f46bSManish Rangankar que->cq_cons_idx = 0; 1205ace7f46bSManish Rangankar } 1206ace7f46bSManish Rangankar wake_up_process(p->iothread); 1207ace7f46bSManish Rangankar spin_unlock_irqrestore(&p->p_work_lock, flags); 1208ace7f46bSManish Rangankar 1209ace7f46bSManish Rangankar return true; 1210ace7f46bSManish Rangankar } 1211ace7f46bSManish Rangankar 1212ace7f46bSManish Rangankar static bool qedi_fp_has_work(struct qedi_fastpath *fp) 1213ace7f46bSManish Rangankar { 1214ace7f46bSManish Rangankar struct qedi_ctx *qedi = fp->qedi; 1215ace7f46bSManish Rangankar struct global_queue *que; 1216ace7f46bSManish Rangankar struct qed_sb_info *sb_info = fp->sb_info; 121721dd79e8STomer Tayar struct status_block_e4 *sb = sb_info->sb_virt; 1218ace7f46bSManish Rangankar u16 prod_idx; 1219ace7f46bSManish Rangankar 1220ace7f46bSManish Rangankar barrier(); 1221ace7f46bSManish Rangankar 1222ace7f46bSManish Rangankar /* Get the current firmware producer index */ 1223ace7f46bSManish Rangankar prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; 1224ace7f46bSManish Rangankar 1225ace7f46bSManish Rangankar /* Get the pointer to the global CQ this completion is on */ 1226ace7f46bSManish Rangankar que = qedi->global_queues[fp->sb_id]; 1227ace7f46bSManish Rangankar 1228ace7f46bSManish Rangankar /* prod idx wrap around uint16 */ 1229ace7f46bSManish Rangankar if (prod_idx >= QEDI_CQ_SIZE) 1230ace7f46bSManish Rangankar prod_idx = prod_idx % QEDI_CQ_SIZE; 1231ace7f46bSManish Rangankar 1232ace7f46bSManish Rangankar return (que->cq_cons_idx != prod_idx); 1233ace7f46bSManish Rangankar } 1234ace7f46bSManish Rangankar 1235ace7f46bSManish Rangankar /* MSI-X fastpath handler code */ 1236ace7f46bSManish Rangankar static irqreturn_t qedi_msix_handler(int irq, void *dev_id) 1237ace7f46bSManish Rangankar { 1238ace7f46bSManish Rangankar struct qedi_fastpath *fp = dev_id; 1239ace7f46bSManish Rangankar struct qedi_ctx *qedi = fp->qedi; 1240ace7f46bSManish Rangankar bool wake_io_thread = true; 1241ace7f46bSManish Rangankar 1242ace7f46bSManish Rangankar qed_sb_ack(fp->sb_info, IGU_INT_DISABLE, 0); 1243ace7f46bSManish Rangankar 1244ace7f46bSManish Rangankar process_again: 1245ace7f46bSManish Rangankar wake_io_thread = qedi_process_completions(fp); 1246ace7f46bSManish Rangankar if (wake_io_thread) { 1247ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 1248ace7f46bSManish Rangankar "process already running\n"); 1249ace7f46bSManish Rangankar } 1250ace7f46bSManish Rangankar 1251ace7f46bSManish Rangankar if (qedi_fp_has_work(fp) == 0) 1252ace7f46bSManish Rangankar qed_sb_update_sb_idx(fp->sb_info); 1253ace7f46bSManish Rangankar 1254ace7f46bSManish Rangankar /* Check for more work */ 1255ace7f46bSManish Rangankar rmb(); 1256ace7f46bSManish Rangankar 1257ace7f46bSManish Rangankar if (qedi_fp_has_work(fp) == 0) 1258ace7f46bSManish Rangankar qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1); 1259ace7f46bSManish Rangankar else 1260ace7f46bSManish Rangankar goto process_again; 1261ace7f46bSManish Rangankar 1262ace7f46bSManish Rangankar return IRQ_HANDLED; 1263ace7f46bSManish Rangankar } 1264ace7f46bSManish Rangankar 1265ace7f46bSManish Rangankar /* simd handler for MSI/INTa */ 1266ace7f46bSManish Rangankar static void qedi_simd_int_handler(void *cookie) 1267ace7f46bSManish Rangankar { 1268ace7f46bSManish Rangankar /* Cookie is qedi_ctx struct */ 1269ace7f46bSManish Rangankar struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; 1270ace7f46bSManish Rangankar 1271ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, "qedi=%p.\n", qedi); 1272ace7f46bSManish Rangankar } 1273ace7f46bSManish Rangankar 1274ace7f46bSManish Rangankar #define QEDI_SIMD_HANDLER_NUM 0 1275ace7f46bSManish Rangankar static void qedi_sync_free_irqs(struct qedi_ctx *qedi) 1276ace7f46bSManish Rangankar { 1277ace7f46bSManish Rangankar int i; 1278ace7f46bSManish Rangankar 1279ace7f46bSManish Rangankar if (qedi->int_info.msix_cnt) { 1280ace7f46bSManish Rangankar for (i = 0; i < qedi->int_info.used_cnt; i++) { 1281ace7f46bSManish Rangankar synchronize_irq(qedi->int_info.msix[i].vector); 1282ace7f46bSManish Rangankar irq_set_affinity_hint(qedi->int_info.msix[i].vector, 1283ace7f46bSManish Rangankar NULL); 1284ace7f46bSManish Rangankar free_irq(qedi->int_info.msix[i].vector, 1285ace7f46bSManish Rangankar &qedi->fp_array[i]); 1286ace7f46bSManish Rangankar } 1287ace7f46bSManish Rangankar } else { 1288ace7f46bSManish Rangankar qedi_ops->common->simd_handler_clean(qedi->cdev, 1289ace7f46bSManish Rangankar QEDI_SIMD_HANDLER_NUM); 1290ace7f46bSManish Rangankar } 1291ace7f46bSManish Rangankar 1292ace7f46bSManish Rangankar qedi->int_info.used_cnt = 0; 1293ace7f46bSManish Rangankar qedi_ops->common->set_fp_int(qedi->cdev, 0); 1294ace7f46bSManish Rangankar } 1295ace7f46bSManish Rangankar 1296ace7f46bSManish Rangankar static int qedi_request_msix_irq(struct qedi_ctx *qedi) 1297ace7f46bSManish Rangankar { 1298ace7f46bSManish Rangankar int i, rc, cpu; 1299ace7f46bSManish Rangankar 1300ace7f46bSManish Rangankar cpu = cpumask_first(cpu_online_mask); 1301ace7f46bSManish Rangankar for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) { 1302ace7f46bSManish Rangankar rc = request_irq(qedi->int_info.msix[i].vector, 1303ace7f46bSManish Rangankar qedi_msix_handler, 0, "qedi", 1304ace7f46bSManish Rangankar &qedi->fp_array[i]); 1305ace7f46bSManish Rangankar 1306ace7f46bSManish Rangankar if (rc) { 1307ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); 1308ace7f46bSManish Rangankar qedi_sync_free_irqs(qedi); 1309ace7f46bSManish Rangankar return rc; 1310ace7f46bSManish Rangankar } 1311ace7f46bSManish Rangankar qedi->int_info.used_cnt++; 1312ace7f46bSManish Rangankar rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector, 1313ace7f46bSManish Rangankar get_cpu_mask(cpu)); 1314ace7f46bSManish Rangankar cpu = cpumask_next(cpu, cpu_online_mask); 1315ace7f46bSManish Rangankar } 1316ace7f46bSManish Rangankar 1317ace7f46bSManish Rangankar return 0; 1318ace7f46bSManish Rangankar } 1319ace7f46bSManish Rangankar 1320ace7f46bSManish Rangankar static int qedi_setup_int(struct qedi_ctx *qedi) 1321ace7f46bSManish Rangankar { 1322ace7f46bSManish Rangankar int rc = 0; 1323ace7f46bSManish Rangankar 1324ace7f46bSManish Rangankar rc = qedi_ops->common->set_fp_int(qedi->cdev, num_online_cpus()); 1325ace7f46bSManish Rangankar rc = qedi_ops->common->get_fp_int(qedi->cdev, &qedi->int_info); 1326ace7f46bSManish Rangankar if (rc) 1327ace7f46bSManish Rangankar goto exit_setup_int; 1328ace7f46bSManish Rangankar 1329ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 1330ace7f46bSManish Rangankar "Number of msix_cnt = 0x%x num of cpus = 0x%x\n", 1331ace7f46bSManish Rangankar qedi->int_info.msix_cnt, num_online_cpus()); 1332ace7f46bSManish Rangankar 1333ace7f46bSManish Rangankar if (qedi->int_info.msix_cnt) { 1334ace7f46bSManish Rangankar rc = qedi_request_msix_irq(qedi); 1335ace7f46bSManish Rangankar goto exit_setup_int; 1336ace7f46bSManish Rangankar } else { 1337ace7f46bSManish Rangankar qedi_ops->common->simd_handler_config(qedi->cdev, &qedi, 1338ace7f46bSManish Rangankar QEDI_SIMD_HANDLER_NUM, 1339ace7f46bSManish Rangankar qedi_simd_int_handler); 1340ace7f46bSManish Rangankar qedi->int_info.used_cnt = 1; 1341ace7f46bSManish Rangankar } 1342ace7f46bSManish Rangankar 1343ace7f46bSManish Rangankar exit_setup_int: 1344ace7f46bSManish Rangankar return rc; 1345ace7f46bSManish Rangankar } 1346ace7f46bSManish Rangankar 1347c57ec8fbSNilesh Javali static void qedi_free_nvm_iscsi_cfg(struct qedi_ctx *qedi) 1348c57ec8fbSNilesh Javali { 1349c57ec8fbSNilesh Javali if (qedi->iscsi_cfg) 1350c57ec8fbSNilesh Javali dma_free_coherent(&qedi->pdev->dev, 1351c57ec8fbSNilesh Javali sizeof(struct nvm_iscsi_cfg), 1352c57ec8fbSNilesh Javali qedi->iscsi_cfg, qedi->nvm_buf_dma); 1353c57ec8fbSNilesh Javali } 1354c57ec8fbSNilesh Javali 1355c57ec8fbSNilesh Javali static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi) 1356c57ec8fbSNilesh Javali { 1357c57ec8fbSNilesh Javali qedi->iscsi_cfg = dma_zalloc_coherent(&qedi->pdev->dev, 1358c57ec8fbSNilesh Javali sizeof(struct nvm_iscsi_cfg), 1359c57ec8fbSNilesh Javali &qedi->nvm_buf_dma, GFP_KERNEL); 1360c57ec8fbSNilesh Javali if (!qedi->iscsi_cfg) { 1361c57ec8fbSNilesh Javali QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n"); 1362c57ec8fbSNilesh Javali return -ENOMEM; 1363c57ec8fbSNilesh Javali } 1364c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 1365c57ec8fbSNilesh Javali "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_cfg, 1366c57ec8fbSNilesh Javali qedi->nvm_buf_dma); 1367c57ec8fbSNilesh Javali 1368c57ec8fbSNilesh Javali return 0; 1369c57ec8fbSNilesh Javali } 1370c57ec8fbSNilesh Javali 1371ace7f46bSManish Rangankar static void qedi_free_bdq(struct qedi_ctx *qedi) 1372ace7f46bSManish Rangankar { 1373ace7f46bSManish Rangankar int i; 1374ace7f46bSManish Rangankar 1375ace7f46bSManish Rangankar if (qedi->bdq_pbl_list) 1376ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, PAGE_SIZE, 1377ace7f46bSManish Rangankar qedi->bdq_pbl_list, qedi->bdq_pbl_list_dma); 1378ace7f46bSManish Rangankar 1379ace7f46bSManish Rangankar if (qedi->bdq_pbl) 1380ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, qedi->bdq_pbl_mem_size, 1381ace7f46bSManish Rangankar qedi->bdq_pbl, qedi->bdq_pbl_dma); 1382ace7f46bSManish Rangankar 1383ace7f46bSManish Rangankar for (i = 0; i < QEDI_BDQ_NUM; i++) { 1384ace7f46bSManish Rangankar if (qedi->bdq[i].buf_addr) { 1385ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, QEDI_BDQ_BUF_SIZE, 1386ace7f46bSManish Rangankar qedi->bdq[i].buf_addr, 1387ace7f46bSManish Rangankar qedi->bdq[i].buf_dma); 1388ace7f46bSManish Rangankar } 1389ace7f46bSManish Rangankar } 1390ace7f46bSManish Rangankar } 1391ace7f46bSManish Rangankar 1392ace7f46bSManish Rangankar static void qedi_free_global_queues(struct qedi_ctx *qedi) 1393ace7f46bSManish Rangankar { 1394ace7f46bSManish Rangankar int i; 1395ace7f46bSManish Rangankar struct global_queue **gl = qedi->global_queues; 1396ace7f46bSManish Rangankar 1397ace7f46bSManish Rangankar for (i = 0; i < qedi->num_queues; i++) { 1398ace7f46bSManish Rangankar if (!gl[i]) 1399ace7f46bSManish Rangankar continue; 1400ace7f46bSManish Rangankar 1401ace7f46bSManish Rangankar if (gl[i]->cq) 1402ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_mem_size, 1403ace7f46bSManish Rangankar gl[i]->cq, gl[i]->cq_dma); 1404ace7f46bSManish Rangankar if (gl[i]->cq_pbl) 1405ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_pbl_size, 1406ace7f46bSManish Rangankar gl[i]->cq_pbl, gl[i]->cq_pbl_dma); 1407ace7f46bSManish Rangankar 1408ace7f46bSManish Rangankar kfree(gl[i]); 1409ace7f46bSManish Rangankar } 1410ace7f46bSManish Rangankar qedi_free_bdq(qedi); 1411c57ec8fbSNilesh Javali qedi_free_nvm_iscsi_cfg(qedi); 1412ace7f46bSManish Rangankar } 1413ace7f46bSManish Rangankar 1414ace7f46bSManish Rangankar static int qedi_alloc_bdq(struct qedi_ctx *qedi) 1415ace7f46bSManish Rangankar { 1416ace7f46bSManish Rangankar int i; 1417ace7f46bSManish Rangankar struct scsi_bd *pbl; 1418ace7f46bSManish Rangankar u64 *list; 1419ace7f46bSManish Rangankar dma_addr_t page; 1420ace7f46bSManish Rangankar 1421ace7f46bSManish Rangankar /* Alloc dma memory for BDQ buffers */ 1422ace7f46bSManish Rangankar for (i = 0; i < QEDI_BDQ_NUM; i++) { 1423ace7f46bSManish Rangankar qedi->bdq[i].buf_addr = 1424ace7f46bSManish Rangankar dma_alloc_coherent(&qedi->pdev->dev, 1425ace7f46bSManish Rangankar QEDI_BDQ_BUF_SIZE, 1426ace7f46bSManish Rangankar &qedi->bdq[i].buf_dma, 1427ace7f46bSManish Rangankar GFP_KERNEL); 1428ace7f46bSManish Rangankar if (!qedi->bdq[i].buf_addr) { 1429ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1430ace7f46bSManish Rangankar "Could not allocate BDQ buffer %d.\n", i); 1431ace7f46bSManish Rangankar return -ENOMEM; 1432ace7f46bSManish Rangankar } 1433ace7f46bSManish Rangankar } 1434ace7f46bSManish Rangankar 1435ace7f46bSManish Rangankar /* Alloc dma memory for BDQ page buffer list */ 1436ace7f46bSManish Rangankar qedi->bdq_pbl_mem_size = QEDI_BDQ_NUM * sizeof(struct scsi_bd); 1437ace7f46bSManish Rangankar qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, PAGE_SIZE); 1438ace7f46bSManish Rangankar qedi->rq_num_entries = qedi->bdq_pbl_mem_size / sizeof(struct scsi_bd); 1439ace7f46bSManish Rangankar 1440ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, "rq_num_entries = %d.\n", 1441ace7f46bSManish Rangankar qedi->rq_num_entries); 1442ace7f46bSManish Rangankar 1443ace7f46bSManish Rangankar qedi->bdq_pbl = dma_alloc_coherent(&qedi->pdev->dev, 1444ace7f46bSManish Rangankar qedi->bdq_pbl_mem_size, 1445ace7f46bSManish Rangankar &qedi->bdq_pbl_dma, GFP_KERNEL); 1446ace7f46bSManish Rangankar if (!qedi->bdq_pbl) { 1447ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Could not allocate BDQ PBL.\n"); 1448ace7f46bSManish Rangankar return -ENOMEM; 1449ace7f46bSManish Rangankar } 1450ace7f46bSManish Rangankar 1451ace7f46bSManish Rangankar /* 1452ace7f46bSManish Rangankar * Populate BDQ PBL with physical and virtual address of individual 1453ace7f46bSManish Rangankar * BDQ buffers 1454ace7f46bSManish Rangankar */ 1455ace7f46bSManish Rangankar pbl = (struct scsi_bd *)qedi->bdq_pbl; 1456ace7f46bSManish Rangankar for (i = 0; i < QEDI_BDQ_NUM; i++) { 1457ace7f46bSManish Rangankar pbl->address.hi = 1458ace7f46bSManish Rangankar cpu_to_le32(QEDI_U64_HI(qedi->bdq[i].buf_dma)); 1459ace7f46bSManish Rangankar pbl->address.lo = 1460ace7f46bSManish Rangankar cpu_to_le32(QEDI_U64_LO(qedi->bdq[i].buf_dma)); 1461ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1462ace7f46bSManish Rangankar "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx], idx [%d]\n", 1463ace7f46bSManish Rangankar pbl, pbl->address.hi, pbl->address.lo, i); 1464da090917STomer Tayar pbl->opaque.iscsi_opaque.reserved_zero[0] = 0; 1465da090917STomer Tayar pbl->opaque.iscsi_opaque.reserved_zero[1] = 0; 1466da090917STomer Tayar pbl->opaque.iscsi_opaque.reserved_zero[2] = 0; 1467da090917STomer Tayar pbl->opaque.iscsi_opaque.opaque = cpu_to_le16(i); 1468ace7f46bSManish Rangankar pbl++; 1469ace7f46bSManish Rangankar } 1470ace7f46bSManish Rangankar 1471ace7f46bSManish Rangankar /* Allocate list of PBL pages */ 1472e9f31779SHimanshu Jha qedi->bdq_pbl_list = dma_zalloc_coherent(&qedi->pdev->dev, PAGE_SIZE, 1473ace7f46bSManish Rangankar &qedi->bdq_pbl_list_dma, 1474ace7f46bSManish Rangankar GFP_KERNEL); 1475ace7f46bSManish Rangankar if (!qedi->bdq_pbl_list) { 1476ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1477ace7f46bSManish Rangankar "Could not allocate list of PBL pages.\n"); 1478ace7f46bSManish Rangankar return -ENOMEM; 1479ace7f46bSManish Rangankar } 1480ace7f46bSManish Rangankar 1481ace7f46bSManish Rangankar /* 1482ace7f46bSManish Rangankar * Now populate PBL list with pages that contain pointers to the 1483ace7f46bSManish Rangankar * individual buffers. 1484ace7f46bSManish Rangankar */ 1485ace7f46bSManish Rangankar qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / PAGE_SIZE; 1486ace7f46bSManish Rangankar list = (u64 *)qedi->bdq_pbl_list; 1487ace7f46bSManish Rangankar page = qedi->bdq_pbl_list_dma; 1488ace7f46bSManish Rangankar for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) { 1489ace7f46bSManish Rangankar *list = qedi->bdq_pbl_dma; 1490ace7f46bSManish Rangankar list++; 1491ace7f46bSManish Rangankar page += PAGE_SIZE; 1492ace7f46bSManish Rangankar } 1493ace7f46bSManish Rangankar 1494ace7f46bSManish Rangankar return 0; 1495ace7f46bSManish Rangankar } 1496ace7f46bSManish Rangankar 1497ace7f46bSManish Rangankar static int qedi_alloc_global_queues(struct qedi_ctx *qedi) 1498ace7f46bSManish Rangankar { 1499ace7f46bSManish Rangankar u32 *list; 1500ace7f46bSManish Rangankar int i; 1501ace7f46bSManish Rangankar int status = 0, rc; 1502ace7f46bSManish Rangankar u32 *pbl; 1503ace7f46bSManish Rangankar dma_addr_t page; 1504ace7f46bSManish Rangankar int num_pages; 1505ace7f46bSManish Rangankar 1506ace7f46bSManish Rangankar /* 1507ace7f46bSManish Rangankar * Number of global queues (CQ / RQ). This should 1508ace7f46bSManish Rangankar * be <= number of available MSIX vectors for the PF 1509ace7f46bSManish Rangankar */ 1510ace7f46bSManish Rangankar if (!qedi->num_queues) { 1511ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "No MSI-X vectors available!\n"); 1512ace7f46bSManish Rangankar return 1; 1513ace7f46bSManish Rangankar } 1514ace7f46bSManish Rangankar 1515ace7f46bSManish Rangankar /* Make sure we allocated the PBL that will contain the physical 1516ace7f46bSManish Rangankar * addresses of our queues 1517ace7f46bSManish Rangankar */ 1518ace7f46bSManish Rangankar if (!qedi->p_cpuq) { 1519ace7f46bSManish Rangankar status = 1; 1520ace7f46bSManish Rangankar goto mem_alloc_failure; 1521ace7f46bSManish Rangankar } 1522ace7f46bSManish Rangankar 1523ace7f46bSManish Rangankar qedi->global_queues = kzalloc((sizeof(struct global_queue *) * 1524ace7f46bSManish Rangankar qedi->num_queues), GFP_KERNEL); 1525ace7f46bSManish Rangankar if (!qedi->global_queues) { 1526ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1527ace7f46bSManish Rangankar "Unable to allocate global queues array ptr memory\n"); 1528ace7f46bSManish Rangankar return -ENOMEM; 1529ace7f46bSManish Rangankar } 1530ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 1531ace7f46bSManish Rangankar "qedi->global_queues=%p.\n", qedi->global_queues); 1532ace7f46bSManish Rangankar 1533ace7f46bSManish Rangankar /* Allocate DMA coherent buffers for BDQ */ 1534ace7f46bSManish Rangankar rc = qedi_alloc_bdq(qedi); 1535ace7f46bSManish Rangankar if (rc) 1536ace7f46bSManish Rangankar goto mem_alloc_failure; 1537ace7f46bSManish Rangankar 1538c57ec8fbSNilesh Javali /* Allocate DMA coherent buffers for NVM_ISCSI_CFG */ 1539c57ec8fbSNilesh Javali rc = qedi_alloc_nvm_iscsi_cfg(qedi); 1540c57ec8fbSNilesh Javali if (rc) 1541c57ec8fbSNilesh Javali goto mem_alloc_failure; 1542c57ec8fbSNilesh Javali 1543ace7f46bSManish Rangankar /* Allocate a CQ and an associated PBL for each MSI-X 1544ace7f46bSManish Rangankar * vector. 1545ace7f46bSManish Rangankar */ 1546ace7f46bSManish Rangankar for (i = 0; i < qedi->num_queues; i++) { 1547ace7f46bSManish Rangankar qedi->global_queues[i] = 1548ace7f46bSManish Rangankar kzalloc(sizeof(*qedi->global_queues[0]), 1549ace7f46bSManish Rangankar GFP_KERNEL); 1550ace7f46bSManish Rangankar if (!qedi->global_queues[i]) { 1551ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1552ace7f46bSManish Rangankar "Unable to allocation global queue %d.\n", i); 1553ace7f46bSManish Rangankar goto mem_alloc_failure; 1554ace7f46bSManish Rangankar } 1555ace7f46bSManish Rangankar 1556ace7f46bSManish Rangankar qedi->global_queues[i]->cq_mem_size = 1557ace7f46bSManish Rangankar (QEDI_CQ_SIZE + 8) * sizeof(union iscsi_cqe); 1558ace7f46bSManish Rangankar qedi->global_queues[i]->cq_mem_size = 1559ace7f46bSManish Rangankar (qedi->global_queues[i]->cq_mem_size + 1560ace7f46bSManish Rangankar (QEDI_PAGE_SIZE - 1)); 1561ace7f46bSManish Rangankar 1562ace7f46bSManish Rangankar qedi->global_queues[i]->cq_pbl_size = 1563ace7f46bSManish Rangankar (qedi->global_queues[i]->cq_mem_size / 1564ace7f46bSManish Rangankar QEDI_PAGE_SIZE) * sizeof(void *); 1565ace7f46bSManish Rangankar qedi->global_queues[i]->cq_pbl_size = 1566ace7f46bSManish Rangankar (qedi->global_queues[i]->cq_pbl_size + 1567ace7f46bSManish Rangankar (QEDI_PAGE_SIZE - 1)); 1568ace7f46bSManish Rangankar 1569e9f31779SHimanshu Jha qedi->global_queues[i]->cq = dma_zalloc_coherent(&qedi->pdev->dev, 1570ace7f46bSManish Rangankar qedi->global_queues[i]->cq_mem_size, 1571ace7f46bSManish Rangankar &qedi->global_queues[i]->cq_dma, 1572ace7f46bSManish Rangankar GFP_KERNEL); 1573ace7f46bSManish Rangankar 1574ace7f46bSManish Rangankar if (!qedi->global_queues[i]->cq) { 1575ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1576ace7f46bSManish Rangankar "Could not allocate cq.\n"); 1577ace7f46bSManish Rangankar status = -ENOMEM; 1578ace7f46bSManish Rangankar goto mem_alloc_failure; 1579ace7f46bSManish Rangankar } 1580e9f31779SHimanshu Jha qedi->global_queues[i]->cq_pbl = dma_zalloc_coherent(&qedi->pdev->dev, 1581ace7f46bSManish Rangankar qedi->global_queues[i]->cq_pbl_size, 1582ace7f46bSManish Rangankar &qedi->global_queues[i]->cq_pbl_dma, 1583ace7f46bSManish Rangankar GFP_KERNEL); 1584ace7f46bSManish Rangankar 1585ace7f46bSManish Rangankar if (!qedi->global_queues[i]->cq_pbl) { 1586ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1587ace7f46bSManish Rangankar "Could not allocate cq PBL.\n"); 1588ace7f46bSManish Rangankar status = -ENOMEM; 1589ace7f46bSManish Rangankar goto mem_alloc_failure; 1590ace7f46bSManish Rangankar } 1591ace7f46bSManish Rangankar 1592ace7f46bSManish Rangankar /* Create PBL */ 1593ace7f46bSManish Rangankar num_pages = qedi->global_queues[i]->cq_mem_size / 1594ace7f46bSManish Rangankar QEDI_PAGE_SIZE; 1595ace7f46bSManish Rangankar page = qedi->global_queues[i]->cq_dma; 1596ace7f46bSManish Rangankar pbl = (u32 *)qedi->global_queues[i]->cq_pbl; 1597ace7f46bSManish Rangankar 1598ace7f46bSManish Rangankar while (num_pages--) { 1599ace7f46bSManish Rangankar *pbl = (u32)page; 1600ace7f46bSManish Rangankar pbl++; 1601ace7f46bSManish Rangankar *pbl = (u32)((u64)page >> 32); 1602ace7f46bSManish Rangankar pbl++; 1603ace7f46bSManish Rangankar page += QEDI_PAGE_SIZE; 1604ace7f46bSManish Rangankar } 1605ace7f46bSManish Rangankar } 1606ace7f46bSManish Rangankar 1607ace7f46bSManish Rangankar list = (u32 *)qedi->p_cpuq; 1608ace7f46bSManish Rangankar 1609ace7f46bSManish Rangankar /* 1610ace7f46bSManish Rangankar * The list is built as follows: CQ#0 PBL pointer, RQ#0 PBL pointer, 1611ace7f46bSManish Rangankar * CQ#1 PBL pointer, RQ#1 PBL pointer, etc. Each PBL pointer points 1612ace7f46bSManish Rangankar * to the physical address which contains an array of pointers to the 1613ace7f46bSManish Rangankar * physical addresses of the specific queue pages. 1614ace7f46bSManish Rangankar */ 1615ace7f46bSManish Rangankar for (i = 0; i < qedi->num_queues; i++) { 1616ace7f46bSManish Rangankar *list = (u32)qedi->global_queues[i]->cq_pbl_dma; 1617ace7f46bSManish Rangankar list++; 1618ace7f46bSManish Rangankar *list = (u32)((u64)qedi->global_queues[i]->cq_pbl_dma >> 32); 1619ace7f46bSManish Rangankar list++; 1620ace7f46bSManish Rangankar 1621ace7f46bSManish Rangankar *list = (u32)0; 1622ace7f46bSManish Rangankar list++; 1623ace7f46bSManish Rangankar *list = (u32)((u64)0 >> 32); 1624ace7f46bSManish Rangankar list++; 1625ace7f46bSManish Rangankar } 1626ace7f46bSManish Rangankar 1627ace7f46bSManish Rangankar return 0; 1628ace7f46bSManish Rangankar 1629ace7f46bSManish Rangankar mem_alloc_failure: 1630ace7f46bSManish Rangankar qedi_free_global_queues(qedi); 1631ace7f46bSManish Rangankar return status; 1632ace7f46bSManish Rangankar } 1633ace7f46bSManish Rangankar 1634ace7f46bSManish Rangankar int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) 1635ace7f46bSManish Rangankar { 1636ace7f46bSManish Rangankar int rval = 0; 1637ace7f46bSManish Rangankar u32 *pbl; 1638ace7f46bSManish Rangankar dma_addr_t page; 1639ace7f46bSManish Rangankar int num_pages; 1640ace7f46bSManish Rangankar 1641ace7f46bSManish Rangankar if (!ep) 1642ace7f46bSManish Rangankar return -EIO; 1643ace7f46bSManish Rangankar 1644ace7f46bSManish Rangankar /* Calculate appropriate queue and PBL sizes */ 1645ace7f46bSManish Rangankar ep->sq_mem_size = QEDI_SQ_SIZE * sizeof(struct iscsi_wqe); 1646ace7f46bSManish Rangankar ep->sq_mem_size += QEDI_PAGE_SIZE - 1; 1647ace7f46bSManish Rangankar 1648ace7f46bSManish Rangankar ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *); 1649ace7f46bSManish Rangankar ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE; 1650ace7f46bSManish Rangankar 1651e9f31779SHimanshu Jha ep->sq = dma_zalloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, 1652ace7f46bSManish Rangankar &ep->sq_dma, GFP_KERNEL); 1653ace7f46bSManish Rangankar if (!ep->sq) { 1654ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1655ace7f46bSManish Rangankar "Could not allocate send queue.\n"); 1656ace7f46bSManish Rangankar rval = -ENOMEM; 1657ace7f46bSManish Rangankar goto out; 1658ace7f46bSManish Rangankar } 1659e9f31779SHimanshu Jha ep->sq_pbl = dma_zalloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, 1660ace7f46bSManish Rangankar &ep->sq_pbl_dma, GFP_KERNEL); 1661ace7f46bSManish Rangankar if (!ep->sq_pbl) { 1662ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, 1663ace7f46bSManish Rangankar "Could not allocate send queue PBL.\n"); 1664ace7f46bSManish Rangankar rval = -ENOMEM; 1665ace7f46bSManish Rangankar goto out_free_sq; 1666ace7f46bSManish Rangankar } 1667ace7f46bSManish Rangankar 1668ace7f46bSManish Rangankar /* Create PBL */ 1669ace7f46bSManish Rangankar num_pages = ep->sq_mem_size / QEDI_PAGE_SIZE; 1670ace7f46bSManish Rangankar page = ep->sq_dma; 1671ace7f46bSManish Rangankar pbl = (u32 *)ep->sq_pbl; 1672ace7f46bSManish Rangankar 1673ace7f46bSManish Rangankar while (num_pages--) { 1674ace7f46bSManish Rangankar *pbl = (u32)page; 1675ace7f46bSManish Rangankar pbl++; 1676ace7f46bSManish Rangankar *pbl = (u32)((u64)page >> 32); 1677ace7f46bSManish Rangankar pbl++; 1678ace7f46bSManish Rangankar page += QEDI_PAGE_SIZE; 1679ace7f46bSManish Rangankar } 1680ace7f46bSManish Rangankar 1681ace7f46bSManish Rangankar return rval; 1682ace7f46bSManish Rangankar 1683ace7f46bSManish Rangankar out_free_sq: 1684ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, 1685ace7f46bSManish Rangankar ep->sq_dma); 1686ace7f46bSManish Rangankar out: 1687ace7f46bSManish Rangankar return rval; 1688ace7f46bSManish Rangankar } 1689ace7f46bSManish Rangankar 1690ace7f46bSManish Rangankar void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) 1691ace7f46bSManish Rangankar { 1692ace7f46bSManish Rangankar if (ep->sq_pbl) 1693ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, ep->sq_pbl_size, ep->sq_pbl, 1694ace7f46bSManish Rangankar ep->sq_pbl_dma); 1695ace7f46bSManish Rangankar if (ep->sq) 1696ace7f46bSManish Rangankar dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, 1697ace7f46bSManish Rangankar ep->sq_dma); 1698ace7f46bSManish Rangankar } 1699ace7f46bSManish Rangankar 1700ace7f46bSManish Rangankar int qedi_get_task_idx(struct qedi_ctx *qedi) 1701ace7f46bSManish Rangankar { 1702ace7f46bSManish Rangankar s16 tmp_idx; 1703ace7f46bSManish Rangankar 1704ace7f46bSManish Rangankar again: 1705ace7f46bSManish Rangankar tmp_idx = find_first_zero_bit(qedi->task_idx_map, 1706ace7f46bSManish Rangankar MAX_ISCSI_TASK_ENTRIES); 1707ace7f46bSManish Rangankar 1708ace7f46bSManish Rangankar if (tmp_idx >= MAX_ISCSI_TASK_ENTRIES) { 1709ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "FW task context pool is full.\n"); 1710ace7f46bSManish Rangankar tmp_idx = -1; 1711ace7f46bSManish Rangankar goto err_idx; 1712ace7f46bSManish Rangankar } 1713ace7f46bSManish Rangankar 1714ace7f46bSManish Rangankar if (test_and_set_bit(tmp_idx, qedi->task_idx_map)) 1715ace7f46bSManish Rangankar goto again; 1716ace7f46bSManish Rangankar 1717ace7f46bSManish Rangankar err_idx: 1718ace7f46bSManish Rangankar return tmp_idx; 1719ace7f46bSManish Rangankar } 1720ace7f46bSManish Rangankar 1721ace7f46bSManish Rangankar void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx) 1722ace7f46bSManish Rangankar { 172302d94e04SManish Rangankar if (!test_and_clear_bit(idx, qedi->task_idx_map)) 1724ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1725ace7f46bSManish Rangankar "FW task context, already cleared, tid=0x%x\n", idx); 1726ace7f46bSManish Rangankar } 1727ace7f46bSManish Rangankar 1728ace7f46bSManish Rangankar void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, 1729ace7f46bSManish Rangankar struct qedi_cmd *cmd) 1730ace7f46bSManish Rangankar { 1731ace7f46bSManish Rangankar qedi->itt_map[tid].itt = proto_itt; 1732ace7f46bSManish Rangankar qedi->itt_map[tid].p_cmd = cmd; 1733ace7f46bSManish Rangankar 1734ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1735ace7f46bSManish Rangankar "update itt map tid=0x%x, with proto itt=0x%x\n", tid, 1736ace7f46bSManish Rangankar qedi->itt_map[tid].itt); 1737ace7f46bSManish Rangankar } 1738ace7f46bSManish Rangankar 1739ace7f46bSManish Rangankar void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid) 1740ace7f46bSManish Rangankar { 1741ace7f46bSManish Rangankar u16 i; 1742ace7f46bSManish Rangankar 1743ace7f46bSManish Rangankar for (i = 0; i < MAX_ISCSI_TASK_ENTRIES; i++) { 1744ace7f46bSManish Rangankar if (qedi->itt_map[i].itt == itt) { 1745ace7f46bSManish Rangankar *tid = i; 1746ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1747ace7f46bSManish Rangankar "Ref itt=0x%x, found at tid=0x%x\n", 1748ace7f46bSManish Rangankar itt, *tid); 1749ace7f46bSManish Rangankar return; 1750ace7f46bSManish Rangankar } 1751ace7f46bSManish Rangankar } 1752ace7f46bSManish Rangankar 1753ace7f46bSManish Rangankar WARN_ON(1); 1754ace7f46bSManish Rangankar } 1755ace7f46bSManish Rangankar 1756ace7f46bSManish Rangankar void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt) 1757ace7f46bSManish Rangankar { 1758ace7f46bSManish Rangankar *proto_itt = qedi->itt_map[tid].itt; 1759ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, 1760ace7f46bSManish Rangankar "Get itt map tid [0x%x with proto itt[0x%x]", 1761ace7f46bSManish Rangankar tid, *proto_itt); 1762ace7f46bSManish Rangankar } 1763ace7f46bSManish Rangankar 1764ace7f46bSManish Rangankar struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) 1765ace7f46bSManish Rangankar { 1766ace7f46bSManish Rangankar struct qedi_cmd *cmd = NULL; 1767ace7f46bSManish Rangankar 1768fa2d9d6eSDan Carpenter if (tid >= MAX_ISCSI_TASK_ENTRIES) 1769ace7f46bSManish Rangankar return NULL; 1770ace7f46bSManish Rangankar 1771ace7f46bSManish Rangankar cmd = qedi->itt_map[tid].p_cmd; 1772ace7f46bSManish Rangankar if (cmd->task_id != tid) 1773ace7f46bSManish Rangankar return NULL; 1774ace7f46bSManish Rangankar 1775ace7f46bSManish Rangankar qedi->itt_map[tid].p_cmd = NULL; 1776ace7f46bSManish Rangankar 1777ace7f46bSManish Rangankar return cmd; 1778ace7f46bSManish Rangankar } 1779ace7f46bSManish Rangankar 1780ace7f46bSManish Rangankar static int qedi_alloc_itt(struct qedi_ctx *qedi) 1781ace7f46bSManish Rangankar { 1782ace7f46bSManish Rangankar qedi->itt_map = kcalloc(MAX_ISCSI_TASK_ENTRIES, 1783ace7f46bSManish Rangankar sizeof(struct qedi_itt_map), GFP_KERNEL); 1784ace7f46bSManish Rangankar if (!qedi->itt_map) { 1785ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 1786ace7f46bSManish Rangankar "Unable to allocate itt map array memory\n"); 1787ace7f46bSManish Rangankar return -ENOMEM; 1788ace7f46bSManish Rangankar } 1789ace7f46bSManish Rangankar return 0; 1790ace7f46bSManish Rangankar } 1791ace7f46bSManish Rangankar 1792ace7f46bSManish Rangankar static void qedi_free_itt(struct qedi_ctx *qedi) 1793ace7f46bSManish Rangankar { 1794ace7f46bSManish Rangankar kfree(qedi->itt_map); 1795ace7f46bSManish Rangankar } 1796ace7f46bSManish Rangankar 1797ace7f46bSManish Rangankar static struct qed_ll2_cb_ops qedi_ll2_cb_ops = { 1798ace7f46bSManish Rangankar .rx_cb = qedi_ll2_rx, 1799ace7f46bSManish Rangankar .tx_cb = NULL, 1800ace7f46bSManish Rangankar }; 1801ace7f46bSManish Rangankar 1802ace7f46bSManish Rangankar static int qedi_percpu_io_thread(void *arg) 1803ace7f46bSManish Rangankar { 1804ace7f46bSManish Rangankar struct qedi_percpu_s *p = arg; 1805ace7f46bSManish Rangankar struct qedi_work *work, *tmp; 1806ace7f46bSManish Rangankar unsigned long flags; 1807ace7f46bSManish Rangankar LIST_HEAD(work_list); 1808ace7f46bSManish Rangankar 1809ace7f46bSManish Rangankar set_user_nice(current, -20); 1810ace7f46bSManish Rangankar 1811ace7f46bSManish Rangankar while (!kthread_should_stop()) { 1812ace7f46bSManish Rangankar spin_lock_irqsave(&p->p_work_lock, flags); 1813ace7f46bSManish Rangankar while (!list_empty(&p->work_list)) { 1814ace7f46bSManish Rangankar list_splice_init(&p->work_list, &work_list); 1815ace7f46bSManish Rangankar spin_unlock_irqrestore(&p->p_work_lock, flags); 1816ace7f46bSManish Rangankar 1817ace7f46bSManish Rangankar list_for_each_entry_safe(work, tmp, &work_list, list) { 1818ace7f46bSManish Rangankar list_del_init(&work->list); 1819ace7f46bSManish Rangankar qedi_fp_process_cqes(work); 1820ace7f46bSManish Rangankar if (!work->is_solicited) 1821ace7f46bSManish Rangankar kfree(work); 1822ace7f46bSManish Rangankar } 1823ace7f46bSManish Rangankar cond_resched(); 1824ace7f46bSManish Rangankar spin_lock_irqsave(&p->p_work_lock, flags); 1825ace7f46bSManish Rangankar } 1826ace7f46bSManish Rangankar set_current_state(TASK_INTERRUPTIBLE); 1827ace7f46bSManish Rangankar spin_unlock_irqrestore(&p->p_work_lock, flags); 1828ace7f46bSManish Rangankar schedule(); 1829ace7f46bSManish Rangankar } 1830ace7f46bSManish Rangankar __set_current_state(TASK_RUNNING); 1831ace7f46bSManish Rangankar 1832ace7f46bSManish Rangankar return 0; 1833ace7f46bSManish Rangankar } 1834ace7f46bSManish Rangankar 1835a98d1a0cSThomas Gleixner static int qedi_cpu_online(unsigned int cpu) 1836ace7f46bSManish Rangankar { 1837a98d1a0cSThomas Gleixner struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); 1838ace7f46bSManish Rangankar struct task_struct *thread; 1839ace7f46bSManish Rangankar 1840ace7f46bSManish Rangankar thread = kthread_create_on_node(qedi_percpu_io_thread, (void *)p, 1841ace7f46bSManish Rangankar cpu_to_node(cpu), 1842ace7f46bSManish Rangankar "qedi_thread/%d", cpu); 1843a98d1a0cSThomas Gleixner if (IS_ERR(thread)) 1844a98d1a0cSThomas Gleixner return PTR_ERR(thread); 1845a98d1a0cSThomas Gleixner 1846ace7f46bSManish Rangankar kthread_bind(thread, cpu); 1847ace7f46bSManish Rangankar p->iothread = thread; 1848ace7f46bSManish Rangankar wake_up_process(thread); 1849a98d1a0cSThomas Gleixner return 0; 1850ace7f46bSManish Rangankar } 1851ace7f46bSManish Rangankar 1852a98d1a0cSThomas Gleixner static int qedi_cpu_offline(unsigned int cpu) 1853ace7f46bSManish Rangankar { 1854a98d1a0cSThomas Gleixner struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu); 1855ace7f46bSManish Rangankar struct qedi_work *work, *tmp; 1856a98d1a0cSThomas Gleixner struct task_struct *thread; 1857ace7f46bSManish Rangankar 1858ace7f46bSManish Rangankar spin_lock_bh(&p->p_work_lock); 1859ace7f46bSManish Rangankar thread = p->iothread; 1860ace7f46bSManish Rangankar p->iothread = NULL; 1861ace7f46bSManish Rangankar 1862ace7f46bSManish Rangankar list_for_each_entry_safe(work, tmp, &p->work_list, list) { 1863ace7f46bSManish Rangankar list_del_init(&work->list); 1864ace7f46bSManish Rangankar qedi_fp_process_cqes(work); 1865ace7f46bSManish Rangankar if (!work->is_solicited) 1866ace7f46bSManish Rangankar kfree(work); 1867ace7f46bSManish Rangankar } 1868ace7f46bSManish Rangankar 1869ace7f46bSManish Rangankar spin_unlock_bh(&p->p_work_lock); 1870ace7f46bSManish Rangankar if (thread) 1871ace7f46bSManish Rangankar kthread_stop(thread); 1872a98d1a0cSThomas Gleixner return 0; 1873ace7f46bSManish Rangankar } 1874ace7f46bSManish Rangankar 1875ace7f46bSManish Rangankar void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu) 1876ace7f46bSManish Rangankar { 1877ace7f46bSManish Rangankar struct qed_ll2_params params; 1878ace7f46bSManish Rangankar 1879ace7f46bSManish Rangankar qedi_recover_all_conns(qedi); 1880ace7f46bSManish Rangankar 1881ace7f46bSManish Rangankar qedi_ops->ll2->stop(qedi->cdev); 1882ace7f46bSManish Rangankar qedi_ll2_free_skbs(qedi); 1883ace7f46bSManish Rangankar 1884ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "old MTU %u, new MTU %u\n", 1885ace7f46bSManish Rangankar qedi->ll2_mtu, mtu); 1886ace7f46bSManish Rangankar memset(¶ms, 0, sizeof(params)); 1887ace7f46bSManish Rangankar qedi->ll2_mtu = mtu; 1888ace7f46bSManish Rangankar params.mtu = qedi->ll2_mtu + IPV6_HDR_LEN + TCP_HDR_LEN; 1889ace7f46bSManish Rangankar params.drop_ttl0_packets = 0; 1890ace7f46bSManish Rangankar params.rx_vlan_stripping = 1; 1891ace7f46bSManish Rangankar ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); 1892ace7f46bSManish Rangankar qedi_ops->ll2->start(qedi->cdev, ¶ms); 1893ace7f46bSManish Rangankar } 1894ace7f46bSManish Rangankar 1895c57ec8fbSNilesh Javali /** 1896c57ec8fbSNilesh Javali * qedi_get_nvram_block: - Scan through the iSCSI NVRAM block (while accounting 1897c57ec8fbSNilesh Javali * for gaps) for the matching absolute-pf-id of the QEDI device. 1898c57ec8fbSNilesh Javali */ 1899c57ec8fbSNilesh Javali static struct nvm_iscsi_block * 1900c57ec8fbSNilesh Javali qedi_get_nvram_block(struct qedi_ctx *qedi) 1901c57ec8fbSNilesh Javali { 1902c57ec8fbSNilesh Javali int i; 1903c57ec8fbSNilesh Javali u8 pf; 1904c57ec8fbSNilesh Javali u32 flags; 1905c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 1906c57ec8fbSNilesh Javali 1907c57ec8fbSNilesh Javali pf = qedi->dev_info.common.abs_pf_id; 1908c57ec8fbSNilesh Javali block = &qedi->iscsi_cfg->block[0]; 1909c57ec8fbSNilesh Javali for (i = 0; i < NUM_OF_ISCSI_PF_SUPPORTED; i++, block++) { 1910c57ec8fbSNilesh Javali flags = ((block->id) & NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK) >> 1911c57ec8fbSNilesh Javali NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET; 1912c57ec8fbSNilesh Javali if (flags & (NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY | 1913c57ec8fbSNilesh Javali NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED) && 1914c57ec8fbSNilesh Javali (pf == (block->id & NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK) 1915c57ec8fbSNilesh Javali >> NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET)) 1916c57ec8fbSNilesh Javali return block; 1917c57ec8fbSNilesh Javali } 1918c57ec8fbSNilesh Javali return NULL; 1919c57ec8fbSNilesh Javali } 1920c57ec8fbSNilesh Javali 1921c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) 1922c57ec8fbSNilesh Javali { 1923c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 1924c57ec8fbSNilesh Javali struct nvm_iscsi_initiator *initiator; 1925c57ec8fbSNilesh Javali int rc = 1; 1926c57ec8fbSNilesh Javali u32 ipv6_en, dhcp_en, ip_len; 1927c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 1928c57ec8fbSNilesh Javali char *fmt, *ip, *sub, *gw; 1929c57ec8fbSNilesh Javali 1930c57ec8fbSNilesh Javali block = qedi_get_nvram_block(qedi); 1931c57ec8fbSNilesh Javali if (!block) 1932c57ec8fbSNilesh Javali return 0; 1933c57ec8fbSNilesh Javali 1934c57ec8fbSNilesh Javali initiator = &block->initiator; 1935c57ec8fbSNilesh Javali ipv6_en = block->generic.ctrl_flags & 1936c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_IPV6_ENABLED; 1937c57ec8fbSNilesh Javali dhcp_en = block->generic.ctrl_flags & 1938c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED; 1939c57ec8fbSNilesh Javali /* Static IP assignments. */ 1940c57ec8fbSNilesh Javali fmt = ipv6_en ? "%pI6\n" : "%pI4\n"; 1941c57ec8fbSNilesh Javali ip = ipv6_en ? initiator->ipv6.addr.byte : initiator->ipv4.addr.byte; 1942c57ec8fbSNilesh Javali ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN; 1943c57ec8fbSNilesh Javali sub = ipv6_en ? initiator->ipv6.subnet_mask.byte : 1944c57ec8fbSNilesh Javali initiator->ipv4.subnet_mask.byte; 1945c57ec8fbSNilesh Javali gw = ipv6_en ? initiator->ipv6.gateway.byte : 1946c57ec8fbSNilesh Javali initiator->ipv4.gateway.byte; 1947c57ec8fbSNilesh Javali /* DHCP IP adjustments. */ 1948c57ec8fbSNilesh Javali fmt = dhcp_en ? "%s\n" : fmt; 1949c57ec8fbSNilesh Javali if (dhcp_en) { 1950c57ec8fbSNilesh Javali ip = ipv6_en ? "0::0" : "0.0.0.0"; 1951c57ec8fbSNilesh Javali sub = ip; 1952c57ec8fbSNilesh Javali gw = ip; 1953c57ec8fbSNilesh Javali ip_len = ipv6_en ? 5 : 8; 1954c57ec8fbSNilesh Javali } 1955c57ec8fbSNilesh Javali 1956c57ec8fbSNilesh Javali switch (type) { 1957c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_IP_ADDR: 19582c08fe64SNilesh Javali rc = snprintf(buf, ip_len, fmt, ip); 1959c57ec8fbSNilesh Javali break; 1960c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_SUBNET_MASK: 19612c08fe64SNilesh Javali rc = snprintf(buf, ip_len, fmt, sub); 1962c57ec8fbSNilesh Javali break; 1963c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_GATEWAY: 19642c08fe64SNilesh Javali rc = snprintf(buf, ip_len, fmt, gw); 1965c57ec8fbSNilesh Javali break; 1966c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_FLAGS: 19672c08fe64SNilesh Javali rc = snprintf(buf, 3, "%hhd\n", 1968c57ec8fbSNilesh Javali SYSFS_FLAG_FW_SEL_BOOT); 1969c57ec8fbSNilesh Javali break; 1970c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_INDEX: 19712c08fe64SNilesh Javali rc = snprintf(buf, 3, "0\n"); 1972c57ec8fbSNilesh Javali break; 1973c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_MAC: 19742c08fe64SNilesh Javali rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN); 1975c57ec8fbSNilesh Javali break; 1976c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_VLAN: 19772c08fe64SNilesh Javali rc = snprintf(buf, 12, "%d\n", 1978c57ec8fbSNilesh Javali GET_FIELD2(initiator->generic_cont0, 1979c57ec8fbSNilesh Javali NVM_ISCSI_CFG_INITIATOR_VLAN)); 1980c57ec8fbSNilesh Javali break; 1981c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_ORIGIN: 1982c57ec8fbSNilesh Javali if (dhcp_en) 19832c08fe64SNilesh Javali rc = snprintf(buf, 3, "3\n"); 1984c57ec8fbSNilesh Javali break; 1985c57ec8fbSNilesh Javali default: 1986c57ec8fbSNilesh Javali rc = 0; 1987c57ec8fbSNilesh Javali break; 1988c57ec8fbSNilesh Javali } 1989c57ec8fbSNilesh Javali 1990c57ec8fbSNilesh Javali return rc; 1991c57ec8fbSNilesh Javali } 1992c57ec8fbSNilesh Javali 1993c57ec8fbSNilesh Javali static umode_t qedi_eth_get_attr_visibility(void *data, int type) 1994c57ec8fbSNilesh Javali { 1995c57ec8fbSNilesh Javali int rc = 1; 1996c57ec8fbSNilesh Javali 1997c57ec8fbSNilesh Javali switch (type) { 1998c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_FLAGS: 1999c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_MAC: 2000c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_INDEX: 2001c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_IP_ADDR: 2002c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_SUBNET_MASK: 2003c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_GATEWAY: 2004c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_ORIGIN: 2005c57ec8fbSNilesh Javali case ISCSI_BOOT_ETH_VLAN: 2006c57ec8fbSNilesh Javali rc = 0444; 2007c57ec8fbSNilesh Javali break; 2008c57ec8fbSNilesh Javali default: 2009c57ec8fbSNilesh Javali rc = 0; 2010c57ec8fbSNilesh Javali break; 2011c57ec8fbSNilesh Javali } 2012c57ec8fbSNilesh Javali return rc; 2013c57ec8fbSNilesh Javali } 2014c57ec8fbSNilesh Javali 2015c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf) 2016c57ec8fbSNilesh Javali { 2017c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2018c57ec8fbSNilesh Javali struct nvm_iscsi_initiator *initiator; 2019c57ec8fbSNilesh Javali int rc; 2020c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 2021c57ec8fbSNilesh Javali 2022c57ec8fbSNilesh Javali block = qedi_get_nvram_block(qedi); 2023c57ec8fbSNilesh Javali if (!block) 2024c57ec8fbSNilesh Javali return 0; 2025c57ec8fbSNilesh Javali 2026c57ec8fbSNilesh Javali initiator = &block->initiator; 2027c57ec8fbSNilesh Javali 2028c57ec8fbSNilesh Javali switch (type) { 2029c57ec8fbSNilesh Javali case ISCSI_BOOT_INI_INITIATOR_NAME: 20302c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, 2031c57ec8fbSNilesh Javali initiator->initiator_name.byte); 2032c57ec8fbSNilesh Javali break; 2033c57ec8fbSNilesh Javali default: 2034c57ec8fbSNilesh Javali rc = 0; 2035c57ec8fbSNilesh Javali break; 2036c57ec8fbSNilesh Javali } 2037c57ec8fbSNilesh Javali return rc; 2038c57ec8fbSNilesh Javali } 2039c57ec8fbSNilesh Javali 2040c57ec8fbSNilesh Javali static umode_t qedi_ini_get_attr_visibility(void *data, int type) 2041c57ec8fbSNilesh Javali { 2042c57ec8fbSNilesh Javali int rc; 2043c57ec8fbSNilesh Javali 2044c57ec8fbSNilesh Javali switch (type) { 2045c57ec8fbSNilesh Javali case ISCSI_BOOT_INI_INITIATOR_NAME: 2046c57ec8fbSNilesh Javali rc = 0444; 2047c57ec8fbSNilesh Javali break; 2048c57ec8fbSNilesh Javali default: 2049c57ec8fbSNilesh Javali rc = 0; 2050c57ec8fbSNilesh Javali break; 2051c57ec8fbSNilesh Javali } 2052c57ec8fbSNilesh Javali return rc; 2053c57ec8fbSNilesh Javali } 2054c57ec8fbSNilesh Javali 2055c57ec8fbSNilesh Javali static ssize_t 2056c57ec8fbSNilesh Javali qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, 2057c57ec8fbSNilesh Javali char *buf, enum qedi_nvm_tgts idx) 2058c57ec8fbSNilesh Javali { 2059c57ec8fbSNilesh Javali int rc = 1; 2060c57ec8fbSNilesh Javali u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len; 2061c57ec8fbSNilesh Javali struct nvm_iscsi_block *block; 2062c57ec8fbSNilesh Javali char *chap_name, *chap_secret; 2063c57ec8fbSNilesh Javali char *mchap_name, *mchap_secret; 2064c57ec8fbSNilesh Javali 2065c57ec8fbSNilesh Javali block = qedi_get_nvram_block(qedi); 2066c57ec8fbSNilesh Javali if (!block) 2067c57ec8fbSNilesh Javali goto exit_show_tgt_info; 2068c57ec8fbSNilesh Javali 2069c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT, 2070c57ec8fbSNilesh Javali "Port:%d, tgt_idx:%d\n", 2071c57ec8fbSNilesh Javali GET_FIELD2(block->id, NVM_ISCSI_CFG_BLK_MAPPED_PF_ID), idx); 2072c57ec8fbSNilesh Javali 2073c57ec8fbSNilesh Javali ctrl_flags = block->target[idx].ctrl_flags & 2074c57ec8fbSNilesh Javali NVM_ISCSI_CFG_TARGET_ENABLED; 2075c57ec8fbSNilesh Javali 2076c57ec8fbSNilesh Javali if (!ctrl_flags) { 2077c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT, 2078c57ec8fbSNilesh Javali "Target disabled\n"); 2079c57ec8fbSNilesh Javali goto exit_show_tgt_info; 2080c57ec8fbSNilesh Javali } 2081c57ec8fbSNilesh Javali 2082c57ec8fbSNilesh Javali ipv6_en = block->generic.ctrl_flags & 2083c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_IPV6_ENABLED; 2084c57ec8fbSNilesh Javali ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN; 2085c57ec8fbSNilesh Javali chap_en = block->generic.ctrl_flags & 2086c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_CHAP_ENABLED; 2087c57ec8fbSNilesh Javali chap_name = chap_en ? block->initiator.chap_name.byte : NULL; 2088c57ec8fbSNilesh Javali chap_secret = chap_en ? block->initiator.chap_password.byte : NULL; 2089c57ec8fbSNilesh Javali 2090c57ec8fbSNilesh Javali mchap_en = block->generic.ctrl_flags & 2091c57ec8fbSNilesh Javali NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED; 2092c57ec8fbSNilesh Javali mchap_name = mchap_en ? block->target[idx].chap_name.byte : NULL; 2093c57ec8fbSNilesh Javali mchap_secret = mchap_en ? block->target[idx].chap_password.byte : NULL; 2094c57ec8fbSNilesh Javali 2095c57ec8fbSNilesh Javali switch (type) { 2096c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NAME: 20972c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, 2098c57ec8fbSNilesh Javali block->target[idx].target_name.byte); 2099c57ec8fbSNilesh Javali break; 2100c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_IP_ADDR: 2101c57ec8fbSNilesh Javali if (ipv6_en) 21022c08fe64SNilesh Javali rc = snprintf(buf, ip_len, "%pI6\n", 2103c57ec8fbSNilesh Javali block->target[idx].ipv6_addr.byte); 2104c57ec8fbSNilesh Javali else 21052c08fe64SNilesh Javali rc = snprintf(buf, ip_len, "%pI4\n", 2106c57ec8fbSNilesh Javali block->target[idx].ipv4_addr.byte); 2107c57ec8fbSNilesh Javali break; 2108c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_PORT: 21092c08fe64SNilesh Javali rc = snprintf(buf, 12, "%d\n", 2110c57ec8fbSNilesh Javali GET_FIELD2(block->target[idx].generic_cont0, 2111c57ec8fbSNilesh Javali NVM_ISCSI_CFG_TARGET_TCP_PORT)); 2112c57ec8fbSNilesh Javali break; 2113c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_LUN: 21142c08fe64SNilesh Javali rc = snprintf(buf, 22, "%.*d\n", 2115c57ec8fbSNilesh Javali block->target[idx].lun.value[1], 2116c57ec8fbSNilesh Javali block->target[idx].lun.value[0]); 2117c57ec8fbSNilesh Javali break; 2118c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_NAME: 21192c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 2120c57ec8fbSNilesh Javali chap_name); 2121c57ec8fbSNilesh Javali break; 2122c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_SECRET: 21232c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 2124c57ec8fbSNilesh Javali chap_secret); 2125c57ec8fbSNilesh Javali break; 2126c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_NAME: 21272c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 2128c57ec8fbSNilesh Javali mchap_name); 2129c57ec8fbSNilesh Javali break; 2130c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 21312c08fe64SNilesh Javali rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, 2132c57ec8fbSNilesh Javali mchap_secret); 2133c57ec8fbSNilesh Javali break; 2134c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_FLAGS: 21352c08fe64SNilesh Javali rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); 2136c57ec8fbSNilesh Javali break; 2137c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NIC_ASSOC: 21382c08fe64SNilesh Javali rc = snprintf(buf, 3, "0\n"); 2139c57ec8fbSNilesh Javali break; 2140c57ec8fbSNilesh Javali default: 2141c57ec8fbSNilesh Javali rc = 0; 2142c57ec8fbSNilesh Javali break; 2143c57ec8fbSNilesh Javali } 2144c57ec8fbSNilesh Javali 2145c57ec8fbSNilesh Javali exit_show_tgt_info: 2146c57ec8fbSNilesh Javali return rc; 2147c57ec8fbSNilesh Javali } 2148c57ec8fbSNilesh Javali 2149c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_tgt_pri_info(void *data, int type, char *buf) 2150c57ec8fbSNilesh Javali { 2151c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2152c57ec8fbSNilesh Javali 2153c57ec8fbSNilesh Javali return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_PRI); 2154c57ec8fbSNilesh Javali } 2155c57ec8fbSNilesh Javali 2156c57ec8fbSNilesh Javali static ssize_t qedi_show_boot_tgt_sec_info(void *data, int type, char *buf) 2157c57ec8fbSNilesh Javali { 2158c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2159c57ec8fbSNilesh Javali 2160c57ec8fbSNilesh Javali return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_SEC); 2161c57ec8fbSNilesh Javali } 2162c57ec8fbSNilesh Javali 2163c57ec8fbSNilesh Javali static umode_t qedi_tgt_get_attr_visibility(void *data, int type) 2164c57ec8fbSNilesh Javali { 2165c57ec8fbSNilesh Javali int rc; 2166c57ec8fbSNilesh Javali 2167c57ec8fbSNilesh Javali switch (type) { 2168c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NAME: 2169c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_IP_ADDR: 2170c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_PORT: 2171c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_LUN: 2172c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_NAME: 2173c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_CHAP_SECRET: 2174c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_NAME: 2175c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 2176c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_NIC_ASSOC: 2177c57ec8fbSNilesh Javali case ISCSI_BOOT_TGT_FLAGS: 2178c57ec8fbSNilesh Javali rc = 0444; 2179c57ec8fbSNilesh Javali break; 2180c57ec8fbSNilesh Javali default: 2181c57ec8fbSNilesh Javali rc = 0; 2182c57ec8fbSNilesh Javali break; 2183c57ec8fbSNilesh Javali } 2184c57ec8fbSNilesh Javali return rc; 2185c57ec8fbSNilesh Javali } 2186c57ec8fbSNilesh Javali 2187c57ec8fbSNilesh Javali static void qedi_boot_release(void *data) 2188c57ec8fbSNilesh Javali { 2189c57ec8fbSNilesh Javali struct qedi_ctx *qedi = data; 2190c57ec8fbSNilesh Javali 2191c57ec8fbSNilesh Javali scsi_host_put(qedi->shost); 2192c57ec8fbSNilesh Javali } 2193c57ec8fbSNilesh Javali 2194c57ec8fbSNilesh Javali static int qedi_get_boot_info(struct qedi_ctx *qedi) 2195c57ec8fbSNilesh Javali { 2196c57ec8fbSNilesh Javali int ret = 1; 2197c57ec8fbSNilesh Javali u16 len; 2198c57ec8fbSNilesh Javali 2199c57ec8fbSNilesh Javali len = sizeof(struct nvm_iscsi_cfg); 2200c57ec8fbSNilesh Javali 2201c57ec8fbSNilesh Javali QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 2202c57ec8fbSNilesh Javali "Get NVM iSCSI CFG image\n"); 2203c57ec8fbSNilesh Javali ret = qedi_ops->common->nvm_get_image(qedi->cdev, 2204c57ec8fbSNilesh Javali QED_NVM_IMAGE_ISCSI_CFG, 2205c57ec8fbSNilesh Javali (char *)qedi->iscsi_cfg, len); 2206c57ec8fbSNilesh Javali if (ret) 2207c57ec8fbSNilesh Javali QEDI_ERR(&qedi->dbg_ctx, 2208c57ec8fbSNilesh Javali "Could not get NVM image. ret = %d\n", ret); 2209c57ec8fbSNilesh Javali 2210c57ec8fbSNilesh Javali return ret; 2211c57ec8fbSNilesh Javali } 2212c57ec8fbSNilesh Javali 2213c57ec8fbSNilesh Javali static int qedi_setup_boot_info(struct qedi_ctx *qedi) 2214c57ec8fbSNilesh Javali { 2215c57ec8fbSNilesh Javali struct iscsi_boot_kobj *boot_kobj; 2216c57ec8fbSNilesh Javali 2217c57ec8fbSNilesh Javali if (qedi_get_boot_info(qedi)) 2218c57ec8fbSNilesh Javali return -EPERM; 2219c57ec8fbSNilesh Javali 2220c57ec8fbSNilesh Javali qedi->boot_kset = iscsi_boot_create_host_kset(qedi->shost->host_no); 2221c57ec8fbSNilesh Javali if (!qedi->boot_kset) 2222c57ec8fbSNilesh Javali goto kset_free; 2223c57ec8fbSNilesh Javali 2224c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2225c57ec8fbSNilesh Javali goto kset_free; 2226c57ec8fbSNilesh Javali 2227c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 0, qedi, 2228c57ec8fbSNilesh Javali qedi_show_boot_tgt_pri_info, 2229c57ec8fbSNilesh Javali qedi_tgt_get_attr_visibility, 2230c57ec8fbSNilesh Javali qedi_boot_release); 2231c57ec8fbSNilesh Javali if (!boot_kobj) 2232c57ec8fbSNilesh Javali goto put_host; 2233c57ec8fbSNilesh Javali 2234c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2235c57ec8fbSNilesh Javali goto kset_free; 2236c57ec8fbSNilesh Javali 2237c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 1, qedi, 2238c57ec8fbSNilesh Javali qedi_show_boot_tgt_sec_info, 2239c57ec8fbSNilesh Javali qedi_tgt_get_attr_visibility, 2240c57ec8fbSNilesh Javali qedi_boot_release); 2241c57ec8fbSNilesh Javali if (!boot_kobj) 2242c57ec8fbSNilesh Javali goto put_host; 2243c57ec8fbSNilesh Javali 2244c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2245c57ec8fbSNilesh Javali goto kset_free; 2246c57ec8fbSNilesh Javali 2247c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_initiator(qedi->boot_kset, 0, qedi, 2248c57ec8fbSNilesh Javali qedi_show_boot_ini_info, 2249c57ec8fbSNilesh Javali qedi_ini_get_attr_visibility, 2250c57ec8fbSNilesh Javali qedi_boot_release); 2251c57ec8fbSNilesh Javali if (!boot_kobj) 2252c57ec8fbSNilesh Javali goto put_host; 2253c57ec8fbSNilesh Javali 2254c57ec8fbSNilesh Javali if (!scsi_host_get(qedi->shost)) 2255c57ec8fbSNilesh Javali goto kset_free; 2256c57ec8fbSNilesh Javali 2257c57ec8fbSNilesh Javali boot_kobj = iscsi_boot_create_ethernet(qedi->boot_kset, 0, qedi, 2258c57ec8fbSNilesh Javali qedi_show_boot_eth_info, 2259c57ec8fbSNilesh Javali qedi_eth_get_attr_visibility, 2260c57ec8fbSNilesh Javali qedi_boot_release); 2261c57ec8fbSNilesh Javali if (!boot_kobj) 2262c57ec8fbSNilesh Javali goto put_host; 2263c57ec8fbSNilesh Javali 2264c57ec8fbSNilesh Javali return 0; 2265c57ec8fbSNilesh Javali 2266c57ec8fbSNilesh Javali put_host: 2267c57ec8fbSNilesh Javali scsi_host_put(qedi->shost); 2268c57ec8fbSNilesh Javali kset_free: 2269c57ec8fbSNilesh Javali iscsi_boot_destroy_kset(qedi->boot_kset); 2270c57ec8fbSNilesh Javali return -ENOMEM; 2271c57ec8fbSNilesh Javali } 2272c57ec8fbSNilesh Javali 2273ace7f46bSManish Rangankar static void __qedi_remove(struct pci_dev *pdev, int mode) 2274ace7f46bSManish Rangankar { 2275ace7f46bSManish Rangankar struct qedi_ctx *qedi = pci_get_drvdata(pdev); 2276ace7f46bSManish Rangankar 2277ace7f46bSManish Rangankar if (qedi->tmf_thread) { 2278ace7f46bSManish Rangankar flush_workqueue(qedi->tmf_thread); 2279ace7f46bSManish Rangankar destroy_workqueue(qedi->tmf_thread); 2280ace7f46bSManish Rangankar qedi->tmf_thread = NULL; 2281ace7f46bSManish Rangankar } 2282ace7f46bSManish Rangankar 2283ace7f46bSManish Rangankar if (qedi->offload_thread) { 2284ace7f46bSManish Rangankar flush_workqueue(qedi->offload_thread); 2285ace7f46bSManish Rangankar destroy_workqueue(qedi->offload_thread); 2286ace7f46bSManish Rangankar qedi->offload_thread = NULL; 2287ace7f46bSManish Rangankar } 2288ace7f46bSManish Rangankar 2289ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2290ace7f46bSManish Rangankar qedi_dbg_host_exit(&qedi->dbg_ctx); 2291ace7f46bSManish Rangankar #endif 2292ace7f46bSManish Rangankar if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) 2293ace7f46bSManish Rangankar qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); 2294ace7f46bSManish Rangankar 2295ace7f46bSManish Rangankar qedi_sync_free_irqs(qedi); 2296ace7f46bSManish Rangankar 2297ace7f46bSManish Rangankar if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { 2298ace7f46bSManish Rangankar qedi_ops->stop(qedi->cdev); 2299ace7f46bSManish Rangankar qedi_ops->ll2->stop(qedi->cdev); 2300ace7f46bSManish Rangankar } 2301ace7f46bSManish Rangankar 2302ace7f46bSManish Rangankar if (mode == QEDI_MODE_NORMAL) 2303ace7f46bSManish Rangankar qedi_free_iscsi_pf_param(qedi); 2304ace7f46bSManish Rangankar 2305ace7f46bSManish Rangankar if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { 2306ace7f46bSManish Rangankar qedi_ops->common->slowpath_stop(qedi->cdev); 2307ace7f46bSManish Rangankar qedi_ops->common->remove(qedi->cdev); 2308ace7f46bSManish Rangankar } 2309ace7f46bSManish Rangankar 2310ace7f46bSManish Rangankar qedi_destroy_fp(qedi); 2311ace7f46bSManish Rangankar 2312ace7f46bSManish Rangankar if (mode == QEDI_MODE_NORMAL) { 2313ace7f46bSManish Rangankar qedi_release_cid_que(qedi); 2314ace7f46bSManish Rangankar qedi_cm_free_mem(qedi); 2315ace7f46bSManish Rangankar qedi_free_uio(qedi->udev); 2316ace7f46bSManish Rangankar qedi_free_itt(qedi); 2317ace7f46bSManish Rangankar 2318ace7f46bSManish Rangankar iscsi_host_remove(qedi->shost); 2319ace7f46bSManish Rangankar iscsi_host_free(qedi->shost); 2320ace7f46bSManish Rangankar 2321ace7f46bSManish Rangankar if (qedi->ll2_recv_thread) { 2322ace7f46bSManish Rangankar kthread_stop(qedi->ll2_recv_thread); 2323ace7f46bSManish Rangankar qedi->ll2_recv_thread = NULL; 2324ace7f46bSManish Rangankar } 2325ace7f46bSManish Rangankar qedi_ll2_free_skbs(qedi); 2326c57ec8fbSNilesh Javali 2327c57ec8fbSNilesh Javali if (qedi->boot_kset) 2328c57ec8fbSNilesh Javali iscsi_boot_destroy_kset(qedi->boot_kset); 2329ace7f46bSManish Rangankar } 2330ace7f46bSManish Rangankar } 2331ace7f46bSManish Rangankar 2332ace7f46bSManish Rangankar static int __qedi_probe(struct pci_dev *pdev, int mode) 2333ace7f46bSManish Rangankar { 2334ace7f46bSManish Rangankar struct qedi_ctx *qedi; 2335ace7f46bSManish Rangankar struct qed_ll2_params params; 2336ace7f46bSManish Rangankar u32 dp_module = 0; 2337ace7f46bSManish Rangankar u8 dp_level = 0; 2338ace7f46bSManish Rangankar bool is_vf = false; 2339ace7f46bSManish Rangankar char host_buf[16]; 2340ace7f46bSManish Rangankar struct qed_link_params link_params; 2341ace7f46bSManish Rangankar struct qed_slowpath_params sp_params; 2342ace7f46bSManish Rangankar struct qed_probe_params qed_params; 2343ace7f46bSManish Rangankar void *task_start, *task_end; 2344ace7f46bSManish Rangankar int rc; 2345ace7f46bSManish Rangankar u16 tmp; 2346ace7f46bSManish Rangankar 2347ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2348ace7f46bSManish Rangankar qedi = qedi_host_alloc(pdev); 2349ace7f46bSManish Rangankar if (!qedi) { 2350ace7f46bSManish Rangankar rc = -ENOMEM; 2351ace7f46bSManish Rangankar goto exit_probe; 2352ace7f46bSManish Rangankar } 2353ace7f46bSManish Rangankar } else { 2354ace7f46bSManish Rangankar qedi = pci_get_drvdata(pdev); 2355ace7f46bSManish Rangankar } 2356ace7f46bSManish Rangankar 2357ace7f46bSManish Rangankar memset(&qed_params, 0, sizeof(qed_params)); 2358ace7f46bSManish Rangankar qed_params.protocol = QED_PROTOCOL_ISCSI; 2359ace7f46bSManish Rangankar qed_params.dp_module = dp_module; 2360ace7f46bSManish Rangankar qed_params.dp_level = dp_level; 2361ace7f46bSManish Rangankar qed_params.is_vf = is_vf; 2362ace7f46bSManish Rangankar qedi->cdev = qedi_ops->common->probe(pdev, &qed_params); 2363ace7f46bSManish Rangankar if (!qedi->cdev) { 2364ace7f46bSManish Rangankar rc = -ENODEV; 2365ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n"); 2366ace7f46bSManish Rangankar goto free_host; 2367ace7f46bSManish Rangankar } 2368ace7f46bSManish Rangankar 2369ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 2370ace7f46bSManish Rangankar 237142d7c10fSManish Rangankar rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); 237242d7c10fSManish Rangankar if (rc) 237342d7c10fSManish Rangankar goto free_host; 237442d7c10fSManish Rangankar 2375ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2376ace7f46bSManish Rangankar rc = qedi_set_iscsi_pf_param(qedi); 2377ace7f46bSManish Rangankar if (rc) { 2378ace7f46bSManish Rangankar rc = -ENOMEM; 2379ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2380ace7f46bSManish Rangankar "Set iSCSI pf param fail\n"); 2381ace7f46bSManish Rangankar goto free_host; 2382ace7f46bSManish Rangankar } 2383ace7f46bSManish Rangankar } 2384ace7f46bSManish Rangankar 2385ace7f46bSManish Rangankar qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); 2386ace7f46bSManish Rangankar 2387ace7f46bSManish Rangankar rc = qedi_prepare_fp(qedi); 2388ace7f46bSManish Rangankar if (rc) { 2389ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath.\n"); 2390ace7f46bSManish Rangankar goto free_pf_params; 2391ace7f46bSManish Rangankar } 2392ace7f46bSManish Rangankar 2393ace7f46bSManish Rangankar /* Start the Slowpath-process */ 2394ace7f46bSManish Rangankar memset(&sp_params, 0, sizeof(struct qed_slowpath_params)); 2395ace7f46bSManish Rangankar sp_params.int_mode = QED_INT_MODE_MSIX; 2396ace7f46bSManish Rangankar sp_params.drv_major = QEDI_DRIVER_MAJOR_VER; 2397ace7f46bSManish Rangankar sp_params.drv_minor = QEDI_DRIVER_MINOR_VER; 2398ace7f46bSManish Rangankar sp_params.drv_rev = QEDI_DRIVER_REV_VER; 2399ace7f46bSManish Rangankar sp_params.drv_eng = QEDI_DRIVER_ENG_VER; 2400ace7f46bSManish Rangankar strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); 2401ace7f46bSManish Rangankar rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params); 2402ace7f46bSManish Rangankar if (rc) { 2403ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n"); 2404ace7f46bSManish Rangankar goto stop_hw; 2405ace7f46bSManish Rangankar } 2406ace7f46bSManish Rangankar 2407ace7f46bSManish Rangankar /* update_pf_params needs to be called before and after slowpath 2408ace7f46bSManish Rangankar * start 2409ace7f46bSManish Rangankar */ 2410ace7f46bSManish Rangankar qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); 2411ace7f46bSManish Rangankar 2412d1a9ccc4SColin Ian King rc = qedi_setup_int(qedi); 2413ace7f46bSManish Rangankar if (rc) 2414ace7f46bSManish Rangankar goto stop_iscsi_func; 2415ace7f46bSManish Rangankar 2416ace7f46bSManish Rangankar qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); 2417ace7f46bSManish Rangankar 2418ace7f46bSManish Rangankar /* Learn information crucial for qedi to progress */ 2419ace7f46bSManish Rangankar rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); 2420ace7f46bSManish Rangankar if (rc) 2421ace7f46bSManish Rangankar goto stop_iscsi_func; 2422ace7f46bSManish Rangankar 2423ace7f46bSManish Rangankar /* Record BDQ producer doorbell addresses */ 2424ace7f46bSManish Rangankar qedi->bdq_primary_prod = qedi->dev_info.primary_dbq_rq_addr; 2425ace7f46bSManish Rangankar qedi->bdq_secondary_prod = qedi->dev_info.secondary_bdq_rq_addr; 2426ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 2427ace7f46bSManish Rangankar "BDQ primary_prod=%p secondary_prod=%p.\n", 2428ace7f46bSManish Rangankar qedi->bdq_primary_prod, 2429ace7f46bSManish Rangankar qedi->bdq_secondary_prod); 2430ace7f46bSManish Rangankar 2431ace7f46bSManish Rangankar /* 2432ace7f46bSManish Rangankar * We need to write the number of BDs in the BDQ we've preallocated so 2433ace7f46bSManish Rangankar * the f/w will do a prefetch and we'll get an unsolicited CQE when a 2434ace7f46bSManish Rangankar * packet arrives. 2435ace7f46bSManish Rangankar */ 2436ace7f46bSManish Rangankar qedi->bdq_prod_idx = QEDI_BDQ_NUM; 2437ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 2438ace7f46bSManish Rangankar "Writing %d to primary and secondary BDQ doorbell registers.\n", 2439ace7f46bSManish Rangankar qedi->bdq_prod_idx); 2440ace7f46bSManish Rangankar writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod); 2441ace7f46bSManish Rangankar tmp = readw(qedi->bdq_primary_prod); 2442ace7f46bSManish Rangankar writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod); 2443ace7f46bSManish Rangankar tmp = readw(qedi->bdq_secondary_prod); 2444ace7f46bSManish Rangankar 2445ace7f46bSManish Rangankar ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac); 2446ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n", 2447ace7f46bSManish Rangankar qedi->mac); 2448ace7f46bSManish Rangankar 2449ace7f46bSManish Rangankar sprintf(host_buf, "host_%d", qedi->shost->host_no); 2450712c3cbfSMintz, Yuval qedi_ops->common->set_name(qedi->cdev, host_buf); 2451ace7f46bSManish Rangankar 2452ace7f46bSManish Rangankar qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); 2453ace7f46bSManish Rangankar 2454ace7f46bSManish Rangankar memset(¶ms, 0, sizeof(params)); 2455ace7f46bSManish Rangankar params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN; 2456ace7f46bSManish Rangankar qedi->ll2_mtu = DEF_PATH_MTU; 2457ace7f46bSManish Rangankar params.drop_ttl0_packets = 0; 2458ace7f46bSManish Rangankar params.rx_vlan_stripping = 1; 2459ace7f46bSManish Rangankar ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); 2460ace7f46bSManish Rangankar 2461ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2462ace7f46bSManish Rangankar /* set up rx path */ 2463ace7f46bSManish Rangankar INIT_LIST_HEAD(&qedi->ll2_skb_list); 2464ace7f46bSManish Rangankar spin_lock_init(&qedi->ll2_lock); 2465ace7f46bSManish Rangankar /* start qedi context */ 2466ace7f46bSManish Rangankar spin_lock_init(&qedi->hba_lock); 2467ace7f46bSManish Rangankar spin_lock_init(&qedi->task_idx_lock); 2468ace7f46bSManish Rangankar } 2469ace7f46bSManish Rangankar qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi); 2470ace7f46bSManish Rangankar qedi_ops->ll2->start(qedi->cdev, ¶ms); 2471ace7f46bSManish Rangankar 2472ace7f46bSManish Rangankar if (mode != QEDI_MODE_RECOVERY) { 2473ace7f46bSManish Rangankar qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread, 2474ace7f46bSManish Rangankar (void *)qedi, 2475ace7f46bSManish Rangankar "qedi_ll2_thread"); 2476ace7f46bSManish Rangankar } 2477ace7f46bSManish Rangankar 2478ace7f46bSManish Rangankar rc = qedi_ops->start(qedi->cdev, &qedi->tasks, 2479ace7f46bSManish Rangankar qedi, qedi_iscsi_event_cb); 2480ace7f46bSManish Rangankar if (rc) { 2481ace7f46bSManish Rangankar rc = -ENODEV; 2482ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, "Cannot start iSCSI function\n"); 2483ace7f46bSManish Rangankar goto stop_slowpath; 2484ace7f46bSManish Rangankar } 2485ace7f46bSManish Rangankar 2486ace7f46bSManish Rangankar task_start = qedi_get_task_mem(&qedi->tasks, 0); 2487ace7f46bSManish Rangankar task_end = qedi_get_task_mem(&qedi->tasks, MAX_TID_BLOCKS_ISCSI - 1); 2488ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, 2489ace7f46bSManish Rangankar "Task context start=%p, end=%p block_size=%u.\n", 2490ace7f46bSManish Rangankar task_start, task_end, qedi->tasks.size); 2491ace7f46bSManish Rangankar 2492ace7f46bSManish Rangankar memset(&link_params, 0, sizeof(link_params)); 2493ace7f46bSManish Rangankar link_params.link_up = true; 2494ace7f46bSManish Rangankar rc = qedi_ops->common->set_link(qedi->cdev, &link_params); 2495ace7f46bSManish Rangankar if (rc) { 2496ace7f46bSManish Rangankar QEDI_WARN(&qedi->dbg_ctx, "Link set up failed.\n"); 2497ace7f46bSManish Rangankar atomic_set(&qedi->link_state, QEDI_LINK_DOWN); 2498ace7f46bSManish Rangankar } 2499ace7f46bSManish Rangankar 2500ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2501779936faSArnd Bergmann qedi_dbg_host_init(&qedi->dbg_ctx, qedi_debugfs_ops, 2502779936faSArnd Bergmann qedi_dbg_fops); 2503ace7f46bSManish Rangankar #endif 2504ace7f46bSManish Rangankar QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, 2505ace7f46bSManish Rangankar "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n", 2506ace7f46bSManish Rangankar QEDI_MODULE_VERSION, FW_MAJOR_VERSION, FW_MINOR_VERSION, 2507ace7f46bSManish Rangankar FW_REVISION_VERSION, FW_ENGINEERING_VERSION); 2508ace7f46bSManish Rangankar 2509ace7f46bSManish Rangankar if (mode == QEDI_MODE_NORMAL) { 2510ace7f46bSManish Rangankar if (iscsi_host_add(qedi->shost, &pdev->dev)) { 2511ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2512ace7f46bSManish Rangankar "Could not add iscsi host\n"); 2513ace7f46bSManish Rangankar rc = -ENOMEM; 2514ace7f46bSManish Rangankar goto remove_host; 2515ace7f46bSManish Rangankar } 2516ace7f46bSManish Rangankar 2517ace7f46bSManish Rangankar /* Allocate uio buffers */ 2518ace7f46bSManish Rangankar rc = qedi_alloc_uio_rings(qedi); 2519ace7f46bSManish Rangankar if (rc) { 2520ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2521ace7f46bSManish Rangankar "UIO alloc ring failed err=%d\n", rc); 2522ace7f46bSManish Rangankar goto remove_host; 2523ace7f46bSManish Rangankar } 2524ace7f46bSManish Rangankar 2525ace7f46bSManish Rangankar rc = qedi_init_uio(qedi); 2526ace7f46bSManish Rangankar if (rc) { 2527ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2528ace7f46bSManish Rangankar "UIO init failed, err=%d\n", rc); 2529ace7f46bSManish Rangankar goto free_uio; 2530ace7f46bSManish Rangankar } 2531ace7f46bSManish Rangankar 2532ace7f46bSManish Rangankar /* host the array on iscsi_conn */ 2533ace7f46bSManish Rangankar rc = qedi_setup_cid_que(qedi); 2534ace7f46bSManish Rangankar if (rc) { 2535ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2536ace7f46bSManish Rangankar "Could not setup cid que\n"); 2537ace7f46bSManish Rangankar goto free_uio; 2538ace7f46bSManish Rangankar } 2539ace7f46bSManish Rangankar 2540ace7f46bSManish Rangankar rc = qedi_cm_alloc_mem(qedi); 2541ace7f46bSManish Rangankar if (rc) { 2542ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2543ace7f46bSManish Rangankar "Could not alloc cm memory\n"); 2544ace7f46bSManish Rangankar goto free_cid_que; 2545ace7f46bSManish Rangankar } 2546ace7f46bSManish Rangankar 2547ace7f46bSManish Rangankar rc = qedi_alloc_itt(qedi); 2548ace7f46bSManish Rangankar if (rc) { 2549ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2550ace7f46bSManish Rangankar "Could not alloc itt memory\n"); 2551ace7f46bSManish Rangankar goto free_cid_que; 2552ace7f46bSManish Rangankar } 2553ace7f46bSManish Rangankar 2554ace7f46bSManish Rangankar sprintf(host_buf, "host_%d", qedi->shost->host_no); 2555ace7f46bSManish Rangankar qedi->tmf_thread = create_singlethread_workqueue(host_buf); 2556ace7f46bSManish Rangankar if (!qedi->tmf_thread) { 2557ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2558ace7f46bSManish Rangankar "Unable to start tmf thread!\n"); 2559ace7f46bSManish Rangankar rc = -ENODEV; 2560ace7f46bSManish Rangankar goto free_cid_que; 2561ace7f46bSManish Rangankar } 2562ace7f46bSManish Rangankar 2563ace7f46bSManish Rangankar sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no); 2564ace7f46bSManish Rangankar qedi->offload_thread = create_workqueue(host_buf); 2565ace7f46bSManish Rangankar if (!qedi->offload_thread) { 2566ace7f46bSManish Rangankar QEDI_ERR(&qedi->dbg_ctx, 2567ace7f46bSManish Rangankar "Unable to start offload thread!\n"); 2568ace7f46bSManish Rangankar rc = -ENODEV; 2569ace7f46bSManish Rangankar goto free_cid_que; 2570ace7f46bSManish Rangankar } 2571ace7f46bSManish Rangankar 2572ace7f46bSManish Rangankar /* F/w needs 1st task context memory entry for performance */ 2573ace7f46bSManish Rangankar set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map); 2574ace7f46bSManish Rangankar atomic_set(&qedi->num_offloads, 0); 2575c57ec8fbSNilesh Javali 2576c57ec8fbSNilesh Javali if (qedi_setup_boot_info(qedi)) 2577c57ec8fbSNilesh Javali QEDI_ERR(&qedi->dbg_ctx, 2578c57ec8fbSNilesh Javali "No iSCSI boot target configured\n"); 2579ace7f46bSManish Rangankar } 2580ace7f46bSManish Rangankar 2581ace7f46bSManish Rangankar return 0; 2582ace7f46bSManish Rangankar 2583ace7f46bSManish Rangankar free_cid_que: 2584ace7f46bSManish Rangankar qedi_release_cid_que(qedi); 2585ace7f46bSManish Rangankar free_uio: 2586ace7f46bSManish Rangankar qedi_free_uio(qedi->udev); 2587ace7f46bSManish Rangankar remove_host: 2588ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2589ace7f46bSManish Rangankar qedi_dbg_host_exit(&qedi->dbg_ctx); 2590ace7f46bSManish Rangankar #endif 2591ace7f46bSManish Rangankar iscsi_host_remove(qedi->shost); 2592ace7f46bSManish Rangankar stop_iscsi_func: 2593ace7f46bSManish Rangankar qedi_ops->stop(qedi->cdev); 2594ace7f46bSManish Rangankar stop_slowpath: 2595ace7f46bSManish Rangankar qedi_ops->common->slowpath_stop(qedi->cdev); 2596ace7f46bSManish Rangankar stop_hw: 2597ace7f46bSManish Rangankar qedi_ops->common->remove(qedi->cdev); 2598ace7f46bSManish Rangankar free_pf_params: 2599ace7f46bSManish Rangankar qedi_free_iscsi_pf_param(qedi); 2600ace7f46bSManish Rangankar free_host: 2601ace7f46bSManish Rangankar iscsi_host_free(qedi->shost); 2602ace7f46bSManish Rangankar exit_probe: 2603ace7f46bSManish Rangankar return rc; 2604ace7f46bSManish Rangankar } 2605ace7f46bSManish Rangankar 2606ace7f46bSManish Rangankar static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 2607ace7f46bSManish Rangankar { 2608ace7f46bSManish Rangankar return __qedi_probe(pdev, QEDI_MODE_NORMAL); 2609ace7f46bSManish Rangankar } 2610ace7f46bSManish Rangankar 2611ace7f46bSManish Rangankar static void qedi_remove(struct pci_dev *pdev) 2612ace7f46bSManish Rangankar { 2613ace7f46bSManish Rangankar __qedi_remove(pdev, QEDI_MODE_NORMAL); 2614ace7f46bSManish Rangankar } 2615ace7f46bSManish Rangankar 2616ace7f46bSManish Rangankar static struct pci_device_id qedi_pci_tbl[] = { 2617ace7f46bSManish Rangankar { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x165E) }, 261804688525SManish Rangankar { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x8084) }, 2619ace7f46bSManish Rangankar { 0 }, 2620ace7f46bSManish Rangankar }; 2621ace7f46bSManish Rangankar MODULE_DEVICE_TABLE(pci, qedi_pci_tbl); 2622ace7f46bSManish Rangankar 2623a98d1a0cSThomas Gleixner static enum cpuhp_state qedi_cpuhp_state; 2624a98d1a0cSThomas Gleixner 2625ace7f46bSManish Rangankar static struct pci_driver qedi_pci_driver = { 2626ace7f46bSManish Rangankar .name = QEDI_MODULE_NAME, 2627ace7f46bSManish Rangankar .id_table = qedi_pci_tbl, 2628ace7f46bSManish Rangankar .probe = qedi_probe, 2629ace7f46bSManish Rangankar .remove = qedi_remove, 2630ace7f46bSManish Rangankar }; 2631ace7f46bSManish Rangankar 2632ace7f46bSManish Rangankar static int __init qedi_init(void) 2633ace7f46bSManish Rangankar { 2634ace7f46bSManish Rangankar struct qedi_percpu_s *p; 2635a98d1a0cSThomas Gleixner int cpu, rc = 0; 2636ace7f46bSManish Rangankar 2637ace7f46bSManish Rangankar qedi_ops = qed_get_iscsi_ops(); 2638ace7f46bSManish Rangankar if (!qedi_ops) { 2639ace7f46bSManish Rangankar QEDI_ERR(NULL, "Failed to get qed iSCSI operations\n"); 2640a98d1a0cSThomas Gleixner return -EINVAL; 2641ace7f46bSManish Rangankar } 2642ace7f46bSManish Rangankar 2643ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2644ace7f46bSManish Rangankar qedi_dbg_init("qedi"); 2645ace7f46bSManish Rangankar #endif 2646ace7f46bSManish Rangankar 2647ace7f46bSManish Rangankar qedi_scsi_transport = iscsi_register_transport(&qedi_iscsi_transport); 2648ace7f46bSManish Rangankar if (!qedi_scsi_transport) { 2649ace7f46bSManish Rangankar QEDI_ERR(NULL, "Could not register qedi transport"); 2650ace7f46bSManish Rangankar rc = -ENOMEM; 2651ace7f46bSManish Rangankar goto exit_qedi_init_1; 2652ace7f46bSManish Rangankar } 2653ace7f46bSManish Rangankar 2654ace7f46bSManish Rangankar for_each_possible_cpu(cpu) { 2655ace7f46bSManish Rangankar p = &per_cpu(qedi_percpu, cpu); 2656ace7f46bSManish Rangankar INIT_LIST_HEAD(&p->work_list); 2657ace7f46bSManish Rangankar spin_lock_init(&p->p_work_lock); 2658ace7f46bSManish Rangankar p->iothread = NULL; 2659ace7f46bSManish Rangankar } 2660ace7f46bSManish Rangankar 2661a98d1a0cSThomas Gleixner rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/qedi:online", 2662a98d1a0cSThomas Gleixner qedi_cpu_online, qedi_cpu_offline); 2663a98d1a0cSThomas Gleixner if (rc < 0) 2664a98d1a0cSThomas Gleixner goto exit_qedi_init_2; 2665a98d1a0cSThomas Gleixner qedi_cpuhp_state = rc; 2666ace7f46bSManish Rangankar 2667a98d1a0cSThomas Gleixner rc = pci_register_driver(&qedi_pci_driver); 2668a98d1a0cSThomas Gleixner if (rc) { 2669a98d1a0cSThomas Gleixner QEDI_ERR(NULL, "Failed to register driver\n"); 2670a98d1a0cSThomas Gleixner goto exit_qedi_hp; 2671a98d1a0cSThomas Gleixner } 2672ace7f46bSManish Rangankar 2673a98d1a0cSThomas Gleixner return 0; 2674a98d1a0cSThomas Gleixner 2675a98d1a0cSThomas Gleixner exit_qedi_hp: 2676a98d1a0cSThomas Gleixner cpuhp_remove_state(qedi_cpuhp_state); 2677ace7f46bSManish Rangankar exit_qedi_init_2: 2678ace7f46bSManish Rangankar iscsi_unregister_transport(&qedi_iscsi_transport); 2679ace7f46bSManish Rangankar exit_qedi_init_1: 2680ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2681ace7f46bSManish Rangankar qedi_dbg_exit(); 2682ace7f46bSManish Rangankar #endif 2683ace7f46bSManish Rangankar qed_put_iscsi_ops(); 2684ace7f46bSManish Rangankar return rc; 2685ace7f46bSManish Rangankar } 2686ace7f46bSManish Rangankar 2687ace7f46bSManish Rangankar static void __exit qedi_cleanup(void) 2688ace7f46bSManish Rangankar { 2689ace7f46bSManish Rangankar pci_unregister_driver(&qedi_pci_driver); 2690a98d1a0cSThomas Gleixner cpuhp_remove_state(qedi_cpuhp_state); 2691ace7f46bSManish Rangankar iscsi_unregister_transport(&qedi_iscsi_transport); 2692ace7f46bSManish Rangankar 2693ace7f46bSManish Rangankar #ifdef CONFIG_DEBUG_FS 2694ace7f46bSManish Rangankar qedi_dbg_exit(); 2695ace7f46bSManish Rangankar #endif 2696ace7f46bSManish Rangankar qed_put_iscsi_ops(); 2697ace7f46bSManish Rangankar } 2698ace7f46bSManish Rangankar 2699ace7f46bSManish Rangankar MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx iSCSI Module"); 2700ace7f46bSManish Rangankar MODULE_LICENSE("GPL"); 2701ace7f46bSManish Rangankar MODULE_AUTHOR("QLogic Corporation"); 2702ace7f46bSManish Rangankar MODULE_VERSION(QEDI_MODULE_VERSION); 2703ace7f46bSManish Rangankar module_init(qedi_init); 2704ace7f46bSManish Rangankar module_exit(qedi_cleanup); 2705