Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
xen.2142
libxl.pvscsi.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libxl.pvscsi.patch of Package xen.2142
* 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 Index: xen-4.5.2-testing/docs/man/xl.cfg.pod.5 =================================================================== --- xen-4.5.2-testing.orig/docs/man/xl.cfg.pod.5 +++ xen-4.5.2-testing/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 Index: xen-4.5.2-testing/docs/man/xl.pod.1 =================================================================== --- xen-4.5.2-testing.orig/docs/man/xl.pod.1 +++ xen-4.5.2-testing/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 Index: xen-4.5.2-testing/tools/libxl/libxl.c =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl.c +++ xen-4.5.2-testing/tools/libxl/libxl.c @@ -2324,6 +2324,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; +} /******************************************************************************/ @@ -4199,6 +4466,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, \ @@ -4254,6 +4523,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 /******************************************************************************/ @@ -4263,6 +4536,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) \ @@ -4294,6 +4568,9 @@ DEFINE_DEVICE_ADD(nic) /* vtpm */ DEFINE_DEVICE_ADD(vtpm) +/* vscsi */ +DEFINE_DEVICE_ADD(vscsi) + #undef DEFINE_DEVICE_ADD /******************************************************************************/ @@ -6836,6 +7113,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 Index: xen-4.5.2-testing/tools/libxl/libxl.h =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl.h +++ xen-4.5.2-testing/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 */ /* Index: xen-4.5.2-testing/tools/libxl/libxl_create.c =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl_create.c +++ xen-4.5.2-testing/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; Index: xen-4.5.2-testing/tools/libxl/libxl_device.c =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl_device.c +++ xen-4.5.2-testing/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) Index: xen-4.5.2-testing/tools/libxl/libxl_internal.h =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl_internal.h +++ xen-4.5.2-testing/tools/libxl/libxl_internal.h @@ -1094,6 +1094,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); @@ -2405,6 +2406,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); @@ -3029,6 +3034,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. */ Index: xen-4.5.2-testing/tools/libxl/libxl_types.idl =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl_types.idl +++ xen-4.5.2-testing/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), Index: xen-4.5.2-testing/tools/libxl/libxl_types_internal.idl =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/libxl_types_internal.idl +++ xen-4.5.2-testing/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", [ Index: xen-4.5.2-testing/tools/libxl/xl.h =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/xl.h +++ xen-4.5.2-testing/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); Index: xen-4.5.2-testing/tools/libxl/xl_cmdimpl.c =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/xl_cmdimpl.c +++ xen-4.5.2-testing/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; Index: xen-4.5.2-testing/tools/libxl/xl_cmdtable.c =================================================================== --- xen-4.5.2-testing.orig/tools/libxl/xl_cmdtable.c +++ xen-4.5.2-testing/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",
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor