|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 4/4] libxl: add support for vscsi
Port pvscsi support from xend to libxl. See pvscsi.txt for details.
Outstanding work is listed in the TODO section.
Signed-off-by: Olaf Hering <olaf@xxxxxxxxx>
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
---
tools/libxl/Makefile | 1 +
tools/libxl/libxl.c | 172 ++++++++++++++++
tools/libxl/libxl.h | 29 +++
tools/libxl/libxl_create.c | 1 +
tools/libxl/libxl_device.c | 2 +
tools/libxl/libxl_freebsd.c | 8 +
tools/libxl/libxl_internal.h | 12 ++
tools/libxl/libxl_linux.c | 60 ++++++
tools/libxl/libxl_netbsd.c | 8 +
tools/libxl/libxl_types.idl | 49 +++++
tools/libxl/libxl_types_internal.idl | 1 +
tools/libxl/libxl_vscsi.c | 375 +++++++++++++++++++++++++++++++++++
tools/libxl/xl.h | 3 +
tools/libxl/xl_cmdimpl.c | 249 ++++++++++++++++++++++-
tools/libxl/xl_cmdtable.c | 15 ++
15 files changed, 984 insertions(+), 1 deletion(-)
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 7329521..9622d66 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -91,6 +91,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 \
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 088786e..73504b9 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1967,6 +1967,166 @@ static int libxl__resolve_domid(libxl__gc *gc, const
char *name,
}
/******************************************************************************/
+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);
+ libxl_ctx *ctx = libxl__gc_owner(gc);
+ flexarray_t *front;
+ flexarray_t *back;
+ libxl__device *device;
+ char *be_path;
+ unsigned int be_dirs = 0, rc, i;
+
+ if (vscsi->devid == -1) {
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ /* Prealloc key+value: 4 toplevel + 4 per device */
+ i = 2 * (4 + (4 * vscsi->num_vscsi_devs));
+ back = flexarray_make(gc, i, 1);
+ front = flexarray_make(gc, 2 * 2, 1);
+
+ GCNEW(device);
+ rc = libxl__device_from_vscsi(gc, domid, vscsi, device);
+ if ( rc != 0 ) goto out;
+
+ /* Check if backend device path is already present */
+ be_path = libxl__device_backend_path(gc, device);
+ if (!libxl__xs_directory(gc, XBT_NULL, be_path, &be_dirs) || !be_dirs) {
+ /* backend does not exist, create a new one */
+ 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;
+ /* Trigger removal, otherwise create new device */
+ if (be_dirs) {
+ unsigned int nb = 0;
+ /* Preserve existing device */
+ if (libxl__xs_directory(gc, XBT_NULL,
GCSPRINTF("%s/vscsi-devs/dev-%u", be_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-devname",
v->vscsi_dev_id), v->p_devname);
+ switch (v->pdev_type) {
+ case LIBXL_VSCSI_PDEV_TYPE_WWN:
+ flexarray_append_pair(back,
+ GCSPRINTF("vscsi-devs/dev-%u/p-dev",
v->vscsi_dev_id),
+ v->p_devname);
+ break;
+ case LIBXL_VSCSI_PDEV_TYPE_DEV:
+ case LIBXL_VSCSI_PDEV_TYPE_HCTL:
+ flexarray_append_pair(back,
+ GCSPRINTF("vscsi-devs/dev-%u/p-dev",
v->vscsi_dev_id),
+ GCSPRINTF("%u:%u:%u:%u", v->pdev.hst,
v->pdev.chn, v->pdev.tgt, v->pdev.lun));
+ break;
+ case LIBXL_VSCSI_PDEV_TYPE_INVALID:
+ default:
+ rc = ERROR_FAIL;
+ goto out;
+ }
+ flexarray_append_pair(back, GCSPRINTF("vscsi-devs/dev-%u/v-dev",
v->vscsi_dev_id),
+ GCSPRINTF("%u:%u:%u:%u", v->vdev.hst,
v->vdev.chn, v->vdev.tgt, v->vdev.lun));
+ flexarray_append_pair(back, GCSPRINTF("vscsi-devs/dev-%u/state",
v->vscsi_dev_id), "1");
+ }
+
+ aodev->dev = device;
+ /* Either create new host or reconfigure existing host */
+ if (be_dirs == 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);
+ rc = 0;
+ /* Done with new host */
+ goto out;
+ }
+
+ /* Only new devices, write them and do vscsi host reconfiguration */
+ xs_transaction_t t;
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ libxl__xs_writev(gc, t, be_path,
+ libxl__xs_kvs_of_flexarray(gc, back, back->count));
+ xs_write(ctx->xsh, t, GCSPRINTF("%s/state", be_path), "7", 2);
+ if (!xs_transaction_end(ctx->xsh, t, 0)) {
+ if (errno == EAGAIN)
+ goto retry_transaction;
+ LOGE(ERROR, "xs transaction failed");
+ rc = ERROR_FAIL;
+ goto out;
+ }
+ libxl__wait_for_backend(gc, be_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 *path, *val;
+ path = GCSPRINTF("%s/vscsi-devs/dev-%u/state", be_path,
v->vscsi_dev_id);
+ val = libxl__xs_read(gc, t, path);
+ if (val && strcmp(val, "6") == 0) {
+ path = GCSPRINTF("%s/vscsi-devs/dev-%u/state", be_path,
v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, path);
+ path = GCSPRINTF("%s/vscsi-devs/dev-%u/p-devname", be_path,
v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, path);
+ path = GCSPRINTF("%s/vscsi-devs/dev-%u/p-dev", be_path,
v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, path);
+ path = GCSPRINTF("%s/vscsi-devs/dev-%u/v-dev", be_path,
v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, path);
+ path = GCSPRINTF("%s/vscsi-devs/dev-%u", be_path,
v->vscsi_dev_id);
+ xs_rm(ctx->xsh, t, path);
+ } else {
+ LOGE(ERROR, "%s: %s has %s, expected 6", __func__, path, val);
+ }
+ }
+ }
+
+ if (!xs_transaction_end(ctx->xsh, t, 0)) {
+ if (errno == EAGAIN)
+ goto retry_transaction2;
+ LOGE(ERROR, "xs transaction failed");
+ rc = ERROR_FAIL;
+ goto out;
+ }
+ /* 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;
+}
+
int libxl__device_vtpm_setdefault(libxl__gc *gc, libxl_device_vtpm *vtpm)
{
int rc;
@@ -4111,6 +4271,8 @@ out:
* libxl_device_disk_destroy
* libxl_device_nic_remove
* libxl_device_nic_destroy
+ * libxl_device_vscsi_remove
+ * libxl_device_vscsi_destroy
* libxl_device_vtpm_remove
* libxl_device_vtpm_destroy
* libxl_device_vkb_remove
@@ -4155,6 +4317,10 @@ DEFINE_DEVICE_REMOVE(disk, destroy, 1)
DEFINE_DEVICE_REMOVE(nic, remove, 0)
DEFINE_DEVICE_REMOVE(nic, destroy, 1)
+/* vtpm */
+DEFINE_DEVICE_REMOVE(vscsi, remove, 0)
+DEFINE_DEVICE_REMOVE(vscsi, destroy, 1)
+
/* vkb */
DEFINE_DEVICE_REMOVE(vkb, remove, 0)
DEFINE_DEVICE_REMOVE(vkb, destroy, 1)
@@ -4209,6 +4375,9 @@ DEFINE_DEVICE_ADD(disk)
/* nic */
DEFINE_DEVICE_ADD(nic)
+/* vscsi */
+DEFINE_DEVICE_ADD(vscsi)
+
/* vtpm */
DEFINE_DEVICE_ADD(vtpm)
@@ -6654,6 +6823,9 @@ int libxl_retrieve_domain_configuration(libxl_ctx *ctx,
uint32_t domid,
MERGE(nic, nics, COMPARE_DEVID, {});
+ /* FIXME */
+ MERGE(vscsi, vscsis, COMPARE_DEVID, {});
+
MERGE(vtpm, vtpms, COMPARE_DEVID, {});
MERGE(pci, pcidevs, COMPARE_PCI, {});
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 6bbc52d..1ad52e3 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1224,6 +1224,35 @@ int libxl_device_channel_getinfo(libxl_ctx *ctx,
uint32_t domid,
libxl_device_channel *channel,
libxl_channelinfo *channelinfo);
+/* 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);
+void libxl_device_vscsi_append_dev(libxl_ctx *ctx, libxl_device_vscsi *hst,
+ libxl_vscsi_dev *dev);
+int libxl_device_vscsi_get_host(libxl_ctx *ctx,
+ uint32_t domid,
+ const char *cfg,
+ libxl_device_vscsi **vscsi_host);
+int libxl_device_vscsi_parse(libxl_ctx *ctx, const char *cfg,
+ libxl_device_vscsi *vscsi_host,
+ libxl_vscsi_dev *vscsi_dev);
+
/* 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 98687bd..5cacc30 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1136,6 +1136,7 @@ static void domcreate_rebuild_done(libxl__egc *egc,
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;
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 0f50d04..035a4b6 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -543,6 +543,7 @@ void libxl__multidev_prepared(libxl__egc *egc,
* The following functions are defined:
* libxl__add_disks
* libxl__add_nics
+ * libxl__add_vscsis
* libxl__add_vtpms
*/
@@ -562,6 +563,7 @@ void libxl__multidev_prepared(libxl__egc *egc,
DEFINE_DEVICES_ADD(disk)
DEFINE_DEVICES_ADD(nic)
+DEFINE_DEVICES_ADD(vscsi)
DEFINE_DEVICES_ADD(vtpm)
#undef DEFINE_DEVICES_ADD
diff --git a/tools/libxl/libxl_freebsd.c b/tools/libxl/libxl_freebsd.c
index e8b88b3..71bfae6 100644
--- a/tools/libxl/libxl_freebsd.c
+++ b/tools/libxl/libxl_freebsd.c
@@ -131,3 +131,11 @@ libxl_device_model_version
libxl__default_device_model(libxl__gc *gc)
{
return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
}
+
+int libxl_device_vscsi_parse_pdev(libxl__gc *gc, char *pdev, unsigned int *hst,
+ unsigned int *chn, unsigned int *tgt,
+ unsigned int *lun)
+{
+
+ return ERROR_NOPARAVIRT;
+}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 934465a..76f6056 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1794,6 +1794,10 @@ _hidden libxl__json_object *libxl__json_parse(libxl__gc
*gc_opt, const char *s);
_hidden int libxl__device_model_version_running(libxl__gc *gc, uint32_t domid);
/* Return the system-wide default device model */
_hidden libxl_device_model_version libxl__default_device_model(libxl__gc *gc);
+ /* Convert h:c:t:l string to int */
+_hidden int libxl_device_vscsi_parse_hctl(libxl__gc *gc, char *str,
libxl_vscsi_hctl *hctl);
+ /* Convert /dev/scsi to h:c:t:l */
+_hidden int libxl_device_vscsi_parse_pdev(libxl__gc *gc, char *pdev,
libxl_vscsi_hctl *hctl);
/* Check how executes hotplug script currently */
int libxl__hotplug_settings(libxl__gc *gc, xs_transaction_t t);
@@ -2386,6 +2390,10 @@ _hidden void libxl__device_nic_add(libxl__egc *egc,
uint32_t domid,
libxl_device_nic *nic,
libxl__ao_device *aodev);
+_hidden void libxl__device_vscsi_add(libxl__egc *egc, uint32_t domid,
+ libxl_device_vscsi *vscsi,
+ libxl__ao_device *aodev);
+
_hidden void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid,
libxl_device_vtpm *vtpm,
libxl__ao_device *aodev);
@@ -3005,6 +3013,10 @@ _hidden void libxl__add_nics(libxl__egc *egc, libxl__ao
*ao, uint32_t domid,
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);
+
_hidden void libxl__add_vtpms(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
libxl_domain_config *d_config,
libxl__multidev *multidev);
diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c
index b51930c..305948e 100644
--- a/tools/libxl/libxl_linux.c
+++ b/tools/libxl/libxl_linux.c
@@ -279,3 +279,63 @@ libxl_device_model_version
libxl__default_device_model(libxl__gc *gc)
{
return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
}
+
+int libxl_device_vscsi_parse_pdev(libxl__gc *gc, char *pdev, libxl_vscsi_hctl
*hctl)
+{
+ struct stat dentry;
+ char *sysfs;
+ 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(ERROR, "vscsi: %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(ERROR, "vscsi: %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 */
+ sysfs = GCSPRINTF("/sys/dev/%s/%u:%u/device/scsi_device", type,
+ major(dentry.st_rdev), minor(dentry.st_rdev));
+
+ dirp = opendir(sysfs);
+ if (!dirp) {
+ LOG(ERROR, "vscsi: %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 (libxl_device_vscsi_parse_hctl(gc, de->d_name, hctl))
+ continue;
+
+ found = 1;
+ break;
+ }
+ closedir(dirp);
+
+ if (!found) {
+ LOG(ERROR, "vscsi: %s, no h:c:t:l link in sysfs", pdev);
+ rc = ERROR_INVAL;
+ goto out;
+ }
+
+ rc = 0;
+out:
+ return rc;
+}
diff --git a/tools/libxl/libxl_netbsd.c b/tools/libxl/libxl_netbsd.c
index 898e160..b8972f0 100644
--- a/tools/libxl/libxl_netbsd.c
+++ b/tools/libxl/libxl_netbsd.c
@@ -95,3 +95,11 @@ libxl_device_model_version
libxl__default_device_model(libxl__gc *gc)
{
return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
}
+
+int libxl_device_vscsi_parse_pdev(libxl__gc *gc, char *pdev, unsigned int *hst,
+ unsigned int *chn, unsigned int *tgt,
+ unsigned int *lun)
+{
+
+ return ERROR_NOPARAVIRT;
+}
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 47af340..e56f231 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -542,6 +542,37 @@ libxl_device_channel = Struct("device_channel", [
])),
])
+libxl_vscsi_pdev_type = Enumeration("vscsi_pdev_type", [
+ (0, "INVALID"),
+ (1, "DEV"),
+ (2, "WWN"),
+ (3, "HCTL"),
+ ], init_val = "LIBXL_VSCSI_PDEV_TYPE_INVALID")
+
+libxl_vscsi_hctl = Struct("vscsi_hctl", [
+ ("hst", uint32),
+ ("chn", uint32),
+ ("tgt", uint32),
+ ("lun", uint32),
+ ])
+
+libxl_vscsi_dev = Struct("vscsi_dev", [
+ ("vscsi_dev_id", libxl_devid),
+ ("remove", bool),
+ ("p_devname", string),
+ ("pdev_type", libxl_vscsi_pdev_type),
+ ("pdev", libxl_vscsi_hctl),
+ ("vdev", libxl_vscsi_hctl),
+ ])
+
+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),
@@ -551,6 +582,7 @@ libxl_domain_config = Struct("domain_config", [
("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
("vfbs", Array(libxl_device_vfb, "num_vfbs")),
("vkbs", Array(libxl_device_vkb, "num_vkbs")),
+ ("vscsis", Array(libxl_device_vscsi, "num_vscsis")),
("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
# a channel manifests as a console with a name,
# see docs/misc/channels.txt
@@ -585,6 +617,23 @@ 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),
+ ("p_devname", string),
+ ("pdev", libxl_vscsi_hctl),
+ ("vdev", libxl_vscsi_hctl),
+ ("vscsi_dev_id", libxl_devid),
+ ("feature_host", bool),
+ ("vscsi_host_state", integer),
+ ("vscsi_dev_state", integer),
+ ("evtch", integer),
+ ("rref", 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 5e55685..84c44f5 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -22,6 +22,7 @@ libxl__device_kind = Enumeration("device_kind", [
(6, "VKBD"),
(7, "CONSOLE"),
(8, "VTPM"),
+ (9, "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 0000000..ab4cb5f
--- /dev/null
+++ b/tools/libxl/libxl_vscsi.c
@@ -0,0 +1,375 @@
+#include "libxl_osdeps.h" /* must come before any other headers */
+#include "libxl_internal.h"
+
+int libxl_device_vscsi_parse_hctl(libxl__gc *gc, char *str, libxl_vscsi_hctl
*hctl)
+{
+ unsigned int hst, chn, tgt, lun;
+
+ if (sscanf(str, "%u:%u:%u:%u", &hst, &chn, &tgt, &lun) != 4)
+ return ERROR_INVAL;
+
+ hctl->hst = hst;
+ hctl->chn = chn;
+ hctl->tgt = tgt;
+ hctl->lun = lun;
+ return 0;
+}
+
+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 bool vscsi_wwn_valid(const char *p)
+{
+ bool ret = true;
+ int i = 0;
+
+ for (i = 0; i < 16; i++, p++) {
+ if (*p >= '0' && *p <= '9')
+ continue;
+ if (*p >= 'a' && *p <= 'f')
+ continue;
+ if (*p >= 'A' && *p <= 'F')
+ continue;
+ ret = false;
+ break;
+ }
+ return ret;
+}
+
+int libxl_device_vscsi_parse(libxl_ctx *ctx, const char *cfg,
+ libxl_device_vscsi *new_host,
+ libxl_vscsi_dev *new_dev)
+{
+ GC_INIT(ctx);
+ int rc;
+ unsigned int lun;
+ char wwn[16 + 1], *buf, *pdev, *vdev, *fhost;
+
+ buf = libxl__strdup(gc, cfg);
+
+ pdev = strtok(buf, ",");
+ vdev = strtok(NULL, ",");
+ fhost = strtok(NULL, ",");
+ if (!(pdev && vdev)) {
+ LOG(ERROR, "invalid vscsi= devspec: '%s'\n", cfg);
+ rc = ERROR_INVAL;
+ goto out;
+ }
+
+ pdev = vscsi_trim_string(pdev);
+ vdev = vscsi_trim_string(vdev);
+
+ new_dev->pdev_type = LIBXL_VSCSI_PDEV_TYPE_INVALID;
+ if (strncmp(pdev, "/dev/", 5) == 0) {
+ if (libxl_device_vscsi_parse_pdev(gc, pdev, &new_dev->pdev) == 0)
+ new_dev->pdev_type = LIBXL_VSCSI_PDEV_TYPE_DEV;
+ } else if (strncmp(pdev, "naa.", 4) == 0) {
+ memset(wwn, 0, sizeof(wwn));
+ if (sscanf(pdev, "naa.%16c:%u", wwn, &lun) == 2 &&
vscsi_wwn_valid(wwn))
+ new_dev->pdev_type = LIBXL_VSCSI_PDEV_TYPE_WWN;
+ } else if (libxl_device_vscsi_parse_hctl(gc, pdev, &new_dev->pdev) == 0) {
+ new_dev->pdev_type = LIBXL_VSCSI_PDEV_TYPE_HCTL;
+ }
+
+ switch (new_dev->pdev_type) {
+ case LIBXL_VSCSI_PDEV_TYPE_WWN:
+ new_dev->pdev.lun = lun;
+ /* Fall through. */
+ case LIBXL_VSCSI_PDEV_TYPE_DEV:
+ case LIBXL_VSCSI_PDEV_TYPE_HCTL:
+ new_dev->p_devname = libxl__strdup(NOGC, pdev);
+ break;
+ case LIBXL_VSCSI_PDEV_TYPE_INVALID:
+ LOG(ERROR, "vscsi: invalid pdev '%s'", pdev);
+ rc = ERROR_INVAL;
+ goto out;
+ }
+
+
+ if (libxl_device_vscsi_parse_hctl(gc, vdev, &new_dev->vdev)) {
+ LOG(ERROR, "vscsi: invalid '%s', expecting hst:chn:tgt:lun", vdev);
+ rc = ERROR_INVAL;
+ goto out;
+ }
+
+ /* Record group index */
+ new_host->v_hst = new_dev->vdev.hst;
+
+ if (fhost) {
+ fhost = vscsi_trim_string(fhost);
+ new_host->feature_host = strcmp(fhost, "feature-host") == 0;
+ if (!new_host->feature_host) {
+ LOG(ERROR, "vscsi: invalid option '%s', expecting %s", fhost,
"feature-host");
+ rc = ERROR_INVAL;
+ goto out;
+ }
+ }
+ rc = 0;
+
+out:
+ GC_FREE;
+ return rc;
+}
+
+void libxl_device_vscsi_append_dev(libxl_ctx *ctx, libxl_device_vscsi *hst,
+ libxl_vscsi_dev *dev)
+{
+ GC_INIT(ctx);
+ hst->vscsi_devs = libxl__realloc(NOGC, hst->vscsi_devs,
+ sizeof(*dev) * (hst->num_vscsi_devs + 1));
+ libxl_vscsi_dev_init(hst->vscsi_devs + hst->num_vscsi_devs);
+ dev->vscsi_dev_id = hst->num_vscsi_devs;
+ libxl_vscsi_dev_copy(ctx, hst->vscsi_devs + hst->num_vscsi_devs, dev);
+ hst->num_vscsi_devs++;
+ GC_FREE;
+}
+
+int libxl_device_vscsi_get_host(libxl_ctx *ctx, uint32_t domid, const char
*cfg, libxl_device_vscsi **vscsi_host)
+{
+ GC_INIT(ctx);
+ libxl_vscsi_dev *new_dev = NULL;
+ libxl_device_vscsi *new_host, *vscsi_hosts = NULL, *tmp;
+ int rc, found_host = -1, i, j;
+ int num_hosts;
+
+ GCNEW(new_host);
+ libxl_device_vscsi_init(new_host);
+
+ GCNEW(new_dev);
+ libxl_vscsi_dev_init(new_dev);
+
+ if (libxl_device_vscsi_parse(ctx, cfg, new_host, new_dev)) {
+ rc = ERROR_INVAL;
+ goto out;
+ }
+
+ /* FIXME: foreach domain, because pdev is not multiplexed by backend */
+ /* FIXME: other device types do not have the multiplexing issue */
+ /* FIXME: pci can solve it by unbinding the native driver */
+
+ /* Look for existing vscsi_host for given domain */
+ vscsi_hosts = libxl_device_vscsi_list(ctx, domid, &num_hosts);
+ if (vscsi_hosts) {
+ for (i = 0; i < num_hosts; ++i) {
+ for (j = 0; j < vscsi_hosts[i].num_vscsi_devs; j++) {
+ if (vscsi_hosts[i].vscsi_devs[j].pdev.hst == new_dev->pdev.hst
&&
+ vscsi_hosts[i].vscsi_devs[j].pdev.chn == new_dev->pdev.chn
&&
+ vscsi_hosts[i].vscsi_devs[j].pdev.tgt == new_dev->pdev.tgt
&&
+ vscsi_hosts[i].vscsi_devs[j].pdev.lun ==
new_dev->pdev.lun) {
+ LOG(ERROR, "Host device '%u:%u:%u:%u' is already in use"
+ " by guest vscsi specification '%u:%u:%u:%u'.\n",
+ new_dev->pdev.hst, new_dev->pdev.chn,
new_dev->pdev.tgt, new_dev->pdev.lun,
+ new_dev->vdev.hst, new_dev->vdev.chn,
new_dev->vdev.tgt, new_dev->vdev.lun);
+ rc = ERROR_INVAL;
+ goto out;
+ }
+ }
+ if (vscsi_hosts[i].v_hst == new_host->v_hst) {
+ found_host = i;
+ break;
+ }
+ }
+ }
+
+ if (found_host == -1) {
+ /* Not found, create new host */
+ new_host->devid = 0;
+ tmp = new_host;
+ } else {
+ tmp = vscsi_hosts + found_host;
+
+ /* Check if the vdev address is already taken */
+ for (i = 0; i < tmp->num_vscsi_devs; ++i) {
+ if (tmp->vscsi_devs[i].vdev.chn == new_dev->vdev.chn &&
+ tmp->vscsi_devs[i].vdev.tgt == new_dev->vdev.tgt &&
+ tmp->vscsi_devs[i].vdev.lun == new_dev->vdev.lun) {
+ fprintf(stderr, "Target vscsi specification '%u:%u:%u:%u' is
already taken\n",
+ new_dev->vdev.hst, new_dev->vdev.chn,
new_dev->vdev.tgt, new_dev->vdev.lun);
+ rc = ERROR_INVAL;
+ goto out;
+ }
+ }
+ }
+
+ /* The caller gets a copy along with appended new_dev */
+ *vscsi_host = libxl__malloc(NOGC, sizeof(*new_host));
+ libxl_device_vscsi_init(*vscsi_host);
+ libxl_device_vscsi_copy(ctx, *vscsi_host, tmp);
+ libxl_device_vscsi_append_dev(ctx, *vscsi_host, new_dev);
+
+ rc = 0;
+
+out:
+ if (vscsi_hosts) {
+ for (i = 0; i < num_hosts; ++i){
+ libxl_device_vscsi_dispose(&vscsi_hosts[i]);
+ }
+ free(vscsi_hosts);
+ }
+ libxl_device_vscsi_dispose(new_host);
+ libxl_vscsi_dev_dispose(new_dev);
+ GC_FREE;
+ return rc;
+}
+
+libxl_device_vscsi *libxl_device_vscsi_list(libxl_ctx *ctx, uint32_t domid,
int *num)
+{
+ GC_INIT(ctx);
+ libxl_vscsi_dev *v_dev;
+ libxl_device_vscsi *v_hst, *vscsi_hosts = NULL;
+ char *fe_path, *tmp, *c, *p, *v;
+ char **dir, **devs_dir;
+ const char *devs_path, *be_path;
+ int r;
+ bool parsed_ok;
+ unsigned int ndirs = 0, ndevs_dirs = 0, i;
+ unsigned int vscsi_dev_id;
+
+ fe_path = libxl__sprintf(gc, "%s/device/vscsi", libxl__xs_get_dompath(gc,
domid));
+ dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs);
+ /* Nothing to do */
+ if (!(dir && ndirs))
+ goto out;
+
+ /* List of hosts to be returned to the caller */
+ vscsi_hosts = libxl__malloc(NOGC, ndirs * sizeof(*vscsi_hosts));
+
+ /* Fill each host */
+ for (v_hst = vscsi_hosts; v_hst < vscsi_hosts + ndirs; ++v_hst, ++dir) {
+ libxl_device_vscsi_init(v_hst);
+
+ v_hst->devid = atoi(*dir);
+
+ tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s/backend-id",
+ fe_path, *dir));
+ /* FIXME what if xenstore is broken? */
+ if (tmp)
+ v_hst->backend_domid = atoi(tmp);
+
+ be_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s/backend",
+ fe_path, *dir));
+ /* FIXME what if xenstore is broken? */
+ if (be_path) {
+ devs_path = libxl__sprintf(gc, "%s/vscsi-devs", be_path);
+ devs_dir = libxl__xs_directory(gc, XBT_NULL, devs_path,
&ndevs_dirs);
+ } else {
+ devs_dir = NULL;
+ }
+
+ if (devs_dir && ndevs_dirs) {
+ v_hst->vscsi_devs = libxl__malloc(NOGC, ndevs_dirs *
sizeof(*v_dev));
+ v_hst->num_vscsi_devs = ndevs_dirs;
+ /* Fill each device connected to the host */
+ for (i = 0; i < ndevs_dirs; i++, devs_dir++) {
+ v_dev = &v_hst->vscsi_devs[i];
+ libxl_vscsi_dev_init(v_dev);
+ parsed_ok = false;
+ r = sscanf(*devs_dir, "dev-%u", &vscsi_dev_id);
+ if (r == 1) {
+ c = libxl__xs_read(gc, XBT_NULL,
+
GCSPRINTF("%s/vscsi-devs/dev-%u/p-devname",
+ be_path, vscsi_dev_id));
+ p = libxl__xs_read(gc, XBT_NULL,
+
GCSPRINTF("%s/vscsi-devs/dev-%u/p-dev",
+ be_path, vscsi_dev_id));
+ v = libxl__xs_read(gc, XBT_NULL,
+
GCSPRINTF("%s/vscsi-devs/dev-%u/v-dev",
+ be_path, vscsi_dev_id));
+ if (c && p && v) {
+ v_dev->p_devname = libxl__strdup(NOGC, c);
+ if (libxl_device_vscsi_parse_hctl(gc, p, &v_dev->pdev)
== 0 &&
+ libxl_device_vscsi_parse_hctl(gc, v, &v_dev->vdev)
== 0)
+ parsed_ok = true;
+ v_dev->vscsi_dev_id = vscsi_dev_id;
+ v_hst->v_hst = v_dev->vdev.hst;
+ }
+ }
+
+ if (!parsed_ok) {
+ /* FIXME what if xenstore is broken? */
+ LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "%s/scsi-devs/%s failed
to parse", be_path, *devs_dir);
+ continue;
+ }
+ }
+ }
+ }
+
+out:
+ *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 = ERROR_FAIL;
+
+ libxl_vscsiinfo_init(vscsiinfo);
+ dompath = libxl__xs_get_dompath(gc, domid);
+ vscsiinfo->devid = vscsi_host->devid;
+ libxl_vscsi_hctl_copy(ctx, &vscsiinfo->pdev, &vscsi_dev->pdev);
+ libxl_vscsi_hctl_copy(ctx, &vscsiinfo->vdev, &vscsi_dev->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->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;
+
+ rc = 0;
+out:
+ GC_FREE;
+ return rc;
+}
+
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 5bc138c..5c82688 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -83,6 +83,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 5c40e84..da5d95b 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -985,7 +985,7 @@ static void parse_config_data(const char *config_source,
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;
@@ -1488,6 +1488,59 @@ static void parse_config_data(const char *config_source,
}
}
+ if (!xlu_cfg_get_list(config, "vscsi", &vscsis, 0, 0)) {
+ int num_vscsi_items = 0;
+ d_config->num_vscsis = 0;
+ d_config->vscsis = NULL;
+ while ((buf = xlu_cfg_get_listitem (vscsis, num_vscsi_items)) != NULL)
{
+ libxl_vscsi_dev v_dev = { };
+ libxl_device_vscsi *tmp, v_hst = { };
+ bool hst_found = false;
+
+ /*
+ * #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
+ */
+ libxl_device_vscsi_init(&v_hst);
+ libxl_vscsi_dev_init(&v_dev);
+
+ if (libxl_device_vscsi_parse(ctx, buf, &v_hst, &v_dev))
+ exit (-1);
+
+ if (d_config->num_vscsis) {
+ for (i = 0; i < d_config->num_vscsis; i++) {
+ if (d_config->vscsis[i].v_hst == v_hst.v_hst) {
+ tmp = &d_config->vscsis[i];
+ libxl_device_vscsi_append_dev(ctx, tmp, &v_dev);
+ hst_found = true;
+ break;
+ }
+ }
+ }
+
+ if (!hst_found || !d_config->num_vscsis) {
+ d_config->vscsis = realloc(d_config->vscsis, sizeof(v_hst) *
(d_config->num_vscsis + 1));
+ tmp = &d_config->vscsis[d_config->num_vscsis];
+ libxl_device_vscsi_init(tmp);
+
+ v_hst.devid = d_config->num_vscsis;
+ libxl_device_vscsi_copy(ctx, tmp, &v_hst);
+
+ libxl_device_vscsi_append_dev(ctx, tmp, &v_dev);
+
+ d_config->num_vscsis++;
+ }
+
+ libxl_vscsi_dev_dispose(&v_dev);
+ libxl_device_vscsi_dispose(&v_hst);
+ num_vscsi_items++;
+ }
+ }
+
if (!xlu_cfg_get_list(config, "vtpm", &vtpms, 0, 0)) {
d_config->num_vtpms = 0;
d_config->vtpms = NULL;
@@ -6439,6 +6492,200 @@ int main_blockdetach(int argc, char **argv)
return rc;
}
+int main_vscsiattach(int argc, char **argv)
+{
+ uint32_t domid;
+ int opt, rc;
+ libxl_device_vscsi *vscsi_host = NULL;
+ char *cfg = NULL, *feat_buf = NULL;
+
+ 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(&cfg, "%s,%s%s", argv[2], argv[3], feat_buf ?: "") < 0) {
+ perror("asprintf");
+ rc = 1;
+ goto out;;
+ }
+
+ /* Parse config string and store result */
+ rc = libxl_device_vscsi_get_host(ctx, domid, cfg, &vscsi_host);
+ if (rc < 0)
+ goto out;
+
+ if (dryrun_only) {
+ char *json = libxl_device_vscsi_to_json(ctx, vscsi_host);
+ 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 (libxl_device_vscsi_add(ctx, domid, vscsi_host, NULL)) {
+ fprintf(stderr, "libxl_device_vscsi_add failed.\n");
+ rc = 1;
+ goto out;
+ }
+
+ rc = 0;
+out:
+ if (vscsi_host)
+ libxl_device_vscsi_dispose(vscsi_host);
+ free(vscsi_host);
+ free(cfg);
+ free(feat_buf);
+ return rc;
+}
+
+int main_vscsilist(int argc, char **argv)
+{
+ int opt;
+ uint32_t domid;
+ 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) {
+ 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.pdev.hst, vscsiinfo.pdev.chn,
vscsiinfo.pdev.tgt, vscsiinfo.pdev.lun);
+ snprintf(vdev, sizeof(vdev), "%u:%u:%u:%u",
+ vscsiinfo.vdev.hst, vscsiinfo.vdev.chn,
vscsiinfo.vdev.tgt, vscsiinfo.vdev.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 v_dev = { }, *vd;
+ libxl_device_vscsi v_hst = { }, *vh;
+ libxl_device_vscsi *vscsi_hosts;
+ char *tmp = NULL, *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;
+
+ /* Create a dummy cfg */
+ if (asprintf(&tmp, "0:0:0:0,%s", vdev) < 0) {
+ perror("asprintf");
+ goto done;
+ }
+
+ libxl_vscsi_dev_init(&v_dev);
+ libxl_device_vscsi_init(&v_hst);
+ if (libxl_device_vscsi_parse(ctx, tmp, &v_hst, &v_dev))
+ goto done;
+
+ 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->vdev.member == v_dev.vdev.member)
+ vd = &vh->vscsi_devs[d];
+ if (CMP(hst) && CMP(chn) && CMP(tgt) && CMP(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
+ }
+ }
+ if (!found)
+ fprintf(stderr, "%s(%u) vdev %s does not exist in domain %s\n",
__func__, __LINE__, vdev, dom);
+done:
+ if (vscsi_hosts) {
+ for (h = 0; h < num_hosts; ++h)
+ libxl_device_vscsi_dispose(&vscsi_hosts[h]);
+ free(vscsi_hosts);
+ }
+ free(tmp);
+ return !found;
+}
+
int main_vtpmattach(int argc, char **argv)
{
int opt;
diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
index 22ab63b..54b7a3a 100644
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -365,6 +365,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@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |