162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Xen SCSI backend driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008, FUJITSU Limited 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Based on the blkback driver code. 762306a36Sopenharmony_ci * Adaption to kernel taget core infrastructure taken from vhost/scsi.c 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 1062306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 1162306a36Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed 1262306a36Sopenharmony_ci * separately from the Linux kernel or incorporated into other 1362306a36Sopenharmony_ci * software packages, subject to the following license: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 1662306a36Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 1762306a36Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 1862306a36Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 1962306a36Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 2062306a36Sopenharmony_ci * the following conditions: 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 2362306a36Sopenharmony_ci * all copies or substantial portions of the Software. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2862306a36Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 3062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 3162306a36Sopenharmony_ci * IN THE SOFTWARE. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define pr_fmt(fmt) "xen-pvscsi: " fmt 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/module.h> 3762306a36Sopenharmony_ci#include <linux/utsname.h> 3862306a36Sopenharmony_ci#include <linux/interrupt.h> 3962306a36Sopenharmony_ci#include <linux/slab.h> 4062306a36Sopenharmony_ci#include <linux/wait.h> 4162306a36Sopenharmony_ci#include <linux/sched.h> 4262306a36Sopenharmony_ci#include <linux/list.h> 4362306a36Sopenharmony_ci#include <linux/gfp.h> 4462306a36Sopenharmony_ci#include <linux/delay.h> 4562306a36Sopenharmony_ci#include <linux/spinlock.h> 4662306a36Sopenharmony_ci#include <linux/configfs.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include <generated/utsrelease.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include <scsi/scsi_host.h> /* SG_ALL */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#include <target/target_core_base.h> 5362306a36Sopenharmony_ci#include <target/target_core_fabric.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include <asm/hypervisor.h> 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#include <xen/xen.h> 5862306a36Sopenharmony_ci#include <xen/balloon.h> 5962306a36Sopenharmony_ci#include <xen/events.h> 6062306a36Sopenharmony_ci#include <xen/xenbus.h> 6162306a36Sopenharmony_ci#include <xen/grant_table.h> 6262306a36Sopenharmony_ci#include <xen/page.h> 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#include <xen/interface/grant_table.h> 6562306a36Sopenharmony_ci#include <xen/interface/io/vscsiif.h> 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define VSCSI_VERSION "v0.1" 6862306a36Sopenharmony_ci#define VSCSI_NAMELEN 32 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct ids_tuple { 7162306a36Sopenharmony_ci unsigned int hst; /* host */ 7262306a36Sopenharmony_ci unsigned int chn; /* channel */ 7362306a36Sopenharmony_ci unsigned int tgt; /* target */ 7462306a36Sopenharmony_ci unsigned int lun; /* LUN */ 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct v2p_entry { 7862306a36Sopenharmony_ci struct ids_tuple v; /* translate from */ 7962306a36Sopenharmony_ci struct scsiback_tpg *tpg; /* translate to */ 8062306a36Sopenharmony_ci unsigned int lun; 8162306a36Sopenharmony_ci struct kref kref; 8262306a36Sopenharmony_ci struct list_head l; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct vscsibk_info { 8662306a36Sopenharmony_ci struct xenbus_device *dev; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci domid_t domid; 8962306a36Sopenharmony_ci unsigned int irq; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci struct vscsiif_back_ring ring; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci spinlock_t ring_lock; 9462306a36Sopenharmony_ci atomic_t nr_unreplied_reqs; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci spinlock_t v2p_lock; 9762306a36Sopenharmony_ci struct list_head v2p_entry_lists; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci wait_queue_head_t waiting_to_free; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci struct gnttab_page_cache free_pages; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* theoretical maximum of grants for one request */ 10562306a36Sopenharmony_ci#define VSCSI_MAX_GRANTS (SG_ALL + VSCSIIF_SG_TABLESIZE) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * VSCSI_GRANT_BATCH is the maximum number of grants to be processed in one 10962306a36Sopenharmony_ci * call to map/unmap grants. Don't choose it too large, as there are arrays 11062306a36Sopenharmony_ci * with VSCSI_GRANT_BATCH elements allocated on the stack. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci#define VSCSI_GRANT_BATCH 16 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistruct vscsibk_pend { 11562306a36Sopenharmony_ci uint16_t rqid; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE]; 11862306a36Sopenharmony_ci uint8_t cmd_len; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci uint8_t sc_data_direction; 12162306a36Sopenharmony_ci uint16_t n_sg; /* real length of SG list */ 12262306a36Sopenharmony_ci uint16_t n_grants; /* SG pages and potentially SG list */ 12362306a36Sopenharmony_ci uint32_t data_len; 12462306a36Sopenharmony_ci uint32_t result; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci struct vscsibk_info *info; 12762306a36Sopenharmony_ci struct v2p_entry *v2p; 12862306a36Sopenharmony_ci struct scatterlist *sgl; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE]; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci grant_handle_t grant_handles[VSCSI_MAX_GRANTS]; 13362306a36Sopenharmony_ci struct page *pages[VSCSI_MAX_GRANTS]; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci struct se_cmd se_cmd; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci struct completion tmr_done; 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci#define VSCSI_DEFAULT_SESSION_TAGS 128 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistruct scsiback_nexus { 14362306a36Sopenharmony_ci /* Pointer to TCM session for I_T Nexus */ 14462306a36Sopenharmony_ci struct se_session *tvn_se_sess; 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistruct scsiback_tport { 14862306a36Sopenharmony_ci /* SCSI protocol the tport is providing */ 14962306a36Sopenharmony_ci u8 tport_proto_id; 15062306a36Sopenharmony_ci /* Binary World Wide unique Port Name for pvscsi Target port */ 15162306a36Sopenharmony_ci u64 tport_wwpn; 15262306a36Sopenharmony_ci /* ASCII formatted WWPN for pvscsi Target port */ 15362306a36Sopenharmony_ci char tport_name[VSCSI_NAMELEN]; 15462306a36Sopenharmony_ci /* Returned by scsiback_make_tport() */ 15562306a36Sopenharmony_ci struct se_wwn tport_wwn; 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistruct scsiback_tpg { 15962306a36Sopenharmony_ci /* scsiback port target portal group tag for TCM */ 16062306a36Sopenharmony_ci u16 tport_tpgt; 16162306a36Sopenharmony_ci /* track number of TPG Port/Lun Links wrt explicit I_T Nexus shutdown */ 16262306a36Sopenharmony_ci int tv_tpg_port_count; 16362306a36Sopenharmony_ci /* xen-pvscsi references to tpg_nexus, protected by tv_tpg_mutex */ 16462306a36Sopenharmony_ci int tv_tpg_fe_count; 16562306a36Sopenharmony_ci /* list for scsiback_list */ 16662306a36Sopenharmony_ci struct list_head tv_tpg_list; 16762306a36Sopenharmony_ci /* Used to protect access for tpg_nexus */ 16862306a36Sopenharmony_ci struct mutex tv_tpg_mutex; 16962306a36Sopenharmony_ci /* Pointer to the TCM pvscsi I_T Nexus for this TPG endpoint */ 17062306a36Sopenharmony_ci struct scsiback_nexus *tpg_nexus; 17162306a36Sopenharmony_ci /* Pointer back to scsiback_tport */ 17262306a36Sopenharmony_ci struct scsiback_tport *tport; 17362306a36Sopenharmony_ci /* Returned by scsiback_make_tpg() */ 17462306a36Sopenharmony_ci struct se_portal_group se_tpg; 17562306a36Sopenharmony_ci /* alias used in xenstore */ 17662306a36Sopenharmony_ci char param_alias[VSCSI_NAMELEN]; 17762306a36Sopenharmony_ci /* list of info structures related to this target portal group */ 17862306a36Sopenharmony_ci struct list_head info_list; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define SCSIBACK_INVALID_HANDLE (~0) 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic bool log_print_stat; 18462306a36Sopenharmony_cimodule_param(log_print_stat, bool, 0644); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int scsiback_max_buffer_pages = 1024; 18762306a36Sopenharmony_cimodule_param_named(max_buffer_pages, scsiback_max_buffer_pages, int, 0644); 18862306a36Sopenharmony_ciMODULE_PARM_DESC(max_buffer_pages, 18962306a36Sopenharmony_ci"Maximum number of free pages to keep in backend buffer"); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* Global spinlock to protect scsiback TPG list */ 19262306a36Sopenharmony_cistatic DEFINE_MUTEX(scsiback_mutex); 19362306a36Sopenharmony_cistatic LIST_HEAD(scsiback_list); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic void scsiback_get(struct vscsibk_info *info) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci atomic_inc(&info->nr_unreplied_reqs); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic void scsiback_put(struct vscsibk_info *info) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci if (atomic_dec_and_test(&info->nr_unreplied_reqs)) 20362306a36Sopenharmony_ci wake_up(&info->waiting_to_free); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic unsigned long vaddr_page(struct page *page) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned long pfn = page_to_pfn(page); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return (unsigned long)pfn_to_kaddr(pfn); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic unsigned long vaddr(struct vscsibk_pend *req, int seg) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return vaddr_page(req->pages[seg]); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void scsiback_print_status(char *sense_buffer, int errors, 21962306a36Sopenharmony_ci struct vscsibk_pend *pending_req) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct scsiback_tpg *tpg = pending_req->v2p->tpg; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x\n", 22462306a36Sopenharmony_ci tpg->tport->tport_name, pending_req->v2p->lun, 22562306a36Sopenharmony_ci pending_req->cmnd[0], errors & 0xff, COMMAND_COMPLETE, 22662306a36Sopenharmony_ci host_byte(errors)); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void scsiback_fast_flush_area(struct vscsibk_pend *req) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct gnttab_unmap_grant_ref unmap[VSCSI_GRANT_BATCH]; 23262306a36Sopenharmony_ci struct page *pages[VSCSI_GRANT_BATCH]; 23362306a36Sopenharmony_ci unsigned int i, invcount = 0; 23462306a36Sopenharmony_ci grant_handle_t handle; 23562306a36Sopenharmony_ci int err; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci kfree(req->sgl); 23862306a36Sopenharmony_ci req->sgl = NULL; 23962306a36Sopenharmony_ci req->n_sg = 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (!req->n_grants) 24262306a36Sopenharmony_ci return; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0; i < req->n_grants; i++) { 24562306a36Sopenharmony_ci handle = req->grant_handles[i]; 24662306a36Sopenharmony_ci if (handle == SCSIBACK_INVALID_HANDLE) 24762306a36Sopenharmony_ci continue; 24862306a36Sopenharmony_ci gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i), 24962306a36Sopenharmony_ci GNTMAP_host_map, handle); 25062306a36Sopenharmony_ci req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; 25162306a36Sopenharmony_ci pages[invcount] = req->pages[i]; 25262306a36Sopenharmony_ci put_page(pages[invcount]); 25362306a36Sopenharmony_ci invcount++; 25462306a36Sopenharmony_ci if (invcount < VSCSI_GRANT_BATCH) 25562306a36Sopenharmony_ci continue; 25662306a36Sopenharmony_ci err = gnttab_unmap_refs(unmap, NULL, pages, invcount); 25762306a36Sopenharmony_ci BUG_ON(err); 25862306a36Sopenharmony_ci invcount = 0; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (invcount) { 26262306a36Sopenharmony_ci err = gnttab_unmap_refs(unmap, NULL, pages, invcount); 26362306a36Sopenharmony_ci BUG_ON(err); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci gnttab_page_cache_put(&req->info->free_pages, req->pages, 26762306a36Sopenharmony_ci req->n_grants); 26862306a36Sopenharmony_ci req->n_grants = 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void scsiback_free_translation_entry(struct kref *kref) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct v2p_entry *entry = container_of(kref, struct v2p_entry, kref); 27462306a36Sopenharmony_ci struct scsiback_tpg *tpg = entry->tpg; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 27762306a36Sopenharmony_ci tpg->tv_tpg_fe_count--; 27862306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci kfree(entry); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int32_t scsiback_result(int32_t result) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci int32_t host_status; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci switch (XEN_VSCSIIF_RSLT_HOST(result)) { 28862306a36Sopenharmony_ci case DID_OK: 28962306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_OK; 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci case DID_NO_CONNECT: 29262306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_NO_CONNECT; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci case DID_BUS_BUSY: 29562306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_BUS_BUSY; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci case DID_TIME_OUT: 29862306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_TIME_OUT; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci case DID_BAD_TARGET: 30162306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_BAD_TARGET; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci case DID_ABORT: 30462306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_ABORT; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci case DID_PARITY: 30762306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_PARITY; 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case DID_ERROR: 31062306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_ERROR; 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci case DID_RESET: 31362306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_RESET; 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci case DID_BAD_INTR: 31662306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_BAD_INTR; 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci case DID_PASSTHROUGH: 31962306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH; 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci case DID_SOFT_ERROR: 32262306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case DID_IMM_RETRY: 32562306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_IMM_RETRY; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case DID_REQUEUE: 32862306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_REQUEUE; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case DID_TRANSPORT_DISRUPTED: 33162306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED; 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci case DID_TRANSPORT_FAILFAST: 33462306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST; 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci case DID_TRANSPORT_MARGINAL: 33762306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL; 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci default: 34062306a36Sopenharmony_ci host_status = XEN_VSCSIIF_RSLT_HOST_ERROR; 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return (host_status << 16) | (result & 0x00ffff); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void scsiback_send_response(struct vscsibk_info *info, 34862306a36Sopenharmony_ci char *sense_buffer, int32_t result, uint32_t resid, 34962306a36Sopenharmony_ci uint16_t rqid) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct vscsiif_response *ring_res; 35262306a36Sopenharmony_ci int notify; 35362306a36Sopenharmony_ci struct scsi_sense_hdr sshdr; 35462306a36Sopenharmony_ci unsigned long flags; 35562306a36Sopenharmony_ci unsigned len; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci spin_lock_irqsave(&info->ring_lock, flags); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt); 36062306a36Sopenharmony_ci info->ring.rsp_prod_pvt++; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ring_res->rslt = scsiback_result(result); 36362306a36Sopenharmony_ci ring_res->rqid = rqid; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (sense_buffer != NULL && 36662306a36Sopenharmony_ci scsi_normalize_sense(sense_buffer, VSCSIIF_SENSE_BUFFERSIZE, 36762306a36Sopenharmony_ci &sshdr)) { 36862306a36Sopenharmony_ci len = min_t(unsigned, 8 + sense_buffer[7], 36962306a36Sopenharmony_ci VSCSIIF_SENSE_BUFFERSIZE); 37062306a36Sopenharmony_ci memcpy(ring_res->sense_buffer, sense_buffer, len); 37162306a36Sopenharmony_ci ring_res->sense_len = len; 37262306a36Sopenharmony_ci } else { 37362306a36Sopenharmony_ci ring_res->sense_len = 0; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ring_res->residual_len = resid; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify); 37962306a36Sopenharmony_ci spin_unlock_irqrestore(&info->ring_lock, flags); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (notify) 38262306a36Sopenharmony_ci notify_remote_via_irq(info->irq); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result, 38662306a36Sopenharmony_ci uint32_t resid, struct vscsibk_pend *pending_req) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci scsiback_send_response(pending_req->info, sense_buffer, result, 38962306a36Sopenharmony_ci resid, pending_req->rqid); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (pending_req->v2p) 39262306a36Sopenharmony_ci kref_put(&pending_req->v2p->kref, 39362306a36Sopenharmony_ci scsiback_free_translation_entry); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic void scsiback_cmd_done(struct vscsibk_pend *pending_req) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct vscsibk_info *info = pending_req->info; 39962306a36Sopenharmony_ci unsigned char *sense_buffer; 40062306a36Sopenharmony_ci unsigned int resid; 40162306a36Sopenharmony_ci int errors; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci sense_buffer = pending_req->sense_buffer; 40462306a36Sopenharmony_ci resid = pending_req->se_cmd.residual_count; 40562306a36Sopenharmony_ci errors = pending_req->result; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (errors && log_print_stat) 40862306a36Sopenharmony_ci scsiback_print_status(sense_buffer, errors, pending_req); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci scsiback_fast_flush_area(pending_req); 41162306a36Sopenharmony_ci scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req); 41262306a36Sopenharmony_ci scsiback_put(info); 41362306a36Sopenharmony_ci /* 41462306a36Sopenharmony_ci * Drop the extra KREF_ACK reference taken by target_submit_cmd_map_sgls() 41562306a36Sopenharmony_ci * ahead of scsiback_check_stop_free() -> transport_generic_free_cmd() 41662306a36Sopenharmony_ci * final se_cmd->cmd_kref put. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci target_put_sess_cmd(&pending_req->se_cmd); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void scsiback_cmd_exec(struct vscsibk_pend *pending_req) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct se_cmd *se_cmd = &pending_req->se_cmd; 42462306a36Sopenharmony_ci struct se_session *sess = pending_req->v2p->tpg->tpg_nexus->tvn_se_sess; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci scsiback_get(pending_req->info); 42762306a36Sopenharmony_ci se_cmd->tag = pending_req->rqid; 42862306a36Sopenharmony_ci target_init_cmd(se_cmd, sess, pending_req->sense_buffer, 42962306a36Sopenharmony_ci pending_req->v2p->lun, pending_req->data_len, 0, 43062306a36Sopenharmony_ci pending_req->sc_data_direction, TARGET_SCF_ACK_KREF); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (target_submit_prep(se_cmd, pending_req->cmnd, pending_req->sgl, 43362306a36Sopenharmony_ci pending_req->n_sg, NULL, 0, NULL, 0, GFP_KERNEL)) 43462306a36Sopenharmony_ci return; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci target_submit(se_cmd); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, 44062306a36Sopenharmony_ci struct page **pg, grant_handle_t *grant, int cnt) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci int err, i; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!cnt) 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci err = gnttab_map_refs(map, NULL, pg, cnt); 44862306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 44962306a36Sopenharmony_ci if (unlikely(map[i].status != GNTST_okay)) { 45062306a36Sopenharmony_ci pr_err("invalid buffer -- could not remap it\n"); 45162306a36Sopenharmony_ci map[i].handle = SCSIBACK_INVALID_HANDLE; 45262306a36Sopenharmony_ci if (!err) 45362306a36Sopenharmony_ci err = -ENOMEM; 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci get_page(pg[i]); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci grant[i] = map[i].handle; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci return err; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req, 46362306a36Sopenharmony_ci struct scsiif_request_segment *seg, struct page **pg, 46462306a36Sopenharmony_ci grant_handle_t *grant, int cnt, u32 flags) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci int mapcount = 0, i, err = 0; 46762306a36Sopenharmony_ci struct gnttab_map_grant_ref map[VSCSI_GRANT_BATCH]; 46862306a36Sopenharmony_ci struct vscsibk_info *info = pending_req->info; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 47162306a36Sopenharmony_ci if (gnttab_page_cache_get(&info->free_pages, pg + mapcount)) { 47262306a36Sopenharmony_ci gnttab_page_cache_put(&info->free_pages, pg, mapcount); 47362306a36Sopenharmony_ci pr_err("no grant page\n"); 47462306a36Sopenharmony_ci return -ENOMEM; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), 47762306a36Sopenharmony_ci flags, seg[i].gref, info->domid); 47862306a36Sopenharmony_ci mapcount++; 47962306a36Sopenharmony_ci if (mapcount < VSCSI_GRANT_BATCH) 48062306a36Sopenharmony_ci continue; 48162306a36Sopenharmony_ci err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount); 48262306a36Sopenharmony_ci pg += mapcount; 48362306a36Sopenharmony_ci grant += mapcount; 48462306a36Sopenharmony_ci pending_req->n_grants += mapcount; 48562306a36Sopenharmony_ci if (err) 48662306a36Sopenharmony_ci return err; 48762306a36Sopenharmony_ci mapcount = 0; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount); 49062306a36Sopenharmony_ci pending_req->n_grants += mapcount; 49162306a36Sopenharmony_ci return err; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, 49562306a36Sopenharmony_ci struct vscsibk_pend *pending_req) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci u32 flags; 49862306a36Sopenharmony_ci int i, err, n_segs, i_seg = 0; 49962306a36Sopenharmony_ci struct page **pg; 50062306a36Sopenharmony_ci struct scsiif_request_segment *seg; 50162306a36Sopenharmony_ci unsigned long end_seg = 0; 50262306a36Sopenharmony_ci unsigned int nr_segments = (unsigned int)ring_req->nr_segments; 50362306a36Sopenharmony_ci unsigned int nr_sgl = 0; 50462306a36Sopenharmony_ci struct scatterlist *sg; 50562306a36Sopenharmony_ci grant_handle_t *grant; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci pending_req->n_sg = 0; 50862306a36Sopenharmony_ci pending_req->n_grants = 0; 50962306a36Sopenharmony_ci pending_req->data_len = 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci nr_segments &= ~VSCSIIF_SG_GRANT; 51262306a36Sopenharmony_ci if (!nr_segments) 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (nr_segments > VSCSIIF_SG_TABLESIZE) { 51662306a36Sopenharmony_ci pr_debug("invalid parameter nr_seg = %d\n", 51762306a36Sopenharmony_ci ring_req->nr_segments); 51862306a36Sopenharmony_ci return -EINVAL; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (ring_req->nr_segments & VSCSIIF_SG_GRANT) { 52262306a36Sopenharmony_ci err = scsiback_gnttab_data_map_list(pending_req, ring_req->seg, 52362306a36Sopenharmony_ci pending_req->pages, pending_req->grant_handles, 52462306a36Sopenharmony_ci nr_segments, GNTMAP_host_map | GNTMAP_readonly); 52562306a36Sopenharmony_ci if (err) 52662306a36Sopenharmony_ci return err; 52762306a36Sopenharmony_ci nr_sgl = nr_segments; 52862306a36Sopenharmony_ci nr_segments = 0; 52962306a36Sopenharmony_ci for (i = 0; i < nr_sgl; i++) { 53062306a36Sopenharmony_ci n_segs = ring_req->seg[i].length / 53162306a36Sopenharmony_ci sizeof(struct scsiif_request_segment); 53262306a36Sopenharmony_ci if ((unsigned)ring_req->seg[i].offset + 53362306a36Sopenharmony_ci (unsigned)ring_req->seg[i].length > PAGE_SIZE || 53462306a36Sopenharmony_ci n_segs * sizeof(struct scsiif_request_segment) != 53562306a36Sopenharmony_ci ring_req->seg[i].length) 53662306a36Sopenharmony_ci return -EINVAL; 53762306a36Sopenharmony_ci nr_segments += n_segs; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci if (nr_segments > SG_ALL) { 54062306a36Sopenharmony_ci pr_debug("invalid nr_seg = %d\n", nr_segments); 54162306a36Sopenharmony_ci return -EINVAL; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* free of (sgl) in fast_flush_area() */ 54662306a36Sopenharmony_ci pending_req->sgl = kmalloc_array(nr_segments, 54762306a36Sopenharmony_ci sizeof(struct scatterlist), GFP_KERNEL); 54862306a36Sopenharmony_ci if (!pending_req->sgl) 54962306a36Sopenharmony_ci return -ENOMEM; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci sg_init_table(pending_req->sgl, nr_segments); 55262306a36Sopenharmony_ci pending_req->n_sg = nr_segments; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci flags = GNTMAP_host_map; 55562306a36Sopenharmony_ci if (pending_req->sc_data_direction == DMA_TO_DEVICE) 55662306a36Sopenharmony_ci flags |= GNTMAP_readonly; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci pg = pending_req->pages + nr_sgl; 55962306a36Sopenharmony_ci grant = pending_req->grant_handles + nr_sgl; 56062306a36Sopenharmony_ci if (!nr_sgl) { 56162306a36Sopenharmony_ci seg = ring_req->seg; 56262306a36Sopenharmony_ci err = scsiback_gnttab_data_map_list(pending_req, seg, 56362306a36Sopenharmony_ci pg, grant, nr_segments, flags); 56462306a36Sopenharmony_ci if (err) 56562306a36Sopenharmony_ci return err; 56662306a36Sopenharmony_ci } else { 56762306a36Sopenharmony_ci for (i = 0; i < nr_sgl; i++) { 56862306a36Sopenharmony_ci seg = (struct scsiif_request_segment *)( 56962306a36Sopenharmony_ci vaddr(pending_req, i) + ring_req->seg[i].offset); 57062306a36Sopenharmony_ci n_segs = ring_req->seg[i].length / 57162306a36Sopenharmony_ci sizeof(struct scsiif_request_segment); 57262306a36Sopenharmony_ci err = scsiback_gnttab_data_map_list(pending_req, seg, 57362306a36Sopenharmony_ci pg, grant, n_segs, flags); 57462306a36Sopenharmony_ci if (err) 57562306a36Sopenharmony_ci return err; 57662306a36Sopenharmony_ci pg += n_segs; 57762306a36Sopenharmony_ci grant += n_segs; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci end_seg = vaddr(pending_req, 0) + ring_req->seg[0].offset; 58062306a36Sopenharmony_ci seg = (struct scsiif_request_segment *)end_seg; 58162306a36Sopenharmony_ci end_seg += ring_req->seg[0].length; 58262306a36Sopenharmony_ci pg = pending_req->pages + nr_sgl; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci for_each_sg(pending_req->sgl, sg, nr_segments, i) { 58662306a36Sopenharmony_ci sg_set_page(sg, pg[i], seg->length, seg->offset); 58762306a36Sopenharmony_ci pending_req->data_len += seg->length; 58862306a36Sopenharmony_ci seg++; 58962306a36Sopenharmony_ci if (nr_sgl && (unsigned long)seg >= end_seg) { 59062306a36Sopenharmony_ci i_seg++; 59162306a36Sopenharmony_ci end_seg = vaddr(pending_req, i_seg) + 59262306a36Sopenharmony_ci ring_req->seg[i_seg].offset; 59362306a36Sopenharmony_ci seg = (struct scsiif_request_segment *)end_seg; 59462306a36Sopenharmony_ci end_seg += ring_req->seg[i_seg].length; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci if (sg->offset >= PAGE_SIZE || 59762306a36Sopenharmony_ci sg->length > PAGE_SIZE || 59862306a36Sopenharmony_ci sg->offset + sg->length > PAGE_SIZE) 59962306a36Sopenharmony_ci return -EINVAL; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void scsiback_disconnect(struct vscsibk_info *info) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci wait_event(info->waiting_to_free, 60862306a36Sopenharmony_ci atomic_read(&info->nr_unreplied_reqs) == 0); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci unbind_from_irqhandler(info->irq, info); 61162306a36Sopenharmony_ci info->irq = 0; 61262306a36Sopenharmony_ci xenbus_unmap_ring_vfree(info->dev, info->ring.sring); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic void scsiback_device_action(struct vscsibk_pend *pending_req, 61662306a36Sopenharmony_ci enum tcm_tmreq_table act, int tag) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct scsiback_tpg *tpg = pending_req->v2p->tpg; 61962306a36Sopenharmony_ci struct scsiback_nexus *nexus = tpg->tpg_nexus; 62062306a36Sopenharmony_ci struct se_cmd *se_cmd = &pending_req->se_cmd; 62162306a36Sopenharmony_ci u64 unpacked_lun = pending_req->v2p->lun; 62262306a36Sopenharmony_ci int rc, err = XEN_VSCSIIF_RSLT_RESET_FAILED; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci init_completion(&pending_req->tmr_done); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci rc = target_submit_tmr(&pending_req->se_cmd, nexus->tvn_se_sess, 62762306a36Sopenharmony_ci &pending_req->sense_buffer[0], 62862306a36Sopenharmony_ci unpacked_lun, NULL, act, GFP_KERNEL, 62962306a36Sopenharmony_ci tag, TARGET_SCF_ACK_KREF); 63062306a36Sopenharmony_ci if (rc) 63162306a36Sopenharmony_ci goto err; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci wait_for_completion(&pending_req->tmr_done); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? 63662306a36Sopenharmony_ci XEN_VSCSIIF_RSLT_RESET_SUCCESS : XEN_VSCSIIF_RSLT_RESET_FAILED; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci scsiback_do_resp_with_sense(NULL, err, 0, pending_req); 63962306a36Sopenharmony_ci transport_generic_free_cmd(&pending_req->se_cmd, 0); 64062306a36Sopenharmony_ci return; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cierr: 64362306a36Sopenharmony_ci scsiback_do_resp_with_sense(NULL, err, 0, pending_req); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/* 64762306a36Sopenharmony_ci Perform virtual to physical translation 64862306a36Sopenharmony_ci*/ 64962306a36Sopenharmony_cistatic struct v2p_entry *scsiback_do_translation(struct vscsibk_info *info, 65062306a36Sopenharmony_ci struct ids_tuple *v) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct v2p_entry *entry; 65362306a36Sopenharmony_ci struct list_head *head = &(info->v2p_entry_lists); 65462306a36Sopenharmony_ci unsigned long flags; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 65762306a36Sopenharmony_ci list_for_each_entry(entry, head, l) { 65862306a36Sopenharmony_ci if ((entry->v.chn == v->chn) && 65962306a36Sopenharmony_ci (entry->v.tgt == v->tgt) && 66062306a36Sopenharmony_ci (entry->v.lun == v->lun)) { 66162306a36Sopenharmony_ci kref_get(&entry->kref); 66262306a36Sopenharmony_ci goto out; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci entry = NULL; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ciout: 66862306a36Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 66962306a36Sopenharmony_ci return entry; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring, 67362306a36Sopenharmony_ci struct v2p_entry *v2p) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct scsiback_tpg *tpg = v2p->tpg; 67662306a36Sopenharmony_ci struct scsiback_nexus *nexus = tpg->tpg_nexus; 67762306a36Sopenharmony_ci struct se_session *se_sess = nexus->tvn_se_sess; 67862306a36Sopenharmony_ci struct vscsibk_pend *req; 67962306a36Sopenharmony_ci int tag, cpu, i; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); 68262306a36Sopenharmony_ci if (tag < 0) { 68362306a36Sopenharmony_ci pr_err("Unable to obtain tag for vscsiif_request\n"); 68462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci req = &((struct vscsibk_pend *)se_sess->sess_cmd_map)[tag]; 68862306a36Sopenharmony_ci memset(req, 0, sizeof(*req)); 68962306a36Sopenharmony_ci req->se_cmd.map_tag = tag; 69062306a36Sopenharmony_ci req->se_cmd.map_cpu = cpu; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci for (i = 0; i < VSCSI_MAX_GRANTS; i++) 69362306a36Sopenharmony_ci req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return req; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic struct vscsibk_pend *prepare_pending_reqs(struct vscsibk_info *info, 69962306a36Sopenharmony_ci struct vscsiif_back_ring *ring, 70062306a36Sopenharmony_ci struct vscsiif_request *ring_req) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct vscsibk_pend *pending_req; 70362306a36Sopenharmony_ci struct v2p_entry *v2p; 70462306a36Sopenharmony_ci struct ids_tuple vir; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* request range check from frontend */ 70762306a36Sopenharmony_ci if ((ring_req->sc_data_direction != DMA_BIDIRECTIONAL) && 70862306a36Sopenharmony_ci (ring_req->sc_data_direction != DMA_TO_DEVICE) && 70962306a36Sopenharmony_ci (ring_req->sc_data_direction != DMA_FROM_DEVICE) && 71062306a36Sopenharmony_ci (ring_req->sc_data_direction != DMA_NONE)) { 71162306a36Sopenharmony_ci pr_debug("invalid parameter data_dir = %d\n", 71262306a36Sopenharmony_ci ring_req->sc_data_direction); 71362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci if (ring_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { 71662306a36Sopenharmony_ci pr_debug("invalid parameter cmd_len = %d\n", 71762306a36Sopenharmony_ci ring_req->cmd_len); 71862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci vir.chn = ring_req->channel; 72262306a36Sopenharmony_ci vir.tgt = ring_req->id; 72362306a36Sopenharmony_ci vir.lun = ring_req->lun; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci v2p = scsiback_do_translation(info, &vir); 72662306a36Sopenharmony_ci if (!v2p) { 72762306a36Sopenharmony_ci pr_debug("the v2p of (chn:%d, tgt:%d, lun:%d) doesn't exist.\n", 72862306a36Sopenharmony_ci vir.chn, vir.tgt, vir.lun); 72962306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci pending_req = scsiback_get_pend_req(ring, v2p); 73362306a36Sopenharmony_ci if (IS_ERR(pending_req)) { 73462306a36Sopenharmony_ci kref_put(&v2p->kref, scsiback_free_translation_entry); 73562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci pending_req->rqid = ring_req->rqid; 73862306a36Sopenharmony_ci pending_req->info = info; 73962306a36Sopenharmony_ci pending_req->v2p = v2p; 74062306a36Sopenharmony_ci pending_req->sc_data_direction = ring_req->sc_data_direction; 74162306a36Sopenharmony_ci pending_req->cmd_len = ring_req->cmd_len; 74262306a36Sopenharmony_ci memcpy(pending_req->cmnd, ring_req->cmnd, pending_req->cmd_len); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return pending_req; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int scsiback_do_cmd_fn(struct vscsibk_info *info, 74862306a36Sopenharmony_ci unsigned int *eoi_flags) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct vscsiif_back_ring *ring = &info->ring; 75162306a36Sopenharmony_ci struct vscsiif_request ring_req; 75262306a36Sopenharmony_ci struct vscsibk_pend *pending_req; 75362306a36Sopenharmony_ci RING_IDX rc, rp; 75462306a36Sopenharmony_ci int more_to_do; 75562306a36Sopenharmony_ci uint32_t result; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci rc = ring->req_cons; 75862306a36Sopenharmony_ci rp = ring->sring->req_prod; 75962306a36Sopenharmony_ci rmb(); /* guest system is accessing ring, too */ 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { 76262306a36Sopenharmony_ci rc = ring->rsp_prod_pvt; 76362306a36Sopenharmony_ci pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", 76462306a36Sopenharmony_ci info->domid, rp, rc, rp - rc); 76562306a36Sopenharmony_ci return -EINVAL; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci while ((rc != rp)) { 76962306a36Sopenharmony_ci *eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (RING_REQUEST_CONS_OVERFLOW(ring, rc)) 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci RING_COPY_REQUEST(ring, rc, &ring_req); 77562306a36Sopenharmony_ci ring->req_cons = ++rc; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci pending_req = prepare_pending_reqs(info, ring, &ring_req); 77862306a36Sopenharmony_ci if (IS_ERR(pending_req)) { 77962306a36Sopenharmony_ci switch (PTR_ERR(pending_req)) { 78062306a36Sopenharmony_ci case -ENODEV: 78162306a36Sopenharmony_ci result = DID_NO_CONNECT; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci default: 78462306a36Sopenharmony_ci result = DID_ERROR; 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci scsiback_send_response(info, NULL, result << 16, 0, 78862306a36Sopenharmony_ci ring_req.rqid); 78962306a36Sopenharmony_ci return 1; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci switch (ring_req.act) { 79362306a36Sopenharmony_ci case VSCSIIF_ACT_SCSI_CDB: 79462306a36Sopenharmony_ci if (scsiback_gnttab_data_map(&ring_req, pending_req)) { 79562306a36Sopenharmony_ci scsiback_fast_flush_area(pending_req); 79662306a36Sopenharmony_ci scsiback_do_resp_with_sense(NULL, 79762306a36Sopenharmony_ci DID_ERROR << 16, 0, pending_req); 79862306a36Sopenharmony_ci transport_generic_free_cmd(&pending_req->se_cmd, 0); 79962306a36Sopenharmony_ci } else { 80062306a36Sopenharmony_ci scsiback_cmd_exec(pending_req); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci case VSCSIIF_ACT_SCSI_ABORT: 80462306a36Sopenharmony_ci scsiback_device_action(pending_req, TMR_ABORT_TASK, 80562306a36Sopenharmony_ci ring_req.ref_rqid); 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci case VSCSIIF_ACT_SCSI_RESET: 80862306a36Sopenharmony_ci scsiback_device_action(pending_req, TMR_LUN_RESET, 0); 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci default: 81162306a36Sopenharmony_ci pr_err_ratelimited("invalid request\n"); 81262306a36Sopenharmony_ci scsiback_do_resp_with_sense(NULL, DID_ERROR << 16, 0, 81362306a36Sopenharmony_ci pending_req); 81462306a36Sopenharmony_ci transport_generic_free_cmd(&pending_req->se_cmd, 0); 81562306a36Sopenharmony_ci break; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* Yield point for this unbounded loop. */ 81962306a36Sopenharmony_ci cond_resched(); 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci gnttab_page_cache_shrink(&info->free_pages, scsiback_max_buffer_pages); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do); 82562306a36Sopenharmony_ci return more_to_do; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic irqreturn_t scsiback_irq_fn(int irq, void *dev_id) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct vscsibk_info *info = dev_id; 83162306a36Sopenharmony_ci int rc; 83262306a36Sopenharmony_ci unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci while ((rc = scsiback_do_cmd_fn(info, &eoi_flags)) > 0) 83562306a36Sopenharmony_ci cond_resched(); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* In case of a ring error we keep the event channel masked. */ 83862306a36Sopenharmony_ci if (!rc) 83962306a36Sopenharmony_ci xen_irq_lateeoi(irq, eoi_flags); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return IRQ_HANDLED; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref, 84562306a36Sopenharmony_ci evtchn_port_t evtchn) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci void *area; 84862306a36Sopenharmony_ci struct vscsiif_sring *sring; 84962306a36Sopenharmony_ci int err; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (info->irq) 85262306a36Sopenharmony_ci return -1; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci err = xenbus_map_ring_valloc(info->dev, &ring_ref, 1, &area); 85562306a36Sopenharmony_ci if (err) 85662306a36Sopenharmony_ci return err; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci sring = (struct vscsiif_sring *)area; 85962306a36Sopenharmony_ci BACK_RING_INIT(&info->ring, sring, PAGE_SIZE); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci err = bind_interdomain_evtchn_to_irq_lateeoi(info->dev, evtchn); 86262306a36Sopenharmony_ci if (err < 0) 86362306a36Sopenharmony_ci goto unmap_page; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci info->irq = err; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci err = request_threaded_irq(info->irq, NULL, scsiback_irq_fn, 86862306a36Sopenharmony_ci IRQF_ONESHOT, "vscsiif-backend", info); 86962306a36Sopenharmony_ci if (err) 87062306a36Sopenharmony_ci goto free_irq; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cifree_irq: 87562306a36Sopenharmony_ci unbind_from_irqhandler(info->irq, info); 87662306a36Sopenharmony_ci info->irq = 0; 87762306a36Sopenharmony_ciunmap_page: 87862306a36Sopenharmony_ci xenbus_unmap_ring_vfree(info->dev, area); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return err; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic int scsiback_map(struct vscsibk_info *info) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct xenbus_device *dev = info->dev; 88662306a36Sopenharmony_ci unsigned int ring_ref; 88762306a36Sopenharmony_ci evtchn_port_t evtchn; 88862306a36Sopenharmony_ci int err; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci err = xenbus_gather(XBT_NIL, dev->otherend, 89162306a36Sopenharmony_ci "ring-ref", "%u", &ring_ref, 89262306a36Sopenharmony_ci "event-channel", "%u", &evtchn, NULL); 89362306a36Sopenharmony_ci if (err) { 89462306a36Sopenharmony_ci xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend); 89562306a36Sopenharmony_ci return err; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return scsiback_init_sring(info, ring_ref, evtchn); 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci/* 90262306a36Sopenharmony_ci Check for a translation entry being present 90362306a36Sopenharmony_ci*/ 90462306a36Sopenharmony_cistatic struct v2p_entry *scsiback_chk_translation_entry( 90562306a36Sopenharmony_ci struct vscsibk_info *info, struct ids_tuple *v) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct list_head *head = &(info->v2p_entry_lists); 90862306a36Sopenharmony_ci struct v2p_entry *entry; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci list_for_each_entry(entry, head, l) 91162306a36Sopenharmony_ci if ((entry->v.chn == v->chn) && 91262306a36Sopenharmony_ci (entry->v.tgt == v->tgt) && 91362306a36Sopenharmony_ci (entry->v.lun == v->lun)) 91462306a36Sopenharmony_ci return entry; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return NULL; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci/* 92062306a36Sopenharmony_ci Add a new translation entry 92162306a36Sopenharmony_ci*/ 92262306a36Sopenharmony_cistatic int scsiback_add_translation_entry(struct vscsibk_info *info, 92362306a36Sopenharmony_ci char *phy, struct ids_tuple *v) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci int err = 0; 92662306a36Sopenharmony_ci struct v2p_entry *new; 92762306a36Sopenharmony_ci unsigned long flags; 92862306a36Sopenharmony_ci char *lunp; 92962306a36Sopenharmony_ci unsigned long long unpacked_lun; 93062306a36Sopenharmony_ci struct se_lun *se_lun; 93162306a36Sopenharmony_ci struct scsiback_tpg *tpg_entry, *tpg = NULL; 93262306a36Sopenharmony_ci char *error = "doesn't exist"; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci lunp = strrchr(phy, ':'); 93562306a36Sopenharmony_ci if (!lunp) { 93662306a36Sopenharmony_ci pr_err("illegal format of physical device %s\n", phy); 93762306a36Sopenharmony_ci return -EINVAL; 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci *lunp = 0; 94062306a36Sopenharmony_ci lunp++; 94162306a36Sopenharmony_ci err = kstrtoull(lunp, 10, &unpacked_lun); 94262306a36Sopenharmony_ci if (err < 0) { 94362306a36Sopenharmony_ci pr_err("lun number not valid: %s\n", lunp); 94462306a36Sopenharmony_ci return err; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci mutex_lock(&scsiback_mutex); 94862306a36Sopenharmony_ci list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) { 94962306a36Sopenharmony_ci if (!strcmp(phy, tpg_entry->tport->tport_name) || 95062306a36Sopenharmony_ci !strcmp(phy, tpg_entry->param_alias)) { 95162306a36Sopenharmony_ci mutex_lock(&tpg_entry->se_tpg.tpg_lun_mutex); 95262306a36Sopenharmony_ci hlist_for_each_entry(se_lun, &tpg_entry->se_tpg.tpg_lun_hlist, link) { 95362306a36Sopenharmony_ci if (se_lun->unpacked_lun == unpacked_lun) { 95462306a36Sopenharmony_ci if (!tpg_entry->tpg_nexus) 95562306a36Sopenharmony_ci error = "nexus undefined"; 95662306a36Sopenharmony_ci else 95762306a36Sopenharmony_ci tpg = tpg_entry; 95862306a36Sopenharmony_ci break; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci mutex_unlock(&tpg_entry->se_tpg.tpg_lun_mutex); 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci if (tpg) { 96662306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 96762306a36Sopenharmony_ci tpg->tv_tpg_fe_count++; 96862306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci mutex_unlock(&scsiback_mutex); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (!tpg) { 97362306a36Sopenharmony_ci pr_err("%s:%llu %s\n", phy, unpacked_lun, error); 97462306a36Sopenharmony_ci return -ENODEV; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL); 97862306a36Sopenharmony_ci if (new == NULL) { 97962306a36Sopenharmony_ci err = -ENOMEM; 98062306a36Sopenharmony_ci goto out_free; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Check double assignment to identical virtual ID */ 98662306a36Sopenharmony_ci if (scsiback_chk_translation_entry(info, v)) { 98762306a36Sopenharmony_ci pr_warn("Virtual ID is already used. Assignment was not performed.\n"); 98862306a36Sopenharmony_ci err = -EEXIST; 98962306a36Sopenharmony_ci goto out; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* Create a new translation entry and add to the list */ 99362306a36Sopenharmony_ci kref_init(&new->kref); 99462306a36Sopenharmony_ci new->v = *v; 99562306a36Sopenharmony_ci new->tpg = tpg; 99662306a36Sopenharmony_ci new->lun = unpacked_lun; 99762306a36Sopenharmony_ci list_add_tail(&new->l, &info->v2p_entry_lists); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ciout: 100062306a36Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ciout_free: 100362306a36Sopenharmony_ci if (err) { 100462306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 100562306a36Sopenharmony_ci tpg->tv_tpg_fe_count--; 100662306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 100762306a36Sopenharmony_ci kfree(new); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return err; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci/* 101462306a36Sopenharmony_ci Delete the translation entry specified 101562306a36Sopenharmony_ci*/ 101662306a36Sopenharmony_cistatic int scsiback_del_translation_entry(struct vscsibk_info *info, 101762306a36Sopenharmony_ci struct ids_tuple *v) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct v2p_entry *entry; 102062306a36Sopenharmony_ci unsigned long flags; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 102362306a36Sopenharmony_ci /* Find out the translation entry specified */ 102462306a36Sopenharmony_ci entry = scsiback_chk_translation_entry(info, v); 102562306a36Sopenharmony_ci if (entry) 102662306a36Sopenharmony_ci list_del(&entry->l); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (!entry) 103162306a36Sopenharmony_ci return -ENOENT; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci kref_put(&entry->kref, scsiback_free_translation_entry); 103462306a36Sopenharmony_ci return 0; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, 103862306a36Sopenharmony_ci char *phy, struct ids_tuple *vir, int try) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct v2p_entry *entry; 104162306a36Sopenharmony_ci unsigned long flags; 104262306a36Sopenharmony_ci int err; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (try) { 104562306a36Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 104662306a36Sopenharmony_ci entry = scsiback_chk_translation_entry(info, vir); 104762306a36Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 104862306a36Sopenharmony_ci if (entry) 104962306a36Sopenharmony_ci return; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci if (!scsiback_add_translation_entry(info, phy, vir)) { 105262306a36Sopenharmony_ci if (xenbus_printf(XBT_NIL, info->dev->nodename, state, 105362306a36Sopenharmony_ci "%d", XenbusStateInitialised)) { 105462306a36Sopenharmony_ci pr_err("xenbus_printf error %s\n", state); 105562306a36Sopenharmony_ci scsiback_del_translation_entry(info, vir); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci } else if (!try) { 105862306a36Sopenharmony_ci err = xenbus_printf(XBT_NIL, info->dev->nodename, state, 105962306a36Sopenharmony_ci "%d", XenbusStateClosed); 106062306a36Sopenharmony_ci if (err) 106162306a36Sopenharmony_ci xenbus_dev_error(info->dev, err, 106262306a36Sopenharmony_ci "%s: writing %s", __func__, state); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic void scsiback_do_del_lun(struct vscsibk_info *info, const char *state, 106762306a36Sopenharmony_ci struct ids_tuple *vir) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci if (!scsiback_del_translation_entry(info, vir)) { 107062306a36Sopenharmony_ci if (xenbus_printf(XBT_NIL, info->dev->nodename, state, 107162306a36Sopenharmony_ci "%d", XenbusStateClosed)) 107262306a36Sopenharmony_ci pr_err("xenbus_printf error %s\n", state); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci#define VSCSIBACK_OP_ADD_OR_DEL_LUN 1 107762306a36Sopenharmony_ci#define VSCSIBACK_OP_UPDATEDEV_STATE 2 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, 108062306a36Sopenharmony_ci char *ent) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci int err; 108362306a36Sopenharmony_ci struct ids_tuple vir; 108462306a36Sopenharmony_ci char *val; 108562306a36Sopenharmony_ci int device_state; 108662306a36Sopenharmony_ci char phy[VSCSI_NAMELEN]; 108762306a36Sopenharmony_ci char str[64]; 108862306a36Sopenharmony_ci char state[64]; 108962306a36Sopenharmony_ci struct xenbus_device *dev = info->dev; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* read status */ 109262306a36Sopenharmony_ci snprintf(state, sizeof(state), "vscsi-devs/%s/state", ent); 109362306a36Sopenharmony_ci err = xenbus_scanf(XBT_NIL, dev->nodename, state, "%u", &device_state); 109462306a36Sopenharmony_ci if (XENBUS_EXIST_ERR(err)) 109562306a36Sopenharmony_ci return; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* physical SCSI device */ 109862306a36Sopenharmony_ci snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent); 109962306a36Sopenharmony_ci val = xenbus_read(XBT_NIL, dev->nodename, str, NULL); 110062306a36Sopenharmony_ci if (IS_ERR(val)) { 110162306a36Sopenharmony_ci err = xenbus_printf(XBT_NIL, dev->nodename, state, 110262306a36Sopenharmony_ci "%d", XenbusStateClosed); 110362306a36Sopenharmony_ci if (err) 110462306a36Sopenharmony_ci xenbus_dev_error(info->dev, err, 110562306a36Sopenharmony_ci "%s: writing %s", __func__, state); 110662306a36Sopenharmony_ci return; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci strscpy(phy, val, VSCSI_NAMELEN); 110962306a36Sopenharmony_ci kfree(val); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* virtual SCSI device */ 111262306a36Sopenharmony_ci snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", ent); 111362306a36Sopenharmony_ci err = xenbus_scanf(XBT_NIL, dev->nodename, str, "%u:%u:%u:%u", 111462306a36Sopenharmony_ci &vir.hst, &vir.chn, &vir.tgt, &vir.lun); 111562306a36Sopenharmony_ci if (XENBUS_EXIST_ERR(err)) { 111662306a36Sopenharmony_ci err = xenbus_printf(XBT_NIL, dev->nodename, state, 111762306a36Sopenharmony_ci "%d", XenbusStateClosed); 111862306a36Sopenharmony_ci if (err) 111962306a36Sopenharmony_ci xenbus_dev_error(info->dev, err, 112062306a36Sopenharmony_ci "%s: writing %s", __func__, state); 112162306a36Sopenharmony_ci return; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci switch (op) { 112562306a36Sopenharmony_ci case VSCSIBACK_OP_ADD_OR_DEL_LUN: 112662306a36Sopenharmony_ci switch (device_state) { 112762306a36Sopenharmony_ci case XenbusStateInitialising: 112862306a36Sopenharmony_ci scsiback_do_add_lun(info, state, phy, &vir, 0); 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case XenbusStateConnected: 113162306a36Sopenharmony_ci scsiback_do_add_lun(info, state, phy, &vir, 1); 113262306a36Sopenharmony_ci break; 113362306a36Sopenharmony_ci case XenbusStateClosing: 113462306a36Sopenharmony_ci scsiback_do_del_lun(info, state, &vir); 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci default: 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci case VSCSIBACK_OP_UPDATEDEV_STATE: 114262306a36Sopenharmony_ci if (device_state == XenbusStateInitialised) { 114362306a36Sopenharmony_ci /* modify vscsi-devs/dev-x/state */ 114462306a36Sopenharmony_ci if (xenbus_printf(XBT_NIL, dev->nodename, state, 114562306a36Sopenharmony_ci "%d", XenbusStateConnected)) { 114662306a36Sopenharmony_ci pr_err("xenbus_printf error %s\n", str); 114762306a36Sopenharmony_ci scsiback_del_translation_entry(info, &vir); 114862306a36Sopenharmony_ci xenbus_printf(XBT_NIL, dev->nodename, state, 114962306a36Sopenharmony_ci "%d", XenbusStateClosed); 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci /* When it is necessary, processing is added here. */ 115462306a36Sopenharmony_ci default: 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic void scsiback_do_lun_hotplug(struct vscsibk_info *info, int op) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci int i; 116262306a36Sopenharmony_ci char **dir; 116362306a36Sopenharmony_ci unsigned int ndir = 0; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci dir = xenbus_directory(XBT_NIL, info->dev->nodename, "vscsi-devs", 116662306a36Sopenharmony_ci &ndir); 116762306a36Sopenharmony_ci if (IS_ERR(dir)) 116862306a36Sopenharmony_ci return; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci for (i = 0; i < ndir; i++) 117162306a36Sopenharmony_ci scsiback_do_1lun_hotplug(info, op, dir[i]); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci kfree(dir); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic void scsiback_frontend_changed(struct xenbus_device *dev, 117762306a36Sopenharmony_ci enum xenbus_state frontend_state) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct vscsibk_info *info = dev_get_drvdata(&dev->dev); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci switch (frontend_state) { 118262306a36Sopenharmony_ci case XenbusStateInitialising: 118362306a36Sopenharmony_ci break; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci case XenbusStateInitialised: 118662306a36Sopenharmony_ci if (scsiback_map(info)) 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN); 119062306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateConnected); 119162306a36Sopenharmony_ci break; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci case XenbusStateConnected: 119462306a36Sopenharmony_ci scsiback_do_lun_hotplug(info, VSCSIBACK_OP_UPDATEDEV_STATE); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (dev->state == XenbusStateConnected) 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateConnected); 120062306a36Sopenharmony_ci break; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci case XenbusStateClosing: 120362306a36Sopenharmony_ci if (info->irq) 120462306a36Sopenharmony_ci scsiback_disconnect(info); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateClosing); 120762306a36Sopenharmony_ci break; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci case XenbusStateClosed: 121062306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateClosed); 121162306a36Sopenharmony_ci if (xenbus_dev_is_online(dev)) 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci fallthrough; /* if not online */ 121462306a36Sopenharmony_ci case XenbusStateUnknown: 121562306a36Sopenharmony_ci device_unregister(&dev->dev); 121662306a36Sopenharmony_ci break; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci case XenbusStateReconfiguring: 121962306a36Sopenharmony_ci scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN); 122062306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateReconfigured); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci default: 122562306a36Sopenharmony_ci xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", 122662306a36Sopenharmony_ci frontend_state); 122762306a36Sopenharmony_ci break; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/* 123262306a36Sopenharmony_ci Release the translation entry specfied 123362306a36Sopenharmony_ci*/ 123462306a36Sopenharmony_cistatic void scsiback_release_translation_entry(struct vscsibk_info *info) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci struct v2p_entry *entry, *tmp; 123762306a36Sopenharmony_ci struct list_head *head = &(info->v2p_entry_lists); 123862306a36Sopenharmony_ci struct list_head tmp_list; 123962306a36Sopenharmony_ci unsigned long flags; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci spin_lock_irqsave(&info->v2p_lock, flags); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci list_cut_before(&tmp_list, head, head); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci spin_unlock_irqrestore(&info->v2p_lock, flags); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &tmp_list, l) { 124862306a36Sopenharmony_ci list_del(&entry->l); 124962306a36Sopenharmony_ci kref_put(&entry->kref, scsiback_free_translation_entry); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic void scsiback_remove(struct xenbus_device *dev) 125462306a36Sopenharmony_ci{ 125562306a36Sopenharmony_ci struct vscsibk_info *info = dev_get_drvdata(&dev->dev); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (info->irq) 125862306a36Sopenharmony_ci scsiback_disconnect(info); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci scsiback_release_translation_entry(info); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci gnttab_page_cache_shrink(&info->free_pages, 0); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, NULL); 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_cistatic int scsiback_probe(struct xenbus_device *dev, 126862306a36Sopenharmony_ci const struct xenbus_device_id *id) 126962306a36Sopenharmony_ci{ 127062306a36Sopenharmony_ci int err; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), 127362306a36Sopenharmony_ci GFP_KERNEL); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci if (!info) { 127862306a36Sopenharmony_ci xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); 127962306a36Sopenharmony_ci return -ENOMEM; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci info->dev = dev; 128262306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, info); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci info->domid = dev->otherend_id; 128562306a36Sopenharmony_ci spin_lock_init(&info->ring_lock); 128662306a36Sopenharmony_ci atomic_set(&info->nr_unreplied_reqs, 0); 128762306a36Sopenharmony_ci init_waitqueue_head(&info->waiting_to_free); 128862306a36Sopenharmony_ci info->dev = dev; 128962306a36Sopenharmony_ci info->irq = 0; 129062306a36Sopenharmony_ci INIT_LIST_HEAD(&info->v2p_entry_lists); 129162306a36Sopenharmony_ci spin_lock_init(&info->v2p_lock); 129262306a36Sopenharmony_ci gnttab_page_cache_init(&info->free_pages); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci err = xenbus_printf(XBT_NIL, dev->nodename, "feature-sg-grant", "%u", 129562306a36Sopenharmony_ci SG_ALL); 129662306a36Sopenharmony_ci if (err) 129762306a36Sopenharmony_ci xenbus_dev_error(dev, err, "writing feature-sg-grant"); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci err = xenbus_switch_state(dev, XenbusStateInitWait); 130062306a36Sopenharmony_ci if (err) 130162306a36Sopenharmony_ci goto fail; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci return 0; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cifail: 130662306a36Sopenharmony_ci pr_warn("%s failed\n", __func__); 130762306a36Sopenharmony_ci scsiback_remove(dev); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci return err; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic char *scsiback_dump_proto_id(struct scsiback_tport *tport) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci switch (tport->tport_proto_id) { 131562306a36Sopenharmony_ci case SCSI_PROTOCOL_SAS: 131662306a36Sopenharmony_ci return "SAS"; 131762306a36Sopenharmony_ci case SCSI_PROTOCOL_FCP: 131862306a36Sopenharmony_ci return "FCP"; 131962306a36Sopenharmony_ci case SCSI_PROTOCOL_ISCSI: 132062306a36Sopenharmony_ci return "iSCSI"; 132162306a36Sopenharmony_ci default: 132262306a36Sopenharmony_ci break; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return "Unknown"; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic char *scsiback_get_fabric_wwn(struct se_portal_group *se_tpg) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 133162306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 133262306a36Sopenharmony_ci struct scsiback_tport *tport = tpg->tport; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci return &tport->tport_name[0]; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic u16 scsiback_get_tag(struct se_portal_group *se_tpg) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 134062306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 134162306a36Sopenharmony_ci return tpg->tport_tpgt; 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic struct se_wwn * 134562306a36Sopenharmony_ciscsiback_make_tport(struct target_fabric_configfs *tf, 134662306a36Sopenharmony_ci struct config_group *group, 134762306a36Sopenharmony_ci const char *name) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct scsiback_tport *tport; 135062306a36Sopenharmony_ci char *ptr; 135162306a36Sopenharmony_ci u64 wwpn = 0; 135262306a36Sopenharmony_ci int off = 0; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci tport = kzalloc(sizeof(struct scsiback_tport), GFP_KERNEL); 135562306a36Sopenharmony_ci if (!tport) 135662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci tport->tport_wwpn = wwpn; 135962306a36Sopenharmony_ci /* 136062306a36Sopenharmony_ci * Determine the emulated Protocol Identifier and Target Port Name 136162306a36Sopenharmony_ci * based on the incoming configfs directory name. 136262306a36Sopenharmony_ci */ 136362306a36Sopenharmony_ci ptr = strstr(name, "naa."); 136462306a36Sopenharmony_ci if (ptr) { 136562306a36Sopenharmony_ci tport->tport_proto_id = SCSI_PROTOCOL_SAS; 136662306a36Sopenharmony_ci goto check_len; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci ptr = strstr(name, "fc."); 136962306a36Sopenharmony_ci if (ptr) { 137062306a36Sopenharmony_ci tport->tport_proto_id = SCSI_PROTOCOL_FCP; 137162306a36Sopenharmony_ci off = 3; /* Skip over "fc." */ 137262306a36Sopenharmony_ci goto check_len; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci ptr = strstr(name, "iqn."); 137562306a36Sopenharmony_ci if (ptr) { 137662306a36Sopenharmony_ci tport->tport_proto_id = SCSI_PROTOCOL_ISCSI; 137762306a36Sopenharmony_ci goto check_len; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci pr_err("Unable to locate prefix for emulated Target Port: %s\n", name); 138162306a36Sopenharmony_ci kfree(tport); 138262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cicheck_len: 138562306a36Sopenharmony_ci if (strlen(name) >= VSCSI_NAMELEN) { 138662306a36Sopenharmony_ci pr_err("Emulated %s Address: %s, exceeds max: %d\n", name, 138762306a36Sopenharmony_ci scsiback_dump_proto_id(tport), VSCSI_NAMELEN); 138862306a36Sopenharmony_ci kfree(tport); 138962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci pr_debug("Allocated emulated Target %s Address: %s\n", 139462306a36Sopenharmony_ci scsiback_dump_proto_id(tport), name); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci return &tport->tport_wwn; 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic void scsiback_drop_tport(struct se_wwn *wwn) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci struct scsiback_tport *tport = container_of(wwn, 140262306a36Sopenharmony_ci struct scsiback_tport, tport_wwn); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci pr_debug("Deallocating emulated Target %s Address: %s\n", 140562306a36Sopenharmony_ci scsiback_dump_proto_id(tport), tport->tport_name); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci kfree(tport); 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_cistatic int scsiback_check_stop_free(struct se_cmd *se_cmd) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci return transport_generic_free_cmd(se_cmd, 0); 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic void scsiback_release_cmd(struct se_cmd *se_cmd) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci target_free_tag(se_cmd->se_sess, se_cmd); 141862306a36Sopenharmony_ci} 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cistatic int scsiback_write_pending(struct se_cmd *se_cmd) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci /* Go ahead and process the write immediately */ 142362306a36Sopenharmony_ci target_execute_cmd(se_cmd); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci return 0; 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic int scsiback_queue_data_in(struct se_cmd *se_cmd) 142962306a36Sopenharmony_ci{ 143062306a36Sopenharmony_ci struct vscsibk_pend *pending_req = container_of(se_cmd, 143162306a36Sopenharmony_ci struct vscsibk_pend, se_cmd); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci pending_req->result = SAM_STAT_GOOD; 143462306a36Sopenharmony_ci scsiback_cmd_done(pending_req); 143562306a36Sopenharmony_ci return 0; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic int scsiback_queue_status(struct se_cmd *se_cmd) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct vscsibk_pend *pending_req = container_of(se_cmd, 144162306a36Sopenharmony_ci struct vscsibk_pend, se_cmd); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (se_cmd->sense_buffer && 144462306a36Sopenharmony_ci ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || 144562306a36Sopenharmony_ci (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) 144662306a36Sopenharmony_ci pending_req->result = SAM_STAT_CHECK_CONDITION; 144762306a36Sopenharmony_ci else 144862306a36Sopenharmony_ci pending_req->result = se_cmd->scsi_status; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci scsiback_cmd_done(pending_req); 145162306a36Sopenharmony_ci return 0; 145262306a36Sopenharmony_ci} 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_cistatic void scsiback_queue_tm_rsp(struct se_cmd *se_cmd) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct vscsibk_pend *pending_req = container_of(se_cmd, 145762306a36Sopenharmony_ci struct vscsibk_pend, se_cmd); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci complete(&pending_req->tmr_done); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic void scsiback_aborted_task(struct se_cmd *se_cmd) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic ssize_t scsiback_tpg_param_alias_show(struct config_item *item, 146762306a36Sopenharmony_ci char *page) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci struct se_portal_group *se_tpg = param_to_tpg(item); 147062306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, 147162306a36Sopenharmony_ci se_tpg); 147262306a36Sopenharmony_ci ssize_t rb; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 147562306a36Sopenharmony_ci rb = snprintf(page, PAGE_SIZE, "%s\n", tpg->param_alias); 147662306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci return rb; 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic ssize_t scsiback_tpg_param_alias_store(struct config_item *item, 148262306a36Sopenharmony_ci const char *page, size_t count) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci struct se_portal_group *se_tpg = param_to_tpg(item); 148562306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, 148662306a36Sopenharmony_ci se_tpg); 148762306a36Sopenharmony_ci int len; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (strlen(page) >= VSCSI_NAMELEN) { 149062306a36Sopenharmony_ci pr_err("param alias: %s, exceeds max: %d\n", page, 149162306a36Sopenharmony_ci VSCSI_NAMELEN); 149262306a36Sopenharmony_ci return -EINVAL; 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 149662306a36Sopenharmony_ci len = snprintf(tpg->param_alias, VSCSI_NAMELEN, "%s", page); 149762306a36Sopenharmony_ci if (tpg->param_alias[len - 1] == '\n') 149862306a36Sopenharmony_ci tpg->param_alias[len - 1] = '\0'; 149962306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return count; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ciCONFIGFS_ATTR(scsiback_tpg_param_, alias); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic struct configfs_attribute *scsiback_param_attrs[] = { 150762306a36Sopenharmony_ci &scsiback_tpg_param_attr_alias, 150862306a36Sopenharmony_ci NULL, 150962306a36Sopenharmony_ci}; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic int scsiback_alloc_sess_cb(struct se_portal_group *se_tpg, 151262306a36Sopenharmony_ci struct se_session *se_sess, void *p) 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 151562306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci tpg->tpg_nexus = p; 151862306a36Sopenharmony_ci return 0; 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cistatic int scsiback_make_nexus(struct scsiback_tpg *tpg, 152262306a36Sopenharmony_ci const char *name) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci struct scsiback_nexus *tv_nexus; 152562306a36Sopenharmony_ci int ret = 0; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 152862306a36Sopenharmony_ci if (tpg->tpg_nexus) { 152962306a36Sopenharmony_ci pr_debug("tpg->tpg_nexus already exists\n"); 153062306a36Sopenharmony_ci ret = -EEXIST; 153162306a36Sopenharmony_ci goto out_unlock; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci tv_nexus = kzalloc(sizeof(struct scsiback_nexus), GFP_KERNEL); 153562306a36Sopenharmony_ci if (!tv_nexus) { 153662306a36Sopenharmony_ci ret = -ENOMEM; 153762306a36Sopenharmony_ci goto out_unlock; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg, 154162306a36Sopenharmony_ci VSCSI_DEFAULT_SESSION_TAGS, 154262306a36Sopenharmony_ci sizeof(struct vscsibk_pend), 154362306a36Sopenharmony_ci TARGET_PROT_NORMAL, name, 154462306a36Sopenharmony_ci tv_nexus, scsiback_alloc_sess_cb); 154562306a36Sopenharmony_ci if (IS_ERR(tv_nexus->tvn_se_sess)) { 154662306a36Sopenharmony_ci kfree(tv_nexus); 154762306a36Sopenharmony_ci ret = -ENOMEM; 154862306a36Sopenharmony_ci goto out_unlock; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ciout_unlock: 155262306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 155362306a36Sopenharmony_ci return ret; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic int scsiback_drop_nexus(struct scsiback_tpg *tpg) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci struct se_session *se_sess; 155962306a36Sopenharmony_ci struct scsiback_nexus *tv_nexus; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 156262306a36Sopenharmony_ci tv_nexus = tpg->tpg_nexus; 156362306a36Sopenharmony_ci if (!tv_nexus) { 156462306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 156562306a36Sopenharmony_ci return -ENODEV; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci se_sess = tv_nexus->tvn_se_sess; 156962306a36Sopenharmony_ci if (!se_sess) { 157062306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 157162306a36Sopenharmony_ci return -ENODEV; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci if (tpg->tv_tpg_port_count != 0) { 157562306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 157662306a36Sopenharmony_ci pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG port count: %d\n", 157762306a36Sopenharmony_ci tpg->tv_tpg_port_count); 157862306a36Sopenharmony_ci return -EBUSY; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (tpg->tv_tpg_fe_count != 0) { 158262306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 158362306a36Sopenharmony_ci pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG frontend count: %d\n", 158462306a36Sopenharmony_ci tpg->tv_tpg_fe_count); 158562306a36Sopenharmony_ci return -EBUSY; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci pr_debug("Removing I_T Nexus to emulated %s Initiator Port: %s\n", 158962306a36Sopenharmony_ci scsiback_dump_proto_id(tpg->tport), 159062306a36Sopenharmony_ci tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* 159362306a36Sopenharmony_ci * Release the SCSI I_T Nexus to the emulated xen-pvscsi Target Port 159462306a36Sopenharmony_ci */ 159562306a36Sopenharmony_ci target_remove_session(se_sess); 159662306a36Sopenharmony_ci tpg->tpg_nexus = NULL; 159762306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci kfree(tv_nexus); 160062306a36Sopenharmony_ci return 0; 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic ssize_t scsiback_tpg_nexus_show(struct config_item *item, char *page) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct se_portal_group *se_tpg = to_tpg(item); 160662306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 160762306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 160862306a36Sopenharmony_ci struct scsiback_nexus *tv_nexus; 160962306a36Sopenharmony_ci ssize_t ret; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 161262306a36Sopenharmony_ci tv_nexus = tpg->tpg_nexus; 161362306a36Sopenharmony_ci if (!tv_nexus) { 161462306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 161562306a36Sopenharmony_ci return -ENODEV; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci ret = snprintf(page, PAGE_SIZE, "%s\n", 161862306a36Sopenharmony_ci tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 161962306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return ret; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic ssize_t scsiback_tpg_nexus_store(struct config_item *item, 162562306a36Sopenharmony_ci const char *page, size_t count) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci struct se_portal_group *se_tpg = to_tpg(item); 162862306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 162962306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 163062306a36Sopenharmony_ci struct scsiback_tport *tport_wwn = tpg->tport; 163162306a36Sopenharmony_ci unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; 163262306a36Sopenharmony_ci int ret; 163362306a36Sopenharmony_ci /* 163462306a36Sopenharmony_ci * Shutdown the active I_T nexus if 'NULL' is passed. 163562306a36Sopenharmony_ci */ 163662306a36Sopenharmony_ci if (!strncmp(page, "NULL", 4)) { 163762306a36Sopenharmony_ci ret = scsiback_drop_nexus(tpg); 163862306a36Sopenharmony_ci return (!ret) ? count : ret; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci /* 164162306a36Sopenharmony_ci * Otherwise make sure the passed virtual Initiator port WWN matches 164262306a36Sopenharmony_ci * the fabric protocol_id set in scsiback_make_tport(), and call 164362306a36Sopenharmony_ci * scsiback_make_nexus(). 164462306a36Sopenharmony_ci */ 164562306a36Sopenharmony_ci if (strlen(page) >= VSCSI_NAMELEN) { 164662306a36Sopenharmony_ci pr_err("Emulated NAA Sas Address: %s, exceeds max: %d\n", 164762306a36Sopenharmony_ci page, VSCSI_NAMELEN); 164862306a36Sopenharmony_ci return -EINVAL; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci snprintf(&i_port[0], VSCSI_NAMELEN, "%s", page); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci ptr = strstr(i_port, "naa."); 165362306a36Sopenharmony_ci if (ptr) { 165462306a36Sopenharmony_ci if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) { 165562306a36Sopenharmony_ci pr_err("Passed SAS Initiator Port %s does not match target port protoid: %s\n", 165662306a36Sopenharmony_ci i_port, scsiback_dump_proto_id(tport_wwn)); 165762306a36Sopenharmony_ci return -EINVAL; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci port_ptr = &i_port[0]; 166062306a36Sopenharmony_ci goto check_newline; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci ptr = strstr(i_port, "fc."); 166362306a36Sopenharmony_ci if (ptr) { 166462306a36Sopenharmony_ci if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) { 166562306a36Sopenharmony_ci pr_err("Passed FCP Initiator Port %s does not match target port protoid: %s\n", 166662306a36Sopenharmony_ci i_port, scsiback_dump_proto_id(tport_wwn)); 166762306a36Sopenharmony_ci return -EINVAL; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci port_ptr = &i_port[3]; /* Skip over "fc." */ 167062306a36Sopenharmony_ci goto check_newline; 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci ptr = strstr(i_port, "iqn."); 167362306a36Sopenharmony_ci if (ptr) { 167462306a36Sopenharmony_ci if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) { 167562306a36Sopenharmony_ci pr_err("Passed iSCSI Initiator Port %s does not match target port protoid: %s\n", 167662306a36Sopenharmony_ci i_port, scsiback_dump_proto_id(tport_wwn)); 167762306a36Sopenharmony_ci return -EINVAL; 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci port_ptr = &i_port[0]; 168062306a36Sopenharmony_ci goto check_newline; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci pr_err("Unable to locate prefix for emulated Initiator Port: %s\n", 168362306a36Sopenharmony_ci i_port); 168462306a36Sopenharmony_ci return -EINVAL; 168562306a36Sopenharmony_ci /* 168662306a36Sopenharmony_ci * Clear any trailing newline for the NAA WWN 168762306a36Sopenharmony_ci */ 168862306a36Sopenharmony_cicheck_newline: 168962306a36Sopenharmony_ci if (i_port[strlen(i_port) - 1] == '\n') 169062306a36Sopenharmony_ci i_port[strlen(i_port) - 1] = '\0'; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci ret = scsiback_make_nexus(tpg, port_ptr); 169362306a36Sopenharmony_ci if (ret < 0) 169462306a36Sopenharmony_ci return ret; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci return count; 169762306a36Sopenharmony_ci} 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ciCONFIGFS_ATTR(scsiback_tpg_, nexus); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_cistatic struct configfs_attribute *scsiback_tpg_attrs[] = { 170262306a36Sopenharmony_ci &scsiback_tpg_attr_nexus, 170362306a36Sopenharmony_ci NULL, 170462306a36Sopenharmony_ci}; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_cistatic ssize_t 170762306a36Sopenharmony_ciscsiback_wwn_version_show(struct config_item *item, char *page) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci return sprintf(page, "xen-pvscsi fabric module %s on %s/%s on " 171062306a36Sopenharmony_ci UTS_RELEASE"\n", 171162306a36Sopenharmony_ci VSCSI_VERSION, utsname()->sysname, utsname()->machine); 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ciCONFIGFS_ATTR_RO(scsiback_wwn_, version); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_cistatic struct configfs_attribute *scsiback_wwn_attrs[] = { 171762306a36Sopenharmony_ci &scsiback_wwn_attr_version, 171862306a36Sopenharmony_ci NULL, 171962306a36Sopenharmony_ci}; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_cistatic int scsiback_port_link(struct se_portal_group *se_tpg, 172262306a36Sopenharmony_ci struct se_lun *lun) 172362306a36Sopenharmony_ci{ 172462306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 172562306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 172862306a36Sopenharmony_ci tpg->tv_tpg_port_count++; 172962306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci return 0; 173262306a36Sopenharmony_ci} 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_cistatic void scsiback_port_unlink(struct se_portal_group *se_tpg, 173562306a36Sopenharmony_ci struct se_lun *lun) 173662306a36Sopenharmony_ci{ 173762306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 173862306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci mutex_lock(&tpg->tv_tpg_mutex); 174162306a36Sopenharmony_ci tpg->tv_tpg_port_count--; 174262306a36Sopenharmony_ci mutex_unlock(&tpg->tv_tpg_mutex); 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic struct se_portal_group * 174662306a36Sopenharmony_ciscsiback_make_tpg(struct se_wwn *wwn, const char *name) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci struct scsiback_tport *tport = container_of(wwn, 174962306a36Sopenharmony_ci struct scsiback_tport, tport_wwn); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci struct scsiback_tpg *tpg; 175262306a36Sopenharmony_ci u16 tpgt; 175362306a36Sopenharmony_ci int ret; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (strstr(name, "tpgt_") != name) 175662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 175762306a36Sopenharmony_ci ret = kstrtou16(name + 5, 10, &tpgt); 175862306a36Sopenharmony_ci if (ret) 175962306a36Sopenharmony_ci return ERR_PTR(ret); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci tpg = kzalloc(sizeof(struct scsiback_tpg), GFP_KERNEL); 176262306a36Sopenharmony_ci if (!tpg) 176362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci mutex_init(&tpg->tv_tpg_mutex); 176662306a36Sopenharmony_ci INIT_LIST_HEAD(&tpg->tv_tpg_list); 176762306a36Sopenharmony_ci INIT_LIST_HEAD(&tpg->info_list); 176862306a36Sopenharmony_ci tpg->tport = tport; 176962306a36Sopenharmony_ci tpg->tport_tpgt = tpgt; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); 177262306a36Sopenharmony_ci if (ret < 0) { 177362306a36Sopenharmony_ci kfree(tpg); 177462306a36Sopenharmony_ci return NULL; 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci mutex_lock(&scsiback_mutex); 177762306a36Sopenharmony_ci list_add_tail(&tpg->tv_tpg_list, &scsiback_list); 177862306a36Sopenharmony_ci mutex_unlock(&scsiback_mutex); 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci return &tpg->se_tpg; 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_cistatic void scsiback_drop_tpg(struct se_portal_group *se_tpg) 178462306a36Sopenharmony_ci{ 178562306a36Sopenharmony_ci struct scsiback_tpg *tpg = container_of(se_tpg, 178662306a36Sopenharmony_ci struct scsiback_tpg, se_tpg); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci mutex_lock(&scsiback_mutex); 178962306a36Sopenharmony_ci list_del(&tpg->tv_tpg_list); 179062306a36Sopenharmony_ci mutex_unlock(&scsiback_mutex); 179162306a36Sopenharmony_ci /* 179262306a36Sopenharmony_ci * Release the virtual I_T Nexus for this xen-pvscsi TPG 179362306a36Sopenharmony_ci */ 179462306a36Sopenharmony_ci scsiback_drop_nexus(tpg); 179562306a36Sopenharmony_ci /* 179662306a36Sopenharmony_ci * Deregister the se_tpg from TCM. 179762306a36Sopenharmony_ci */ 179862306a36Sopenharmony_ci core_tpg_deregister(se_tpg); 179962306a36Sopenharmony_ci kfree(tpg); 180062306a36Sopenharmony_ci} 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_cistatic int scsiback_check_true(struct se_portal_group *se_tpg) 180362306a36Sopenharmony_ci{ 180462306a36Sopenharmony_ci return 1; 180562306a36Sopenharmony_ci} 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_cistatic const struct target_core_fabric_ops scsiback_ops = { 180862306a36Sopenharmony_ci .module = THIS_MODULE, 180962306a36Sopenharmony_ci .fabric_name = "xen-pvscsi", 181062306a36Sopenharmony_ci .tpg_get_wwn = scsiback_get_fabric_wwn, 181162306a36Sopenharmony_ci .tpg_get_tag = scsiback_get_tag, 181262306a36Sopenharmony_ci .tpg_check_demo_mode = scsiback_check_true, 181362306a36Sopenharmony_ci .tpg_check_demo_mode_cache = scsiback_check_true, 181462306a36Sopenharmony_ci .check_stop_free = scsiback_check_stop_free, 181562306a36Sopenharmony_ci .release_cmd = scsiback_release_cmd, 181662306a36Sopenharmony_ci .sess_get_initiator_sid = NULL, 181762306a36Sopenharmony_ci .write_pending = scsiback_write_pending, 181862306a36Sopenharmony_ci .queue_data_in = scsiback_queue_data_in, 181962306a36Sopenharmony_ci .queue_status = scsiback_queue_status, 182062306a36Sopenharmony_ci .queue_tm_rsp = scsiback_queue_tm_rsp, 182162306a36Sopenharmony_ci .aborted_task = scsiback_aborted_task, 182262306a36Sopenharmony_ci /* 182362306a36Sopenharmony_ci * Setup callers for generic logic in target_core_fabric_configfs.c 182462306a36Sopenharmony_ci */ 182562306a36Sopenharmony_ci .fabric_make_wwn = scsiback_make_tport, 182662306a36Sopenharmony_ci .fabric_drop_wwn = scsiback_drop_tport, 182762306a36Sopenharmony_ci .fabric_make_tpg = scsiback_make_tpg, 182862306a36Sopenharmony_ci .fabric_drop_tpg = scsiback_drop_tpg, 182962306a36Sopenharmony_ci .fabric_post_link = scsiback_port_link, 183062306a36Sopenharmony_ci .fabric_pre_unlink = scsiback_port_unlink, 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci .tfc_wwn_attrs = scsiback_wwn_attrs, 183362306a36Sopenharmony_ci .tfc_tpg_base_attrs = scsiback_tpg_attrs, 183462306a36Sopenharmony_ci .tfc_tpg_param_attrs = scsiback_param_attrs, 183562306a36Sopenharmony_ci}; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cistatic const struct xenbus_device_id scsiback_ids[] = { 183862306a36Sopenharmony_ci { "vscsi" }, 183962306a36Sopenharmony_ci { "" } 184062306a36Sopenharmony_ci}; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic struct xenbus_driver scsiback_driver = { 184362306a36Sopenharmony_ci .ids = scsiback_ids, 184462306a36Sopenharmony_ci .probe = scsiback_probe, 184562306a36Sopenharmony_ci .remove = scsiback_remove, 184662306a36Sopenharmony_ci .otherend_changed = scsiback_frontend_changed 184762306a36Sopenharmony_ci}; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_cistatic int __init scsiback_init(void) 185062306a36Sopenharmony_ci{ 185162306a36Sopenharmony_ci int ret; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (!xen_domain()) 185462306a36Sopenharmony_ci return -ENODEV; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", 185762306a36Sopenharmony_ci VSCSI_VERSION, utsname()->sysname, utsname()->machine); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci ret = xenbus_register_backend(&scsiback_driver); 186062306a36Sopenharmony_ci if (ret) 186162306a36Sopenharmony_ci goto out; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci ret = target_register_template(&scsiback_ops); 186462306a36Sopenharmony_ci if (ret) 186562306a36Sopenharmony_ci goto out_unregister_xenbus; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci return 0; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ciout_unregister_xenbus: 187062306a36Sopenharmony_ci xenbus_unregister_driver(&scsiback_driver); 187162306a36Sopenharmony_ciout: 187262306a36Sopenharmony_ci pr_err("%s: error %d\n", __func__, ret); 187362306a36Sopenharmony_ci return ret; 187462306a36Sopenharmony_ci} 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_cistatic void __exit scsiback_exit(void) 187762306a36Sopenharmony_ci{ 187862306a36Sopenharmony_ci target_unregister_template(&scsiback_ops); 187962306a36Sopenharmony_ci xenbus_unregister_driver(&scsiback_driver); 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_cimodule_init(scsiback_init); 188362306a36Sopenharmony_cimodule_exit(scsiback_exit); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ciMODULE_DESCRIPTION("Xen SCSI backend driver"); 188662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 188762306a36Sopenharmony_ciMODULE_ALIAS("xen-backend:vscsi"); 188862306a36Sopenharmony_ciMODULE_AUTHOR("Juergen Gross <jgross@suse.com>"); 1889