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