[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] Refactor ESX storage driver and add iSCSI support



The patch refactors the current ESX storage driver due to following reasons:

1. Given most of the public APIs exposed by the storage driver in Libvirt
   remains same, ESX storage driver should not implement logic specific
   for only one supported format (current implementation only supports VMFS).
2. Decoupling interface from specific storage implementation gives us an
   extensible design to hook implementation for other supported storage
   formats.

This patch refactors the current driver to implement it as a facade pattern i.e.
the driver exposes all the public libvirt APIs, but uses backend drivers to get
the required task done. The backend drivers provide implementation specific to
the type of storage device.

File changes:
------------------
 esx_storage_driver.c ----> esx_storage_driver.c (base storage driver)
                      |
                      |---> esx_storage_backend_vmfs.c (VMFS backend)
                      |
                      |---> esx_storage_backend_iscsi.c (iSCSI backend)

The patch adds the backend driver to support iSCSI format storage pools
and volumes for ESX host. The mapping of ESX iSCSI specifics to Libvirt
is as follows:

1. ESX static iSCSI target <------> Libvirt Storage Pools
2. ESX iSCSI LUNs          <------> Libvirt Storage Volumes.

The above understanding is based on http://libvirt.org/storage.html.

The operation supported on iSCSI pools includes:

1. List storage pools & volumes.
2. Get xml descriptor operaion on pools & volumes.
3. Lookup operation on pools & volumes by name, uuid and path (if applicable).

iSCSI pools does not support operations such as: Create / remove pools
and volumes
---
 src/Makefile.am                     |   16 +-
 src/esx/esx_driver.c                |    4 +-
 src/esx/esx_storage_backend_iscsi.c |  794 +++++++++++++++++++
 src/esx/esx_storage_backend_iscsi.h |   31 +
 src/esx/esx_storage_backend_vmfs.c  | 1471 +++++++++++++++++++++++++++++++++++
 src/esx/esx_storage_backend_vmfs.h  |   31 +
 src/esx/esx_storage_driver.c        | 1303 +++++--------------------------
 src/esx/esx_vi.c                    |  341 +++++++-
 src/esx/esx_vi.h                    |   21 +-
 src/esx/esx_vi_generator.input      |  308 +++++++-
 src/esx/esx_vi_generator.py         |   19 +
 11 files changed, 3218 insertions(+), 1121 deletions(-)
 create mode 100644 src/esx/esx_storage_backend_iscsi.c
 create mode 100644 src/esx/esx_storage_backend_iscsi.h
 create mode 100644 src/esx/esx_storage_backend_vmfs.c
 create mode 100644 src/esx/esx_storage_backend_vmfs.h

diff --git a/src/Makefile.am b/src/Makefile.am
index d35edd6..8f58a8a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -475,13 +475,15 @@ UML_DRIVER_SOURCES =						\
 		uml/uml_conf.c uml/uml_conf.h			\
 		uml/uml_driver.c uml/uml_driver.h
 
-ESX_DRIVER_SOURCES =							\
-		esx/esx_private.h					\
-		esx/esx_driver.c esx/esx_driver.h			\
-		esx/esx_interface_driver.c esx/esx_interface_driver.h	\
-		esx/esx_network_driver.c esx/esx_network_driver.h	\
-		esx/esx_storage_driver.c esx/esx_storage_driver.h	\
-		esx/esx_device_monitor.c esx/esx_device_monitor.h	\
+ESX_DRIVER_SOURCES =						\
+		esx/esx_private.h						\
+		esx/esx_driver.c esx/esx_driver.h		\
+		esx/esx_interface_driver.c esx/esx_interface_driver.h		\
+		esx/esx_network_driver.c esx/esx_network_driver.h		\
+		esx/esx_storage_driver.c esx/esx_storage_driver.h		\
+		esx/esx_storage_backend_vmfs.c esx/esx_storage_backend_vmfs.h   \
+		esx/esx_storage_backend_iscsi.c esx/esx_storage_backend_iscsi.h	\
+		esx/esx_device_monitor.c esx/esx_device_monitor.h		\
 		esx/esx_secret_driver.c esx/esx_secret_driver.h		\
 		esx/esx_nwfilter_driver.c esx/esx_nwfilter_driver.h	\
 		esx/esx_util.c esx/esx_util.h				\
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 72a7acc..359de53 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -162,7 +162,7 @@ esxParseVMXFileName(const char *fileName, void *opaque)
             datastoreName = NULL;
 
             if (esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
-                                               &hostMount) < 0 ||
+                  &hostMount, esxVI_Occurrence_RequiredItem) < 0 ||
                 esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
                                      esxVI_Occurrence_RequiredItem) < 0) {
                 goto cleanup;
@@ -306,7 +306,7 @@ esxFormatVMXFileName(const char *fileName, void *opaque)
         if (esxVI_LookupDatastoreByName(data->ctx, datastoreName, NULL, &datastore,
                                         esxVI_Occurrence_RequiredItem) < 0 ||
             esxVI_LookupDatastoreHostMount(data->ctx, datastore->obj,
-                                           &hostMount) < 0) {
+                &hostMount, esxVI_Occurrence_RequiredItem) < 0) {
             goto cleanup;
         }
 
diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c
new file mode 100644
index 0000000..4f79a0f
--- /dev/null
+++ b/src/esx/esx_storage_backend_iscsi.c
@@ -0,0 +1,794 @@
+/*
+ * esx_storage_backend_iscsi.c: ESX storage backend for iSCSI handling
+ *
+ * Copyright (C) 2007-2008, 2010-2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Ata E Husain Bohra (ata husain hotmail com)
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "internal.h"
+#include "md5.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+
+#include "storage_conf.h"
+#include "storage_file.h"
+#include "esx_private.h"
+#include "esx_vi.h"
+#include "esx_vi_methods.h"
+#include "esx_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+/*
+ * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore,
+ * verify that UUID and MD5 sum match in size, because we rely on that.
+ */
+verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+
+
+
+static int
+esxStorageBackendISCSINumberOfStoragePools(virConnectPtr conn)
+{
+    int count = 0;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+    bool success = false;
+
+    if (esxVI_LookupHostInternetScsiHba(
+          priv->primary, &hostInternetScsiHba) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Unable to obtain iSCSI adapter"));
+        goto cleanup;
+    }
+
+    if (hostInternetScsiHba == NULL) {
+        /* iSCSI adapter may not be enabled for this host */
+        return 0;
+    }
+
+    /**
+     * ESX has two kind of targets:
+     * 1. staticIscsiTargets
+     * 2. dynamicIscsiTargets
+     * For each dynamic target if its reachable a static target is added.
+     * return iSCSI names for all static targets to avoid duplicate names.
+     */
+    if (hostInternetScsiHba->configuredStaticTarget) {
+        const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+        for (target = hostInternetScsiHba->configuredStaticTarget;
+             target != NULL; target = target->_next) {
+            ++count;
+        }
+    }
+
+    success = true;
+
+cleanup:
+
+    esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+    return success ? count : -1;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIListStoragePools(virConnectPtr conn,
+                                       char **const names,
+                                       const int maxnames)
+{
+    int count = 0;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+    bool success = false;
+    int i = 0;
+
+    if (maxnames ==0) {
+        return 0;
+    }
+
+    if (esxVI_LookupHostInternetScsiHba(
+          priv->primary, &hostInternetScsiHba) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Unable to obtain iSCSI adapter"));
+        goto cleanup;
+    }
+
+    if (hostInternetScsiHba == NULL) {
+        /* iSCSI adapter may not be enabled for this host */
+        return 0;
+    }
+
+    /**
+     * ESX has two kind of targets:
+     * 1. staticIscsiTargets
+     * 2. dynamicIscsiTargets
+     * For each dynamic target if its reachable a static target is added.
+     * return iSCSI names for all static targets to avoid duplicate names.
+     */
+    if (hostInternetScsiHba->configuredStaticTarget) {
+        const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+        for (target = hostInternetScsiHba->configuredStaticTarget;
+          target != NULL && count < maxnames;
+          target = target->_next, ++count) {
+            names[count] = strdup(target->iScsiName);
+
+            if (names[count] == NULL) {
+                virReportOOMError();
+                goto cleanup;
+            }
+        }
+    }
+
+    success = true;
+
+cleanup:
+    if (! success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+        count = -1;
+    }
+
+    esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+    return success ? count : -1;
+}
+
+
+
+static virStoragePoolPtr
+esxStorageBackendISCSIPoolLookupByName(virConnectPtr conn,
+                                       const char *name)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+    virStoragePoolPtr pool = NULL;
+
+    if (esxVI_LookupHostInternetScsiHbaStaticTargetByName(
+          priv->primary, name, &target, esxVI_Occurrence_OptionalItem) < 0) {
+        goto cleanup;
+    }
+
+    /**
+     * HostInternetScsiHbaStaticTarget does not provide a uuid field,
+     * but iSsiName (or widely known as IQN) is unique across the multiple
+     * hosts, using it to compute key
+     */
+
+    md5_buffer(target->iScsiName, strlen(target->iScsiName), md5);
+
+    pool = virGetStoragePool(conn, name, md5);
+
+ cleanup:
+
+    esxVI_HostInternetScsiHbaStaticTarget_Free(&target);
+
+    return pool;
+
+}
+
+
+
+static virStoragePoolPtr
+esxStorageBackendISCSIPoolLookupByUUID(virConnectPtr conn,
+                                       const unsigned char *uuid)
+{
+    virStoragePoolPtr pool = NULL;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+    const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+
+    if (esxVI_LookupHostInternetScsiHba(
+          priv->primary, &hostInternetScsiHba) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Unable to obtain iSCSI adapter"));
+        goto cleanup;
+    }
+
+    if (hostInternetScsiHba == NULL) {
+        /* iSCSI adapter may not be enabled for this host */
+        return NULL;
+    }
+
+    if (hostInternetScsiHba->configuredStaticTarget) {
+        for (target = hostInternetScsiHba->configuredStaticTarget;
+          target != NULL; target = target->_next) {
+            md5_buffer(target->iScsiName, strlen(target->iScsiName), md5);
+
+            if (memcmp(uuid, md5, VIR_UUID_STRING_BUFLEN) == 0) {
+                break;
+            }
+        }
+    }
+
+    if (target == NULL) {
+        /* pool not found */
+        goto cleanup;
+    }
+
+    pool = virGetStoragePool(conn, target->iScsiName, md5);
+
+ cleanup:
+    esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+    return pool;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIPoolRefresh(virStoragePoolPtr pool,
+                                  unsigned int flags)
+{
+    int result = -1;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_ManagedObjectReference *hostStorageSystem = NULL;
+    esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_String *propertyNameList = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+          "configManager.storageSystem\0") < 0 ||
+        esxVI_LookupHostSystemProperties(priv->primary,
+            propertyNameList, &hostSystem) < 0 ||
+        esxVI_GetManagedObjectReference(hostSystem,
+            "configManager.storageSystem", &hostStorageSystem,
+            esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_LookupHostInternetScsiHba(
+            priv->primary, &hostInternetScsiHba) < 0) {
+        goto cleanup;
+    }
+
+     /**
+      * ESX does not allow rescan on a particular target,
+      * rescan all the static targets
+     */
+    if (esxVI_RescanHba(priv->primary, hostStorageSystem,
+                        hostInternetScsiHba->device) < 0) {
+        goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ManagedObjectReference_Free(&hostStorageSystem);
+    esxVI_ObjectContent_Free(&hostSystem);
+    esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+    return result;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIPoolGetInfo(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+                                  virStoragePoolInfoPtr info)
+{
+    /* these fields are not valid for iSCSI pool */
+    info->allocation = info->capacity = info->available = 0;
+    info->state = esxVI_Boolean_True;
+
+    return 0;
+}
+
+
+
+static char *
+esxStorageBackendISCSIPoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+    char *xml = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+    const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+    virStoragePoolDef def;
+
+    virCheckFlags(0, NULL);
+
+    memset(&def, 0, sizeof(def));
+
+    if (esxVI_LookupHostInternetScsiHba(priv->primary, &hostInternetScsiHba)) {
+        goto cleanup;
+    }
+
+    if (hostInternetScsiHba->configuredStaticTarget) {
+        for (target = hostInternetScsiHba->configuredStaticTarget;
+             target != NULL; target = target->_next) {
+            if (STREQ(target->iScsiName, pool->name)) {
+                break;
+            }
+        }
+    }
+
+    if (target == NULL) {
+        goto cleanup;
+    }
+
+    def.name = pool->name;
+    memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+    def.type = VIR_STORAGE_POOL_ISCSI;
+
+    def.source.initiator.iqn = target->iScsiName;
+
+    def.source.nhost = 1;
+    if (VIR_ALLOC_N(def.source.hosts, def.source.nhost) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def.source.hosts[0].name = target->address;
+    if (target->port) {
+        def.source.hosts[0].port = target->port->value;
+    }
+
+    /* TODO: add CHAP authentication params */
+
+    xml = virStoragePoolDefFormat(&def);
+
+  cleanup:
+
+    VIR_FREE(def.source.hosts);
+    esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+    return xml;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIPoolNumberOfStorageVolumes(virStoragePoolPtr pool)
+{
+    int  count = 0;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL;
+    const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = NULL;
+    bool success = false;
+
+    if (esxVI_LookupHostScsiTopologyLunListByTargetName(
+          priv->primary, pool->name, &hostScsiTopologyLunList) < 0) {
+        goto cleanup;
+    }
+
+    for (hostScsiTopologyLun = hostScsiTopologyLunList ;
+         hostScsiTopologyLun != NULL;
+         hostScsiTopologyLun = hostScsiTopologyLun->_next) {
+        ++count;
+    }
+
+    success = true;
+
+  cleanup:
+
+    esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList);
+
+    return success ? count : -1;
+
+}
+
+
+static int
+esxStorageBackendISCSIPoolListStorageVolumes(virStoragePoolPtr pool,
+                                             char **const names,
+                                             int maxnames)
+{
+    int  count = 0;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_HostScsiTopologyLun *hostScsiTopologyLunList = NULL;
+    const esxVI_HostScsiTopologyLun *hostScsiTopologyLun = NULL;
+    esxVI_ScsiLun *scsiLunList = NULL;
+    const esxVI_ScsiLun *scsiLun = NULL;
+    bool success = false;
+    int i = 0;
+
+    if (esxVI_LookupHostScsiTopologyLunListByTargetName(
+          priv->primary, pool->name, &hostScsiTopologyLunList) < 0) {
+        goto cleanup;
+    }
+
+    if (hostScsiTopologyLunList == NULL) {
+        /* iSCSI adapter may not be enabled on ESX host */
+        return 0;
+    }
+
+    if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+        goto cleanup;
+    }
+
+    /* O^2 but still faster than hash given N is not that large */
+    for (scsiLun = scsiLunList; scsiLun != NULL && count < maxnames;
+         scsiLun = scsiLun->_next) {
+        for (hostScsiTopologyLun = hostScsiTopologyLunList;
+             hostScsiTopologyLun != NULL && count < maxnames;
+             hostScsiTopologyLun = hostScsiTopologyLun->_next) {
+            if (STREQ(hostScsiTopologyLun->scsiLun, scsiLun->key)) {
+                names[count] = strdup(scsiLun->deviceName);
+
+                if (names[count] == NULL) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+                ++count;
+            }
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (! success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+        count = -1;
+    }
+
+    esxVI_HostScsiTopologyLun_Free(&hostScsiTopologyLunList);
+    esxVI_ScsiLun_Free(&scsiLunList);
+
+    return count;
+}
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeLookupByName(virStoragePoolPtr pool,
+                                         const char *name)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_ScsiLun *scsiLunList = NULL;
+    const esxVI_ScsiLun *scsiLun = NULL;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+    if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+        goto cleanup;
+    }
+
+    for (scsiLun = scsiLunList; scsiLun != NULL;
+         scsiLun = scsiLun->_next) {
+        if (STREQ(scsiLun->deviceName, name)) {
+            /**
+             * ScsiLun provides an UUID field that is unique accross
+             * multiple servers. But this field length is ~55 characters
+             * compute MD5 hash to transform it to an acceptable
+             * libvirt format
+             */
+            md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5);
+
+            virUUIDFormat(md5, uuid_string);
+
+            /**
+             * ScsiLun provides displayName and canonicalName but both are
+             * optional and its observed that they can be NULL, using
+             * deviceName to create volume.
+             */
+            volume = virGetStorageVol(pool->conn, pool->name, name, uuid_string);
+            break;
+        }
+    }
+
+  cleanup:
+
+    esxVI_ScsiLun_Free(&scsiLunList);
+
+    return volume;
+
+}
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeLookupByPath(virConnectPtr conn, const char *path)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = conn->storagePrivateData;
+    char *poolName = NULL;
+    esxVI_ScsiLun *scsiLunList = NULL;
+    const esxVI_ScsiLun *scsiLun = NULL;
+    const esxVI_HostScsiDisk *hostScsiDisk = NULL;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+    if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+        goto cleanup;
+    }
+
+    for (scsiLun = scsiLunList ; scsiLun != NULL;
+         scsiLun = scsiLun->_next) {
+         hostScsiDisk =
+            esxVI_HostScsiDisk_DynamicCast((esxVI_ScsiLun *)scsiLun);
+
+        if (hostScsiDisk != NULL &&
+            STREQ(hostScsiDisk->devicePath, path)) {
+            /* Found matching device */
+            if (esxVI_LookupStoragePoolNameByScsiLunKey(
+                  priv->primary, hostScsiDisk->key, &poolName) < 0) {
+                goto cleanup;
+            }
+
+            md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5);
+
+            virUUIDFormat(md5, uuid_string);
+
+            volume = virGetStorageVol(conn, poolName, path, uuid_string);
+            break;
+        }
+    }
+
+  cleanup:
+
+    esxVI_ScsiLun_Free(&scsiLunList);
+    VIR_FREE(poolName);
+
+    return volume;
+
+}
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeLookupByKey(virConnectPtr conn, const char *key)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = conn->storagePrivateData;
+    char *poolName = NULL;
+    esxVI_ScsiLun *scsiLunList = NULL;
+    const esxVI_ScsiLun *scsiLun = NULL;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+
+    /* key may be LUN device path */
+    if (STRPREFIX(key, "/")) {
+        return esxStorageBackendISCSIVolumeLookupByPath(conn, key);
+    }
+
+    if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+        goto cleanup;
+    }
+
+    for (scsiLun = scsiLunList; scsiLun != NULL;
+         scsiLun = scsiLun->_next) {
+
+        memset(uuid_string, '\0', sizeof(uuid_string));
+        memset(md5, '\0', sizeof(md5));
+
+        md5_buffer(scsiLun->uuid, strlen(scsiLun->uuid), md5);
+
+        virUUIDFormat(md5, uuid_string);
+
+        if (STREQ(key, uuid_string)) {
+            /* Found matching UUID */
+            if (esxVI_LookupStoragePoolNameByScsiLunKey(
+                  priv->primary, scsiLun->key, &poolName) < 0) {
+                goto cleanup;
+            }
+
+            volume = virGetStorageVol(conn, poolName,
+                                      scsiLun->deviceName, uuid_string);
+            break;
+        }
+    }
+
+  cleanup:
+
+    esxVI_ScsiLun_Free(&scsiLunList);
+    VIR_FREE(poolName);
+
+    return volume;
+
+}
+
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeCreateXML(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+                                      const char *xmldesc ATTRIBUTE_UNUSED,
+                                      unsigned int flags)
+{
+    virCheckFlags(0, NULL);
+
+    /* not supported operation for iSCSI pools */
+    return NULL;
+}
+
+
+
+static virStorageVolPtr
+esxStorageBackendISCSIVolumeCreateXMLFrom(
+  virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+  const char *xmldesc ATTRIBUTE_UNUSED,
+  virStorageVolPtr sourceVolume ATTRIBUTE_UNUSED,
+  unsigned int flags)
+{
+    virCheckFlags(0, NULL);
+
+    /* not supported operation for iSCSI pools */
+    return NULL;
+}
+
+
+
+static char*
+esxStorageBackendISCSIVolumeGetXMLDesc(virStorageVolPtr volume,
+                                       unsigned int flags)
+{
+    char *xml = NULL;
+    esxPrivate *priv = volume->conn->storagePrivateData;
+    virStoragePoolDef pool;
+    esxVI_ScsiLun *scsiLunList = NULL;
+    const esxVI_ScsiLun *scsiLun = NULL;
+    const esxVI_HostScsiDisk *hostScsiDisk = NULL;
+    virStorageVolDef def;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+
+    virCheckFlags(0, NULL);
+
+    memset(&pool, 0, sizeof(pool));
+    memset(&def, 0, sizeof(def));
+
+    if (esxVI_LookupScsiLunList(priv->primary, &scsiLunList) < 0) {
+        goto cleanup;
+    }
+
+    for (scsiLun = scsiLunList; scsiLun != NULL;
+         scsiLun = scsiLun->_next) {
+         hostScsiDisk =
+             esxVI_HostScsiDisk_DynamicCast((esxVI_ScsiLun *)scsiLun);
+
+        if (hostScsiDisk != NULL &&
+            STREQ(hostScsiDisk->deviceName, volume->name)) {
+            break;
+        }
+    }
+
+    if (hostScsiDisk == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Could find volume with name: %s"), volume->name);
+        goto cleanup;
+    }
+
+    pool.type = VIR_STORAGE_POOL_ISCSI;
+
+    def.name = volume->name;
+
+    md5_buffer(scsiLun->uuid, strlen(hostScsiDisk->uuid), md5);
+
+    virUUIDFormat(md5, uuid_string);
+
+    if (esxVI_String_DeepCopyValue(&def.key, uuid_string) < 0) {
+        goto cleanup;
+    }
+
+    /* iSCSI LUN exposes a block device */
+    def.type = VIR_STORAGE_VOL_BLOCK;
+
+    def.target.path = hostScsiDisk->devicePath;
+
+    def.capacity = hostScsiDisk->capacity->block->value *
+                   hostScsiDisk->capacity->blockSize->value;
+
+    def.allocation = def.capacity;
+
+    /* iSCSI LUN(s) hosting a datastore will be auto-mounted by
+     * ESX host
+     */
+    def.target.format = VIR_STORAGE_FILE_RAW;
+
+    xml = virStorageVolDefFormat(&pool, &def);
+
+  cleanup:
+
+    esxVI_ScsiLun_Free(&scsiLunList);
+    VIR_FREE(def.key);
+
+    return xml;
+
+}
+
+static int
+esxStorageBackendISCSIVolumeDelete(virStorageVolPtr volume ATTRIBUTE_UNUSED,
+                                   unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+    /* unsupported operation for iSCSI volume */
+    return 1;
+
+}
+
+
+
+static int
+esxStorageBackendISCSIVolumeWipe(virStorageVolPtr volume ATTRIBUTE_UNUSED,
+                                   unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+    /* unsupported operation for iSCSI volume */
+    return 1;
+
+}
+
+
+
+static char*
+esxStorageBackendISCSIVolumeGetPath(virStorageVolPtr volume)
+{
+    char *path;
+
+    if (virAsprintf(&path, "%s", volume->name) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return path;
+
+}
+
+
+
+virStorageDriver esxStorageBackendISCSIDrv = {
+    .name = "ESX ISCSI backend",
+    .open = NULL, /* 0.10.0 */
+    .close = NULL, /* 0.10.0 */
+    .numOfPools = esxStorageBackendISCSINumberOfStoragePools, /* 0.10.0 */
+    .listPools = esxStorageBackendISCSIListStoragePools, /* 0.10.0 */
+    .poolLookupByName = esxStorageBackendISCSIPoolLookupByName, /* 0.10.0 */
+    .poolLookupByUUID = esxStorageBackendISCSIPoolLookupByUUID, /* 0.10.0 */
+    .poolRefresh = esxStorageBackendISCSIPoolRefresh, /* 0.10.0 */
+    .poolGetInfo = esxStorageBackendISCSIPoolGetInfo, /* 0.10.0 */
+    .poolGetXMLDesc = esxStorageBackendISCSIPoolGetXMLDesc, /* 0.10.0 */
+    .poolNumOfVolumes = esxStorageBackendISCSIPoolNumberOfStorageVolumes, /* 0.10.0 */
+    .poolListVolumes = esxStorageBackendISCSIPoolListStorageVolumes, /* 0.10.0 */
+    .volLookupByName = esxStorageBackendISCSIVolumeLookupByName, /* 0.10.0 */
+    .volLookupByKey = esxStorageBackendISCSIVolumeLookupByKey, /* 0.10.0 */
+    .volLookupByPath = esxStorageBackendISCSIVolumeLookupByPath, /* 0.10.0 */
+    .volCreateXML = esxStorageBackendISCSIVolumeCreateXML, /* 0.10.0 */
+    .volCreateXMLFrom = esxStorageBackendISCSIVolumeCreateXMLFrom, /* 0.10.0 */
+    .volGetXMLDesc = esxStorageBackendISCSIVolumeGetXMLDesc, /* 0.10.0 */
+    .volDelete = esxStorageBackendISCSIVolumeDelete, /* 0.10.0 */
+    .volWipe = esxStorageBackendISCSIVolumeWipe, /* 0.10.0 */
+    .volGetPath = esxStorageBackendISCSIVolumeGetPath, /* 0.10.0 */
+
+};
diff --git a/src/esx/esx_storage_backend_iscsi.h b/src/esx/esx_storage_backend_iscsi.h
new file mode 100644
index 0000000..ca756ac
--- /dev/null
+++ b/src/esx/esx_storage_backend_iscsi.h
@@ -0,0 +1,31 @@
+/*
+ * esx_storage_backend_iscsi.h: ESX storage backend for iSCSI handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Ata E Husain Bohra (ata husain hotmail com)
+ */
+
+#ifndef __ESX_STORAGE_BACKEND_ISCSI_H__
+# define __ESX_STORAGE_BACKEND_ISCSI_H__
+
+#include "driver.h"
+
+extern virStorageDriver esxStorageBackendISCSIDrv;
+
+#endif /* __ESX_STORAGE_BACKEND_ISCSI_H__ */
+
diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c
new file mode 100644
index 0000000..6550196
--- /dev/null
+++ b/src/esx/esx_storage_backend_vmfs.c
@@ -0,0 +1,1471 @@
+
+/*
+ * esx_storage_backend_vmfs.c: ESX storage backend for VMFS datastores
+ *
+ * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010 Matthias Bolte <matthias bolte googlemail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ata E Husain Bohra (ata husain hotmail com)
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "internal.h"
+#include "md5.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+
+#include "storage_conf.h"
+#include "storage_file.h"
+#include "esx_storage_backend_vmfs.h"
+#include "esx_private.h"
+#include "esx_vi.h"
+#include "esx_vi_methods.h"
+#include "esx_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+/*
+ * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore,
+ * verify that UUID and MD5 sum match in size, because we rely on that.
+ */
+verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+
+
+
+static int
+esxStorageBackendVMFSPoolLookupType(virConnectPtr conn, const char *poolName,
+                                    int *poolType)
+{
+    int result = -1;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_DatastoreInfo *datastoreInfo = NULL;
+
+    if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
+        esxVI_LookupDatastoreByName(priv->primary, poolName,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_OptionalItem) < 0) {
+        goto cleanup;
+    }
+
+    if (datastore == NULL) {
+        /* not found */
+        goto cleanup;
+    }
+
+    for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "info")) {
+            if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+                                                    &datastoreInfo) < 0) {
+                goto cleanup;
+            }
+
+            break;
+        }
+    }
+
+    if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+        *poolType = VIR_STORAGE_POOL_DIR;
+    } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+        *poolType = VIR_STORAGE_POOL_NETFS;
+    } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+        *poolType = VIR_STORAGE_POOL_FS;
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+          _("DatastoreInfo has unexpected type"));
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+    esxVI_DatastoreInfo_Free(&datastoreInfo);
+
+    return result;
+}
+
+
+
+
+static int
+esxStorageBackendVMFSNumberOfStoragePools(virConnectPtr conn)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    int count = 0;
+
+    if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) {
+        goto cleanup;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        ++count;
+    }
+
+  cleanup:
+    esxVI_ObjectContent_Free(&datastoreList);
+
+    return count;
+}
+
+static int
+esxStorageBackendVMFSListStoragePools(virConnectPtr conn,
+                                      char **const names,
+                                      const int maxnames)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    int count = 0;
+    int i = 0;
+    bool success = false;
+
+    if (maxnames == 0) {
+        return 0;
+    }
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+                                       "summary.name") < 0 ||
+        esxVI_LookupDatastoreList(priv->primary, propertyNameList,
+                                  &datastoreList) < 0) {
+        goto cleanup;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.name")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_String) < 0) {
+                    goto cleanup;
+                }
+
+                names[count] = strdup(dynamicProperty->val->string);
+
+                if (names[count] == NULL) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+
+                ++count;
+                break;
+            } else {
+                VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+            }
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (! success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+
+        count = -1;
+    }
+
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastoreList);
+
+    return count;
+}
+
+static virStoragePoolPtr
+esxStorageBackendVMFSPoolLookupByName(virConnectPtr conn,
+                                      const char *name)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DatastoreHostMount *hostMount = NULL;
+    /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    unsigned char md5[MD5_DIGEST_SIZE];
+    virStoragePoolPtr pool = NULL;
+
+    virCheckNonNullArgReturn(name, NULL);
+
+    if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore,
+                                    esxVI_Occurrence_OptionalItem) < 0) {
+        goto cleanup;
+    }
+
+    if (datastore == NULL) {
+        /* not found */
+        goto cleanup;
+    }
+
+    /*
+     * Datastores don't have a UUID, but we can use the 'host.mountInfo.path'
+     * property as source for a UUID. The mount path is unique per host and
+     * cannot change during the lifetime of the datastore.
+     *
+     * The MD5 sum of the mount path can be used as UUID, assuming MD5 is
+     * considered to be collision-free enough for this use case.
+     */
+    if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
+                &hostMount, esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    md5_buffer(hostMount->mountInfo->path,
+               strlen(hostMount->mountInfo->path), md5);
+
+    pool = virGetStoragePool(conn, name, md5);
+
+  cleanup:
+    esxVI_ObjectContent_Free(&datastore);
+    esxVI_DatastoreHostMount_Free(&hostMount);
+
+    return pool;
+}
+
+static virStoragePoolPtr
+esxStorageBackendVMFSPoolLookupByUUID(virConnectPtr conn,
+                                      const unsigned char *uuid)
+{
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DatastoreHostMount *hostMount = NULL;
+    unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
+    char *name = NULL;
+    virStoragePoolPtr pool = NULL;
+
+
+    if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
+        esxVI_LookupDatastoreList(priv->primary, propertyNameList,
+                                  &datastoreList) < 0) {
+        goto cleanup;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        esxVI_DatastoreHostMount_Free(&hostMount);
+
+        if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
+              &hostMount, esxVI_Occurrence_OptionalItem) < 0) {
+            goto cleanup;
+        }
+
+        if (hostMount == NULL) {
+            /* not found */
+            goto cleanup;
+        }
+
+        md5_buffer(hostMount->mountInfo->path,
+                   strlen(hostMount->mountInfo->path), md5);
+
+        if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) {
+            break;
+        }
+    }
+
+    if (datastore == NULL) {
+        goto cleanup;
+    }
+
+    if (esxVI_GetStringValue(datastore, "summary.name", &name,
+                             esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    pool = virGetStoragePool(conn, name, uuid);
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastoreList);
+    esxVI_DatastoreHostMount_Free(&hostMount);
+
+    return pool;
+}
+
+static int
+esxStorageBackendVMFSPoolRefresh(virStoragePoolPtr pool, unsigned int flags)
+{
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_ObjectContent *datastore = NULL;
+    int result = -1;
+
+    virCheckFlags(0, -1);
+
+    if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) {
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_ObjectContent_Free(&datastore);
+
+    return result;
+}
+
+
+static int
+esxStorageBackendVMFSPoolGetInfo(virStoragePoolPtr pool,
+                                 virStoragePoolInfoPtr info)
+{
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+    int result = -1;
+
+    if (esxVI_String_AppendValueListToList(&propertyNameList,
+                                           "summary.accessible\0"
+                                           "summary.capacity\0"
+                                           "summary.freeSpace\0") < 0 ||
+        esxVI_LookupDatastoreByName(priv->primary, pool->name,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_GetBoolean(datastore, "summary.accessible",
+                         &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    if (accessible == esxVI_Boolean_True) {
+        info->state = VIR_STORAGE_POOL_RUNNING;
+
+        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.capacity")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                info->capacity = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                info->available = dynamicProperty->val->int64;
+            }
+        }
+
+        info->allocation = info->capacity - info->available;
+    } else {
+        info->state = VIR_STORAGE_POOL_INACCESSIBLE;
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+
+    return result;
+}
+
+static char *
+esxStorageBackendVMFSPoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    esxVI_DatastoreHostMount *hostMount = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+    virStoragePoolDef def;
+    esxVI_DatastoreInfo *info = NULL;
+    esxVI_NasDatastoreInfo *nasInfo = NULL;
+    char *xml = NULL;
+
+    virCheckFlags(0, NULL);
+
+    memset(&def, 0, sizeof(def));
+
+    if (esxVI_String_AppendValueListToList(&propertyNameList,
+                                           "summary.accessible\0"
+                                           "summary.capacity\0"
+                                           "summary.freeSpace\0"
+                                           "info\0") < 0 ||
+        esxVI_LookupDatastoreByName(priv->primary, pool->name,
+                                    propertyNameList, &datastore,
+                                    esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_GetBoolean(datastore, "summary.accessible",
+                         &accessible, esxVI_Occurrence_RequiredItem) < 0 ||
+        esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
+            &hostMount, esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    def.name = pool->name;
+    memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+    def.target.path = hostMount->mountInfo->path;
+
+    if (accessible == esxVI_Boolean_True) {
+        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+             dynamicProperty = dynamicProperty->_next) {
+            if (STREQ(dynamicProperty->name, "summary.capacity")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                def.capacity = dynamicProperty->val->int64;
+            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+                                             esxVI_Type_Long) < 0) {
+                    goto cleanup;
+                }
+
+                def.available = dynamicProperty->val->int64;
+            }
+        }
+
+        def.allocation = def.capacity - def.available;
+    }
+
+    for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "info")) {
+            if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+                                                    &info) < 0) {
+                goto cleanup;
+            }
+
+            break;
+        }
+    }
+
+    /* See vSphere API documentation about HostDatastoreSystem for details */
+    if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
+        def.type = VIR_STORAGE_POOL_DIR;
+    } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
+        if (VIR_ALLOC_N(def.source.hosts, 1) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        def.type = VIR_STORAGE_POOL_NETFS;
+        def.source.hosts[0].name = nasInfo->nas->remoteHost;
+        def.source.dir = nasInfo->nas->remotePath;
+
+        if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
+            def.source.format = VIR_STORAGE_POOL_NETFS_NFS;
+        } else  if (STRCASEEQ(nasInfo->nas->type, "CIFS")) {
+            def.source.format = VIR_STORAGE_POOL_NETFS_CIFS;
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Datastore has unexpected type '%s'"),
+                           nasInfo->nas->type);
+            goto cleanup;
+        }
+    } else if (esxVI_VmfsDatastoreInfo_DynamicCast(info) != NULL) {
+        def.type = VIR_STORAGE_POOL_FS;
+        /*
+         * FIXME: I'm not sure how to represent the source and target of a
+         * VMFS based datastore in libvirt terms
+         */
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("DatastoreInfo has unexpected type"));
+        goto cleanup;
+    }
+
+    xml = virStoragePoolDefFormat(&def);
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastore);
+    esxVI_DatastoreHostMount_Free(&hostMount);
+    esxVI_DatastoreInfo_Free(&info);
+
+    return xml;
+}
+
+
+static int
+esxStorageBackendVMFSPoolNumberOfStorageVolumes(virStoragePoolPtr pool)
+{
+    bool success = false;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
+    esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    int count = 0;
+
+    if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
+                                                    &searchResultsList) < 0) {
+        goto cleanup;
+    }
+
+    /* Interpret search result */
+    for (searchResults = searchResultsList; searchResults != NULL;
+         searchResults = searchResults->_next) {
+        for (fileInfo = searchResults->file; fileInfo != NULL;
+             fileInfo = fileInfo->_next) {
+            ++count;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+
+    return success ? count : -1;
+}
+
+static int
+esxStorageBackendVMFSPoolListStorageVolumes(virStoragePoolPtr pool, char **const names,
+                                            int maxnames)
+
+{
+    bool success = false;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
+    esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    char *directoryAndFileName = NULL;
+    size_t length;
+    int count = 0;
+    int i;
+
+    if (names == NULL || maxnames < 0) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (maxnames == 0) {
+        return 0;
+    }
+
+    if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
+                                                    &searchResultsList) < 0) {
+        goto cleanup;
+    }
+
+    /* Interpret search result */
+    for (searchResults = searchResultsList; searchResults != NULL;
+         searchResults = searchResults->_next) {
+        VIR_FREE(directoryAndFileName);
+
+        if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, NULL,
+                                       &directoryAndFileName) < 0) {
+            goto cleanup;
+        }
+
+        /* Strip trailing separators */
+        length = strlen(directoryAndFileName);
+
+        while (length > 0 && directoryAndFileName[length - 1] == '/') {
+            directoryAndFileName[length - 1] = '\0';
+            --length;
+        }
+
+        /* Build volume names */
+        for (fileInfo = searchResults->file; fileInfo != NULL;
+             fileInfo = fileInfo->_next) {
+            if (length < 1) {
+                names[count] = strdup(fileInfo->path);
+
+                if (names[count] == NULL) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+            } else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName,
+                                   fileInfo->path) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            ++count;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (! success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+
+        count = -1;
+    }
+
+    esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+    VIR_FREE(directoryAndFileName);
+
+    return count;
+
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeLookupByName(virStoragePoolPtr pool,
+                                        const char *name)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    char *datastorePath = NULL;
+    char *key = NULL;
+
+    if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary,
+                                                    datastorePath, &key) < 0) {
+        goto cleanup;
+    }
+
+    volume = virGetStorageVol(pool->conn, pool->name, name, key);
+
+  cleanup:
+    VIR_FREE(datastorePath);
+    VIR_FREE(key);
+
+    return volume;
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeLookupByPath(virConnectPtr conn, const char *path)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = conn->storagePrivateData;
+    char *datastoreName = NULL;
+    char *directoryAndFileName = NULL;
+    char *key = NULL;
+
+    if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL,
+                                   &directoryAndFileName) < 0) {
+        goto cleanup;
+    }
+
+    if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path,
+                                                    &key) < 0) {
+        goto cleanup;
+    }
+
+    volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key);
+
+  cleanup:
+    VIR_FREE(datastoreName);
+    VIR_FREE(directoryAndFileName);
+    VIR_FREE(key);
+
+    return volume;
+}
+
+
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeLookupByKey(virConnectPtr conn, const char *key)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = conn->storagePrivateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *datastoreList = NULL;
+    esxVI_ObjectContent *datastore = NULL;
+    char *datastoreName = NULL;
+    esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
+    esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
+    char *directoryAndFileName = NULL;
+    size_t length;
+    char *datastorePath = NULL;
+    char *volumeName = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    char *uuid_string = NULL;
+    char key_candidate[VIR_UUID_STRING_BUFLEN] = "";
+
+    if (STRPREFIX(key, "[")) {
+        /* Key is probably a datastore path */
+        return esxStorageBackendVMFSVolumeLookupByPath(conn, key);
+    }
+
+    if (!priv->primary->hasQueryVirtualDiskUuid) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("QueryVirtualDiskUuid not available, cannot lookup storage "
+                         "volume by UUID"));
+        return NULL;
+    }
+
+    /* Lookup all datastores */
+    if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
+        esxVI_LookupDatastoreList(priv->primary, propertyNameList,
+                                  &datastoreList) < 0) {
+        goto cleanup;
+    }
+
+    for (datastore = datastoreList; datastore != NULL;
+         datastore = datastore->_next) {
+        datastoreName = NULL;
+
+        if (esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
+                                 esxVI_Occurrence_RequiredItem) < 0) {
+            goto cleanup;
+        }
+
+        /* Lookup datastore content */
+        esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+
+        if (esxVI_LookupDatastoreContentByDatastoreName
+              (priv->primary, datastoreName, &searchResultsList) < 0) {
+            goto cleanup;
+        }
+
+        /* Interpret search result */
+        for (searchResults = searchResultsList; searchResults != NULL;
+             searchResults = searchResults->_next) {
+            VIR_FREE(directoryAndFileName);
+
+            if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL,
+                                           NULL, &directoryAndFileName) < 0) {
+                goto cleanup;
+            }
+
+            /* Strip trailing separators */
+            length = strlen(directoryAndFileName);
+
+            while (length > 0 && directoryAndFileName[length - 1] == '/') {
+                directoryAndFileName[length - 1] = '\0';
+                --length;
+            }
+
+            /* Build datastore path and query the UUID */
+            for (fileInfo = searchResults->file; fileInfo != NULL;
+                 fileInfo = fileInfo->_next) {
+                VIR_FREE(datastorePath);
+
+                if (length < 1) {
+                    if (virAsprintf(&volumeName, "%s",
+                                    fileInfo->path) < 0) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+                } else if (virAsprintf(&volumeName, "%s/%s",
+                                       directoryAndFileName,
+                                       fileInfo->path) < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+
+                if (virAsprintf(&datastorePath, "[%s] %s", datastoreName,
+                                volumeName) < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+
+                if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo) == NULL) {
+                    /* Only a VirtualDisk has a UUID */
+                    continue;
+                }
+
+                VIR_FREE(uuid_string);
+
+                if (esxVI_QueryVirtualDiskUuid
+                      (priv->primary, datastorePath,
+                       priv->primary->datacenter->_reference,
+                       &uuid_string) < 0) {
+                    goto cleanup;
+                }
+
+                if (esxUtil_ReformatUuid(uuid_string, key_candidate) < 0) {
+                    goto cleanup;
+                }
+
+                if (STREQ(key, key_candidate)) {
+                    /* Found matching UUID */
+                    volume = virGetStorageVol(conn, datastoreName,
+                                              volumeName, key);
+                    goto cleanup;
+                }
+            }
+        }
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&datastoreList);
+    esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
+    VIR_FREE(directoryAndFileName);
+    VIR_FREE(datastorePath);
+    VIR_FREE(volumeName);
+    VIR_FREE(uuid_string);
+
+    return volume;
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
+                                     unsigned int flags)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    virStoragePoolDef poolDef;
+    virStorageVolDefPtr def = NULL;
+    char *tmp;
+    char *unescapedDatastorePath = NULL;
+    char *unescapedDirectoryName = NULL;
+    char *unescapedDirectoryAndFileName = NULL;
+    char *directoryName = NULL;
+    char *fileName = NULL;
+    char *datastorePathWithoutFileName = NULL;
+    char *datastorePath = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+    char *taskInfoErrorMessage = NULL;
+    char *uuid_string = NULL;
+    char *key = NULL;
+
+    virCheckFlags(0, NULL);
+
+    memset(&poolDef, 0, sizeof(poolDef));
+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return NULL;
+    }
+
+    if (esxStorageBackendVMFSPoolLookupType(
+          pool->conn, pool->name, &poolDef.type) < 0) {
+        return NULL;
+    }
+
+    /* Parse config */
+    def = virStorageVolDefParseString(&poolDef, xmldesc);
+
+    if (def == NULL) {
+        goto cleanup;
+    }
+
+    if (def->type != VIR_STORAGE_VOL_FILE) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Creating non-file volumes is not supported"));
+        goto cleanup;
+    }
+
+    /* Validate config */
+    tmp = strrchr(def->name, '/');
+
+    if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Volume name '%s' doesn't have expected format "
+                         "'<directory>/<file>'"), def->name);
+        goto cleanup;
+    }
+
+    if (! virFileHasSuffix(def->name, ".vmdk")) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
+                       def->name);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
+                    def->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
+        /* Parse and escape datastore path */
+        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
+                                       &unescapedDirectoryName,
+                                       &unescapedDirectoryAndFileName) < 0) {
+            goto cleanup;
+        }
+
+        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
+
+        if (directoryName == NULL) {
+            goto cleanup;
+        }
+
+        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
+                                               strlen(unescapedDirectoryName) + 1);
+
+        if (fileName == NULL) {
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
+                        directoryName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
+                        fileName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* Create directory, if it doesn't exist yet */
+        if (esxVI_LookupFileInfoByDatastorePath
+              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
+               esxVI_Occurrence_OptionalItem) < 0) {
+            goto cleanup;
+        }
+
+        if (fileInfo == NULL) {
+            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
+                                    priv->primary->datacenter->_reference,
+                                    esxVI_Boolean_True) < 0) {
+                goto cleanup;
+            }
+        }
+
+        /* Create VirtualDisk */
+        if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
+            esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
+            goto cleanup;
+        }
+
+        /* From the vSphere API documentation about VirtualDiskType ... */
+        if (def->allocation == def->capacity) {
+            /*
+             * "A preallocated disk has all space allocated at creation time
+             *  and the space is zeroed on demand as the space is used."
+             */
+            virtualDiskSpec->diskType = (char *)"preallocated";
+        } else if (def->allocation == 0) {
+            /*
+             * "Space required for thin-provisioned virtual disk is allocated
+             *  and zeroed on demand as the space is used."
+             */
+            virtualDiskSpec->diskType = (char *)"thin";
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Unsupported capacity-to-allocation relation"));
+            goto cleanup;
+        }
+
+        /*
+         * FIXME: The adapter type is a required parameter, but there is no
+         * way to let the user specify it in the volume XML config. Therefore,
+         * default to 'busLogic' here.
+         */
+        virtualDiskSpec->adapterType = (char *)"busLogic";
+
+        virtualDiskSpec->capacityKb->value =
+          VIR_DIV_UP(def->capacity, 1024); /* Scale from byte to kilobyte */
+
+        if (esxVI_CreateVirtualDisk_Task
+              (priv->primary, datastorePath, priv->primary->datacenter->_reference,
+               esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
+            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+                                        esxVI_Occurrence_None,
+                                        priv->parsedUri->autoAnswer,
+                                        &taskInfoState,
+                                        &taskInfoErrorMessage) < 0) {
+            goto cleanup;
+        }
+
+        if (taskInfoState != esxVI_TaskInfoState_Success) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"),
+                           taskInfoErrorMessage);
+            goto cleanup;
+        }
+
+        if (priv->primary->hasQueryVirtualDiskUuid) {
+            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
+                                           priv->primary->datacenter->_reference,
+                                           &uuid_string) < 0) {
+                goto cleanup;
+            }
+
+            if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
+                goto cleanup;
+            }
+        } else {
+            /* Fall back to the path as key */
+            if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
+                goto cleanup;
+            }
+        }
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Creation of %s volumes is not supported"),
+                       virStorageFileFormatTypeToString(def->target.format));
+        goto cleanup;
+    }
+
+    volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+
+  cleanup:
+    if (virtualDiskSpec != NULL) {
+        virtualDiskSpec->diskType = NULL;
+        virtualDiskSpec->adapterType = NULL;
+    }
+
+    virStorageVolDefFree(def);
+    VIR_FREE(unescapedDatastorePath);
+    VIR_FREE(unescapedDirectoryName);
+    VIR_FREE(unescapedDirectoryAndFileName);
+    VIR_FREE(directoryName);
+    VIR_FREE(fileName);
+    VIR_FREE(datastorePathWithoutFileName);
+    VIR_FREE(datastorePath);
+    esxVI_FileInfo_Free(&fileInfo);
+    esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
+    esxVI_ManagedObjectReference_Free(&task);
+    VIR_FREE(taskInfoErrorMessage);
+    VIR_FREE(uuid_string);
+    VIR_FREE(key);
+
+    return volume;
+}
+
+static virStorageVolPtr
+esxStorageBackendVMFSVolumeCreateXMLFrom(virStoragePoolPtr pool,
+                                         const char *xmldesc,
+                                         virStorageVolPtr sourceVolume,
+                                         unsigned int flags)
+{
+    virStorageVolPtr volume = NULL;
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    virStoragePoolDef poolDef;
+    char *sourceDatastorePath = NULL;
+    virStorageVolDefPtr def = NULL;
+    char *tmp;
+    char *unescapedDatastorePath = NULL;
+    char *unescapedDirectoryName = NULL;
+    char *unescapedDirectoryAndFileName = NULL;
+    char *directoryName = NULL;
+    char *fileName = NULL;
+    char *datastorePathWithoutFileName = NULL;
+    char *datastorePath = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+    char *taskInfoErrorMessage = NULL;
+    char *uuid_string = NULL;
+    char *key = NULL;
+
+    virCheckFlags(0, NULL);
+
+    memset(&poolDef, 0, sizeof(poolDef));
+
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        return NULL;
+    }
+
+    if (esxStorageBackendVMFSPoolLookupType(
+          pool->conn, pool->name, &poolDef.type) < 0) {
+        return NULL;
+    }
+
+    if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool,
+                    sourceVolume->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* Parse config */
+    def = virStorageVolDefParseString(&poolDef, xmldesc);
+
+    if (def == NULL) {
+        goto cleanup;
+    }
+
+    if (def->type != VIR_STORAGE_VOL_FILE) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Creating non-file volumes is not supported"));
+        goto cleanup;
+    }
+
+    /* Validate config */
+    tmp = strrchr(def->name, '/');
+
+    if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Volume name '%s' doesn't have expected format "
+                         "'<directory>/<file>'"), def->name);
+        goto cleanup;
+    }
+
+    if (! virFileHasSuffix(def->name, ".vmdk")) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
+                       def->name);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
+                    def->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
+        /* Parse and escape datastore path */
+        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
+                                       &unescapedDirectoryName,
+                                       &unescapedDirectoryAndFileName) < 0) {
+            goto cleanup;
+        }
+
+        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
+
+        if (directoryName == NULL) {
+            goto cleanup;
+        }
+
+        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
+                                               strlen(unescapedDirectoryName) + 1);
+
+        if (fileName == NULL) {
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
+                        directoryName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
+                        fileName) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* Create directory, if it doesn't exist yet */
+        if (esxVI_LookupFileInfoByDatastorePath
+              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
+               esxVI_Occurrence_OptionalItem) < 0) {
+            goto cleanup;
+        }
+
+        if (fileInfo == NULL) {
+            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
+                                    priv->primary->datacenter->_reference,
+                                    esxVI_Boolean_True) < 0) {
+                goto cleanup;
+            }
+        }
+
+        /* Copy VirtualDisk */
+        if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
+                                       priv->primary->datacenter->_reference,
+                                       datastorePath,
+                                       priv->primary->datacenter->_reference,
+                                       NULL, esxVI_Boolean_False, &task) < 0 ||
+            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+                                        esxVI_Occurrence_None,
+                                        priv->parsedUri->autoAnswer,
+                                        &taskInfoState,
+                                        &taskInfoErrorMessage) < 0) {
+            goto cleanup;
+        }
+
+        if (taskInfoState != esxVI_TaskInfoState_Success) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
+                           taskInfoErrorMessage);
+            goto cleanup;
+        }
+
+        if (priv->primary->hasQueryVirtualDiskUuid) {
+            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
+                                           priv->primary->datacenter->_reference,
+                                           &uuid_string) < 0) {
+                goto cleanup;
+            }
+
+            if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
+                goto cleanup;
+            }
+        } else {
+            /* Fall back to the path as key */
+            if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
+                goto cleanup;
+            }
+        }
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Creation of %s volumes is not supported"),
+                       virStorageFileFormatTypeToString(def->target.format));
+        goto cleanup;
+    }
+
+    volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+
+  cleanup:
+    VIR_FREE(sourceDatastorePath);
+    virStorageVolDefFree(def);
+    VIR_FREE(unescapedDatastorePath);
+    VIR_FREE(unescapedDirectoryName);
+    VIR_FREE(unescapedDirectoryAndFileName);
+    VIR_FREE(directoryName);
+    VIR_FREE(fileName);
+    VIR_FREE(datastorePathWithoutFileName);
+    VIR_FREE(datastorePath);
+    esxVI_FileInfo_Free(&fileInfo);
+    esxVI_ManagedObjectReference_Free(&task);
+    VIR_FREE(taskInfoErrorMessage);
+    VIR_FREE(uuid_string);
+    VIR_FREE(key);
+
+    return volume;
+}
+
+
+
+static char *
+esxStorageBackendVMFSVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
+{
+    esxPrivate *priv = volume->conn->storagePrivateData;
+    virStoragePoolDef pool;
+    char *datastorePath = NULL;
+    esxVI_FileInfo *fileInfo = NULL;
+    esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
+    esxVI_IsoImageFileInfo *isoImageFileInfo = NULL;
+    esxVI_FloppyImageFileInfo *floppyImageFileInfo = NULL;
+    virStorageVolDef def;
+    char *xml = NULL;
+
+    virCheckFlags(0, NULL);
+
+    memset(&pool, 0, sizeof(pool));
+    memset(&def, 0, sizeof(def));
+
+    if (esxStorageBackendVMFSPoolLookupType(
+          volume->conn, volume->pool, &pool.type) < 0) {
+        return NULL;
+    }
+
+    /* Lookup file info */
+    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
+                                            false, &fileInfo,
+                                            esxVI_Occurrence_RequiredItem) < 0) {
+        goto cleanup;
+    }
+
+    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
+    isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo);
+    floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo);
+
+    def.name = volume->name;
+
+    if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath,
+                                                    &def.key) < 0) {
+        goto cleanup;
+    }
+
+    def.type = VIR_STORAGE_VOL_FILE;
+    def.target.path = datastorePath;
+
+    if (vmDiskFileInfo != NULL) {
+        def.capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
+        def.allocation = vmDiskFileInfo->fileSize->value;
+
+        def.target.format = VIR_STORAGE_FILE_VMDK;
+    } else if (isoImageFileInfo != NULL) {
+        def.capacity = fileInfo->fileSize->value;
+        def.allocation = fileInfo->fileSize->value;
+
+        def.target.format = VIR_STORAGE_FILE_ISO;
+    } else if (floppyImageFileInfo != NULL) {
+        def.capacity = fileInfo->fileSize->value;
+        def.allocation = fileInfo->fileSize->value;
+
+        def.target.format = VIR_STORAGE_FILE_RAW;
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("File '%s' has unknown type"), datastorePath);
+        goto cleanup;
+    }
+
+    xml = virStorageVolDefFormat(&pool, &def);
+
+  cleanup:
+    VIR_FREE(datastorePath);
+    esxVI_FileInfo_Free(&fileInfo);
+    VIR_FREE(def.key);
+
+    return xml;
+}
+
+
+
+static int
+esxStorageBackendVMFSVolumeDelete(virStorageVolPtr volume, unsigned int flags)
+{
+    int result = -1;
+    esxPrivate *priv = volume->conn->storagePrivateData;
+    char *datastorePath = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+    char *taskInfoErrorMessage = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (esxVI_DeleteVirtualDisk_Task(priv->primary, datastorePath,
+                                     priv->primary->datacenter->_reference,
+                                     &task) < 0 ||
+        esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+                                    esxVI_Occurrence_None,
+                                    priv->parsedUri->autoAnswer,
+                                    &taskInfoState, &taskInfoErrorMessage) < 0) {
+        goto cleanup;
+    }
+
+    if (taskInfoState != esxVI_TaskInfoState_Success) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"),
+                       taskInfoErrorMessage);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    VIR_FREE(datastorePath);
+    esxVI_ManagedObjectReference_Free(&task);
+    VIR_FREE(taskInfoErrorMessage);
+
+    return result;
+
+}
+
+
+
+static int
+esxStorageBackendVMFSVolumeWipe(virStorageVolPtr volume, unsigned int flags)
+{
+    int result = -1;
+    esxPrivate *priv = volume->conn->storagePrivateData;
+    char *datastorePath = NULL;
+    esxVI_ManagedObjectReference *task = NULL;
+    esxVI_TaskInfoState taskInfoState;
+    char *taskInfoErrorMessage = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (esxVI_ZeroFillVirtualDisk_Task(priv->primary, datastorePath,
+                                       priv->primary->datacenter->_reference,
+                                       &task) < 0 ||
+        esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
+                                    esxVI_Occurrence_None,
+                                    priv->parsedUri->autoAnswer,
+                                    &taskInfoState, &taskInfoErrorMessage) < 0) {
+        goto cleanup;
+    }
+
+    if (taskInfoState != esxVI_TaskInfoState_Success) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"),
+                       taskInfoErrorMessage);
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+    VIR_FREE(datastorePath);
+    esxVI_ManagedObjectReference_Free(&task);
+    VIR_FREE(taskInfoErrorMessage);
+
+    return result;
+
+}
+
+
+static char*
+esxStorageBackendVMFSVolumeGetPath(virStorageVolPtr volume)
+{
+    char *path;
+
+    if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return path;
+
+}
+
+
+
+
+virStorageDriver esxStorageBackendVMFSDrv = {
+    .name = "ESX VMFS backend",
+    .open = NULL, /* 0.7.6 */
+    .close = NULL, /* 0.7.6 */
+    .numOfPools = esxStorageBackendVMFSNumberOfStoragePools, /* 0.8.2 */
+    .listPools = esxStorageBackendVMFSListStoragePools, /* 0.8.2 */
+    .poolLookupByName = esxStorageBackendVMFSPoolLookupByName, /* 0.8.2 */
+    .poolLookupByUUID = esxStorageBackendVMFSPoolLookupByUUID, /* 0.8.2 */
+    .poolRefresh = esxStorageBackendVMFSPoolRefresh, /* 0.8.2 */
+    .poolGetInfo = esxStorageBackendVMFSPoolGetInfo, /* 0.8.2 */
+    .poolGetXMLDesc = esxStorageBackendVMFSPoolGetXMLDesc, /* 0.8.2 */
+    .poolNumOfVolumes = esxStorageBackendVMFSPoolNumberOfStorageVolumes, /* 0.8.4 */
+    .poolListVolumes = esxStorageBackendVMFSPoolListStorageVolumes, /* 0.8.4 */
+    .volLookupByName = esxStorageBackendVMFSVolumeLookupByName, /* x.x.x */
+    .volLookupByKey = esxStorageBackendVMFSVolumeLookupByKey, /* 0.8.4 */
+    .volLookupByPath = esxStorageBackendVMFSVolumeLookupByPath, /* 0.8.4 */
+    .volCreateXML = esxStorageBackendVMFSVolumeCreateXML, /* 0.8.4 */
+    .volCreateXMLFrom = esxStorageBackendVMFSVolumeCreateXMLFrom, /* 0.8.7 */
+    .volGetXMLDesc = esxStorageBackendVMFSVolumeGetXMLDesc, /* 0.8.4 */
+    .volDelete = esxStorageBackendVMFSVolumeDelete, /* 0.8.7 */
+    .volWipe = esxStorageBackendVMFSVolumeWipe, /* 0.8.7 */
+    .volGetPath = esxStorageBackendVMFSVolumeGetPath, /* 0.10.0 */
+
+};
diff --git a/src/esx/esx_storage_backend_vmfs.h b/src/esx/esx_storage_backend_vmfs.h
new file mode 100644
index 0000000..d3adf73
--- /dev/null
+++ b/src/esx/esx_storage_backend_vmfs.h
@@ -0,0 +1,31 @@
+/*
+ * esx_storage_backend_vmfs.h: ESX storage backend for VMFS datastores
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Ata E Husain Bohra (ata husain hotmail com)
+ */
+
+#ifndef __ESX_STORAGE_BACKEND_VMFS_H__
+# define __ESX_STORAGE_BACKEND_VMFS_H__
+
+#include "driver.h"
+
+extern virStorageDriver esxStorageBackendVMFSDrv;
+
+#endif /* __ESX_STORAGE_BACKEND_VMFS_H__ */
+
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 348bd62..d4e81f3 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -24,82 +24,67 @@
 
 #include <config.h>
 
-#include "md5.h"
-#include "verify.h"
 #include "internal.h"
 #include "util.h"
 #include "memory.h"
 #include "logging.h"
-#include "uuid.h"
 #include "storage_conf.h"
-#include "storage_file.h"
 #include "esx_private.h"
 #include "esx_storage_driver.h"
+#include "esx_storage_backend_iscsi.h"
+#include "esx_storage_backend_vmfs.h"
 #include "esx_vi.h"
 #include "esx_vi_methods.h"
 #include "esx_util.h"
 
 #define VIR_FROM_THIS VIR_FROM_ESX
 
-/*
- * The UUID of a storage pool is the MD5 sum of it's mount path. Therefore,
- * verify that UUID and MD5 sum match in size, because we rely on that.
+/**
+ * ESX storage driver implements a facade pattern;
+ * the driver exposes the routines supported by Libvirt
+ * public interface to manage ESX storage devices. Internally
+ * it uses backend drivers to perform the required task.
  */
-verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+enum {
+    ISCSI = 0,
+    VMFS,
+    LAST_DRIVER
+};
 
+static virStorageDriverPtr backendDrv[LAST_DRIVER] = {NULL};
 
 
 static int
-esxStoragePoolLookupType(esxVI_Context *ctx, const char *poolName,
-                         int *poolType)
+esxStorageGetBackendDriver(virConnectPtr conn, const char *name,
+                           virStorageDriverPtr *backend)
 {
     int result = -1;
-    esxVI_String *propertyNameList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
-    esxVI_DynamicProperty *dynamicProperty = NULL;
-    esxVI_DatastoreInfo *datastoreInfo = NULL;
-
-    if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
-        esxVI_LookupDatastoreByName(ctx, poolName, propertyNameList, &datastore,
-                                    esxVI_Occurrence_RequiredItem) < 0) {
-        goto cleanup;
-    }
+    int i = 0;
 
-    for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
-         dynamicProperty = dynamicProperty->_next) {
-        if (STREQ(dynamicProperty->name, "info")) {
-            if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
-                                                    &datastoreInfo) < 0) {
-                goto cleanup;
-            }
+    virCheckNonNullArgGoto(backend, cleanup);
 
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        const virStoragePoolPtr tempPool =
+            backendDrv[i]->poolLookupByName(conn, name);
+        if (tempPool != NULL) {
+            *backend = backendDrv[i];
             break;
         }
     }
 
-    if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
-        *poolType = VIR_STORAGE_POOL_DIR;
-    } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
-        *poolType = VIR_STORAGE_POOL_NETFS;
-    } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
-        *poolType = VIR_STORAGE_POOL_FS;
-    } else {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("DatastoreInfo has unexpected type"));
+    if (*backend == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Could not find storage pool with name '%s'"), name);
         goto cleanup;
     }
 
     result = 0;
 
-  cleanup:
-    esxVI_String_Free(&propertyNameList);
-    esxVI_ObjectContent_Free(&datastore);
-    esxVI_DatastoreInfo_Free(&datastoreInfo);
+cleanup:
 
     return result;
-}
-
 
+}
 
 static virDrvOpenStatus
 esxStorageOpen(virConnectPtr conn,
@@ -114,6 +99,10 @@ esxStorageOpen(virConnectPtr conn,
 
     conn->storagePrivateData = conn->privateData;
 
+    /* set backend driver pointers */
+    backendDrv[ISCSI] = &esxStorageBackendISCSIDrv;
+    backendDrv[VMFS] = &esxStorageBackendVMFSDrv;
+
     return VIR_DRV_OPEN_SUCCESS;
 }
 
@@ -122,6 +111,13 @@ esxStorageOpen(virConnectPtr conn,
 static int
 esxStorageClose(virConnectPtr conn)
 {
+    int i = 0;
+
+    /* reset the backend driver pointers */
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        backendDrv[i] = NULL;
+    }
+
     conn->storagePrivateData = NULL;
 
     return 0;
@@ -132,27 +128,28 @@ esxStorageClose(virConnectPtr conn)
 static int
 esxNumberOfStoragePools(virConnectPtr conn)
 {
-    int count = 0;
     esxPrivate *priv = conn->storagePrivateData;
-    esxVI_ObjectContent *datastoreList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
+    int count = 0;
+    int i = 0;
+    bool success = false;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return -1;
+        goto cleanup;
     }
 
-    if (esxVI_LookupDatastoreList(priv->primary, NULL, &datastoreList) < 0) {
-        return -1;
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        int tempCount = backendDrv[i]->numOfPools(conn);
+        if (tempCount < 0) {
+            goto cleanup;
+        }
+        count += tempCount;
     }
 
-    for (datastore = datastoreList; datastore != NULL;
-         datastore = datastore->_next) {
-        ++count;
-    }
+    success = true;
 
-    esxVI_ObjectContent_Free(&datastoreList);
+  cleanup:
 
-    return count;
+    return success ? count : -1;
 }
 
 
@@ -162,56 +159,32 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
 {
     bool success = false;
     esxPrivate *priv = conn->storagePrivateData;
-    esxVI_String *propertyNameList = NULL;
-    esxVI_DynamicProperty *dynamicProperty = NULL;
-    esxVI_ObjectContent *datastoreList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
     int count = 0;
-    int i;
+    int i = 0;
 
     if (maxnames == 0) {
         return 0;
     }
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return -1;
-    }
-
-    if (esxVI_String_AppendValueToList(&propertyNameList,
-                                       "summary.name") < 0 ||
-        esxVI_LookupDatastoreList(priv->primary, propertyNameList,
-                                  &datastoreList) < 0) {
         goto cleanup;
     }
 
-    for (datastore = datastoreList; datastore != NULL;
-         datastore = datastore->_next) {
-        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
-             dynamicProperty = dynamicProperty->_next) {
-            if (STREQ(dynamicProperty->name, "summary.name")) {
-                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
-                                             esxVI_Type_String) < 0) {
-                    goto cleanup;
-                }
-
-                names[count] = strdup(dynamicProperty->val->string);
-
-                if (names[count] == NULL) {
-                    virReportOOMError();
-                    goto cleanup;
-                }
-
-                ++count;
-                break;
-            } else {
-                VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
-            }
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        int tempCount =
+            backendDrv[i]->listPools(conn, &names[count], maxnames-count);
+
+        if (tempCount < 0) {
+            goto cleanup;
         }
