All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] libxl: add support for pvscsi, iteration 13
@ 2017-02-17 10:49 Olaf Hering
  2017-02-17 10:49 ` [PATCH 1/2] libxl: add support for vscsi Olaf Hering
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Olaf Hering @ 2017-02-17 10:49 UTC (permalink / raw)
  To: xen-devel

Port vscsi=[] and scsi-{attach,detach,list} commands from xend to libxl.

libvirt uses its existing SCSI support:
http://lists.xenproject.org/archives/html/xen-devel/2015-04/msg02963.html

targetcli/rtslib has to be aware of xen-scsiback (upstream unresponsive):
http://article.gmane.org/gmane.linux.scsi.target.devel/8146

TODO:
 - document pvscsi in xen wiki
 - find a way to carry vscsi devices during live migration to remote host
   could be done with using 'string' for pdev/vdev in idl

Changes between v12 and v13:
 - rebase to 'staging' (936a7a5..a7a578ce6b)
 - rebase to 'staging' (8b27d2b..936a7a5)

Changes between v11 and v12:
 - rebase to 'staging' (3dac42f..8b27d2b)
 - rebase to 'staging' (a35dc6c..3dac42f)
 - Rework API of xlu_vscsi_get_ctrl
 - Sanitize input from frontend in vscsi_fill_ctrl
 - Use macro for libxl_ctrl_index
https://lists.xenproject.org/archives/html/xen-devel/2016-04/msg01772.html

Changes between v10 and v11:
 - rebase to 'staging' (d887c19..a35dc6c)
 - rebase to 'staging' (829e03c..d887c19)
 - Remove evtch and rref from vscsiinfo
 - Remove COMPARE_VSCSI, use COMPARE_DEVID
 - Remove vscsi_wwn_valid helpers, use sscanf instead
http://lists.xenproject.org/archives/html/xen-devel/2016-04/msg01120.html

Changes between v9 and v10:
 - rebase to 'staging' (3b971de..829e03c)
http://lists.xenproject.org/archives/html/xen-devel/2016-03/msg02773.html

Changes between v8 and v9:
 - Mention libxl_ctrl_index in vscsiif.h
 - Rename idx to libxl_ctrl_index
 - Fix device assignment in vscsidev_remove
 - Add vscsictrls to multidev callchain
 - Reorder some functions
 - Move and rename vscsidev_rm
 - Remove libxl prefix from static functions
 - Reorder functions in libxl_vscsi.c
 - Add comment to libxl_vscsidev_aodev_cb
 - Move libxl_device_vscsictrl_remove into libxl_vscsi.c
 - Enclose libxl__device instead of aodev in libxl__vscsidev_rm
 - Update typedef of libxl__vscsidev_rm
 - Assign devid earlier in libxl__device_vscsictrl_add
 - Rework xlu_vscsi_get_ctrl and main_vscsiattach
 - Add config idx also to libxl_vscsiinfo
 - Make libxl__vscsi_collect_ctrls static
 - Implement libxl_device_vscsidev_add
 - Move vscsictrl add from libxl.c to libxl_vscsi.c
 - Export libxl__device_nextid for internal use
 - Remove some checks for empty controllers
 - Introduce an idx file to present the config index in empty vscsictrls
 - Use libxl__ev_devstate_wait in libxl__device_vscsictrl_reconfigure_add
 - Rework error handling in libxl__vscsi_fill_ctrl
 - Remove state checking from libxl__vscsi_fill_dev
 - Wrap long lines in libxl__device_vscsictrl_new_backend
 - Use LIBXL_DESTROY_TIMEOUT in libxl__device_vscsidev_rm
 - Remove tab from libxl__vscsi_collect_ctrls
 - Goto out if libxl__device_vscsidev_backend_set_add fails
 - Add fallthrough to libxl__device_vscsidev_backend_set_add
 - Fix typo in xl.cfg.pod: naa.
 - Wrap long line in xl.cfg.pod.5
 - Use memmove in libxl_device_vscsictrl_remove_vscsidev
 - Adjust code in main_vscsilist to fit in 80 chars
 - Align switch and case to gain 4 columns
 - Wrap long line in libxl__device_vscsi_reconfigure_rm
 - Wrap long line in libxl__device_vscsidev_rm_be
 - Adjust flexarray size in libxl__device_vscsi_reconfigure_rm
 - Rework libxl_device_vscsidev_remove
 - Introduce libxl_device_vscsictrl_remove_vscsidev
 - Use stack variables in xlu_vscsi_get_ctrl
 - Rename function names to refer to vscsictrl
 - Rename local variables to refer to vscsictrl
 - Use generic vscsictrl->devid
http://lists.xenproject.org/archives/html/xen-devel/2016-02/msg03196.html

Changes between v7 and v8:
 - Make be_path const in libxl__device_vscsictrl_add
 - Adjust years in Copyright
 - Whitespace in libxl_device_vscsictrl idl
 - Implement libxl_device_vscsictrl_destroy
 - Set backend_devid
 - Reorder assignments in libxl__device_vscsictrl_add
 - Whitespace changes for libxl__device_vscsi_reconfigure_add
 - Register watch unconditionally in libxl__device_vscsidev_rm
 - Wait for StateClosing for unconnected frontends in detach
 - Adjust logic in libxl__vscsi_fill_dev
 - Rework scsi-detach
 - Increase swap partition from 12 to 96 blocks for mkswap
 - Update MERGE macro for vscsictrls
http://lists.xenproject.org/archives/html/xen-devel/2016-02/msg01662.html

Changes between v6 and v7:
 - rebase to 'staging' (3b971de)
 - Introduce libxl_device_vscsictrl_append_vscsidev
 - Add libxl__vscsi_collect_ctrls and used it in libxl_device_vscsictrl_list
 - Convert type of lun from u32 to u64 per SCSI spec
 - Use vscsi_saved in libxl__device_vscsictrl_add
 - Assign unique vscsidev_id per vscsictrl
 - Rename vscsi_dev to vscsidev in function names
 - Rename variables in libxl_vscsiinfo
 - Rename locals to refer to ctrl/dev
 - Rename various strings from host to ctrl
 - Rename local variables vscsi_ctrl to vscsictrl
 - Rename libxl_device_vscsictrl->vscsi_devs to vscsidevs
 - Remove libxl_device_vscsidev->remove, rework detach
 - Rename libxl_device_vscsidev->vscsi_dev_id to vscsidev_id
 - Rename local variables vscsi_host to vscsi_ctrl
 - Rename local variables v_hst to v_ctrl
 - Remove libxl_device_vscsictrl->v_hst
 - Rename libxl_vscsi_dev to libxl_device_vscsidev
 - Rename libxl_device_vscsi to libxl_device_vscsictrl
http://lists.xenproject.org/archives/html/xen-devel/2016-02/msg00884.html

Changes between v5 and v6:
 - rebase to 'staging' (a7b39c8 and b7e7ad8)
 - Fix off-by-one in xlu__vscsi_compare_udev
 - xl.cfg: use options instead of option
 - xl.cfg: fix grammar for pdev/options
 - xl.cfg: fix Usually typo
 - Remove next_vscsi_dev_id from libxl_device_vscsi
 - Use XLU_WWN_LEN also in libxl_vscsi.c
http://lists.xenproject.org/archives/html/xen-devel/2015-11/msg01446.html

Changes between v4 and v5:
 - vscsiif.h: refer to backend_domid
 - Set update_json in libxl_device_vscsi_remove
 - Remove comment from libxl__device_vscsi_add
 - Remove debug LOG from libxl__device_vscsi_reconfigure
 - Move local nb variable in libxl__device_vscsi_reconfigure
 - Make be_path const in libxl__device_vscsi_reconfigure
 - Adjust libxl__device_vscsi_dev_backend_set to avoid long lines
 - Adjust libxl__device_vscsi_dev_backend_rm to avoid long lines
 - Use CTX in libxl__device_vscsi_dev_backend_rm
 - Make be_path const in libxl__device_vscsi_dev_backend_rm
 - xl.cfg: Its typo
 - xl.cfg: Use persistent instead of persistant
 - Rename feature_host to scsi_raw_cmds
 - target-create-xen-scsiback.sh: detect pvops and xenlinux
 - Wrap long lines in main_vscsilist
 - Call libxl_vscsiinfo_dispose unconditional
 - Let scsi-list print p-dev instead of p-devname
 - Handle broken vscsi device entry in xenstore
 - Split libxl__vscsi_fill_host from libxl_device_vscsi_list
 - Make xlu_vscsi_append_dev static
 - Remove reference to pvscsi.txt from xenstore-paths.markdown
 - xl.cfg: update Linux and xenlinux
 - xl.cfg: refer to backend domain instead of dom0
 - xl.cfg: be more verbose what persistant format is
 - return if libxl__device_vscsi_dev_backend_set fails in libxl__device_vscsi_new_backend
 - target-create-xen-scsiback.sh: set also alias for libvirt
http://lists.xenproject.org/archives/html/xen-devel/2015-05/msg00523.html

Changes between v3 and v4:
 - Use libxl__device_nextid in libxl__device_vscsi_add
 - Remove check for duplicate pdev assignment from libxl_device_vscsi_get_host
 - Caller provides libxl_device_vscsi to libxl_device_vscsi_get_host
 - Define LIBXL_HAVE_VSCSI
 - Remove init_val from libxl_vscsi_pdev_type
 - Move some functions from libxl to libxlu
 - Introduce libxl_device_vscsi->next_vscsi_dev_id to handle holes
 - Use Struct in KeyedUnion for ocaml idl
 - docs: Mention pvscsi in xl and xl.cfg
 - Turn feature_host into a defbool and add checking
 - Support pvops and /dev/ nodes in config
 - Wrap entire libxlu_vscsi.c with ifdef linux
 - Set remove flag in libxl_device_vscsi_list
 - Fix vscsiif path in xenstore-paths.markdown
 - vscsiif.h: add some notes about xenstore layout
 - Add copyright to libxlu_vscsi.c and libxl_vscsi.c
 - Scripts to create and delete xen-scsiback nodes in Linux target framework
 - Remove pvscsi.txt
http://lists.xenproject.org/archives/html/xen-devel/2015-04/msg01949.html

Changes between v2 and v3:
 - Adjust change for vscsiif.h
 - Support "naa.wwn:lun" notation in pvops kernel
 - Add example for pvops kernel using targetcli
   patch required for python-rtslib:
   http://article.gmane.org/gmane.linux.scsi.target.devel/8146
 - Use vdev variable in libxl_device_vscsi_parse
http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg00734.html

Changes between v1 and v2:
 - ported to current staging
http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg00030.html

Initial attempt was sent a year ago:
http://lists.xenproject.org/archives/html/xen-devel/2014-04/msg03958.html
Most comments are addressed.

This version has been tested with SLES as backend and frontend.
This version has been tested with pvops as backend and SLES as frontend.



Olaf Hering (2):
  libxl: add support for vscsi
  Scripts to create and delete xen-scsiback nodes in Linux target
    framework

 docs/man/xl.cfg.pod.5.in                 |   56 ++
 docs/man/xl.pod.1.in                     |   18 +
 tools/libxl/Makefile                     |    2 +
 tools/libxl/libxl.h                      |   42 ++
 tools/libxl/libxl_create.c               |    1 +
 tools/libxl/libxl_internal.h             |    1 +
 tools/libxl/libxl_types.idl              |   53 ++
 tools/libxl/libxl_types_internal.idl     |    1 +
 tools/libxl/libxl_vscsi.c                | 1176 ++++++++++++++++++++++++++++++
 tools/libxl/libxlu_vscsi.c               |  667 +++++++++++++++++
 tools/libxl/libxlutil.h                  |   19 +
 tools/libxl/xl.h                         |    3 +
 tools/libxl/xl_cmdimpl.c                 |  225 +++++-
 tools/libxl/xl_cmdtable.c                |   15 +
 tools/misc/Makefile                      |    4 +
 tools/misc/target-create-xen-scsiback.sh |  135 ++++
 tools/misc/target-delete-xen-scsiback.sh |   41 ++
 17 files changed, 2458 insertions(+), 1 deletion(-)
 create mode 100644 tools/libxl/libxl_vscsi.c
 create mode 100644 tools/libxl/libxlu_vscsi.c
 create mode 100755 tools/misc/target-create-xen-scsiback.sh
 create mode 100755 tools/misc/target-delete-xen-scsiback.sh


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] libxl: add support for vscsi
  2017-02-17 10:49 [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Olaf Hering
@ 2017-02-17 10:49 ` Olaf Hering
  2017-02-17 10:49 ` [PATCH 2/2] Scripts to create and delete xen-scsiback nodes in Linux target framework Olaf Hering
  2017-02-20 17:05 ` [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Wei Liu
  2 siblings, 0 replies; 5+ messages in thread
From: Olaf Hering @ 2017-02-17 10:49 UTC (permalink / raw)
  To: xen-devel

Port pvscsi support from xend to libxl:

 vscsi=['pdev,vdev{,options}']
 xl scsi-attach
 xl scsi-detach
 xl scsi-list

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Cc: Wei Liu <wei.liu2@citrix.com>
---

Just a rebase to RELEASE-4.8.0

 docs/man/xl.cfg.pod.5.in             |   56 ++
 docs/man/xl.pod.1.in                 |   18 +
 tools/libxl/Makefile                 |    2 +
 tools/libxl/libxl.h                  |   42 ++
 tools/libxl/libxl_create.c           |    1 +
 tools/libxl/libxl_internal.h         |    1 +
 tools/libxl/libxl_types.idl          |   53 ++
 tools/libxl/libxl_types_internal.idl |    1 +
 tools/libxl/libxl_vscsi.c            | 1176 ++++++++++++++++++++++++++++++++++
 tools/libxl/libxlu_vscsi.c           |  667 +++++++++++++++++++
 tools/libxl/libxlutil.h              |   19 +
 tools/libxl/xl.h                     |    3 +
 tools/libxl/xl_cmdimpl.c             |  225 ++++++-
 tools/libxl/xl_cmdtable.c            |   15 +
 14 files changed, 2278 insertions(+), 1 deletion(-)

diff --git a/docs/man/xl.cfg.pod.5.in b/docs/man/xl.cfg.pod.5.in
index 21b58bc21e..886303ed5b 100644
--- a/docs/man/xl.cfg.pod.5.in
+++ b/docs/man/xl.cfg.pod.5.in
@@ -517,6 +517,62 @@ value is optional if this is a guest domain.
 
 =back
 
+=item B<vscsi=[ "VSCSI_SPEC_STRING", "VSCSI_SPEC_STRING", ...]>
+
+Specifies the PVSCSI devices to be provided to the guest. PVSCSI passes
+SCSI devices from the backend domain to the guest.
+
+Each VSCSI_SPEC_STRING consists of "pdev,vdev[,options]".
+'pdev' describes the physical device, preferable in a persistent format
+such as /dev/disk/by-*/*.
+'vdev' is the domU device in vHOST:CHANNEL:TARGET:LUN notation, all integers.
+'options' lists additional flags which a backend may recognize.
+
+The supported values for "pdev" and "options" depends on the backend driver used:
+
+=over 4
+
+=item B<Linux>
+
+=over 4
+
+=item C<pdev>
+
+The backend driver in the pvops kernel is part of the Linux-IO Target framework
+(LIO). As such the SCSI devices have to be configured first with the tools
+provided by this framework, such as a xen-scsiback aware targetcli. The "pdev"
+in domU.cfg has to refer to a config item in that framework instead of the raw
+device. Usually this is a WWN in the form of "naa.WWN:LUN".
+
+=item C<options>
+
+No options recognized.
+
+=back
+
+=item B<Linux based on classic Xen kernel>
+
+=over 4
+
+=item C<pdev>
+
+The dom0 device in either /dev/scsidev or pHOST:CHANNEL:TARGET:LUN notation.
+
+It's recommended to use persistent names "/dev/disk/by-*/*" to refer to a "pdev".
+The toolstack will translate this internally to "h:c:t:l" notation, which is how
+the backend driver will access the device. Using the "h:c:t:l" notation for
+"pdev" in domU.cfg is discouraged because this value will change across reboots,
+depending on the detection order in the OS.
+
+=item C<options>
+
+Currently only the option value "feature-host" is recognized. SCSI command
+emulation in backend driver is bypassed when "feature-host" is specified.
+
+=back
+
+=back
+
 =item B<vfb=[ "VFB_SPEC_STRING", "VFB_SPEC_STRING", ...]>
 
 Specifies the paravirtual framebuffer devices which should be supplied
diff --git a/docs/man/xl.pod.1.in b/docs/man/xl.pod.1.in
index 8e2aa5b5af..eea99ccd25 100644
--- a/docs/man/xl.pod.1.in
+++ b/docs/man/xl.pod.1.in
@@ -1436,6 +1436,24 @@ List virtual trusted platform modules for a domain.
 
 =back
 
+=head2 PVSCSI DEVICES
+
+=over 4
+
+=item B<scsi-attach> I<domain-id> I<pdev> I<vdev>,I<[feature-host]>
+
+Creates a new vscsi device in the domain specified by I<domain-id>.
+
+=item B<scsi-detach> I<domain-id> I<vdev>
+
+Removes the vscsi device from domain specified by I<domain-id>.
+
+=item B<scsi-list> I<domain-id> I<[domain-id] ...>
+
+List vscsi devices for the domain specified by I<domain-id>.
+
+=back
+
 =head1 PCI PASS-THROUGH
 
 =over 4
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index ef017859ba..aff35ea18a 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -129,6 +129,7 @@ endif
 LIBXL_LIBS += -lyajl
 
 LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
+			libxl_vscsi.o \
 			libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o \
 			libxl_internal.o libxl_utils.o libxl_uuid.o \
 			libxl_json.o libxl_aoutils.o libxl_numa.o libxl_vnuma.o \
@@ -173,6 +174,7 @@ AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h _libxl_list.h _paths.h \
 AUTOSRCS= libxlu_cfg_y.c libxlu_cfg_l.c
 AUTOSRCS += _libxl_save_msgs_callout.c _libxl_save_msgs_helper.c
 LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o \
+	libxlu_vscsi.o \
 	libxlu_disk_l.o libxlu_disk.o libxlu_vif.o libxlu_pci.o
 $(LIBXLU_OBJS): CFLAGS += $(CFLAGS_libxenctrl) # For xentoollog.h
 
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index acbf47690e..e83af6e9a8 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -915,6 +915,13 @@ void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, const libxl_mac *src);
 #define LIBXL_HAVE_PCITOPOLOGY 1
 
 /*
+ * LIBXL_HAVE_VSCSI
+ *
+ * If this is defined, the PV SCSI feature is supported.
+ */
+#define LIBXL_HAVE_VSCSI 1
+
+/*
  * LIBXL_HAVE_SOCKET_BITMAP
  *
  * If this is defined, then libxl_socket_bitmap_alloc and
@@ -1809,6 +1816,41 @@ int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
                                  libxl_device_channel *channel,
                                  libxl_channelinfo *channelinfo);
 
+/* Virtual SCSI */
+int libxl_device_vscsictrl_add(libxl_ctx *ctx, uint32_t domid,
+                               libxl_device_vscsictrl *vscsi,
+                               const libxl_asyncop_how *ao_how)
+                               LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vscsictrl_remove(libxl_ctx *ctx, uint32_t domid,
+                                  libxl_device_vscsictrl *vscsi,
+                                  const libxl_asyncop_how *ao_how)
+                                  LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vscsictrl_destroy(libxl_ctx *ctx, uint32_t domid,
+                                   libxl_device_vscsictrl *vscsi,
+                                   const libxl_asyncop_how *ao_how)
+                                   LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_vscsictrl *libxl_device_vscsictrl_list(libxl_ctx *ctx, uint32_t domid, int *num);
+int libxl_device_vscsictrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                   libxl_device_vscsictrl *vscsictrl,
+                                   libxl_device_vscsidev *vscsidev,
+                                   libxl_vscsiinfo *vscsiinfo);
+int libxl_device_vscsidev_add(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vscsidev *dev,
+                              const libxl_asyncop_how *ao_how)
+                              LIBXL_EXTERNAL_CALLERS_ONLY;
+/* Remove vscsidev connected to vscsictrl */
+int libxl_device_vscsidev_remove(libxl_ctx *ctx, uint32_t domid,
+                                 libxl_device_vscsidev *dev,
+                                 const libxl_asyncop_how *ao_how)
+                                 LIBXL_EXTERNAL_CALLERS_ONLY;
+void libxl_device_vscsictrl_append_vscsidev(libxl_ctx *ctx,
+                                            libxl_device_vscsictrl *ctrl,
+                                            libxl_device_vscsidev *dev);
+void libxl_device_vscsictrl_remove_vscsidev(libxl_ctx *ctx,
+                                            libxl_device_vscsictrl *ctrl,
+                                            unsigned int idx);
+
 /* Virtual TPMs */
 int libxl_device_vtpm_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vtpm *vtpm,
                           const libxl_asyncop_how *ao_how)
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 7c1695a1fd..c25a149bd4 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1439,6 +1439,7 @@ const struct libxl_device_type *device_type_tbl[] = {
     &libxl__disk_devtype,
     &libxl__nic_devtype,
     &libxl__vtpm_devtype,
+    &libxl__vscsictrl_devtype,
     &libxl__usbctrl_devtype,
     &libxl__usbdev_devtype,
     &libxl__pcidev_devtype,
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 8366fee25f..cfc5f8e77e 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -3504,6 +3504,7 @@ static inline int *libxl__device_type_get_num(
 extern const struct libxl_device_type libxl__disk_devtype;
 extern const struct libxl_device_type libxl__nic_devtype;
 extern const struct libxl_device_type libxl__vtpm_devtype;
+extern const struct libxl_device_type libxl__vscsictrl_devtype;
 extern const struct libxl_device_type libxl__usbctrl_devtype;
 extern const struct libxl_device_type libxl__usbdev_devtype;
 extern const struct libxl_device_type libxl__pcidev_devtype;
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index a32c751b0e..54a1d7f158 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -703,6 +703,43 @@ libxl_device_channel = Struct("device_channel", [
            ])),
 ])
 
