xen/libxl.pvscsi.patch
Charles Arnold 763b78040d - bnc#935634 - VUL-0: CVE-2015-3259: xen: XSA-137: xl command line
config handling stack overflow
  CVE-2015-3259-xsa137.patch
- Upstream patches from Jan
  558bfaa0-x86-traps-avoid-using-current-too-early.patch
  5592a116-nested-EPT-fix-the-handling-of-nested-EPT.patch
  559b9dd6-x86-p2m-ept-don-t-unmap-in-use-EPT-pagetable.patch
  559bdde5-pull-in-latest-linux-earlycpio.patch
- Upstream patches from Jan pending review
  552d0fd2-x86-hvm-don-t-include-asm-spinlock-h.patch
  552d0fe8-x86-mtrr-include-asm-atomic.h.patch
  552d293b-x86-vMSI-X-honor-all-mask-requests.patch
  552d2966-x86-vMSI-X-add-valid-bits-for-read-acceleration.patch
  554c7aee-x86-provide-arch_fetch_and_add.patch
  554c7b00-arm-provide-arch_fetch_and_add.patch
  55534b0a-x86-provide-add_sized.patch
  55534b25-arm-provide-add_sized.patch
  5555a4f8-use-ticket-locks-for-spin-locks.patch
  5555a5b9-x86-arm-remove-asm-spinlock-h.patch
  5555a8ec-introduce-non-contiguous-allocation.patch
  55795a52-x86-vMSI-X-support-qword-MMIO-access.patch
  557eb55f-gnttab-per-active-entry-locking.patch
  557eb5b6-gnttab-introduce-maptrack-lock.patch
  557eb620-gnttab-make-the-grant-table-lock-a-read-write-lock.patch
  557ffab8-evtchn-factor-out-freeing-an-event-channel.patch
  5582bf43-evtchn-simplify-port_is_valid.patch
  5582bf81-evtchn-remove-the-locking-when-unmasking-an-event-channel.patch
  5583d9c5-x86-MSI-X-cleanup.patch
  5583da09-x86-MSI-track-host-and-guest-masking-separately.patch
  5583da64-gnttab-use-per-VCPU-maptrack-free-lists.patch

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=369
2015-07-10 15:21:29 +00:00

1166 lines
42 KiB
Diff

* local-fate316613-pvscsi-staging-4.4
git://github.com/olafhering/xen.git : local-fate316613-pvscsi-staging-4.4
Implement pvscsi in xl/libxl
fate#316613 , https://fate.suse.com/316613
10bd594 pvscsi: move parse_vscsi_config code block to avoid fuzz
06914e1 Merge pull request #4 from aaannz/pvscsi
fe65eb3 define SUSE PVSCSI extension for 3rd party use
8a34a98 pvscsi: check null pointer in libxl__add_vscsis
09fa151 pvscsi: avoid double assignment of host devices
aa88928 pvscsi: fix double free in scsi-attach
2de1507 pvscsi: update comments about libxl.so ABI
483f7e9 Merge pull request #3 from aaannz/pvscsi
d98458c Xen4.2 ABI compat
73744a5 preserve Xen4.2 ABI, WIP
0f8e701 fix minor memory leaks
1b1c55d pvscsi: correct comment for DEFINE_DEVICES_ADD
6f50972 pvscsi: move libxl__add_vscsis call
6fd1327 pvscsi: add comment for DEFINE_DEVICES_ADD
e4bf1fd pvscsi: fix DEFINE_DEVICE_REMOVE destroy
51b63a6 pvscsi: man pages
e461042 pvscsi: implememnt single device scsi-detach
540e524 Merge pull request #2 from aaannz/pvscsi
919a851 implement vscsi-attach
e07db68 fix indentation
b087b9d pvscsi: implement simple scsi-detach
824f286 pvscsi: simplify sysfs parsing in parse_vscsi_config
977d81d pvscsi: include stddef in xl_cmdimpl.c to get offsetof
ee2e7e5 Merge pull request #1 from aaannz/pvscsi
7de6f49 support character devices too
c84381b allow /dev/sda as scsi devspec
f11e3a2 pvscsi
--- a/docs/man/xl.cfg.pod.5
+++ b/docs/man/xl.cfg.pod.5
@@ -448,6 +448,36 @@ value is optional if this is a guest dom
=back
+=item B<vscsi=[ "VSCSI_SPEC_STRING", "VSCSI_SPEC_STRING", ...]>
+
+Specifies the PVSCSI devices to be provided to the guest. PVSCSI passes
+dom0 SCSI devices as-is to the guest.
+
+Each B<VSCSI_SPEC_STRING> is a mapping from dom0 SCSI devices to guest visible
+SCSI devices, like 'pvdev,vdev[,option]'. Example: '/dev/sdm,3:0:4:5,feature-host'
+
+=over 4
+
+=item C<pdev>
+
+Specifies the dom0 visible SCSI device. The string can be either a device path
+like to a block device like /dev/disk/by-id/scsi-XYZ. Or it can be a device path
+to a char device like /dev/sg5. Or it can be specified in the SCSI notation
+HOST:CHANNEL:TARGET:LUN. Note that the latter format is unreliable because
+the HOST value can change across dom0 reboots.
+
+=item C<vdev>
+
+Specifies how the SCSI device is mapped into the guest. The notation is in
+SCSI notation HOST:CHANNEL:TARGET:LUN. HOST in this case means a virthal
+SCSI host within the guest.
+
+=item C<option>
+
+Right now only one option is recognized: feature-host.
+
+=back
+
=item B<vfb=[ "VFB_SPEC_STRING", "VFB_SPEC_STRING", ...]>
Specifies the paravirtual framebuffer devices which should be supplied
--- a/docs/man/xl.pod.1
+++ b/docs/man/xl.pod.1
@@ -1323,6 +1323,26 @@ List virtual trusted platform modules fo
=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>.
+Note that the whole virtual SCSI host with all its devices is removed.
+This is a BUG!
+
+=item B<vscsi-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
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2310,6 +2310,273 @@ int libxl_devid_to_device_vtpm(libxl_ctx
return rc;
}
+/******************************************************************************/
+static int libxl__device_from_vscsi(libxl__gc *gc, uint32_t domid,
+ libxl_device_vscsi *vscsi,
+ libxl__device *device)
+{
+ device->backend_domid = vscsi->backend_domid;
+ device->devid = vscsi->devid;
+ device->domid = domid;
+ device->backend_kind = LIBXL__DEVICE_KIND_VSCSI;
+ device->kind = LIBXL__DEVICE_KIND_VSCSI;
+
+ return 0;
+}
+
+void libxl__device_vscsi_add(libxl__egc *egc, uint32_t domid,
+ libxl_device_vscsi *vscsi,
+ libxl__ao_device *aodev)
+{
+ STATE_AO_GC(aodev->ao);
+ flexarray_t *front;
+ flexarray_t *back;
+ libxl__device *device;
+ unsigned int rc, i;
+
+ i = 2 * (4 + (3 * vscsi->num_vscsi_devs));
+ front = flexarray_make(gc, 4, 1);
+ back = flexarray_make(gc, i, 1);
+
+ if (vscsi->devid == -1) {
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ GCNEW(device);
+ rc = libxl__device_from_vscsi(gc, domid, vscsi, device);
+ if ( rc != 0 ) goto out;
+
+ /* get backend device path to check if is already present */
+ char *backend_path;
+ unsigned int ndirs = 0;
+ backend_path = libxl__device_backend_path(gc, device);
+ if (!libxl__xs_directory(gc, XBT_NULL, backend_path, &ndirs) || !ndirs) {
+ /* backend does not exist => vscsi host does not exist */
+ flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
+ flexarray_append_pair(back, "online", "1");
+ flexarray_append_pair(back, "state", "1");
+ flexarray_append_pair(back, "feature-host", GCSPRINTF("%d", !!vscsi->feature_host));
+
+ flexarray_append_pair(front, "backend-id", GCSPRINTF("%d", vscsi->backend_domid));
+ flexarray_append_pair(front, "state", "1");
+ }
+
+ for (i = 0; i < vscsi->num_vscsi_devs; i++) {
+ libxl_vscsi_dev *v = vscsi->vscsi_devs + i;
+ if (ndirs) {
+ unsigned int nb = 0;
+ /* vhost exist, check if not overwriting records */
+ if (libxl__xs_directory(gc, XBT_NULL,
+ GCSPRINTF("%s/vscsi-devs/dev-%u", backend_path, v->vscsi_dev_id),
+ &nb) && nb) {
+ /* trigger device removal by forwarding state to XenbusStateClosing */
+ if (v->remove)
+ flexarray_append_pair(back, GCSPRINTF("vscsi-devs/dev-%u/state", v->vscsi_dev_id), "5");
+ continue;
+ }
+ }
+ flexarray_append_pair(back, GCSPRINTF("vscsi-devs/dev-%u/p-dev", v->vscsi_dev_id),
+ GCSPRINTF("%u:%u:%u:%u", v->p_hst, v->p_chn, v->p_tgt, v->p_lun));
+ flexarray_append_pair(back, GCSPRINTF("vscsi-devs/dev-%u/v-dev", v->vscsi_dev_id),
+ GCSPRINTF("%u:%u:%u:%u", vscsi->v_hst, v->v_chn, v->v_tgt, v->v_lun));
+ flexarray_append_pair(back, GCSPRINTF("vscsi-devs/dev-%u/state", v->vscsi_dev_id), "1");
+ }
+
+ aodev->dev = device;
+ if (ndirs == 0) {
+ libxl__device_generic_add(gc, XBT_NULL, device,
+ libxl__xs_kvs_of_flexarray(gc, back, back->count),
+ libxl__xs_kvs_of_flexarray(gc, front, front->count),
+ NULL);
+
+ aodev->action = LIBXL__DEVICE_ACTION_ADD;
+ libxl__wait_device_connection(egc, aodev);
+ }
+ else {
+ /* we added only new vscsi devices, write them and trigger vscsi host reconfiguration */
+ libxl_ctx *ctx = libxl__gc_owner(gc);
+ xs_transaction_t t;
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ libxl__xs_writev(gc, t, backend_path,
+ libxl__xs_kvs_of_flexarray(gc, back, back->count));
+ xs_write(ctx->xsh, t, GCSPRINTF("%s/state", backend_path), "7", 2);
+ if(!xs_transaction_end(ctx->xsh, t, 0)) {
+ if (errno == EAGAIN) {
+ goto retry_transaction;
+ }
+ else {
+ LOGE(ERROR, "xs transaction failed");
+ return;
+ }
+ }
+ libxl__wait_for_backend(gc, backend_path, "4");
+
+retry_transaction2:
+ t = xs_transaction_start(ctx->xsh);
+ for (i = 0; i < vscsi->num_vscsi_devs; i++) {
+ libxl_vscsi_dev *v = vscsi->vscsi_devs + i;
+ if (v->remove) {
+ char *tmppath, *tmpval;
+ tmppath = GCSPRINTF("%s/vscsi-devs/dev-%u/state", backend_path, v->vscsi_dev_id);
+ tmpval = libxl__xs_read(gc, t, tmppath);
+ if (tmpval && strcmp(tmpval, "6") == 0) {
+ tmppath = GCSPRINTF("%s/vscsi-devs/dev-%u/state", backend_path, v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, tmppath);
+ tmppath = GCSPRINTF("%s/vscsi-devs/dev-%u/p-dev", backend_path, v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, tmppath);
+ tmppath = GCSPRINTF("%s/vscsi-devs/dev-%u/v-dev", backend_path, v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, tmppath);
+ tmppath = GCSPRINTF("%s/vscsi-devs/dev-%u", backend_path, v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, tmppath);
+ } else {
+ LOGE(ERROR, "%s: %s has %s, expected 6", __func__, tmppath, tmpval);
+ }
+ }
+ }
+ if(!xs_transaction_end(ctx->xsh, t, 0)) {
+ if (errno == EAGAIN) {
+ goto retry_transaction2;
+ }
+ else {
+ LOGE(ERROR, "xs transaction failed");
+ return;
+ }
+ }
+ /* as we are not adding new device, skip waiting for it */
+ libxl__ao_complete(egc, aodev->ao, 0);
+ }
+
+ rc = 0;
+out:
+ aodev->rc = rc;
+ if(rc) aodev->callback(egc, aodev);
+ return;
+}
+
+libxl_device_vscsi *libxl_device_vscsi_list(libxl_ctx *ctx, uint32_t domid, int *num)
+{
+ GC_INIT(ctx);
+
+ libxl_device_vscsi *vscsi_hosts = NULL;
+ char *fe_path;
+ char **dir;
+ unsigned int ndirs = 0;
+
+ fe_path = libxl__sprintf(gc, "%s/device/vscsi", libxl__xs_get_dompath(gc, domid));
+ dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs);
+ if (dir && ndirs) {
+ libxl_device_vscsi *vscsi, *end;
+ vscsi_hosts = calloc(ndirs, sizeof(*vscsi_hosts));
+ for (vscsi = vscsi_hosts, end = vscsi_hosts + ndirs; vscsi_hosts && vscsi < end; ++vscsi, ++dir) {
+ unsigned int vd_dirs = 0, i;
+ char *tmp;
+ char **vscsi_devs_dir;
+ const char *vscsi_devs_path, *be_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s/backend", fe_path, *dir));
+
+ libxl_device_vscsi_init(vscsi);
+
+ vscsi->devid = atoi(*dir);
+
+ tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s/backend-id", fe_path, *dir));
+ vscsi->backend_domid = atoi(tmp);
+
+ vscsi_devs_path = libxl__sprintf(gc, "%s/vscsi-devs", be_path);
+ vscsi_devs_dir = libxl__xs_directory(gc, XBT_NULL, vscsi_devs_path, &vd_dirs);
+ if (vscsi_devs_dir && vd_dirs) {
+ vscsi->vscsi_devs = calloc(vd_dirs, sizeof(*vscsi->vscsi_devs));
+ vscsi->num_vscsi_devs = vd_dirs;
+ for (i = 0; i < vd_dirs; i++, vscsi_devs_dir++) {
+ unsigned int vscsi_dev_id;
+ if (sscanf(*vscsi_devs_dir, "dev-%u", &vscsi_dev_id) != 1) {
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "%s/scsi-devs/%s failed to parse", be_path, *vscsi_devs_dir);
+ continue;
+ }
+ vscsi->vscsi_devs[i].vscsi_dev_id = vscsi_dev_id;
+ tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/vscsi-devs/dev-%u/p-dev", be_path, vscsi_dev_id));
+ if (tmp)
+ sscanf(tmp, "%u:%u:%u:%u", &vscsi->vscsi_devs[i].p_hst, &vscsi->vscsi_devs[i].p_chn, &vscsi->vscsi_devs[i].p_tgt, &vscsi->vscsi_devs[i].p_lun);
+ tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/vscsi-devs/dev-%u/v-dev", be_path, vscsi_dev_id));
+ if (tmp)
+ sscanf(tmp, "%u:%u:%u:%u", &vscsi->v_hst, &vscsi->vscsi_devs[i].v_chn, &vscsi->vscsi_devs[i].v_tgt, &vscsi->vscsi_devs[i].v_lun);
+ }
+ }
+ }
+ }
+ *num = ndirs;
+
+ GC_FREE;
+ return vscsi_hosts;
+}
+
+int libxl_device_vscsi_getinfo(libxl_ctx *ctx,
+ uint32_t domid,
+ libxl_device_vscsi *vscsi_host,
+ libxl_vscsi_dev *vscsi_dev,
+ libxl_vscsiinfo *vscsiinfo)
+{
+ GC_INIT(ctx);
+ char *dompath, *vscsipath;
+ char *val;
+ int rc = 0;
+
+ libxl_vscsiinfo_init(vscsiinfo);
+ dompath = libxl__xs_get_dompath(gc, domid);
+ vscsiinfo->devid = vscsi_host->devid;
+ vscsiinfo->p_hst = vscsi_dev->p_hst;
+ vscsiinfo->p_chn = vscsi_dev->p_chn;
+ vscsiinfo->p_tgt = vscsi_dev->p_tgt;
+ vscsiinfo->p_lun = vscsi_dev->p_lun;
+ vscsiinfo->v_hst = vscsi_host->v_hst;
+ vscsiinfo->v_chn = vscsi_dev->v_chn;
+ vscsiinfo->v_tgt = vscsi_dev->v_tgt;
+ vscsiinfo->v_lun = vscsi_dev->v_lun;
+
+ 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 err;
+ }
+ if(!libxl__xs_read(gc, XBT_NULL, vscsiinfo->backend)) {
+ goto err;
+ }
+
+ 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->vscsi_host_state = val ? strtoul(val, NULL, 10) : -1;
+
+ val = libxl__xs_read(gc, XBT_NULL,
+ GCSPRINTF("%s/event-channel", vscsipath));
+ vscsiinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+
+ val = libxl__xs_read(gc, XBT_NULL,
+ GCSPRINTF("%s/ring-ref", vscsipath));
+ vscsiinfo->rref = 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, vscsi_dev->vscsi_dev_id));
+ vscsiinfo->vscsi_dev_state = val ? strtoul(val, NULL, 10) : -1;
+
+ goto exit;
+err:
+ rc = ERROR_FAIL;
+exit:
+ GC_FREE;
+ return rc;
+}
/******************************************************************************/
@@ -4185,6 +4452,8 @@ out:
* libxl_device_vkb_destroy
* libxl_device_vfb_remove
* libxl_device_vfb_destroy
+ * libxl_device_vscsi_remove
+ * libxl_device_vscsi_destroy
*/
#define DEFINE_DEVICE_REMOVE(type, removedestroy, f) \
int libxl_device_##type##_##removedestroy(libxl_ctx *ctx, \
@@ -4240,6 +4509,10 @@ DEFINE_DEVICE_REMOVE(vtpm, destroy, 1)
* 1. add support for secondary consoles to xenconsoled
* 2. dynamically add/remove qemu chardevs via qmp messages. */
+/* vscsi */
+DEFINE_DEVICE_REMOVE(vscsi, remove, 0)
+DEFINE_DEVICE_REMOVE(vscsi, destroy, 1)
+
#undef DEFINE_DEVICE_REMOVE
/******************************************************************************/
@@ -4249,6 +4522,7 @@ DEFINE_DEVICE_REMOVE(vtpm, destroy, 1)
* libxl_device_disk_add
* libxl_device_nic_add
* libxl_device_vtpm_add
+ * libxl_device_vscsi_add
*/
#define DEFINE_DEVICE_ADD(type) \
@@ -4280,6 +4554,9 @@ DEFINE_DEVICE_ADD(nic)
/* vtpm */
DEFINE_DEVICE_ADD(vtpm)
+/* vscsi */
+DEFINE_DEVICE_ADD(vscsi)
+
#undef DEFINE_DEVICE_ADD
/******************************************************************************/
@@ -6822,6 +7099,20 @@ out:
return rc;
}
+/* libxl.so.4.4 ABI compatilibity hack - do not do this at home */
+static libxl_device_vscsi_suse* libxl__global_vscsi_list_suse;
+
+libxl_device_vscsi_suse* libxl_get_vscsi_devices_suse(void)
+{
+ return libxl__global_vscsi_list_suse;
+}
+
+void libxl_set_vscsi_devices_suse(libxl_device_vscsi_suse* vscsi_host)
+{
+ libxl__global_vscsi_list_suse = vscsi_host;
+}
+/* EOF libxl.so.4.4 ABI compat hack */
+
/*
* Local variables:
* mode: C
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1238,6 +1238,26 @@ libxl_device_vtpm *libxl_device_vtpm_lis
int libxl_device_vtpm_getinfo(libxl_ctx *ctx, uint32_t domid,
libxl_device_vtpm *vtpm, libxl_vtpminfo *vtpminfo);
+/* Virtual SCSI */
+int libxl_device_vscsi_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vscsi *vscsi,
+ const libxl_asyncop_how *ao_how)
+ LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vscsi_remove(libxl_ctx *ctx, uint32_t domid,
+ libxl_device_vscsi *vscsi,
+ const libxl_asyncop_how *ao_how)
+ LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vscsi_destroy(libxl_ctx *ctx, uint32_t domid,
+ libxl_device_vscsi *vscsi,
+ const libxl_asyncop_how *ao_how)
+ LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_vscsi *libxl_device_vscsi_list(libxl_ctx *ctx, uint32_t domid, int *num);
+int libxl_device_vscsi_getinfo(libxl_ctx *ctx,
+ uint32_t domid,
+ libxl_device_vscsi *vscsi_host,
+ libxl_vscsi_dev *vscsi_dev,
+ libxl_vscsiinfo *vscsiinfo);
+
/* Keyboard */
int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
const libxl_asyncop_how *ao_how)
@@ -1495,6 +1515,27 @@ int libxl_fd_set_nonblock(libxl_ctx *ctx
#include <libxl_event.h>
+/* libxl.so.4.4 ABI compatilibity hack - do not do this at home */
+
+/*
+ * LIBXL_HAVE_DEVICE_PVSCSI_SUSE
+ *
+ * If this is defined, set pvscsi devices through helpers
+ * libxl_get_vscsi_devices_suse and libxl_set_vscsi_devices_suse.
+ *
+ * If this is not defined, pvscsi is either unavailable or available through
+ * libxl_domain_config structure
+ */
+#define LIBXL_HAVE_DEVICE_PVSCSI_SUSE 1
+typedef struct {
+ libxl_device_vscsi* vscsi_devices;
+ int num_vscsi_devices;
+} libxl_device_vscsi_suse;
+
+libxl_device_vscsi_suse* libxl_get_vscsi_devices_suse(void);
+void libxl_set_vscsi_devices_suse(libxl_device_vscsi_suse* vscsi_host);
+/* EOF libxl.so.4.4 ABI compat hack */
+
#endif /* LIBXL_H */
/*
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1141,6 +1141,7 @@ static void domcreate_rebuild_done(libxl
libxl__multidev_begin(ao, &dcs->multidev);
dcs->multidev.callback = domcreate_launch_dm;
libxl__add_disks(egc, ao, domid, d_config, &dcs->multidev);
+ libxl__add_vscsis(egc, ao, domid, d_config, &dcs->multidev);
libxl__multidev_prepared(egc, &dcs->multidev, 0);
return;
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -541,6 +541,7 @@ void libxl__multidev_prepared(libxl__egc
* The following functions are defined:
* libxl__add_disks
* libxl__add_nics
+ * libxl__add_vscsis
* libxl__add_vtpms
*/
@@ -560,10 +561,32 @@ void libxl__multidev_prepared(libxl__egc
DEFINE_DEVICES_ADD(disk)
DEFINE_DEVICES_ADD(nic)
+// DEFINE_DEVICES_ADD(vscsi)
DEFINE_DEVICES_ADD(vtpm)
#undef DEFINE_DEVICES_ADD
+// to preserve libxl.so.4.4 ABI custom define libxl__add_vscsi
+void libxl__add_vscsis(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+ libxl_domain_config *d_config,
+ libxl__multidev *multidev)
+{
+ AO_GC;
+ int i;
+
+ libxl_device_vscsi *vhosts;
+ int num_vhosts;
+ libxl_device_vscsi_suse* vscsi_hosts_suse = libxl_get_vscsi_devices_suse();
+ if (!vscsi_hosts_suse)
+ return;
+ num_vhosts = vscsi_hosts_suse->num_vscsi_devices;
+ vhosts = vscsi_hosts_suse->vscsi_devices;
+ for (i = 0; i < num_vhosts; i++) {
+ libxl__ao_device *aodev = libxl__multidev_prepare(multidev);
+ libxl__device_vscsi_add(egc, domid, vhosts+i, aodev);
+ }
+}
+
/******************************************************************************/
int libxl__device_destroy(libxl__gc *gc, libxl__device *dev)
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1079,6 +1079,7 @@ _hidden int libxl__device_disk_setdefaul
_hidden int libxl__device_nic_setdefault(libxl__gc *gc, libxl_device_nic *nic,
uint32_t domid);
_hidden int libxl__device_vtpm_setdefault(libxl__gc *gc, libxl_device_vtpm *vtpm);
+_hidden int libxl__device_vscsi_setdefault(libxl__gc *gc, libxl_device_vscsi *vscsi);
_hidden int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb);
_hidden int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb);
_hidden int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci);
@@ -2390,6 +2391,10 @@ _hidden void libxl__device_vtpm_add(libx
libxl_device_vtpm *vtpm,
libxl__ao_device *aodev);
+_hidden void libxl__device_vscsi_add(libxl__egc *egc, uint32_t domid,
+ libxl_device_vscsi *vscsi,
+ libxl__ao_device *aodev);
+
/* Internal function to connect a vkb device */
_hidden int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
libxl_device_vkb *vkb);
@@ -3014,6 +3019,10 @@ _hidden void libxl__add_vtpms(libxl__egc
libxl_domain_config *d_config,
libxl__multidev *multidev);
+_hidden void libxl__add_vscsis(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+ libxl_domain_config *d_config,
+ libxl__multidev *multidev);
+
/*----- device model creation -----*/
/* First layer; wraps libxl__spawn_spawn. */
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -540,6 +540,26 @@ libxl_device_channel = Struct("device_ch
])),
])
+libxl_vscsi_dev = Struct("vscsi_dev", [
+ ("vscsi_dev_id", libxl_devid),
+ ("remove", bool),
+ ("p_hst", uint32),
+ ("p_chn", uint32),
+ ("p_tgt", uint32),
+ ("p_lun", uint32),
+ ("v_chn", uint32),
+ ("v_tgt", uint32),
+ ("v_lun", uint32),
+ ])
+
+libxl_device_vscsi = Struct("device_vscsi", [
+ ("backend_domid", libxl_domid),
+ ("devid", libxl_devid),
+ ("v_hst", uint32),
+ ("vscsi_devs", Array(libxl_vscsi_dev, "num_vscsi_devs")),
+ ("feature_host", bool),
+ ])
+
libxl_domain_config = Struct("domain_config", [
("c_info", libxl_domain_create_info),
("b_info", libxl_domain_build_info),
@@ -553,6 +573,8 @@ libxl_domain_config = Struct("domain_con
# a channel manifests as a console with a name,
# see docs/misc/channels.txt
("channels", Array(libxl_device_channel, "num_channels")),
+# preserve libxl.so.4.4 ABI
+# ("vscsis", Array(libxl_device_vscsi, "num_vscsis")),
("on_poweroff", libxl_action_on_shutdown),
("on_reboot", libxl_action_on_shutdown),
@@ -595,6 +617,28 @@ libxl_vtpminfo = Struct("vtpminfo", [
("uuid", libxl_uuid),
], dir=DIR_OUT)
+libxl_vscsiinfo = Struct("vscsiinfo", [
+ ("backend", string),
+ ("backend_id", uint32),
+ ("frontend", string),
+ ("frontend_id", uint32),
+ ("devid", libxl_devid),
+ ("p_hst", uint32),
+ ("p_chn", uint32),
+ ("p_tgt", uint32),
+ ("p_lun", uint32),
+ ("vscsi_dev_id", libxl_devid),
+ ("v_hst", uint32),
+ ("v_chn", uint32),
+ ("v_tgt", uint32),
+ ("v_lun", uint32),
+ ("feature_host", bool),
+ ("vscsi_host_state", integer),
+ ("vscsi_dev_state", integer),
+ ("evtch", integer),
+ ("rref", integer),
+ ], dir=DIR_OUT)
+
libxl_vcpuinfo = Struct("vcpuinfo", [
("vcpuid", uint32),
("cpu", uint32),
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -22,6 +22,7 @@ libxl__device_kind = Enumeration("device
(6, "VKBD"),
(7, "CONSOLE"),
(8, "VTPM"),
+ (9, "VSCSI"),
])
libxl__console_backend = Enumeration("console_backend", [
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -83,6 +83,9 @@ int main_channellist(int argc, char **ar
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);
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -17,6 +17,7 @@
#include "libxl_osdeps.h"
#include <stdio.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -34,6 +35,7 @@
#include <ctype.h>
#include <inttypes.h>
#include <limits.h>
+#include <dirent.h>
#include <xen/hvm/e820.h>
#include "libxl.h"
@@ -549,6 +551,122 @@ static void set_default_nic_values(libxl
}
}
+static char *vscsi_trim_string(char *s)
+{
+ unsigned int len;
+
+ while (isspace(*s))
+ s++;
+ len = strlen(s);
+ while (len-- > 1 && isspace(s[len]))
+ s[len] = '\0';
+ return s;
+}
+
+static void parse_vscsi_config(libxl_device_vscsi *vscsi_host,
+ libxl_vscsi_dev *vscsi_dev,
+ char *buf)
+{
+ char *pdev, *vdev, *fhost;
+ unsigned int hst, chn, tgt, lun;
+
+ libxl_device_vscsi_init(vscsi_host);
+ pdev = strtok(buf, ",");
+ vdev = strtok(NULL, ",");
+ fhost = strtok(NULL, ",");
+ if (!(pdev && vdev)) {
+ fprintf(stderr, "invalid vscsi= devspec: '%s'\n", buf);
+ exit(1);
+ }
+
+ pdev = vscsi_trim_string(pdev);
+ vdev = vscsi_trim_string(vdev);
+
+ if (strncmp(pdev, "/dev/", 5) == 0) {
+#ifdef __linux__
+ struct stat pdev_stat;
+ char pdev_sysfs_path[PATH_MAX];
+ const char *type;
+ int result = 0;
+ DIR *dirp;
+ struct dirent *de;
+
+ /* stat pdev to get device's sysfs entry */
+ if (stat (pdev, &pdev_stat) == -1) {
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', device not found or cannot be read\n", "pdev", pdev, buf);
+ exit(1);
+ }
+ if (S_ISBLK (pdev_stat.st_mode)) {
+ type = "block";
+ } else if (S_ISCHR (pdev_stat.st_mode)) {
+ type = "char";
+ } else {
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', not a valid block or char device\n", "pdev", pdev, buf);
+ exit(1);
+ }
+
+ /* get pdev scsi address - subdir of scsi_device sysfs entry */
+ snprintf(pdev_sysfs_path, sizeof(pdev_sysfs_path), "/sys/dev/%s/%u:%u/device/scsi_device",
+ type,
+ major(pdev_stat.st_rdev),
+ minor(pdev_stat.st_rdev));
+
+ dirp = opendir(pdev_sysfs_path);
+ if (!dirp) {
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', cannot find scsi device\n", "pdev", pdev, buf);
+ exit(1);
+ }
+
+ while ((de = readdir(dirp))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ if (sscanf(de->d_name, "%u:%u:%u:%u", &hst, &chn, &tgt, &lun) != 4) {
+ fprintf(stderr, "vscsi: ignoring unknown devspec '%s' for device '%s'\n",
+ de->d_name, pdev);
+ continue;
+ }
+ result = 1;
+ break;
+ }
+ closedir(dirp);
+
+ if (!result) {
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', cannot find scsi device in sysfs\n", "pdev", pdev, buf);
+ exit(1);
+ }
+#else
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', expecting hst:chn:tgt:lun\n", "pdev", pdev, buf);
+ exit(1);
+#endif
+ } else if (sscanf(pdev, "%u:%u:%u:%u", &hst, &chn, &tgt, &lun) != 4) {
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', expecting hst:chn:tgt:lun\n", "pdev", pdev, buf);
+ exit(1);
+ }
+ vscsi_dev->p_hst = hst;
+ vscsi_dev->p_chn = chn;
+ vscsi_dev->p_tgt = tgt;
+ vscsi_dev->p_lun = lun;
+
+ if (sscanf(vdev, "%u:%u:%u:%u", &hst, &chn, &tgt, &lun) != 4) {
+ fprintf(stderr, "vscsi: invalid %s '%s' in vscsi= devspec: '%s', expecting hst:chn:tgt:lun\n", "vdev", vdev, buf);
+ exit(1);
+ }
+ vscsi_host->v_hst = hst;
+ vscsi_dev->v_chn = chn;
+ vscsi_dev->v_tgt = tgt;
+ vscsi_dev->v_lun = lun;
+
+ if (fhost) {
+ fhost = vscsi_trim_string(fhost);
+ vscsi_host->feature_host = strcmp(fhost, "feature-host") == 0;
+ if (!vscsi_host->feature_host) {
+ fprintf(stderr, "vscsi: invalid option '%s' in vscsi= devspec: '%s', expecting %s\n", fhost, buf, "feature-host");
+ exit(1);
+ }
+ }
+}
+
static void split_string_into_string_list(const char *str,
const char *delim,
libxl_string_list *psl)
@@ -918,7 +1036,7 @@ static void parse_config_data(const char
const char *buf;
long l;
XLU_Config *config;
- XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms;
+ XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms, *vscsis;
XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian;
int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
int pci_power_mgmt = 0;
@@ -1421,6 +1539,66 @@ static void parse_config_data(const char
}
}
+ if (!xlu_cfg_get_list(config, "vscsi", &vscsis, 0, 0)) {
+ int cnt_vscsi_devs = 0;
+
+ /*
+ * to preserve libxl.so.4.4 ABI, do not store vscsis to d_config
+ * we are using extra array for that
+ */
+ libxl_device_vscsi* vscsi_hosts = calloc(1, sizeof(libxl_device_vscsi));
+ int num_vscsi_hosts = 0;
+
+ while ((buf = xlu_cfg_get_listitem (vscsis, cnt_vscsi_devs)) != NULL) {
+ libxl_vscsi_dev vscsi_dev = { };
+ libxl_device_vscsi vscsi_host = { };
+ libxl_device_vscsi *host;
+ char *tmp_buf;
+ int num_vscsis, host_found = 0;
+
+ /*
+ * #1: parse the devspec and place it in temporary host+dev part
+ * #2: find existing vscsi_host with number v_hst
+ * if found, append the vscsi_dev to this vscsi_host
+ * #3: otherwise, create new vscsi_host and append vscsi_dev
+ * Note: v_hst does not represent the index named "num_vscsis",
+ * it is a private index used just in the config file
+ */
+ tmp_buf = strdup(buf);
+ parse_vscsi_config(&vscsi_host, &vscsi_dev, tmp_buf);
+ free(tmp_buf);
+
+ if (num_vscsi_hosts) {
+ for (num_vscsis = 0; num_vscsis < num_vscsi_hosts; num_vscsis++) {
+ if (vscsi_hosts[num_vscsis].v_hst == vscsi_host.v_hst) {
+ host = vscsi_hosts + num_vscsis;
+ host->vscsi_devs = realloc(host->vscsi_devs, sizeof(libxl_vscsi_dev) * (host->num_vscsi_devs + 1));
+ vscsi_dev.vscsi_dev_id = host->num_vscsi_devs;
+ memcpy(host->vscsi_devs + host->num_vscsi_devs, &vscsi_dev, sizeof(vscsi_dev));
+ host->num_vscsi_devs++;
+ host_found = 1;
+ break;
+ }
+ }
+ }
+ if (!host_found || !num_vscsi_hosts) {
+ vscsi_hosts = realloc(vscsi_hosts, sizeof(libxl_device_vscsi) * (num_vscsi_hosts + 1));
+ vscsi_host.vscsi_devs = malloc(sizeof(libxl_vscsi_dev));
+ vscsi_dev.vscsi_dev_id = 0;
+ memcpy(vscsi_host.vscsi_devs, &vscsi_dev, sizeof(vscsi_dev));
+ vscsi_host.num_vscsi_devs++;
+ vscsi_host.devid = num_vscsi_hosts;
+ memcpy(vscsi_hosts + num_vscsi_hosts, &vscsi_host, sizeof(vscsi_host));
+ num_vscsi_hosts++;
+ }
+ cnt_vscsi_devs++;
+ }
+ libxl_device_vscsi_suse* vscsis_suse = calloc(1, sizeof(libxl_device_vscsi_suse));
+ vscsis_suse->vscsi_devices = vscsi_hosts;
+ vscsis_suse->num_vscsi_devices = num_vscsi_hosts;
+ libxl_set_vscsi_devices_suse(vscsis_suse);
+ }
+
if (!xlu_cfg_get_list(config, "vtpm", &vtpms, 0, 0)) {
d_config->num_vtpms = 0;
d_config->vtpms = NULL;
@@ -6511,6 +6689,256 @@ int main_blockdetach(int argc, char **ar
return rc;
}
+int main_vscsiattach(int argc, char **argv)
+{
+ int opt;
+ int num_hosts, i = 0, found_host = -1, res = 0;
+ libxl_vscsi_dev *vscsi_dev;
+ libxl_device_vscsi *vscsi_host, *vscsi_tmphst;
+ libxl_device_vscsi *vscsi_hosts_existing = NULL;
+ uint32_t domid;
+ char *tmp_buf, *feat_buf = NULL;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "scsi-attach", 1) {
+ /* No options */
+ }
+
+ if (argc < 4) {
+ 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 < 4) {
+ fprintf(stderr, "scsi-attach: 3 options required.\n");
+ return 1;
+ }
+ if (argc == 5) {
+ if (asprintf(&feat_buf, ",%s", argv[4]) < 0) {
+ perror("asprintf");
+ return 1;
+ }
+ }
+ if (asprintf(&tmp_buf, "%s,%s%s", argv[2], argv[3], feat_buf ?: "") < 0) {
+ perror("asprintf");
+ return 1;
+ }
+
+ vscsi_dev = calloc(1, sizeof(*vscsi_dev));
+ vscsi_host = calloc(1, sizeof(*vscsi_host));
+ if (!(vscsi_dev && vscsi_host)) {
+ fprintf(stderr, "%s ENOMEM\n", __func__);
+ res = 1;
+ goto vscsi_attach_out;
+ }
+ parse_vscsi_config(vscsi_host, vscsi_dev, tmp_buf);
+
+ /* look for existing vscsi_host for given domain */
+ vscsi_hosts_existing = libxl_device_vscsi_list(ctx, domid, &num_hosts);
+ if (vscsi_hosts_existing) {
+ for (i = 0; i < num_hosts; ++i) {
+ int j;
+ for (j = 0; j < vscsi_hosts_existing[i].num_vscsi_devs; j++) {
+ if (vscsi_hosts_existing[i].vscsi_devs[j].p_hst == vscsi_dev->p_hst &&
+ vscsi_hosts_existing[i].vscsi_devs[j].p_chn == vscsi_dev->p_chn &&
+ vscsi_hosts_existing[i].vscsi_devs[j].p_tgt == vscsi_dev->p_tgt &&
+ vscsi_hosts_existing[i].vscsi_devs[j].p_lun == vscsi_dev->p_lun) {
+ fprintf(stderr, "Host device '%u:%u:%u:%u' is already in use"
+ " by guest vscsi specification '%u:%u:%u:%u'.\n",
+ vscsi_dev->p_hst, vscsi_dev->p_chn, vscsi_dev->p_tgt, vscsi_dev->p_lun,
+ vscsi_hosts_existing[i].v_hst, vscsi_dev->v_chn, vscsi_dev->v_tgt, vscsi_dev->v_lun);
+ res = 1;
+ goto vscsi_attach_out;
+ }
+ }
+ if (vscsi_host->v_hst == vscsi_hosts_existing[i].v_hst) {
+ found_host = i;
+ break;
+ }
+ }
+ }
+ if (found_host == -1) {
+ vscsi_host->devid = i;
+ vscsi_host->vscsi_devs = vscsi_dev;
+ vscsi_host->num_vscsi_devs = 1;
+ vscsi_tmphst = vscsi_host;
+ } else {
+ /* look if the vdev address is not taken */
+ vscsi_tmphst = vscsi_hosts_existing + found_host;
+ for (i = 0; i < vscsi_tmphst->num_vscsi_devs; ++i) {
+ if (vscsi_tmphst->vscsi_devs[i].v_chn == vscsi_dev->v_chn &&
+ vscsi_tmphst->vscsi_devs[i].v_tgt == vscsi_dev->v_tgt &&
+ vscsi_tmphst->vscsi_devs[i].v_lun == vscsi_dev->v_lun) {
+ fprintf(stderr, "Target vscsi specification '%u:%u:%u:%u' is already taken\n",
+ vscsi_tmphst->v_hst, vscsi_dev->v_chn,
+ vscsi_dev->v_tgt, vscsi_dev->v_lun);
+ res = 1;
+ goto vscsi_attach_out;
+ }
+ }
+ vscsi_tmphst->vscsi_devs = realloc(vscsi_tmphst->vscsi_devs,
+ sizeof(libxl_vscsi_dev) *
+ (vscsi_tmphst->num_vscsi_devs + 1));
+ if (vscsi_tmphst->vscsi_devs == NULL) {
+ fprintf(stderr, "%s ENOMEM\n", __func__);
+ res = 1;
+ goto vscsi_attach_out;
+ }
+ vscsi_dev->vscsi_dev_id = vscsi_tmphst->num_vscsi_devs;
+ memcpy(vscsi_tmphst->vscsi_devs + vscsi_tmphst->num_vscsi_devs,
+ vscsi_dev, sizeof(*vscsi_dev));
+ vscsi_tmphst->num_vscsi_devs++;
+ }
+
+ if (dryrun_only) {
+ char* json = libxl_device_vscsi_to_json(ctx, vscsi_tmphst);
+ printf("vscsi: %s\n", json);
+ free(json);
+ if (ferror(stdout) || fflush(stdout)) { perror("stdout"); exit(-1); }
+ }
+ else if (libxl_device_vscsi_add(ctx, domid, vscsi_tmphst, 0)) {
+ fprintf(stderr, "libxl_device_vscsi_add failed.\n");
+ res = 1;
+ }
+
+vscsi_attach_out:
+ if (vscsi_hosts_existing) {
+ for (i = 0; i < num_hosts; ++i)
+ libxl_device_vscsi_dispose(vscsi_hosts_existing+i);
+ free(vscsi_hosts_existing);
+ }
+ free(vscsi_host);
+ free(vscsi_dev);
+ free(tmp_buf);
+ free(feat_buf);
+ return res;
+}
+
+int main_vscsilist(int argc, char **argv)
+{
+ int opt;
+ libxl_device_vscsi *vscsi_hosts;
+ libxl_vscsiinfo vscsiinfo;
+ int num_hosts, h, d;
+
+ SWITCH_FOREACH_OPT(opt, "", NULL, "scsi-list", 1) {
+ /* No options */
+ }
+ if (argc < 2) {
+ help("scsi-list");
+ return 1;
+ }
+ /* Idx BE state host p_hst v_hst state */
+ printf("%-3s %-3s %-5s %-5s %-10s %-10s %-5s\n",
+ "Idx", "BE", "state", "host", "phy-hctl", "vir-hctl", "devstate");
+ for (argv += optind, argc -= optind; argc > 0; --argc, ++argv) {
+ uint32_t domid;
+ if (libxl_domain_qualifier_to_domid(ctx, *argv, &domid) < 0) {
+ fprintf(stderr, "%s is an invalid domain identifier\n", *argv);
+ continue;
+ }
+ if (!(vscsi_hosts = libxl_device_vscsi_list(ctx, domid, &num_hosts))) {
+ continue;
+ }
+ for (h = 0; h < num_hosts; ++h) {
+ for (d = 0; d < vscsi_hosts[h].num_vscsi_devs; d++) {
+ if (!libxl_device_vscsi_getinfo(ctx, domid, &vscsi_hosts[h], &vscsi_hosts[h].vscsi_devs[d], &vscsiinfo)) {
+ char pdev[64], vdev[64];
+ snprintf(pdev, sizeof(pdev), "%u:%u:%u:%u",
+ vscsiinfo.p_hst, vscsiinfo.p_chn, vscsiinfo.p_tgt, vscsiinfo.p_lun);
+ snprintf(vdev, sizeof(vdev), "%u:%u:%u:%u",
+ vscsiinfo.v_hst, vscsiinfo.v_chn, vscsiinfo.v_tgt, vscsiinfo.v_lun);
+ /* Idx BE state Sta */
+ printf("%-3d %-3d %-5d %-5d %-10s %-10s %d\n",
+ vscsiinfo.devid,
+ vscsiinfo.backend_id,
+ vscsiinfo.vscsi_host_state,
+ vscsiinfo.backend_id,
+ pdev, vdev,
+ vscsiinfo.vscsi_dev_state);
+
+ libxl_vscsiinfo_dispose(&vscsiinfo);
+ }
+ }
+ libxl_device_vscsi_dispose(&vscsi_hosts[h]);
+ }
+ free(vscsi_hosts);
+ }
+ return 0;
+}
+
+int main_vscsidetach(int argc, char **argv)
+{
+ int opt;
+ libxl_vscsi_dev *vscsi_dev, *vd;
+ libxl_device_vscsi *vscsi_host, *vh;
+ libxl_device_vscsi *vscsi_hosts;
+ char *tmp_buf, *dom = argv[1], *vdev = argv[2];
+ uint32_t domid;
+ int num_hosts, h, d, found = 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;
+ }
+ vscsi_hosts = libxl_device_vscsi_list(ctx, domid, &num_hosts);
+ if (!vscsi_hosts)
+ return 0;
+
+ if (asprintf(&tmp_buf, "0:0:0:0,%s", vdev) < 0) {
+ perror("asprintf");
+ return 1;
+ }
+ vscsi_dev = calloc(1, sizeof(*vscsi_dev));
+ vscsi_host = calloc(1, sizeof(*vscsi_host));
+ if (!(vscsi_dev && vscsi_host)) {
+ fprintf(stderr, "%s ENOMEM\n", __func__);
+ goto done;
+ }
+ parse_vscsi_config(vscsi_host, vscsi_dev, tmp_buf);
+
+ for (h = 0; h < num_hosts; ++h) {
+ vh = &vscsi_hosts[h];
+ for (d = 0; !found && d < vh->num_vscsi_devs; d++) {
+#define CMP(member) (vd->member == vscsi_dev->member)
+ vd = &vh->vscsi_devs[d];
+ if (vh->v_hst == vscsi_host->v_hst && CMP(v_chn) && CMP(v_tgt) && CMP(v_lun)) {
+ if (vh->num_vscsi_devs > 1) {
+ vd->remove = true;
+ if (libxl_device_vscsi_add(ctx, domid, vh, 0)) {
+ fprintf(stderr, "libxl_device_vscsi_remove failed.\n");
+ goto done;
+ }
+ } else {
+ libxl_device_vscsi_remove(ctx, domid, vh, 0);
+ }
+ found = 1;
+ }
+#undef CMP
+ }
+ libxl_device_vscsi_dispose(vh);
+ }
+ if (!found)
+ fprintf(stderr, "%s(%u) vdev %s does not exist in domain %s\n", __func__, __LINE__, vdev, dom);
+done:
+ free(vscsi_hosts);
+ free(vscsi_host);
+ free(vscsi_dev);
+ free(tmp_buf);
+ return !found;
+}
+
int main_vtpmattach(int argc, char **argv)
{
int opt;
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -372,6 +372,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.",
+ "<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",