1942b7654SJitendra Bhivare /* 294583217SKetan Mukadam * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI 394583217SKetan Mukadam * Host Bus Adapters. Refer to the README file included with this package 494583217SKetan Mukadam * for driver version and adapter compatibility. 56733b39aSJayamohan Kallickal * 694583217SKetan Mukadam * Copyright (c) 2018 Broadcom. All Rights Reserved. 794583217SKetan Mukadam * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 894583217SKetan Mukadam * 994583217SKetan Mukadam * This program is free software; you can redistribute it and/or modify it 1094583217SKetan Mukadam * under the terms of version 2 of the GNU General Public License as published 1194583217SKetan Mukadam * by the Free Software Foundation. 1294583217SKetan Mukadam * 1394583217SKetan Mukadam * This program is distributed in the hope that it will be useful. ALL EXPRESS 1494583217SKetan Mukadam * OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY 1594583217SKetan Mukadam * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 1694583217SKetan Mukadam * OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH 1794583217SKetan Mukadam * DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. 1894583217SKetan Mukadam * See the GNU General Public License for more details, a copy of which 1994583217SKetan Mukadam * can be found in the file COPYING included with this package. 206733b39aSJayamohan Kallickal * 216733b39aSJayamohan Kallickal * Contact Information: 2260f36e04SJitendra Bhivare * linux-drivers@broadcom.com 236733b39aSJayamohan Kallickal * 246733b39aSJayamohan Kallickal */ 25255fa9a3SJayamohan Kallickal 266733b39aSJayamohan Kallickal #include <linux/reboot.h> 276733b39aSJayamohan Kallickal #include <linux/delay.h> 285a0e3ad6STejun Heo #include <linux/slab.h> 296733b39aSJayamohan Kallickal #include <linux/interrupt.h> 306733b39aSJayamohan Kallickal #include <linux/blkdev.h> 316733b39aSJayamohan Kallickal #include <linux/pci.h> 326733b39aSJayamohan Kallickal #include <linux/string.h> 336733b39aSJayamohan Kallickal #include <linux/kernel.h> 346733b39aSJayamohan Kallickal #include <linux/semaphore.h> 35c7acc5b8SJayamohan Kallickal #include <linux/iscsi_boot_sysfs.h> 36acf3368fSPaul Gortmaker #include <linux/module.h> 37ffce3e2eSJayamohan Kallickal #include <linux/bsg-lib.h> 381094cf68SJitendra Bhivare #include <linux/irq_poll.h> 396733b39aSJayamohan Kallickal 406733b39aSJayamohan Kallickal #include <scsi/libiscsi.h> 41ffce3e2eSJayamohan Kallickal #include <scsi/scsi_bsg_iscsi.h> 42ffce3e2eSJayamohan Kallickal #include <scsi/scsi_netlink.h> 436733b39aSJayamohan Kallickal #include <scsi/scsi_transport_iscsi.h> 446733b39aSJayamohan Kallickal #include <scsi/scsi_transport.h> 456733b39aSJayamohan Kallickal #include <scsi/scsi_cmnd.h> 466733b39aSJayamohan Kallickal #include <scsi/scsi_device.h> 476733b39aSJayamohan Kallickal #include <scsi/scsi_host.h> 486733b39aSJayamohan Kallickal #include <scsi/scsi.h> 496733b39aSJayamohan Kallickal #include "be_main.h" 506733b39aSJayamohan Kallickal #include "be_iscsi.h" 516733b39aSJayamohan Kallickal #include "be_mgmt.h" 520a513dd8SJohn Soni Jose #include "be_cmds.h" 536733b39aSJayamohan Kallickal 546733b39aSJayamohan Kallickal static unsigned int be_iopoll_budget = 10; 556733b39aSJayamohan Kallickal static unsigned int be_max_phys_size = 64; 56bfead3b2SJayamohan Kallickal static unsigned int enable_msix = 1; 576733b39aSJayamohan Kallickal 586733b39aSJayamohan Kallickal MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); 5976d15dbdSJayamohan Kallickal MODULE_VERSION(BUILD_STR); 60c4f39bdaSKetan Mukadam MODULE_AUTHOR("Emulex Corporation"); 616733b39aSJayamohan Kallickal MODULE_LICENSE("GPL"); 626733b39aSJayamohan Kallickal module_param(be_iopoll_budget, int, 0); 636733b39aSJayamohan Kallickal module_param(enable_msix, int, 0); 646733b39aSJayamohan Kallickal module_param(be_max_phys_size, uint, S_IRUGO); 6599bc5d55SJohn Soni Jose MODULE_PARM_DESC(be_max_phys_size, 6699bc5d55SJohn Soni Jose "Maximum Size (In Kilobytes) of physically contiguous " 6799bc5d55SJohn Soni Jose "memory that can be allocated. Range is 16 - 128"); 6899bc5d55SJohn Soni Jose 6999bc5d55SJohn Soni Jose #define beiscsi_disp_param(_name)\ 700825b8eeSBaoyou Xie static ssize_t \ 7199bc5d55SJohn Soni Jose beiscsi_##_name##_disp(struct device *dev,\ 7299bc5d55SJohn Soni Jose struct device_attribute *attrib, char *buf) \ 7399bc5d55SJohn Soni Jose { \ 7499bc5d55SJohn Soni Jose struct Scsi_Host *shost = class_to_shost(dev);\ 7599bc5d55SJohn Soni Jose struct beiscsi_hba *phba = iscsi_host_priv(shost); \ 7699bc5d55SJohn Soni Jose return snprintf(buf, PAGE_SIZE, "%d\n",\ 7799bc5d55SJohn Soni Jose phba->attr_##_name);\ 7899bc5d55SJohn Soni Jose } 7999bc5d55SJohn Soni Jose 8099bc5d55SJohn Soni Jose #define beiscsi_change_param(_name, _minval, _maxval, _defaval)\ 810825b8eeSBaoyou Xie static int \ 8299bc5d55SJohn Soni Jose beiscsi_##_name##_change(struct beiscsi_hba *phba, uint32_t val)\ 8399bc5d55SJohn Soni Jose {\ 8499bc5d55SJohn Soni Jose if (val >= _minval && val <= _maxval) {\ 8599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,\ 8699bc5d55SJohn Soni Jose "BA_%d : beiscsi_"#_name" updated "\ 8799bc5d55SJohn Soni Jose "from 0x%x ==> 0x%x\n",\ 8899bc5d55SJohn Soni Jose phba->attr_##_name, val); \ 8999bc5d55SJohn Soni Jose phba->attr_##_name = val;\ 9099bc5d55SJohn Soni Jose return 0;\ 9199bc5d55SJohn Soni Jose } \ 9299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, \ 9399bc5d55SJohn Soni Jose "BA_%d beiscsi_"#_name" attribute "\ 9499bc5d55SJohn Soni Jose "cannot be updated to 0x%x, "\ 9599bc5d55SJohn Soni Jose "range allowed is ["#_minval" - "#_maxval"]\n", val);\ 9699bc5d55SJohn Soni Jose return -EINVAL;\ 9799bc5d55SJohn Soni Jose } 9899bc5d55SJohn Soni Jose 9999bc5d55SJohn Soni Jose #define beiscsi_store_param(_name) \ 1000825b8eeSBaoyou Xie static ssize_t \ 10199bc5d55SJohn Soni Jose beiscsi_##_name##_store(struct device *dev,\ 10299bc5d55SJohn Soni Jose struct device_attribute *attr, const char *buf,\ 10399bc5d55SJohn Soni Jose size_t count) \ 10499bc5d55SJohn Soni Jose { \ 10599bc5d55SJohn Soni Jose struct Scsi_Host *shost = class_to_shost(dev);\ 10699bc5d55SJohn Soni Jose struct beiscsi_hba *phba = iscsi_host_priv(shost);\ 10799bc5d55SJohn Soni Jose uint32_t param_val = 0;\ 10899bc5d55SJohn Soni Jose if (!isdigit(buf[0]))\ 10999bc5d55SJohn Soni Jose return -EINVAL;\ 11099bc5d55SJohn Soni Jose if (sscanf(buf, "%i", ¶m_val) != 1)\ 11199bc5d55SJohn Soni Jose return -EINVAL;\ 11299bc5d55SJohn Soni Jose if (beiscsi_##_name##_change(phba, param_val) == 0) \ 11399bc5d55SJohn Soni Jose return strlen(buf);\ 11499bc5d55SJohn Soni Jose else \ 11599bc5d55SJohn Soni Jose return -EINVAL;\ 11699bc5d55SJohn Soni Jose } 11799bc5d55SJohn Soni Jose 11899bc5d55SJohn Soni Jose #define beiscsi_init_param(_name, _minval, _maxval, _defval) \ 1190825b8eeSBaoyou Xie static int \ 12099bc5d55SJohn Soni Jose beiscsi_##_name##_init(struct beiscsi_hba *phba, uint32_t val) \ 12199bc5d55SJohn Soni Jose { \ 12299bc5d55SJohn Soni Jose if (val >= _minval && val <= _maxval) {\ 12399bc5d55SJohn Soni Jose phba->attr_##_name = val;\ 12499bc5d55SJohn Soni Jose return 0;\ 12599bc5d55SJohn Soni Jose } \ 12699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,\ 12799bc5d55SJohn Soni Jose "BA_%d beiscsi_"#_name" attribute " \ 12899bc5d55SJohn Soni Jose "cannot be updated to 0x%x, "\ 12999bc5d55SJohn Soni Jose "range allowed is ["#_minval" - "#_maxval"]\n", val);\ 13099bc5d55SJohn Soni Jose phba->attr_##_name = _defval;\ 13199bc5d55SJohn Soni Jose return -EINVAL;\ 13299bc5d55SJohn Soni Jose } 13399bc5d55SJohn Soni Jose 13499bc5d55SJohn Soni Jose #define BEISCSI_RW_ATTR(_name, _minval, _maxval, _defval, _descp) \ 13599bc5d55SJohn Soni Jose static uint beiscsi_##_name = _defval;\ 13699bc5d55SJohn Soni Jose module_param(beiscsi_##_name, uint, S_IRUGO);\ 13799bc5d55SJohn Soni Jose MODULE_PARM_DESC(beiscsi_##_name, _descp);\ 13899bc5d55SJohn Soni Jose beiscsi_disp_param(_name)\ 13999bc5d55SJohn Soni Jose beiscsi_change_param(_name, _minval, _maxval, _defval)\ 14099bc5d55SJohn Soni Jose beiscsi_store_param(_name)\ 14199bc5d55SJohn Soni Jose beiscsi_init_param(_name, _minval, _maxval, _defval)\ 14299bc5d55SJohn Soni Jose DEVICE_ATTR(beiscsi_##_name, S_IRUGO | S_IWUSR,\ 14399bc5d55SJohn Soni Jose beiscsi_##_name##_disp, beiscsi_##_name##_store) 14499bc5d55SJohn Soni Jose 14599bc5d55SJohn Soni Jose /* 14699bc5d55SJohn Soni Jose * When new log level added update the 14799bc5d55SJohn Soni Jose * the MAX allowed value for log_enable 14899bc5d55SJohn Soni Jose */ 14999bc5d55SJohn Soni Jose BEISCSI_RW_ATTR(log_enable, 0x00, 15099bc5d55SJohn Soni Jose 0xFF, 0x00, "Enable logging Bit Mask\n" 15199bc5d55SJohn Soni Jose "\t\t\t\tInitialization Events : 0x01\n" 15299bc5d55SJohn Soni Jose "\t\t\t\tMailbox Events : 0x02\n" 15399bc5d55SJohn Soni Jose "\t\t\t\tMiscellaneous Events : 0x04\n" 15499bc5d55SJohn Soni Jose "\t\t\t\tError Handling : 0x08\n" 15599bc5d55SJohn Soni Jose "\t\t\t\tIO Path Events : 0x10\n" 156afb96058SJayamohan Kallickal "\t\t\t\tConfiguration Path : 0x20\n" 157afb96058SJayamohan Kallickal "\t\t\t\tiSCSI Protocol : 0x40\n"); 15899bc5d55SJohn Soni Jose 1595cac7596SJohn Soni Jose DEVICE_ATTR(beiscsi_drvr_ver, S_IRUGO, beiscsi_drvr_ver_disp, NULL); 16026000db7SJohn Soni Jose DEVICE_ATTR(beiscsi_adapter_family, S_IRUGO, beiscsi_adap_family_disp, NULL); 16122661e25SJayamohan Kallickal DEVICE_ATTR(beiscsi_fw_ver, S_IRUGO, beiscsi_fw_ver_disp, NULL); 162d3fea9afSJayamohan Kallickal DEVICE_ATTR(beiscsi_phys_port, S_IRUGO, beiscsi_phys_port_disp, NULL); 1636103c1f7SJayamohan Kallickal DEVICE_ATTR(beiscsi_active_session_count, S_IRUGO, 1646103c1f7SJayamohan Kallickal beiscsi_active_session_disp, NULL); 1656103c1f7SJayamohan Kallickal DEVICE_ATTR(beiscsi_free_session_count, S_IRUGO, 1666103c1f7SJayamohan Kallickal beiscsi_free_session_disp, NULL); 1674ab2990aSZou Wei static struct device_attribute *beiscsi_attrs[] = { 16899bc5d55SJohn Soni Jose &dev_attr_beiscsi_log_enable, 1695cac7596SJohn Soni Jose &dev_attr_beiscsi_drvr_ver, 17026000db7SJohn Soni Jose &dev_attr_beiscsi_adapter_family, 17122661e25SJayamohan Kallickal &dev_attr_beiscsi_fw_ver, 1726103c1f7SJayamohan Kallickal &dev_attr_beiscsi_active_session_count, 1736103c1f7SJayamohan Kallickal &dev_attr_beiscsi_free_session_count, 174d3fea9afSJayamohan Kallickal &dev_attr_beiscsi_phys_port, 17599bc5d55SJohn Soni Jose NULL, 17699bc5d55SJohn Soni Jose }; 1776733b39aSJayamohan Kallickal 1786763daaeSJohn Soni Jose static char const *cqe_desc[] = { 1796763daaeSJohn Soni Jose "RESERVED_DESC", 1806763daaeSJohn Soni Jose "SOL_CMD_COMPLETE", 1816763daaeSJohn Soni Jose "SOL_CMD_KILLED_DATA_DIGEST_ERR", 1826763daaeSJohn Soni Jose "CXN_KILLED_PDU_SIZE_EXCEEDS_DSL", 1836763daaeSJohn Soni Jose "CXN_KILLED_BURST_LEN_MISMATCH", 1846763daaeSJohn Soni Jose "CXN_KILLED_AHS_RCVD", 1856763daaeSJohn Soni Jose "CXN_KILLED_HDR_DIGEST_ERR", 1866763daaeSJohn Soni Jose "CXN_KILLED_UNKNOWN_HDR", 1876763daaeSJohn Soni Jose "CXN_KILLED_STALE_ITT_TTT_RCVD", 1886763daaeSJohn Soni Jose "CXN_KILLED_INVALID_ITT_TTT_RCVD", 1896763daaeSJohn Soni Jose "CXN_KILLED_RST_RCVD", 1906763daaeSJohn Soni Jose "CXN_KILLED_TIMED_OUT", 1916763daaeSJohn Soni Jose "CXN_KILLED_RST_SENT", 1926763daaeSJohn Soni Jose "CXN_KILLED_FIN_RCVD", 1936763daaeSJohn Soni Jose "CXN_KILLED_BAD_UNSOL_PDU_RCVD", 1946763daaeSJohn Soni Jose "CXN_KILLED_BAD_WRB_INDEX_ERROR", 1956763daaeSJohn Soni Jose "CXN_KILLED_OVER_RUN_RESIDUAL", 1966763daaeSJohn Soni Jose "CXN_KILLED_UNDER_RUN_RESIDUAL", 1976763daaeSJohn Soni Jose "CMD_KILLED_INVALID_STATSN_RCVD", 1986763daaeSJohn Soni Jose "CMD_KILLED_INVALID_R2T_RCVD", 1996763daaeSJohn Soni Jose "CMD_CXN_KILLED_LUN_INVALID", 2006763daaeSJohn Soni Jose "CMD_CXN_KILLED_ICD_INVALID", 2016763daaeSJohn Soni Jose "CMD_CXN_KILLED_ITT_INVALID", 2026763daaeSJohn Soni Jose "CMD_CXN_KILLED_SEQ_OUTOFORDER", 2036763daaeSJohn Soni Jose "CMD_CXN_KILLED_INVALID_DATASN_RCVD", 2046763daaeSJohn Soni Jose "CXN_INVALIDATE_NOTIFY", 2056763daaeSJohn Soni Jose "CXN_INVALIDATE_INDEX_NOTIFY", 2066763daaeSJohn Soni Jose "CMD_INVALIDATED_NOTIFY", 2076763daaeSJohn Soni Jose "UNSOL_HDR_NOTIFY", 2086763daaeSJohn Soni Jose "UNSOL_DATA_NOTIFY", 2096763daaeSJohn Soni Jose "UNSOL_DATA_DIGEST_ERROR_NOTIFY", 2106763daaeSJohn Soni Jose "DRIVERMSG_NOTIFY", 2116763daaeSJohn Soni Jose "CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN", 2126763daaeSJohn Soni Jose "SOL_CMD_KILLED_DIF_ERR", 2136763daaeSJohn Soni Jose "CXN_KILLED_SYN_RCVD", 2146763daaeSJohn Soni Jose "CXN_KILLED_IMM_DATA_RCVD" 2156763daaeSJohn Soni Jose }; 2166763daaeSJohn Soni Jose 2174183122dSJayamohan Kallickal static int beiscsi_eh_abort(struct scsi_cmnd *sc) 2184183122dSJayamohan Kallickal { 219faa0a22dSJitendra Bhivare struct iscsi_task *abrt_task = (struct iscsi_task *)sc->SCp.ptr; 2204183122dSJayamohan Kallickal struct iscsi_cls_session *cls_session; 221faa0a22dSJitendra Bhivare struct beiscsi_io_task *abrt_io_task; 2224183122dSJayamohan Kallickal struct beiscsi_conn *beiscsi_conn; 2234183122dSJayamohan Kallickal struct iscsi_session *session; 224f3505013SJitendra Bhivare struct invldt_cmd_tbl inv_tbl; 225faa0a22dSJitendra Bhivare struct beiscsi_hba *phba; 226faa0a22dSJitendra Bhivare struct iscsi_conn *conn; 2271957aa7fSJayamohan Kallickal int rc; 2284183122dSJayamohan Kallickal 2294183122dSJayamohan Kallickal cls_session = starget_to_session(scsi_target(sc->device)); 2304183122dSJayamohan Kallickal session = cls_session->dd_data; 2314183122dSJayamohan Kallickal 232faa0a22dSJitendra Bhivare /* check if we raced, task just got cleaned up under us */ 233faa0a22dSJitendra Bhivare spin_lock_bh(&session->back_lock); 234faa0a22dSJitendra Bhivare if (!abrt_task || !abrt_task->sc) { 235faa0a22dSJitendra Bhivare spin_unlock_bh(&session->back_lock); 2364183122dSJayamohan Kallickal return SUCCESS; 2374183122dSJayamohan Kallickal } 238faa0a22dSJitendra Bhivare /* get a task ref till FW processes the req for the ICD used */ 239faa0a22dSJitendra Bhivare __iscsi_get_task(abrt_task); 240faa0a22dSJitendra Bhivare abrt_io_task = abrt_task->dd_data; 241faa0a22dSJitendra Bhivare conn = abrt_task->conn; 2424183122dSJayamohan Kallickal beiscsi_conn = conn->dd_data; 2434183122dSJayamohan Kallickal phba = beiscsi_conn->phba; 244faa0a22dSJitendra Bhivare /* mark WRB invalid which have been not processed by FW yet */ 245392b7d2fSJitendra Bhivare if (is_chip_be2_be3r(phba)) { 246f3505013SJitendra Bhivare AMAP_SET_BITS(struct amap_iscsi_wrb, invld, 247faa0a22dSJitendra Bhivare abrt_io_task->pwrb_handle->pwrb, 1); 248392b7d2fSJitendra Bhivare } else { 249392b7d2fSJitendra Bhivare AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld, 250392b7d2fSJitendra Bhivare abrt_io_task->pwrb_handle->pwrb, 1); 251392b7d2fSJitendra Bhivare } 252faa0a22dSJitendra Bhivare inv_tbl.cid = beiscsi_conn->beiscsi_conn_cid; 253faa0a22dSJitendra Bhivare inv_tbl.icd = abrt_io_task->psgl_handle->sgl_index; 254faa0a22dSJitendra Bhivare spin_unlock_bh(&session->back_lock); 255faa0a22dSJitendra Bhivare 25698713216SJitendra Bhivare rc = beiscsi_mgmt_invalidate_icds(phba, &inv_tbl, 1); 257faa0a22dSJitendra Bhivare iscsi_put_task(abrt_task); 25898713216SJitendra Bhivare if (rc) { 25999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, 26098713216SJitendra Bhivare "BM_%d : sc %p invalidation failed %d\n", 26198713216SJitendra Bhivare sc, rc); 2624183122dSJayamohan Kallickal return FAILED; 2634183122dSJayamohan Kallickal } 264e175defeSJohn Soni Jose 2654183122dSJayamohan Kallickal return iscsi_eh_abort(sc); 2664183122dSJayamohan Kallickal } 2674183122dSJayamohan Kallickal 2684183122dSJayamohan Kallickal static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) 2694183122dSJayamohan Kallickal { 27098713216SJitendra Bhivare struct beiscsi_invldt_cmd_tbl { 27198713216SJitendra Bhivare struct invldt_cmd_tbl tbl[BE_INVLDT_CMD_TBL_SZ]; 27298713216SJitendra Bhivare struct iscsi_task *task[BE_INVLDT_CMD_TBL_SZ]; 27398713216SJitendra Bhivare } *inv_tbl; 2744183122dSJayamohan Kallickal struct iscsi_cls_session *cls_session; 27598713216SJitendra Bhivare struct beiscsi_conn *beiscsi_conn; 27698713216SJitendra Bhivare struct beiscsi_io_task *io_task; 27798713216SJitendra Bhivare struct iscsi_session *session; 27898713216SJitendra Bhivare struct beiscsi_hba *phba; 27998713216SJitendra Bhivare struct iscsi_conn *conn; 28098713216SJitendra Bhivare struct iscsi_task *task; 28198713216SJitendra Bhivare unsigned int i, nents; 282f3505013SJitendra Bhivare int rc, more = 0; 2834183122dSJayamohan Kallickal 2844183122dSJayamohan Kallickal cls_session = starget_to_session(scsi_target(sc->device)); 2854183122dSJayamohan Kallickal session = cls_session->dd_data; 28698713216SJitendra Bhivare 287659743b0SShlomo Pongratz spin_lock_bh(&session->frwd_lock); 288db7f7709SJayamohan Kallickal if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) { 289659743b0SShlomo Pongratz spin_unlock_bh(&session->frwd_lock); 290db7f7709SJayamohan Kallickal return FAILED; 291db7f7709SJayamohan Kallickal } 29298713216SJitendra Bhivare 2934183122dSJayamohan Kallickal conn = session->leadconn; 2944183122dSJayamohan Kallickal beiscsi_conn = conn->dd_data; 2954183122dSJayamohan Kallickal phba = beiscsi_conn->phba; 296f3505013SJitendra Bhivare 297f2534736SWei Yongjun inv_tbl = kzalloc(sizeof(*inv_tbl), GFP_ATOMIC); 298f3505013SJitendra Bhivare if (!inv_tbl) { 299f3505013SJitendra Bhivare spin_unlock_bh(&session->frwd_lock); 300f3505013SJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, 301f3505013SJitendra Bhivare "BM_%d : invldt_cmd_tbl alloc failed\n"); 302f3505013SJitendra Bhivare return FAILED; 303f3505013SJitendra Bhivare } 304f3505013SJitendra Bhivare nents = 0; 30598713216SJitendra Bhivare /* take back_lock to prevent task from getting cleaned up under us */ 30698713216SJitendra Bhivare spin_lock(&session->back_lock); 3074183122dSJayamohan Kallickal for (i = 0; i < conn->session->cmds_max; i++) { 30898713216SJitendra Bhivare task = conn->session->cmds[i]; 30998713216SJitendra Bhivare if (!task->sc) 3104183122dSJayamohan Kallickal continue; 3114183122dSJayamohan Kallickal 31298713216SJitendra Bhivare if (sc->device->lun != task->sc->device->lun) 3134183122dSJayamohan Kallickal continue; 314f3505013SJitendra Bhivare /** 315f3505013SJitendra Bhivare * Can't fit in more cmds? Normally this won't happen b'coz 316f3505013SJitendra Bhivare * BEISCSI_CMD_PER_LUN is same as BE_INVLDT_CMD_TBL_SZ. 317f3505013SJitendra Bhivare */ 318f3505013SJitendra Bhivare if (nents == BE_INVLDT_CMD_TBL_SZ) { 319f3505013SJitendra Bhivare more = 1; 320f3505013SJitendra Bhivare break; 321f3505013SJitendra Bhivare } 3224183122dSJayamohan Kallickal 32398713216SJitendra Bhivare /* get a task ref till FW processes the req for the ICD used */ 32498713216SJitendra Bhivare __iscsi_get_task(task); 32598713216SJitendra Bhivare io_task = task->dd_data; 32698713216SJitendra Bhivare /* mark WRB invalid which have been not processed by FW yet */ 327392b7d2fSJitendra Bhivare if (is_chip_be2_be3r(phba)) { 3287626c06bSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, invld, 329392b7d2fSJitendra Bhivare io_task->pwrb_handle->pwrb, 1); 330392b7d2fSJitendra Bhivare } else { 331392b7d2fSJitendra Bhivare AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld, 332392b7d2fSJitendra Bhivare io_task->pwrb_handle->pwrb, 1); 333392b7d2fSJitendra Bhivare } 3347626c06bSJayamohan Kallickal 33598713216SJitendra Bhivare inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid; 33698713216SJitendra Bhivare inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index; 33798713216SJitendra Bhivare inv_tbl->task[nents] = task; 338f3505013SJitendra Bhivare nents++; 3394183122dSJayamohan Kallickal } 340d1e1d63bSJitendra Bhivare spin_unlock(&session->back_lock); 341659743b0SShlomo Pongratz spin_unlock_bh(&session->frwd_lock); 3424183122dSJayamohan Kallickal 34398713216SJitendra Bhivare rc = SUCCESS; 34498713216SJitendra Bhivare if (!nents) 34598713216SJitendra Bhivare goto end_reset; 34698713216SJitendra Bhivare 347f3505013SJitendra Bhivare if (more) { 348f3505013SJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, 349f3505013SJitendra Bhivare "BM_%d : number of cmds exceeds size of invalidation table\n"); 35098713216SJitendra Bhivare rc = FAILED; 35198713216SJitendra Bhivare goto end_reset; 352f3505013SJitendra Bhivare } 353f3505013SJitendra Bhivare 35498713216SJitendra Bhivare if (beiscsi_mgmt_invalidate_icds(phba, &inv_tbl->tbl[0], nents)) { 35599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH, 35698713216SJitendra Bhivare "BM_%d : cid %u scmds invalidation failed\n", 35798713216SJitendra Bhivare beiscsi_conn->beiscsi_conn_cid); 35898713216SJitendra Bhivare rc = FAILED; 3594183122dSJayamohan Kallickal } 360e175defeSJohn Soni Jose 36198713216SJitendra Bhivare end_reset: 36298713216SJitendra Bhivare for (i = 0; i < nents; i++) 36398713216SJitendra Bhivare iscsi_put_task(inv_tbl->task[i]); 36498713216SJitendra Bhivare kfree(inv_tbl); 36598713216SJitendra Bhivare 36698713216SJitendra Bhivare if (rc == SUCCESS) 36798713216SJitendra Bhivare rc = iscsi_eh_device_reset(sc); 36898713216SJitendra Bhivare return rc; 3694183122dSJayamohan Kallickal } 3704183122dSJayamohan Kallickal 371bfead3b2SJayamohan Kallickal /*------------------- PCI Driver operations and data ----------------- */ 3729baa3c34SBenoit Taine static const struct pci_device_id beiscsi_pci_id_table[] = { 373bfead3b2SJayamohan Kallickal { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, 374f98c96b0SJayamohan Kallickal { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, 375bfead3b2SJayamohan Kallickal { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, 376bfead3b2SJayamohan Kallickal { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, 377bfead3b2SJayamohan Kallickal { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, 378139a1b1eSJohn Soni Jose { PCI_DEVICE(ELX_VENDOR_ID, OC_SKH_ID1) }, 379bfead3b2SJayamohan Kallickal { 0 } 380bfead3b2SJayamohan Kallickal }; 381bfead3b2SJayamohan Kallickal MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); 382bfead3b2SJayamohan Kallickal 38399bc5d55SJohn Soni Jose 3846733b39aSJayamohan Kallickal static struct scsi_host_template beiscsi_sht = { 3856733b39aSJayamohan Kallickal .module = THIS_MODULE, 386c4f39bdaSKetan Mukadam .name = "Emulex 10Gbe open-iscsi Initiator Driver", 3876733b39aSJayamohan Kallickal .proc_name = DRV_NAME, 3886733b39aSJayamohan Kallickal .queuecommand = iscsi_queuecommand, 389db5ed4dfSChristoph Hellwig .change_queue_depth = scsi_change_queue_depth, 3906733b39aSJayamohan Kallickal .target_alloc = iscsi_target_alloc, 391b6a05c82SChristoph Hellwig .eh_timed_out = iscsi_eh_cmd_timed_out, 3924183122dSJayamohan Kallickal .eh_abort_handler = beiscsi_eh_abort, 3934183122dSJayamohan Kallickal .eh_device_reset_handler = beiscsi_eh_device_reset, 394309ce156SJayamohan Kallickal .eh_target_reset_handler = iscsi_eh_session_reset, 39599bc5d55SJohn Soni Jose .shost_attrs = beiscsi_attrs, 3966733b39aSJayamohan Kallickal .sg_tablesize = BEISCSI_SGLIST_ELEMENTS, 3976733b39aSJayamohan Kallickal .can_queue = BE2_IO_DEPTH, 3986733b39aSJayamohan Kallickal .this_id = -1, 3996733b39aSJayamohan Kallickal .max_sectors = BEISCSI_MAX_SECTORS, 40050c2e910SChristoph Hellwig .max_segment_size = 65536, 4016733b39aSJayamohan Kallickal .cmd_per_lun = BEISCSI_CMD_PER_LUN, 402ffce3e2eSJayamohan Kallickal .vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID, 403c40ecc12SChristoph Hellwig .track_queue_depth = 1, 4046733b39aSJayamohan Kallickal }; 4056733b39aSJayamohan Kallickal 406bfead3b2SJayamohan Kallickal static struct scsi_transport_template *beiscsi_scsi_transport; 4076733b39aSJayamohan Kallickal 4086733b39aSJayamohan Kallickal static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) 4096733b39aSJayamohan Kallickal { 4106733b39aSJayamohan Kallickal struct beiscsi_hba *phba; 4116733b39aSJayamohan Kallickal struct Scsi_Host *shost; 4126733b39aSJayamohan Kallickal 4136733b39aSJayamohan Kallickal shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0); 4146733b39aSJayamohan Kallickal if (!shost) { 41599bc5d55SJohn Soni Jose dev_err(&pcidev->dev, 41699bc5d55SJohn Soni Jose "beiscsi_hba_alloc - iscsi_host_alloc failed\n"); 4176733b39aSJayamohan Kallickal return NULL; 4186733b39aSJayamohan Kallickal } 4196733b39aSJayamohan Kallickal shost->max_id = BE2_MAX_SESSIONS; 4206733b39aSJayamohan Kallickal shost->max_channel = 0; 4216733b39aSJayamohan Kallickal shost->max_cmd_len = BEISCSI_MAX_CMD_LEN; 4226733b39aSJayamohan Kallickal shost->max_lun = BEISCSI_NUM_MAX_LUN; 4236733b39aSJayamohan Kallickal shost->transportt = beiscsi_scsi_transport; 4246733b39aSJayamohan Kallickal phba = iscsi_host_priv(shost); 4256733b39aSJayamohan Kallickal memset(phba, 0, sizeof(*phba)); 4266733b39aSJayamohan Kallickal phba->shost = shost; 4276733b39aSJayamohan Kallickal phba->pcidev = pci_dev_get(pcidev); 4282807afb7SJayamohan Kallickal pci_set_drvdata(pcidev, phba); 4290e43895eSMike Christie phba->interface_handle = 0xFFFFFFFF; 4306733b39aSJayamohan Kallickal 4316733b39aSJayamohan Kallickal return phba; 4326733b39aSJayamohan Kallickal } 4336733b39aSJayamohan Kallickal 4346733b39aSJayamohan Kallickal static void beiscsi_unmap_pci_function(struct beiscsi_hba *phba) 4356733b39aSJayamohan Kallickal { 4366733b39aSJayamohan Kallickal if (phba->csr_va) { 4376733b39aSJayamohan Kallickal iounmap(phba->csr_va); 4386733b39aSJayamohan Kallickal phba->csr_va = NULL; 4396733b39aSJayamohan Kallickal } 4406733b39aSJayamohan Kallickal if (phba->db_va) { 4416733b39aSJayamohan Kallickal iounmap(phba->db_va); 4426733b39aSJayamohan Kallickal phba->db_va = NULL; 4436733b39aSJayamohan Kallickal } 4446733b39aSJayamohan Kallickal if (phba->pci_va) { 4456733b39aSJayamohan Kallickal iounmap(phba->pci_va); 4466733b39aSJayamohan Kallickal phba->pci_va = NULL; 4476733b39aSJayamohan Kallickal } 4486733b39aSJayamohan Kallickal } 4496733b39aSJayamohan Kallickal 4506733b39aSJayamohan Kallickal static int beiscsi_map_pci_bars(struct beiscsi_hba *phba, 4516733b39aSJayamohan Kallickal struct pci_dev *pcidev) 4526733b39aSJayamohan Kallickal { 4536733b39aSJayamohan Kallickal u8 __iomem *addr; 454f98c96b0SJayamohan Kallickal int pcicfg_reg; 4556733b39aSJayamohan Kallickal 4564bdc0d67SChristoph Hellwig addr = ioremap(pci_resource_start(pcidev, 2), 4576733b39aSJayamohan Kallickal pci_resource_len(pcidev, 2)); 4586733b39aSJayamohan Kallickal if (addr == NULL) 4596733b39aSJayamohan Kallickal return -ENOMEM; 4606733b39aSJayamohan Kallickal phba->ctrl.csr = addr; 4616733b39aSJayamohan Kallickal phba->csr_va = addr; 4626733b39aSJayamohan Kallickal 4634bdc0d67SChristoph Hellwig addr = ioremap(pci_resource_start(pcidev, 4), 128 * 1024); 4646733b39aSJayamohan Kallickal if (addr == NULL) 4656733b39aSJayamohan Kallickal goto pci_map_err; 4666733b39aSJayamohan Kallickal phba->ctrl.db = addr; 4676733b39aSJayamohan Kallickal phba->db_va = addr; 4686733b39aSJayamohan Kallickal 469f98c96b0SJayamohan Kallickal if (phba->generation == BE_GEN2) 470f98c96b0SJayamohan Kallickal pcicfg_reg = 1; 471f98c96b0SJayamohan Kallickal else 472f98c96b0SJayamohan Kallickal pcicfg_reg = 0; 473f98c96b0SJayamohan Kallickal 4744bdc0d67SChristoph Hellwig addr = ioremap(pci_resource_start(pcidev, pcicfg_reg), 475f98c96b0SJayamohan Kallickal pci_resource_len(pcidev, pcicfg_reg)); 476f98c96b0SJayamohan Kallickal 4776733b39aSJayamohan Kallickal if (addr == NULL) 4786733b39aSJayamohan Kallickal goto pci_map_err; 4796733b39aSJayamohan Kallickal phba->ctrl.pcicfg = addr; 4806733b39aSJayamohan Kallickal phba->pci_va = addr; 4816733b39aSJayamohan Kallickal return 0; 4826733b39aSJayamohan Kallickal 4836733b39aSJayamohan Kallickal pci_map_err: 4846733b39aSJayamohan Kallickal beiscsi_unmap_pci_function(phba); 4856733b39aSJayamohan Kallickal return -ENOMEM; 4866733b39aSJayamohan Kallickal } 4876733b39aSJayamohan Kallickal 4886733b39aSJayamohan Kallickal static int beiscsi_enable_pci(struct pci_dev *pcidev) 4896733b39aSJayamohan Kallickal { 4906733b39aSJayamohan Kallickal int ret; 4916733b39aSJayamohan Kallickal 4926733b39aSJayamohan Kallickal ret = pci_enable_device(pcidev); 4936733b39aSJayamohan Kallickal if (ret) { 49499bc5d55SJohn Soni Jose dev_err(&pcidev->dev, 49599bc5d55SJohn Soni Jose "beiscsi_enable_pci - enable device failed\n"); 4966733b39aSJayamohan Kallickal return ret; 4976733b39aSJayamohan Kallickal } 4986733b39aSJayamohan Kallickal 499e307f3acSJohn Soni Jose ret = pci_request_regions(pcidev, DRV_NAME); 500e307f3acSJohn Soni Jose if (ret) { 501e307f3acSJohn Soni Jose dev_err(&pcidev->dev, 502e307f3acSJohn Soni Jose "beiscsi_enable_pci - request region failed\n"); 503e307f3acSJohn Soni Jose goto pci_dev_disable; 504e307f3acSJohn Soni Jose } 505e307f3acSJohn Soni Jose 506bfead3b2SJayamohan Kallickal pci_set_master(pcidev); 50726a4c991SChristoph Hellwig ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64)); 5086c57625bSJayamohan Kallickal if (ret) { 50926a4c991SChristoph Hellwig ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)); 5106733b39aSJayamohan Kallickal if (ret) { 5116733b39aSJayamohan Kallickal dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n"); 512e307f3acSJohn Soni Jose goto pci_region_release; 5136733b39aSJayamohan Kallickal } 5146733b39aSJayamohan Kallickal } 5156733b39aSJayamohan Kallickal return 0; 516e307f3acSJohn Soni Jose 517e307f3acSJohn Soni Jose pci_region_release: 518e307f3acSJohn Soni Jose pci_release_regions(pcidev); 519e307f3acSJohn Soni Jose pci_dev_disable: 520e307f3acSJohn Soni Jose pci_disable_device(pcidev); 521e307f3acSJohn Soni Jose 522e307f3acSJohn Soni Jose return ret; 5236733b39aSJayamohan Kallickal } 5246733b39aSJayamohan Kallickal 5256733b39aSJayamohan Kallickal static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) 5266733b39aSJayamohan Kallickal { 5276733b39aSJayamohan Kallickal struct be_ctrl_info *ctrl = &phba->ctrl; 5286733b39aSJayamohan Kallickal struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; 5296733b39aSJayamohan Kallickal struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; 5306733b39aSJayamohan Kallickal int status = 0; 5316733b39aSJayamohan Kallickal 5326733b39aSJayamohan Kallickal ctrl->pdev = pdev; 5336733b39aSJayamohan Kallickal status = beiscsi_map_pci_bars(phba, pdev); 5346733b39aSJayamohan Kallickal if (status) 5356733b39aSJayamohan Kallickal return status; 5366733b39aSJayamohan Kallickal mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; 53726a4c991SChristoph Hellwig mbox_mem_alloc->va = dma_alloc_coherent(&pdev->dev, 53826a4c991SChristoph Hellwig mbox_mem_alloc->size, &mbox_mem_alloc->dma, GFP_KERNEL); 5396733b39aSJayamohan Kallickal if (!mbox_mem_alloc->va) { 5406733b39aSJayamohan Kallickal beiscsi_unmap_pci_function(phba); 541a49e06d5SJayamohan Kallickal return -ENOMEM; 5426733b39aSJayamohan Kallickal } 5436733b39aSJayamohan Kallickal 5446733b39aSJayamohan Kallickal mbox_mem_align->size = sizeof(struct be_mcc_mailbox); 5456733b39aSJayamohan Kallickal mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); 5466733b39aSJayamohan Kallickal mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); 5476733b39aSJayamohan Kallickal memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); 548c03a50f7SJitendra Bhivare mutex_init(&ctrl->mbox_lock); 549bfead3b2SJayamohan Kallickal spin_lock_init(&phba->ctrl.mcc_lock); 550bfead3b2SJayamohan Kallickal 5516733b39aSJayamohan Kallickal return status; 5526733b39aSJayamohan Kallickal } 5536733b39aSJayamohan Kallickal 554843ae752SJayamohan Kallickal /** 555843ae752SJayamohan Kallickal * beiscsi_get_params()- Set the config paramters 556843ae752SJayamohan Kallickal * @phba: ptr device priv structure 557843ae752SJayamohan Kallickal **/ 5586733b39aSJayamohan Kallickal static void beiscsi_get_params(struct beiscsi_hba *phba) 5596733b39aSJayamohan Kallickal { 560843ae752SJayamohan Kallickal uint32_t total_cid_count = 0; 561843ae752SJayamohan Kallickal uint32_t total_icd_count = 0; 562843ae752SJayamohan Kallickal uint8_t ulp_num = 0; 563843ae752SJayamohan Kallickal 564843ae752SJayamohan Kallickal total_cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) + 565843ae752SJayamohan Kallickal BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1); 566843ae752SJayamohan Kallickal 567cf987b79SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 568cf987b79SJayamohan Kallickal uint32_t align_mask = 0; 569cf987b79SJayamohan Kallickal uint32_t icd_post_per_page = 0; 570cf987b79SJayamohan Kallickal uint32_t icd_count_unavailable = 0; 571cf987b79SJayamohan Kallickal uint32_t icd_start = 0, icd_count = 0; 572cf987b79SJayamohan Kallickal uint32_t icd_start_align = 0, icd_count_align = 0; 573cf987b79SJayamohan Kallickal 574843ae752SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 575cf987b79SJayamohan Kallickal icd_start = phba->fw_config.iscsi_icd_start[ulp_num]; 576cf987b79SJayamohan Kallickal icd_count = phba->fw_config.iscsi_icd_count[ulp_num]; 577cf987b79SJayamohan Kallickal 578cf987b79SJayamohan Kallickal /* Get ICD count that can be posted on each page */ 579cf987b79SJayamohan Kallickal icd_post_per_page = (PAGE_SIZE / (BE2_SGE * 580cf987b79SJayamohan Kallickal sizeof(struct iscsi_sge))); 581cf987b79SJayamohan Kallickal align_mask = (icd_post_per_page - 1); 582cf987b79SJayamohan Kallickal 583cf987b79SJayamohan Kallickal /* Check if icd_start is aligned ICD per page posting */ 584cf987b79SJayamohan Kallickal if (icd_start % icd_post_per_page) { 585cf987b79SJayamohan Kallickal icd_start_align = ((icd_start + 586cf987b79SJayamohan Kallickal icd_post_per_page) & 587cf987b79SJayamohan Kallickal ~(align_mask)); 588cf987b79SJayamohan Kallickal phba->fw_config. 589cf987b79SJayamohan Kallickal iscsi_icd_start[ulp_num] = 590cf987b79SJayamohan Kallickal icd_start_align; 591843ae752SJayamohan Kallickal } 592843ae752SJayamohan Kallickal 593cf987b79SJayamohan Kallickal icd_count_align = (icd_count & ~align_mask); 594cf987b79SJayamohan Kallickal 595cf987b79SJayamohan Kallickal /* ICD discarded in the process of alignment */ 596cf987b79SJayamohan Kallickal if (icd_start_align) 597cf987b79SJayamohan Kallickal icd_count_unavailable = ((icd_start_align - 598cf987b79SJayamohan Kallickal icd_start) + 599cf987b79SJayamohan Kallickal (icd_count - 600cf987b79SJayamohan Kallickal icd_count_align)); 601cf987b79SJayamohan Kallickal 602cf987b79SJayamohan Kallickal /* Updated ICD count available */ 603cf987b79SJayamohan Kallickal phba->fw_config.iscsi_icd_count[ulp_num] = (icd_count - 604cf987b79SJayamohan Kallickal icd_count_unavailable); 605cf987b79SJayamohan Kallickal 606cf987b79SJayamohan Kallickal beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 607cf987b79SJayamohan Kallickal "BM_%d : Aligned ICD values\n" 608cf987b79SJayamohan Kallickal "\t ICD Start : %d\n" 609cf987b79SJayamohan Kallickal "\t ICD Count : %d\n" 610cf987b79SJayamohan Kallickal "\t ICD Discarded : %d\n", 611cf987b79SJayamohan Kallickal phba->fw_config. 612cf987b79SJayamohan Kallickal iscsi_icd_start[ulp_num], 613cf987b79SJayamohan Kallickal phba->fw_config. 614cf987b79SJayamohan Kallickal iscsi_icd_count[ulp_num], 615cf987b79SJayamohan Kallickal icd_count_unavailable); 616cf987b79SJayamohan Kallickal break; 617cf987b79SJayamohan Kallickal } 618cf987b79SJayamohan Kallickal } 619cf987b79SJayamohan Kallickal 620cf987b79SJayamohan Kallickal total_icd_count = phba->fw_config.iscsi_icd_count[ulp_num]; 621843ae752SJayamohan Kallickal phba->params.ios_per_ctrl = (total_icd_count - 622843ae752SJayamohan Kallickal (total_cid_count + 623843ae752SJayamohan Kallickal BE2_TMFS + BE2_NOPOUT_REQ)); 624843ae752SJayamohan Kallickal phba->params.cxns_per_ctrl = total_cid_count; 625843ae752SJayamohan Kallickal phba->params.icds_per_ctrl = total_icd_count; 6266733b39aSJayamohan Kallickal phba->params.num_sge_per_io = BE2_SGE; 6276733b39aSJayamohan Kallickal phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; 6286733b39aSJayamohan Kallickal phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; 629843ae752SJayamohan Kallickal phba->params.num_eq_entries = 1024; 630843ae752SJayamohan Kallickal phba->params.num_cq_entries = 1024; 6316733b39aSJayamohan Kallickal phba->params.wrbs_per_cxn = 256; 6326733b39aSJayamohan Kallickal } 6336733b39aSJayamohan Kallickal 6346733b39aSJayamohan Kallickal static void hwi_ring_eq_db(struct beiscsi_hba *phba, 6356733b39aSJayamohan Kallickal unsigned int id, unsigned int clr_interrupt, 6366733b39aSJayamohan Kallickal unsigned int num_processed, 6376733b39aSJayamohan Kallickal unsigned char rearm, unsigned char event) 6386733b39aSJayamohan Kallickal { 6396733b39aSJayamohan Kallickal u32 val = 0; 640e08b3c8bSJayamohan Kallickal 6416733b39aSJayamohan Kallickal if (rearm) 6426733b39aSJayamohan Kallickal val |= 1 << DB_EQ_REARM_SHIFT; 6436733b39aSJayamohan Kallickal if (clr_interrupt) 6446733b39aSJayamohan Kallickal val |= 1 << DB_EQ_CLR_SHIFT; 6456733b39aSJayamohan Kallickal if (event) 6466733b39aSJayamohan Kallickal val |= 1 << DB_EQ_EVNT_SHIFT; 647e08b3c8bSJayamohan Kallickal 6486733b39aSJayamohan Kallickal val |= num_processed << DB_EQ_NUM_POPPED_SHIFT; 649e08b3c8bSJayamohan Kallickal /* Setting lower order EQ_ID Bits */ 650e08b3c8bSJayamohan Kallickal val |= (id & DB_EQ_RING_ID_LOW_MASK); 651e08b3c8bSJayamohan Kallickal 652e08b3c8bSJayamohan Kallickal /* Setting Higher order EQ_ID Bits */ 653e08b3c8bSJayamohan Kallickal val |= (((id >> DB_EQ_HIGH_FEILD_SHIFT) & 654e08b3c8bSJayamohan Kallickal DB_EQ_RING_ID_HIGH_MASK) 655e08b3c8bSJayamohan Kallickal << DB_EQ_HIGH_SET_SHIFT); 656e08b3c8bSJayamohan Kallickal 6576733b39aSJayamohan Kallickal iowrite32(val, phba->db_va + DB_EQ_OFFSET); 6586733b39aSJayamohan Kallickal } 6596733b39aSJayamohan Kallickal 6606733b39aSJayamohan Kallickal /** 661bfead3b2SJayamohan Kallickal * be_isr_mcc - The isr routine of the driver. 662bfead3b2SJayamohan Kallickal * @irq: Not used 663bfead3b2SJayamohan Kallickal * @dev_id: Pointer to host adapter structure 664bfead3b2SJayamohan Kallickal */ 665bfead3b2SJayamohan Kallickal static irqreturn_t be_isr_mcc(int irq, void *dev_id) 666bfead3b2SJayamohan Kallickal { 667bfead3b2SJayamohan Kallickal struct beiscsi_hba *phba; 668a3095016SJitendra Bhivare struct be_eq_entry *eqe; 669bfead3b2SJayamohan Kallickal struct be_queue_info *eq; 670bfead3b2SJayamohan Kallickal struct be_queue_info *mcc; 671a3095016SJitendra Bhivare unsigned int mcc_events; 672bfead3b2SJayamohan Kallickal struct be_eq_obj *pbe_eq; 673bfead3b2SJayamohan Kallickal 674bfead3b2SJayamohan Kallickal pbe_eq = dev_id; 675bfead3b2SJayamohan Kallickal eq = &pbe_eq->q; 676bfead3b2SJayamohan Kallickal phba = pbe_eq->phba; 677bfead3b2SJayamohan Kallickal mcc = &phba->ctrl.mcc_obj.cq; 678bfead3b2SJayamohan Kallickal eqe = queue_tail_node(eq); 679bfead3b2SJayamohan Kallickal 680a3095016SJitendra Bhivare mcc_events = 0; 681bfead3b2SJayamohan Kallickal while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] 682bfead3b2SJayamohan Kallickal & EQE_VALID_MASK) { 683bfead3b2SJayamohan Kallickal if (((eqe->dw[offsetof(struct amap_eq_entry, 684bfead3b2SJayamohan Kallickal resource_id) / 32] & 685bfead3b2SJayamohan Kallickal EQE_RESID_MASK) >> 16) == mcc->id) { 686a3095016SJitendra Bhivare mcc_events++; 687bfead3b2SJayamohan Kallickal } 688bfead3b2SJayamohan Kallickal AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); 689bfead3b2SJayamohan Kallickal queue_tail_inc(eq); 690bfead3b2SJayamohan Kallickal eqe = queue_tail_node(eq); 691bfead3b2SJayamohan Kallickal } 692bfead3b2SJayamohan Kallickal 693a3095016SJitendra Bhivare if (mcc_events) { 694a3095016SJitendra Bhivare queue_work(phba->wq, &pbe_eq->mcc_work); 695a3095016SJitendra Bhivare hwi_ring_eq_db(phba, eq->id, 1, mcc_events, 1, 1); 696a3095016SJitendra Bhivare } 697bfead3b2SJayamohan Kallickal return IRQ_HANDLED; 698bfead3b2SJayamohan Kallickal } 699bfead3b2SJayamohan Kallickal 700bfead3b2SJayamohan Kallickal /** 701bfead3b2SJayamohan Kallickal * be_isr_msix - The isr routine of the driver. 702bfead3b2SJayamohan Kallickal * @irq: Not used 703bfead3b2SJayamohan Kallickal * @dev_id: Pointer to host adapter structure 704bfead3b2SJayamohan Kallickal */ 705bfead3b2SJayamohan Kallickal static irqreturn_t be_isr_msix(int irq, void *dev_id) 706bfead3b2SJayamohan Kallickal { 707bfead3b2SJayamohan Kallickal struct beiscsi_hba *phba; 708bfead3b2SJayamohan Kallickal struct be_queue_info *eq; 709bfead3b2SJayamohan Kallickal struct be_eq_obj *pbe_eq; 710bfead3b2SJayamohan Kallickal 711bfead3b2SJayamohan Kallickal pbe_eq = dev_id; 712bfead3b2SJayamohan Kallickal eq = &pbe_eq->q; 713bfead3b2SJayamohan Kallickal 714bfead3b2SJayamohan Kallickal phba = pbe_eq->phba; 7151094cf68SJitendra Bhivare /* disable interrupt till iopoll completes */ 7161094cf68SJitendra Bhivare hwi_ring_eq_db(phba, eq->id, 1, 0, 0, 1); 717511cbce2SChristoph Hellwig irq_poll_sched(&pbe_eq->iopoll); 718bfead3b2SJayamohan Kallickal 719bfead3b2SJayamohan Kallickal return IRQ_HANDLED; 720bfead3b2SJayamohan Kallickal } 721bfead3b2SJayamohan Kallickal 722bfead3b2SJayamohan Kallickal /** 7236733b39aSJayamohan Kallickal * be_isr - The isr routine of the driver. 7246733b39aSJayamohan Kallickal * @irq: Not used 7256733b39aSJayamohan Kallickal * @dev_id: Pointer to host adapter structure 7266733b39aSJayamohan Kallickal */ 7276733b39aSJayamohan Kallickal static irqreturn_t be_isr(int irq, void *dev_id) 7286733b39aSJayamohan Kallickal { 7296733b39aSJayamohan Kallickal struct beiscsi_hba *phba; 7306733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 7316733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context; 732a3095016SJitendra Bhivare struct be_eq_entry *eqe; 7336733b39aSJayamohan Kallickal struct be_queue_info *eq; 734bfead3b2SJayamohan Kallickal struct be_queue_info *mcc; 735a3095016SJitendra Bhivare unsigned int mcc_events, io_events; 7366733b39aSJayamohan Kallickal struct be_ctrl_info *ctrl; 737bfead3b2SJayamohan Kallickal struct be_eq_obj *pbe_eq; 738a3095016SJitendra Bhivare int isr, rearm; 7396733b39aSJayamohan Kallickal 7406733b39aSJayamohan Kallickal phba = dev_id; 7416eab04a8SJustin P. Mattock ctrl = &phba->ctrl; 7426733b39aSJayamohan Kallickal isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET + 7436733b39aSJayamohan Kallickal (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE)); 7446733b39aSJayamohan Kallickal if (!isr) 7456733b39aSJayamohan Kallickal return IRQ_NONE; 7466733b39aSJayamohan Kallickal 7476733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 7486733b39aSJayamohan Kallickal phwi_context = phwi_ctrlr->phwi_ctxt; 749bfead3b2SJayamohan Kallickal pbe_eq = &phwi_context->be_eq[0]; 750bfead3b2SJayamohan Kallickal 751bfead3b2SJayamohan Kallickal eq = &phwi_context->be_eq[0].q; 752bfead3b2SJayamohan Kallickal mcc = &phba->ctrl.mcc_obj.cq; 7536733b39aSJayamohan Kallickal eqe = queue_tail_node(eq); 7546733b39aSJayamohan Kallickal 755a3095016SJitendra Bhivare io_events = 0; 756a3095016SJitendra Bhivare mcc_events = 0; 7576733b39aSJayamohan Kallickal while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] 7586733b39aSJayamohan Kallickal & EQE_VALID_MASK) { 759bfead3b2SJayamohan Kallickal if (((eqe->dw[offsetof(struct amap_eq_entry, 760a3095016SJitendra Bhivare resource_id) / 32] & EQE_RESID_MASK) >> 16) == mcc->id) 761a3095016SJitendra Bhivare mcc_events++; 762a3095016SJitendra Bhivare else 763a3095016SJitendra Bhivare io_events++; 7646733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); 7656733b39aSJayamohan Kallickal queue_tail_inc(eq); 7666733b39aSJayamohan Kallickal eqe = queue_tail_node(eq); 7676733b39aSJayamohan Kallickal } 768a3095016SJitendra Bhivare if (!io_events && !mcc_events) 7696733b39aSJayamohan Kallickal return IRQ_NONE; 770a3095016SJitendra Bhivare 771a3095016SJitendra Bhivare /* no need to rearm if interrupt is only for IOs */ 772a3095016SJitendra Bhivare rearm = 0; 773a3095016SJitendra Bhivare if (mcc_events) { 774a3095016SJitendra Bhivare queue_work(phba->wq, &pbe_eq->mcc_work); 775a3095016SJitendra Bhivare /* rearm for MCCQ */ 776a3095016SJitendra Bhivare rearm = 1; 777a3095016SJitendra Bhivare } 778a3095016SJitendra Bhivare if (io_events) 779a3095016SJitendra Bhivare irq_poll_sched(&pbe_eq->iopoll); 780a3095016SJitendra Bhivare hwi_ring_eq_db(phba, eq->id, 0, (io_events + mcc_events), rearm, 1); 781a3095016SJitendra Bhivare return IRQ_HANDLED; 7826733b39aSJayamohan Kallickal } 7836733b39aSJayamohan Kallickal 78445371aa3SJitendra Bhivare static void beiscsi_free_irqs(struct beiscsi_hba *phba) 78545371aa3SJitendra Bhivare { 78645371aa3SJitendra Bhivare struct hwi_context_memory *phwi_context; 78745371aa3SJitendra Bhivare int i; 78845371aa3SJitendra Bhivare 78945371aa3SJitendra Bhivare if (!phba->pcidev->msix_enabled) { 79045371aa3SJitendra Bhivare if (phba->pcidev->irq) 79145371aa3SJitendra Bhivare free_irq(phba->pcidev->irq, phba); 79245371aa3SJitendra Bhivare return; 79345371aa3SJitendra Bhivare } 79445371aa3SJitendra Bhivare 79545371aa3SJitendra Bhivare phwi_context = phba->phwi_ctrlr->phwi_ctxt; 79645371aa3SJitendra Bhivare for (i = 0; i <= phba->num_cpus; i++) { 79745371aa3SJitendra Bhivare free_irq(pci_irq_vector(phba->pcidev, i), 79845371aa3SJitendra Bhivare &phwi_context->be_eq[i]); 79945371aa3SJitendra Bhivare kfree(phba->msi_name[i]); 80045371aa3SJitendra Bhivare } 80145371aa3SJitendra Bhivare } 8021094cf68SJitendra Bhivare 8036733b39aSJayamohan Kallickal static int beiscsi_init_irqs(struct beiscsi_hba *phba) 8046733b39aSJayamohan Kallickal { 8056733b39aSJayamohan Kallickal struct pci_dev *pcidev = phba->pcidev; 806bfead3b2SJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 807bfead3b2SJayamohan Kallickal struct hwi_context_memory *phwi_context; 80883148866SChristoph Hellwig int ret, i, j; 8096733b39aSJayamohan Kallickal 810bfead3b2SJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 811bfead3b2SJayamohan Kallickal phwi_context = phwi_ctrlr->phwi_ctxt; 812bfead3b2SJayamohan Kallickal 81383148866SChristoph Hellwig if (pcidev->msix_enabled) { 814bfead3b2SJayamohan Kallickal for (i = 0; i < phba->num_cpus; i++) { 815d38c9a80SHimanshu Jha phba->msi_name[i] = kasprintf(GFP_KERNEL, 816d38c9a80SHimanshu Jha "beiscsi_%02x_%02x", 817d38c9a80SHimanshu Jha phba->shost->host_no, i); 8188fcfb210SJayamohan Kallickal if (!phba->msi_name[i]) { 8198fcfb210SJayamohan Kallickal ret = -ENOMEM; 8208fcfb210SJayamohan Kallickal goto free_msix_irqs; 8218fcfb210SJayamohan Kallickal } 8228fcfb210SJayamohan Kallickal 82383148866SChristoph Hellwig ret = request_irq(pci_irq_vector(pcidev, i), 82483148866SChristoph Hellwig be_isr_msix, 0, phba->msi_name[i], 825bfead3b2SJayamohan Kallickal &phwi_context->be_eq[i]); 8264f5af07eSJayamohan Kallickal if (ret) { 82799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 82899bc5d55SJohn Soni Jose "BM_%d : beiscsi_init_irqs-Failed to" 82999bc5d55SJohn Soni Jose "register msix for i = %d\n", 83099bc5d55SJohn Soni Jose i); 8318fcfb210SJayamohan Kallickal kfree(phba->msi_name[i]); 8324f5af07eSJayamohan Kallickal goto free_msix_irqs; 8334f5af07eSJayamohan Kallickal } 834bfead3b2SJayamohan Kallickal } 835d38c9a80SHimanshu Jha phba->msi_name[i] = kasprintf(GFP_KERNEL, "beiscsi_mcc_%02x", 836d38c9a80SHimanshu Jha phba->shost->host_no); 8378fcfb210SJayamohan Kallickal if (!phba->msi_name[i]) { 8388fcfb210SJayamohan Kallickal ret = -ENOMEM; 8398fcfb210SJayamohan Kallickal goto free_msix_irqs; 8408fcfb210SJayamohan Kallickal } 84183148866SChristoph Hellwig ret = request_irq(pci_irq_vector(pcidev, i), be_isr_mcc, 0, 84283148866SChristoph Hellwig phba->msi_name[i], &phwi_context->be_eq[i]); 8434f5af07eSJayamohan Kallickal if (ret) { 84499bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT , 84599bc5d55SJohn Soni Jose "BM_%d : beiscsi_init_irqs-" 8464f5af07eSJayamohan Kallickal "Failed to register beiscsi_msix_mcc\n"); 8478fcfb210SJayamohan Kallickal kfree(phba->msi_name[i]); 8484f5af07eSJayamohan Kallickal goto free_msix_irqs; 8494f5af07eSJayamohan Kallickal } 8504f5af07eSJayamohan Kallickal 851bfead3b2SJayamohan Kallickal } else { 852bfead3b2SJayamohan Kallickal ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, 853bfead3b2SJayamohan Kallickal "beiscsi", phba); 8546733b39aSJayamohan Kallickal if (ret) { 85599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 85699bc5d55SJohn Soni Jose "BM_%d : beiscsi_init_irqs-" 8576733b39aSJayamohan Kallickal "Failed to register irq\\n"); 8586733b39aSJayamohan Kallickal return ret; 8596733b39aSJayamohan Kallickal } 860bfead3b2SJayamohan Kallickal } 8616733b39aSJayamohan Kallickal return 0; 8624f5af07eSJayamohan Kallickal free_msix_irqs: 8638fcfb210SJayamohan Kallickal for (j = i - 1; j >= 0; j--) { 86483148866SChristoph Hellwig free_irq(pci_irq_vector(pcidev, i), &phwi_context->be_eq[j]); 8658fcfb210SJayamohan Kallickal kfree(phba->msi_name[j]); 8668fcfb210SJayamohan Kallickal } 8674f5af07eSJayamohan Kallickal return ret; 8686733b39aSJayamohan Kallickal } 8696733b39aSJayamohan Kallickal 870e08b3c8bSJayamohan Kallickal void hwi_ring_cq_db(struct beiscsi_hba *phba, 8716733b39aSJayamohan Kallickal unsigned int id, unsigned int num_processed, 8721094cf68SJitendra Bhivare unsigned char rearm) 8736733b39aSJayamohan Kallickal { 8746733b39aSJayamohan Kallickal u32 val = 0; 875e08b3c8bSJayamohan Kallickal 8766733b39aSJayamohan Kallickal if (rearm) 8776733b39aSJayamohan Kallickal val |= 1 << DB_CQ_REARM_SHIFT; 878e08b3c8bSJayamohan Kallickal 8796733b39aSJayamohan Kallickal val |= num_processed << DB_CQ_NUM_POPPED_SHIFT; 880e08b3c8bSJayamohan Kallickal 881e08b3c8bSJayamohan Kallickal /* Setting lower order CQ_ID Bits */ 882e08b3c8bSJayamohan Kallickal val |= (id & DB_CQ_RING_ID_LOW_MASK); 883e08b3c8bSJayamohan Kallickal 884e08b3c8bSJayamohan Kallickal /* Setting Higher order CQ_ID Bits */ 885e08b3c8bSJayamohan Kallickal val |= (((id >> DB_CQ_HIGH_FEILD_SHIFT) & 886e08b3c8bSJayamohan Kallickal DB_CQ_RING_ID_HIGH_MASK) 887e08b3c8bSJayamohan Kallickal << DB_CQ_HIGH_SET_SHIFT); 888e08b3c8bSJayamohan Kallickal 8896733b39aSJayamohan Kallickal iowrite32(val, phba->db_va + DB_CQ_OFFSET); 8906733b39aSJayamohan Kallickal } 8916733b39aSJayamohan Kallickal 8926733b39aSJayamohan Kallickal static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) 8936733b39aSJayamohan Kallickal { 8946733b39aSJayamohan Kallickal struct sgl_handle *psgl_handle; 8957d2c0d64SJitendra Bhivare unsigned long flags; 8966733b39aSJayamohan Kallickal 8977d2c0d64SJitendra Bhivare spin_lock_irqsave(&phba->io_sgl_lock, flags); 8986733b39aSJayamohan Kallickal if (phba->io_sgl_hndl_avbl) { 89999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO, 90099bc5d55SJohn Soni Jose "BM_%d : In alloc_io_sgl_handle," 90199bc5d55SJohn Soni Jose " io_sgl_alloc_index=%d\n", 9026733b39aSJayamohan Kallickal phba->io_sgl_alloc_index); 90399bc5d55SJohn Soni Jose 9046733b39aSJayamohan Kallickal psgl_handle = phba->io_sgl_hndl_base[phba-> 9056733b39aSJayamohan Kallickal io_sgl_alloc_index]; 9066733b39aSJayamohan Kallickal phba->io_sgl_hndl_base[phba->io_sgl_alloc_index] = NULL; 9076733b39aSJayamohan Kallickal phba->io_sgl_hndl_avbl--; 908bfead3b2SJayamohan Kallickal if (phba->io_sgl_alloc_index == (phba->params. 909bfead3b2SJayamohan Kallickal ios_per_ctrl - 1)) 9106733b39aSJayamohan Kallickal phba->io_sgl_alloc_index = 0; 9116733b39aSJayamohan Kallickal else 9126733b39aSJayamohan Kallickal phba->io_sgl_alloc_index++; 9136733b39aSJayamohan Kallickal } else 9146733b39aSJayamohan Kallickal psgl_handle = NULL; 9157d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&phba->io_sgl_lock, flags); 9166733b39aSJayamohan Kallickal return psgl_handle; 9176733b39aSJayamohan Kallickal } 9186733b39aSJayamohan Kallickal 9196733b39aSJayamohan Kallickal static void 9206733b39aSJayamohan Kallickal free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) 9216733b39aSJayamohan Kallickal { 9227d2c0d64SJitendra Bhivare unsigned long flags; 9237d2c0d64SJitendra Bhivare 9247d2c0d64SJitendra Bhivare spin_lock_irqsave(&phba->io_sgl_lock, flags); 92599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO, 92699bc5d55SJohn Soni Jose "BM_%d : In free_,io_sgl_free_index=%d\n", 9276733b39aSJayamohan Kallickal phba->io_sgl_free_index); 92899bc5d55SJohn Soni Jose 9296733b39aSJayamohan Kallickal if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) { 9306733b39aSJayamohan Kallickal /* 9316733b39aSJayamohan Kallickal * this can happen if clean_task is called on a task that 9326733b39aSJayamohan Kallickal * failed in xmit_task or alloc_pdu. 9336733b39aSJayamohan Kallickal */ 93499bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO, 93545efc940SJitendra Bhivare "BM_%d : Double Free in IO SGL io_sgl_free_index=%d, value there=%p\n", 93645efc940SJitendra Bhivare phba->io_sgl_free_index, 93745efc940SJitendra Bhivare phba->io_sgl_hndl_base[phba->io_sgl_free_index]); 9387d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&phba->io_sgl_lock, flags); 9396733b39aSJayamohan Kallickal return; 9406733b39aSJayamohan Kallickal } 9416733b39aSJayamohan Kallickal phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle; 9426733b39aSJayamohan Kallickal phba->io_sgl_hndl_avbl++; 9436733b39aSJayamohan Kallickal if (phba->io_sgl_free_index == (phba->params.ios_per_ctrl - 1)) 9446733b39aSJayamohan Kallickal phba->io_sgl_free_index = 0; 9456733b39aSJayamohan Kallickal else 9466733b39aSJayamohan Kallickal phba->io_sgl_free_index++; 9477d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&phba->io_sgl_lock, flags); 9486733b39aSJayamohan Kallickal } 9496733b39aSJayamohan Kallickal 950cb564c6bSJitendra Bhivare static inline struct wrb_handle * 951cb564c6bSJitendra Bhivare beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context, 952cb564c6bSJitendra Bhivare unsigned int wrbs_per_cxn) 953cb564c6bSJitendra Bhivare { 954cb564c6bSJitendra Bhivare struct wrb_handle *pwrb_handle; 9557d2c0d64SJitendra Bhivare unsigned long flags; 956cb564c6bSJitendra Bhivare 9577d2c0d64SJitendra Bhivare spin_lock_irqsave(&pwrb_context->wrb_lock, flags); 9583f7f62eeSJitendra Bhivare if (!pwrb_context->wrb_handles_available) { 9593f7f62eeSJitendra Bhivare spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); 9603f7f62eeSJitendra Bhivare return NULL; 9613f7f62eeSJitendra Bhivare } 962cb564c6bSJitendra Bhivare pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index]; 963cb564c6bSJitendra Bhivare pwrb_context->wrb_handles_available--; 964cb564c6bSJitendra Bhivare if (pwrb_context->alloc_index == (wrbs_per_cxn - 1)) 965cb564c6bSJitendra Bhivare pwrb_context->alloc_index = 0; 966cb564c6bSJitendra Bhivare else 967cb564c6bSJitendra Bhivare pwrb_context->alloc_index++; 9687d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); 969bf9b7554SJitendra Bhivare 970bf9b7554SJitendra Bhivare if (pwrb_handle) 971e1f9d31eSJitendra Bhivare memset(pwrb_handle->pwrb, 0, sizeof(*pwrb_handle->pwrb)); 972cb564c6bSJitendra Bhivare 973cb564c6bSJitendra Bhivare return pwrb_handle; 974cb564c6bSJitendra Bhivare } 975cb564c6bSJitendra Bhivare 9766733b39aSJayamohan Kallickal /** 9776733b39aSJayamohan Kallickal * alloc_wrb_handle - To allocate a wrb handle 9786733b39aSJayamohan Kallickal * @phba: The hba pointer 9796733b39aSJayamohan Kallickal * @cid: The cid to use for allocation 980dbc019a4SLee Jones * @pcontext: ptr to ptr to wrb context 9816733b39aSJayamohan Kallickal * 9826733b39aSJayamohan Kallickal * This happens under session_lock until submission to chip 9836733b39aSJayamohan Kallickal */ 984340c99e9SJohn Soni Jose struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, 985340c99e9SJohn Soni Jose struct hwi_wrb_context **pcontext) 9866733b39aSJayamohan Kallickal { 9876733b39aSJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 9886733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 989a7909b39SJayamohan Kallickal uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); 9906733b39aSJayamohan Kallickal 9916733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 992a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; 993cb564c6bSJitendra Bhivare /* return the context address */ 994340c99e9SJohn Soni Jose *pcontext = pwrb_context; 995cb564c6bSJitendra Bhivare return beiscsi_get_wrb_handle(pwrb_context, phba->params.wrbs_per_cxn); 996cb564c6bSJitendra Bhivare } 997cb564c6bSJitendra Bhivare 998cb564c6bSJitendra Bhivare static inline void 999cb564c6bSJitendra Bhivare beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context, 1000cb564c6bSJitendra Bhivare struct wrb_handle *pwrb_handle, 1001cb564c6bSJitendra Bhivare unsigned int wrbs_per_cxn) 1002cb564c6bSJitendra Bhivare { 10037d2c0d64SJitendra Bhivare unsigned long flags; 10047d2c0d64SJitendra Bhivare 10057d2c0d64SJitendra Bhivare spin_lock_irqsave(&pwrb_context->wrb_lock, flags); 1006cb564c6bSJitendra Bhivare pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle; 1007cb564c6bSJitendra Bhivare pwrb_context->wrb_handles_available++; 1008cb564c6bSJitendra Bhivare if (pwrb_context->free_index == (wrbs_per_cxn - 1)) 1009cb564c6bSJitendra Bhivare pwrb_context->free_index = 0; 1010cb564c6bSJitendra Bhivare else 1011cb564c6bSJitendra Bhivare pwrb_context->free_index++; 10123f7f62eeSJitendra Bhivare pwrb_handle->pio_handle = NULL; 10137d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags); 10146733b39aSJayamohan Kallickal } 10156733b39aSJayamohan Kallickal 10166733b39aSJayamohan Kallickal /** 10176733b39aSJayamohan Kallickal * free_wrb_handle - To free the wrb handle back to pool 10186733b39aSJayamohan Kallickal * @phba: The hba pointer 10196733b39aSJayamohan Kallickal * @pwrb_context: The context to free from 10206733b39aSJayamohan Kallickal * @pwrb_handle: The wrb_handle to free 10216733b39aSJayamohan Kallickal * 10226733b39aSJayamohan Kallickal * This happens under session_lock until submission to chip 10236733b39aSJayamohan Kallickal */ 10246733b39aSJayamohan Kallickal static void 10256733b39aSJayamohan Kallickal free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, 10266733b39aSJayamohan Kallickal struct wrb_handle *pwrb_handle) 10276733b39aSJayamohan Kallickal { 1028cb564c6bSJitendra Bhivare beiscsi_put_wrb_handle(pwrb_context, 1029cb564c6bSJitendra Bhivare pwrb_handle, 1030cb564c6bSJitendra Bhivare phba->params.wrbs_per_cxn); 103199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, 103299bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 103399bc5d55SJohn Soni Jose "BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x" 10346733b39aSJayamohan Kallickal "wrb_handles_available=%d\n", 10356733b39aSJayamohan Kallickal pwrb_handle, pwrb_context->free_index, 1036bfead3b2SJayamohan Kallickal pwrb_context->wrb_handles_available); 10376733b39aSJayamohan Kallickal } 10386733b39aSJayamohan Kallickal 10396733b39aSJayamohan Kallickal static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba) 10406733b39aSJayamohan Kallickal { 10416733b39aSJayamohan Kallickal struct sgl_handle *psgl_handle; 10427d2c0d64SJitendra Bhivare unsigned long flags; 10436733b39aSJayamohan Kallickal 10447d2c0d64SJitendra Bhivare spin_lock_irqsave(&phba->mgmt_sgl_lock, flags); 10456733b39aSJayamohan Kallickal if (phba->eh_sgl_hndl_avbl) { 10466733b39aSJayamohan Kallickal psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index]; 10476733b39aSJayamohan Kallickal phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL; 104899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, 104999bc5d55SJohn Soni Jose "BM_%d : mgmt_sgl_alloc_index=%d=0x%x\n", 105099bc5d55SJohn Soni Jose phba->eh_sgl_alloc_index, 105199bc5d55SJohn Soni Jose phba->eh_sgl_alloc_index); 105299bc5d55SJohn Soni Jose 10536733b39aSJayamohan Kallickal phba->eh_sgl_hndl_avbl--; 10546733b39aSJayamohan Kallickal if (phba->eh_sgl_alloc_index == 10556733b39aSJayamohan Kallickal (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - 10566733b39aSJayamohan Kallickal 1)) 10576733b39aSJayamohan Kallickal phba->eh_sgl_alloc_index = 0; 10586733b39aSJayamohan Kallickal else 10596733b39aSJayamohan Kallickal phba->eh_sgl_alloc_index++; 10606733b39aSJayamohan Kallickal } else 10616733b39aSJayamohan Kallickal psgl_handle = NULL; 10627d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags); 10636733b39aSJayamohan Kallickal return psgl_handle; 10646733b39aSJayamohan Kallickal } 10656733b39aSJayamohan Kallickal 10666733b39aSJayamohan Kallickal void 10676733b39aSJayamohan Kallickal free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) 10686733b39aSJayamohan Kallickal { 10697d2c0d64SJitendra Bhivare unsigned long flags; 10707d2c0d64SJitendra Bhivare 10717d2c0d64SJitendra Bhivare spin_lock_irqsave(&phba->mgmt_sgl_lock, flags); 107299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, 107399bc5d55SJohn Soni Jose "BM_%d : In free_mgmt_sgl_handle," 107499bc5d55SJohn Soni Jose "eh_sgl_free_index=%d\n", 1075bfead3b2SJayamohan Kallickal phba->eh_sgl_free_index); 107699bc5d55SJohn Soni Jose 10776733b39aSJayamohan Kallickal if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) { 10786733b39aSJayamohan Kallickal /* 10796733b39aSJayamohan Kallickal * this can happen if clean_task is called on a task that 10806733b39aSJayamohan Kallickal * failed in xmit_task or alloc_pdu. 10816733b39aSJayamohan Kallickal */ 108299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, 108399bc5d55SJohn Soni Jose "BM_%d : Double Free in eh SGL ," 108499bc5d55SJohn Soni Jose "eh_sgl_free_index=%d\n", 10856733b39aSJayamohan Kallickal phba->eh_sgl_free_index); 10867d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags); 10876733b39aSJayamohan Kallickal return; 10886733b39aSJayamohan Kallickal } 10896733b39aSJayamohan Kallickal phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle; 10906733b39aSJayamohan Kallickal phba->eh_sgl_hndl_avbl++; 10916733b39aSJayamohan Kallickal if (phba->eh_sgl_free_index == 10926733b39aSJayamohan Kallickal (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - 1)) 10936733b39aSJayamohan Kallickal phba->eh_sgl_free_index = 0; 10946733b39aSJayamohan Kallickal else 10956733b39aSJayamohan Kallickal phba->eh_sgl_free_index++; 10967d2c0d64SJitendra Bhivare spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags); 10976733b39aSJayamohan Kallickal } 10986733b39aSJayamohan Kallickal 10996733b39aSJayamohan Kallickal static void 11006733b39aSJayamohan Kallickal be_complete_io(struct beiscsi_conn *beiscsi_conn, 110173133261SJohn Soni Jose struct iscsi_task *task, 110273133261SJohn Soni Jose struct common_sol_cqe *csol_cqe) 11036733b39aSJayamohan Kallickal { 11046733b39aSJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 11056733b39aSJayamohan Kallickal struct be_status_bhs *sts_bhs = 11066733b39aSJayamohan Kallickal (struct be_status_bhs *)io_task->cmd_bhs; 11076733b39aSJayamohan Kallickal struct iscsi_conn *conn = beiscsi_conn->conn; 11086733b39aSJayamohan Kallickal unsigned char *sense; 11096733b39aSJayamohan Kallickal u32 resid = 0, exp_cmdsn, max_cmdsn; 11106733b39aSJayamohan Kallickal u8 rsp, status, flags; 11116733b39aSJayamohan Kallickal 111273133261SJohn Soni Jose exp_cmdsn = csol_cqe->exp_cmdsn; 111373133261SJohn Soni Jose max_cmdsn = (csol_cqe->exp_cmdsn + 111473133261SJohn Soni Jose csol_cqe->cmd_wnd - 1); 111573133261SJohn Soni Jose rsp = csol_cqe->i_resp; 111673133261SJohn Soni Jose status = csol_cqe->i_sts; 111773133261SJohn Soni Jose flags = csol_cqe->i_flags; 111873133261SJohn Soni Jose resid = csol_cqe->res_cnt; 111973133261SJohn Soni Jose 1120bd535451SJayamohan Kallickal if (!task->sc) { 1121da334977SJayamohan Kallickal if (io_task->scsi_cmnd) { 1122bd535451SJayamohan Kallickal scsi_dma_unmap(io_task->scsi_cmnd); 1123da334977SJayamohan Kallickal io_task->scsi_cmnd = NULL; 1124da334977SJayamohan Kallickal } 11256733b39aSJayamohan Kallickal 1126bd535451SJayamohan Kallickal return; 1127bd535451SJayamohan Kallickal } 11286733b39aSJayamohan Kallickal task->sc->result = (DID_OK << 16) | status; 11296733b39aSJayamohan Kallickal if (rsp != ISCSI_STATUS_CMD_COMPLETED) { 11306733b39aSJayamohan Kallickal task->sc->result = DID_ERROR << 16; 11316733b39aSJayamohan Kallickal goto unmap; 11326733b39aSJayamohan Kallickal } 11336733b39aSJayamohan Kallickal 11346733b39aSJayamohan Kallickal /* bidi not initially supported */ 11356733b39aSJayamohan Kallickal if (flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) { 11366733b39aSJayamohan Kallickal if (!status && (flags & ISCSI_FLAG_CMD_OVERFLOW)) 11376733b39aSJayamohan Kallickal task->sc->result = DID_ERROR << 16; 11386733b39aSJayamohan Kallickal 11396733b39aSJayamohan Kallickal if (flags & ISCSI_FLAG_CMD_UNDERFLOW) { 11406733b39aSJayamohan Kallickal scsi_set_resid(task->sc, resid); 11416733b39aSJayamohan Kallickal if (!status && (scsi_bufflen(task->sc) - resid < 11426733b39aSJayamohan Kallickal task->sc->underflow)) 11436733b39aSJayamohan Kallickal task->sc->result = DID_ERROR << 16; 11446733b39aSJayamohan Kallickal } 11456733b39aSJayamohan Kallickal } 11466733b39aSJayamohan Kallickal 11476733b39aSJayamohan Kallickal if (status == SAM_STAT_CHECK_CONDITION) { 11484053a4beSDan Carpenter u16 sense_len; 1149bfead3b2SJayamohan Kallickal unsigned short *slen = (unsigned short *)sts_bhs->sense_info; 11504053a4beSDan Carpenter 11516733b39aSJayamohan Kallickal sense = sts_bhs->sense_info + sizeof(unsigned short); 11524053a4beSDan Carpenter sense_len = be16_to_cpu(*slen); 11536733b39aSJayamohan Kallickal memcpy(task->sc->sense_buffer, sense, 11546733b39aSJayamohan Kallickal min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); 11556733b39aSJayamohan Kallickal } 1156756d29c8SJayamohan Kallickal 115773133261SJohn Soni Jose if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) 115873133261SJohn Soni Jose conn->rxdata_octets += resid; 11596733b39aSJayamohan Kallickal unmap: 1160eb1c4692SJohn Soni Jose if (io_task->scsi_cmnd) { 11616733b39aSJayamohan Kallickal scsi_dma_unmap(io_task->scsi_cmnd); 1162da334977SJayamohan Kallickal io_task->scsi_cmnd = NULL; 1163eb1c4692SJohn Soni Jose } 11646733b39aSJayamohan Kallickal iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn); 11656733b39aSJayamohan Kallickal } 11666733b39aSJayamohan Kallickal 11676733b39aSJayamohan Kallickal static void 11686733b39aSJayamohan Kallickal be_complete_logout(struct beiscsi_conn *beiscsi_conn, 116973133261SJohn Soni Jose struct iscsi_task *task, 117073133261SJohn Soni Jose struct common_sol_cqe *csol_cqe) 11716733b39aSJayamohan Kallickal { 11726733b39aSJayamohan Kallickal struct iscsi_logout_rsp *hdr; 1173bfead3b2SJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 11746733b39aSJayamohan Kallickal struct iscsi_conn *conn = beiscsi_conn->conn; 11756733b39aSJayamohan Kallickal 11766733b39aSJayamohan Kallickal hdr = (struct iscsi_logout_rsp *)task->hdr; 11777bd6e25cSJayamohan Kallickal hdr->opcode = ISCSI_OP_LOGOUT_RSP; 11786733b39aSJayamohan Kallickal hdr->t2wait = 5; 11796733b39aSJayamohan Kallickal hdr->t2retain = 0; 118073133261SJohn Soni Jose hdr->flags = csol_cqe->i_flags; 118173133261SJohn Soni Jose hdr->response = csol_cqe->i_resp; 1182702dc5e8SJayamohan Kallickal hdr->exp_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn); 1183702dc5e8SJayamohan Kallickal hdr->max_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn + 1184702dc5e8SJayamohan Kallickal csol_cqe->cmd_wnd - 1); 118573133261SJohn Soni Jose 11867bd6e25cSJayamohan Kallickal hdr->dlength[0] = 0; 11877bd6e25cSJayamohan Kallickal hdr->dlength[1] = 0; 11887bd6e25cSJayamohan Kallickal hdr->dlength[2] = 0; 11896733b39aSJayamohan Kallickal hdr->hlength = 0; 1190bfead3b2SJayamohan Kallickal hdr->itt = io_task->libiscsi_itt; 11916733b39aSJayamohan Kallickal __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); 11926733b39aSJayamohan Kallickal } 11936733b39aSJayamohan Kallickal 11946733b39aSJayamohan Kallickal static void 11956733b39aSJayamohan Kallickal be_complete_tmf(struct beiscsi_conn *beiscsi_conn, 119673133261SJohn Soni Jose struct iscsi_task *task, 119773133261SJohn Soni Jose struct common_sol_cqe *csol_cqe) 11986733b39aSJayamohan Kallickal { 11996733b39aSJayamohan Kallickal struct iscsi_tm_rsp *hdr; 12006733b39aSJayamohan Kallickal struct iscsi_conn *conn = beiscsi_conn->conn; 1201bfead3b2SJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 12026733b39aSJayamohan Kallickal 12036733b39aSJayamohan Kallickal hdr = (struct iscsi_tm_rsp *)task->hdr; 12047bd6e25cSJayamohan Kallickal hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; 120573133261SJohn Soni Jose hdr->flags = csol_cqe->i_flags; 120673133261SJohn Soni Jose hdr->response = csol_cqe->i_resp; 1207702dc5e8SJayamohan Kallickal hdr->exp_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn); 1208702dc5e8SJayamohan Kallickal hdr->max_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn + 120973133261SJohn Soni Jose csol_cqe->cmd_wnd - 1); 121073133261SJohn Soni Jose 1211bfead3b2SJayamohan Kallickal hdr->itt = io_task->libiscsi_itt; 12126733b39aSJayamohan Kallickal __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); 12136733b39aSJayamohan Kallickal } 12146733b39aSJayamohan Kallickal 12156733b39aSJayamohan Kallickal static void 12166733b39aSJayamohan Kallickal hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, 12176733b39aSJayamohan Kallickal struct beiscsi_hba *phba, struct sol_cqe *psol) 12186733b39aSJayamohan Kallickal { 12196733b39aSJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 1220a7909b39SJayamohan Kallickal uint16_t wrb_index, cid, cri_index; 1221e1f9d31eSJitendra Bhivare struct hwi_controller *phwi_ctrlr; 1222e1f9d31eSJitendra Bhivare struct wrb_handle *pwrb_handle; 12233f7f62eeSJitendra Bhivare struct iscsi_session *session; 1224e1f9d31eSJitendra Bhivare struct iscsi_task *task; 12256733b39aSJayamohan Kallickal 12266733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 12272c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) { 122873133261SJohn Soni Jose wrb_index = AMAP_GET_BITS(struct amap_it_dmsg_cqe, 122973133261SJohn Soni Jose wrb_idx, psol); 123073133261SJohn Soni Jose cid = AMAP_GET_BITS(struct amap_it_dmsg_cqe, 123173133261SJohn Soni Jose cid, psol); 12322c9dfd36SJayamohan Kallickal } else { 12332c9dfd36SJayamohan Kallickal wrb_index = AMAP_GET_BITS(struct amap_it_dmsg_cqe_v2, 12342c9dfd36SJayamohan Kallickal wrb_idx, psol); 12352c9dfd36SJayamohan Kallickal cid = AMAP_GET_BITS(struct amap_it_dmsg_cqe_v2, 12362c9dfd36SJayamohan Kallickal cid, psol); 123773133261SJohn Soni Jose } 123873133261SJohn Soni Jose 1239a7909b39SJayamohan Kallickal cri_index = BE_GET_CRI_FROM_CID(cid); 1240a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; 124173133261SJohn Soni Jose pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index]; 12423f7f62eeSJitendra Bhivare session = beiscsi_conn->conn->session; 12433f7f62eeSJitendra Bhivare spin_lock_bh(&session->back_lock); 1244bfead3b2SJayamohan Kallickal task = pwrb_handle->pio_handle; 12453f7f62eeSJitendra Bhivare if (task) 12463f7f62eeSJitendra Bhivare __iscsi_put_task(task); 12473f7f62eeSJitendra Bhivare spin_unlock_bh(&session->back_lock); 12486733b39aSJayamohan Kallickal } 12496733b39aSJayamohan Kallickal 12506733b39aSJayamohan Kallickal static void 12516733b39aSJayamohan Kallickal be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn, 125273133261SJohn Soni Jose struct iscsi_task *task, 125373133261SJohn Soni Jose struct common_sol_cqe *csol_cqe) 12546733b39aSJayamohan Kallickal { 12556733b39aSJayamohan Kallickal struct iscsi_nopin *hdr; 12566733b39aSJayamohan Kallickal struct iscsi_conn *conn = beiscsi_conn->conn; 1257bfead3b2SJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 12586733b39aSJayamohan Kallickal 12596733b39aSJayamohan Kallickal hdr = (struct iscsi_nopin *)task->hdr; 126073133261SJohn Soni Jose hdr->flags = csol_cqe->i_flags; 126173133261SJohn Soni Jose hdr->exp_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn); 1262702dc5e8SJayamohan Kallickal hdr->max_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn + 126373133261SJohn Soni Jose csol_cqe->cmd_wnd - 1); 126473133261SJohn Soni Jose 12656733b39aSJayamohan Kallickal hdr->opcode = ISCSI_OP_NOOP_IN; 1266bfead3b2SJayamohan Kallickal hdr->itt = io_task->libiscsi_itt; 12676733b39aSJayamohan Kallickal __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); 12686733b39aSJayamohan Kallickal } 12696733b39aSJayamohan Kallickal 127073133261SJohn Soni Jose static void adapter_get_sol_cqe(struct beiscsi_hba *phba, 127173133261SJohn Soni Jose struct sol_cqe *psol, 127273133261SJohn Soni Jose struct common_sol_cqe *csol_cqe) 127373133261SJohn Soni Jose { 12742c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) { 12752c9dfd36SJayamohan Kallickal csol_cqe->exp_cmdsn = AMAP_GET_BITS(struct amap_sol_cqe, 12762c9dfd36SJayamohan Kallickal i_exp_cmd_sn, psol); 12772c9dfd36SJayamohan Kallickal csol_cqe->res_cnt = AMAP_GET_BITS(struct amap_sol_cqe, 12782c9dfd36SJayamohan Kallickal i_res_cnt, psol); 12792c9dfd36SJayamohan Kallickal csol_cqe->cmd_wnd = AMAP_GET_BITS(struct amap_sol_cqe, 12802c9dfd36SJayamohan Kallickal i_cmd_wnd, psol); 12812c9dfd36SJayamohan Kallickal csol_cqe->wrb_index = AMAP_GET_BITS(struct amap_sol_cqe, 12822c9dfd36SJayamohan Kallickal wrb_index, psol); 12832c9dfd36SJayamohan Kallickal csol_cqe->cid = AMAP_GET_BITS(struct amap_sol_cqe, 12842c9dfd36SJayamohan Kallickal cid, psol); 12852c9dfd36SJayamohan Kallickal csol_cqe->hw_sts = AMAP_GET_BITS(struct amap_sol_cqe, 12862c9dfd36SJayamohan Kallickal hw_sts, psol); 12872c9dfd36SJayamohan Kallickal csol_cqe->i_resp = AMAP_GET_BITS(struct amap_sol_cqe, 12882c9dfd36SJayamohan Kallickal i_resp, psol); 12892c9dfd36SJayamohan Kallickal csol_cqe->i_sts = AMAP_GET_BITS(struct amap_sol_cqe, 12902c9dfd36SJayamohan Kallickal i_sts, psol); 12912c9dfd36SJayamohan Kallickal csol_cqe->i_flags = AMAP_GET_BITS(struct amap_sol_cqe, 12922c9dfd36SJayamohan Kallickal i_flags, psol); 12932c9dfd36SJayamohan Kallickal } else { 129473133261SJohn Soni Jose csol_cqe->exp_cmdsn = AMAP_GET_BITS(struct amap_sol_cqe_v2, 129573133261SJohn Soni Jose i_exp_cmd_sn, psol); 129673133261SJohn Soni Jose csol_cqe->res_cnt = AMAP_GET_BITS(struct amap_sol_cqe_v2, 129773133261SJohn Soni Jose i_res_cnt, psol); 129873133261SJohn Soni Jose csol_cqe->wrb_index = AMAP_GET_BITS(struct amap_sol_cqe_v2, 129973133261SJohn Soni Jose wrb_index, psol); 130073133261SJohn Soni Jose csol_cqe->cid = AMAP_GET_BITS(struct amap_sol_cqe_v2, 130173133261SJohn Soni Jose cid, psol); 130273133261SJohn Soni Jose csol_cqe->hw_sts = AMAP_GET_BITS(struct amap_sol_cqe_v2, 130373133261SJohn Soni Jose hw_sts, psol); 1304702dc5e8SJayamohan Kallickal csol_cqe->cmd_wnd = AMAP_GET_BITS(struct amap_sol_cqe_v2, 130573133261SJohn Soni Jose i_cmd_wnd, psol); 130673133261SJohn Soni Jose if (AMAP_GET_BITS(struct amap_sol_cqe_v2, 130773133261SJohn Soni Jose cmd_cmpl, psol)) 130873133261SJohn Soni Jose csol_cqe->i_sts = AMAP_GET_BITS(struct amap_sol_cqe_v2, 130973133261SJohn Soni Jose i_sts, psol); 131073133261SJohn Soni Jose else 131173133261SJohn Soni Jose csol_cqe->i_resp = AMAP_GET_BITS(struct amap_sol_cqe_v2, 131273133261SJohn Soni Jose i_sts, psol); 131373133261SJohn Soni Jose if (AMAP_GET_BITS(struct amap_sol_cqe_v2, 131473133261SJohn Soni Jose u, psol)) 131573133261SJohn Soni Jose csol_cqe->i_flags = ISCSI_FLAG_CMD_UNDERFLOW; 131673133261SJohn Soni Jose 131773133261SJohn Soni Jose if (AMAP_GET_BITS(struct amap_sol_cqe_v2, 131873133261SJohn Soni Jose o, psol)) 131973133261SJohn Soni Jose csol_cqe->i_flags |= ISCSI_FLAG_CMD_OVERFLOW; 132073133261SJohn Soni Jose } 132173133261SJohn Soni Jose } 132273133261SJohn Soni Jose 132373133261SJohn Soni Jose 13246733b39aSJayamohan Kallickal static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, 13256733b39aSJayamohan Kallickal struct beiscsi_hba *phba, struct sol_cqe *psol) 13266733b39aSJayamohan Kallickal { 13276733b39aSJayamohan Kallickal struct iscsi_conn *conn = beiscsi_conn->conn; 13286733b39aSJayamohan Kallickal struct iscsi_session *session = conn->session; 132973133261SJohn Soni Jose struct common_sol_cqe csol_cqe = {0}; 13303f7f62eeSJitendra Bhivare struct hwi_wrb_context *pwrb_context; 13313f7f62eeSJitendra Bhivare struct hwi_controller *phwi_ctrlr; 13323f7f62eeSJitendra Bhivare struct wrb_handle *pwrb_handle; 13333f7f62eeSJitendra Bhivare struct iscsi_task *task; 1334a7909b39SJayamohan Kallickal uint16_t cri_index = 0; 13353f7f62eeSJitendra Bhivare uint8_t type; 13366733b39aSJayamohan Kallickal 13376733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 133873133261SJohn Soni Jose 133973133261SJohn Soni Jose /* Copy the elements to a common structure */ 134073133261SJohn Soni Jose adapter_get_sol_cqe(phba, psol, &csol_cqe); 134173133261SJohn Soni Jose 1342a7909b39SJayamohan Kallickal cri_index = BE_GET_CRI_FROM_CID(csol_cqe.cid); 1343a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; 134473133261SJohn Soni Jose 134573133261SJohn Soni Jose pwrb_handle = pwrb_context->pwrb_handle_basestd[ 134673133261SJohn Soni Jose csol_cqe.wrb_index]; 134773133261SJohn Soni Jose 13483f7f62eeSJitendra Bhivare spin_lock_bh(&session->back_lock); 13496733b39aSJayamohan Kallickal task = pwrb_handle->pio_handle; 13503f7f62eeSJitendra Bhivare if (!task) { 13513f7f62eeSJitendra Bhivare spin_unlock_bh(&session->back_lock); 13523f7f62eeSJitendra Bhivare return; 13533f7f62eeSJitendra Bhivare } 135473133261SJohn Soni Jose type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type; 135532951dd8SJayamohan Kallickal 1356bfead3b2SJayamohan Kallickal switch (type) { 13576733b39aSJayamohan Kallickal case HWH_TYPE_IO: 13586733b39aSJayamohan Kallickal case HWH_TYPE_IO_RD: 13596733b39aSJayamohan Kallickal if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == 1360dafab8e0SJayamohan Kallickal ISCSI_OP_NOOP_OUT) 136173133261SJohn Soni Jose be_complete_nopin_resp(beiscsi_conn, task, &csol_cqe); 1362dafab8e0SJayamohan Kallickal else 136373133261SJohn Soni Jose be_complete_io(beiscsi_conn, task, &csol_cqe); 13646733b39aSJayamohan Kallickal break; 13656733b39aSJayamohan Kallickal 13666733b39aSJayamohan Kallickal case HWH_TYPE_LOGOUT: 1367dafab8e0SJayamohan Kallickal if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) 136873133261SJohn Soni Jose be_complete_logout(beiscsi_conn, task, &csol_cqe); 1369dafab8e0SJayamohan Kallickal else 137073133261SJohn Soni Jose be_complete_tmf(beiscsi_conn, task, &csol_cqe); 13716733b39aSJayamohan Kallickal break; 13726733b39aSJayamohan Kallickal 13736733b39aSJayamohan Kallickal case HWH_TYPE_LOGIN: 137499bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 137599bc5d55SJohn Soni Jose BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 137699bc5d55SJohn Soni Jose "BM_%d :\t\t No HWH_TYPE_LOGIN Expected in" 137799bc5d55SJohn Soni Jose " hwi_complete_cmd- Solicited path\n"); 13786733b39aSJayamohan Kallickal break; 13796733b39aSJayamohan Kallickal 13806733b39aSJayamohan Kallickal case HWH_TYPE_NOP: 138173133261SJohn Soni Jose be_complete_nopin_resp(beiscsi_conn, task, &csol_cqe); 13826733b39aSJayamohan Kallickal break; 13836733b39aSJayamohan Kallickal 13846733b39aSJayamohan Kallickal default: 138599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_WARNING, 138699bc5d55SJohn Soni Jose BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 138799bc5d55SJohn Soni Jose "BM_%d : In hwi_complete_cmd, unknown type = %d" 1388bfead3b2SJayamohan Kallickal "wrb_index 0x%x CID 0x%x\n", type, 138973133261SJohn Soni Jose csol_cqe.wrb_index, 139073133261SJohn Soni Jose csol_cqe.cid); 13916733b39aSJayamohan Kallickal break; 13926733b39aSJayamohan Kallickal } 139335e66019SJayamohan Kallickal 1394659743b0SShlomo Pongratz spin_unlock_bh(&session->back_lock); 13956733b39aSJayamohan Kallickal } 13966733b39aSJayamohan Kallickal 1397dbc019a4SLee Jones /* 1398938f372cSJitendra Bhivare * ASYNC PDUs include 1399938f372cSJitendra Bhivare * a. Unsolicited NOP-In (target initiated NOP-In) 1400938f372cSJitendra Bhivare * b. ASYNC Messages 1401938f372cSJitendra Bhivare * c. Reject PDU 1402938f372cSJitendra Bhivare * d. Login response 1403938f372cSJitendra Bhivare * These headers arrive unprocessed by the EP firmware. 1404938f372cSJitendra Bhivare * iSCSI layer processes them. 1405938f372cSJitendra Bhivare */ 14066733b39aSJayamohan Kallickal static unsigned int 1407938f372cSJitendra Bhivare beiscsi_complete_pdu(struct beiscsi_conn *beiscsi_conn, 1408938f372cSJitendra Bhivare struct pdu_base *phdr, void *pdata, unsigned int dlen) 14096733b39aSJayamohan Kallickal { 1410938f372cSJitendra Bhivare struct beiscsi_hba *phba = beiscsi_conn->phba; 1411938f372cSJitendra Bhivare struct iscsi_conn *conn = beiscsi_conn->conn; 1412938f372cSJitendra Bhivare struct beiscsi_io_task *io_task; 1413938f372cSJitendra Bhivare struct iscsi_hdr *login_hdr; 1414938f372cSJitendra Bhivare struct iscsi_task *task; 1415938f372cSJitendra Bhivare u8 code; 14166733b39aSJayamohan Kallickal 1417938f372cSJitendra Bhivare code = AMAP_GET_BITS(struct amap_pdu_base, opcode, phdr); 1418938f372cSJitendra Bhivare switch (code) { 1419938f372cSJitendra Bhivare case ISCSI_OP_NOOP_IN: 1420938f372cSJitendra Bhivare pdata = NULL; 1421938f372cSJitendra Bhivare dlen = 0; 1422938f372cSJitendra Bhivare break; 1423938f372cSJitendra Bhivare case ISCSI_OP_ASYNC_EVENT: 1424938f372cSJitendra Bhivare break; 1425938f372cSJitendra Bhivare case ISCSI_OP_REJECT: 1426938f372cSJitendra Bhivare WARN_ON(!pdata); 1427938f372cSJitendra Bhivare WARN_ON(!(dlen == 48)); 142899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 142999bc5d55SJohn Soni Jose BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 1430938f372cSJitendra Bhivare "BM_%d : In ISCSI_OP_REJECT\n"); 1431938f372cSJitendra Bhivare break; 1432938f372cSJitendra Bhivare case ISCSI_OP_LOGIN_RSP: 1433938f372cSJitendra Bhivare case ISCSI_OP_TEXT_RSP: 1434938f372cSJitendra Bhivare task = conn->login_task; 1435938f372cSJitendra Bhivare io_task = task->dd_data; 1436938f372cSJitendra Bhivare login_hdr = (struct iscsi_hdr *)phdr; 1437938f372cSJitendra Bhivare login_hdr->itt = io_task->libiscsi_itt; 1438938f372cSJitendra Bhivare break; 1439938f372cSJitendra Bhivare default: 1440938f372cSJitendra Bhivare beiscsi_log(phba, KERN_WARNING, 1441938f372cSJitendra Bhivare BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 1442938f372cSJitendra Bhivare "BM_%d : unrecognized async PDU opcode 0x%x\n", 1443938f372cSJitendra Bhivare code); 1444938f372cSJitendra Bhivare return 1; 14456733b39aSJayamohan Kallickal } 1446938f372cSJitendra Bhivare __iscsi_complete_pdu(conn, (struct iscsi_hdr *)phdr, pdata, dlen); 14476733b39aSJayamohan Kallickal return 0; 14486733b39aSJayamohan Kallickal } 14496733b39aSJayamohan Kallickal 1450938f372cSJitendra Bhivare static inline void 1451938f372cSJitendra Bhivare beiscsi_hdl_put_handle(struct hd_async_context *pasync_ctx, 1452938f372cSJitendra Bhivare struct hd_async_handle *pasync_handle) 14536733b39aSJayamohan Kallickal { 1454ba6983a7SJitendra Bhivare pasync_handle->is_final = 0; 1455ba6983a7SJitendra Bhivare pasync_handle->buffer_len = 0; 1456ba6983a7SJitendra Bhivare pasync_handle->in_use = 0; 1457ba6983a7SJitendra Bhivare list_del_init(&pasync_handle->link); 14586733b39aSJayamohan Kallickal } 1459ba6983a7SJitendra Bhivare 1460ba6983a7SJitendra Bhivare static void 1461ba6983a7SJitendra Bhivare beiscsi_hdl_purge_handles(struct beiscsi_hba *phba, 1462ba6983a7SJitendra Bhivare struct hd_async_context *pasync_ctx, 1463ba6983a7SJitendra Bhivare u16 cri) 1464ba6983a7SJitendra Bhivare { 1465ba6983a7SJitendra Bhivare struct hd_async_handle *pasync_handle, *tmp_handle; 1466ba6983a7SJitendra Bhivare struct list_head *plist; 1467ba6983a7SJitendra Bhivare 1468ba6983a7SJitendra Bhivare plist = &pasync_ctx->async_entry[cri].wq.list; 1469ba6983a7SJitendra Bhivare list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) 1470ba6983a7SJitendra Bhivare beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); 1471ba6983a7SJitendra Bhivare 1472ba6983a7SJitendra Bhivare INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wq.list); 1473ba6983a7SJitendra Bhivare pasync_ctx->async_entry[cri].wq.hdr_len = 0; 1474ba6983a7SJitendra Bhivare pasync_ctx->async_entry[cri].wq.bytes_received = 0; 1475ba6983a7SJitendra Bhivare pasync_ctx->async_entry[cri].wq.bytes_needed = 0; 14766733b39aSJayamohan Kallickal } 14776733b39aSJayamohan Kallickal 1478938f372cSJitendra Bhivare static struct hd_async_handle * 1479938f372cSJitendra Bhivare beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn, 1480938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx, 14811e2931f1SJitendra Bhivare struct i_t_dpdu_cqe *pdpdu_cqe, 14821e2931f1SJitendra Bhivare u8 *header) 1483938f372cSJitendra Bhivare { 1484938f372cSJitendra Bhivare struct beiscsi_hba *phba = beiscsi_conn->phba; 1485938f372cSJitendra Bhivare struct hd_async_handle *pasync_handle; 1486938f372cSJitendra Bhivare struct be_bus_address phys_addr; 1487ba6983a7SJitendra Bhivare u16 cid, code, ci, cri; 1488938f372cSJitendra Bhivare u8 final, error = 0; 1489938f372cSJitendra Bhivare u32 dpl; 1490938f372cSJitendra Bhivare 1491938f372cSJitendra Bhivare cid = beiscsi_conn->beiscsi_conn_cid; 1492ba6983a7SJitendra Bhivare cri = BE_GET_ASYNC_CRI_FROM_CID(cid); 1493938f372cSJitendra Bhivare /** 1494938f372cSJitendra Bhivare * This function is invoked to get the right async_handle structure 1495938f372cSJitendra Bhivare * from a given DEF PDU CQ entry. 1496938f372cSJitendra Bhivare * 1497938f372cSJitendra Bhivare * - index in CQ entry gives the vertical index 1498938f372cSJitendra Bhivare * - address in CQ entry is the offset where the DMA last ended 1499938f372cSJitendra Bhivare * - final - no more notifications for this PDU 1500938f372cSJitendra Bhivare */ 1501938f372cSJitendra Bhivare if (is_chip_be2_be3r(phba)) { 1502938f372cSJitendra Bhivare dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, 1503938f372cSJitendra Bhivare dpl, pdpdu_cqe); 1504938f372cSJitendra Bhivare ci = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, 1505938f372cSJitendra Bhivare index, pdpdu_cqe); 1506938f372cSJitendra Bhivare final = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, 1507938f372cSJitendra Bhivare final, pdpdu_cqe); 1508938f372cSJitendra Bhivare } else { 1509938f372cSJitendra Bhivare dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, 1510938f372cSJitendra Bhivare dpl, pdpdu_cqe); 1511938f372cSJitendra Bhivare ci = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, 1512938f372cSJitendra Bhivare index, pdpdu_cqe); 1513938f372cSJitendra Bhivare final = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, 1514938f372cSJitendra Bhivare final, pdpdu_cqe); 15156733b39aSJayamohan Kallickal } 15166733b39aSJayamohan Kallickal 1517938f372cSJitendra Bhivare /** 1518938f372cSJitendra Bhivare * DB addr Hi/Lo is same for BE and SKH. 1519938f372cSJitendra Bhivare * Subtract the dataplacementlength to get to the base. 1520938f372cSJitendra Bhivare */ 1521938f372cSJitendra Bhivare phys_addr.u.a32.address_lo = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, 1522938f372cSJitendra Bhivare db_addr_lo, pdpdu_cqe); 1523938f372cSJitendra Bhivare phys_addr.u.a32.address_lo -= dpl; 1524938f372cSJitendra Bhivare phys_addr.u.a32.address_hi = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, 1525938f372cSJitendra Bhivare db_addr_hi, pdpdu_cqe); 15266733b39aSJayamohan Kallickal 1527938f372cSJitendra Bhivare code = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, code, pdpdu_cqe); 1528938f372cSJitendra Bhivare switch (code) { 1529938f372cSJitendra Bhivare case UNSOL_HDR_NOTIFY: 1530938f372cSJitendra Bhivare pasync_handle = pasync_ctx->async_entry[ci].header; 15311e2931f1SJitendra Bhivare *header = 1; 1532938f372cSJitendra Bhivare break; 1533938f372cSJitendra Bhivare case UNSOL_DATA_DIGEST_ERROR_NOTIFY: 1534938f372cSJitendra Bhivare error = 1; 1535df561f66SGustavo A. R. Silva fallthrough; 1536938f372cSJitendra Bhivare case UNSOL_DATA_NOTIFY: 1537938f372cSJitendra Bhivare pasync_handle = pasync_ctx->async_entry[ci].data; 1538938f372cSJitendra Bhivare break; 1539938f372cSJitendra Bhivare /* called only for above codes */ 1540938f372cSJitendra Bhivare default: 1541ba6983a7SJitendra Bhivare return NULL; 1542938f372cSJitendra Bhivare } 1543938f372cSJitendra Bhivare 1544938f372cSJitendra Bhivare if (pasync_handle->pa.u.a64.address != phys_addr.u.a64.address || 1545938f372cSJitendra Bhivare pasync_handle->index != ci) { 1546938f372cSJitendra Bhivare /* driver bug - if ci does not match async handle index */ 1547938f372cSJitendra Bhivare error = 1; 1548938f372cSJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, 1549938f372cSJitendra Bhivare "BM_%d : cid %u async PDU handle mismatch - addr in %cQE %llx at %u:addr in CQE %llx ci %u\n", 1550938f372cSJitendra Bhivare cid, pasync_handle->is_header ? 'H' : 'D', 1551938f372cSJitendra Bhivare pasync_handle->pa.u.a64.address, 1552938f372cSJitendra Bhivare pasync_handle->index, 1553938f372cSJitendra Bhivare phys_addr.u.a64.address, ci); 1554938f372cSJitendra Bhivare /* FW has stale address - attempt continuing by dropping */ 1555938f372cSJitendra Bhivare } 1556938f372cSJitendra Bhivare 1557938f372cSJitendra Bhivare /** 1558938f372cSJitendra Bhivare * DEF PDU header and data buffers with errors should be simply 1559938f372cSJitendra Bhivare * dropped as there are no consumers for it. 1560938f372cSJitendra Bhivare */ 1561938f372cSJitendra Bhivare if (error) { 1562938f372cSJitendra Bhivare beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); 1563ba6983a7SJitendra Bhivare return NULL; 1564938f372cSJitendra Bhivare } 1565ba6983a7SJitendra Bhivare 1566ba6983a7SJitendra Bhivare if (pasync_handle->in_use || !list_empty(&pasync_handle->link)) { 1567ba6983a7SJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, 1568ba6983a7SJitendra Bhivare "BM_%d : cid %d async PDU handle in use - code %d ci %d addr %llx\n", 1569ba6983a7SJitendra Bhivare cid, code, ci, phys_addr.u.a64.address); 1570ba6983a7SJitendra Bhivare beiscsi_hdl_purge_handles(phba, pasync_ctx, cri); 1571ba6983a7SJitendra Bhivare } 1572ba6983a7SJitendra Bhivare 1573ba6983a7SJitendra Bhivare list_del_init(&pasync_handle->link); 1574ba6983a7SJitendra Bhivare /** 1575ba6983a7SJitendra Bhivare * Each CID is associated with unique CRI. 1576ba6983a7SJitendra Bhivare * ASYNC_CRI_FROM_CID mapping and CRI_FROM_CID are totaly different. 1577ba6983a7SJitendra Bhivare **/ 1578ba6983a7SJitendra Bhivare pasync_handle->cri = cri; 1579ba6983a7SJitendra Bhivare pasync_handle->is_final = final; 1580ba6983a7SJitendra Bhivare pasync_handle->buffer_len = dpl; 1581ba6983a7SJitendra Bhivare pasync_handle->in_use = 1; 1582ba6983a7SJitendra Bhivare 1583938f372cSJitendra Bhivare return pasync_handle; 15846733b39aSJayamohan Kallickal } 15856733b39aSJayamohan Kallickal 1586938f372cSJitendra Bhivare static unsigned int 1587938f372cSJitendra Bhivare beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn, 1588938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx, 1589938f372cSJitendra Bhivare u16 cri) 1590938f372cSJitendra Bhivare { 1591938f372cSJitendra Bhivare struct iscsi_session *session = beiscsi_conn->conn->session; 1592938f372cSJitendra Bhivare struct hd_async_handle *pasync_handle, *plast_handle; 1593938f372cSJitendra Bhivare struct beiscsi_hba *phba = beiscsi_conn->phba; 1594938f372cSJitendra Bhivare void *phdr = NULL, *pdata = NULL; 1595938f372cSJitendra Bhivare u32 dlen = 0, status = 0; 1596938f372cSJitendra Bhivare struct list_head *plist; 1597938f372cSJitendra Bhivare 1598938f372cSJitendra Bhivare plist = &pasync_ctx->async_entry[cri].wq.list; 1599938f372cSJitendra Bhivare plast_handle = NULL; 1600938f372cSJitendra Bhivare list_for_each_entry(pasync_handle, plist, link) { 1601938f372cSJitendra Bhivare plast_handle = pasync_handle; 1602938f372cSJitendra Bhivare /* get the header, the first entry */ 1603938f372cSJitendra Bhivare if (!phdr) { 1604938f372cSJitendra Bhivare phdr = pasync_handle->pbuffer; 1605938f372cSJitendra Bhivare continue; 1606938f372cSJitendra Bhivare } 1607938f372cSJitendra Bhivare /* use first buffer to collect all the data */ 1608938f372cSJitendra Bhivare if (!pdata) { 1609938f372cSJitendra Bhivare pdata = pasync_handle->pbuffer; 1610938f372cSJitendra Bhivare dlen = pasync_handle->buffer_len; 1611938f372cSJitendra Bhivare continue; 1612938f372cSJitendra Bhivare } 16130ddee50eSJitendra Bhivare if (!pasync_handle->buffer_len || 16140ddee50eSJitendra Bhivare (dlen + pasync_handle->buffer_len) > 16150ddee50eSJitendra Bhivare pasync_ctx->async_data.buffer_size) 16160ddee50eSJitendra Bhivare break; 1617938f372cSJitendra Bhivare memcpy(pdata + dlen, pasync_handle->pbuffer, 1618938f372cSJitendra Bhivare pasync_handle->buffer_len); 1619938f372cSJitendra Bhivare dlen += pasync_handle->buffer_len; 1620938f372cSJitendra Bhivare } 1621938f372cSJitendra Bhivare 1622938f372cSJitendra Bhivare if (!plast_handle->is_final) { 1623938f372cSJitendra Bhivare /* last handle should have final PDU notification from FW */ 1624938f372cSJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, 16250ddee50eSJitendra Bhivare "BM_%d : cid %u %p fwd async PDU opcode %x with last handle missing - HL%u:DN%u:DR%u\n", 1626938f372cSJitendra Bhivare beiscsi_conn->beiscsi_conn_cid, plast_handle, 16270ddee50eSJitendra Bhivare AMAP_GET_BITS(struct amap_pdu_base, opcode, phdr), 1628938f372cSJitendra Bhivare pasync_ctx->async_entry[cri].wq.hdr_len, 1629938f372cSJitendra Bhivare pasync_ctx->async_entry[cri].wq.bytes_needed, 1630938f372cSJitendra Bhivare pasync_ctx->async_entry[cri].wq.bytes_received); 1631938f372cSJitendra Bhivare } 1632938f372cSJitendra Bhivare spin_lock_bh(&session->back_lock); 1633938f372cSJitendra Bhivare status = beiscsi_complete_pdu(beiscsi_conn, phdr, pdata, dlen); 1634938f372cSJitendra Bhivare spin_unlock_bh(&session->back_lock); 1635938f372cSJitendra Bhivare beiscsi_hdl_purge_handles(phba, pasync_ctx, cri); 1636938f372cSJitendra Bhivare return status; 1637938f372cSJitendra Bhivare } 1638938f372cSJitendra Bhivare 1639938f372cSJitendra Bhivare static unsigned int 1640938f372cSJitendra Bhivare beiscsi_hdl_gather_pdu(struct beiscsi_conn *beiscsi_conn, 1641938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx, 1642938f372cSJitendra Bhivare struct hd_async_handle *pasync_handle) 1643938f372cSJitendra Bhivare { 1644938f372cSJitendra Bhivare unsigned int bytes_needed = 0, status = 0; 1645938f372cSJitendra Bhivare u16 cri = pasync_handle->cri; 1646938f372cSJitendra Bhivare struct cri_wait_queue *wq; 1647938f372cSJitendra Bhivare struct beiscsi_hba *phba; 1648938f372cSJitendra Bhivare struct pdu_base *ppdu; 1649938f372cSJitendra Bhivare char *err = ""; 1650938f372cSJitendra Bhivare 1651938f372cSJitendra Bhivare phba = beiscsi_conn->phba; 1652938f372cSJitendra Bhivare wq = &pasync_ctx->async_entry[cri].wq; 1653938f372cSJitendra Bhivare if (pasync_handle->is_header) { 1654938f372cSJitendra Bhivare /* check if PDU hdr is rcv'd when old hdr not completed */ 1655938f372cSJitendra Bhivare if (wq->hdr_len) { 1656938f372cSJitendra Bhivare err = "incomplete"; 1657938f372cSJitendra Bhivare goto drop_pdu; 1658938f372cSJitendra Bhivare } 1659938f372cSJitendra Bhivare ppdu = pasync_handle->pbuffer; 1660938f372cSJitendra Bhivare bytes_needed = AMAP_GET_BITS(struct amap_pdu_base, 1661938f372cSJitendra Bhivare data_len_hi, ppdu); 1662938f372cSJitendra Bhivare bytes_needed <<= 16; 1663938f372cSJitendra Bhivare bytes_needed |= be16_to_cpu(AMAP_GET_BITS(struct amap_pdu_base, 1664938f372cSJitendra Bhivare data_len_lo, ppdu)); 1665938f372cSJitendra Bhivare wq->hdr_len = pasync_handle->buffer_len; 1666938f372cSJitendra Bhivare wq->bytes_received = 0; 1667938f372cSJitendra Bhivare wq->bytes_needed = bytes_needed; 1668938f372cSJitendra Bhivare list_add_tail(&pasync_handle->link, &wq->list); 1669938f372cSJitendra Bhivare if (!bytes_needed) 1670938f372cSJitendra Bhivare status = beiscsi_hdl_fwd_pdu(beiscsi_conn, 1671938f372cSJitendra Bhivare pasync_ctx, cri); 1672938f372cSJitendra Bhivare } else { 1673938f372cSJitendra Bhivare /* check if data received has header and is needed */ 1674938f372cSJitendra Bhivare if (!wq->hdr_len || !wq->bytes_needed) { 1675938f372cSJitendra Bhivare err = "header less"; 1676938f372cSJitendra Bhivare goto drop_pdu; 1677938f372cSJitendra Bhivare } 1678938f372cSJitendra Bhivare wq->bytes_received += pasync_handle->buffer_len; 1679938f372cSJitendra Bhivare /* Something got overwritten? Better catch it here. */ 1680938f372cSJitendra Bhivare if (wq->bytes_received > wq->bytes_needed) { 1681938f372cSJitendra Bhivare err = "overflow"; 1682938f372cSJitendra Bhivare goto drop_pdu; 1683938f372cSJitendra Bhivare } 1684938f372cSJitendra Bhivare list_add_tail(&pasync_handle->link, &wq->list); 1685938f372cSJitendra Bhivare if (wq->bytes_received == wq->bytes_needed) 1686938f372cSJitendra Bhivare status = beiscsi_hdl_fwd_pdu(beiscsi_conn, 1687938f372cSJitendra Bhivare pasync_ctx, cri); 1688938f372cSJitendra Bhivare } 1689938f372cSJitendra Bhivare return status; 1690938f372cSJitendra Bhivare 1691938f372cSJitendra Bhivare drop_pdu: 1692938f372cSJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_ISCSI, 1693938f372cSJitendra Bhivare "BM_%d : cid %u async PDU %s - def-%c:HL%u:DN%u:DR%u\n", 1694938f372cSJitendra Bhivare beiscsi_conn->beiscsi_conn_cid, err, 1695938f372cSJitendra Bhivare pasync_handle->is_header ? 'H' : 'D', 1696938f372cSJitendra Bhivare wq->hdr_len, wq->bytes_needed, 1697938f372cSJitendra Bhivare pasync_handle->buffer_len); 1698938f372cSJitendra Bhivare /* discard this handle */ 1699938f372cSJitendra Bhivare beiscsi_hdl_put_handle(pasync_ctx, pasync_handle); 1700938f372cSJitendra Bhivare /* free all the other handles in cri_wait_queue */ 1701938f372cSJitendra Bhivare beiscsi_hdl_purge_handles(phba, pasync_ctx, cri); 1702938f372cSJitendra Bhivare /* try continuing */ 1703938f372cSJitendra Bhivare return status; 1704938f372cSJitendra Bhivare } 1705938f372cSJitendra Bhivare 1706938f372cSJitendra Bhivare static void 1707938f372cSJitendra Bhivare beiscsi_hdq_post_handles(struct beiscsi_hba *phba, 17081e2931f1SJitendra Bhivare u8 header, u8 ulp_num, u16 nbuf) 1709938f372cSJitendra Bhivare { 17101e2931f1SJitendra Bhivare struct hd_async_handle *pasync_handle; 1711938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx; 17126733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 17136733b39aSJayamohan Kallickal struct phys_addr *pasync_sge; 1714938f372cSJitendra Bhivare u32 ring_id, doorbell = 0; 1715938f372cSJitendra Bhivare u32 doorbell_offset; 17161e2931f1SJitendra Bhivare u16 prod, pi; 17176733b39aSJayamohan Kallickal 17186733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 17198a86e833SJayamohan Kallickal pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); 1720938f372cSJitendra Bhivare if (header) { 17211e2931f1SJitendra Bhivare pasync_sge = pasync_ctx->async_header.ring_base; 17221e2931f1SJitendra Bhivare pi = pasync_ctx->async_header.pi; 17238a86e833SJayamohan Kallickal ring_id = phwi_ctrlr->default_pdu_hdr[ulp_num].id; 17248a86e833SJayamohan Kallickal doorbell_offset = phwi_ctrlr->default_pdu_hdr[ulp_num]. 17258a86e833SJayamohan Kallickal doorbell_offset; 17266733b39aSJayamohan Kallickal } else { 17271e2931f1SJitendra Bhivare pasync_sge = pasync_ctx->async_data.ring_base; 17281e2931f1SJitendra Bhivare pi = pasync_ctx->async_data.pi; 17298a86e833SJayamohan Kallickal ring_id = phwi_ctrlr->default_pdu_data[ulp_num].id; 17308a86e833SJayamohan Kallickal doorbell_offset = phwi_ctrlr->default_pdu_data[ulp_num]. 17318a86e833SJayamohan Kallickal doorbell_offset; 17326733b39aSJayamohan Kallickal } 17336733b39aSJayamohan Kallickal 17341e2931f1SJitendra Bhivare for (prod = 0; prod < nbuf; prod++) { 17351e2931f1SJitendra Bhivare if (header) 17361e2931f1SJitendra Bhivare pasync_handle = pasync_ctx->async_entry[pi].header; 17371e2931f1SJitendra Bhivare else 17381e2931f1SJitendra Bhivare pasync_handle = pasync_ctx->async_entry[pi].data; 1739938f372cSJitendra Bhivare WARN_ON(pasync_handle->is_header != header); 17401e2931f1SJitendra Bhivare WARN_ON(pasync_handle->index != pi); 17411e2931f1SJitendra Bhivare /* setup the ring only once */ 17421e2931f1SJitendra Bhivare if (nbuf == pasync_ctx->num_entries) { 17431e2931f1SJitendra Bhivare /* note hi is lo */ 17441e2931f1SJitendra Bhivare pasync_sge[pi].hi = pasync_handle->pa.u.a32.address_lo; 17451e2931f1SJitendra Bhivare pasync_sge[pi].lo = pasync_handle->pa.u.a32.address_hi; 1746938f372cSJitendra Bhivare } 17471e2931f1SJitendra Bhivare if (++pi == pasync_ctx->num_entries) 17481e2931f1SJitendra Bhivare pi = 0; 17491e2931f1SJitendra Bhivare } 17506733b39aSJayamohan Kallickal 1751938f372cSJitendra Bhivare if (header) 17521e2931f1SJitendra Bhivare pasync_ctx->async_header.pi = pi; 1753938f372cSJitendra Bhivare else 17541e2931f1SJitendra Bhivare pasync_ctx->async_data.pi = pi; 17556733b39aSJayamohan Kallickal 17566733b39aSJayamohan Kallickal doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; 17576733b39aSJayamohan Kallickal doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; 17586733b39aSJayamohan Kallickal doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT; 1759938f372cSJitendra Bhivare doorbell |= (prod & DB_DEF_PDU_CQPROC_MASK) << DB_DEF_PDU_CQPROC_SHIFT; 17608a86e833SJayamohan Kallickal iowrite32(doorbell, phba->db_va + doorbell_offset); 17616733b39aSJayamohan Kallickal } 17626733b39aSJayamohan Kallickal 1763938f372cSJitendra Bhivare static void 1764938f372cSJitendra Bhivare beiscsi_hdq_process_compl(struct beiscsi_conn *beiscsi_conn, 17656733b39aSJayamohan Kallickal struct i_t_dpdu_cqe *pdpdu_cqe) 17666733b39aSJayamohan Kallickal { 1767938f372cSJitendra Bhivare struct beiscsi_hba *phba = beiscsi_conn->phba; 1768938f372cSJitendra Bhivare struct hd_async_handle *pasync_handle = NULL; 1769938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx; 17706733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 17711e2931f1SJitendra Bhivare u8 ulp_num, consumed, header = 0; 1772938f372cSJitendra Bhivare u16 cid_cri; 17736733b39aSJayamohan Kallickal 17746733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 1775938f372cSJitendra Bhivare cid_cri = BE_GET_CRI_FROM_CID(beiscsi_conn->beiscsi_conn_cid); 1776938f372cSJitendra Bhivare ulp_num = BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cid_cri); 1777938f372cSJitendra Bhivare pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num); 1778938f372cSJitendra Bhivare pasync_handle = beiscsi_hdl_get_handle(beiscsi_conn, pasync_ctx, 17791e2931f1SJitendra Bhivare pdpdu_cqe, &header); 17801e2931f1SJitendra Bhivare if (is_chip_be2_be3r(phba)) 17811e2931f1SJitendra Bhivare consumed = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe, 17821e2931f1SJitendra Bhivare num_cons, pdpdu_cqe); 17831e2931f1SJitendra Bhivare else 17841e2931f1SJitendra Bhivare consumed = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2, 17851e2931f1SJitendra Bhivare num_cons, pdpdu_cqe); 17861e2931f1SJitendra Bhivare if (pasync_handle) 1787938f372cSJitendra Bhivare beiscsi_hdl_gather_pdu(beiscsi_conn, pasync_ctx, pasync_handle); 17881e2931f1SJitendra Bhivare /* num_cons indicates number of 8 RQEs consumed */ 17891e2931f1SJitendra Bhivare if (consumed) 17901e2931f1SJitendra Bhivare beiscsi_hdq_post_handles(phba, header, ulp_num, 8 * consumed); 17916733b39aSJayamohan Kallickal } 17926733b39aSJayamohan Kallickal 17932e4e8f65SJitendra Bhivare void beiscsi_process_mcc_cq(struct beiscsi_hba *phba) 1794756d29c8SJayamohan Kallickal { 1795756d29c8SJayamohan Kallickal struct be_queue_info *mcc_cq; 1796756d29c8SJayamohan Kallickal struct be_mcc_compl *mcc_compl; 1797756d29c8SJayamohan Kallickal unsigned int num_processed = 0; 1798756d29c8SJayamohan Kallickal 1799756d29c8SJayamohan Kallickal mcc_cq = &phba->ctrl.mcc_obj.cq; 1800756d29c8SJayamohan Kallickal mcc_compl = queue_tail_node(mcc_cq); 1801756d29c8SJayamohan Kallickal mcc_compl->flags = le32_to_cpu(mcc_compl->flags); 1802756d29c8SJayamohan Kallickal while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) { 18039122e991SJitendra Bhivare if (beiscsi_hba_in_error(phba)) 18049122e991SJitendra Bhivare return; 18059122e991SJitendra Bhivare 1806756d29c8SJayamohan Kallickal if (num_processed >= 32) { 1807756d29c8SJayamohan Kallickal hwi_ring_cq_db(phba, mcc_cq->id, 18081094cf68SJitendra Bhivare num_processed, 0); 1809756d29c8SJayamohan Kallickal num_processed = 0; 1810756d29c8SJayamohan Kallickal } 1811756d29c8SJayamohan Kallickal if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) { 181253aefe25SJitendra Bhivare beiscsi_process_async_event(phba, mcc_compl); 1813756d29c8SJayamohan Kallickal } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) { 18142e4e8f65SJitendra Bhivare beiscsi_process_mcc_compl(&phba->ctrl, mcc_compl); 1815756d29c8SJayamohan Kallickal } 1816756d29c8SJayamohan Kallickal 1817756d29c8SJayamohan Kallickal mcc_compl->flags = 0; 1818756d29c8SJayamohan Kallickal queue_tail_inc(mcc_cq); 1819756d29c8SJayamohan Kallickal mcc_compl = queue_tail_node(mcc_cq); 1820756d29c8SJayamohan Kallickal mcc_compl->flags = le32_to_cpu(mcc_compl->flags); 1821756d29c8SJayamohan Kallickal num_processed++; 1822756d29c8SJayamohan Kallickal } 1823756d29c8SJayamohan Kallickal 1824756d29c8SJayamohan Kallickal if (num_processed > 0) 18251094cf68SJitendra Bhivare hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1); 1826756d29c8SJayamohan Kallickal } 1827bfead3b2SJayamohan Kallickal 1828a3095016SJitendra Bhivare static void beiscsi_mcc_work(struct work_struct *work) 1829a3095016SJitendra Bhivare { 1830a3095016SJitendra Bhivare struct be_eq_obj *pbe_eq; 1831a3095016SJitendra Bhivare struct beiscsi_hba *phba; 1832a3095016SJitendra Bhivare 1833a3095016SJitendra Bhivare pbe_eq = container_of(work, struct be_eq_obj, mcc_work); 1834a3095016SJitendra Bhivare phba = pbe_eq->phba; 1835a3095016SJitendra Bhivare beiscsi_process_mcc_cq(phba); 1836a3095016SJitendra Bhivare /* rearm EQ for further interrupts */ 18379122e991SJitendra Bhivare if (!beiscsi_hba_in_error(phba)) 1838a3095016SJitendra Bhivare hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); 1839a3095016SJitendra Bhivare } 1840a3095016SJitendra Bhivare 18416763daaeSJohn Soni Jose /** 18426763daaeSJohn Soni Jose * beiscsi_process_cq()- Process the Completion Queue 18436763daaeSJohn Soni Jose * @pbe_eq: Event Q on which the Completion has come 18441094cf68SJitendra Bhivare * @budget: Max number of events to processed 18456763daaeSJohn Soni Jose * 18466763daaeSJohn Soni Jose * return 18476763daaeSJohn Soni Jose * Number of Completion Entries processed. 18486763daaeSJohn Soni Jose **/ 18491094cf68SJitendra Bhivare unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget) 18506733b39aSJayamohan Kallickal { 18516733b39aSJayamohan Kallickal struct be_queue_info *cq; 18526733b39aSJayamohan Kallickal struct sol_cqe *sol; 18531094cf68SJitendra Bhivare unsigned int total = 0; 18546733b39aSJayamohan Kallickal unsigned int num_processed = 0; 18550a513dd8SJohn Soni Jose unsigned short code = 0, cid = 0; 1856a7909b39SJayamohan Kallickal uint16_t cri_index = 0; 18576733b39aSJayamohan Kallickal struct beiscsi_conn *beiscsi_conn; 1858c2462288SJayamohan Kallickal struct beiscsi_endpoint *beiscsi_ep; 1859c2462288SJayamohan Kallickal struct iscsi_endpoint *ep; 1860bfead3b2SJayamohan Kallickal struct beiscsi_hba *phba; 18616733b39aSJayamohan Kallickal 1862bfead3b2SJayamohan Kallickal cq = pbe_eq->cq; 18636733b39aSJayamohan Kallickal sol = queue_tail_node(cq); 1864bfead3b2SJayamohan Kallickal phba = pbe_eq->phba; 18656733b39aSJayamohan Kallickal 18666733b39aSJayamohan Kallickal while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] & 18676733b39aSJayamohan Kallickal CQE_VALID_MASK) { 18689122e991SJitendra Bhivare if (beiscsi_hba_in_error(phba)) 18699122e991SJitendra Bhivare return 0; 18709122e991SJitendra Bhivare 18716733b39aSJayamohan Kallickal be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); 18726733b39aSJayamohan Kallickal 187345efc940SJitendra Bhivare code = (sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & 187445efc940SJitendra Bhivare CQE_CODE_MASK); 187532951dd8SJayamohan Kallickal 187673133261SJohn Soni Jose /* Get the CID */ 18772c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) { 18782c9dfd36SJayamohan Kallickal cid = AMAP_GET_BITS(struct amap_sol_cqe, cid, sol); 18792c9dfd36SJayamohan Kallickal } else { 188073133261SJohn Soni Jose if ((code == DRIVERMSG_NOTIFY) || 188173133261SJohn Soni Jose (code == UNSOL_HDR_NOTIFY) || 188273133261SJohn Soni Jose (code == UNSOL_DATA_NOTIFY)) 188373133261SJohn Soni Jose cid = AMAP_GET_BITS( 188473133261SJohn Soni Jose struct amap_i_t_dpdu_cqe_v2, 188573133261SJohn Soni Jose cid, sol); 188673133261SJohn Soni Jose else 188773133261SJohn Soni Jose cid = AMAP_GET_BITS(struct amap_sol_cqe_v2, 188873133261SJohn Soni Jose cid, sol); 18892c9dfd36SJayamohan Kallickal } 189073133261SJohn Soni Jose 1891a7909b39SJayamohan Kallickal cri_index = BE_GET_CRI_FROM_CID(cid); 1892a7909b39SJayamohan Kallickal ep = phba->ep_array[cri_index]; 1893b7ab35b1SJayamohan Kallickal 1894b7ab35b1SJayamohan Kallickal if (ep == NULL) { 1895b7ab35b1SJayamohan Kallickal /* connection has already been freed 1896b7ab35b1SJayamohan Kallickal * just move on to next one 1897b7ab35b1SJayamohan Kallickal */ 1898b7ab35b1SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 1899b7ab35b1SJayamohan Kallickal BEISCSI_LOG_INIT, 1900b7ab35b1SJayamohan Kallickal "BM_%d : proc cqe of disconn ep: cid %d\n", 1901b7ab35b1SJayamohan Kallickal cid); 1902b7ab35b1SJayamohan Kallickal goto proc_next_cqe; 1903b7ab35b1SJayamohan Kallickal } 1904b7ab35b1SJayamohan Kallickal 1905c2462288SJayamohan Kallickal beiscsi_ep = ep->dd_data; 1906c2462288SJayamohan Kallickal beiscsi_conn = beiscsi_ep->conn; 1907756d29c8SJayamohan Kallickal 19081094cf68SJitendra Bhivare /* replenish cq */ 19091094cf68SJitendra Bhivare if (num_processed == 32) { 19101094cf68SJitendra Bhivare hwi_ring_cq_db(phba, cq->id, 32, 0); 19116733b39aSJayamohan Kallickal num_processed = 0; 19126733b39aSJayamohan Kallickal } 19131094cf68SJitendra Bhivare total++; 19146733b39aSJayamohan Kallickal 19150a513dd8SJohn Soni Jose switch (code) { 19166733b39aSJayamohan Kallickal case SOL_CMD_COMPLETE: 19176733b39aSJayamohan Kallickal hwi_complete_cmd(beiscsi_conn, phba, sol); 19186733b39aSJayamohan Kallickal break; 19196733b39aSJayamohan Kallickal case DRIVERMSG_NOTIFY: 192099bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, 192199bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 19226763daaeSJohn Soni Jose "BM_%d : Received %s[%d] on CID : %d\n", 19236763daaeSJohn Soni Jose cqe_desc[code], code, cid); 192499bc5d55SJohn Soni Jose 19256733b39aSJayamohan Kallickal hwi_complete_drvr_msgs(beiscsi_conn, phba, sol); 19266733b39aSJayamohan Kallickal break; 19276733b39aSJayamohan Kallickal case UNSOL_HDR_NOTIFY: 192899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, 192999bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 19306763daaeSJohn Soni Jose "BM_%d : Received %s[%d] on CID : %d\n", 19316763daaeSJohn Soni Jose cqe_desc[code], code, cid); 193299bc5d55SJohn Soni Jose 19338f09a3b9SJayamohan Kallickal spin_lock_bh(&phba->async_pdu_lock); 1934938f372cSJitendra Bhivare beiscsi_hdq_process_compl(beiscsi_conn, 1935bfead3b2SJayamohan Kallickal (struct i_t_dpdu_cqe *)sol); 19368f09a3b9SJayamohan Kallickal spin_unlock_bh(&phba->async_pdu_lock); 1937bfead3b2SJayamohan Kallickal break; 19386733b39aSJayamohan Kallickal case UNSOL_DATA_NOTIFY: 193999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, 194099bc5d55SJohn Soni Jose BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 19416763daaeSJohn Soni Jose "BM_%d : Received %s[%d] on CID : %d\n", 19426763daaeSJohn Soni Jose cqe_desc[code], code, cid); 194399bc5d55SJohn Soni Jose 19448f09a3b9SJayamohan Kallickal spin_lock_bh(&phba->async_pdu_lock); 1945938f372cSJitendra Bhivare beiscsi_hdq_process_compl(beiscsi_conn, 19466733b39aSJayamohan Kallickal (struct i_t_dpdu_cqe *)sol); 19478f09a3b9SJayamohan Kallickal spin_unlock_bh(&phba->async_pdu_lock); 19486733b39aSJayamohan Kallickal break; 19496733b39aSJayamohan Kallickal case CXN_INVALIDATE_INDEX_NOTIFY: 19506733b39aSJayamohan Kallickal case CMD_INVALIDATED_NOTIFY: 19516733b39aSJayamohan Kallickal case CXN_INVALIDATE_NOTIFY: 195299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 195399bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 19546763daaeSJohn Soni Jose "BM_%d : Ignoring %s[%d] on CID : %d\n", 19556763daaeSJohn Soni Jose cqe_desc[code], code, cid); 19566733b39aSJayamohan Kallickal break; 19571094cf68SJitendra Bhivare case CXN_KILLED_HDR_DIGEST_ERR: 19586733b39aSJayamohan Kallickal case SOL_CMD_KILLED_DATA_DIGEST_ERR: 19591094cf68SJitendra Bhivare beiscsi_log(phba, KERN_ERR, 19601094cf68SJitendra Bhivare BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 19611094cf68SJitendra Bhivare "BM_%d : Cmd Notification %s[%d] on CID : %d\n", 19621094cf68SJitendra Bhivare cqe_desc[code], code, cid); 19631094cf68SJitendra Bhivare break; 19646733b39aSJayamohan Kallickal case CMD_KILLED_INVALID_STATSN_RCVD: 19656733b39aSJayamohan Kallickal case CMD_KILLED_INVALID_R2T_RCVD: 19666733b39aSJayamohan Kallickal case CMD_CXN_KILLED_LUN_INVALID: 19676733b39aSJayamohan Kallickal case CMD_CXN_KILLED_ICD_INVALID: 19686733b39aSJayamohan Kallickal case CMD_CXN_KILLED_ITT_INVALID: 19696733b39aSJayamohan Kallickal case CMD_CXN_KILLED_SEQ_OUTOFORDER: 19706733b39aSJayamohan Kallickal case CMD_CXN_KILLED_INVALID_DATASN_RCVD: 197199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 197299bc5d55SJohn Soni Jose BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 19736763daaeSJohn Soni Jose "BM_%d : Cmd Notification %s[%d] on CID : %d\n", 19746763daaeSJohn Soni Jose cqe_desc[code], code, cid); 19756733b39aSJayamohan Kallickal break; 19766733b39aSJayamohan Kallickal case UNSOL_DATA_DIGEST_ERROR_NOTIFY: 197799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 197899bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 19796763daaeSJohn Soni Jose "BM_%d : Dropping %s[%d] on DPDU ring on CID : %d\n", 19806763daaeSJohn Soni Jose cqe_desc[code], code, cid); 19818f09a3b9SJayamohan Kallickal spin_lock_bh(&phba->async_pdu_lock); 1982938f372cSJitendra Bhivare /* driver consumes the entry and drops the contents */ 1983938f372cSJitendra Bhivare beiscsi_hdq_process_compl(beiscsi_conn, 19846733b39aSJayamohan Kallickal (struct i_t_dpdu_cqe *)sol); 19858f09a3b9SJayamohan Kallickal spin_unlock_bh(&phba->async_pdu_lock); 19866733b39aSJayamohan Kallickal break; 19876733b39aSJayamohan Kallickal case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL: 19886733b39aSJayamohan Kallickal case CXN_KILLED_BURST_LEN_MISMATCH: 19896733b39aSJayamohan Kallickal case CXN_KILLED_AHS_RCVD: 19906733b39aSJayamohan Kallickal case CXN_KILLED_UNKNOWN_HDR: 19916733b39aSJayamohan Kallickal case CXN_KILLED_STALE_ITT_TTT_RCVD: 19926733b39aSJayamohan Kallickal case CXN_KILLED_INVALID_ITT_TTT_RCVD: 19936733b39aSJayamohan Kallickal case CXN_KILLED_TIMED_OUT: 19946733b39aSJayamohan Kallickal case CXN_KILLED_FIN_RCVD: 19956763daaeSJohn Soni Jose case CXN_KILLED_RST_SENT: 19966763daaeSJohn Soni Jose case CXN_KILLED_RST_RCVD: 19976733b39aSJayamohan Kallickal case CXN_KILLED_BAD_UNSOL_PDU_RCVD: 19986733b39aSJayamohan Kallickal case CXN_KILLED_BAD_WRB_INDEX_ERROR: 19996733b39aSJayamohan Kallickal case CXN_KILLED_OVER_RUN_RESIDUAL: 20006733b39aSJayamohan Kallickal case CXN_KILLED_UNDER_RUN_RESIDUAL: 20016733b39aSJayamohan Kallickal case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN: 200299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 200399bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 20046763daaeSJohn Soni Jose "BM_%d : Event %s[%d] received on CID : %d\n", 20056763daaeSJohn Soni Jose cqe_desc[code], code, cid); 20060a513dd8SJohn Soni Jose if (beiscsi_conn) 20076733b39aSJayamohan Kallickal iscsi_conn_failure(beiscsi_conn->conn, 20086733b39aSJayamohan Kallickal ISCSI_ERR_CONN_FAILED); 20096733b39aSJayamohan Kallickal break; 20106733b39aSJayamohan Kallickal default: 201199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, 201299bc5d55SJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 20136763daaeSJohn Soni Jose "BM_%d : Invalid CQE Event Received Code : %d" 20146763daaeSJohn Soni Jose "CID 0x%x...\n", 20150a513dd8SJohn Soni Jose code, cid); 20166733b39aSJayamohan Kallickal break; 20176733b39aSJayamohan Kallickal } 20186733b39aSJayamohan Kallickal 2019b7ab35b1SJayamohan Kallickal proc_next_cqe: 20206733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_sol_cqe, valid, sol, 0); 20216733b39aSJayamohan Kallickal queue_tail_inc(cq); 20226733b39aSJayamohan Kallickal sol = queue_tail_node(cq); 20236733b39aSJayamohan Kallickal num_processed++; 20241094cf68SJitendra Bhivare if (total == budget) 20251094cf68SJitendra Bhivare break; 20266733b39aSJayamohan Kallickal } 20276733b39aSJayamohan Kallickal 20281094cf68SJitendra Bhivare hwi_ring_cq_db(phba, cq->id, num_processed, 1); 20291094cf68SJitendra Bhivare return total; 20306733b39aSJayamohan Kallickal } 20316733b39aSJayamohan Kallickal 2032511cbce2SChristoph Hellwig static int be_iopoll(struct irq_poll *iop, int budget) 20336733b39aSJayamohan Kallickal { 2034a3095016SJitendra Bhivare unsigned int ret, io_events; 20356733b39aSJayamohan Kallickal struct beiscsi_hba *phba; 2036bfead3b2SJayamohan Kallickal struct be_eq_obj *pbe_eq; 20371094cf68SJitendra Bhivare struct be_eq_entry *eqe = NULL; 20381094cf68SJitendra Bhivare struct be_queue_info *eq; 20396733b39aSJayamohan Kallickal 2040bfead3b2SJayamohan Kallickal pbe_eq = container_of(iop, struct be_eq_obj, iopoll); 20411094cf68SJitendra Bhivare phba = pbe_eq->phba; 20429122e991SJitendra Bhivare if (beiscsi_hba_in_error(phba)) { 20439122e991SJitendra Bhivare irq_poll_complete(iop); 20449122e991SJitendra Bhivare return 0; 20459122e991SJitendra Bhivare } 20469122e991SJitendra Bhivare 20479122e991SJitendra Bhivare io_events = 0; 20481094cf68SJitendra Bhivare eq = &pbe_eq->q; 20491094cf68SJitendra Bhivare eqe = queue_tail_node(eq); 20501094cf68SJitendra Bhivare while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & 20511094cf68SJitendra Bhivare EQE_VALID_MASK) { 20521094cf68SJitendra Bhivare AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); 20531094cf68SJitendra Bhivare queue_tail_inc(eq); 20541094cf68SJitendra Bhivare eqe = queue_tail_node(eq); 2055a3095016SJitendra Bhivare io_events++; 20561094cf68SJitendra Bhivare } 2057a3095016SJitendra Bhivare hwi_ring_eq_db(phba, eq->id, 1, io_events, 0, 1); 20581094cf68SJitendra Bhivare 20591094cf68SJitendra Bhivare ret = beiscsi_process_cq(pbe_eq, budget); 206073af08e1SJayamohan Kallickal pbe_eq->cq_count += ret; 20616733b39aSJayamohan Kallickal if (ret < budget) { 2062511cbce2SChristoph Hellwig irq_poll_complete(iop); 206399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, 206499bc5d55SJohn Soni Jose BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO, 20651094cf68SJitendra Bhivare "BM_%d : rearm pbe_eq->q.id =%d ret %d\n", 20661094cf68SJitendra Bhivare pbe_eq->q.id, ret); 20679122e991SJitendra Bhivare if (!beiscsi_hba_in_error(phba)) 2068bfead3b2SJayamohan Kallickal hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); 20696733b39aSJayamohan Kallickal } 20706733b39aSJayamohan Kallickal return ret; 20716733b39aSJayamohan Kallickal } 20726733b39aSJayamohan Kallickal 20736733b39aSJayamohan Kallickal static void 207409a1093aSJohn Soni Jose hwi_write_sgl_v2(struct iscsi_wrb *pwrb, struct scatterlist *sg, 207509a1093aSJohn Soni Jose unsigned int num_sg, struct beiscsi_io_task *io_task) 207609a1093aSJohn Soni Jose { 207709a1093aSJohn Soni Jose struct iscsi_sge *psgl; 207809a1093aSJohn Soni Jose unsigned int sg_len, index; 207909a1093aSJohn Soni Jose unsigned int sge_len = 0; 208009a1093aSJohn Soni Jose unsigned long long addr; 208109a1093aSJohn Soni Jose struct scatterlist *l_sg; 208209a1093aSJohn Soni Jose unsigned int offset; 208309a1093aSJohn Soni Jose 208409a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, iscsi_bhs_addr_lo, pwrb, 208509a1093aSJohn Soni Jose io_task->bhs_pa.u.a32.address_lo); 208609a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, iscsi_bhs_addr_hi, pwrb, 208709a1093aSJohn Soni Jose io_task->bhs_pa.u.a32.address_hi); 208809a1093aSJohn Soni Jose 208909a1093aSJohn Soni Jose l_sg = sg; 209009a1093aSJohn Soni Jose for (index = 0; (index < num_sg) && (index < 2); index++, 209109a1093aSJohn Soni Jose sg = sg_next(sg)) { 209209a1093aSJohn Soni Jose if (index == 0) { 209309a1093aSJohn Soni Jose sg_len = sg_dma_len(sg); 209409a1093aSJohn Soni Jose addr = (u64) sg_dma_address(sg); 209509a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 209609a1093aSJohn Soni Jose sge0_addr_lo, pwrb, 209709a1093aSJohn Soni Jose lower_32_bits(addr)); 209809a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 209909a1093aSJohn Soni Jose sge0_addr_hi, pwrb, 210009a1093aSJohn Soni Jose upper_32_bits(addr)); 210109a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 210209a1093aSJohn Soni Jose sge0_len, pwrb, 210309a1093aSJohn Soni Jose sg_len); 210409a1093aSJohn Soni Jose sge_len = sg_len; 210509a1093aSJohn Soni Jose } else { 210609a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_r2t_offset, 210709a1093aSJohn Soni Jose pwrb, sge_len); 210809a1093aSJohn Soni Jose sg_len = sg_dma_len(sg); 210909a1093aSJohn Soni Jose addr = (u64) sg_dma_address(sg); 211009a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 211109a1093aSJohn Soni Jose sge1_addr_lo, pwrb, 211209a1093aSJohn Soni Jose lower_32_bits(addr)); 211309a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 211409a1093aSJohn Soni Jose sge1_addr_hi, pwrb, 211509a1093aSJohn Soni Jose upper_32_bits(addr)); 211609a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 211709a1093aSJohn Soni Jose sge1_len, pwrb, 211809a1093aSJohn Soni Jose sg_len); 211909a1093aSJohn Soni Jose } 212009a1093aSJohn Soni Jose } 212109a1093aSJohn Soni Jose psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; 212209a1093aSJohn Soni Jose memset(psgl, 0, sizeof(*psgl) * BE2_SGE); 212309a1093aSJohn Soni Jose 212409a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2); 212509a1093aSJohn Soni Jose 212609a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 212709a1093aSJohn Soni Jose io_task->bhs_pa.u.a32.address_hi); 212809a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 212909a1093aSJohn Soni Jose io_task->bhs_pa.u.a32.address_lo); 213009a1093aSJohn Soni Jose 213109a1093aSJohn Soni Jose if (num_sg == 1) { 213209a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge0_last, pwrb, 213309a1093aSJohn Soni Jose 1); 213409a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_last, pwrb, 213509a1093aSJohn Soni Jose 0); 213609a1093aSJohn Soni Jose } else if (num_sg == 2) { 213709a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge0_last, pwrb, 213809a1093aSJohn Soni Jose 0); 213909a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_last, pwrb, 214009a1093aSJohn Soni Jose 1); 214109a1093aSJohn Soni Jose } else { 214209a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge0_last, pwrb, 214309a1093aSJohn Soni Jose 0); 214409a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_last, pwrb, 214509a1093aSJohn Soni Jose 0); 214609a1093aSJohn Soni Jose } 214709a1093aSJohn Soni Jose 214809a1093aSJohn Soni Jose sg = l_sg; 214909a1093aSJohn Soni Jose psgl++; 215009a1093aSJohn Soni Jose psgl++; 215109a1093aSJohn Soni Jose offset = 0; 215209a1093aSJohn Soni Jose for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) { 215309a1093aSJohn Soni Jose sg_len = sg_dma_len(sg); 215409a1093aSJohn Soni Jose addr = (u64) sg_dma_address(sg); 215509a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 215609a1093aSJohn Soni Jose lower_32_bits(addr)); 215709a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 215809a1093aSJohn Soni Jose upper_32_bits(addr)); 215909a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len); 216009a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset); 216109a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); 216209a1093aSJohn Soni Jose offset += sg_len; 216309a1093aSJohn Soni Jose } 216409a1093aSJohn Soni Jose psgl--; 216509a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); 216609a1093aSJohn Soni Jose } 216709a1093aSJohn Soni Jose 216809a1093aSJohn Soni Jose static void 21696733b39aSJayamohan Kallickal hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, 21706733b39aSJayamohan Kallickal unsigned int num_sg, struct beiscsi_io_task *io_task) 21716733b39aSJayamohan Kallickal { 21726733b39aSJayamohan Kallickal struct iscsi_sge *psgl; 217358ff4bd0SJayamohan Kallickal unsigned int sg_len, index; 21746733b39aSJayamohan Kallickal unsigned int sge_len = 0; 21756733b39aSJayamohan Kallickal unsigned long long addr; 21766733b39aSJayamohan Kallickal struct scatterlist *l_sg; 21776733b39aSJayamohan Kallickal unsigned int offset; 21786733b39aSJayamohan Kallickal 21796733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb, 21806733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_lo); 21816733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb, 21826733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_hi); 21836733b39aSJayamohan Kallickal 21846733b39aSJayamohan Kallickal l_sg = sg; 218548bd86cfSJayamohan Kallickal for (index = 0; (index < num_sg) && (index < 2); index++, 218648bd86cfSJayamohan Kallickal sg = sg_next(sg)) { 21876733b39aSJayamohan Kallickal if (index == 0) { 21886733b39aSJayamohan Kallickal sg_len = sg_dma_len(sg); 21896733b39aSJayamohan Kallickal addr = (u64) sg_dma_address(sg); 21906733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, 2191457ff3b7SJayamohan Kallickal ((u32)(addr & 0xFFFFFFFF))); 21926733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, 2193457ff3b7SJayamohan Kallickal ((u32)(addr >> 32))); 21946733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, 21956733b39aSJayamohan Kallickal sg_len); 21966733b39aSJayamohan Kallickal sge_len = sg_len; 21976733b39aSJayamohan Kallickal } else { 21986733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset, 21996733b39aSJayamohan Kallickal pwrb, sge_len); 22006733b39aSJayamohan Kallickal sg_len = sg_dma_len(sg); 22016733b39aSJayamohan Kallickal addr = (u64) sg_dma_address(sg); 22026733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb, 2203457ff3b7SJayamohan Kallickal ((u32)(addr & 0xFFFFFFFF))); 22046733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb, 2205457ff3b7SJayamohan Kallickal ((u32)(addr >> 32))); 22066733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb, 22076733b39aSJayamohan Kallickal sg_len); 22086733b39aSJayamohan Kallickal } 22096733b39aSJayamohan Kallickal } 22106733b39aSJayamohan Kallickal psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; 22116733b39aSJayamohan Kallickal memset(psgl, 0, sizeof(*psgl) * BE2_SGE); 22126733b39aSJayamohan Kallickal 22136733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2); 22146733b39aSJayamohan Kallickal 22156733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 22166733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_hi); 22176733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 22186733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_lo); 22196733b39aSJayamohan Kallickal 2220caf818f1SJayamohan Kallickal if (num_sg == 1) { 2221caf818f1SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 2222caf818f1SJayamohan Kallickal 1); 2223caf818f1SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 2224caf818f1SJayamohan Kallickal 0); 2225caf818f1SJayamohan Kallickal } else if (num_sg == 2) { 2226caf818f1SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 2227caf818f1SJayamohan Kallickal 0); 2228caf818f1SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 2229caf818f1SJayamohan Kallickal 1); 2230caf818f1SJayamohan Kallickal } else { 2231caf818f1SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 2232caf818f1SJayamohan Kallickal 0); 2233caf818f1SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 2234caf818f1SJayamohan Kallickal 0); 2235caf818f1SJayamohan Kallickal } 22366733b39aSJayamohan Kallickal sg = l_sg; 22376733b39aSJayamohan Kallickal psgl++; 22386733b39aSJayamohan Kallickal psgl++; 22396733b39aSJayamohan Kallickal offset = 0; 224048bd86cfSJayamohan Kallickal for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) { 22416733b39aSJayamohan Kallickal sg_len = sg_dma_len(sg); 22426733b39aSJayamohan Kallickal addr = (u64) sg_dma_address(sg); 22436733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 22446733b39aSJayamohan Kallickal (addr & 0xFFFFFFFF)); 22456733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 22466733b39aSJayamohan Kallickal (addr >> 32)); 22476733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len); 22486733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset); 22496733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); 22506733b39aSJayamohan Kallickal offset += sg_len; 22516733b39aSJayamohan Kallickal } 22526733b39aSJayamohan Kallickal psgl--; 22536733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); 22546733b39aSJayamohan Kallickal } 22556733b39aSJayamohan Kallickal 2256d629c471SJohn Soni Jose /** 2257d629c471SJohn Soni Jose * hwi_write_buffer()- Populate the WRB with task info 2258d629c471SJohn Soni Jose * @pwrb: ptr to the WRB entry 2259d629c471SJohn Soni Jose * @task: iscsi task which is to be executed 2260d629c471SJohn Soni Jose **/ 2261e0493627SAlexey Khoroshilov static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) 22626733b39aSJayamohan Kallickal { 22636733b39aSJayamohan Kallickal struct iscsi_sge *psgl; 22646733b39aSJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 22656733b39aSJayamohan Kallickal struct beiscsi_conn *beiscsi_conn = io_task->conn; 22666733b39aSJayamohan Kallickal struct beiscsi_hba *phba = beiscsi_conn->phba; 226709a1093aSJohn Soni Jose uint8_t dsp_value = 0; 22686733b39aSJayamohan Kallickal 22696733b39aSJayamohan Kallickal io_task->bhs_len = sizeof(struct be_nonio_bhs) - 2; 22706733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb, 22716733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_lo); 22726733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb, 22736733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_hi); 22746733b39aSJayamohan Kallickal 22756733b39aSJayamohan Kallickal if (task->data) { 227609a1093aSJohn Soni Jose 227709a1093aSJohn Soni Jose /* Check for the data_count */ 227809a1093aSJohn Soni Jose dsp_value = (task->data_count) ? 1 : 0; 227909a1093aSJohn Soni Jose 22802c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) 22812c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, 228209a1093aSJohn Soni Jose pwrb, dsp_value); 228309a1093aSJohn Soni Jose else 22842c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, dsp, 228509a1093aSJohn Soni Jose pwrb, dsp_value); 228609a1093aSJohn Soni Jose 228709a1093aSJohn Soni Jose /* Map addr only if there is data_count */ 228809a1093aSJohn Soni Jose if (dsp_value) { 228926a4c991SChristoph Hellwig io_task->mtask_addr = dma_map_single(&phba->pcidev->dev, 22906733b39aSJayamohan Kallickal task->data, 2291d629c471SJohn Soni Jose task->data_count, 229226a4c991SChristoph Hellwig DMA_TO_DEVICE); 229326a4c991SChristoph Hellwig if (dma_mapping_error(&phba->pcidev->dev, 2294e0493627SAlexey Khoroshilov io_task->mtask_addr)) 2295e0493627SAlexey Khoroshilov return -ENOMEM; 2296d629c471SJohn Soni Jose io_task->mtask_data_count = task->data_count; 229709a1093aSJohn Soni Jose } else 2298d629c471SJohn Soni Jose io_task->mtask_addr = 0; 229909a1093aSJohn Soni Jose 23006733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, 2301d629c471SJohn Soni Jose lower_32_bits(io_task->mtask_addr)); 23026733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, 2303d629c471SJohn Soni Jose upper_32_bits(io_task->mtask_addr)); 23046733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, 23056733b39aSJayamohan Kallickal task->data_count); 23066733b39aSJayamohan Kallickal 23076733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 1); 23086733b39aSJayamohan Kallickal } else { 23096733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); 2310d629c471SJohn Soni Jose io_task->mtask_addr = 0; 23116733b39aSJayamohan Kallickal } 23126733b39aSJayamohan Kallickal 23136733b39aSJayamohan Kallickal psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; 23146733b39aSJayamohan Kallickal 23156733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len); 23166733b39aSJayamohan Kallickal 23176733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 23186733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_hi); 23196733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 23206733b39aSJayamohan Kallickal io_task->bhs_pa.u.a32.address_lo); 23216733b39aSJayamohan Kallickal if (task->data) { 23226733b39aSJayamohan Kallickal psgl++; 23236733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 0); 23246733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 0); 23256733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0); 23266733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, 0); 23276733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, rsvd0, psgl, 0); 23286733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); 23296733b39aSJayamohan Kallickal 23306733b39aSJayamohan Kallickal psgl++; 23316733b39aSJayamohan Kallickal if (task->data) { 23326733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 2333d629c471SJohn Soni Jose lower_32_bits(io_task->mtask_addr)); 23346733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 2335d629c471SJohn Soni Jose upper_32_bits(io_task->mtask_addr)); 23366733b39aSJayamohan Kallickal } 23376733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106); 23386733b39aSJayamohan Kallickal } 23396733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); 2340e0493627SAlexey Khoroshilov return 0; 23416733b39aSJayamohan Kallickal } 23426733b39aSJayamohan Kallickal 2343843ae752SJayamohan Kallickal /** 2344843ae752SJayamohan Kallickal * beiscsi_find_mem_req()- Find mem needed 2345843ae752SJayamohan Kallickal * @phba: ptr to HBA struct 2346843ae752SJayamohan Kallickal **/ 23476733b39aSJayamohan Kallickal static void beiscsi_find_mem_req(struct beiscsi_hba *phba) 23486733b39aSJayamohan Kallickal { 23498a86e833SJayamohan Kallickal uint8_t mem_descr_index, ulp_num; 2350fa1261c4SJitendra Bhivare unsigned int num_async_pdu_buf_pages; 23516733b39aSJayamohan Kallickal unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn; 23526733b39aSJayamohan Kallickal unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages; 23536733b39aSJayamohan Kallickal 23546733b39aSJayamohan Kallickal phba->params.hwi_ws_sz = sizeof(struct hwi_controller); 23556733b39aSJayamohan Kallickal 23566733b39aSJayamohan Kallickal phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 * 23576733b39aSJayamohan Kallickal BE_ISCSI_PDU_HEADER_SIZE; 23586733b39aSJayamohan Kallickal phba->mem_req[HWI_MEM_ADDN_CONTEXT] = 23596733b39aSJayamohan Kallickal sizeof(struct hwi_context_memory); 23606733b39aSJayamohan Kallickal 23616733b39aSJayamohan Kallickal 23626733b39aSJayamohan Kallickal phba->mem_req[HWI_MEM_WRB] = sizeof(struct iscsi_wrb) 23636733b39aSJayamohan Kallickal * (phba->params.wrbs_per_cxn) 23646733b39aSJayamohan Kallickal * phba->params.cxns_per_ctrl; 23656733b39aSJayamohan Kallickal wrb_sz_per_cxn = sizeof(struct wrb_handle) * 23666733b39aSJayamohan Kallickal (phba->params.wrbs_per_cxn); 23676733b39aSJayamohan Kallickal phba->mem_req[HWI_MEM_WRBH] = roundup_pow_of_two((wrb_sz_per_cxn) * 23686733b39aSJayamohan Kallickal phba->params.cxns_per_ctrl); 23696733b39aSJayamohan Kallickal 23706733b39aSJayamohan Kallickal phba->mem_req[HWI_MEM_SGLH] = sizeof(struct sgl_handle) * 23716733b39aSJayamohan Kallickal phba->params.icds_per_ctrl; 23726733b39aSJayamohan Kallickal phba->mem_req[HWI_MEM_SGE] = sizeof(struct iscsi_sge) * 23736733b39aSJayamohan Kallickal phba->params.num_sge_per_io * phba->params.icds_per_ctrl; 23748a86e833SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 23758a86e833SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 23766733b39aSJayamohan Kallickal 23778a86e833SJayamohan Kallickal num_async_pdu_buf_sgl_pages = 2378fecc3824SJitendra Bhivare PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( 23798a86e833SJayamohan Kallickal phba, ulp_num) * 23808a86e833SJayamohan Kallickal sizeof(struct phys_addr)); 23818a86e833SJayamohan Kallickal 23828a86e833SJayamohan Kallickal num_async_pdu_buf_pages = 2383fecc3824SJitendra Bhivare PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( 23848a86e833SJayamohan Kallickal phba, ulp_num) * 23858a86e833SJayamohan Kallickal phba->params.defpdu_hdr_sz); 23868a86e833SJayamohan Kallickal 23878a86e833SJayamohan Kallickal num_async_pdu_data_pages = 2388fecc3824SJitendra Bhivare PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( 23898a86e833SJayamohan Kallickal phba, ulp_num) * 23908a86e833SJayamohan Kallickal phba->params.defpdu_data_sz); 23918a86e833SJayamohan Kallickal 23928a86e833SJayamohan Kallickal num_async_pdu_data_sgl_pages = 2393fecc3824SJitendra Bhivare PAGES_REQUIRED(BEISCSI_ASYNC_HDQ_SIZE( 23948a86e833SJayamohan Kallickal phba, ulp_num) * 23958a86e833SJayamohan Kallickal sizeof(struct phys_addr)); 23968a86e833SJayamohan Kallickal 2397a129d92fSJayamohan Kallickal mem_descr_index = (HWI_MEM_TEMPLATE_HDR_ULP0 + 2398a129d92fSJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 2399a129d92fSJayamohan Kallickal phba->mem_req[mem_descr_index] = 2400a129d92fSJayamohan Kallickal BEISCSI_GET_CID_COUNT(phba, ulp_num) * 2401a129d92fSJayamohan Kallickal BEISCSI_TEMPLATE_HDR_PER_CXN_SIZE; 2402a129d92fSJayamohan Kallickal 24038a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_HEADER_BUF_ULP0 + 24048a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24058a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 24068a86e833SJayamohan Kallickal num_async_pdu_buf_pages * 24078a86e833SJayamohan Kallickal PAGE_SIZE; 24088a86e833SJayamohan Kallickal 24098a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_DATA_BUF_ULP0 + 24108a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24118a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 24128a86e833SJayamohan Kallickal num_async_pdu_data_pages * 24138a86e833SJayamohan Kallickal PAGE_SIZE; 24148a86e833SJayamohan Kallickal 24158a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_HEADER_RING_ULP0 + 24168a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24178a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 24188a86e833SJayamohan Kallickal num_async_pdu_buf_sgl_pages * 24198a86e833SJayamohan Kallickal PAGE_SIZE; 24208a86e833SJayamohan Kallickal 24218a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_DATA_RING_ULP0 + 24228a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24238a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 24248a86e833SJayamohan Kallickal num_async_pdu_data_sgl_pages * 24258a86e833SJayamohan Kallickal PAGE_SIZE; 24268a86e833SJayamohan Kallickal 24278a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_HEADER_HANDLE_ULP0 + 24288a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24298a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 2430fecc3824SJitendra Bhivare BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * 2431938f372cSJitendra Bhivare sizeof(struct hd_async_handle); 24328a86e833SJayamohan Kallickal 24338a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_DATA_HANDLE_ULP0 + 24348a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24358a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 2436fecc3824SJitendra Bhivare BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * 2437938f372cSJitendra Bhivare sizeof(struct hd_async_handle); 24388a86e833SJayamohan Kallickal 24398a86e833SJayamohan Kallickal mem_descr_index = (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + 24408a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 24418a86e833SJayamohan Kallickal phba->mem_req[mem_descr_index] = 2442938f372cSJitendra Bhivare sizeof(struct hd_async_context) + 2443fecc3824SJitendra Bhivare (BEISCSI_ASYNC_HDQ_SIZE(phba, ulp_num) * 2444938f372cSJitendra Bhivare sizeof(struct hd_async_entry)); 24458a86e833SJayamohan Kallickal } 24468a86e833SJayamohan Kallickal } 24476733b39aSJayamohan Kallickal } 24486733b39aSJayamohan Kallickal 24496733b39aSJayamohan Kallickal static int beiscsi_alloc_mem(struct beiscsi_hba *phba) 24506733b39aSJayamohan Kallickal { 24516733b39aSJayamohan Kallickal dma_addr_t bus_add; 2452a7909b39SJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 2453a7909b39SJayamohan Kallickal struct be_mem_descriptor *mem_descr; 24546733b39aSJayamohan Kallickal struct mem_array *mem_arr, *mem_arr_orig; 24556733b39aSJayamohan Kallickal unsigned int i, j, alloc_size, curr_alloc_size; 24566733b39aSJayamohan Kallickal 24573ec78271SJayamohan Kallickal phba->phwi_ctrlr = kzalloc(phba->params.hwi_ws_sz, GFP_KERNEL); 24586733b39aSJayamohan Kallickal if (!phba->phwi_ctrlr) 24596733b39aSJayamohan Kallickal return -ENOMEM; 24606733b39aSJayamohan Kallickal 2461a7909b39SJayamohan Kallickal /* Allocate memory for wrb_context */ 2462a7909b39SJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 24636396bb22SKees Cook phwi_ctrlr->wrb_context = kcalloc(phba->params.cxns_per_ctrl, 24646396bb22SKees Cook sizeof(struct hwi_wrb_context), 2465a7909b39SJayamohan Kallickal GFP_KERNEL); 24660c88740dSMaurizio Lombardi if (!phwi_ctrlr->wrb_context) { 24670c88740dSMaurizio Lombardi kfree(phba->phwi_ctrlr); 2468a7909b39SJayamohan Kallickal return -ENOMEM; 24690c88740dSMaurizio Lombardi } 2470a7909b39SJayamohan Kallickal 24716733b39aSJayamohan Kallickal phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr), 24726733b39aSJayamohan Kallickal GFP_KERNEL); 24736733b39aSJayamohan Kallickal if (!phba->init_mem) { 2474a7909b39SJayamohan Kallickal kfree(phwi_ctrlr->wrb_context); 24756733b39aSJayamohan Kallickal kfree(phba->phwi_ctrlr); 24766733b39aSJayamohan Kallickal return -ENOMEM; 24776733b39aSJayamohan Kallickal } 24786733b39aSJayamohan Kallickal 24796da2ec56SKees Cook mem_arr_orig = kmalloc_array(BEISCSI_MAX_FRAGS_INIT, 24806da2ec56SKees Cook sizeof(*mem_arr_orig), 24816733b39aSJayamohan Kallickal GFP_KERNEL); 24826733b39aSJayamohan Kallickal if (!mem_arr_orig) { 24836733b39aSJayamohan Kallickal kfree(phba->init_mem); 2484a7909b39SJayamohan Kallickal kfree(phwi_ctrlr->wrb_context); 24856733b39aSJayamohan Kallickal kfree(phba->phwi_ctrlr); 24866733b39aSJayamohan Kallickal return -ENOMEM; 24876733b39aSJayamohan Kallickal } 24886733b39aSJayamohan Kallickal 24896733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 24906733b39aSJayamohan Kallickal for (i = 0; i < SE_MEM_MAX; i++) { 24918a86e833SJayamohan Kallickal if (!phba->mem_req[i]) { 24928a86e833SJayamohan Kallickal mem_descr->mem_array = NULL; 24938a86e833SJayamohan Kallickal mem_descr++; 24948a86e833SJayamohan Kallickal continue; 24958a86e833SJayamohan Kallickal } 24968a86e833SJayamohan Kallickal 24976733b39aSJayamohan Kallickal j = 0; 24986733b39aSJayamohan Kallickal mem_arr = mem_arr_orig; 24996733b39aSJayamohan Kallickal alloc_size = phba->mem_req[i]; 25006733b39aSJayamohan Kallickal memset(mem_arr, 0, sizeof(struct mem_array) * 25016733b39aSJayamohan Kallickal BEISCSI_MAX_FRAGS_INIT); 25026733b39aSJayamohan Kallickal curr_alloc_size = min(be_max_phys_size * 1024, alloc_size); 25036733b39aSJayamohan Kallickal do { 250426a4c991SChristoph Hellwig mem_arr->virtual_address = 250526a4c991SChristoph Hellwig dma_alloc_coherent(&phba->pcidev->dev, 250626a4c991SChristoph Hellwig curr_alloc_size, &bus_add, GFP_KERNEL); 25076733b39aSJayamohan Kallickal if (!mem_arr->virtual_address) { 25086733b39aSJayamohan Kallickal if (curr_alloc_size <= BE_MIN_MEM_SIZE) 25096733b39aSJayamohan Kallickal goto free_mem; 25106733b39aSJayamohan Kallickal if (curr_alloc_size - 25116733b39aSJayamohan Kallickal rounddown_pow_of_two(curr_alloc_size)) 25126733b39aSJayamohan Kallickal curr_alloc_size = rounddown_pow_of_two 25136733b39aSJayamohan Kallickal (curr_alloc_size); 25146733b39aSJayamohan Kallickal else 25156733b39aSJayamohan Kallickal curr_alloc_size = curr_alloc_size / 2; 25166733b39aSJayamohan Kallickal } else { 25176733b39aSJayamohan Kallickal mem_arr->bus_address.u. 25186733b39aSJayamohan Kallickal a64.address = (__u64) bus_add; 25196733b39aSJayamohan Kallickal mem_arr->size = curr_alloc_size; 25206733b39aSJayamohan Kallickal alloc_size -= curr_alloc_size; 25216733b39aSJayamohan Kallickal curr_alloc_size = min(be_max_phys_size * 25226733b39aSJayamohan Kallickal 1024, alloc_size); 25236733b39aSJayamohan Kallickal j++; 25246733b39aSJayamohan Kallickal mem_arr++; 25256733b39aSJayamohan Kallickal } 25266733b39aSJayamohan Kallickal } while (alloc_size); 25276733b39aSJayamohan Kallickal mem_descr->num_elements = j; 25286733b39aSJayamohan Kallickal mem_descr->size_in_bytes = phba->mem_req[i]; 25296da2ec56SKees Cook mem_descr->mem_array = kmalloc_array(j, sizeof(*mem_arr), 25306733b39aSJayamohan Kallickal GFP_KERNEL); 25316733b39aSJayamohan Kallickal if (!mem_descr->mem_array) 25326733b39aSJayamohan Kallickal goto free_mem; 25336733b39aSJayamohan Kallickal 25346733b39aSJayamohan Kallickal memcpy(mem_descr->mem_array, mem_arr_orig, 25356733b39aSJayamohan Kallickal sizeof(struct mem_array) * j); 25366733b39aSJayamohan Kallickal mem_descr++; 25376733b39aSJayamohan Kallickal } 25386733b39aSJayamohan Kallickal kfree(mem_arr_orig); 25396733b39aSJayamohan Kallickal return 0; 25406733b39aSJayamohan Kallickal free_mem: 25416733b39aSJayamohan Kallickal mem_descr->num_elements = j; 25426733b39aSJayamohan Kallickal while ((i) || (j)) { 25436733b39aSJayamohan Kallickal for (j = mem_descr->num_elements; j > 0; j--) { 254426a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, 25456733b39aSJayamohan Kallickal mem_descr->mem_array[j - 1].size, 25466733b39aSJayamohan Kallickal mem_descr->mem_array[j - 1]. 25476733b39aSJayamohan Kallickal virtual_address, 2548457ff3b7SJayamohan Kallickal (unsigned long)mem_descr-> 2549457ff3b7SJayamohan Kallickal mem_array[j - 1]. 25506733b39aSJayamohan Kallickal bus_address.u.a64.address); 25516733b39aSJayamohan Kallickal } 25526733b39aSJayamohan Kallickal if (i) { 25536733b39aSJayamohan Kallickal i--; 25546733b39aSJayamohan Kallickal kfree(mem_descr->mem_array); 25556733b39aSJayamohan Kallickal mem_descr--; 25566733b39aSJayamohan Kallickal } 25576733b39aSJayamohan Kallickal } 25586733b39aSJayamohan Kallickal kfree(mem_arr_orig); 25596733b39aSJayamohan Kallickal kfree(phba->init_mem); 2560a7909b39SJayamohan Kallickal kfree(phba->phwi_ctrlr->wrb_context); 25616733b39aSJayamohan Kallickal kfree(phba->phwi_ctrlr); 25626733b39aSJayamohan Kallickal return -ENOMEM; 25636733b39aSJayamohan Kallickal } 25646733b39aSJayamohan Kallickal 25656733b39aSJayamohan Kallickal static int beiscsi_get_memory(struct beiscsi_hba *phba) 25666733b39aSJayamohan Kallickal { 25676733b39aSJayamohan Kallickal beiscsi_find_mem_req(phba); 25686733b39aSJayamohan Kallickal return beiscsi_alloc_mem(phba); 25696733b39aSJayamohan Kallickal } 25706733b39aSJayamohan Kallickal 25716733b39aSJayamohan Kallickal static void iscsi_init_global_templates(struct beiscsi_hba *phba) 25726733b39aSJayamohan Kallickal { 25736733b39aSJayamohan Kallickal struct pdu_data_out *pdata_out; 25746733b39aSJayamohan Kallickal struct pdu_nop_out *pnop_out; 25756733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 25766733b39aSJayamohan Kallickal 25776733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 25786733b39aSJayamohan Kallickal mem_descr += ISCSI_MEM_GLOBAL_HEADER; 25796733b39aSJayamohan Kallickal pdata_out = 25806733b39aSJayamohan Kallickal (struct pdu_data_out *)mem_descr->mem_array[0].virtual_address; 25816733b39aSJayamohan Kallickal memset(pdata_out, 0, BE_ISCSI_PDU_HEADER_SIZE); 25826733b39aSJayamohan Kallickal 25836733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_pdu_data_out, opcode, pdata_out, 25846733b39aSJayamohan Kallickal IIOC_SCSI_DATA); 25856733b39aSJayamohan Kallickal 25866733b39aSJayamohan Kallickal pnop_out = 25876733b39aSJayamohan Kallickal (struct pdu_nop_out *)((unsigned char *)mem_descr->mem_array[0]. 25886733b39aSJayamohan Kallickal virtual_address + BE_ISCSI_PDU_HEADER_SIZE); 25896733b39aSJayamohan Kallickal 25906733b39aSJayamohan Kallickal memset(pnop_out, 0, BE_ISCSI_PDU_HEADER_SIZE); 25916733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_pdu_nop_out, ttt, pnop_out, 0xFFFFFFFF); 25926733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_pdu_nop_out, f_bit, pnop_out, 1); 25936733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0); 25946733b39aSJayamohan Kallickal } 25956733b39aSJayamohan Kallickal 25963ec78271SJayamohan Kallickal static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba) 25976733b39aSJayamohan Kallickal { 25986733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb; 2599a7909b39SJayamohan Kallickal struct hwi_context_memory *phwi_ctxt; 26003ec78271SJayamohan Kallickal struct wrb_handle *pwrb_handle = NULL; 26016733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 26026733b39aSJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 26033ec78271SJayamohan Kallickal struct iscsi_wrb *pwrb = NULL; 26043ec78271SJayamohan Kallickal unsigned int num_cxn_wrbh = 0; 26053ec78271SJayamohan Kallickal unsigned int num_cxn_wrb = 0, j, idx = 0, index; 26066733b39aSJayamohan Kallickal 26076733b39aSJayamohan Kallickal mem_descr_wrbh = phba->init_mem; 26086733b39aSJayamohan Kallickal mem_descr_wrbh += HWI_MEM_WRBH; 26096733b39aSJayamohan Kallickal 26106733b39aSJayamohan Kallickal mem_descr_wrb = phba->init_mem; 26116733b39aSJayamohan Kallickal mem_descr_wrb += HWI_MEM_WRB; 26126733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 26136733b39aSJayamohan Kallickal 2614a7909b39SJayamohan Kallickal /* Allocate memory for WRBQ */ 2615a7909b39SJayamohan Kallickal phwi_ctxt = phwi_ctrlr->phwi_ctxt; 26166396bb22SKees Cook phwi_ctxt->be_wrbq = kcalloc(phba->params.cxns_per_ctrl, 26176396bb22SKees Cook sizeof(struct be_queue_info), 2618a7909b39SJayamohan Kallickal GFP_KERNEL); 2619a7909b39SJayamohan Kallickal if (!phwi_ctxt->be_wrbq) { 2620a7909b39SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 2621a7909b39SJayamohan Kallickal "BM_%d : WRBQ Mem Alloc Failed\n"); 2622a7909b39SJayamohan Kallickal return -ENOMEM; 2623a7909b39SJayamohan Kallickal } 2624a7909b39SJayamohan Kallickal 2625a7909b39SJayamohan Kallickal for (index = 0; index < phba->params.cxns_per_ctrl; index++) { 26266733b39aSJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[index]; 26276733b39aSJayamohan Kallickal pwrb_context->pwrb_handle_base = 26286396bb22SKees Cook kcalloc(phba->params.wrbs_per_cxn, 26296396bb22SKees Cook sizeof(struct wrb_handle *), 26306396bb22SKees Cook GFP_KERNEL); 26313ec78271SJayamohan Kallickal if (!pwrb_context->pwrb_handle_base) { 263299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 263399bc5d55SJohn Soni Jose "BM_%d : Mem Alloc Failed. Failing to load\n"); 26343ec78271SJayamohan Kallickal goto init_wrb_hndl_failed; 26353ec78271SJayamohan Kallickal } 26366733b39aSJayamohan Kallickal pwrb_context->pwrb_handle_basestd = 26376396bb22SKees Cook kcalloc(phba->params.wrbs_per_cxn, 26386396bb22SKees Cook sizeof(struct wrb_handle *), 26396396bb22SKees Cook GFP_KERNEL); 26403ec78271SJayamohan Kallickal if (!pwrb_context->pwrb_handle_basestd) { 264199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 264299bc5d55SJohn Soni Jose "BM_%d : Mem Alloc Failed. Failing to load\n"); 26433ec78271SJayamohan Kallickal goto init_wrb_hndl_failed; 26446733b39aSJayamohan Kallickal } 26453ec78271SJayamohan Kallickal if (!num_cxn_wrbh) { 26466733b39aSJayamohan Kallickal pwrb_handle = 26476733b39aSJayamohan Kallickal mem_descr_wrbh->mem_array[idx].virtual_address; 26483ec78271SJayamohan Kallickal num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) / 26496733b39aSJayamohan Kallickal ((sizeof(struct wrb_handle)) * 26506733b39aSJayamohan Kallickal phba->params.wrbs_per_cxn)); 26513ec78271SJayamohan Kallickal idx++; 26523ec78271SJayamohan Kallickal } 26536733b39aSJayamohan Kallickal pwrb_context->alloc_index = 0; 26543ec78271SJayamohan Kallickal pwrb_context->wrb_handles_available = 0; 26553ec78271SJayamohan Kallickal pwrb_context->free_index = 0; 26563ec78271SJayamohan Kallickal 26573ec78271SJayamohan Kallickal if (num_cxn_wrbh) { 26586733b39aSJayamohan Kallickal for (j = 0; j < phba->params.wrbs_per_cxn; j++) { 26596733b39aSJayamohan Kallickal pwrb_context->pwrb_handle_base[j] = pwrb_handle; 26606733b39aSJayamohan Kallickal pwrb_context->pwrb_handle_basestd[j] = 26616733b39aSJayamohan Kallickal pwrb_handle; 26626733b39aSJayamohan Kallickal pwrb_context->wrb_handles_available++; 2663bfead3b2SJayamohan Kallickal pwrb_handle->wrb_index = j; 26646733b39aSJayamohan Kallickal pwrb_handle++; 26656733b39aSJayamohan Kallickal } 26666733b39aSJayamohan Kallickal num_cxn_wrbh--; 26676733b39aSJayamohan Kallickal } 2668f64d92e6SJitendra Bhivare spin_lock_init(&pwrb_context->wrb_lock); 26696733b39aSJayamohan Kallickal } 26706733b39aSJayamohan Kallickal idx = 0; 2671a7909b39SJayamohan Kallickal for (index = 0; index < phba->params.cxns_per_ctrl; index++) { 26723ec78271SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[index]; 26733ec78271SJayamohan Kallickal if (!num_cxn_wrb) { 26746733b39aSJayamohan Kallickal pwrb = mem_descr_wrb->mem_array[idx].virtual_address; 26757c56533cSJayamohan Kallickal num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / 26767c56533cSJayamohan Kallickal ((sizeof(struct iscsi_wrb) * 26777c56533cSJayamohan Kallickal phba->params.wrbs_per_cxn)); 26783ec78271SJayamohan Kallickal idx++; 26793ec78271SJayamohan Kallickal } 26803ec78271SJayamohan Kallickal 26816733b39aSJayamohan Kallickal if (num_cxn_wrb) { 26826733b39aSJayamohan Kallickal for (j = 0; j < phba->params.wrbs_per_cxn; j++) { 26836733b39aSJayamohan Kallickal pwrb_handle = pwrb_context->pwrb_handle_base[j]; 26846733b39aSJayamohan Kallickal pwrb_handle->pwrb = pwrb; 26856733b39aSJayamohan Kallickal pwrb++; 26866733b39aSJayamohan Kallickal } 26876733b39aSJayamohan Kallickal num_cxn_wrb--; 26886733b39aSJayamohan Kallickal } 26896733b39aSJayamohan Kallickal } 26903ec78271SJayamohan Kallickal return 0; 26913ec78271SJayamohan Kallickal init_wrb_hndl_failed: 26923ec78271SJayamohan Kallickal for (j = index; j > 0; j--) { 26933ec78271SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[j]; 26943ec78271SJayamohan Kallickal kfree(pwrb_context->pwrb_handle_base); 26953ec78271SJayamohan Kallickal kfree(pwrb_context->pwrb_handle_basestd); 26963ec78271SJayamohan Kallickal } 26973ec78271SJayamohan Kallickal return -ENOMEM; 26986733b39aSJayamohan Kallickal } 26996733b39aSJayamohan Kallickal 2700a7909b39SJayamohan Kallickal static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) 27016733b39aSJayamohan Kallickal { 27028a86e833SJayamohan Kallickal uint8_t ulp_num; 27036733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 27046733b39aSJayamohan Kallickal struct hba_parameters *p = &phba->params; 2705938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx; 2706938f372cSJitendra Bhivare struct hd_async_handle *pasync_header_h, *pasync_data_h; 2707dc63aac6SJayamohan Kallickal unsigned int index, idx, num_per_mem, num_async_data; 27086733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 27096733b39aSJayamohan Kallickal 27108a86e833SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 27118a86e833SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 2712938f372cSJitendra Bhivare /* get async_ctx for each ULP */ 27136733b39aSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 27148a86e833SJayamohan Kallickal mem_descr += (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 + 27158a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET)); 27166733b39aSJayamohan Kallickal 27176733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 27188a86e833SJayamohan Kallickal phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num] = 2719938f372cSJitendra Bhivare (struct hd_async_context *) 27206733b39aSJayamohan Kallickal mem_descr->mem_array[0].virtual_address; 27218a86e833SJayamohan Kallickal 27228a86e833SJayamohan Kallickal pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num]; 27236733b39aSJayamohan Kallickal memset(pasync_ctx, 0, sizeof(*pasync_ctx)); 27246733b39aSJayamohan Kallickal 27258a86e833SJayamohan Kallickal pasync_ctx->async_entry = 2726938f372cSJitendra Bhivare (struct hd_async_entry *) 27278a86e833SJayamohan Kallickal ((long unsigned int)pasync_ctx + 2728938f372cSJitendra Bhivare sizeof(struct hd_async_context)); 2729a7909b39SJayamohan Kallickal 2730fecc3824SJitendra Bhivare pasync_ctx->num_entries = BEISCSI_ASYNC_HDQ_SIZE(phba, 27318a86e833SJayamohan Kallickal ulp_num); 2732938f372cSJitendra Bhivare /* setup header buffers */ 27336733b39aSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 27348a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_HEADER_BUF_ULP0 + 27358a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 27366733b39aSJayamohan Kallickal if (mem_descr->mem_array[0].virtual_address) { 273799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 273899bc5d55SJohn Soni Jose "BM_%d : hwi_init_async_pdu_ctx" 27398a86e833SJayamohan Kallickal " HWI_MEM_ASYNC_HEADER_BUF_ULP%d va=%p\n", 27408a86e833SJayamohan Kallickal ulp_num, 27418a86e833SJayamohan Kallickal mem_descr->mem_array[0]. 27428a86e833SJayamohan Kallickal virtual_address); 27436733b39aSJayamohan Kallickal } else 27448a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 27458a86e833SJayamohan Kallickal BEISCSI_LOG_INIT, 27468a86e833SJayamohan Kallickal "BM_%d : No Virtual address for ULP : %d\n", 27478a86e833SJayamohan Kallickal ulp_num); 27486733b39aSJayamohan Kallickal 27491e2931f1SJitendra Bhivare pasync_ctx->async_header.pi = 0; 2750938f372cSJitendra Bhivare pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; 27516733b39aSJayamohan Kallickal pasync_ctx->async_header.va_base = 27526733b39aSJayamohan Kallickal mem_descr->mem_array[0].virtual_address; 27536733b39aSJayamohan Kallickal 27546733b39aSJayamohan Kallickal pasync_ctx->async_header.pa_base.u.a64.address = 27558a86e833SJayamohan Kallickal mem_descr->mem_array[0]. 27568a86e833SJayamohan Kallickal bus_address.u.a64.address; 27576733b39aSJayamohan Kallickal 2758938f372cSJitendra Bhivare /* setup header buffer sgls */ 27596733b39aSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 27608a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_HEADER_RING_ULP0 + 27618a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 27626733b39aSJayamohan Kallickal if (mem_descr->mem_array[0].virtual_address) { 276399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 276499bc5d55SJohn Soni Jose "BM_%d : hwi_init_async_pdu_ctx" 27658a86e833SJayamohan Kallickal " HWI_MEM_ASYNC_HEADER_RING_ULP%d va=%p\n", 27668a86e833SJayamohan Kallickal ulp_num, 27678a86e833SJayamohan Kallickal mem_descr->mem_array[0]. 27688a86e833SJayamohan Kallickal virtual_address); 27696733b39aSJayamohan Kallickal } else 27708a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 27718a86e833SJayamohan Kallickal BEISCSI_LOG_INIT, 27728a86e833SJayamohan Kallickal "BM_%d : No Virtual address for ULP : %d\n", 27738a86e833SJayamohan Kallickal ulp_num); 277499bc5d55SJohn Soni Jose 27756733b39aSJayamohan Kallickal pasync_ctx->async_header.ring_base = 27766733b39aSJayamohan Kallickal mem_descr->mem_array[0].virtual_address; 27776733b39aSJayamohan Kallickal 2778938f372cSJitendra Bhivare /* setup header buffer handles */ 27796733b39aSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 27808a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE_ULP0 + 27818a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 27826733b39aSJayamohan Kallickal if (mem_descr->mem_array[0].virtual_address) { 278399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 278499bc5d55SJohn Soni Jose "BM_%d : hwi_init_async_pdu_ctx" 27858a86e833SJayamohan Kallickal " HWI_MEM_ASYNC_HEADER_HANDLE_ULP%d va=%p\n", 27868a86e833SJayamohan Kallickal ulp_num, 27878a86e833SJayamohan Kallickal mem_descr->mem_array[0]. 27888a86e833SJayamohan Kallickal virtual_address); 27896733b39aSJayamohan Kallickal } else 27908a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 27918a86e833SJayamohan Kallickal BEISCSI_LOG_INIT, 27928a86e833SJayamohan Kallickal "BM_%d : No Virtual address for ULP : %d\n", 27938a86e833SJayamohan Kallickal ulp_num); 27946733b39aSJayamohan Kallickal 27956733b39aSJayamohan Kallickal pasync_ctx->async_header.handle_base = 27966733b39aSJayamohan Kallickal mem_descr->mem_array[0].virtual_address; 27976733b39aSJayamohan Kallickal 2798938f372cSJitendra Bhivare /* setup data buffer sgls */ 27996733b39aSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 28008a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_DATA_RING_ULP0 + 28018a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 28026733b39aSJayamohan Kallickal if (mem_descr->mem_array[0].virtual_address) { 280399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 280499bc5d55SJohn Soni Jose "BM_%d : hwi_init_async_pdu_ctx" 28058a86e833SJayamohan Kallickal " HWI_MEM_ASYNC_DATA_RING_ULP%d va=%p\n", 28068a86e833SJayamohan Kallickal ulp_num, 28078a86e833SJayamohan Kallickal mem_descr->mem_array[0]. 28088a86e833SJayamohan Kallickal virtual_address); 28096733b39aSJayamohan Kallickal } else 28108a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 28118a86e833SJayamohan Kallickal BEISCSI_LOG_INIT, 28128a86e833SJayamohan Kallickal "BM_%d : No Virtual address for ULP : %d\n", 28138a86e833SJayamohan Kallickal ulp_num); 28146733b39aSJayamohan Kallickal 28156733b39aSJayamohan Kallickal pasync_ctx->async_data.ring_base = 28166733b39aSJayamohan Kallickal mem_descr->mem_array[0].virtual_address; 28176733b39aSJayamohan Kallickal 2818938f372cSJitendra Bhivare /* setup data buffer handles */ 28196733b39aSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 28208a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_DATA_HANDLE_ULP0 + 28218a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 28226733b39aSJayamohan Kallickal if (!mem_descr->mem_array[0].virtual_address) 28238a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 28248a86e833SJayamohan Kallickal BEISCSI_LOG_INIT, 28258a86e833SJayamohan Kallickal "BM_%d : No Virtual address for ULP : %d\n", 28268a86e833SJayamohan Kallickal ulp_num); 28276733b39aSJayamohan Kallickal 28286733b39aSJayamohan Kallickal pasync_ctx->async_data.handle_base = 28296733b39aSJayamohan Kallickal mem_descr->mem_array[0].virtual_address; 28306733b39aSJayamohan Kallickal 28316733b39aSJayamohan Kallickal pasync_header_h = 2832938f372cSJitendra Bhivare (struct hd_async_handle *) 28338a86e833SJayamohan Kallickal pasync_ctx->async_header.handle_base; 28346733b39aSJayamohan Kallickal pasync_data_h = 2835938f372cSJitendra Bhivare (struct hd_async_handle *) 28368a86e833SJayamohan Kallickal pasync_ctx->async_data.handle_base; 28376733b39aSJayamohan Kallickal 2838938f372cSJitendra Bhivare /* setup data buffers */ 2839dc63aac6SJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 28408a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_DATA_BUF_ULP0 + 28418a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 2842dc63aac6SJayamohan Kallickal if (mem_descr->mem_array[0].virtual_address) { 284399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 284499bc5d55SJohn Soni Jose "BM_%d : hwi_init_async_pdu_ctx" 28458a86e833SJayamohan Kallickal " HWI_MEM_ASYNC_DATA_BUF_ULP%d va=%p\n", 28468a86e833SJayamohan Kallickal ulp_num, 28478a86e833SJayamohan Kallickal mem_descr->mem_array[0]. 28488a86e833SJayamohan Kallickal virtual_address); 2849dc63aac6SJayamohan Kallickal } else 28508a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, 28518a86e833SJayamohan Kallickal BEISCSI_LOG_INIT, 28528a86e833SJayamohan Kallickal "BM_%d : No Virtual address for ULP : %d\n", 28538a86e833SJayamohan Kallickal ulp_num); 285499bc5d55SJohn Soni Jose 2855dc63aac6SJayamohan Kallickal idx = 0; 28561e2931f1SJitendra Bhivare pasync_ctx->async_data.pi = 0; 2857938f372cSJitendra Bhivare pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; 2858dc63aac6SJayamohan Kallickal pasync_ctx->async_data.va_base = 2859dc63aac6SJayamohan Kallickal mem_descr->mem_array[idx].virtual_address; 2860dc63aac6SJayamohan Kallickal pasync_ctx->async_data.pa_base.u.a64.address = 28618a86e833SJayamohan Kallickal mem_descr->mem_array[idx]. 28628a86e833SJayamohan Kallickal bus_address.u.a64.address; 2863dc63aac6SJayamohan Kallickal 2864dc63aac6SJayamohan Kallickal num_async_data = ((mem_descr->mem_array[idx].size) / 2865dc63aac6SJayamohan Kallickal phba->params.defpdu_data_sz); 2866dc63aac6SJayamohan Kallickal num_per_mem = 0; 2867dc63aac6SJayamohan Kallickal 2868fecc3824SJitendra Bhivare for (index = 0; index < BEISCSI_ASYNC_HDQ_SIZE 28698a86e833SJayamohan Kallickal (phba, ulp_num); index++) { 28706733b39aSJayamohan Kallickal pasync_header_h->cri = -1; 2871938f372cSJitendra Bhivare pasync_header_h->is_header = 1; 2872938f372cSJitendra Bhivare pasync_header_h->index = index; 28736733b39aSJayamohan Kallickal INIT_LIST_HEAD(&pasync_header_h->link); 28746733b39aSJayamohan Kallickal pasync_header_h->pbuffer = 28756733b39aSJayamohan Kallickal (void *)((unsigned long) 28768a86e833SJayamohan Kallickal (pasync_ctx-> 28778a86e833SJayamohan Kallickal async_header.va_base) + 28786733b39aSJayamohan Kallickal (p->defpdu_hdr_sz * index)); 28796733b39aSJayamohan Kallickal 28806733b39aSJayamohan Kallickal pasync_header_h->pa.u.a64.address = 28818a86e833SJayamohan Kallickal pasync_ctx->async_header.pa_base.u.a64. 28828a86e833SJayamohan Kallickal address + (p->defpdu_hdr_sz * index); 28836733b39aSJayamohan Kallickal 28841e2931f1SJitendra Bhivare pasync_ctx->async_entry[index].header = 28851e2931f1SJitendra Bhivare pasync_header_h; 28866733b39aSJayamohan Kallickal pasync_header_h++; 2887938f372cSJitendra Bhivare INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. 2888938f372cSJitendra Bhivare wq.list); 28896733b39aSJayamohan Kallickal 28906733b39aSJayamohan Kallickal pasync_data_h->cri = -1; 2891938f372cSJitendra Bhivare pasync_data_h->is_header = 0; 2892938f372cSJitendra Bhivare pasync_data_h->index = index; 28936733b39aSJayamohan Kallickal INIT_LIST_HEAD(&pasync_data_h->link); 2894dc63aac6SJayamohan Kallickal 2895dc63aac6SJayamohan Kallickal if (!num_async_data) { 2896dc63aac6SJayamohan Kallickal num_per_mem = 0; 2897dc63aac6SJayamohan Kallickal idx++; 2898dc63aac6SJayamohan Kallickal pasync_ctx->async_data.va_base = 28998a86e833SJayamohan Kallickal mem_descr->mem_array[idx]. 29008a86e833SJayamohan Kallickal virtual_address; 29018a86e833SJayamohan Kallickal pasync_ctx->async_data.pa_base.u. 29028a86e833SJayamohan Kallickal a64.address = 2903dc63aac6SJayamohan Kallickal mem_descr->mem_array[idx]. 2904dc63aac6SJayamohan Kallickal bus_address.u.a64.address; 29058a86e833SJayamohan Kallickal num_async_data = 29068a86e833SJayamohan Kallickal ((mem_descr->mem_array[idx]. 29078a86e833SJayamohan Kallickal size) / 2908dc63aac6SJayamohan Kallickal phba->params.defpdu_data_sz); 2909dc63aac6SJayamohan Kallickal } 29106733b39aSJayamohan Kallickal pasync_data_h->pbuffer = 29116733b39aSJayamohan Kallickal (void *)((unsigned long) 29126733b39aSJayamohan Kallickal (pasync_ctx->async_data.va_base) + 2913dc63aac6SJayamohan Kallickal (p->defpdu_data_sz * num_per_mem)); 29146733b39aSJayamohan Kallickal 29156733b39aSJayamohan Kallickal pasync_data_h->pa.u.a64.address = 29168a86e833SJayamohan Kallickal pasync_ctx->async_data.pa_base.u.a64. 29178a86e833SJayamohan Kallickal address + (p->defpdu_data_sz * 29188a86e833SJayamohan Kallickal num_per_mem); 2919dc63aac6SJayamohan Kallickal num_per_mem++; 2920dc63aac6SJayamohan Kallickal num_async_data--; 29216733b39aSJayamohan Kallickal 29221e2931f1SJitendra Bhivare pasync_ctx->async_entry[index].data = 29231e2931f1SJitendra Bhivare pasync_data_h; 29246733b39aSJayamohan Kallickal pasync_data_h++; 29256733b39aSJayamohan Kallickal } 29268a86e833SJayamohan Kallickal } 29278a86e833SJayamohan Kallickal } 2928a7909b39SJayamohan Kallickal 2929a7909b39SJayamohan Kallickal return 0; 29306733b39aSJayamohan Kallickal } 29316733b39aSJayamohan Kallickal 29326733b39aSJayamohan Kallickal static int 29336733b39aSJayamohan Kallickal be_sgl_create_contiguous(void *virtual_address, 29346733b39aSJayamohan Kallickal u64 physical_address, u32 length, 29356733b39aSJayamohan Kallickal struct be_dma_mem *sgl) 29366733b39aSJayamohan Kallickal { 29376733b39aSJayamohan Kallickal WARN_ON(!virtual_address); 29386733b39aSJayamohan Kallickal WARN_ON(!physical_address); 2939dd29dae0STim Gardner WARN_ON(!length); 29406733b39aSJayamohan Kallickal WARN_ON(!sgl); 29416733b39aSJayamohan Kallickal 29426733b39aSJayamohan Kallickal sgl->va = virtual_address; 2943457ff3b7SJayamohan Kallickal sgl->dma = (unsigned long)physical_address; 29446733b39aSJayamohan Kallickal sgl->size = length; 29456733b39aSJayamohan Kallickal 29466733b39aSJayamohan Kallickal return 0; 29476733b39aSJayamohan Kallickal } 29486733b39aSJayamohan Kallickal 29496733b39aSJayamohan Kallickal static void be_sgl_destroy_contiguous(struct be_dma_mem *sgl) 29506733b39aSJayamohan Kallickal { 29516733b39aSJayamohan Kallickal memset(sgl, 0, sizeof(*sgl)); 29526733b39aSJayamohan Kallickal } 29536733b39aSJayamohan Kallickal 29546733b39aSJayamohan Kallickal static void 29556733b39aSJayamohan Kallickal hwi_build_be_sgl_arr(struct beiscsi_hba *phba, 29566733b39aSJayamohan Kallickal struct mem_array *pmem, struct be_dma_mem *sgl) 29576733b39aSJayamohan Kallickal { 29586733b39aSJayamohan Kallickal if (sgl->va) 29596733b39aSJayamohan Kallickal be_sgl_destroy_contiguous(sgl); 29606733b39aSJayamohan Kallickal 29616733b39aSJayamohan Kallickal be_sgl_create_contiguous(pmem->virtual_address, 29626733b39aSJayamohan Kallickal pmem->bus_address.u.a64.address, 29636733b39aSJayamohan Kallickal pmem->size, sgl); 29646733b39aSJayamohan Kallickal } 29656733b39aSJayamohan Kallickal 29666733b39aSJayamohan Kallickal static void 29676733b39aSJayamohan Kallickal hwi_build_be_sgl_by_offset(struct beiscsi_hba *phba, 29686733b39aSJayamohan Kallickal struct mem_array *pmem, struct be_dma_mem *sgl) 29696733b39aSJayamohan Kallickal { 29706733b39aSJayamohan Kallickal if (sgl->va) 29716733b39aSJayamohan Kallickal be_sgl_destroy_contiguous(sgl); 29726733b39aSJayamohan Kallickal 29736733b39aSJayamohan Kallickal be_sgl_create_contiguous((unsigned char *)pmem->virtual_address, 29746733b39aSJayamohan Kallickal pmem->bus_address.u.a64.address, 29756733b39aSJayamohan Kallickal pmem->size, sgl); 29766733b39aSJayamohan Kallickal } 29776733b39aSJayamohan Kallickal 29786733b39aSJayamohan Kallickal static int be_fill_queue(struct be_queue_info *q, 29796733b39aSJayamohan Kallickal u16 len, u16 entry_size, void *vaddress) 29806733b39aSJayamohan Kallickal { 29816733b39aSJayamohan Kallickal struct be_dma_mem *mem = &q->dma_mem; 29826733b39aSJayamohan Kallickal 29836733b39aSJayamohan Kallickal memset(q, 0, sizeof(*q)); 29846733b39aSJayamohan Kallickal q->len = len; 29856733b39aSJayamohan Kallickal q->entry_size = entry_size; 29866733b39aSJayamohan Kallickal mem->size = len * entry_size; 29876733b39aSJayamohan Kallickal mem->va = vaddress; 29886733b39aSJayamohan Kallickal if (!mem->va) 29896733b39aSJayamohan Kallickal return -ENOMEM; 29906733b39aSJayamohan Kallickal memset(mem->va, 0, mem->size); 29916733b39aSJayamohan Kallickal return 0; 29926733b39aSJayamohan Kallickal } 29936733b39aSJayamohan Kallickal 2994bfead3b2SJayamohan Kallickal static int beiscsi_create_eqs(struct beiscsi_hba *phba, 29956733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context) 29966733b39aSJayamohan Kallickal { 2997deeea8edSChristophe JAILLET int ret = -ENOMEM, eq_for_mcc; 2998bfead3b2SJayamohan Kallickal unsigned int i, num_eq_pages; 29996733b39aSJayamohan Kallickal struct be_queue_info *eq; 30006733b39aSJayamohan Kallickal struct be_dma_mem *mem; 30016733b39aSJayamohan Kallickal void *eq_vaddress; 3002bfead3b2SJayamohan Kallickal dma_addr_t paddr; 30036733b39aSJayamohan Kallickal 3004bfead3b2SJayamohan Kallickal num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \ 3005bfead3b2SJayamohan Kallickal sizeof(struct be_eq_entry)); 3006bfead3b2SJayamohan Kallickal 300783148866SChristoph Hellwig if (phba->pcidev->msix_enabled) 3008bfead3b2SJayamohan Kallickal eq_for_mcc = 1; 3009bfead3b2SJayamohan Kallickal else 3010bfead3b2SJayamohan Kallickal eq_for_mcc = 0; 3011bfead3b2SJayamohan Kallickal for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { 3012bfead3b2SJayamohan Kallickal eq = &phwi_context->be_eq[i].q; 30136733b39aSJayamohan Kallickal mem = &eq->dma_mem; 3014bfead3b2SJayamohan Kallickal phwi_context->be_eq[i].phba = phba; 301526a4c991SChristoph Hellwig eq_vaddress = dma_alloc_coherent(&phba->pcidev->dev, 3016bfead3b2SJayamohan Kallickal num_eq_pages * PAGE_SIZE, 301726a4c991SChristoph Hellwig &paddr, GFP_KERNEL); 301884a261ffSPan Bian if (!eq_vaddress) { 301984a261ffSPan Bian ret = -ENOMEM; 3020bfead3b2SJayamohan Kallickal goto create_eq_error; 302184a261ffSPan Bian } 30226733b39aSJayamohan Kallickal 3023bfead3b2SJayamohan Kallickal mem->va = eq_vaddress; 30246733b39aSJayamohan Kallickal ret = be_fill_queue(eq, phba->params.num_eq_entries, 30256733b39aSJayamohan Kallickal sizeof(struct be_eq_entry), eq_vaddress); 30266733b39aSJayamohan Kallickal if (ret) { 302799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 302899bc5d55SJohn Soni Jose "BM_%d : be_fill_queue Failed for EQ\n"); 3029bfead3b2SJayamohan Kallickal goto create_eq_error; 30306733b39aSJayamohan Kallickal } 30316733b39aSJayamohan Kallickal 3032eeaf06afSDan Carpenter mem->dma = paddr; 30336733b39aSJayamohan Kallickal ret = beiscsi_cmd_eq_create(&phba->ctrl, eq, 303445efc940SJitendra Bhivare BEISCSI_EQ_DELAY_DEF); 30356733b39aSJayamohan Kallickal if (ret) { 303699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 303799bc5d55SJohn Soni Jose "BM_%d : beiscsi_cmd_eq_create" 30386733b39aSJayamohan Kallickal "Failed for EQ\n"); 3039bfead3b2SJayamohan Kallickal goto create_eq_error; 3040bfead3b2SJayamohan Kallickal } 304199bc5d55SJohn Soni Jose 304299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 304399bc5d55SJohn Soni Jose "BM_%d : eqid = %d\n", 304499bc5d55SJohn Soni Jose phwi_context->be_eq[i].q.id); 3045bfead3b2SJayamohan Kallickal } 3046bfead3b2SJayamohan Kallickal return 0; 3047deeea8edSChristophe JAILLET 3048bfead3b2SJayamohan Kallickal create_eq_error: 3049107dfcbaSJohn Soni Jose for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { 3050bfead3b2SJayamohan Kallickal eq = &phwi_context->be_eq[i].q; 3051bfead3b2SJayamohan Kallickal mem = &eq->dma_mem; 3052bfead3b2SJayamohan Kallickal if (mem->va) 305326a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, num_eq_pages 3054bfead3b2SJayamohan Kallickal * PAGE_SIZE, 3055bfead3b2SJayamohan Kallickal mem->va, mem->dma); 3056bfead3b2SJayamohan Kallickal } 30576733b39aSJayamohan Kallickal return ret; 30586733b39aSJayamohan Kallickal } 30596733b39aSJayamohan Kallickal 3060bfead3b2SJayamohan Kallickal static int beiscsi_create_cqs(struct beiscsi_hba *phba, 30616733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context) 30626733b39aSJayamohan Kallickal { 3063bfead3b2SJayamohan Kallickal unsigned int i, num_cq_pages; 30646733b39aSJayamohan Kallickal struct be_queue_info *cq, *eq; 30656733b39aSJayamohan Kallickal struct be_dma_mem *mem; 3066bfead3b2SJayamohan Kallickal struct be_eq_obj *pbe_eq; 30676733b39aSJayamohan Kallickal void *cq_vaddress; 3068deeea8edSChristophe JAILLET int ret = -ENOMEM; 3069bfead3b2SJayamohan Kallickal dma_addr_t paddr; 30706733b39aSJayamohan Kallickal 3071bfead3b2SJayamohan Kallickal num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ 3072bfead3b2SJayamohan Kallickal sizeof(struct sol_cqe)); 3073bfead3b2SJayamohan Kallickal 3074bfead3b2SJayamohan Kallickal for (i = 0; i < phba->num_cpus; i++) { 3075bfead3b2SJayamohan Kallickal cq = &phwi_context->be_cq[i]; 3076bfead3b2SJayamohan Kallickal eq = &phwi_context->be_eq[i].q; 3077bfead3b2SJayamohan Kallickal pbe_eq = &phwi_context->be_eq[i]; 3078bfead3b2SJayamohan Kallickal pbe_eq->cq = cq; 3079bfead3b2SJayamohan Kallickal pbe_eq->phba = phba; 30806733b39aSJayamohan Kallickal mem = &cq->dma_mem; 308126a4c991SChristoph Hellwig cq_vaddress = dma_alloc_coherent(&phba->pcidev->dev, 3082bfead3b2SJayamohan Kallickal num_cq_pages * PAGE_SIZE, 308326a4c991SChristoph Hellwig &paddr, GFP_KERNEL); 308429b33252SPan Bian if (!cq_vaddress) { 308529b33252SPan Bian ret = -ENOMEM; 3086bfead3b2SJayamohan Kallickal goto create_cq_error; 308729b33252SPan Bian } 3088deeea8edSChristophe JAILLET 30897da50879SJayamohan Kallickal ret = be_fill_queue(cq, phba->params.num_cq_entries, 30906733b39aSJayamohan Kallickal sizeof(struct sol_cqe), cq_vaddress); 30916733b39aSJayamohan Kallickal if (ret) { 309299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 309399bc5d55SJohn Soni Jose "BM_%d : be_fill_queue Failed " 309499bc5d55SJohn Soni Jose "for ISCSI CQ\n"); 3095bfead3b2SJayamohan Kallickal goto create_cq_error; 30966733b39aSJayamohan Kallickal } 30976733b39aSJayamohan Kallickal 3098eeaf06afSDan Carpenter mem->dma = paddr; 3099bfead3b2SJayamohan Kallickal ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false, 3100bfead3b2SJayamohan Kallickal false, 0); 31016733b39aSJayamohan Kallickal if (ret) { 310299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 310399bc5d55SJohn Soni Jose "BM_%d : beiscsi_cmd_eq_create" 3104bfead3b2SJayamohan Kallickal "Failed for ISCSI CQ\n"); 3105bfead3b2SJayamohan Kallickal goto create_cq_error; 31066733b39aSJayamohan Kallickal } 310799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 310899bc5d55SJohn Soni Jose "BM_%d : iscsi cq_id is %d for eq_id %d\n" 310999bc5d55SJohn Soni Jose "iSCSI CQ CREATED\n", cq->id, eq->id); 3110bfead3b2SJayamohan Kallickal } 31116733b39aSJayamohan Kallickal return 0; 3112bfead3b2SJayamohan Kallickal 3113bfead3b2SJayamohan Kallickal create_cq_error: 3114bfead3b2SJayamohan Kallickal for (i = 0; i < phba->num_cpus; i++) { 3115bfead3b2SJayamohan Kallickal cq = &phwi_context->be_cq[i]; 3116bfead3b2SJayamohan Kallickal mem = &cq->dma_mem; 3117bfead3b2SJayamohan Kallickal if (mem->va) 311826a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, num_cq_pages 3119bfead3b2SJayamohan Kallickal * PAGE_SIZE, 3120bfead3b2SJayamohan Kallickal mem->va, mem->dma); 3121bfead3b2SJayamohan Kallickal } 3122bfead3b2SJayamohan Kallickal return ret; 31236733b39aSJayamohan Kallickal } 31246733b39aSJayamohan Kallickal 31256733b39aSJayamohan Kallickal static int 31266733b39aSJayamohan Kallickal beiscsi_create_def_hdr(struct beiscsi_hba *phba, 31276733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context, 31286733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr, 31298a86e833SJayamohan Kallickal unsigned int def_pdu_ring_sz, uint8_t ulp_num) 31306733b39aSJayamohan Kallickal { 31316733b39aSJayamohan Kallickal unsigned int idx; 31326733b39aSJayamohan Kallickal int ret; 31336733b39aSJayamohan Kallickal struct be_queue_info *dq, *cq; 31346733b39aSJayamohan Kallickal struct be_dma_mem *mem; 31356733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 31366733b39aSJayamohan Kallickal void *dq_vaddress; 31376733b39aSJayamohan Kallickal 31386733b39aSJayamohan Kallickal idx = 0; 31398a86e833SJayamohan Kallickal dq = &phwi_context->be_def_hdrq[ulp_num]; 3140bfead3b2SJayamohan Kallickal cq = &phwi_context->be_cq[0]; 31416733b39aSJayamohan Kallickal mem = &dq->dma_mem; 31426733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 31438a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_HEADER_RING_ULP0 + 31448a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 31456733b39aSJayamohan Kallickal dq_vaddress = mem_descr->mem_array[idx].virtual_address; 31466733b39aSJayamohan Kallickal ret = be_fill_queue(dq, mem_descr->mem_array[0].size / 31476733b39aSJayamohan Kallickal sizeof(struct phys_addr), 31486733b39aSJayamohan Kallickal sizeof(struct phys_addr), dq_vaddress); 31496733b39aSJayamohan Kallickal if (ret) { 315099bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 31518a86e833SJayamohan Kallickal "BM_%d : be_fill_queue Failed for DEF PDU HDR on ULP : %d\n", 31528a86e833SJayamohan Kallickal ulp_num); 31538a86e833SJayamohan Kallickal 31546733b39aSJayamohan Kallickal return ret; 31556733b39aSJayamohan Kallickal } 3156457ff3b7SJayamohan Kallickal mem->dma = (unsigned long)mem_descr->mem_array[idx]. 3157457ff3b7SJayamohan Kallickal bus_address.u.a64.address; 31586733b39aSJayamohan Kallickal ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq, 31596733b39aSJayamohan Kallickal def_pdu_ring_sz, 31608a86e833SJayamohan Kallickal phba->params.defpdu_hdr_sz, 31618a86e833SJayamohan Kallickal BEISCSI_DEFQ_HDR, ulp_num); 31626733b39aSJayamohan Kallickal if (ret) { 316399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 31648a86e833SJayamohan Kallickal "BM_%d : be_cmd_create_default_pdu_queue Failed DEFHDR on ULP : %d\n", 31658a86e833SJayamohan Kallickal ulp_num); 31668a86e833SJayamohan Kallickal 31676733b39aSJayamohan Kallickal return ret; 31686733b39aSJayamohan Kallickal } 316999bc5d55SJohn Soni Jose 31708a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 31718a86e833SJayamohan Kallickal "BM_%d : iscsi hdr def pdu id for ULP : %d is %d\n", 31728a86e833SJayamohan Kallickal ulp_num, 31738a86e833SJayamohan Kallickal phwi_context->be_def_hdrq[ulp_num].id); 31746733b39aSJayamohan Kallickal return 0; 31756733b39aSJayamohan Kallickal } 31766733b39aSJayamohan Kallickal 31776733b39aSJayamohan Kallickal static int 31786733b39aSJayamohan Kallickal beiscsi_create_def_data(struct beiscsi_hba *phba, 31796733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context, 31806733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr, 31818a86e833SJayamohan Kallickal unsigned int def_pdu_ring_sz, uint8_t ulp_num) 31826733b39aSJayamohan Kallickal { 31836733b39aSJayamohan Kallickal unsigned int idx; 31846733b39aSJayamohan Kallickal int ret; 31856733b39aSJayamohan Kallickal struct be_queue_info *dataq, *cq; 31866733b39aSJayamohan Kallickal struct be_dma_mem *mem; 31876733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 31886733b39aSJayamohan Kallickal void *dq_vaddress; 31896733b39aSJayamohan Kallickal 31906733b39aSJayamohan Kallickal idx = 0; 31918a86e833SJayamohan Kallickal dataq = &phwi_context->be_def_dataq[ulp_num]; 3192bfead3b2SJayamohan Kallickal cq = &phwi_context->be_cq[0]; 31936733b39aSJayamohan Kallickal mem = &dataq->dma_mem; 31946733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 31958a86e833SJayamohan Kallickal mem_descr += HWI_MEM_ASYNC_DATA_RING_ULP0 + 31968a86e833SJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 31976733b39aSJayamohan Kallickal dq_vaddress = mem_descr->mem_array[idx].virtual_address; 31986733b39aSJayamohan Kallickal ret = be_fill_queue(dataq, mem_descr->mem_array[0].size / 31996733b39aSJayamohan Kallickal sizeof(struct phys_addr), 32006733b39aSJayamohan Kallickal sizeof(struct phys_addr), dq_vaddress); 32016733b39aSJayamohan Kallickal if (ret) { 320299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 32038a86e833SJayamohan Kallickal "BM_%d : be_fill_queue Failed for DEF PDU " 32048a86e833SJayamohan Kallickal "DATA on ULP : %d\n", 32058a86e833SJayamohan Kallickal ulp_num); 32068a86e833SJayamohan Kallickal 32076733b39aSJayamohan Kallickal return ret; 32086733b39aSJayamohan Kallickal } 3209457ff3b7SJayamohan Kallickal mem->dma = (unsigned long)mem_descr->mem_array[idx]. 3210457ff3b7SJayamohan Kallickal bus_address.u.a64.address; 32116733b39aSJayamohan Kallickal ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq, 32126733b39aSJayamohan Kallickal def_pdu_ring_sz, 32138a86e833SJayamohan Kallickal phba->params.defpdu_data_sz, 32148a86e833SJayamohan Kallickal BEISCSI_DEFQ_DATA, ulp_num); 32156733b39aSJayamohan Kallickal if (ret) { 321699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 321799bc5d55SJohn Soni Jose "BM_%d be_cmd_create_default_pdu_queue" 32188a86e833SJayamohan Kallickal " Failed for DEF PDU DATA on ULP : %d\n", 32198a86e833SJayamohan Kallickal ulp_num); 32206733b39aSJayamohan Kallickal return ret; 32216733b39aSJayamohan Kallickal } 322299bc5d55SJohn Soni Jose 322399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 32248a86e833SJayamohan Kallickal "BM_%d : iscsi def data id on ULP : %d is %d\n", 32258a86e833SJayamohan Kallickal ulp_num, 32268a86e833SJayamohan Kallickal phwi_context->be_def_dataq[ulp_num].id); 32278a86e833SJayamohan Kallickal 32288a86e833SJayamohan Kallickal beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 32298a86e833SJayamohan Kallickal "BM_%d : DEFAULT PDU DATA RING CREATED" 32308a86e833SJayamohan Kallickal "on ULP : %d\n", ulp_num); 32316733b39aSJayamohan Kallickal return 0; 32326733b39aSJayamohan Kallickal } 32336733b39aSJayamohan Kallickal 323415a90fe0SJayamohan Kallickal 323515a90fe0SJayamohan Kallickal static int 323615a90fe0SJayamohan Kallickal beiscsi_post_template_hdr(struct beiscsi_hba *phba) 323715a90fe0SJayamohan Kallickal { 323815a90fe0SJayamohan Kallickal struct be_mem_descriptor *mem_descr; 323915a90fe0SJayamohan Kallickal struct mem_array *pm_arr; 324015a90fe0SJayamohan Kallickal struct be_dma_mem sgl; 3241a129d92fSJayamohan Kallickal int status, ulp_num; 324215a90fe0SJayamohan Kallickal 3243a129d92fSJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 3244a129d92fSJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 3245a129d92fSJayamohan Kallickal mem_descr = (struct be_mem_descriptor *)phba->init_mem; 3246a129d92fSJayamohan Kallickal mem_descr += HWI_MEM_TEMPLATE_HDR_ULP0 + 3247a129d92fSJayamohan Kallickal (ulp_num * MEM_DESCR_OFFSET); 324815a90fe0SJayamohan Kallickal pm_arr = mem_descr->mem_array; 324915a90fe0SJayamohan Kallickal 325015a90fe0SJayamohan Kallickal hwi_build_be_sgl_arr(phba, pm_arr, &sgl); 3251a129d92fSJayamohan Kallickal status = be_cmd_iscsi_post_template_hdr( 3252a129d92fSJayamohan Kallickal &phba->ctrl, &sgl); 325315a90fe0SJayamohan Kallickal 325415a90fe0SJayamohan Kallickal if (status != 0) { 325515a90fe0SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 3256a129d92fSJayamohan Kallickal "BM_%d : Post Template HDR Failed for" 3257a129d92fSJayamohan Kallickal "ULP_%d\n", ulp_num); 325815a90fe0SJayamohan Kallickal return status; 325915a90fe0SJayamohan Kallickal } 326015a90fe0SJayamohan Kallickal 326115a90fe0SJayamohan Kallickal beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 3262a129d92fSJayamohan Kallickal "BM_%d : Template HDR Pages Posted for" 3263a129d92fSJayamohan Kallickal "ULP_%d\n", ulp_num); 3264a129d92fSJayamohan Kallickal } 3265a129d92fSJayamohan Kallickal } 326615a90fe0SJayamohan Kallickal return 0; 326715a90fe0SJayamohan Kallickal } 326815a90fe0SJayamohan Kallickal 32696733b39aSJayamohan Kallickal static int 32706733b39aSJayamohan Kallickal beiscsi_post_pages(struct beiscsi_hba *phba) 32716733b39aSJayamohan Kallickal { 32726733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 32736733b39aSJayamohan Kallickal struct mem_array *pm_arr; 32746733b39aSJayamohan Kallickal unsigned int page_offset, i; 32756733b39aSJayamohan Kallickal struct be_dma_mem sgl; 3276843ae752SJayamohan Kallickal int status, ulp_num = 0; 32776733b39aSJayamohan Kallickal 32786733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 32796733b39aSJayamohan Kallickal mem_descr += HWI_MEM_SGE; 32806733b39aSJayamohan Kallickal pm_arr = mem_descr->mem_array; 32816733b39aSJayamohan Kallickal 328290622db3SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) 328390622db3SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) 328490622db3SJayamohan Kallickal break; 328590622db3SJayamohan Kallickal 32866733b39aSJayamohan Kallickal page_offset = (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io * 3287843ae752SJayamohan Kallickal phba->fw_config.iscsi_icd_start[ulp_num]) / PAGE_SIZE; 32886733b39aSJayamohan Kallickal for (i = 0; i < mem_descr->num_elements; i++) { 32896733b39aSJayamohan Kallickal hwi_build_be_sgl_arr(phba, pm_arr, &sgl); 32906733b39aSJayamohan Kallickal status = be_cmd_iscsi_post_sgl_pages(&phba->ctrl, &sgl, 32916733b39aSJayamohan Kallickal page_offset, 32926733b39aSJayamohan Kallickal (pm_arr->size / PAGE_SIZE)); 32936733b39aSJayamohan Kallickal page_offset += pm_arr->size / PAGE_SIZE; 32946733b39aSJayamohan Kallickal if (status != 0) { 329599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 329699bc5d55SJohn Soni Jose "BM_%d : post sgl failed.\n"); 32976733b39aSJayamohan Kallickal return status; 32986733b39aSJayamohan Kallickal } 32996733b39aSJayamohan Kallickal pm_arr++; 33006733b39aSJayamohan Kallickal } 330199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 330299bc5d55SJohn Soni Jose "BM_%d : POSTED PAGES\n"); 33036733b39aSJayamohan Kallickal return 0; 33046733b39aSJayamohan Kallickal } 33056733b39aSJayamohan Kallickal 3306bfead3b2SJayamohan Kallickal static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q) 3307bfead3b2SJayamohan Kallickal { 3308bfead3b2SJayamohan Kallickal struct be_dma_mem *mem = &q->dma_mem; 3309c8b25598SJayamohan Kallickal if (mem->va) { 331026a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, mem->size, 3311bfead3b2SJayamohan Kallickal mem->va, mem->dma); 3312c8b25598SJayamohan Kallickal mem->va = NULL; 3313c8b25598SJayamohan Kallickal } 3314bfead3b2SJayamohan Kallickal } 3315bfead3b2SJayamohan Kallickal 3316bfead3b2SJayamohan Kallickal static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q, 3317bfead3b2SJayamohan Kallickal u16 len, u16 entry_size) 3318bfead3b2SJayamohan Kallickal { 3319bfead3b2SJayamohan Kallickal struct be_dma_mem *mem = &q->dma_mem; 3320bfead3b2SJayamohan Kallickal 3321bfead3b2SJayamohan Kallickal memset(q, 0, sizeof(*q)); 3322bfead3b2SJayamohan Kallickal q->len = len; 3323bfead3b2SJayamohan Kallickal q->entry_size = entry_size; 3324bfead3b2SJayamohan Kallickal mem->size = len * entry_size; 3325750afb08SLuis Chamberlain mem->va = dma_alloc_coherent(&phba->pcidev->dev, mem->size, &mem->dma, 332626a4c991SChristoph Hellwig GFP_KERNEL); 3327bfead3b2SJayamohan Kallickal if (!mem->va) 3328d3ad2bb3SJayamohan Kallickal return -ENOMEM; 3329bfead3b2SJayamohan Kallickal return 0; 3330bfead3b2SJayamohan Kallickal } 3331bfead3b2SJayamohan Kallickal 33326733b39aSJayamohan Kallickal static int 33336733b39aSJayamohan Kallickal beiscsi_create_wrb_rings(struct beiscsi_hba *phba, 33346733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context, 33356733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr) 33366733b39aSJayamohan Kallickal { 3337fa1261c4SJitendra Bhivare unsigned int num_wrb_rings; 33386733b39aSJayamohan Kallickal u64 pa_addr_lo; 33394eea99d5SJayamohan Kallickal unsigned int idx, num, i, ulp_num; 33406733b39aSJayamohan Kallickal struct mem_array *pwrb_arr; 33416733b39aSJayamohan Kallickal void *wrb_vaddr; 33426733b39aSJayamohan Kallickal struct be_dma_mem sgl; 33436733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 3344a7909b39SJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 33456733b39aSJayamohan Kallickal int status; 33464eea99d5SJayamohan Kallickal uint8_t ulp_count = 0, ulp_base_num = 0; 33474eea99d5SJayamohan Kallickal uint16_t cid_count_ulp[BEISCSI_ULP_COUNT] = { 0 }; 33486733b39aSJayamohan Kallickal 33496733b39aSJayamohan Kallickal idx = 0; 33506733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 33516733b39aSJayamohan Kallickal mem_descr += HWI_MEM_WRB; 33526da2ec56SKees Cook pwrb_arr = kmalloc_array(phba->params.cxns_per_ctrl, 33536da2ec56SKees Cook sizeof(*pwrb_arr), 33546733b39aSJayamohan Kallickal GFP_KERNEL); 33556733b39aSJayamohan Kallickal if (!pwrb_arr) { 335699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 335799bc5d55SJohn Soni Jose "BM_%d : Memory alloc failed in create wrb ring.\n"); 33586733b39aSJayamohan Kallickal return -ENOMEM; 33596733b39aSJayamohan Kallickal } 33606733b39aSJayamohan Kallickal wrb_vaddr = mem_descr->mem_array[idx].virtual_address; 33616733b39aSJayamohan Kallickal pa_addr_lo = mem_descr->mem_array[idx].bus_address.u.a64.address; 33626733b39aSJayamohan Kallickal num_wrb_rings = mem_descr->mem_array[idx].size / 33636733b39aSJayamohan Kallickal (phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb)); 33646733b39aSJayamohan Kallickal 33656733b39aSJayamohan Kallickal for (num = 0; num < phba->params.cxns_per_ctrl; num++) { 33666733b39aSJayamohan Kallickal if (num_wrb_rings) { 33676733b39aSJayamohan Kallickal pwrb_arr[num].virtual_address = wrb_vaddr; 33686733b39aSJayamohan Kallickal pwrb_arr[num].bus_address.u.a64.address = pa_addr_lo; 33696733b39aSJayamohan Kallickal pwrb_arr[num].size = phba->params.wrbs_per_cxn * 33706733b39aSJayamohan Kallickal sizeof(struct iscsi_wrb); 33716733b39aSJayamohan Kallickal wrb_vaddr += pwrb_arr[num].size; 33726733b39aSJayamohan Kallickal pa_addr_lo += pwrb_arr[num].size; 33736733b39aSJayamohan Kallickal num_wrb_rings--; 33746733b39aSJayamohan Kallickal } else { 33756733b39aSJayamohan Kallickal idx++; 33766733b39aSJayamohan Kallickal wrb_vaddr = mem_descr->mem_array[idx].virtual_address; 33776733b39aSJayamohan Kallickal pa_addr_lo = mem_descr->mem_array[idx].\ 33786733b39aSJayamohan Kallickal bus_address.u.a64.address; 33796733b39aSJayamohan Kallickal num_wrb_rings = mem_descr->mem_array[idx].size / 33806733b39aSJayamohan Kallickal (phba->params.wrbs_per_cxn * 33816733b39aSJayamohan Kallickal sizeof(struct iscsi_wrb)); 33826733b39aSJayamohan Kallickal pwrb_arr[num].virtual_address = wrb_vaddr; 33836733b39aSJayamohan Kallickal pwrb_arr[num].bus_address.u.a64.address\ 33846733b39aSJayamohan Kallickal = pa_addr_lo; 33856733b39aSJayamohan Kallickal pwrb_arr[num].size = phba->params.wrbs_per_cxn * 33866733b39aSJayamohan Kallickal sizeof(struct iscsi_wrb); 33876733b39aSJayamohan Kallickal wrb_vaddr += pwrb_arr[num].size; 33886733b39aSJayamohan Kallickal pa_addr_lo += pwrb_arr[num].size; 33896733b39aSJayamohan Kallickal num_wrb_rings--; 33906733b39aSJayamohan Kallickal } 33916733b39aSJayamohan Kallickal } 33924eea99d5SJayamohan Kallickal 33934eea99d5SJayamohan Kallickal /* Get the ULP Count */ 33944eea99d5SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) 33954eea99d5SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 33964eea99d5SJayamohan Kallickal ulp_count++; 33974eea99d5SJayamohan Kallickal ulp_base_num = ulp_num; 33984eea99d5SJayamohan Kallickal cid_count_ulp[ulp_num] = 33994eea99d5SJayamohan Kallickal BEISCSI_GET_CID_COUNT(phba, ulp_num); 34004eea99d5SJayamohan Kallickal } 34014eea99d5SJayamohan Kallickal 34026733b39aSJayamohan Kallickal for (i = 0; i < phba->params.cxns_per_ctrl; i++) { 34034eea99d5SJayamohan Kallickal if (ulp_count > 1) { 34044eea99d5SJayamohan Kallickal ulp_base_num = (ulp_base_num + 1) % BEISCSI_ULP_COUNT; 34054eea99d5SJayamohan Kallickal 34064eea99d5SJayamohan Kallickal if (!cid_count_ulp[ulp_base_num]) 34074eea99d5SJayamohan Kallickal ulp_base_num = (ulp_base_num + 1) % 34084eea99d5SJayamohan Kallickal BEISCSI_ULP_COUNT; 34094eea99d5SJayamohan Kallickal 34104eea99d5SJayamohan Kallickal cid_count_ulp[ulp_base_num]--; 34114eea99d5SJayamohan Kallickal } 34124eea99d5SJayamohan Kallickal 34134eea99d5SJayamohan Kallickal 34146733b39aSJayamohan Kallickal hwi_build_be_sgl_by_offset(phba, &pwrb_arr[i], &sgl); 34156733b39aSJayamohan Kallickal status = be_cmd_wrbq_create(&phba->ctrl, &sgl, 34164eea99d5SJayamohan Kallickal &phwi_context->be_wrbq[i], 34174eea99d5SJayamohan Kallickal &phwi_ctrlr->wrb_context[i], 34184eea99d5SJayamohan Kallickal ulp_base_num); 34196733b39aSJayamohan Kallickal if (status != 0) { 342099bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 342199bc5d55SJohn Soni Jose "BM_%d : wrbq create failed."); 34221462b8ffSDan Carpenter kfree(pwrb_arr); 34236733b39aSJayamohan Kallickal return status; 34246733b39aSJayamohan Kallickal } 3425a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[i]; 3426a7909b39SJayamohan Kallickal BE_SET_CID_TO_CRI(i, pwrb_context->cid); 34276733b39aSJayamohan Kallickal } 34286733b39aSJayamohan Kallickal kfree(pwrb_arr); 34296733b39aSJayamohan Kallickal return 0; 34306733b39aSJayamohan Kallickal } 34316733b39aSJayamohan Kallickal 34326733b39aSJayamohan Kallickal static void free_wrb_handles(struct beiscsi_hba *phba) 34336733b39aSJayamohan Kallickal { 34346733b39aSJayamohan Kallickal unsigned int index; 34356733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 34366733b39aSJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 34376733b39aSJayamohan Kallickal 34386733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 3439a7909b39SJayamohan Kallickal for (index = 0; index < phba->params.cxns_per_ctrl; index++) { 34406733b39aSJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[index]; 34416733b39aSJayamohan Kallickal kfree(pwrb_context->pwrb_handle_base); 34426733b39aSJayamohan Kallickal kfree(pwrb_context->pwrb_handle_basestd); 34436733b39aSJayamohan Kallickal } 34446733b39aSJayamohan Kallickal } 34456733b39aSJayamohan Kallickal 3446bfead3b2SJayamohan Kallickal static void be_mcc_queues_destroy(struct beiscsi_hba *phba) 3447bfead3b2SJayamohan Kallickal { 3448bfead3b2SJayamohan Kallickal struct be_ctrl_info *ctrl = &phba->ctrl; 3449d1d5ca88SJitendra Bhivare struct be_dma_mem *ptag_mem; 3450d1d5ca88SJitendra Bhivare struct be_queue_info *q; 3451d1d5ca88SJitendra Bhivare int i, tag; 3452bfead3b2SJayamohan Kallickal 3453bfead3b2SJayamohan Kallickal q = &phba->ctrl.mcc_obj.q; 3454d1d5ca88SJitendra Bhivare for (i = 0; i < MAX_MCC_CMD; i++) { 3455d1d5ca88SJitendra Bhivare tag = i + 1; 3456d1d5ca88SJitendra Bhivare if (!test_bit(MCC_TAG_STATE_RUNNING, 3457d1d5ca88SJitendra Bhivare &ctrl->ptag_state[tag].tag_state)) 3458d1d5ca88SJitendra Bhivare continue; 3459d1d5ca88SJitendra Bhivare 3460d1d5ca88SJitendra Bhivare if (test_bit(MCC_TAG_STATE_TIMEOUT, 3461d1d5ca88SJitendra Bhivare &ctrl->ptag_state[tag].tag_state)) { 3462d1d5ca88SJitendra Bhivare ptag_mem = &ctrl->ptag_state[tag].tag_mem_state; 3463d1d5ca88SJitendra Bhivare if (ptag_mem->size) { 346426a4c991SChristoph Hellwig dma_free_coherent(&ctrl->pdev->dev, 3465d1d5ca88SJitendra Bhivare ptag_mem->size, 3466d1d5ca88SJitendra Bhivare ptag_mem->va, 3467d1d5ca88SJitendra Bhivare ptag_mem->dma); 3468d1d5ca88SJitendra Bhivare ptag_mem->size = 0; 3469d1d5ca88SJitendra Bhivare } 3470d1d5ca88SJitendra Bhivare continue; 3471d1d5ca88SJitendra Bhivare } 3472d1d5ca88SJitendra Bhivare /** 3473d1d5ca88SJitendra Bhivare * If MCC is still active and waiting then wake up the process. 3474d1d5ca88SJitendra Bhivare * We are here only because port is going offline. The process 3475d1d5ca88SJitendra Bhivare * sees that (BEISCSI_HBA_ONLINE is cleared) and EIO error is 3476d1d5ca88SJitendra Bhivare * returned for the operation and allocated memory cleaned up. 3477d1d5ca88SJitendra Bhivare */ 3478d1d5ca88SJitendra Bhivare if (waitqueue_active(&ctrl->mcc_wait[tag])) { 3479d1d5ca88SJitendra Bhivare ctrl->mcc_tag_status[tag] = MCC_STATUS_FAILED; 3480d1d5ca88SJitendra Bhivare ctrl->mcc_tag_status[tag] |= CQE_VALID_MASK; 3481d1d5ca88SJitendra Bhivare wake_up_interruptible(&ctrl->mcc_wait[tag]); 3482d1d5ca88SJitendra Bhivare /* 3483d1d5ca88SJitendra Bhivare * Control tag info gets reinitialized in enable 3484d1d5ca88SJitendra Bhivare * so wait for the process to clear running state. 3485d1d5ca88SJitendra Bhivare */ 3486d1d5ca88SJitendra Bhivare while (test_bit(MCC_TAG_STATE_RUNNING, 3487d1d5ca88SJitendra Bhivare &ctrl->ptag_state[tag].tag_state)) 3488d1d5ca88SJitendra Bhivare schedule_timeout_uninterruptible(HZ); 3489d1d5ca88SJitendra Bhivare } 3490d1d5ca88SJitendra Bhivare /** 3491d1d5ca88SJitendra Bhivare * For MCC with tag_states MCC_TAG_STATE_ASYNC and 3492d1d5ca88SJitendra Bhivare * MCC_TAG_STATE_IGNORE nothing needs to done. 3493d1d5ca88SJitendra Bhivare */ 3494d1d5ca88SJitendra Bhivare } 34954e2bdf7aSJohn Soni Jose if (q->created) { 3496bfead3b2SJayamohan Kallickal beiscsi_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); 3497bfead3b2SJayamohan Kallickal be_queue_free(phba, q); 34984e2bdf7aSJohn Soni Jose } 3499bfead3b2SJayamohan Kallickal 3500bfead3b2SJayamohan Kallickal q = &phba->ctrl.mcc_obj.cq; 35014e2bdf7aSJohn Soni Jose if (q->created) { 3502bfead3b2SJayamohan Kallickal beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); 3503bfead3b2SJayamohan Kallickal be_queue_free(phba, q); 3504bfead3b2SJayamohan Kallickal } 35054e2bdf7aSJohn Soni Jose } 3506bfead3b2SJayamohan Kallickal 3507bfead3b2SJayamohan Kallickal static int be_mcc_queues_create(struct beiscsi_hba *phba, 3508bfead3b2SJayamohan Kallickal struct hwi_context_memory *phwi_context) 3509bfead3b2SJayamohan Kallickal { 3510bfead3b2SJayamohan Kallickal struct be_queue_info *q, *cq; 3511bfead3b2SJayamohan Kallickal struct be_ctrl_info *ctrl = &phba->ctrl; 3512bfead3b2SJayamohan Kallickal 3513bfead3b2SJayamohan Kallickal /* Alloc MCC compl queue */ 3514bfead3b2SJayamohan Kallickal cq = &phba->ctrl.mcc_obj.cq; 3515bfead3b2SJayamohan Kallickal if (be_queue_alloc(phba, cq, MCC_CQ_LEN, 3516bfead3b2SJayamohan Kallickal sizeof(struct be_mcc_compl))) 3517bfead3b2SJayamohan Kallickal goto err; 3518bfead3b2SJayamohan Kallickal /* Ask BE to create MCC compl queue; */ 351983148866SChristoph Hellwig if (phba->pcidev->msix_enabled) { 352045efc940SJitendra Bhivare if (beiscsi_cmd_cq_create(ctrl, cq, 352145efc940SJitendra Bhivare &phwi_context->be_eq[phba->num_cpus].q, 352245efc940SJitendra Bhivare false, true, 0)) 3523bfead3b2SJayamohan Kallickal goto mcc_cq_free; 3524bfead3b2SJayamohan Kallickal } else { 3525bfead3b2SJayamohan Kallickal if (beiscsi_cmd_cq_create(ctrl, cq, &phwi_context->be_eq[0].q, 3526bfead3b2SJayamohan Kallickal false, true, 0)) 3527bfead3b2SJayamohan Kallickal goto mcc_cq_free; 3528bfead3b2SJayamohan Kallickal } 3529bfead3b2SJayamohan Kallickal 3530bfead3b2SJayamohan Kallickal /* Alloc MCC queue */ 3531bfead3b2SJayamohan Kallickal q = &phba->ctrl.mcc_obj.q; 3532bfead3b2SJayamohan Kallickal if (be_queue_alloc(phba, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) 3533bfead3b2SJayamohan Kallickal goto mcc_cq_destroy; 3534bfead3b2SJayamohan Kallickal 3535bfead3b2SJayamohan Kallickal /* Ask BE to create MCC queue */ 353635e66019SJayamohan Kallickal if (beiscsi_cmd_mccq_create(phba, q, cq)) 3537bfead3b2SJayamohan Kallickal goto mcc_q_free; 3538bfead3b2SJayamohan Kallickal 3539bfead3b2SJayamohan Kallickal return 0; 3540bfead3b2SJayamohan Kallickal 3541bfead3b2SJayamohan Kallickal mcc_q_free: 3542bfead3b2SJayamohan Kallickal be_queue_free(phba, q); 3543bfead3b2SJayamohan Kallickal mcc_cq_destroy: 3544bfead3b2SJayamohan Kallickal beiscsi_cmd_q_destroy(ctrl, cq, QTYPE_CQ); 3545bfead3b2SJayamohan Kallickal mcc_cq_free: 3546bfead3b2SJayamohan Kallickal be_queue_free(phba, cq); 3547bfead3b2SJayamohan Kallickal err: 3548d3ad2bb3SJayamohan Kallickal return -ENOMEM; 3549bfead3b2SJayamohan Kallickal } 3550bfead3b2SJayamohan Kallickal 355183148866SChristoph Hellwig static void be2iscsi_enable_msix(struct beiscsi_hba *phba) 3552bfead3b2SJayamohan Kallickal { 355383148866SChristoph Hellwig int nvec = 1; 3554bfead3b2SJayamohan Kallickal 355522abeef0SJohn Soni Jose switch (phba->generation) { 355622abeef0SJohn Soni Jose case BE_GEN2: 355722abeef0SJohn Soni Jose case BE_GEN3: 355883148866SChristoph Hellwig nvec = BEISCSI_MAX_NUM_CPUS + 1; 355922abeef0SJohn Soni Jose break; 356022abeef0SJohn Soni Jose case BE_GEN4: 356183148866SChristoph Hellwig nvec = phba->fw_config.eqid_count; 356222abeef0SJohn Soni Jose break; 356322abeef0SJohn Soni Jose default: 356483148866SChristoph Hellwig nvec = 2; 356583148866SChristoph Hellwig break; 356622abeef0SJohn Soni Jose } 356783148866SChristoph Hellwig 356883148866SChristoph Hellwig /* if eqid_count == 1 fall back to INTX */ 356983148866SChristoph Hellwig if (enable_msix && nvec > 1) { 3570c66d4bd1SMing Lei struct irq_affinity desc = { .post_vectors = 1 }; 357183148866SChristoph Hellwig 357283148866SChristoph Hellwig if (pci_alloc_irq_vectors_affinity(phba->pcidev, 2, nvec, 357383148866SChristoph Hellwig PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, &desc) < 0) { 357483148866SChristoph Hellwig phba->num_cpus = nvec - 1; 357583148866SChristoph Hellwig return; 357683148866SChristoph Hellwig } 357783148866SChristoph Hellwig } 357883148866SChristoph Hellwig 357983148866SChristoph Hellwig phba->num_cpus = 1; 3580bfead3b2SJayamohan Kallickal } 35816733b39aSJayamohan Kallickal 3582d1d5ca88SJitendra Bhivare static void hwi_purge_eq(struct beiscsi_hba *phba) 3583d1d5ca88SJitendra Bhivare { 3584d1d5ca88SJitendra Bhivare struct hwi_controller *phwi_ctrlr; 3585d1d5ca88SJitendra Bhivare struct hwi_context_memory *phwi_context; 3586d1d5ca88SJitendra Bhivare struct be_queue_info *eq; 3587d1d5ca88SJitendra Bhivare struct be_eq_entry *eqe = NULL; 3588d1d5ca88SJitendra Bhivare int i, eq_msix; 3589d1d5ca88SJitendra Bhivare unsigned int num_processed; 3590d1d5ca88SJitendra Bhivare 3591d1d5ca88SJitendra Bhivare if (beiscsi_hba_in_error(phba)) 3592d1d5ca88SJitendra Bhivare return; 3593d1d5ca88SJitendra Bhivare 3594d1d5ca88SJitendra Bhivare phwi_ctrlr = phba->phwi_ctrlr; 3595d1d5ca88SJitendra Bhivare phwi_context = phwi_ctrlr->phwi_ctxt; 359683148866SChristoph Hellwig if (phba->pcidev->msix_enabled) 3597d1d5ca88SJitendra Bhivare eq_msix = 1; 3598d1d5ca88SJitendra Bhivare else 3599d1d5ca88SJitendra Bhivare eq_msix = 0; 3600d1d5ca88SJitendra Bhivare 3601d1d5ca88SJitendra Bhivare for (i = 0; i < (phba->num_cpus + eq_msix); i++) { 3602d1d5ca88SJitendra Bhivare eq = &phwi_context->be_eq[i].q; 3603d1d5ca88SJitendra Bhivare eqe = queue_tail_node(eq); 3604d1d5ca88SJitendra Bhivare num_processed = 0; 3605d1d5ca88SJitendra Bhivare while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] 3606d1d5ca88SJitendra Bhivare & EQE_VALID_MASK) { 3607d1d5ca88SJitendra Bhivare AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); 3608d1d5ca88SJitendra Bhivare queue_tail_inc(eq); 3609d1d5ca88SJitendra Bhivare eqe = queue_tail_node(eq); 3610d1d5ca88SJitendra Bhivare num_processed++; 3611d1d5ca88SJitendra Bhivare } 3612d1d5ca88SJitendra Bhivare 3613d1d5ca88SJitendra Bhivare if (num_processed) 3614d1d5ca88SJitendra Bhivare hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); 3615d1d5ca88SJitendra Bhivare } 3616d1d5ca88SJitendra Bhivare } 3617d1d5ca88SJitendra Bhivare 3618d1d5ca88SJitendra Bhivare static void hwi_cleanup_port(struct beiscsi_hba *phba) 3619d1d5ca88SJitendra Bhivare { 3620d1d5ca88SJitendra Bhivare struct be_queue_info *q; 3621d1d5ca88SJitendra Bhivare struct be_ctrl_info *ctrl = &phba->ctrl; 3622d1d5ca88SJitendra Bhivare struct hwi_controller *phwi_ctrlr; 3623d1d5ca88SJitendra Bhivare struct hwi_context_memory *phwi_context; 3624d1d5ca88SJitendra Bhivare int i, eq_for_mcc, ulp_num; 3625d1d5ca88SJitendra Bhivare 3626d1d5ca88SJitendra Bhivare for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) 3627d1d5ca88SJitendra Bhivare if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) 3628d1d5ca88SJitendra Bhivare beiscsi_cmd_iscsi_cleanup(phba, ulp_num); 3629d1d5ca88SJitendra Bhivare 3630d1d5ca88SJitendra Bhivare /** 3631d1d5ca88SJitendra Bhivare * Purge all EQ entries that may have been left out. This is to 3632d1d5ca88SJitendra Bhivare * workaround a problem we've seen occasionally where driver gets an 3633d1d5ca88SJitendra Bhivare * interrupt with EQ entry bit set after stopping the controller. 3634d1d5ca88SJitendra Bhivare */ 3635d1d5ca88SJitendra Bhivare hwi_purge_eq(phba); 3636d1d5ca88SJitendra Bhivare 3637d1d5ca88SJitendra Bhivare phwi_ctrlr = phba->phwi_ctrlr; 3638d1d5ca88SJitendra Bhivare phwi_context = phwi_ctrlr->phwi_ctxt; 3639d1d5ca88SJitendra Bhivare 3640d1d5ca88SJitendra Bhivare be_cmd_iscsi_remove_template_hdr(ctrl); 3641d1d5ca88SJitendra Bhivare 3642d1d5ca88SJitendra Bhivare for (i = 0; i < phba->params.cxns_per_ctrl; i++) { 3643d1d5ca88SJitendra Bhivare q = &phwi_context->be_wrbq[i]; 3644d1d5ca88SJitendra Bhivare if (q->created) 3645d1d5ca88SJitendra Bhivare beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ); 3646d1d5ca88SJitendra Bhivare } 3647d1d5ca88SJitendra Bhivare kfree(phwi_context->be_wrbq); 3648d1d5ca88SJitendra Bhivare free_wrb_handles(phba); 3649d1d5ca88SJitendra Bhivare 3650d1d5ca88SJitendra Bhivare for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 3651d1d5ca88SJitendra Bhivare if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 3652d1d5ca88SJitendra Bhivare 3653d1d5ca88SJitendra Bhivare q = &phwi_context->be_def_hdrq[ulp_num]; 3654d1d5ca88SJitendra Bhivare if (q->created) 3655d1d5ca88SJitendra Bhivare beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); 3656d1d5ca88SJitendra Bhivare 3657d1d5ca88SJitendra Bhivare q = &phwi_context->be_def_dataq[ulp_num]; 3658d1d5ca88SJitendra Bhivare if (q->created) 3659d1d5ca88SJitendra Bhivare beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); 3660d1d5ca88SJitendra Bhivare } 3661d1d5ca88SJitendra Bhivare } 3662d1d5ca88SJitendra Bhivare 3663d1d5ca88SJitendra Bhivare beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); 3664d1d5ca88SJitendra Bhivare 3665d1d5ca88SJitendra Bhivare for (i = 0; i < (phba->num_cpus); i++) { 3666d1d5ca88SJitendra Bhivare q = &phwi_context->be_cq[i]; 3667d1d5ca88SJitendra Bhivare if (q->created) { 3668d1d5ca88SJitendra Bhivare be_queue_free(phba, q); 3669d1d5ca88SJitendra Bhivare beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); 3670d1d5ca88SJitendra Bhivare } 3671d1d5ca88SJitendra Bhivare } 3672d1d5ca88SJitendra Bhivare 3673d1d5ca88SJitendra Bhivare be_mcc_queues_destroy(phba); 367483148866SChristoph Hellwig if (phba->pcidev->msix_enabled) 3675d1d5ca88SJitendra Bhivare eq_for_mcc = 1; 3676d1d5ca88SJitendra Bhivare else 3677d1d5ca88SJitendra Bhivare eq_for_mcc = 0; 3678d1d5ca88SJitendra Bhivare for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { 3679d1d5ca88SJitendra Bhivare q = &phwi_context->be_eq[i].q; 3680d1d5ca88SJitendra Bhivare if (q->created) { 3681d1d5ca88SJitendra Bhivare be_queue_free(phba, q); 3682d1d5ca88SJitendra Bhivare beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ); 3683d1d5ca88SJitendra Bhivare } 3684d1d5ca88SJitendra Bhivare } 36854ee1ec42SJitendra Bhivare /* this ensures complete FW cleanup */ 36864ee1ec42SJitendra Bhivare beiscsi_cmd_function_reset(phba); 3687d1d5ca88SJitendra Bhivare /* last communication, indicate driver is unloading */ 3688d1d5ca88SJitendra Bhivare beiscsi_cmd_special_wrb(&phba->ctrl, 0); 3689d1d5ca88SJitendra Bhivare } 36904ee1ec42SJitendra Bhivare 36916733b39aSJayamohan Kallickal static int hwi_init_port(struct beiscsi_hba *phba) 36926733b39aSJayamohan Kallickal { 36936733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 36946733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context; 36956733b39aSJayamohan Kallickal unsigned int def_pdu_ring_sz; 36966733b39aSJayamohan Kallickal struct be_ctrl_info *ctrl = &phba->ctrl; 36978a86e833SJayamohan Kallickal int status, ulp_num; 36981e2931f1SJitendra Bhivare u16 nbufs; 36996733b39aSJayamohan Kallickal 37006733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 37016733b39aSJayamohan Kallickal phwi_context = phwi_ctrlr->phwi_ctxt; 37024d2ee1e6SJitendra Bhivare /* set port optic state to unknown */ 370353aefe25SJitendra Bhivare phba->optic_state = 0xff; 3704bfead3b2SJayamohan Kallickal 3705bfead3b2SJayamohan Kallickal status = beiscsi_create_eqs(phba, phwi_context); 37066733b39aSJayamohan Kallickal if (status != 0) { 370799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 370899bc5d55SJohn Soni Jose "BM_%d : EQ not created\n"); 37096733b39aSJayamohan Kallickal goto error; 37106733b39aSJayamohan Kallickal } 37116733b39aSJayamohan Kallickal 3712bfead3b2SJayamohan Kallickal status = be_mcc_queues_create(phba, phwi_context); 3713bfead3b2SJayamohan Kallickal if (status != 0) 3714bfead3b2SJayamohan Kallickal goto error; 3715bfead3b2SJayamohan Kallickal 3716480195c2SJitendra Bhivare status = beiscsi_check_supported_fw(ctrl, phba); 37176733b39aSJayamohan Kallickal if (status != 0) { 371899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 371999bc5d55SJohn Soni Jose "BM_%d : Unsupported fw version\n"); 37206733b39aSJayamohan Kallickal goto error; 37216733b39aSJayamohan Kallickal } 37226733b39aSJayamohan Kallickal 3723bfead3b2SJayamohan Kallickal status = beiscsi_create_cqs(phba, phwi_context); 37246733b39aSJayamohan Kallickal if (status != 0) { 372599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 372699bc5d55SJohn Soni Jose "BM_%d : CQ not created\n"); 37276733b39aSJayamohan Kallickal goto error; 37286733b39aSJayamohan Kallickal } 37296733b39aSJayamohan Kallickal 37308a86e833SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 37318a86e833SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 37321e2931f1SJitendra Bhivare nbufs = phwi_context->pasync_ctx[ulp_num]->num_entries; 37331e2931f1SJitendra Bhivare def_pdu_ring_sz = nbufs * sizeof(struct phys_addr); 37348a86e833SJayamohan Kallickal 37358a86e833SJayamohan Kallickal status = beiscsi_create_def_hdr(phba, phwi_context, 37368a86e833SJayamohan Kallickal phwi_ctrlr, 37378a86e833SJayamohan Kallickal def_pdu_ring_sz, 37388a86e833SJayamohan Kallickal ulp_num); 37396733b39aSJayamohan Kallickal if (status != 0) { 374099bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 37418a86e833SJayamohan Kallickal "BM_%d : Default Header not created for ULP : %d\n", 37428a86e833SJayamohan Kallickal ulp_num); 37436733b39aSJayamohan Kallickal goto error; 37446733b39aSJayamohan Kallickal } 37456733b39aSJayamohan Kallickal 37466733b39aSJayamohan Kallickal status = beiscsi_create_def_data(phba, phwi_context, 37478a86e833SJayamohan Kallickal phwi_ctrlr, 37488a86e833SJayamohan Kallickal def_pdu_ring_sz, 37498a86e833SJayamohan Kallickal ulp_num); 37506733b39aSJayamohan Kallickal if (status != 0) { 375199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 37528a86e833SJayamohan Kallickal "BM_%d : Default Data not created for ULP : %d\n", 37538a86e833SJayamohan Kallickal ulp_num); 37546733b39aSJayamohan Kallickal goto error; 37556733b39aSJayamohan Kallickal } 3756f79929deSJitendra Bhivare /** 3757f79929deSJitendra Bhivare * Now that the default PDU rings have been created, 3758f79929deSJitendra Bhivare * let EP know about it. 3759f79929deSJitendra Bhivare */ 3760938f372cSJitendra Bhivare beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR, 37611e2931f1SJitendra Bhivare ulp_num, nbufs); 3762938f372cSJitendra Bhivare beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA, 37631e2931f1SJitendra Bhivare ulp_num, nbufs); 37648a86e833SJayamohan Kallickal } 37658a86e833SJayamohan Kallickal } 37666733b39aSJayamohan Kallickal 37676733b39aSJayamohan Kallickal status = beiscsi_post_pages(phba); 37686733b39aSJayamohan Kallickal if (status != 0) { 376999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 377099bc5d55SJohn Soni Jose "BM_%d : Post SGL Pages Failed\n"); 37716733b39aSJayamohan Kallickal goto error; 37726733b39aSJayamohan Kallickal } 37736733b39aSJayamohan Kallickal 377415a90fe0SJayamohan Kallickal status = beiscsi_post_template_hdr(phba); 377515a90fe0SJayamohan Kallickal if (status != 0) { 377615a90fe0SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 377715a90fe0SJayamohan Kallickal "BM_%d : Template HDR Posting for CXN Failed\n"); 377815a90fe0SJayamohan Kallickal } 377915a90fe0SJayamohan Kallickal 37806733b39aSJayamohan Kallickal status = beiscsi_create_wrb_rings(phba, phwi_context, phwi_ctrlr); 37816733b39aSJayamohan Kallickal if (status != 0) { 378299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 378399bc5d55SJohn Soni Jose "BM_%d : WRB Rings not created\n"); 37846733b39aSJayamohan Kallickal goto error; 37856733b39aSJayamohan Kallickal } 37866733b39aSJayamohan Kallickal 37878a86e833SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 37888a86e833SJayamohan Kallickal uint16_t async_arr_idx = 0; 37898a86e833SJayamohan Kallickal 37908a86e833SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) { 37918a86e833SJayamohan Kallickal uint16_t cri = 0; 3792938f372cSJitendra Bhivare struct hd_async_context *pasync_ctx; 37938a86e833SJayamohan Kallickal 37948a86e833SJayamohan Kallickal pasync_ctx = HWI_GET_ASYNC_PDU_CTX( 37958a86e833SJayamohan Kallickal phwi_ctrlr, ulp_num); 37968a86e833SJayamohan Kallickal for (cri = 0; cri < 37978a86e833SJayamohan Kallickal phba->params.cxns_per_ctrl; cri++) { 37988a86e833SJayamohan Kallickal if (ulp_num == BEISCSI_GET_ULP_FROM_CRI 37998a86e833SJayamohan Kallickal (phwi_ctrlr, cri)) 38008a86e833SJayamohan Kallickal pasync_ctx->cid_to_async_cri_map[ 38018a86e833SJayamohan Kallickal phwi_ctrlr->wrb_context[cri].cid] = 38028a86e833SJayamohan Kallickal async_arr_idx++; 38038a86e833SJayamohan Kallickal } 38048a86e833SJayamohan Kallickal } 38058a86e833SJayamohan Kallickal } 38068a86e833SJayamohan Kallickal 380799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 380899bc5d55SJohn Soni Jose "BM_%d : hwi_init_port success\n"); 38096733b39aSJayamohan Kallickal return 0; 38106733b39aSJayamohan Kallickal 38116733b39aSJayamohan Kallickal error: 381299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 381399bc5d55SJohn Soni Jose "BM_%d : hwi_init_port failed"); 38144d2ee1e6SJitendra Bhivare hwi_cleanup_port(phba); 3815a49e06d5SJayamohan Kallickal return status; 38166733b39aSJayamohan Kallickal } 38176733b39aSJayamohan Kallickal 38186733b39aSJayamohan Kallickal static int hwi_init_controller(struct beiscsi_hba *phba) 38196733b39aSJayamohan Kallickal { 38206733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 38216733b39aSJayamohan Kallickal 38226733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 38236733b39aSJayamohan Kallickal if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) { 38246733b39aSJayamohan Kallickal phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba-> 38256733b39aSJayamohan Kallickal init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address; 382699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 382799bc5d55SJohn Soni Jose "BM_%d : phwi_ctrlr->phwi_ctxt=%p\n", 38286733b39aSJayamohan Kallickal phwi_ctrlr->phwi_ctxt); 38296733b39aSJayamohan Kallickal } else { 383099bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 383199bc5d55SJohn Soni Jose "BM_%d : HWI_MEM_ADDN_CONTEXT is more " 383299bc5d55SJohn Soni Jose "than one element.Failing to load\n"); 38336733b39aSJayamohan Kallickal return -ENOMEM; 38346733b39aSJayamohan Kallickal } 38356733b39aSJayamohan Kallickal 38366733b39aSJayamohan Kallickal iscsi_init_global_templates(phba); 38373ec78271SJayamohan Kallickal if (beiscsi_init_wrb_handle(phba)) 38383ec78271SJayamohan Kallickal return -ENOMEM; 38393ec78271SJayamohan Kallickal 3840a7909b39SJayamohan Kallickal if (hwi_init_async_pdu_ctx(phba)) { 3841a7909b39SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 3842a7909b39SJayamohan Kallickal "BM_%d : hwi_init_async_pdu_ctx failed\n"); 3843a7909b39SJayamohan Kallickal return -ENOMEM; 3844a7909b39SJayamohan Kallickal } 3845a7909b39SJayamohan Kallickal 38466733b39aSJayamohan Kallickal if (hwi_init_port(phba) != 0) { 384799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 384899bc5d55SJohn Soni Jose "BM_%d : hwi_init_controller failed\n"); 384999bc5d55SJohn Soni Jose 38506733b39aSJayamohan Kallickal return -ENOMEM; 38516733b39aSJayamohan Kallickal } 38526733b39aSJayamohan Kallickal return 0; 38536733b39aSJayamohan Kallickal } 38546733b39aSJayamohan Kallickal 38556733b39aSJayamohan Kallickal static void beiscsi_free_mem(struct beiscsi_hba *phba) 38566733b39aSJayamohan Kallickal { 38576733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr; 38586733b39aSJayamohan Kallickal int i, j; 38596733b39aSJayamohan Kallickal 38606733b39aSJayamohan Kallickal mem_descr = phba->init_mem; 38616733b39aSJayamohan Kallickal for (i = 0; i < SE_MEM_MAX; i++) { 38626733b39aSJayamohan Kallickal for (j = mem_descr->num_elements; j > 0; j--) { 386326a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, 38646733b39aSJayamohan Kallickal mem_descr->mem_array[j - 1].size, 38656733b39aSJayamohan Kallickal mem_descr->mem_array[j - 1].virtual_address, 3866457ff3b7SJayamohan Kallickal (unsigned long)mem_descr->mem_array[j - 1]. 3867457ff3b7SJayamohan Kallickal bus_address.u.a64.address); 38686733b39aSJayamohan Kallickal } 38698a86e833SJayamohan Kallickal 38706733b39aSJayamohan Kallickal kfree(mem_descr->mem_array); 38716733b39aSJayamohan Kallickal mem_descr++; 38726733b39aSJayamohan Kallickal } 38736733b39aSJayamohan Kallickal kfree(phba->init_mem); 3874a7909b39SJayamohan Kallickal kfree(phba->phwi_ctrlr->wrb_context); 38756733b39aSJayamohan Kallickal kfree(phba->phwi_ctrlr); 38766733b39aSJayamohan Kallickal } 38776733b39aSJayamohan Kallickal 38786733b39aSJayamohan Kallickal static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) 38796733b39aSJayamohan Kallickal { 38806733b39aSJayamohan Kallickal struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg; 38816733b39aSJayamohan Kallickal struct sgl_handle *psgl_handle; 38826733b39aSJayamohan Kallickal struct iscsi_sge *pfrag; 388390622db3SJayamohan Kallickal unsigned int arr_index, i, idx; 388490622db3SJayamohan Kallickal unsigned int ulp_icd_start, ulp_num = 0; 38856733b39aSJayamohan Kallickal 38866733b39aSJayamohan Kallickal phba->io_sgl_hndl_avbl = 0; 38876733b39aSJayamohan Kallickal phba->eh_sgl_hndl_avbl = 0; 3888bfead3b2SJayamohan Kallickal 38896733b39aSJayamohan Kallickal mem_descr_sglh = phba->init_mem; 38906733b39aSJayamohan Kallickal mem_descr_sglh += HWI_MEM_SGLH; 38916733b39aSJayamohan Kallickal if (1 == mem_descr_sglh->num_elements) { 38926396bb22SKees Cook phba->io_sgl_hndl_base = kcalloc(phba->params.ios_per_ctrl, 38936396bb22SKees Cook sizeof(struct sgl_handle *), 38946733b39aSJayamohan Kallickal GFP_KERNEL); 38956733b39aSJayamohan Kallickal if (!phba->io_sgl_hndl_base) { 389699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 389799bc5d55SJohn Soni Jose "BM_%d : Mem Alloc Failed. Failing to load\n"); 38986733b39aSJayamohan Kallickal return -ENOMEM; 38996733b39aSJayamohan Kallickal } 39006396bb22SKees Cook phba->eh_sgl_hndl_base = 39016396bb22SKees Cook kcalloc(phba->params.icds_per_ctrl - 39026396bb22SKees Cook phba->params.ios_per_ctrl, 39036396bb22SKees Cook sizeof(struct sgl_handle *), GFP_KERNEL); 39046733b39aSJayamohan Kallickal if (!phba->eh_sgl_hndl_base) { 39056733b39aSJayamohan Kallickal kfree(phba->io_sgl_hndl_base); 390699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 390799bc5d55SJohn Soni Jose "BM_%d : Mem Alloc Failed. Failing to load\n"); 39086733b39aSJayamohan Kallickal return -ENOMEM; 39096733b39aSJayamohan Kallickal } 39106733b39aSJayamohan Kallickal } else { 391199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 391299bc5d55SJohn Soni Jose "BM_%d : HWI_MEM_SGLH is more than one element." 39136733b39aSJayamohan Kallickal "Failing to load\n"); 39146733b39aSJayamohan Kallickal return -ENOMEM; 39156733b39aSJayamohan Kallickal } 39166733b39aSJayamohan Kallickal 39176733b39aSJayamohan Kallickal arr_index = 0; 39186733b39aSJayamohan Kallickal idx = 0; 39196733b39aSJayamohan Kallickal while (idx < mem_descr_sglh->num_elements) { 39206733b39aSJayamohan Kallickal psgl_handle = mem_descr_sglh->mem_array[idx].virtual_address; 39216733b39aSJayamohan Kallickal 39226733b39aSJayamohan Kallickal for (i = 0; i < (mem_descr_sglh->mem_array[idx].size / 39236733b39aSJayamohan Kallickal sizeof(struct sgl_handle)); i++) { 39246733b39aSJayamohan Kallickal if (arr_index < phba->params.ios_per_ctrl) { 39256733b39aSJayamohan Kallickal phba->io_sgl_hndl_base[arr_index] = psgl_handle; 39266733b39aSJayamohan Kallickal phba->io_sgl_hndl_avbl++; 39276733b39aSJayamohan Kallickal arr_index++; 39286733b39aSJayamohan Kallickal } else { 39296733b39aSJayamohan Kallickal phba->eh_sgl_hndl_base[arr_index - 39306733b39aSJayamohan Kallickal phba->params.ios_per_ctrl] = 39316733b39aSJayamohan Kallickal psgl_handle; 39326733b39aSJayamohan Kallickal arr_index++; 39336733b39aSJayamohan Kallickal phba->eh_sgl_hndl_avbl++; 39346733b39aSJayamohan Kallickal } 39356733b39aSJayamohan Kallickal psgl_handle++; 39366733b39aSJayamohan Kallickal } 39376733b39aSJayamohan Kallickal idx++; 39386733b39aSJayamohan Kallickal } 393999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 394099bc5d55SJohn Soni Jose "BM_%d : phba->io_sgl_hndl_avbl=%d" 39416733b39aSJayamohan Kallickal "phba->eh_sgl_hndl_avbl=%d\n", 39426733b39aSJayamohan Kallickal phba->io_sgl_hndl_avbl, 39436733b39aSJayamohan Kallickal phba->eh_sgl_hndl_avbl); 394499bc5d55SJohn Soni Jose 39456733b39aSJayamohan Kallickal mem_descr_sg = phba->init_mem; 39466733b39aSJayamohan Kallickal mem_descr_sg += HWI_MEM_SGE; 394799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 394899bc5d55SJohn Soni Jose "\n BM_%d : mem_descr_sg->num_elements=%d\n", 39496733b39aSJayamohan Kallickal mem_descr_sg->num_elements); 395099bc5d55SJohn Soni Jose 395190622db3SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) 395290622db3SJayamohan Kallickal if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) 395390622db3SJayamohan Kallickal break; 395490622db3SJayamohan Kallickal 395590622db3SJayamohan Kallickal ulp_icd_start = phba->fw_config.iscsi_icd_start[ulp_num]; 395690622db3SJayamohan Kallickal 39576733b39aSJayamohan Kallickal arr_index = 0; 39586733b39aSJayamohan Kallickal idx = 0; 39596733b39aSJayamohan Kallickal while (idx < mem_descr_sg->num_elements) { 39606733b39aSJayamohan Kallickal pfrag = mem_descr_sg->mem_array[idx].virtual_address; 39616733b39aSJayamohan Kallickal 39626733b39aSJayamohan Kallickal for (i = 0; 39636733b39aSJayamohan Kallickal i < (mem_descr_sg->mem_array[idx].size) / 39646733b39aSJayamohan Kallickal (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io); 39656733b39aSJayamohan Kallickal i++) { 39666733b39aSJayamohan Kallickal if (arr_index < phba->params.ios_per_ctrl) 39676733b39aSJayamohan Kallickal psgl_handle = phba->io_sgl_hndl_base[arr_index]; 39686733b39aSJayamohan Kallickal else 39696733b39aSJayamohan Kallickal psgl_handle = phba->eh_sgl_hndl_base[arr_index - 39706733b39aSJayamohan Kallickal phba->params.ios_per_ctrl]; 39716733b39aSJayamohan Kallickal psgl_handle->pfrag = pfrag; 39726733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, pfrag, 0); 39736733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0); 39746733b39aSJayamohan Kallickal pfrag += phba->params.num_sge_per_io; 397590622db3SJayamohan Kallickal psgl_handle->sgl_index = ulp_icd_start + arr_index++; 39766733b39aSJayamohan Kallickal } 39776733b39aSJayamohan Kallickal idx++; 39786733b39aSJayamohan Kallickal } 39796733b39aSJayamohan Kallickal phba->io_sgl_free_index = 0; 39806733b39aSJayamohan Kallickal phba->io_sgl_alloc_index = 0; 39816733b39aSJayamohan Kallickal phba->eh_sgl_free_index = 0; 39826733b39aSJayamohan Kallickal phba->eh_sgl_alloc_index = 0; 39836733b39aSJayamohan Kallickal return 0; 39846733b39aSJayamohan Kallickal } 39856733b39aSJayamohan Kallickal 39866733b39aSJayamohan Kallickal static int hba_setup_cid_tbls(struct beiscsi_hba *phba) 39876733b39aSJayamohan Kallickal { 39880a3db7c0SJayamohan Kallickal int ret; 39890a3db7c0SJayamohan Kallickal uint16_t i, ulp_num; 39900a3db7c0SJayamohan Kallickal struct ulp_cid_info *ptr_cid_info = NULL; 39916733b39aSJayamohan Kallickal 39920a3db7c0SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 39930a3db7c0SJayamohan Kallickal if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { 39940a3db7c0SJayamohan Kallickal ptr_cid_info = kzalloc(sizeof(struct ulp_cid_info), 39956733b39aSJayamohan Kallickal GFP_KERNEL); 39960a3db7c0SJayamohan Kallickal 39970a3db7c0SJayamohan Kallickal if (!ptr_cid_info) { 399899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 39990a3db7c0SJayamohan Kallickal "BM_%d : Failed to allocate memory" 40000a3db7c0SJayamohan Kallickal "for ULP_CID_INFO for ULP : %d\n", 40010a3db7c0SJayamohan Kallickal ulp_num); 40020a3db7c0SJayamohan Kallickal ret = -ENOMEM; 40030a3db7c0SJayamohan Kallickal goto free_memory; 40040a3db7c0SJayamohan Kallickal 40050a3db7c0SJayamohan Kallickal } 40060a3db7c0SJayamohan Kallickal 40070a3db7c0SJayamohan Kallickal /* Allocate memory for CID array */ 4008413f3656SJitendra Bhivare ptr_cid_info->cid_array = 4009413f3656SJitendra Bhivare kcalloc(BEISCSI_GET_CID_COUNT(phba, ulp_num), 4010413f3656SJitendra Bhivare sizeof(*ptr_cid_info->cid_array), 4011413f3656SJitendra Bhivare GFP_KERNEL); 40120a3db7c0SJayamohan Kallickal if (!ptr_cid_info->cid_array) { 40130a3db7c0SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 40140a3db7c0SJayamohan Kallickal "BM_%d : Failed to allocate memory" 40150a3db7c0SJayamohan Kallickal "for CID_ARRAY for ULP : %d\n", 40160a3db7c0SJayamohan Kallickal ulp_num); 40170a3db7c0SJayamohan Kallickal kfree(ptr_cid_info); 40180a3db7c0SJayamohan Kallickal ptr_cid_info = NULL; 40190a3db7c0SJayamohan Kallickal ret = -ENOMEM; 40200a3db7c0SJayamohan Kallickal 40210a3db7c0SJayamohan Kallickal goto free_memory; 40220a3db7c0SJayamohan Kallickal } 40230a3db7c0SJayamohan Kallickal ptr_cid_info->avlbl_cids = BEISCSI_GET_CID_COUNT( 40240a3db7c0SJayamohan Kallickal phba, ulp_num); 40250a3db7c0SJayamohan Kallickal 40260a3db7c0SJayamohan Kallickal /* Save the cid_info_array ptr */ 40270a3db7c0SJayamohan Kallickal phba->cid_array_info[ulp_num] = ptr_cid_info; 40280a3db7c0SJayamohan Kallickal } 40296733b39aSJayamohan Kallickal } 40306396bb22SKees Cook phba->ep_array = kcalloc(phba->params.cxns_per_ctrl, 40316396bb22SKees Cook sizeof(struct iscsi_endpoint *), 40326396bb22SKees Cook GFP_KERNEL); 40336733b39aSJayamohan Kallickal if (!phba->ep_array) { 403499bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 403599bc5d55SJohn Soni Jose "BM_%d : Failed to allocate memory in " 40366733b39aSJayamohan Kallickal "hba_setup_cid_tbls\n"); 40370a3db7c0SJayamohan Kallickal ret = -ENOMEM; 40380a3db7c0SJayamohan Kallickal 40390a3db7c0SJayamohan Kallickal goto free_memory; 40406733b39aSJayamohan Kallickal } 4041a7909b39SJayamohan Kallickal 40426396bb22SKees Cook phba->conn_table = kcalloc(phba->params.cxns_per_ctrl, 40436396bb22SKees Cook sizeof(struct beiscsi_conn *), 40446396bb22SKees Cook GFP_KERNEL); 4045a7909b39SJayamohan Kallickal if (!phba->conn_table) { 4046a7909b39SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 4047a7909b39SJayamohan Kallickal "BM_%d : Failed to allocate memory in" 4048a7909b39SJayamohan Kallickal "hba_setup_cid_tbls\n"); 4049a7909b39SJayamohan Kallickal 4050a7909b39SJayamohan Kallickal kfree(phba->ep_array); 4051a7909b39SJayamohan Kallickal phba->ep_array = NULL; 40520a3db7c0SJayamohan Kallickal ret = -ENOMEM; 40535f2d25efSTomas Henzl 40545f2d25efSTomas Henzl goto free_memory; 40556733b39aSJayamohan Kallickal } 4056a7909b39SJayamohan Kallickal 40570a3db7c0SJayamohan Kallickal for (i = 0; i < phba->params.cxns_per_ctrl; i++) { 40580a3db7c0SJayamohan Kallickal ulp_num = phba->phwi_ctrlr->wrb_context[i].ulp_num; 4059a7909b39SJayamohan Kallickal 40600a3db7c0SJayamohan Kallickal ptr_cid_info = phba->cid_array_info[ulp_num]; 40610a3db7c0SJayamohan Kallickal ptr_cid_info->cid_array[ptr_cid_info->cid_alloc++] = 40620a3db7c0SJayamohan Kallickal phba->phwi_ctrlr->wrb_context[i].cid; 40630a3db7c0SJayamohan Kallickal 40640a3db7c0SJayamohan Kallickal } 40650a3db7c0SJayamohan Kallickal 40660a3db7c0SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 40670a3db7c0SJayamohan Kallickal if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { 40680a3db7c0SJayamohan Kallickal ptr_cid_info = phba->cid_array_info[ulp_num]; 40690a3db7c0SJayamohan Kallickal 40700a3db7c0SJayamohan Kallickal ptr_cid_info->cid_alloc = 0; 40710a3db7c0SJayamohan Kallickal ptr_cid_info->cid_free = 0; 40720a3db7c0SJayamohan Kallickal } 40730a3db7c0SJayamohan Kallickal } 40746733b39aSJayamohan Kallickal return 0; 40750a3db7c0SJayamohan Kallickal 40760a3db7c0SJayamohan Kallickal free_memory: 40770a3db7c0SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 40780a3db7c0SJayamohan Kallickal if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { 40790a3db7c0SJayamohan Kallickal ptr_cid_info = phba->cid_array_info[ulp_num]; 40800a3db7c0SJayamohan Kallickal 40810a3db7c0SJayamohan Kallickal if (ptr_cid_info) { 40820a3db7c0SJayamohan Kallickal kfree(ptr_cid_info->cid_array); 40830a3db7c0SJayamohan Kallickal kfree(ptr_cid_info); 40840a3db7c0SJayamohan Kallickal phba->cid_array_info[ulp_num] = NULL; 40850a3db7c0SJayamohan Kallickal } 40860a3db7c0SJayamohan Kallickal } 40870a3db7c0SJayamohan Kallickal } 40880a3db7c0SJayamohan Kallickal 40890a3db7c0SJayamohan Kallickal return ret; 40906733b39aSJayamohan Kallickal } 40916733b39aSJayamohan Kallickal 4092238f6b72SJayamohan Kallickal static void hwi_enable_intr(struct beiscsi_hba *phba) 40936733b39aSJayamohan Kallickal { 40946733b39aSJayamohan Kallickal struct be_ctrl_info *ctrl = &phba->ctrl; 40956733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 40966733b39aSJayamohan Kallickal struct hwi_context_memory *phwi_context; 40976733b39aSJayamohan Kallickal struct be_queue_info *eq; 40986733b39aSJayamohan Kallickal u8 __iomem *addr; 4099bfead3b2SJayamohan Kallickal u32 reg, i; 41006733b39aSJayamohan Kallickal u32 enabled; 41016733b39aSJayamohan Kallickal 41026733b39aSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 41036733b39aSJayamohan Kallickal phwi_context = phwi_ctrlr->phwi_ctxt; 41046733b39aSJayamohan Kallickal 41056733b39aSJayamohan Kallickal addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg + 41066733b39aSJayamohan Kallickal PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); 41076733b39aSJayamohan Kallickal reg = ioread32(addr); 41086733b39aSJayamohan Kallickal 41096733b39aSJayamohan Kallickal enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; 41106733b39aSJayamohan Kallickal if (!enabled) { 41116733b39aSJayamohan Kallickal reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; 411299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 411399bc5d55SJohn Soni Jose "BM_%d : reg =x%08x addr=%p\n", reg, addr); 41146733b39aSJayamohan Kallickal iowrite32(reg, addr); 4115665d6d94SJayamohan Kallickal } 4116665d6d94SJayamohan Kallickal 411783148866SChristoph Hellwig if (!phba->pcidev->msix_enabled) { 4118c03af1aeSJayamohan Kallickal eq = &phwi_context->be_eq[0].q; 411999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 412099bc5d55SJohn Soni Jose "BM_%d : eq->id=%d\n", eq->id); 412199bc5d55SJohn Soni Jose 4122c03af1aeSJayamohan Kallickal hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); 4123c03af1aeSJayamohan Kallickal } else { 4124bfead3b2SJayamohan Kallickal for (i = 0; i <= phba->num_cpus; i++) { 4125bfead3b2SJayamohan Kallickal eq = &phwi_context->be_eq[i].q; 412699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 412799bc5d55SJohn Soni Jose "BM_%d : eq->id=%d\n", eq->id); 41286733b39aSJayamohan Kallickal hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); 4129bfead3b2SJayamohan Kallickal } 4130c03af1aeSJayamohan Kallickal } 4131c03af1aeSJayamohan Kallickal } 41326733b39aSJayamohan Kallickal 41336733b39aSJayamohan Kallickal static void hwi_disable_intr(struct beiscsi_hba *phba) 41346733b39aSJayamohan Kallickal { 41356733b39aSJayamohan Kallickal struct be_ctrl_info *ctrl = &phba->ctrl; 41366733b39aSJayamohan Kallickal 41376733b39aSJayamohan Kallickal u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; 41386733b39aSJayamohan Kallickal u32 reg = ioread32(addr); 41396733b39aSJayamohan Kallickal 41406733b39aSJayamohan Kallickal u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; 41416733b39aSJayamohan Kallickal if (enabled) { 41426733b39aSJayamohan Kallickal reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; 41436733b39aSJayamohan Kallickal iowrite32(reg, addr); 41446733b39aSJayamohan Kallickal } else 414599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, 414699bc5d55SJohn Soni Jose "BM_%d : In hwi_disable_intr, Already Disabled\n"); 41476733b39aSJayamohan Kallickal } 41486733b39aSJayamohan Kallickal 41496733b39aSJayamohan Kallickal static int beiscsi_init_port(struct beiscsi_hba *phba) 41506733b39aSJayamohan Kallickal { 41516733b39aSJayamohan Kallickal int ret; 41526733b39aSJayamohan Kallickal 4153dd940972SJitendra Bhivare ret = hwi_init_controller(phba); 41546733b39aSJayamohan Kallickal if (ret < 0) { 415599bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 4156dd940972SJitendra Bhivare "BM_%d : init controller failed\n"); 41576733b39aSJayamohan Kallickal return ret; 41586733b39aSJayamohan Kallickal } 41596733b39aSJayamohan Kallickal ret = beiscsi_init_sgl_handle(phba); 41606733b39aSJayamohan Kallickal if (ret < 0) { 416199bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 4162dd940972SJitendra Bhivare "BM_%d : init sgl handles failed\n"); 4163dd940972SJitendra Bhivare goto cleanup_port; 41646733b39aSJayamohan Kallickal } 41656733b39aSJayamohan Kallickal 4166deeea8edSChristophe JAILLET ret = hba_setup_cid_tbls(phba); 4167deeea8edSChristophe JAILLET if (ret < 0) { 416899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 4169dd940972SJitendra Bhivare "BM_%d : setup CID table failed\n"); 41706733b39aSJayamohan Kallickal kfree(phba->io_sgl_hndl_base); 41716733b39aSJayamohan Kallickal kfree(phba->eh_sgl_hndl_base); 4172dd940972SJitendra Bhivare goto cleanup_port; 41736733b39aSJayamohan Kallickal } 41746733b39aSJayamohan Kallickal return ret; 41756733b39aSJayamohan Kallickal 4176dd940972SJitendra Bhivare cleanup_port: 41774d2ee1e6SJitendra Bhivare hwi_cleanup_port(phba); 41786733b39aSJayamohan Kallickal return ret; 41796733b39aSJayamohan Kallickal } 41806733b39aSJayamohan Kallickal 41814d2ee1e6SJitendra Bhivare static void beiscsi_cleanup_port(struct beiscsi_hba *phba) 41826733b39aSJayamohan Kallickal { 41830a3db7c0SJayamohan Kallickal struct ulp_cid_info *ptr_cid_info = NULL; 4184f79929deSJitendra Bhivare int ulp_num; 41856733b39aSJayamohan Kallickal 41866733b39aSJayamohan Kallickal kfree(phba->io_sgl_hndl_base); 41876733b39aSJayamohan Kallickal kfree(phba->eh_sgl_hndl_base); 41886733b39aSJayamohan Kallickal kfree(phba->ep_array); 4189a7909b39SJayamohan Kallickal kfree(phba->conn_table); 41900a3db7c0SJayamohan Kallickal 41910a3db7c0SJayamohan Kallickal for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { 41920a3db7c0SJayamohan Kallickal if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { 41930a3db7c0SJayamohan Kallickal ptr_cid_info = phba->cid_array_info[ulp_num]; 41940a3db7c0SJayamohan Kallickal 41950a3db7c0SJayamohan Kallickal if (ptr_cid_info) { 41960a3db7c0SJayamohan Kallickal kfree(ptr_cid_info->cid_array); 41970a3db7c0SJayamohan Kallickal kfree(ptr_cid_info); 41980a3db7c0SJayamohan Kallickal phba->cid_array_info[ulp_num] = NULL; 41990a3db7c0SJayamohan Kallickal } 42000a3db7c0SJayamohan Kallickal } 42010a3db7c0SJayamohan Kallickal } 42026733b39aSJayamohan Kallickal } 42036733b39aSJayamohan Kallickal 4204d629c471SJohn Soni Jose /** 420543f388b0SJayamohan Kallickal * beiscsi_free_mgmt_task_handles()- Free driver CXN resources 420643f388b0SJayamohan Kallickal * @beiscsi_conn: ptr to the conn to be cleaned up 42074a4a11b9SJayamohan Kallickal * @task: ptr to iscsi_task resource to be freed. 420843f388b0SJayamohan Kallickal * 420943f388b0SJayamohan Kallickal * Free driver mgmt resources binded to CXN. 421043f388b0SJayamohan Kallickal **/ 421143f388b0SJayamohan Kallickal void 42124a4a11b9SJayamohan Kallickal beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn, 42134a4a11b9SJayamohan Kallickal struct iscsi_task *task) 421443f388b0SJayamohan Kallickal { 421543f388b0SJayamohan Kallickal struct beiscsi_io_task *io_task; 421643f388b0SJayamohan Kallickal struct beiscsi_hba *phba = beiscsi_conn->phba; 421743f388b0SJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 421843f388b0SJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 4219a7909b39SJayamohan Kallickal uint16_t cri_index = BE_GET_CRI_FROM_CID( 4220a7909b39SJayamohan Kallickal beiscsi_conn->beiscsi_conn_cid); 422143f388b0SJayamohan Kallickal 422243f388b0SJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 4223a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; 4224a7909b39SJayamohan Kallickal 42254a4a11b9SJayamohan Kallickal io_task = task->dd_data; 422643f388b0SJayamohan Kallickal 422743f388b0SJayamohan Kallickal if (io_task->pwrb_handle) { 4228e1f9d31eSJitendra Bhivare free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); 422943f388b0SJayamohan Kallickal io_task->pwrb_handle = NULL; 423043f388b0SJayamohan Kallickal } 423143f388b0SJayamohan Kallickal 423243f388b0SJayamohan Kallickal if (io_task->psgl_handle) { 4233e1f9d31eSJitendra Bhivare free_mgmt_sgl_handle(phba, io_task->psgl_handle); 423443f388b0SJayamohan Kallickal io_task->psgl_handle = NULL; 423543f388b0SJayamohan Kallickal } 423643f388b0SJayamohan Kallickal 4237eb1c4692SJohn Soni Jose if (io_task->mtask_addr) { 423826a4c991SChristoph Hellwig dma_unmap_single(&phba->pcidev->dev, 423943f388b0SJayamohan Kallickal io_task->mtask_addr, 424043f388b0SJayamohan Kallickal io_task->mtask_data_count, 424126a4c991SChristoph Hellwig DMA_TO_DEVICE); 4242eb1c4692SJohn Soni Jose io_task->mtask_addr = 0; 4243eb1c4692SJohn Soni Jose } 424443f388b0SJayamohan Kallickal } 424543f388b0SJayamohan Kallickal 424643f388b0SJayamohan Kallickal /** 4247d629c471SJohn Soni Jose * beiscsi_cleanup_task()- Free driver resources of the task 4248d629c471SJohn Soni Jose * @task: ptr to the iscsi task 4249d629c471SJohn Soni Jose * 4250d629c471SJohn Soni Jose **/ 42511282ab76SMike Christie static void beiscsi_cleanup_task(struct iscsi_task *task) 42521282ab76SMike Christie { 42531282ab76SMike Christie struct beiscsi_io_task *io_task = task->dd_data; 42541282ab76SMike Christie struct iscsi_conn *conn = task->conn; 42551282ab76SMike Christie struct beiscsi_conn *beiscsi_conn = conn->dd_data; 42561282ab76SMike Christie struct beiscsi_hba *phba = beiscsi_conn->phba; 42571282ab76SMike Christie struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; 42581282ab76SMike Christie struct hwi_wrb_context *pwrb_context; 42591282ab76SMike Christie struct hwi_controller *phwi_ctrlr; 4260a7909b39SJayamohan Kallickal uint16_t cri_index = BE_GET_CRI_FROM_CID( 4261a7909b39SJayamohan Kallickal beiscsi_conn->beiscsi_conn_cid); 42621282ab76SMike Christie 42631282ab76SMike Christie phwi_ctrlr = phba->phwi_ctrlr; 4264a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; 42651282ab76SMike Christie 42661282ab76SMike Christie if (io_task->cmd_bhs) { 4267af007b02SRomain Perier dma_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, 42681282ab76SMike Christie io_task->bhs_pa.u.a64.address); 42691282ab76SMike Christie io_task->cmd_bhs = NULL; 4270e1f9d31eSJitendra Bhivare task->hdr = NULL; 42711282ab76SMike Christie } 42721282ab76SMike Christie 42731282ab76SMike Christie if (task->sc) { 42741282ab76SMike Christie if (io_task->pwrb_handle) { 42751282ab76SMike Christie free_wrb_handle(phba, pwrb_context, 42761282ab76SMike Christie io_task->pwrb_handle); 42771282ab76SMike Christie io_task->pwrb_handle = NULL; 42781282ab76SMike Christie } 42791282ab76SMike Christie 42801282ab76SMike Christie if (io_task->psgl_handle) { 42811282ab76SMike Christie free_io_sgl_handle(phba, io_task->psgl_handle); 42821282ab76SMike Christie io_task->psgl_handle = NULL; 42831282ab76SMike Christie } 4284da334977SJayamohan Kallickal 4285da334977SJayamohan Kallickal if (io_task->scsi_cmnd) { 42869122e991SJitendra Bhivare if (io_task->num_sg) 4287da334977SJayamohan Kallickal scsi_dma_unmap(io_task->scsi_cmnd); 4288da334977SJayamohan Kallickal io_task->scsi_cmnd = NULL; 4289da334977SJayamohan Kallickal } 42901282ab76SMike Christie } else { 429143f388b0SJayamohan Kallickal if (!beiscsi_conn->login_in_progress) 42924a4a11b9SJayamohan Kallickal beiscsi_free_mgmt_task_handles(beiscsi_conn, task); 42931282ab76SMike Christie } 42941282ab76SMike Christie } 42951282ab76SMike Christie 42966733b39aSJayamohan Kallickal void 42976733b39aSJayamohan Kallickal beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, 42986733b39aSJayamohan Kallickal struct beiscsi_offload_params *params) 42996733b39aSJayamohan Kallickal { 43006733b39aSJayamohan Kallickal struct wrb_handle *pwrb_handle; 4301340c99e9SJohn Soni Jose struct hwi_wrb_context *pwrb_context = NULL; 43026733b39aSJayamohan Kallickal struct beiscsi_hba *phba = beiscsi_conn->phba; 43031282ab76SMike Christie struct iscsi_task *task = beiscsi_conn->task; 43041282ab76SMike Christie struct iscsi_session *session = task->conn->session; 43056733b39aSJayamohan Kallickal u32 doorbell = 0; 43066733b39aSJayamohan Kallickal 43076733b39aSJayamohan Kallickal /* 43086733b39aSJayamohan Kallickal * We can always use 0 here because it is reserved by libiscsi for 43096733b39aSJayamohan Kallickal * login/startup related tasks. 43106733b39aSJayamohan Kallickal */ 43111282ab76SMike Christie beiscsi_conn->login_in_progress = 0; 4312659743b0SShlomo Pongratz spin_lock_bh(&session->back_lock); 43131282ab76SMike Christie beiscsi_cleanup_task(task); 4314659743b0SShlomo Pongratz spin_unlock_bh(&session->back_lock); 43151282ab76SMike Christie 4316340c99e9SJohn Soni Jose pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 4317340c99e9SJohn Soni Jose &pwrb_context); 43186733b39aSJayamohan Kallickal 4319acb9693cSJohn Soni Jose /* Check for the adapter family */ 43202c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) 4321acb9693cSJohn Soni Jose beiscsi_offload_cxn_v0(params, pwrb_handle, 4322340c99e9SJohn Soni Jose phba->init_mem, 4323340c99e9SJohn Soni Jose pwrb_context); 43242c9dfd36SJayamohan Kallickal else 4325340c99e9SJohn Soni Jose beiscsi_offload_cxn_v2(params, pwrb_handle, 4326340c99e9SJohn Soni Jose pwrb_context); 43276733b39aSJayamohan Kallickal 4328acb9693cSJohn Soni Jose be_dws_le_to_cpu(pwrb_handle->pwrb, 4329acb9693cSJohn Soni Jose sizeof(struct iscsi_target_context_update_wrb)); 43306733b39aSJayamohan Kallickal 43316733b39aSJayamohan Kallickal doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; 4332bfead3b2SJayamohan Kallickal doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) 4333bfead3b2SJayamohan Kallickal << DB_DEF_PDU_WRB_INDEX_SHIFT; 43346733b39aSJayamohan Kallickal doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; 43351e4be6ffSJayamohan Kallickal iowrite32(doorbell, phba->db_va + 43361e4be6ffSJayamohan Kallickal beiscsi_conn->doorbell_offset); 4337cb564c6bSJitendra Bhivare 4338cb564c6bSJitendra Bhivare /* 4339cb564c6bSJitendra Bhivare * There is no completion for CONTEXT_UPDATE. The completion of next 4340cb564c6bSJitendra Bhivare * WRB posted guarantees FW's processing and DMA'ing of it. 4341cb564c6bSJitendra Bhivare * Use beiscsi_put_wrb_handle to put it back in the pool which makes 4342cb564c6bSJitendra Bhivare * sure zero'ing or reuse of the WRB only after wrbs_per_cxn. 4343cb564c6bSJitendra Bhivare */ 4344cb564c6bSJitendra Bhivare beiscsi_put_wrb_handle(pwrb_context, pwrb_handle, 4345cb564c6bSJitendra Bhivare phba->params.wrbs_per_cxn); 4346cb564c6bSJitendra Bhivare beiscsi_log(phba, KERN_INFO, 4347cb564c6bSJitendra Bhivare BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 4348cb564c6bSJitendra Bhivare "BM_%d : put CONTEXT_UPDATE pwrb_handle=%p free_index=0x%x wrb_handles_available=%d\n", 4349cb564c6bSJitendra Bhivare pwrb_handle, pwrb_context->free_index, 4350cb564c6bSJitendra Bhivare pwrb_context->wrb_handles_available); 43516733b39aSJayamohan Kallickal } 43526733b39aSJayamohan Kallickal 43536733b39aSJayamohan Kallickal static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt, 43546733b39aSJayamohan Kallickal int *index, int *age) 43556733b39aSJayamohan Kallickal { 4356bfead3b2SJayamohan Kallickal *index = (int)itt; 43576733b39aSJayamohan Kallickal if (age) 43586733b39aSJayamohan Kallickal *age = conn->session->age; 43596733b39aSJayamohan Kallickal } 43606733b39aSJayamohan Kallickal 43616733b39aSJayamohan Kallickal /** 43626733b39aSJayamohan Kallickal * beiscsi_alloc_pdu - allocates pdu and related resources 43636733b39aSJayamohan Kallickal * @task: libiscsi task 43646733b39aSJayamohan Kallickal * @opcode: opcode of pdu for task 43656733b39aSJayamohan Kallickal * 43666733b39aSJayamohan Kallickal * This is called with the session lock held. It will allocate 43676733b39aSJayamohan Kallickal * the wrb and sgl if needed for the command. And it will prep 43686733b39aSJayamohan Kallickal * the pdu's itt. beiscsi_parse_pdu will later translate 43696733b39aSJayamohan Kallickal * the pdu itt to the libiscsi task itt. 43706733b39aSJayamohan Kallickal */ 43716733b39aSJayamohan Kallickal static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) 43726733b39aSJayamohan Kallickal { 43736733b39aSJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 43746733b39aSJayamohan Kallickal struct iscsi_conn *conn = task->conn; 43756733b39aSJayamohan Kallickal struct beiscsi_conn *beiscsi_conn = conn->dd_data; 43766733b39aSJayamohan Kallickal struct beiscsi_hba *phba = beiscsi_conn->phba; 43776733b39aSJayamohan Kallickal struct hwi_wrb_context *pwrb_context; 43786733b39aSJayamohan Kallickal struct hwi_controller *phwi_ctrlr; 43796733b39aSJayamohan Kallickal itt_t itt; 4380a7909b39SJayamohan Kallickal uint16_t cri_index = 0; 43812afc95bfSJayamohan Kallickal struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; 43822afc95bfSJayamohan Kallickal dma_addr_t paddr; 43836733b39aSJayamohan Kallickal 4384af007b02SRomain Perier io_task->cmd_bhs = dma_pool_alloc(beiscsi_sess->bhs_pool, 4385bc7accecSMike Christie GFP_ATOMIC, &paddr); 43862afc95bfSJayamohan Kallickal if (!io_task->cmd_bhs) 43872afc95bfSJayamohan Kallickal return -ENOMEM; 43882afc95bfSJayamohan Kallickal io_task->bhs_pa.u.a64.address = paddr; 4389bfead3b2SJayamohan Kallickal io_task->libiscsi_itt = (itt_t)task->itt; 43906733b39aSJayamohan Kallickal io_task->conn = beiscsi_conn; 43916733b39aSJayamohan Kallickal 43926733b39aSJayamohan Kallickal task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; 43936733b39aSJayamohan Kallickal task->hdr_max = sizeof(struct be_cmd_bhs); 4394d2cecf0dSJayamohan Kallickal io_task->psgl_handle = NULL; 43953ec78271SJayamohan Kallickal io_task->pwrb_handle = NULL; 43966733b39aSJayamohan Kallickal 43976733b39aSJayamohan Kallickal if (task->sc) { 43986733b39aSJayamohan Kallickal io_task->psgl_handle = alloc_io_sgl_handle(phba); 43998359c79bSJohn Soni Jose if (!io_task->psgl_handle) { 44008359c79bSJohn Soni Jose beiscsi_log(phba, KERN_ERR, 44018359c79bSJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 44028359c79bSJohn Soni Jose "BM_%d : Alloc of IO_SGL_ICD Failed" 44038359c79bSJohn Soni Jose "for the CID : %d\n", 44048359c79bSJohn Soni Jose beiscsi_conn->beiscsi_conn_cid); 44052afc95bfSJayamohan Kallickal goto free_hndls; 44068359c79bSJohn Soni Jose } 4407d2cecf0dSJayamohan Kallickal io_task->pwrb_handle = alloc_wrb_handle(phba, 4408340c99e9SJohn Soni Jose beiscsi_conn->beiscsi_conn_cid, 4409340c99e9SJohn Soni Jose &io_task->pwrb_context); 44108359c79bSJohn Soni Jose if (!io_task->pwrb_handle) { 44118359c79bSJohn Soni Jose beiscsi_log(phba, KERN_ERR, 44128359c79bSJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 44138359c79bSJohn Soni Jose "BM_%d : Alloc of WRB_HANDLE Failed" 44148359c79bSJohn Soni Jose "for the CID : %d\n", 44158359c79bSJohn Soni Jose beiscsi_conn->beiscsi_conn_cid); 4416d2cecf0dSJayamohan Kallickal goto free_io_hndls; 44178359c79bSJohn Soni Jose } 44186733b39aSJayamohan Kallickal } else { 44196733b39aSJayamohan Kallickal io_task->scsi_cmnd = NULL; 4420d7aea67bSJayamohan Kallickal if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { 442143f388b0SJayamohan Kallickal beiscsi_conn->task = task; 44226733b39aSJayamohan Kallickal if (!beiscsi_conn->login_in_progress) { 44236733b39aSJayamohan Kallickal io_task->psgl_handle = (struct sgl_handle *) 44246733b39aSJayamohan Kallickal alloc_mgmt_sgl_handle(phba); 44258359c79bSJohn Soni Jose if (!io_task->psgl_handle) { 44268359c79bSJohn Soni Jose beiscsi_log(phba, KERN_ERR, 44278359c79bSJohn Soni Jose BEISCSI_LOG_IO | 44288359c79bSJohn Soni Jose BEISCSI_LOG_CONFIG, 44298359c79bSJohn Soni Jose "BM_%d : Alloc of MGMT_SGL_ICD Failed" 44308359c79bSJohn Soni Jose "for the CID : %d\n", 44318359c79bSJohn Soni Jose beiscsi_conn-> 44328359c79bSJohn Soni Jose beiscsi_conn_cid); 44332afc95bfSJayamohan Kallickal goto free_hndls; 44348359c79bSJohn Soni Jose } 44352afc95bfSJayamohan Kallickal 44366733b39aSJayamohan Kallickal beiscsi_conn->login_in_progress = 1; 44376733b39aSJayamohan Kallickal beiscsi_conn->plogin_sgl_handle = 44386733b39aSJayamohan Kallickal io_task->psgl_handle; 4439d2cecf0dSJayamohan Kallickal io_task->pwrb_handle = 4440d2cecf0dSJayamohan Kallickal alloc_wrb_handle(phba, 4441340c99e9SJohn Soni Jose beiscsi_conn->beiscsi_conn_cid, 4442340c99e9SJohn Soni Jose &io_task->pwrb_context); 44438359c79bSJohn Soni Jose if (!io_task->pwrb_handle) { 44448359c79bSJohn Soni Jose beiscsi_log(phba, KERN_ERR, 44458359c79bSJohn Soni Jose BEISCSI_LOG_IO | 44468359c79bSJohn Soni Jose BEISCSI_LOG_CONFIG, 44478359c79bSJohn Soni Jose "BM_%d : Alloc of WRB_HANDLE Failed" 44488359c79bSJohn Soni Jose "for the CID : %d\n", 44498359c79bSJohn Soni Jose beiscsi_conn-> 44508359c79bSJohn Soni Jose beiscsi_conn_cid); 44518359c79bSJohn Soni Jose goto free_mgmt_hndls; 44528359c79bSJohn Soni Jose } 4453d2cecf0dSJayamohan Kallickal beiscsi_conn->plogin_wrb_handle = 4454d2cecf0dSJayamohan Kallickal io_task->pwrb_handle; 4455d2cecf0dSJayamohan Kallickal 44566733b39aSJayamohan Kallickal } else { 44576733b39aSJayamohan Kallickal io_task->psgl_handle = 44586733b39aSJayamohan Kallickal beiscsi_conn->plogin_sgl_handle; 4459d2cecf0dSJayamohan Kallickal io_task->pwrb_handle = 4460d2cecf0dSJayamohan Kallickal beiscsi_conn->plogin_wrb_handle; 44616733b39aSJayamohan Kallickal } 44626733b39aSJayamohan Kallickal } else { 44636733b39aSJayamohan Kallickal io_task->psgl_handle = alloc_mgmt_sgl_handle(phba); 44648359c79bSJohn Soni Jose if (!io_task->psgl_handle) { 44658359c79bSJohn Soni Jose beiscsi_log(phba, KERN_ERR, 44668359c79bSJohn Soni Jose BEISCSI_LOG_IO | 44678359c79bSJohn Soni Jose BEISCSI_LOG_CONFIG, 44688359c79bSJohn Soni Jose "BM_%d : Alloc of MGMT_SGL_ICD Failed" 44698359c79bSJohn Soni Jose "for the CID : %d\n", 44708359c79bSJohn Soni Jose beiscsi_conn-> 44718359c79bSJohn Soni Jose beiscsi_conn_cid); 44722afc95bfSJayamohan Kallickal goto free_hndls; 44738359c79bSJohn Soni Jose } 4474d2cecf0dSJayamohan Kallickal io_task->pwrb_handle = 4475d2cecf0dSJayamohan Kallickal alloc_wrb_handle(phba, 4476340c99e9SJohn Soni Jose beiscsi_conn->beiscsi_conn_cid, 4477340c99e9SJohn Soni Jose &io_task->pwrb_context); 44788359c79bSJohn Soni Jose if (!io_task->pwrb_handle) { 44798359c79bSJohn Soni Jose beiscsi_log(phba, KERN_ERR, 44808359c79bSJohn Soni Jose BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, 44818359c79bSJohn Soni Jose "BM_%d : Alloc of WRB_HANDLE Failed" 44828359c79bSJohn Soni Jose "for the CID : %d\n", 44838359c79bSJohn Soni Jose beiscsi_conn->beiscsi_conn_cid); 4484d2cecf0dSJayamohan Kallickal goto free_mgmt_hndls; 44858359c79bSJohn Soni Jose } 4486d2cecf0dSJayamohan Kallickal 44876733b39aSJayamohan Kallickal } 44886733b39aSJayamohan Kallickal } 4489bfead3b2SJayamohan Kallickal itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle-> 4490bfead3b2SJayamohan Kallickal wrb_index << 16) | (unsigned int) 4491bfead3b2SJayamohan Kallickal (io_task->psgl_handle->sgl_index)); 4492bfead3b2SJayamohan Kallickal io_task->pwrb_handle->pio_handle = task; 4493bfead3b2SJayamohan Kallickal 44946733b39aSJayamohan Kallickal io_task->cmd_bhs->iscsi_hdr.itt = itt; 44956733b39aSJayamohan Kallickal return 0; 44962afc95bfSJayamohan Kallickal 4497d2cecf0dSJayamohan Kallickal free_io_hndls: 4498d2cecf0dSJayamohan Kallickal free_io_sgl_handle(phba, io_task->psgl_handle); 4499d2cecf0dSJayamohan Kallickal goto free_hndls; 4500d2cecf0dSJayamohan Kallickal free_mgmt_hndls: 4501d2cecf0dSJayamohan Kallickal free_mgmt_sgl_handle(phba, io_task->psgl_handle); 4502a7909b39SJayamohan Kallickal io_task->psgl_handle = NULL; 45032afc95bfSJayamohan Kallickal free_hndls: 45042afc95bfSJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 4505a7909b39SJayamohan Kallickal cri_index = BE_GET_CRI_FROM_CID( 4506a7909b39SJayamohan Kallickal beiscsi_conn->beiscsi_conn_cid); 4507a7909b39SJayamohan Kallickal pwrb_context = &phwi_ctrlr->wrb_context[cri_index]; 4508d2cecf0dSJayamohan Kallickal if (io_task->pwrb_handle) 45092afc95bfSJayamohan Kallickal free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); 45102afc95bfSJayamohan Kallickal io_task->pwrb_handle = NULL; 4511af007b02SRomain Perier dma_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, 45122afc95bfSJayamohan Kallickal io_task->bhs_pa.u.a64.address); 45131282ab76SMike Christie io_task->cmd_bhs = NULL; 45142afc95bfSJayamohan Kallickal return -ENOMEM; 45156733b39aSJayamohan Kallickal } 45160825b8eeSBaoyou Xie static int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg, 451709a1093aSJohn Soni Jose unsigned int num_sg, unsigned int xferlen, 451809a1093aSJohn Soni Jose unsigned int writedir) 451909a1093aSJohn Soni Jose { 452009a1093aSJohn Soni Jose 452109a1093aSJohn Soni Jose struct beiscsi_io_task *io_task = task->dd_data; 452209a1093aSJohn Soni Jose struct iscsi_conn *conn = task->conn; 452309a1093aSJohn Soni Jose struct beiscsi_conn *beiscsi_conn = conn->dd_data; 452409a1093aSJohn Soni Jose struct beiscsi_hba *phba = beiscsi_conn->phba; 452509a1093aSJohn Soni Jose struct iscsi_wrb *pwrb = NULL; 452609a1093aSJohn Soni Jose unsigned int doorbell = 0; 452709a1093aSJohn Soni Jose 452809a1093aSJohn Soni Jose pwrb = io_task->pwrb_handle->pwrb; 452909a1093aSJohn Soni Jose 453009a1093aSJohn Soni Jose io_task->bhs_len = sizeof(struct be_cmd_bhs); 453109a1093aSJohn Soni Jose 453209a1093aSJohn Soni Jose if (writedir) { 453309a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, type, pwrb, 453409a1093aSJohn Soni Jose INI_WR_CMD); 453509a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, dsp, pwrb, 1); 453609a1093aSJohn Soni Jose } else { 453709a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, type, pwrb, 453809a1093aSJohn Soni Jose INI_RD_CMD); 453909a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, dsp, pwrb, 0); 454009a1093aSJohn Soni Jose } 454109a1093aSJohn Soni Jose 454209a1093aSJohn Soni Jose io_task->wrb_type = AMAP_GET_BITS(struct amap_iscsi_wrb_v2, 454309a1093aSJohn Soni Jose type, pwrb); 454409a1093aSJohn Soni Jose 454509a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, lun, pwrb, 454609a1093aSJohn Soni Jose cpu_to_be16(*(unsigned short *) 454709a1093aSJohn Soni Jose &io_task->cmd_bhs->iscsi_hdr.lun)); 454809a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb, xferlen); 454909a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, wrb_idx, pwrb, 455009a1093aSJohn Soni Jose io_task->pwrb_handle->wrb_index); 455109a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb, 455209a1093aSJohn Soni Jose be32_to_cpu(task->cmdsn)); 455309a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sgl_idx, pwrb, 455409a1093aSJohn Soni Jose io_task->psgl_handle->sgl_index); 455509a1093aSJohn Soni Jose 455609a1093aSJohn Soni Jose hwi_write_sgl_v2(pwrb, sg, num_sg, io_task); 455709a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb, 4558340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4559340c99e9SJohn Soni Jose if (io_task->pwrb_context->plast_wrb) 4560340c99e9SJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, 4561340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb, 4562340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4563340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb = pwrb; 456409a1093aSJohn Soni Jose 456509a1093aSJohn Soni Jose be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); 456609a1093aSJohn Soni Jose 456709a1093aSJohn Soni Jose doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; 456809a1093aSJohn Soni Jose doorbell |= (io_task->pwrb_handle->wrb_index & 456909a1093aSJohn Soni Jose DB_DEF_PDU_WRB_INDEX_MASK) << 457009a1093aSJohn Soni Jose DB_DEF_PDU_WRB_INDEX_SHIFT; 457109a1093aSJohn Soni Jose doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; 45721e4be6ffSJayamohan Kallickal iowrite32(doorbell, phba->db_va + 45731e4be6ffSJayamohan Kallickal beiscsi_conn->doorbell_offset); 457409a1093aSJohn Soni Jose return 0; 457509a1093aSJohn Soni Jose } 45766733b39aSJayamohan Kallickal 45776733b39aSJayamohan Kallickal static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, 45786733b39aSJayamohan Kallickal unsigned int num_sg, unsigned int xferlen, 45796733b39aSJayamohan Kallickal unsigned int writedir) 45806733b39aSJayamohan Kallickal { 45816733b39aSJayamohan Kallickal 45826733b39aSJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 45836733b39aSJayamohan Kallickal struct iscsi_conn *conn = task->conn; 45846733b39aSJayamohan Kallickal struct beiscsi_conn *beiscsi_conn = conn->dd_data; 45856733b39aSJayamohan Kallickal struct beiscsi_hba *phba = beiscsi_conn->phba; 45866733b39aSJayamohan Kallickal struct iscsi_wrb *pwrb = NULL; 45876733b39aSJayamohan Kallickal unsigned int doorbell = 0; 45886733b39aSJayamohan Kallickal 45896733b39aSJayamohan Kallickal pwrb = io_task->pwrb_handle->pwrb; 45906733b39aSJayamohan Kallickal io_task->bhs_len = sizeof(struct be_cmd_bhs); 45916733b39aSJayamohan Kallickal 45926733b39aSJayamohan Kallickal if (writedir) { 4593bfead3b2SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, 4594bfead3b2SJayamohan Kallickal INI_WR_CMD); 45956733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); 45966733b39aSJayamohan Kallickal } else { 4597bfead3b2SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, 4598bfead3b2SJayamohan Kallickal INI_RD_CMD); 45996733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); 46006733b39aSJayamohan Kallickal } 46016733b39aSJayamohan Kallickal 460209a1093aSJohn Soni Jose io_task->wrb_type = AMAP_GET_BITS(struct amap_iscsi_wrb, 460309a1093aSJohn Soni Jose type, pwrb); 460409a1093aSJohn Soni Jose 46056733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb, 4606dc63aac6SJayamohan Kallickal cpu_to_be16(*(unsigned short *) 4607dc63aac6SJayamohan Kallickal &io_task->cmd_bhs->iscsi_hdr.lun)); 46086733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen); 46096733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, 46106733b39aSJayamohan Kallickal io_task->pwrb_handle->wrb_index); 46116733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 46126733b39aSJayamohan Kallickal be32_to_cpu(task->cmdsn)); 46136733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, 46146733b39aSJayamohan Kallickal io_task->psgl_handle->sgl_index); 46156733b39aSJayamohan Kallickal 46166733b39aSJayamohan Kallickal hwi_write_sgl(pwrb, sg, num_sg, io_task); 46176733b39aSJayamohan Kallickal 46186733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, 4619340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4620340c99e9SJohn Soni Jose if (io_task->pwrb_context->plast_wrb) 4621340c99e9SJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, 4622340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb, 4623340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4624340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb = pwrb; 4625340c99e9SJohn Soni Jose 46266733b39aSJayamohan Kallickal be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); 46276733b39aSJayamohan Kallickal 46286733b39aSJayamohan Kallickal doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; 46296733b39aSJayamohan Kallickal doorbell |= (io_task->pwrb_handle->wrb_index & 46306733b39aSJayamohan Kallickal DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; 46316733b39aSJayamohan Kallickal doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; 46326733b39aSJayamohan Kallickal 46331e4be6ffSJayamohan Kallickal iowrite32(doorbell, phba->db_va + 46341e4be6ffSJayamohan Kallickal beiscsi_conn->doorbell_offset); 46356733b39aSJayamohan Kallickal return 0; 46366733b39aSJayamohan Kallickal } 46376733b39aSJayamohan Kallickal 46386733b39aSJayamohan Kallickal static int beiscsi_mtask(struct iscsi_task *task) 46396733b39aSJayamohan Kallickal { 4640dafab8e0SJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 46416733b39aSJayamohan Kallickal struct iscsi_conn *conn = task->conn; 46426733b39aSJayamohan Kallickal struct beiscsi_conn *beiscsi_conn = conn->dd_data; 46436733b39aSJayamohan Kallickal struct beiscsi_hba *phba = beiscsi_conn->phba; 46446733b39aSJayamohan Kallickal struct iscsi_wrb *pwrb = NULL; 46456733b39aSJayamohan Kallickal unsigned int doorbell = 0; 4646dafab8e0SJayamohan Kallickal unsigned int cid; 464709a1093aSJohn Soni Jose unsigned int pwrb_typeoffset = 0; 4648e0493627SAlexey Khoroshilov int ret = 0; 46496733b39aSJayamohan Kallickal 4650bfead3b2SJayamohan Kallickal cid = beiscsi_conn->beiscsi_conn_cid; 46516733b39aSJayamohan Kallickal pwrb = io_task->pwrb_handle->pwrb; 465209a1093aSJohn Soni Jose 46532c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) { 46546733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 46556733b39aSJayamohan Kallickal be32_to_cpu(task->cmdsn)); 46566733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, 46576733b39aSJayamohan Kallickal io_task->pwrb_handle->wrb_index); 46586733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, 46596733b39aSJayamohan Kallickal io_task->psgl_handle->sgl_index); 466009a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, 466109a1093aSJohn Soni Jose task->data_count); 466209a1093aSJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, 4663340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4664340c99e9SJohn Soni Jose if (io_task->pwrb_context->plast_wrb) 4665340c99e9SJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, 4666340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb, 4667340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4668340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb = pwrb; 4669340c99e9SJohn Soni Jose 467009a1093aSJohn Soni Jose pwrb_typeoffset = BE_WRB_TYPE_OFFSET; 46712c9dfd36SJayamohan Kallickal } else { 46722c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb, 46732c9dfd36SJayamohan Kallickal be32_to_cpu(task->cmdsn)); 46742c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, wrb_idx, pwrb, 46752c9dfd36SJayamohan Kallickal io_task->pwrb_handle->wrb_index); 46762c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sgl_idx, pwrb, 46772c9dfd36SJayamohan Kallickal io_task->psgl_handle->sgl_index); 46782c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb, 46792c9dfd36SJayamohan Kallickal task->data_count); 46802c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb, 4681340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4682340c99e9SJohn Soni Jose if (io_task->pwrb_context->plast_wrb) 4683340c99e9SJohn Soni Jose AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, 4684340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb, 4685340c99e9SJohn Soni Jose io_task->pwrb_handle->wrb_index); 4686340c99e9SJohn Soni Jose io_task->pwrb_context->plast_wrb = pwrb; 4687340c99e9SJohn Soni Jose 46882c9dfd36SJayamohan Kallickal pwrb_typeoffset = SKH_WRB_TYPE_OFFSET; 468909a1093aSJohn Soni Jose } 469009a1093aSJohn Soni Jose 4691dafab8e0SJayamohan Kallickal 46926733b39aSJayamohan Kallickal switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { 46936733b39aSJayamohan Kallickal case ISCSI_OP_LOGIN: 46946733b39aSJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1); 469509a1093aSJohn Soni Jose ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset); 4696e0493627SAlexey Khoroshilov ret = hwi_write_buffer(pwrb, task); 46976733b39aSJayamohan Kallickal break; 46986733b39aSJayamohan Kallickal case ISCSI_OP_NOOP_OUT: 46991390b01bSJayamohan Kallickal if (task->hdr->ttt != ISCSI_RESERVED_TAG) { 470009a1093aSJohn Soni Jose ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset); 47012c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) 47022c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, 470309a1093aSJohn Soni Jose dmsg, pwrb, 1); 470409a1093aSJohn Soni Jose else 47052c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 470609a1093aSJohn Soni Jose dmsg, pwrb, 1); 47071390b01bSJayamohan Kallickal } else { 470809a1093aSJohn Soni Jose ADAPTER_SET_WRB_TYPE(pwrb, INI_RD_CMD, pwrb_typeoffset); 47092c9dfd36SJayamohan Kallickal if (is_chip_be2_be3r(phba)) 47102c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb, 471109a1093aSJohn Soni Jose dmsg, pwrb, 0); 471209a1093aSJohn Soni Jose else 47132c9dfd36SJayamohan Kallickal AMAP_SET_BITS(struct amap_iscsi_wrb_v2, 471409a1093aSJohn Soni Jose dmsg, pwrb, 0); 47151390b01bSJayamohan Kallickal } 4716e0493627SAlexey Khoroshilov ret = hwi_write_buffer(pwrb, task); 47176733b39aSJayamohan Kallickal break; 47186733b39aSJayamohan Kallickal case ISCSI_OP_TEXT: 471909a1093aSJohn Soni Jose ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset); 4720e0493627SAlexey Khoroshilov ret = hwi_write_buffer(pwrb, task); 47216733b39aSJayamohan Kallickal break; 47226733b39aSJayamohan Kallickal case ISCSI_OP_SCSI_TMFUNC: 472309a1093aSJohn Soni Jose ADAPTER_SET_WRB_TYPE(pwrb, INI_TMF_CMD, pwrb_typeoffset); 4724e0493627SAlexey Khoroshilov ret = hwi_write_buffer(pwrb, task); 47256733b39aSJayamohan Kallickal break; 47266733b39aSJayamohan Kallickal case ISCSI_OP_LOGOUT: 472709a1093aSJohn Soni Jose ADAPTER_SET_WRB_TYPE(pwrb, HWH_TYPE_LOGOUT, pwrb_typeoffset); 4728e0493627SAlexey Khoroshilov ret = hwi_write_buffer(pwrb, task); 47296733b39aSJayamohan Kallickal break; 47306733b39aSJayamohan Kallickal 47316733b39aSJayamohan Kallickal default: 473299bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, 473399bc5d55SJohn Soni Jose "BM_%d : opcode =%d Not supported\n", 47346733b39aSJayamohan Kallickal task->hdr->opcode & ISCSI_OPCODE_MASK); 473599bc5d55SJohn Soni Jose 47366733b39aSJayamohan Kallickal return -EINVAL; 47376733b39aSJayamohan Kallickal } 47386733b39aSJayamohan Kallickal 4739e0493627SAlexey Khoroshilov if (ret) 4740e0493627SAlexey Khoroshilov return ret; 4741e0493627SAlexey Khoroshilov 474209a1093aSJohn Soni Jose /* Set the task type */ 47432c9dfd36SJayamohan Kallickal io_task->wrb_type = (is_chip_be2_be3r(phba)) ? 47442c9dfd36SJayamohan Kallickal AMAP_GET_BITS(struct amap_iscsi_wrb, type, pwrb) : 47452c9dfd36SJayamohan Kallickal AMAP_GET_BITS(struct amap_iscsi_wrb_v2, type, pwrb); 47466733b39aSJayamohan Kallickal 4747bfead3b2SJayamohan Kallickal doorbell |= cid & DB_WRB_POST_CID_MASK; 47486733b39aSJayamohan Kallickal doorbell |= (io_task->pwrb_handle->wrb_index & 47496733b39aSJayamohan Kallickal DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; 47506733b39aSJayamohan Kallickal doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; 47511e4be6ffSJayamohan Kallickal iowrite32(doorbell, phba->db_va + 47521e4be6ffSJayamohan Kallickal beiscsi_conn->doorbell_offset); 47536733b39aSJayamohan Kallickal return 0; 47546733b39aSJayamohan Kallickal } 47556733b39aSJayamohan Kallickal 47566733b39aSJayamohan Kallickal static int beiscsi_task_xmit(struct iscsi_task *task) 47576733b39aSJayamohan Kallickal { 47586733b39aSJayamohan Kallickal struct beiscsi_io_task *io_task = task->dd_data; 47596733b39aSJayamohan Kallickal struct scsi_cmnd *sc = task->sc; 47601868379bSJitendra Bhivare struct beiscsi_hba *phba; 47616733b39aSJayamohan Kallickal struct scatterlist *sg; 47626733b39aSJayamohan Kallickal int num_sg; 47636733b39aSJayamohan Kallickal unsigned int writedir = 0, xferlen = 0; 47646733b39aSJayamohan Kallickal 47659122e991SJitendra Bhivare phba = io_task->conn->phba; 47669122e991SJitendra Bhivare /** 47679122e991SJitendra Bhivare * HBA in error includes BEISCSI_HBA_FW_TIMEOUT. IO path might be 47689122e991SJitendra Bhivare * operational if FW still gets heartbeat from EP FW. Is management 47699122e991SJitendra Bhivare * path really needed to continue further? 47709122e991SJitendra Bhivare */ 4771d1d5ca88SJitendra Bhivare if (!beiscsi_hba_is_online(phba)) 47729122e991SJitendra Bhivare return -EIO; 47739122e991SJitendra Bhivare 47741868379bSJitendra Bhivare if (!io_task->conn->login_in_progress) 47751868379bSJitendra Bhivare task->hdr->exp_statsn = 0; 477609a1093aSJohn Soni Jose 47776733b39aSJayamohan Kallickal if (!sc) 47786733b39aSJayamohan Kallickal return beiscsi_mtask(task); 47796733b39aSJayamohan Kallickal 47806733b39aSJayamohan Kallickal io_task->scsi_cmnd = sc; 47819122e991SJitendra Bhivare io_task->num_sg = 0; 47826733b39aSJayamohan Kallickal num_sg = scsi_dma_map(sc); 47836733b39aSJayamohan Kallickal if (num_sg < 0) { 4784afb96058SJayamohan Kallickal beiscsi_log(phba, KERN_ERR, 4785afb96058SJayamohan Kallickal BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI, 4786afb96058SJayamohan Kallickal "BM_%d : scsi_dma_map Failed " 4787afb96058SJayamohan Kallickal "Driver_ITT : 0x%x ITT : 0x%x Xferlen : 0x%x\n", 4788afb96058SJayamohan Kallickal be32_to_cpu(io_task->cmd_bhs->iscsi_hdr.itt), 4789afb96058SJayamohan Kallickal io_task->libiscsi_itt, scsi_bufflen(sc)); 479099bc5d55SJohn Soni Jose 47916733b39aSJayamohan Kallickal return num_sg; 47926733b39aSJayamohan Kallickal } 47939122e991SJitendra Bhivare /** 47949122e991SJitendra Bhivare * For scsi cmd task, check num_sg before unmapping in cleanup_task. 47959122e991SJitendra Bhivare * For management task, cleanup_task checks mtask_addr before unmapping. 47969122e991SJitendra Bhivare */ 47979122e991SJitendra Bhivare io_task->num_sg = num_sg; 47986733b39aSJayamohan Kallickal xferlen = scsi_bufflen(sc); 47996733b39aSJayamohan Kallickal sg = scsi_sglist(sc); 480099bc5d55SJohn Soni Jose if (sc->sc_data_direction == DMA_TO_DEVICE) 48016733b39aSJayamohan Kallickal writedir = 1; 480299bc5d55SJohn Soni Jose else 48036733b39aSJayamohan Kallickal writedir = 0; 480499bc5d55SJohn Soni Jose 480509a1093aSJohn Soni Jose return phba->iotask_fn(task, sg, num_sg, xferlen, writedir); 48066733b39aSJayamohan Kallickal } 48076733b39aSJayamohan Kallickal 4808ffce3e2eSJayamohan Kallickal /** 4809ffce3e2eSJayamohan Kallickal * beiscsi_bsg_request - handle bsg request from ISCSI transport 4810ffce3e2eSJayamohan Kallickal * @job: job to handle 4811ffce3e2eSJayamohan Kallickal */ 4812ffce3e2eSJayamohan Kallickal static int beiscsi_bsg_request(struct bsg_job *job) 4813ffce3e2eSJayamohan Kallickal { 4814ffce3e2eSJayamohan Kallickal struct Scsi_Host *shost; 4815ffce3e2eSJayamohan Kallickal struct beiscsi_hba *phba; 4816ffce3e2eSJayamohan Kallickal struct iscsi_bsg_request *bsg_req = job->request; 4817ffce3e2eSJayamohan Kallickal int rc = -EINVAL; 4818ffce3e2eSJayamohan Kallickal unsigned int tag; 4819ffce3e2eSJayamohan Kallickal struct be_dma_mem nonemb_cmd; 4820ffce3e2eSJayamohan Kallickal struct be_cmd_resp_hdr *resp; 4821ffce3e2eSJayamohan Kallickal struct iscsi_bsg_reply *bsg_reply = job->reply; 4822ffce3e2eSJayamohan Kallickal unsigned short status, extd_status; 4823ffce3e2eSJayamohan Kallickal 4824ffce3e2eSJayamohan Kallickal shost = iscsi_job_to_shost(job); 4825ffce3e2eSJayamohan Kallickal phba = iscsi_host_priv(shost); 4826ffce3e2eSJayamohan Kallickal 4827d1d5ca88SJitendra Bhivare if (!beiscsi_hba_is_online(phba)) { 48289122e991SJitendra Bhivare beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, 48299122e991SJitendra Bhivare "BM_%d : HBA in error 0x%lx\n", phba->state); 48309122e991SJitendra Bhivare return -ENXIO; 48319122e991SJitendra Bhivare } 48329122e991SJitendra Bhivare 4833ffce3e2eSJayamohan Kallickal switch (bsg_req->msgcode) { 4834ffce3e2eSJayamohan Kallickal case ISCSI_BSG_HST_VENDOR: 483526a4c991SChristoph Hellwig nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev, 4836ffce3e2eSJayamohan Kallickal job->request_payload.payload_len, 483726a4c991SChristoph Hellwig &nonemb_cmd.dma, GFP_KERNEL); 4838ffce3e2eSJayamohan Kallickal if (nonemb_cmd.va == NULL) { 483999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, 484099bc5d55SJohn Soni Jose "BM_%d : Failed to allocate memory for " 4841ffce3e2eSJayamohan Kallickal "beiscsi_bsg_request\n"); 48428359c79bSJohn Soni Jose return -ENOMEM; 4843ffce3e2eSJayamohan Kallickal } 4844ffce3e2eSJayamohan Kallickal tag = mgmt_vendor_specific_fw_cmd(&phba->ctrl, phba, job, 4845ffce3e2eSJayamohan Kallickal &nonemb_cmd); 4846ffce3e2eSJayamohan Kallickal if (!tag) { 484799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, 48488359c79bSJohn Soni Jose "BM_%d : MBX Tag Allocation Failed\n"); 484999bc5d55SJohn Soni Jose 485026a4c991SChristoph Hellwig dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, 4851ffce3e2eSJayamohan Kallickal nonemb_cmd.va, nonemb_cmd.dma); 4852ffce3e2eSJayamohan Kallickal return -EAGAIN; 4853e175defeSJohn Soni Jose } 4854e175defeSJohn Soni Jose 4855e175defeSJohn Soni Jose rc = wait_event_interruptible_timeout( 4856e175defeSJohn Soni Jose phba->ctrl.mcc_wait[tag], 485767296ad9SJitendra Bhivare phba->ctrl.mcc_tag_status[tag], 4858e175defeSJohn Soni Jose msecs_to_jiffies( 4859e175defeSJohn Soni Jose BEISCSI_HOST_MBX_TIMEOUT)); 4860d1d5ca88SJitendra Bhivare 4861d1d5ca88SJitendra Bhivare if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) { 4862d1d5ca88SJitendra Bhivare clear_bit(MCC_TAG_STATE_RUNNING, 4863d1d5ca88SJitendra Bhivare &phba->ctrl.ptag_state[tag].tag_state); 486426a4c991SChristoph Hellwig dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, 4865d1d5ca88SJitendra Bhivare nonemb_cmd.va, nonemb_cmd.dma); 4866d1d5ca88SJitendra Bhivare return -EIO; 4867d1d5ca88SJitendra Bhivare } 486867296ad9SJitendra Bhivare extd_status = (phba->ctrl.mcc_tag_status[tag] & 486967296ad9SJitendra Bhivare CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT; 487067296ad9SJitendra Bhivare status = phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_MASK; 4871090e2184SJitendra Bhivare free_mcc_wrb(&phba->ctrl, tag); 4872ffce3e2eSJayamohan Kallickal resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va; 4873ffce3e2eSJayamohan Kallickal sg_copy_from_buffer(job->reply_payload.sg_list, 4874ffce3e2eSJayamohan Kallickal job->reply_payload.sg_cnt, 4875ffce3e2eSJayamohan Kallickal nonemb_cmd.va, (resp->response_length 4876ffce3e2eSJayamohan Kallickal + sizeof(*resp))); 4877ffce3e2eSJayamohan Kallickal bsg_reply->reply_payload_rcv_len = resp->response_length; 4878ffce3e2eSJayamohan Kallickal bsg_reply->result = status; 4879ffce3e2eSJayamohan Kallickal bsg_job_done(job, bsg_reply->result, 4880ffce3e2eSJayamohan Kallickal bsg_reply->reply_payload_rcv_len); 488126a4c991SChristoph Hellwig dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size, 4882ffce3e2eSJayamohan Kallickal nonemb_cmd.va, nonemb_cmd.dma); 4883ffce3e2eSJayamohan Kallickal if (status || extd_status) { 488499bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, 48858359c79bSJohn Soni Jose "BM_%d : MBX Cmd Failed" 4886ffce3e2eSJayamohan Kallickal " status = %d extd_status = %d\n", 4887ffce3e2eSJayamohan Kallickal status, extd_status); 488899bc5d55SJohn Soni Jose 4889ffce3e2eSJayamohan Kallickal return -EIO; 48908359c79bSJohn Soni Jose } else { 48918359c79bSJohn Soni Jose rc = 0; 4892ffce3e2eSJayamohan Kallickal } 4893ffce3e2eSJayamohan Kallickal break; 4894ffce3e2eSJayamohan Kallickal 4895ffce3e2eSJayamohan Kallickal default: 489699bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, 489799bc5d55SJohn Soni Jose "BM_%d : Unsupported bsg command: 0x%x\n", 4898ffce3e2eSJayamohan Kallickal bsg_req->msgcode); 4899ffce3e2eSJayamohan Kallickal break; 4900ffce3e2eSJayamohan Kallickal } 4901ffce3e2eSJayamohan Kallickal 4902ffce3e2eSJayamohan Kallickal return rc; 4903ffce3e2eSJayamohan Kallickal } 4904ffce3e2eSJayamohan Kallickal 49050825b8eeSBaoyou Xie static void beiscsi_hba_attrs_init(struct beiscsi_hba *phba) 490699bc5d55SJohn Soni Jose { 490799bc5d55SJohn Soni Jose /* Set the logging parameter */ 490899bc5d55SJohn Soni Jose beiscsi_log_enable_init(phba, beiscsi_log_enable); 490999bc5d55SJohn Soni Jose } 491099bc5d55SJohn Soni Jose 491150a4b824SJitendra Bhivare void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle) 491250a4b824SJitendra Bhivare { 491350a4b824SJitendra Bhivare if (phba->boot_struct.boot_kset) 491450a4b824SJitendra Bhivare return; 491550a4b824SJitendra Bhivare 491650a4b824SJitendra Bhivare /* skip if boot work is already in progress */ 491750a4b824SJitendra Bhivare if (test_and_set_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) 491850a4b824SJitendra Bhivare return; 491950a4b824SJitendra Bhivare 492050a4b824SJitendra Bhivare phba->boot_struct.retry = 3; 492150a4b824SJitendra Bhivare phba->boot_struct.tag = 0; 492250a4b824SJitendra Bhivare phba->boot_struct.s_handle = s_handle; 492350a4b824SJitendra Bhivare phba->boot_struct.action = BEISCSI_BOOT_GET_SHANDLE; 492450a4b824SJitendra Bhivare schedule_work(&phba->boot_work); 492550a4b824SJitendra Bhivare } 492650a4b824SJitendra Bhivare 4927f1d50e8eSLee Jones #define BEISCSI_SYSFS_ISCSI_BOOT_FLAGS 3 4928a90a8c60SLee Jones /* 4929a905a1dcSLee Jones * beiscsi_show_boot_tgt_info() 49308d9ecd49SJitendra Bhivare * Boot flag info for iscsi-utilities 49318d9ecd49SJitendra Bhivare * Bit 0 Block valid flag 49328d9ecd49SJitendra Bhivare * Bit 1 Firmware booting selected 49338d9ecd49SJitendra Bhivare */ 493450a4b824SJitendra Bhivare static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) 493550a4b824SJitendra Bhivare { 493650a4b824SJitendra Bhivare struct beiscsi_hba *phba = data; 493750a4b824SJitendra Bhivare struct mgmt_session_info *boot_sess = &phba->boot_struct.boot_sess; 493850a4b824SJitendra Bhivare struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; 493950a4b824SJitendra Bhivare char *str = buf; 494050a4b824SJitendra Bhivare int rc = -EPERM; 494150a4b824SJitendra Bhivare 494250a4b824SJitendra Bhivare switch (type) { 494350a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_NAME: 494450a4b824SJitendra Bhivare rc = sprintf(buf, "%.*s\n", 494550a4b824SJitendra Bhivare (int)strlen(boot_sess->target_name), 494650a4b824SJitendra Bhivare (char *)&boot_sess->target_name); 494750a4b824SJitendra Bhivare break; 494850a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_IP_ADDR: 494950a4b824SJitendra Bhivare if (boot_conn->dest_ipaddr.ip_type == BEISCSI_IP_TYPE_V4) 495050a4b824SJitendra Bhivare rc = sprintf(buf, "%pI4\n", 495150a4b824SJitendra Bhivare (char *)&boot_conn->dest_ipaddr.addr); 495250a4b824SJitendra Bhivare else 495350a4b824SJitendra Bhivare rc = sprintf(str, "%pI6\n", 495450a4b824SJitendra Bhivare (char *)&boot_conn->dest_ipaddr.addr); 495550a4b824SJitendra Bhivare break; 495650a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_PORT: 495750a4b824SJitendra Bhivare rc = sprintf(str, "%d\n", boot_conn->dest_port); 495850a4b824SJitendra Bhivare break; 495950a4b824SJitendra Bhivare 496050a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_CHAP_NAME: 496150a4b824SJitendra Bhivare rc = sprintf(str, "%.*s\n", 496250a4b824SJitendra Bhivare boot_conn->negotiated_login_options.auth_data.chap. 496350a4b824SJitendra Bhivare target_chap_name_length, 496450a4b824SJitendra Bhivare (char *)&boot_conn->negotiated_login_options. 496550a4b824SJitendra Bhivare auth_data.chap.target_chap_name); 496650a4b824SJitendra Bhivare break; 496750a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_CHAP_SECRET: 496850a4b824SJitendra Bhivare rc = sprintf(str, "%.*s\n", 496950a4b824SJitendra Bhivare boot_conn->negotiated_login_options.auth_data.chap. 497050a4b824SJitendra Bhivare target_secret_length, 497150a4b824SJitendra Bhivare (char *)&boot_conn->negotiated_login_options. 497250a4b824SJitendra Bhivare auth_data.chap.target_secret); 497350a4b824SJitendra Bhivare break; 497450a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_REV_CHAP_NAME: 497550a4b824SJitendra Bhivare rc = sprintf(str, "%.*s\n", 497650a4b824SJitendra Bhivare boot_conn->negotiated_login_options.auth_data.chap. 497750a4b824SJitendra Bhivare intr_chap_name_length, 497850a4b824SJitendra Bhivare (char *)&boot_conn->negotiated_login_options. 497950a4b824SJitendra Bhivare auth_data.chap.intr_chap_name); 498050a4b824SJitendra Bhivare break; 498150a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 498250a4b824SJitendra Bhivare rc = sprintf(str, "%.*s\n", 498350a4b824SJitendra Bhivare boot_conn->negotiated_login_options.auth_data.chap. 498450a4b824SJitendra Bhivare intr_secret_length, 498550a4b824SJitendra Bhivare (char *)&boot_conn->negotiated_login_options. 498650a4b824SJitendra Bhivare auth_data.chap.intr_secret); 498750a4b824SJitendra Bhivare break; 498850a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_FLAGS: 49898d9ecd49SJitendra Bhivare rc = sprintf(str, "%d\n", BEISCSI_SYSFS_ISCSI_BOOT_FLAGS); 499050a4b824SJitendra Bhivare break; 499150a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_NIC_ASSOC: 499250a4b824SJitendra Bhivare rc = sprintf(str, "0\n"); 499350a4b824SJitendra Bhivare break; 499450a4b824SJitendra Bhivare } 499550a4b824SJitendra Bhivare return rc; 499650a4b824SJitendra Bhivare } 499750a4b824SJitendra Bhivare 499850a4b824SJitendra Bhivare static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) 499950a4b824SJitendra Bhivare { 500050a4b824SJitendra Bhivare struct beiscsi_hba *phba = data; 500150a4b824SJitendra Bhivare char *str = buf; 500250a4b824SJitendra Bhivare int rc = -EPERM; 500350a4b824SJitendra Bhivare 500450a4b824SJitendra Bhivare switch (type) { 500550a4b824SJitendra Bhivare case ISCSI_BOOT_INI_INITIATOR_NAME: 500650a4b824SJitendra Bhivare rc = sprintf(str, "%s\n", 500750a4b824SJitendra Bhivare phba->boot_struct.boot_sess.initiator_iscsiname); 500850a4b824SJitendra Bhivare break; 500950a4b824SJitendra Bhivare } 501050a4b824SJitendra Bhivare return rc; 501150a4b824SJitendra Bhivare } 501250a4b824SJitendra Bhivare 501350a4b824SJitendra Bhivare static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) 501450a4b824SJitendra Bhivare { 501550a4b824SJitendra Bhivare struct beiscsi_hba *phba = data; 501650a4b824SJitendra Bhivare char *str = buf; 501750a4b824SJitendra Bhivare int rc = -EPERM; 501850a4b824SJitendra Bhivare 501950a4b824SJitendra Bhivare switch (type) { 502050a4b824SJitendra Bhivare case ISCSI_BOOT_ETH_FLAGS: 50218d9ecd49SJitendra Bhivare rc = sprintf(str, "%d\n", BEISCSI_SYSFS_ISCSI_BOOT_FLAGS); 502250a4b824SJitendra Bhivare break; 502350a4b824SJitendra Bhivare case ISCSI_BOOT_ETH_INDEX: 502450a4b824SJitendra Bhivare rc = sprintf(str, "0\n"); 502550a4b824SJitendra Bhivare break; 502650a4b824SJitendra Bhivare case ISCSI_BOOT_ETH_MAC: 502750a4b824SJitendra Bhivare rc = beiscsi_get_macaddr(str, phba); 502850a4b824SJitendra Bhivare break; 502950a4b824SJitendra Bhivare } 503050a4b824SJitendra Bhivare return rc; 503150a4b824SJitendra Bhivare } 503250a4b824SJitendra Bhivare 503350a4b824SJitendra Bhivare static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) 503450a4b824SJitendra Bhivare { 503550a4b824SJitendra Bhivare umode_t rc = 0; 503650a4b824SJitendra Bhivare 503750a4b824SJitendra Bhivare switch (type) { 503850a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_NAME: 503950a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_IP_ADDR: 504050a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_PORT: 504150a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_CHAP_NAME: 504250a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_CHAP_SECRET: 504350a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_REV_CHAP_NAME: 504450a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_REV_CHAP_SECRET: 504550a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_NIC_ASSOC: 504650a4b824SJitendra Bhivare case ISCSI_BOOT_TGT_FLAGS: 504750a4b824SJitendra Bhivare rc = S_IRUGO; 504850a4b824SJitendra Bhivare break; 504950a4b824SJitendra Bhivare } 505050a4b824SJitendra Bhivare return rc; 505150a4b824SJitendra Bhivare } 505250a4b824SJitendra Bhivare 505350a4b824SJitendra Bhivare static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) 505450a4b824SJitendra Bhivare { 505550a4b824SJitendra Bhivare umode_t rc = 0; 505650a4b824SJitendra Bhivare 505750a4b824SJitendra Bhivare switch (type) { 505850a4b824SJitendra Bhivare case ISCSI_BOOT_INI_INITIATOR_NAME: 505950a4b824SJitendra Bhivare rc = S_IRUGO; 506050a4b824SJitendra Bhivare break; 506150a4b824SJitendra Bhivare } 506250a4b824SJitendra Bhivare return rc; 506350a4b824SJitendra Bhivare } 506450a4b824SJitendra Bhivare 506550a4b824SJitendra Bhivare static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) 506650a4b824SJitendra Bhivare { 506750a4b824SJitendra Bhivare umode_t rc = 0; 506850a4b824SJitendra Bhivare 506950a4b824SJitendra Bhivare switch (type) { 507050a4b824SJitendra Bhivare case ISCSI_BOOT_ETH_FLAGS: 507150a4b824SJitendra Bhivare case ISCSI_BOOT_ETH_MAC: 507250a4b824SJitendra Bhivare case ISCSI_BOOT_ETH_INDEX: 507350a4b824SJitendra Bhivare rc = S_IRUGO; 507450a4b824SJitendra Bhivare break; 507550a4b824SJitendra Bhivare } 507650a4b824SJitendra Bhivare return rc; 507750a4b824SJitendra Bhivare } 507850a4b824SJitendra Bhivare 507950a4b824SJitendra Bhivare static void beiscsi_boot_kobj_release(void *data) 508050a4b824SJitendra Bhivare { 508150a4b824SJitendra Bhivare struct beiscsi_hba *phba = data; 508250a4b824SJitendra Bhivare 508350a4b824SJitendra Bhivare scsi_host_put(phba->shost); 508450a4b824SJitendra Bhivare } 508550a4b824SJitendra Bhivare 508650a4b824SJitendra Bhivare static int beiscsi_boot_create_kset(struct beiscsi_hba *phba) 508750a4b824SJitendra Bhivare { 508850a4b824SJitendra Bhivare struct boot_struct *bs = &phba->boot_struct; 508950a4b824SJitendra Bhivare struct iscsi_boot_kobj *boot_kobj; 509050a4b824SJitendra Bhivare 509150a4b824SJitendra Bhivare if (bs->boot_kset) { 509250a4b824SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 509350a4b824SJitendra Bhivare "BM_%d: boot_kset already created\n"); 509450a4b824SJitendra Bhivare return 0; 509550a4b824SJitendra Bhivare } 509650a4b824SJitendra Bhivare 509750a4b824SJitendra Bhivare bs->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); 509850a4b824SJitendra Bhivare if (!bs->boot_kset) { 509950a4b824SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 510050a4b824SJitendra Bhivare "BM_%d: boot_kset alloc failed\n"); 510150a4b824SJitendra Bhivare return -ENOMEM; 510250a4b824SJitendra Bhivare } 510350a4b824SJitendra Bhivare 510450a4b824SJitendra Bhivare /* get shost ref because the show function will refer phba */ 510550a4b824SJitendra Bhivare if (!scsi_host_get(phba->shost)) 510650a4b824SJitendra Bhivare goto free_kset; 510750a4b824SJitendra Bhivare 510850a4b824SJitendra Bhivare boot_kobj = iscsi_boot_create_target(bs->boot_kset, 0, phba, 510950a4b824SJitendra Bhivare beiscsi_show_boot_tgt_info, 511050a4b824SJitendra Bhivare beiscsi_tgt_get_attr_visibility, 511150a4b824SJitendra Bhivare beiscsi_boot_kobj_release); 511250a4b824SJitendra Bhivare if (!boot_kobj) 511350a4b824SJitendra Bhivare goto put_shost; 511450a4b824SJitendra Bhivare 511550a4b824SJitendra Bhivare if (!scsi_host_get(phba->shost)) 511650a4b824SJitendra Bhivare goto free_kset; 511750a4b824SJitendra Bhivare 511850a4b824SJitendra Bhivare boot_kobj = iscsi_boot_create_initiator(bs->boot_kset, 0, phba, 511950a4b824SJitendra Bhivare beiscsi_show_boot_ini_info, 512050a4b824SJitendra Bhivare beiscsi_ini_get_attr_visibility, 512150a4b824SJitendra Bhivare beiscsi_boot_kobj_release); 512250a4b824SJitendra Bhivare if (!boot_kobj) 512350a4b824SJitendra Bhivare goto put_shost; 512450a4b824SJitendra Bhivare 512550a4b824SJitendra Bhivare if (!scsi_host_get(phba->shost)) 512650a4b824SJitendra Bhivare goto free_kset; 512750a4b824SJitendra Bhivare 512850a4b824SJitendra Bhivare boot_kobj = iscsi_boot_create_ethernet(bs->boot_kset, 0, phba, 512950a4b824SJitendra Bhivare beiscsi_show_boot_eth_info, 513050a4b824SJitendra Bhivare beiscsi_eth_get_attr_visibility, 513150a4b824SJitendra Bhivare beiscsi_boot_kobj_release); 513250a4b824SJitendra Bhivare if (!boot_kobj) 513350a4b824SJitendra Bhivare goto put_shost; 513450a4b824SJitendra Bhivare 513550a4b824SJitendra Bhivare return 0; 513650a4b824SJitendra Bhivare 513750a4b824SJitendra Bhivare put_shost: 513850a4b824SJitendra Bhivare scsi_host_put(phba->shost); 513950a4b824SJitendra Bhivare free_kset: 514050a4b824SJitendra Bhivare iscsi_boot_destroy_kset(bs->boot_kset); 514150a4b824SJitendra Bhivare bs->boot_kset = NULL; 514250a4b824SJitendra Bhivare return -ENOMEM; 514350a4b824SJitendra Bhivare } 514450a4b824SJitendra Bhivare 514550a4b824SJitendra Bhivare static void beiscsi_boot_work(struct work_struct *work) 514650a4b824SJitendra Bhivare { 514750a4b824SJitendra Bhivare struct beiscsi_hba *phba = 514850a4b824SJitendra Bhivare container_of(work, struct beiscsi_hba, boot_work); 514950a4b824SJitendra Bhivare struct boot_struct *bs = &phba->boot_struct; 515050a4b824SJitendra Bhivare unsigned int tag = 0; 515150a4b824SJitendra Bhivare 5152d1d5ca88SJitendra Bhivare if (!beiscsi_hba_is_online(phba)) 515350a4b824SJitendra Bhivare return; 515450a4b824SJitendra Bhivare 515550a4b824SJitendra Bhivare beiscsi_log(phba, KERN_INFO, 515650a4b824SJitendra Bhivare BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, 515750a4b824SJitendra Bhivare "BM_%d : %s action %d\n", 515850a4b824SJitendra Bhivare __func__, phba->boot_struct.action); 515950a4b824SJitendra Bhivare 516050a4b824SJitendra Bhivare switch (phba->boot_struct.action) { 516150a4b824SJitendra Bhivare case BEISCSI_BOOT_REOPEN_SESS: 516250a4b824SJitendra Bhivare tag = beiscsi_boot_reopen_sess(phba); 516350a4b824SJitendra Bhivare break; 516450a4b824SJitendra Bhivare case BEISCSI_BOOT_GET_SHANDLE: 516550a4b824SJitendra Bhivare tag = __beiscsi_boot_get_shandle(phba, 1); 516650a4b824SJitendra Bhivare break; 516750a4b824SJitendra Bhivare case BEISCSI_BOOT_GET_SINFO: 516850a4b824SJitendra Bhivare tag = beiscsi_boot_get_sinfo(phba); 516950a4b824SJitendra Bhivare break; 517050a4b824SJitendra Bhivare case BEISCSI_BOOT_LOGOUT_SESS: 517150a4b824SJitendra Bhivare tag = beiscsi_boot_logout_sess(phba); 517250a4b824SJitendra Bhivare break; 517350a4b824SJitendra Bhivare case BEISCSI_BOOT_CREATE_KSET: 517450a4b824SJitendra Bhivare beiscsi_boot_create_kset(phba); 517550a4b824SJitendra Bhivare /** 517650a4b824SJitendra Bhivare * updated boot_kset is made visible to all before 517750a4b824SJitendra Bhivare * ending the boot work. 517850a4b824SJitendra Bhivare */ 517950a4b824SJitendra Bhivare mb(); 518050a4b824SJitendra Bhivare clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); 518150a4b824SJitendra Bhivare return; 518250a4b824SJitendra Bhivare } 518350a4b824SJitendra Bhivare if (!tag) { 518450a4b824SJitendra Bhivare if (bs->retry--) 518550a4b824SJitendra Bhivare schedule_work(&phba->boot_work); 518650a4b824SJitendra Bhivare else 518750a4b824SJitendra Bhivare clear_bit(BEISCSI_HBA_BOOT_WORK, &phba->state); 518850a4b824SJitendra Bhivare } 518950a4b824SJitendra Bhivare } 519050a4b824SJitendra Bhivare 519110bcd47dSJitendra Bhivare static void beiscsi_eqd_update_work(struct work_struct *work) 519210bcd47dSJitendra Bhivare { 519310bcd47dSJitendra Bhivare struct hwi_context_memory *phwi_context; 519410bcd47dSJitendra Bhivare struct be_set_eqd set_eqd[MAX_CPUS]; 519510bcd47dSJitendra Bhivare struct hwi_controller *phwi_ctrlr; 519610bcd47dSJitendra Bhivare struct be_eq_obj *pbe_eq; 519710bcd47dSJitendra Bhivare struct beiscsi_hba *phba; 519810bcd47dSJitendra Bhivare unsigned int pps, delta; 519910bcd47dSJitendra Bhivare struct be_aic_obj *aic; 520010bcd47dSJitendra Bhivare int eqd, i, num = 0; 520110bcd47dSJitendra Bhivare unsigned long now; 520210bcd47dSJitendra Bhivare 520310bcd47dSJitendra Bhivare phba = container_of(work, struct beiscsi_hba, eqd_update.work); 5204d1d5ca88SJitendra Bhivare if (!beiscsi_hba_is_online(phba)) 52059122e991SJitendra Bhivare return; 52069122e991SJitendra Bhivare 520773af08e1SJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 520873af08e1SJayamohan Kallickal phwi_context = phwi_ctrlr->phwi_ctxt; 520973af08e1SJayamohan Kallickal 521073af08e1SJayamohan Kallickal for (i = 0; i <= phba->num_cpus; i++) { 521173af08e1SJayamohan Kallickal aic = &phba->aic_obj[i]; 521273af08e1SJayamohan Kallickal pbe_eq = &phwi_context->be_eq[i]; 521373af08e1SJayamohan Kallickal now = jiffies; 521410bcd47dSJitendra Bhivare if (!aic->jiffies || time_before(now, aic->jiffies) || 521573af08e1SJayamohan Kallickal pbe_eq->cq_count < aic->eq_prev) { 521610bcd47dSJitendra Bhivare aic->jiffies = now; 521773af08e1SJayamohan Kallickal aic->eq_prev = pbe_eq->cq_count; 521873af08e1SJayamohan Kallickal continue; 521973af08e1SJayamohan Kallickal } 522010bcd47dSJitendra Bhivare delta = jiffies_to_msecs(now - aic->jiffies); 522173af08e1SJayamohan Kallickal pps = (((u32)(pbe_eq->cq_count - aic->eq_prev) * 1000) / delta); 522273af08e1SJayamohan Kallickal eqd = (pps / 1500) << 2; 522373af08e1SJayamohan Kallickal 522473af08e1SJayamohan Kallickal if (eqd < 8) 522573af08e1SJayamohan Kallickal eqd = 0; 522645efc940SJitendra Bhivare eqd = min_t(u32, eqd, BEISCSI_EQ_DELAY_MAX); 522745efc940SJitendra Bhivare eqd = max_t(u32, eqd, BEISCSI_EQ_DELAY_MIN); 522873af08e1SJayamohan Kallickal 522910bcd47dSJitendra Bhivare aic->jiffies = now; 523073af08e1SJayamohan Kallickal aic->eq_prev = pbe_eq->cq_count; 523173af08e1SJayamohan Kallickal 523273af08e1SJayamohan Kallickal if (eqd != aic->prev_eqd) { 523373af08e1SJayamohan Kallickal set_eqd[num].delay_multiplier = (eqd * 65)/100; 523473af08e1SJayamohan Kallickal set_eqd[num].eq_id = pbe_eq->q.id; 523573af08e1SJayamohan Kallickal aic->prev_eqd = eqd; 523673af08e1SJayamohan Kallickal num++; 523773af08e1SJayamohan Kallickal } 523873af08e1SJayamohan Kallickal } 523910bcd47dSJitendra Bhivare if (num) 524010bcd47dSJitendra Bhivare /* completion of this is ignored */ 524110bcd47dSJitendra Bhivare beiscsi_modify_eq_delay(phba, set_eqd, num); 524273af08e1SJayamohan Kallickal 524310bcd47dSJitendra Bhivare schedule_delayed_work(&phba->eqd_update, 524410bcd47dSJitendra Bhivare msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); 52457a158003SJohn Soni Jose } 52467a158003SJohn Soni Jose 5247b386eec6SKees Cook static void beiscsi_hw_tpe_check(struct timer_list *t) 5248d1d5ca88SJitendra Bhivare { 5249b386eec6SKees Cook struct beiscsi_hba *phba = from_timer(phba, t, hw_check); 5250d1d5ca88SJitendra Bhivare u32 wait; 5251d1d5ca88SJitendra Bhivare 5252d1d5ca88SJitendra Bhivare /* if not TPE, do nothing */ 5253d1d5ca88SJitendra Bhivare if (!beiscsi_detect_tpe(phba)) 5254d1d5ca88SJitendra Bhivare return; 5255d1d5ca88SJitendra Bhivare 5256d1d5ca88SJitendra Bhivare /* wait default 4000ms before recovering */ 5257d1d5ca88SJitendra Bhivare wait = 4000; 5258d1d5ca88SJitendra Bhivare if (phba->ue2rp > BEISCSI_UE_DETECT_INTERVAL) 5259d1d5ca88SJitendra Bhivare wait = phba->ue2rp - BEISCSI_UE_DETECT_INTERVAL; 5260d1d5ca88SJitendra Bhivare queue_delayed_work(phba->wq, &phba->recover_port, 5261d1d5ca88SJitendra Bhivare msecs_to_jiffies(wait)); 5262d1d5ca88SJitendra Bhivare } 5263d1d5ca88SJitendra Bhivare 5264b386eec6SKees Cook static void beiscsi_hw_health_check(struct timer_list *t) 5265d1d5ca88SJitendra Bhivare { 5266b386eec6SKees Cook struct beiscsi_hba *phba = from_timer(phba, t, hw_check); 5267d1d5ca88SJitendra Bhivare 5268d1d5ca88SJitendra Bhivare beiscsi_detect_ue(phba); 5269d1d5ca88SJitendra Bhivare if (beiscsi_detect_ue(phba)) { 5270d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 5271d1d5ca88SJitendra Bhivare "BM_%d : port in error: %lx\n", phba->state); 527210e1a44aSJitendra Bhivare /* sessions are no longer valid, so first fail the sessions */ 527310e1a44aSJitendra Bhivare queue_work(phba->wq, &phba->sess_work); 527410e1a44aSJitendra Bhivare 527510e1a44aSJitendra Bhivare /* detect UER supported */ 5276d1d5ca88SJitendra Bhivare if (!test_bit(BEISCSI_HBA_UER_SUPP, &phba->state)) 5277d1d5ca88SJitendra Bhivare return; 5278d1d5ca88SJitendra Bhivare /* modify this timer to check TPE */ 5279841b86f3SKees Cook phba->hw_check.function = beiscsi_hw_tpe_check; 5280d1d5ca88SJitendra Bhivare } 5281d1d5ca88SJitendra Bhivare 5282d1d5ca88SJitendra Bhivare mod_timer(&phba->hw_check, 5283d1d5ca88SJitendra Bhivare jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL)); 5284d1d5ca88SJitendra Bhivare } 5285d1d5ca88SJitendra Bhivare 5286d1d5ca88SJitendra Bhivare /* 5287d1d5ca88SJitendra Bhivare * beiscsi_enable_port()- Enables the disabled port. 5288d1d5ca88SJitendra Bhivare * Only port resources freed in disable function are reallocated. 5289d1d5ca88SJitendra Bhivare * This is called in HBA error handling path. 5290d1d5ca88SJitendra Bhivare * 5291d1d5ca88SJitendra Bhivare * @phba: Instance of driver private structure 5292d1d5ca88SJitendra Bhivare * 5293d1d5ca88SJitendra Bhivare **/ 5294d1d5ca88SJitendra Bhivare static int beiscsi_enable_port(struct beiscsi_hba *phba) 5295d1d5ca88SJitendra Bhivare { 5296d1d5ca88SJitendra Bhivare struct hwi_context_memory *phwi_context; 5297d1d5ca88SJitendra Bhivare struct hwi_controller *phwi_ctrlr; 5298d1d5ca88SJitendra Bhivare struct be_eq_obj *pbe_eq; 5299d1d5ca88SJitendra Bhivare int ret, i; 5300d1d5ca88SJitendra Bhivare 5301d1d5ca88SJitendra Bhivare if (test_bit(BEISCSI_HBA_ONLINE, &phba->state)) { 5302d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 5303d1d5ca88SJitendra Bhivare "BM_%d : %s : port is online %lx\n", 5304d1d5ca88SJitendra Bhivare __func__, phba->state); 5305d1d5ca88SJitendra Bhivare return 0; 5306d1d5ca88SJitendra Bhivare } 5307d1d5ca88SJitendra Bhivare 5308d1d5ca88SJitendra Bhivare ret = beiscsi_init_sliport(phba); 5309d1d5ca88SJitendra Bhivare if (ret) 5310d1d5ca88SJitendra Bhivare return ret; 5311d1d5ca88SJitendra Bhivare 531283148866SChristoph Hellwig be2iscsi_enable_msix(phba); 5313d1d5ca88SJitendra Bhivare 5314d1d5ca88SJitendra Bhivare beiscsi_get_params(phba); 53151cb3c3fdSJitendra Bhivare beiscsi_set_host_data(phba); 5316d1d5ca88SJitendra Bhivare /* Re-enable UER. If different TPE occurs then it is recoverable. */ 5317d1d5ca88SJitendra Bhivare beiscsi_set_uer_feature(phba); 5318d1d5ca88SJitendra Bhivare 5319d1d5ca88SJitendra Bhivare phba->shost->max_id = phba->params.cxns_per_ctrl; 5320d1d5ca88SJitendra Bhivare phba->shost->can_queue = phba->params.ios_per_ctrl; 5321dd940972SJitendra Bhivare ret = beiscsi_init_port(phba); 5322dd940972SJitendra Bhivare if (ret < 0) { 5323d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 5324dd940972SJitendra Bhivare "BM_%d : init port failed\n"); 5325d1d5ca88SJitendra Bhivare goto disable_msix; 5326d1d5ca88SJitendra Bhivare } 5327d1d5ca88SJitendra Bhivare 5328d1d5ca88SJitendra Bhivare for (i = 0; i < MAX_MCC_CMD; i++) { 5329d1d5ca88SJitendra Bhivare init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); 5330d1d5ca88SJitendra Bhivare phba->ctrl.mcc_tag[i] = i + 1; 5331d1d5ca88SJitendra Bhivare phba->ctrl.mcc_tag_status[i + 1] = 0; 5332d1d5ca88SJitendra Bhivare phba->ctrl.mcc_tag_available++; 5333d1d5ca88SJitendra Bhivare } 5334d1d5ca88SJitendra Bhivare 5335d1d5ca88SJitendra Bhivare phwi_ctrlr = phba->phwi_ctrlr; 5336d1d5ca88SJitendra Bhivare phwi_context = phwi_ctrlr->phwi_ctxt; 5337d1d5ca88SJitendra Bhivare for (i = 0; i < phba->num_cpus; i++) { 5338d1d5ca88SJitendra Bhivare pbe_eq = &phwi_context->be_eq[i]; 5339d1d5ca88SJitendra Bhivare irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll); 5340d1d5ca88SJitendra Bhivare } 5341d1d5ca88SJitendra Bhivare 534283148866SChristoph Hellwig i = (phba->pcidev->msix_enabled) ? i : 0; 5343d1d5ca88SJitendra Bhivare /* Work item for MCC handling */ 5344d1d5ca88SJitendra Bhivare pbe_eq = &phwi_context->be_eq[i]; 5345d1d5ca88SJitendra Bhivare INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work); 5346d1d5ca88SJitendra Bhivare 5347d1d5ca88SJitendra Bhivare ret = beiscsi_init_irqs(phba); 5348d1d5ca88SJitendra Bhivare if (ret < 0) { 5349d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 5350d1d5ca88SJitendra Bhivare "BM_%d : setup IRQs failed %d\n", ret); 5351d1d5ca88SJitendra Bhivare goto cleanup_port; 5352d1d5ca88SJitendra Bhivare } 5353d1d5ca88SJitendra Bhivare hwi_enable_intr(phba); 5354d1d5ca88SJitendra Bhivare /* port operational: clear all error bits */ 5355d1d5ca88SJitendra Bhivare set_bit(BEISCSI_HBA_ONLINE, &phba->state); 5356d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_INFO, 5357d1d5ca88SJitendra Bhivare "BM_%d : port online: 0x%lx\n", phba->state); 5358d1d5ca88SJitendra Bhivare 5359d1d5ca88SJitendra Bhivare /* start hw_check timer and eqd_update work */ 5360d1d5ca88SJitendra Bhivare schedule_delayed_work(&phba->eqd_update, 5361d1d5ca88SJitendra Bhivare msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); 5362d1d5ca88SJitendra Bhivare 5363d1d5ca88SJitendra Bhivare /** 5364d1d5ca88SJitendra Bhivare * Timer function gets modified for TPE detection. 5365d1d5ca88SJitendra Bhivare * Always reinit to do health check first. 5366d1d5ca88SJitendra Bhivare */ 5367841b86f3SKees Cook phba->hw_check.function = beiscsi_hw_health_check; 5368d1d5ca88SJitendra Bhivare mod_timer(&phba->hw_check, 5369d1d5ca88SJitendra Bhivare jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL)); 5370d1d5ca88SJitendra Bhivare return 0; 5371d1d5ca88SJitendra Bhivare 5372d1d5ca88SJitendra Bhivare cleanup_port: 5373d1d5ca88SJitendra Bhivare for (i = 0; i < phba->num_cpus; i++) { 5374d1d5ca88SJitendra Bhivare pbe_eq = &phwi_context->be_eq[i]; 5375d1d5ca88SJitendra Bhivare irq_poll_disable(&pbe_eq->iopoll); 5376d1d5ca88SJitendra Bhivare } 5377d1d5ca88SJitendra Bhivare hwi_cleanup_port(phba); 5378d1d5ca88SJitendra Bhivare 5379d1d5ca88SJitendra Bhivare disable_msix: 538083148866SChristoph Hellwig pci_free_irq_vectors(phba->pcidev); 5381d1d5ca88SJitendra Bhivare return ret; 5382d1d5ca88SJitendra Bhivare } 5383d1d5ca88SJitendra Bhivare 5384d1d5ca88SJitendra Bhivare /* 5385d1d5ca88SJitendra Bhivare * beiscsi_disable_port()- Disable port and cleanup driver resources. 5386d1d5ca88SJitendra Bhivare * This is called in HBA error handling and driver removal. 5387d1d5ca88SJitendra Bhivare * @phba: Instance Priv structure 5388d1d5ca88SJitendra Bhivare * @unload: indicate driver is unloading 5389d1d5ca88SJitendra Bhivare * 5390d1d5ca88SJitendra Bhivare * Free the OS and HW resources held by the driver 5391d1d5ca88SJitendra Bhivare **/ 5392d1d5ca88SJitendra Bhivare static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload) 5393d1d5ca88SJitendra Bhivare { 5394d1d5ca88SJitendra Bhivare struct hwi_context_memory *phwi_context; 5395d1d5ca88SJitendra Bhivare struct hwi_controller *phwi_ctrlr; 5396d1d5ca88SJitendra Bhivare struct be_eq_obj *pbe_eq; 539783148866SChristoph Hellwig unsigned int i; 5398d1d5ca88SJitendra Bhivare 5399d1d5ca88SJitendra Bhivare if (!test_and_clear_bit(BEISCSI_HBA_ONLINE, &phba->state)) 5400d1d5ca88SJitendra Bhivare return; 5401d1d5ca88SJitendra Bhivare 5402d1d5ca88SJitendra Bhivare phwi_ctrlr = phba->phwi_ctrlr; 5403d1d5ca88SJitendra Bhivare phwi_context = phwi_ctrlr->phwi_ctxt; 5404d1d5ca88SJitendra Bhivare hwi_disable_intr(phba); 540545371aa3SJitendra Bhivare beiscsi_free_irqs(phba); 540683148866SChristoph Hellwig pci_free_irq_vectors(phba->pcidev); 5407d1d5ca88SJitendra Bhivare 5408d1d5ca88SJitendra Bhivare for (i = 0; i < phba->num_cpus; i++) { 5409d1d5ca88SJitendra Bhivare pbe_eq = &phwi_context->be_eq[i]; 5410d1d5ca88SJitendra Bhivare irq_poll_disable(&pbe_eq->iopoll); 5411d1d5ca88SJitendra Bhivare } 5412d1d5ca88SJitendra Bhivare cancel_delayed_work_sync(&phba->eqd_update); 5413d1d5ca88SJitendra Bhivare cancel_work_sync(&phba->boot_work); 5414d1d5ca88SJitendra Bhivare /* WQ might be running cancel queued mcc_work if we are not exiting */ 5415d1d5ca88SJitendra Bhivare if (!unload && beiscsi_hba_in_error(phba)) { 5416d1d5ca88SJitendra Bhivare pbe_eq = &phwi_context->be_eq[i]; 5417d1d5ca88SJitendra Bhivare cancel_work_sync(&pbe_eq->mcc_work); 5418d1d5ca88SJitendra Bhivare } 5419d1d5ca88SJitendra Bhivare hwi_cleanup_port(phba); 5420dd940972SJitendra Bhivare beiscsi_cleanup_port(phba); 5421d1d5ca88SJitendra Bhivare } 5422d1d5ca88SJitendra Bhivare 542310e1a44aSJitendra Bhivare static void beiscsi_sess_work(struct work_struct *work) 542410e1a44aSJitendra Bhivare { 542510e1a44aSJitendra Bhivare struct beiscsi_hba *phba; 542610e1a44aSJitendra Bhivare 542710e1a44aSJitendra Bhivare phba = container_of(work, struct beiscsi_hba, sess_work); 542810e1a44aSJitendra Bhivare /* 542910e1a44aSJitendra Bhivare * This work gets scheduled only in case of HBA error. 543010e1a44aSJitendra Bhivare * Old sessions are gone so need to be re-established. 543110e1a44aSJitendra Bhivare * iscsi_session_failure needs process context hence this work. 543210e1a44aSJitendra Bhivare */ 543310e1a44aSJitendra Bhivare iscsi_host_for_each_session(phba->shost, beiscsi_session_fail); 543410e1a44aSJitendra Bhivare } 543510e1a44aSJitendra Bhivare 5436d1d5ca88SJitendra Bhivare static void beiscsi_recover_port(struct work_struct *work) 5437d1d5ca88SJitendra Bhivare { 5438d1d5ca88SJitendra Bhivare struct beiscsi_hba *phba; 5439d1d5ca88SJitendra Bhivare 5440d1d5ca88SJitendra Bhivare phba = container_of(work, struct beiscsi_hba, recover_port.work); 5441d1d5ca88SJitendra Bhivare beiscsi_disable_port(phba, 0); 5442d1d5ca88SJitendra Bhivare beiscsi_enable_port(phba); 5443d1d5ca88SJitendra Bhivare } 54443567f36aSJayamohan Kallickal 54453567f36aSJayamohan Kallickal static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev, 54463567f36aSJayamohan Kallickal pci_channel_state_t state) 54473567f36aSJayamohan Kallickal { 54483567f36aSJayamohan Kallickal struct beiscsi_hba *phba = NULL; 54493567f36aSJayamohan Kallickal 54503567f36aSJayamohan Kallickal phba = (struct beiscsi_hba *)pci_get_drvdata(pdev); 54519122e991SJitendra Bhivare set_bit(BEISCSI_HBA_PCI_ERR, &phba->state); 54523567f36aSJayamohan Kallickal 54533567f36aSJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 54543567f36aSJayamohan Kallickal "BM_%d : EEH error detected\n"); 54553567f36aSJayamohan Kallickal 5456d1d5ca88SJitendra Bhivare /* first stop UE detection when PCI error detected */ 5457d1d5ca88SJitendra Bhivare del_timer_sync(&phba->hw_check); 5458d1d5ca88SJitendra Bhivare cancel_delayed_work_sync(&phba->recover_port); 5459d1d5ca88SJitendra Bhivare 546010e1a44aSJitendra Bhivare /* sessions are no longer valid, so first fail the sessions */ 546110e1a44aSJitendra Bhivare iscsi_host_for_each_session(phba->shost, beiscsi_session_fail); 5462d1d5ca88SJitendra Bhivare beiscsi_disable_port(phba, 0); 54633567f36aSJayamohan Kallickal 54643567f36aSJayamohan Kallickal if (state == pci_channel_io_perm_failure) { 54653567f36aSJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 54663567f36aSJayamohan Kallickal "BM_%d : EEH : State PERM Failure"); 54673567f36aSJayamohan Kallickal return PCI_ERS_RESULT_DISCONNECT; 54683567f36aSJayamohan Kallickal } 54693567f36aSJayamohan Kallickal 54703567f36aSJayamohan Kallickal pci_disable_device(pdev); 54713567f36aSJayamohan Kallickal 54723567f36aSJayamohan Kallickal /* The error could cause the FW to trigger a flash debug dump. 54733567f36aSJayamohan Kallickal * Resetting the card while flash dump is in progress 54743567f36aSJayamohan Kallickal * can cause it not to recover; wait for it to finish. 54753567f36aSJayamohan Kallickal * Wait only for first function as it is needed only once per 54763567f36aSJayamohan Kallickal * adapter. 54773567f36aSJayamohan Kallickal **/ 54783567f36aSJayamohan Kallickal if (pdev->devfn == 0) 54793567f36aSJayamohan Kallickal ssleep(30); 54803567f36aSJayamohan Kallickal 54813567f36aSJayamohan Kallickal return PCI_ERS_RESULT_NEED_RESET; 54823567f36aSJayamohan Kallickal } 54833567f36aSJayamohan Kallickal 54843567f36aSJayamohan Kallickal static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev) 54853567f36aSJayamohan Kallickal { 54863567f36aSJayamohan Kallickal struct beiscsi_hba *phba = NULL; 54873567f36aSJayamohan Kallickal int status = 0; 54883567f36aSJayamohan Kallickal 54893567f36aSJayamohan Kallickal phba = (struct beiscsi_hba *)pci_get_drvdata(pdev); 54903567f36aSJayamohan Kallickal 54913567f36aSJayamohan Kallickal beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 54923567f36aSJayamohan Kallickal "BM_%d : EEH Reset\n"); 54933567f36aSJayamohan Kallickal 54943567f36aSJayamohan Kallickal status = pci_enable_device(pdev); 54953567f36aSJayamohan Kallickal if (status) 54963567f36aSJayamohan Kallickal return PCI_ERS_RESULT_DISCONNECT; 54973567f36aSJayamohan Kallickal 54983567f36aSJayamohan Kallickal pci_set_master(pdev); 54993567f36aSJayamohan Kallickal pci_set_power_state(pdev, PCI_D0); 55003567f36aSJayamohan Kallickal pci_restore_state(pdev); 55013567f36aSJayamohan Kallickal 55024d2ee1e6SJitendra Bhivare status = beiscsi_check_fw_rdy(phba); 55034d2ee1e6SJitendra Bhivare if (status) { 55043567f36aSJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, 55053567f36aSJayamohan Kallickal "BM_%d : EEH Reset Completed\n"); 55063567f36aSJayamohan Kallickal } else { 55073567f36aSJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, 55083567f36aSJayamohan Kallickal "BM_%d : EEH Reset Completion Failure\n"); 55093567f36aSJayamohan Kallickal return PCI_ERS_RESULT_DISCONNECT; 55103567f36aSJayamohan Kallickal } 55113567f36aSJayamohan Kallickal 55123567f36aSJayamohan Kallickal return PCI_ERS_RESULT_RECOVERED; 55133567f36aSJayamohan Kallickal } 55143567f36aSJayamohan Kallickal 55153567f36aSJayamohan Kallickal static void beiscsi_eeh_resume(struct pci_dev *pdev) 55163567f36aSJayamohan Kallickal { 5517d1d5ca88SJitendra Bhivare struct beiscsi_hba *phba; 5518d1d5ca88SJitendra Bhivare int ret; 55193567f36aSJayamohan Kallickal 55203567f36aSJayamohan Kallickal phba = (struct beiscsi_hba *)pci_get_drvdata(pdev); 55213567f36aSJayamohan Kallickal pci_save_state(pdev); 55223567f36aSJayamohan Kallickal 5523d1d5ca88SJitendra Bhivare ret = beiscsi_enable_port(phba); 55244d2ee1e6SJitendra Bhivare if (ret) 5525d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_ERR, 5526d1d5ca88SJitendra Bhivare "BM_%d : AER EEH resume failed\n"); 55273567f36aSJayamohan Kallickal } 55283567f36aSJayamohan Kallickal 55296f039790SGreg Kroah-Hartman static int beiscsi_dev_probe(struct pci_dev *pcidev, 55306733b39aSJayamohan Kallickal const struct pci_device_id *id) 55316733b39aSJayamohan Kallickal { 5532bfead3b2SJayamohan Kallickal struct hwi_context_memory *phwi_context; 553329e80b7cSJitendra Bhivare struct hwi_controller *phwi_ctrlr; 553429e80b7cSJitendra Bhivare struct beiscsi_hba *phba = NULL; 5535bfead3b2SJayamohan Kallickal struct be_eq_obj *pbe_eq; 553650a4b824SJitendra Bhivare unsigned int s_handle; 553729e80b7cSJitendra Bhivare char wq_name[20]; 5538deeea8edSChristophe JAILLET int ret, i; 55396733b39aSJayamohan Kallickal 55406733b39aSJayamohan Kallickal ret = beiscsi_enable_pci(pcidev); 55416733b39aSJayamohan Kallickal if (ret < 0) { 554299bc5d55SJohn Soni Jose dev_err(&pcidev->dev, 554399bc5d55SJohn Soni Jose "beiscsi_dev_probe - Failed to enable pci device\n"); 55446733b39aSJayamohan Kallickal return ret; 55456733b39aSJayamohan Kallickal } 55466733b39aSJayamohan Kallickal 55476733b39aSJayamohan Kallickal phba = beiscsi_hba_alloc(pcidev); 55486733b39aSJayamohan Kallickal if (!phba) { 554999bc5d55SJohn Soni Jose dev_err(&pcidev->dev, 555099bc5d55SJohn Soni Jose "beiscsi_dev_probe - Failed in beiscsi_hba_alloc\n"); 5551deeea8edSChristophe JAILLET ret = -ENOMEM; 55526733b39aSJayamohan Kallickal goto disable_pci; 55536733b39aSJayamohan Kallickal } 55546733b39aSJayamohan Kallickal 55553567f36aSJayamohan Kallickal /* Enable EEH reporting */ 55563567f36aSJayamohan Kallickal ret = pci_enable_pcie_error_reporting(pcidev); 55573567f36aSJayamohan Kallickal if (ret) 55583567f36aSJayamohan Kallickal beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT, 55593567f36aSJayamohan Kallickal "BM_%d : PCIe Error Reporting " 55603567f36aSJayamohan Kallickal "Enabling Failed\n"); 55613567f36aSJayamohan Kallickal 55623567f36aSJayamohan Kallickal pci_save_state(pcidev); 55633567f36aSJayamohan Kallickal 556499bc5d55SJohn Soni Jose /* Initialize Driver configuration Paramters */ 556599bc5d55SJohn Soni Jose beiscsi_hba_attrs_init(phba); 556699bc5d55SJohn Soni Jose 55676c83185aSJayamohan Kallickal phba->mac_addr_set = false; 5568e175defeSJohn Soni Jose 5569f98c96b0SJayamohan Kallickal switch (pcidev->device) { 5570f98c96b0SJayamohan Kallickal case BE_DEVICE_ID1: 5571f98c96b0SJayamohan Kallickal case OC_DEVICE_ID1: 5572f98c96b0SJayamohan Kallickal case OC_DEVICE_ID2: 5573f98c96b0SJayamohan Kallickal phba->generation = BE_GEN2; 557409a1093aSJohn Soni Jose phba->iotask_fn = beiscsi_iotask; 55755fa7db21SKetan Mukadam dev_warn(&pcidev->dev, 55765fa7db21SKetan Mukadam "Obsolete/Unsupported BE2 Adapter Family\n"); 5577f98c96b0SJayamohan Kallickal break; 5578f98c96b0SJayamohan Kallickal case BE_DEVICE_ID2: 5579f98c96b0SJayamohan Kallickal case OC_DEVICE_ID3: 5580f98c96b0SJayamohan Kallickal phba->generation = BE_GEN3; 558109a1093aSJohn Soni Jose phba->iotask_fn = beiscsi_iotask; 5582f98c96b0SJayamohan Kallickal break; 5583139a1b1eSJohn Soni Jose case OC_SKH_ID1: 5584139a1b1eSJohn Soni Jose phba->generation = BE_GEN4; 558509a1093aSJohn Soni Jose phba->iotask_fn = beiscsi_iotask_v2; 5586bf9131cbSJayamohan Kallickal break; 5587f98c96b0SJayamohan Kallickal default: 5588f98c96b0SJayamohan Kallickal phba->generation = 0; 5589f98c96b0SJayamohan Kallickal } 5590f98c96b0SJayamohan Kallickal 55916733b39aSJayamohan Kallickal ret = be_ctrl_init(phba, pcidev); 55926733b39aSJayamohan Kallickal if (ret) { 559399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 55944d2ee1e6SJitendra Bhivare "BM_%d : be_ctrl_init failed\n"); 559545371aa3SJitendra Bhivare goto free_hba; 55966733b39aSJayamohan Kallickal } 55976733b39aSJayamohan Kallickal 55984d2ee1e6SJitendra Bhivare ret = beiscsi_init_sliport(phba); 55994d2ee1e6SJitendra Bhivare if (ret) 560045371aa3SJitendra Bhivare goto free_hba; 56014d2ee1e6SJitendra Bhivare 56026733b39aSJayamohan Kallickal spin_lock_init(&phba->io_sgl_lock); 56036733b39aSJayamohan Kallickal spin_lock_init(&phba->mgmt_sgl_lock); 56048f09a3b9SJayamohan Kallickal spin_lock_init(&phba->async_pdu_lock); 5605480195c2SJitendra Bhivare ret = beiscsi_get_fw_config(&phba->ctrl, phba); 56067da50879SJayamohan Kallickal if (ret != 0) { 560799bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 560899bc5d55SJohn Soni Jose "BM_%d : Error getting fw config\n"); 56097da50879SJayamohan Kallickal goto free_port; 56107da50879SJayamohan Kallickal } 5611480195c2SJitendra Bhivare beiscsi_get_port_name(&phba->ctrl, phba); 56124570f161SJitendra Bhivare beiscsi_get_params(phba); 56131cb3c3fdSJitendra Bhivare beiscsi_set_host_data(phba); 56146694095bSJitendra Bhivare beiscsi_set_uer_feature(phba); 561568c26a3aSJayamohan Kallickal 561683148866SChristoph Hellwig be2iscsi_enable_msix(phba); 561768c26a3aSJayamohan Kallickal 561868c26a3aSJayamohan Kallickal beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 561968c26a3aSJayamohan Kallickal "BM_%d : num_cpus = %d\n", 562068c26a3aSJayamohan Kallickal phba->num_cpus); 562168c26a3aSJayamohan Kallickal 5622843ae752SJayamohan Kallickal phba->shost->max_id = phba->params.cxns_per_ctrl; 5623aa874f07SJayamohan Kallickal phba->shost->can_queue = phba->params.ios_per_ctrl; 5624dd940972SJitendra Bhivare ret = beiscsi_get_memory(phba); 5625dd940972SJitendra Bhivare if (ret < 0) { 5626dd940972SJitendra Bhivare beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 5627dd940972SJitendra Bhivare "BM_%d : alloc host mem failed\n"); 5628dd940972SJitendra Bhivare goto free_port; 5629dd940972SJitendra Bhivare } 5630dd940972SJitendra Bhivare 56316733b39aSJayamohan Kallickal ret = beiscsi_init_port(phba); 56326733b39aSJayamohan Kallickal if (ret < 0) { 563399bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 5634dd940972SJitendra Bhivare "BM_%d : init port failed\n"); 5635dd940972SJitendra Bhivare beiscsi_free_mem(phba); 56366733b39aSJayamohan Kallickal goto free_port; 56376733b39aSJayamohan Kallickal } 56386733b39aSJayamohan Kallickal 5639756d29c8SJayamohan Kallickal for (i = 0; i < MAX_MCC_CMD; i++) { 5640756d29c8SJayamohan Kallickal init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); 5641756d29c8SJayamohan Kallickal phba->ctrl.mcc_tag[i] = i + 1; 564267296ad9SJitendra Bhivare phba->ctrl.mcc_tag_status[i + 1] = 0; 5643756d29c8SJayamohan Kallickal phba->ctrl.mcc_tag_available++; 56441957aa7fSJayamohan Kallickal memset(&phba->ctrl.ptag_state[i].tag_mem_state, 0, 56458fc01eaaSJayamohan Kallickal sizeof(struct be_dma_mem)); 5646756d29c8SJayamohan Kallickal } 5647756d29c8SJayamohan Kallickal 5648756d29c8SJayamohan Kallickal phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; 5649756d29c8SJayamohan Kallickal 565029e80b7cSJitendra Bhivare snprintf(wq_name, sizeof(wq_name), "beiscsi_%02x_wq", 56516733b39aSJayamohan Kallickal phba->shost->host_no); 565229e80b7cSJitendra Bhivare phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, wq_name); 56536733b39aSJayamohan Kallickal if (!phba->wq) { 565499bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 565599bc5d55SJohn Soni Jose "BM_%d : beiscsi_dev_probe-" 56566733b39aSJayamohan Kallickal "Failed to allocate work queue\n"); 5657deeea8edSChristophe JAILLET ret = -ENOMEM; 56586733b39aSJayamohan Kallickal goto free_twq; 56596733b39aSJayamohan Kallickal } 56606733b39aSJayamohan Kallickal 566110bcd47dSJitendra Bhivare INIT_DELAYED_WORK(&phba->eqd_update, beiscsi_eqd_update_work); 56626733b39aSJayamohan Kallickal 5663bfead3b2SJayamohan Kallickal phwi_ctrlr = phba->phwi_ctrlr; 5664bfead3b2SJayamohan Kallickal phwi_context = phwi_ctrlr->phwi_ctxt; 566572fb46a9SJohn Soni Jose 5666bfead3b2SJayamohan Kallickal for (i = 0; i < phba->num_cpus; i++) { 5667bfead3b2SJayamohan Kallickal pbe_eq = &phwi_context->be_eq[i]; 5668d1d5ca88SJitendra Bhivare irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll); 56696733b39aSJayamohan Kallickal } 567072fb46a9SJohn Soni Jose 567183148866SChristoph Hellwig i = (phba->pcidev->msix_enabled) ? i : 0; 567272fb46a9SJohn Soni Jose /* Work item for MCC handling */ 567372fb46a9SJohn Soni Jose pbe_eq = &phwi_context->be_eq[i]; 5674a3095016SJitendra Bhivare INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work); 567572fb46a9SJohn Soni Jose 56766733b39aSJayamohan Kallickal ret = beiscsi_init_irqs(phba); 56776733b39aSJayamohan Kallickal if (ret < 0) { 567899bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, 567999bc5d55SJohn Soni Jose "BM_%d : beiscsi_dev_probe-" 56806733b39aSJayamohan Kallickal "Failed to beiscsi_init_irqs\n"); 568145371aa3SJitendra Bhivare goto disable_iopoll; 56826733b39aSJayamohan Kallickal } 5683238f6b72SJayamohan Kallickal hwi_enable_intr(phba); 5684f457a46fSMike Christie 5685d1d5ca88SJitendra Bhivare ret = iscsi_host_add(phba->shost, &phba->pcidev->dev); 5686d1d5ca88SJitendra Bhivare if (ret) 568745371aa3SJitendra Bhivare goto free_irqs; 56880598b8afSJayamohan Kallickal 5689d1d5ca88SJitendra Bhivare /* set online bit after port is operational */ 5690d1d5ca88SJitendra Bhivare set_bit(BEISCSI_HBA_ONLINE, &phba->state); 5691d1d5ca88SJitendra Bhivare __beiscsi_log(phba, KERN_INFO, 5692d1d5ca88SJitendra Bhivare "BM_%d : port online: 0x%lx\n", phba->state); 5693d1d5ca88SJitendra Bhivare 569450a4b824SJitendra Bhivare INIT_WORK(&phba->boot_work, beiscsi_boot_work); 569550a4b824SJitendra Bhivare ret = beiscsi_boot_get_shandle(phba, &s_handle); 569650a4b824SJitendra Bhivare if (ret > 0) { 569750a4b824SJitendra Bhivare beiscsi_start_boot_work(phba, s_handle); 569850a4b824SJitendra Bhivare /** 569950a4b824SJitendra Bhivare * Set this bit after starting the work to let 570050a4b824SJitendra Bhivare * probe handle it first. 570150a4b824SJitendra Bhivare * ASYNC event can too schedule this work. 5702f457a46fSMike Christie */ 570350a4b824SJitendra Bhivare set_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state); 570450a4b824SJitendra Bhivare } 5705f457a46fSMike Christie 570696b48b92SJitendra Bhivare beiscsi_iface_create_default(phba); 570710bcd47dSJitendra Bhivare schedule_delayed_work(&phba->eqd_update, 570810bcd47dSJitendra Bhivare msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL)); 5709d1d5ca88SJitendra Bhivare 571010e1a44aSJitendra Bhivare INIT_WORK(&phba->sess_work, beiscsi_sess_work); 5711d1d5ca88SJitendra Bhivare INIT_DELAYED_WORK(&phba->recover_port, beiscsi_recover_port); 571210bcd47dSJitendra Bhivare /** 571310bcd47dSJitendra Bhivare * Start UE detection here. UE before this will cause stall in probe 571410bcd47dSJitendra Bhivare * and eventually fail the probe. 571510bcd47dSJitendra Bhivare */ 5716b386eec6SKees Cook timer_setup(&phba->hw_check, beiscsi_hw_health_check, 0); 571710bcd47dSJitendra Bhivare mod_timer(&phba->hw_check, 571810bcd47dSJitendra Bhivare jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL)); 571999bc5d55SJohn Soni Jose beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT, 572099bc5d55SJohn Soni Jose "\n\n\n BM_%d : SUCCESS - DRIVER LOADED\n\n\n"); 57216733b39aSJayamohan Kallickal return 0; 57226733b39aSJayamohan Kallickal 572345371aa3SJitendra Bhivare free_irqs: 572445371aa3SJitendra Bhivare hwi_disable_intr(phba); 572545371aa3SJitendra Bhivare beiscsi_free_irqs(phba); 572645371aa3SJitendra Bhivare disable_iopoll: 5727bfead3b2SJayamohan Kallickal for (i = 0; i < phba->num_cpus; i++) { 5728bfead3b2SJayamohan Kallickal pbe_eq = &phwi_context->be_eq[i]; 5729511cbce2SChristoph Hellwig irq_poll_disable(&pbe_eq->iopoll); 5730bfead3b2SJayamohan Kallickal } 573145371aa3SJitendra Bhivare destroy_workqueue(phba->wq); 57326733b39aSJayamohan Kallickal free_twq: 5733d1d5ca88SJitendra Bhivare hwi_cleanup_port(phba); 57344d2ee1e6SJitendra Bhivare beiscsi_cleanup_port(phba); 57356733b39aSJayamohan Kallickal beiscsi_free_mem(phba); 57366733b39aSJayamohan Kallickal free_port: 573726a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, 57386733b39aSJayamohan Kallickal phba->ctrl.mbox_mem_alloced.size, 57396733b39aSJayamohan Kallickal phba->ctrl.mbox_mem_alloced.va, 57406733b39aSJayamohan Kallickal phba->ctrl.mbox_mem_alloced.dma); 57416733b39aSJayamohan Kallickal beiscsi_unmap_pci_function(phba); 574245371aa3SJitendra Bhivare free_hba: 5743238f6b72SJayamohan Kallickal pci_disable_msix(phba->pcidev); 57446733b39aSJayamohan Kallickal pci_dev_put(phba->pcidev); 57456733b39aSJayamohan Kallickal iscsi_host_free(phba->shost); 57462e7cee02SJohn Soni Jose pci_set_drvdata(pcidev, NULL); 57476733b39aSJayamohan Kallickal disable_pci: 5748e307f3acSJohn Soni Jose pci_release_regions(pcidev); 57496733b39aSJayamohan Kallickal pci_disable_device(pcidev); 57506733b39aSJayamohan Kallickal return ret; 57516733b39aSJayamohan Kallickal } 57526733b39aSJayamohan Kallickal 5753d1d5ca88SJitendra Bhivare static void beiscsi_remove(struct pci_dev *pcidev) 5754d1d5ca88SJitendra Bhivare { 5755d1d5ca88SJitendra Bhivare struct beiscsi_hba *phba = NULL; 5756d1d5ca88SJitendra Bhivare 5757d1d5ca88SJitendra Bhivare phba = pci_get_drvdata(pcidev); 5758d1d5ca88SJitendra Bhivare if (!phba) { 5759d1d5ca88SJitendra Bhivare dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n"); 5760d1d5ca88SJitendra Bhivare return; 5761d1d5ca88SJitendra Bhivare } 5762d1d5ca88SJitendra Bhivare 5763d1d5ca88SJitendra Bhivare /* first stop UE detection before unloading */ 5764d1d5ca88SJitendra Bhivare del_timer_sync(&phba->hw_check); 5765d1d5ca88SJitendra Bhivare cancel_delayed_work_sync(&phba->recover_port); 576610e1a44aSJitendra Bhivare cancel_work_sync(&phba->sess_work); 5767d1d5ca88SJitendra Bhivare 5768d1d5ca88SJitendra Bhivare beiscsi_iface_destroy_default(phba); 5769d1d5ca88SJitendra Bhivare iscsi_host_remove(phba->shost); 5770d1d5ca88SJitendra Bhivare beiscsi_disable_port(phba, 1); 5771d1d5ca88SJitendra Bhivare 5772d1d5ca88SJitendra Bhivare /* after cancelling boot_work */ 5773d1d5ca88SJitendra Bhivare iscsi_boot_destroy_kset(phba->boot_struct.boot_kset); 5774d1d5ca88SJitendra Bhivare 5775d1d5ca88SJitendra Bhivare /* free all resources */ 5776d1d5ca88SJitendra Bhivare destroy_workqueue(phba->wq); 5777d1d5ca88SJitendra Bhivare beiscsi_free_mem(phba); 5778d1d5ca88SJitendra Bhivare 5779d1d5ca88SJitendra Bhivare /* ctrl uninit */ 5780d1d5ca88SJitendra Bhivare beiscsi_unmap_pci_function(phba); 578126a4c991SChristoph Hellwig dma_free_coherent(&phba->pcidev->dev, 5782d1d5ca88SJitendra Bhivare phba->ctrl.mbox_mem_alloced.size, 5783d1d5ca88SJitendra Bhivare phba->ctrl.mbox_mem_alloced.va, 5784d1d5ca88SJitendra Bhivare phba->ctrl.mbox_mem_alloced.dma); 5785d1d5ca88SJitendra Bhivare 5786d1d5ca88SJitendra Bhivare pci_dev_put(phba->pcidev); 5787d1d5ca88SJitendra Bhivare iscsi_host_free(phba->shost); 5788d1d5ca88SJitendra Bhivare pci_disable_pcie_error_reporting(pcidev); 5789d1d5ca88SJitendra Bhivare pci_set_drvdata(pcidev, NULL); 5790d1d5ca88SJitendra Bhivare pci_release_regions(pcidev); 5791d1d5ca88SJitendra Bhivare pci_disable_device(pcidev); 5792d1d5ca88SJitendra Bhivare } 5793d1d5ca88SJitendra Bhivare 5794d1d5ca88SJitendra Bhivare 57953567f36aSJayamohan Kallickal static struct pci_error_handlers beiscsi_eeh_handlers = { 57963567f36aSJayamohan Kallickal .error_detected = beiscsi_eeh_err_detected, 57973567f36aSJayamohan Kallickal .slot_reset = beiscsi_eeh_reset, 57983567f36aSJayamohan Kallickal .resume = beiscsi_eeh_resume, 57993567f36aSJayamohan Kallickal }; 58003567f36aSJayamohan Kallickal 58016733b39aSJayamohan Kallickal struct iscsi_transport beiscsi_iscsi_transport = { 58026733b39aSJayamohan Kallickal .owner = THIS_MODULE, 58036733b39aSJayamohan Kallickal .name = DRV_NAME, 58049db0fb3aSJayamohan Kallickal .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO | 58056733b39aSJayamohan Kallickal CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD, 58066733b39aSJayamohan Kallickal .create_session = beiscsi_session_create, 58076733b39aSJayamohan Kallickal .destroy_session = beiscsi_session_destroy, 58086733b39aSJayamohan Kallickal .create_conn = beiscsi_conn_create, 58096733b39aSJayamohan Kallickal .bind_conn = beiscsi_conn_bind, 5810*891e2639SMike Christie .unbind_conn = iscsi_conn_unbind, 58116733b39aSJayamohan Kallickal .destroy_conn = iscsi_conn_teardown, 581296b48b92SJitendra Bhivare .attr_is_visible = beiscsi_attr_is_visible, 581396b48b92SJitendra Bhivare .set_iface_param = beiscsi_iface_set_param, 581496b48b92SJitendra Bhivare .get_iface_param = beiscsi_iface_get_param, 58156733b39aSJayamohan Kallickal .set_param = beiscsi_set_param, 5816c7f7fd5bSMike Christie .get_conn_param = iscsi_conn_get_param, 58176733b39aSJayamohan Kallickal .get_session_param = iscsi_session_get_param, 58186733b39aSJayamohan Kallickal .get_host_param = beiscsi_get_host_param, 58196733b39aSJayamohan Kallickal .start_conn = beiscsi_conn_start, 5820fa95d206SMike Christie .stop_conn = iscsi_conn_stop, 58216733b39aSJayamohan Kallickal .send_pdu = iscsi_conn_send_pdu, 58226733b39aSJayamohan Kallickal .xmit_task = beiscsi_task_xmit, 58236733b39aSJayamohan Kallickal .cleanup_task = beiscsi_cleanup_task, 58246733b39aSJayamohan Kallickal .alloc_pdu = beiscsi_alloc_pdu, 58256733b39aSJayamohan Kallickal .parse_pdu_itt = beiscsi_parse_pdu, 58266733b39aSJayamohan Kallickal .get_stats = beiscsi_conn_get_stats, 5827c7f7fd5bSMike Christie .get_ep_param = beiscsi_ep_get_param, 58286733b39aSJayamohan Kallickal .ep_connect = beiscsi_ep_connect, 58296733b39aSJayamohan Kallickal .ep_poll = beiscsi_ep_poll, 58306733b39aSJayamohan Kallickal .ep_disconnect = beiscsi_ep_disconnect, 58316733b39aSJayamohan Kallickal .session_recovery_timedout = iscsi_session_recovery_timedout, 5832ffce3e2eSJayamohan Kallickal .bsg_request = beiscsi_bsg_request, 58336733b39aSJayamohan Kallickal }; 58346733b39aSJayamohan Kallickal 58356733b39aSJayamohan Kallickal static struct pci_driver beiscsi_pci_driver = { 58366733b39aSJayamohan Kallickal .name = DRV_NAME, 58376733b39aSJayamohan Kallickal .probe = beiscsi_dev_probe, 58386733b39aSJayamohan Kallickal .remove = beiscsi_remove, 58393567f36aSJayamohan Kallickal .id_table = beiscsi_pci_id_table, 58403567f36aSJayamohan Kallickal .err_handler = &beiscsi_eeh_handlers 58416733b39aSJayamohan Kallickal }; 58426733b39aSJayamohan Kallickal 58436733b39aSJayamohan Kallickal static int __init beiscsi_module_init(void) 58446733b39aSJayamohan Kallickal { 58456733b39aSJayamohan Kallickal int ret; 58466733b39aSJayamohan Kallickal 58476733b39aSJayamohan Kallickal beiscsi_scsi_transport = 58486733b39aSJayamohan Kallickal iscsi_register_transport(&beiscsi_iscsi_transport); 58496733b39aSJayamohan Kallickal if (!beiscsi_scsi_transport) { 585099bc5d55SJohn Soni Jose printk(KERN_ERR 585199bc5d55SJohn Soni Jose "beiscsi_module_init - Unable to register beiscsi transport.\n"); 5852f55a24f2SJayamohan Kallickal return -ENOMEM; 58536733b39aSJayamohan Kallickal } 585499bc5d55SJohn Soni Jose printk(KERN_INFO "In beiscsi_module_init, tt=%p\n", 58556733b39aSJayamohan Kallickal &beiscsi_iscsi_transport); 58566733b39aSJayamohan Kallickal 58576733b39aSJayamohan Kallickal ret = pci_register_driver(&beiscsi_pci_driver); 58586733b39aSJayamohan Kallickal if (ret) { 585999bc5d55SJohn Soni Jose printk(KERN_ERR 586099bc5d55SJohn Soni Jose "beiscsi_module_init - Unable to register beiscsi pci driver.\n"); 58616733b39aSJayamohan Kallickal goto unregister_iscsi_transport; 58626733b39aSJayamohan Kallickal } 58636733b39aSJayamohan Kallickal return 0; 58646733b39aSJayamohan Kallickal 58656733b39aSJayamohan Kallickal unregister_iscsi_transport: 58666733b39aSJayamohan Kallickal iscsi_unregister_transport(&beiscsi_iscsi_transport); 58676733b39aSJayamohan Kallickal return ret; 58686733b39aSJayamohan Kallickal } 58696733b39aSJayamohan Kallickal 58706733b39aSJayamohan Kallickal static void __exit beiscsi_module_exit(void) 58716733b39aSJayamohan Kallickal { 58726733b39aSJayamohan Kallickal pci_unregister_driver(&beiscsi_pci_driver); 58736733b39aSJayamohan Kallickal iscsi_unregister_transport(&beiscsi_iscsi_transport); 58746733b39aSJayamohan Kallickal } 58756733b39aSJayamohan Kallickal 58766733b39aSJayamohan Kallickal module_init(beiscsi_module_init); 58776733b39aSJayamohan Kallickal module_exit(beiscsi_module_exit); 5878