+libxl_vscsi_pdev_type = Enumeration("vscsi_pdev_type", [
+    (0, "INVALID"),
+    (1, "HCTL"),
+    (2, "WWN"),
+    ])
+
+libxl_vscsi_hctl = Struct("vscsi_hctl", [
+    ("hst", uint32),
+    ("chn", uint32),
+    ("tgt", uint32),
+    ("lun", uint64),
+    ])
+
+libxl_vscsi_pdev = Struct("vscsi_pdev", [
+    ("p_devname",        string),
+    ("u", KeyedUnion(None, libxl_vscsi_pdev_type, "type",
+        [
+         ("invalid", None),
+         ("hctl", Struct(None, [("m", libxl_vscsi_hctl)])),
+         ("wwn", Struct(None, [("m", string)])),
+        ])),
+    ])
+
+libxl_device_vscsidev = Struct("device_vscsidev", [
+    ("vscsidev_id",      libxl_devid),
+    ("pdev",             libxl_vscsi_pdev),
+    ("vdev",             libxl_vscsi_hctl),
+    ])
+
+libxl_device_vscsictrl = Struct("device_vscsictrl", [
+    ("backend_domid",    libxl_domid),
+    ("devid",            libxl_devid),
+    ("idx",              libxl_devid),
+    ("vscsidevs",        Array(libxl_device_vscsidev, "num_vscsidevs")),
+    ("scsi_raw_cmds",    libxl_defbool),
+    ])
+
 libxl_domain_config = Struct("domain_config", [
     ("c_info", libxl_domain_create_info),
     ("b_info", libxl_domain_build_info),
@@ -714,6 +751,7 @@ libxl_domain_config = Struct("domain_config", [
     ("dtdevs", Array(libxl_device_dtdev, "num_dtdevs")),
     ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
     ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
+    ("vscsictrls", Array(libxl_device_vscsictrl, "num_vscsictrls")),
     ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
     # a channel manifests as a console with a name,
     # see docs/misc/channels.txt
@@ -751,6 +789,21 @@ libxl_nicinfo = Struct("nicinfo", [
     ("rref_rx", integer),
     ], dir=DIR_OUT)
 
+libxl_vscsiinfo = Struct("vscsiinfo", [
+    ("backend", string),
+    ("backend_id", uint32),
+    ("frontend", string),
+    ("frontend_id", uint32),
+    ("devid", libxl_devid),
+    ("pdev", libxl_vscsi_pdev),
+    ("vdev", libxl_vscsi_hctl),
+    ("idx", libxl_devid),
+    ("vscsidev_id", libxl_devid),
+    ("scsi_raw_cmds", bool),
+    ("vscsictrl_state", integer),
+    ("vscsidev_state", integer),
+    ], dir=DIR_OUT)
+
 libxl_vtpminfo = Struct("vtpminfo", [
     ("backend", string),
     ("backend_id", uint32),
diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
index 82e5c0759a..d375bbbb3d 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -25,6 +25,7 @@ libxl__device_kind = Enumeration("device_kind", [
     (8, "VTPM"),
     (9, "VUSB"),
     (10, "QUSB"),
+    (11, "VSCSI"),
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
diff --git a/tools/libxl/libxl_vscsi.c b/tools/libxl/libxl_vscsi.c
new file mode 100644
index 0000000000..8d9049a4bc
--- /dev/null
+++ b/tools/libxl/libxl_vscsi.c
@@ -0,0 +1,1176 @@
+/*
+ * Copyright (C) 2016      SUSE Linux GmbH
+ * Author Olaf Hering <olaf@aepfle.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+#include "libxl_osdeps.h" /* must come before any other headers */
+#include "libxl_internal.h"
+
+typedef struct vscsidev_rm {
+    libxl_device_vscsictrl *ctrl;
+    char *be_path;
+    int dev_wait;
+    libxl__device dev;
+} vscsidev_rm_t;
+
+typedef void (*vscsictrl_add)(libxl__egc *egc,
+                              libxl__ao_device *aodev,
+                              libxl_device_vscsictrl *vscsictrl,
+                              libxl_domain_config *d_config);
+
+#define LIBXL_CTRL_INDEX "libxl_ctrl_index"
+
+#define XLU_WWN_LEN 16
+
+static int vscsi_parse_hctl(char *str, libxl_vscsi_hctl *hctl)
+{
+    unsigned int hst, chn, tgt;
+    unsigned long long lun;
+
+    if (sscanf(str, "%u:%u:%u:%llu", &hst, &chn, &tgt, &lun) != 4)
+        return ERROR_INVAL;
+
+    hctl->hst = hst;
+    hctl->chn = chn;
+    hctl->tgt = tgt;
+    hctl->lun = lun;
+    return 0;
+}
+
+/* Translate p-dev back into pdev.type */
+static bool vscsi_parse_pdev(libxl__gc *gc, libxl_device_vscsidev *dev,
+                             char *c, char *p, char *v)
+{
+    libxl_vscsi_hctl hctl;
+    unsigned long long lun;
+    char wwn[XLU_WWN_LEN + 1];
+    bool parsed_ok = false;
+
+    libxl_vscsi_hctl_init(&hctl);
+
+    dev->pdev.p_devname = libxl__strdup(NOGC, c);
+
+    if (strncmp(p, "naa.", 4) == 0) {
+        /* WWN as understood by pvops */
+        memset(wwn, 0, sizeof(wwn));
+        if (sscanf(p, "naa.%16[0-9a-fA-F]:%llu", wwn, &lun) == 2) {
+            libxl_vscsi_pdev_init_type(&dev->pdev, LIBXL_VSCSI_PDEV_TYPE_WWN);
+            dev->pdev.u.wwn.m = libxl__strdup(NOGC, p);
+            parsed_ok = true;
+        }
+    } else if (vscsi_parse_hctl(p, &hctl) == 0) {
+        /* Either xenlinux, or pvops with properly configured alias in sysfs */
+        libxl_vscsi_pdev_init_type(&dev->pdev, LIBXL_VSCSI_PDEV_TYPE_HCTL);
+        libxl_vscsi_hctl_copy(CTX, &dev->pdev.u.hctl.m, &hctl);
+        parsed_ok = true;
+    }
+
+    if (parsed_ok && vscsi_parse_hctl(v, &dev->vdev) != 0)
+        parsed_ok = false;
+
+    libxl_vscsi_hctl_dispose(&hctl);
+
+    return parsed_ok;
+}
+
+static bool vscsi_fill_dev(libxl__gc *gc,
+                           xs_transaction_t t,
+                           const char *devs_path,
+                           const char *dev_dir,
+                           libxl_device_vscsidev *dev)
+{
+    char *path, *c, *p, *v, *s;
+    unsigned int devid;
+    int r;
+
+    r = sscanf(dev_dir, "dev-%u", &devid);
+    if (r != 1) {
+        LOG(ERROR, "expected dev-N, got '%s'", dev_dir);
+        return false;
+    }
+    dev->vscsidev_id = devid;
+
+    path = GCSPRINTF("%s/%s", devs_path, dev_dir);
+    c = libxl__xs_read(gc, t, GCSPRINTF("%s/p-devname", path));
+    p = libxl__xs_read(gc, t, GCSPRINTF("%s/p-dev", path));
+    v = libxl__xs_read(gc, t, GCSPRINTF("%s/v-dev", path));
+    s = libxl__xs_read(gc, t, GCSPRINTF("%s/state", path));
+    LOG(DEBUG, "%s/state is %s", path, s);
+    if (!(c && p && v && s)) {
+        LOG(ERROR, "p-devname '%s' p-dev '%s' v-dev '%s'", c, p, v);
+        return false;
+    }
+
+    if (!vscsi_parse_pdev(gc, dev, c, p, v)) {
+        LOG(ERROR, "failed to parse %s: %s %s %s %s", path, c, p, v, s);
+        return false;
+    }
+
+    return true;
+}
+
+static bool vscsi_fill_ctrl(libxl__gc *gc,
+                            uint32_t tgt_domid,
+                            xs_transaction_t t,
+                            const char *fe_path,
+                            const char *dir,
+                            libxl_device_vscsictrl *ctrl)
+{
+    libxl_device_vscsidev dev;
+    char *tmp, *devs_path;
+    const char *be_path;
+    char **dev_dirs;
+    unsigned int ndev_dirs, dev_dir;
+    uint32_t be_domid, fe_domid;
+    char be_type[16];
+    int r;
+    bool ok;
+
+    ctrl->devid = atoi(dir);
+
+    tmp = GCSPRINTF("%s/%s/backend", fe_path, dir);
+    r = libxl__xs_read_checked(gc, t, tmp, &be_path);
+    if (r || !be_path)
+        goto out;
+
+    r = sscanf(be_path, "/local/domain/%u/backend/%15[^/]/%u",
+               &be_domid, be_type, &fe_domid);
+    if (r != 3 || fe_domid != tgt_domid)
+        goto out;
+    ctrl->backend_domid = be_domid;
+
+    tmp = libxl__xs_read(gc, t, GCSPRINTF("%s/" LIBXL_CTRL_INDEX, be_path));
+    if (!tmp)
+        goto out;
+    ctrl->idx = atoi(tmp);
+
+    tmp = libxl__xs_read(gc, t, GCSPRINTF("%s/feature-host", be_path));
+    if (!tmp)
+        goto out;
+    ok = atoi(tmp) != 0;
+    libxl_defbool_set(&ctrl->scsi_raw_cmds, ok);
+
+    ok = true;
+    devs_path = GCSPRINTF("%s/vscsi-devs", be_path);
+    dev_dirs = libxl__xs_directory(gc, t, devs_path, &ndev_dirs);
+    for (dev_dir = 0; dev_dirs && dev_dir < ndev_dirs; dev_dir++) {
+        libxl_device_vscsidev_init(&dev);
+        ok = vscsi_fill_dev(gc, t, devs_path, dev_dirs[dev_dir], &dev);
+        if (ok == true)
+            ok = ctrl->idx == dev.vdev.hst;
+        if (ok == true)
+            libxl_device_vscsictrl_append_vscsidev(CTX, ctrl, &dev);
+        libxl_device_vscsidev_dispose(&dev);
+        if (ok == false)
+            break;
+    }
+
+    return ok;
+
+out:
+    libxl_defbool_set(&ctrl->scsi_raw_cmds, false);
+    return false;
+}
+
+/* return an array of vscsictrls with num elements */
+static int vscsi_collect_ctrls(libxl__gc *gc,
+                               uint32_t domid,
+                               libxl_device_vscsictrl **ctrls,
+                               int *num)
+{
+    xs_transaction_t t = XBT_NULL;
+    libxl_device_vscsictrl ctrl;
+    char *fe_path;
+    char **dirs;
+    unsigned int ndirs = 0, dir;
+    int rc;
+
+    fe_path = GCSPRINTF("%s/device/vscsi", libxl__xs_get_dompath(gc, domid));
+
+    for (;;) {
+        *num = 0;
+
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        dirs = libxl__xs_directory(gc, t, fe_path, &ndirs);
+        /* Nothing to do */
+        if (!(dirs && ndirs))
+            break;
+
+        /* List of ctrls to be returned to the caller */
+        *ctrls = libxl__malloc(NOGC, ndirs * sizeof(**ctrls));
+
+        for (dir = 0; dir < ndirs; dir++) {
+            libxl_device_vscsictrl_init(*ctrls + dir);
+
+            libxl_device_vscsictrl_init(&ctrl);
+            if (vscsi_fill_ctrl(gc, domid, t, fe_path, dirs[dir], &ctrl)) {
+                libxl_device_vscsictrl_copy(CTX, *ctrls + *num, &ctrl);
+                (*num)++;
+            }
+            libxl_device_vscsictrl_dispose(&ctrl);
+        }
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+
+        if (rc < 0) {
+            for (dir = 0; dir < ndirs; dir++)
+                libxl_device_vscsictrl_dispose(*ctrls + dir);
+            free(*ctrls);
+            *ctrls = NULL;
+            *num = 0;
+            goto out;
+        }
+    }
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    return rc;
+}
+
+/* Simplified variant of device_addrm_aocomplete */
+static void vscsi_aodev_complete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__ao_complete(egc, ao, aodev->rc);
+}
+
+static int libxl__device_from_vscsictrl(libxl__gc *gc, uint32_t domid,
+                                        libxl_device_vscsictrl *vscsictrl,
+                                        libxl__device *device)
+{
+    device->backend_devid = vscsictrl->devid;
+    device->backend_domid = vscsictrl->backend_domid;
+    device->devid         = vscsictrl->devid;
+    device->domid         = domid;
+    device->backend_kind  = LIBXL__DEVICE_KIND_VSCSI;
+    device->kind          = LIBXL__DEVICE_KIND_VSCSI;
+
+    return 0;
+}
+
+static int vscsictrl_remove(libxl_ctx *ctx,
+                            uint32_t domid,
+                            libxl_device_vscsictrl *vscsictrl,
+                            const libxl_asyncop_how *ao_how,
+                            int force)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__device *device;
+    libxl__ao_device *aodev;
+    int rc;
+
+    GCNEW(device);
+    rc = libxl__device_from_vscsictrl(gc, domid, vscsictrl, device);
+    if (rc != 0) goto out;
+
+    GCNEW(aodev);
+    libxl__prepare_ao_device(ao, aodev);
+    aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
+    aodev->dev = device;
+    aodev->callback = vscsi_aodev_complete;
+    aodev->force = force;
+    libxl__initiate_device_generic_remove(egc, aodev);
+
+out:
+    if (rc) return AO_CREATE_FAIL(rc);
+    return AO_INPROGRESS;
+}
+
+static int vscsidev_be_set_rm(libxl__gc *gc,
+                              libxl_device_vscsidev *v,
+                              flexarray_t *back)
+{
+    int rc;
+    char *dir;
+
+    dir = GCSPRINTF("vscsi-devs/dev-%u", v->vscsidev_id);
+    rc = flexarray_append_pair(back,
+                               GCSPRINTF("%s/state", dir),
+                               GCSPRINTF("%d", XenbusStateClosing));
+    return rc;
+}
+
+static int vscsictrl_reconfigure_rm(libxl__ao_device *aodev,
+                                    const char *state_path,
+                                    int *be_wait)
+
+{
+    STATE_AO_GC(aodev->ao);
+    vscsidev_rm_t *vscsidev_rm = CONTAINER_OF(aodev->dev, *vscsidev_rm, dev);
+    libxl_device_vscsictrl *ctrl = vscsidev_rm->ctrl;
+    const char *be_path = vscsidev_rm->be_path;
+    int rc, i, be_state;
+    char *dev_path, *state_val;
+    flexarray_t *back;
+    libxl_device_vscsidev *v;
+    xs_transaction_t t = XBT_NULL;
+
+    /* Prealloc key+value: 1 toplevel + 1 per device */
+    i = 2 * (1 + 1);
+    back = flexarray_make(gc, i, 1);
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        state_val = libxl__xs_read(gc, t, state_path);
+        LOG(DEBUG, "%s is %s", state_path, state_val);
+        if (!state_val) {
+            rc = ERROR_NOTFOUND;
+            goto out;
+        }
+
+        be_state = atoi(state_val);
+        switch (be_state) {
+        case XenbusStateUnknown:
+        case XenbusStateInitialising:
+        case XenbusStateClosing:
+        case XenbusStateClosed:
+        default:
+            /* The backend is in a bad state */
+            rc = ERROR_FAIL;
+            goto out;
+        case XenbusStateInitialised:
+        case XenbusStateReconfiguring:
+        case XenbusStateReconfigured:
+            /* Backend is still busy, caller has to retry */
+            rc = ERROR_NOT_READY;
+            goto out;
+        case XenbusStateInitWait:
+            /* The frontend did not connect yet */
+            *be_wait = XenbusStateInitWait;
+            vscsidev_rm->dev_wait = XenbusStateClosing;
+            break;
+        case XenbusStateConnected:
+            /* The backend can handle reconfigure */
+            *be_wait = XenbusStateConnected;
+            vscsidev_rm->dev_wait = XenbusStateClosed;
+            flexarray_append_pair(back, "state",
+                                  GCSPRINTF("%d", XenbusStateReconfiguring));
+            break;
+        }
+
+        /* Append new vscsidev or skip existing  */
+        for (i = 0; i < ctrl->num_vscsidevs; i++) {
+            unsigned int nb = 0;
+            v = ctrl->vscsidevs + i;
+            dev_path = GCSPRINTF("%s/vscsi-devs/dev-%u", be_path, v->vscsidev_id);
+            if (!libxl__xs_directory(gc, XBT_NULL, dev_path, &nb)) {
+                /* FIXME Sanity check */
+                LOG(DEBUG, "%s does not exist anymore", dev_path);
+                continue;
+            }
+            rc = vscsidev_be_set_rm(gc, v, back);
+            if (rc) goto out;
+        }
+
+        libxl__xs_writev(gc, t, be_path, libxl__xs_kvs_of_flexarray(gc, back));
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    rc = 0;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    return rc;
+}
+
+static void vscsictrl_remove_be_dev(libxl__gc *gc,
+                                    libxl_device_vscsidev *v,
+                                    xs_transaction_t t,
+                                    const char *be_path,
+                                    int dev_wait)
+{
+    char *dir, *path, *val;
+
+    dir = GCSPRINTF("%s/vscsi-devs/dev-%u", be_path, v->vscsidev_id);
+    path = GCSPRINTF("%s/state", dir);
+    val = libxl__xs_read(gc, t, path);
+    LOG(DEBUG, "%s is %s", path, val);
+    if (val && strcmp(val, GCSPRINTF("%d", dev_wait)) == 0) {
+        xs_rm(CTX->xsh, t, GCSPRINTF("%s/state", dir));
+        xs_rm(CTX->xsh, t, GCSPRINTF("%s/p-devname", dir));
+        xs_rm(CTX->xsh, t, GCSPRINTF("%s/p-dev", dir));
+        xs_rm(CTX->xsh, t, GCSPRINTF("%s/v-dev", dir));
+        xs_rm(CTX->xsh, t, dir);
+    } else {
+        LOG(ERROR, "%s has %s, expected %d", path, val, dev_wait);
+    }
+}
+
+static void vscsictrl_remove_be_cb(libxl__egc *egc,
+                                   libxl__ev_devstate *ds,
+                                   int rc)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(ds, *aodev, backend_ds);
+    STATE_AO_GC(aodev->ao);
+    vscsidev_rm_t *vscsidev_rm = CONTAINER_OF(aodev->dev, *vscsidev_rm, dev);
+    libxl_device_vscsictrl *ctrl = vscsidev_rm->ctrl;
+    xs_transaction_t t = XBT_NULL;
+    int i;
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        for (i = 0; i < ctrl->num_vscsidevs; i++)
+            vscsictrl_remove_be_dev(gc, ctrl->vscsidevs + i, t,
+                                    vscsidev_rm->be_path,
+                                    vscsidev_rm->dev_wait);
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+out:
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+}
+
+static void vscsidev__remove(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    vscsidev_rm_t *vscsidev_rm = CONTAINER_OF(aodev->dev, *vscsidev_rm, dev);
+    char *state_path;
+    int rc, be_wait;
+
+    vscsidev_rm->be_path = libxl__device_backend_path(gc, aodev->dev);
+    state_path = GCSPRINTF("%s/state", vscsidev_rm->be_path);
+
+    rc = vscsictrl_reconfigure_rm(aodev, state_path, &be_wait);
+    if (rc) goto out;
+
+    rc = libxl__ev_devstate_wait(ao, &aodev->backend_ds,
+                                 vscsictrl_remove_be_cb,
+                                 state_path, be_wait,
+                                 LIBXL_DESTROY_TIMEOUT * 1000);
+    if (rc) {
+        LOG(ERROR, "unable to wait for %s", state_path);
+        goto out;
+    }
+
+    return;
+
+out:
+    aodev->rc = rc;
+    /* Notify that this is done */
+    aodev->callback(egc, aodev);
+}
+
+static int vscsidev_remove(libxl_ctx *ctx,
+                           uint32_t domid,
+                           libxl_device_vscsictrl *vscsictrl,
+                           const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *aodev;
+    vscsidev_rm_t *vscsidev_rm;
+    libxl__device *device;
+    int rc;
+
+    GCNEW(aodev);
+
+    GCNEW(vscsidev_rm);
+    vscsidev_rm->ctrl = vscsictrl;
+    device = &vscsidev_rm->dev;
+
+    rc = libxl__device_from_vscsictrl(gc, domid, vscsictrl, device);
+    if (rc) goto out;
+
+    libxl__prepare_ao_device(ao, aodev);
+    aodev->dev = device;
+    aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
+    aodev->callback = vscsi_aodev_complete;
+
+    vscsidev__remove(egc, aodev);
+
+out:
+    if (rc) AO_CREATE_FAIL(rc);
+    return AO_INPROGRESS;
+}
+
+static int vscsidev_backend_add(libxl__gc *gc,
+                                libxl_device_vscsidev *v,
+                                flexarray_t *back)
+{
+    int rc;
+    char *dir;
+    unsigned int hst, chn, tgt;
+    unsigned long long lun;
+
+
+    dir = GCSPRINTF("vscsi-devs/dev-%u", v->vscsidev_id);
+    switch (v->pdev.type) {
+    case LIBXL_VSCSI_PDEV_TYPE_WWN:
+        flexarray_append_pair(back,
+                              GCSPRINTF("%s/p-dev", dir),
+                              v->pdev.u.wwn.m);
+        break;
+    case LIBXL_VSCSI_PDEV_TYPE_HCTL:
+        hst = v->pdev.u.hctl.m.hst;
+        chn = v->pdev.u.hctl.m.chn;
+        tgt = v->pdev.u.hctl.m.tgt;
+        lun = v->pdev.u.hctl.m.lun;
+        flexarray_append_pair(back,
+                              GCSPRINTF("%s/p-dev", dir),
+                              GCSPRINTF("%u:%u:%u:%llu", hst, chn, tgt, lun));
+        break;
+    case LIBXL_VSCSI_PDEV_TYPE_INVALID:
+        /* fallthrough */
+    default:
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    flexarray_append_pair(back,
+                          GCSPRINTF("%s/p-devname", dir),
+                          v->pdev.p_devname);
+    hst = v->vdev.hst;
+    chn = v->vdev.chn;
+    tgt = v->vdev.tgt;
+    lun = v->vdev.lun;
+    flexarray_append_pair(back,
+                          GCSPRINTF("%s/v-dev", dir),
+                          GCSPRINTF("%u:%u:%u:%llu", hst, chn, tgt, lun));
+    flexarray_append_pair(back,
+                          GCSPRINTF("%s/state", dir),
+                          GCSPRINTF("%d", XenbusStateInitialising));
+    rc = 0;
+out:
+    return rc;
+}
+
+static void vscsictrl_new_backend(libxl__egc *egc,
+                                  libxl__ao_device *aodev,
+                                  libxl_device_vscsictrl *vscsictrl,
+                                  libxl_domain_config *d_config)
+{
+    STATE_AO_GC(aodev->ao);
+    int rc, i;
+    flexarray_t *back;
+    flexarray_t *front;
+    libxl_device_vscsidev *v;
+    xs_transaction_t t = XBT_NULL;
+
+    /* Prealloc key+value: 4 toplevel + 4 per device */
+    i = 2 * (4 + (4 * vscsictrl->num_vscsidevs));
+    back = flexarray_make(gc, i, 1);
+    front = flexarray_make(gc, 2 * 2, 1);
+
+    flexarray_append_pair(back,
+                          "frontend-id",
+                          GCSPRINTF("%d", aodev->dev->domid));
+    flexarray_append_pair(back, "online", "1");
+    flexarray_append_pair(back,
+                          "state",
+                          GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append_pair(back,
+                          LIBXL_CTRL_INDEX,
+                          GCSPRINTF("%d", vscsictrl->idx));
+    flexarray_append_pair(back, "feature-host",
+                          libxl_defbool_val(vscsictrl->scsi_raw_cmds) ?
+                          "1" : "0");
+
+    flexarray_append_pair(front,
+                          "backend-id",
+                          GCSPRINTF("%d", vscsictrl->backend_domid));
+    flexarray_append_pair(front,
+                          "state",
+                          GCSPRINTF("%d", XenbusStateInitialising));
+
+    for (i = 0; i < vscsictrl->num_vscsidevs; i++) {
+        v = vscsictrl->vscsidevs + i;
+        rc = vscsidev_backend_add(gc, v, back);
+        if (rc) goto out;
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        rc = libxl__device_exists(gc, t, aodev->dev);
+        if (rc < 0) goto out;
+        if (rc == 1) {              /* already exists in xenstore */
+            LOG(ERROR, "device already exists in xenstore");
+            rc = ERROR_DEVICE_EXISTS;
+            goto out;
+        }
+
+        if (aodev->update_json) {
+            rc = libxl__set_domain_configuration(gc, aodev->dev->domid, d_config);
+            if (rc) goto out;
+        }
+
+        libxl__device_generic_add(gc, t, aodev->dev,
+                                  libxl__xs_kvs_of_flexarray(gc, back),
+                                  libxl__xs_kvs_of_flexarray(gc, front),
+                                  NULL);
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    libxl__wait_device_connection(egc, aodev);
+    return;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+}
+
+static void vscsictrl_do_reconfigure_add_cb(libxl__egc *egc,
+                                            libxl__ev_devstate *ds,
+                                            int rc)
+{
+    libxl__ao_device *aodev = CONTAINER_OF(ds, *aodev, backend_ds);
+    STATE_AO_GC(aodev->ao);
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+}
+
+static void vscsictrl_do_reconfigure_add(libxl__egc *egc,
+                                         libxl__ao_device *aodev,
+                                         libxl_device_vscsictrl *vscsictrl,
+                                         libxl_domain_config *d_config)
+{
+    STATE_AO_GC(aodev->ao);
+    int rc, i, be_state, be_wait;
+    const char *be_path;
+    char *dev_path, *state_path, *state_val;
+    flexarray_t *back;
+    libxl_device_vscsidev *v;
+    xs_transaction_t t = XBT_NULL;
+    bool do_reconfigure = false;
+
+    /* Prealloc key+value: 1 toplevel + 4 per device */
+    i = 2 * (1 + (4 * vscsictrl->num_vscsidevs));
+    back = flexarray_make(gc, i, 1);
+
+    be_path = libxl__device_backend_path(gc, aodev->dev);
+    state_path = GCSPRINTF("%s/state", be_path);
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        state_val = libxl__xs_read(gc, t, state_path);
+        LOG(DEBUG, "%s is %s", state_path, state_val);
+        if (!state_val) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        be_state = atoi(state_val);
+        switch (be_state) {
+        case XenbusStateUnknown:
+        case XenbusStateInitialising:
+        case XenbusStateClosing:
+        case XenbusStateClosed:
+        default:
+            /* The backend is in a bad state */
+            rc = ERROR_FAIL;
+            goto out;
+        case XenbusStateInitialised:
+        case XenbusStateReconfiguring:
+        case XenbusStateReconfigured:
+            /* Backend is still busy, caller has to retry */
+            rc = ERROR_NOT_READY;
+            goto out;
+        case XenbusStateInitWait:
+            /* The frontend did not connect yet */
+            be_wait = XenbusStateInitWait;
+            do_reconfigure = false;
+            break;
+        case XenbusStateConnected:
+            /* The backend can handle reconfigure */
+            be_wait = XenbusStateConnected;
+            flexarray_append_pair(back, "state", GCSPRINTF("%d", XenbusStateReconfiguring));
+            do_reconfigure = true;
+            break;
+        }
+
+        /* Append new vscsidev or skip existing  */
+        for (i = 0; i < vscsictrl->num_vscsidevs; i++) {
+            unsigned int nb = 0;
+            v = vscsictrl->vscsidevs + i;
+            dev_path = GCSPRINTF("%s/vscsi-devs/dev-%u", be_path, v->vscsidev_id);
+            if (libxl__xs_directory(gc, XBT_NULL, dev_path, &nb)) {
+                /* FIXME Sanity check */
+                LOG(DEBUG, "%s exists already with %u entries", dev_path, nb);
+                continue;
+            }
+            rc = vscsidev_backend_add(gc, v, back);
+            if (rc) goto out;
+        }
+
+        if (aodev->update_json) {
+            rc = libxl__set_domain_configuration(gc, aodev->dev->domid, d_config);
+            if (rc) goto out;
+        }
+
+        libxl__xs_writev(gc, t, be_path, libxl__xs_kvs_of_flexarray(gc, back));
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    if (do_reconfigure) {
+        rc = libxl__ev_devstate_wait(ao, &aodev->backend_ds,
+                                     vscsictrl_do_reconfigure_add_cb,
+                                     state_path, be_wait,
+                                     LIBXL_INIT_TIMEOUT * 1000);
+        if (rc) goto out;
+    }
+    return;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+}
+
+static int vscsictrl_next_vscsidev_id(libxl__gc *gc,
+                                      const char *libxl_path,
+                                      libxl_devid *vscsidev_id)
+{
+    const char *val;
+    xs_transaction_t t = XBT_NULL;
+    unsigned int id;
+    int rc;
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        val = libxl__xs_read(gc, t, libxl_path);
+        id = val ? strtoul(val, NULL, 10) : 0;
+
+        LOG(DEBUG, "%s = %s vscsidev_id %u", libxl_path, val, id);
+
+        val = GCSPRINTF("%u", id + 1);
+        rc = libxl__xs_write_checked(gc, t, libxl_path, val);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    *vscsidev_id = id;
+    rc = 0;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    return rc;
+}
+
+static int vscsictrl_assign_vscsidev_ids(libxl__gc *gc,
+                                         uint32_t domid,
+                                         libxl_device_vscsictrl *vscsictrl)
+{
+    libxl_device_vscsidev *dev;
+    libxl_devid vscsidev_id;
+    const char *libxl_path;
+    int rc, i;
+
+    libxl_path = GCSPRINTF("%s/vscsi/%u/next_vscsidev_id",
+                           libxl__xs_libxl_path(gc, domid),
+                           vscsictrl->devid);
+    for (i = 0; i < vscsictrl->num_vscsidevs; i++) {
+        dev = &vscsictrl->vscsidevs[i];
+        if (dev->vscsidev_id >= 0)
+            continue;
+        rc = vscsictrl_next_vscsidev_id(gc, libxl_path, &vscsidev_id);
+        if (rc) {
+            LOG(ERROR, "failed to assign vscsidev_id to %s for %s",
+                libxl_path, dev->pdev.p_devname);
+            goto out;
+        }
+        dev->vscsidev_id = vscsidev_id;
+    }
+
+    rc = 0;
+out:
+    return rc;
+}
+
+static void vscsictrl_update_json(libxl__egc *egc,
+                                  libxl__ao_device *aodev,
+                                  libxl_device_vscsictrl *vscsictrl,
+                                  vscsictrl_add fn)
+{
+    STATE_AO_GC(aodev->ao);
+    int rc;
+    uint32_t domid = aodev->dev->domid;
+    libxl_device_vscsictrl vscsictrl_saved;
+    libxl_domain_config d_config;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_vscsictrl_init(&vscsictrl_saved);
+
+    libxl_device_vscsictrl_copy(CTX, &vscsictrl_saved, vscsictrl);
+
+    rc = vscsictrl_assign_vscsidev_ids(gc, domid, &vscsictrl_saved);
+    if (rc) goto out;
+
+    if (aodev->update_json) {
+        lock = libxl__lock_domain_userdata(gc, domid);
+        if (!lock) {
+            rc = ERROR_LOCK_FAIL;
+            goto out;
+        }
+
+        rc = libxl__get_domain_configuration(gc, domid, &d_config);
+        if (rc) goto out;
+
+        /* Replace or append the copy to the domain config */
+        DEVICE_ADD(vscsictrl, vscsictrls, domid, &vscsictrl_saved, COMPARE_DEVID, &d_config);
+    }
+
+    fn(egc, aodev, &vscsictrl_saved, &d_config);
+
+out:
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_device_vscsictrl_dispose(&vscsictrl_saved);
+    libxl_domain_config_dispose(&d_config);
+    if (rc) {
+        aodev->rc = rc;
+        aodev->callback(egc, aodev);
+    }
+}
+
+static void vscsictrl__reconfigure_add(libxl__egc *egc,
+                                       uint32_t domid,
+                                       libxl_device_vscsictrl *vscsictrl,
+                                       libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__device *device;
+    vscsictrl_add fn;
+    int rc;
+
+    GCNEW(device);
+    rc = libxl__device_from_vscsictrl(gc, domid, vscsictrl, device);
+    if (rc) goto out;
+    aodev->dev = device;
+
+    fn = vscsictrl_do_reconfigure_add;
+    vscsictrl_update_json(egc, aodev, vscsictrl, fn);
+    return;
+
+out:
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+}
+
+static int vscsictrl_reconfigure_add(libxl_ctx *ctx,
+                                     uint32_t domid,
+                                     libxl_device_vscsictrl *vscsictrl,
+                                     const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *aodev;
+
+    GCNEW(aodev);
+    libxl__prepare_ao_device(ao, aodev);
+    aodev->action = LIBXL__DEVICE_ACTION_ADD;
+    aodev->callback = vscsi_aodev_complete;
+    aodev->update_json = true;
+    vscsictrl__reconfigure_add(egc, domid, vscsictrl, aodev);
+
+    return AO_INPROGRESS;
+}
+
+static void libxl__device_vscsictrl_add(libxl__egc *egc, uint32_t domid,
+                                 libxl_device_vscsictrl *vscsictrl,
+                                 libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__device *device;
+    vscsictrl_add fn;
+    int rc;
+
+    if (vscsictrl->devid == -1) {
+        if ((vscsictrl->devid = libxl__device_nextid(gc, domid, "vscsi")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    GCNEW(device);
+    rc = libxl__device_from_vscsictrl(gc, domid, vscsictrl, device);
+    if (rc) goto out;
+    aodev->dev = device;
+
+    fn = vscsictrl_new_backend;
+    vscsictrl_update_json(egc, aodev, vscsictrl, fn);
+    return;
+
+out:
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+}
+
+int libxl_device_vscsictrl_remove(libxl_ctx *ctx, uint32_t domid,
+                                  libxl_device_vscsictrl *vscsictrl,
+                                  const libxl_asyncop_how *ao_how)
+{
+    return vscsictrl_remove(ctx, domid, vscsictrl, ao_how, 0);
+}
+
+int libxl_device_vscsictrl_destroy(libxl_ctx *ctx, uint32_t domid,
+                                   libxl_device_vscsictrl *vscsictrl,
+                                   const libxl_asyncop_how *ao_how)
+{
+    return vscsictrl_remove(ctx, domid, vscsictrl, ao_how, 1);
+}
+
+libxl_device_vscsictrl *libxl_device_vscsictrl_list(libxl_ctx *ctx,
+                                                    uint32_t domid,
+                                                    int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_vscsictrl *ctrls = NULL;
+    int rc, num_ctrls = 0;
+
+    *num = 0;
+
+    rc = vscsi_collect_ctrls(gc, domid, &ctrls, &num_ctrls);
+    if (rc == 0)
+        *num = num_ctrls;
+
+    GC_FREE;
+    return ctrls;
+}
+
+int libxl_device_vscsictrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                   libxl_device_vscsictrl *vscsictrl,
+                                   libxl_device_vscsidev *vscsidev,
+                                   libxl_vscsiinfo *vscsiinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *vscsipath;
+    char *val;
+    int rc = ERROR_FAIL;
+
+    libxl_vscsiinfo_init(vscsiinfo);
+    dompath = libxl__xs_get_dompath(gc, domid);
+    vscsiinfo->devid = vscsictrl->devid;
+    vscsiinfo->vscsidev_id = vscsidev->vscsidev_id;
+    libxl_vscsi_pdev_copy(ctx, &vscsiinfo->pdev, &vscsidev->pdev);
+    libxl_vscsi_hctl_copy(ctx, &vscsiinfo->vdev, &vscsidev->vdev);
+
+    vscsipath = GCSPRINTF("%s/device/vscsi/%d", dompath, vscsiinfo->devid);
+    vscsiinfo->backend = xs_read(ctx->xsh, XBT_NULL,
+                                 GCSPRINTF("%s/backend", vscsipath), NULL);
+    if (!vscsiinfo->backend)
+        goto out;
+    if(!libxl__xs_read(gc, XBT_NULL, vscsiinfo->backend))
+        goto out;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/backend-id", vscsipath));
+    vscsiinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", vscsipath));
+    vscsiinfo->vscsictrl_state = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/" LIBXL_CTRL_INDEX, vscsipath));
+    vscsiinfo->idx = val ? strtoul(val, NULL, 10) : -1;
+
+    vscsiinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
+                                  GCSPRINTF("%s/frontend", vscsiinfo->backend), NULL);
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/frontend-id", vscsiinfo->backend));
+    vscsiinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/vscsi-devs/dev-%u/state",
+                         vscsiinfo->backend, vscsidev->vscsidev_id));
+    vscsiinfo->vscsidev_state = val ? strtoul(val, NULL, 10) : -1;
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_device_vscsidev_add(libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_vscsidev *vscsidev,
+                              const libxl_asyncop_how *ao_how)
+{
+    GC_INIT(ctx);
+    libxl_device_vscsictrl *vc, *ctrls = NULL;
+    libxl_device_vscsidev *vd;
+    int c, d, rc, num_ctrls = 0;
+    int duplicate = 0;
+
+    rc = vscsi_collect_ctrls(gc, domid, &ctrls, &num_ctrls);
+    if (rc != 0) goto out;
+
+
+    for (c = 0; c < num_ctrls; ++c) {
+        vc = ctrls + c;
+        if (vc->idx != vscsidev->vdev.hst)
+            continue;
+
+        for (d = 0; d < vc->num_vscsidevs; d++) {
+            vd = vc->vscsidevs + d;
+            if (vd->vdev.hst == vscsidev->vdev.hst &&
+                vd->vdev.chn == vscsidev->vdev.chn &&
+                vd->vdev.tgt == vscsidev->vdev.tgt &&
+                vd->vdev.lun == vscsidev->vdev.lun) {
+                unsigned long long lun = vd->vdev.lun;
+                LOG(ERROR, "vdev '%u:%u:%u:%llu' is already used.\n",
+                    vd->vdev.hst, vd->vdev.chn, vd->vdev.tgt, lun);
+                rc = ERROR_DEVICE_EXISTS;
+                duplicate = 1;
+                break;
+            }
+        }
+
+        if (!duplicate) {
+            /* Append vscsidev to this vscsictrl, trigger reconfigure */
+            libxl_device_vscsictrl_append_vscsidev(ctx, vc, vscsidev);
+            rc = vscsictrl_reconfigure_add(ctx, domid, vc, ao_how);
+        }
+        break;
+    }
+
+    for (c = 0; c < num_ctrls; ++c)
+        libxl_device_vscsictrl_dispose(ctrls + c);
+    free(ctrls);
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_device_vscsidev_remove(libxl_ctx *ctx, uint32_t domid,
+                                 libxl_device_vscsidev *vscsidev,
+                                 const libxl_asyncop_how *ao_how)
+{
+    GC_INIT(ctx);
+    libxl_device_vscsictrl *vc, *ctrls = NULL;
+    libxl_device_vscsidev *vd;
+    int c, d, rc, num_ctrls = 0;
+    int found = 0, idx;
+    int head, tail, i;
+
+    rc = vscsi_collect_ctrls(gc, domid, &ctrls, &num_ctrls);
+    if (rc != 0) goto out;
+
+
+    for (c = 0; c < num_ctrls; ++c) {
+        vc = ctrls + c;
+
+        for (d = 0; d < vc->num_vscsidevs; d++) {
+            vd = vc->vscsidevs + d;
+            if (vd->vdev.hst == vscsidev->vdev.hst &&
+                vd->vdev.chn == vscsidev->vdev.chn &&
+                vd->vdev.tgt == vscsidev->vdev.tgt &&
+                vd->vdev.lun == vscsidev->vdev.lun) {
+                found = 1;
+                idx = d;
+                break;
+            }
+        }
+
+        if (found) {
+            if (vc->num_vscsidevs > 1) {
+                /* Prepare vscsictrl, leave only desired vscsidev */
+                head = idx;
+                tail = vc->num_vscsidevs - idx - 1;
+                for (i = 0; i < head; i++)
+                    libxl_device_vscsictrl_remove_vscsidev(ctx, vc, 0);
+                for (i = 0; i < tail; i++)
+                    libxl_device_vscsictrl_remove_vscsidev(ctx, vc, 1);
+
+                /* Remove single vscsidev connected to this vscsictrl */
+                rc = vscsidev_remove(ctx, domid, vc, ao_how);
+            } else {
+                /* Wipe entire vscsictrl */;
+                rc = vscsictrl_remove(ctx, domid, vc, ao_how, 0);
+            }
+            break;
+        }
+    }
+
+    for (c = 0; c < num_ctrls; ++c)
+        libxl_device_vscsictrl_dispose(ctrls + c);
+    free(ctrls);
+
+    if (!found)
+        rc = ERROR_NOTFOUND;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+void libxl_device_vscsictrl_append_vscsidev(libxl_ctx *ctx,
+                                            libxl_device_vscsictrl *ctrl,
+                                            libxl_device_vscsidev *dev)
+{
+    GC_INIT(ctx);
+    ctrl->vscsidevs = libxl__realloc(NOGC, ctrl->vscsidevs, sizeof(*dev) * (ctrl->num_vscsidevs + 1));
+    libxl_device_vscsidev_init(ctrl->vscsidevs + ctrl->num_vscsidevs);
+    libxl_device_vscsidev_copy(CTX, ctrl->vscsidevs + ctrl->num_vscsidevs, dev);
+    ctrl->num_vscsidevs++;
+    GC_FREE;
+}
+
+void libxl_device_vscsictrl_remove_vscsidev(libxl_ctx *ctx,
+                                            libxl_device_vscsictrl *ctrl,
+                                            unsigned int idx)
+{
+    GC_INIT(ctx);
+    if (idx >= ctrl->num_vscsidevs)
+        return;
+    libxl_device_vscsidev_dispose(&ctrl->vscsidevs[idx]);
+    if (ctrl->num_vscsidevs > idx + 1)
+        memmove(&ctrl->vscsidevs[idx],
+                &ctrl->vscsidevs[idx + 1],
+                (ctrl->num_vscsidevs - idx - 1) * sizeof(*ctrl->vscsidevs));
+    ctrl->vscsidevs = libxl__realloc(NOGC, ctrl->vscsidevs, sizeof(*ctrl->vscsidevs) * (ctrl->num_vscsidevs - 1));
+    ctrl->num_vscsidevs--;
+    GC_FREE;
+}
+
+static int libxl_device_vscsictrl_compare(libxl_device_vscsictrl *d1,
+                                          libxl_device_vscsictrl *d2)
+{
+    return COMPARE_DEVID(d1, d2);
+}
+
+LIBXL_DEFINE_DEVICE_ADD(vscsictrl)
+static LIBXL_DEFINE_DEVICES_ADD(vscsictrl)
+//LIBXL_DEFINE_DEVICE_REMOVE(vscsictrl)
+DEFINE_DEVICE_TYPE_STRUCT(vscsictrl);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxl/libxlu_vscsi.c b/tools/libxl/libxlu_vscsi.c
new file mode 100644
index 0000000000..f0fafc767c
--- /dev/null
+++ b/tools/libxl/libxlu_vscsi.c
@@ -0,0 +1,667 @@
+/*
+ * libxlu_vscsi.c - xl configuration file parsing: setup and helper functions
+ *
+ * Copyright (C) 2016      SUSE Linux GmbH
+ * Author Olaf Hering <olaf@aepfle.de>
+ * Author Ondřej Holeček <aaannz@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+#include "libxl_osdeps.h" /* must come before any other headers */
+#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libxlu_internal.h"
+
+#ifdef __linux__
+#define LOG(_c, _x, _a...) \
+        if((_c) && (_c)->report) fprintf((_c)->report, "%s(%u): " _x "\n", __func__, __LINE__, ##_a)
+
+#define XLU_SYSFS_TARGET_PVSCSI "/sys/kernel/config/target/xen-pvscsi"
+#define XLU_WWN_LEN 16
+struct xlu__vscsi_target {
+    XLU_Config *cfg;
+    libxl_vscsi_hctl *pdev_hctl;
+    libxl_vscsi_pdev *pdev;
+    char path[PATH_MAX];
+    char udev_path[PATH_MAX];
+    char wwn[XLU_WWN_LEN + 1];
+    unsigned long long lun;
+};
+
+static int xlu__vscsi_parse_hctl(char *str, libxl_vscsi_hctl *hctl)
+{
+    unsigned int hst, chn, tgt;
+    unsigned long long lun;
+
+    if (sscanf(str, "%u:%u:%u:%llu", &hst, &chn, &tgt, &lun) != 4)
+        return ERROR_INVAL;
+
+    hctl->hst = hst;
+    hctl->chn = chn;
+    hctl->tgt = tgt;
+    hctl->lun = lun;
+    return 0;
+}
+
+static char *xlu__vscsi_trim_string(char *s)
+{
+    size_t len;
+
+    while (isspace(*s))
+        s++;
+    len = strlen(s);
+    while (len-- > 1 && isspace(s[len]))
+        s[len] = '\0';
+    return s;
+}
+
+
+static int xlu__vscsi_parse_dev(XLU_Config *cfg, char *pdev, libxl_vscsi_hctl *hctl)
+{
+    struct stat dentry;
+    char *sysfs = NULL;
+    const char *type;
+    int rc, found = 0;
+    DIR *dirp;
+    struct dirent *de;
+
+    /* stat pdev to get device's sysfs entry */
+    if (stat (pdev, &dentry) < 0) {
+        LOG(cfg, "%s, device node not found", pdev);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    if (S_ISBLK (dentry.st_mode)) {
+        type = "block";
+    } else if (S_ISCHR (dentry.st_mode)) {
+        type = "char";
+    } else {
+        LOG(cfg, "%s, device node not a block or char device", pdev);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    /* /sys/dev/type/major:minor symlink added in 2.6.27 */
+    if (asprintf(&sysfs, "/sys/dev/%s/%u:%u/device/scsi_device", type,
+                 major(dentry.st_rdev), minor(dentry.st_rdev)) < 0) {
+        sysfs = NULL;
+        rc = ERROR_NOMEM;
+        goto out;
+    }
+
+    dirp = opendir(sysfs);
+    if (!dirp) {
+        LOG(cfg, "%s, no major:minor link in sysfs", pdev);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    while ((de = readdir(dirp))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        if (xlu__vscsi_parse_hctl(de->d_name, hctl))
+            continue;
+
+        found = 1;
+        break;
+    }
+    closedir(dirp);
+
+    if (!found) {
+        LOG(cfg, "%s, no h:c:t:l link in sysfs", pdev);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    rc = 0;
+out:
+    free(sysfs);
+    return rc;
+}
+
+static bool xlu__vscsi_compare_hctl(libxl_vscsi_hctl *a, libxl_vscsi_hctl *b)
+{
+    if (a->hst == b->hst &&
+        a->chn == b->chn &&
+        a->tgt == b->tgt &&
+        a->lun == b->lun)
+        return true;
+    return false;
+}
+
+/* Finally at
+ * /sys/kernel/config/target/xen-pvscsi/naa.<wwn>/tpgt_1/lun/lun_0/<X>/udev_path
+ */
+static bool xlu__vscsi_compare_udev(struct xlu__vscsi_target *tgt)
+{
+    bool ret;
+    int fd;
+    ssize_t read_sz;
+    libxl_vscsi_hctl udev_hctl;
+
+    libxl_vscsi_hctl_init(&udev_hctl);
+
+    fd = open(tgt->path, O_RDONLY);
+    if (fd < 0){
+        ret = false;
+        goto out;
+    }
+    read_sz = read(fd, &tgt->udev_path, sizeof(tgt->udev_path) - 1);
+    close(fd);
+
+    if (read_sz <= 0 || read_sz > sizeof(tgt->udev_path) - 1) {
+        ret = false;
+        goto out;
+    }
+    tgt->udev_path[read_sz] = '\0';
+    read_sz--;
+    if (tgt->udev_path[read_sz] == '\n')
+        tgt->udev_path[read_sz] = '\0';
+
+    if (xlu__vscsi_parse_dev(tgt->cfg, tgt->udev_path, &udev_hctl)) {
+        ret = false;
+        goto out;
+    }
+    ret = xlu__vscsi_compare_hctl(tgt->pdev_hctl, &udev_hctl);
+
+out:
+    libxl_vscsi_hctl_dispose(&udev_hctl);
+    return ret;
+}
+
+/* /sys/kernel/config/target/xen-pvscsi/naa.<wwn>/tpgt_1/lun/lun_0/<X>/udev_path */
+static bool xlu__vscsi_walk_dir_lun(struct xlu__vscsi_target *tgt)
+{
+    bool found;
+    DIR *dirp;
+    struct dirent *de;
+    size_t path_len = strlen(tgt->path);
+    char *subdir = &tgt->path[path_len];
+
+    dirp = opendir(tgt->path);
+    if (!dirp)
+        return false;
+
+    found = false;
+    while ((de = readdir(dirp))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        snprintf(subdir, sizeof(tgt->path) - path_len, "/%s/udev_path", de->d_name);
+
+        found = xlu__vscsi_compare_udev(tgt);
+        if (found)
+            break;
+
+        *subdir = '\0';
+    }
+    closedir(dirp);
+    return found;
+}
+
+/* /sys/kernel/config/target/xen-pvscsi/naa.<wwn>/tpgt_1/lun/lun_0 */
+static bool xlu__vscsi_walk_dir_luns(struct xlu__vscsi_target *tgt)
+{
+    bool found;
+    DIR *dirp;
+    struct dirent *de;
+    size_t path_len = strlen(tgt->path);
+    char *subdir = &tgt->path[path_len];
+
+    dirp = opendir(tgt->path);
+    if (!dirp)
+        return false;
+
+    found = false;
+    while ((de = readdir(dirp))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        if (sscanf(de->d_name, "lun_%llu", &tgt->lun) != 1)
+            continue;
+
+
+        snprintf(subdir, sizeof(tgt->path) - path_len, "/%s", de->d_name);
+
+        found = xlu__vscsi_walk_dir_lun(tgt);
+        if (found)
+            break;
+
+        *subdir = '\0';
+    }
+    closedir(dirp);
+    return found;
+}
+
+/* /sys/kernel/config/target/xen-pvscsi/naa.<wwn>/tpgt_1 */
+static bool xlu__vscsi_walk_dir_naa(struct xlu__vscsi_target *tgt)
+{
+    bool found;
+    DIR *dirp;
+    struct dirent *de;
+    size_t path_len = strlen(tgt->path);
+    char *subdir = &tgt->path[path_len];
+    unsigned int tpgt;
+
+    dirp = opendir(tgt->path);
+    if (!dirp)
+        return false;
+
+    found = false;
+    while ((de = readdir(dirp))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        if (sscanf(de->d_name, "tpgt_%u", &tpgt) != 1)
+            continue;
+
+        snprintf(subdir, sizeof(tgt->path) - path_len, "/%s/lun", de->d_name);
+
+        found = xlu__vscsi_walk_dir_luns(tgt);
+        if (found)
+            break;
+
+        *subdir = '\0';
+    }
+    closedir(dirp);
+    return found;
+}
+
+/* /sys/kernel/config/target/xen-pvscsi/naa.<wwn> */
+static bool xlu__vscsi_find_target_wwn(struct xlu__vscsi_target *tgt)
+{
+    bool found;
+    DIR *dirp;
+    struct dirent *de;
+    size_t path_len = strlen(tgt->path);
+    char *subdir = &tgt->path[path_len];
+
+    dirp = opendir(tgt->path);
+    if (!dirp)
+        return false;
+
+    found = false;
+    while ((de = readdir(dirp))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        if (sscanf(de->d_name, "naa.%16[0-9a-fA-F]", tgt->wwn) != 1)
+            continue;
+
+        snprintf(subdir, sizeof(tgt->path) - path_len, "/%s", de->d_name);
+
+        found = xlu__vscsi_walk_dir_naa(tgt);
+        if (found)
+            break;
+
+        *subdir = '\0';
+    }
+    closedir(dirp);
+    return found;
+}
+
+/*
+ * Convert pdev from config string into pdev property for backend,
+ * which is either h:c:t:l for xenlinux or naa.wwn:lun for pvops
+ */
+static int xlu__vscsi_dev_to_pdev(XLU_Config *cfg, libxl_ctx *ctx, char *str,
+                                  libxl_vscsi_hctl *pdev_hctl,
+                                  libxl_vscsi_pdev *pdev)
+{
+    int rc = ERROR_INVAL;
+    struct xlu__vscsi_target *tgt;
+    static const char xen_pvscsi[] = XLU_SYSFS_TARGET_PVSCSI;
+
+    /* First get hctl representation of config item */
+    if (xlu__vscsi_parse_dev(cfg, str, pdev_hctl))
+        goto out;
+
+    /* Check if a SCSI target item exists for the config item */
+    if (access(xen_pvscsi, F_OK) == 0) {
+        tgt = calloc(1, sizeof(*tgt));
+        if (!tgt) {
+            rc = ERROR_NOMEM;
+            goto out;
+        }
+        tgt->cfg = cfg;
+        tgt->pdev_hctl = pdev_hctl;
+        tgt->pdev = pdev;
+        snprintf(tgt->path, sizeof(tgt->path), "%s", xen_pvscsi);
+        if (xlu__vscsi_find_target_wwn(tgt) == true) {
+            LOG(cfg, "'%s' maps to '%s(%s)'", str, tgt->path, tgt->udev_path);
+            libxl_vscsi_pdev_init_type(pdev, LIBXL_VSCSI_PDEV_TYPE_WWN);
+            if (asprintf(&pdev->u.wwn.m, "naa.%s:%llu", tgt->wwn, tgt->lun) < 0) {
+                rc = ERROR_NOMEM;
+                goto out;
+            }
+        }
+        free(tgt);
+    } else {
+        /* Assume xenlinux backend */
+        libxl_vscsi_pdev_init_type(pdev, LIBXL_VSCSI_PDEV_TYPE_HCTL);
+        libxl_vscsi_hctl_copy(ctx, &pdev->u.hctl.m, pdev_hctl);
+    }
+    rc = 0;
+
+out:
+    return rc;
+}
+
+/* WWN as understood by pvops */
+static int xlu__vscsi_wwn_to_pdev(XLU_Config *cfg, char *str, libxl_vscsi_pdev *pdev)
+{
+    int rc = ERROR_INVAL;
+    unsigned long long lun;
+    char wwn[XLU_WWN_LEN + 1];
+
+    memset(wwn, 0, sizeof(wwn));
+    if (sscanf(str, "naa.%16[0-9a-fA-F]:%llu", wwn, &lun) == 2) {
+        libxl_vscsi_pdev_init_type(pdev, LIBXL_VSCSI_PDEV_TYPE_WWN);
+        pdev->u.wwn.m = strdup(str);
+        rc = pdev->u.wwn.m ? 0 : ERROR_NOMEM;
+    }
+    return rc;
+}
+
+static int xlu__vscsi_parse_pdev(XLU_Config *cfg, libxl_ctx *ctx, char *str,
+                                 libxl_vscsi_pdev *pdev)
+{
+    int rc = ERROR_INVAL;
+    libxl_vscsi_hctl pdev_hctl;
+
+    libxl_vscsi_hctl_init(&pdev_hctl);
+    if (strncmp(str, "/dev/", 5) == 0) {
+        rc = xlu__vscsi_dev_to_pdev(cfg, ctx, str, &pdev_hctl, pdev);
+    } else if (strncmp(str, "naa.", 4) == 0) {
+        rc = xlu__vscsi_wwn_to_pdev(cfg, str, pdev);
+    } else if (xlu__vscsi_parse_hctl(str, &pdev_hctl) == 0) {
+        /* Either xenlinux, or pvops with properly configured alias in sysfs */
+        libxl_vscsi_pdev_init_type(pdev, LIBXL_VSCSI_PDEV_TYPE_HCTL);
+        libxl_vscsi_hctl_copy(ctx, &pdev->u.hctl.m, &pdev_hctl);
+        rc = 0;
+    }
+
+    if (rc == 0) {
+            pdev->p_devname = strdup(str);
+            if (!pdev->p_devname)
+                rc = ERROR_NOMEM;
+    }
+
+    libxl_vscsi_hctl_dispose(&pdev_hctl);
+    return rc;
+}
+
+int xlu_vscsi_parse(XLU_Config *cfg, libxl_ctx *ctx, const char *str,
+                    libxl_device_vscsictrl *new_ctrl,
+                    libxl_device_vscsidev *new_dev)
+{
+    int rc;
+    char *tmp, *pdev, *vdev, *fhost;
+
+    tmp = strdup(str);
+    if (!tmp) {
+        rc = ERROR_NOMEM;
+        goto out;
+    }
+
+    pdev = strtok(tmp, ",");
+    vdev = strtok(NULL, ",");
+    fhost = strtok(NULL, ",");
+    if (!(pdev && vdev)) {
+        LOG(cfg, "invalid devspec: '%s'\n", str);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    pdev = xlu__vscsi_trim_string(pdev);
+    vdev = xlu__vscsi_trim_string(vdev);
+
+    rc = xlu__vscsi_parse_pdev(cfg, ctx, pdev, &new_dev->pdev);
+    if (rc) {
+        LOG(cfg, "failed to parse %s, rc == %d", pdev, rc);
+        goto out;
+    }
+
+    if (xlu__vscsi_parse_hctl(vdev, &new_dev->vdev)) {
+        LOG(cfg, "invalid '%s', expecting hst:chn:tgt:lun", vdev);
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    new_ctrl->idx = new_dev->vdev.hst;
+
+    if (fhost) {
+        fhost = xlu__vscsi_trim_string(fhost);
+        if (strcmp(fhost, "feature-host") == 0) {
+            libxl_defbool_set(&new_ctrl->scsi_raw_cmds, true);
+        } else {
+            LOG(cfg, "invalid option '%s', expecting %s", fhost, "feature-host");
+            rc = ERROR_INVAL;
+            goto out;
+        }
+    } else
+        libxl_defbool_set(&new_ctrl->scsi_raw_cmds, false);
+    rc = 0;
+
+out:
+    free(tmp);
+    return rc;
+}
+
+int xlu_vscsi_get_ctrl(XLU_Config *cfg, libxl_ctx *ctx, uint32_t domid,
+                       const char *str,
+                       libxl_device_vscsictrl *ctrl,
+                       libxl_device_vscsidev *dev,
+                       libxl_device_vscsictrl *existing,
+                       bool *found_existing)
+{
+    libxl_device_vscsictrl *vscsictrls = NULL, *tmp;
+    int rc, found_ctrl = -1, i;
+    int num_ctrls;
+
+
+    rc = xlu_vscsi_parse(cfg, ctx, str, ctrl, dev);
+    if (rc)
+        goto out;
+
+    /* Look for existing vscsictrl for given domain */
+    vscsictrls = libxl_device_vscsictrl_list(ctx, domid, &num_ctrls);
+    if (vscsictrls) {
+        for (i = 0; i < num_ctrls; ++i) {
+            if (vscsictrls[i].idx == dev->vdev.hst) {
+                found_ctrl = i;
+                break;
+            }
+        }
+    }
+
+    if (found_ctrl == -1) {
+        *found_existing = false;
+    } else {
+        *found_existing = true;
+        tmp = vscsictrls + found_ctrl;
+
+        /* Check if the vdev address is already taken */
+        for (i = 0; i < tmp->num_vscsidevs; ++i) {
+            if (tmp->vscsidevs[i].vdev.chn == dev->vdev.chn &&
+                tmp->vscsidevs[i].vdev.tgt == dev->vdev.tgt &&
+                tmp->vscsidevs[i].vdev.lun == dev->vdev.lun) {
+                unsigned long long lun = dev->vdev.lun;
+                LOG(cfg, "vdev '%u:%u:%u:%llu' is already used.\n",
+                    dev->vdev.hst, dev->vdev.chn, dev->vdev.tgt, lun);
+                rc = ERROR_INVAL;
+                goto out;
+            }
+        }
+
+        if (libxl_defbool_val(ctrl->scsi_raw_cmds) !=
+            libxl_defbool_val(tmp->scsi_raw_cmds)) {
+            LOG(cfg, "different feature-host setting: "
+                      "existing ctrl has it %s, new ctrl has it %s\n",
+                libxl_defbool_val(ctrl->scsi_raw_cmds) ? "set" : "unset",
+                libxl_defbool_val(tmp->scsi_raw_cmds) ? "set" : "unset");
+            rc = ERROR_INVAL;
+            goto out;
+        }
+
+        libxl_device_vscsictrl_copy(ctx, existing, tmp);
+    }
+
+    rc = 0;
+
+out:
+    if (vscsictrls) {
+        for (i = 0; i < num_ctrls; ++i)
+            libxl_device_vscsictrl_dispose(vscsictrls + i);
+        free(vscsictrls);
+    }
+    return rc;
+}
+
+int xlu_vscsi_detach(XLU_Config *cfg, libxl_ctx *ctx, uint32_t domid, char *str)
+{
+    libxl_device_vscsidev dev = { };
+    libxl_device_vscsictrl ctrl = { };
+    int rc;
+    char *tmp = NULL;
+
+    libxl_device_vscsictrl_init(&ctrl);
+    libxl_device_vscsidev_init(&dev);
+
+    /* Create a dummy cfg */
+    if (asprintf(&tmp, "0:0:0:0,%s", str) < 0) {
+        LOG(cfg, "asprintf failed while removing %s from domid %u", str, domid);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = xlu_vscsi_parse(cfg, ctx, tmp, &ctrl, &dev);
+    if (rc) goto out;
+
+    rc = libxl_device_vscsidev_remove(ctx, domid, &dev, NULL);
+    switch (rc) {
+    case ERROR_NOTFOUND:
+        LOG(cfg, "detach failed: %s does not exist in domid %u", str, domid);
+        break;
+    default:
+        break;
+    }
+
+out:
+    free(tmp);
+    libxl_device_vscsidev_dispose(&dev);
+    libxl_device_vscsictrl_dispose(&ctrl);
+    return rc;
+}
+
+int xlu_vscsi_config_add(XLU_Config *cfg,
+                         libxl_ctx *ctx,
+                         const char *str,
+                         int *num_vscsis,
+                         libxl_device_vscsictrl **vscsis)
+{
+    int rc, i;
+    libxl_device_vscsidev dev = { };
+    libxl_device_vscsictrl *tmp_ctrl, ctrl = { };
+    bool ctrl_found = false;
+
+    /*
+     * #1: parse the devspec and place it in temporary ctrl+dev part
+     * #2: find existing vscsictrl with number vdev.hst
+     *     if found, append the vscsidev to this vscsictrl
+     * #3: otherwise, create new vscsictrl and append vscsidev
+     * Note: vdev.hst does not represent the index named "num_vscsis",
+     *       it is a private index used just in the config file
+     */
+    libxl_device_vscsictrl_init(&ctrl);
+    libxl_device_vscsidev_init(&dev);
+
+    rc = xlu_vscsi_parse(cfg, ctx, str, &ctrl, &dev);
+    if (rc)
+        goto out;
+
+    if (*num_vscsis) {
+        for (i = 0; i < *num_vscsis; i++) {
+            tmp_ctrl = *vscsis + i;
+            if (tmp_ctrl->idx == dev.vdev.hst) {
+                libxl_device_vscsictrl_append_vscsidev(ctx, tmp_ctrl, &dev);
+                ctrl_found = true;
+                break;
+	           }
+        }
+    }
+
+    if (!ctrl_found || !*num_vscsis) {
+        tmp_ctrl = realloc(*vscsis, sizeof(ctrl) * (*num_vscsis + 1));
+        if (!tmp_ctrl) {
+            LOG(cfg, "realloc #%d failed", *num_vscsis + 1);
+            rc = ERROR_NOMEM;
+            goto out;
+        }
+        *vscsis = tmp_ctrl;
+        tmp_ctrl = *vscsis + *num_vscsis;
+        libxl_device_vscsictrl_init(tmp_ctrl);
+
+        libxl_device_vscsictrl_copy(ctx, tmp_ctrl, &ctrl);
+
+        libxl_device_vscsictrl_append_vscsidev(ctx, tmp_ctrl, &dev);
+
+        (*num_vscsis)++;
+    }
+
+    rc = 0;
+out:
+    libxl_device_vscsidev_dispose(&dev);
+    libxl_device_vscsictrl_dispose(&ctrl);
+    return rc;
+}
+#else /* ! __linux__ */
+int xlu_vscsi_get_ctrl(XLU_Config *cfg, libxl_ctx *ctx, uint32_t domid,
+                       const char *str,
+                       libxl_device_vscsictrl *ctrl,
+                       libxl_device_vscsidev *dev,
+                       libxl_device_vscsictrl *existing,
+                       bool *found_existing)
+{
+    return ERROR_INVAL;
+}
+
+int xlu_vscsi_parse(XLU_Config *cfg,
+                    libxl_ctx *ctx,
+                    const char *str,
+                    libxl_device_vscsictrl *new_ctrl,
+                    libxl_device_vscsidev *new_dev)
+{
+    return ERROR_INVAL;
+}
+
+int xlu_vscsi_detach(XLU_Config *cfg,
+                     libxl_ctx *ctx,
+                     uint32_t domid,
+                     char *str)
+{
+    return ERROR_INVAL;
+}
+
+int xlu_vscsi_config_add(XLU_Config *cfg,
+                         libxl_ctx *ctx,
+                         const char *str,
+                         int *num_vscsis,
+                         libxl_device_vscsictrl **vscsis)
+{
+    return ERROR_INVAL;
+}
+#endif
diff --git a/tools/libxl/libxlutil.h b/tools/libxl/libxlutil.h
index e81b644c01..4cad2d8cbb 100644
--- a/tools/libxl/libxlutil.h
+++ b/tools/libxl/libxlutil.h
@@ -118,6 +118,25 @@ int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str);
 int xlu_vif_parse_rate(XLU_Config *cfg, const char *rate,
                        libxl_device_nic *nic);
 
+/* Fill ctrl/dev with device described in str (pdev,vdev[,options]) */
+int xlu_vscsi_get_ctrl(XLU_Config *cfg, libxl_ctx *ctx, uint32_t domid,
+                       const char *str,
+                       libxl_device_vscsictrl *ctrl,
+                       libxl_device_vscsidev *dev,
+                       libxl_device_vscsictrl *existing,
+                       bool *found_existing);
+/* Parse config string and fill provided vscsi ctrl and vscsi device */
+int xlu_vscsi_parse(XLU_Config *cfg, libxl_ctx *ctx, const char *str,
+                    libxl_device_vscsictrl *new_ctrl,
+                    libxl_device_vscsidev *new_dev);
+/* Detach vscsi device described in config string (pdev,vdev[,options]) */
+int xlu_vscsi_detach(XLU_Config *cfg, libxl_ctx *ctx, uint32_t domid, char *str);
+/* Add vscsi device described in config string (pdev,vdev[,options]) to d_config */
+int xlu_vscsi_config_add(XLU_Config *cfg,
+                         libxl_ctx *ctx,
+                         const char *str,
+                         int *num_vscsis,
+                         libxl_device_vscsictrl **vscsis);
 #endif /* LIBXLUTIL_H */
 
 /*
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 0a8c8133cf..dcca240815 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -89,6 +89,9 @@ int main_channellist(int argc, char **argv);
 int main_blockattach(int argc, char **argv);
 int main_blocklist(int argc, char **argv);
 int main_blockdetach(int argc, char **argv);
+int main_vscsiattach(int argc, char **argv);
+int main_vscsilist(int argc, char **argv);
+int main_vscsidetach(int argc, char **argv);
 int main_vtpmattach(int argc, char **argv);
 int main_vtpmlist(int argc, char **argv);
 int main_vtpmdetach(int argc, char **argv);
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 7e8a8ae5c4..cc76aa8adc 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1328,7 +1328,7 @@ static void parse_config_data(const char *config_source,
     long l, vcpus = 0;
     XLU_Config *config;
     XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
-                   *usbctrls, *usbdevs;
+                   *usbctrls, *usbdevs, *vscsictrls;
     XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs;
     int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
     int pci_power_mgmt = 0;
@@ -1863,6 +1863,17 @@ static void parse_config_data(const char *config_source,
         }
     }
 
+    if (!xlu_cfg_get_list(config, "vscsi", &vscsictrls, 0, 0)) {
+        int num_vscsi_items = 0;
+        d_config->num_vscsictrls = 0;
+        d_config->vscsictrls = NULL;
+        while ((buf = xlu_cfg_get_listitem (vscsictrls, num_vscsi_items)) != NULL) {
+            if (xlu_vscsi_config_add(config, ctx, buf, &d_config->num_vscsictrls, &d_config->vscsictrls))
+                exit(1);
+            num_vscsi_items++;
+        }
+    }
+
     if (!xlu_cfg_get_list(config, "vtpm", &vtpms, 0, 0)) {
         d_config->num_vtpms = 0;
         d_config->vtpms = NULL;
@@ -7601,6 +7612,218 @@ int main_blockdetach(int argc, char **argv)
     return rc;
 }
 
+int main_vscsiattach(int argc, char **argv)
+{
+    uint32_t domid;
+    int opt, rc;
+    XLU_Config *config = NULL;
+    libxl_device_vscsictrl ctrl, existing;
+    libxl_device_vscsidev dev;
+    bool found_existing = false;
+    char *str = NULL, *feat_buf = NULL;
+    char *json;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "scsi-attach", 1) {
+        /* No options */
+    }
+
+    if (argc < 4 || argc > 5) {
+        help("scsi-attach");
+        return 1;
+    }
+
+    if (libxl_domain_qualifier_to_domid(ctx, argv[optind], &domid) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", argv[optind]);
+        return 1;
+    }
+
+    optind++;
+
+    if (argc == 5) {
+        if (asprintf(&feat_buf, ",%s", argv[4]) < 0) {
+            perror("asprintf");
+            return 1;
+        }
+    }
+
+    if (asprintf(&str, "%s,%s%s", argv[2], argv[3], feat_buf ?: "") < 0) {
+        perror("asprintf");
+        rc = 1;
+        goto out;;
+    }
+
+    libxl_device_vscsictrl_init(&existing);
+    libxl_device_vscsictrl_init(&ctrl);
+    libxl_device_vscsidev_init(&dev);
+
+    config = xlu_cfg_init(stderr, "command line");
+    if (!config) {
+        fprintf(stderr, "Failed to allocate for configuration\n");
+        rc = 1;
+        goto out;
+    }
+
+    /* Parse config string and store result */
+    rc = xlu_vscsi_get_ctrl(config, ctx, domid, str, &ctrl, &dev, &existing, &found_existing);
+    if (rc < 0)
+        goto out;
+
+    if (dryrun_only) {
+        libxl_device_vscsictrl *tmp = found_existing ? &existing : &ctrl;
+        libxl_device_vscsictrl_append_vscsidev(ctx, tmp , &dev);
+        json = libxl_device_vscsictrl_to_json(ctx, tmp);
+        printf("vscsi: %s\n", json);
+        free(json);
+        if (ferror(stdout) || fflush(stdout)) { perror("stdout"); exit(-1); }
+        rc = 0;
+        goto out;
+    }
+
+    /* Finally add the device */
+    if (found_existing) {
+        if (libxl_device_vscsidev_add(ctx, domid, &dev, NULL)) {
+            fprintf(stderr, "libxl_device_vscsidev_add failed\n");
+            rc = 1;
+            goto out;
+        }
+    } else {
+        libxl_device_vscsictrl_append_vscsidev(ctx, &ctrl, &dev);
+        if (libxl_device_vscsictrl_add(ctx, domid, &ctrl, NULL)) {
+            fprintf(stderr, "libxl_device_vscsictrl_add failed.\n");
+            rc = 1;
+            goto out;
+        }
+    }
+
+    rc = 0;
+out:
+    if (config)
+        xlu_cfg_destroy(config);
+    libxl_device_vscsictrl_dispose(&existing);
+    libxl_device_vscsictrl_dispose(&ctrl);
+    libxl_device_vscsidev_dispose(&dev);
+    free(str);
+    free(feat_buf);
+    return rc;
+}
+
+int main_vscsilist(int argc, char **argv)
+{
+    int opt;
+    uint32_t domid;
+    libxl_device_vscsictrl *vscsictrls;
+    libxl_vscsiinfo vscsiinfo;
+    int num_ctrls, h, d;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "scsi-list", 1) {
+        /* No options */
+    }
+    if (argc < 2) {
+        help("scsi-list");
+        return 1;
+    }
+
+    /*      Idx  BE  state ctrl p_hst v_hst state */
+    printf("%-3s %-3s %-5s %-5s %-10s %-10s %-5s\n",
+           "Idx", "BE", "state", "ctrl", "phy-hctl", "vir-hctl", "devstate");
+    for (argv += optind, argc -= optind; argc > 0; --argc, ++argv) {
+        if (libxl_domain_qualifier_to_domid(ctx, *argv, &domid) < 0) {
+            fprintf(stderr, "%s is an invalid domain identifier\n", *argv);
+            continue;
+        }
+        vscsictrls = libxl_device_vscsictrl_list(ctx, domid, &num_ctrls);
+        if (!vscsictrls)
+            continue;
+
+        for (h = 0; h < num_ctrls; ++h) {
+            for (d = 0; d < vscsictrls[h].num_vscsidevs; d++) {
+                if (!libxl_device_vscsictrl_getinfo(ctx, domid, &vscsictrls[h],
+                                                &vscsictrls[h].vscsidevs[d],
+                                                &vscsiinfo)) {
+                    char pdev[64], vdev[64];
+                    unsigned long long lun;
+                    switch (vscsiinfo.pdev.type) {
+                    case LIBXL_VSCSI_PDEV_TYPE_HCTL:
+                        lun = vscsiinfo.pdev.u.hctl.m.lun;
+                        snprintf(pdev, sizeof(pdev), "%u:%u:%u:%llu",
+                                 vscsiinfo.pdev.u.hctl.m.hst,
+                                 vscsiinfo.pdev.u.hctl.m.chn,
+                                 vscsiinfo.pdev.u.hctl.m.tgt,
+                                 lun);
+                        break;
+                    case LIBXL_VSCSI_PDEV_TYPE_WWN:
+                        snprintf(pdev, sizeof(pdev), "%s",
+                                 vscsiinfo.pdev.u.wwn.m);
+                        break;
+                    default:
+                        pdev[0] = '\0';
+                        break;
+                    }
+                    lun = vscsiinfo.vdev.lun;
+                    snprintf(vdev, sizeof(vdev), "%u:%u:%u:%llu",
+                             vscsiinfo.vdev.hst,
+                             vscsiinfo.vdev.chn,
+                             vscsiinfo.vdev.tgt,
+                             lun);
+                    /*      Idx  BE  state Sta */
+                    printf("%-3d %-3d %-5d %-5d %-10s %-10s %d\n",
+                           vscsiinfo.devid,
+                           vscsiinfo.backend_id,
+                           vscsiinfo.vscsictrl_state,
+                           vscsiinfo.backend_id,
+                           pdev, vdev,
+                           vscsiinfo.vscsidev_state);
+
+                }
+                libxl_vscsiinfo_dispose(&vscsiinfo);
+            }
+            libxl_device_vscsictrl_dispose(&vscsictrls[h]);
+        }
+        free(vscsictrls);
+
+    }
+
+    return 0;
+}
+
+int main_vscsidetach(int argc, char **argv)
+{
+    int opt;
+    char *dom = argv[1], *str = argv[2];
+    uint32_t domid;
+    XLU_Config *config = NULL;
+    int rc = 0;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "scsi-detach", 1) {
+        /* No options */
+    }
+
+    if (argc < 3) {
+        help("scsi-detach");
+        return 1;
+    }
+
+    if (libxl_domain_qualifier_to_domid(ctx, dom, &domid) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
+        return 1;
+    }
+
+    config = xlu_cfg_init(stderr, "command line");
+    if (!config) {
+        fprintf(stderr, "Failed to allocate for configuration\n");
+        goto out;
+    }
+
+    rc = xlu_vscsi_detach(config, ctx, domid, str);
+    if (rc)
+        fprintf(stderr, "scsi-detach %s %s failed: %d\n", dom, str, rc);
+
+out:
+    if (config)
+        xlu_cfg_destroy(config);
+    return !!rc;
+}
+
 int main_vtpmattach(int argc, char **argv)
 {
     int opt;
diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
index 588d5d9604..3f098b699d 100644
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -357,6 +357,21 @@ struct cmd_spec cmd_table[] = {
       "Destroy a domain's virtual block device",
       "<Domain> <DevId>",
     },
+    { "scsi-attach",
+      &main_vscsiattach, 1, 1,
+      "Attach a dom0 SCSI device to a domain.",
+      "<Domain> <PhysDevice> <VirtDevice>",
+    },
+    { "scsi-list",
+      &main_vscsilist, 0, 0,
+      "List all dom0 SCSI devices currently attached to a domain.",
+      "<Domain(s)>",
+    },
+    { "scsi-detach",
+      &main_vscsidetach, 0, 1,
+      "Detach a specified SCSI device from a domain.",
+      "<Domain> <VirtDevice>",
+    },
     { "vtpm-attach",
       &main_vtpmattach, 1, 1,
       "Create a new virtual TPM device",

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] Scripts to create and delete xen-scsiback nodes in Linux target framework
  2017-02-17 10:49 [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Olaf Hering
  2017-02-17 10:49 ` [PATCH 1/2] libxl: add support for vscsi Olaf Hering
@ 2017-02-17 10:49 ` Olaf Hering
  2017-02-20 17:05 ` [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Wei Liu
  2 siblings, 0 replies; 5+ messages in thread
From: Olaf Hering @ 2017-02-17 10:49 UTC (permalink / raw)
  To: xen-devel

Just to make them public, not meant for merging:
The scripts used during development to create a bunch of SCSI devices in
dom0 using the Linux target framework. targetcli3 and rtslib3 is used.

A patch is required for python-rtslib:
http://article.gmane.org/gmane.linux.scsi.target.devel/8146

These scripts are not use by libxl.
These scripts are meant for testing vscsi= in libxl

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 tools/misc/Makefile                      |   4 +
 tools/misc/target-create-xen-scsiback.sh | 135 +++++++++++++++++++++++++++++++
 tools/misc/target-delete-xen-scsiback.sh |  41 ++++++++++
 3 files changed, 180 insertions(+)

diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index 8152f7bfb5..97985ddf22 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -35,6 +35,8 @@ INSTALL_SBIN += $(INSTALL_SBIN-y)
 
 # Everything to be installed in a private bin/
 INSTALL_PRIVBIN                += xenpvnetboot
+INSTALL_PRIVBIN                += target-create-xen-scsiback.sh
+INSTALL_PRIVBIN                += target-delete-xen-scsiback.sh
 
 # Everything to be installed
 TARGETS_ALL := $(INSTALL_BIN) $(INSTALL_SBIN) $(INSTALL_PRIVBIN)
@@ -45,6 +47,8 @@ TARGETS_COPY += xen-ringwatch
 TARGETS_COPY += xencons
 TARGETS_COPY += xencov_split
 TARGETS_COPY += xenpvnetboot
+TARGETS_COPY += target-create-xen-scsiback.sh
+TARGETS_COPY += target-delete-xen-scsiback.sh
 
 # Everything which needs to be built
 TARGETS_BUILD := $(filter-out $(TARGETS_COPY),$(TARGETS_ALL))
diff --git a/tools/misc/target-create-xen-scsiback.sh b/tools/misc/target-create-xen-scsiback.sh
new file mode 100755
index 0000000000..d014a0a813
--- /dev/null
+++ b/tools/misc/target-create-xen-scsiback.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+unset LANG
+unset ${!LC_*}
+set -x
+set -e
+
+modprobe --version
+targetcli --version
+udevadm --version
+blockdev --version
+parted --version
+sfdisk --version
+mkswap --version
+
+configfs=/sys/kernel/config
+target_path=$configfs/target
+
+num_luns=4
+num_hosts=4
+
+case "$1" in
+	-p)
+	backend="pvops"
+	;;
+	-x)
+	backend="xenlinux"
+	;;
+	*)
+	: "usage: $0 [-p|-x]"
+	if grep -qw xenfs$ /proc/filesystems
+	then
+		backend="pvops"
+	else
+		backend="xenlinux"
+	fi
+	;;
+esac
+
+get_wwn() {
+	sed '
+	s@-@@g
+	s@^\(.\{16\}\)\(.*\)@\1@
+	' /proc/sys/kernel/random/uuid
+}
+
+if test ! -d "${target_path}"
+then
+	modprobe -v configfs
+	mount -vt configfs configfs $configfs
+	modprobe -v target_core_mod
+fi
+if test "${backend}" = "pvops"
+then
+	modprobe -v xen-scsiback
+fi
+
+host=0
+while test $host -lt $num_hosts
+do
+	host=$(( $host + 1 ))
+	lun=0
+	loopback_wwn="naa.`get_wwn`"
+	pvscsi_wwn="naa.`get_wwn`"
+	targetcli /loopback create ${loopback_wwn}
+	if test "${backend}" = "pvops"
+	then
+		targetcli /xen-pvscsi create ${pvscsi_wwn}
+	fi
+	while test $lun -lt $num_luns
+	do
+		: h $host l $lun
+		f_file=/dev/shm/Fileio.${host}.${lun}.file
+		f_uuid=/dev/shm/Fileio.${host}.${lun}.uuid
+		f_link=/dev/shm/Fileio.${host}.${lun}.link
+		fileio_name="fio_${host}.${lun}"
+		pscsi_name="ps_${host}.${lun}"
+
+		targetcli /backstores/fileio create name=${fileio_name} "file_or_dev=${f_file}" size=$((1024*1024 * 8 )) sparse=true
+		targetcli /loopback/${loopback_wwn}/luns create /backstores/fileio/${fileio_name} $lun
+
+		vpd_uuid="`sed -n '/^T10 VPD Unit Serial Number:/s@^[^:]\+:[[:blank:]]\+@@p' /sys/kernel/config/target/core/fileio_*/${fileio_name}/wwn/vpd_unit_serial`"
+		if test -z "${vpd_uuid}"
+		then
+			exit 1
+		fi
+		echo "${vpd_uuid}" > "${f_uuid}"
+		by_id="`echo ${vpd_uuid} | sed 's@-@@g;s@^\(.\{25\}\)\(.*\)@scsi-36001405\1@'`"
+		udevadm settle --exit-if-exists="/dev/disk/by-id/${by_id}"
+		ln -sfvbn "/dev/disk/by-id/${by_id}" "${f_link}"
+
+		f_major=$((`stat --dereference --format=0x%t "${f_link}"`))
+		f_minor=$((`stat --dereference --format=0x%T "${f_link}"`))
+		if test -z "${f_major}" || test -z "${f_minor}"
+		then
+			exit 1
+		fi
+		f_alias=`ls -d /sys/dev/block/${f_major}:${f_minor}/device/scsi_device/*:*:*:*`
+		if test -z "${f_alias}"
+		then
+			exit 1
+		fi
+		f_alias=${f_alias##*/}
+
+		blockdev --rereadpt "${f_link}"
+		udevadm settle
+		echo 1,96,S | sfdisk "${f_link}"
+		udevadm settle
+		blockdev --rereadpt "${f_link}"
+		udevadm settle
+		parted -s "${f_link}" unit s print
+
+		d_link="`readlink \"${f_link}\"`"
+		if test -n "${d_link}"
+		then
+			p_link="${d_link}-part1"
+			udevadm settle --exit-if-exists="${p_link}"
+			ls -l "${p_link}"
+			mkswap -L "swp_${fileio_name}" "${p_link}"
+			udevadm settle
+			blockdev --rereadpt "${f_link}"
+			udevadm settle
+			parted -s "${f_link}" unit s print
+		fi
+
+		targetcli /backstores/pscsi create "dev=${f_link}" "${pscsi_name}"
+		if test "${backend}" = "pvops"
+		then
+			targetcli /xen-pvscsi/${pvscsi_wwn}/tpg1/luns create "/backstores/pscsi/${pscsi_name}" $lun
+			targetcli /xen-pvscsi/${pvscsi_wwn}/tpg1  set parameter alias=${f_alias%:*}
+		fi
+
+		lun=$(( $lun + 1 ))
+	done
+done
+
diff --git a/tools/misc/target-delete-xen-scsiback.sh b/tools/misc/target-delete-xen-scsiback.sh
new file mode 100755
index 0000000000..5b6dc5444c
--- /dev/null
+++ b/tools/misc/target-delete-xen-scsiback.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+unset LANG
+unset ${!LC_*}
+set -x
+set -e
+
+targetcli --version
+
+configfs=/sys/kernel/config
+target_path=$configfs/target
+
+cd "${target_path}"
+if cd xen-pvscsi
+then
+	for wwn in `ls -d naa.*`
+	do
+		targetcli /xen-pvscsi delete $wwn
+	done
+fi
+cd "${target_path}"
+cd core
+for name in `ls -d pscsi_*/*/wwn`
+do
+	name=${name%/wwn}
+	name=${name##*/}
+	targetcli /backstores/pscsi delete $name
+done
+cd "${target_path}"
+cd loopback
+for wwn in `ls -d naa.*`
+do
+	targetcli /loopback delete $wwn
+done
+cd "${target_path}"
+cd core
+for name in `ls -d fileio_*/*/wwn`
+do
+	name=${name%/wwn}
+	name=${name##*/}
+	targetcli /backstores/fileio delete $name
+done

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] libxl: add support for pvscsi, iteration 13
  2017-02-17 10:49 [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Olaf Hering
  2017-02-17 10:49 ` [PATCH 1/2] libxl: add support for vscsi Olaf Hering
  2017-02-17 10:49 ` [PATCH 2/2] Scripts to create and delete xen-scsiback nodes in Linux target framework Olaf Hering
@ 2017-02-20 17:05 ` Wei Liu
  2017-02-20 17:18   ` Olaf Hering
  2 siblings, 1 reply; 5+ messages in thread
From: Wei Liu @ 2017-02-20 17:05 UTC (permalink / raw)
  To: Olaf Hering; +Cc: Ian Jackson, Wei Liu, xen-devel

CC Ian -- I think he followed more closely than I did.

On Fri, Feb 17, 2017 at 10:49:54AM +0000, Olaf Hering wrote:
> Port vscsi=[] and scsi-{attach,detach,list} commands from xend to libxl.
> 
> libvirt uses its existing SCSI support:
> http://lists.xenproject.org/archives/html/xen-devel/2015-04/msg02963.html
> 
> targetcli/rtslib has to be aware of xen-scsiback (upstream unresponsive):
> http://article.gmane.org/gmane.linux.scsi.target.devel/8146
> 
> TODO:
>  - document pvscsi in xen wiki
>  - find a way to carry vscsi devices during live migration to remote host
>    could be done with using 'string' for pdev/vdev in idl
> 
> Changes between v12 and v13:
>  - rebase to 'staging' (936a7a5..a7a578ce6b)
>  - rebase to 'staging' (8b27d2b..936a7a5)
> 
> Changes between v11 and v12:
>  - rebase to 'staging' (3dac42f..8b27d2b)
>  - rebase to 'staging' (a35dc6c..3dac42f)
>  - Rework API of xlu_vscsi_get_ctrl
>  - Sanitize input from frontend in vscsi_fill_ctrl
>  - Use macro for libxl_ctrl_index
> https://lists.xenproject.org/archives/html/xen-devel/2016-04/msg01772.html
> 
> Changes between v10 and v11:
>  - rebase to 'staging' (d887c19..a35dc6c)
>  - rebase to 'staging' (829e03c..d887c19)
>  - Remove evtch and rref from vscsiinfo
>  - Remove COMPARE_VSCSI, use COMPARE_DEVID
>  - Remove vscsi_wwn_valid helpers, use sscanf instead
> http://lists.xenproject.org/archives/html/xen-devel/2016-04/msg01120.html
> 
> Changes between v9 and v10:
>  - rebase to 'staging' (3b971de..829e03c)
> http://lists.xenproject.org/archives/html/xen-devel/2016-03/msg02773.html
> 
> Changes between v8 and v9:
>  - Mention libxl_ctrl_index in vscsiif.h
>  - Rename idx to libxl_ctrl_index
>  - Fix device assignment in vscsidev_remove
>  - Add vscsictrls to multidev callchain
>  - Reorder some functions
>  - Move and rename vscsidev_rm
>  - Remove libxl prefix from static functions
>  - Reorder functions in libxl_vscsi.c
>  - Add comment to libxl_vscsidev_aodev_cb
>  - Move libxl_device_vscsictrl_remove into libxl_vscsi.c
>  - Enclose libxl__device instead of aodev in libxl__vscsidev_rm
>  - Update typedef of libxl__vscsidev_rm
>  - Assign devid earlier in libxl__device_vscsictrl_add
>  - Rework xlu_vscsi_get_ctrl and main_vscsiattach
>  - Add config idx also to libxl_vscsiinfo
>  - Make libxl__vscsi_collect_ctrls static
>  - Implement libxl_device_vscsidev_add
>  - Move vscsictrl add from libxl.c to libxl_vscsi.c
>  - Export libxl__device_nextid for internal use
>  - Remove some checks for empty controllers
>  - Introduce an idx file to present the config index in empty vscsictrls
>  - Use libxl__ev_devstate_wait in libxl__device_vscsictrl_reconfigure_add
>  - Rework error handling in libxl__vscsi_fill_ctrl
>  - Remove state checking from libxl__vscsi_fill_dev
>  - Wrap long lines in libxl__device_vscsictrl_new_backend
>  - Use LIBXL_DESTROY_TIMEOUT in libxl__device_vscsidev_rm
>  - Remove tab from libxl__vscsi_collect_ctrls
>  - Goto out if libxl__device_vscsidev_backend_set_add fails
>  - Add fallthrough to libxl__device_vscsidev_backend_set_add
>  - Fix typo in xl.cfg.pod: naa.
>  - Wrap long line in xl.cfg.pod.5
>  - Use memmove in libxl_device_vscsictrl_remove_vscsidev
>  - Adjust code in main_vscsilist to fit in 80 chars
>  - Align switch and case to gain 4 columns
>  - Wrap long line in libxl__device_vscsi_reconfigure_rm
>  - Wrap long line in libxl__device_vscsidev_rm_be
>  - Adjust flexarray size in libxl__device_vscsi_reconfigure_rm
>  - Rework libxl_device_vscsidev_remove
>  - Introduce libxl_device_vscsictrl_remove_vscsidev
>  - Use stack variables in xlu_vscsi_get_ctrl
>  - Rename function names to refer to vscsictrl
>  - Rename local variables to refer to vscsictrl
>  - Use generic vscsictrl->devid
> http://lists.xenproject.org/archives/html/xen-devel/2016-02/msg03196.html
> 
> Changes between v7 and v8:
>  - Make be_path const in libxl__device_vscsictrl_add
>  - Adjust years in Copyright
>  - Whitespace in libxl_device_vscsictrl idl
>  - Implement libxl_device_vscsictrl_destroy
>  - Set backend_devid
>  - Reorder assignments in libxl__device_vscsictrl_add
>  - Whitespace changes for libxl__device_vscsi_reconfigure_add
>  - Register watch unconditionally in libxl__device_vscsidev_rm
>  - Wait for StateClosing for unconnected frontends in detach
>  - Adjust logic in libxl__vscsi_fill_dev
>  - Rework scsi-detach
>  - Increase swap partition from 12 to 96 blocks for mkswap
>  - Update MERGE macro for vscsictrls
> http://lists.xenproject.org/archives/html/xen-devel/2016-02/msg01662.html
> 
> Changes between v6 and v7:
>  - rebase to 'staging' (3b971de)
>  - Introduce libxl_device_vscsictrl_append_vscsidev
>  - Add libxl__vscsi_collect_ctrls and used it in libxl_device_vscsictrl_list
>  - Convert type of lun from u32 to u64 per SCSI spec
>  - Use vscsi_saved in libxl__device_vscsictrl_add
>  - Assign unique vscsidev_id per vscsictrl
>  - Rename vscsi_dev to vscsidev in function names
>  - Rename variables in libxl_vscsiinfo
>  - Rename locals to refer to ctrl/dev
>  - Rename various strings from host to ctrl
>  - Rename local variables vscsi_ctrl to vscsictrl
>  - Rename libxl_device_vscsictrl->vscsi_devs to vscsidevs
>  - Remove libxl_device_vscsidev->remove, rework detach
>  - Rename libxl_device_vscsidev->vscsi_dev_id to vscsidev_id
>  - Rename local variables vscsi_host to vscsi_ctrl
>  - Rename local variables v_hst to v_ctrl
>  - Remove libxl_device_vscsictrl->v_hst
>  - Rename libxl_vscsi_dev to libxl_device_vscsidev
>  - Rename libxl_device_vscsi to libxl_device_vscsictrl
> http://lists.xenproject.org/archives/html/xen-devel/2016-02/msg00884.html
> 
> Changes between v5 and v6:
>  - rebase to 'staging' (a7b39c8 and b7e7ad8)
>  - Fix off-by-one in xlu__vscsi_compare_udev
>  - xl.cfg: use options instead of option
>  - xl.cfg: fix grammar for pdev/options
>  - xl.cfg: fix Usually typo
>  - Remove next_vscsi_dev_id from libxl_device_vscsi
>  - Use XLU_WWN_LEN also in libxl_vscsi.c
> http://lists.xenproject.org/archives/html/xen-devel/2015-11/msg01446.html
> 
> Changes between v4 and v5:
>  - vscsiif.h: refer to backend_domid
>  - Set update_json in libxl_device_vscsi_remove
>  - Remove comment from libxl__device_vscsi_add
>  - Remove debug LOG from libxl__device_vscsi_reconfigure
>  - Move local nb variable in libxl__device_vscsi_reconfigure
>  - Make be_path const in libxl__device_vscsi_reconfigure
>  - Adjust libxl__device_vscsi_dev_backend_set to avoid long lines
>  - Adjust libxl__device_vscsi_dev_backend_rm to avoid long lines
>  - Use CTX in libxl__device_vscsi_dev_backend_rm
>  - Make be_path const in libxl__device_vscsi_dev_backend_rm
>  - xl.cfg: Its typo
>  - xl.cfg: Use persistent instead of persistant
>  - Rename feature_host to scsi_raw_cmds
>  - target-create-xen-scsiback.sh: detect pvops and xenlinux
>  - Wrap long lines in main_vscsilist
>  - Call libxl_vscsiinfo_dispose unconditional
>  - Let scsi-list print p-dev instead of p-devname
>  - Handle broken vscsi device entry in xenstore
>  - Split libxl__vscsi_fill_host from libxl_device_vscsi_list
>  - Make xlu_vscsi_append_dev static
>  - Remove reference to pvscsi.txt from xenstore-paths.markdown
>  - xl.cfg: update Linux and xenlinux
>  - xl.cfg: refer to backend domain instead of dom0
>  - xl.cfg: be more verbose what persistant format is
>  - return if libxl__device_vscsi_dev_backend_set fails in libxl__device_vscsi_new_backend
>  - target-create-xen-scsiback.sh: set also alias for libvirt
> http://lists.xenproject.org/archives/html/xen-devel/2015-05/msg00523.html
> 
> Changes between v3 and v4:
>  - Use libxl__device_nextid in libxl__device_vscsi_add
>  - Remove check for duplicate pdev assignment from libxl_device_vscsi_get_host
>  - Caller provides libxl_device_vscsi to libxl_device_vscsi_get_host
>  - Define LIBXL_HAVE_VSCSI
>  - Remove init_val from libxl_vscsi_pdev_type
>  - Move some functions from libxl to libxlu
>  - Introduce libxl_device_vscsi->next_vscsi_dev_id to handle holes
>  - Use Struct in KeyedUnion for ocaml idl
>  - docs: Mention pvscsi in xl and xl.cfg
>  - Turn feature_host into a defbool and add checking
>  - Support pvops and /dev/ nodes in config
>  - Wrap entire libxlu_vscsi.c with ifdef linux
>  - Set remove flag in libxl_device_vscsi_list
>  - Fix vscsiif path in xenstore-paths.markdown
>  - vscsiif.h: add some notes about xenstore layout
>  - Add copyright to libxlu_vscsi.c and libxl_vscsi.c
>  - Scripts to create and delete xen-scsiback nodes in Linux target framework
>  - Remove pvscsi.txt
> http://lists.xenproject.org/archives/html/xen-devel/2015-04/msg01949.html
> 
> Changes between v2 and v3:
>  - Adjust change for vscsiif.h
>  - Support "naa.wwn:lun" notation in pvops kernel
>  - Add example for pvops kernel using targetcli
>    patch required for python-rtslib:
>    http://article.gmane.org/gmane.linux.scsi.target.devel/8146
>  - Use vdev variable in libxl_device_vscsi_parse
> http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg00734.html
> 
> Changes between v1 and v2:
>  - ported to current staging
> http://lists.xenproject.org/archives/html/xen-devel/2015-03/msg00030.html
> 
> Initial attempt was sent a year ago:
> http://lists.xenproject.org/archives/html/xen-devel/2014-04/msg03958.html
> Most comments are addressed.
> 
> This version has been tested with SLES as backend and frontend.
> This version has been tested with pvops as backend and SLES as frontend.
> 
> 
> 
> Olaf Hering (2):
>   libxl: add support for vscsi
>   Scripts to create and delete xen-scsiback nodes in Linux target
>     framework
> 
>  docs/man/xl.cfg.pod.5.in                 |   56 ++
>  docs/man/xl.pod.1.in                     |   18 +
>  tools/libxl/Makefile                     |    2 +
>  tools/libxl/libxl.h                      |   42 ++
>  tools/libxl/libxl_create.c               |    1 +
>  tools/libxl/libxl_internal.h             |    1 +
>  tools/libxl/libxl_types.idl              |   53 ++
>  tools/libxl/libxl_types_internal.idl     |    1 +
>  tools/libxl/libxl_vscsi.c                | 1176 ++++++++++++++++++++++++++++++
>  tools/libxl/libxlu_vscsi.c               |  667 +++++++++++++++++
>  tools/libxl/libxlutil.h                  |   19 +
>  tools/libxl/xl.h                         |    3 +
>  tools/libxl/xl_cmdimpl.c                 |  225 +++++-
>  tools/libxl/xl_cmdtable.c                |   15 +
>  tools/misc/Makefile                      |    4 +
>  tools/misc/target-create-xen-scsiback.sh |  135 ++++
>  tools/misc/target-delete-xen-scsiback.sh |   41 ++
>  17 files changed, 2458 insertions(+), 1 deletion(-)
>  create mode 100644 tools/libxl/libxl_vscsi.c
>  create mode 100644 tools/libxl/libxlu_vscsi.c
>  create mode 100755 tools/misc/target-create-xen-scsiback.sh
>  create mode 100755 tools/misc/target-delete-xen-scsiback.sh
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] libxl: add support for pvscsi, iteration 13
  2017-02-20 17:05 ` [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Wei Liu
@ 2017-02-20 17:18   ` Olaf Hering
  0 siblings, 0 replies; 5+ messages in thread
From: Olaf Hering @ 2017-02-20 17:18 UTC (permalink / raw)
  To: Wei Liu; +Cc: Ian Jackson, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 737 bytes --]

Am Mon, 20 Feb 2017 17:05:18 +0000
schrieb Wei Liu <wei.liu2@citrix.com>:

> CC Ian -- I think he followed more closely than I did.

Thanks, but this is just a rebase to 4.8 in case anyone needs it.
No code changes since last review round.

I'm currently working on an update for the idl representation to
support migration. 'pdev' has to be reevaluated on each dom0, which
means 'pdev' has to be a string and what is currently stored in a
"libxl_vscsi_pdev" has be evaluated shortly before it gets written to
xenstore. This avoids "libxl_vscsi_pdev_type" becoming part of the json.

Olaf

> > Changes between v12 and v13:
> >  - rebase to 'staging' (936a7a5..a7a578ce6b)
> >  - rebase to 'staging' (8b27d2b..936a7a5)

[-- Attachment #1.2: Digitale Signatur von OpenPGP --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 127 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-02-20 17:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-17 10:49 [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Olaf Hering
2017-02-17 10:49 ` [PATCH 1/2] libxl: add support for vscsi Olaf Hering
2017-02-17 10:49 ` [PATCH 2/2] Scripts to create and delete xen-scsiback nodes in Linux target framework Olaf Hering
2017-02-20 17:05 ` [PATCH 0/2] libxl: add support for pvscsi, iteration 13 Wei Liu
2017-02-20 17:18   ` Olaf Hering

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.