1d9d660f6SJuergen Gross /* 2d9d660f6SJuergen Gross * Xen SCSI backend driver 3d9d660f6SJuergen Gross * 4d9d660f6SJuergen Gross * Copyright (c) 2008, FUJITSU Limited 5d9d660f6SJuergen Gross * 6d9d660f6SJuergen Gross * Based on the blkback driver code. 7d9d660f6SJuergen Gross * Adaption to kernel taget core infrastructure taken from vhost/scsi.c 8d9d660f6SJuergen Gross * 9d9d660f6SJuergen Gross * This program is free software; you can redistribute it and/or 10d9d660f6SJuergen Gross * modify it under the terms of the GNU General Public License version 2 11d9d660f6SJuergen Gross * as published by the Free Software Foundation; or, when distributed 12d9d660f6SJuergen Gross * separately from the Linux kernel or incorporated into other 13d9d660f6SJuergen Gross * software packages, subject to the following license: 14d9d660f6SJuergen Gross * 15d9d660f6SJuergen Gross * Permission is hereby granted, free of charge, to any person obtaining a copy 16d9d660f6SJuergen Gross * of this source file (the "Software"), to deal in the Software without 17d9d660f6SJuergen Gross * restriction, including without limitation the rights to use, copy, modify, 18d9d660f6SJuergen Gross * merge, publish, distribute, sublicense, and/or sell copies of the Software, 19d9d660f6SJuergen Gross * and to permit persons to whom the Software is furnished to do so, subject to 20d9d660f6SJuergen Gross * the following conditions: 21d9d660f6SJuergen Gross * 22d9d660f6SJuergen Gross * The above copyright notice and this permission notice shall be included in 23d9d660f6SJuergen Gross * all copies or substantial portions of the Software. 24d9d660f6SJuergen Gross * 25d9d660f6SJuergen Gross * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26d9d660f6SJuergen Gross * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27d9d660f6SJuergen Gross * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28d9d660f6SJuergen Gross * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29d9d660f6SJuergen Gross * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30d9d660f6SJuergen Gross * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 31d9d660f6SJuergen Gross * IN THE SOFTWARE. 32d9d660f6SJuergen Gross */ 33d9d660f6SJuergen Gross 34d9d660f6SJuergen Gross #include <stdarg.h> 35d9d660f6SJuergen Gross 36d9d660f6SJuergen Gross #include <linux/module.h> 37d9d660f6SJuergen Gross #include <linux/utsname.h> 38d9d660f6SJuergen Gross #include <linux/interrupt.h> 39d9d660f6SJuergen Gross #include <linux/slab.h> 40d9d660f6SJuergen Gross #include <linux/wait.h> 41d9d660f6SJuergen Gross #include <linux/sched.h> 42d9d660f6SJuergen Gross #include <linux/list.h> 43d9d660f6SJuergen Gross #include <linux/gfp.h> 44d9d660f6SJuergen Gross #include <linux/delay.h> 45d9d660f6SJuergen Gross #include <linux/spinlock.h> 46d9d660f6SJuergen Gross #include <linux/configfs.h> 47d9d660f6SJuergen Gross 48d9d660f6SJuergen Gross #include <generated/utsrelease.h> 49d9d660f6SJuergen Gross 502dd951ecSHannes Reinecke #include <scsi/scsi.h> 51d9d660f6SJuergen Gross #include <scsi/scsi_dbg.h> 52d9d660f6SJuergen Gross #include <scsi/scsi_eh.h> 53d9d660f6SJuergen Gross #include <scsi/scsi_tcq.h> 54d9d660f6SJuergen Gross 55d9d660f6SJuergen Gross #include <target/target_core_base.h> 56d9d660f6SJuergen Gross #include <target/target_core_fabric.h> 57d9d660f6SJuergen Gross #include <target/target_core_configfs.h> 58d9d660f6SJuergen Gross #include <target/target_core_fabric_configfs.h> 59d9d660f6SJuergen Gross 60d9d660f6SJuergen Gross #include <asm/hypervisor.h> 61d9d660f6SJuergen Gross 62d9d660f6SJuergen Gross #include <xen/xen.h> 63d9d660f6SJuergen Gross #include <xen/balloon.h> 64d9d660f6SJuergen Gross #include <xen/events.h> 65d9d660f6SJuergen Gross #include <xen/xenbus.h> 66d9d660f6SJuergen Gross #include <xen/grant_table.h> 67d9d660f6SJuergen Gross #include <xen/page.h> 68d9d660f6SJuergen Gross 69d9d660f6SJuergen Gross #include <xen/interface/grant_table.h> 70d9d660f6SJuergen Gross #include <xen/interface/io/vscsiif.h> 71d9d660f6SJuergen Gross 72d9d660f6SJuergen Gross #define DPRINTK(_f, _a...) \ 73d9d660f6SJuergen Gross pr_debug("(file=%s, line=%d) " _f, __FILE__ , __LINE__ , ## _a) 74d9d660f6SJuergen Gross 75d9d660f6SJuergen Gross #define VSCSI_VERSION "v0.1" 76d9d660f6SJuergen Gross #define VSCSI_NAMELEN 32 77d9d660f6SJuergen Gross 78d9d660f6SJuergen Gross struct ids_tuple { 79d9d660f6SJuergen Gross unsigned int hst; /* host */ 80d9d660f6SJuergen Gross unsigned int chn; /* channel */ 81d9d660f6SJuergen Gross unsigned int tgt; /* target */ 82d9d660f6SJuergen Gross unsigned int lun; /* LUN */ 83d9d660f6SJuergen Gross }; 84d9d660f6SJuergen Gross 85d9d660f6SJuergen Gross struct v2p_entry { 86d9d660f6SJuergen Gross struct ids_tuple v; /* translate from */ 87d9d660f6SJuergen Gross struct scsiback_tpg *tpg; /* translate to */ 88d9d660f6SJuergen Gross unsigned int lun; 89d9d660f6SJuergen Gross struct kref kref; 90d9d660f6SJuergen Gross struct list_head l; 91d9d660f6SJuergen Gross }; 92d9d660f6SJuergen Gross 93d9d660f6SJuergen Gross struct vscsibk_info { 94d9d660f6SJuergen Gross struct xenbus_device *dev; 95d9d660f6SJuergen Gross 96d9d660f6SJuergen Gross domid_t domid; 97d9d660f6SJuergen Gross unsigned int irq; 98d9d660f6SJuergen Gross 99d9d660f6SJuergen Gross struct vscsiif_back_ring ring; 100d9d660f6SJuergen Gross int ring_error; 101d9d660f6SJuergen Gross 102d9d660f6SJuergen Gross spinlock_t ring_lock; 103d9d660f6SJuergen Gross atomic_t nr_unreplied_reqs; 104d9d660f6SJuergen Gross 105d9d660f6SJuergen Gross spinlock_t v2p_lock; 106d9d660f6SJuergen Gross struct list_head v2p_entry_lists; 107d9d660f6SJuergen Gross 108d9d660f6SJuergen Gross wait_queue_head_t waiting_to_free; 109d9d660f6SJuergen Gross }; 110d9d660f6SJuergen Gross 111d9d660f6SJuergen Gross /* theoretical maximum of grants for one request */ 112d9d660f6SJuergen Gross #define VSCSI_MAX_GRANTS (SG_ALL + VSCSIIF_SG_TABLESIZE) 113d9d660f6SJuergen Gross 114d9d660f6SJuergen Gross /* 115d9d660f6SJuergen Gross * VSCSI_GRANT_BATCH is the maximum number of grants to be processed in one 116d9d660f6SJuergen Gross * call to map/unmap grants. Don't choose it too large, as there are arrays 117d9d660f6SJuergen Gross * with VSCSI_GRANT_BATCH elements allocated on the stack. 118d9d660f6SJuergen Gross */ 119d9d660f6SJuergen Gross #define VSCSI_GRANT_BATCH 16 120d9d660f6SJuergen Gross 121d9d660f6SJuergen Gross struct vscsibk_pend { 122d9d660f6SJuergen Gross uint16_t rqid; 123d9d660f6SJuergen Gross 124d9d660f6SJuergen Gross uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE]; 125d9d660f6SJuergen Gross uint8_t cmd_len; 126d9d660f6SJuergen Gross 127d9d660f6SJuergen Gross uint8_t sc_data_direction; 128d9d660f6SJuergen Gross uint16_t n_sg; /* real length of SG list */ 129d9d660f6SJuergen Gross uint16_t n_grants; /* SG pages and potentially SG list */ 130d9d660f6SJuergen Gross uint32_t data_len; 131d9d660f6SJuergen Gross uint32_t result; 132d9d660f6SJuergen Gross 133d9d660f6SJuergen Gross struct vscsibk_info *info; 134d9d660f6SJuergen Gross struct v2p_entry *v2p; 135d9d660f6SJuergen Gross struct scatterlist *sgl; 136d9d660f6SJuergen Gross 137d9d660f6SJuergen Gross uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE]; 138d9d660f6SJuergen Gross 139d9d660f6SJuergen Gross grant_handle_t grant_handles[VSCSI_MAX_GRANTS]; 140d9d660f6SJuergen Gross struct page *pages[VSCSI_MAX_GRANTS]; 141d9d660f6SJuergen Gross 142d9d660f6SJuergen Gross struct se_cmd se_cmd; 143d9d660f6SJuergen Gross }; 144d9d660f6SJuergen Gross 145d9d660f6SJuergen Gross struct scsiback_tmr { 146d9d660f6SJuergen Gross atomic_t tmr_complete; 147d9d660f6SJuergen Gross wait_queue_head_t tmr_wait; 148d9d660f6SJuergen Gross }; 149d9d660f6SJuergen Gross 150d9d660f6SJuergen Gross struct scsiback_nexus { 151d9d660f6SJuergen Gross /* Pointer to TCM session for I_T Nexus */ 152d9d660f6SJuergen Gross struct se_session *tvn_se_sess; 153d9d660f6SJuergen Gross }; 154d9d660f6SJuergen Gross 155d9d660f6SJuergen Gross struct scsiback_tport { 156d9d660f6SJuergen Gross /* SCSI protocol the tport is providing */ 157d9d660f6SJuergen Gross u8 tport_proto_id; 158d9d660f6SJuergen Gross /* Binary World Wide unique Port Name for pvscsi Target port */ 159d9d660f6SJuergen Gross u64 tport_wwpn; 160d9d660f6SJuergen Gross /* ASCII formatted WWPN for pvscsi Target port */ 161d9d660f6SJuergen Gross char tport_name[VSCSI_NAMELEN]; 162d9d660f6SJuergen Gross /* Returned by scsiback_make_tport() */ 163d9d660f6SJuergen Gross struct se_wwn tport_wwn; 164d9d660f6SJuergen Gross }; 165d9d660f6SJuergen Gross 166d9d660f6SJuergen Gross struct scsiback_tpg { 167d9d660f6SJuergen Gross /* scsiback port target portal group tag for TCM */ 168d9d660f6SJuergen Gross u16 tport_tpgt; 169d9d660f6SJuergen Gross /* track number of TPG Port/Lun Links wrt explicit I_T Nexus shutdown */ 170d9d660f6SJuergen Gross int tv_tpg_port_count; 171d9d660f6SJuergen Gross /* xen-pvscsi references to tpg_nexus, protected by tv_tpg_mutex */ 172d9d660f6SJuergen Gross int tv_tpg_fe_count; 173d9d660f6SJuergen Gross /* list for scsiback_list */ 174d9d660f6SJuergen Gross struct list_head tv_tpg_list; 175d9d660f6SJuergen Gross /* Used to protect access for tpg_nexus */ 176d9d660f6SJuergen Gross struct mutex tv_tpg_mutex; 177d9d660f6SJuergen Gross /* Pointer to the TCM pvscsi I_T Nexus for this TPG endpoint */ 178d9d660f6SJuergen Gross struct scsiback_nexus *tpg_nexus; 179d9d660f6SJuergen Gross /* Pointer back to scsiback_tport */ 180d9d660f6SJuergen Gross struct scsiback_tport *tport; 181d9d660f6SJuergen Gross /* Returned by scsiback_make_tpg() */ 182d9d660f6SJuergen Gross struct se_portal_group se_tpg; 183d9d660f6SJuergen Gross /* alias used in xenstore */ 184d9d660f6SJuergen Gross char param_alias[VSCSI_NAMELEN]; 185d9d660f6SJuergen Gross /* list of info structures related to this target portal group */ 186d9d660f6SJuergen Gross struct list_head info_list; 187d9d660f6SJuergen Gross }; 188d9d660f6SJuergen Gross 189d9d660f6SJuergen Gross #define SCSIBACK_INVALID_HANDLE (~0) 190d9d660f6SJuergen Gross 191d9d660f6SJuergen Gross static bool log_print_stat; 192d9d660f6SJuergen Gross module_param(log_print_stat, bool, 0644); 193d9d660f6SJuergen Gross 194d9d660f6SJuergen Gross static int scsiback_max_buffer_pages = 1024; 195d9d660f6SJuergen Gross module_param_named(max_buffer_pages, scsiback_max_buffer_pages, int, 0644); 196d9d660f6SJuergen Gross MODULE_PARM_DESC(max_buffer_pages, 197d9d660f6SJuergen Gross "Maximum number of free pages to keep in backend buffer"); 198d9d660f6SJuergen Gross 199d9d660f6SJuergen Gross static struct kmem_cache *scsiback_cachep; 200d9d660f6SJuergen Gross static DEFINE_SPINLOCK(free_pages_lock); 201d9d660f6SJuergen Gross static int free_pages_num; 202d9d660f6SJuergen Gross static LIST_HEAD(scsiback_free_pages); 203d9d660f6SJuergen Gross 204d9d660f6SJuergen Gross /* Global spinlock to protect scsiback TPG list */ 205d9d660f6SJuergen Gross static DEFINE_MUTEX(scsiback_mutex); 206d9d660f6SJuergen Gross static LIST_HEAD(scsiback_list); 207d9d660f6SJuergen Gross 208d9d660f6SJuergen Gross /* Local pointer to allocated TCM configfs fabric module */ 209d9d660f6SJuergen Gross static struct target_fabric_configfs *scsiback_fabric_configfs; 210d9d660f6SJuergen Gross 211d9d660f6SJuergen Gross static void scsiback_get(struct vscsibk_info *info) 212d9d660f6SJuergen Gross { 213d9d660f6SJuergen Gross atomic_inc(&info->nr_unreplied_reqs); 214d9d660f6SJuergen Gross } 215d9d660f6SJuergen Gross 216d9d660f6SJuergen Gross static void scsiback_put(struct vscsibk_info *info) 217d9d660f6SJuergen Gross { 218d9d660f6SJuergen Gross if (atomic_dec_and_test(&info->nr_unreplied_reqs)) 219d9d660f6SJuergen Gross wake_up(&info->waiting_to_free); 220d9d660f6SJuergen Gross } 221d9d660f6SJuergen Gross 222d9d660f6SJuergen Gross static void put_free_pages(struct page **page, int num) 223d9d660f6SJuergen Gross { 224d9d660f6SJuergen Gross unsigned long flags; 225d9d660f6SJuergen Gross int i = free_pages_num + num, n = num; 226d9d660f6SJuergen Gross 227d9d660f6SJuergen Gross if (num == 0) 228d9d660f6SJuergen Gross return; 229d9d660f6SJuergen Gross if (i > scsiback_max_buffer_pages) { 230d9d660f6SJuergen Gross n = min(num, i - scsiback_max_buffer_pages); 231ff4b156fSDavid Vrabel gnttab_free_pages(n, page + num - n); 232d9d660f6SJuergen Gross n = num - n; 233d9d660f6SJuergen Gross } 234d9d660f6SJuergen Gross spin_lock_irqsave(&free_pages_lock, flags); 235d9d660f6SJuergen Gross for (i = 0; i < n; i++) 236d9d660f6SJuergen Gross list_add(&page[i]->lru, &scsiback_free_pages); 237d9d660f6SJuergen Gross free_pages_num += n; 238d9d660f6SJuergen Gross spin_unlock_irqrestore(&free_pages_lock, flags); 239d9d660f6SJuergen Gross } 240d9d660f6SJuergen Gross 241d9d660f6SJuergen Gross static int get_free_page(struct page **page) 242d9d660f6SJuergen Gross { 243d9d660f6SJuergen Gross unsigned long flags; 244d9d660f6SJuergen Gross 245d9d660f6SJuergen Gross spin_lock_irqsave(&free_pages_lock, flags); 246d9d660f6SJuergen Gross if (list_empty(&scsiback_free_pages)) { 247d9d660f6SJuergen Gross spin_unlock_irqrestore(&free_pages_lock, flags); 248ff4b156fSDavid Vrabel return gnttab_alloc_pages(1, page); 249d9d660f6SJuergen Gross } 250d9d660f6SJuergen Gross page[0] = list_first_entry(&scsiback_free_pages, struct page, lru); 251d9d660f6SJuergen Gross list_del(&page[0]->lru); 252d9d660f6SJuergen Gross free_pages_num--; 253d9d660f6SJuergen Gross spin_unlock_irqrestore(&free_pages_lock, flags); 254d9d660f6SJuergen Gross return 0; 255d9d660f6SJuergen Gross } 256d9d660f6SJuergen Gross 257d9d660f6SJuergen Gross static unsigned long vaddr_page(struct page *page) 258d9d660f6SJuergen Gross { 259d9d660f6SJuergen Gross unsigned long pfn = page_to_pfn(page); 260d9d660f6SJuergen Gross 261d9d660f6SJuergen Gross return (unsigned long)pfn_to_kaddr(pfn); 262d9d660f6SJuergen Gross } 263d9d660f6SJuergen Gross 264d9d660f6SJuergen Gross static unsigned long vaddr(struct vscsibk_pend *req, int seg) 265d9d660f6SJuergen Gross { 266d9d660f6SJuergen Gross return vaddr_page(req->pages[seg]); 267d9d660f6SJuergen Gross } 268d9d660f6SJuergen Gross 269d9d660f6SJuergen Gross static void scsiback_print_status(char *sense_buffer, int errors, 270d9d660f6SJuergen Gross struct vscsibk_pend *pending_req) 271d9d660f6SJuergen Gross { 272d9d660f6SJuergen Gross struct scsiback_tpg *tpg = pending_req->v2p->tpg; 273d9d660f6SJuergen Gross 274d9d660f6SJuergen Gross pr_err("xen-pvscsi[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", 275d9d660f6SJuergen Gross tpg->tport->tport_name, pending_req->v2p->lun, 276d9d660f6SJuergen Gross pending_req->cmnd[0], status_byte(errors), msg_byte(errors), 277d9d660f6SJuergen Gross host_byte(errors), driver_byte(errors)); 278d9d660f6SJuergen Gross } 279d9d660f6SJuergen Gross 280d9d660f6SJuergen Gross static void scsiback_fast_flush_area(struct vscsibk_pend *req) 281d9d660f6SJuergen Gross { 282d9d660f6SJuergen Gross struct gnttab_unmap_grant_ref unmap[VSCSI_GRANT_BATCH]; 283d9d660f6SJuergen Gross struct page *pages[VSCSI_GRANT_BATCH]; 284d9d660f6SJuergen Gross unsigned int i, invcount = 0; 285d9d660f6SJuergen Gross grant_handle_t handle; 286d9d660f6SJuergen Gross int err; 287d9d660f6SJuergen Gross 288d9d660f6SJuergen Gross kfree(req->sgl); 289d9d660f6SJuergen Gross req->sgl = NULL; 290d9d660f6SJuergen Gross req->n_sg = 0; 291d9d660f6SJuergen Gross 292d9d660f6SJuergen Gross if (!req->n_grants) 293d9d660f6SJuergen Gross return; 294d9d660f6SJuergen Gross 295d9d660f6SJuergen Gross for (i = 0; i < req->n_grants; i++) { 296d9d660f6SJuergen Gross handle = req->grant_handles[i]; 297d9d660f6SJuergen Gross if (handle == SCSIBACK_INVALID_HANDLE) 298d9d660f6SJuergen Gross continue; 299d9d660f6SJuergen Gross gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i), 300d9d660f6SJuergen Gross GNTMAP_host_map, handle); 301d9d660f6SJuergen Gross req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; 302d9d660f6SJuergen Gross pages[invcount] = req->pages[i]; 303d9d660f6SJuergen Gross put_page(pages[invcount]); 304d9d660f6SJuergen Gross invcount++; 305d9d660f6SJuergen Gross if (invcount < VSCSI_GRANT_BATCH) 306d9d660f6SJuergen Gross continue; 307d9d660f6SJuergen Gross err = gnttab_unmap_refs(unmap, NULL, pages, invcount); 308d9d660f6SJuergen Gross BUG_ON(err); 309d9d660f6SJuergen Gross invcount = 0; 310d9d660f6SJuergen Gross } 311d9d660f6SJuergen Gross 312d9d660f6SJuergen Gross if (invcount) { 313d9d660f6SJuergen Gross err = gnttab_unmap_refs(unmap, NULL, pages, invcount); 314d9d660f6SJuergen Gross BUG_ON(err); 315d9d660f6SJuergen Gross } 316d9d660f6SJuergen Gross 317d9d660f6SJuergen Gross put_free_pages(req->pages, req->n_grants); 318d9d660f6SJuergen Gross req->n_grants = 0; 319d9d660f6SJuergen Gross } 320d9d660f6SJuergen Gross 321d9d660f6SJuergen Gross static void scsiback_free_translation_entry(struct kref *kref) 322d9d660f6SJuergen Gross { 323d9d660f6SJuergen Gross struct v2p_entry *entry = container_of(kref, struct v2p_entry, kref); 324d9d660f6SJuergen Gross struct scsiback_tpg *tpg = entry->tpg; 325d9d660f6SJuergen Gross 326d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 327d9d660f6SJuergen Gross tpg->tv_tpg_fe_count--; 328d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 329d9d660f6SJuergen Gross 330d9d660f6SJuergen Gross kfree(entry); 331d9d660f6SJuergen Gross } 332d9d660f6SJuergen Gross 333d9d660f6SJuergen Gross static void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result, 334d9d660f6SJuergen Gross uint32_t resid, struct vscsibk_pend *pending_req) 335d9d660f6SJuergen Gross { 336d9d660f6SJuergen Gross struct vscsiif_response *ring_res; 337d9d660f6SJuergen Gross struct vscsibk_info *info = pending_req->info; 338d9d660f6SJuergen Gross int notify; 339d9d660f6SJuergen Gross struct scsi_sense_hdr sshdr; 340d9d660f6SJuergen Gross unsigned long flags; 341d9d660f6SJuergen Gross unsigned len; 342d9d660f6SJuergen Gross 343d9d660f6SJuergen Gross spin_lock_irqsave(&info->ring_lock, flags); 344d9d660f6SJuergen Gross 345d9d660f6SJuergen Gross ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt); 346d9d660f6SJuergen Gross info->ring.rsp_prod_pvt++; 347d9d660f6SJuergen Gross 348d9d660f6SJuergen Gross ring_res->rslt = result; 349d9d660f6SJuergen Gross ring_res->rqid = pending_req->rqid; 350d9d660f6SJuergen Gross 351d9d660f6SJuergen Gross if (sense_buffer != NULL && 352d9d660f6SJuergen Gross scsi_normalize_sense(sense_buffer, VSCSIIF_SENSE_BUFFERSIZE, 353d9d660f6SJuergen Gross &sshdr)) { 354d9d660f6SJuergen Gross len = min_t(unsigned, 8 + sense_buffer[7], 355d9d660f6SJuergen Gross VSCSIIF_SENSE_BUFFERSIZE); 356d9d660f6SJuergen Gross memcpy(ring_res->sense_buffer, sense_buffer, len); 357d9d660f6SJuergen Gross ring_res->sense_len = len; 358d9d660f6SJuergen Gross } else { 359d9d660f6SJuergen Gross ring_res->sense_len = 0; 360d9d660f6SJuergen Gross } 361d9d660f6SJuergen Gross 362d9d660f6SJuergen Gross ring_res->residual_len = resid; 363d9d660f6SJuergen Gross 364d9d660f6SJuergen Gross RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify); 365d9d660f6SJuergen Gross spin_unlock_irqrestore(&info->ring_lock, flags); 366d9d660f6SJuergen Gross 367d9d660f6SJuergen Gross if (notify) 368d9d660f6SJuergen Gross notify_remote_via_irq(info->irq); 369d9d660f6SJuergen Gross 370d9d660f6SJuergen Gross if (pending_req->v2p) 371d9d660f6SJuergen Gross kref_put(&pending_req->v2p->kref, 372d9d660f6SJuergen Gross scsiback_free_translation_entry); 373d9d660f6SJuergen Gross } 374d9d660f6SJuergen Gross 375d9d660f6SJuergen Gross static void scsiback_cmd_done(struct vscsibk_pend *pending_req) 376d9d660f6SJuergen Gross { 377d9d660f6SJuergen Gross struct vscsibk_info *info = pending_req->info; 378d9d660f6SJuergen Gross unsigned char *sense_buffer; 379d9d660f6SJuergen Gross unsigned int resid; 380d9d660f6SJuergen Gross int errors; 381d9d660f6SJuergen Gross 382d9d660f6SJuergen Gross sense_buffer = pending_req->sense_buffer; 383d9d660f6SJuergen Gross resid = pending_req->se_cmd.residual_count; 384d9d660f6SJuergen Gross errors = pending_req->result; 385d9d660f6SJuergen Gross 386d9d660f6SJuergen Gross if (errors && log_print_stat) 387d9d660f6SJuergen Gross scsiback_print_status(sense_buffer, errors, pending_req); 388d9d660f6SJuergen Gross 389d9d660f6SJuergen Gross scsiback_fast_flush_area(pending_req); 390d9d660f6SJuergen Gross scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req); 391d9d660f6SJuergen Gross scsiback_put(info); 392d9d660f6SJuergen Gross } 393d9d660f6SJuergen Gross 394d9d660f6SJuergen Gross static void scsiback_cmd_exec(struct vscsibk_pend *pending_req) 395d9d660f6SJuergen Gross { 396d9d660f6SJuergen Gross struct se_cmd *se_cmd = &pending_req->se_cmd; 397d9d660f6SJuergen Gross struct se_session *sess = pending_req->v2p->tpg->tpg_nexus->tvn_se_sess; 398d9d660f6SJuergen Gross int rc; 399d9d660f6SJuergen Gross 400d9d660f6SJuergen Gross memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE); 401d9d660f6SJuergen Gross 402d9d660f6SJuergen Gross memset(se_cmd, 0, sizeof(*se_cmd)); 403d9d660f6SJuergen Gross 404d9d660f6SJuergen Gross scsiback_get(pending_req->info); 405d9d660f6SJuergen Gross rc = target_submit_cmd_map_sgls(se_cmd, sess, pending_req->cmnd, 406d9d660f6SJuergen Gross pending_req->sense_buffer, pending_req->v2p->lun, 407d9d660f6SJuergen Gross pending_req->data_len, 0, 408d9d660f6SJuergen Gross pending_req->sc_data_direction, 0, 409d9d660f6SJuergen Gross pending_req->sgl, pending_req->n_sg, 410d9d660f6SJuergen Gross NULL, 0, NULL, 0); 411d9d660f6SJuergen Gross if (rc < 0) { 412d9d660f6SJuergen Gross transport_send_check_condition_and_sense(se_cmd, 413d9d660f6SJuergen Gross TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); 414d9d660f6SJuergen Gross transport_generic_free_cmd(se_cmd, 0); 415d9d660f6SJuergen Gross } 416d9d660f6SJuergen Gross } 417d9d660f6SJuergen Gross 418d9d660f6SJuergen Gross static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, 419d9d660f6SJuergen Gross struct page **pg, grant_handle_t *grant, int cnt) 420d9d660f6SJuergen Gross { 421d9d660f6SJuergen Gross int err, i; 422d9d660f6SJuergen Gross 423d9d660f6SJuergen Gross if (!cnt) 424d9d660f6SJuergen Gross return 0; 425d9d660f6SJuergen Gross 426d9d660f6SJuergen Gross err = gnttab_map_refs(map, NULL, pg, cnt); 427d9d660f6SJuergen Gross BUG_ON(err); 428d9d660f6SJuergen Gross for (i = 0; i < cnt; i++) { 429d9d660f6SJuergen Gross if (unlikely(map[i].status != GNTST_okay)) { 430d9d660f6SJuergen Gross pr_err("xen-pvscsi: invalid buffer -- could not remap it\n"); 431d9d660f6SJuergen Gross map[i].handle = SCSIBACK_INVALID_HANDLE; 432d9d660f6SJuergen Gross err = -ENOMEM; 433d9d660f6SJuergen Gross } else { 434d9d660f6SJuergen Gross get_page(pg[i]); 435d9d660f6SJuergen Gross } 436d9d660f6SJuergen Gross grant[i] = map[i].handle; 437d9d660f6SJuergen Gross } 438d9d660f6SJuergen Gross return err; 439d9d660f6SJuergen Gross } 440d9d660f6SJuergen Gross 441d9d660f6SJuergen Gross static int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req, 442d9d660f6SJuergen Gross struct scsiif_request_segment *seg, struct page **pg, 443d9d660f6SJuergen Gross grant_handle_t *grant, int cnt, u32 flags) 444d9d660f6SJuergen Gross { 445d9d660f6SJuergen Gross int mapcount = 0, i, err = 0; 446d9d660f6SJuergen Gross struct gnttab_map_grant_ref map[VSCSI_GRANT_BATCH]; 447d9d660f6SJuergen Gross struct vscsibk_info *info = pending_req->info; 448d9d660f6SJuergen Gross 449d9d660f6SJuergen Gross for (i = 0; i < cnt; i++) { 450d9d660f6SJuergen Gross if (get_free_page(pg + mapcount)) { 451d9d660f6SJuergen Gross put_free_pages(pg, mapcount); 452d9d660f6SJuergen Gross pr_err("xen-pvscsi: no grant page\n"); 453d9d660f6SJuergen Gross return -ENOMEM; 454d9d660f6SJuergen Gross } 455d9d660f6SJuergen Gross gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), 456d9d660f6SJuergen Gross flags, seg[i].gref, info->domid); 457d9d660f6SJuergen Gross mapcount++; 458d9d660f6SJuergen Gross if (mapcount < VSCSI_GRANT_BATCH) 459d9d660f6SJuergen Gross continue; 460d9d660f6SJuergen Gross err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount); 461d9d660f6SJuergen Gross pg += mapcount; 462d9d660f6SJuergen Gross grant += mapcount; 463d9d660f6SJuergen Gross pending_req->n_grants += mapcount; 464d9d660f6SJuergen Gross if (err) 465d9d660f6SJuergen Gross return err; 466d9d660f6SJuergen Gross mapcount = 0; 467d9d660f6SJuergen Gross } 468d9d660f6SJuergen Gross err = scsiback_gnttab_data_map_batch(map, pg, grant, mapcount); 469d9d660f6SJuergen Gross pending_req->n_grants += mapcount; 470d9d660f6SJuergen Gross return err; 471d9d660f6SJuergen Gross } 472d9d660f6SJuergen Gross 473d9d660f6SJuergen Gross static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, 474d9d660f6SJuergen Gross struct vscsibk_pend *pending_req) 475d9d660f6SJuergen Gross { 476d9d660f6SJuergen Gross u32 flags; 477d9d660f6SJuergen Gross int i, err, n_segs, i_seg = 0; 478d9d660f6SJuergen Gross struct page **pg; 479d9d660f6SJuergen Gross struct scsiif_request_segment *seg; 480d9d660f6SJuergen Gross unsigned long end_seg = 0; 481d9d660f6SJuergen Gross unsigned int nr_segments = (unsigned int)ring_req->nr_segments; 482d9d660f6SJuergen Gross unsigned int nr_sgl = 0; 483d9d660f6SJuergen Gross struct scatterlist *sg; 484d9d660f6SJuergen Gross grant_handle_t *grant; 485d9d660f6SJuergen Gross 486d9d660f6SJuergen Gross pending_req->n_sg = 0; 487d9d660f6SJuergen Gross pending_req->n_grants = 0; 488d9d660f6SJuergen Gross pending_req->data_len = 0; 489d9d660f6SJuergen Gross 490d9d660f6SJuergen Gross nr_segments &= ~VSCSIIF_SG_GRANT; 491d9d660f6SJuergen Gross if (!nr_segments) 492d9d660f6SJuergen Gross return 0; 493d9d660f6SJuergen Gross 494d9d660f6SJuergen Gross if (nr_segments > VSCSIIF_SG_TABLESIZE) { 495d9d660f6SJuergen Gross DPRINTK("xen-pvscsi: invalid parameter nr_seg = %d\n", 496d9d660f6SJuergen Gross ring_req->nr_segments); 497d9d660f6SJuergen Gross return -EINVAL; 498d9d660f6SJuergen Gross } 499d9d660f6SJuergen Gross 500d9d660f6SJuergen Gross if (ring_req->nr_segments & VSCSIIF_SG_GRANT) { 501d9d660f6SJuergen Gross err = scsiback_gnttab_data_map_list(pending_req, ring_req->seg, 502d9d660f6SJuergen Gross pending_req->pages, pending_req->grant_handles, 503d9d660f6SJuergen Gross nr_segments, GNTMAP_host_map | GNTMAP_readonly); 504d9d660f6SJuergen Gross if (err) 505d9d660f6SJuergen Gross return err; 506d9d660f6SJuergen Gross nr_sgl = nr_segments; 507d9d660f6SJuergen Gross nr_segments = 0; 508d9d660f6SJuergen Gross for (i = 0; i < nr_sgl; i++) { 509d9d660f6SJuergen Gross n_segs = ring_req->seg[i].length / 510d9d660f6SJuergen Gross sizeof(struct scsiif_request_segment); 511d9d660f6SJuergen Gross if ((unsigned)ring_req->seg[i].offset + 512d9d660f6SJuergen Gross (unsigned)ring_req->seg[i].length > PAGE_SIZE || 513d9d660f6SJuergen Gross n_segs * sizeof(struct scsiif_request_segment) != 514d9d660f6SJuergen Gross ring_req->seg[i].length) 515d9d660f6SJuergen Gross return -EINVAL; 516d9d660f6SJuergen Gross nr_segments += n_segs; 517d9d660f6SJuergen Gross } 518d9d660f6SJuergen Gross if (nr_segments > SG_ALL) { 519d9d660f6SJuergen Gross DPRINTK("xen-pvscsi: invalid nr_seg = %d\n", 520d9d660f6SJuergen Gross nr_segments); 521d9d660f6SJuergen Gross return -EINVAL; 522d9d660f6SJuergen Gross } 523d9d660f6SJuergen Gross } 524d9d660f6SJuergen Gross 525d9d660f6SJuergen Gross /* free of (sgl) in fast_flush_area()*/ 526d9d660f6SJuergen Gross pending_req->sgl = kmalloc_array(nr_segments, 527d9d660f6SJuergen Gross sizeof(struct scatterlist), GFP_KERNEL); 528d9d660f6SJuergen Gross if (!pending_req->sgl) 529d9d660f6SJuergen Gross return -ENOMEM; 530d9d660f6SJuergen Gross 531d9d660f6SJuergen Gross sg_init_table(pending_req->sgl, nr_segments); 532d9d660f6SJuergen Gross pending_req->n_sg = nr_segments; 533d9d660f6SJuergen Gross 534d9d660f6SJuergen Gross flags = GNTMAP_host_map; 535d9d660f6SJuergen Gross if (pending_req->sc_data_direction == DMA_TO_DEVICE) 536d9d660f6SJuergen Gross flags |= GNTMAP_readonly; 537d9d660f6SJuergen Gross 538d9d660f6SJuergen Gross pg = pending_req->pages + nr_sgl; 539d9d660f6SJuergen Gross grant = pending_req->grant_handles + nr_sgl; 540d9d660f6SJuergen Gross if (!nr_sgl) { 541d9d660f6SJuergen Gross seg = ring_req->seg; 542d9d660f6SJuergen Gross err = scsiback_gnttab_data_map_list(pending_req, seg, 543d9d660f6SJuergen Gross pg, grant, nr_segments, flags); 544d9d660f6SJuergen Gross if (err) 545d9d660f6SJuergen Gross return err; 546d9d660f6SJuergen Gross } else { 547d9d660f6SJuergen Gross for (i = 0; i < nr_sgl; i++) { 548d9d660f6SJuergen Gross seg = (struct scsiif_request_segment *)( 549d9d660f6SJuergen Gross vaddr(pending_req, i) + ring_req->seg[i].offset); 550d9d660f6SJuergen Gross n_segs = ring_req->seg[i].length / 551d9d660f6SJuergen Gross sizeof(struct scsiif_request_segment); 552d9d660f6SJuergen Gross err = scsiback_gnttab_data_map_list(pending_req, seg, 553d9d660f6SJuergen Gross pg, grant, n_segs, flags); 554d9d660f6SJuergen Gross if (err) 555d9d660f6SJuergen Gross return err; 556d9d660f6SJuergen Gross pg += n_segs; 557d9d660f6SJuergen Gross grant += n_segs; 558d9d660f6SJuergen Gross } 559d9d660f6SJuergen Gross end_seg = vaddr(pending_req, 0) + ring_req->seg[0].offset; 560d9d660f6SJuergen Gross seg = (struct scsiif_request_segment *)end_seg; 561d9d660f6SJuergen Gross end_seg += ring_req->seg[0].length; 562d9d660f6SJuergen Gross pg = pending_req->pages + nr_sgl; 563d9d660f6SJuergen Gross } 564d9d660f6SJuergen Gross 565d9d660f6SJuergen Gross for_each_sg(pending_req->sgl, sg, nr_segments, i) { 566d9d660f6SJuergen Gross sg_set_page(sg, pg[i], seg->length, seg->offset); 567d9d660f6SJuergen Gross pending_req->data_len += seg->length; 568d9d660f6SJuergen Gross seg++; 569d9d660f6SJuergen Gross if (nr_sgl && (unsigned long)seg >= end_seg) { 570d9d660f6SJuergen Gross i_seg++; 571d9d660f6SJuergen Gross end_seg = vaddr(pending_req, i_seg) + 572d9d660f6SJuergen Gross ring_req->seg[i_seg].offset; 573d9d660f6SJuergen Gross seg = (struct scsiif_request_segment *)end_seg; 574d9d660f6SJuergen Gross end_seg += ring_req->seg[i_seg].length; 575d9d660f6SJuergen Gross } 576d9d660f6SJuergen Gross if (sg->offset >= PAGE_SIZE || 577d9d660f6SJuergen Gross sg->length > PAGE_SIZE || 578d9d660f6SJuergen Gross sg->offset + sg->length > PAGE_SIZE) 579d9d660f6SJuergen Gross return -EINVAL; 580d9d660f6SJuergen Gross } 581d9d660f6SJuergen Gross 582d9d660f6SJuergen Gross return 0; 583d9d660f6SJuergen Gross } 584d9d660f6SJuergen Gross 585d9d660f6SJuergen Gross static void scsiback_disconnect(struct vscsibk_info *info) 586d9d660f6SJuergen Gross { 587d9d660f6SJuergen Gross wait_event(info->waiting_to_free, 588d9d660f6SJuergen Gross atomic_read(&info->nr_unreplied_reqs) == 0); 589d9d660f6SJuergen Gross 590d9d660f6SJuergen Gross unbind_from_irqhandler(info->irq, info); 591d9d660f6SJuergen Gross info->irq = 0; 592d9d660f6SJuergen Gross xenbus_unmap_ring_vfree(info->dev, info->ring.sring); 593d9d660f6SJuergen Gross } 594d9d660f6SJuergen Gross 595d9d660f6SJuergen Gross static void scsiback_device_action(struct vscsibk_pend *pending_req, 596d9d660f6SJuergen Gross enum tcm_tmreq_table act, int tag) 597d9d660f6SJuergen Gross { 598d9d660f6SJuergen Gross int rc, err = FAILED; 599d9d660f6SJuergen Gross struct scsiback_tpg *tpg = pending_req->v2p->tpg; 600d9d660f6SJuergen Gross struct se_cmd *se_cmd = &pending_req->se_cmd; 601d9d660f6SJuergen Gross struct scsiback_tmr *tmr; 602d9d660f6SJuergen Gross 603d9d660f6SJuergen Gross tmr = kzalloc(sizeof(struct scsiback_tmr), GFP_KERNEL); 604d9d660f6SJuergen Gross if (!tmr) 605d9d660f6SJuergen Gross goto out; 606d9d660f6SJuergen Gross 607d9d660f6SJuergen Gross init_waitqueue_head(&tmr->tmr_wait); 608d9d660f6SJuergen Gross 609d9d660f6SJuergen Gross transport_init_se_cmd(se_cmd, tpg->se_tpg.se_tpg_tfo, 61068d81f40SChristoph Hellwig tpg->tpg_nexus->tvn_se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, 611d9d660f6SJuergen Gross &pending_req->sense_buffer[0]); 612d9d660f6SJuergen Gross 613d9d660f6SJuergen Gross rc = core_tmr_alloc_req(se_cmd, tmr, act, GFP_KERNEL); 614d9d660f6SJuergen Gross if (rc < 0) 615d9d660f6SJuergen Gross goto out; 616d9d660f6SJuergen Gross 617d9d660f6SJuergen Gross se_cmd->se_tmr_req->ref_task_tag = tag; 618d9d660f6SJuergen Gross 619d9d660f6SJuergen Gross if (transport_lookup_tmr_lun(se_cmd, pending_req->v2p->lun) < 0) 620d9d660f6SJuergen Gross goto out; 621d9d660f6SJuergen Gross 622d9d660f6SJuergen Gross transport_generic_handle_tmr(se_cmd); 623d9d660f6SJuergen Gross wait_event(tmr->tmr_wait, atomic_read(&tmr->tmr_complete)); 624d9d660f6SJuergen Gross 625d9d660f6SJuergen Gross err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? 626d9d660f6SJuergen Gross SUCCESS : FAILED; 627d9d660f6SJuergen Gross 628d9d660f6SJuergen Gross out: 629d9d660f6SJuergen Gross if (tmr) { 630d9d660f6SJuergen Gross transport_generic_free_cmd(&pending_req->se_cmd, 1); 631d9d660f6SJuergen Gross kfree(tmr); 632d9d660f6SJuergen Gross } 633d9d660f6SJuergen Gross 634d9d660f6SJuergen Gross scsiback_do_resp_with_sense(NULL, err, 0, pending_req); 635d9d660f6SJuergen Gross 636d9d660f6SJuergen Gross kmem_cache_free(scsiback_cachep, pending_req); 637d9d660f6SJuergen Gross } 638d9d660f6SJuergen Gross 639d9d660f6SJuergen Gross /* 640d9d660f6SJuergen Gross Perform virtual to physical translation 641d9d660f6SJuergen Gross */ 642d9d660f6SJuergen Gross static struct v2p_entry *scsiback_do_translation(struct vscsibk_info *info, 643d9d660f6SJuergen Gross struct ids_tuple *v) 644d9d660f6SJuergen Gross { 645d9d660f6SJuergen Gross struct v2p_entry *entry; 646d9d660f6SJuergen Gross struct list_head *head = &(info->v2p_entry_lists); 647d9d660f6SJuergen Gross unsigned long flags; 648d9d660f6SJuergen Gross 649d9d660f6SJuergen Gross spin_lock_irqsave(&info->v2p_lock, flags); 650d9d660f6SJuergen Gross list_for_each_entry(entry, head, l) { 651d9d660f6SJuergen Gross if ((entry->v.chn == v->chn) && 652d9d660f6SJuergen Gross (entry->v.tgt == v->tgt) && 653d9d660f6SJuergen Gross (entry->v.lun == v->lun)) { 654d9d660f6SJuergen Gross kref_get(&entry->kref); 655d9d660f6SJuergen Gross goto out; 656d9d660f6SJuergen Gross } 657d9d660f6SJuergen Gross } 658d9d660f6SJuergen Gross entry = NULL; 659d9d660f6SJuergen Gross 660d9d660f6SJuergen Gross out: 661d9d660f6SJuergen Gross spin_unlock_irqrestore(&info->v2p_lock, flags); 662d9d660f6SJuergen Gross return entry; 663d9d660f6SJuergen Gross } 664d9d660f6SJuergen Gross 665d9d660f6SJuergen Gross static int prepare_pending_reqs(struct vscsibk_info *info, 666d9d660f6SJuergen Gross struct vscsiif_request *ring_req, 667d9d660f6SJuergen Gross struct vscsibk_pend *pending_req) 668d9d660f6SJuergen Gross { 669d9d660f6SJuergen Gross struct v2p_entry *v2p; 670d9d660f6SJuergen Gross struct ids_tuple vir; 671d9d660f6SJuergen Gross 672d9d660f6SJuergen Gross pending_req->rqid = ring_req->rqid; 673d9d660f6SJuergen Gross pending_req->info = info; 674d9d660f6SJuergen Gross 675d9d660f6SJuergen Gross vir.chn = ring_req->channel; 676d9d660f6SJuergen Gross vir.tgt = ring_req->id; 677d9d660f6SJuergen Gross vir.lun = ring_req->lun; 678d9d660f6SJuergen Gross 679d9d660f6SJuergen Gross v2p = scsiback_do_translation(info, &vir); 680d9d660f6SJuergen Gross if (!v2p) { 681d9d660f6SJuergen Gross pending_req->v2p = NULL; 682d9d660f6SJuergen Gross DPRINTK("xen-pvscsi: doesn't exist.\n"); 683d9d660f6SJuergen Gross return -ENODEV; 684d9d660f6SJuergen Gross } 685d9d660f6SJuergen Gross pending_req->v2p = v2p; 686d9d660f6SJuergen Gross 687d9d660f6SJuergen Gross /* request range check from frontend */ 688d9d660f6SJuergen Gross pending_req->sc_data_direction = ring_req->sc_data_direction; 689d9d660f6SJuergen Gross if ((pending_req->sc_data_direction != DMA_BIDIRECTIONAL) && 690d9d660f6SJuergen Gross (pending_req->sc_data_direction != DMA_TO_DEVICE) && 691d9d660f6SJuergen Gross (pending_req->sc_data_direction != DMA_FROM_DEVICE) && 692d9d660f6SJuergen Gross (pending_req->sc_data_direction != DMA_NONE)) { 693d9d660f6SJuergen Gross DPRINTK("xen-pvscsi: invalid parameter data_dir = %d\n", 694d9d660f6SJuergen Gross pending_req->sc_data_direction); 695d9d660f6SJuergen Gross return -EINVAL; 696d9d660f6SJuergen Gross } 697d9d660f6SJuergen Gross 698d9d660f6SJuergen Gross pending_req->cmd_len = ring_req->cmd_len; 699d9d660f6SJuergen Gross if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { 700d9d660f6SJuergen Gross DPRINTK("xen-pvscsi: invalid parameter cmd_len = %d\n", 701d9d660f6SJuergen Gross pending_req->cmd_len); 702d9d660f6SJuergen Gross return -EINVAL; 703d9d660f6SJuergen Gross } 704d9d660f6SJuergen Gross memcpy(pending_req->cmnd, ring_req->cmnd, pending_req->cmd_len); 705d9d660f6SJuergen Gross 706d9d660f6SJuergen Gross return 0; 707d9d660f6SJuergen Gross } 708d9d660f6SJuergen Gross 709d9d660f6SJuergen Gross static int scsiback_do_cmd_fn(struct vscsibk_info *info) 710d9d660f6SJuergen Gross { 711d9d660f6SJuergen Gross struct vscsiif_back_ring *ring = &info->ring; 712*facb5732SJuergen Gross struct vscsiif_request ring_req; 713d9d660f6SJuergen Gross struct vscsibk_pend *pending_req; 714d9d660f6SJuergen Gross RING_IDX rc, rp; 715d9d660f6SJuergen Gross int err, more_to_do; 716d9d660f6SJuergen Gross uint32_t result; 717d9d660f6SJuergen Gross 718d9d660f6SJuergen Gross rc = ring->req_cons; 719d9d660f6SJuergen Gross rp = ring->sring->req_prod; 720d9d660f6SJuergen Gross rmb(); /* guest system is accessing ring, too */ 721d9d660f6SJuergen Gross 722d9d660f6SJuergen Gross if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { 723d9d660f6SJuergen Gross rc = ring->rsp_prod_pvt; 724d9d660f6SJuergen Gross pr_warn("xen-pvscsi: Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", 725d9d660f6SJuergen Gross info->domid, rp, rc, rp - rc); 726d9d660f6SJuergen Gross info->ring_error = 1; 727d9d660f6SJuergen Gross return 0; 728d9d660f6SJuergen Gross } 729d9d660f6SJuergen Gross 730d9d660f6SJuergen Gross while ((rc != rp)) { 731d9d660f6SJuergen Gross if (RING_REQUEST_CONS_OVERFLOW(ring, rc)) 732d9d660f6SJuergen Gross break; 733d9d660f6SJuergen Gross pending_req = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL); 734d9d660f6SJuergen Gross if (!pending_req) 735d9d660f6SJuergen Gross return 1; 736d9d660f6SJuergen Gross 737*facb5732SJuergen Gross ring_req = *RING_GET_REQUEST(ring, rc); 738d9d660f6SJuergen Gross ring->req_cons = ++rc; 739d9d660f6SJuergen Gross 740*facb5732SJuergen Gross err = prepare_pending_reqs(info, &ring_req, pending_req); 741d9d660f6SJuergen Gross if (err) { 742d9d660f6SJuergen Gross switch (err) { 743d9d660f6SJuergen Gross case -ENODEV: 744d9d660f6SJuergen Gross result = DID_NO_CONNECT; 745d9d660f6SJuergen Gross break; 746d9d660f6SJuergen Gross default: 747d9d660f6SJuergen Gross result = DRIVER_ERROR; 748d9d660f6SJuergen Gross break; 749d9d660f6SJuergen Gross } 750d9d660f6SJuergen Gross scsiback_do_resp_with_sense(NULL, result << 24, 0, 751d9d660f6SJuergen Gross pending_req); 752d9d660f6SJuergen Gross kmem_cache_free(scsiback_cachep, pending_req); 753d9d660f6SJuergen Gross return 1; 754d9d660f6SJuergen Gross } 755d9d660f6SJuergen Gross 756*facb5732SJuergen Gross switch (ring_req.act) { 757d9d660f6SJuergen Gross case VSCSIIF_ACT_SCSI_CDB: 758*facb5732SJuergen Gross if (scsiback_gnttab_data_map(&ring_req, pending_req)) { 759d9d660f6SJuergen Gross scsiback_fast_flush_area(pending_req); 760d9d660f6SJuergen Gross scsiback_do_resp_with_sense(NULL, 761d9d660f6SJuergen Gross DRIVER_ERROR << 24, 0, pending_req); 762d9d660f6SJuergen Gross kmem_cache_free(scsiback_cachep, pending_req); 763d9d660f6SJuergen Gross } else { 764d9d660f6SJuergen Gross scsiback_cmd_exec(pending_req); 765d9d660f6SJuergen Gross } 766d9d660f6SJuergen Gross break; 767d9d660f6SJuergen Gross case VSCSIIF_ACT_SCSI_ABORT: 768d9d660f6SJuergen Gross scsiback_device_action(pending_req, TMR_ABORT_TASK, 769*facb5732SJuergen Gross ring_req.ref_rqid); 770d9d660f6SJuergen Gross break; 771d9d660f6SJuergen Gross case VSCSIIF_ACT_SCSI_RESET: 772d9d660f6SJuergen Gross scsiback_device_action(pending_req, TMR_LUN_RESET, 0); 773d9d660f6SJuergen Gross break; 774d9d660f6SJuergen Gross default: 775d9d660f6SJuergen Gross pr_err_ratelimited("xen-pvscsi: invalid request\n"); 776d9d660f6SJuergen Gross scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, 777d9d660f6SJuergen Gross 0, pending_req); 778d9d660f6SJuergen Gross kmem_cache_free(scsiback_cachep, pending_req); 779d9d660f6SJuergen Gross break; 780d9d660f6SJuergen Gross } 781d9d660f6SJuergen Gross 782d9d660f6SJuergen Gross /* Yield point for this unbounded loop. */ 783d9d660f6SJuergen Gross cond_resched(); 784d9d660f6SJuergen Gross } 785d9d660f6SJuergen Gross 786d9d660f6SJuergen Gross RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do); 787d9d660f6SJuergen Gross return more_to_do; 788d9d660f6SJuergen Gross } 789d9d660f6SJuergen Gross 790d9d660f6SJuergen Gross static irqreturn_t scsiback_irq_fn(int irq, void *dev_id) 791d9d660f6SJuergen Gross { 792d9d660f6SJuergen Gross struct vscsibk_info *info = dev_id; 793d9d660f6SJuergen Gross 794d9d660f6SJuergen Gross if (info->ring_error) 795d9d660f6SJuergen Gross return IRQ_HANDLED; 796d9d660f6SJuergen Gross 797d9d660f6SJuergen Gross while (scsiback_do_cmd_fn(info)) 798d9d660f6SJuergen Gross cond_resched(); 799d9d660f6SJuergen Gross 800d9d660f6SJuergen Gross return IRQ_HANDLED; 801d9d660f6SJuergen Gross } 802d9d660f6SJuergen Gross 803d9d660f6SJuergen Gross static int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref, 804d9d660f6SJuergen Gross evtchn_port_t evtchn) 805d9d660f6SJuergen Gross { 806d9d660f6SJuergen Gross void *area; 807d9d660f6SJuergen Gross struct vscsiif_sring *sring; 808d9d660f6SJuergen Gross int err; 809d9d660f6SJuergen Gross 810d9d660f6SJuergen Gross if (info->irq) 811d9d660f6SJuergen Gross return -1; 812d9d660f6SJuergen Gross 813d9d660f6SJuergen Gross err = xenbus_map_ring_valloc(info->dev, ring_ref, &area); 814d9d660f6SJuergen Gross if (err) 815d9d660f6SJuergen Gross return err; 816d9d660f6SJuergen Gross 817d9d660f6SJuergen Gross sring = (struct vscsiif_sring *)area; 818d9d660f6SJuergen Gross BACK_RING_INIT(&info->ring, sring, PAGE_SIZE); 819d9d660f6SJuergen Gross 820d9d660f6SJuergen Gross err = bind_interdomain_evtchn_to_irq(info->domid, evtchn); 821d9d660f6SJuergen Gross if (err < 0) 822d9d660f6SJuergen Gross goto unmap_page; 823d9d660f6SJuergen Gross 824d9d660f6SJuergen Gross info->irq = err; 825d9d660f6SJuergen Gross 826d9d660f6SJuergen Gross err = request_threaded_irq(info->irq, NULL, scsiback_irq_fn, 827d9d660f6SJuergen Gross IRQF_ONESHOT, "vscsiif-backend", info); 828d9d660f6SJuergen Gross if (err) 829d9d660f6SJuergen Gross goto free_irq; 830d9d660f6SJuergen Gross 831d9d660f6SJuergen Gross return 0; 832d9d660f6SJuergen Gross 833d9d660f6SJuergen Gross free_irq: 834d9d660f6SJuergen Gross unbind_from_irqhandler(info->irq, info); 835d9d660f6SJuergen Gross info->irq = 0; 836d9d660f6SJuergen Gross unmap_page: 837d9d660f6SJuergen Gross xenbus_unmap_ring_vfree(info->dev, area); 838d9d660f6SJuergen Gross 839d9d660f6SJuergen Gross return err; 840d9d660f6SJuergen Gross } 841d9d660f6SJuergen Gross 842d9d660f6SJuergen Gross static int scsiback_map(struct vscsibk_info *info) 843d9d660f6SJuergen Gross { 844d9d660f6SJuergen Gross struct xenbus_device *dev = info->dev; 845d9d660f6SJuergen Gross unsigned int ring_ref, evtchn; 846d9d660f6SJuergen Gross int err; 847d9d660f6SJuergen Gross 848d9d660f6SJuergen Gross err = xenbus_gather(XBT_NIL, dev->otherend, 849d9d660f6SJuergen Gross "ring-ref", "%u", &ring_ref, 850d9d660f6SJuergen Gross "event-channel", "%u", &evtchn, NULL); 851d9d660f6SJuergen Gross if (err) { 852d9d660f6SJuergen Gross xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend); 853d9d660f6SJuergen Gross return err; 854d9d660f6SJuergen Gross } 855d9d660f6SJuergen Gross 856d9d660f6SJuergen Gross return scsiback_init_sring(info, ring_ref, evtchn); 857d9d660f6SJuergen Gross } 858d9d660f6SJuergen Gross 859d9d660f6SJuergen Gross /* 860d9d660f6SJuergen Gross Add a new translation entry 861d9d660f6SJuergen Gross */ 862d9d660f6SJuergen Gross static int scsiback_add_translation_entry(struct vscsibk_info *info, 863d9d660f6SJuergen Gross char *phy, struct ids_tuple *v) 864d9d660f6SJuergen Gross { 865d9d660f6SJuergen Gross int err = 0; 866d9d660f6SJuergen Gross struct v2p_entry *entry; 867d9d660f6SJuergen Gross struct v2p_entry *new; 868d9d660f6SJuergen Gross struct list_head *head = &(info->v2p_entry_lists); 869d9d660f6SJuergen Gross unsigned long flags; 870d9d660f6SJuergen Gross char *lunp; 871d9d660f6SJuergen Gross unsigned int lun; 872d9d660f6SJuergen Gross struct scsiback_tpg *tpg_entry, *tpg = NULL; 873d9d660f6SJuergen Gross char *error = "doesn't exist"; 874d9d660f6SJuergen Gross 875d9d660f6SJuergen Gross lunp = strrchr(phy, ':'); 876d9d660f6SJuergen Gross if (!lunp) { 877d9d660f6SJuergen Gross pr_err("xen-pvscsi: illegal format of physical device %s\n", 878d9d660f6SJuergen Gross phy); 879d9d660f6SJuergen Gross return -EINVAL; 880d9d660f6SJuergen Gross } 881d9d660f6SJuergen Gross *lunp = 0; 882d9d660f6SJuergen Gross lunp++; 883d9d660f6SJuergen Gross if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { 884d9d660f6SJuergen Gross pr_err("xen-pvscsi: lun number not valid: %s\n", lunp); 885d9d660f6SJuergen Gross return -EINVAL; 886d9d660f6SJuergen Gross } 887d9d660f6SJuergen Gross 888d9d660f6SJuergen Gross mutex_lock(&scsiback_mutex); 889d9d660f6SJuergen Gross list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) { 890d9d660f6SJuergen Gross if (!strcmp(phy, tpg_entry->tport->tport_name) || 891d9d660f6SJuergen Gross !strcmp(phy, tpg_entry->param_alias)) { 892d9d660f6SJuergen Gross spin_lock(&tpg_entry->se_tpg.tpg_lun_lock); 893d9d660f6SJuergen Gross if (tpg_entry->se_tpg.tpg_lun_list[lun]->lun_status == 894d9d660f6SJuergen Gross TRANSPORT_LUN_STATUS_ACTIVE) { 895d9d660f6SJuergen Gross if (!tpg_entry->tpg_nexus) 896d9d660f6SJuergen Gross error = "nexus undefined"; 897d9d660f6SJuergen Gross else 898d9d660f6SJuergen Gross tpg = tpg_entry; 899d9d660f6SJuergen Gross } 900d9d660f6SJuergen Gross spin_unlock(&tpg_entry->se_tpg.tpg_lun_lock); 901d9d660f6SJuergen Gross break; 902d9d660f6SJuergen Gross } 903d9d660f6SJuergen Gross } 904d9d660f6SJuergen Gross if (tpg) { 905d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 906d9d660f6SJuergen Gross tpg->tv_tpg_fe_count++; 907d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 908d9d660f6SJuergen Gross } 909d9d660f6SJuergen Gross mutex_unlock(&scsiback_mutex); 910d9d660f6SJuergen Gross 911d9d660f6SJuergen Gross if (!tpg) { 912d9d660f6SJuergen Gross pr_err("xen-pvscsi: %s:%d %s\n", phy, lun, error); 913d9d660f6SJuergen Gross return -ENODEV; 914d9d660f6SJuergen Gross } 915d9d660f6SJuergen Gross 916d9d660f6SJuergen Gross new = kmalloc(sizeof(struct v2p_entry), GFP_KERNEL); 917d9d660f6SJuergen Gross if (new == NULL) { 918d9d660f6SJuergen Gross err = -ENOMEM; 919d9d660f6SJuergen Gross goto out_free; 920d9d660f6SJuergen Gross } 921d9d660f6SJuergen Gross 922d9d660f6SJuergen Gross spin_lock_irqsave(&info->v2p_lock, flags); 923d9d660f6SJuergen Gross 924d9d660f6SJuergen Gross /* Check double assignment to identical virtual ID */ 925d9d660f6SJuergen Gross list_for_each_entry(entry, head, l) { 926d9d660f6SJuergen Gross if ((entry->v.chn == v->chn) && 927d9d660f6SJuergen Gross (entry->v.tgt == v->tgt) && 928d9d660f6SJuergen Gross (entry->v.lun == v->lun)) { 929d9d660f6SJuergen Gross pr_warn("xen-pvscsi: Virtual ID is already used. Assignment was not performed.\n"); 930d9d660f6SJuergen Gross err = -EEXIST; 931d9d660f6SJuergen Gross goto out; 932d9d660f6SJuergen Gross } 933d9d660f6SJuergen Gross 934d9d660f6SJuergen Gross } 935d9d660f6SJuergen Gross 936d9d660f6SJuergen Gross /* Create a new translation entry and add to the list */ 937d9d660f6SJuergen Gross kref_init(&new->kref); 938d9d660f6SJuergen Gross new->v = *v; 939d9d660f6SJuergen Gross new->tpg = tpg; 940d9d660f6SJuergen Gross new->lun = lun; 941d9d660f6SJuergen Gross list_add_tail(&new->l, head); 942d9d660f6SJuergen Gross 943d9d660f6SJuergen Gross out: 944d9d660f6SJuergen Gross spin_unlock_irqrestore(&info->v2p_lock, flags); 945d9d660f6SJuergen Gross 946d9d660f6SJuergen Gross out_free: 947d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 948d9d660f6SJuergen Gross tpg->tv_tpg_fe_count--; 949d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 950d9d660f6SJuergen Gross 951d9d660f6SJuergen Gross if (err) 952d9d660f6SJuergen Gross kfree(new); 953d9d660f6SJuergen Gross 954d9d660f6SJuergen Gross return err; 955d9d660f6SJuergen Gross } 956d9d660f6SJuergen Gross 957d9d660f6SJuergen Gross static void __scsiback_del_translation_entry(struct v2p_entry *entry) 958d9d660f6SJuergen Gross { 959d9d660f6SJuergen Gross list_del(&entry->l); 960d9d660f6SJuergen Gross kref_put(&entry->kref, scsiback_free_translation_entry); 961d9d660f6SJuergen Gross } 962d9d660f6SJuergen Gross 963d9d660f6SJuergen Gross /* 964d9d660f6SJuergen Gross Delete the translation entry specfied 965d9d660f6SJuergen Gross */ 966d9d660f6SJuergen Gross static int scsiback_del_translation_entry(struct vscsibk_info *info, 967d9d660f6SJuergen Gross struct ids_tuple *v) 968d9d660f6SJuergen Gross { 969d9d660f6SJuergen Gross struct v2p_entry *entry; 970d9d660f6SJuergen Gross struct list_head *head = &(info->v2p_entry_lists); 971d9d660f6SJuergen Gross unsigned long flags; 972d9d660f6SJuergen Gross 973d9d660f6SJuergen Gross spin_lock_irqsave(&info->v2p_lock, flags); 974d9d660f6SJuergen Gross /* Find out the translation entry specified */ 975d9d660f6SJuergen Gross list_for_each_entry(entry, head, l) { 976d9d660f6SJuergen Gross if ((entry->v.chn == v->chn) && 977d9d660f6SJuergen Gross (entry->v.tgt == v->tgt) && 978d9d660f6SJuergen Gross (entry->v.lun == v->lun)) { 979d9d660f6SJuergen Gross goto found; 980d9d660f6SJuergen Gross } 981d9d660f6SJuergen Gross } 982d9d660f6SJuergen Gross 983d9d660f6SJuergen Gross spin_unlock_irqrestore(&info->v2p_lock, flags); 984d9d660f6SJuergen Gross return 1; 985d9d660f6SJuergen Gross 986d9d660f6SJuergen Gross found: 987d9d660f6SJuergen Gross /* Delete the translation entry specfied */ 988d9d660f6SJuergen Gross __scsiback_del_translation_entry(entry); 989d9d660f6SJuergen Gross 990d9d660f6SJuergen Gross spin_unlock_irqrestore(&info->v2p_lock, flags); 991d9d660f6SJuergen Gross return 0; 992d9d660f6SJuergen Gross } 993d9d660f6SJuergen Gross 994d9d660f6SJuergen Gross static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, 995d9d660f6SJuergen Gross char *phy, struct ids_tuple *vir) 996d9d660f6SJuergen Gross { 997d9d660f6SJuergen Gross if (!scsiback_add_translation_entry(info, phy, vir)) { 998d9d660f6SJuergen Gross if (xenbus_printf(XBT_NIL, info->dev->nodename, state, 999d9d660f6SJuergen Gross "%d", XenbusStateInitialised)) { 1000d9d660f6SJuergen Gross pr_err("xen-pvscsi: xenbus_printf error %s\n", state); 1001d9d660f6SJuergen Gross scsiback_del_translation_entry(info, vir); 1002d9d660f6SJuergen Gross } 1003d9d660f6SJuergen Gross } else { 1004d9d660f6SJuergen Gross xenbus_printf(XBT_NIL, info->dev->nodename, state, 1005d9d660f6SJuergen Gross "%d", XenbusStateClosed); 1006d9d660f6SJuergen Gross } 1007d9d660f6SJuergen Gross } 1008d9d660f6SJuergen Gross 1009d9d660f6SJuergen Gross static void scsiback_do_del_lun(struct vscsibk_info *info, const char *state, 1010d9d660f6SJuergen Gross struct ids_tuple *vir) 1011d9d660f6SJuergen Gross { 1012d9d660f6SJuergen Gross if (!scsiback_del_translation_entry(info, vir)) { 1013d9d660f6SJuergen Gross if (xenbus_printf(XBT_NIL, info->dev->nodename, state, 1014d9d660f6SJuergen Gross "%d", XenbusStateClosed)) 1015d9d660f6SJuergen Gross pr_err("xen-pvscsi: xenbus_printf error %s\n", state); 1016d9d660f6SJuergen Gross } 1017d9d660f6SJuergen Gross } 1018d9d660f6SJuergen Gross 1019d9d660f6SJuergen Gross #define VSCSIBACK_OP_ADD_OR_DEL_LUN 1 1020d9d660f6SJuergen Gross #define VSCSIBACK_OP_UPDATEDEV_STATE 2 1021d9d660f6SJuergen Gross 1022d9d660f6SJuergen Gross static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, 1023d9d660f6SJuergen Gross char *ent) 1024d9d660f6SJuergen Gross { 1025d9d660f6SJuergen Gross int err; 1026d9d660f6SJuergen Gross struct ids_tuple vir; 1027d9d660f6SJuergen Gross char *val; 1028d9d660f6SJuergen Gross int device_state; 1029d9d660f6SJuergen Gross char phy[VSCSI_NAMELEN]; 1030d9d660f6SJuergen Gross char str[64]; 1031d9d660f6SJuergen Gross char state[64]; 1032d9d660f6SJuergen Gross struct xenbus_device *dev = info->dev; 1033d9d660f6SJuergen Gross 1034d9d660f6SJuergen Gross /* read status */ 1035d9d660f6SJuergen Gross snprintf(state, sizeof(state), "vscsi-devs/%s/state", ent); 1036d9d660f6SJuergen Gross err = xenbus_scanf(XBT_NIL, dev->nodename, state, "%u", &device_state); 1037d9d660f6SJuergen Gross if (XENBUS_EXIST_ERR(err)) 1038d9d660f6SJuergen Gross return; 1039d9d660f6SJuergen Gross 1040d9d660f6SJuergen Gross /* physical SCSI device */ 1041d9d660f6SJuergen Gross snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent); 1042d9d660f6SJuergen Gross val = xenbus_read(XBT_NIL, dev->nodename, str, NULL); 1043d9d660f6SJuergen Gross if (IS_ERR(val)) { 1044d9d660f6SJuergen Gross xenbus_printf(XBT_NIL, dev->nodename, state, 1045d9d660f6SJuergen Gross "%d", XenbusStateClosed); 1046d9d660f6SJuergen Gross return; 1047d9d660f6SJuergen Gross } 1048d9d660f6SJuergen Gross strlcpy(phy, val, VSCSI_NAMELEN); 1049d9d660f6SJuergen Gross kfree(val); 1050d9d660f6SJuergen Gross 1051d9d660f6SJuergen Gross /* virtual SCSI device */ 1052d9d660f6SJuergen Gross snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", ent); 1053d9d660f6SJuergen Gross err = xenbus_scanf(XBT_NIL, dev->nodename, str, "%u:%u:%u:%u", 1054d9d660f6SJuergen Gross &vir.hst, &vir.chn, &vir.tgt, &vir.lun); 1055d9d660f6SJuergen Gross if (XENBUS_EXIST_ERR(err)) { 1056d9d660f6SJuergen Gross xenbus_printf(XBT_NIL, dev->nodename, state, 1057d9d660f6SJuergen Gross "%d", XenbusStateClosed); 1058d9d660f6SJuergen Gross return; 1059d9d660f6SJuergen Gross } 1060d9d660f6SJuergen Gross 1061d9d660f6SJuergen Gross switch (op) { 1062d9d660f6SJuergen Gross case VSCSIBACK_OP_ADD_OR_DEL_LUN: 1063d9d660f6SJuergen Gross if (device_state == XenbusStateInitialising) 1064d9d660f6SJuergen Gross scsiback_do_add_lun(info, state, phy, &vir); 1065d9d660f6SJuergen Gross if (device_state == XenbusStateClosing) 1066d9d660f6SJuergen Gross scsiback_do_del_lun(info, state, &vir); 1067d9d660f6SJuergen Gross break; 1068d9d660f6SJuergen Gross 1069d9d660f6SJuergen Gross case VSCSIBACK_OP_UPDATEDEV_STATE: 1070d9d660f6SJuergen Gross if (device_state == XenbusStateInitialised) { 1071d9d660f6SJuergen Gross /* modify vscsi-devs/dev-x/state */ 1072d9d660f6SJuergen Gross if (xenbus_printf(XBT_NIL, dev->nodename, state, 1073d9d660f6SJuergen Gross "%d", XenbusStateConnected)) { 1074d9d660f6SJuergen Gross pr_err("xen-pvscsi: xenbus_printf error %s\n", 1075d9d660f6SJuergen Gross str); 1076d9d660f6SJuergen Gross scsiback_del_translation_entry(info, &vir); 1077d9d660f6SJuergen Gross xenbus_printf(XBT_NIL, dev->nodename, state, 1078d9d660f6SJuergen Gross "%d", XenbusStateClosed); 1079d9d660f6SJuergen Gross } 1080d9d660f6SJuergen Gross } 1081d9d660f6SJuergen Gross break; 1082d9d660f6SJuergen Gross /*When it is necessary, processing is added here.*/ 1083d9d660f6SJuergen Gross default: 1084d9d660f6SJuergen Gross break; 1085d9d660f6SJuergen Gross } 1086d9d660f6SJuergen Gross } 1087d9d660f6SJuergen Gross 1088d9d660f6SJuergen Gross static void scsiback_do_lun_hotplug(struct vscsibk_info *info, int op) 1089d9d660f6SJuergen Gross { 1090d9d660f6SJuergen Gross int i; 1091d9d660f6SJuergen Gross char **dir; 1092d9d660f6SJuergen Gross unsigned int ndir = 0; 1093d9d660f6SJuergen Gross 1094d9d660f6SJuergen Gross dir = xenbus_directory(XBT_NIL, info->dev->nodename, "vscsi-devs", 1095d9d660f6SJuergen Gross &ndir); 1096d9d660f6SJuergen Gross if (IS_ERR(dir)) 1097d9d660f6SJuergen Gross return; 1098d9d660f6SJuergen Gross 1099d9d660f6SJuergen Gross for (i = 0; i < ndir; i++) 1100d9d660f6SJuergen Gross scsiback_do_1lun_hotplug(info, op, dir[i]); 1101d9d660f6SJuergen Gross 1102d9d660f6SJuergen Gross kfree(dir); 1103d9d660f6SJuergen Gross } 1104d9d660f6SJuergen Gross 1105d9d660f6SJuergen Gross static void scsiback_frontend_changed(struct xenbus_device *dev, 1106d9d660f6SJuergen Gross enum xenbus_state frontend_state) 1107d9d660f6SJuergen Gross { 1108d9d660f6SJuergen Gross struct vscsibk_info *info = dev_get_drvdata(&dev->dev); 1109d9d660f6SJuergen Gross 1110d9d660f6SJuergen Gross switch (frontend_state) { 1111d9d660f6SJuergen Gross case XenbusStateInitialising: 1112d9d660f6SJuergen Gross break; 1113d9d660f6SJuergen Gross 1114d9d660f6SJuergen Gross case XenbusStateInitialised: 1115d9d660f6SJuergen Gross if (scsiback_map(info)) 1116d9d660f6SJuergen Gross break; 1117d9d660f6SJuergen Gross 1118d9d660f6SJuergen Gross scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN); 1119d9d660f6SJuergen Gross xenbus_switch_state(dev, XenbusStateConnected); 1120d9d660f6SJuergen Gross break; 1121d9d660f6SJuergen Gross 1122d9d660f6SJuergen Gross case XenbusStateConnected: 1123d9d660f6SJuergen Gross scsiback_do_lun_hotplug(info, VSCSIBACK_OP_UPDATEDEV_STATE); 1124d9d660f6SJuergen Gross 1125d9d660f6SJuergen Gross if (dev->state == XenbusStateConnected) 1126d9d660f6SJuergen Gross break; 1127d9d660f6SJuergen Gross 1128d9d660f6SJuergen Gross xenbus_switch_state(dev, XenbusStateConnected); 1129d9d660f6SJuergen Gross break; 1130d9d660f6SJuergen Gross 1131d9d660f6SJuergen Gross case XenbusStateClosing: 1132d9d660f6SJuergen Gross if (info->irq) 1133d9d660f6SJuergen Gross scsiback_disconnect(info); 1134d9d660f6SJuergen Gross 1135d9d660f6SJuergen Gross xenbus_switch_state(dev, XenbusStateClosing); 1136d9d660f6SJuergen Gross break; 1137d9d660f6SJuergen Gross 1138d9d660f6SJuergen Gross case XenbusStateClosed: 1139d9d660f6SJuergen Gross xenbus_switch_state(dev, XenbusStateClosed); 1140d9d660f6SJuergen Gross if (xenbus_dev_is_online(dev)) 1141d9d660f6SJuergen Gross break; 1142d9d660f6SJuergen Gross /* fall through if not online */ 1143d9d660f6SJuergen Gross case XenbusStateUnknown: 1144d9d660f6SJuergen Gross device_unregister(&dev->dev); 1145d9d660f6SJuergen Gross break; 1146d9d660f6SJuergen Gross 1147d9d660f6SJuergen Gross case XenbusStateReconfiguring: 1148d9d660f6SJuergen Gross scsiback_do_lun_hotplug(info, VSCSIBACK_OP_ADD_OR_DEL_LUN); 1149d9d660f6SJuergen Gross xenbus_switch_state(dev, XenbusStateReconfigured); 1150d9d660f6SJuergen Gross 1151d9d660f6SJuergen Gross break; 1152d9d660f6SJuergen Gross 1153d9d660f6SJuergen Gross default: 1154d9d660f6SJuergen Gross xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", 1155d9d660f6SJuergen Gross frontend_state); 1156d9d660f6SJuergen Gross break; 1157d9d660f6SJuergen Gross } 1158d9d660f6SJuergen Gross } 1159d9d660f6SJuergen Gross 1160d9d660f6SJuergen Gross /* 1161d9d660f6SJuergen Gross Release the translation entry specfied 1162d9d660f6SJuergen Gross */ 1163d9d660f6SJuergen Gross static void scsiback_release_translation_entry(struct vscsibk_info *info) 1164d9d660f6SJuergen Gross { 1165d9d660f6SJuergen Gross struct v2p_entry *entry, *tmp; 1166d9d660f6SJuergen Gross struct list_head *head = &(info->v2p_entry_lists); 1167d9d660f6SJuergen Gross unsigned long flags; 1168d9d660f6SJuergen Gross 1169d9d660f6SJuergen Gross spin_lock_irqsave(&info->v2p_lock, flags); 1170d9d660f6SJuergen Gross 1171d9d660f6SJuergen Gross list_for_each_entry_safe(entry, tmp, head, l) 1172d9d660f6SJuergen Gross __scsiback_del_translation_entry(entry); 1173d9d660f6SJuergen Gross 1174d9d660f6SJuergen Gross spin_unlock_irqrestore(&info->v2p_lock, flags); 1175d9d660f6SJuergen Gross } 1176d9d660f6SJuergen Gross 1177d9d660f6SJuergen Gross static int scsiback_remove(struct xenbus_device *dev) 1178d9d660f6SJuergen Gross { 1179d9d660f6SJuergen Gross struct vscsibk_info *info = dev_get_drvdata(&dev->dev); 1180d9d660f6SJuergen Gross 1181d9d660f6SJuergen Gross if (info->irq) 1182d9d660f6SJuergen Gross scsiback_disconnect(info); 1183d9d660f6SJuergen Gross 1184d9d660f6SJuergen Gross scsiback_release_translation_entry(info); 1185d9d660f6SJuergen Gross 1186d9d660f6SJuergen Gross dev_set_drvdata(&dev->dev, NULL); 1187d9d660f6SJuergen Gross 1188d9d660f6SJuergen Gross return 0; 1189d9d660f6SJuergen Gross } 1190d9d660f6SJuergen Gross 1191d9d660f6SJuergen Gross static int scsiback_probe(struct xenbus_device *dev, 1192d9d660f6SJuergen Gross const struct xenbus_device_id *id) 1193d9d660f6SJuergen Gross { 1194d9d660f6SJuergen Gross int err; 1195d9d660f6SJuergen Gross 1196d9d660f6SJuergen Gross struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), 1197d9d660f6SJuergen Gross GFP_KERNEL); 1198d9d660f6SJuergen Gross 1199d9d660f6SJuergen Gross DPRINTK("%p %d\n", dev, dev->otherend_id); 1200d9d660f6SJuergen Gross 1201d9d660f6SJuergen Gross if (!info) { 1202d9d660f6SJuergen Gross xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); 1203d9d660f6SJuergen Gross return -ENOMEM; 1204d9d660f6SJuergen Gross } 1205d9d660f6SJuergen Gross info->dev = dev; 1206d9d660f6SJuergen Gross dev_set_drvdata(&dev->dev, info); 1207d9d660f6SJuergen Gross 1208d9d660f6SJuergen Gross info->domid = dev->otherend_id; 1209d9d660f6SJuergen Gross spin_lock_init(&info->ring_lock); 1210d9d660f6SJuergen Gross info->ring_error = 0; 1211d9d660f6SJuergen Gross atomic_set(&info->nr_unreplied_reqs, 0); 1212d9d660f6SJuergen Gross init_waitqueue_head(&info->waiting_to_free); 1213d9d660f6SJuergen Gross info->dev = dev; 1214d9d660f6SJuergen Gross info->irq = 0; 1215d9d660f6SJuergen Gross INIT_LIST_HEAD(&info->v2p_entry_lists); 1216d9d660f6SJuergen Gross spin_lock_init(&info->v2p_lock); 1217d9d660f6SJuergen Gross 1218d9d660f6SJuergen Gross err = xenbus_printf(XBT_NIL, dev->nodename, "feature-sg-grant", "%u", 1219d9d660f6SJuergen Gross SG_ALL); 1220d9d660f6SJuergen Gross if (err) 1221d9d660f6SJuergen Gross xenbus_dev_error(dev, err, "writing feature-sg-grant"); 1222d9d660f6SJuergen Gross 1223d9d660f6SJuergen Gross err = xenbus_switch_state(dev, XenbusStateInitWait); 1224d9d660f6SJuergen Gross if (err) 1225d9d660f6SJuergen Gross goto fail; 1226d9d660f6SJuergen Gross 1227d9d660f6SJuergen Gross return 0; 1228d9d660f6SJuergen Gross 1229d9d660f6SJuergen Gross fail: 1230d9d660f6SJuergen Gross pr_warn("xen-pvscsi: %s failed\n", __func__); 1231d9d660f6SJuergen Gross scsiback_remove(dev); 1232d9d660f6SJuergen Gross 1233d9d660f6SJuergen Gross return err; 1234d9d660f6SJuergen Gross } 1235d9d660f6SJuergen Gross 1236d9d660f6SJuergen Gross static char *scsiback_dump_proto_id(struct scsiback_tport *tport) 1237d9d660f6SJuergen Gross { 1238d9d660f6SJuergen Gross switch (tport->tport_proto_id) { 1239d9d660f6SJuergen Gross case SCSI_PROTOCOL_SAS: 1240d9d660f6SJuergen Gross return "SAS"; 1241d9d660f6SJuergen Gross case SCSI_PROTOCOL_FCP: 1242d9d660f6SJuergen Gross return "FCP"; 1243d9d660f6SJuergen Gross case SCSI_PROTOCOL_ISCSI: 1244d9d660f6SJuergen Gross return "iSCSI"; 1245d9d660f6SJuergen Gross default: 1246d9d660f6SJuergen Gross break; 1247d9d660f6SJuergen Gross } 1248d9d660f6SJuergen Gross 1249d9d660f6SJuergen Gross return "Unknown"; 1250d9d660f6SJuergen Gross } 1251d9d660f6SJuergen Gross 1252d9d660f6SJuergen Gross static u8 scsiback_get_fabric_proto_ident(struct se_portal_group *se_tpg) 1253d9d660f6SJuergen Gross { 1254d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1255d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1256d9d660f6SJuergen Gross struct scsiback_tport *tport = tpg->tport; 1257d9d660f6SJuergen Gross 1258d9d660f6SJuergen Gross switch (tport->tport_proto_id) { 1259d9d660f6SJuergen Gross case SCSI_PROTOCOL_SAS: 1260d9d660f6SJuergen Gross return sas_get_fabric_proto_ident(se_tpg); 1261d9d660f6SJuergen Gross case SCSI_PROTOCOL_FCP: 1262d9d660f6SJuergen Gross return fc_get_fabric_proto_ident(se_tpg); 1263d9d660f6SJuergen Gross case SCSI_PROTOCOL_ISCSI: 1264d9d660f6SJuergen Gross return iscsi_get_fabric_proto_ident(se_tpg); 1265d9d660f6SJuergen Gross default: 1266d9d660f6SJuergen Gross pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", 1267d9d660f6SJuergen Gross tport->tport_proto_id); 1268d9d660f6SJuergen Gross break; 1269d9d660f6SJuergen Gross } 1270d9d660f6SJuergen Gross 1271d9d660f6SJuergen Gross return sas_get_fabric_proto_ident(se_tpg); 1272d9d660f6SJuergen Gross } 1273d9d660f6SJuergen Gross 1274d9d660f6SJuergen Gross static char *scsiback_get_fabric_wwn(struct se_portal_group *se_tpg) 1275d9d660f6SJuergen Gross { 1276d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1277d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1278d9d660f6SJuergen Gross struct scsiback_tport *tport = tpg->tport; 1279d9d660f6SJuergen Gross 1280d9d660f6SJuergen Gross return &tport->tport_name[0]; 1281d9d660f6SJuergen Gross } 1282d9d660f6SJuergen Gross 1283d9d660f6SJuergen Gross static u16 scsiback_get_tag(struct se_portal_group *se_tpg) 1284d9d660f6SJuergen Gross { 1285d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1286d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1287d9d660f6SJuergen Gross return tpg->tport_tpgt; 1288d9d660f6SJuergen Gross } 1289d9d660f6SJuergen Gross 1290d9d660f6SJuergen Gross static u32 scsiback_get_default_depth(struct se_portal_group *se_tpg) 1291d9d660f6SJuergen Gross { 1292d9d660f6SJuergen Gross return 1; 1293d9d660f6SJuergen Gross } 1294d9d660f6SJuergen Gross 1295d9d660f6SJuergen Gross static u32 1296d9d660f6SJuergen Gross scsiback_get_pr_transport_id(struct se_portal_group *se_tpg, 1297d9d660f6SJuergen Gross struct se_node_acl *se_nacl, 1298d9d660f6SJuergen Gross struct t10_pr_registration *pr_reg, 1299d9d660f6SJuergen Gross int *format_code, 1300d9d660f6SJuergen Gross unsigned char *buf) 1301d9d660f6SJuergen Gross { 1302d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1303d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1304d9d660f6SJuergen Gross struct scsiback_tport *tport = tpg->tport; 1305d9d660f6SJuergen Gross 1306d9d660f6SJuergen Gross switch (tport->tport_proto_id) { 1307d9d660f6SJuergen Gross case SCSI_PROTOCOL_SAS: 1308d9d660f6SJuergen Gross return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 1309d9d660f6SJuergen Gross format_code, buf); 1310d9d660f6SJuergen Gross case SCSI_PROTOCOL_FCP: 1311d9d660f6SJuergen Gross return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 1312d9d660f6SJuergen Gross format_code, buf); 1313d9d660f6SJuergen Gross case SCSI_PROTOCOL_ISCSI: 1314d9d660f6SJuergen Gross return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 1315d9d660f6SJuergen Gross format_code, buf); 1316d9d660f6SJuergen Gross default: 1317d9d660f6SJuergen Gross pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", 1318d9d660f6SJuergen Gross tport->tport_proto_id); 1319d9d660f6SJuergen Gross break; 1320d9d660f6SJuergen Gross } 1321d9d660f6SJuergen Gross 1322d9d660f6SJuergen Gross return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 1323d9d660f6SJuergen Gross format_code, buf); 1324d9d660f6SJuergen Gross } 1325d9d660f6SJuergen Gross 1326d9d660f6SJuergen Gross static u32 1327d9d660f6SJuergen Gross scsiback_get_pr_transport_id_len(struct se_portal_group *se_tpg, 1328d9d660f6SJuergen Gross struct se_node_acl *se_nacl, 1329d9d660f6SJuergen Gross struct t10_pr_registration *pr_reg, 1330d9d660f6SJuergen Gross int *format_code) 1331d9d660f6SJuergen Gross { 1332d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1333d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1334d9d660f6SJuergen Gross struct scsiback_tport *tport = tpg->tport; 1335d9d660f6SJuergen Gross 1336d9d660f6SJuergen Gross switch (tport->tport_proto_id) { 1337d9d660f6SJuergen Gross case SCSI_PROTOCOL_SAS: 1338d9d660f6SJuergen Gross return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 1339d9d660f6SJuergen Gross format_code); 1340d9d660f6SJuergen Gross case SCSI_PROTOCOL_FCP: 1341d9d660f6SJuergen Gross return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 1342d9d660f6SJuergen Gross format_code); 1343d9d660f6SJuergen Gross case SCSI_PROTOCOL_ISCSI: 1344d9d660f6SJuergen Gross return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 1345d9d660f6SJuergen Gross format_code); 1346d9d660f6SJuergen Gross default: 1347d9d660f6SJuergen Gross pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", 1348d9d660f6SJuergen Gross tport->tport_proto_id); 1349d9d660f6SJuergen Gross break; 1350d9d660f6SJuergen Gross } 1351d9d660f6SJuergen Gross 1352d9d660f6SJuergen Gross return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 1353d9d660f6SJuergen Gross format_code); 1354d9d660f6SJuergen Gross } 1355d9d660f6SJuergen Gross 1356d9d660f6SJuergen Gross static char * 1357d9d660f6SJuergen Gross scsiback_parse_pr_out_transport_id(struct se_portal_group *se_tpg, 1358d9d660f6SJuergen Gross const char *buf, 1359d9d660f6SJuergen Gross u32 *out_tid_len, 1360d9d660f6SJuergen Gross char **port_nexus_ptr) 1361d9d660f6SJuergen Gross { 1362d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1363d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1364d9d660f6SJuergen Gross struct scsiback_tport *tport = tpg->tport; 1365d9d660f6SJuergen Gross 1366d9d660f6SJuergen Gross switch (tport->tport_proto_id) { 1367d9d660f6SJuergen Gross case SCSI_PROTOCOL_SAS: 1368d9d660f6SJuergen Gross return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 1369d9d660f6SJuergen Gross port_nexus_ptr); 1370d9d660f6SJuergen Gross case SCSI_PROTOCOL_FCP: 1371d9d660f6SJuergen Gross return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 1372d9d660f6SJuergen Gross port_nexus_ptr); 1373d9d660f6SJuergen Gross case SCSI_PROTOCOL_ISCSI: 1374d9d660f6SJuergen Gross return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 1375d9d660f6SJuergen Gross port_nexus_ptr); 1376d9d660f6SJuergen Gross default: 1377d9d660f6SJuergen Gross pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", 1378d9d660f6SJuergen Gross tport->tport_proto_id); 1379d9d660f6SJuergen Gross break; 1380d9d660f6SJuergen Gross } 1381d9d660f6SJuergen Gross 1382d9d660f6SJuergen Gross return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 1383d9d660f6SJuergen Gross port_nexus_ptr); 1384d9d660f6SJuergen Gross } 1385d9d660f6SJuergen Gross 1386d9d660f6SJuergen Gross static struct se_wwn * 1387d9d660f6SJuergen Gross scsiback_make_tport(struct target_fabric_configfs *tf, 1388d9d660f6SJuergen Gross struct config_group *group, 1389d9d660f6SJuergen Gross const char *name) 1390d9d660f6SJuergen Gross { 1391d9d660f6SJuergen Gross struct scsiback_tport *tport; 1392d9d660f6SJuergen Gross char *ptr; 1393d9d660f6SJuergen Gross u64 wwpn = 0; 1394d9d660f6SJuergen Gross int off = 0; 1395d9d660f6SJuergen Gross 1396d9d660f6SJuergen Gross tport = kzalloc(sizeof(struct scsiback_tport), GFP_KERNEL); 1397d9d660f6SJuergen Gross if (!tport) 1398d9d660f6SJuergen Gross return ERR_PTR(-ENOMEM); 1399d9d660f6SJuergen Gross 1400d9d660f6SJuergen Gross tport->tport_wwpn = wwpn; 1401d9d660f6SJuergen Gross /* 1402d9d660f6SJuergen Gross * Determine the emulated Protocol Identifier and Target Port Name 1403d9d660f6SJuergen Gross * based on the incoming configfs directory name. 1404d9d660f6SJuergen Gross */ 1405d9d660f6SJuergen Gross ptr = strstr(name, "naa."); 1406d9d660f6SJuergen Gross if (ptr) { 1407d9d660f6SJuergen Gross tport->tport_proto_id = SCSI_PROTOCOL_SAS; 1408d9d660f6SJuergen Gross goto check_len; 1409d9d660f6SJuergen Gross } 1410d9d660f6SJuergen Gross ptr = strstr(name, "fc."); 1411d9d660f6SJuergen Gross if (ptr) { 1412d9d660f6SJuergen Gross tport->tport_proto_id = SCSI_PROTOCOL_FCP; 1413d9d660f6SJuergen Gross off = 3; /* Skip over "fc." */ 1414d9d660f6SJuergen Gross goto check_len; 1415d9d660f6SJuergen Gross } 1416d9d660f6SJuergen Gross ptr = strstr(name, "iqn."); 1417d9d660f6SJuergen Gross if (ptr) { 1418d9d660f6SJuergen Gross tport->tport_proto_id = SCSI_PROTOCOL_ISCSI; 1419d9d660f6SJuergen Gross goto check_len; 1420d9d660f6SJuergen Gross } 1421d9d660f6SJuergen Gross 1422d9d660f6SJuergen Gross pr_err("Unable to locate prefix for emulated Target Port: %s\n", name); 1423d9d660f6SJuergen Gross kfree(tport); 1424d9d660f6SJuergen Gross return ERR_PTR(-EINVAL); 1425d9d660f6SJuergen Gross 1426d9d660f6SJuergen Gross check_len: 1427d9d660f6SJuergen Gross if (strlen(name) >= VSCSI_NAMELEN) { 1428d9d660f6SJuergen Gross pr_err("Emulated %s Address: %s, exceeds max: %d\n", name, 1429d9d660f6SJuergen Gross scsiback_dump_proto_id(tport), VSCSI_NAMELEN); 1430d9d660f6SJuergen Gross kfree(tport); 1431d9d660f6SJuergen Gross return ERR_PTR(-EINVAL); 1432d9d660f6SJuergen Gross } 1433d9d660f6SJuergen Gross snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); 1434d9d660f6SJuergen Gross 1435d9d660f6SJuergen Gross pr_debug("xen-pvscsi: Allocated emulated Target %s Address: %s\n", 1436d9d660f6SJuergen Gross scsiback_dump_proto_id(tport), name); 1437d9d660f6SJuergen Gross 1438d9d660f6SJuergen Gross return &tport->tport_wwn; 1439d9d660f6SJuergen Gross } 1440d9d660f6SJuergen Gross 1441d9d660f6SJuergen Gross static void scsiback_drop_tport(struct se_wwn *wwn) 1442d9d660f6SJuergen Gross { 1443d9d660f6SJuergen Gross struct scsiback_tport *tport = container_of(wwn, 1444d9d660f6SJuergen Gross struct scsiback_tport, tport_wwn); 1445d9d660f6SJuergen Gross 1446d9d660f6SJuergen Gross pr_debug("xen-pvscsi: Deallocating emulated Target %s Address: %s\n", 1447d9d660f6SJuergen Gross scsiback_dump_proto_id(tport), tport->tport_name); 1448d9d660f6SJuergen Gross 1449d9d660f6SJuergen Gross kfree(tport); 1450d9d660f6SJuergen Gross } 1451d9d660f6SJuergen Gross 1452d9d660f6SJuergen Gross static struct se_node_acl * 1453d9d660f6SJuergen Gross scsiback_alloc_fabric_acl(struct se_portal_group *se_tpg) 1454d9d660f6SJuergen Gross { 1455d9d660f6SJuergen Gross return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); 1456d9d660f6SJuergen Gross } 1457d9d660f6SJuergen Gross 1458d9d660f6SJuergen Gross static void 1459d9d660f6SJuergen Gross scsiback_release_fabric_acl(struct se_portal_group *se_tpg, 1460d9d660f6SJuergen Gross struct se_node_acl *se_nacl) 1461d9d660f6SJuergen Gross { 1462d9d660f6SJuergen Gross kfree(se_nacl); 1463d9d660f6SJuergen Gross } 1464d9d660f6SJuergen Gross 1465d9d660f6SJuergen Gross static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) 1466d9d660f6SJuergen Gross { 1467d9d660f6SJuergen Gross return 1; 1468d9d660f6SJuergen Gross } 1469d9d660f6SJuergen Gross 1470d9d660f6SJuergen Gross static int scsiback_check_stop_free(struct se_cmd *se_cmd) 1471d9d660f6SJuergen Gross { 1472d9d660f6SJuergen Gross /* 1473d9d660f6SJuergen Gross * Do not release struct se_cmd's containing a valid TMR 1474d9d660f6SJuergen Gross * pointer. These will be released directly in scsiback_device_action() 1475d9d660f6SJuergen Gross * with transport_generic_free_cmd(). 1476d9d660f6SJuergen Gross */ 1477d9d660f6SJuergen Gross if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) 1478d9d660f6SJuergen Gross return 0; 1479d9d660f6SJuergen Gross 1480d9d660f6SJuergen Gross transport_generic_free_cmd(se_cmd, 0); 1481d9d660f6SJuergen Gross return 1; 1482d9d660f6SJuergen Gross } 1483d9d660f6SJuergen Gross 1484d9d660f6SJuergen Gross static void scsiback_release_cmd(struct se_cmd *se_cmd) 1485d9d660f6SJuergen Gross { 1486d9d660f6SJuergen Gross struct vscsibk_pend *pending_req = container_of(se_cmd, 1487d9d660f6SJuergen Gross struct vscsibk_pend, se_cmd); 1488d9d660f6SJuergen Gross 1489d9d660f6SJuergen Gross kmem_cache_free(scsiback_cachep, pending_req); 1490d9d660f6SJuergen Gross } 1491d9d660f6SJuergen Gross 1492d9d660f6SJuergen Gross static int scsiback_shutdown_session(struct se_session *se_sess) 1493d9d660f6SJuergen Gross { 1494d9d660f6SJuergen Gross return 0; 1495d9d660f6SJuergen Gross } 1496d9d660f6SJuergen Gross 1497d9d660f6SJuergen Gross static void scsiback_close_session(struct se_session *se_sess) 1498d9d660f6SJuergen Gross { 1499d9d660f6SJuergen Gross } 1500d9d660f6SJuergen Gross 1501d9d660f6SJuergen Gross static u32 scsiback_sess_get_index(struct se_session *se_sess) 1502d9d660f6SJuergen Gross { 1503d9d660f6SJuergen Gross return 0; 1504d9d660f6SJuergen Gross } 1505d9d660f6SJuergen Gross 1506d9d660f6SJuergen Gross static int scsiback_write_pending(struct se_cmd *se_cmd) 1507d9d660f6SJuergen Gross { 1508d9d660f6SJuergen Gross /* Go ahead and process the write immediately */ 1509d9d660f6SJuergen Gross target_execute_cmd(se_cmd); 1510d9d660f6SJuergen Gross 1511d9d660f6SJuergen Gross return 0; 1512d9d660f6SJuergen Gross } 1513d9d660f6SJuergen Gross 1514d9d660f6SJuergen Gross static int scsiback_write_pending_status(struct se_cmd *se_cmd) 1515d9d660f6SJuergen Gross { 1516d9d660f6SJuergen Gross return 0; 1517d9d660f6SJuergen Gross } 1518d9d660f6SJuergen Gross 1519d9d660f6SJuergen Gross static void scsiback_set_default_node_attrs(struct se_node_acl *nacl) 1520d9d660f6SJuergen Gross { 1521d9d660f6SJuergen Gross } 1522d9d660f6SJuergen Gross 1523d9d660f6SJuergen Gross static u32 scsiback_get_task_tag(struct se_cmd *se_cmd) 1524d9d660f6SJuergen Gross { 1525d9d660f6SJuergen Gross struct vscsibk_pend *pending_req = container_of(se_cmd, 1526d9d660f6SJuergen Gross struct vscsibk_pend, se_cmd); 1527d9d660f6SJuergen Gross 1528d9d660f6SJuergen Gross return pending_req->rqid; 1529d9d660f6SJuergen Gross } 1530d9d660f6SJuergen Gross 1531d9d660f6SJuergen Gross static int scsiback_get_cmd_state(struct se_cmd *se_cmd) 1532d9d660f6SJuergen Gross { 1533d9d660f6SJuergen Gross return 0; 1534d9d660f6SJuergen Gross } 1535d9d660f6SJuergen Gross 1536d9d660f6SJuergen Gross static int scsiback_queue_data_in(struct se_cmd *se_cmd) 1537d9d660f6SJuergen Gross { 1538d9d660f6SJuergen Gross struct vscsibk_pend *pending_req = container_of(se_cmd, 1539d9d660f6SJuergen Gross struct vscsibk_pend, se_cmd); 1540d9d660f6SJuergen Gross 1541d9d660f6SJuergen Gross pending_req->result = SAM_STAT_GOOD; 1542d9d660f6SJuergen Gross scsiback_cmd_done(pending_req); 1543d9d660f6SJuergen Gross return 0; 1544d9d660f6SJuergen Gross } 1545d9d660f6SJuergen Gross 1546d9d660f6SJuergen Gross static int scsiback_queue_status(struct se_cmd *se_cmd) 1547d9d660f6SJuergen Gross { 1548d9d660f6SJuergen Gross struct vscsibk_pend *pending_req = container_of(se_cmd, 1549d9d660f6SJuergen Gross struct vscsibk_pend, se_cmd); 1550d9d660f6SJuergen Gross 1551d9d660f6SJuergen Gross if (se_cmd->sense_buffer && 1552d9d660f6SJuergen Gross ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || 1553d9d660f6SJuergen Gross (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) 1554d9d660f6SJuergen Gross pending_req->result = (DRIVER_SENSE << 24) | 1555d9d660f6SJuergen Gross SAM_STAT_CHECK_CONDITION; 1556d9d660f6SJuergen Gross else 1557d9d660f6SJuergen Gross pending_req->result = se_cmd->scsi_status; 1558d9d660f6SJuergen Gross 1559d9d660f6SJuergen Gross scsiback_cmd_done(pending_req); 1560d9d660f6SJuergen Gross return 0; 1561d9d660f6SJuergen Gross } 1562d9d660f6SJuergen Gross 1563d9d660f6SJuergen Gross static void scsiback_queue_tm_rsp(struct se_cmd *se_cmd) 1564d9d660f6SJuergen Gross { 1565d9d660f6SJuergen Gross struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; 1566d9d660f6SJuergen Gross struct scsiback_tmr *tmr = se_tmr->fabric_tmr_ptr; 1567d9d660f6SJuergen Gross 1568d9d660f6SJuergen Gross atomic_set(&tmr->tmr_complete, 1); 1569d9d660f6SJuergen Gross wake_up(&tmr->tmr_wait); 1570d9d660f6SJuergen Gross } 1571d9d660f6SJuergen Gross 1572d9d660f6SJuergen Gross static void scsiback_aborted_task(struct se_cmd *se_cmd) 1573d9d660f6SJuergen Gross { 1574d9d660f6SJuergen Gross } 1575d9d660f6SJuergen Gross 1576d9d660f6SJuergen Gross static ssize_t scsiback_tpg_param_show_alias(struct se_portal_group *se_tpg, 1577d9d660f6SJuergen Gross char *page) 1578d9d660f6SJuergen Gross { 1579d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, 1580d9d660f6SJuergen Gross se_tpg); 1581d9d660f6SJuergen Gross ssize_t rb; 1582d9d660f6SJuergen Gross 1583d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1584d9d660f6SJuergen Gross rb = snprintf(page, PAGE_SIZE, "%s\n", tpg->param_alias); 1585d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1586d9d660f6SJuergen Gross 1587d9d660f6SJuergen Gross return rb; 1588d9d660f6SJuergen Gross } 1589d9d660f6SJuergen Gross 1590d9d660f6SJuergen Gross static ssize_t scsiback_tpg_param_store_alias(struct se_portal_group *se_tpg, 1591d9d660f6SJuergen Gross const char *page, size_t count) 1592d9d660f6SJuergen Gross { 1593d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg, 1594d9d660f6SJuergen Gross se_tpg); 1595d9d660f6SJuergen Gross int len; 1596d9d660f6SJuergen Gross 1597d9d660f6SJuergen Gross if (strlen(page) >= VSCSI_NAMELEN) { 1598d9d660f6SJuergen Gross pr_err("param alias: %s, exceeds max: %d\n", page, 1599d9d660f6SJuergen Gross VSCSI_NAMELEN); 1600d9d660f6SJuergen Gross return -EINVAL; 1601d9d660f6SJuergen Gross } 1602d9d660f6SJuergen Gross 1603d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1604d9d660f6SJuergen Gross len = snprintf(tpg->param_alias, VSCSI_NAMELEN, "%s", page); 1605d9d660f6SJuergen Gross if (tpg->param_alias[len - 1] == '\n') 1606d9d660f6SJuergen Gross tpg->param_alias[len - 1] = '\0'; 1607d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1608d9d660f6SJuergen Gross 1609d9d660f6SJuergen Gross return count; 1610d9d660f6SJuergen Gross } 1611d9d660f6SJuergen Gross 1612d9d660f6SJuergen Gross TF_TPG_PARAM_ATTR(scsiback, alias, S_IRUGO | S_IWUSR); 1613d9d660f6SJuergen Gross 1614d9d660f6SJuergen Gross static struct configfs_attribute *scsiback_param_attrs[] = { 1615d9d660f6SJuergen Gross &scsiback_tpg_param_alias.attr, 1616d9d660f6SJuergen Gross NULL, 1617d9d660f6SJuergen Gross }; 1618d9d660f6SJuergen Gross 1619d9d660f6SJuergen Gross static int scsiback_make_nexus(struct scsiback_tpg *tpg, 1620d9d660f6SJuergen Gross const char *name) 1621d9d660f6SJuergen Gross { 1622d9d660f6SJuergen Gross struct se_portal_group *se_tpg; 1623d9d660f6SJuergen Gross struct se_session *se_sess; 1624d9d660f6SJuergen Gross struct scsiback_nexus *tv_nexus; 1625d9d660f6SJuergen Gross 1626d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1627d9d660f6SJuergen Gross if (tpg->tpg_nexus) { 1628d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1629d9d660f6SJuergen Gross pr_debug("tpg->tpg_nexus already exists\n"); 1630d9d660f6SJuergen Gross return -EEXIST; 1631d9d660f6SJuergen Gross } 1632d9d660f6SJuergen Gross se_tpg = &tpg->se_tpg; 1633d9d660f6SJuergen Gross 1634d9d660f6SJuergen Gross tv_nexus = kzalloc(sizeof(struct scsiback_nexus), GFP_KERNEL); 1635d9d660f6SJuergen Gross if (!tv_nexus) { 1636d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1637d9d660f6SJuergen Gross return -ENOMEM; 1638d9d660f6SJuergen Gross } 1639d9d660f6SJuergen Gross /* 1640d9d660f6SJuergen Gross * Initialize the struct se_session pointer 1641d9d660f6SJuergen Gross */ 1642d9d660f6SJuergen Gross tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); 1643d9d660f6SJuergen Gross if (IS_ERR(tv_nexus->tvn_se_sess)) { 1644d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1645d9d660f6SJuergen Gross kfree(tv_nexus); 1646d9d660f6SJuergen Gross return -ENOMEM; 1647d9d660f6SJuergen Gross } 1648d9d660f6SJuergen Gross se_sess = tv_nexus->tvn_se_sess; 1649d9d660f6SJuergen Gross /* 1650d9d660f6SJuergen Gross * Since we are running in 'demo mode' this call with generate a 1651d9d660f6SJuergen Gross * struct se_node_acl for the scsiback struct se_portal_group with 1652d9d660f6SJuergen Gross * the SCSI Initiator port name of the passed configfs group 'name'. 1653d9d660f6SJuergen Gross */ 1654d9d660f6SJuergen Gross tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( 1655d9d660f6SJuergen Gross se_tpg, (unsigned char *)name); 1656d9d660f6SJuergen Gross if (!tv_nexus->tvn_se_sess->se_node_acl) { 1657d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1658d9d660f6SJuergen Gross pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n", 1659d9d660f6SJuergen Gross name); 1660d9d660f6SJuergen Gross goto out; 1661d9d660f6SJuergen Gross } 1662d9d660f6SJuergen Gross /* 1663d9d660f6SJuergen Gross * Now register the TCM pvscsi virtual I_T Nexus as active with the 1664d9d660f6SJuergen Gross * call to __transport_register_session() 1665d9d660f6SJuergen Gross */ 1666d9d660f6SJuergen Gross __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, 1667d9d660f6SJuergen Gross tv_nexus->tvn_se_sess, tv_nexus); 1668d9d660f6SJuergen Gross tpg->tpg_nexus = tv_nexus; 1669d9d660f6SJuergen Gross 1670d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1671d9d660f6SJuergen Gross return 0; 1672d9d660f6SJuergen Gross 1673d9d660f6SJuergen Gross out: 1674d9d660f6SJuergen Gross transport_free_session(se_sess); 1675d9d660f6SJuergen Gross kfree(tv_nexus); 1676d9d660f6SJuergen Gross return -ENOMEM; 1677d9d660f6SJuergen Gross } 1678d9d660f6SJuergen Gross 1679d9d660f6SJuergen Gross static int scsiback_drop_nexus(struct scsiback_tpg *tpg) 1680d9d660f6SJuergen Gross { 1681d9d660f6SJuergen Gross struct se_session *se_sess; 1682d9d660f6SJuergen Gross struct scsiback_nexus *tv_nexus; 1683d9d660f6SJuergen Gross 1684d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1685d9d660f6SJuergen Gross tv_nexus = tpg->tpg_nexus; 1686d9d660f6SJuergen Gross if (!tv_nexus) { 1687d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1688d9d660f6SJuergen Gross return -ENODEV; 1689d9d660f6SJuergen Gross } 1690d9d660f6SJuergen Gross 1691d9d660f6SJuergen Gross se_sess = tv_nexus->tvn_se_sess; 1692d9d660f6SJuergen Gross if (!se_sess) { 1693d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1694d9d660f6SJuergen Gross return -ENODEV; 1695d9d660f6SJuergen Gross } 1696d9d660f6SJuergen Gross 1697d9d660f6SJuergen Gross if (tpg->tv_tpg_port_count != 0) { 1698d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1699d9d660f6SJuergen Gross pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG port count: %d\n", 1700d9d660f6SJuergen Gross tpg->tv_tpg_port_count); 1701d9d660f6SJuergen Gross return -EBUSY; 1702d9d660f6SJuergen Gross } 1703d9d660f6SJuergen Gross 1704d9d660f6SJuergen Gross if (tpg->tv_tpg_fe_count != 0) { 1705d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1706d9d660f6SJuergen Gross pr_err("Unable to remove xen-pvscsi I_T Nexus with active TPG frontend count: %d\n", 1707d9d660f6SJuergen Gross tpg->tv_tpg_fe_count); 1708d9d660f6SJuergen Gross return -EBUSY; 1709d9d660f6SJuergen Gross } 1710d9d660f6SJuergen Gross 1711d9d660f6SJuergen Gross pr_debug("xen-pvscsi: Removing I_T Nexus to emulated %s Initiator Port: %s\n", 1712d9d660f6SJuergen Gross scsiback_dump_proto_id(tpg->tport), 1713d9d660f6SJuergen Gross tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 1714d9d660f6SJuergen Gross 1715d9d660f6SJuergen Gross /* 1716d9d660f6SJuergen Gross * Release the SCSI I_T Nexus to the emulated xen-pvscsi Target Port 1717d9d660f6SJuergen Gross */ 1718d9d660f6SJuergen Gross transport_deregister_session(tv_nexus->tvn_se_sess); 1719d9d660f6SJuergen Gross tpg->tpg_nexus = NULL; 1720d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1721d9d660f6SJuergen Gross 1722d9d660f6SJuergen Gross kfree(tv_nexus); 1723d9d660f6SJuergen Gross return 0; 1724d9d660f6SJuergen Gross } 1725d9d660f6SJuergen Gross 1726d9d660f6SJuergen Gross static ssize_t scsiback_tpg_show_nexus(struct se_portal_group *se_tpg, 1727d9d660f6SJuergen Gross char *page) 1728d9d660f6SJuergen Gross { 1729d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1730d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1731d9d660f6SJuergen Gross struct scsiback_nexus *tv_nexus; 1732d9d660f6SJuergen Gross ssize_t ret; 1733d9d660f6SJuergen Gross 1734d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1735d9d660f6SJuergen Gross tv_nexus = tpg->tpg_nexus; 1736d9d660f6SJuergen Gross if (!tv_nexus) { 1737d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1738d9d660f6SJuergen Gross return -ENODEV; 1739d9d660f6SJuergen Gross } 1740d9d660f6SJuergen Gross ret = snprintf(page, PAGE_SIZE, "%s\n", 1741d9d660f6SJuergen Gross tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 1742d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1743d9d660f6SJuergen Gross 1744d9d660f6SJuergen Gross return ret; 1745d9d660f6SJuergen Gross } 1746d9d660f6SJuergen Gross 1747d9d660f6SJuergen Gross static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg, 1748d9d660f6SJuergen Gross const char *page, 1749d9d660f6SJuergen Gross size_t count) 1750d9d660f6SJuergen Gross { 1751d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1752d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1753d9d660f6SJuergen Gross struct scsiback_tport *tport_wwn = tpg->tport; 1754d9d660f6SJuergen Gross unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; 1755d9d660f6SJuergen Gross int ret; 1756d9d660f6SJuergen Gross /* 1757d9d660f6SJuergen Gross * Shutdown the active I_T nexus if 'NULL' is passed.. 1758d9d660f6SJuergen Gross */ 1759d9d660f6SJuergen Gross if (!strncmp(page, "NULL", 4)) { 1760d9d660f6SJuergen Gross ret = scsiback_drop_nexus(tpg); 1761d9d660f6SJuergen Gross return (!ret) ? count : ret; 1762d9d660f6SJuergen Gross } 1763d9d660f6SJuergen Gross /* 1764d9d660f6SJuergen Gross * Otherwise make sure the passed virtual Initiator port WWN matches 1765d9d660f6SJuergen Gross * the fabric protocol_id set in scsiback_make_tport(), and call 1766d9d660f6SJuergen Gross * scsiback_make_nexus(). 1767d9d660f6SJuergen Gross */ 1768d9d660f6SJuergen Gross if (strlen(page) >= VSCSI_NAMELEN) { 1769d9d660f6SJuergen Gross pr_err("Emulated NAA Sas Address: %s, exceeds max: %d\n", 1770d9d660f6SJuergen Gross page, VSCSI_NAMELEN); 1771d9d660f6SJuergen Gross return -EINVAL; 1772d9d660f6SJuergen Gross } 1773d9d660f6SJuergen Gross snprintf(&i_port[0], VSCSI_NAMELEN, "%s", page); 1774d9d660f6SJuergen Gross 1775d9d660f6SJuergen Gross ptr = strstr(i_port, "naa."); 1776d9d660f6SJuergen Gross if (ptr) { 1777d9d660f6SJuergen Gross if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) { 1778d9d660f6SJuergen Gross pr_err("Passed SAS Initiator Port %s does not match target port protoid: %s\n", 1779d9d660f6SJuergen Gross i_port, scsiback_dump_proto_id(tport_wwn)); 1780d9d660f6SJuergen Gross return -EINVAL; 1781d9d660f6SJuergen Gross } 1782d9d660f6SJuergen Gross port_ptr = &i_port[0]; 1783d9d660f6SJuergen Gross goto check_newline; 1784d9d660f6SJuergen Gross } 1785d9d660f6SJuergen Gross ptr = strstr(i_port, "fc."); 1786d9d660f6SJuergen Gross if (ptr) { 1787d9d660f6SJuergen Gross if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) { 1788d9d660f6SJuergen Gross pr_err("Passed FCP Initiator Port %s does not match target port protoid: %s\n", 1789d9d660f6SJuergen Gross i_port, scsiback_dump_proto_id(tport_wwn)); 1790d9d660f6SJuergen Gross return -EINVAL; 1791d9d660f6SJuergen Gross } 1792d9d660f6SJuergen Gross port_ptr = &i_port[3]; /* Skip over "fc." */ 1793d9d660f6SJuergen Gross goto check_newline; 1794d9d660f6SJuergen Gross } 1795d9d660f6SJuergen Gross ptr = strstr(i_port, "iqn."); 1796d9d660f6SJuergen Gross if (ptr) { 1797d9d660f6SJuergen Gross if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) { 1798d9d660f6SJuergen Gross pr_err("Passed iSCSI Initiator Port %s does not match target port protoid: %s\n", 1799d9d660f6SJuergen Gross i_port, scsiback_dump_proto_id(tport_wwn)); 1800d9d660f6SJuergen Gross return -EINVAL; 1801d9d660f6SJuergen Gross } 1802d9d660f6SJuergen Gross port_ptr = &i_port[0]; 1803d9d660f6SJuergen Gross goto check_newline; 1804d9d660f6SJuergen Gross } 1805d9d660f6SJuergen Gross pr_err("Unable to locate prefix for emulated Initiator Port: %s\n", 1806d9d660f6SJuergen Gross i_port); 1807d9d660f6SJuergen Gross return -EINVAL; 1808d9d660f6SJuergen Gross /* 1809d9d660f6SJuergen Gross * Clear any trailing newline for the NAA WWN 1810d9d660f6SJuergen Gross */ 1811d9d660f6SJuergen Gross check_newline: 1812d9d660f6SJuergen Gross if (i_port[strlen(i_port) - 1] == '\n') 1813d9d660f6SJuergen Gross i_port[strlen(i_port) - 1] = '\0'; 1814d9d660f6SJuergen Gross 1815d9d660f6SJuergen Gross ret = scsiback_make_nexus(tpg, port_ptr); 1816d9d660f6SJuergen Gross if (ret < 0) 1817d9d660f6SJuergen Gross return ret; 1818d9d660f6SJuergen Gross 1819d9d660f6SJuergen Gross return count; 1820d9d660f6SJuergen Gross } 1821d9d660f6SJuergen Gross 1822d9d660f6SJuergen Gross TF_TPG_BASE_ATTR(scsiback, nexus, S_IRUGO | S_IWUSR); 1823d9d660f6SJuergen Gross 1824d9d660f6SJuergen Gross static struct configfs_attribute *scsiback_tpg_attrs[] = { 1825d9d660f6SJuergen Gross &scsiback_tpg_nexus.attr, 1826d9d660f6SJuergen Gross NULL, 1827d9d660f6SJuergen Gross }; 1828d9d660f6SJuergen Gross 1829d9d660f6SJuergen Gross static ssize_t 1830d9d660f6SJuergen Gross scsiback_wwn_show_attr_version(struct target_fabric_configfs *tf, 1831d9d660f6SJuergen Gross char *page) 1832d9d660f6SJuergen Gross { 1833d9d660f6SJuergen Gross return sprintf(page, "xen-pvscsi fabric module %s on %s/%s on " 1834d9d660f6SJuergen Gross UTS_RELEASE"\n", 1835d9d660f6SJuergen Gross VSCSI_VERSION, utsname()->sysname, utsname()->machine); 1836d9d660f6SJuergen Gross } 1837d9d660f6SJuergen Gross 1838d9d660f6SJuergen Gross TF_WWN_ATTR_RO(scsiback, version); 1839d9d660f6SJuergen Gross 1840d9d660f6SJuergen Gross static struct configfs_attribute *scsiback_wwn_attrs[] = { 1841d9d660f6SJuergen Gross &scsiback_wwn_version.attr, 1842d9d660f6SJuergen Gross NULL, 1843d9d660f6SJuergen Gross }; 1844d9d660f6SJuergen Gross 1845d9d660f6SJuergen Gross static char *scsiback_get_fabric_name(void) 1846d9d660f6SJuergen Gross { 1847d9d660f6SJuergen Gross return "xen-pvscsi"; 1848d9d660f6SJuergen Gross } 1849d9d660f6SJuergen Gross 1850d9d660f6SJuergen Gross static int scsiback_port_link(struct se_portal_group *se_tpg, 1851d9d660f6SJuergen Gross struct se_lun *lun) 1852d9d660f6SJuergen Gross { 1853d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1854d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1855d9d660f6SJuergen Gross 1856d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1857d9d660f6SJuergen Gross tpg->tv_tpg_port_count++; 1858d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1859d9d660f6SJuergen Gross 1860d9d660f6SJuergen Gross return 0; 1861d9d660f6SJuergen Gross } 1862d9d660f6SJuergen Gross 1863d9d660f6SJuergen Gross static void scsiback_port_unlink(struct se_portal_group *se_tpg, 1864d9d660f6SJuergen Gross struct se_lun *lun) 1865d9d660f6SJuergen Gross { 1866d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1867d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1868d9d660f6SJuergen Gross 1869d9d660f6SJuergen Gross mutex_lock(&tpg->tv_tpg_mutex); 1870d9d660f6SJuergen Gross tpg->tv_tpg_port_count--; 1871d9d660f6SJuergen Gross mutex_unlock(&tpg->tv_tpg_mutex); 1872d9d660f6SJuergen Gross } 1873d9d660f6SJuergen Gross 1874d9d660f6SJuergen Gross static struct se_portal_group * 1875d9d660f6SJuergen Gross scsiback_make_tpg(struct se_wwn *wwn, 1876d9d660f6SJuergen Gross struct config_group *group, 1877d9d660f6SJuergen Gross const char *name) 1878d9d660f6SJuergen Gross { 1879d9d660f6SJuergen Gross struct scsiback_tport *tport = container_of(wwn, 1880d9d660f6SJuergen Gross struct scsiback_tport, tport_wwn); 1881d9d660f6SJuergen Gross 1882d9d660f6SJuergen Gross struct scsiback_tpg *tpg; 1883495daef9SDan Carpenter u16 tpgt; 1884d9d660f6SJuergen Gross int ret; 1885d9d660f6SJuergen Gross 1886d9d660f6SJuergen Gross if (strstr(name, "tpgt_") != name) 1887d9d660f6SJuergen Gross return ERR_PTR(-EINVAL); 1888495daef9SDan Carpenter ret = kstrtou16(name + 5, 10, &tpgt); 1889495daef9SDan Carpenter if (ret) 1890495daef9SDan Carpenter return ERR_PTR(ret); 1891d9d660f6SJuergen Gross 1892d9d660f6SJuergen Gross tpg = kzalloc(sizeof(struct scsiback_tpg), GFP_KERNEL); 1893d9d660f6SJuergen Gross if (!tpg) 1894d9d660f6SJuergen Gross return ERR_PTR(-ENOMEM); 1895d9d660f6SJuergen Gross 1896d9d660f6SJuergen Gross mutex_init(&tpg->tv_tpg_mutex); 1897d9d660f6SJuergen Gross INIT_LIST_HEAD(&tpg->tv_tpg_list); 1898d9d660f6SJuergen Gross INIT_LIST_HEAD(&tpg->info_list); 1899d9d660f6SJuergen Gross tpg->tport = tport; 1900d9d660f6SJuergen Gross tpg->tport_tpgt = tpgt; 1901d9d660f6SJuergen Gross 1902d9d660f6SJuergen Gross ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn, 1903d9d660f6SJuergen Gross &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); 1904d9d660f6SJuergen Gross if (ret < 0) { 1905d9d660f6SJuergen Gross kfree(tpg); 1906d9d660f6SJuergen Gross return NULL; 1907d9d660f6SJuergen Gross } 1908d9d660f6SJuergen Gross mutex_lock(&scsiback_mutex); 1909d9d660f6SJuergen Gross list_add_tail(&tpg->tv_tpg_list, &scsiback_list); 1910d9d660f6SJuergen Gross mutex_unlock(&scsiback_mutex); 1911d9d660f6SJuergen Gross 1912d9d660f6SJuergen Gross return &tpg->se_tpg; 1913d9d660f6SJuergen Gross } 1914d9d660f6SJuergen Gross 1915d9d660f6SJuergen Gross static void scsiback_drop_tpg(struct se_portal_group *se_tpg) 1916d9d660f6SJuergen Gross { 1917d9d660f6SJuergen Gross struct scsiback_tpg *tpg = container_of(se_tpg, 1918d9d660f6SJuergen Gross struct scsiback_tpg, se_tpg); 1919d9d660f6SJuergen Gross 1920d9d660f6SJuergen Gross mutex_lock(&scsiback_mutex); 1921d9d660f6SJuergen Gross list_del(&tpg->tv_tpg_list); 1922d9d660f6SJuergen Gross mutex_unlock(&scsiback_mutex); 1923d9d660f6SJuergen Gross /* 1924d9d660f6SJuergen Gross * Release the virtual I_T Nexus for this xen-pvscsi TPG 1925d9d660f6SJuergen Gross */ 1926d9d660f6SJuergen Gross scsiback_drop_nexus(tpg); 1927d9d660f6SJuergen Gross /* 1928d9d660f6SJuergen Gross * Deregister the se_tpg from TCM.. 1929d9d660f6SJuergen Gross */ 1930d9d660f6SJuergen Gross core_tpg_deregister(se_tpg); 1931d9d660f6SJuergen Gross kfree(tpg); 1932d9d660f6SJuergen Gross } 1933d9d660f6SJuergen Gross 1934d9d660f6SJuergen Gross static int scsiback_check_true(struct se_portal_group *se_tpg) 1935d9d660f6SJuergen Gross { 1936d9d660f6SJuergen Gross return 1; 1937d9d660f6SJuergen Gross } 1938d9d660f6SJuergen Gross 1939d9d660f6SJuergen Gross static int scsiback_check_false(struct se_portal_group *se_tpg) 1940d9d660f6SJuergen Gross { 1941d9d660f6SJuergen Gross return 0; 1942d9d660f6SJuergen Gross } 1943d9d660f6SJuergen Gross 1944d9d660f6SJuergen Gross static struct target_core_fabric_ops scsiback_ops = { 1945d9d660f6SJuergen Gross .get_fabric_name = scsiback_get_fabric_name, 1946d9d660f6SJuergen Gross .get_fabric_proto_ident = scsiback_get_fabric_proto_ident, 1947d9d660f6SJuergen Gross .tpg_get_wwn = scsiback_get_fabric_wwn, 1948d9d660f6SJuergen Gross .tpg_get_tag = scsiback_get_tag, 1949d9d660f6SJuergen Gross .tpg_get_default_depth = scsiback_get_default_depth, 1950d9d660f6SJuergen Gross .tpg_get_pr_transport_id = scsiback_get_pr_transport_id, 1951d9d660f6SJuergen Gross .tpg_get_pr_transport_id_len = scsiback_get_pr_transport_id_len, 1952d9d660f6SJuergen Gross .tpg_parse_pr_out_transport_id = scsiback_parse_pr_out_transport_id, 1953d9d660f6SJuergen Gross .tpg_check_demo_mode = scsiback_check_true, 1954d9d660f6SJuergen Gross .tpg_check_demo_mode_cache = scsiback_check_true, 1955d9d660f6SJuergen Gross .tpg_check_demo_mode_write_protect = scsiback_check_false, 1956d9d660f6SJuergen Gross .tpg_check_prod_mode_write_protect = scsiback_check_false, 1957d9d660f6SJuergen Gross .tpg_alloc_fabric_acl = scsiback_alloc_fabric_acl, 1958d9d660f6SJuergen Gross .tpg_release_fabric_acl = scsiback_release_fabric_acl, 1959d9d660f6SJuergen Gross .tpg_get_inst_index = scsiback_tpg_get_inst_index, 1960d9d660f6SJuergen Gross .check_stop_free = scsiback_check_stop_free, 1961d9d660f6SJuergen Gross .release_cmd = scsiback_release_cmd, 1962d9d660f6SJuergen Gross .put_session = NULL, 1963d9d660f6SJuergen Gross .shutdown_session = scsiback_shutdown_session, 1964d9d660f6SJuergen Gross .close_session = scsiback_close_session, 1965d9d660f6SJuergen Gross .sess_get_index = scsiback_sess_get_index, 1966d9d660f6SJuergen Gross .sess_get_initiator_sid = NULL, 1967d9d660f6SJuergen Gross .write_pending = scsiback_write_pending, 1968d9d660f6SJuergen Gross .write_pending_status = scsiback_write_pending_status, 1969d9d660f6SJuergen Gross .set_default_node_attributes = scsiback_set_default_node_attrs, 1970d9d660f6SJuergen Gross .get_task_tag = scsiback_get_task_tag, 1971d9d660f6SJuergen Gross .get_cmd_state = scsiback_get_cmd_state, 1972d9d660f6SJuergen Gross .queue_data_in = scsiback_queue_data_in, 1973d9d660f6SJuergen Gross .queue_status = scsiback_queue_status, 1974d9d660f6SJuergen Gross .queue_tm_rsp = scsiback_queue_tm_rsp, 1975d9d660f6SJuergen Gross .aborted_task = scsiback_aborted_task, 1976d9d660f6SJuergen Gross /* 1977d9d660f6SJuergen Gross * Setup callers for generic logic in target_core_fabric_configfs.c 1978d9d660f6SJuergen Gross */ 1979d9d660f6SJuergen Gross .fabric_make_wwn = scsiback_make_tport, 1980d9d660f6SJuergen Gross .fabric_drop_wwn = scsiback_drop_tport, 1981d9d660f6SJuergen Gross .fabric_make_tpg = scsiback_make_tpg, 1982d9d660f6SJuergen Gross .fabric_drop_tpg = scsiback_drop_tpg, 1983d9d660f6SJuergen Gross .fabric_post_link = scsiback_port_link, 1984d9d660f6SJuergen Gross .fabric_pre_unlink = scsiback_port_unlink, 1985d9d660f6SJuergen Gross .fabric_make_np = NULL, 1986d9d660f6SJuergen Gross .fabric_drop_np = NULL, 1987d9d660f6SJuergen Gross #if 0 1988d9d660f6SJuergen Gross .fabric_make_nodeacl = scsiback_make_nodeacl, 1989d9d660f6SJuergen Gross .fabric_drop_nodeacl = scsiback_drop_nodeacl, 1990d9d660f6SJuergen Gross #endif 1991d9d660f6SJuergen Gross }; 1992d9d660f6SJuergen Gross 1993d9d660f6SJuergen Gross static int scsiback_register_configfs(void) 1994d9d660f6SJuergen Gross { 1995d9d660f6SJuergen Gross struct target_fabric_configfs *fabric; 1996d9d660f6SJuergen Gross int ret; 1997d9d660f6SJuergen Gross 1998d9d660f6SJuergen Gross pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", 1999d9d660f6SJuergen Gross VSCSI_VERSION, utsname()->sysname, utsname()->machine); 2000d9d660f6SJuergen Gross /* 2001d9d660f6SJuergen Gross * Register the top level struct config_item_type with TCM core 2002d9d660f6SJuergen Gross */ 2003d9d660f6SJuergen Gross fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi"); 2004d9d660f6SJuergen Gross if (IS_ERR(fabric)) 2005d9d660f6SJuergen Gross return PTR_ERR(fabric); 2006d9d660f6SJuergen Gross 2007d9d660f6SJuergen Gross /* 2008d9d660f6SJuergen Gross * Setup fabric->tf_ops from our local scsiback_ops 2009d9d660f6SJuergen Gross */ 2010d9d660f6SJuergen Gross fabric->tf_ops = scsiback_ops; 2011d9d660f6SJuergen Gross /* 2012d9d660f6SJuergen Gross * Setup default attribute lists for various fabric->tf_cit_tmpl 2013d9d660f6SJuergen Gross */ 2014d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs; 2015d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs; 2016d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; 2017d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs; 2018d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; 2019d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; 2020d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; 2021d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; 2022d9d660f6SJuergen Gross fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; 2023d9d660f6SJuergen Gross /* 2024d9d660f6SJuergen Gross * Register the fabric for use within TCM 2025d9d660f6SJuergen Gross */ 2026d9d660f6SJuergen Gross ret = target_fabric_configfs_register(fabric); 2027d9d660f6SJuergen Gross if (ret < 0) { 2028d9d660f6SJuergen Gross target_fabric_configfs_free(fabric); 2029d9d660f6SJuergen Gross return ret; 2030d9d660f6SJuergen Gross } 2031d9d660f6SJuergen Gross /* 2032d9d660f6SJuergen Gross * Setup our local pointer to *fabric 2033d9d660f6SJuergen Gross */ 2034d9d660f6SJuergen Gross scsiback_fabric_configfs = fabric; 2035d9d660f6SJuergen Gross pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n"); 2036d9d660f6SJuergen Gross return 0; 2037d9d660f6SJuergen Gross }; 2038d9d660f6SJuergen Gross 2039d9d660f6SJuergen Gross static void scsiback_deregister_configfs(void) 2040d9d660f6SJuergen Gross { 2041d9d660f6SJuergen Gross if (!scsiback_fabric_configfs) 2042d9d660f6SJuergen Gross return; 2043d9d660f6SJuergen Gross 2044d9d660f6SJuergen Gross target_fabric_configfs_deregister(scsiback_fabric_configfs); 2045d9d660f6SJuergen Gross scsiback_fabric_configfs = NULL; 2046d9d660f6SJuergen Gross pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n"); 2047d9d660f6SJuergen Gross }; 2048d9d660f6SJuergen Gross 2049d9d660f6SJuergen Gross static const struct xenbus_device_id scsiback_ids[] = { 2050d9d660f6SJuergen Gross { "vscsi" }, 2051d9d660f6SJuergen Gross { "" } 2052d9d660f6SJuergen Gross }; 2053d9d660f6SJuergen Gross 205495afae48SDavid Vrabel static struct xenbus_driver scsiback_driver = { 205595afae48SDavid Vrabel .ids = scsiback_ids, 2056d9d660f6SJuergen Gross .probe = scsiback_probe, 2057d9d660f6SJuergen Gross .remove = scsiback_remove, 2058d9d660f6SJuergen Gross .otherend_changed = scsiback_frontend_changed 205995afae48SDavid Vrabel }; 2060d9d660f6SJuergen Gross 2061d9d660f6SJuergen Gross static void scsiback_init_pend(void *p) 2062d9d660f6SJuergen Gross { 2063d9d660f6SJuergen Gross struct vscsibk_pend *pend = p; 2064d9d660f6SJuergen Gross int i; 2065d9d660f6SJuergen Gross 2066d9d660f6SJuergen Gross memset(pend, 0, sizeof(*pend)); 2067d9d660f6SJuergen Gross for (i = 0; i < VSCSI_MAX_GRANTS; i++) 2068d9d660f6SJuergen Gross pend->grant_handles[i] = SCSIBACK_INVALID_HANDLE; 2069d9d660f6SJuergen Gross } 2070d9d660f6SJuergen Gross 2071d9d660f6SJuergen Gross static int __init scsiback_init(void) 2072d9d660f6SJuergen Gross { 2073d9d660f6SJuergen Gross int ret; 2074d9d660f6SJuergen Gross 2075d9d660f6SJuergen Gross if (!xen_domain()) 2076d9d660f6SJuergen Gross return -ENODEV; 2077d9d660f6SJuergen Gross 2078d9d660f6SJuergen Gross scsiback_cachep = kmem_cache_create("vscsiif_cache", 2079d9d660f6SJuergen Gross sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend); 2080d9d660f6SJuergen Gross if (!scsiback_cachep) 2081d9d660f6SJuergen Gross return -ENOMEM; 2082d9d660f6SJuergen Gross 2083d9d660f6SJuergen Gross ret = xenbus_register_backend(&scsiback_driver); 2084d9d660f6SJuergen Gross if (ret) 2085d9d660f6SJuergen Gross goto out_cache_destroy; 2086d9d660f6SJuergen Gross 2087d9d660f6SJuergen Gross ret = scsiback_register_configfs(); 2088d9d660f6SJuergen Gross if (ret) 2089d9d660f6SJuergen Gross goto out_unregister_xenbus; 2090d9d660f6SJuergen Gross 2091d9d660f6SJuergen Gross return 0; 2092d9d660f6SJuergen Gross 2093d9d660f6SJuergen Gross out_unregister_xenbus: 2094d9d660f6SJuergen Gross xenbus_unregister_driver(&scsiback_driver); 2095d9d660f6SJuergen Gross out_cache_destroy: 2096d9d660f6SJuergen Gross kmem_cache_destroy(scsiback_cachep); 2097d9d660f6SJuergen Gross pr_err("xen-pvscsi: %s: error %d\n", __func__, ret); 2098d9d660f6SJuergen Gross return ret; 2099d9d660f6SJuergen Gross } 2100d9d660f6SJuergen Gross 2101d9d660f6SJuergen Gross static void __exit scsiback_exit(void) 2102d9d660f6SJuergen Gross { 2103d9d660f6SJuergen Gross struct page *page; 2104d9d660f6SJuergen Gross 2105d9d660f6SJuergen Gross while (free_pages_num) { 2106d9d660f6SJuergen Gross if (get_free_page(&page)) 2107d9d660f6SJuergen Gross BUG(); 2108ff4b156fSDavid Vrabel gnttab_free_pages(1, &page); 2109d9d660f6SJuergen Gross } 2110d9d660f6SJuergen Gross scsiback_deregister_configfs(); 2111d9d660f6SJuergen Gross xenbus_unregister_driver(&scsiback_driver); 2112d9d660f6SJuergen Gross kmem_cache_destroy(scsiback_cachep); 2113d9d660f6SJuergen Gross } 2114d9d660f6SJuergen Gross 2115d9d660f6SJuergen Gross module_init(scsiback_init); 2116d9d660f6SJuergen Gross module_exit(scsiback_exit); 2117d9d660f6SJuergen Gross 2118d9d660f6SJuergen Gross MODULE_DESCRIPTION("Xen SCSI backend driver"); 2119d9d660f6SJuergen Gross MODULE_LICENSE("Dual BSD/GPL"); 2120d9d660f6SJuergen Gross MODULE_ALIAS("xen-backend:vscsi"); 2121d9d660f6SJuergen Gross MODULE_AUTHOR("Juergen Gross <jgross@suse.com>"); 2122