+
+        count += tempCount;
     }
 
     success = true;
 
   cleanup:
+
     if (! success) {
         for (i = 0; i < count; ++i) {
             VIR_FREE(names[i]);
@@ -220,10 +193,8 @@ esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
         count = -1;
     }
 
-    esxVI_String_Free(&propertyNameList);
-    esxVI_ObjectContent_Free(&datastoreList);
-
     return count;
+
 }
 
 
@@ -252,43 +223,31 @@ static virStoragePoolPtr
 esxStoragePoolLookupByName(virConnectPtr conn, const char *name)
 {
     esxPrivate *priv = conn->storagePrivateData;
-    esxVI_ObjectContent *datastore = NULL;
-    esxVI_DatastoreHostMount *hostMount = NULL;
-    unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
     virStoragePoolPtr pool = NULL;
+    int i = 0;
 
-    if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
+    virCheckNonNullArgGoto(name, cleanup);
 
-    if (esxVI_LookupDatastoreByName(priv->primary, name, NULL, &datastore,
-                                    esxVI_Occurrence_RequiredItem) < 0) {
+    if (esxVI_EnsureSession(priv->primary) < 0) {
         goto cleanup;
     }
 
-    /*
-     * Datastores don't have a UUID, but we can use the 'host.mountInfo.path'
-     * property as source for a UUID. The mount path is unique per host and
-     * cannot change during the lifetime of the datastore.
-     *
-     * The MD5 sum of the mount path can be used as UUID, assuming MD5 is
-     * considered to be collision-free enough for this use case.
-     */
-    if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
-                                       &hostMount) < 0) {
-        goto cleanup;
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        pool = backendDrv[i]->poolLookupByName(conn, name);
+        if (pool != NULL) {
+            break;
+        }
     }
 
-    md5_buffer(hostMount->mountInfo->path,
-               strlen(hostMount->mountInfo->path), md5);
-
-    pool = virGetStoragePool(conn, name, md5);
+    if (pool == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Could not find storage pool with name '%s'"), name);
+    }
 
-  cleanup:
-    esxVI_ObjectContent_Free(&datastore);
-    esxVI_DatastoreHostMount_Free(&hostMount);
+cleanup:
 
     return pool;
+
 }
 
 
@@ -297,65 +256,31 @@ static virStoragePoolPtr
 esxStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
 {
     esxPrivate *priv = conn->storagePrivateData;
-    esxVI_String *propertyNameList = NULL;
-    esxVI_ObjectContent *datastoreList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
-    esxVI_DatastoreHostMount *hostMount = NULL;
-    unsigned char md5[MD5_DIGEST_SIZE]; /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */
-    char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
-    char *name = NULL;
     virStoragePoolPtr pool = NULL;
+    int i = 0;
 
-    if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
+    virCheckNonNullArgGoto(uuid, cleanup);
 
-    if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
-        esxVI_LookupDatastoreList(priv->primary, propertyNameList,
-                                  &datastoreList) < 0) {
+    if (esxVI_EnsureSession(priv->primary) < 0) {
         goto cleanup;
     }
 
-    for (datastore = datastoreList; datastore != NULL;
-         datastore = datastore->_next) {
-        esxVI_DatastoreHostMount_Free(&hostMount);
-
-        if (esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
-                                           &hostMount) < 0) {
-            goto cleanup;
-        }
-
-        md5_buffer(hostMount->mountInfo->path,
-                   strlen(hostMount->mountInfo->path), md5);
-
-        if (memcmp(uuid, md5, VIR_UUID_BUFLEN) == 0) {
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        pool = backendDrv[i]->poolLookupByUUID(conn, uuid);
+        if (pool != NULL) {
             break;
         }
     }
 
-    if (datastore == NULL) {
-        virUUIDFormat(uuid, uuid_string);
-
-        virReportError(VIR_ERR_NO_STORAGE_POOL,
-                       _("Could not find datastore with UUID '%s'"),
-                       uuid_string);
-
-        goto cleanup;
-    }
-
-    if (esxVI_GetStringValue(datastore, "summary.name", &name,
-                             esxVI_Occurrence_RequiredItem) < 0) {
-        goto cleanup;
+    if (pool == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Could not find storage pool with uuid '%s'"), uuid);
     }
 
-    pool = virGetStoragePool(conn, name, uuid);
-
-  cleanup:
-    esxVI_String_Free(&propertyNameList);
-    esxVI_ObjectContent_Free(&datastoreList);
-    esxVI_DatastoreHostMount_Free(&hostMount);
+cleanup:
 
     return pool;
+
 }
 
 
@@ -373,26 +298,23 @@ esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
 {
     int result = -1;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    esxVI_ObjectContent *datastore = NULL;
-
-    virCheckFlags(0, -1);
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return -1;
+        goto cleanup;
     }
 
-    if (esxVI_LookupDatastoreByName(priv->primary, pool->name, NULL, &datastore,
-                                    esxVI_Occurrence_RequiredItem) < 0 ||
-        esxVI_RefreshDatastore(priv->primary, datastore->obj) < 0) {
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0 ||
+        backend->poolRefresh(pool, flags) < 0) {
         goto cleanup;
     }
 
     result = 0;
 
   cleanup:
-    esxVI_ObjectContent_Free(&datastore);
 
     return result;
+
 }
 
 
@@ -402,63 +324,25 @@ esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
 {
     int result = -1;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    esxVI_String *propertyNameList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
-    esxVI_DynamicProperty *dynamicProperty = NULL;
-    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+    virStorageDriverPtr backend = NULL;
 
     memset(info, 0, sizeof(*info));
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return -1;
-    }
-
-    if (esxVI_String_AppendValueListToList(&propertyNameList,
-                                           "summary.accessible\0"
-                                           "summary.capacity\0"
-                                           "summary.freeSpace\0") < 0 ||
-        esxVI_LookupDatastoreByName(priv->primary, pool->name,
-                                    propertyNameList, &datastore,
-                                    esxVI_Occurrence_RequiredItem) < 0 ||
-        esxVI_GetBoolean(datastore, "summary.accessible",
-                         &accessible, esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
 
-    if (accessible == esxVI_Boolean_True) {
-        info->state = VIR_STORAGE_POOL_RUNNING;
-
-        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
-             dynamicProperty = dynamicProperty->_next) {
-            if (STREQ(dynamicProperty->name, "summary.capacity")) {
-                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
-                                             esxVI_Type_Long) < 0) {
-                    goto cleanup;
-                }
-
-                info->capacity = dynamicProperty->val->int64;
-            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
-                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
-                                             esxVI_Type_Long) < 0) {
-                    goto cleanup;
-                }
-
-                info->available = dynamicProperty->val->int64;
-            }
-        }
-
-        info->allocation = info->capacity - info->available;
-    } else {
-        info->state = VIR_STORAGE_POOL_INACCESSIBLE;
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0 ||
+        backend->poolGetInfo(pool, info) < 0) {
+        goto cleanup;
     }
 
     result = 0;
 
   cleanup:
-    esxVI_String_Free(&propertyNameList);
-    esxVI_ObjectContent_Free(&datastore);
 
     return result;
+
 }
 
 
@@ -466,123 +350,24 @@ esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
 static char *
 esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
 {
-    esxPrivate *priv = pool->conn->storagePrivateData;
-    esxVI_String *propertyNameList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
-    esxVI_DatastoreHostMount *hostMount = NULL;
-    esxVI_DynamicProperty *dynamicProperty = NULL;
-    esxVI_Boolean accessible = esxVI_Boolean_Undefined;
-    virStoragePoolDef def;
-    esxVI_DatastoreInfo *info = NULL;
-    esxVI_NasDatastoreInfo *nasInfo = NULL;
     char *xml = NULL;
-
-    virCheckFlags(0, NULL);
-
-    memset(&def, 0, sizeof(def));
+    esxPrivate *priv = pool->conn->storagePrivateData;
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
-
-    if (esxVI_String_AppendValueListToList(&propertyNameList,
-                                           "summary.accessible\0"
-                                           "summary.capacity\0"
-                                           "summary.freeSpace\0"
-                                           "info\0") < 0 ||
-        esxVI_LookupDatastoreByName(priv->primary, pool->name,
-                                    propertyNameList, &datastore,
-                                    esxVI_Occurrence_RequiredItem) < 0 ||
-        esxVI_GetBoolean(datastore, "summary.accessible",
-                         &accessible, esxVI_Occurrence_RequiredItem) < 0 ||
-        esxVI_LookupDatastoreHostMount(priv->primary, datastore->obj,
-                                       &hostMount) < 0) {
         goto cleanup;
     }
 
-    def.name = pool->name;
-    memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
-
-    def.target.path = hostMount->mountInfo->path;
-
-    if (accessible == esxVI_Boolean_True) {
-        for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
-             dynamicProperty = dynamicProperty->_next) {
-            if (STREQ(dynamicProperty->name, "summary.capacity")) {
-                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
-                                             esxVI_Type_Long) < 0) {
-                    goto cleanup;
-                }
-
-                def.capacity = dynamicProperty->val->int64;
-            } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
-                if (esxVI_AnyType_ExpectType(dynamicProperty->val,
-                                             esxVI_Type_Long) < 0) {
-                    goto cleanup;
-                }
-
-                def.available = dynamicProperty->val->int64;
-            }
-        }
-
-        def.allocation = def.capacity - def.available;
-    }
-
-    for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
-         dynamicProperty = dynamicProperty->_next) {
-        if (STREQ(dynamicProperty->name, "info")) {
-            if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
-                                                    &info) < 0) {
-                goto cleanup;
-            }
-
-            break;
-        }
-    }
-
-    /* See vSphere API documentation about HostDatastoreSystem for details */
-    if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
-        def.type = VIR_STORAGE_POOL_DIR;
-    } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
-        if (VIR_ALLOC_N(def.source.hosts, 1) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-        def.type = VIR_STORAGE_POOL_NETFS;
-        def.source.hosts[0].name = nasInfo->nas->remoteHost;
-        def.source.dir = nasInfo->nas->remotePath;
-
-        if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
-            def.source.format = VIR_STORAGE_POOL_NETFS_NFS;
-        } else  if (STRCASEEQ(nasInfo->nas->type, "CIFS")) {
-            def.source.format = VIR_STORAGE_POOL_NETFS_CIFS;
-        } else {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Datastore has unexpected type '%s'"),
-                           nasInfo->nas->type);
-            goto cleanup;
-        }
-    } else if (esxVI_VmfsDatastoreInfo_DynamicCast(info) != NULL) {
-        def.type = VIR_STORAGE_POOL_FS;
-        /*
-         * FIXME: I'm not sure how to represent the source and target of a
-         * VMFS based datastore in libvirt terms
-         */
-    } else {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("DatastoreInfo has unexpected type"));
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
         goto cleanup;
     }
 
-    xml = virStoragePoolDefFormat(&def);
+    xml = backend->poolGetXMLDesc(pool, flags);
 
   cleanup:
-    esxVI_String_Free(&propertyNameList);
-    esxVI_ObjectContent_Free(&datastore);
-    esxVI_DatastoreHostMount_Free(&hostMount);
-    esxVI_DatastoreInfo_Free(&info);
 
     return xml;
+
 }
 
 
@@ -622,33 +407,25 @@ esxStoragePoolNumberOfStorageVolumes(virStoragePoolPtr pool)
 {
     bool success = false;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
-    esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
+    virStorageDriverPtr backend = NULL;
     int count = 0;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return -1;
+        goto cleanup;
     }
 
-    if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
-                                                    &searchResultsList) < 0) {
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
         goto cleanup;
     }
 
-    /* Interpret search result */
-    for (searchResults = searchResultsList; searchResults != NULL;
-         searchResults = searchResults->_next) {
-        for (fileInfo = searchResults->file; fileInfo != NULL;
-             fileInfo = fileInfo->_next) {
-            ++count;
-        }
+    count = backend->poolNumOfVolumes(pool);
+    if (count < 0) {
+        goto cleanup;
     }
 
     success = true;
 
   cleanup:
-    esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
 
     return success ? count : -1;
 }
@@ -659,87 +436,25 @@ static int
 esxStoragePoolListStorageVolumes(virStoragePoolPtr pool, char **const names,
                                  int maxnames)
 {
-    bool success = false;
+    int result = -1;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
-    esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
-    char *directoryAndFileName = NULL;
-    size_t length;
-    int count = 0;
-    int i;
-
-    if (names == NULL || maxnames < 0) {
-        virReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
-        return -1;
-    }
-
-    if (maxnames == 0) {
-        return 0;
-    }
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return -1;
-    }
-
-    if (esxVI_LookupDatastoreContentByDatastoreName(priv->primary, pool->name,
-                                                    &searchResultsList) < 0) {
         goto cleanup;
     }
 
-    /* Interpret search result */
-    for (searchResults = searchResultsList; searchResults != NULL;
-         searchResults = searchResults->_next) {
-        VIR_FREE(directoryAndFileName);
-
-        if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL, NULL,
-                                       &directoryAndFileName) < 0) {
-            goto cleanup;
-        }
-
-        /* Strip trailing separators */
-        length = strlen(directoryAndFileName);
-
-        while (length > 0 && directoryAndFileName[length - 1] == '/') {
-            directoryAndFileName[length - 1] = '\0';
-            --length;
-        }
-
-        /* Build volume names */
-        for (fileInfo = searchResults->file; fileInfo != NULL;
-             fileInfo = fileInfo->_next) {
-            if (length < 1) {
-                names[count] = strdup(fileInfo->path);
-
-                if (names[count] == NULL) {
-                    virReportOOMError();
-                    goto cleanup;
-                }
-            } else if (virAsprintf(&names[count], "%s/%s", directoryAndFileName,
-                                   fileInfo->path) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-
-            ++count;
-        }
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0 ||
+        backend->poolListVolumes(pool, names, maxnames) < 0) {
+        goto cleanup;
     }
 
-    success = true;
+    result = 0;
 
   cleanup:
-    if (! success) {
-        for (i = 0; i < count; ++i) {
-            VIR_FREE(names[i]);
-        }
 
-        count = -1;
-    }
-
-    esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
-    VIR_FREE(directoryAndFileName);
+    return result;
 
-    return count;
 }
 
 
@@ -749,30 +464,24 @@ esxStorageVolumeLookupByName(virStoragePoolPtr pool, const char *name)
 {
     virStorageVolPtr volume = NULL;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    char *datastorePath = NULL;
-    char *key = NULL;
+    virStorageDriverPtr backend = NULL;
 
-    if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
+    virCheckNonNullArgGoto(name, cleanup);
 
-    if (virAsprintf(&datastorePath, "[%s] %s", pool->name, name) < 0) {
-        virReportOOMError();
+    if (esxVI_EnsureSession(priv->primary) < 0) {
         goto cleanup;
     }
 
-    if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary,
-                                                    datastorePath, &key) < 0) {
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
         goto cleanup;
     }
 
-    volume = virGetStorageVol(pool->conn, pool->name, name, key);
+    volume = backend->volLookupByName(pool, name);
 
   cleanup:
-    VIR_FREE(datastorePath);
-    VIR_FREE(key);
 
     return volume;
+
 }
 
 
@@ -782,32 +491,33 @@ esxStorageVolumeLookupByPath(virConnectPtr conn, const char *path)
 {
     virStorageVolPtr volume = NULL;
     esxPrivate *priv = conn->storagePrivateData;
-    char *datastoreName = NULL;
-    char *directoryAndFileName = NULL;
-    char *key = NULL;
 
-    if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
+    virCheckNonNullArgGoto(path, cleanup);
 
-    if (esxUtil_ParseDatastorePath(path, &datastoreName, NULL,
-                                   &directoryAndFileName) < 0) {
+    if (esxVI_EnsureSession(priv->primary) < 0) {
         goto cleanup;
     }
 
-    if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, path,
-                                                    &key) < 0) {
-        goto cleanup;
+    /* FIXME: calling backend blindly may set unwanted error codes
+     *
+     * VMFS Datastore path follows cannonical format i.e.:
+     * [<datastore_name>] <file_path>
+     *          WHEREAS
+     * iSCSI LUNs device path follows normal linux path convention
+     */
+    if (STRPREFIX(path, "[")) {
+        volume = backendDrv[VMFS]->volLookupByPath(conn, path);
+    } else if (STRPREFIX(path, "/")) {
+        volume = backendDrv[ISCSI]->volLookupByPath(conn, path);
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+          _("Unexpected volume path format: %s"), path);
     }
 
