# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1215088746 -3600
# Node ID 6ae87b27cceadaf8339b42b7489f81b66ea03cf1
# Parent d90c5e8d4ac2c547a81d4a464c83a7b8090c1946
pvSCSI: xend changes
Signed-off-by: Tomonari Horikoshi <t.horikoshi@xxxxxxxxxxxxxx>
Signed-off-by: Jun Kamada <kama@xxxxxxxxxxxxxx>
---
tools/examples/vscsi | 22 +++
tools/examples/xen-backend.agent | 3
tools/examples/xen-backend.rules | 1
tools/examples/xmexample.hvm | 23 +++
tools/examples/xmexample.vti | 22 +++
tools/examples/xmexample1 | 25 +++
tools/examples/xmexample2 | 24 +++
tools/python/xen/util/vscsi_util.py | 133 ++++++++++++++++++
tools/python/xen/xend/XendConfig.py | 11 -
tools/python/xen/xend/XendDevices.py | 3
tools/python/xen/xend/XendDomainInfo.py | 93 ++++++++++++-
tools/python/xen/xend/server/vscsiif.py | 228 ++++++++++++++++++++++++++++++++
tools/python/xen/xm/create.py | 94 +++++++++++++
tools/python/xen/xm/main.py | 101 ++++++++++++++
14 files changed, 775 insertions(+), 8 deletions(-)
diff -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/vscsi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/examples/vscsi Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/xen-backend.agent
--- a/tools/examples/xen-backend.agent Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/examples/xen-backend.agent Thu Jul 03 13:39:06 2008 +0100
@@ -19,6 +19,9 @@ case "$XENBUS_TYPE" in
vif)
[ -n "$script" ] && $script "$ACTION"
;;
+ vscsi)
+ /etc/xen/scripts/vscsi "$ACTION"
+ ;;
esac
case "$ACTION" in
diff -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/xen-backend.rules
--- a/tools/examples/xen-backend.rules Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/examples/xen-backend.rules Thu Jul 03 13:39:06 2008 +0100
@@ -3,6 +3,7 @@ SUBSYSTEM=="xen-backend", KERNEL=="vtpm*
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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/xmexample.hvm
--- a/tools/examples/xmexample.hvm Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/examples/xmexample.hvm Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/xmexample.vti
--- a/tools/examples/xmexample.vti Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/examples/xmexample.vti Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/xmexample1
--- a/tools/examples/xmexample1 Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/examples/xmexample1 Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/examples/xmexample2
--- a/tools/examples/xmexample2 Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/examples/xmexample2 Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/util/vscsi_util.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/vscsi_util.py Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/python/xen/xend/XendConfig.py Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/xend/XendDevices.py
--- a/tools/python/xen/xend/XendDevices.py Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/python/xen/xend/XendDevices.py Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py Thu Jul 03 13:39:06 2008 +0100
@@ -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.
@@ -767,6 +813,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:
@@ -940,6 +989,25 @@ class XendDomainInfo:
if dev_type != 'pci':
continue
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):
@@ -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)
@@ -1822,6 +1892,27 @@ class XendDomainInfo:
# store devid in XendConfig for caching reasons
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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/xend/server/vscsiif.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/vscsiif.py Thu Jul 03 13:39:06 2008 +0100
@@ -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 -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/python/xen/xm/create.py Thu Jul 03 13:39:06 2008 +0100
@@ -33,6 +33,7 @@ import xen.xend.XendClient
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
@@ -306,6 +307,11 @@ gopts.var('pci', val='BUS:DEV.FUNC',
use="""Add a PCI device to a domain, using given params (in hex).
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=[],
@@ -637,6 +643,73 @@ def configure_pci(config_devs, vals):
if len(config_pci)>0:
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)
@@ -895,6 +969,25 @@ def preprocess_pci(vals):
except IndexError:
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
@@ -1075,6 +1168,7 @@ def preprocess(vals):
def preprocess(vals):
preprocess_disk(vals)
preprocess_pci(vals)
+ preprocess_vscsi(vals)
preprocess_ioports(vals)
preprocess_ip(vals)
preprocess_nfs(vals)
diff -r d90c5e8d4ac2 -r 6ae87b27ccea tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py Thu Jul 03 11:32:10 2008 +0100
+++ b/tools/python/xen/xm/main.py Thu Jul 03 13:39:06 2008 +0100
@@ -37,6 +37,7 @@ from select import select
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.
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|