ia64/xen-unstable

changeset 17962:6ae87b27ccea

pvSCSI: xend changes

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jul 03 13:39:06 2008 +0100 (2008-07-03)
parents d90c5e8d4ac2
children 1db0b09b290e
files tools/examples/vscsi tools/examples/xen-backend.agent tools/examples/xen-backend.rules tools/examples/xmexample.hvm tools/examples/xmexample.vti tools/examples/xmexample1 tools/examples/xmexample2 tools/python/xen/util/vscsi_util.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDevices.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/vscsiif.py tools/python/xen/xm/create.py tools/python/xen/xm/main.py
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/examples/vscsi	Thu Jul 03 13:39:06 2008 +0100
     1.3 @@ -0,0 +1,22 @@
     1.4 +#!/bin/sh
     1.5 +#
     1.6 +# Copyright (c) 2007, FUJITSU Limited
     1.7 +# Based on the block scripts code.
     1.8 +#
     1.9 +
    1.10 +dir=$(dirname "$0")
    1.11 +. "$dir/xen-hotplug-common.sh"
    1.12 +
    1.13 +findCommand "$@"
    1.14 +
    1.15 +case "$command" in
    1.16 +	add)
    1.17 +		success
    1.18 +		;;
    1.19 +	remove)
    1.20 +		# TODO
    1.21 +		exit 0
    1.22 +		;;
    1.23 +esac
    1.24 +
    1.25 +exit 0
     2.1 --- a/tools/examples/xen-backend.agent	Thu Jul 03 11:32:10 2008 +0100
     2.2 +++ b/tools/examples/xen-backend.agent	Thu Jul 03 13:39:06 2008 +0100
     2.3 @@ -19,6 +19,9 @@ case "$XENBUS_TYPE" in
     2.4    vif)
     2.5      [ -n "$script" ] && $script "$ACTION"
     2.6      ;;
     2.7 +  vscsi)
     2.8 +    /etc/xen/scripts/vscsi "$ACTION"
     2.9 +    ;;
    2.10  esac
    2.11  
    2.12  case "$ACTION" in
     3.1 --- a/tools/examples/xen-backend.rules	Thu Jul 03 11:32:10 2008 +0100
     3.2 +++ b/tools/examples/xen-backend.rules	Thu Jul 03 13:39:06 2008 +0100
     3.3 @@ -3,6 +3,7 @@ SUBSYSTEM=="xen-backend", KERNEL=="vbd*"
     3.4  SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
     3.5  SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} online"
     3.6  SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline", RUN+="$env{script} offline"
     3.7 +SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
     3.8  SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
     3.9  KERNEL=="evtchn", NAME="xen/%k"
    3.10  KERNEL=="blktap[0-9]*", NAME="xen/%k"
     4.1 --- a/tools/examples/xmexample.hvm	Thu Jul 03 11:32:10 2008 +0100
     4.2 +++ b/tools/examples/xmexample.hvm	Thu Jul 03 13:39:06 2008 +0100
     4.3 @@ -282,3 +282,26 @@ serial='pty'
     4.4  #  '0' -> the bit must be '0'
     4.5  #  'x' -> we don't care (do not check)
     4.6  #  's' -> the bit must be the same as on the host that started this VM
     4.7 +
     4.8 +
     4.9 +#-----------------------------------------------------------------------------
    4.10 +#   Configure PVSCSI devices:
    4.11 +#
    4.12 +#vscsi=[ 'PDEV, VDEV' ]
    4.13 +#
    4.14 +#   PDEV   gives physical SCSI device to be attached to specified guest
    4.15 +#          domain by one of the following identifier format.
    4.16 +#          - XX:XX:XX:XX (4-tuples with decimal notation which shows
    4.17 +#                          "host:channel:target:lun")
    4.18 +#          - /dev/sdxx or sdx
    4.19 +#          - /dev/stxx or stx
    4.20 +#          - /dev/sgxx or sgx
    4.21 +#          - result of 'scsi_id -gu -s'.
    4.22 +#            ex. # scsi_id -gu -s /block/sdb
    4.23 +#                  36000b5d0006a0000006a0257004c0000
    4.24 +#
    4.25 +#   VDEV   gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as 
    4.26 +#          which the specified guest domain recognize.
    4.27 +#
    4.28 +
    4.29 +#vscsi = [ '/dev/sdx, 0:0:0:0' ]
     5.1 --- a/tools/examples/xmexample.vti	Thu Jul 03 11:32:10 2008 +0100
     5.2 +++ b/tools/examples/xmexample.vti	Thu Jul 03 13:39:06 2008 +0100
     5.3 @@ -161,3 +161,25 @@ serial='pty'
     5.4  #    'windows' - All Windows variants (Windows Server 2003/2008)
     5.5  #
     5.6  #guest_os_type='default'
     5.7 +
     5.8 +#-----------------------------------------------------------------------------
     5.9 +#   Configure PVSCSI devices:
    5.10 +#
    5.11 +#vscsi=[ 'PDEV, VDEV' ]
    5.12 +#
    5.13 +#   PDEV   gives physical SCSI device to be attached to specified guest
    5.14 +#          domain by one of the following identifier format.
    5.15 +#          - XX:XX:XX:XX (4-tuples with decimal notation which shows
    5.16 +#                          "host:channel:target:lun")
    5.17 +#          - /dev/sdxx or sdx
    5.18 +#          - /dev/stxx or stx
    5.19 +#          - /dev/sgxx or sgx
    5.20 +#          - result of 'scsi_id -gu -s'.
    5.21 +#            ex. # scsi_id -gu -s /block/sdb
    5.22 +#                  36000b5d0006a0000006a0257004c0000
    5.23 +#
    5.24 +#   VDEV   gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as 
    5.25 +#          which the specified guest domain recognize.
    5.26 +#
    5.27 +
    5.28 +#vscsi = [ '/dev/sdx, 0:0:0:0' ]
     6.1 --- a/tools/examples/xmexample1	Thu Jul 03 11:32:10 2008 +0100
     6.2 +++ b/tools/examples/xmexample1	Thu Jul 03 13:39:06 2008 +0100
     6.3 @@ -185,4 +185,27 @@ extra = "4"
     6.4  #on_reboot   = 'restart'
     6.5  #on_crash    = 'restart'
     6.6  
     6.7 +#-----------------------------------------------------------------------------
     6.8 +#   Configure PVSCSI devices:
     6.9 +#
    6.10 +#vscsi=[ 'PDEV, VDEV' ]
    6.11 +#
    6.12 +#   PDEV   gives physical SCSI device to be attached to specified guest
    6.13 +#          domain by one of the following identifier format.
    6.14 +#          - XX:XX:XX:XX (4-tuples with decimal notation which shows
    6.15 +#                          "host:channel:target:lun")
    6.16 +#          - /dev/sdxx or sdx
    6.17 +#          - /dev/stxx or stx
    6.18 +#          - /dev/sgxx or sgx
    6.19 +#          - result of 'scsi_id -gu -s'.
    6.20 +#            ex. # scsi_id -gu -s /block/sdb
    6.21 +#                  36000b5d0006a0000006a0257004c0000
    6.22 +#
    6.23 +#   VDEV   gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as 
    6.24 +#          which the specified guest domain recognize.
    6.25 +#
    6.26 +
    6.27 +#vscsi = [ '/dev/sdx, 0:0:0:0' ]
    6.28 +
    6.29  #============================================================================
    6.30 +
     7.1 --- a/tools/examples/xmexample2	Thu Jul 03 11:32:10 2008 +0100
     7.2 +++ b/tools/examples/xmexample2	Thu Jul 03 13:39:06 2008 +0100
     7.3 @@ -221,4 +221,26 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid
     7.4  #on_reboot   = 'restart'
     7.5  #on_crash    = 'restart'
     7.6  
     7.7 +#-----------------------------------------------------------------------------
     7.8 +#   Configure PVSCSI devices:
     7.9 +#
    7.10 +#vscsi=[ 'PDEV, VDEV' ]
    7.11 +#
    7.12 +#   PDEV   gives physical SCSI device to be attached to specified guest
    7.13 +#          domain by one of the following identifier format.
    7.14 +#          - XX:XX:XX:XX (4-tuples with decimal notation which shows
    7.15 +#                          "host:channel:target:lun")
    7.16 +#          - /dev/sdxx or sdx
    7.17 +#          - /dev/stxx or stx
    7.18 +#          - /dev/sgxx or sgx
    7.19 +#          - result of 'scsi_id -gu -s'.
    7.20 +#            ex. # scsi_id -gu -s /block/sdb
    7.21 +#                  36000b5d0006a0000006a0257004c0000
    7.22 +#
    7.23 +#   VDEV   gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as 
    7.24 +#          which the specified guest domain recognize.
    7.25 +#
    7.26 +
    7.27 +#vscsi = [ '/dev/sdx, 0:0:0:0' ]
    7.28 +
    7.29  #============================================================================
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/python/xen/util/vscsi_util.py	Thu Jul 03 13:39:06 2008 +0100
     8.3 @@ -0,0 +1,133 @@
     8.4 +#!/usr/bin/env python
     8.5 +#  -*- mode: python; -*-
     8.6 +
     8.7 +#============================================================================
     8.8 +# This library is free software; you can redistribute it and/or
     8.9 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
    8.10 +# License as published by the Free Software Foundation.
    8.11 +#
    8.12 +# This library is distributed in the hope that it will be useful,
    8.13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    8.15 +# Lesser General Public License for more details.
    8.16 +#
    8.17 +# You should have received a copy of the GNU Lesser General Public
    8.18 +# License along with this library; if not, write to the Free Software
    8.19 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    8.20 +#============================================================================
    8.21 +# Copyright (C) 2008 FUJITSU Limited
    8.22 +#                     Based on the blkif.py
    8.23 +#============================================================================
    8.24 +
    8.25 +
    8.26 +"""Support for VSCSI Devices.
    8.27 +"""
    8.28 +import os
    8.29 +import sys
    8.30 +import re
    8.31 +import string
    8.32 +
    8.33 +def _vscsi_hctl_block(name, scsi_devices):
    8.34 +    """ block-device name is convert into hctl. (e.g., '/dev/sda',
    8.35 +    '0:0:0:0')"""
    8.36 +    try:
    8.37 +        search = re.compile(r'' + name + '$', re.DOTALL)
    8.38 +    except Exception, e:
    8.39 +        raise VmError("vscsi: invalid expression. " + str(e))
    8.40 +    chk = 0
    8.41 +    for hctl, block, sg, scsi_id in scsi_devices:
    8.42 +        if search.match(hctl):
    8.43 +            chk = 1
    8.44 +            break
    8.45 +
    8.46 +    if chk:
    8.47 +        return (hctl, block)
    8.48 +    else:
    8.49 +        return (None, None)
    8.50 +
    8.51 +
    8.52 +def _vscsi_block_scsiid_to_hctl(phyname, scsi_devices):
    8.53 +    """ block-device name is convert into hctl. (e.g., '/dev/sda',
    8.54 +    '0:0:0:0')"""
    8.55 +    
    8.56 +    if re.match('/dev/sd[a-z]+([1-9]|1[0-5])?$', phyname):
    8.57 +        # sd driver
    8.58 +        name = re.sub('(^/dev/)|([1-9]|1[0-5])?$', '', phyname)
    8.59 +    elif re.match('/dev/sg[0-9]+$', phyname):
    8.60 +        # sg driver
    8.61 +        name = re.sub('^/dev/', '', phyname)
    8.62 +    elif re.match('/dev/st[0-9]+$', phyname):
    8.63 +        # st driver
    8.64 +        name = re.sub('^/dev/', '', phyname)
    8.65 +    else:
    8.66 +        # scsi_id -gu
    8.67 +        name = phyname
    8.68 +
    8.69 +    chk = 0
    8.70 +    for hctl, block, sg, scsi_id in scsi_devices:
    8.71 +        if block == name:
    8.72 +            chk = 1
    8.73 +            break
    8.74 +        elif sg == name:
    8.75 +            chk = 1
    8.76 +            break
    8.77 +        elif scsi_id == name:
    8.78 +            chk = 1
    8.79 +            break
    8.80 +
    8.81 +    if chk:
    8.82 +        return (hctl, block)
    8.83 +    else:
    8.84 +        return (None, None)
    8.85 +
    8.86 +
    8.87 +def vscsi_get_scsidevices():
    8.88 +    """ get all scsi devices"""
    8.89 +
    8.90 +    SERCH_SCSI_PATH = "/sys/bus/scsi/devices"
    8.91 +    devices = []
    8.92 +
    8.93 +    for dirpath, dirnames, files in os.walk(SERCH_SCSI_PATH):
    8.94 +        for hctl in dirnames:
    8.95 +            paths = os.path.join(dirpath, hctl)
    8.96 +            block = "-"
    8.97 +            for f in os.listdir(paths):
    8.98 +                if re.match('^block', f):
    8.99 +                    os.chdir(os.path.join(paths, f))
   8.100 +                    block = os.path.basename(os.getcwd())
   8.101 +                elif re.match('^tape', f):
   8.102 +                    os.chdir(os.path.join(paths, f))
   8.103 +                    block = os.path.basename(os.getcwd())
   8.104 +                elif re.match('^scsi_changer', f):
   8.105 +                    os.chdir(os.path.join(paths, f))
   8.106 +                    block = os.path.basename(os.getcwd())
   8.107 +                elif re.match('^onstream_tape', f):
   8.108 +                    os.chdir(os.path.join(paths, f))
   8.109 +                    block = os.path.basename(os.getcwd())
   8.110 +
   8.111 +                if re.match('^scsi_generic', f):
   8.112 +                    os.chdir(os.path.join(paths, f))
   8.113 +                    sg = os.path.basename(os.getcwd())
   8.114 +                    lines = os.popen('/sbin/scsi_id -gu -s /class/scsi_generic/' + sg).read().split()
   8.115 +                    if len(lines) == 0:
   8.116 +                        scsi_id = '-'
   8.117 +                    else:
   8.118 +                        scsi_id = lines[0]
   8.119 +
   8.120 +            devices.append([hctl, block, sg, scsi_id])
   8.121 +
   8.122 +    return devices
   8.123 +
   8.124 +
   8.125 +def vscsi_search_hctl_and_block(device):
   8.126 +
   8.127 +    scsi_devices = vscsi_get_scsidevices()
   8.128 +
   8.129 +    tmp = device.split(':')
   8.130 +    if len(tmp) == 4:
   8.131 +        (hctl, block) = _vscsi_hctl_block(device, scsi_devices)
   8.132 +    else:
   8.133 +        (hctl, block) = _vscsi_block_scsiid_to_hctl(device, scsi_devices)
   8.134 +
   8.135 +    return (hctl, block)
   8.136 +
     9.1 --- a/tools/python/xen/xend/XendConfig.py	Thu Jul 03 11:32:10 2008 +0100
     9.2 +++ b/tools/python/xen/xend/XendConfig.py	Thu Jul 03 13:39:06 2008 +0100
     9.3 @@ -1216,7 +1216,7 @@ class XendConfig(dict):
     9.4              dev_type = sxp.name(config)
     9.5              dev_info = {}
     9.6  
     9.7 -            if dev_type == 'pci':
     9.8 +            if dev_type == 'pci' or dev_type == 'vscsi':
     9.9                  pci_devs_uuid = sxp.child_value(config, 'uuid',
    9.10                                                  uuid.createString())
    9.11  
    9.12 @@ -1625,7 +1625,7 @@ class XendConfig(dict):
    9.13  
    9.14              dev_type, dev_info = self['devices'][dev_uuid]
    9.15  
    9.16 -            if dev_type == 'pci': # Special case for pci
    9.17 +            if dev_type == 'pci' or dev_type == 'vscsi': # Special case for pci
    9.18                  pci_dict = self.pci_convert_sxp_to_dict(config)
    9.19                  pci_devs = pci_dict['devs']
    9.20  
    9.21 @@ -1739,8 +1739,11 @@ class XendConfig(dict):
    9.22          ordered_refs = self.ordered_device_refs(target = target)
    9.23          for dev_uuid in ordered_refs:
    9.24              dev_type, dev_info = target['devices'][dev_uuid]
    9.25 -            if dev_type == 'pci': # special case for pci devices
    9.26 -                sxpr = ['pci', ['uuid', dev_info['uuid']]]
    9.27 +            if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
    9.28 +                if dev_type == 'pci':
    9.29 +                    sxpr = ['pci', ['uuid', dev_info['uuid']]]
    9.30 +                elif dev_type == 'vscsi':
    9.31 +                    sxpr = ['vscsi', ['uuid', dev_info['uuid']]]
    9.32                  for pci_dev_info in dev_info['devs']:
    9.33                      pci_dev_sxpr = ['dev']
    9.34                      for opt, val in pci_dev_info.items():
    10.1 --- a/tools/python/xen/xend/XendDevices.py	Thu Jul 03 11:32:10 2008 +0100
    10.2 +++ b/tools/python/xen/xend/XendDevices.py	Thu Jul 03 13:39:06 2008 +0100
    10.3 @@ -19,7 +19,7 @@
    10.4  # A collection of DevControllers 
    10.5  #
    10.6  
    10.7 -from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif
    10.8 +from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif
    10.9  from xen.xend.server.BlktapController import BlktapController
   10.10  from xen.xend.server.ConsoleController import ConsoleController
   10.11  
   10.12 @@ -45,6 +45,7 @@ class XendDevices:
   10.13          'vfb': vfbif.VfbifController,
   10.14          'vkbd': vfbif.VkbdifController,
   10.15          'console': ConsoleController,
   10.16 +        'vscsi': vscsiif.VSCSIController,
   10.17      }
   10.18  
   10.19      #@classmethod
    11.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Jul 03 11:32:10 2008 +0100
    11.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Jul 03 13:39:06 2008 +0100
    11.3 @@ -750,6 +750,52 @@ class XendDomainInfo:
    11.4  
    11.5          return True
    11.6  
    11.7 +    def vscsi_device_configure(self, dev_sxp):
    11.8 +        """Configure an existing vscsi device.
    11.9 +            quoted pci funciton
   11.10 +        """
   11.11 +        dev_class = sxp.name(dev_sxp)
   11.12 +        if dev_class != 'vscsi':
   11.13 +            return False
   11.14 +
   11.15 +        dev_config = self.pci_convert_sxp_to_dict(dev_sxp)
   11.16 +        dev = dev_config['devs'][0]
   11.17 +        req_devid = sxp.child_value(dev_sxp, 'devid')
   11.18 +        req_devid = int(req_devid)
   11.19 +        existing_dev_info = self._getDeviceInfo_vscsi(req_devid, dev['v-dev'])
   11.20 +        state = sxp.child_value(dev_sxp, 'state')
   11.21 +
   11.22 +        if state == 'Initialising':
   11.23 +            # new create
   11.24 +            # If request devid does not exist, create and exit.
   11.25 +            if existing_dev_info is None:
   11.26 +                self.device_create(dev_sxp)
   11.27 +                return True
   11.28 +            elif existing_dev_info == "exists":
   11.29 +                raise XendError("The virtual device %s is already defined" % dev['v-dev'])
   11.30 +
   11.31 +        elif state == 'Closing':
   11.32 +            if existing_dev_info is None:
   11.33 +                raise XendError("Cannot detach vscsi device does not exist")
   11.34 +
   11.35 +        # use DevController.reconfigureDevice to change device config
   11.36 +        dev_control = self.getDeviceController(dev_class)
   11.37 +        dev_uuid = dev_control.reconfigureDevice(req_devid, dev_config)
   11.38 +        dev_control.waitForDevice_reconfigure(req_devid)
   11.39 +        num_devs = dev_control.cleanupDevice(req_devid)
   11.40 +
   11.41 +        # update XendConfig with new device info
   11.42 +        if dev_uuid:
   11.43 +            new_dev_sxp = dev_control.configuration(req_devid)
   11.44 +            self.info.device_update(dev_uuid, new_dev_sxp)
   11.45 +
   11.46 +        # If there is no device left, destroy vscsi and remove config.
   11.47 +        if num_devs == 0:
   11.48 +            self.destroyDevice('vscsi', req_devid)
   11.49 +            del self.info['devices'][dev_uuid]
   11.50 +
   11.51 +        return True
   11.52 +
   11.53      def device_configure(self, dev_sxp, devid = None):
   11.54          """Configure an existing device.
   11.55          
   11.56 @@ -768,6 +814,9 @@ class XendDomainInfo:
   11.57          if dev_class == 'pci':
   11.58              return self.pci_device_configure(dev_sxp)
   11.59  
   11.60 +        if dev_class == 'vscsi':
   11.61 +            return self.vscsi_device_configure(dev_sxp)
   11.62 +
   11.63          for opt_val in dev_sxp[1:]:
   11.64              try:
   11.65                  dev_config[opt_val[0]] = opt_val[1]
   11.66 @@ -942,6 +991,25 @@ class XendDomainInfo:
   11.67              return dev_info
   11.68          return None
   11.69  
   11.70 +    def _getDeviceInfo_vscsi(self, devid, vdev):
   11.71 +        devid = int(devid)
   11.72 +        for dev_type, dev_info in self.info.all_devices_sxpr():
   11.73 +            if dev_type != 'vscsi':
   11.74 +                continue
   11.75 +            existing_dev_uuid = sxp.child_value(dev_info, 'uuid')
   11.76 +            existing_conf = self.info['devices'][existing_dev_uuid][1]
   11.77 +            existing_dev = existing_conf['devs'][0]
   11.78 +            existing_devid = int(existing_dev['devid'])
   11.79 +            existing_vdev = existing_dev['v-dev']
   11.80 +
   11.81 +            if vdev == existing_vdev:
   11.82 +                return "exists"
   11.83 +
   11.84 +            if devid == existing_devid:
   11.85 +                return dev_info
   11.86 +
   11.87 +        return None
   11.88 +
   11.89      def setMemoryTarget(self, target):
   11.90          """Set the memory target of this domain.
   11.91          @param target: In MiB.
   11.92 @@ -1811,10 +1879,12 @@ class XendDomainInfo:
   11.93          if self.image:
   11.94              self.image.prepareEnvironment()
   11.95  
   11.96 +        vscsi_uuidlist = {}
   11.97 +        vscsi_devidlist = []
   11.98          ordered_refs = self.info.ordered_device_refs()
   11.99          for dev_uuid in ordered_refs:
  11.100              devclass, config = self.info['devices'][dev_uuid]
  11.101 -            if devclass in XendDevices.valid_devices():
  11.102 +            if devclass in XendDevices.valid_devices() and devclass != 'vscsi':
  11.103                  log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
  11.104                  dev_uuid = config.get('uuid')
  11.105                  devid = self._createDevice(devclass, config)
  11.106 @@ -1823,6 +1893,27 @@ class XendDomainInfo:
  11.107                  if dev_uuid in self.info['devices']:
  11.108                      self.info['devices'][dev_uuid][1]['devid'] = devid
  11.109  
  11.110 +            elif devclass == 'vscsi':
  11.111 +                vscsi_config = config.get('devs', [])[0]
  11.112 +                devid = vscsi_config.get('devid', '')
  11.113 +                dev_uuid = config.get('uuid')
  11.114 +                vscsi_uuidlist[devid] = dev_uuid
  11.115 +                vscsi_devidlist.append(devid)
  11.116 +
  11.117 +        #It is necessary to sorted it for /dev/sdxx in guest. 
  11.118 +        if len(vscsi_uuidlist) > 0:
  11.119 +            vscsi_devidlist.sort()
  11.120 +            for vscsiid in vscsi_devidlist:
  11.121 +                dev_uuid = vscsi_uuidlist[vscsiid]
  11.122 +                devclass, config = self.info['devices'][dev_uuid]
  11.123 +                log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
  11.124 +                dev_uuid = config.get('uuid')
  11.125 +                devid = self._createDevice(devclass, config)
  11.126 +                # store devid in XendConfig for caching reasons
  11.127 +                if dev_uuid in self.info['devices']:
  11.128 +                    self.info['devices'][dev_uuid][1]['devid'] = devid
  11.129 +
  11.130 +
  11.131          if self.image:
  11.132              self.image.createDeviceModel()
  11.133  
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tools/python/xen/xend/server/vscsiif.py	Thu Jul 03 13:39:06 2008 +0100
    12.3 @@ -0,0 +1,228 @@
    12.4 +#============================================================================
    12.5 +# This library is free software; you can redistribute it and/or
    12.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
    12.7 +# License as published by the Free Software Foundation.
    12.8 +#
    12.9 +# This library is distributed in the hope that it will be useful,
   12.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
   12.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12.12 +# Lesser General Public License for more details.
   12.13 +#
   12.14 +# You should have received a copy of the GNU Lesser General Public
   12.15 +# License along with this library; if not, write to the Free Software
   12.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   12.17 +#============================================================================
   12.18 +# Copyright (C) 2007 FUJITSU Limited
   12.19 +#                     Based on the blkif.py
   12.20 +#============================================================================
   12.21 +
   12.22 +
   12.23 +"""Support for VSCSI Devices.
   12.24 +"""
   12.25 +import re
   12.26 +import string
   12.27 +
   12.28 +import types
   12.29 +
   12.30 +from xen.xend import sxp
   12.31 +from xen.xend.XendError import VmError
   12.32 +from xen.xend.XendLogging import log
   12.33 +
   12.34 +from xen.xend.server.DevController import DevController, xenbusState
   12.35 +from xen.xend.xenstore.xstransact import xstransact
   12.36 +
   12.37 +class VSCSIController(DevController):
   12.38 +    """VSCSI Devices.
   12.39 +    """
   12.40 +    def __init__(self, vm):
   12.41 +        """Create a VSCSI Devices.
   12.42 +        """
   12.43 +        DevController.__init__(self, vm)
   12.44 +
   12.45 +
   12.46 +    def sxprs(self):
   12.47 +        """@see DevController.sxprs"""
   12.48 +        devslist = []
   12.49 +        for devid in self.deviceIDs():
   12.50 +            vscsi_devs = self.readBackendList(devid, "vscsi-devs")
   12.51 +            vscsipath = "vscsi-devs/"
   12.52 +            devs = []
   12.53 +            vscsi_config = []
   12.54 +            for dev in vscsi_devs:
   12.55 +                devpath = vscsipath + dev
   12.56 +                backstate = self.readBackend(devid, devpath + '/state')
   12.57 +                pdev = self.readBackend(devid, devpath + '/p-dev')
   12.58 +                pdevname = self.readBackend(devid, devpath + '/p-devname')
   12.59 +                vdev = self.readBackend(devid, devpath + '/v-dev')
   12.60 +                localdevid = self.readBackend(devid, devpath + '/devid')
   12.61 +                frontstate = self.readFrontend(devid, devpath + '/state')
   12.62 +                devs.append(['dev', \
   12.63 +                                    ['state', backstate], \
   12.64 +                                    ['devid', localdevid], \
   12.65 +                                    ['p-dev', pdev], \
   12.66 +                                    ['p-devname', pdevname], \
   12.67 +                                    ['v-dev', vdev], \
   12.68 +                                    ['frontstate', frontstate] ])
   12.69 +
   12.70 +            vscsi_config.append(['devs', devs])
   12.71 +            state = self.readFrontend(devid, 'state')
   12.72 +            vscsi_config.append(['state', state])
   12.73 +            backid = self.readFrontend(devid, 'backend-id')
   12.74 +            vscsi_config.append(['backend-id', backid])
   12.75 +            backpath = self.readFrontend(devid, 'backend')
   12.76 +            vscsi_config.append(['backend', backpath])
   12.77 +
   12.78 +            devslist.append([devid, vscsi_config])
   12.79 +
   12.80 +        return devslist
   12.81 +
   12.82 +
   12.83 +    def getDeviceDetails(self, config):
   12.84 +        """@see DevController.getDeviceDetails"""
   12.85 +        back = {}
   12.86 +        vscsipath = "vscsi-devs/"
   12.87 +        for vscsi_config in config.get('devs', []):
   12.88 +            localdevid = self.allocateDeviceID()
   12.89 +            # vscsi-devs/dev-0
   12.90 +            devpath = vscsipath + 'dev-%i' % localdevid
   12.91 +            back[devpath] = ""
   12.92 +            pdev = vscsi_config.get('p-dev', '')
   12.93 +            back[devpath + '/p-dev'] = pdev
   12.94 +            pdevname = vscsi_config.get('p-devname', '')
   12.95 +            back[devpath + '/p-devname'] = pdevname
   12.96 +            vdev = vscsi_config.get('v-dev', '')
   12.97 +            back[devpath + '/v-dev'] = vdev
   12.98 +            state = vscsi_config.get('state', '')
   12.99 +            back[devpath + '/state'] = str(xenbusState[state])
  12.100 +            devid = vscsi_config.get('devid', '')
  12.101 +            back[devpath + '/devid'] = str(devid)
  12.102 +
  12.103 +        back['uuid'] = config.get('uuid','')
  12.104 +        devid = int(devid)
  12.105 +        return (devid, back, {})
  12.106 +
  12.107 +
  12.108 +    def readBackendList(self, devid, *args):
  12.109 +        frontpath = self.frontendPath(devid)
  12.110 +        backpath = xstransact.Read(frontpath + "/backend")
  12.111 +        if backpath:
  12.112 +            paths = map(lambda x: backpath + "/" + x, args)
  12.113 +            return xstransact.List(*paths)
  12.114 +
  12.115 +
  12.116 +    def getDeviceConfiguration(self, devid, transaction = None):
  12.117 +        config = DevController.getDeviceConfiguration(self, devid, transaction)
  12.118 +
  12.119 +        vscsi_devs = []
  12.120 +
  12.121 +        devs = self.readBackendList(devid, "vscsi-devs")
  12.122 +        vscsipath = "vscsi-devs/"
  12.123 +        for dev in devs:
  12.124 +            devpath = vscsipath + dev
  12.125 +            pdev = self.readBackend(devid, devpath + '/p-dev')
  12.126 +            pdevname = self.readBackend(devid, devpath + '/p-devname')
  12.127 +            vdev = self.readBackend(devid, devpath + '/v-dev')
  12.128 +            state = self.readBackend(devid, devpath + '/state')
  12.129 +            localdevid = self.readBackend(devid, devpath + '/devid')
  12.130 +            dev_dict = {'p-dev': pdev,
  12.131 +                            'p-devname': pdevname,
  12.132 +                            'v-dev': pdevname,
  12.133 +                            'state': state,
  12.134 +                            'devid': localdevid }
  12.135 +            vscsi_devs.append(dev_dict)
  12.136 +
  12.137 +        config['devs'] = vscsi_devs
  12.138 +        config['uuid'] = self.readBackend(devid, 'uuid')
  12.139 +        return config
  12.140 +
  12.141 +
  12.142 +    def configuration(self, devid, transaction = None):
  12.143 +        """Returns SXPR for devices on domain.
  12.144 +        @note: we treat this dict especially to convert to
  12.145 +        SXP because it is not a straight dict of strings."""
  12.146 +        
  12.147 +        configDict = self.getDeviceConfiguration(devid, transaction)
  12.148 +        sxpr = [self.deviceClass]
  12.149 +
  12.150 +        # remove devs
  12.151 +        devs = configDict.pop('devs', [])
  12.152 +        
  12.153 +        for dev in devs:
  12.154 +            dev_sxpr = ['dev']
  12.155 +            for dev_item in dev.items():
  12.156 +                dev_sxpr.append(list(dev_item))
  12.157 +            sxpr.append(dev_sxpr)
  12.158 +        
  12.159 +        for key, val in configDict.items():
  12.160 +            if type(val) == type(list()):
  12.161 +                for v in val:
  12.162 +                    sxpr.append([key, v])
  12.163 +            else:
  12.164 +                sxpr.append([key, val])
  12.165 +
  12.166 +        return sxpr
  12.167 +
  12.168 +
  12.169 +    def reconfigureDevice(self, _, config):
  12.170 +        """@see DevController.reconfigureDevice"""
  12.171 +        (devid, back, front) = self.getDeviceDetails(config)
  12.172 +        devid = int(devid)
  12.173 +        vscsi_config = config['devs'][0]
  12.174 +        states = config.get('states', [])
  12.175 +        uuid = self.readBackend(devid, 'uuid')
  12.176 +        if states[0] == 'Initialising':
  12.177 +            back['uuid'] = uuid
  12.178 +            self.writeBackend(devid, back)
  12.179 +
  12.180 +        elif states[0] == 'Closing':
  12.181 +            found = False
  12.182 +            devs = self.readBackendList(devid, "vscsi-devs")
  12.183 +            vscsipath = "vscsi-devs/"
  12.184 +            vdev = vscsi_config.get('v-dev', '')
  12.185 +
  12.186 +            for dev in devs:
  12.187 +                devpath = vscsipath + dev
  12.188 +                old_vdev = self.readBackend(devid, devpath + '/v-dev')
  12.189 +                if vdev == old_vdev:
  12.190 +                    found = True
  12.191 +                    self.writeBackend(devid, devpath + '/state', \
  12.192 +                                    str(xenbusState['Closing']))
  12.193 +                    break
  12.194 +
  12.195 +            if not found:
  12.196 +                raise VmError("Device %s not connected" % vdev)
  12.197 +
  12.198 +        else:
  12.199 +            raise XendError('Error configuring device invalid state %s'
  12.200 +                                % state)
  12.201 +
  12.202 +        self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring']))
  12.203 +        return self.readBackend(devid, 'uuid')
  12.204 +
  12.205 +
  12.206 +    def cleanupDevice(self, devid):
  12.207 +        devs = self.readBackendList(devid, "vscsi-devs")
  12.208 +        vscsipath = "vscsi-devs/"
  12.209 +        new_num_devs = 0
  12.210 +        
  12.211 +        for dev in devs:
  12.212 +            new_num_devs = new_num_devs + 1
  12.213 +            devpath = vscsipath + dev
  12.214 +            devstate = self.readBackend(devid, devpath + '/state')
  12.215 +
  12.216 +            if str(xenbusState['Closed']) == devstate:
  12.217 +                self.removeBackend(devid, devpath)
  12.218 +                frontpath = self.frontendPath(devid)
  12.219 +                xstransact.Remove(frontpath + '/' + devpath)
  12.220 +                new_num_devs = new_num_devs - 1
  12.221 +
  12.222 +            frontpath = self.frontendPath(devid)
  12.223 +            front_devstate = xstransact.Read(frontpath + '/' + devpath)
  12.224 +            if front_devstate is not None:
  12.225 +                if str(xenbusState['Closed']) == front_devstate:
  12.226 +                    self.removeBackend(devid, devpath)
  12.227 +                    xstransact.Remove(frontpath + '/' + devpath)
  12.228 +                    new_num_devs = new_num_devs - 1
  12.229 +
  12.230 +        return new_num_devs
  12.231 +
    13.1 --- a/tools/python/xen/xm/create.py	Thu Jul 03 11:32:10 2008 +0100
    13.2 +++ b/tools/python/xen/xm/create.py	Thu Jul 03 13:39:06 2008 +0100
    13.3 @@ -33,6 +33,7 @@ from xen.xend import osdep
    13.4  import xen.xend.XendClient
    13.5  from xen.xend.XendBootloader import bootloader
    13.6  from xen.util import blkif
    13.7 +from xen.util import vscsi_util
    13.8  import xen.util.xsm.xsm as security
    13.9  from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
   13.10  
   13.11 @@ -307,6 +308,11 @@ gopts.var('pci', val='BUS:DEV.FUNC',
   13.12           For example 'pci=c0:02.1'.
   13.13           The option may be repeated to add more than one pci device.""")
   13.14  
   13.15 +gopts.var('vscsi', val='PDEV,VDEV[,DOM]',
   13.16 +          fn=append_value, default=[],
   13.17 +          use="""Add a SCSI device to a domain. The physical device is PDEV,
   13.18 +          which is exported to the domain as VDEV(X:X:X:X).""")
   13.19 +
   13.20  gopts.var('ioports', val='FROM[-TO]',
   13.21            fn=append_value, default=[],
   13.22            use="""Add a legacy I/O range to a domain, using given params (in hex).
   13.23 @@ -638,6 +644,73 @@ def configure_pci(config_devs, vals):
   13.24          config_pci.insert(0, 'pci')
   13.25          config_devs.append(['device', config_pci])
   13.26  
   13.27 +def vscsi_convert_sxp_to_dict(dev_sxp):
   13.28 +    dev_dict = {}
   13.29 +    for opt_val in dev_sxp[1:]:
   13.30 +        try:
   13.31 +            opt, val = opt_val
   13.32 +            dev_dict[opt] = val
   13.33 +        except TypeError:
   13.34 +            pass
   13.35 +    return dev_dict
   13.36 +
   13.37 +def vscsi_lookup_devid(devlist, req_devid):
   13.38 +    if len(devlist) == 0:
   13.39 +        return 0
   13.40 +    else:
   13.41 +        for devid, backend in devlist:
   13.42 +            if devid == req_devid:
   13.43 +                return 1
   13.44 +        return 0
   13.45 +
   13.46 +def configure_vscsis(config_devs, vals):
   13.47 +    """Create the config for vscsis (virtual scsi devices).
   13.48 +    """
   13.49 +    devidlist = []
   13.50 +    config_scsi = []
   13.51 +    if len(vals.vscsi) == 0:
   13.52 +        return 0
   13.53 +
   13.54 +    scsi_devices = vscsi_util.vscsi_get_scsidevices()
   13.55 +    for (p_dev, v_dev, backend) in vals.vscsi:
   13.56 +        tmp = p_dev.split(':')
   13.57 +        if len(tmp) == 4:
   13.58 +            (p_hctl, block) = vscsi_util._vscsi_hctl_block(p_dev, scsi_devices)
   13.59 +        else:
   13.60 +            (p_hctl, block) = vscsi_util._vscsi_block_scsiid_to_hctl(p_dev, scsi_devices)
   13.61 +
   13.62 +        if p_hctl == None:
   13.63 +            raise ValueError("Cannot find device \"%s\"" % p_dev)
   13.64 +
   13.65 +        for config in config_scsi:
   13.66 +            dev = vscsi_convert_sxp_to_dict(config)
   13.67 +            if dev['v-dev'] == v_dev:
   13.68 +                raise ValueError('The virtual device "%s" is already defined' % v_dev)
   13.69 +
   13.70 +        v_hctl = v_dev.split(':')
   13.71 +        devid = int(v_hctl[0])
   13.72 +        config_scsi.append(['dev', \
   13.73 +                        ['state', 'Initialising'], \
   13.74 +                        ['devid', devid], \
   13.75 +                        ['p-dev', p_hctl], \
   13.76 +                        ['p-devname', block], \
   13.77 +                        ['v-dev', v_dev] ])
   13.78 +
   13.79 +        if vscsi_lookup_devid(devidlist, devid) == 0:
   13.80 +            devidlist.append([devid, backend])
   13.81 +
   13.82 +    for devid, backend in devidlist:
   13.83 +        tmp = []
   13.84 +        for config in config_scsi:
   13.85 +            dev = vscsi_convert_sxp_to_dict(config)
   13.86 +            if dev['devid'] == devid:
   13.87 +                tmp.append(config)
   13.88 +
   13.89 +        tmp.insert(0, 'vscsi')
   13.90 +        if backend:
   13.91 +            tmp.append(['backend', backend])
   13.92 +        config_devs.append(['device', tmp])
   13.93 +
   13.94  def configure_ioports(config_devs, vals):
   13.95      """Create the config for legacy i/o ranges.
   13.96      """
   13.97 @@ -829,6 +902,7 @@ def make_config(vals):
   13.98      config_devs = []
   13.99      configure_disks(config_devs, vals)
  13.100      configure_pci(config_devs, vals)
  13.101 +    configure_vscsis(config_devs, vals)
  13.102      configure_ioports(config_devs, vals)
  13.103      configure_irq(config_devs, vals)
  13.104      configure_vifs(config_devs, vals)
  13.105 @@ -896,6 +970,25 @@ def preprocess_pci(vals):
  13.106                  err('Error in PCI slot syntax "%s"'%(pci_dev_str))
  13.107      vals.pci = pci
  13.108  
  13.109 +def preprocess_vscsi(vals):
  13.110 +    if not vals.vscsi: return
  13.111 +    scsi = []
  13.112 +    for scsi_str in vals.vscsi:
  13.113 +        d = scsi_str.split(',')
  13.114 +        n = len(d)
  13.115 +        if n == 2:
  13.116 +            tmp = d[1].split(':')
  13.117 +            if len(tmp) != 4:
  13.118 +                err('vscsi syntax error "%s"' % d[1])
  13.119 +            else:
  13.120 +                d.append(None)
  13.121 +        elif n == 3:
  13.122 +            pass
  13.123 +        else:
  13.124 +            err('vscsi syntax error "%s"' % scsi_str)
  13.125 +        scsi.append(d)
  13.126 +    vals.vscsi = scsi
  13.127 +
  13.128  def preprocess_ioports(vals):
  13.129      if not vals.ioports: return
  13.130      ioports = []
  13.131 @@ -1075,6 +1168,7 @@ def preprocess_vnc(vals):
  13.132  def preprocess(vals):
  13.133      preprocess_disk(vals)
  13.134      preprocess_pci(vals)
  13.135 +    preprocess_vscsi(vals)
  13.136      preprocess_ioports(vals)
  13.137      preprocess_ip(vals)
  13.138      preprocess_nfs(vals)
    14.1 --- a/tools/python/xen/xm/main.py	Thu Jul 03 11:32:10 2008 +0100
    14.2 +++ b/tools/python/xen/xm/main.py	Thu Jul 03 13:39:06 2008 +0100
    14.3 @@ -37,6 +37,7 @@ import datetime
    14.4  from select import select
    14.5  import xml.dom.minidom
    14.6  from xen.util.blkif import blkdev_name_to_number
    14.7 +from xen.util import vscsi_util
    14.8  
    14.9  import warnings
   14.10  warnings.filterwarnings('ignore', category=FutureWarning)
   14.11 @@ -182,6 +183,12 @@ SUBCOMMAND_HELP = {
   14.12                          'Remove a domain\'s pass-through pci device.'),
   14.13      'pci-list'      :  ('<Domain>',
   14.14                          'List pass-through pci devices for a domain.'),
   14.15 +    'scsi-attach'  :  ('<Domain> <PhysDevice> <VirtDevice> [BackDomain]',
   14.16 +                        'Attach a new SCSI device.'),
   14.17 +    'scsi-detach'  :  ('<Domain> <VirtDevice>',
   14.18 +                        'Detach a specified SCSI device.'),
   14.19 +    'scsi-list'    :  ('<Domain> [--long]',
   14.20 +                        'List all SCSI devices currently attached.'),
   14.21  
   14.22      # security
   14.23  
   14.24 @@ -348,6 +355,9 @@ device_commands = [
   14.25      "pci-attach",
   14.26      "pci-detach",
   14.27      "pci-list",
   14.28 +    "scsi-attach",
   14.29 +    "scsi-detach",
   14.30 +    "scsi-list",
   14.31      ]
   14.32  
   14.33  vnet_commands = [
   14.34 @@ -2106,6 +2116,40 @@ def xm_pci_list(args):
   14.35              hdr = 1
   14.36          print ( fmt_str % x )
   14.37  
   14.38 +def vscsi_convert_sxp_to_dict(dev_sxp):
   14.39 +    dev_dict = {}
   14.40 +    for opt_val in dev_sxp[1:]:
   14.41 +        try:
   14.42 +            opt, val = opt_val
   14.43 +            dev_dict[opt] = val
   14.44 +        except TypeError:
   14.45 +            pass
   14.46 +    return dev_dict
   14.47 +
   14.48 +def xm_scsi_list(args):
   14.49 +    xenapi_unsupported()
   14.50 +    (use_long, params) = arg_check_for_resource_list(args, "scsi-list")
   14.51 +
   14.52 +    dom = params[0]
   14.53 +
   14.54 +    devs = server.xend.domain.getDeviceSxprs(dom, 'vscsi')
   14.55 +
   14.56 +    if use_long:
   14.57 +        map(PrettyPrint.prettyprint, devs)
   14.58 +    else:
   14.59 +        hdr = 0
   14.60 +        for x in devs:
   14.61 +            if hdr == 0:
   14.62 +                print "%-3s %-3s %-5s  %-10s %-5s %-10s %-4s" \
   14.63 +                        % ('Idx', 'BE', 'state', 'phy-hctl', 'phy', 'vir-hctl', 'devstate')
   14.64 +                hdr = 1
   14.65 +            ni = parse_dev_info(x[1])
   14.66 +            ni['idx'] = int(x[0])
   14.67 +            for dev in x[1][0][1]:
   14.68 +                mi = vscsi_convert_sxp_to_dict(dev)
   14.69 +                print "%(idx)-3d %(backend-id)-3d %(state)-5d " % ni,
   14.70 +                print "%(p-dev)-10s %(p-devname)-5s %(v-dev)-10s %(frontstate)-4s" % mi
   14.71 +
   14.72  def parse_block_configuration(args):
   14.73      dom = args[0]
   14.74  
   14.75 @@ -2285,6 +2329,38 @@ def xm_pci_attach(args):
   14.76      (dom, pci) = parse_pci_configuration(args, 'Initialising')
   14.77      server.xend.domain.device_configure(dom, pci)
   14.78  
   14.79 +def xm_scsi_attach(args):
   14.80 +    xenapi_unsupported()
   14.81 +
   14.82 +    arg_check(args, 'scsi-attach', 3, 4)
   14.83 +    p_devname = args[1]
   14.84 +    v_dev = args[2]
   14.85 +
   14.86 +    v_hctl = v_dev.split(':')
   14.87 +    if len(v_hctl) != 4:
   14.88 +        raise OptionError("Invalid argument: %s" % v_dev)
   14.89 +
   14.90 +    (p_hctl, block) = vscsi_util.vscsi_search_hctl_and_block(p_devname)
   14.91 +
   14.92 +    if p_hctl == None:
   14.93 +        raise OptionError("Cannot find device \"%s\"" % p_devname)
   14.94 +
   14.95 +    dom = args[0]
   14.96 +    vscsi = ['vscsi']
   14.97 +    vscsi.append(['dev', \
   14.98 +                ['state', 'Initialising'], \
   14.99 +                ['devid', v_hctl[0]], \
  14.100 +                ['p-dev', p_hctl], \
  14.101 +                ['p-devname', block], \
  14.102 +                ['v-dev', v_dev] ])
  14.103 +
  14.104 +    if len(args) == 4:
  14.105 +        vscsi.append(['backend', args[3]])
  14.106 +
  14.107 +    vscsi.append(['state', 'Initialising'])
  14.108 +    vscsi.append(['devid', v_hctl[0]])
  14.109 +    server.xend.domain.device_configure(dom, vscsi)
  14.110 +
  14.111  def detach(args, deviceClass):
  14.112      rm_cfg = True
  14.113      dom = args[0]
  14.114 @@ -2353,6 +2429,27 @@ def xm_pci_detach(args):
  14.115      (dom, pci) = parse_pci_configuration(args, 'Closing')
  14.116      server.xend.domain.device_configure(dom, pci)
  14.117  
  14.118 +def xm_scsi_detach(args):
  14.119 +    xenapi_unsupported()
  14.120 +    arg_check(args, 'scsi-detach', 2)
  14.121 +
  14.122 +    v_dev = args[1]
  14.123 +    v_hctl = v_dev.split(':')
  14.124 +    if len(v_hctl) != 4:
  14.125 +        raise OptionError("Invalid argument: %s" % v_dev)
  14.126 +
  14.127 +    dom = args[0]
  14.128 +    vscsi = ['vscsi']
  14.129 +    vscsi.append(['dev', \
  14.130 +                ['state', 'Closing'], \
  14.131 +                ['devid', v_hctl[0]], \
  14.132 +                ['p-dev', ''], \
  14.133 +                ['p-devname', ''], \
  14.134 +                ['v-dev', v_dev] ])
  14.135 +
  14.136 +    vscsi.append(['state', 'Closing'])
  14.137 +    vscsi.append(['devid', v_hctl[0]])
  14.138 +    server.xend.domain.device_configure(dom, vscsi)
  14.139  
  14.140  def xm_vnet_list(args):
  14.141      xenapi_unsupported()
  14.142 @@ -2548,6 +2645,10 @@ commands = {
  14.143      "pci-attach": xm_pci_attach,
  14.144      "pci-detach": xm_pci_detach,
  14.145      "pci-list": xm_pci_list,
  14.146 +    # vscsi
  14.147 +    "scsi-attach": xm_scsi_attach,
  14.148 +    "scsi-detach": xm_scsi_detach,
  14.149 +    "scsi-list": xm_scsi_list,
  14.150      }
  14.151  
  14.152  ## The commands supported by a separate argument parser in xend.xm.