This code implements the creation and deletion of virtual HBAs using the sysfs interface
of vport_create and vport_delete.
---
src/storage_backend_scsi.c | 116 ++++++++++++++++++++++++++++++++++++++++++-
src/storage_backend_scsi.h | 8 +++-
src/storage_conf.c | 53 ++++++++++++++++++++
src/storage_conf.h | 6 ++
4 files changed, 179 insertions(+), 4 deletions(-)
diff --git a/src/storage_backend_scsi.c b/src/storage_backend_scsi.c
index 1d2378b..cf203ce 100644
--- a/src/storage_backend_scsi.c
+++ b/src/storage_backend_scsi.c
@@ -566,12 +566,121 @@ out:
static int
+virStorageBackendVportCreateDelete(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ int operation)
+{
+ int fd = -1;
+ int retval = 0;
+ char *operation_path;
+ const char *operation_file;
+ char *vport_name;
+ size_t towrite = 0;
+
+ switch (operation) {
+ case VPORT_CREATE:
+ operation_file = LINUX_SYSFS_VPORT_CREATE_POSTFIX;
+ break;
+ case VPORT_DELETE:
+ operation_file = LINUX_SYSFS_VPORT_DELETE_POSTFIX;
+ break;
+ default:
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid vport operation (%d)"), operation);
+ retval = -1;
+ goto no_unwind;
+ break;
+ }
+
+ if (virAsprintf(&operation_path,
+ "%s/%s/%s",
+ LINUX_SYSFS_FC_HOST_PREFIX,
+ pool->def->source.adapter,
+ operation_file) < 0) {
+
+ virReportOOMError(conn);
+ retval = -1;
+ goto no_unwind;
+ }
+
+ VIR_DEBUG(_("Vport operation path is '%s'"), operation_path);
+
+ fd = open(operation_path, O_WRONLY);
+
+ if (fd < 0) {
+ virReportSystemError(conn, errno,
+ _("Could not open '%s' for vport
operation"),
+ operation_path);
+ retval = -1;
+ goto free_path;
+ }
+
+ if (virAsprintf(&vport_name,
+ "%s:%s",
+ pool->def->source.wwpn,
+ pool->def->source.wwnn) < 0) {
+
+ virReportOOMError(conn);
+ retval = -1;
+ goto close_fd;
+ }
+
+ towrite = sizeof(vport_name);
+ if (safewrite(fd, vport_name, towrite) != towrite) {
+ virReportSystemError(conn, errno,
+ _("Write of '%s' to '%s' during "
+ "vport create/delete failed"),
+ vport_name, operation_path);
+ retval = -1;
+ }
+
+ VIR_FREE(vport_name);
+close_fd:
+ close(fd);
+free_path:
+ VIR_FREE(operation_path);
+no_unwind:
+ VIR_DEBUG("%s", _("Vport operation complete"));
+ return retval;
+}
+
+
+static int
+virStorageBackendSCSIStartPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ int retval = 0;
+
+ if (pool->def->source.wwnn != NULL) {
+ retval = virStorageBackendVportCreateDelete(conn, pool, VPORT_CREATE);
+ }
+
+ return retval;
+}
+
+
+static int
+virStorageBackendSCSIStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
+{
+ int retval = 0;
+
+ if (pool->def->source.wwnn != NULL) {
+ retval = virStorageBackendVportCreateDelete(conn, pool, VPORT_DELETE);
+ }
+
+ return retval;
+}
+
+
+static int
virStorageBackendSCSITriggerRescan(virConnectPtr conn,
uint32_t host)
{
int fd = -1;
int retval = 0;
char *path;
+ size_t towrite = 0;
VIR_DEBUG(_("Triggering rescan of host %d"), host);
@@ -593,9 +702,8 @@ virStorageBackendSCSITriggerRescan(virConnectPtr conn,
goto free_path;
}
- if (safewrite(fd,
- LINUX_SYSFS_SCSI_HOST_SCAN_STRING,
- sizeof(LINUX_SYSFS_SCSI_HOST_SCAN_STRING)) < 0) {
+ towrite = sizeof(LINUX_SYSFS_SCSI_HOST_SCAN_STRING);
+ if (safewrite(fd, LINUX_SYSFS_SCSI_HOST_SCAN_STRING, towrite) != towrite) {
virReportSystemError(conn, errno,
_("Write to '%s' to trigger host scan
failed"),
@@ -645,5 +753,7 @@ out:
virStorageBackend virStorageBackendSCSI = {
.type = VIR_STORAGE_POOL_SCSI,
+ .startPool = virStorageBackendSCSIStartPool,
.refreshPool = virStorageBackendSCSIRefreshPool,
+ .stopPool = virStorageBackendSCSIStopPool,
};
diff --git a/src/storage_backend_scsi.h b/src/storage_backend_scsi.h
index d130086..9962d6c 100644
--- a/src/storage_backend_scsi.h
+++ b/src/storage_backend_scsi.h
@@ -28,7 +28,13 @@
#define LINUX_SYSFS_SCSI_HOST_PREFIX "/sys/class/scsi_host"
#define LINUX_SYSFS_SCSI_HOST_POSTFIX "device"
-#define LINUX_SYSFS_SCSI_HOST_SCAN_STRING "- - -"
+#define LINUX_SYSFS_SCSI_HOST_SCAN_STRING "- - -\n"
+#define LINUX_SYSFS_FC_HOST_PREFIX "/sys/class/fc_host/"
+
+#define VPORT_CREATE 0
+#define VPORT_DELETE 1
+#define LINUX_SYSFS_VPORT_CREATE_POSTFIX "/vport_create"
+#define LINUX_SYSFS_VPORT_DELETE_POSTFIX "/vport_delete"
extern virStorageBackend virStorageBackendSCSI;
diff --git a/src/storage_conf.c b/src/storage_conf.c
index 9e25ccb..4827d69 100644
--- a/src/storage_conf.c
+++ b/src/storage_conf.c
@@ -42,6 +42,7 @@
#include "buf.h"
#include "util.h"
#include "memory.h"
+#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -451,6 +452,55 @@ error:
}
+static int
+getNPIVParameters(virConnectPtr conn,
+ virStoragePoolDefPtr pool,
+ xmlXPathContextPtr ctxt)
+{
+ int retval = 0;
+
+ if ((pool->source.wwpn = virXPathString(conn,
+
"string(/pool/source/adapter/@wwpn)",
+ ctxt)) == NULL) {
+ VIR_DEBUG("%s", _("No WWPN found"));
+ goto out;
+ }
+
+ VIR_DEBUG(_("Found WWPN '%s'"), pool->source.wwpn);
+
+ if ((pool->source.wwnn = virXPathString(conn,
+
"string(/pool/source/adapter/@wwnn)",
+ ctxt)) == NULL) {
+ VIR_DEBUG("%s", _("No WWNN found"));
+ goto out;
+ }
+
+ VIR_DEBUG(_("Found WWNN '%s'"), pool->source.wwnn);
+
+ if (pool->source.wwpn != NULL || pool->source.wwnn != NULL) {
+ if (pool->source.wwpn == NULL || pool->source.wwnn == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("Both WWPN and WWNN must be specified "
+ "if either is specified"));
+ retval = -1;
+ goto cleanup;
+ }
+ }
+
+ /* We don't check the values for validity, because the kernel does
+ * that. Any invalid values will be rejected when the pool
+ * starts. The kernel has the final say on what it will accept
+ * and we should not second guess it. */
+
+cleanup:
+ VIR_FREE(pool->source.wwpn);
+ VIR_FREE(pool->source.wwnn);
+
+out:
+ return retval;
+}
+
+
static virStoragePoolDefPtr
virStoragePoolDefParseDoc(virConnectPtr conn,
xmlXPathContextPtr ctxt,
@@ -590,6 +640,9 @@ virStoragePoolDefParseDoc(virConnectPtr conn,
"%s", _("missing storage pool source adapter
name"));
goto cleanup;
}
+ if (getNPIVParameters(conn, ret, ctxt) < 0) {
+ goto cleanup;
+ }
}
authType = virXPathString(conn, "string(/pool/source/auth/@type)", ctxt);
diff --git a/src/storage_conf.h b/src/storage_conf.h
index 4e35ccb..cfd8b14 100644
--- a/src/storage_conf.h
+++ b/src/storage_conf.h
@@ -192,6 +192,12 @@ struct _virStoragePoolSource {
/* Or an adapter */
char *adapter;
+ /* And an optional WWPN */
+ char *wwpn;
+
+ /* And an optional WWNN */
+ char *wwnn;
+
/* Or a name */
char *name;
--
1.6.0.6