-    volume = virGetStorageVol(conn, datastoreName, directoryAndFileName, key);
-
-  cleanup:
-    VIR_FREE(datastoreName);
-    VIR_FREE(directoryAndFileName);
-    VIR_FREE(key);
+cleanup:
 
     return volume;
+
 }
 
 
@@ -817,140 +527,29 @@ esxStorageVolumeLookupByKey(virConnectPtr conn, const char *key)
 {
     virStorageVolPtr volume = NULL;
     esxPrivate *priv = conn->storagePrivateData;
-    esxVI_String *propertyNameList = NULL;
-    esxVI_ObjectContent *datastoreList = NULL;
-    esxVI_ObjectContent *datastore = NULL;
-    char *datastoreName = NULL;
-    esxVI_HostDatastoreBrowserSearchResults *searchResultsList = NULL;
-    esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
-    char *directoryAndFileName = NULL;
-    size_t length;
-    char *datastorePath = NULL;
-    char *volumeName = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
-    char *uuid_string = NULL;
-    char key_candidate[VIR_UUID_STRING_BUFLEN] = "";
-
-    if (STRPREFIX(key, "[")) {
-        /* Key is probably a datastore path */
-        return esxStorageVolumeLookupByPath(conn, key);
-    }
+    int i = 0;
 
-    if (!priv->primary->hasQueryVirtualDiskUuid) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("QueryVirtualDiskUuid not available, cannot lookup storage "
-                         "volume by UUID"));
-        return NULL;
-    }
+    virCheckNonNullArgGoto(key, cleanup);
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
-
-    /* Lookup all datastores */
-    if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
-        esxVI_LookupDatastoreList(priv->primary, propertyNameList,
-                                  &datastoreList) < 0) {
         goto cleanup;
     }
 
-    for (datastore = datastoreList; datastore != NULL;
-         datastore = datastore->_next) {
-        datastoreName = NULL;
-
-        if (esxVI_GetStringValue(datastore, "summary.name", &datastoreName,
-                                 esxVI_Occurrence_RequiredItem) < 0) {
-            goto cleanup;
-        }
-
-        /* Lookup datastore content */
-        esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
-
-        if (esxVI_LookupDatastoreContentByDatastoreName
-              (priv->primary, datastoreName, &searchResultsList) < 0) {
-            goto cleanup;
-        }
-
-        /* Interpret search result */
-        for (searchResults = searchResultsList; searchResults != NULL;
-             searchResults = searchResults->_next) {
-            VIR_FREE(directoryAndFileName);
-
-            if (esxUtil_ParseDatastorePath(searchResults->folderPath, NULL,
-                                           NULL, &directoryAndFileName) < 0) {
-                goto cleanup;
-            }
-
-            /* Strip trailing separators */
-            length = strlen(directoryAndFileName);
-
-            while (length > 0 && directoryAndFileName[length - 1] == '/') {
-                directoryAndFileName[length - 1] = '\0';
-                --length;
-            }
-
-            /* Build datastore path and query the UUID */
-            for (fileInfo = searchResults->file; fileInfo != NULL;
-                 fileInfo = fileInfo->_next) {
-                VIR_FREE(datastorePath);
-
-                if (length < 1) {
-                    if (virAsprintf(&volumeName, "%s",
-                                    fileInfo->path) < 0) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-                } else if (virAsprintf(&volumeName, "%s/%s",
-                                       directoryAndFileName,
-                                       fileInfo->path) < 0) {
-                    virReportOOMError();
-                    goto cleanup;
-                }
-
-                if (virAsprintf(&datastorePath, "[%s] %s", datastoreName,
-                                volumeName) < 0) {
-                    virReportOOMError();
-                    goto cleanup;
-                }
-
-                if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo) == NULL) {
-                    /* Only a VirtualDisk has a UUID */
-                    continue;
-                }
-
-                VIR_FREE(uuid_string);
-
-                if (esxVI_QueryVirtualDiskUuid
-                      (priv->primary, datastorePath,
-                       priv->primary->datacenter->_reference,
-                       &uuid_string) < 0) {
-                    goto cleanup;
-                }
-
-                if (esxUtil_ReformatUuid(uuid_string, key_candidate) < 0) {
-                    goto cleanup;
-                }
-
-                if (STREQ(key, key_candidate)) {
-                    /* Found matching UUID */
-                    volume = virGetStorageVol(conn, datastoreName,
-                                              volumeName, key);
-                    goto cleanup;
-                }
-            }
+    /* lookup by key operation is supported using connection
+     * pointer, so poke all supported backend drivers to perform
+     * the desired operation
+     */
+    for (i = 0; i < LAST_DRIVER; ++i) {
+        volume = backendDrv[i]->volLookupByKey(conn, key);
+        if (volume != NULL) {
+            break;
         }
     }
 
-  cleanup:
-    esxVI_String_Free(&propertyNameList);
-    esxVI_ObjectContent_Free(&datastoreList);
-    esxVI_HostDatastoreBrowserSearchResults_Free(&searchResultsList);
-    VIR_FREE(directoryAndFileName);
-    VIR_FREE(datastorePath);
-    VIR_FREE(volumeName);
-    VIR_FREE(uuid_string);
+cleanup:
 
     return volume;
+
 }
 
 
@@ -961,224 +560,24 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
 {
     virStorageVolPtr volume = NULL;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    virStoragePoolDef poolDef;
-    virStorageVolDefPtr def = NULL;
-    char *tmp;
-    char *unescapedDatastorePath = NULL;
-    char *unescapedDirectoryName = NULL;
-    char *unescapedDirectoryAndFileName = NULL;
-    char *directoryName = NULL;
-    char *fileName = NULL;
-    char *datastorePathWithoutFileName = NULL;
-    char *datastorePath = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
-    esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
-    esxVI_ManagedObjectReference *task = NULL;
-    esxVI_TaskInfoState taskInfoState;
-    char *taskInfoErrorMessage = NULL;
-    char *uuid_string = NULL;
-    char *key = NULL;
-
-    virCheckFlags(0, NULL);
-
-    memset(&poolDef, 0, sizeof(poolDef));
-
-    if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
-
-    if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
-        return NULL;
-    }
-
-    /* Parse config */
-    def = virStorageVolDefParseString(&poolDef, xmldesc);
+    virStorageDriverPtr backend = NULL;
 
-    if (def == NULL) {
-        goto cleanup;
-    }
-
-    if (def->type != VIR_STORAGE_VOL_FILE) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Creating non-file volumes is not supported"));
-        goto cleanup;
-    }
-
-    /* Validate config */
-    tmp = strrchr(def->name, '/');
-
-    if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Volume name '%s' doesn't have expected format "
-                         "'<directory>/<file>'"), def->name);
-        goto cleanup;
-    }
+    virCheckNonNullArgGoto(xmldesc, cleanup);
 
-    if (! virFileHasSuffix(def->name, ".vmdk")) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
-                       def->name);
+    if (esxVI_EnsureSession(priv->primary) < 0) {
         goto cleanup;
     }
 
-    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
-                    def->name) < 0) {
-        virReportOOMError();
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
         goto cleanup;
     }
 
-    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
-        /* Parse and escape datastore path */
-        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
-                                       &unescapedDirectoryName,
-                                       &unescapedDirectoryAndFileName) < 0) {
-            goto cleanup;
-        }
-
-        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
-
-        if (directoryName == NULL) {
-            goto cleanup;
-        }
-
-        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
-                                               strlen(unescapedDirectoryName) + 1);
-
-        if (fileName == NULL) {
-            goto cleanup;
-        }
-
-        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
-                        directoryName) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
-                        fileName) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        /* Create directory, if it doesn't exist yet */
-        if (esxVI_LookupFileInfoByDatastorePath
-              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
-               esxVI_Occurrence_OptionalItem) < 0) {
-            goto cleanup;
-        }
-
-        if (fileInfo == NULL) {
-            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
-                                    priv->primary->datacenter->_reference,
-                                    esxVI_Boolean_True) < 0) {
-                goto cleanup;
-            }
-        }
-
-        /* Create VirtualDisk */
-        if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
-            esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
-            goto cleanup;
-        }
-
-        /* From the vSphere API documentation about VirtualDiskType ... */
-        if (def->allocation == def->capacity) {
-            /*
-             * "A preallocated disk has all space allocated at creation time
-             *  and the space is zeroed on demand as the space is used."
-             */
-            virtualDiskSpec->diskType = (char *)"preallocated";
-        } else if (def->allocation == 0) {
-            /*
-             * "Space required for thin-provisioned virtual disk is allocated
-             *  and zeroed on demand as the space is used."
-             */
-            virtualDiskSpec->diskType = (char *)"thin";
-        } else {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("Unsupported capacity-to-allocation relation"));
-            goto cleanup;
-        }
-
-        /*
-         * FIXME: The adapter type is a required parameter, but there is no
-         * way to let the user specify it in the volume XML config. Therefore,
-         * default to 'busLogic' here.
-         */
-        virtualDiskSpec->adapterType = (char *)"busLogic";
-
-        virtualDiskSpec->capacityKb->value =
-          VIR_DIV_UP(def->capacity, 1024); /* Scale from byte to kilobyte */
-
-        if (esxVI_CreateVirtualDisk_Task
-              (priv->primary, datastorePath, priv->primary->datacenter->_reference,
-               esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
-            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
-                                        esxVI_Occurrence_None,
-                                        priv->parsedUri->autoAnswer,
-                                        &taskInfoState,
-                                        &taskInfoErrorMessage) < 0) {
-            goto cleanup;
-        }
-
-        if (taskInfoState != esxVI_TaskInfoState_Success) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"),
-                           taskInfoErrorMessage);
-            goto cleanup;
-        }
-
-        if (priv->primary->hasQueryVirtualDiskUuid) {
-            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-
-            if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
-                                           priv->primary->datacenter->_reference,
-                                           &uuid_string) < 0) {
-                goto cleanup;
-            }
-
-            if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
-                goto cleanup;
-            }
-        } else {
-            /* Fall back to the path as key */
-            if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
-                goto cleanup;
-            }
-        }
-    } else {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Creation of %s volumes is not supported"),
-                       virStorageFileFormatTypeToString(def->target.format));
-        goto cleanup;
-    }
-
-    volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+    volume = backend->volCreateXML(pool, xmldesc, flags);
 
   cleanup:
-    if (virtualDiskSpec != NULL) {
-        virtualDiskSpec->diskType = NULL;
-        virtualDiskSpec->adapterType = NULL;
-    }
-
-    virStorageVolDefFree(def);
-    VIR_FREE(unescapedDatastorePath);
-    VIR_FREE(unescapedDirectoryName);
-    VIR_FREE(unescapedDirectoryAndFileName);
-    VIR_FREE(directoryName);
-    VIR_FREE(fileName);
-    VIR_FREE(datastorePathWithoutFileName);
-    VIR_FREE(datastorePath);
-    esxVI_FileInfo_Free(&fileInfo);
-    esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
-    esxVI_ManagedObjectReference_Free(&task);
-    VIR_FREE(taskInfoErrorMessage);
-    VIR_FREE(uuid_string);
-    VIR_FREE(key);
 
     return volume;
+
 }
 
 
@@ -1189,193 +588,24 @@ esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
 {
     virStorageVolPtr volume = NULL;
     esxPrivate *priv = pool->conn->storagePrivateData;
-    virStoragePoolDef poolDef;
-    char *sourceDatastorePath = NULL;
-    virStorageVolDefPtr def = NULL;
-    char *tmp;
-    char *unescapedDatastorePath = NULL;
-    char *unescapedDirectoryName = NULL;
-    char *unescapedDirectoryAndFileName = NULL;
-    char *directoryName = NULL;
-    char *fileName = NULL;
-    char *datastorePathWithoutFileName = NULL;
-    char *datastorePath = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
-    esxVI_ManagedObjectReference *task = NULL;
-    esxVI_TaskInfoState taskInfoState;
-    char *taskInfoErrorMessage = NULL;
-    char *uuid_string = NULL;
-    char *key = NULL;
-
-    virCheckFlags(0, NULL);
-
-    memset(&poolDef, 0, sizeof(poolDef));
-
-    if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
-
-    if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
-        return NULL;
-    }
-
-    if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool,
-                    sourceVolume->name) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    /* Parse config */
-    def = virStorageVolDefParseString(&poolDef, xmldesc);
-
-    if (def == NULL) {
-        goto cleanup;
-    }
-
-    if (def->type != VIR_STORAGE_VOL_FILE) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Creating non-file volumes is not supported"));
-        goto cleanup;
-    }
-
-    /* Validate config */
-    tmp = strrchr(def->name, '/');
+    virStorageDriverPtr backend = NULL;
 
-    if (tmp == NULL || *def->name == '/' || tmp[1] == '\0') {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Volume name '%s' doesn't have expected format "
-                         "'<directory>/<file>'"), def->name);
-        goto cleanup;
-    }
+    virCheckNonNullArgGoto(xmldesc, cleanup);
 
-    if (! virFileHasSuffix(def->name, ".vmdk")) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Volume name '%s' has unsupported suffix, expecting '.vmdk'"),
-                       def->name);
+    if (esxVI_EnsureSession(priv->primary) < 0) {
         goto cleanup;
     }
 
-    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
-                    def->name) < 0) {
-        virReportOOMError();
+    if (esxStorageGetBackendDriver(pool->conn, pool->name, &backend) < 0) {
         goto cleanup;
     }
 
-    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
-        /* Parse and escape datastore path */
-        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
-                                       &unescapedDirectoryName,
-                                       &unescapedDirectoryAndFileName) < 0) {
-            goto cleanup;
-        }
-
-        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);
-
-        if (directoryName == NULL) {
-            goto cleanup;
-        }
-
-        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
-                                               strlen(unescapedDirectoryName) + 1);
-
-        if (fileName == NULL) {
-            goto cleanup;
-        }
-
-        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
-                        directoryName) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
-                        fileName) < 0) {
-            virReportOOMError();
-            goto cleanup;
-        }
-
-        /* Create directory, if it doesn't exist yet */
-        if (esxVI_LookupFileInfoByDatastorePath
-              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
-               esxVI_Occurrence_OptionalItem) < 0) {
-            goto cleanup;
-        }
-
-        if (fileInfo == NULL) {
-            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
-                                    priv->primary->datacenter->_reference,
-                                    esxVI_Boolean_True) < 0) {
-                goto cleanup;
-            }
-        }
-
-        /* Copy VirtualDisk */
-        if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
-                                       priv->primary->datacenter->_reference,
-                                       datastorePath,
-                                       priv->primary->datacenter->_reference,
-                                       NULL, esxVI_Boolean_False, &task) < 0 ||
-            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
-                                        esxVI_Occurrence_None,
-                                        priv->parsedUri->autoAnswer,
-                                        &taskInfoState,
-                                        &taskInfoErrorMessage) < 0) {
-            goto cleanup;
-        }
-
-        if (taskInfoState != esxVI_TaskInfoState_Success) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
-                           taskInfoErrorMessage);
-            goto cleanup;
-        }
-
-        if (priv->primary->hasQueryVirtualDiskUuid) {
-            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-
-            if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
-                                           priv->primary->datacenter->_reference,
-                                           &uuid_string) < 0) {
-                goto cleanup;
-            }
-
-            if (esxUtil_ReformatUuid(uuid_string, key) < 0) {
-                goto cleanup;
-            }
-        } else {
-            /* Fall back to the path as key */
-            if (esxVI_String_DeepCopyValue(&key, datastorePath) < 0) {
-                goto cleanup;
-            }
-        }
-    } else {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Creation of %s volumes is not supported"),
-                       virStorageFileFormatTypeToString(def->target.format));
-        goto cleanup;
-    }
-
-    volume = virGetStorageVol(pool->conn, pool->name, def->name, key);
+    volume = backend->volCreateXMLFrom(pool, xmldesc, sourceVolume, flags);
 
   cleanup:
