18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Xen SCSI backend driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008, FUJITSU Limited 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on the blkback driver code. 78c2ecf20Sopenharmony_ci * Adaption to kernel taget core infrastructure taken from vhost/scsi.c 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 108c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 118c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed 128c2ecf20Sopenharmony_ci * separately from the Linux kernel or incorporated into other 138c2ecf20Sopenharmony_ci * software packages, subject to the following license: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 168c2ecf20Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 178c2ecf20Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 188c2ecf20Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 198c2ecf20Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 208c2ecf20Sopenharmony_ci * the following conditions: 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 238c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 268c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 278c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 288c2ecf20Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 298c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 308c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 318c2ecf20Sopenharmony_ci * IN THE SOFTWARE. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "xen-pvscsi: " fmt 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <stdarg.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <linux/module.h> 398c2ecf20Sopenharmony_ci#include <linux/utsname.h> 408c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include <linux/wait.h> 438c2ecf20Sopenharmony_ci#include <linux/sched.h> 448c2ecf20Sopenharmony_ci#include <linux/list.h> 458c2ecf20Sopenharmony_ci#include <linux/gfp.h> 468c2ecf20Sopenharmony_ci#include <linux/delay.h> 478c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 488c2ecf20Sopenharmony_ci#include <linux/configfs.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <generated/utsrelease.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> /* SG_ALL */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#include <target/target_core_base.h> 558c2ecf20Sopenharmony_ci#include <target/target_core_fabric.h> 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include <asm/hypervisor.h> 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#include <xen/xen.h> 608c2ecf20Sopenharmony_ci#include <xen/balloon.h> 618c2ecf20Sopenharmony_ci#include <xen/events.h> 628c2ecf20Sopenharmony_ci#include <xen/xenbus.h> 638c2ecf20Sopenharmony_ci#include <xen/grant_table.h> 648c2ecf20Sopenharmony_ci#include <xen/page.h> 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#include <xen/interface/grant_table.h> 678c2ecf20Sopenharmony_ci#include <xen/interface/io/vscsiif.h> 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define VSCSI_VERSION "v0.1" 708c2ecf20Sopenharmony_ci#define VSCSI_NAMELEN 32 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct ids_tuple { 738c2ecf20Sopenharmony_ci unsigned int hst; /* host */ 748c2ecf20Sopenharmony_ci unsigned int chn; /* channel */ 758c2ecf20Sopenharmony_ci unsigned int tgt; /* target */ 768c2ecf20Sopenharmony_ci unsigned int lun; /* LUN */ 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct v2p_entry { 808c2ecf20Sopenharmony_ci struct ids_tuple v; /* translate from */ 818c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg; /* translate to */ 828c2ecf20Sopenharmony_ci unsigned int lun; 838c2ecf20Sopenharmony_ci struct kref kref; 848c2ecf20Sopenharmony_ci struct list_head l; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct vscsibk_info { 888c2ecf20Sopenharmony_ci struct xenbus_device *dev; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci domid_t domid; 918c2ecf20Sopenharmony_ci unsigned int irq; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci struct vscsiif_back_ring ring; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci spinlock_t ring_lock; 968c2ecf20Sopenharmony_ci atomic_t nr_unreplied_reqs; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci spinlock_t v2p_lock; 998c2ecf20Sopenharmony_ci struct list_head v2p_entry_lists; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci wait_queue_head_t waiting_to_free; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci struct gnttab_page_cache free_pages; 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* theoretical maximum of grants for one request */ 1078c2ecf20Sopenharmony_ci#define VSCSI_MAX_GRANTS (SG_ALL + VSCSIIF_SG_TABLESIZE) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * VSCSI_GRANT_BATCH is the maximum number of grants to be processed in one 1118c2ecf20Sopenharmony_ci * call to map/unmap grants. Don't choose it too large, as there are arrays 1128c2ecf20Sopenharmony_ci * with VSCSI_GRANT_BATCH elements allocated on the stack. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci#define VSCSI_GRANT_BATCH 16 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistruct vscsibk_pend { 1178c2ecf20Sopenharmony_ci uint16_t rqid; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE]; 1208c2ecf20Sopenharmony_ci uint8_t cmd_len; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci uint8_t sc_data_direction; 1238c2ecf20Sopenharmony_ci uint16_t n_sg; /* real length of SG list */ 1248c2ecf20Sopenharmony_ci uint16_t n_grants; /* SG pages and potentially SG list */ 1258c2ecf20Sopenharmony_ci uint32_t data_len; 1268c2ecf20Sopenharmony_ci uint32_t result; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci struct vscsibk_info *info; 1298c2ecf20Sopenharmony_ci struct v2p_entry *v2p; 1308c2ecf20Sopenharmony_ci struct scatterlist *sgl; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE]; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci grant_handle_t grant_handles[VSCSI_MAX_GRANTS]; 1358c2ecf20Sopenharmony_ci struct page *pages[VSCSI_MAX_GRANTS]; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci struct se_cmd se_cmd; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci struct completion tmr_done; 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define VSCSI_DEFAULT_SESSION_TAGS 128 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistruct scsiback_nexus { 1458c2ecf20Sopenharmony_ci /* Pointer to TCM session for I_T Nexus */ 1468c2ecf20Sopenharmony_ci struct se_session *tvn_se_sess; 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistruct scsiback_tport { 1508c2ecf20Sopenharmony_ci /* SCSI protocol the tport is providing */ 1518c2ecf20Sopenharmony_ci u8 tport_proto_id; 1528c2ecf20Sopenharmony_ci /* Binary World Wide unique Port Name for pvscsi Target port */ 1538c2ecf20Sopenharmony_ci u64 tport_wwpn; 1548c2ecf20Sopenharmony_ci /* ASCII formatted WWPN for pvscsi Target port */ 1558c2ecf20Sopenharmony_ci char tport_name[VSCSI_NAMELEN]; 1568c2ecf20Sopenharmony_ci /* Returned by scsiback_make_tport() */ 1578c2ecf20Sopenharmony_ci struct se_wwn tport_wwn; 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistruct scsiback_tpg { 1618c2ecf20Sopenharmony_ci /* scsiback port target portal group tag for TCM */ 1628c2ecf20Sopenharmony_ci u16 tport_tpgt; 1638c2ecf20Sopenharmony_ci /* track number of TPG Port/Lun Links wrt explicit I_T Nexus shutdown */ 1648c2ecf20Sopenharmony_ci int tv_tpg_port_count; 1658c2ecf20Sopenharmony_ci /* xen-pvscsi references to tpg_nexus, protected by tv_tpg_mutex */ 1668c2ecf20Sopenharmony_ci int tv_tpg_fe_count; 1678c2ecf20Sopenharmony_ci /* list for scsiback_list */ 1688c2ecf20Sopenharmony_ci struct list_head tv_tpg_list; 1698c2ecf20Sopenharmony_ci /* Used to protect access for tpg_nexus */ 1708c2ecf20Sopenharmony_ci struct mutex tv_tpg_mutex; 1718c2ecf20Sopenharmony_ci /* Pointer to the TCM pvscsi I_T Nexus for this TPG endpoint */ 1728c2ecf20Sopenharmony_ci struct scsiback_nexus *tpg_nexus; 1738c2ecf20Sopenharmony_ci /* Pointer back to scsiback_tport */ 1748c2ecf20Sopenharmony_ci struct scsiback_tport *tport; 1758c2ecf20Sopenharmony_ci /* Returned by scsiback_make_tpg() */ 1768c2ecf20Sopenharmony_ci struct se_portal_group se_tpg; 1778c2ecf20Sopenharmony_ci /* alias used in xenstore */ 1788c2ecf20Sopenharmony_ci char param_alias[VSCSI_NAMELEN]; 1798c2ecf20Sopenharmony_ci /* list of info structures related to this target portal group */ 1808c2ecf20Sopenharmony_ci struct list_head info_list; 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define SCSIBACK_INVALID_HANDLE (~0) 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic bool log_print_stat; 1868c2ecf20Sopenharmony_cimodule_param(log_print_stat, bool, 0644); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int scsiback_max_buffer_pages = 1024; 1898c2ecf20Sopenharmony_cimodule_param_named(max_buffer_pages, scsiback_max_buffer_pages, int, 0644); 1908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_buffer_pages, 1918c2ecf20Sopenharmony_ci"Maximum number of free pages to keep in backend buffer"); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* Global spinlock to protect scsiback TPG list */ 1948c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(scsiback_mutex); 1958c2ecf20Sopenharmony_cistatic LIST_HEAD(scsiback_list); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void scsiback_get(struct vscsibk_info *info) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci atomic_inc(&info->nr_unreplied_reqs); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void scsiback_put(struct vscsibk_info *info) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&info->nr_unreplied_reqs)) 2058c2ecf20Sopenharmony_ci wake_up(&info->waiting_to_free); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic unsigned long vaddr_page(struct page *page) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci unsigned long pfn = page_to_pfn(page); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return (unsigned long)pfn_to_kaddr(pfn); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic unsigned long vaddr(struct vscsibk_pend *req, int seg) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return vaddr_page(req->pages[seg]); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void scsiback_print_status(char *sense_buffer, int errors, 2218c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = pending_req->v2p->tpg; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", 2268c2ecf20Sopenharmony_ci tpg->tport->tport_name, pending_req->v2p->lun, 2278c2ecf20Sopenharmony_ci pending_req->cmnd[0], status_byte(errors), msg_byte(errors), 2288c2ecf20Sopenharmony_ci host_byte(errors), driver_byte(errors)); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void scsiback_fast_flush_area(struct vscsibk_pend *req) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct gnttab_unmap_grant_ref unmap[VSCSI_GRANT_BATCH]; 2348c2ecf20Sopenharmony_ci struct page *pages[VSCSI_GRANT_BATCH]; 2358c2ecf20Sopenharmony_ci unsigned int i, invcount = 0; 2368c2ecf20Sopenharmony_ci grant_handle_t handle; 2378c2ecf20Sopenharmony_ci int err; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci kfree(req->sgl); 2408c2ecf20Sopenharmony_ci req->sgl = NULL; 2418c2ecf20Sopenharmony_ci req->n_sg = 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!req->n_grants) 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci for (i = 0; i < req->n_grants; i++) { 2478c2ecf20Sopenharmony_ci handle = req->grant_handles[i]; 2488c2ecf20Sopenharmony_ci if (handle == SCSIBACK_INVALID_HANDLE) 2498c2ecf20Sopenharmony_ci continue; 2508c2ecf20Sopenharmony_ci gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i), 2518c2ecf20Sopenharmony_ci GNTMAP_host_map, handle); 2528c2ecf20Sopenharmony_ci req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; 2538c2ecf20Sopenharmony_ci pages[invcount] = req->pages[i]; 2548c2ecf20Sopenharmony_ci put_page(pages[invcount]); 2558c2ecf20Sopenharmony_ci invcount++; 2568c2ecf20Sopenharmony_ci if (invcount < VSCSI_GRANT_BATCH) 2578c2ecf20Sopenharmony_ci continue; 2588c2ecf20Sopenharmony_ci err = gnttab_unmap_refs(unmap, NULL, pages, invcount); 2598c2ecf20Sopenharmony_ci BUG_ON(err); 2608c2ecf20Sopenharmony_ci invcount = 0; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (invcount) { 2648c2ecf20Sopenharmony_ci err = gnttab_unmap_refs(unmap, NULL, pages, invcount); 2658c2ecf20Sopenharmony_ci BUG_ON(err); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci gnttab_page_cache_put(&req->info->free_pages, req->pages, 2698c2ecf20Sopenharmony_ci req->n_grants); 2708c2ecf20Sopenharmony_ci req->n_grants = 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void scsiback_free_translation_entry(struct kref *kref) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct v2p_entry *entry = container_of(kref, struct v2p_entry, kref); 2768c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = entry->tpg; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 2798c2ecf20Sopenharmony_ci tpg->tv_tpg_fe_count--; 2808c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci kfree(entry); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void scsiback_send_response(struct vscsibk_info *info, 2868c2ecf20Sopenharmony_ci char *sense_buffer, int32_t result, uint32_t resid, 2878c2ecf20Sopenharmony_ci uint16_t rqid) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct vscsiif_response *ring_res; 2908c2ecf20Sopenharmony_ci int notify; 2918c2ecf20Sopenharmony_ci struct scsi_sense_hdr sshdr; 2928c2ecf20Sopenharmony_ci unsigned long flags; 2938c2ecf20Sopenharmony_ci unsigned len; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->ring_lock, flags); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt); 2988c2ecf20Sopenharmony_ci info->ring.rsp_prod_pvt++; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ring_res->rslt = result; 3018c2ecf20Sopenharmony_ci ring_res->rqid = rqid; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (sense_buffer != NULL && 3048c2ecf20Sopenharmony_ci scsi_normalize_sense(sense_buffer, VSCSIIF_SENSE_BUFFERSIZE, 3058c2ecf20Sopenharmony_ci &sshdr)) { 3068c2ecf20Sopenharmony_ci len = min_t(unsigned, 8 + sense_buffer[7], 3078c2ecf20Sopenharmony_ci VSCSIIF_SENSE_BUFFERSIZE); 3088c2ecf20Sopenharmony_ci memcpy(ring_res->sense_buffer, sense_buffer, len); 3098c2ecf20Sopenharmony_ci ring_res->sense_len = len; 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci ring_res->sense_len = 0; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ring_res->residual_len = resid; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify); 3178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->ring_lock, flags); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (notify) 3208c2ecf20Sopenharmony_ci notify_remote_via_irq(info->irq); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result, 3248c2ecf20Sopenharmony_ci uint32_t resid, struct vscsibk_pend *pending_req) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci scsiback_send_response(pending_req->info, sense_buffer, result, 3278c2ecf20Sopenharmony_ci resid, pending_req->rqid); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (pending_req->v2p) 3308c2ecf20Sopenharmony_ci kref_put(&pending_req->v2p->kref, 3318c2ecf20Sopenharmony_ci scsiback_free_translation_entry); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic void scsiback_cmd_done(struct vscsibk_pend *pending_req) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct vscsibk_info *info = pending_req->info; 3378c2ecf20Sopenharmony_ci unsigned char *sense_buffer; 3388c2ecf20Sopenharmony_ci unsigned int resid; 3398c2ecf20Sopenharmony_ci int errors; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci sense_buffer = pending_req->sense_buffer; 3428c2ecf20Sopenharmony_ci resid = pending_req->se_cmd.residual_count; 3438c2ecf20Sopenharmony_ci errors = pending_req->result; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (errors && log_print_stat) 3468c2ecf20Sopenharmony_ci scsiback_print_status(sense_buffer, errors, pending_req); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci scsiback_fast_flush_area(pending_req); 3498c2ecf20Sopenharmony_ci scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req); 3508c2ecf20Sopenharmony_ci scsiback_put(info); 3518c2ecf20Sopenharmony_ci /* 3528c2ecf20Sopenharmony_ci * Drop the extra KREF_ACK reference taken by target_submit_cmd_map_sgls() 3538c2ecf20Sopenharmony_ci * ahead of scsiback_check_stop_free() -> transport_generic_free_cmd() 3548c2ecf20Sopenharmony_ci * final se_cmd->cmd_kref put. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ci target_put_sess_cmd(&pending_req->se_cmd); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void scsiback_cmd_exec(struct vscsibk_pend *pending_req) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct se_cmd *se_cmd = &pending_req->se_cmd; 3628c2ecf20Sopenharmony_ci struct se_session *sess = pending_req->v2p->tpg->tpg_nexus->tvn_se_sess; 3638c2ecf20Sopenharmony_ci int rc; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci scsiback_get(pending_req->info); 3668c2ecf20Sopenharmony_ci se_cmd->tag = pending_req->rqid; 3678c2ecf20Sopenharmony_ci rc = target_submit_cmd_map_sgls(se_cmd, sess, pending_req->cmnd, 3688c2ecf20Sopenharmony_ci pending_req->sense_buffer, pending_req->v2p->lun, 3698c2ecf20Sopenharmony_ci pending_req->data_len, 0, 3708c2ecf20Sopenharmony_ci pending_req->sc_data_direction, TARGET_SCF_ACK_KREF, 3718c2ecf20Sopenharmony_ci pending_req->sgl, pending_req->n_sg, 3728c2ecf20Sopenharmony_ci NULL, 0, NULL, 0); 3738c2ecf20Sopenharmony_ci if (rc < 0) { 3748c2ecf20Sopenharmony_ci transport_send_check_condition_and_sense(se_cmd, 3758c2ecf20Sopenharmony_ci TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); 3768c2ecf20Sopenharmony_ci transport_generic_free_cmd(se_cmd, 0); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, 3818c2ecf20Sopenharmony_ci struct page **pg, grant_handle_t *grant, int cnt) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci int err, i; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (!cnt) 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci err = gnttab_map_refs(map, NULL, pg, cnt); 3898c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 3908c2ecf20Sopenharmony_ci if (unlikely(map[i].status != GNTST_okay)) { 3918c2ecf20Sopenharmony_ci pr_err("invalid buffer -- could not remap it\n"); 3928c2ecf20Sopenharmony_ci map[i].handle = SCSIBACK_INVALID_HANDLE; 3938c2ecf20Sopenharmony_ci if (!err) 3948c2ecf20Sopenharmony_ci err = -ENOMEM; 3958c2ecf20Sopenharmony_ci } else { 3968c2ecf20Sopenharmony_ci get_page(pg[i]); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci grant[i] = map[i].handle; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci return err; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req, 4048c2ecf20Sopenharmony_ci struct scsiif_request_segment *seg, struct page **pg, 4058c2ecf20Sopenharmony_ci grant_handle_t *grant, int cnt, u32 flags) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci int mapcount = 0, i, err = 0; 4088c2ecf20Sopenharmony_ci struct gnttab_map_grant_ref map[VSCSI_GRANT_BATCH]; 4098c2ecf20Sopenharmony_ci struct vscsibk_info *info = pending_req->info; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 4128c2ecf20Sopenharmony_ci if (gnttab_page_cache_get(&info->free_pages, pg + mapcount)) { 4138c2ecf20Sopenharmony_ci gnttab_page_cache_put(&info->free_pages, pg, mapcount); 4148c2ecf20Sopenharmony_ci pr_err("no grant page\n"); 4158c2ecf20Sopenharmony_ci return -ENOMEM; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), 4188c2ecf20Sopenharmony_ci flags, seg[i].gref, info->domid); 4198c2ecf20Sopenharmony_ci mapcount++; 4208c2ecf20Sopenharmony_ci if (mapcount < VSCSI_GRANT_BATCH) 4218c2ecf20Sopenharmony_ci continue; 4228c2ecf20Sopenharmony_ci err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount); 4238c2ecf20Sopenharmony_ci pg += mapcount; 4248c2ecf20Sopenharmony_ci grant += mapcount; 4258c2ecf20Sopenharmony_ci pending_req->n_grants += mapcount; 4268c2ecf20Sopenharmony_ci if (err) 4278c2ecf20Sopenharmony_ci return err; 4288c2ecf20Sopenharmony_ci mapcount = 0; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount); 4318c2ecf20Sopenharmony_ci pending_req->n_grants += mapcount; 4328c2ecf20Sopenharmony_ci return err; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, 4368c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci u32 flags; 4398c2ecf20Sopenharmony_ci int i, err, n_segs, i_seg = 0; 4408c2ecf20Sopenharmony_ci struct page **pg; 4418c2ecf20Sopenharmony_ci struct scsiif_request_segment *seg; 4428c2ecf20Sopenharmony_ci unsigned long end_seg = 0; 4438c2ecf20Sopenharmony_ci unsigned int nr_segments = (unsigned int)ring_req->nr_segments; 4448c2ecf20Sopenharmony_ci unsigned int nr_sgl = 0; 4458c2ecf20Sopenharmony_ci struct scatterlist *sg; 4468c2ecf20Sopenharmony_ci grant_handle_t *grant; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci pending_req->n_sg = 0; 4498c2ecf20Sopenharmony_ci pending_req->n_grants = 0; 4508c2ecf20Sopenharmony_ci pending_req->data_len = 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci nr_segments &= ~VSCSIIF_SG_GRANT; 4538c2ecf20Sopenharmony_ci if (!nr_segments) 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (nr_segments > VSCSIIF_SG_TABLESIZE) { 4578c2ecf20Sopenharmony_ci pr_debug("invalid parameter nr_seg = %d\n", 4588c2ecf20Sopenharmony_ci ring_req->nr_segments); 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (ring_req->nr_segments & VSCSIIF_SG_GRANT) { 4638c2ecf20Sopenharmony_ci err = scsiback_gnttab_data_map_list(pending_req, ring_req->seg, 4648c2ecf20Sopenharmony_ci pending_req->pages, pending_req->grant_handles, 4658c2ecf20Sopenharmony_ci nr_segments, GNTMAP_host_map | GNTMAP_readonly); 4668c2ecf20Sopenharmony_ci if (err) 4678c2ecf20Sopenharmony_ci return err; 4688c2ecf20Sopenharmony_ci nr_sgl = nr_segments; 4698c2ecf20Sopenharmony_ci nr_segments = 0; 4708c2ecf20Sopenharmony_ci for (i = 0; i < nr_sgl; i++) { 4718c2ecf20Sopenharmony_ci n_segs = ring_req->seg[i].length / 4728c2ecf20Sopenharmony_ci sizeof(struct scsiif_request_segment); 4738c2ecf20Sopenharmony_ci if ((unsigned)ring_req->seg[i].offset + 4748c2ecf20Sopenharmony_ci (unsigned)ring_req->seg[i].length > PAGE_SIZE || 4758c2ecf20Sopenharmony_ci n_segs * sizeof(struct scsiif_request_segment) != 4768c2ecf20Sopenharmony_ci ring_req->seg[i].length) 4778c2ecf20Sopenharmony_ci return -EINVAL; 4788c2ecf20Sopenharmony_ci nr_segments += n_segs; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci if (nr_segments > SG_ALL) { 4818c2ecf20Sopenharmony_ci pr_debug("invalid nr_seg = %d\n", nr_segments); 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* free of (sgl) in fast_flush_area() */ 4878c2ecf20Sopenharmony_ci pending_req->sgl = kmalloc_array(nr_segments, 4888c2ecf20Sopenharmony_ci sizeof(struct scatterlist), GFP_KERNEL); 4898c2ecf20Sopenharmony_ci if (!pending_req->sgl) 4908c2ecf20Sopenharmony_ci return -ENOMEM; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci sg_init_table(pending_req->sgl, nr_segments); 4938c2ecf20Sopenharmony_ci pending_req->n_sg = nr_segments; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci flags = GNTMAP_host_map; 4968c2ecf20Sopenharmony_ci if (pending_req->sc_data_direction == DMA_TO_DEVICE) 4978c2ecf20Sopenharmony_ci flags |= GNTMAP_readonly; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci pg = pending_req->pages + nr_sgl; 5008c2ecf20Sopenharmony_ci grant = pending_req->grant_handles + nr_sgl; 5018c2ecf20Sopenharmony_ci if (!nr_sgl) { 5028c2ecf20Sopenharmony_ci seg = ring_req->seg; 5038c2ecf20Sopenharmony_ci err = scsiback_gnttab_data_map_list(pending_req, seg, 5048c2ecf20Sopenharmony_ci pg, grant, nr_segments, flags); 5058c2ecf20Sopenharmony_ci if (err) 5068c2ecf20Sopenharmony_ci return err; 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci for (i = 0; i < nr_sgl; i++) { 5098c2ecf20Sopenharmony_ci seg = (struct scsiif_request_segment *)( 5108c2ecf20Sopenharmony_ci vaddr(pending_req, i) + ring_req->seg[i].offset); 5118c2ecf20Sopenharmony_ci n_segs = ring_req->seg[i].length / 5128c2ecf20Sopenharmony_ci sizeof(struct scsiif_request_segment); 5138c2ecf20Sopenharmony_ci err = scsiback_gnttab_data_map_list(pending_req, seg, 5148c2ecf20Sopenharmony_ci pg, grant, n_segs, flags); 5158c2ecf20Sopenharmony_ci if (err) 5168c2ecf20Sopenharmony_ci return err; 5178c2ecf20Sopenharmony_ci pg += n_segs; 5188c2ecf20Sopenharmony_ci grant += n_segs; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci end_seg = vaddr(pending_req, 0) + ring_req->seg[0].offset; 5218c2ecf20Sopenharmony_ci seg = (struct scsiif_request_segment *)end_seg; 5228c2ecf20Sopenharmony_ci end_seg += ring_req->seg[0].length; 5238c2ecf20Sopenharmony_ci pg = pending_req->pages + nr_sgl; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci for_each_sg(pending_req->sgl, sg, nr_segments, i) { 5278c2ecf20Sopenharmony_ci sg_set_page(sg, pg[i], seg->length, seg->offset); 5288c2ecf20Sopenharmony_ci pending_req->data_len += seg->length; 5298c2ecf20Sopenharmony_ci seg++; 5308c2ecf20Sopenharmony_ci if (nr_sgl && (unsigned long)seg >= end_seg) { 5318c2ecf20Sopenharmony_ci i_seg++; 5328c2ecf20Sopenharmony_ci end_seg = vaddr(pending_req, i_seg) + 5338c2ecf20Sopenharmony_ci ring_req->seg[i_seg].offset; 5348c2ecf20Sopenharmony_ci seg = (struct scsiif_request_segment *)end_seg; 5358c2ecf20Sopenharmony_ci end_seg += ring_req->seg[i_seg].length; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci if (sg->offset >= PAGE_SIZE || 5388c2ecf20Sopenharmony_ci sg->length > PAGE_SIZE || 5398c2ecf20Sopenharmony_ci sg->offset + sg->length > PAGE_SIZE) 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void scsiback_disconnect(struct vscsibk_info *info) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci wait_event(info->waiting_to_free, 5498c2ecf20Sopenharmony_ci atomic_read(&info->nr_unreplied_reqs) == 0); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci unbind_from_irqhandler(info->irq, info); 5528c2ecf20Sopenharmony_ci info->irq = 0; 5538c2ecf20Sopenharmony_ci xenbus_unmap_ring_vfree(info->dev, info->ring.sring); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void scsiback_device_action(struct vscsibk_pend *pending_req, 5578c2ecf20Sopenharmony_ci enum tcm_tmreq_table act, int tag) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = pending_req->v2p->tpg; 5608c2ecf20Sopenharmony_ci struct scsiback_nexus *nexus = tpg->tpg_nexus; 5618c2ecf20Sopenharmony_ci struct se_cmd *se_cmd = &pending_req->se_cmd; 5628c2ecf20Sopenharmony_ci u64 unpacked_lun = pending_req->v2p->lun; 5638c2ecf20Sopenharmony_ci int rc, err = FAILED; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci init_completion(&pending_req->tmr_done); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci rc = target_submit_tmr(&pending_req->se_cmd, nexus->tvn_se_sess, 5688c2ecf20Sopenharmony_ci &pending_req->sense_buffer[0], 5698c2ecf20Sopenharmony_ci unpacked_lun, NULL, act, GFP_KERNEL, 5708c2ecf20Sopenharmony_ci tag, TARGET_SCF_ACK_KREF); 5718c2ecf20Sopenharmony_ci if (rc) 5728c2ecf20Sopenharmony_ci goto err; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci wait_for_completion(&pending_req->tmr_done); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? 5778c2ecf20Sopenharmony_ci SUCCESS : FAILED; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci scsiback_do_resp_with_sense(NULL, err, 0, pending_req); 5808c2ecf20Sopenharmony_ci transport_generic_free_cmd(&pending_req->se_cmd, 0); 5818c2ecf20Sopenharmony_ci return; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cierr: 5848c2ecf20Sopenharmony_ci scsiback_do_resp_with_sense(NULL, err, 0, pending_req); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* 5888c2ecf20Sopenharmony_ci Perform virtual to physical translation 5898c2ecf20Sopenharmony_ci*/ 5908c2ecf20Sopenharmony_cistatic struct v2p_entry *scsiback_do_translation(struct vscsibk_info *info, 5918c2ecf20Sopenharmony_ci struct ids_tuple *v) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct v2p_entry *entry; 5948c2ecf20Sopenharmony_ci struct list_head *head = &(info->v2p_entry_lists); 5958c2ecf20Sopenharmony_ci unsigned long flags; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 5988c2ecf20Sopenharmony_ci list_for_each_entry(entry, head, l) { 5998c2ecf20Sopenharmony_ci if ((entry->v.chn == v->chn) && 6008c2ecf20Sopenharmony_ci (entry->v.tgt == v->tgt) && 6018c2ecf20Sopenharmony_ci (entry->v.lun == v->lun)) { 6028c2ecf20Sopenharmony_ci kref_get(&entry->kref); 6038c2ecf20Sopenharmony_ci goto out; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci entry = NULL; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ciout: 6098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 6108c2ecf20Sopenharmony_ci return entry; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring, 6148c2ecf20Sopenharmony_ci struct v2p_entry *v2p) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = v2p->tpg; 6178c2ecf20Sopenharmony_ci struct scsiback_nexus *nexus = tpg->tpg_nexus; 6188c2ecf20Sopenharmony_ci struct se_session *se_sess = nexus->tvn_se_sess; 6198c2ecf20Sopenharmony_ci struct vscsibk_pend *req; 6208c2ecf20Sopenharmony_ci int tag, cpu, i; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); 6238c2ecf20Sopenharmony_ci if (tag < 0) { 6248c2ecf20Sopenharmony_ci pr_err("Unable to obtain tag for vscsiif_request\n"); 6258c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci req = &((struct vscsibk_pend *)se_sess->sess_cmd_map)[tag]; 6298c2ecf20Sopenharmony_ci memset(req, 0, sizeof(*req)); 6308c2ecf20Sopenharmony_ci req->se_cmd.map_tag = tag; 6318c2ecf20Sopenharmony_ci req->se_cmd.map_cpu = cpu; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci for (i = 0; i < VSCSI_MAX_GRANTS; i++) 6348c2ecf20Sopenharmony_ci req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return req; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic struct vscsibk_pend *prepare_pending_reqs(struct vscsibk_info *info, 6408c2ecf20Sopenharmony_ci struct vscsiif_back_ring *ring, 6418c2ecf20Sopenharmony_ci struct vscsiif_request *ring_req) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req; 6448c2ecf20Sopenharmony_ci struct v2p_entry *v2p; 6458c2ecf20Sopenharmony_ci struct ids_tuple vir; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* request range check from frontend */ 6488c2ecf20Sopenharmony_ci if ((ring_req->sc_data_direction != DMA_BIDIRECTIONAL) && 6498c2ecf20Sopenharmony_ci (ring_req->sc_data_direction != DMA_TO_DEVICE) && 6508c2ecf20Sopenharmony_ci (ring_req->sc_data_direction != DMA_FROM_DEVICE) && 6518c2ecf20Sopenharmony_ci (ring_req->sc_data_direction != DMA_NONE)) { 6528c2ecf20Sopenharmony_ci pr_debug("invalid parameter data_dir = %d\n", 6538c2ecf20Sopenharmony_ci ring_req->sc_data_direction); 6548c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci if (ring_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { 6578c2ecf20Sopenharmony_ci pr_debug("invalid parameter cmd_len = %d\n", 6588c2ecf20Sopenharmony_ci ring_req->cmd_len); 6598c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci vir.chn = ring_req->channel; 6638c2ecf20Sopenharmony_ci vir.tgt = ring_req->id; 6648c2ecf20Sopenharmony_ci vir.lun = ring_req->lun; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci v2p = scsiback_do_translation(info, &vir); 6678c2ecf20Sopenharmony_ci if (!v2p) { 6688c2ecf20Sopenharmony_ci pr_debug("the v2p of (chn:%d, tgt:%d, lun:%d) doesn't exist.\n", 6698c2ecf20Sopenharmony_ci vir.chn, vir.tgt, vir.lun); 6708c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci pending_req = scsiback_get_pend_req(ring, v2p); 6748c2ecf20Sopenharmony_ci if (IS_ERR(pending_req)) { 6758c2ecf20Sopenharmony_ci kref_put(&v2p->kref, scsiback_free_translation_entry); 6768c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci pending_req->rqid = ring_req->rqid; 6798c2ecf20Sopenharmony_ci pending_req->info = info; 6808c2ecf20Sopenharmony_ci pending_req->v2p = v2p; 6818c2ecf20Sopenharmony_ci pending_req->sc_data_direction = ring_req->sc_data_direction; 6828c2ecf20Sopenharmony_ci pending_req->cmd_len = ring_req->cmd_len; 6838c2ecf20Sopenharmony_ci memcpy(pending_req->cmnd, ring_req->cmnd, pending_req->cmd_len); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return pending_req; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic int scsiback_do_cmd_fn(struct vscsibk_info *info, 6898c2ecf20Sopenharmony_ci unsigned int *eoi_flags) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct vscsiif_back_ring *ring = &info->ring; 6928c2ecf20Sopenharmony_ci struct vscsiif_request ring_req; 6938c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req; 6948c2ecf20Sopenharmony_ci RING_IDX rc, rp; 6958c2ecf20Sopenharmony_ci int more_to_do; 6968c2ecf20Sopenharmony_ci uint32_t result; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci rc = ring->req_cons; 6998c2ecf20Sopenharmony_ci rp = ring->sring->req_prod; 7008c2ecf20Sopenharmony_ci rmb(); /* guest system is accessing ring, too */ 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { 7038c2ecf20Sopenharmony_ci rc = ring->rsp_prod_pvt; 7048c2ecf20Sopenharmony_ci pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", 7058c2ecf20Sopenharmony_ci info->domid, rp, rc, rp - rc); 7068c2ecf20Sopenharmony_ci return -EINVAL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci while ((rc != rp)) { 7108c2ecf20Sopenharmony_ci *eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (RING_REQUEST_CONS_OVERFLOW(ring, rc)) 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci RING_COPY_REQUEST(ring, rc, &ring_req); 7168c2ecf20Sopenharmony_ci ring->req_cons = ++rc; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci pending_req = prepare_pending_reqs(info, ring, &ring_req); 7198c2ecf20Sopenharmony_ci if (IS_ERR(pending_req)) { 7208c2ecf20Sopenharmony_ci switch (PTR_ERR(pending_req)) { 7218c2ecf20Sopenharmony_ci case -ENODEV: 7228c2ecf20Sopenharmony_ci result = DID_NO_CONNECT; 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci default: 7258c2ecf20Sopenharmony_ci result = DRIVER_ERROR; 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci scsiback_send_response(info, NULL, result << 24, 0, 7298c2ecf20Sopenharmony_ci ring_req.rqid); 7308c2ecf20Sopenharmony_ci return 1; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci switch (ring_req.act) { 7348c2ecf20Sopenharmony_ci case VSCSIIF_ACT_SCSI_CDB: 7358c2ecf20Sopenharmony_ci if (scsiback_gnttab_data_map(&ring_req, pending_req)) { 7368c2ecf20Sopenharmony_ci scsiback_fast_flush_area(pending_req); 7378c2ecf20Sopenharmony_ci scsiback_do_resp_with_sense(NULL, 7388c2ecf20Sopenharmony_ci DRIVER_ERROR << 24, 0, pending_req); 7398c2ecf20Sopenharmony_ci transport_generic_free_cmd(&pending_req->se_cmd, 0); 7408c2ecf20Sopenharmony_ci } else { 7418c2ecf20Sopenharmony_ci scsiback_cmd_exec(pending_req); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci case VSCSIIF_ACT_SCSI_ABORT: 7458c2ecf20Sopenharmony_ci scsiback_device_action(pending_req, TMR_ABORT_TASK, 7468c2ecf20Sopenharmony_ci ring_req.ref_rqid); 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci case VSCSIIF_ACT_SCSI_RESET: 7498c2ecf20Sopenharmony_ci scsiback_device_action(pending_req, TMR_LUN_RESET, 0); 7508c2ecf20Sopenharmony_ci break; 7518c2ecf20Sopenharmony_ci default: 7528c2ecf20Sopenharmony_ci pr_err_ratelimited("invalid request\n"); 7538c2ecf20Sopenharmony_ci scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, 0, 7548c2ecf20Sopenharmony_ci pending_req); 7558c2ecf20Sopenharmony_ci transport_generic_free_cmd(&pending_req->se_cmd, 0); 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* Yield point for this unbounded loop. */ 7608c2ecf20Sopenharmony_ci cond_resched(); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci gnttab_page_cache_shrink(&info->free_pages, scsiback_max_buffer_pages); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do); 7668c2ecf20Sopenharmony_ci return more_to_do; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic irqreturn_t scsiback_irq_fn(int irq, void *dev_id) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct vscsibk_info *info = dev_id; 7728c2ecf20Sopenharmony_ci int rc; 7738c2ecf20Sopenharmony_ci unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci while ((rc = scsiback_do_cmd_fn(info, &eoi_flags)) > 0) 7768c2ecf20Sopenharmony_ci cond_resched(); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* In case of a ring error we keep the event channel masked. */ 7798c2ecf20Sopenharmony_ci if (!rc) 7808c2ecf20Sopenharmony_ci xen_irq_lateeoi(irq, eoi_flags); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref, 7868c2ecf20Sopenharmony_ci evtchn_port_t evtchn) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci void *area; 7898c2ecf20Sopenharmony_ci struct vscsiif_sring *sring; 7908c2ecf20Sopenharmony_ci int err; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (info->irq) 7938c2ecf20Sopenharmony_ci return -1; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci err = xenbus_map_ring_valloc(info->dev, &ring_ref, 1, &area); 7968c2ecf20Sopenharmony_ci if (err) 7978c2ecf20Sopenharmony_ci return err; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci sring = (struct vscsiif_sring *)area; 8008c2ecf20Sopenharmony_ci BACK_RING_INIT(&info->ring, sring, PAGE_SIZE); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci err = bind_interdomain_evtchn_to_irq_lateeoi(info->domid, evtchn); 8038c2ecf20Sopenharmony_ci if (err < 0) 8048c2ecf20Sopenharmony_ci goto unmap_page; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci info->irq = err; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci err = request_threaded_irq(info->irq, NULL, scsiback_irq_fn, 8098c2ecf20Sopenharmony_ci IRQF_ONESHOT, "vscsiif-backend", info); 8108c2ecf20Sopenharmony_ci if (err) 8118c2ecf20Sopenharmony_ci goto free_irq; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return 0; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cifree_irq: 8168c2ecf20Sopenharmony_ci unbind_from_irqhandler(info->irq, info); 8178c2ecf20Sopenharmony_ci info->irq = 0; 8188c2ecf20Sopenharmony_ciunmap_page: 8198c2ecf20Sopenharmony_ci xenbus_unmap_ring_vfree(info->dev, area); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci return err; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic int scsiback_map(struct vscsibk_info *info) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci struct xenbus_device *dev = info->dev; 8278c2ecf20Sopenharmony_ci unsigned int ring_ref; 8288c2ecf20Sopenharmony_ci evtchn_port_t evtchn; 8298c2ecf20Sopenharmony_ci int err; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci err = xenbus_gather(XBT_NIL, dev->otherend, 8328c2ecf20Sopenharmony_ci "ring-ref", "%u", &ring_ref, 8338c2ecf20Sopenharmony_ci "event-channel", "%u", &evtchn, NULL); 8348c2ecf20Sopenharmony_ci if (err) { 8358c2ecf20Sopenharmony_ci xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend); 8368c2ecf20Sopenharmony_ci return err; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return scsiback_init_sring(info, ring_ref, evtchn); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci/* 8438c2ecf20Sopenharmony_ci Check for a translation entry being present 8448c2ecf20Sopenharmony_ci*/ 8458c2ecf20Sopenharmony_cistatic struct v2p_entry *scsiback_chk_translation_entry( 8468c2ecf20Sopenharmony_ci struct vscsibk_info *info, struct ids_tuple *v) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct list_head *head = &(info->v2p_entry_lists); 8498c2ecf20Sopenharmony_ci struct v2p_entry *entry; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci list_for_each_entry(entry, head, l) 8528c2ecf20Sopenharmony_ci if ((entry->v.chn == v->chn) && 8538c2ecf20Sopenharmony_ci (entry->v.tgt == v->tgt) && 8548c2ecf20Sopenharmony_ci (entry->v.lun == v->lun)) 8558c2ecf20Sopenharmony_ci return entry; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return NULL; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci/* 8618c2ecf20Sopenharmony_ci Add a new translation entry 8628c2ecf20Sopenharmony_ci*/ 8638c2ecf20Sopenharmony_cistatic int scsiback_add_translation_entry(struct vscsibk_info *info, 8648c2ecf20Sopenharmony_ci char *phy, struct ids_tuple *v) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci int err = 0; 8678c2ecf20Sopenharmony_ci struct v2p_entry *new; 8688c2ecf20Sopenharmony_ci unsigned long flags; 8698c2ecf20Sopenharmony_ci char *lunp; 8708c2ecf20Sopenharmony_ci unsigned long long unpacked_lun; 8718c2ecf20Sopenharmony_ci struct se_lun *se_lun; 8728c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg_entry, *tpg = NULL; 8738c2ecf20Sopenharmony_ci char *error = "doesn't exist"; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci lunp = strrchr(phy, ':'); 8768c2ecf20Sopenharmony_ci if (!lunp) { 8778c2ecf20Sopenharmony_ci pr_err("illegal format of physical device %s\n", phy); 8788c2ecf20Sopenharmony_ci return -EINVAL; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci *lunp = 0; 8818c2ecf20Sopenharmony_ci lunp++; 8828c2ecf20Sopenharmony_ci err = kstrtoull(lunp, 10, &unpacked_lun); 8838c2ecf20Sopenharmony_ci if (err < 0) { 8848c2ecf20Sopenharmony_ci pr_err("lun number not valid: %s\n", lunp); 8858c2ecf20Sopenharmony_ci return err; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci mutex_lock(&scsiback_mutex); 8898c2ecf20Sopenharmony_ci list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) { 8908c2ecf20Sopenharmony_ci if (!strcmp(phy, tpg_entry->tport->tport_name) || 8918c2ecf20Sopenharmony_ci !strcmp(phy, tpg_entry->param_alias)) { 8928c2ecf20Sopenharmony_ci mutex_lock(&tpg_entry->se_tpg.tpg_lun_mutex); 8938c2ecf20Sopenharmony_ci hlist_for_each_entry(se_lun, &tpg_entry->se_tpg.tpg_lun_hlist, link) { 8948c2ecf20Sopenharmony_ci if (se_lun->unpacked_lun == unpacked_lun) { 8958c2ecf20Sopenharmony_ci if (!tpg_entry->tpg_nexus) 8968c2ecf20Sopenharmony_ci error = "nexus undefined"; 8978c2ecf20Sopenharmony_ci else 8988c2ecf20Sopenharmony_ci tpg = tpg_entry; 8998c2ecf20Sopenharmony_ci break; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci mutex_unlock(&tpg_entry->se_tpg.tpg_lun_mutex); 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci if (tpg) { 9078c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 9088c2ecf20Sopenharmony_ci tpg->tv_tpg_fe_count++; 9098c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci mutex_unlock(&scsiback_mutex); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!tpg) { 9148c2ecf20Sopenharmony_ci pr_err("%s:%llu %s\n", phy, unpacked_lun, error); 9158c2ecf20Sopenharmony_ci return -ENODEV; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL); 9198c2ecf20Sopenharmony_ci if (new == NULL) { 9208c2ecf20Sopenharmony_ci err = -ENOMEM; 9218c2ecf20Sopenharmony_ci goto out_free; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* Check double assignment to identical virtual ID */ 9278c2ecf20Sopenharmony_ci if (scsiback_chk_translation_entry(info, v)) { 9288c2ecf20Sopenharmony_ci pr_warn("Virtual ID is already used. Assignment was not performed.\n"); 9298c2ecf20Sopenharmony_ci err = -EEXIST; 9308c2ecf20Sopenharmony_ci goto out; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* Create a new translation entry and add to the list */ 9348c2ecf20Sopenharmony_ci kref_init(&new->kref); 9358c2ecf20Sopenharmony_ci new->v = *v; 9368c2ecf20Sopenharmony_ci new->tpg = tpg; 9378c2ecf20Sopenharmony_ci new->lun = unpacked_lun; 9388c2ecf20Sopenharmony_ci list_add_tail(&new->l, &info->v2p_entry_lists); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ciout: 9418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciout_free: 9448c2ecf20Sopenharmony_ci if (err) { 9458c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 9468c2ecf20Sopenharmony_ci tpg->tv_tpg_fe_count--; 9478c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 9488c2ecf20Sopenharmony_ci kfree(new); 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci return err; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic void __scsiback_del_translation_entry(struct v2p_entry *entry) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci list_del(&entry->l); 9578c2ecf20Sopenharmony_ci kref_put(&entry->kref, scsiback_free_translation_entry); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci/* 9618c2ecf20Sopenharmony_ci Delete the translation entry specified 9628c2ecf20Sopenharmony_ci*/ 9638c2ecf20Sopenharmony_cistatic int scsiback_del_translation_entry(struct vscsibk_info *info, 9648c2ecf20Sopenharmony_ci struct ids_tuple *v) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct v2p_entry *entry; 9678c2ecf20Sopenharmony_ci unsigned long flags; 9688c2ecf20Sopenharmony_ci int ret = 0; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 9718c2ecf20Sopenharmony_ci /* Find out the translation entry specified */ 9728c2ecf20Sopenharmony_ci entry = scsiback_chk_translation_entry(info, v); 9738c2ecf20Sopenharmony_ci if (entry) 9748c2ecf20Sopenharmony_ci __scsiback_del_translation_entry(entry); 9758c2ecf20Sopenharmony_ci else 9768c2ecf20Sopenharmony_ci ret = -ENOENT; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 9798c2ecf20Sopenharmony_ci return ret; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, 9838c2ecf20Sopenharmony_ci char *phy, struct ids_tuple *vir, int try) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct v2p_entry *entry; 9868c2ecf20Sopenharmony_ci unsigned long flags; 9878c2ecf20Sopenharmony_ci int err; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (try) { 9908c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 9918c2ecf20Sopenharmony_ci entry = scsiback_chk_translation_entry(info, vir); 9928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 9938c2ecf20Sopenharmony_ci if (entry) 9948c2ecf20Sopenharmony_ci return; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci if (!scsiback_add_translation_entry(info, phy, vir)) { 9978c2ecf20Sopenharmony_ci if (xenbus_printf(XBT_NIL, info->dev->nodename, state, 9988c2ecf20Sopenharmony_ci "%d", XenbusStateInitialised)) { 9998c2ecf20Sopenharmony_ci pr_err("xenbus_printf error %s\n", state); 10008c2ecf20Sopenharmony_ci scsiback_del_translation_entry(info, vir); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } else if (!try) { 10038c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, info->dev->nodename, state, 10048c2ecf20Sopenharmony_ci "%d", XenbusStateClosed); 10058c2ecf20Sopenharmony_ci if (err) 10068c2ecf20Sopenharmony_ci xenbus_dev_error(info->dev, err, 10078c2ecf20Sopenharmony_ci "%s: writing %s", __func__, state); 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic void scsiback_do_del_lun(struct vscsibk_info *info, const char *state, 10128c2ecf20Sopenharmony_ci struct ids_tuple *vir) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci if (!scsiback_del_translation_entry(info, vir)) { 10158c2ecf20Sopenharmony_ci if (xenbus_printf(XBT_NIL, info->dev->nodename, state, 10168c2ecf20Sopenharmony_ci "%d", XenbusStateClosed)) 10178c2ecf20Sopenharmony_ci pr_err("xenbus_printf error %s\n", state); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci#define VSCSIBACK_OP_ADD_OR_DEL_LUN 1 10228c2ecf20Sopenharmony_ci#define VSCSIBACK_OP_UPDATEDEV_STATE 2 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, 10258c2ecf20Sopenharmony_ci char *ent) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci int err; 10288c2ecf20Sopenharmony_ci struct ids_tuple vir; 10298c2ecf20Sopenharmony_ci char *val; 10308c2ecf20Sopenharmony_ci int device_state; 10318c2ecf20Sopenharmony_ci char phy[VSCSI_NAMELEN]; 10328c2ecf20Sopenharmony_ci char str[64]; 10338c2ecf20Sopenharmony_ci char state[64]; 10348c2ecf20Sopenharmony_ci struct xenbus_device *dev = info->dev; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* read status */ 10378c2ecf20Sopenharmony_ci snprintf(state, sizeof(state), "vscsi-devs/%s/state", ent); 10388c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, dev->nodename, state, "%u", &device_state); 10398c2ecf20Sopenharmony_ci if (XENBUS_EXIST_ERR(err)) 10408c2ecf20Sopenharmony_ci return; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* physical SCSI device */ 10438c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent); 10448c2ecf20Sopenharmony_ci val = xenbus_read(XBT_NIL, dev->nodename, str, NULL); 10458c2ecf20Sopenharmony_ci if (IS_ERR(val)) { 10468c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, dev->nodename, state, 10478c2ecf20Sopenharmony_ci "%d", XenbusStateClosed); 10488c2ecf20Sopenharmony_ci if (err) 10498c2ecf20Sopenharmony_ci xenbus_dev_error(info->dev, err, 10508c2ecf20Sopenharmony_ci "%s: writing %s", __func__, state); 10518c2ecf20Sopenharmony_ci return; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci strlcpy(phy, val, VSCSI_NAMELEN); 10548c2ecf20Sopenharmony_ci kfree(val); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* virtual SCSI device */ 10578c2ecf20Sopenharmony_ci snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", ent); 10588c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, dev->nodename, str, "%u:%u:%u:%u", 10598c2ecf20Sopenharmony_ci &vir.hst, &vir.chn, &vir.tgt, &vir.lun); 10608c2ecf20Sopenharmony_ci if (XENBUS_EXIST_ERR(err)) { 10618c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, dev->nodename, state, 10628c2ecf20Sopenharmony_ci "%d", XenbusStateClosed); 10638c2ecf20Sopenharmony_ci if (err) 10648c2ecf20Sopenharmony_ci xenbus_dev_error(info->dev, err, 10658c2ecf20Sopenharmony_ci "%s: writing %s", __func__, state); 10668c2ecf20Sopenharmony_ci return; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci switch (op) { 10708c2ecf20Sopenharmony_ci case VSCSIBACK_OP_ADD_OR_DEL_LUN: 10718c2ecf20Sopenharmony_ci switch (device_state) { 10728c2ecf20Sopenharmony_ci case XenbusStateInitialising: 10738c2ecf20Sopenharmony_ci scsiback_do_add_lun(info, state, phy, &vir, 0); 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case XenbusStateConnected: 10768c2ecf20Sopenharmony_ci scsiback_do_add_lun(info, state, phy, &vir, 1); 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci case XenbusStateClosing: 10798c2ecf20Sopenharmony_ci scsiback_do_del_lun(info, state, &vir); 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci default: 10828c2ecf20Sopenharmony_ci break; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci case VSCSIBACK_OP_UPDATEDEV_STATE: 10878c2ecf20Sopenharmony_ci if (device_state == XenbusStateInitialised) { 10888c2ecf20Sopenharmony_ci /* modify vscsi-devs/dev-x/state */ 10898c2ecf20Sopenharmony_ci if (xenbus_printf(XBT_NIL, dev->nodename, state, 10908c2ecf20Sopenharmony_ci "%d", XenbusStateConnected)) { 10918c2ecf20Sopenharmony_ci pr_err("xenbus_printf error %s\n", str); 10928c2ecf20Sopenharmony_ci scsiback_del_translation_entry(info, &vir); 10938c2ecf20Sopenharmony_ci xenbus_printf(XBT_NIL, dev->nodename, state, 10948c2ecf20Sopenharmony_ci "%d", XenbusStateClosed); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci /* When it is necessary, processing is added here. */ 10998c2ecf20Sopenharmony_ci default: 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void scsiback_do_lun_hotplug(struct vscsibk_info *info, int op) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci int i; 11078c2ecf20Sopenharmony_ci char **dir; 11088c2ecf20Sopenharmony_ci unsigned int ndir = 0; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci dir = xenbus_directory(XBT_NIL, info->dev->nodename, "vscsi-devs", 11118c2ecf20Sopenharmony_ci &ndir); 11128c2ecf20Sopenharmony_ci if (IS_ERR(dir)) 11138c2ecf20Sopenharmony_ci return; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci for (i = 0; i < ndir; i++) 11168c2ecf20Sopenharmony_ci scsiback_do_1lun_hotplug(info, op, dir[i]); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci kfree(dir); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic void scsiback_frontend_changed(struct xenbus_device *dev, 11228c2ecf20Sopenharmony_ci enum xenbus_state frontend_state) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci struct vscsibk_info *info = dev_get_drvdata(&dev->dev); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci switch (frontend_state) { 11278c2ecf20Sopenharmony_ci case XenbusStateInitialising: 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci case XenbusStateInitialised: 11318c2ecf20Sopenharmony_ci if (scsiback_map(info)) 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN); 11358c2ecf20Sopenharmony_ci xenbus_switch_state(dev, XenbusStateConnected); 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci case XenbusStateConnected: 11398c2ecf20Sopenharmony_ci scsiback_do_lun_hotplug(info, VSCSIBACK_OP_UPDATEDEV_STATE); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (dev->state == XenbusStateConnected) 11428c2ecf20Sopenharmony_ci break; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci xenbus_switch_state(dev, XenbusStateConnected); 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci case XenbusStateClosing: 11488c2ecf20Sopenharmony_ci if (info->irq) 11498c2ecf20Sopenharmony_ci scsiback_disconnect(info); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci xenbus_switch_state(dev, XenbusStateClosing); 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci case XenbusStateClosed: 11558c2ecf20Sopenharmony_ci xenbus_switch_state(dev, XenbusStateClosed); 11568c2ecf20Sopenharmony_ci if (xenbus_dev_is_online(dev)) 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci fallthrough; /* if not online */ 11598c2ecf20Sopenharmony_ci case XenbusStateUnknown: 11608c2ecf20Sopenharmony_ci device_unregister(&dev->dev); 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci case XenbusStateReconfiguring: 11648c2ecf20Sopenharmony_ci scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN); 11658c2ecf20Sopenharmony_ci xenbus_switch_state(dev, XenbusStateReconfigured); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci break; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci default: 11708c2ecf20Sopenharmony_ci xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", 11718c2ecf20Sopenharmony_ci frontend_state); 11728c2ecf20Sopenharmony_ci break; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci/* 11778c2ecf20Sopenharmony_ci Release the translation entry specfied 11788c2ecf20Sopenharmony_ci*/ 11798c2ecf20Sopenharmony_cistatic void scsiback_release_translation_entry(struct vscsibk_info *info) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct v2p_entry *entry, *tmp; 11828c2ecf20Sopenharmony_ci struct list_head *head = &(info->v2p_entry_lists); 11838c2ecf20Sopenharmony_ci unsigned long flags; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, tmp, head, l) 11888c2ecf20Sopenharmony_ci __scsiback_del_translation_entry(entry); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic int scsiback_remove(struct xenbus_device *dev) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct vscsibk_info *info = dev_get_drvdata(&dev->dev); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (info->irq) 11988c2ecf20Sopenharmony_ci scsiback_disconnect(info); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci scsiback_release_translation_entry(info); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci gnttab_page_cache_shrink(&info->free_pages, 0); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, NULL); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci return 0; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic int scsiback_probe(struct xenbus_device *dev, 12108c2ecf20Sopenharmony_ci const struct xenbus_device_id *id) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci int err; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), 12158c2ecf20Sopenharmony_ci GFP_KERNEL); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (!info) { 12208c2ecf20Sopenharmony_ci xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); 12218c2ecf20Sopenharmony_ci return -ENOMEM; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci info->dev = dev; 12248c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, info); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci info->domid = dev->otherend_id; 12278c2ecf20Sopenharmony_ci spin_lock_init(&info->ring_lock); 12288c2ecf20Sopenharmony_ci atomic_set(&info->nr_unreplied_reqs, 0); 12298c2ecf20Sopenharmony_ci init_waitqueue_head(&info->waiting_to_free); 12308c2ecf20Sopenharmony_ci info->dev = dev; 12318c2ecf20Sopenharmony_ci info->irq = 0; 12328c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&info->v2p_entry_lists); 12338c2ecf20Sopenharmony_ci spin_lock_init(&info->v2p_lock); 12348c2ecf20Sopenharmony_ci gnttab_page_cache_init(&info->free_pages); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, dev->nodename, "feature-sg-grant", "%u", 12378c2ecf20Sopenharmony_ci SG_ALL); 12388c2ecf20Sopenharmony_ci if (err) 12398c2ecf20Sopenharmony_ci xenbus_dev_error(dev, err, "writing feature-sg-grant"); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci err = xenbus_switch_state(dev, XenbusStateInitWait); 12428c2ecf20Sopenharmony_ci if (err) 12438c2ecf20Sopenharmony_ci goto fail; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cifail: 12488c2ecf20Sopenharmony_ci pr_warn("%s failed\n", __func__); 12498c2ecf20Sopenharmony_ci scsiback_remove(dev); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci return err; 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic char *scsiback_dump_proto_id(struct scsiback_tport *tport) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci switch (tport->tport_proto_id) { 12578c2ecf20Sopenharmony_ci case SCSI_PROTOCOL_SAS: 12588c2ecf20Sopenharmony_ci return "SAS"; 12598c2ecf20Sopenharmony_ci case SCSI_PROTOCOL_FCP: 12608c2ecf20Sopenharmony_ci return "FCP"; 12618c2ecf20Sopenharmony_ci case SCSI_PROTOCOL_ISCSI: 12628c2ecf20Sopenharmony_ci return "iSCSI"; 12638c2ecf20Sopenharmony_ci default: 12648c2ecf20Sopenharmony_ci break; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci return "Unknown"; 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_cistatic char *scsiback_get_fabric_wwn(struct se_portal_group *se_tpg) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 12738c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 12748c2ecf20Sopenharmony_ci struct scsiback_tport *tport = tpg->tport; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return &tport->tport_name[0]; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic u16 scsiback_get_tag(struct se_portal_group *se_tpg) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 12828c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 12838c2ecf20Sopenharmony_ci return tpg->tport_tpgt; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic struct se_wwn * 12878c2ecf20Sopenharmony_ciscsiback_make_tport(struct target_fabric_configfs *tf, 12888c2ecf20Sopenharmony_ci struct config_group *group, 12898c2ecf20Sopenharmony_ci const char *name) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci struct scsiback_tport *tport; 12928c2ecf20Sopenharmony_ci char *ptr; 12938c2ecf20Sopenharmony_ci u64 wwpn = 0; 12948c2ecf20Sopenharmony_ci int off = 0; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci tport = kzalloc(sizeof(struct scsiback_tport), GFP_KERNEL); 12978c2ecf20Sopenharmony_ci if (!tport) 12988c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci tport->tport_wwpn = wwpn; 13018c2ecf20Sopenharmony_ci /* 13028c2ecf20Sopenharmony_ci * Determine the emulated Protocol Identifier and Target Port Name 13038c2ecf20Sopenharmony_ci * based on the incoming configfs directory name. 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_ci ptr = strstr(name, "naa."); 13068c2ecf20Sopenharmony_ci if (ptr) { 13078c2ecf20Sopenharmony_ci tport->tport_proto_id = SCSI_PROTOCOL_SAS; 13088c2ecf20Sopenharmony_ci goto check_len; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci ptr = strstr(name, "fc."); 13118c2ecf20Sopenharmony_ci if (ptr) { 13128c2ecf20Sopenharmony_ci tport->tport_proto_id = SCSI_PROTOCOL_FCP; 13138c2ecf20Sopenharmony_ci off = 3; /* Skip over "fc." */ 13148c2ecf20Sopenharmony_ci goto check_len; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci ptr = strstr(name, "iqn."); 13178c2ecf20Sopenharmony_ci if (ptr) { 13188c2ecf20Sopenharmony_ci tport->tport_proto_id = SCSI_PROTOCOL_ISCSI; 13198c2ecf20Sopenharmony_ci goto check_len; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci pr_err("Unable to locate prefix for emulated Target Port: %s\n", name); 13238c2ecf20Sopenharmony_ci kfree(tport); 13248c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cicheck_len: 13278c2ecf20Sopenharmony_ci if (strlen(name) >= VSCSI_NAMELEN) { 13288c2ecf20Sopenharmony_ci pr_err("Emulated %s Address: %s, exceeds max: %d\n", name, 13298c2ecf20Sopenharmony_ci scsiback_dump_proto_id(tport), VSCSI_NAMELEN); 13308c2ecf20Sopenharmony_ci kfree(tport); 13318c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci pr_debug("Allocated emulated Target %s Address: %s\n", 13368c2ecf20Sopenharmony_ci scsiback_dump_proto_id(tport), name); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci return &tport->tport_wwn; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic void scsiback_drop_tport(struct se_wwn *wwn) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct scsiback_tport *tport = container_of(wwn, 13448c2ecf20Sopenharmony_ci struct scsiback_tport, tport_wwn); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci pr_debug("Deallocating emulated Target %s Address: %s\n", 13478c2ecf20Sopenharmony_ci scsiback_dump_proto_id(tport), tport->tport_name); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci kfree(tport); 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cistatic u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci return 1; 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic int scsiback_check_stop_free(struct se_cmd *se_cmd) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci return transport_generic_free_cmd(se_cmd, 0); 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic void scsiback_release_cmd(struct se_cmd *se_cmd) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci target_free_tag(se_cmd->se_sess, se_cmd); 13658c2ecf20Sopenharmony_ci} 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_cistatic u32 scsiback_sess_get_index(struct se_session *se_sess) 13688c2ecf20Sopenharmony_ci{ 13698c2ecf20Sopenharmony_ci return 0; 13708c2ecf20Sopenharmony_ci} 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_cistatic int scsiback_write_pending(struct se_cmd *se_cmd) 13738c2ecf20Sopenharmony_ci{ 13748c2ecf20Sopenharmony_ci /* Go ahead and process the write immediately */ 13758c2ecf20Sopenharmony_ci target_execute_cmd(se_cmd); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci return 0; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic void scsiback_set_default_node_attrs(struct se_node_acl *nacl) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic int scsiback_get_cmd_state(struct se_cmd *se_cmd) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci return 0; 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int scsiback_queue_data_in(struct se_cmd *se_cmd) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req = container_of(se_cmd, 13928c2ecf20Sopenharmony_ci struct vscsibk_pend, se_cmd); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci pending_req->result = SAM_STAT_GOOD; 13958c2ecf20Sopenharmony_ci scsiback_cmd_done(pending_req); 13968c2ecf20Sopenharmony_ci return 0; 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic int scsiback_queue_status(struct se_cmd *se_cmd) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req = container_of(se_cmd, 14028c2ecf20Sopenharmony_ci struct vscsibk_pend, se_cmd); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (se_cmd->sense_buffer && 14058c2ecf20Sopenharmony_ci ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || 14068c2ecf20Sopenharmony_ci (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) 14078c2ecf20Sopenharmony_ci pending_req->result = (DRIVER_SENSE << 24) | 14088c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 14098c2ecf20Sopenharmony_ci else 14108c2ecf20Sopenharmony_ci pending_req->result = se_cmd->scsi_status; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci scsiback_cmd_done(pending_req); 14138c2ecf20Sopenharmony_ci return 0; 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic void scsiback_queue_tm_rsp(struct se_cmd *se_cmd) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct vscsibk_pend *pending_req = container_of(se_cmd, 14198c2ecf20Sopenharmony_ci struct vscsibk_pend, se_cmd); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci complete(&pending_req->tmr_done); 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic void scsiback_aborted_task(struct se_cmd *se_cmd) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_cistatic ssize_t scsiback_tpg_param_alias_show(struct config_item *item, 14298c2ecf20Sopenharmony_ci char *page) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci struct se_portal_group *se_tpg = param_to_tpg(item); 14328c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, 14338c2ecf20Sopenharmony_ci se_tpg); 14348c2ecf20Sopenharmony_ci ssize_t rb; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 14378c2ecf20Sopenharmony_ci rb = snprintf(page, PAGE_SIZE, "%s\n", tpg->param_alias); 14388c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci return rb; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic ssize_t scsiback_tpg_param_alias_store(struct config_item *item, 14448c2ecf20Sopenharmony_ci const char *page, size_t count) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci struct se_portal_group *se_tpg = param_to_tpg(item); 14478c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, 14488c2ecf20Sopenharmony_ci se_tpg); 14498c2ecf20Sopenharmony_ci int len; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (strlen(page) >= VSCSI_NAMELEN) { 14528c2ecf20Sopenharmony_ci pr_err("param alias: %s, exceeds max: %d\n", page, 14538c2ecf20Sopenharmony_ci VSCSI_NAMELEN); 14548c2ecf20Sopenharmony_ci return -EINVAL; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 14588c2ecf20Sopenharmony_ci len = snprintf(tpg->param_alias, VSCSI_NAMELEN, "%s", page); 14598c2ecf20Sopenharmony_ci if (tpg->param_alias[len - 1] == '\n') 14608c2ecf20Sopenharmony_ci tpg->param_alias[len - 1] = '\0'; 14618c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci return count; 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ciCONFIGFS_ATTR(scsiback_tpg_param_, alias); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic struct configfs_attribute *scsiback_param_attrs[] = { 14698c2ecf20Sopenharmony_ci &scsiback_tpg_param_attr_alias, 14708c2ecf20Sopenharmony_ci NULL, 14718c2ecf20Sopenharmony_ci}; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic int scsiback_alloc_sess_cb(struct se_portal_group *se_tpg, 14748c2ecf20Sopenharmony_ci struct se_session *se_sess, void *p) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 14778c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci tpg->tpg_nexus = p; 14808c2ecf20Sopenharmony_ci return 0; 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic int scsiback_make_nexus(struct scsiback_tpg *tpg, 14848c2ecf20Sopenharmony_ci const char *name) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci struct scsiback_nexus *tv_nexus; 14878c2ecf20Sopenharmony_ci int ret = 0; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 14908c2ecf20Sopenharmony_ci if (tpg->tpg_nexus) { 14918c2ecf20Sopenharmony_ci pr_debug("tpg->tpg_nexus already exists\n"); 14928c2ecf20Sopenharmony_ci ret = -EEXIST; 14938c2ecf20Sopenharmony_ci goto out_unlock; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci tv_nexus = kzalloc(sizeof(struct scsiback_nexus), GFP_KERNEL); 14978c2ecf20Sopenharmony_ci if (!tv_nexus) { 14988c2ecf20Sopenharmony_ci ret = -ENOMEM; 14998c2ecf20Sopenharmony_ci goto out_unlock; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg, 15038c2ecf20Sopenharmony_ci VSCSI_DEFAULT_SESSION_TAGS, 15048c2ecf20Sopenharmony_ci sizeof(struct vscsibk_pend), 15058c2ecf20Sopenharmony_ci TARGET_PROT_NORMAL, name, 15068c2ecf20Sopenharmony_ci tv_nexus, scsiback_alloc_sess_cb); 15078c2ecf20Sopenharmony_ci if (IS_ERR(tv_nexus->tvn_se_sess)) { 15088c2ecf20Sopenharmony_ci kfree(tv_nexus); 15098c2ecf20Sopenharmony_ci ret = -ENOMEM; 15108c2ecf20Sopenharmony_ci goto out_unlock; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ciout_unlock: 15148c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15158c2ecf20Sopenharmony_ci return ret; 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_cistatic int scsiback_drop_nexus(struct scsiback_tpg *tpg) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci struct se_session *se_sess; 15218c2ecf20Sopenharmony_ci struct scsiback_nexus *tv_nexus; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 15248c2ecf20Sopenharmony_ci tv_nexus = tpg->tpg_nexus; 15258c2ecf20Sopenharmony_ci if (!tv_nexus) { 15268c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15278c2ecf20Sopenharmony_ci return -ENODEV; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci se_sess = tv_nexus->tvn_se_sess; 15318c2ecf20Sopenharmony_ci if (!se_sess) { 15328c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15338c2ecf20Sopenharmony_ci return -ENODEV; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (tpg->tv_tpg_port_count != 0) { 15378c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15388c2ecf20Sopenharmony_ci pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG port count: %d\n", 15398c2ecf20Sopenharmony_ci tpg->tv_tpg_port_count); 15408c2ecf20Sopenharmony_ci return -EBUSY; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (tpg->tv_tpg_fe_count != 0) { 15448c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15458c2ecf20Sopenharmony_ci pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG frontend count: %d\n", 15468c2ecf20Sopenharmony_ci tpg->tv_tpg_fe_count); 15478c2ecf20Sopenharmony_ci return -EBUSY; 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci pr_debug("Removing I_T Nexus to emulated %s Initiator Port: %s\n", 15518c2ecf20Sopenharmony_ci scsiback_dump_proto_id(tpg->tport), 15528c2ecf20Sopenharmony_ci tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* 15558c2ecf20Sopenharmony_ci * Release the SCSI I_T Nexus to the emulated xen-pvscsi Target Port 15568c2ecf20Sopenharmony_ci */ 15578c2ecf20Sopenharmony_ci target_remove_session(se_sess); 15588c2ecf20Sopenharmony_ci tpg->tpg_nexus = NULL; 15598c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci kfree(tv_nexus); 15628c2ecf20Sopenharmony_ci return 0; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic ssize_t scsiback_tpg_nexus_show(struct config_item *item, char *page) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci struct se_portal_group *se_tpg = to_tpg(item); 15688c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 15698c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 15708c2ecf20Sopenharmony_ci struct scsiback_nexus *tv_nexus; 15718c2ecf20Sopenharmony_ci ssize_t ret; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 15748c2ecf20Sopenharmony_ci tv_nexus = tpg->tpg_nexus; 15758c2ecf20Sopenharmony_ci if (!tv_nexus) { 15768c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15778c2ecf20Sopenharmony_ci return -ENODEV; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci ret = snprintf(page, PAGE_SIZE, "%s\n", 15808c2ecf20Sopenharmony_ci tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 15818c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci return ret; 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic ssize_t scsiback_tpg_nexus_store(struct config_item *item, 15878c2ecf20Sopenharmony_ci const char *page, size_t count) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci struct se_portal_group *se_tpg = to_tpg(item); 15908c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 15918c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 15928c2ecf20Sopenharmony_ci struct scsiback_tport *tport_wwn = tpg->tport; 15938c2ecf20Sopenharmony_ci unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; 15948c2ecf20Sopenharmony_ci int ret; 15958c2ecf20Sopenharmony_ci /* 15968c2ecf20Sopenharmony_ci * Shutdown the active I_T nexus if 'NULL' is passed. 15978c2ecf20Sopenharmony_ci */ 15988c2ecf20Sopenharmony_ci if (!strncmp(page, "NULL", 4)) { 15998c2ecf20Sopenharmony_ci ret = scsiback_drop_nexus(tpg); 16008c2ecf20Sopenharmony_ci return (!ret) ? count : ret; 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci /* 16038c2ecf20Sopenharmony_ci * Otherwise make sure the passed virtual Initiator port WWN matches 16048c2ecf20Sopenharmony_ci * the fabric protocol_id set in scsiback_make_tport(), and call 16058c2ecf20Sopenharmony_ci * scsiback_make_nexus(). 16068c2ecf20Sopenharmony_ci */ 16078c2ecf20Sopenharmony_ci if (strlen(page) >= VSCSI_NAMELEN) { 16088c2ecf20Sopenharmony_ci pr_err("Emulated NAA Sas Address: %s, exceeds max: %d\n", 16098c2ecf20Sopenharmony_ci page, VSCSI_NAMELEN); 16108c2ecf20Sopenharmony_ci return -EINVAL; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci snprintf(&i_port[0], VSCSI_NAMELEN, "%s", page); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci ptr = strstr(i_port, "naa."); 16158c2ecf20Sopenharmony_ci if (ptr) { 16168c2ecf20Sopenharmony_ci if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) { 16178c2ecf20Sopenharmony_ci pr_err("Passed SAS Initiator Port %s does not match target port protoid: %s\n", 16188c2ecf20Sopenharmony_ci i_port, scsiback_dump_proto_id(tport_wwn)); 16198c2ecf20Sopenharmony_ci return -EINVAL; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci port_ptr = &i_port[0]; 16228c2ecf20Sopenharmony_ci goto check_newline; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci ptr = strstr(i_port, "fc."); 16258c2ecf20Sopenharmony_ci if (ptr) { 16268c2ecf20Sopenharmony_ci if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) { 16278c2ecf20Sopenharmony_ci pr_err("Passed FCP Initiator Port %s does not match target port protoid: %s\n", 16288c2ecf20Sopenharmony_ci i_port, scsiback_dump_proto_id(tport_wwn)); 16298c2ecf20Sopenharmony_ci return -EINVAL; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci port_ptr = &i_port[3]; /* Skip over "fc." */ 16328c2ecf20Sopenharmony_ci goto check_newline; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci ptr = strstr(i_port, "iqn."); 16358c2ecf20Sopenharmony_ci if (ptr) { 16368c2ecf20Sopenharmony_ci if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) { 16378c2ecf20Sopenharmony_ci pr_err("Passed iSCSI Initiator Port %s does not match target port protoid: %s\n", 16388c2ecf20Sopenharmony_ci i_port, scsiback_dump_proto_id(tport_wwn)); 16398c2ecf20Sopenharmony_ci return -EINVAL; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci port_ptr = &i_port[0]; 16428c2ecf20Sopenharmony_ci goto check_newline; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci pr_err("Unable to locate prefix for emulated Initiator Port: %s\n", 16458c2ecf20Sopenharmony_ci i_port); 16468c2ecf20Sopenharmony_ci return -EINVAL; 16478c2ecf20Sopenharmony_ci /* 16488c2ecf20Sopenharmony_ci * Clear any trailing newline for the NAA WWN 16498c2ecf20Sopenharmony_ci */ 16508c2ecf20Sopenharmony_cicheck_newline: 16518c2ecf20Sopenharmony_ci if (i_port[strlen(i_port) - 1] == '\n') 16528c2ecf20Sopenharmony_ci i_port[strlen(i_port) - 1] = '\0'; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci ret = scsiback_make_nexus(tpg, port_ptr); 16558c2ecf20Sopenharmony_ci if (ret < 0) 16568c2ecf20Sopenharmony_ci return ret; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci return count; 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ciCONFIGFS_ATTR(scsiback_tpg_, nexus); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic struct configfs_attribute *scsiback_tpg_attrs[] = { 16648c2ecf20Sopenharmony_ci &scsiback_tpg_attr_nexus, 16658c2ecf20Sopenharmony_ci NULL, 16668c2ecf20Sopenharmony_ci}; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_cistatic ssize_t 16698c2ecf20Sopenharmony_ciscsiback_wwn_version_show(struct config_item *item, char *page) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci return sprintf(page, "xen-pvscsi fabric module %s on %s/%s on " 16728c2ecf20Sopenharmony_ci UTS_RELEASE"\n", 16738c2ecf20Sopenharmony_ci VSCSI_VERSION, utsname()->sysname, utsname()->machine); 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ciCONFIGFS_ATTR_RO(scsiback_wwn_, version); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_cistatic struct configfs_attribute *scsiback_wwn_attrs[] = { 16798c2ecf20Sopenharmony_ci &scsiback_wwn_attr_version, 16808c2ecf20Sopenharmony_ci NULL, 16818c2ecf20Sopenharmony_ci}; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_cistatic int scsiback_port_link(struct se_portal_group *se_tpg, 16848c2ecf20Sopenharmony_ci struct se_lun *lun) 16858c2ecf20Sopenharmony_ci{ 16868c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 16878c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 16908c2ecf20Sopenharmony_ci tpg->tv_tpg_port_count++; 16918c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci return 0; 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cistatic void scsiback_port_unlink(struct se_portal_group *se_tpg, 16978c2ecf20Sopenharmony_ci struct se_lun *lun) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 17008c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 17038c2ecf20Sopenharmony_ci tpg->tv_tpg_port_count--; 17048c2ecf20Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_cistatic struct se_portal_group * 17088c2ecf20Sopenharmony_ciscsiback_make_tpg(struct se_wwn *wwn, const char *name) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci struct scsiback_tport *tport = container_of(wwn, 17118c2ecf20Sopenharmony_ci struct scsiback_tport, tport_wwn); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg; 17148c2ecf20Sopenharmony_ci u16 tpgt; 17158c2ecf20Sopenharmony_ci int ret; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (strstr(name, "tpgt_") != name) 17188c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 17198c2ecf20Sopenharmony_ci ret = kstrtou16(name + 5, 10, &tpgt); 17208c2ecf20Sopenharmony_ci if (ret) 17218c2ecf20Sopenharmony_ci return ERR_PTR(ret); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci tpg = kzalloc(sizeof(struct scsiback_tpg), GFP_KERNEL); 17248c2ecf20Sopenharmony_ci if (!tpg) 17258c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci mutex_init(&tpg->tv_tpg_mutex); 17288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tpg->tv_tpg_list); 17298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tpg->info_list); 17308c2ecf20Sopenharmony_ci tpg->tport = tport; 17318c2ecf20Sopenharmony_ci tpg->tport_tpgt = tpgt; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); 17348c2ecf20Sopenharmony_ci if (ret < 0) { 17358c2ecf20Sopenharmony_ci kfree(tpg); 17368c2ecf20Sopenharmony_ci return NULL; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci mutex_lock(&scsiback_mutex); 17398c2ecf20Sopenharmony_ci list_add_tail(&tpg->tv_tpg_list, &scsiback_list); 17408c2ecf20Sopenharmony_ci mutex_unlock(&scsiback_mutex); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci return &tpg->se_tpg; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cistatic void scsiback_drop_tpg(struct se_portal_group *se_tpg) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 17488c2ecf20Sopenharmony_ci struct scsiback_tpg, se_tpg); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci mutex_lock(&scsiback_mutex); 17518c2ecf20Sopenharmony_ci list_del(&tpg->tv_tpg_list); 17528c2ecf20Sopenharmony_ci mutex_unlock(&scsiback_mutex); 17538c2ecf20Sopenharmony_ci /* 17548c2ecf20Sopenharmony_ci * Release the virtual I_T Nexus for this xen-pvscsi TPG 17558c2ecf20Sopenharmony_ci */ 17568c2ecf20Sopenharmony_ci scsiback_drop_nexus(tpg); 17578c2ecf20Sopenharmony_ci /* 17588c2ecf20Sopenharmony_ci * Deregister the se_tpg from TCM. 17598c2ecf20Sopenharmony_ci */ 17608c2ecf20Sopenharmony_ci core_tpg_deregister(se_tpg); 17618c2ecf20Sopenharmony_ci kfree(tpg); 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistatic int scsiback_check_true(struct se_portal_group *se_tpg) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci return 1; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic int scsiback_check_false(struct se_portal_group *se_tpg) 17708c2ecf20Sopenharmony_ci{ 17718c2ecf20Sopenharmony_ci return 0; 17728c2ecf20Sopenharmony_ci} 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_cistatic const struct target_core_fabric_ops scsiback_ops = { 17758c2ecf20Sopenharmony_ci .module = THIS_MODULE, 17768c2ecf20Sopenharmony_ci .fabric_name = "xen-pvscsi", 17778c2ecf20Sopenharmony_ci .tpg_get_wwn = scsiback_get_fabric_wwn, 17788c2ecf20Sopenharmony_ci .tpg_get_tag = scsiback_get_tag, 17798c2ecf20Sopenharmony_ci .tpg_check_demo_mode = scsiback_check_true, 17808c2ecf20Sopenharmony_ci .tpg_check_demo_mode_cache = scsiback_check_true, 17818c2ecf20Sopenharmony_ci .tpg_check_demo_mode_write_protect = scsiback_check_false, 17828c2ecf20Sopenharmony_ci .tpg_check_prod_mode_write_protect = scsiback_check_false, 17838c2ecf20Sopenharmony_ci .tpg_get_inst_index = scsiback_tpg_get_inst_index, 17848c2ecf20Sopenharmony_ci .check_stop_free = scsiback_check_stop_free, 17858c2ecf20Sopenharmony_ci .release_cmd = scsiback_release_cmd, 17868c2ecf20Sopenharmony_ci .sess_get_index = scsiback_sess_get_index, 17878c2ecf20Sopenharmony_ci .sess_get_initiator_sid = NULL, 17888c2ecf20Sopenharmony_ci .write_pending = scsiback_write_pending, 17898c2ecf20Sopenharmony_ci .set_default_node_attributes = scsiback_set_default_node_attrs, 17908c2ecf20Sopenharmony_ci .get_cmd_state = scsiback_get_cmd_state, 17918c2ecf20Sopenharmony_ci .queue_data_in = scsiback_queue_data_in, 17928c2ecf20Sopenharmony_ci .queue_status = scsiback_queue_status, 17938c2ecf20Sopenharmony_ci .queue_tm_rsp = scsiback_queue_tm_rsp, 17948c2ecf20Sopenharmony_ci .aborted_task = scsiback_aborted_task, 17958c2ecf20Sopenharmony_ci /* 17968c2ecf20Sopenharmony_ci * Setup callers for generic logic in target_core_fabric_configfs.c 17978c2ecf20Sopenharmony_ci */ 17988c2ecf20Sopenharmony_ci .fabric_make_wwn = scsiback_make_tport, 17998c2ecf20Sopenharmony_ci .fabric_drop_wwn = scsiback_drop_tport, 18008c2ecf20Sopenharmony_ci .fabric_make_tpg = scsiback_make_tpg, 18018c2ecf20Sopenharmony_ci .fabric_drop_tpg = scsiback_drop_tpg, 18028c2ecf20Sopenharmony_ci .fabric_post_link = scsiback_port_link, 18038c2ecf20Sopenharmony_ci .fabric_pre_unlink = scsiback_port_unlink, 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci .tfc_wwn_attrs = scsiback_wwn_attrs, 18068c2ecf20Sopenharmony_ci .tfc_tpg_base_attrs = scsiback_tpg_attrs, 18078c2ecf20Sopenharmony_ci .tfc_tpg_param_attrs = scsiback_param_attrs, 18088c2ecf20Sopenharmony_ci}; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_cistatic const struct xenbus_device_id scsiback_ids[] = { 18118c2ecf20Sopenharmony_ci { "vscsi" }, 18128c2ecf20Sopenharmony_ci { "" } 18138c2ecf20Sopenharmony_ci}; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic struct xenbus_driver scsiback_driver = { 18168c2ecf20Sopenharmony_ci .ids = scsiback_ids, 18178c2ecf20Sopenharmony_ci .probe = scsiback_probe, 18188c2ecf20Sopenharmony_ci .remove = scsiback_remove, 18198c2ecf20Sopenharmony_ci .otherend_changed = scsiback_frontend_changed 18208c2ecf20Sopenharmony_ci}; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic int __init scsiback_init(void) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci int ret; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (!xen_domain()) 18278c2ecf20Sopenharmony_ci return -ENODEV; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", 18308c2ecf20Sopenharmony_ci VSCSI_VERSION, utsname()->sysname, utsname()->machine); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci ret = xenbus_register_backend(&scsiback_driver); 18338c2ecf20Sopenharmony_ci if (ret) 18348c2ecf20Sopenharmony_ci goto out; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci ret = target_register_template(&scsiback_ops); 18378c2ecf20Sopenharmony_ci if (ret) 18388c2ecf20Sopenharmony_ci goto out_unregister_xenbus; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci return 0; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ciout_unregister_xenbus: 18438c2ecf20Sopenharmony_ci xenbus_unregister_driver(&scsiback_driver); 18448c2ecf20Sopenharmony_ciout: 18458c2ecf20Sopenharmony_ci pr_err("%s: error %d\n", __func__, ret); 18468c2ecf20Sopenharmony_ci return ret; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic void __exit scsiback_exit(void) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci target_unregister_template(&scsiback_ops); 18528c2ecf20Sopenharmony_ci xenbus_unregister_driver(&scsiback_driver); 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_cimodule_init(scsiback_init); 18568c2ecf20Sopenharmony_cimodule_exit(scsiback_exit); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xen SCSI backend driver"); 18598c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 18608c2ecf20Sopenharmony_ciMODULE_ALIAS("xen-backend:vscsi"); 18618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Juergen Gross <jgross@suse.com>"); 1862