From patchwork Wed May 25 14:17:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Bryant G. Ly" X-Patchwork-Id: 9135471 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3599D607D7 for ; Wed, 25 May 2016 14:20:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D79428110 for ; Wed, 25 May 2016 14:20:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1173F282B3; Wed, 25 May 2016 14:20:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3112F28110 for ; Wed, 25 May 2016 14:20:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753665AbcEYOUN (ORCPT ); Wed, 25 May 2016 10:20:13 -0400 Received: from e33.co.us.ibm.com ([32.97.110.151]:58683 "EHLO e33.co.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752864AbcEYOSO (ORCPT ); Wed, 25 May 2016 10:18:14 -0400 Received: from localhost by e33.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 25 May 2016 08:18:10 -0600 Received: from d03dlp02.boulder.ibm.com (9.17.202.178) by e33.co.us.ibm.com (192.168.1.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 25 May 2016 08:18:06 -0600 X-IBM-Helo: d03dlp02.boulder.ibm.com X-IBM-MailFrom: bryantly@linux.vnet.ibm.com X-IBM-RcptTo: kvalo@codeaurora.org; davem@davemloft.net; akpm@linux-foundation.org; martin.petersen@oracle.com; mchehab@osg.samsung.com; joe@perches.com; bart.vanassche@sandisk.com; jslaby@suse.com; bp@suse.de; linux-kernel@vger.kernel.org; linux-scsi@vger.kernel.org; target-devel@vger.kernel.org Received: from b03cxnp08026.gho.boulder.ibm.com (b03cxnp08026.gho.boulder.ibm.com [9.17.130.18]) by d03dlp02.boulder.ibm.com (Postfix) with ESMTP id B675C3E40054; Wed, 25 May 2016 08:18:05 -0600 (MDT) Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08026.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u4PEI5AZ45809682; Wed, 25 May 2016 07:18:05 -0700 Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 27CCA6E03A; Wed, 25 May 2016 08:18:05 -0600 (MDT) Received: from bryants-mbp.rchland.ibm.com (unknown [9.10.80.38]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP id 51D9D6E048; Wed, 25 May 2016 08:18:04 -0600 (MDT) From: "Bryant G. Ly" To: tyreld@linux.vnet.ibm.com, bart.vanassche@sandisk.com, joe@perches.com Cc: martin.petersen@oracle.com, akpm@linux-foundation.org, kvalo@codeaurora.org, davem@davemloft.net, mchehab@osg.samsung.com, jslaby@suse.com, bp@suse.de, linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, target-devel@vger.kernel.org, bryantly Subject: [PATCH 3/3] ibmvscsis: clean up functions Date: Wed, 25 May 2016 09:17:34 -0500 Message-Id: <1464185854-19761-3-git-send-email-bryantly@linux.vnet.ibm.com> X-Mailer: git-send-email 2.5.4 (Apple Git-61) In-Reply-To: <1464185854-19761-1-git-send-email-bryantly@linux.vnet.ibm.com> References: <1464097978-88457-1-git-send-email-bryantly@linux.vnet.ibm.com> <1464185854-19761-1-git-send-email-bryantly@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16052514-0009-0000-0000-000037B38B5D X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: bryantly This patch removes forward declarations and re-organizes the functions within the driver. This patch also fixes MAINTAINERS for ibmvscsis. Signed-off-by: bryantly Signed-off-by: Bryant G. Ly --- MAINTAINERS | 4 +- drivers/scsi/ibmvscsi/ibmvscsis.c | 2709 ++++++++++++++++++------------------- 2 files changed, 1315 insertions(+), 1398 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a11905c..3f09a15 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5388,8 +5388,8 @@ L: target-devel@vger.kernel.org S: Supported F: drivers/scsi/ibmvscsi/ibmvscsis.c F: drivers/scsi/ibmvscsi/ibmvscsis.h -F: drivers/scsi/libsrp.h -F: drivers/scsi/libsrp.c +F: drivers/scsi/ibmvscsi/libsrp.c +F: drivers/scsi/ibmvscsi/libsrp.h IBM Power Virtual FC Device Drivers M: Tyrel Datwyler diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c index 6f9e9ba..610f4f5 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsis.c +++ b/drivers/scsi/ibmvscsi/ibmvscsis.c @@ -62,88 +62,17 @@ #define SRP_RSP_SENSE_DATA_LEN 18 +static const char ibmvscsis_driver_name[] = "ibmvscsis"; +static char system_id[SYS_ID_NAME_LEN] = ""; +static char partition_name[PARTITION_NAMELEN] = "UNKNOWN"; +static unsigned int partition_number = -1; + static struct workqueue_struct *vtgtd; static unsigned max_vdma_size = MAX_H_COPY_RDMA; static DEFINE_SPINLOCK(ibmvscsis_dev_lock); static LIST_HEAD(ibmvscsis_dev_list); -static int ibmvscsis_probe(struct vio_dev *vdev, - const struct vio_device_id *id); -static void ibmvscsis_dev_release(struct device *dev); -static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd); -static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd); -static int read_dma_window(struct vio_dev *vdev, - struct ibmvscsis_adapter *adapter); -static char *ibmvscsis_get_fabric_name(void); -static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg); -static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg); -static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg); -static int ibmvscsis_check_true(struct se_portal_group *se_tpg); -static int ibmvscsis_check_false(struct se_portal_group *se_tpg); -static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg); -static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd); -static void ibmvscsis_release_cmd(struct se_cmd *se_cmd); -static int ibmvscsis_shutdown_session(struct se_session *se_sess); -static void ibmvscsis_close_session(struct se_session *se_sess); -static u32 ibmvscsis_sess_get_index(struct se_session *se_sess); -static int ibmvscsis_write_pending(struct se_cmd *se_cmd); -static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd); -static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl); -static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd); -static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd); -static int ibmvscsis_queue_status(struct se_cmd *se_cmd); -static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd); -static void ibmvscsis_aborted_task(struct se_cmd *se_cmd); -static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf, - struct config_group *group, - const char *name); -static void ibmvscsis_drop_tport(struct se_wwn *wwn); -static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, - struct config_group *group, - const char *name); -static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg); -static int ibmvscsis_remove(struct vio_dev *vdev); -static ssize_t system_id_show(struct device *dev, - struct device_attribute *attr, - char *buf); -static ssize_t partition_number_show(struct device *dev, - struct device_attribute *attr, - char *buf); -static ssize_t unit_address_show(struct device *dev, - struct device_attribute *attr, char *buf); -static int get_system_info(void); -static irqreturn_t ibmvscsis_interrupt(int dummy, void *data); -static int process_srp_iu(struct iu_entry *iue); -static void process_iu(struct viosrp_crq *crq, - struct ibmvscsis_adapter *adapter); -static void process_crq(struct viosrp_crq *crq, - struct ibmvscsis_adapter *adapter); -static void handle_crq(struct work_struct *work); -static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter); -static void crq_queue_destroy(struct ibmvscsis_adapter *adapter); -static inline struct viosrp_crq *next_crq(struct crq_queue *queue); -static int send_iu(struct iu_entry *iue, u64 length, u8 format); -static int send_adapter_info(struct iu_entry *iue, - dma_addr_t remote_buffer, u16 length); -static int process_mad_iu(struct iu_entry *iue); -static void ibmvscsis_srp_i_logout(struct iu_entry *iue); -static void process_login(struct iu_entry *iue); -static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter, - struct iu_entry *iue); -static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, - int nsg, struct srp_direct_buf *md, int nmd, - enum dma_data_direction dir, unsigned int rest); -static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, - struct iu_entry *iue); -static u64 ibmvscsis_unpack_lun(const u8 *lun, int len); -static int tcm_queuecommand(struct ibmvscsis_adapter *adapter, - struct ibmvscsis_cmnd *vsc, - struct srp_cmd *scmd); -static void ibmvscsis_determine_resid(struct se_cmd *se_cmd, - struct srp_rsp *rsp); -static bool connection_broken(struct ibmvscsis_adapter *adapter); - static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba, u64 dliobn, u64 dlioba) { @@ -189,986 +118,759 @@ static inline long h_send_crq(struct ibmvscsis_adapter *adapter, return rc; } -/*****************************************************************************/ -/* Global device driver data areas */ -/*****************************************************************************/ - -static const char ibmvscsis_driver_name[] = "ibmvscsis"; -static char system_id[SYS_ID_NAME_LEN] = ""; -static char partition_name[PARTITION_NAMELEN] = "UNKNOWN"; -static unsigned int partition_number = -1; +static void ibmvscsis_determine_resid(struct se_cmd *se_cmd, + struct srp_rsp *rsp) +{ + if (se_cmd->residual_count) { + if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { + if (se_cmd->data_direction == DMA_TO_DEVICE) { + /* residual data from an underflow write */ + rsp->flags = SRP_RSP_FLAG_DOUNDER; + rsp->data_out_res_cnt = + cpu_to_be32(se_cmd->residual_count); + } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { + /* residual data from an underflow read */ + rsp->flags = SRP_RSP_FLAG_DIUNDER; + rsp->data_in_res_cnt = + cpu_to_be32(se_cmd->residual_count); + } + } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + if (se_cmd->data_direction == DMA_TO_DEVICE) { + /* residual data from an overflow write */ + rsp->flags = SRP_RSP_FLAG_DOOVER; + rsp->data_out_res_cnt = + cpu_to_be32(se_cmd->residual_count); + } else if (se_cmd->data_direction == + DMA_FROM_DEVICE) { + /* residual data from an overflow read */ + rsp->flags = SRP_RSP_FLAG_DIOVER; + rsp->data_in_res_cnt = + cpu_to_be32(se_cmd->residual_count); + } + } + } +} -static struct class_attribute ibmvscsis_class_attrs[] = { - __ATTR_NULL, -}; +static bool connection_broken(struct ibmvscsis_adapter *adapter) +{ + u64 buffer[2]; + struct viosrp_crq *crq; + long h_return_code; + bool rc = false; -static struct device_attribute dev_attr_system_id = - __ATTR(system_id, S_IRUGO, system_id_show, NULL); + /* create a PING crq */ + crq = (struct viosrp_crq *)&buffer; + buffer[0] = 0; + buffer[1] = 0; + crq->valid = 0x80; + crq->format = 6; + crq->status = 0xF5; -static struct device_attribute dev_attr_partition_number = - __ATTR(partition_number, S_IRUGO, partition_number_show, NULL); + h_return_code = h_send_crq(adapter, + cpu_to_be64(buffer[0]), + cpu_to_be64(buffer[1])); -static struct device_attribute dev_attr_unit_address = - __ATTR(unit_address, S_IRUGO, unit_address_show, NULL); + pr_debug("connection_broken: rc %ld\n", h_return_code); -static struct attribute *ibmvscsis_dev_attrs[] = { - &dev_attr_system_id.attr, - &dev_attr_partition_number.attr, - &dev_attr_unit_address.attr, -}; -ATTRIBUTE_GROUPS(ibmvscsis_dev); + if (h_return_code == H_CLOSED) + rc = true; -static struct class ibmvscsis_class = { - .name = "ibmvscsis", - .dev_release = ibmvscsis_dev_release, - .class_attrs = ibmvscsis_class_attrs, - .dev_groups = ibmvscsis_dev_groups, -}; + return rc; +} -static ssize_t ibmvscsis_wwn_version_show(struct config_item *item, - char *page) +static u64 ibmvscsis_unpack_lun(const u8 *lun, int len) { - return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION); -} -CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version); + u64 res = NO_SUCH_LUN; + int addressing_method; -static struct configfs_attribute *ibmvscsis_wwn_attrs[] = { - &ibmvscsis_wwn_attr_version, - NULL, -}; + if (unlikely(len < 2)) { + pr_err("Illegal LUN length %d, expected 2 bytes or more\n", + len); + goto out; + } -static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item, - char *page) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct ibmvscsis_tport *tport = container_of(se_tpg, - struct ibmvscsis_tport, - se_tpg); + switch (len) { + case 8: + if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0) + goto out_err; + break; + case 4: + if (*((__be16 *)&lun[2]) != 0) + goto out_err; + break; + case 6: + if (*((__be32 *)&lun[2]) != 0) + goto out_err; + break; + case 2: + break; + default: + goto out_err; + } - return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0); + addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */ + switch (addressing_method) { + case SCSI_LUN_ADDR_METHOD_PERIPHERAL: + case SCSI_LUN_ADDR_METHOD_FLAT: + case SCSI_LUN_ADDR_METHOD_LUN: + res = *(lun + 1) | (((*lun) & 0x3f) << 8); + break; + + case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN: + default: + pr_err("Unimplemented LUN addressing method %u\n", + addressing_method); + break; + } + +out: + return res; +out_err: + pr_err("Support for multi-level LUNs has not yet been implemented\n"); + goto out; } -static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item, - const char *page, size_t count) +static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd) { - struct se_portal_group *se_tpg = to_tpg(item); - struct ibmvscsis_tport *tport = container_of(se_tpg, - struct ibmvscsis_tport, - se_tpg); - unsigned long tmp; - int ret; + s32 len = se_cmd->data_length; + u16 data_len; + unsigned char *buf = NULL; - ret = kstrtoul(page, 0, &tmp); - if (ret < 0) { - pr_err("Unable to extract ibmvscsis_tpg_store_enable\n"); - return -EINVAL; - } + if (len <= 8) + return; - if ((tmp != 0) && (tmp != 1)) { - pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n", - tmp); - return -EINVAL; + len -= 8; + buf = transport_kmap_data_sg(se_cmd); + if (buf) { + data_len = be32_to_cpu(*(u32 *)buf); + pr_debug("modify_rep_luns: len %d data_len %hud\n", + len, data_len); + if (data_len < len) + len = data_len; + buf += 8; + while (len > 0) { + *buf |= SCSI_LUN_ADDR_METHOD_FLAT << 6; + len -= 8; + buf += 8; + } + transport_kunmap_data_sg(se_cmd); } +} - if (tmp == 1) - tport->enabled = true; - else - tport->enabled = false; +/* + * This function modifies the inquiry data prior to sending to initiator + * so that we can make support current AIX. Internally we are going to + * add new ODM entries to support the emulation from LIO. This function + * is temporary until those changes are done. + */ +static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd) +{ + struct se_device *dev = se_cmd->se_dev; + unsigned char *buf = NULL; + u32 cmd_len = se_cmd->data_length; - return count; + if (cmd_len <= INQ_DATA_OFFSET) + return; + + buf = transport_kmap_data_sg(se_cmd); + if (buf) { + memcpy(&buf[8], "IBM ", 8); + if (dev->transport->get_device_type(dev) == TYPE_ROM) + memcpy(&buf[16], "VOPTA ", 16); + else + memcpy(&buf[16], "3303 NVDISK", 16); + memcpy(&buf[32], "0001", 4); + transport_kunmap_data_sg(se_cmd); + } } -CONFIGFS_ATTR(ibmvscsis_tpg_, enable); -static struct configfs_attribute *ibmvscsis_tpg_attrs[] = { - &ibmvscsis_tpg_attr_enable, - NULL, -}; +static int read_dma_window(struct vio_dev *vdev, + struct ibmvscsis_adapter *adapter) +{ + const __be32 *dma_window; + const __be32 *prop; -static const struct target_core_fabric_ops ibmvscsis_ops = { - .module = THIS_MODULE, - .name = "ibmvscsis", - .max_data_sg_nents = SCSI_MAX_SG_SEGMENTS, - .get_fabric_name = ibmvscsis_get_fabric_name, - .tpg_get_wwn = ibmvscsis_get_fabric_wwn, - .tpg_get_tag = ibmvscsis_get_tag, - .tpg_get_default_depth = ibmvscsis_get_default_depth, - .tpg_check_demo_mode = ibmvscsis_check_true, - .tpg_check_demo_mode_cache = ibmvscsis_check_true, - .tpg_check_demo_mode_write_protect = ibmvscsis_check_false, - .tpg_check_prod_mode_write_protect = ibmvscsis_check_false, - .tpg_get_inst_index = ibmvscsis_tpg_get_inst_index, - .check_stop_free = ibmvscsis_check_stop_free, - .release_cmd = ibmvscsis_release_cmd, - .shutdown_session = ibmvscsis_shutdown_session, - .close_session = ibmvscsis_close_session, - .sess_get_index = ibmvscsis_sess_get_index, - .write_pending = ibmvscsis_write_pending, - .write_pending_status = ibmvscsis_write_pending_status, - .set_default_node_attributes = ibmvscsis_set_default_node_attrs, - .get_cmd_state = ibmvscsis_get_cmd_state, - .queue_data_in = ibmvscsis_queue_data_in, - .queue_status = ibmvscsis_queue_status, - .queue_tm_rsp = ibmvscsis_queue_tm_rsp, - .aborted_task = ibmvscsis_aborted_task, - /* - * Setup function pointers for logic in target_cor_fabric_configfs.c - */ - .fabric_make_wwn = ibmvscsis_make_tport, - .fabric_drop_wwn = ibmvscsis_drop_tport, - .fabric_make_tpg = ibmvscsis_make_tpg, - .fabric_drop_tpg = ibmvscsis_drop_tpg, - - .tfc_wwn_attrs = ibmvscsis_wwn_attrs, - .tfc_tpg_base_attrs = ibmvscsis_tpg_attrs, -}; - -static struct vio_device_id ibmvscsis_device_table[] = { - {"v-scsi-host", "IBM,v-scsi-host"}, - {"", ""} -}; -MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table); - -static struct vio_driver ibmvscsis_driver = { - .name = ibmvscsis_driver_name, - .id_table = ibmvscsis_device_table, - .probe = ibmvscsis_probe, - .remove = ibmvscsis_remove, -}; - -/*****************************************************************************/ -/* End of global device driver data areas */ -/*****************************************************************************/ -static int crq_queue_create(struct crq_queue *queue, - struct ibmvscsis_adapter *adapter) -{ - int retrc; - int err; - struct vio_dev *vdev = adapter->dma_dev; - - queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); - - if (!queue->msgs) - goto malloc_failed; - - queue->size = PAGE_SIZE / sizeof(*queue->msgs); - - queue->msg_token = dma_map_single(&vdev->dev, queue->msgs, - queue->size * sizeof(*queue->msgs), - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(&vdev->dev, queue->msg_token)) - goto map_failed; - - err = h_reg_crq(vdev->unit_address, queue->msg_token, - PAGE_SIZE); - retrc = err; - - /* If the adapter was left active for some reason (like kexec) - * try freeing and re-registering + /* TODO Using of_parse_dma_window would be better, but it doesn't give + * a way to read multiple windows without already knowing the size of + * a window or the number of windows */ - if (err == H_RESOURCE) - err = ibmvscsis_reset_crq_queue(adapter); - if (err == 2) { - pr_warn("Partner adapter not ready\n"); - retrc = 0; - } else if (err != 0) { - pr_err("Error 0x%x opening virtual adapter\n", err); - goto reg_crq_failed; + dma_window = + (const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window", + NULL); + if (!dma_window) { + pr_err("Couldn't find ibm,my-dma-window property\n"); + return -1; } - queue->cur = 0; - spin_lock_init(&queue->lock); - - INIT_WORK(&adapter->crq_work, handle_crq); + adapter->liobn = be32_to_cpu(*dma_window); + dma_window++; - err = request_irq(vdev->irq, &ibmvscsis_interrupt, - 0, "ibmvscsis", adapter); - if (err) { - pr_err("Error 0x%x h_send_crq\n", err); - goto req_irq_failed; + prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells", + NULL); + if (!prop) { + pr_warn("Couldn't find ibm, #dma-address-cells property\n"); + dma_window++; + } else { + dma_window += be32_to_cpu(*prop); } - err = vio_enable_interrupts(vdev); - if (err != 0) { - pr_err("Error %d enabling interrupts!!!\n", err); - goto req_irq_failed; + prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells", + NULL); + if (!prop) { + pr_warn("Couldn't find ibm, #dma-size-cells property\n"); + dma_window++; + } else { + dma_window += be32_to_cpu(*prop); } - return retrc; + /* dma_window should point to the second window now */ + adapter->riobn = be32_to_cpu(*dma_window); -req_irq_failed: - h_free_crq(vdev->unit_address); -reg_crq_failed: - dma_unmap_single(&vdev->dev, queue->msg_token, - queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); -map_failed: - free_page((unsigned long)queue->msgs); -malloc_failed: - return -1; + return 0; } -static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id) +static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name) { - int ret = -ENOMEM; - struct ibmvscsis_adapter *adapter; - struct srp_target *target; struct ibmvscsis_tport *tport; + struct vio_dev *vdev; + struct ibmvscsis_adapter *adapter; + int ret; unsigned long flags; - pr_debug("Probe for UA 0x%x\n", vdev->unit_address); - - adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); - if (!adapter) - return ret; - target = kzalloc(sizeof(*target), GFP_KERNEL); - if (!target) - goto free_adapter; - - adapter->dma_dev = vdev; - adapter->target = target; - tport = &adapter->tport; + spin_lock_irqsave(&ibmvscsis_dev_lock, flags); + list_for_each_entry(adapter, &ibmvscsis_dev_list, list) { + vdev = adapter->dma_dev; + ret = strcmp(dev_name(&vdev->dev), name); + if (ret == 0) + tport = &adapter->tport; + if (tport) + goto found; + } + spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); + return NULL; +found: + spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); + return tport; +} - tport->enabled = false; - snprintf(&adapter->tport.tport_name[0], 256, "%s", - dev_name(&vdev->dev)); +static irqreturn_t ibmvscsis_interrupt(int dummy, void *data) +{ + struct ibmvscsis_adapter *adapter = data; - ret = read_dma_window(adapter->dma_dev, adapter); - if (ret != 0) - goto free_target; + vio_disable_interrupts(adapter->dma_dev); + queue_work(vtgtd, &adapter->crq_work); - pr_debug("Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn, - adapter->riobn); + return IRQ_HANDLED; +} - spin_lock_irqsave(&ibmvscsis_dev_lock, flags); - list_add_tail(&adapter->list, &ibmvscsis_dev_list); - spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); +static int send_iu(struct iu_entry *iue, u64 length, u8 format) +{ + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + struct ibmvscsis_crq_msg crq_msg; + struct srp_rsp *rsp; + __be64 *crq_as_u64 = (__be64 *)&crq_msg; + long rc, rc1; - ret = srp_target_alloc(target, &vdev->dev, - INITIAL_SRP_LIMIT, - SRP_MAX_IU_LEN); + rsp = &vio_iu(iue)->srp.rsp; + pr_debug("send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", + (unsigned long)length, + (unsigned long)adapter->liobn, + (unsigned long)iue->sbuf->dma, + (unsigned long)adapter->riobn, + (unsigned long)be64_to_cpu(iue->remote_token)); - adapter->target->ldata = adapter; + /* First copy the SRP */ + rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma, + adapter->riobn, be64_to_cpu(iue->remote_token)); - if (ret) { - pr_err("failed target alloc ret: %d\n", ret); - goto free_srp_target; + switch (rc) { + case H_SUCCESS: + break; + case H_PERMISSION: + case H_SOURCE_PARM: + case H_DEST_PARM: + if (connection_broken(adapter)) { + pr_debug("rdma connection broken\n"); + goto end; + } + break; + default: + pr_err("Error %ld transferring data\n", rc); + length = 0; + break; } - ret = crq_queue_create(&adapter->crq_queue, adapter); - if (ret != 0 && ret != H_RESOURCE) { - pr_err("failed crq_queue_create ret: %d\n", ret); - ret = -1; - } + pr_debug("crq pre cooked: 0x%x, 0x%llx, 0x%llx\n", + format, length, vio_iu(iue)->srp.rsp.tag); - if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0 && - ret != H_RESOURCE) { - pr_warn("Failed to send CRQ message\n"); - ret = 0; - } + crq_msg.valid = 0x80; + crq_msg.format = format; + crq_msg.rsvd = 0; + if (rc == 0) + crq_msg.status = 0x99; + else + crq_msg.status = rsp->status; + crq_msg.rsvd1 = 0; + crq_msg.IU_length = cpu_to_be16(length); + crq_msg.IU_data_ptr = vio_iu(iue)->srp.rsp.tag; - dev_set_drvdata(&vdev->dev, adapter); + pr_debug("send crq: 0x%x, 0x%llx, 0x%llx\n", + adapter->dma_dev->unit_address, + be64_to_cpu(crq_as_u64[0]), + be64_to_cpu(crq_as_u64[1])); - return 0; + srp_iu_put(iue); -free_srp_target: - srp_target_free(target); -free_target: - kfree(target); -free_adapter: - kfree(adapter); - return ret; -} + rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), + be64_to_cpu(crq_as_u64[1])); -static int ibmvscsis_remove(struct vio_dev *dev) -{ - unsigned long flags; - struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev); - struct srp_target *target; + if (rc1) { + pr_err("%ld sending response\n", rc1); + return rc1; + } + return rc; +end: + return rc; +} - target = adapter->target; +static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter) +{ + int rc = 0; + struct vio_dev *vdev = adapter->dma_dev; + struct crq_queue *queue = &adapter->crq_queue; - spin_lock_irqsave(&ibmvscsis_dev_lock, flags); - list_del(&adapter->list); - spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); + /* Close the CRQ */ + h_free_crq(vdev->unit_address); - crq_queue_destroy(adapter); - srp_target_free(target); + /* Clean out the queue */ + memset(queue->msgs, 0x00, PAGE_SIZE); + queue->cur = 0; - kfree(target); - kfree(adapter); + /* And re-open it again */ + rc = h_reg_crq(vdev->unit_address, queue->msg_token, PAGE_SIZE); + if (rc == 2) + /* Adapter is good, but other end is not ready */ + pr_warn("Partner adapter not ready\n"); + else if (rc != 0) + pr_err("Couldn't register crq--rc 0x%x\n", rc); - return 0; + return rc; } -static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd) +static int send_adapter_info(struct iu_entry *iue, + dma_addr_t remote_buffer, u16 length) { - s32 len = se_cmd->data_length; - u16 data_len; - unsigned char *buf = NULL; + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + dma_addr_t data_token; + struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info; + struct mad_adapter_info_data *info; + int err; - if (len <= 8) - return; + mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS); - len -= 8; - buf = transport_kmap_data_sg(se_cmd); - if (buf) { - data_len = be32_to_cpu(*(u32 *)buf); - pr_debug("modify_rep_luns: len %d data_len %hud\n", - len, data_len); - if (data_len < len) - len = data_len; - buf += 8; - while (len > 0) { - *buf |= SCSI_LUN_ADDR_METHOD_FLAT << 6; - len -= 8; - buf += 8; - } - transport_kunmap_data_sg(se_cmd); + if (be16_to_cpu(mad->common.length) > sizeof(*info)) { + mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED); + return 0; } -} -/* - * This function modifies the inquiry data prior to sending to initiator - * so that we can make support current AIX. Internally we are going to - * add new ODM entries to support the emulation from LIO. This function - * is temporary until those changes are done. - */ -static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd) -{ - struct se_device *dev = se_cmd->se_dev; - unsigned char *buf = NULL; - u32 cmd_len = se_cmd->data_length; + info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info), + &data_token, GFP_KERNEL); + if (!info) { + pr_err("bad dma_alloc_coherent %p\n", target); + mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED); + return 1; + } - if (cmd_len <= INQ_DATA_OFFSET) - return; + /* Get remote info */ + err = h_copy_rdma(sizeof(*info), adapter->riobn, + be64_to_cpu(remote_buffer), + adapter->liobn, data_token); - buf = transport_kmap_data_sg(se_cmd); - if (buf) { - memcpy(&buf[8], "IBM ", 8); - if (dev->transport->get_device_type(dev) == TYPE_ROM) - memcpy(&buf[16], "VOPTA ", 16); - else - memcpy(&buf[16], "3303 NVDISK", 16); - memcpy(&buf[32], "0001", 4); - transport_kunmap_data_sg(se_cmd); - } -} + if (err == H_SUCCESS) { + pr_err("Client connect: %s (%d)\n", + info->partition_name, info->partition_number); -static int read_dma_window(struct vio_dev *vdev, - struct ibmvscsis_adapter *adapter) -{ - const __be32 *dma_window; - const __be32 *prop; + if (adapter->client_data.partition_number == 0) + adapter->client_data.partition_number = + be32_to_cpu(info->partition_number); + strncpy(adapter->client_data.srp_version, info->srp_version, + sizeof(adapter->client_data.srp_version)); + strncpy(adapter->client_data.partition_name, + info->partition_name, + sizeof(adapter->client_data.partition_name)); + adapter->client_data.mad_version = + be32_to_cpu(info->mad_version); + adapter->client_data.os_type = be32_to_cpu(info->os_type); + pr_debug("adapter info client adapter %u\n", + adapter->client_data.os_type); - /* TODO Using of_parse_dma_window would be better, but it doesn't give - * a way to read multiple windows without already knowing the size of - * a window or the number of windows - */ - dma_window = - (const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window", - NULL); - if (!dma_window) { - pr_err("Couldn't find ibm,my-dma-window property\n"); - return -1; - } + strcpy(info->srp_version, "16.a"); + strncpy(info->partition_name, partition_name, + sizeof(info->partition_name)); - adapter->liobn = be32_to_cpu(*dma_window); - dma_window++; + info->partition_number = cpu_to_be32(partition_number); + info->mad_version = cpu_to_be32(1); + info->os_type = cpu_to_be32(2); + memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu)); + info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS * + PAGE_SIZE); - prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells", - NULL); - if (!prop) { - pr_warn("Couldn't find ibm, #dma-address-cells property\n"); - dma_window++; - } else { - dma_window += be32_to_cpu(*prop); - } + dma_rmb(); + /* Send our info to remote */ + err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token, + adapter->riobn, be64_to_cpu(remote_buffer)); - prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells", - NULL); - if (!prop) { - pr_warn("Couldn't find ibm, #dma-size-cells property\n"); - dma_window++; + switch (err) { + case H_SUCCESS: + break; + case H_PERMISSION: + case H_SOURCE_PARM: + case H_DEST_PARM: + if (connection_broken(adapter)) + pr_debug("rdma connection broken\n"); + default: + pr_err("Error sending adapter info %d\n", + err); + return -EIO; + } } else { - dma_window += be32_to_cpu(*prop); + pr_err("Error sending adapter info %d\n", err); + return 1; } - /* dma_window should point to the second window now */ - adapter->riobn = be32_to_cpu(*dma_window); + dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info, + data_token); return 0; } -static void ibmvscsis_dev_release(struct device *dev) {}; - -static char *ibmvscsis_get_fabric_name(void) -{ - return "ibmvscsis"; -} - -static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg) -{ - struct ibmvscsis_tport *tport = - container_of(se_tpg, struct ibmvscsis_tport, se_tpg); - - return &tport->tport_name[0]; -} - -static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg) +static int process_mad_iu(struct iu_entry *iue) { - struct ibmvscsis_tport *tport = - container_of(se_tpg, struct ibmvscsis_tport, se_tpg); + union viosrp_iu *iu = vio_iu(iue); + struct viosrp_adapter_info *info; + struct viosrp_host_config *conf; - return tport->tport_tpgt; -} + switch (be32_to_cpu(iu->mad.empty_iu.common.type)) { + case VIOSRP_EMPTY_IU_TYPE: + pr_err("%s\n", "Unsupported EMPTY MAD IU"); + break; + case VIOSRP_ERROR_LOG_TYPE: + pr_err("%s\n", "Unsupported ERROR LOG MAD IU"); + iu->mad.error_log.common.status = 1; + send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT); + break; + case VIOSRP_ADAPTER_INFO_TYPE: + info = &iu->mad.adapter_info; + info->common.status = send_adapter_info(iue, info->buffer, + info->common.length); + send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT); + break; + case VIOSRP_HOST_CONFIG_TYPE: + conf = &iu->mad.host_config; + conf->common.status = 1; + send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT); + break; + default: + pr_err("Unknown type %u\n", iu->srp.rsp.opcode); + iu->mad.empty_iu.common.status = + cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED); + send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT); + break; + } -static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg) -{ return 1; } -static int ibmvscsis_check_true(struct se_portal_group *se_tpg) +static struct se_portal_group *ibmvscsis_make_nexus(struct ibmvscsis_tport + *tport, + const char *name) { - return 1; -} + struct se_node_acl *acl; -static int ibmvscsis_check_false(struct se_portal_group *se_tpg) -{ - return 0; -} + if (tport->se_sess) { + pr_debug("tport->se_sess already exists\n"); + return &tport->se_tpg; + } -static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg) -{ - return 1; -} - -static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd) -{ - struct ibmvscsis_cmnd *cmd = container_of(se_cmd, - struct ibmvscsis_cmnd, - se_cmd); - - return target_put_sess_cmd(&cmd->se_cmd); -} - -static void ibmvscsis_release_cmd(struct se_cmd *se_cmd) -{ - struct ibmvscsis_cmnd *cmd = - container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd); - - kfree(cmd); -} + /* + * Initialize the struct se_session pointer and setup tagpool + * for struct ibmvscsis_cmd descriptors + */ + tport->se_sess = transport_init_session(TARGET_PROT_NORMAL); + if (IS_ERR(tport->se_sess)) + goto transport_init_fail; -static int ibmvscsis_shutdown_session(struct se_session *se_sess) -{ - return 0; -} + /* + * Since we are running in 'demo mode' this call will generate a + * struct se_node_acl for the ibmvscsis struct se_portal_group with + * the SCSI Initiator port name of the passed configfs group 'name'. + */ -static void ibmvscsis_close_session(struct se_session *se_sess) -{ -} + acl = core_tpg_check_initiator_node_acl(&tport->se_tpg, + (unsigned char *)name); + if (!acl) { + pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n", + name); + goto acl_failed; + } + tport->se_sess->se_node_acl = acl; -static u32 ibmvscsis_sess_get_index(struct se_session *se_sess) -{ - return 0; -} + /* + * Now register the TCM ibmvscsis virtual I_T Nexus as active. + */ + transport_register_session(&tport->se_tpg, + tport->se_sess->se_node_acl, + tport->se_sess, tport); -static int ibmvscsis_write_pending(struct se_cmd *se_cmd) -{ - struct ibmvscsis_cmnd *cmd = container_of(se_cmd, - struct ibmvscsis_cmnd, - se_cmd); - struct scsi_cmnd *sc = &cmd->sc; - struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; - int ret; + tport->se_sess->se_tpg = &tport->se_tpg; - sc->sdb.length = se_cmd->data_length; - sc->sdb.table.nents = se_cmd->t_data_nents; - sc->sdb.table.sgl = se_cmd->t_data_sg; + return &tport->se_tpg; - ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, - ibmvscsis_rdma, 1, 1); - if (ret) { - pr_err("srp_transfer_data() failed: %d\n", ret); - return -EAGAIN; - } - /* - * We now tell TCM to add this WRITE CDB directly into the TCM storage - * object execution queue. - */ - target_execute_cmd(&cmd->se_cmd); - return 0; +acl_failed: + transport_free_session(tport->se_sess); +transport_init_fail: + kfree(tport); + return ERR_PTR(-ENOMEM); } -static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd) +static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport) { - return 0; -} + struct se_session *se_sess; -static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl) -{ -} + se_sess = tport->se_sess; + if (!se_sess) + return -ENODEV; -static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd) -{ + transport_deregister_session(tport->se_sess); + transport_free_session(tport->se_sess); return 0; } -static void ibmvscsis_determine_resid(struct se_cmd *se_cmd, - struct srp_rsp *rsp) -{ - if (se_cmd->residual_count) { - if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { - if (se_cmd->data_direction == DMA_TO_DEVICE) { - /* residual data from an underflow write */ - rsp->flags = SRP_RSP_FLAG_DOUNDER; - rsp->data_out_res_cnt = - cpu_to_be32(se_cmd->residual_count); - } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { - /* residual data from an underflow read */ - rsp->flags = SRP_RSP_FLAG_DIUNDER; - rsp->data_in_res_cnt = - cpu_to_be32(se_cmd->residual_count); - } - } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { - if (se_cmd->data_direction == DMA_TO_DEVICE) { - /* residual data from an overflow write */ - rsp->flags = SRP_RSP_FLAG_DOOVER; - rsp->data_out_res_cnt = - cpu_to_be32(se_cmd->residual_count); - } else if (se_cmd->data_direction == - DMA_FROM_DEVICE) { - /* residual data from an overflow read */ - rsp->flags = SRP_RSP_FLAG_DIOVER; - rsp->data_in_res_cnt = - cpu_to_be32(se_cmd->residual_count); - } - } - } -} - -static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd) +static void process_login(struct iu_entry *iue) { - struct ibmvscsis_cmnd *cmd = container_of(se_cmd, - struct ibmvscsis_cmnd, - se_cmd); - struct scsi_cmnd *sc = &cmd->sc; - struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; - struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf; - struct srp_rsp *rsp; - char *sd; - char *data; - int ret; - uint len; - + union viosrp_iu *iu = vio_iu(iue); + struct srp_login_rsp *rsp = &iu->srp.login_rsp; + struct srp_login_rej *rej = &iu->srp.login_rej; struct srp_target *target = iue->target; struct ibmvscsis_adapter *adapter = target->ldata; + struct vio_dev *vdev = adapter->dma_dev; + struct se_portal_group *se_tpg; + char name[16]; + u64 tag = iu->srp.rsp.tag; /* - * Check for overflow residual count + * TODO handle case that requested size is wrong and buffer + * format is wrong */ + memset(iu, 0, max(sizeof(*rsp), sizeof(*rej))); - if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) - scsi_set_resid(sc, se_cmd->residual_count); + snprintf(name, sizeof(name), "%x", vdev->unit_address); - sc->sdb.length = se_cmd->data_length; - sc->sdb.table.nents = se_cmd->t_data_nents; - sc->sdb.table.sgl = se_cmd->t_data_sg; + if (!adapter->tport.enabled) { + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_err("Rejected SRP_LOGIN_REQ because target %s has not yet been enabled", + name); + goto reject; + } - if (scsi_sg_count(sc)) { - if (srp->cdb[0] == REPORT_LUNS && - adapter->client_data.os_type != LINUX) - ibmvscsis_modify_rep_luns(se_cmd); - if ((srp->cdb[0] == INQUIRY) && ((srp->cdb[1] & 0x1) == 0)) - ibmvscsis_modify_std_inquiry(se_cmd); - ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, - ibmvscsis_rdma, 1, 1); - if (ret) { - pr_err("srp_transfer_data failed: %d\n", ret); - sd = cmd->se_cmd.sense_buffer; - cmd->se_cmd.scsi_sense_length = 18; - memset(cmd->se_cmd.sense_buffer, 0, - cmd->se_cmd.scsi_sense_length); - sd[0] = 0x70; - sd[2] = 3; - sd[7] = 10; - sd[12] = 8; - sd[13] = 1; - } + se_tpg = ibmvscsis_make_nexus(&adapter->tport, + &adapter->tport.tport_name[0]); + if (!se_tpg) { + pr_debug("login make nexus fail se_tpg(%p)\n", se_tpg); + goto reject; } - rsp = &vio_iu(iue)->srp.rsp; - len = sizeof(*rsp); - memset(rsp, 0, len); - data = rsp->data; + rsp->opcode = SRP_LOGIN_RSP; - rsp->tag = se_cmd->tag; - rsp->req_lim_delta = cpu_to_be32(1); - rsp->opcode = SRP_RSP; + rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT); - ibmvscsis_determine_resid(se_cmd, rsp); - rsp->status = se_cmd->scsi_status; + pr_debug("process_login, tag:%llu\n", tag); - if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) { - rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length); - rsp->flags |= SRP_RSP_FLAG_SNSVALID; - len += se_cmd->scsi_sense_length; - memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length); - } + rsp->tag = tag; + rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu)); + rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu)); + /* direct and indirect */ + rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | + SRP_BUF_FORMAT_INDIRECT); - send_iu(iue, len, VIOSRP_SRP_FORMAT); - return 0; + send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT); + return; + +reject: + rej->opcode = SRP_LOGIN_REJ; + rej->tag = tag; + rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | + SRP_BUF_FORMAT_INDIRECT); + + send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT); } -static int ibmvscsis_queue_status(struct se_cmd *se_cmd) +static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter, + struct iu_entry *iue) { - struct ibmvscsis_cmnd *cmd = container_of(se_cmd, - struct ibmvscsis_cmnd, - se_cmd); - struct scsi_cmnd *sc = &cmd->sc; - struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; + struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt; + struct ibmvscsis_cmnd *cmd = adapter->cmd; struct srp_rsp *rsp; - uint len; - char *data; - - /* - * Copy any generated SENSE data into sc->sense_buffer and - * set the appropriate sc->result to be translated by - * ibmvscsis_cmnd_done() - */ + u64 unpacked_lun = 0; + u64 tag_to_abort = 0; + int tcm_type; + int rc = 0; rsp = &vio_iu(iue)->srp.rsp; - len = sizeof(*rsp); - memset(rsp, 0, len); - data = rsp->data; - - rsp->tag = se_cmd->tag; - rsp->req_lim_delta = cpu_to_be32(1); - rsp->opcode = SRP_RSP; - - ibmvscsis_determine_resid(se_cmd, rsp); - rsp->status = se_cmd->scsi_status; + unpacked_lun = ibmvscsis_unpack_lun((u8 *)&srp_tsk->lun, + sizeof(srp_tsk->lun)); - if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) { - rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length); - rsp->flags |= SRP_RSP_FLAG_SNSVALID; - len += se_cmd->scsi_sense_length; - memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length); + switch (srp_tsk->tsk_mgmt_func) { + case SRP_TSK_ABORT_TASK: + tcm_type = TMR_ABORT_TASK; + tag_to_abort = be64_to_cpu(srp_tsk->task_tag); + srp_iu_put(iue); + break; + case SRP_TSK_ABORT_TASK_SET: + tcm_type = TMR_ABORT_TASK_SET; + break; + case SRP_TSK_CLEAR_TASK_SET: + tcm_type = TMR_CLEAR_TASK_SET; + break; + case SRP_TSK_LUN_RESET: + tcm_type = TMR_LUN_RESET; + break; + case SRP_TSK_CLEAR_ACA: + tcm_type = TMR_CLEAR_ACA; + break; + default: + pr_err("unknown task mgmt func %d\n", srp_tsk->tsk_mgmt_func); + cmd->se_cmd.se_tmr_req->response = + TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; + goto fail; } - send_iu(iue, len, VIOSRP_SRP_FORMAT); - return 0; -} - -static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd) -{ - struct ibmvscsis_cmnd *cmd = container_of(se_cmd, - struct ibmvscsis_cmnd, - se_cmd); - struct scsi_cmnd *sc = &cmd->sc; - struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; - struct srp_target *target = iue->target; - struct ibmvscsis_adapter *adapter = target->ldata; - struct srp_rsp *rsp; - uint len; - char *data; - u32 *tsk_status; - u32 rsp_code; - rsp = &vio_iu(iue)->srp.rsp; + cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag); - if (transport_check_aborted_status(se_cmd, false) != 0) { - pr_debug("queue_tm_rsp aborted\n"); - atomic_inc(&adapter->req_lim_delta); - srp_iu_put(iue); - } else { - rsp->req_lim_delta = cpu_to_be32(1 + - atomic_xchg(&adapter-> - req_lim_delta, 0)); + pr_debug("calling submit_tmr, func %d\n", + srp_tsk->tsk_mgmt_func); + rc = target_submit_tmr(&cmd->se_cmd, + adapter->tport.se_sess, NULL, + unpacked_lun, srp_tsk, tcm_type, + GFP_KERNEL, tag_to_abort, + TARGET_SCF_ACK_KREF); + if (rc != 0) { + pr_err("target_submit_tmr failed, rc %d\n", rc); + cmd->se_cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED; + goto fail; } - len = sizeof(*rsp); - memset(rsp, 0, len); - data = rsp->data; +fail: + if (rc) + transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0); +} - rsp->opcode = SRP_RSP; - rsp->tag = se_cmd->se_tmr_req->ref_task_tag; - rsp->status = 0; - rsp->resp_data_len = cpu_to_be32(4); - rsp->flags |= SRP_RSP_FLAG_RSPVALID; - rsp->req_lim_delta = cpu_to_be32(1); +static int tcm_queuecommand(struct ibmvscsis_adapter *adapter, + struct ibmvscsis_cmnd *vsc, + struct srp_cmd *scmd) +{ + struct se_cmd *se_cmd; + int attr; + u64 data_len; + int ret; + u64 unpacked_lun; - switch (se_cmd->se_tmr_req->response) { - case TMR_FUNCTION_COMPLETE: - case TMR_TASK_DOES_NOT_EXIST: - rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE; + switch (scmd->task_attr) { + case SRP_SIMPLE_TASK: + attr = TCM_SIMPLE_TAG; break; - case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: - case TMR_LUN_DOES_NOT_EXIST: - rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED; + case SRP_ORDERED_TASK: + attr = TCM_ORDERED_TAG; break; - case TMR_FUNCTION_FAILED: - case TMR_FUNCTION_REJECTED: - default: - rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED; + case SRP_HEAD_TASK: + attr = TCM_HEAD_TAG; + break; + case SRP_ACA_TASK: + attr = TCM_ACA_TAG; break; + default: + pr_err("Task attribute %d not supported\n", scmd->task_attr); + attr = TCM_SIMPLE_TAG; } - tsk_status = (u32 *)data; - *tsk_status = cpu_to_be32(rsp_code); - data = (char *)(tsk_status + 1); - len += 4; + pr_debug("srp_data_length: %llx, srp_direction:%x\n", + srp_data_length(scmd, srp_cmd_direction(scmd)), + srp_cmd_direction(scmd)); + data_len = srp_data_length(scmd, srp_cmd_direction(scmd)); - send_iu(iue, len, VIOSRP_SRP_FORMAT); -} + vsc->se_cmd.tag = scmd->tag; + se_cmd = &vsc->se_cmd; -static void ibmvscsis_aborted_task(struct se_cmd *se_cmd) -{ -} + pr_debug("size of lun:%lx, lun:%s\n", sizeof(scmd->lun), + &scmd->lun.scsi_lun[0]); -static struct se_portal_group *ibmvscsis_make_nexus(struct ibmvscsis_tport - *tport, - const char *name) -{ - struct se_node_acl *acl; + unpacked_lun = ibmvscsis_unpack_lun((u8 *)&scmd->lun, + sizeof(scmd->lun)); - if (tport->se_sess) { - pr_debug("tport->se_sess already exists\n"); - return &tport->se_tpg; + ret = target_submit_cmd(se_cmd, adapter->tport.se_sess, + &scmd->cdb[0], &vsc->sense_buf[0], unpacked_lun, + data_len, attr, srp_cmd_direction(scmd), + TARGET_SCF_ACK_KREF); + if (ret != 0) { + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + pr_debug("tcm_queuecommand fail submit_cmd\n"); + goto send_sense; } + return 0; - /* - * Initialize the struct se_session pointer and setup tagpool - * for struct ibmvscsis_cmd descriptors - */ - tport->se_sess = transport_init_session(TARGET_PROT_NORMAL); - if (IS_ERR(tport->se_sess)) - goto transport_init_fail; - - /* - * Since we are running in 'demo mode' this call will generate a - * struct se_node_acl for the ibmvscsis struct se_portal_group with - * the SCSI Initiator port name of the passed configfs group 'name'. - */ - - acl = core_tpg_check_initiator_node_acl(&tport->se_tpg, - (unsigned char *)name); - if (!acl) { - pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n", - name); - goto acl_failed; - } - tport->se_sess->se_node_acl = acl; +send_sense: + transport_send_check_condition_and_sense(&vsc->se_cmd, ret, 0); + transport_generic_free_cmd(&vsc->se_cmd, 0); + return -1; +} - /* - * Now register the TCM ibmvscsis virtual I_T Nexus as active. - */ - transport_register_session(&tport->se_tpg, - tport->se_sess->se_node_acl, - tport->se_sess, tport); +static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, + struct iu_entry *iue) +{ + struct srp_cmd *cmd = iue->sbuf->buf; + struct scsi_cmnd *sc; + struct ibmvscsis_cmnd *vsc; + int ret; - tport->se_sess->se_tpg = &tport->se_tpg; + vsc = kzalloc(sizeof(*vsc), GFP_KERNEL); + adapter->cmd = vsc; + sc = &vsc->sc; + sc->sense_buffer = vsc->se_cmd.sense_buffer; + sc->cmnd = cmd->cdb; + sc->SCp.ptr = (char *)iue; - return &tport->se_tpg; + ret = tcm_queuecommand(adapter, vsc, cmd); -acl_failed: - transport_free_session(tport->se_sess); -transport_init_fail: - kfree(tport); - return ERR_PTR(-ENOMEM); + return ret; } -static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport) +static void ibmvscsis_srp_i_logout(struct iu_entry *iue) { - struct se_session *se_sess; - - se_sess = tport->se_sess; - if (!se_sess) - return -ENODEV; + union viosrp_iu *iu = vio_iu(iue); + struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout; + u64 tag = iu->srp.rsp.tag; - transport_deregister_session(tport->se_sess); - transport_free_session(tport->se_sess); - return 0; + log_out->opcode = SRP_I_LOGOUT; + log_out->tag = tag; + send_iu(iue, sizeof(*log_out), VIOSRP_SRP_FORMAT); } -static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name) +static int process_srp_iu(struct iu_entry *iue) { - struct ibmvscsis_tport *tport; - struct vio_dev *vdev; - struct ibmvscsis_adapter *adapter; - int ret; + union viosrp_iu *iu = vio_iu(iue); + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + u8 opcode = iu->srp.rsp.opcode; unsigned long flags; + int err = 1; - spin_lock_irqsave(&ibmvscsis_dev_lock, flags); - list_for_each_entry(adapter, &ibmvscsis_dev_list, list) { - vdev = adapter->dma_dev; - ret = strcmp(dev_name(&vdev->dev), name); - if (ret == 0) - tport = &adapter->tport; - if (tport) - goto found; - } - spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); - return NULL; -found: - spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); - return tport; -} - -static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf, - struct config_group *group, - const char *name) -{ - struct ibmvscsis_tport *tport; - int ret; - - tport = ibmvscsis_lookup_port(name); - ret = -EINVAL; - - if (!tport) - goto err; - - tport->tport_proto_id = SCSI_PROTOCOL_SRP; - pr_debug("make_tport(%s), pointer:%p tport_id:%x\n", name, tport, - tport->tport_proto_id); - - return &tport->tport_wwn; -err: - return ERR_PTR(ret); -} - -static void ibmvscsis_drop_tport(struct se_wwn *wwn) -{ - struct ibmvscsis_tport *tport = container_of(wwn, - struct ibmvscsis_tport, - tport_wwn); - - pr_debug("drop_tport(%s\n", - config_item_name(&tport->tport_wwn.wwn_group.cg_item)); -} - -static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, - struct config_group *group, - const char *name) -{ - struct ibmvscsis_tport *tport = - container_of(wwn, struct ibmvscsis_tport, tport_wwn); - int ret; - - tport->releasing = false; - - ret = core_tpg_register(&tport->tport_wwn, - &tport->se_tpg, - tport->tport_proto_id); - if (ret) - return ERR_PTR(ret); - - return &tport->se_tpg; -} - -static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg) -{ - struct ibmvscsis_tport *tport = container_of(se_tpg, - struct ibmvscsis_tport, - se_tpg); - - tport->releasing = true; - tport->enabled = false; - - /* - * Release the virtual I_T Nexus for this ibmvscsis TPG - */ - ibmvscsis_drop_nexus(tport); - /* - * Deregister the se_tpg from TCM.. - */ - core_tpg_deregister(se_tpg); -} - -static ssize_t system_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", system_id); -} - -static ssize_t partition_number_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%x\n", partition_number); -} - -static ssize_t unit_address_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ibmvscsis_adapter *adapter = - container_of(dev, struct ibmvscsis_adapter, dev); - - return snprintf(buf, PAGE_SIZE, "%x\n", adapter->dma_dev->unit_address); -} - -static int get_system_info(void) -{ - struct device_node *rootdn, *vdevdn; - const char *id, *model, *name; - const unsigned int *num; - - rootdn = of_find_node_by_path("/"); - if (!rootdn) - return -ENOENT; - - model = of_get_property(rootdn, "model", NULL); - id = of_get_property(rootdn, "system-id", NULL); - if (model && id) - snprintf(system_id, sizeof(system_id), "%s-%s", model, id); - - name = of_get_property(rootdn, "ibm,partition-name", NULL); - if (name) - strncpy(partition_name, name, sizeof(partition_name)); - - num = of_get_property(rootdn, "ibm,partition-no", NULL); - if (num) - partition_number = of_read_number(num, 1); - - of_node_put(rootdn); - - vdevdn = of_find_node_by_path("/vdevice"); - vdevdn = of_find_node_by_path("/vdevice"); - if (vdevdn) { - const unsigned *mvds; - - mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size", - NULL); - if (mvds) - max_vdma_size = *mvds; - of_node_put(vdevdn); - } - - return 0; -}; - -static irqreturn_t ibmvscsis_interrupt(int dummy, void *data) -{ - struct ibmvscsis_adapter *adapter = data; - - vio_disable_interrupts(adapter->dma_dev); - queue_work(vtgtd, &adapter->crq_work); - - return IRQ_HANDLED; -} - -static int process_srp_iu(struct iu_entry *iue) -{ - union viosrp_iu *iu = vio_iu(iue); - struct srp_target *target = iue->target; - struct ibmvscsis_adapter *adapter = target->ldata; - u8 opcode = iu->srp.rsp.opcode; - unsigned long flags; - int err = 1; - - spin_lock_irqsave(&target->lock, flags); - if (adapter->tport.releasing) { - pr_err("process_srp_iu error, tport is released:%x\n", - adapter->tport.releasing); - goto done; + spin_lock_irqsave(&target->lock, flags); + if (adapter->tport.releasing) { + pr_err("process_srp_iu error, tport is released:%x\n", + adapter->tport.releasing); + goto done; } if (!adapter->tport.enabled) { pr_err("process_srp_iu, tport not enabled:%x\n", @@ -1306,6 +1008,29 @@ static void process_crq(struct viosrp_crq *crq, } } +static inline struct viosrp_crq *next_crq(struct crq_queue *queue) +{ + struct viosrp_crq *crq; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + crq = &queue->msgs[queue->cur]; + if (crq->valid & 0x80 || crq->valid & 0xFF) { + if (++queue->cur == queue->size) + queue->cur = 0; + + /* Ensure the read of the valid bit occurs before reading any + * other bits of the CRQ entry + */ + rmb(); + } else { + crq = NULL; + } + spin_unlock_irqrestore(&queue->lock, flags); + + return crq; +} + static void handle_crq(struct work_struct *work) { struct ibmvscsis_adapter *adapter = @@ -1332,623 +1057,815 @@ static void handle_crq(struct work_struct *work) } } -static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter) +static int crq_queue_create(struct crq_queue *queue, + struct ibmvscsis_adapter *adapter) { - int rc = 0; + int retrc; + int err; struct vio_dev *vdev = adapter->dma_dev; - struct crq_queue *queue = &adapter->crq_queue; - /* Close the CRQ */ - h_free_crq(vdev->unit_address); + queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); - /* Clean out the queue */ - memset(queue->msgs, 0x00, PAGE_SIZE); - queue->cur = 0; + if (!queue->msgs) + goto malloc_failed; - /* And re-open it again */ - rc = h_reg_crq(vdev->unit_address, queue->msg_token, PAGE_SIZE); - if (rc == 2) - /* Adapter is good, but other end is not ready */ - pr_warn("Partner adapter not ready\n"); - else if (rc != 0) - pr_err("Couldn't register crq--rc 0x%x\n", rc); + queue->size = PAGE_SIZE / sizeof(*queue->msgs); - return rc; -} + queue->msg_token = dma_map_single(&vdev->dev, queue->msgs, + queue->size * sizeof(*queue->msgs), + DMA_BIDIRECTIONAL); -static void crq_queue_destroy(struct ibmvscsis_adapter *adapter) -{ - struct vio_dev *vdev = adapter->dma_dev; - struct crq_queue *queue = &adapter->crq_queue; + if (dma_mapping_error(&vdev->dev, queue->msg_token)) + goto map_failed; - free_irq(vdev->irq, (void *)adapter); - flush_work(&adapter->crq_work); - h_free_crq(vdev->unit_address); - dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token, - queue->size * sizeof(*queue->msgs), - DMA_BIDIRECTIONAL); + err = h_reg_crq(vdev->unit_address, queue->msg_token, + PAGE_SIZE); + retrc = err; - free_page((unsigned long)queue->msgs); -} + /* If the adapter was left active for some reason (like kexec) + * try freeing and re-registering + */ + if (err == H_RESOURCE) + err = ibmvscsis_reset_crq_queue(adapter); + if (err == 2) { + pr_warn("Partner adapter not ready\n"); + retrc = 0; + } else if (err != 0) { + pr_err("Error 0x%x opening virtual adapter\n", err); + goto reg_crq_failed; + } -static inline struct viosrp_crq *next_crq(struct crq_queue *queue) -{ - struct viosrp_crq *crq; - unsigned long flags; + queue->cur = 0; + spin_lock_init(&queue->lock); - spin_lock_irqsave(&queue->lock, flags); - crq = &queue->msgs[queue->cur]; - if (crq->valid & 0x80 || crq->valid & 0xFF) { - if (++queue->cur == queue->size) - queue->cur = 0; + INIT_WORK(&adapter->crq_work, handle_crq); - /* Ensure the read of the valid bit occurs before reading any - * other bits of the CRQ entry - */ - rmb(); - } else { - crq = NULL; + err = request_irq(vdev->irq, &ibmvscsis_interrupt, + 0, "ibmvscsis", adapter); + if (err) { + pr_err("Error 0x%x h_send_crq\n", err); + goto req_irq_failed; } - spin_unlock_irqrestore(&queue->lock, flags); - return crq; + err = vio_enable_interrupts(vdev); + if (err != 0) { + pr_err("Error %d enabling interrupts!!!\n", err); + goto req_irq_failed; + } + + return retrc; + +req_irq_failed: + h_free_crq(vdev->unit_address); +reg_crq_failed: + dma_unmap_single(&vdev->dev, queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); +map_failed: + free_page((unsigned long)queue->msgs); +malloc_failed: + return -1; } -static int send_iu(struct iu_entry *iue, u64 length, u8 format) +static void crq_queue_destroy(struct ibmvscsis_adapter *adapter) { - struct srp_target *target = iue->target; - struct ibmvscsis_adapter *adapter = target->ldata; - struct ibmvscsis_crq_msg crq_msg; - struct srp_rsp *rsp; - __be64 *crq_as_u64 = (__be64 *)&crq_msg; - long rc, rc1; + struct vio_dev *vdev = adapter->dma_dev; + struct crq_queue *queue = &adapter->crq_queue; - rsp = &vio_iu(iue)->srp.rsp; - pr_debug("send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", - (unsigned long)length, - (unsigned long)adapter->liobn, - (unsigned long)iue->sbuf->dma, - (unsigned long)adapter->riobn, - (unsigned long)be64_to_cpu(iue->remote_token)); + free_irq(vdev->irq, (void *)adapter); + flush_work(&adapter->crq_work); + h_free_crq(vdev->unit_address); + dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token, + queue->size * sizeof(*queue->msgs), + DMA_BIDIRECTIONAL); - /* First copy the SRP */ - rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma, - adapter->riobn, be64_to_cpu(iue->remote_token)); + free_page((unsigned long)queue->msgs); +} - switch (rc) { - case H_SUCCESS: - break; - case H_PERMISSION: - case H_SOURCE_PARM: - case H_DEST_PARM: - if (connection_broken(adapter)) { - pr_debug("rdma connection broken\n"); - goto end; - } - break; - default: - pr_err("Error %ld transferring data\n", rc); - length = 0; - break; - } +static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, + struct srp_direct_buf *md, int nmd, + enum dma_data_direction dir, unsigned int rest) +{ + struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + dma_addr_t token; + long err; + unsigned int done = 0; + int i, sidx, soff; - pr_debug("crq pre cooked: 0x%x, 0x%llx, 0x%llx\n", - format, length, vio_iu(iue)->srp.rsp.tag); + sidx = 0; + soff = 0; + token = sg_dma_address(sg + sidx); - crq_msg.valid = 0x80; - crq_msg.format = format; - crq_msg.rsvd = 0; - if (rc == 0) - crq_msg.status = 0x99; - else - crq_msg.status = rsp->status; - crq_msg.rsvd1 = 0; - crq_msg.IU_length = cpu_to_be16(length); - crq_msg.IU_data_ptr = vio_iu(iue)->srp.rsp.tag; + for (i = 0; i < nmd && rest; i++) { + unsigned int mdone, mlen; - pr_debug("send crq: 0x%x, 0x%llx, 0x%llx\n", - adapter->dma_dev->unit_address, - be64_to_cpu(crq_as_u64[0]), - be64_to_cpu(crq_as_u64[1])); + mlen = min(rest, be32_to_cpu(md[i].len)); + for (mdone = 0; mlen;) { + int slen = min(sg_dma_len(sg + sidx) - soff, mlen); - srp_iu_put(iue); + if (dir == DMA_TO_DEVICE) + err = h_copy_rdma(slen, + adapter->riobn, + be64_to_cpu(md[i].va) + mdone, + adapter->liobn, + token + soff); + else + err = h_copy_rdma(slen, + adapter->liobn, + token + soff, + adapter->riobn, + be64_to_cpu(md[i].va) + + mdone); + switch (err) { + case H_SUCCESS: + break; + case H_PERMISSION: + case H_SOURCE_PARM: + case H_DEST_PARM: + if (connection_broken(adapter)) + pr_debug("rdma connection broken\n"); + default: + pr_err("rdma error %d %d %ld\n", + dir, slen, err); + return -EIO; + } - rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), - be64_to_cpu(crq_as_u64[1])); + mlen -= slen; + mdone += slen; + soff += slen; + done += slen; - if (rc1) { - pr_err("%ld sending response\n", rc1); - return rc1; + if (soff == sg_dma_len(sg + sidx)) { + sidx++; + soff = 0; + token = sg_dma_address(sg + sidx); + + if (sidx > nsg) { + pr_err("out of sg %p %d %d\n", + iue, sidx, nsg); + return -EIO; + } + } + } + rest -= mlen; } - return rc; -end: - return rc; + return 0; } -static int send_adapter_info(struct iu_entry *iue, - dma_addr_t remote_buffer, u16 length) +static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id) { - struct srp_target *target = iue->target; - struct ibmvscsis_adapter *adapter = target->ldata; - dma_addr_t data_token; - struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info; - struct mad_adapter_info_data *info; - int err; + int ret = -ENOMEM; + struct ibmvscsis_adapter *adapter; + struct srp_target *target; + struct ibmvscsis_tport *tport; + unsigned long flags; - mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS); + pr_debug("Probe for UA 0x%x\n", vdev->unit_address); - if (be16_to_cpu(mad->common.length) > sizeof(*info)) { - mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED); - return 0; - } + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) + return ret; + target = kzalloc(sizeof(*target), GFP_KERNEL); + if (!target) + goto free_adapter; - info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info), - &data_token, GFP_KERNEL); - if (!info) { - pr_err("bad dma_alloc_coherent %p\n", target); - mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED); - return 1; - } + adapter->dma_dev = vdev; + adapter->target = target; + tport = &adapter->tport; - /* Get remote info */ - err = h_copy_rdma(sizeof(*info), adapter->riobn, - be64_to_cpu(remote_buffer), - adapter->liobn, data_token); + tport->enabled = false; + snprintf(&adapter->tport.tport_name[0], 256, "%s", + dev_name(&vdev->dev)); - if (err == H_SUCCESS) { - pr_err("Client connect: %s (%d)\n", - info->partition_name, info->partition_number); + ret = read_dma_window(adapter->dma_dev, adapter); + if (ret != 0) + goto free_target; - if (adapter->client_data.partition_number == 0) - adapter->client_data.partition_number = - be32_to_cpu(info->partition_number); - strncpy(adapter->client_data.srp_version, info->srp_version, - sizeof(adapter->client_data.srp_version)); - strncpy(adapter->client_data.partition_name, - info->partition_name, - sizeof(adapter->client_data.partition_name)); - adapter->client_data.mad_version = - be32_to_cpu(info->mad_version); - adapter->client_data.os_type = be32_to_cpu(info->os_type); - pr_debug("adapter info client adapter %u\n", - adapter->client_data.os_type); + pr_debug("Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn, + adapter->riobn); - strcpy(info->srp_version, "16.a"); - strncpy(info->partition_name, partition_name, - sizeof(info->partition_name)); + spin_lock_irqsave(&ibmvscsis_dev_lock, flags); + list_add_tail(&adapter->list, &ibmvscsis_dev_list); + spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); - info->partition_number = cpu_to_be32(partition_number); - info->mad_version = cpu_to_be32(1); - info->os_type = cpu_to_be32(2); - memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu)); - info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS * - PAGE_SIZE); + ret = srp_target_alloc(target, &vdev->dev, + INITIAL_SRP_LIMIT, + SRP_MAX_IU_LEN); - dma_rmb(); - /* Send our info to remote */ - err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token, - adapter->riobn, be64_to_cpu(remote_buffer)); + adapter->target->ldata = adapter; - switch (err) { - case H_SUCCESS: - break; - case H_PERMISSION: - case H_SOURCE_PARM: - case H_DEST_PARM: - if (connection_broken(adapter)) - pr_debug("rdma connection broken\n"); - default: - pr_err("Error sending adapter info %d\n", - err); - return -EIO; - } - } else { - pr_err("Error sending adapter info %d\n", err); - return 1; + if (ret) { + pr_err("failed target alloc ret: %d\n", ret); + goto free_srp_target; } - dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info, - data_token); + ret = crq_queue_create(&adapter->crq_queue, adapter); + if (ret != 0 && ret != H_RESOURCE) { + pr_err("failed crq_queue_create ret: %d\n", ret); + ret = -1; + } + + if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0 && + ret != H_RESOURCE) { + pr_warn("Failed to send CRQ message\n"); + ret = 0; + } + + dev_set_drvdata(&vdev->dev, adapter); return 0; + +free_srp_target: + srp_target_free(target); +free_target: + kfree(target); +free_adapter: + kfree(adapter); + return ret; } -static int process_mad_iu(struct iu_entry *iue) +static int ibmvscsis_remove(struct vio_dev *dev) { - union viosrp_iu *iu = vio_iu(iue); - struct viosrp_adapter_info *info; - struct viosrp_host_config *conf; + unsigned long flags; + struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev); + struct srp_target *target; - switch (be32_to_cpu(iu->mad.empty_iu.common.type)) { - case VIOSRP_EMPTY_IU_TYPE: - pr_err("%s\n", "Unsupported EMPTY MAD IU"); - break; - case VIOSRP_ERROR_LOG_TYPE: - pr_err("%s\n", "Unsupported ERROR LOG MAD IU"); - iu->mad.error_log.common.status = 1; - send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT); - break; - case VIOSRP_ADAPTER_INFO_TYPE: - info = &iu->mad.adapter_info; - info->common.status = send_adapter_info(iue, info->buffer, - info->common.length); - send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT); - break; - case VIOSRP_HOST_CONFIG_TYPE: - conf = &iu->mad.host_config; - conf->common.status = 1; - send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT); - break; - default: - pr_err("Unknown type %u\n", iu->srp.rsp.opcode); - iu->mad.empty_iu.common.status = - cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED); - send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT); - break; - } + target = adapter->target; - return 1; + spin_lock_irqsave(&ibmvscsis_dev_lock, flags); + list_del(&adapter->list); + spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); + + crq_queue_destroy(adapter); + srp_target_free(target); + + kfree(target); + kfree(adapter); + + return 0; } -static void ibmvscsis_srp_i_logout(struct iu_entry *iue) +static ssize_t system_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { - union viosrp_iu *iu = vio_iu(iue); - struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout; - u64 tag = iu->srp.rsp.tag; + return snprintf(buf, PAGE_SIZE, "%s\n", system_id); +} - log_out->opcode = SRP_I_LOGOUT; - log_out->tag = tag; - send_iu(iue, sizeof(*log_out), VIOSRP_SRP_FORMAT); +static ssize_t partition_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%x\n", partition_number); } -static void process_login(struct iu_entry *iue) +static ssize_t unit_address_show(struct device *dev, + struct device_attribute *attr, char *buf) { - union viosrp_iu *iu = vio_iu(iue); - struct srp_login_rsp *rsp = &iu->srp.login_rsp; - struct srp_login_rej *rej = &iu->srp.login_rej; - struct srp_target *target = iue->target; - struct ibmvscsis_adapter *adapter = target->ldata; - struct vio_dev *vdev = adapter->dma_dev; - struct se_portal_group *se_tpg; - char name[16]; - u64 tag = iu->srp.rsp.tag; + struct ibmvscsis_adapter *adapter = + container_of(dev, struct ibmvscsis_adapter, dev); - /* - * TODO handle case that requested size is wrong and buffer - * format is wrong - */ - memset(iu, 0, max(sizeof(*rsp), sizeof(*rej))); + return snprintf(buf, PAGE_SIZE, "%x\n", adapter->dma_dev->unit_address); +} - snprintf(name, sizeof(name), "%x", vdev->unit_address); +static int get_system_info(void) +{ + struct device_node *rootdn, *vdevdn; + const char *id, *model, *name; + const unsigned int *num; - if (!adapter->tport.enabled) { - rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); - pr_err("Rejected SRP_LOGIN_REQ because target %s has not yet been enabled", - name); - goto reject; - } + rootdn = of_find_node_by_path("/"); + if (!rootdn) + return -ENOENT; - se_tpg = ibmvscsis_make_nexus(&adapter->tport, - &adapter->tport.tport_name[0]); - if (!se_tpg) { - pr_debug("login make nexus fail se_tpg(%p)\n", se_tpg); - goto reject; - } + model = of_get_property(rootdn, "model", NULL); + id = of_get_property(rootdn, "system-id", NULL); + if (model && id) + snprintf(system_id, sizeof(system_id), "%s-%s", model, id); - rsp->opcode = SRP_LOGIN_RSP; + name = of_get_property(rootdn, "ibm,partition-name", NULL); + if (name) + strncpy(partition_name, name, sizeof(partition_name)); - rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT); + num = of_get_property(rootdn, "ibm,partition-no", NULL); + if (num) + partition_number = of_read_number(num, 1); - pr_debug("process_login, tag:%llu\n", tag); + of_node_put(rootdn); - rsp->tag = tag; - rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu)); - rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu)); - /* direct and indirect */ - rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | - SRP_BUF_FORMAT_INDIRECT); + vdevdn = of_find_node_by_path("/vdevice"); + vdevdn = of_find_node_by_path("/vdevice"); + if (vdevdn) { + const unsigned *mvds; - send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT); - return; + mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size", + NULL); + if (mvds) + max_vdma_size = *mvds; + of_node_put(vdevdn); + } -reject: - rej->opcode = SRP_LOGIN_REJ; - rej->tag = tag; - rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | - SRP_BUF_FORMAT_INDIRECT); + return 0; +}; - send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT); +static char *ibmvscsis_get_fabric_name(void) +{ + return "ibmvscsis"; } -static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter, - struct iu_entry *iue) +static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg) { - struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt; - struct ibmvscsis_cmnd *cmd = adapter->cmd; - struct srp_rsp *rsp; - u64 unpacked_lun = 0; - u64 tag_to_abort = 0; - int tcm_type; - int rc = 0; - - rsp = &vio_iu(iue)->srp.rsp; - unpacked_lun = ibmvscsis_unpack_lun((u8 *)&srp_tsk->lun, - sizeof(srp_tsk->lun)); + struct ibmvscsis_tport *tport = + container_of(se_tpg, struct ibmvscsis_tport, se_tpg); - switch (srp_tsk->tsk_mgmt_func) { - case SRP_TSK_ABORT_TASK: - tcm_type = TMR_ABORT_TASK; - tag_to_abort = be64_to_cpu(srp_tsk->task_tag); - srp_iu_put(iue); - break; - case SRP_TSK_ABORT_TASK_SET: - tcm_type = TMR_ABORT_TASK_SET; - break; - case SRP_TSK_CLEAR_TASK_SET: - tcm_type = TMR_CLEAR_TASK_SET; - break; - case SRP_TSK_LUN_RESET: - tcm_type = TMR_LUN_RESET; - break; - case SRP_TSK_CLEAR_ACA: - tcm_type = TMR_CLEAR_ACA; - break; - default: - pr_err("unknown task mgmt func %d\n", srp_tsk->tsk_mgmt_func); - cmd->se_cmd.se_tmr_req->response = - TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; - goto fail; - } + return &tport->tport_name[0]; +} - cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag); +static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg) +{ + struct ibmvscsis_tport *tport = + container_of(se_tpg, struct ibmvscsis_tport, se_tpg); - pr_debug("calling submit_tmr, func %d\n", - srp_tsk->tsk_mgmt_func); - rc = target_submit_tmr(&cmd->se_cmd, - adapter->tport.se_sess, NULL, - unpacked_lun, srp_tsk, tcm_type, - GFP_KERNEL, tag_to_abort, - TARGET_SCF_ACK_KREF); - if (rc != 0) { - pr_err("target_submit_tmr failed, rc %d\n", rc); - cmd->se_cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED; - goto fail; - } + return tport->tport_tpgt; +} -fail: - if (rc) - transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0); +static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; } -static bool connection_broken(struct ibmvscsis_adapter *adapter) +static int ibmvscsis_check_true(struct se_portal_group *se_tpg) { - u64 buffer[2]; - struct viosrp_crq *crq; - long h_return_code; - bool rc = false; + return 1; +} - /* create a PING crq */ - crq = (struct viosrp_crq *)&buffer; - buffer[0] = 0; - buffer[1] = 0; - crq->valid = 0x80; - crq->format = 6; - crq->status = 0xF5; - - h_return_code = h_send_crq(adapter, - cpu_to_be64(buffer[0]), - cpu_to_be64(buffer[1])); +static int ibmvscsis_check_false(struct se_portal_group *se_tpg) +{ + return 0; +} - pr_debug("connection_broken: rc %ld\n", h_return_code); +static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg) +{ + return 1; +} - if (h_return_code == H_CLOSED) - rc = true; +static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd) +{ + struct ibmvscsis_cmnd *cmd = container_of(se_cmd, + struct ibmvscsis_cmnd, + se_cmd); - return rc; + return target_put_sess_cmd(&cmd->se_cmd); } -static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, - struct srp_direct_buf *md, int nmd, - enum dma_data_direction dir, unsigned int rest) +static void ibmvscsis_release_cmd(struct se_cmd *se_cmd) { - struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; - struct srp_target *target = iue->target; - struct ibmvscsis_adapter *adapter = target->ldata; - dma_addr_t token; - long err; - unsigned int done = 0; - int i, sidx, soff; + struct ibmvscsis_cmnd *cmd = + container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd); - sidx = 0; - soff = 0; - token = sg_dma_address(sg + sidx); + kfree(cmd); +} - for (i = 0; i < nmd && rest; i++) { - unsigned int mdone, mlen; +static int ibmvscsis_shutdown_session(struct se_session *se_sess) +{ + return 0; +} - mlen = min(rest, be32_to_cpu(md[i].len)); - for (mdone = 0; mlen;) { - int slen = min(sg_dma_len(sg + sidx) - soff, mlen); +static void ibmvscsis_close_session(struct se_session *se_sess) +{ +} - if (dir == DMA_TO_DEVICE) - err = h_copy_rdma(slen, - adapter->riobn, - be64_to_cpu(md[i].va) + mdone, - adapter->liobn, - token + soff); - else - err = h_copy_rdma(slen, - adapter->liobn, - token + soff, - adapter->riobn, - be64_to_cpu(md[i].va) + - mdone); - switch (err) { - case H_SUCCESS: - break; - case H_PERMISSION: - case H_SOURCE_PARM: - case H_DEST_PARM: - if (connection_broken(adapter)) - pr_debug("rdma connection broken\n"); - default: - pr_err("rdma error %d %d %ld\n", - dir, slen, err); - return -EIO; - } +static u32 ibmvscsis_sess_get_index(struct se_session *se_sess) +{ + return 0; +} - mlen -= slen; - mdone += slen; - soff += slen; - done += slen; +static int ibmvscsis_write_pending(struct se_cmd *se_cmd) +{ + struct ibmvscsis_cmnd *cmd = container_of(se_cmd, + struct ibmvscsis_cmnd, + se_cmd); + struct scsi_cmnd *sc = &cmd->sc; + struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; + int ret; - if (soff == sg_dma_len(sg + sidx)) { - sidx++; - soff = 0; - token = sg_dma_address(sg + sidx); + sc->sdb.length = se_cmd->data_length; + sc->sdb.table.nents = se_cmd->t_data_nents; + sc->sdb.table.sgl = se_cmd->t_data_sg; - if (sidx > nsg) { - pr_err("out of sg %p %d %d\n", - iue, sidx, nsg); - return -EIO; - } - } - } - rest -= mlen; + ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, + ibmvscsis_rdma, 1, 1); + if (ret) { + pr_err("srp_transfer_data() failed: %d\n", ret); + return -EAGAIN; } + /* + * We now tell TCM to add this WRITE CDB directly into the TCM storage + * object execution queue. + */ + target_execute_cmd(&cmd->se_cmd); return 0; } -static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, - struct iu_entry *iue) +static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd) { - struct srp_cmd *cmd = iue->sbuf->buf; - struct scsi_cmnd *sc; - struct ibmvscsis_cmnd *vsc; - int ret; - - vsc = kzalloc(sizeof(*vsc), GFP_KERNEL); - adapter->cmd = vsc; - sc = &vsc->sc; - sc->sense_buffer = vsc->se_cmd.sense_buffer; - sc->cmnd = cmd->cdb; - sc->SCp.ptr = (char *)iue; + return 0; +} - ret = tcm_queuecommand(adapter, vsc, cmd); +static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl) +{ +} - return ret; +static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd) +{ + return 0; } -static u64 ibmvscsis_unpack_lun(const u8 *lun, int len) +static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd) { - u64 res = NO_SUCH_LUN; - int addressing_method; + struct ibmvscsis_cmnd *cmd = container_of(se_cmd, + struct ibmvscsis_cmnd, + se_cmd); + struct scsi_cmnd *sc = &cmd->sc; + struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; + struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf; + struct srp_rsp *rsp; + char *sd; + char *data; + int ret; + uint len; - if (unlikely(len < 2)) { - pr_err("Illegal LUN length %d, expected 2 bytes or more\n", - len); - goto out; - } + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; - switch (len) { - case 8: - if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0) - goto out_err; - break; - case 4: - if (*((__be16 *)&lun[2]) != 0) - goto out_err; - break; - case 6: - if (*((__be32 *)&lun[2]) != 0) - goto out_err; - break; - case 2: - break; - default: - goto out_err; + /* + * Check for overflow residual count + */ + + if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) + scsi_set_resid(sc, se_cmd->residual_count); + + sc->sdb.length = se_cmd->data_length; + sc->sdb.table.nents = se_cmd->t_data_nents; + sc->sdb.table.sgl = se_cmd->t_data_sg; + + if (scsi_sg_count(sc)) { + if (srp->cdb[0] == REPORT_LUNS && + adapter->client_data.os_type != LINUX) + ibmvscsis_modify_rep_luns(se_cmd); + if ((srp->cdb[0] == INQUIRY) && ((srp->cdb[1] & 0x1) == 0)) + ibmvscsis_modify_std_inquiry(se_cmd); + ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, + ibmvscsis_rdma, 1, 1); + if (ret) { + pr_err("srp_transfer_data failed: %d\n", ret); + sd = cmd->se_cmd.sense_buffer; + cmd->se_cmd.scsi_sense_length = 18; + memset(cmd->se_cmd.sense_buffer, 0, + cmd->se_cmd.scsi_sense_length); + sd[0] = 0x70; + sd[2] = 3; + sd[7] = 10; + sd[12] = 8; + sd[13] = 1; + } } - addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */ - switch (addressing_method) { - case SCSI_LUN_ADDR_METHOD_PERIPHERAL: - case SCSI_LUN_ADDR_METHOD_FLAT: - case SCSI_LUN_ADDR_METHOD_LUN: - res = *(lun + 1) | (((*lun) & 0x3f) << 8); - break; + rsp = &vio_iu(iue)->srp.rsp; + len = sizeof(*rsp); + memset(rsp, 0, len); + data = rsp->data; - case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN: - default: - pr_err("Unimplemented LUN addressing method %u\n", - addressing_method); - break; + rsp->tag = se_cmd->tag; + rsp->req_lim_delta = cpu_to_be32(1); + rsp->opcode = SRP_RSP; + + ibmvscsis_determine_resid(se_cmd, rsp); + rsp->status = se_cmd->scsi_status; + + if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) { + rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length); + rsp->flags |= SRP_RSP_FLAG_SNSVALID; + len += se_cmd->scsi_sense_length; + memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length); } -out: - return res; -out_err: - pr_err("Support for multi-level LUNs has not yet been implemented\n"); - goto out; + send_iu(iue, len, VIOSRP_SRP_FORMAT); + return 0; } -static int tcm_queuecommand(struct ibmvscsis_adapter *adapter, - struct ibmvscsis_cmnd *vsc, - struct srp_cmd *scmd) +static int ibmvscsis_queue_status(struct se_cmd *se_cmd) { - struct se_cmd *se_cmd; - int attr; - u64 data_len; - int ret; - u64 unpacked_lun; + struct ibmvscsis_cmnd *cmd = container_of(se_cmd, + struct ibmvscsis_cmnd, + se_cmd); + struct scsi_cmnd *sc = &cmd->sc; + struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; + struct srp_rsp *rsp; + uint len; + char *data; - switch (scmd->task_attr) { - case SRP_SIMPLE_TASK: - attr = TCM_SIMPLE_TAG; - break; - case SRP_ORDERED_TASK: - attr = TCM_ORDERED_TAG; - break; - case SRP_HEAD_TASK: - attr = TCM_HEAD_TAG; + /* + * Copy any generated SENSE data into sc->sense_buffer and + * set the appropriate sc->result to be translated by + * ibmvscsis_cmnd_done() + */ + + rsp = &vio_iu(iue)->srp.rsp; + len = sizeof(*rsp); + memset(rsp, 0, len); + data = rsp->data; + + rsp->tag = se_cmd->tag; + rsp->req_lim_delta = cpu_to_be32(1); + rsp->opcode = SRP_RSP; + + ibmvscsis_determine_resid(se_cmd, rsp); + rsp->status = se_cmd->scsi_status; + + if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) { + rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length); + rsp->flags |= SRP_RSP_FLAG_SNSVALID; + len += se_cmd->scsi_sense_length; + memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length); + } + send_iu(iue, len, VIOSRP_SRP_FORMAT); + return 0; +} + +static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd) +{ + struct ibmvscsis_cmnd *cmd = container_of(se_cmd, + struct ibmvscsis_cmnd, + se_cmd); + struct scsi_cmnd *sc = &cmd->sc; + struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr; + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + struct srp_rsp *rsp; + uint len; + char *data; + u32 *tsk_status; + u32 rsp_code; + + rsp = &vio_iu(iue)->srp.rsp; + + if (transport_check_aborted_status(se_cmd, false) != 0) { + pr_debug("queue_tm_rsp aborted\n"); + atomic_inc(&adapter->req_lim_delta); + srp_iu_put(iue); + } else { + rsp->req_lim_delta = cpu_to_be32(1 + + atomic_xchg(&adapter-> + req_lim_delta, 0)); + } + + len = sizeof(*rsp); + memset(rsp, 0, len); + data = rsp->data; + + rsp->opcode = SRP_RSP; + rsp->tag = se_cmd->se_tmr_req->ref_task_tag; + rsp->status = 0; + rsp->resp_data_len = cpu_to_be32(4); + rsp->flags |= SRP_RSP_FLAG_RSPVALID; + rsp->req_lim_delta = cpu_to_be32(1); + + switch (se_cmd->se_tmr_req->response) { + case TMR_FUNCTION_COMPLETE: + case TMR_TASK_DOES_NOT_EXIST: + rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE; break; - case SRP_ACA_TASK: - attr = TCM_ACA_TAG; + case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: + case TMR_LUN_DOES_NOT_EXIST: + rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED; break; + case TMR_FUNCTION_FAILED: + case TMR_FUNCTION_REJECTED: default: - pr_err("Task attribute %d not supported\n", scmd->task_attr); - attr = TCM_SIMPLE_TAG; + rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED; + break; } - pr_debug("srp_data_length: %llx, srp_direction:%x\n", - srp_data_length(scmd, srp_cmd_direction(scmd)), - srp_cmd_direction(scmd)); - data_len = srp_data_length(scmd, srp_cmd_direction(scmd)); + tsk_status = (u32 *)data; + *tsk_status = cpu_to_be32(rsp_code); + data = (char *)(tsk_status + 1); + len += 4; - vsc->se_cmd.tag = scmd->tag; - se_cmd = &vsc->se_cmd; + send_iu(iue, len, VIOSRP_SRP_FORMAT); +} - pr_debug("size of lun:%lx, lun:%s\n", sizeof(scmd->lun), - &scmd->lun.scsi_lun[0]); +static void ibmvscsis_aborted_task(struct se_cmd *se_cmd) +{ +} - unpacked_lun = ibmvscsis_unpack_lun((u8 *)&scmd->lun, - sizeof(scmd->lun)); +static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct ibmvscsis_tport *tport; + int ret; - ret = target_submit_cmd(se_cmd, adapter->tport.se_sess, - &scmd->cdb[0], &vsc->sense_buf[0], unpacked_lun, - data_len, attr, srp_cmd_direction(scmd), - TARGET_SCF_ACK_KREF); - if (ret != 0) { - ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - pr_debug("tcm_queuecommand fail submit_cmd\n"); - goto send_sense; + tport = ibmvscsis_lookup_port(name); + ret = -EINVAL; + + if (!tport) + goto err; + + tport->tport_proto_id = SCSI_PROTOCOL_SRP; + pr_debug("make_tport(%s), pointer:%p tport_id:%x\n", name, tport, + tport->tport_proto_id); + + return &tport->tport_wwn; +err: + return ERR_PTR(ret); +} + +static void ibmvscsis_drop_tport(struct se_wwn *wwn) +{ + struct ibmvscsis_tport *tport = container_of(wwn, + struct ibmvscsis_tport, + tport_wwn); + + pr_debug("drop_tport(%s\n", + config_item_name(&tport->tport_wwn.wwn_group.cg_item)); +} + +static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct ibmvscsis_tport *tport = + container_of(wwn, struct ibmvscsis_tport, tport_wwn); + int ret; + + tport->releasing = false; + + ret = core_tpg_register(&tport->tport_wwn, + &tport->se_tpg, + tport->tport_proto_id); + if (ret) + return ERR_PTR(ret); + + return &tport->se_tpg; +} + +static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg) +{ + struct ibmvscsis_tport *tport = container_of(se_tpg, + struct ibmvscsis_tport, + se_tpg); + + tport->releasing = true; + tport->enabled = false; + + /* + * Release the virtual I_T Nexus for this ibmvscsis TPG + */ + ibmvscsis_drop_nexus(tport); + /* + * Deregister the se_tpg from TCM.. + */ + core_tpg_deregister(se_tpg); +} + +static ssize_t ibmvscsis_wwn_version_show(struct config_item *item, + char *page) +{ + return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION); +} +CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version); + +static struct configfs_attribute *ibmvscsis_wwn_attrs[] = { + &ibmvscsis_wwn_attr_version, + NULL, +}; + +static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item, + char *page) +{ + struct se_portal_group *se_tpg = to_tpg(item); + struct ibmvscsis_tport *tport = container_of(se_tpg, + struct ibmvscsis_tport, + se_tpg); + + return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0); +} + +static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item, + const char *page, size_t count) +{ + struct se_portal_group *se_tpg = to_tpg(item); + struct ibmvscsis_tport *tport = container_of(se_tpg, + struct ibmvscsis_tport, + se_tpg); + unsigned long tmp; + int ret; + + ret = kstrtoul(page, 0, &tmp); + if (ret < 0) { + pr_err("Unable to extract ibmvscsis_tpg_store_enable\n"); + return -EINVAL; } - return 0; -send_sense: - transport_send_check_condition_and_sense(&vsc->se_cmd, ret, 0); - transport_generic_free_cmd(&vsc->se_cmd, 0); - return -1; + if ((tmp != 0) && (tmp != 1)) { + pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n", + tmp); + return -EINVAL; + } + + if (tmp == 1) + tport->enabled = true; + else + tport->enabled = false; + + return count; } +CONFIGFS_ATTR(ibmvscsis_tpg_, enable); + +static struct configfs_attribute *ibmvscsis_tpg_attrs[] = { + &ibmvscsis_tpg_attr_enable, + NULL, +}; + +static const struct target_core_fabric_ops ibmvscsis_ops = { + .module = THIS_MODULE, + .name = "ibmvscsis", + .max_data_sg_nents = SCSI_MAX_SG_SEGMENTS, + .get_fabric_name = ibmvscsis_get_fabric_name, + .tpg_get_wwn = ibmvscsis_get_fabric_wwn, + .tpg_get_tag = ibmvscsis_get_tag, + .tpg_get_default_depth = ibmvscsis_get_default_depth, + .tpg_check_demo_mode = ibmvscsis_check_true, + .tpg_check_demo_mode_cache = ibmvscsis_check_true, + .tpg_check_demo_mode_write_protect = ibmvscsis_check_false, + .tpg_check_prod_mode_write_protect = ibmvscsis_check_false, + .tpg_get_inst_index = ibmvscsis_tpg_get_inst_index, + .check_stop_free = ibmvscsis_check_stop_free, + .release_cmd = ibmvscsis_release_cmd, + .shutdown_session = ibmvscsis_shutdown_session, + .close_session = ibmvscsis_close_session, + .sess_get_index = ibmvscsis_sess_get_index, + .write_pending = ibmvscsis_write_pending, + .write_pending_status = ibmvscsis_write_pending_status, + .set_default_node_attributes = ibmvscsis_set_default_node_attrs, + .get_cmd_state = ibmvscsis_get_cmd_state, + .queue_data_in = ibmvscsis_queue_data_in, + .queue_status = ibmvscsis_queue_status, + .queue_tm_rsp = ibmvscsis_queue_tm_rsp, + .aborted_task = ibmvscsis_aborted_task, + /* + * Setup function pointers for logic in target_cor_fabric_configfs.c + */ + .fabric_make_wwn = ibmvscsis_make_tport, + .fabric_drop_wwn = ibmvscsis_drop_tport, + .fabric_make_tpg = ibmvscsis_make_tpg, + .fabric_drop_tpg = ibmvscsis_drop_tpg, + + .tfc_wwn_attrs = ibmvscsis_wwn_attrs, + .tfc_tpg_base_attrs = ibmvscsis_tpg_attrs, +}; + +static void ibmvscsis_dev_release(struct device *dev) {}; + +static struct class_attribute ibmvscsis_class_attrs[] = { + __ATTR_NULL, +}; + +static struct device_attribute dev_attr_system_id = + __ATTR(system_id, S_IRUGO, system_id_show, NULL); + +static struct device_attribute dev_attr_partition_number = + __ATTR(partition_number, S_IRUGO, partition_number_show, NULL); + +static struct device_attribute dev_attr_unit_address = + __ATTR(unit_address, S_IRUGO, unit_address_show, NULL); + +static struct attribute *ibmvscsis_dev_attrs[] = { + &dev_attr_system_id.attr, + &dev_attr_partition_number.attr, + &dev_attr_unit_address.attr, +}; +ATTRIBUTE_GROUPS(ibmvscsis_dev); + +static struct class ibmvscsis_class = { + .name = "ibmvscsis", + .dev_release = ibmvscsis_dev_release, + .class_attrs = ibmvscsis_class_attrs, + .dev_groups = ibmvscsis_dev_groups, +}; + +static struct vio_device_id ibmvscsis_device_table[] = { + {"v-scsi-host", "IBM,v-scsi-host"}, + {"", ""} +}; +MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table); + +static struct vio_driver ibmvscsis_driver = { + .name = ibmvscsis_driver_name, + .id_table = ibmvscsis_device_table, + .probe = ibmvscsis_probe, + .remove = ibmvscsis_remove, +}; /* * ibmvscsis_init() - Kernel Module initialization