提交 2b13361b 编写于 作者: J John Ferlan

nodedev: Add the ability to create vHBA by parent wwnn/wwpn or fabric_wwn

https://bugzilla.redhat.com/show_bug.cgi?id=1349696

When creating a vHBA, the process is to feed XML to nodeDeviceCreateXML
that lists the <parent> scsi_hostX to use to create the vHBA. However,
between reboots, it's possible that the <parent> changes its scsi_hostX
to scsi_hostY and saved XML to perform the creation will either fail or
create a vHBA using the wrong parent.

So add the ability to provide "wwnn" and "wwpn" or "fabric_wwn" to
the <parent> instead of a name of the scsi_hostN that is the parent.
The allowed XML will thus be:

  <parent>scsi_host3</parent>  (current)

or

  <parent wwnn='$WWNN' wwpn='$WWPN'/>

or

  <parent fabric_wwn='$WWNN'/>

Using the wwnn/wwpn or fabric_wwn ensures the same 'scsi_hostN' is
selected between hardware reconfigs or host reboots. The fabric_wwn
Using the wwnn/wwpn pair will provide the most specific search option,
while fabric_wwn will at least ensure usage of the same SAN, but maybe
not the same scsi_hostN.

This patch will add the new fields to the nodedev.rng for input purposes
only since the input XML is essentially thrown away, no need to Format
the values since they'd already be printed as part of the scsi_host
data block.

New API virNodeDeviceGetParentHostByWWNs will take the parent "wwnn" and
"wwpn" in order to search the list of devices for matching capability
data fields wwnn and wwpn.

New API virNodeDeviceGetParentHostByFabricWWN will take the parent "fabric_wwn"
in order to search the list of devices for matching capability data field
fabric_wwn.
上级 d47db7b1
......@@ -16,7 +16,7 @@
<element name="path"><text/></element>
</optional>
<optional>
<element name="parent"><text/></element>
<ref name="parent"/>
</optional>
<optional>
......@@ -31,6 +31,29 @@
</element>
</define>
<define name='parent'>
<element name='parent'>
<choice>
<group>
<attribute name='wwnn'>
<ref name='wwn'/>
</attribute>
<attribute name='wwpn'>
<ref name='wwn'/>
</attribute>
<empty/>
</group>
<group>
<attribute name='fabric_wwn'>
<ref name='wwn'/>
</attribute>
<empty/>
</group>
<text/>
</choice>
</element>
</define>
<define name='capability'>
<element name="capability">
<choice>
......
......@@ -97,6 +97,30 @@ int virNodeDeviceHasCap(const virNodeDeviceObj *dev, const char *cap)
}
/* virNodeDeviceFindFCCapDef:
* @dev: Pointer to current device
*
* Search the device object 'caps' array for fc_host capability.
*
* Returns:
* Pointer to the caps or NULL if not found
*/
static virNodeDevCapsDefPtr
virNodeDeviceFindFCCapDef(const virNodeDeviceObj *dev)
{
virNodeDevCapsDefPtr caps = dev->def->caps;
while (caps) {
if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST &&
(caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST))
break;
caps = caps->next;
}
return caps;
}
/* virNodeDeviceFindVPORTCapDef:
* @dev: Pointer to current device
*
......@@ -156,6 +180,46 @@ virNodeDeviceObjPtr virNodeDeviceFindByName(virNodeDeviceObjListPtr devs,
}
static virNodeDeviceObjPtr
virNodeDeviceFindByWWNs(virNodeDeviceObjListPtr devs,
const char *parent_wwnn,
const char *parent_wwpn)
{
size_t i;
for (i = 0; i < devs->count; i++) {
virNodeDevCapsDefPtr cap;
virNodeDeviceObjLock(devs->objs[i]);
if ((cap = virNodeDeviceFindFCCapDef(devs->objs[i])) &&
STREQ_NULLABLE(cap->data.scsi_host.wwnn, parent_wwnn) &&
STREQ_NULLABLE(cap->data.scsi_host.wwpn, parent_wwpn))
return devs->objs[i];
virNodeDeviceObjUnlock(devs->objs[i]);
}
return NULL;
}
static virNodeDeviceObjPtr
virNodeDeviceFindByFabricWWN(virNodeDeviceObjListPtr devs,
const char *parent_fabric_wwn)
{
size_t i;
for (i = 0; i < devs->count; i++) {
virNodeDevCapsDefPtr cap;
virNodeDeviceObjLock(devs->objs[i]);
if ((cap = virNodeDeviceFindFCCapDef(devs->objs[i])) &&
STREQ_NULLABLE(cap->data.scsi_host.fabric_wwn, parent_fabric_wwn))
return devs->objs[i];
virNodeDeviceObjUnlock(devs->objs[i]);
}
return NULL;
}
static virNodeDeviceObjPtr
virNodeDeviceFindByCap(virNodeDeviceObjListPtr devs,
const char *cap)
......@@ -182,6 +246,9 @@ void virNodeDeviceDefFree(virNodeDeviceDefPtr def)
VIR_FREE(def->name);
VIR_FREE(def->parent);
VIR_FREE(def->parent_wwnn);
VIR_FREE(def->parent_wwpn);
VIR_FREE(def->parent_fabric_wwn);
VIR_FREE(def->driver);
VIR_FREE(def->sysfs_path);
VIR_FREE(def->parent_sysfs_path);
......@@ -1657,6 +1724,16 @@ virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt,
/* Extract device parent, if any */
def->parent = virXPathString("string(./parent[1])", ctxt);
def->parent_wwnn = virXPathString("string(./parent[1]/@wwnn)", ctxt);
def->parent_wwpn = virXPathString("string(./parent[1]/@wwpn)", ctxt);
if ((def->parent_wwnn && !def->parent_wwpn) ||
(!def->parent_wwnn && def->parent_wwpn)) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("must supply both wwnn and wwpn for parent"));
goto error;
}
def->parent_fabric_wwn = virXPathString("string(./parent[1]/@fabric_wwn)",
ctxt);
/* Parse device capabilities */
nodes = NULL;
......@@ -1851,6 +1928,55 @@ virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
}
int
virNodeDeviceGetParentHostByWWNs(virNodeDeviceObjListPtr devs,
const char *dev_name,
const char *parent_wwnn,
const char *parent_wwpn,
int *parent_host)
{
virNodeDeviceObjPtr parent = NULL;
int ret;
if (!(parent = virNodeDeviceFindByWWNs(devs, parent_wwnn, parent_wwpn))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find parent device for '%s'"),
dev_name);
return -1;
}
ret = virNodeDeviceFindFCParentHost(parent, parent_host);
virNodeDeviceObjUnlock(parent);
return ret;
}
int
virNodeDeviceGetParentHostByFabricWWN(virNodeDeviceObjListPtr devs,
const char *dev_name,
const char *parent_fabric_wwn,
int *parent_host)
{
virNodeDeviceObjPtr parent = NULL;
int ret;
if (!(parent = virNodeDeviceFindByFabricWWN(devs, parent_fabric_wwn))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not find parent device for '%s'"),
dev_name);
return -1;
}
ret = virNodeDeviceFindFCParentHost(parent, parent_host);
virNodeDeviceObjUnlock(parent);
return ret;
}
int
virNodeDeviceFindVportParentHost(virNodeDeviceObjListPtr devs,
int *parent_host)
......
......@@ -200,6 +200,9 @@ struct _virNodeDeviceDef {
char *sysfs_path; /* udev name/sysfs path */
char *parent; /* optional parent device name */
char *parent_sysfs_path; /* udev parent name/sysfs path */
char *parent_wwnn; /* optional parent wwnn */
char *parent_wwpn; /* optional parent wwpn */
char *parent_fabric_wwn; /* optional parent fabric_wwn */
char *driver; /* optional driver name */
virNodeDevCapsDefPtr caps; /* optional device capabilities */
};
......@@ -273,6 +276,17 @@ int virNodeDeviceGetParentHost(virNodeDeviceObjListPtr devs,
const char *parent_name,
int *parent_host);
int virNodeDeviceGetParentHostByWWNs(virNodeDeviceObjListPtr devs,
const char *dev_name,
const char *parent_wwnn,
const char *parent_wwpn,
int *parent_host);
int virNodeDeviceGetParentHostByFabricWWN(virNodeDeviceObjListPtr devs,
const char *dev_name,
const char *parent_fabric_wwn,
int *parent_host);
int virNodeDeviceFindVportParentHost(virNodeDeviceObjListPtr devs,
int *parent_host);
......
......@@ -702,6 +702,8 @@ virNodeDeviceFindByName;
virNodeDeviceFindBySysfsPath;
virNodeDeviceFindVportParentHost;
virNodeDeviceGetParentHost;
virNodeDeviceGetParentHostByFabricWWN;
virNodeDeviceGetParentHostByWWNs;
virNodeDeviceGetWWNs;
virNodeDeviceHasCap;
virNodeDeviceObjListExport;
......
......@@ -590,6 +590,19 @@ nodeDeviceCreateXML(virConnectPtr conn,
def->parent,
&parent_host) < 0)
goto cleanup;
} else if (def->parent_wwnn && def->parent_wwpn) {
if (virNodeDeviceGetParentHostByWWNs(&driver->devs,
def->name,
def->parent_wwnn,
def->parent_wwpn,
&parent_host) < 0)
goto cleanup;
} else if (def->parent_fabric_wwn) {
if (virNodeDeviceGetParentHostByFabricWWN(&driver->devs,
def->name,
def->parent_fabric_wwn,
&parent_host) < 0)
goto cleanup;
} else {
/* Try to find a vport capable scsi_host when no parent supplied */
if (virNodeDeviceFindVportParentHost(&driver->devs, &parent_host) < 0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册