-    VIR_FREE(sourceDatastorePath);
-    virStorageVolDefFree(def);
-    VIR_FREE(unescapedDatastorePath);
-    VIR_FREE(unescapedDirectoryName);
-    VIR_FREE(unescapedDirectoryAndFileName);
-    VIR_FREE(directoryName);
-    VIR_FREE(fileName);
-    VIR_FREE(datastorePathWithoutFileName);
-    VIR_FREE(datastorePath);
-    esxVI_FileInfo_Free(&fileInfo);
-    esxVI_ManagedObjectReference_Free(&task);
-    VIR_FREE(taskInfoErrorMessage);
-    VIR_FREE(uuid_string);
-    VIR_FREE(key);
 
     return volume;
+
 }
 
 
@@ -1383,48 +613,19 @@ esxStorageVolumeCreateXMLFrom(virStoragePoolPtr pool, const char *xmldesc,
 static int
 esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags)
 {
-    int result = -1;
     esxPrivate *priv = volume->conn->storagePrivateData;
-    char *datastorePath = NULL;
-    esxVI_ManagedObjectReference *task = NULL;
-    esxVI_TaskInfoState taskInfoState;
-    char *taskInfoErrorMessage = NULL;
-
-    virCheckFlags(0, -1);
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
         return -1;
     }
 
-    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    if (esxVI_DeleteVirtualDisk_Task(priv->primary, datastorePath,
-                                     priv->primary->datacenter->_reference,
-                                     &task) < 0 ||
-        esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
-                                    esxVI_Occurrence_None,
-                                    priv->parsedUri->autoAnswer,
-                                    &taskInfoState, &taskInfoErrorMessage) < 0) {
-        goto cleanup;
-    }
-
-    if (taskInfoState != esxVI_TaskInfoState_Success) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not delete volume: %s"),
-                       taskInfoErrorMessage);
-        goto cleanup;
+    if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0 ||
+        backend->volDelete(volume , flags) < 0) {
+        return -1;
     }
 
-    result = 0;
-
-  cleanup:
-    VIR_FREE(datastorePath);
-    esxVI_ManagedObjectReference_Free(&task);
-    VIR_FREE(taskInfoErrorMessage);
-
-    return result;
+    return 0;
 }
 
 
@@ -1432,97 +633,39 @@ esxStorageVolumeDelete(virStorageVolPtr volume, unsigned int flags)
 static int
 esxStorageVolumeWipe(virStorageVolPtr volume, unsigned int flags)
 {
-    int result = -1;
     esxPrivate *priv = volume->conn->storagePrivateData;
-    char *datastorePath = NULL;
-    esxVI_ManagedObjectReference *task = NULL;
-    esxVI_TaskInfoState taskInfoState;
-    char *taskInfoErrorMessage = NULL;
-
-    virCheckFlags(0, -1);
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
         return -1;
     }
 
-    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    if (esxVI_ZeroFillVirtualDisk_Task(priv->primary, datastorePath,
-                                       priv->primary->datacenter->_reference,
-                                       &task) < 0 ||
-        esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
-                                    esxVI_Occurrence_None,
-                                    priv->parsedUri->autoAnswer,
-                                    &taskInfoState, &taskInfoErrorMessage) < 0) {
-        goto cleanup;
-    }
-
-    if (taskInfoState != esxVI_TaskInfoState_Success) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not wipe volume: %s"),
-                       taskInfoErrorMessage);
-        goto cleanup;
+    if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0 ||
+        backend->volDelete(volume , flags) < 0) {
+        return -1;
     }
 
-    result = 0;
-
-  cleanup:
-    VIR_FREE(datastorePath);
-    esxVI_ManagedObjectReference_Free(&task);
-    VIR_FREE(taskInfoErrorMessage);
-
-    return result;
+    return 0;
 }
 
 
-
 static int
 esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
 {
-    int result = -1;
     esxPrivate *priv = volume->conn->storagePrivateData;
-    char *datastorePath = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
-    esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
-
-    memset(info, 0, sizeof(*info));
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
         return -1;
     }
 
-    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
-                                            false, &fileInfo,
-                                            esxVI_Occurrence_RequiredItem) < 0) {
-        goto cleanup;
-    }
-
-    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
-
-    info->type = VIR_STORAGE_VOL_FILE;
-
-    if (vmDiskFileInfo != NULL) {
-        info->capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
-        info->allocation = vmDiskFileInfo->fileSize->value;
-    } else {
-        info->capacity = fileInfo->fileSize->value;
-        info->allocation = fileInfo->fileSize->value;
+    if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0 ||
+        backend->volGetInfo(volume , info) < 0) {
+        return -1;
     }
 
-    result = 0;
-
-  cleanup:
-    VIR_FREE(datastorePath);
-    esxVI_FileInfo_Free(&fileInfo);
+    return 0;
 
-    return result;
 }
 
 
@@ -1530,84 +673,24 @@ esxStorageVolumeGetInfo(virStorageVolPtr volume, virStorageVolInfoPtr info)
 static char *
 esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
 {
-    esxPrivate *priv = volume->conn->storagePrivateData;
-    virStoragePoolDef pool;
-    char *datastorePath = NULL;
-    esxVI_FileInfo *fileInfo = NULL;
-    esxVI_VmDiskFileInfo *vmDiskFileInfo = NULL;
-    esxVI_IsoImageFileInfo *isoImageFileInfo = NULL;
-    esxVI_FloppyImageFileInfo *floppyImageFileInfo = NULL;
-    virStorageVolDef def;
     char *xml = NULL;
-
-    virCheckFlags(0, NULL);
-
-    memset(&pool, 0, sizeof(pool));
-    memset(&def, 0, sizeof(def));
+    esxPrivate *priv = volume->conn->storagePrivateData;
+    virStorageDriverPtr backend = NULL;
 
     if (esxVI_EnsureSession(priv->primary) < 0) {
-        return NULL;
-    }
-
-    if (esxStoragePoolLookupType(priv->primary, volume->pool, &pool.type) < 0) {
-        return NULL;
-    }
-
-    /* Lookup file info */
-    if (virAsprintf(&datastorePath, "[%s] %s", volume->pool, volume->name) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    if (esxVI_LookupFileInfoByDatastorePath(priv->primary, datastorePath,
-                                            false, &fileInfo,
-                                            esxVI_Occurrence_RequiredItem) < 0) {
         goto cleanup;
     }
 
-    vmDiskFileInfo = esxVI_VmDiskFileInfo_DynamicCast(fileInfo);
-    isoImageFileInfo = esxVI_IsoImageFileInfo_DynamicCast(fileInfo);
-    floppyImageFileInfo = esxVI_FloppyImageFileInfo_DynamicCast(fileInfo);
-
-    def.name = volume->name;
-
-    if (esxVI_LookupStorageVolumeKeyByDatastorePath(priv->primary, datastorePath,
-                                                    &def.key) < 0) {
-        goto cleanup;
-    }
-
-    def.type = VIR_STORAGE_VOL_FILE;
-    def.target.path = datastorePath;
-
-    if (vmDiskFileInfo != NULL) {
-        def.capacity = vmDiskFileInfo->capacityKb->value * 1024; /* Scale from kilobyte to byte */
-        def.allocation = vmDiskFileInfo->fileSize->value;
-
-        def.target.format = VIR_STORAGE_FILE_VMDK;
-    } else if (isoImageFileInfo != NULL) {
-        def.capacity = fileInfo->fileSize->value;
-        def.allocation = fileInfo->fileSize->value;
-
-        def.target.format = VIR_STORAGE_FILE_ISO;
-    } else if (floppyImageFileInfo != NULL) {
-        def.capacity = fileInfo->fileSize->value;
-        def.allocation = fileInfo->fileSize->value;
-
-        def.target.format = VIR_STORAGE_FILE_RAW;
-    } else {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("File '%s' has unknown type"), datastorePath);
+    if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0) {
         goto cleanup;
     }
 
-    xml = virStorageVolDefFormat(&pool, &def);
+    xml = backend->volGetXMLDesc(volume, flags);
 
-  cleanup:
-    VIR_FREE(datastorePath);
-    esxVI_FileInfo_Free(&fileInfo);
-    VIR_FREE(def.key);
+ cleanup:
 
     return xml;
+
 }
 
 
@@ -1615,14 +698,24 @@ esxStorageVolumeGetXMLDesc(virStorageVolPtr volume, unsigned int flags)
 static char *
 esxStorageVolumeGetPath(virStorageVolPtr volume)
 {
-    char *path;
+    char *path = NULL;
+    esxPrivate *priv = volume->conn->storagePrivateData;
+    virStorageDriverPtr backend = NULL;
 
-    if (virAsprintf(&path, "[%s] %s", volume->pool, volume->name) < 0) {
-        virReportOOMError();
-        return NULL;
+    if (esxVI_EnsureSession(priv->primary) < 0) {
+        goto cleanup;
     }
 
+    if (esxStorageGetBackendDriver(volume->conn, volume->pool, &backend) < 0) {
+        goto cleanup;
+    }
+
+    path = backend->volGetPath(volume);
+
+  cleanup:
+
     return path;
+
 }
 
 
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 65e1d9a..0e647d4 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -3011,7 +3011,7 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
 
     if (*datastore == NULL && occurrence != esxVI_Occurrence_OptionalItem) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Could not find datastore with name '%s'"), name);
+          _("Could not find datastore with name '%s'"), name);
         goto cleanup;
     }
 
@@ -3118,7 +3118,8 @@ esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx,
 int
 esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
                                esxVI_ManagedObjectReference *datastore,
-                               esxVI_DatastoreHostMount **hostMount)
+                               esxVI_DatastoreHostMount **hostMount,
+                               esxVI_Occurrence occurrence)
 {
     int result = -1;
     esxVI_String *propertyNameList = NULL;
@@ -3166,9 +3167,9 @@ esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
         break;
     }
 
-    if (*hostMount == NULL) {
+    if (*hostMount == NULL && occurrence != esxVI_Occurrence_OptionalItem) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Could not lookup datastore host mount"));
+          _("Could not lookup datastore host mount"));
         goto cleanup;
     }
 
@@ -4883,5 +4884,337 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx,
 }
 
 
