Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull tcm_vhost level target fabric driver from Nicholas Bellinger:
"Here is the PULL request for the initial merge of tcm_vhost based on
RFC-v5 code with MST's ACK appended to the initial merge commit."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
tcm_vhost: Initial merge for vhost level target fabric driver

+1740
+3
drivers/vhost/Kconfig
··· 9 9 To compile this driver as a module, choose M here: the module will 10 10 be called vhost_net. 11 11 12 + if STAGING 13 + source "drivers/vhost/Kconfig.tcm" 14 + endif
+6
drivers/vhost/Kconfig.tcm
··· 1 + config TCM_VHOST 2 + tristate "TCM_VHOST fabric module (EXPERIMENTAL)" 3 + depends on TARGET_CORE && EVENTFD && EXPERIMENTAL && m 4 + default n 5 + ---help--- 6 + Say M here to enable the TCM_VHOST fabric module for use with virtio-scsi guests
+2
drivers/vhost/Makefile
··· 1 1 obj-$(CONFIG_VHOST_NET) += vhost_net.o 2 2 vhost_net-y := vhost.o net.o 3 + 4 + obj-$(CONFIG_TCM_VHOST) += tcm_vhost.o
+1628
drivers/vhost/tcm_vhost.c
··· 1 + /******************************************************************************* 2 + * Vhost kernel TCM fabric driver for virtio SCSI initiators 3 + * 4 + * (C) Copyright 2010-2012 RisingTide Systems LLC. 5 + * (C) Copyright 2010-2012 IBM Corp. 6 + * 7 + * Licensed to the Linux Foundation under the General Public License (GPL) version 2. 8 + * 9 + * Authors: Nicholas A. Bellinger <nab@risingtidesystems.com> 10 + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License as published by 14 + * the Free Software Foundation; either version 2 of the License, or 15 + * (at your option) any later version. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + ****************************************************************************/ 23 + 24 + #include <linux/module.h> 25 + #include <linux/moduleparam.h> 26 + #include <generated/utsrelease.h> 27 + #include <linux/utsname.h> 28 + #include <linux/init.h> 29 + #include <linux/slab.h> 30 + #include <linux/kthread.h> 31 + #include <linux/types.h> 32 + #include <linux/string.h> 33 + #include <linux/configfs.h> 34 + #include <linux/ctype.h> 35 + #include <linux/compat.h> 36 + #include <linux/eventfd.h> 37 + #include <linux/vhost.h> 38 + #include <linux/fs.h> 39 + #include <linux/miscdevice.h> 40 + #include <asm/unaligned.h> 41 + #include <scsi/scsi.h> 42 + #include <scsi/scsi_tcq.h> 43 + #include <target/target_core_base.h> 44 + #include <target/target_core_fabric.h> 45 + #include <target/target_core_fabric_configfs.h> 46 + #include <target/target_core_configfs.h> 47 + #include <target/configfs_macros.h> 48 + #include <linux/vhost.h> 49 + #include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */ 50 + #include <linux/virtio_scsi.h> 51 + 52 + #include "vhost.c" 53 + #include "vhost.h" 54 + #include "tcm_vhost.h" 55 + 56 + struct vhost_scsi { 57 + atomic_t vhost_ref_cnt; 58 + struct tcm_vhost_tpg *vs_tpg; 59 + struct vhost_dev dev; 60 + struct vhost_virtqueue vqs[3]; 61 + 62 + struct vhost_work vs_completion_work; /* cmd completion work item */ 63 + struct list_head vs_completion_list; /* cmd completion queue */ 64 + spinlock_t vs_completion_lock; /* protects s_completion_list */ 65 + }; 66 + 67 + /* Local pointer to allocated TCM configfs fabric module */ 68 + static struct target_fabric_configfs *tcm_vhost_fabric_configfs; 69 + 70 + static struct workqueue_struct *tcm_vhost_workqueue; 71 + 72 + /* Global spinlock to protect tcm_vhost TPG list for vhost IOCTL access */ 73 + static DEFINE_MUTEX(tcm_vhost_mutex); 74 + static LIST_HEAD(tcm_vhost_list); 75 + 76 + static int tcm_vhost_check_true(struct se_portal_group *se_tpg) 77 + { 78 + return 1; 79 + } 80 + 81 + static int tcm_vhost_check_false(struct se_portal_group *se_tpg) 82 + { 83 + return 0; 84 + } 85 + 86 + static char *tcm_vhost_get_fabric_name(void) 87 + { 88 + return "vhost"; 89 + } 90 + 91 + static u8 tcm_vhost_get_fabric_proto_ident(struct se_portal_group *se_tpg) 92 + { 93 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 94 + struct tcm_vhost_tpg, se_tpg); 95 + struct tcm_vhost_tport *tport = tpg->tport; 96 + 97 + switch (tport->tport_proto_id) { 98 + case SCSI_PROTOCOL_SAS: 99 + return sas_get_fabric_proto_ident(se_tpg); 100 + case SCSI_PROTOCOL_FCP: 101 + return fc_get_fabric_proto_ident(se_tpg); 102 + case SCSI_PROTOCOL_ISCSI: 103 + return iscsi_get_fabric_proto_ident(se_tpg); 104 + default: 105 + pr_err("Unknown tport_proto_id: 0x%02x, using" 106 + " SAS emulation\n", tport->tport_proto_id); 107 + break; 108 + } 109 + 110 + return sas_get_fabric_proto_ident(se_tpg); 111 + } 112 + 113 + static char *tcm_vhost_get_fabric_wwn(struct se_portal_group *se_tpg) 114 + { 115 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 116 + struct tcm_vhost_tpg, se_tpg); 117 + struct tcm_vhost_tport *tport = tpg->tport; 118 + 119 + return &tport->tport_name[0]; 120 + } 121 + 122 + static u16 tcm_vhost_get_tag(struct se_portal_group *se_tpg) 123 + { 124 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 125 + struct tcm_vhost_tpg, se_tpg); 126 + return tpg->tport_tpgt; 127 + } 128 + 129 + static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg) 130 + { 131 + return 1; 132 + } 133 + 134 + static u32 tcm_vhost_get_pr_transport_id( 135 + struct se_portal_group *se_tpg, 136 + struct se_node_acl *se_nacl, 137 + struct t10_pr_registration *pr_reg, 138 + int *format_code, 139 + unsigned char *buf) 140 + { 141 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 142 + struct tcm_vhost_tpg, se_tpg); 143 + struct tcm_vhost_tport *tport = tpg->tport; 144 + 145 + switch (tport->tport_proto_id) { 146 + case SCSI_PROTOCOL_SAS: 147 + return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 148 + format_code, buf); 149 + case SCSI_PROTOCOL_FCP: 150 + return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 151 + format_code, buf); 152 + case SCSI_PROTOCOL_ISCSI: 153 + return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 154 + format_code, buf); 155 + default: 156 + pr_err("Unknown tport_proto_id: 0x%02x, using" 157 + " SAS emulation\n", tport->tport_proto_id); 158 + break; 159 + } 160 + 161 + return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, 162 + format_code, buf); 163 + } 164 + 165 + static u32 tcm_vhost_get_pr_transport_id_len( 166 + struct se_portal_group *se_tpg, 167 + struct se_node_acl *se_nacl, 168 + struct t10_pr_registration *pr_reg, 169 + int *format_code) 170 + { 171 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 172 + struct tcm_vhost_tpg, se_tpg); 173 + struct tcm_vhost_tport *tport = tpg->tport; 174 + 175 + switch (tport->tport_proto_id) { 176 + case SCSI_PROTOCOL_SAS: 177 + return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 178 + format_code); 179 + case SCSI_PROTOCOL_FCP: 180 + return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 181 + format_code); 182 + case SCSI_PROTOCOL_ISCSI: 183 + return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 184 + format_code); 185 + default: 186 + pr_err("Unknown tport_proto_id: 0x%02x, using" 187 + " SAS emulation\n", tport->tport_proto_id); 188 + break; 189 + } 190 + 191 + return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, 192 + format_code); 193 + } 194 + 195 + static char *tcm_vhost_parse_pr_out_transport_id( 196 + struct se_portal_group *se_tpg, 197 + const char *buf, 198 + u32 *out_tid_len, 199 + char **port_nexus_ptr) 200 + { 201 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 202 + struct tcm_vhost_tpg, se_tpg); 203 + struct tcm_vhost_tport *tport = tpg->tport; 204 + 205 + switch (tport->tport_proto_id) { 206 + case SCSI_PROTOCOL_SAS: 207 + return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 208 + port_nexus_ptr); 209 + case SCSI_PROTOCOL_FCP: 210 + return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 211 + port_nexus_ptr); 212 + case SCSI_PROTOCOL_ISCSI: 213 + return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 214 + port_nexus_ptr); 215 + default: 216 + pr_err("Unknown tport_proto_id: 0x%02x, using" 217 + " SAS emulation\n", tport->tport_proto_id); 218 + break; 219 + } 220 + 221 + return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, 222 + port_nexus_ptr); 223 + } 224 + 225 + static struct se_node_acl *tcm_vhost_alloc_fabric_acl( 226 + struct se_portal_group *se_tpg) 227 + { 228 + struct tcm_vhost_nacl *nacl; 229 + 230 + nacl = kzalloc(sizeof(struct tcm_vhost_nacl), GFP_KERNEL); 231 + if (!nacl) { 232 + pr_err("Unable to alocate struct tcm_vhost_nacl\n"); 233 + return NULL; 234 + } 235 + 236 + return &nacl->se_node_acl; 237 + } 238 + 239 + static void tcm_vhost_release_fabric_acl( 240 + struct se_portal_group *se_tpg, 241 + struct se_node_acl *se_nacl) 242 + { 243 + struct tcm_vhost_nacl *nacl = container_of(se_nacl, 244 + struct tcm_vhost_nacl, se_node_acl); 245 + kfree(nacl); 246 + } 247 + 248 + static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg) 249 + { 250 + return 1; 251 + } 252 + 253 + static void tcm_vhost_release_cmd(struct se_cmd *se_cmd) 254 + { 255 + return; 256 + } 257 + 258 + static int tcm_vhost_shutdown_session(struct se_session *se_sess) 259 + { 260 + return 0; 261 + } 262 + 263 + static void tcm_vhost_close_session(struct se_session *se_sess) 264 + { 265 + return; 266 + } 267 + 268 + static u32 tcm_vhost_sess_get_index(struct se_session *se_sess) 269 + { 270 + return 0; 271 + } 272 + 273 + static int tcm_vhost_write_pending(struct se_cmd *se_cmd) 274 + { 275 + /* Go ahead and process the write immediately */ 276 + target_execute_cmd(se_cmd); 277 + return 0; 278 + } 279 + 280 + static int tcm_vhost_write_pending_status(struct se_cmd *se_cmd) 281 + { 282 + return 0; 283 + } 284 + 285 + static void tcm_vhost_set_default_node_attrs(struct se_node_acl *nacl) 286 + { 287 + return; 288 + } 289 + 290 + static u32 tcm_vhost_get_task_tag(struct se_cmd *se_cmd) 291 + { 292 + return 0; 293 + } 294 + 295 + static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd) 296 + { 297 + return 0; 298 + } 299 + 300 + static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *); 301 + 302 + static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd) 303 + { 304 + struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd, 305 + struct tcm_vhost_cmd, tvc_se_cmd); 306 + vhost_scsi_complete_cmd(tv_cmd); 307 + return 0; 308 + } 309 + 310 + static int tcm_vhost_queue_status(struct se_cmd *se_cmd) 311 + { 312 + struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd, 313 + struct tcm_vhost_cmd, tvc_se_cmd); 314 + vhost_scsi_complete_cmd(tv_cmd); 315 + return 0; 316 + } 317 + 318 + static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd) 319 + { 320 + return 0; 321 + } 322 + 323 + static u16 tcm_vhost_set_fabric_sense_len(struct se_cmd *se_cmd, 324 + u32 sense_length) 325 + { 326 + return 0; 327 + } 328 + 329 + static u16 tcm_vhost_get_fabric_sense_len(void) 330 + { 331 + return 0; 332 + } 333 + 334 + static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd) 335 + { 336 + struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; 337 + 338 + /* TODO locking against target/backend threads? */ 339 + transport_generic_free_cmd(se_cmd, 1); 340 + 341 + if (tv_cmd->tvc_sgl_count) { 342 + u32 i; 343 + for (i = 0; i < tv_cmd->tvc_sgl_count; i++) 344 + put_page(sg_page(&tv_cmd->tvc_sgl[i])); 345 + 346 + kfree(tv_cmd->tvc_sgl); 347 + } 348 + 349 + kfree(tv_cmd); 350 + } 351 + 352 + /* Dequeue a command from the completion list */ 353 + static struct tcm_vhost_cmd *vhost_scsi_get_cmd_from_completion( 354 + struct vhost_scsi *vs) 355 + { 356 + struct tcm_vhost_cmd *tv_cmd = NULL; 357 + 358 + spin_lock_bh(&vs->vs_completion_lock); 359 + if (list_empty(&vs->vs_completion_list)) { 360 + spin_unlock_bh(&vs->vs_completion_lock); 361 + return NULL; 362 + } 363 + 364 + list_for_each_entry(tv_cmd, &vs->vs_completion_list, 365 + tvc_completion_list) { 366 + list_del(&tv_cmd->tvc_completion_list); 367 + break; 368 + } 369 + spin_unlock_bh(&vs->vs_completion_lock); 370 + return tv_cmd; 371 + } 372 + 373 + /* Fill in status and signal that we are done processing this command 374 + * 375 + * This is scheduled in the vhost work queue so we are called with the owner 376 + * process mm and can access the vring. 377 + */ 378 + static void vhost_scsi_complete_cmd_work(struct vhost_work *work) 379 + { 380 + struct vhost_scsi *vs = container_of(work, struct vhost_scsi, 381 + vs_completion_work); 382 + struct tcm_vhost_cmd *tv_cmd; 383 + 384 + while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs)) != NULL) { 385 + struct virtio_scsi_cmd_resp v_rsp; 386 + struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; 387 + int ret; 388 + 389 + pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, 390 + tv_cmd, se_cmd->residual_count, se_cmd->scsi_status); 391 + 392 + memset(&v_rsp, 0, sizeof(v_rsp)); 393 + v_rsp.resid = se_cmd->residual_count; 394 + /* TODO is status_qualifier field needed? */ 395 + v_rsp.status = se_cmd->scsi_status; 396 + v_rsp.sense_len = se_cmd->scsi_sense_length; 397 + memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf, 398 + v_rsp.sense_len); 399 + ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp)); 400 + if (likely(ret == 0)) 401 + vhost_add_used(&vs->vqs[2], tv_cmd->tvc_vq_desc, 0); 402 + else 403 + pr_err("Faulted on virtio_scsi_cmd_resp\n"); 404 + 405 + vhost_scsi_free_cmd(tv_cmd); 406 + } 407 + 408 + vhost_signal(&vs->dev, &vs->vqs[2]); 409 + } 410 + 411 + static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd) 412 + { 413 + struct vhost_scsi *vs = tv_cmd->tvc_vhost; 414 + 415 + pr_debug("%s tv_cmd %p\n", __func__, tv_cmd); 416 + 417 + spin_lock_bh(&vs->vs_completion_lock); 418 + list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); 419 + spin_unlock_bh(&vs->vs_completion_lock); 420 + 421 + vhost_work_queue(&vs->dev, &vs->vs_completion_work); 422 + } 423 + 424 + static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd( 425 + struct tcm_vhost_tpg *tv_tpg, 426 + struct virtio_scsi_cmd_req *v_req, 427 + u32 exp_data_len, 428 + int data_direction) 429 + { 430 + struct tcm_vhost_cmd *tv_cmd; 431 + struct tcm_vhost_nexus *tv_nexus; 432 + struct se_portal_group *se_tpg = &tv_tpg->se_tpg; 433 + struct se_session *se_sess; 434 + struct se_cmd *se_cmd; 435 + int sam_task_attr; 436 + 437 + tv_nexus = tv_tpg->tpg_nexus; 438 + if (!tv_nexus) { 439 + pr_err("Unable to locate active struct tcm_vhost_nexus\n"); 440 + return ERR_PTR(-EIO); 441 + } 442 + se_sess = tv_nexus->tvn_se_sess; 443 + 444 + tv_cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC); 445 + if (!tv_cmd) { 446 + pr_err("Unable to allocate struct tcm_vhost_cmd\n"); 447 + return ERR_PTR(-ENOMEM); 448 + } 449 + INIT_LIST_HEAD(&tv_cmd->tvc_completion_list); 450 + tv_cmd->tvc_tag = v_req->tag; 451 + 452 + se_cmd = &tv_cmd->tvc_se_cmd; 453 + /* 454 + * Locate the SAM Task Attr from virtio_scsi_cmd_req 455 + */ 456 + sam_task_attr = v_req->task_attr; 457 + /* 458 + * Initialize struct se_cmd descriptor from TCM infrastructure 459 + */ 460 + transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, exp_data_len, 461 + data_direction, sam_task_attr, 462 + &tv_cmd->tvc_sense_buf[0]); 463 + 464 + #if 0 /* FIXME: vhost_scsi_allocate_cmd() BIDI operation */ 465 + if (bidi) 466 + se_cmd->se_cmd_flags |= SCF_BIDI; 467 + #endif 468 + return tv_cmd; 469 + } 470 + 471 + /* 472 + * Map a user memory range into a scatterlist 473 + * 474 + * Returns the number of scatterlist entries used or -errno on error. 475 + */ 476 + static int vhost_scsi_map_to_sgl(struct scatterlist *sgl, 477 + unsigned int sgl_count, void __user *ptr, size_t len, int write) 478 + { 479 + struct scatterlist *sg = sgl; 480 + unsigned int npages = 0; 481 + int ret; 482 + 483 + while (len > 0) { 484 + struct page *page; 485 + unsigned int offset = (uintptr_t)ptr & ~PAGE_MASK; 486 + unsigned int nbytes = min_t(unsigned int, 487 + PAGE_SIZE - offset, len); 488 + 489 + if (npages == sgl_count) { 490 + ret = -ENOBUFS; 491 + goto err; 492 + } 493 + 494 + ret = get_user_pages_fast((unsigned long)ptr, 1, write, &page); 495 + BUG_ON(ret == 0); /* we should either get our page or fail */ 496 + if (ret < 0) 497 + goto err; 498 + 499 + sg_set_page(sg, page, nbytes, offset); 500 + ptr += nbytes; 501 + len -= nbytes; 502 + sg++; 503 + npages++; 504 + } 505 + return npages; 506 + 507 + err: 508 + /* Put pages that we hold */ 509 + for (sg = sgl; sg != &sgl[npages]; sg++) 510 + put_page(sg_page(sg)); 511 + return ret; 512 + } 513 + 514 + static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd, 515 + struct iovec *iov, unsigned int niov, int write) 516 + { 517 + int ret; 518 + unsigned int i; 519 + u32 sgl_count; 520 + struct scatterlist *sg; 521 + 522 + /* 523 + * Find out how long sglist needs to be 524 + */ 525 + sgl_count = 0; 526 + for (i = 0; i < niov; i++) { 527 + sgl_count += (((uintptr_t)iov[i].iov_base + iov[i].iov_len + 528 + PAGE_SIZE - 1) >> PAGE_SHIFT) - 529 + ((uintptr_t)iov[i].iov_base >> PAGE_SHIFT); 530 + } 531 + /* TODO overflow checking */ 532 + 533 + sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC); 534 + if (!sg) 535 + return -ENOMEM; 536 + pr_debug("%s sg %p sgl_count %u is_err %ld\n", __func__, 537 + sg, sgl_count, IS_ERR(sg)); 538 + sg_init_table(sg, sgl_count); 539 + 540 + tv_cmd->tvc_sgl = sg; 541 + tv_cmd->tvc_sgl_count = sgl_count; 542 + 543 + pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); 544 + for (i = 0; i < niov; i++) { 545 + ret = vhost_scsi_map_to_sgl(sg, sgl_count, iov[i].iov_base, 546 + iov[i].iov_len, write); 547 + if (ret < 0) { 548 + for (i = 0; i < tv_cmd->tvc_sgl_count; i++) 549 + put_page(sg_page(&tv_cmd->tvc_sgl[i])); 550 + kfree(tv_cmd->tvc_sgl); 551 + tv_cmd->tvc_sgl = NULL; 552 + tv_cmd->tvc_sgl_count = 0; 553 + return ret; 554 + } 555 + 556 + sg += ret; 557 + sgl_count -= ret; 558 + } 559 + return 0; 560 + } 561 + 562 + static void tcm_vhost_submission_work(struct work_struct *work) 563 + { 564 + struct tcm_vhost_cmd *tv_cmd = 565 + container_of(work, struct tcm_vhost_cmd, work); 566 + struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; 567 + struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL; 568 + int rc, sg_no_bidi = 0; 569 + /* 570 + * Locate the struct se_lun pointer based on v_req->lun, and 571 + * attach it to struct se_cmd 572 + */ 573 + rc = transport_lookup_cmd_lun(&tv_cmd->tvc_se_cmd, tv_cmd->tvc_lun); 574 + if (rc < 0) { 575 + pr_err("Failed to look up lun: %d\n", tv_cmd->tvc_lun); 576 + transport_send_check_condition_and_sense(&tv_cmd->tvc_se_cmd, 577 + tv_cmd->tvc_se_cmd.scsi_sense_reason, 0); 578 + transport_generic_free_cmd(se_cmd, 0); 579 + return; 580 + } 581 + 582 + rc = target_setup_cmd_from_cdb(se_cmd, tv_cmd->tvc_cdb); 583 + if (rc == -ENOMEM) { 584 + transport_send_check_condition_and_sense(se_cmd, 585 + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); 586 + transport_generic_free_cmd(se_cmd, 0); 587 + return; 588 + } else if (rc < 0) { 589 + if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) 590 + tcm_vhost_queue_status(se_cmd); 591 + else 592 + transport_send_check_condition_and_sense(se_cmd, 593 + se_cmd->scsi_sense_reason, 0); 594 + transport_generic_free_cmd(se_cmd, 0); 595 + return; 596 + } 597 + 598 + if (tv_cmd->tvc_sgl_count) { 599 + sg_ptr = tv_cmd->tvc_sgl; 600 + /* 601 + * For BIDI commands, pass in the extra READ buffer 602 + * to transport_generic_map_mem_to_cmd() below.. 603 + */ 604 + /* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */ 605 + #if 0 606 + if (se_cmd->se_cmd_flags & SCF_BIDI) { 607 + sg_bidi_ptr = NULL; 608 + sg_no_bidi = 0; 609 + } 610 + #endif 611 + } else { 612 + sg_ptr = NULL; 613 + } 614 + 615 + rc = transport_generic_map_mem_to_cmd(se_cmd, sg_ptr, 616 + tv_cmd->tvc_sgl_count, sg_bidi_ptr, 617 + sg_no_bidi); 618 + if (rc < 0) { 619 + transport_send_check_condition_and_sense(se_cmd, 620 + se_cmd->scsi_sense_reason, 0); 621 + transport_generic_free_cmd(se_cmd, 0); 622 + return; 623 + } 624 + transport_handle_cdb_direct(se_cmd); 625 + } 626 + 627 + static void vhost_scsi_handle_vq(struct vhost_scsi *vs) 628 + { 629 + struct vhost_virtqueue *vq = &vs->vqs[2]; 630 + struct virtio_scsi_cmd_req v_req; 631 + struct tcm_vhost_tpg *tv_tpg; 632 + struct tcm_vhost_cmd *tv_cmd; 633 + u32 exp_data_len, data_first, data_num, data_direction; 634 + unsigned out, in, i; 635 + int head, ret; 636 + 637 + /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */ 638 + tv_tpg = vs->vs_tpg; 639 + if (unlikely(!tv_tpg)) { 640 + pr_err("%s endpoint not set\n", __func__); 641 + return; 642 + } 643 + 644 + mutex_lock(&vq->mutex); 645 + vhost_disable_notify(&vs->dev, vq); 646 + 647 + for (;;) { 648 + head = vhost_get_vq_desc(&vs->dev, vq, vq->iov, 649 + ARRAY_SIZE(vq->iov), &out, &in, 650 + NULL, NULL); 651 + pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n", 652 + head, out, in); 653 + /* On error, stop handling until the next kick. */ 654 + if (unlikely(head < 0)) 655 + break; 656 + /* Nothing new? Wait for eventfd to tell us they refilled. */ 657 + if (head == vq->num) { 658 + if (unlikely(vhost_enable_notify(&vs->dev, vq))) { 659 + vhost_disable_notify(&vs->dev, vq); 660 + continue; 661 + } 662 + break; 663 + } 664 + 665 + /* FIXME: BIDI operation */ 666 + if (out == 1 && in == 1) { 667 + data_direction = DMA_NONE; 668 + data_first = 0; 669 + data_num = 0; 670 + } else if (out == 1 && in > 1) { 671 + data_direction = DMA_FROM_DEVICE; 672 + data_first = out + 1; 673 + data_num = in - 1; 674 + } else if (out > 1 && in == 1) { 675 + data_direction = DMA_TO_DEVICE; 676 + data_first = 1; 677 + data_num = out - 1; 678 + } else { 679 + vq_err(vq, "Invalid buffer layout out: %u in: %u\n", 680 + out, in); 681 + break; 682 + } 683 + 684 + /* 685 + * Check for a sane resp buffer so we can report errors to 686 + * the guest. 687 + */ 688 + if (unlikely(vq->iov[out].iov_len != 689 + sizeof(struct virtio_scsi_cmd_resp))) { 690 + vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu" 691 + " bytes\n", vq->iov[out].iov_len); 692 + break; 693 + } 694 + 695 + if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) { 696 + vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu" 697 + " bytes\n", vq->iov[0].iov_len); 698 + break; 699 + } 700 + pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p," 701 + " len: %zu\n", vq->iov[0].iov_base, sizeof(v_req)); 702 + ret = __copy_from_user(&v_req, vq->iov[0].iov_base, 703 + sizeof(v_req)); 704 + if (unlikely(ret)) { 705 + vq_err(vq, "Faulted on virtio_scsi_cmd_req\n"); 706 + break; 707 + } 708 + 709 + exp_data_len = 0; 710 + for (i = 0; i < data_num; i++) 711 + exp_data_len += vq->iov[data_first + i].iov_len; 712 + 713 + tv_cmd = vhost_scsi_allocate_cmd(tv_tpg, &v_req, 714 + exp_data_len, data_direction); 715 + if (IS_ERR(tv_cmd)) { 716 + vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n", 717 + PTR_ERR(tv_cmd)); 718 + break; 719 + } 720 + pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction" 721 + ": %d\n", tv_cmd, exp_data_len, data_direction); 722 + 723 + tv_cmd->tvc_vhost = vs; 724 + 725 + if (unlikely(vq->iov[out].iov_len != 726 + sizeof(struct virtio_scsi_cmd_resp))) { 727 + vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu" 728 + " bytes, out: %d, in: %d\n", 729 + vq->iov[out].iov_len, out, in); 730 + break; 731 + } 732 + 733 + tv_cmd->tvc_resp = vq->iov[out].iov_base; 734 + 735 + /* 736 + * Copy in the recieved CDB descriptor into tv_cmd->tvc_cdb 737 + * that will be used by tcm_vhost_new_cmd_map() and down into 738 + * target_setup_cmd_from_cdb() 739 + */ 740 + memcpy(tv_cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE); 741 + /* 742 + * Check that the recieved CDB size does not exceeded our 743 + * hardcoded max for tcm_vhost 744 + */ 745 + /* TODO what if cdb was too small for varlen cdb header? */ 746 + if (unlikely(scsi_command_size(tv_cmd->tvc_cdb) > 747 + TCM_VHOST_MAX_CDB_SIZE)) { 748 + vq_err(vq, "Received SCSI CDB with command_size: %d that" 749 + " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", 750 + scsi_command_size(tv_cmd->tvc_cdb), 751 + TCM_VHOST_MAX_CDB_SIZE); 752 + break; /* TODO */ 753 + } 754 + tv_cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF; 755 + 756 + pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n", 757 + tv_cmd->tvc_cdb[0], tv_cmd->tvc_lun); 758 + 759 + if (data_direction != DMA_NONE) { 760 + ret = vhost_scsi_map_iov_to_sgl(tv_cmd, 761 + &vq->iov[data_first], data_num, 762 + data_direction == DMA_TO_DEVICE); 763 + if (unlikely(ret)) { 764 + vq_err(vq, "Failed to map iov to sgl\n"); 765 + break; /* TODO */ 766 + } 767 + } 768 + 769 + /* 770 + * Save the descriptor from vhost_get_vq_desc() to be used to 771 + * complete the virtio-scsi request in TCM callback context via 772 + * tcm_vhost_queue_data_in() and tcm_vhost_queue_status() 773 + */ 774 + tv_cmd->tvc_vq_desc = head; 775 + /* 776 + * Dispatch tv_cmd descriptor for cmwq execution in process 777 + * context provided by tcm_vhost_workqueue. This also ensures 778 + * tv_cmd is executed on the same kworker CPU as this vhost 779 + * thread to gain positive L2 cache locality effects.. 780 + */ 781 + INIT_WORK(&tv_cmd->work, tcm_vhost_submission_work); 782 + queue_work(tcm_vhost_workqueue, &tv_cmd->work); 783 + } 784 + 785 + mutex_unlock(&vq->mutex); 786 + } 787 + 788 + static void vhost_scsi_ctl_handle_kick(struct vhost_work *work) 789 + { 790 + pr_err("%s: The handling func for control queue.\n", __func__); 791 + } 792 + 793 + static void vhost_scsi_evt_handle_kick(struct vhost_work *work) 794 + { 795 + pr_err("%s: The handling func for event queue.\n", __func__); 796 + } 797 + 798 + static void vhost_scsi_handle_kick(struct vhost_work *work) 799 + { 800 + struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue, 801 + poll.work); 802 + struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev); 803 + 804 + vhost_scsi_handle_vq(vs); 805 + } 806 + 807 + /* 808 + * Called from vhost_scsi_ioctl() context to walk the list of available 809 + * tcm_vhost_tpg with an active struct tcm_vhost_nexus 810 + */ 811 + static int vhost_scsi_set_endpoint( 812 + struct vhost_scsi *vs, 813 + struct vhost_scsi_target *t) 814 + { 815 + struct tcm_vhost_tport *tv_tport; 816 + struct tcm_vhost_tpg *tv_tpg; 817 + int index; 818 + 819 + mutex_lock(&vs->dev.mutex); 820 + /* Verify that ring has been setup correctly. */ 821 + for (index = 0; index < vs->dev.nvqs; ++index) { 822 + /* Verify that ring has been setup correctly. */ 823 + if (!vhost_vq_access_ok(&vs->vqs[index])) { 824 + mutex_unlock(&vs->dev.mutex); 825 + return -EFAULT; 826 + } 827 + } 828 + 829 + if (vs->vs_tpg) { 830 + mutex_unlock(&vs->dev.mutex); 831 + return -EEXIST; 832 + } 833 + mutex_unlock(&vs->dev.mutex); 834 + 835 + mutex_lock(&tcm_vhost_mutex); 836 + list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) { 837 + mutex_lock(&tv_tpg->tv_tpg_mutex); 838 + if (!tv_tpg->tpg_nexus) { 839 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 840 + continue; 841 + } 842 + if (atomic_read(&tv_tpg->tv_tpg_vhost_count)) { 843 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 844 + continue; 845 + } 846 + tv_tport = tv_tpg->tport; 847 + 848 + if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) && 849 + (tv_tpg->tport_tpgt == t->vhost_tpgt)) { 850 + atomic_inc(&tv_tpg->tv_tpg_vhost_count); 851 + smp_mb__after_atomic_inc(); 852 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 853 + mutex_unlock(&tcm_vhost_mutex); 854 + 855 + mutex_lock(&vs->dev.mutex); 856 + vs->vs_tpg = tv_tpg; 857 + atomic_inc(&vs->vhost_ref_cnt); 858 + smp_mb__after_atomic_inc(); 859 + mutex_unlock(&vs->dev.mutex); 860 + return 0; 861 + } 862 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 863 + } 864 + mutex_unlock(&tcm_vhost_mutex); 865 + return -EINVAL; 866 + } 867 + 868 + static int vhost_scsi_clear_endpoint( 869 + struct vhost_scsi *vs, 870 + struct vhost_scsi_target *t) 871 + { 872 + struct tcm_vhost_tport *tv_tport; 873 + struct tcm_vhost_tpg *tv_tpg; 874 + int index; 875 + 876 + mutex_lock(&vs->dev.mutex); 877 + /* Verify that ring has been setup correctly. */ 878 + for (index = 0; index < vs->dev.nvqs; ++index) { 879 + if (!vhost_vq_access_ok(&vs->vqs[index])) { 880 + mutex_unlock(&vs->dev.mutex); 881 + return -EFAULT; 882 + } 883 + } 884 + 885 + if (!vs->vs_tpg) { 886 + mutex_unlock(&vs->dev.mutex); 887 + return -ENODEV; 888 + } 889 + tv_tpg = vs->vs_tpg; 890 + tv_tport = tv_tpg->tport; 891 + 892 + if (strcmp(tv_tport->tport_name, t->vhost_wwpn) || 893 + (tv_tpg->tport_tpgt != t->vhost_tpgt)) { 894 + mutex_unlock(&vs->dev.mutex); 895 + pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu" 896 + " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n", 897 + tv_tport->tport_name, tv_tpg->tport_tpgt, 898 + t->vhost_wwpn, t->vhost_tpgt); 899 + return -EINVAL; 900 + } 901 + atomic_dec(&tv_tpg->tv_tpg_vhost_count); 902 + vs->vs_tpg = NULL; 903 + mutex_unlock(&vs->dev.mutex); 904 + 905 + return 0; 906 + } 907 + 908 + static int vhost_scsi_open(struct inode *inode, struct file *f) 909 + { 910 + struct vhost_scsi *s; 911 + int r; 912 + 913 + s = kzalloc(sizeof(*s), GFP_KERNEL); 914 + if (!s) 915 + return -ENOMEM; 916 + 917 + vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work); 918 + INIT_LIST_HEAD(&s->vs_completion_list); 919 + spin_lock_init(&s->vs_completion_lock); 920 + 921 + s->vqs[0].handle_kick = vhost_scsi_ctl_handle_kick; 922 + s->vqs[1].handle_kick = vhost_scsi_evt_handle_kick; 923 + s->vqs[2].handle_kick = vhost_scsi_handle_kick; 924 + r = vhost_dev_init(&s->dev, s->vqs, 3); 925 + if (r < 0) { 926 + kfree(s); 927 + return r; 928 + } 929 + 930 + f->private_data = s; 931 + return 0; 932 + } 933 + 934 + static int vhost_scsi_release(struct inode *inode, struct file *f) 935 + { 936 + struct vhost_scsi *s = f->private_data; 937 + 938 + if (s->vs_tpg && s->vs_tpg->tport) { 939 + struct vhost_scsi_target backend; 940 + 941 + memcpy(backend.vhost_wwpn, s->vs_tpg->tport->tport_name, 942 + sizeof(backend.vhost_wwpn)); 943 + backend.vhost_tpgt = s->vs_tpg->tport_tpgt; 944 + vhost_scsi_clear_endpoint(s, &backend); 945 + } 946 + 947 + vhost_dev_cleanup(&s->dev, false); 948 + kfree(s); 949 + return 0; 950 + } 951 + 952 + static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) 953 + { 954 + if (features & ~VHOST_FEATURES) 955 + return -EOPNOTSUPP; 956 + 957 + mutex_lock(&vs->dev.mutex); 958 + if ((features & (1 << VHOST_F_LOG_ALL)) && 959 + !vhost_log_access_ok(&vs->dev)) { 960 + mutex_unlock(&vs->dev.mutex); 961 + return -EFAULT; 962 + } 963 + vs->dev.acked_features = features; 964 + /* TODO possibly smp_wmb() and flush vqs */ 965 + mutex_unlock(&vs->dev.mutex); 966 + return 0; 967 + } 968 + 969 + static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl, 970 + unsigned long arg) 971 + { 972 + struct vhost_scsi *vs = f->private_data; 973 + struct vhost_scsi_target backend; 974 + void __user *argp = (void __user *)arg; 975 + u64 __user *featurep = argp; 976 + u64 features; 977 + int r; 978 + 979 + switch (ioctl) { 980 + case VHOST_SCSI_SET_ENDPOINT: 981 + if (copy_from_user(&backend, argp, sizeof backend)) 982 + return -EFAULT; 983 + 984 + return vhost_scsi_set_endpoint(vs, &backend); 985 + case VHOST_SCSI_CLEAR_ENDPOINT: 986 + if (copy_from_user(&backend, argp, sizeof backend)) 987 + return -EFAULT; 988 + 989 + return vhost_scsi_clear_endpoint(vs, &backend); 990 + case VHOST_SCSI_GET_ABI_VERSION: 991 + if (copy_from_user(&backend, argp, sizeof backend)) 992 + return -EFAULT; 993 + 994 + backend.abi_version = VHOST_SCSI_ABI_VERSION; 995 + 996 + if (copy_to_user(argp, &backend, sizeof backend)) 997 + return -EFAULT; 998 + return 0; 999 + case VHOST_GET_FEATURES: 1000 + features = VHOST_FEATURES; 1001 + if (copy_to_user(featurep, &features, sizeof features)) 1002 + return -EFAULT; 1003 + return 0; 1004 + case VHOST_SET_FEATURES: 1005 + if (copy_from_user(&features, featurep, sizeof features)) 1006 + return -EFAULT; 1007 + return vhost_scsi_set_features(vs, features); 1008 + default: 1009 + mutex_lock(&vs->dev.mutex); 1010 + r = vhost_dev_ioctl(&vs->dev, ioctl, arg); 1011 + mutex_unlock(&vs->dev.mutex); 1012 + return r; 1013 + } 1014 + } 1015 + 1016 + static const struct file_operations vhost_scsi_fops = { 1017 + .owner = THIS_MODULE, 1018 + .release = vhost_scsi_release, 1019 + .unlocked_ioctl = vhost_scsi_ioctl, 1020 + /* TODO compat ioctl? */ 1021 + .open = vhost_scsi_open, 1022 + .llseek = noop_llseek, 1023 + }; 1024 + 1025 + static struct miscdevice vhost_scsi_misc = { 1026 + MISC_DYNAMIC_MINOR, 1027 + "vhost-scsi", 1028 + &vhost_scsi_fops, 1029 + }; 1030 + 1031 + static int __init vhost_scsi_register(void) 1032 + { 1033 + return misc_register(&vhost_scsi_misc); 1034 + } 1035 + 1036 + static int vhost_scsi_deregister(void) 1037 + { 1038 + return misc_deregister(&vhost_scsi_misc); 1039 + } 1040 + 1041 + static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport) 1042 + { 1043 + switch (tport->tport_proto_id) { 1044 + case SCSI_PROTOCOL_SAS: 1045 + return "SAS"; 1046 + case SCSI_PROTOCOL_FCP: 1047 + return "FCP"; 1048 + case SCSI_PROTOCOL_ISCSI: 1049 + return "iSCSI"; 1050 + default: 1051 + break; 1052 + } 1053 + 1054 + return "Unknown"; 1055 + } 1056 + 1057 + static int tcm_vhost_port_link( 1058 + struct se_portal_group *se_tpg, 1059 + struct se_lun *lun) 1060 + { 1061 + struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, 1062 + struct tcm_vhost_tpg, se_tpg); 1063 + 1064 + atomic_inc(&tv_tpg->tv_tpg_port_count); 1065 + smp_mb__after_atomic_inc(); 1066 + 1067 + return 0; 1068 + } 1069 + 1070 + static void tcm_vhost_port_unlink( 1071 + struct se_portal_group *se_tpg, 1072 + struct se_lun *se_lun) 1073 + { 1074 + struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, 1075 + struct tcm_vhost_tpg, se_tpg); 1076 + 1077 + atomic_dec(&tv_tpg->tv_tpg_port_count); 1078 + smp_mb__after_atomic_dec(); 1079 + } 1080 + 1081 + static struct se_node_acl *tcm_vhost_make_nodeacl( 1082 + struct se_portal_group *se_tpg, 1083 + struct config_group *group, 1084 + const char *name) 1085 + { 1086 + struct se_node_acl *se_nacl, *se_nacl_new; 1087 + struct tcm_vhost_nacl *nacl; 1088 + u64 wwpn = 0; 1089 + u32 nexus_depth; 1090 + 1091 + /* tcm_vhost_parse_wwn(name, &wwpn, 1) < 0) 1092 + return ERR_PTR(-EINVAL); */ 1093 + se_nacl_new = tcm_vhost_alloc_fabric_acl(se_tpg); 1094 + if (!se_nacl_new) 1095 + return ERR_PTR(-ENOMEM); 1096 + 1097 + nexus_depth = 1; 1098 + /* 1099 + * se_nacl_new may be released by core_tpg_add_initiator_node_acl() 1100 + * when converting a NodeACL from demo mode -> explict 1101 + */ 1102 + se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, 1103 + name, nexus_depth); 1104 + if (IS_ERR(se_nacl)) { 1105 + tcm_vhost_release_fabric_acl(se_tpg, se_nacl_new); 1106 + return se_nacl; 1107 + } 1108 + /* 1109 + * Locate our struct tcm_vhost_nacl and set the FC Nport WWPN 1110 + */ 1111 + nacl = container_of(se_nacl, struct tcm_vhost_nacl, se_node_acl); 1112 + nacl->iport_wwpn = wwpn; 1113 + 1114 + return se_nacl; 1115 + } 1116 + 1117 + static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl) 1118 + { 1119 + struct tcm_vhost_nacl *nacl = container_of(se_acl, 1120 + struct tcm_vhost_nacl, se_node_acl); 1121 + core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); 1122 + kfree(nacl); 1123 + } 1124 + 1125 + static int tcm_vhost_make_nexus( 1126 + struct tcm_vhost_tpg *tv_tpg, 1127 + const char *name) 1128 + { 1129 + struct se_portal_group *se_tpg; 1130 + struct tcm_vhost_nexus *tv_nexus; 1131 + 1132 + mutex_lock(&tv_tpg->tv_tpg_mutex); 1133 + if (tv_tpg->tpg_nexus) { 1134 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1135 + pr_debug("tv_tpg->tpg_nexus already exists\n"); 1136 + return -EEXIST; 1137 + } 1138 + se_tpg = &tv_tpg->se_tpg; 1139 + 1140 + tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL); 1141 + if (!tv_nexus) { 1142 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1143 + pr_err("Unable to allocate struct tcm_vhost_nexus\n"); 1144 + return -ENOMEM; 1145 + } 1146 + /* 1147 + * Initialize the struct se_session pointer 1148 + */ 1149 + tv_nexus->tvn_se_sess = transport_init_session(); 1150 + if (IS_ERR(tv_nexus->tvn_se_sess)) { 1151 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1152 + kfree(tv_nexus); 1153 + return -ENOMEM; 1154 + } 1155 + /* 1156 + * Since we are running in 'demo mode' this call with generate a 1157 + * struct se_node_acl for the tcm_vhost struct se_portal_group with 1158 + * the SCSI Initiator port name of the passed configfs group 'name'. 1159 + */ 1160 + tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( 1161 + se_tpg, (unsigned char *)name); 1162 + if (!tv_nexus->tvn_se_sess->se_node_acl) { 1163 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1164 + pr_debug("core_tpg_check_initiator_node_acl() failed" 1165 + " for %s\n", name); 1166 + transport_free_session(tv_nexus->tvn_se_sess); 1167 + kfree(tv_nexus); 1168 + return -ENOMEM; 1169 + } 1170 + /* 1171 + * Now register the TCM vHost virtual I_T Nexus as active with the 1172 + * call to __transport_register_session() 1173 + */ 1174 + __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, 1175 + tv_nexus->tvn_se_sess, tv_nexus); 1176 + tv_tpg->tpg_nexus = tv_nexus; 1177 + 1178 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1179 + return 0; 1180 + } 1181 + 1182 + static int tcm_vhost_drop_nexus( 1183 + struct tcm_vhost_tpg *tpg) 1184 + { 1185 + struct se_session *se_sess; 1186 + struct tcm_vhost_nexus *tv_nexus; 1187 + 1188 + mutex_lock(&tpg->tv_tpg_mutex); 1189 + tv_nexus = tpg->tpg_nexus; 1190 + if (!tv_nexus) { 1191 + mutex_unlock(&tpg->tv_tpg_mutex); 1192 + return -ENODEV; 1193 + } 1194 + 1195 + se_sess = tv_nexus->tvn_se_sess; 1196 + if (!se_sess) { 1197 + mutex_unlock(&tpg->tv_tpg_mutex); 1198 + return -ENODEV; 1199 + } 1200 + 1201 + if (atomic_read(&tpg->tv_tpg_port_count)) { 1202 + mutex_unlock(&tpg->tv_tpg_mutex); 1203 + pr_err("Unable to remove TCM_vHost I_T Nexus with" 1204 + " active TPG port count: %d\n", 1205 + atomic_read(&tpg->tv_tpg_port_count)); 1206 + return -EPERM; 1207 + } 1208 + 1209 + if (atomic_read(&tpg->tv_tpg_vhost_count)) { 1210 + mutex_unlock(&tpg->tv_tpg_mutex); 1211 + pr_err("Unable to remove TCM_vHost I_T Nexus with" 1212 + " active TPG vhost count: %d\n", 1213 + atomic_read(&tpg->tv_tpg_vhost_count)); 1214 + return -EPERM; 1215 + } 1216 + 1217 + pr_debug("TCM_vHost_ConfigFS: Removing I_T Nexus to emulated" 1218 + " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport), 1219 + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 1220 + /* 1221 + * Release the SCSI I_T Nexus to the emulated vHost Target Port 1222 + */ 1223 + transport_deregister_session(tv_nexus->tvn_se_sess); 1224 + tpg->tpg_nexus = NULL; 1225 + mutex_unlock(&tpg->tv_tpg_mutex); 1226 + 1227 + kfree(tv_nexus); 1228 + return 0; 1229 + } 1230 + 1231 + static ssize_t tcm_vhost_tpg_show_nexus( 1232 + struct se_portal_group *se_tpg, 1233 + char *page) 1234 + { 1235 + struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, 1236 + struct tcm_vhost_tpg, se_tpg); 1237 + struct tcm_vhost_nexus *tv_nexus; 1238 + ssize_t ret; 1239 + 1240 + mutex_lock(&tv_tpg->tv_tpg_mutex); 1241 + tv_nexus = tv_tpg->tpg_nexus; 1242 + if (!tv_nexus) { 1243 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1244 + return -ENODEV; 1245 + } 1246 + ret = snprintf(page, PAGE_SIZE, "%s\n", 1247 + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); 1248 + mutex_unlock(&tv_tpg->tv_tpg_mutex); 1249 + 1250 + return ret; 1251 + } 1252 + 1253 + static ssize_t tcm_vhost_tpg_store_nexus( 1254 + struct se_portal_group *se_tpg, 1255 + const char *page, 1256 + size_t count) 1257 + { 1258 + struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg, 1259 + struct tcm_vhost_tpg, se_tpg); 1260 + struct tcm_vhost_tport *tport_wwn = tv_tpg->tport; 1261 + unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr; 1262 + int ret; 1263 + /* 1264 + * Shutdown the active I_T nexus if 'NULL' is passed.. 1265 + */ 1266 + if (!strncmp(page, "NULL", 4)) { 1267 + ret = tcm_vhost_drop_nexus(tv_tpg); 1268 + return (!ret) ? count : ret; 1269 + } 1270 + /* 1271 + * Otherwise make sure the passed virtual Initiator port WWN matches 1272 + * the fabric protocol_id set in tcm_vhost_make_tport(), and call 1273 + * tcm_vhost_make_nexus(). 1274 + */ 1275 + if (strlen(page) >= TCM_VHOST_NAMELEN) { 1276 + pr_err("Emulated NAA Sas Address: %s, exceeds" 1277 + " max: %d\n", page, TCM_VHOST_NAMELEN); 1278 + return -EINVAL; 1279 + } 1280 + snprintf(&i_port[0], TCM_VHOST_NAMELEN, "%s", page); 1281 + 1282 + ptr = strstr(i_port, "naa."); 1283 + if (ptr) { 1284 + if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) { 1285 + pr_err("Passed SAS Initiator Port %s does not" 1286 + " match target port protoid: %s\n", i_port, 1287 + tcm_vhost_dump_proto_id(tport_wwn)); 1288 + return -EINVAL; 1289 + } 1290 + port_ptr = &i_port[0]; 1291 + goto check_newline; 1292 + } 1293 + ptr = strstr(i_port, "fc."); 1294 + if (ptr) { 1295 + if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) { 1296 + pr_err("Passed FCP Initiator Port %s does not" 1297 + " match target port protoid: %s\n", i_port, 1298 + tcm_vhost_dump_proto_id(tport_wwn)); 1299 + return -EINVAL; 1300 + } 1301 + port_ptr = &i_port[3]; /* Skip over "fc." */ 1302 + goto check_newline; 1303 + } 1304 + ptr = strstr(i_port, "iqn."); 1305 + if (ptr) { 1306 + if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) { 1307 + pr_err("Passed iSCSI Initiator Port %s does not" 1308 + " match target port protoid: %s\n", i_port, 1309 + tcm_vhost_dump_proto_id(tport_wwn)); 1310 + return -EINVAL; 1311 + } 1312 + port_ptr = &i_port[0]; 1313 + goto check_newline; 1314 + } 1315 + pr_err("Unable to locate prefix for emulated Initiator Port:" 1316 + " %s\n", i_port); 1317 + return -EINVAL; 1318 + /* 1319 + * Clear any trailing newline for the NAA WWN 1320 + */ 1321 + check_newline: 1322 + if (i_port[strlen(i_port)-1] == '\n') 1323 + i_port[strlen(i_port)-1] = '\0'; 1324 + 1325 + ret = tcm_vhost_make_nexus(tv_tpg, port_ptr); 1326 + if (ret < 0) 1327 + return ret; 1328 + 1329 + return count; 1330 + } 1331 + 1332 + TF_TPG_BASE_ATTR(tcm_vhost, nexus, S_IRUGO | S_IWUSR); 1333 + 1334 + static struct configfs_attribute *tcm_vhost_tpg_attrs[] = { 1335 + &tcm_vhost_tpg_nexus.attr, 1336 + NULL, 1337 + }; 1338 + 1339 + static struct se_portal_group *tcm_vhost_make_tpg( 1340 + struct se_wwn *wwn, 1341 + struct config_group *group, 1342 + const char *name) 1343 + { 1344 + struct tcm_vhost_tport *tport = container_of(wwn, 1345 + struct tcm_vhost_tport, tport_wwn); 1346 + 1347 + struct tcm_vhost_tpg *tpg; 1348 + unsigned long tpgt; 1349 + int ret; 1350 + 1351 + if (strstr(name, "tpgt_") != name) 1352 + return ERR_PTR(-EINVAL); 1353 + if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX) 1354 + return ERR_PTR(-EINVAL); 1355 + 1356 + tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL); 1357 + if (!tpg) { 1358 + pr_err("Unable to allocate struct tcm_vhost_tpg"); 1359 + return ERR_PTR(-ENOMEM); 1360 + } 1361 + mutex_init(&tpg->tv_tpg_mutex); 1362 + INIT_LIST_HEAD(&tpg->tv_tpg_list); 1363 + tpg->tport = tport; 1364 + tpg->tport_tpgt = tpgt; 1365 + 1366 + ret = core_tpg_register(&tcm_vhost_fabric_configfs->tf_ops, wwn, 1367 + &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); 1368 + if (ret < 0) { 1369 + kfree(tpg); 1370 + return NULL; 1371 + } 1372 + mutex_lock(&tcm_vhost_mutex); 1373 + list_add_tail(&tpg->tv_tpg_list, &tcm_vhost_list); 1374 + mutex_unlock(&tcm_vhost_mutex); 1375 + 1376 + return &tpg->se_tpg; 1377 + } 1378 + 1379 + static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg) 1380 + { 1381 + struct tcm_vhost_tpg *tpg = container_of(se_tpg, 1382 + struct tcm_vhost_tpg, se_tpg); 1383 + 1384 + mutex_lock(&tcm_vhost_mutex); 1385 + list_del(&tpg->tv_tpg_list); 1386 + mutex_unlock(&tcm_vhost_mutex); 1387 + /* 1388 + * Release the virtual I_T Nexus for this vHost TPG 1389 + */ 1390 + tcm_vhost_drop_nexus(tpg); 1391 + /* 1392 + * Deregister the se_tpg from TCM.. 1393 + */ 1394 + core_tpg_deregister(se_tpg); 1395 + kfree(tpg); 1396 + } 1397 + 1398 + static struct se_wwn *tcm_vhost_make_tport( 1399 + struct target_fabric_configfs *tf, 1400 + struct config_group *group, 1401 + const char *name) 1402 + { 1403 + struct tcm_vhost_tport *tport; 1404 + char *ptr; 1405 + u64 wwpn = 0; 1406 + int off = 0; 1407 + 1408 + /* if (tcm_vhost_parse_wwn(name, &wwpn, 1) < 0) 1409 + return ERR_PTR(-EINVAL); */ 1410 + 1411 + tport = kzalloc(sizeof(struct tcm_vhost_tport), GFP_KERNEL); 1412 + if (!tport) { 1413 + pr_err("Unable to allocate struct tcm_vhost_tport"); 1414 + return ERR_PTR(-ENOMEM); 1415 + } 1416 + tport->tport_wwpn = wwpn; 1417 + /* 1418 + * Determine the emulated Protocol Identifier and Target Port Name 1419 + * based on the incoming configfs directory name. 1420 + */ 1421 + ptr = strstr(name, "naa."); 1422 + if (ptr) { 1423 + tport->tport_proto_id = SCSI_PROTOCOL_SAS; 1424 + goto check_len; 1425 + } 1426 + ptr = strstr(name, "fc."); 1427 + if (ptr) { 1428 + tport->tport_proto_id = SCSI_PROTOCOL_FCP; 1429 + off = 3; /* Skip over "fc." */ 1430 + goto check_len; 1431 + } 1432 + ptr = strstr(name, "iqn."); 1433 + if (ptr) { 1434 + tport->tport_proto_id = SCSI_PROTOCOL_ISCSI; 1435 + goto check_len; 1436 + } 1437 + 1438 + pr_err("Unable to locate prefix for emulated Target Port:" 1439 + " %s\n", name); 1440 + kfree(tport); 1441 + return ERR_PTR(-EINVAL); 1442 + 1443 + check_len: 1444 + if (strlen(name) >= TCM_VHOST_NAMELEN) { 1445 + pr_err("Emulated %s Address: %s, exceeds" 1446 + " max: %d\n", name, tcm_vhost_dump_proto_id(tport), 1447 + TCM_VHOST_NAMELEN); 1448 + kfree(tport); 1449 + return ERR_PTR(-EINVAL); 1450 + } 1451 + snprintf(&tport->tport_name[0], TCM_VHOST_NAMELEN, "%s", &name[off]); 1452 + 1453 + pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target" 1454 + " %s Address: %s\n", tcm_vhost_dump_proto_id(tport), name); 1455 + 1456 + return &tport->tport_wwn; 1457 + } 1458 + 1459 + static void tcm_vhost_drop_tport(struct se_wwn *wwn) 1460 + { 1461 + struct tcm_vhost_tport *tport = container_of(wwn, 1462 + struct tcm_vhost_tport, tport_wwn); 1463 + 1464 + pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target" 1465 + " %s Address: %s\n", tcm_vhost_dump_proto_id(tport), 1466 + tport->tport_name); 1467 + 1468 + kfree(tport); 1469 + } 1470 + 1471 + static ssize_t tcm_vhost_wwn_show_attr_version( 1472 + struct target_fabric_configfs *tf, 1473 + char *page) 1474 + { 1475 + return sprintf(page, "TCM_VHOST fabric module %s on %s/%s" 1476 + "on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname, 1477 + utsname()->machine); 1478 + } 1479 + 1480 + TF_WWN_ATTR_RO(tcm_vhost, version); 1481 + 1482 + static struct configfs_attribute *tcm_vhost_wwn_attrs[] = { 1483 + &tcm_vhost_wwn_version.attr, 1484 + NULL, 1485 + }; 1486 + 1487 + static struct target_core_fabric_ops tcm_vhost_ops = { 1488 + .get_fabric_name = tcm_vhost_get_fabric_name, 1489 + .get_fabric_proto_ident = tcm_vhost_get_fabric_proto_ident, 1490 + .tpg_get_wwn = tcm_vhost_get_fabric_wwn, 1491 + .tpg_get_tag = tcm_vhost_get_tag, 1492 + .tpg_get_default_depth = tcm_vhost_get_default_depth, 1493 + .tpg_get_pr_transport_id = tcm_vhost_get_pr_transport_id, 1494 + .tpg_get_pr_transport_id_len = tcm_vhost_get_pr_transport_id_len, 1495 + .tpg_parse_pr_out_transport_id = tcm_vhost_parse_pr_out_transport_id, 1496 + .tpg_check_demo_mode = tcm_vhost_check_true, 1497 + .tpg_check_demo_mode_cache = tcm_vhost_check_true, 1498 + .tpg_check_demo_mode_write_protect = tcm_vhost_check_false, 1499 + .tpg_check_prod_mode_write_protect = tcm_vhost_check_false, 1500 + .tpg_alloc_fabric_acl = tcm_vhost_alloc_fabric_acl, 1501 + .tpg_release_fabric_acl = tcm_vhost_release_fabric_acl, 1502 + .tpg_get_inst_index = tcm_vhost_tpg_get_inst_index, 1503 + .release_cmd = tcm_vhost_release_cmd, 1504 + .shutdown_session = tcm_vhost_shutdown_session, 1505 + .close_session = tcm_vhost_close_session, 1506 + .sess_get_index = tcm_vhost_sess_get_index, 1507 + .sess_get_initiator_sid = NULL, 1508 + .write_pending = tcm_vhost_write_pending, 1509 + .write_pending_status = tcm_vhost_write_pending_status, 1510 + .set_default_node_attributes = tcm_vhost_set_default_node_attrs, 1511 + .get_task_tag = tcm_vhost_get_task_tag, 1512 + .get_cmd_state = tcm_vhost_get_cmd_state, 1513 + .queue_data_in = tcm_vhost_queue_data_in, 1514 + .queue_status = tcm_vhost_queue_status, 1515 + .queue_tm_rsp = tcm_vhost_queue_tm_rsp, 1516 + .get_fabric_sense_len = tcm_vhost_get_fabric_sense_len, 1517 + .set_fabric_sense_len = tcm_vhost_set_fabric_sense_len, 1518 + /* 1519 + * Setup callers for generic logic in target_core_fabric_configfs.c 1520 + */ 1521 + .fabric_make_wwn = tcm_vhost_make_tport, 1522 + .fabric_drop_wwn = tcm_vhost_drop_tport, 1523 + .fabric_make_tpg = tcm_vhost_make_tpg, 1524 + .fabric_drop_tpg = tcm_vhost_drop_tpg, 1525 + .fabric_post_link = tcm_vhost_port_link, 1526 + .fabric_pre_unlink = tcm_vhost_port_unlink, 1527 + .fabric_make_np = NULL, 1528 + .fabric_drop_np = NULL, 1529 + .fabric_make_nodeacl = tcm_vhost_make_nodeacl, 1530 + .fabric_drop_nodeacl = tcm_vhost_drop_nodeacl, 1531 + }; 1532 + 1533 + static int tcm_vhost_register_configfs(void) 1534 + { 1535 + struct target_fabric_configfs *fabric; 1536 + int ret; 1537 + 1538 + pr_debug("TCM_VHOST fabric module %s on %s/%s" 1539 + " on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname, 1540 + utsname()->machine); 1541 + /* 1542 + * Register the top level struct config_item_type with TCM core 1543 + */ 1544 + fabric = target_fabric_configfs_init(THIS_MODULE, "vhost"); 1545 + if (IS_ERR(fabric)) { 1546 + pr_err("target_fabric_configfs_init() failed\n"); 1547 + return PTR_ERR(fabric); 1548 + } 1549 + /* 1550 + * Setup fabric->tf_ops from our local tcm_vhost_ops 1551 + */ 1552 + fabric->tf_ops = tcm_vhost_ops; 1553 + /* 1554 + * Setup default attribute lists for various fabric->tf_cit_tmpl 1555 + */ 1556 + TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_vhost_wwn_attrs; 1557 + TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_vhost_tpg_attrs; 1558 + TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; 1559 + TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; 1560 + TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; 1561 + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; 1562 + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; 1563 + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; 1564 + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; 1565 + /* 1566 + * Register the fabric for use within TCM 1567 + */ 1568 + ret = target_fabric_configfs_register(fabric); 1569 + if (ret < 0) { 1570 + pr_err("target_fabric_configfs_register() failed" 1571 + " for TCM_VHOST\n"); 1572 + return ret; 1573 + } 1574 + /* 1575 + * Setup our local pointer to *fabric 1576 + */ 1577 + tcm_vhost_fabric_configfs = fabric; 1578 + pr_debug("TCM_VHOST[0] - Set fabric -> tcm_vhost_fabric_configfs\n"); 1579 + return 0; 1580 + }; 1581 + 1582 + static void tcm_vhost_deregister_configfs(void) 1583 + { 1584 + if (!tcm_vhost_fabric_configfs) 1585 + return; 1586 + 1587 + target_fabric_configfs_deregister(tcm_vhost_fabric_configfs); 1588 + tcm_vhost_fabric_configfs = NULL; 1589 + pr_debug("TCM_VHOST[0] - Cleared tcm_vhost_fabric_configfs\n"); 1590 + }; 1591 + 1592 + static int __init tcm_vhost_init(void) 1593 + { 1594 + int ret = -ENOMEM; 1595 + 1596 + tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0); 1597 + if (!tcm_vhost_workqueue) 1598 + goto out; 1599 + 1600 + ret = vhost_scsi_register(); 1601 + if (ret < 0) 1602 + goto out_destroy_workqueue; 1603 + 1604 + ret = tcm_vhost_register_configfs(); 1605 + if (ret < 0) 1606 + goto out_vhost_scsi_deregister; 1607 + 1608 + return 0; 1609 + 1610 + out_vhost_scsi_deregister: 1611 + vhost_scsi_deregister(); 1612 + out_destroy_workqueue: 1613 + destroy_workqueue(tcm_vhost_workqueue); 1614 + out: 1615 + return ret; 1616 + }; 1617 + 1618 + static void tcm_vhost_exit(void) 1619 + { 1620 + tcm_vhost_deregister_configfs(); 1621 + vhost_scsi_deregister(); 1622 + destroy_workqueue(tcm_vhost_workqueue); 1623 + }; 1624 + 1625 + MODULE_DESCRIPTION("TCM_VHOST series fabric driver"); 1626 + MODULE_LICENSE("GPL"); 1627 + module_init(tcm_vhost_init); 1628 + module_exit(tcm_vhost_exit);
+101
drivers/vhost/tcm_vhost.h
··· 1 + #define TCM_VHOST_VERSION "v0.1" 2 + #define TCM_VHOST_NAMELEN 256 3 + #define TCM_VHOST_MAX_CDB_SIZE 32 4 + 5 + struct tcm_vhost_cmd { 6 + /* Descriptor from vhost_get_vq_desc() for virt_queue segment */ 7 + int tvc_vq_desc; 8 + /* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */ 9 + u64 tvc_tag; 10 + /* The number of scatterlists associated with this cmd */ 11 + u32 tvc_sgl_count; 12 + /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */ 13 + u32 tvc_lun; 14 + /* Pointer to the SGL formatted memory from virtio-scsi */ 15 + struct scatterlist *tvc_sgl; 16 + /* Pointer to response */ 17 + struct virtio_scsi_cmd_resp __user *tvc_resp; 18 + /* Pointer to vhost_scsi for our device */ 19 + struct vhost_scsi *tvc_vhost; 20 + /* The TCM I/O descriptor that is accessed via container_of() */ 21 + struct se_cmd tvc_se_cmd; 22 + /* work item used for cmwq dispatch to tcm_vhost_submission_work() */ 23 + struct work_struct work; 24 + /* Copy of the incoming SCSI command descriptor block (CDB) */ 25 + unsigned char tvc_cdb[TCM_VHOST_MAX_CDB_SIZE]; 26 + /* Sense buffer that will be mapped into outgoing status */ 27 + unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER]; 28 + /* Completed commands list, serviced from vhost worker thread */ 29 + struct list_head tvc_completion_list; 30 + }; 31 + 32 + struct tcm_vhost_nexus { 33 + /* Pointer to TCM session for I_T Nexus */ 34 + struct se_session *tvn_se_sess; 35 + }; 36 + 37 + struct tcm_vhost_nacl { 38 + /* Binary World Wide unique Port Name for Vhost Initiator port */ 39 + u64 iport_wwpn; 40 + /* ASCII formatted WWPN for Sas Initiator port */ 41 + char iport_name[TCM_VHOST_NAMELEN]; 42 + /* Returned by tcm_vhost_make_nodeacl() */ 43 + struct se_node_acl se_node_acl; 44 + }; 45 + 46 + struct tcm_vhost_tpg { 47 + /* Vhost port target portal group tag for TCM */ 48 + u16 tport_tpgt; 49 + /* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */ 50 + atomic_t tv_tpg_port_count; 51 + /* Used for vhost_scsi device reference to tpg_nexus */ 52 + atomic_t tv_tpg_vhost_count; 53 + /* list for tcm_vhost_list */ 54 + struct list_head tv_tpg_list; 55 + /* Used to protect access for tpg_nexus */ 56 + struct mutex tv_tpg_mutex; 57 + /* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */ 58 + struct tcm_vhost_nexus *tpg_nexus; 59 + /* Pointer back to tcm_vhost_tport */ 60 + struct tcm_vhost_tport *tport; 61 + /* Returned by tcm_vhost_make_tpg() */ 62 + struct se_portal_group se_tpg; 63 + }; 64 + 65 + struct tcm_vhost_tport { 66 + /* SCSI protocol the tport is providing */ 67 + u8 tport_proto_id; 68 + /* Binary World Wide unique Port Name for Vhost Target port */ 69 + u64 tport_wwpn; 70 + /* ASCII formatted WWPN for Vhost Target port */ 71 + char tport_name[TCM_VHOST_NAMELEN]; 72 + /* Returned by tcm_vhost_make_tport() */ 73 + struct se_wwn tport_wwn; 74 + }; 75 + 76 + /* 77 + * As per request from MST, keep TCM_VHOST related ioctl defines out of 78 + * linux/vhost.h (user-space) for now.. 79 + */ 80 + 81 + #include <linux/vhost.h> 82 + 83 + /* 84 + * Used by QEMU userspace to ensure a consistent vhost-scsi ABI. 85 + * 86 + * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + 87 + * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage 88 + */ 89 + 90 + #define VHOST_SCSI_ABI_VERSION 0 91 + 92 + struct vhost_scsi_target { 93 + int abi_version; 94 + unsigned char vhost_wwpn[TRANSPORT_IQN_LEN]; 95 + unsigned short vhost_tpgt; 96 + }; 97 + 98 + /* VHOST_SCSI specific defines */ 99 + #define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) 100 + #define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) 101 + #define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, struct vhost_scsi_target)