aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/examples/vscsi22
-rwxr-xr-xtools/examples/xen-backend.agent3
-rw-r--r--tools/examples/xen-backend.rules1
-rw-r--r--tools/examples/xmexample.hvm23
-rw-r--r--tools/examples/xmexample.vti22
-rw-r--r--tools/examples/xmexample123
-rw-r--r--tools/examples/xmexample222
-rw-r--r--tools/python/xen/util/vscsi_util.py133
-rw-r--r--tools/python/xen/xend/XendConfig.py11
-rw-r--r--tools/python/xen/xend/XendDevices.py3
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py93
-rw-r--r--tools/python/xen/xend/server/vscsiif.py228
-rw-r--r--tools/python/xen/xm/create.py94
-rw-r--r--tools/python/xen/xm/main.py101
14 files changed, 773 insertions, 6 deletions
diff --git a/tools/examples/vscsi b/tools/examples/vscsi
new file mode 100644
index 0000000000..5ac26147ec
--- /dev/null
+++ b/tools/examples/vscsi
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# Copyright (c) 2007, FUJITSU Limited
+# Based on the block scripts code.
+#
+
+dir=$(dirname "$0")
+. "$dir/xen-hotplug-common.sh"
+
+findCommand "$@"
+
+case "$command" in
+ add)
+ success
+ ;;
+ remove)
+ # TODO
+ exit 0
+ ;;
+esac
+
+exit 0
diff --git a/tools/examples/xen-backend.agent b/tools/examples/xen-backend.agent
index f043854ad0..5cb536a6a9 100755
--- a/tools/examples/xen-backend.agent
+++ b/tools/examples/xen-backend.agent
@@ -19,6 +19,9 @@ case "$XENBUS_TYPE" in
vif)
[ -n "$script" ] && $script "$ACTION"
;;
+ vscsi)
+ /etc/xen/scripts/vscsi "$ACTION"
+ ;;
esac
case "$ACTION" in
diff --git a/tools/examples/xen-backend.rules b/tools/examples/xen-backend.rules
index 33064acdb6..fe21fc1357 100644
--- a/tools/examples/xen-backend.rules
+++ b/tools/examples/xen-backend.rules
@@ -3,6 +3,7 @@ SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTI
SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} online"
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline", RUN+="$env{script} offline"
+SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
KERNEL=="evtchn", NAME="xen/%k"
KERNEL=="blktap[0-9]*", NAME="xen/%k"
diff --git a/tools/examples/xmexample.hvm b/tools/examples/xmexample.hvm
index f5b21b576c..94f5b92eef 100644
--- a/tools/examples/xmexample.hvm
+++ b/tools/examples/xmexample.hvm
@@ -282,3 +282,26 @@ serial='pty'
# '0' -> the bit must be '0'
# 'x' -> we don't care (do not check)
# 's' -> the bit must be the same as on the host that started this VM
+
+
+#-----------------------------------------------------------------------------
+# Configure PVSCSI devices:
+#
+#vscsi=[ 'PDEV, VDEV' ]
+#
+# PDEV gives physical SCSI device to be attached to specified guest
+# domain by one of the following identifier format.
+# - XX:XX:XX:XX (4-tuples with decimal notation which shows
+# "host:channel:target:lun")
+# - /dev/sdxx or sdx
+# - /dev/stxx or stx
+# - /dev/sgxx or sgx
+# - result of 'scsi_id -gu -s'.
+# ex. # scsi_id -gu -s /block/sdb
+# 36000b5d0006a0000006a0257004c0000
+#
+# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
+# which the specified guest domain recognize.
+#
+
+#vscsi = [ '/dev/sdx, 0:0:0:0' ]
diff --git a/tools/examples/xmexample.vti b/tools/examples/xmexample.vti
index 1aed0db090..9493bae130 100644
--- a/tools/examples/xmexample.vti
+++ b/tools/examples/xmexample.vti
@@ -161,3 +161,25 @@ serial='pty'
# 'windows' - All Windows variants (Windows Server 2003/2008)
#
#guest_os_type='default'
+
+#-----------------------------------------------------------------------------
+# Configure PVSCSI devices:
+#
+#vscsi=[ 'PDEV, VDEV' ]
+#
+# PDEV gives physical SCSI device to be attached to specified guest
+# domain by one of the following identifier format.
+# - XX:XX:XX:XX (4-tuples with decimal notation which shows
+# "host:channel:target:lun")
+# - /dev/sdxx or sdx
+# - /dev/stxx or stx
+# - /dev/sgxx or sgx
+# - result of 'scsi_id -gu -s'.
+# ex. # scsi_id -gu -s /block/sdb
+# 36000b5d0006a0000006a0257004c0000
+#
+# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
+# which the specified guest domain recognize.
+#
+
+#vscsi = [ '/dev/sdx, 0:0:0:0' ]
diff --git a/tools/examples/xmexample1 b/tools/examples/xmexample1
index 1a5c4d999e..fe382d43f6 100644
--- a/tools/examples/xmexample1
+++ b/tools/examples/xmexample1
@@ -185,4 +185,27 @@ extra = "4"
#on_reboot = 'restart'
#on_crash = 'restart'
+#-----------------------------------------------------------------------------
+# Configure PVSCSI devices:
+#
+#vscsi=[ 'PDEV, VDEV' ]
+#
+# PDEV gives physical SCSI device to be attached to specified guest
+# domain by one of the following identifier format.
+# - XX:XX:XX:XX (4-tuples with decimal notation which shows
+# "host:channel:target:lun")
+# - /dev/sdxx or sdx
+# - /dev/stxx or stx
+# - /dev/sgxx or sgx
+# - result of 'scsi_id -gu -s'.
+# ex. # scsi_id -gu -s /block/sdb
+# 36000b5d0006a0000006a0257004c0000
+#
+# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
+# which the specified guest domain recognize.
+#
+
+#vscsi = [ '/dev/sdx, 0:0:0:0' ]
+
#============================================================================
+
diff --git a/tools/examples/xmexample2 b/tools/examples/xmexample2
index 12b9b0f6ca..53ee3aa98e 100644
--- a/tools/examples/xmexample2
+++ b/tools/examples/xmexample2
@@ -221,4 +221,26 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid
#on_reboot = 'restart'
#on_crash = 'restart'
+#-----------------------------------------------------------------------------
+# Configure PVSCSI devices:
+#
+#vscsi=[ 'PDEV, VDEV' ]
+#
+# PDEV gives physical SCSI device to be attached to specified guest
+# domain by one of the following identifier format.
+# - XX:XX:XX:XX (4-tuples with decimal notation which shows
+# "host:channel:target:lun")
+# - /dev/sdxx or sdx
+# - /dev/stxx or stx
+# - /dev/sgxx or sgx
+# - result of 'scsi_id -gu -s'.
+# ex. # scsi_id -gu -s /block/sdb
+# 36000b5d0006a0000006a0257004c0000
+#
+# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
+# which the specified guest domain recognize.
+#
+
+#vscsi = [ '/dev/sdx, 0:0:0:0' ]
+
#============================================================================
diff --git a/tools/python/xen/util/vscsi_util.py b/tools/python/xen/util/vscsi_util.py
new file mode 100644
index 0000000000..eb5484838d
--- /dev/null
+++ b/tools/python/xen/util/vscsi_util.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# -*- mode: python; -*-
+
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# 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
+#============================================================================
+# Copyright (C) 2008 FUJITSU Limited
+# Based on the blkif.py
+#============================================================================
+
+
+"""Support for VSCSI Devices.
+"""
+import os
+import sys
+import re
+import string
+
+def _vscsi_hctl_block(name, scsi_devices):
+ """ block-device name is convert into hctl. (e.g., '/dev/sda',
+ '0:0:0:0')"""
+ try:
+ search = re.compile(r'' + name + '$', re.DOTALL)
+ except Exception, e:
+ raise VmError("vscsi: invalid expression. " + str(e))
+ chk = 0
+ for hctl, block, sg, scsi_id in scsi_devices:
+ if search.match(hctl):
+ chk = 1
+ break
+
+ if chk:
+ return (hctl, block)
+ else:
+ return (None, None)
+
+
+def _vscsi_block_scsiid_to_hctl(phyname, scsi_devices):
+ """ block-device name is convert into hctl. (e.g., '/dev/sda',
+ '0:0:0:0')"""
+
+ if re.match('/dev/sd[a-z]+([1-9]|1[0-5])?$', phyname):
+ # sd driver
+ name = re.sub('(^/dev/)|([1-9]|1[0-5])?$', '', phyname)
+ elif re.match('/dev/sg[0-9]+$', phyname):
+ # sg driver
+ name = re.sub('^/dev/', '', phyname)
+ elif re.match('/dev/st[0-9]+$', phyname):
+ # st driver
+ name = re.sub('^/dev/', '', phyname)
+ else:
+ # scsi_id -gu
+ name = phyname
+
+ chk = 0
+ for hctl, block, sg, scsi_id in scsi_devices:
+ if block == name:
+ chk = 1
+ break
+ elif sg == name:
+ chk = 1
+ break
+ elif scsi_id == name:
+ chk = 1
+ break
+
+ if chk:
+ return (hctl, block)
+ else:
+ return (None, None)
+
+
+def vscsi_get_scsidevices():
+ """ get all scsi devices"""
+
+ SERCH_SCSI_PATH = "/sys/bus/scsi/devices"
+ devices = []
+
+ for dirpath, dirnames, files in os.walk(SERCH_SCSI_PATH):
+ for hctl in dirnames:
+ paths = os.path.join(dirpath, hctl)
+ block = "-"
+ for f in os.listdir(paths):
+ if re.match('^block', f):
+ os.chdir(os.path.join(paths, f))
+ block = os.path.basename(os.getcwd())
+ elif re.match('^tape', f):
+ os.chdir(os.path.join(paths, f))
+ block = os.path.basename(os.getcwd())
+ elif re.match('^scsi_changer', f):
+ os.chdir(os.path.join(paths, f))
+ block = os.path.basename(os.getcwd())
+ elif re.match('^onstream_tape', f):
+ os.chdir(os.path.join(paths, f))
+ block = os.path.basename(os.getcwd())
+
+ if re.match('^scsi_generic', f):
+ os.chdir(os.path.join(paths, f))
+ sg = os.path.basename(os.getcwd())
+ lines = os.popen('/sbin/scsi_id -gu -s /class/scsi_generic/' + sg).read().split()
+ if len(lines) == 0:
+ scsi_id = '-'
+ else:
+ scsi_id = lines[0]
+
+ devices.append([hctl, block, sg, scsi_id])
+
+ return devices
+
+
+def vscsi_search_hctl_and_block(device):
+
+ scsi_devices = vscsi_get_scsidevices()
+
+ tmp = device.split(':')
+ if len(tmp) == 4:
+ (hctl, block) = _vscsi_hctl_block(device, scsi_devices)
+ else:
+ (hctl, block) = _vscsi_block_scsiid_to_hctl(device, scsi_devices)
+
+ return (hctl, block)
+
diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py
index 63cc303a5e..097c18e701 100644
--- a/tools/python/xen/xend/XendConfig.py
+++ b/tools/python/xen/xend/XendConfig.py
@@ -1216,7 +1216,7 @@ class XendConfig(dict):
dev_type = sxp.name(config)
dev_info = {}
- if dev_type == 'pci':
+ if dev_type == 'pci' or dev_type == 'vscsi':
pci_devs_uuid = sxp.child_value(config, 'uuid',
uuid.createString())
@@ -1625,7 +1625,7 @@ class XendConfig(dict):
dev_type, dev_info = self['devices'][dev_uuid]
- if dev_type == 'pci': # Special case for pci
+ if dev_type == 'pci' or dev_type == 'vscsi': # Special case for pci
pci_dict = self.pci_convert_sxp_to_dict(config)
pci_devs = pci_dict['devs']
@@ -1739,8 +1739,11 @@ class XendConfig(dict):
ordered_refs = self.ordered_device_refs(target = target)
for dev_uuid in ordered_refs:
dev_type, dev_info = target['devices'][dev_uuid]
- if dev_type == 'pci': # special case for pci devices
- sxpr = ['pci', ['uuid', dev_info['uuid']]]
+ if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
+ if dev_type == 'pci':
+ sxpr = ['pci', ['uuid', dev_info['uuid']]]
+ elif dev_type == 'vscsi':
+ sxpr = ['vscsi', ['uuid', dev_info['uuid']]]
for pci_dev_info in dev_info['devs']:
pci_dev_sxpr = ['dev']
for opt, val in pci_dev_info.items():
diff --git a/tools/python/xen/xend/XendDevices.py b/tools/python/xen/xend/XendDevices.py
index 635ff923f8..44638424a9 100644
--- a/tools/python/xen/xend/XendDevices.py
+++ b/tools/python/xen/xend/XendDevices.py
@@ -19,7 +19,7 @@
# A collection of DevControllers
#
-from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif
+from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif
from xen.xend.server.BlktapController import BlktapController
from xen.xend.server.ConsoleController import ConsoleController
@@ -45,6 +45,7 @@ class XendDevices:
'vfb': vfbif.VfbifController,
'vkbd': vfbif.VkbdifController,
'console': ConsoleController,
+ 'vscsi': vscsiif.VSCSIController,
}
#@classmethod
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 1f14c41639..968d8d1411 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -750,6 +750,52 @@ class XendDomainInfo:
return True
+ def vscsi_device_configure(self, dev_sxp):
+ """Configure an existing vscsi device.
+ quoted pci funciton
+ """
+ dev_class = sxp.name(dev_sxp)
+ if dev_class != 'vscsi':
+ return False
+
+ dev_config = self.pci_convert_sxp_to_dict(dev_sxp)
+ dev = dev_config['devs'][0]
+ req_devid = sxp.child_value(dev_sxp, 'devid')
+ req_devid = int(req_devid)
+ existing_dev_info = self._getDeviceInfo_vscsi(req_devid, dev['v-dev'])
+ state = sxp.child_value(dev_sxp, 'state')
+
+ if state == 'Initialising':
+ # new create
+ # If request devid does not exist, create and exit.
+ if existing_dev_info is None:
+ self.device_create(dev_sxp)
+ return True
+ elif existing_dev_info == "exists":
+ raise XendError("The virtual device %s is already defined" % dev['v-dev'])
+
+ elif state == 'Closing':
+ if existing_dev_info is None:
+ raise XendError("Cannot detach vscsi device does not exist")
+
+ # use DevController.reconfigureDevice to change device config
+ dev_control = self.getDeviceController(dev_class)
+ dev_uuid = dev_control.reconfigureDevice(req_devid, dev_config)
+ dev_control.waitForDevice_reconfigure(req_devid)
+ num_devs = dev_control.cleanupDevice(req_devid)
+
+ # update XendConfig with new device info
+ if dev_uuid:
+ new_dev_sxp = dev_control.configuration(req_devid)
+ self.info.device_update(dev_uuid, new_dev_sxp)
+
+ # If there is no device left, destroy vscsi and remove config.
+ if num_devs == 0:
+ self.destroyDevice('vscsi', req_devid)
+ del self.info['devices'][dev_uuid]
+
+ return True
+
def device_configure(self, dev_sxp, devid = None):
"""Configure an existing device.
@@ -768,6 +814,9 @@ class XendDomainInfo:
if dev_class == 'pci':
return self.pci_device_configure(dev_sxp)
+ if dev_class == 'vscsi':
+ return self.vscsi_device_configure(dev_sxp)
+
for opt_val in dev_sxp[1:]:
try:
dev_config[opt_val[0]] = opt_val[1]
@@ -942,6 +991,25 @@ class XendDomainInfo:
return dev_info
return None
+ def _getDeviceInfo_vscsi(self, devid, vdev):
+ devid = int(devid)
+ for dev_type, dev_info in self.info.all_devices_sxpr():
+ if dev_type != 'vscsi':
+ continue
+ existing_dev_uuid = sxp.child_value(dev_info, 'uuid')
+ existing_conf = self.info['devices'][existing_dev_uuid][1]
+ existing_dev = existing_conf['devs'][0]
+ existing_devid = int(existing_dev['devid'])
+ existing_vdev = existing_dev['v-dev']
+
+ if vdev == existing_vdev:
+ return "exists"
+
+ if devid == existing_devid:
+ return dev_info
+
+ return None
+
def setMemoryTarget(self, target):
"""Set the memory target of this domain.
@param target: In MiB.
@@ -1811,10 +1879,12 @@ class XendDomainInfo:
if self.image:
self.image.prepareEnvironment()
+ vscsi_uuidlist = {}
+ vscsi_devidlist = []
ordered_refs = self.info.ordered_device_refs()
for dev_uuid in ordered_refs:
devclass, config = self.info['devices'][dev_uuid]
- if devclass in XendDevices.valid_devices():
+ if devclass in XendDevices.valid_devices() and devclass != 'vscsi':
log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
dev_uuid = config.get('uuid')
devid = self._createDevice(devclass, config)
@@ -1823,6 +1893,27 @@ class XendDomainInfo:
if dev_uuid in self.info['devices']:
self.info['devices'][dev_uuid][1]['devid'] = devid
+ elif devclass == 'vscsi':
+ vscsi_config = config.get('devs', [])[0]
+ devid = vscsi_config.get('devid', '')
+ dev_uuid = config.get('uuid')
+ vscsi_uuidlist[devid] = dev_uuid
+ vscsi_devidlist.append(devid)
+
+ #It is necessary to sorted it for /dev/sdxx in guest.
+ if len(vscsi_uuidlist) > 0:
+ vscsi_devidlist.sort()
+ for vscsiid in vscsi_devidlist:
+ dev_uuid = vscsi_uuidlist[vscsiid]
+ devclass, config = self.info['devices'][dev_uuid]
+ log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
+ dev_uuid = config.get('uuid')
+ devid = self._createDevice(devclass, config)
+ # store devid in XendConfig for caching reasons
+ if dev_uuid in self.info['devices']:
+ self.info['devices'][dev_uuid][1]['devid'] = devid
+
+
if self.image:
self.image.createDeviceModel()
diff --git a/tools/python/xen/xend/server/vscsiif.py b/tools/python/xen/xend/server/vscsiif.py
new file mode 100644
index 0000000000..af37eae699
--- /dev/null
+++ b/tools/python/xen/xend/server/vscsiif.py
@@ -0,0 +1,228 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# 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
+#============================================================================
+# Copyright (C) 2007 FUJITSU Limited
+# Based on the blkif.py
+#============================================================================
+
+
+"""Support for VSCSI Devices.
+"""
+import re
+import string
+
+import types
+
+from xen.xend import sxp
+from xen.xend.XendError import VmError
+from xen.xend.XendLogging import log
+
+from xen.xend.server.DevController import DevController, xenbusState
+from xen.xend.xenstore.xstransact import xstransact
+
+class VSCSIController(DevController):
+ """VSCSI Devices.
+ """
+ def __init__(self, vm):
+ """Create a VSCSI Devices.
+ """
+ DevController.__init__(self, vm)
+
+
+ def sxprs(self):
+ """@see DevController.sxprs"""
+ devslist = []
+ for devid in self.deviceIDs():
+ vscsi_devs = self.readBackendList(devid, "vscsi-devs")
+ vscsipath = "vscsi-devs/"
+ devs = []
+ vscsi_config = []
+ for dev in vscsi_devs:
+ devpath = vscsipath + dev
+ backstate = self.readBackend(devid, devpath + '/state')
+ pdev = self.readBackend(devid, devpath + '/p-dev')
+ pdevname = self.readBackend(devid, devpath + '/p-devname')
+ vdev = self.readBackend(devid, devpath + '/v-dev')
+ localdevid = self.readBackend(devid, devpath + '/devid')
+ frontstate = self.readFrontend(devid, devpath + '/state')
+ devs.append(['dev', \
+ ['state', backstate], \
+ ['devid', localdevid], \
+ ['p-dev', pdev], \
+ ['p-devname', pdevname], \
+ ['v-dev', vdev], \
+ ['frontstate', frontstate] ])
+
+ vscsi_config.append(['devs', devs])
+ state = self.readFrontend(devid, 'state')
+ vscsi_config.append(['state', state])
+ backid = self.readFrontend(devid, 'backend-id')
+ vscsi_config.append(['backend-id', backid])
+ backpath = self.readFrontend(devid, 'backend')
+ vscsi_config.append(['backend', backpath])
+
+ devslist.append([devid, vscsi_config])
+
+ return devslist
+
+
+ def getDeviceDetails(self, config):
+ """@see DevController.getDeviceDetails"""
+ back = {}
+ vscsipath = "vscsi-devs/"
+ for vscsi_config in config.get('devs', []):
+ localdevid = self.allocateDeviceID()
+ # vscsi-devs/dev-0
+ devpath = vscsipath + 'dev-%i' % localdevid
+ back[devpath] = ""
+ pdev = vscsi_config.get('p-dev', '')
+ back[devpath + '/p-dev'] = pdev
+ pdevname = vscsi_config.get('p-devname', '')
+ back[devpath + '/p-devname'] = pdevname
+ vdev = vscsi_config.get('v-dev', '')
+ back[devpath + '/v-dev'] = vdev
+ state = vscsi_config.get('state', '')
+ back[devpath + '/state'] = str(xenbusState[state])
+ devid = vscsi_config.get('devid', '')
+ back[devpath + '/devid'] = str(devid)
+
+ back['uuid'] = config.get('uuid','')
+ devid = int(devid)
+ return (devid, back, {})
+
+
+ def readBackendList(self, devid, *args):
+ frontpath = self.frontendPath(devid)
+ backpath = xstransact.Read(frontpath + "/backend")
+ if backpath:
+ paths = map(lambda x: backpath + "/" + x, args)
+ return xstransact.List(*paths)
+
+
+ def getDeviceConfiguration(self, devid, transaction = None):
+ config = DevController.getDeviceConfiguration(self, devid, transaction)
+
+ vscsi_devs = []
+
+ devs = self.readBackendList(devid, "vscsi-devs")
+ vscsipath = "vscsi-devs/"
+ for dev in devs:
+ devpath = vscsipath + dev
+ pdev = self.readBackend(devid, devpath + '/p-dev')
+ pdevname = self.readBackend(devid, devpath + '/p-devname')
+ vdev = self.readBackend(devid, devpath + '/v-dev')
+ state = self.readBackend(devid, devpath + '/state')
+ localdevid = self.readBackend(devid, devpath + '/devid')
+ dev_dict = {'p-dev': pdev,
+ 'p-devname': pdevname,
+ 'v-dev': pdevname,
+ 'state': state,
+ 'devid': localdevid }
+ vscsi_devs.append(dev_dict)
+
+ config['devs'] = vscsi_devs
+ config['uuid'] = self.readBackend(devid, 'uuid')
+ return config
+
+
+ def configuration(self, devid, transaction = None):
+ """Returns SXPR for devices on domain.
+ @note: we treat this dict especially to convert to
+ SXP because it is not a straight dict of strings."""
+
+ configDict = self.getDeviceConfiguration(devid, transaction)
+ sxpr = [self.deviceClass]
+
+ # remove devs
+ devs = configDict.pop('devs', [])
+
+ for dev in devs:
+ dev_sxpr = ['dev']
+ for dev_item in dev.items():
+ dev_sxpr.append(list(dev_item))
+ sxpr.append(dev_sxpr)
+
+ for key, val in configDict.items():
+ if type(val) == type(list()):
+ for v in val:
+ sxpr.append([key, v])
+ else:
+ sxpr.append([key, val])
+
+ return sxpr
+
+
+ def reconfigureDevice(self, _, config):
+ """@see DevController.reconfigureDevice"""
+ (devid, back, front) = self.getDeviceDetails(config)
+ devid = int(devid)
+ vscsi_config = config['devs'][0]
+ states = config.get('states', [])
+ uuid = self.readBackend(devid, 'uuid')
+ if states[0] == 'Initialising':
+ back['uuid'] = uuid
+ self.writeBackend(devid, back)
+
+ elif states[0] == 'Closing':
+ found = False
+ devs = self.readBackendList(devid, "vscsi-devs")
+ vscsipath = "vscsi-devs/"
+ vdev = vscsi_config.get('v-dev', '')
+
+ for dev in devs:
+ devpath = vscsipath + dev
+ old_vdev = self.readBackend(devid, devpath + '/v-dev')
+ if vdev == old_vdev:
+ found = True
+ self.writeBackend(devid, devpath + '/state', \
+ str(xenbusState['Closing']))
+ break
+
+ if not found:
+ raise VmError("Device %s not connected" % vdev)
+
+ else:
+ raise XendError('Error configuring device invalid state %s'
+ % state)
+
+ self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring']))
+ return self.readBackend(devid, 'uuid')
+
+
+ def cleanupDevice(self, devid):
+ devs = self.readBackendList(devid, "vscsi-devs")
+ vscsipath = "vscsi-devs/"
+ new_num_devs = 0
+
+ for dev in devs:
+ new_num_devs = new_num_devs + 1
+ devpath = vscsipath + dev
+ devstate = self.readBackend(devid, devpath + '/state')
+
+ if str(xenbusState['Closed']) == devstate:
+ self.removeBackend(devid, devpath)
+ frontpath = self.frontendPath(devid)
+ xstransact.Remove(frontpath + '/' + devpath)
+ new_num_devs = new_num_devs - 1
+
+ frontpath = self.frontendPath(devid)
+ front_devstate = xstransact.Read(frontpath + '/' + devpath)
+ if front_devstate is not None:
+ if str(xenbusState['Closed']) == front_devstate:
+ self.removeBackend(devid, devpath)
+ xstransact.Remove(frontpath + '/' + devpath)
+ new_num_devs = new_num_devs - 1
+
+ return new_num_devs
+
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index ddd0e47e76..60b350e310 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -33,6 +33,7 @@ from xen.xend import osdep
import xen.xend.XendClient
from xen.xend.XendBootloader import bootloader
from xen.util import blkif
+from xen.util import vscsi_util
import xen.util.xsm.xsm as security
from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
@@ -307,6 +308,11 @@ gopts.var('pci', val='BUS:DEV.FUNC',
For example 'pci=c0:02.1'.
The option may be repeated to add more than one pci device.""")
+gopts.var('vscsi', val='PDEV,VDEV[,DOM]',
+ fn=append_value, default=[],
+ use="""Add a SCSI device to a domain. The physical device is PDEV,
+ which is exported to the domain as VDEV(X:X:X:X).""")
+
gopts.var('ioports', val='FROM[-TO]',
fn=append_value, default=[],
use="""Add a legacy I/O range to a domain, using given params (in hex).
@@ -638,6 +644,73 @@ def configure_pci(config_devs, vals):
config_pci.insert(0, 'pci')
config_devs.append(['device', config_pci])
+def vscsi_convert_sxp_to_dict(dev_sxp):
+ dev_dict = {}
+ for opt_val in dev_sxp[1:]:
+ try:
+ opt, val = opt_val
+ dev_dict[opt] = val
+ except TypeError:
+ pass
+ return dev_dict
+
+def vscsi_lookup_devid(devlist, req_devid):
+ if len(devlist) == 0:
+ return 0
+ else:
+ for devid, backend in devlist:
+ if devid == req_devid:
+ return 1
+ return 0
+
+def configure_vscsis(config_devs, vals):
+ """Create the config for vscsis (virtual scsi devices).
+ """
+ devidlist = []
+ config_scsi = []
+ if len(vals.vscsi) == 0:
+ return 0
+
+ scsi_devices = vscsi_util.vscsi_get_scsidevices()
+ for (p_dev, v_dev, backend) in vals.vscsi:
+ tmp = p_dev.split(':')
+ if len(tmp) == 4:
+ (p_hctl, block) = vscsi_util._vscsi_hctl_block(p_dev, scsi_devices)
+ else:
+ (p_hctl, block) = vscsi_util._vscsi_block_scsiid_to_hctl(p_dev, scsi_devices)
+
+ if p_hctl == None:
+ raise ValueError("Cannot find device \"%s\"" % p_dev)
+
+ for config in config_scsi:
+ dev = vscsi_convert_sxp_to_dict(config)
+ if dev['v-dev'] == v_dev:
+ raise ValueError('The virtual device "%s" is already defined' % v_dev)
+
+ v_hctl = v_dev.split(':')
+ devid = int(v_hctl[0])
+ config_scsi.append(['dev', \
+ ['state', 'Initialising'], \
+ ['devid', devid], \
+ ['p-dev', p_hctl], \
+ ['p-devname', block], \
+ ['v-dev', v_dev] ])
+
+ if vscsi_lookup_devid(devidlist, devid) == 0:
+ devidlist.append([devid, backend])
+
+ for devid, backend in devidlist:
+ tmp = []
+ for config in config_scsi:
+ dev = vscsi_convert_sxp_to_dict(config)
+ if dev['devid'] == devid:
+ tmp.append(config)
+
+ tmp.insert(0, 'vscsi')
+ if backend:
+ tmp.append(['backend', backend])
+ config_devs.append(['device', tmp])
+
def configure_ioports(config_devs, vals):
"""Create the config for legacy i/o ranges.
"""
@@ -829,6 +902,7 @@ def make_config(vals):
config_devs = []
configure_disks(config_devs, vals)
configure_pci(config_devs, vals)
+ configure_vscsis(config_devs, vals)
configure_ioports(config_devs, vals)
configure_irq(config_devs, vals)
configure_vifs(config_devs, vals)
@@ -896,6 +970,25 @@ def preprocess_pci(vals):
err('Error in PCI slot syntax "%s"'%(pci_dev_str))
vals.pci = pci
+def preprocess_vscsi(vals):
+ if not vals.vscsi: return
+ scsi = []
+ for scsi_str in vals.vscsi:
+ d = scsi_str.split(',')
+ n = len(d)
+ if n == 2:
+ tmp = d[1].split(':')
+ if len(tmp) != 4:
+ err('vscsi syntax error "%s"' % d[1])
+ else:
+ d.append(None)
+ elif n == 3:
+ pass
+ else:
+ err('vscsi syntax error "%s"' % scsi_str)
+ scsi.append(d)
+ vals.vscsi = scsi
+
def preprocess_ioports(vals):
if not vals.ioports: return
ioports = []
@@ -1075,6 +1168,7 @@ def preprocess_vnc(vals):
def preprocess(vals):
preprocess_disk(vals)
preprocess_pci(vals)
+ preprocess_vscsi(vals)
preprocess_ioports(vals)
preprocess_ip(vals)
preprocess_nfs(vals)
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index a0c3657f7a..fb432b140e 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -37,6 +37,7 @@ import datetime
from select import select
import xml.dom.minidom
from xen.util.blkif import blkdev_name_to_number
+from xen.util import vscsi_util
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
@@ -182,6 +183,12 @@ SUBCOMMAND_HELP = {
'Remove a domain\'s pass-through pci device.'),
'pci-list' : ('<Domain>',
'List pass-through pci devices for a domain.'),
+ 'scsi-attach' : ('<Domain> <PhysDevice> <VirtDevice> [BackDomain]',
+ 'Attach a new SCSI device.'),
+ 'scsi-detach' : ('<Domain> <VirtDevice>',
+ 'Detach a specified SCSI device.'),
+ 'scsi-list' : ('<Domain> [--long]',
+ 'List all SCSI devices currently attached.'),
# security
@@ -348,6 +355,9 @@ device_commands = [
"pci-attach",
"pci-detach",
"pci-list",
+ "scsi-attach",
+ "scsi-detach",
+ "scsi-list",
]
vnet_commands = [
@@ -2106,6 +2116,40 @@ def xm_pci_list(args):
hdr = 1
print ( fmt_str % x )
+def vscsi_convert_sxp_to_dict(dev_sxp):
+ dev_dict = {}
+ for opt_val in dev_sxp[1:]:
+ try:
+ opt, val = opt_val
+ dev_dict[opt] = val
+ except TypeError:
+ pass
+ return dev_dict
+
+def xm_scsi_list(args):
+ xenapi_unsupported()
+ (use_long, params) = arg_check_for_resource_list(args, "scsi-list")
+
+ dom = params[0]
+
+ devs = server.xend.domain.getDeviceSxprs(dom, 'vscsi')
+
+ if use_long:
+ map(PrettyPrint.prettyprint, devs)
+ else:
+ hdr = 0
+ for x in devs:
+ if hdr == 0:
+ print "%-3s %-3s %-5s %-10s %-5s %-10s %-4s" \
+ % ('Idx', 'BE', 'state', 'phy-hctl', 'phy', 'vir-hctl', 'devstate')
+ hdr = 1
+ ni = parse_dev_info(x[1])
+ ni['idx'] = int(x[0])
+ for dev in x[1][0][1]:
+ mi = vscsi_convert_sxp_to_dict(dev)
+ print "%(idx)-3d %(backend-id)-3d %(state)-5d " % ni,
+ print "%(p-dev)-10s %(p-devname)-5s %(v-dev)-10s %(frontstate)-4s" % mi
+
def parse_block_configuration(args):
dom = args[0]
@@ -2285,6 +2329,38 @@ def xm_pci_attach(args):
(dom, pci) = parse_pci_configuration(args, 'Initialising')
server.xend.domain.device_configure(dom, pci)
+def xm_scsi_attach(args):
+ xenapi_unsupported()
+
+ arg_check(args, 'scsi-attach', 3, 4)
+ p_devname = args[1]
+ v_dev = args[2]
+
+ v_hctl = v_dev.split(':')
+ if len(v_hctl) != 4:
+ raise OptionError("Invalid argument: %s" % v_dev)
+
+ (p_hctl, block) = vscsi_util.vscsi_search_hctl_and_block(p_devname)
+
+ if p_hctl == None:
+ raise OptionError("Cannot find device \"%s\"" % p_devname)
+
+ dom = args[0]
+ vscsi = ['vscsi']
+ vscsi.append(['dev', \
+ ['state', 'Initialising'], \
+ ['devid', v_hctl[0]], \
+ ['p-dev', p_hctl], \
+ ['p-devname', block], \
+ ['v-dev', v_dev] ])
+
+ if len(args) == 4:
+ vscsi.append(['backend', args[3]])
+
+ vscsi.append(['state', 'Initialising'])
+ vscsi.append(['devid', v_hctl[0]])
+ server.xend.domain.device_configure(dom, vscsi)
+
def detach(args, deviceClass):
rm_cfg = True
dom = args[0]
@@ -2353,6 +2429,27 @@ def xm_pci_detach(args):
(dom, pci) = parse_pci_configuration(args, 'Closing')
server.xend.domain.device_configure(dom, pci)
+def xm_scsi_detach(args):
+ xenapi_unsupported()
+ arg_check(args, 'scsi-detach', 2)
+
+ v_dev = args[1]
+ v_hctl = v_dev.split(':')
+ if len(v_hctl) != 4:
+ raise OptionError("Invalid argument: %s" % v_dev)
+
+ dom = args[0]
+ vscsi = ['vscsi']
+ vscsi.append(['dev', \
+ ['state', 'Closing'], \
+ ['devid', v_hctl[0]], \
+ ['p-dev', ''], \
+ ['p-devname', ''], \
+ ['v-dev', v_dev] ])
+
+ vscsi.append(['state', 'Closing'])
+ vscsi.append(['devid', v_hctl[0]])
+ server.xend.domain.device_configure(dom, vscsi)
def xm_vnet_list(args):
xenapi_unsupported()
@@ -2548,6 +2645,10 @@ commands = {
"pci-attach": xm_pci_attach,
"pci-detach": xm_pci_detach,
"pci-list": xm_pci_list,
+ # vscsi
+ "scsi-attach": xm_scsi_attach,
+ "scsi-detach": xm_scsi_detach,
+ "scsi-list": xm_scsi_list,
}
## The commands supported by a separate argument parser in xend.xm.