+int
+esxVI_LookupHostInternetScsiHbaStaticTargetByName(
+  esxVI_Context *ctx,
+  const char *name,
+  esxVI_HostInternetScsiHbaStaticTarget **ret,
+  esxVI_Occurrence occurrence)
+{
+    int result = -1;
+    esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
+    const esxVI_HostInternetScsiHbaStaticTarget *target = NULL;
+
+    if (esxVI_LookupHostInternetScsiHba(ctx, &hostInternetScsiHba) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+          _("Unable to obtain hostInternetScsiHba"));
+        goto cleanup;
+    }
+
+    if (hostInternetScsiHba == NULL) {
+        /* iSCSI adapter may not be enabled for this host */
+        return 0;
+    }
+
+    if (hostInternetScsiHba->configuredStaticTarget) {
+        for (target = hostInternetScsiHba->configuredStaticTarget;
+          target != NULL; target = target->_next) {
+            if (STREQ(target->iScsiName, name)) {
+                break;
+            }
+        }
+    }
+
+    if (target == NULL) {
+        if (occurrence == esxVI_Occurrence_RequiredItem) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+              _("Could not find storage pool with name: %s"), name);
+        }
+        goto cleanup;
+    }
+
+    if (esxVI_HostInternetScsiHbaStaticTarget_DeepCopy(
+          ret, (esxVI_HostInternetScsiHbaStaticTarget *)target) < 0) {
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+
+    esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
+
+    return result;
+}
+
+
+int
+esxVI_LookupHostInternetScsiHba(
+  esxVI_Context *ctx,
+  esxVI_HostInternetScsiHba **hostInternetScsiHba)
+{
+    int result = -1;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_HostHostBusAdapter *hostHostBusAdapterList = NULL;
+    esxVI_HostHostBusAdapter *hostHostBusAdapter = NULL;
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+          "config.storageDevice.hostBusAdapter\0") < 0 ||
+        esxVI_LookupHostSystemProperties(ctx, propertyNameList,
+            &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name,
+              "config.storageDevice.hostBusAdapter")) {
+            if (esxVI_HostHostBusAdapter_CastListFromAnyType(
+                  dynamicProperty->val, &hostHostBusAdapterList) < 0 ||
+                hostHostBusAdapterList == NULL) {
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    /* See vSphere API documentation about HostInternetScsiHba for details */
+    for (hostHostBusAdapter = hostHostBusAdapterList; hostHostBusAdapter != NULL;
+         hostHostBusAdapter = hostHostBusAdapter->_next) {
+        esxVI_HostInternetScsiHba *candidate=
+            esxVI_HostInternetScsiHba_DynamicCast(hostHostBusAdapter);
+
+        if (candidate) {
+            if (esxVI_HostInternetScsiHba_DeepCopy(hostInternetScsiHba,
+                  candidate) < 0) {
+                goto cleanup;
+            }
+            break;
+        }
+    }
+
+    result = 0;
+
+cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&hostSystem);
+    esxVI_HostHostBusAdapter_Free(&hostHostBusAdapterList);
+
+    return result;
+}
+
+int
+esxVI_LookupScsiLunList(esxVI_Context *ctx,
+                        esxVI_ScsiLun **ret)
+{
+    int result = -1;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ScsiLun *scsiLunList = NULL;
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+        "config.storageDevice.scsiLun\0") < 0 ||
+        esxVI_LookupHostSystemProperties(
+            ctx, propertyNameList, &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name,
+                     "config.storageDevice.scsiLun")) {
+            if (esxVI_ScsiLun_CastListFromAnyType(dynamicProperty->val,
+                  &scsiLunList) < 0) {
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if (scsiLunList == NULL) {
+        goto cleanup;
+    }
+
+    /**
+     * FIXME: deep list copy operation fails with error:
+     * " libvir: ESX Driver error :
+     * internal error Call to esxVI_HostDevice_Free for
+     * unexpected type 'HostScsiDisk' "
+     * HostScsiDisk extends ScsiLun
+     */
+    *ret = scsiLunList;
+    scsiLunList = NULL; /* prevent double free */
+
+    result = 0;
+
+cleanup:
+
+    esxVI_ScsiLun_Free(&scsiLunList);
+
+    return result;
+
+}
+
+int
+esxVI_LookupHostScsiTopologyLunListByTargetName(
+  esxVI_Context *ctx, const char *name, esxVI_HostScsiTopologyLun **ret)
+{
+    int result = -1;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
+    const esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
+    const esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
+    bool found = false;
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+        "config.storageDevice.scsiTopology.adapter\0") < 0 ||
+        esxVI_LookupHostSystemProperties(
+            ctx, propertyNameList, &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name,
+              "config.storageDevice.scsiTopology.adapter")) {
+            esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+            if ((esxVI_HostScsiTopologyInterface_CastListFromAnyType
+                  (dynamicProperty->val, &hostScsiInterfaceList) < 0)) {
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if (hostScsiInterfaceList == NULL) {
+        /* iSCSI adapter may not be enabled */
+        return 0;
+    }
+
+    /* See vSphere API documentation about HostScsiTopologyInterface */
+    for (hostScsiInterface = hostScsiInterfaceList;
+         hostScsiInterface != NULL && !found;
+         hostScsiInterface = hostScsiInterface->_next) {
+        for (hostScsiTopologyTarget = hostScsiInterface->target;
+             hostScsiTopologyTarget != NULL;
+             hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
+            const esxVI_HostInternetScsiTargetTransport *candidate =
+                esxVI_HostInternetScsiTargetTransport_DynamicCast(
+                  hostScsiTopologyTarget->transport);
+
+            if (candidate && STREQ(candidate->iScsiName, name)) {
+                found = true;
+                break;
+            }
+        }
+    }
+
+    if (!found || hostScsiTopologyTarget == NULL) {
+        goto cleanup;
+    }
+
+    if (esxVI_HostScsiTopologyLun_DeepCopyList(
+          ret, hostScsiTopologyTarget->lun) < 0) {
+        goto cleanup;
+    }
+
+    if (*ret == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+          _("Target not found"));
+        goto cleanup;
+    }
+
+    result = 0;
+
+  cleanup:
+
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&hostSystem);
+    esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+    return result;
+}
+
+
+int
+esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx,
+                                        const char *key,
+                                        char **poolName)
+{
+    int result = -1;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
+    const esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
+    const esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
+    bool found = false;
+
+    if (esxVI_String_AppendValueToList(&propertyNameList,
+        "config.storageDevice.scsiTopology.adapter\0") < 0 ||
+        esxVI_LookupHostSystemProperties(
+            ctx, propertyNameList, &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name,
+              "config.storageDevice.scsiTopology.adapter")) {
+            esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+            if ((esxVI_HostScsiTopologyInterface_CastListFromAnyType
+                  (dynamicProperty->val, &hostScsiInterfaceList) < 0)) {
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if (hostScsiInterfaceList == NULL) {
+        /* iSCSI adapter may not be enabled */
+        return 0;
+    }
+
+    /* See vSphere API documentation about HostScsiTopologyInterface */
+    for (hostScsiInterface = hostScsiInterfaceList;
+         hostScsiInterface != NULL && !found;
+         hostScsiInterface = hostScsiInterface->_next) {
+        for (hostScsiTopologyTarget = hostScsiInterface->target;
+             hostScsiTopologyTarget != NULL;
+             hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
+            const esxVI_HostInternetScsiTargetTransport *candidate =
+                esxVI_HostInternetScsiTargetTransport_DynamicCast(
+                  hostScsiTopologyTarget->transport);
+
+            if (candidate) {
+                /* iterate hostScsiTopologyLun list to find matching key */
+                const esxVI_HostScsiTopologyLun *hostScsiTopologyLun =
+                                                hostScsiTopologyTarget->lun;
+                for (; hostScsiTopologyLun != NULL;
+                     hostScsiTopologyLun = hostScsiTopologyLun->_next) {
+                    if (STREQ(hostScsiTopologyLun->scsiLun, key)) {
+                        *poolName = strdup(candidate->iScsiName);
+
+                        if (*poolName == NULL) {
+                            virReportOOMError();
+                            goto cleanup;
+                        }
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    result = 0;
+
+  cleanup:
+    esxVI_ObjectContent_Free(&hostSystem);
+    esxVI_String_Free(&propertyNameList);
+    esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
+
+    return result;
+}
 
 #include "esx_vi.generated.c"
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 12394e7..6149c2d 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -438,7 +438,8 @@ int esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx,
 
 int esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
                                    esxVI_ManagedObjectReference *datastore,
-                                   esxVI_DatastoreHostMount **hostMount);
+                                   esxVI_DatastoreHostMount **hostMount,
+                                   esxVI_Occurrence occurrence);
 
 int esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
                                esxVI_ManagedObjectReference *task,
@@ -524,6 +525,24 @@ int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
 
 int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion);
 
+int esxVI_LookupHostInternetScsiHbaStaticTargetByName(esxVI_Context *ctx,
+  const char *name, esxVI_HostInternetScsiHbaStaticTarget **ret,
+  esxVI_Occurrence occurrence);
+
+int esxVI_LookupHostInternetScsiHba(
+  esxVI_Context *ctx,
+  esxVI_HostInternetScsiHba **hostInternetScsiHba);
+
+int esxVI_LookupScsiLunList(esxVI_Context *ctx, esxVI_ScsiLun **ret);
+
+int esxVI_LookupHostScsiTopologyLunListByTargetName(
+  esxVI_Context *ctx, const char *name, esxVI_HostScsiTopologyLun **ret);
+
+int
+esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx,
+                                        const char *key,
+                                        char **poolName);
+
 # include "esx_vi.generated.h"
 
 #endif /* __ESX_VI_H__ */
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index c4a3e56..6e50be5 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -58,6 +58,14 @@ enum AutoStartWaitHeartbeatSetting
 end
 
 
+enum FibreChannelPortType
+    fabric
+    loop
+    pointToPoint
+    unknown
+end
+
+
 enum ManagedEntityStatus
     gray
     green
@@ -128,6 +136,11 @@ enum VirtualMachinePowerState
 end
 
 
+enum vStorageSupport
+    vStorageUnknown
+end
+
+
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 # Objects
 #
@@ -263,6 +276,13 @@ object HostAutoStartManagerConfig
 end
 
 
+object HostBlockAdapterTargetTransport extends HostTargetTransport
+end
+
+object HostBlockHba extends HostHostBusAdapter
+end
+
+
 object HostConfigManager
     ManagedObjectReference                   cpuScheduler                   o
     ManagedObjectReference                   datastoreSystem                o
@@ -310,6 +330,32 @@ object HostDatastoreBrowserSearchSpec
 end
 
 
+object HostDevice
+    String                                   deviceName                     r
+    String                                   deviceType                     r
+end
+
+
+object HostDiskDimensionsLba
+    Int                                      blockSize                      r
+    Long                                     block                          r
+end
+
+
+object HostFibreChannelHba extends HostHostBusAdapter
+    Long                                     nodeWorldWideName              r
+    FibreChannelPortType                     portType                       r
+    Long                                     portWorldWideName              r
+    Long                                     speed                          r
+end
+
+
+object HostFibreChannelTargetTransport extends HostTargetTransport
+    Long                                     nodeWorldWideName              r
+    Long                                     portWorldWideName              r
+end
+
+
 object HostFileSystemVolume
     String                                   type                           r
     String                                   name                           r
@@ -317,11 +363,171 @@ object HostFileSystemVolume
 end
 
 
+object HostHostBusAdapter
+    Int                                      bus                            r
+    String                                   device                         r
+    String                                   driver                         o
+    String                                   key                            o
+    String                                   model                          r
+    String                                   pci                            o
+    String                                   status                         r
+end
+
+
+object HostInternetScsiTargetTransport extends HostTargetTransport
+    String                                   iScsiName                      r
+    String                                   iScsiAlias                     r
+    String                                   address                        ol
+
+end
+
+
+object HostInternetScsiHba extends HostHostBusAdapter
+    HostInternetScsiHbaAuthenticationCapabilities   authenticationCapabilities  r
+    HostInternetScsiHbaAuthenticationProperties     authenticationProperties    r
+    HostInternetScsiHbaDiscoveryCapabilities        discoveryCapabilities       r
+    HostInternetScsiHbaDiscoveryProperties          discoveryProperties         r
+    HostInternetScsiHbaIPCapabilities               ipCapabilities              r
+    HostInternetScsiHbaIPProperties                 ipProperties                r
+    String                                          iScsiName                   r
+    Boolean                                         isSoftwareBased             r
+    HostInternetScsiHbaParamValue                   advancedOptions             ol
+    HostInternetScsiHbaSendTarget                   configuredSendTarget        ol
+    HostInternetScsiHbaStaticTarget                 configuredStaticTarget      ol
+    Int                                             currentSpeedMb              o
+    HostInternetScsiHbaDigestCapabilities           digestCapabilities          o
+    HostInternetScsiHbaDigestProperties             digestProperties            o
+    String                                          iScsiAlias                  o
+    Int                                             maxSpeedMb                  o
+    OptionDef                                       supportedAdvancedOptions    ol
+end
+
+
+
+object HostInternetScsiHbaAuthenticationCapabilities
+    Boolean                                  chapAuthSettable               r
+    Boolean                                  krb5AuthSettable               r
+    Boolean                                  spkmAuthSettable               r
+    Boolean                                  srpAuthSettable                r
+    Boolean                                  mutualChapSettable             o
+    Boolean                                  targetChapSettable             o
+    Boolean                                  targetMutualChapSettable       o
+end
+
+
+object HostInternetScsiHbaAuthenticationProperties
+    Boolean                                  chapAuthEnabled                r
+    String                                   chapAuthenticationType         o
+    Boolean                                  chapInherited                  o
+    String                                   chapName                       o
+    String                                   chapSecret                     o
+    String                                   mutualChapAuthenticationType   o
+    Boolean                                  mutualChapInherited            o
+    String                                   mutualChapName                 o
+    String                                   mutualChapSecret               o
+end
+
+
+object HostInternetScsiHbaDigestCapabilities
+    Boolean                                  dataDigestSettable             o
+    Boolean                                  headerDigestSettable           o
+    Boolean                                  targetDataDigestSettable       o
+    Boolean                                  targetHeaderDigestSettable     o
+end
+
+
+object HostInternetScsiHbaDigestProperties
+    Boolean                                  dataDigestInherited            o
+    String                                   dataDigestType                 o
+    Boolean                                  headerDigestInherited          o
+    String                                   headerDigestType               o
+end
+
+
+object HostInternetScsiHbaDiscoveryCapabilities
+    Boolean                                  iSnsDiscoverySettable          r
+    Boolean                                  sendTargetsDiscoverySettable   r
+    Boolean                                  slpDiscoverySettable           r
+    Boolean                                  staticTargetDiscoverySettable  r
+end
+
+
+object HostInternetScsiHbaDiscoveryProperties
+    Boolean                                  iSnsDiscoveryEnabled           r
+    Boolean                                  sendTargetsDiscoveryEnabled    r
+    Boolean                                  slpDiscoveryEnabled            r
+    Boolean                                  staticTargetDiscoveryEnabled   r
+    String                                   iSnsDiscoveryMethod            o
+    String                                   iSnsHost                       o
+    String                                   slpDiscoveryMethod             o
+    String                                   slpHost                        o
+end
+
+
+object HostInternetScsiHbaIPCapabilities
+    Boolean                                         addressSettable             r
+    Boolean                                         alternateDnsServerAddressSettable   r
+    Boolean                                         defaultGatewaySettable              r
+    Boolean                                         ipConfigurationMethodSettable       r
+    Boolean                                         primaryDnsServerAddressSettable     r
+    Boolean                                         subnetMaskSettable                  r
+    Boolean                                         arpRedirectSettable                 o
+    Boolean                                         hostNameAsTargetAddress             o
+    Boolean                                         ipv6Supported                       o
+    Boolean                                         mtuSettable                         o
+    Boolean                                         nameAliasSettable                   o
+end
+
+
+object HostInternetScsiHbaIPProperties
+    Boolean                                         dhcpConfigurationEnabled    r
+    String                                          address                     o
+    String                                          alternateDnsServerAddress   o
+    Boolean                                         arpRedirectEnabled          o
+    String                                          defaultGateway              o
+    String                                          ipv6Address                 o
+    String                                          ipv6DefaultGateway          o
+    Boolean                                         jumboFramesEnabled          o
+    String                                          mac                         o
+    Int                                             mtu                         o
+    String                                          primaryDnsServerAddress     o
+    String                                          subnetMask                  o
+end
+
+
+object HostInternetScsiHbaParamValue extends OptionValue
+    Boolean                                  isInherited                    o
+end
+
+
+object HostInternetScsiHbaSendTarget
+    String                                   address                        r
+    HostInternetScsiHbaParamValue            advancedOptions                ol
+    HostInternetScsiHbaAuthenticationProperties  authenticationProperties   o
+    HostInternetScsiHbaDigestProperties      digestProperties               o
+    String                                   parent                         o
+    Int                                      port                           o
+    OptionDef                                supportedAdvancedOptions       ol
+end
+
+
+object HostInternetScsiHbaStaticTarget
+    String                                   address                        r
+    String                                   iScsiName                      r
+    HostInternetScsiHbaParamValue            advancedOptions                ol
+    HostInternetScsiHbaAuthenticationProperties  authenticationProperties   o
+    HostInternetScsiHbaDigestProperties      digestProperties               o
+    String                                   parent                         o
+    Int                                      port                           o
+    OptionDef                                supportedAdvancedOptions       ol
+end
+
+
+
 object HostIpConfig
     Boolean                                  dhcp                           r
     String                                   ipAddress                      o
     String                                   subnetMask                     o
-end
 
 
 object HostMountInfo
@@ -416,6 +622,19 @@ object HostPortGroupSpec
     Int                                      vlanId                         r
     String                                   vswitchName                    r
     HostNetworkPolicy                        policy                         r
+
+
+object HostParallelScsiHba extends HostHostBusAdapter
+end
+
+
+object HostParallelScsiTargetTransport extends HostTargetTransport
+end
+
+
+object HostScsiDisk extends ScsiLun
+    HostDiskDimensionsLba                    capacity                       r
+    String                                   devicePath                     r
 end
 
 
@@ -425,6 +644,37 @@ object HostScsiDiskPartition
 end
 
 
+object HostScsiTopology
+    HostScsiTopologyInterface                adapater                       ol
+end
+
+
+object HostScsiTopologyInterface
+    String                                   adapter                        r
+    String                                   key                            r
+    HostScsiTopologyTarget                   target                         ol
+end
+
+
+object HostScsiTopologyLun
+    String                                   key                            r
+    Int                                      lun                            r
+    String                                   scsiLun                        r
+end
+
+
+object HostScsiTopologyTarget
+    String                                   key                            r
+    Int                                      target                         r
+    HostScsiTopologyLun                      lun                            ol
+    HostTargetTransport                      transport                      o
+end
+
+
+object HostTargetTransport
+end
+
+
 object HostVirtualSwitch
     String                                   name                           r
     String                                   key                            r
@@ -467,7 +717,6 @@ object HostVirtualSwitchSpec
     HostVirtualSwitchBridge                  bridge                         o
     HostNetworkPolicy                        policy                         o
     Int                                      mtu                            o
-end
 
 
 object HostVmfsVolume                extends HostFileSystemVolume
@@ -527,11 +776,22 @@ object ObjectUpdate
 end
 
 
+object OptionDef extends ElementDescription
+    OptionType                               optionType                     r
+end
+
+
 object OptionType
     Boolean                                  valueIsReadonly                o
 end
 
 
+object OptionValue
+    String                                   key                            r
+    AnyType                                  value                          r
+end
+
+
 object PerfCounterInfo
     Int                                      key                            r
     ElementDescription                       nameInfo                       r
@@ -664,6 +924,45 @@ object SelectionSpec
 end
 
 
+object ScsiLun extends HostDevice
+    String                                   lunType                        r
+    String                                   operationalState               rl
+    String                                   uuid                           r
+    ScsiLunDurableName                       alternateName                  ol
+    String                                   canonicalName                  o
+    ScsiLunCapabilities                      capabilities                   o
+    ScsiLunDescriptor                        descriptor                     ol
+    String                                   displayName                    o
+    ScsiLunDurableName                       durableName                    o
+    String                                   key                            o
+    String                                   model                          o
+    Int                                      queueDepth                     o
+    String                                   revision                       o
+    Int                                      scsiLevel                      o
+    String                                   serialNumber                   o
+    Byte                                     standardInquiry                ol
+    String                                   vendor                         o
+end
+
+
+object ScsiLunCapabilities
+    Boolean                                  updateDisplayNameSupported     r
+end
+
+
+object ScsiLunDescriptor
+    String                                   id                             r
+    String                                   quality                        r
+end
+
+
+object ScsiLunDurableName
+    String                                   namespace                      r
+    Byte                                     namespaceId                    r
+    Byte                                     data                           ol
+end
+
+
 object ServiceContent
     ManagedObjectReference                   rootFolder                     r
     ManagedObjectReference                   propertyCollector              r
@@ -1135,6 +1434,11 @@ end
 method RemoveVirtualSwitch
     ManagedObjectReference                   _this                          r
     String                                   vswitchName                    r
+
+
+method RescanHba
+   ManagedObjectReference                    _this                          r
+   String                                    hbaDevice                      r
 end
 
 
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index b49db70..7c0c1f2 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -1520,6 +1520,21 @@ additional_object_features = { "AutoStartDefaults"          : Object.FEATURE__AN
                                                               Object.FEATURE__ANY_TYPE,
                                "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST |
                                                               Object.FEATURE__ANY_TYPE,
+                               "HostHostBusAdapter"         : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE,
+                               "HostInternetScsiHba"        : Object.FEATURE__DYNAMIC_CAST |
+                                                              Object.FEATURE__DEEP_COPY,
+                               "HostInternetScsiTargetTransport"  : Object.FEATURE__DYNAMIC_CAST,
+                               "HostScsiDisk"               : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__DYNAMIC_CAST,
+                               "HostScsiTopologyInterface"  : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE,
+                               "HostScsiTopologyLun"        : Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__LIST |
+                                                              Object.FEATURE__DEEP_COPY,
+                               "HostScsiTopologyTarget"     : Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__LIST,
                                "HostPortGroup"              : Object.FEATURE__LIST |
                                                               Object.FEATURE__ANY_TYPE,
                                "HostVirtualSwitch"          : Object.FEATURE__DEEP_COPY |
@@ -1531,6 +1546,10 @@ additional_object_features = { "AutoStartDefaults"          : Object.FEATURE__AN
                                                               Object.FEATURE__LIST |
                                                               Object.FEATURE__ANY_TYPE,
                                "ResourcePoolResourceUsage"  : Object.FEATURE__ANY_TYPE,
+                               "ScsiLun"                    : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__DEEP_COPY,
+                               "ScsiLunDurableName"         : Object.FEATURE__LIST,
                                "ServiceContent"             : Object.FEATURE__DESERIALIZE,
                                "SharesInfo"                 : Object.FEATURE__ANY_TYPE,
                                "TaskInfo"                   : Object.FEATURE__LIST |
-- 
1.7.9.5


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]