ia64/xen-unstable

view tools/python/xen/util/vscsi_util.py @ 19447:2d19139c1c9c

xend: Fix scsi_id for pvSCSI

pvSCSI allocations fail if the version of udev in a host OS is
relatively new. I have not been able to detect the failure because
I have used udev of the version 095. The failure occurs by
an incompatibility problem of scsi_id command included udev.
This patch tackles the incompatibility problem.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 31 11:27:10 2009 +0100 (2009-03-31)
parents 2b61a1ee35ee
children 46188402c2d9
line source
1 #!/usr/bin/env python
2 # -*- mode: python; -*-
4 #============================================================================
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #============================================================================
18 # Copyright (C) 2008 FUJITSU Limited
19 # Based on the blkif.py
20 #============================================================================
23 """Support for VSCSI Devices.
24 """
25 import os
26 import os.path
27 import sys
28 import re
29 import string
30 from xen.util import utils
32 SYSFS_SCSI_PATH = "/bus/scsi/devices"
33 SYSFS_SCSI_DEV_VENDOR_PATH = '/vendor'
34 SYSFS_SCSI_DEV_MODEL_PATH = '/model'
35 SYSFS_SCSI_DEV_TYPEID_PATH = '/type'
36 SYSFS_SCSI_DEV_REVISION_PATH = '/rev'
37 SYSFS_SCSI_DEV_SCSILEVEL_PATH = '/scsi_level'
39 SCSI_ID_COMMANDS = [
40 "/lib/udev/scsi_id -gu --sg-version 3 -d /dev/%s 2>/dev/null",
41 "/sbin/scsi_id -gu -s /class/scsi_generic/%s 2>/dev/null"
42 ]
44 def _vscsi_get_devname_by(name, scsi_devices):
45 """A device name is gotten by the HCTL.
46 (e.g., '0:0:0:0' to '/dev/sda')
47 """
49 try:
50 search = re.compile(r'' + name + '$', re.DOTALL)
51 except Exception, e:
52 raise VmError("vscsi: invalid expression. " + str(e))
54 for hctl, devname, sg, scsi_id in scsi_devices:
55 if search.match(hctl):
56 return (hctl, devname)
58 return (None, None)
61 def _vscsi_get_hctl_by(phyname, scsi_devices):
62 """An HCTL is gotten by the device name or the scsi_id.
63 (e.g., '/dev/sda' to '0:0:0:0')
64 """
66 if re.match('/dev/sd[a-z]+([1-9]|1[0-5])?$', phyname):
67 # sd driver
68 name = re.sub('(^/dev/)|([1-9]|1[0-5])?$', '', phyname)
69 elif re.match('/dev/sg[0-9]+$', phyname):
70 # sg driver
71 name = re.sub('^/dev/', '', phyname)
72 elif re.match('/dev/st[0-9]+$', phyname):
73 # st driver
74 name = re.sub('^/dev/', '', phyname)
75 else:
76 # scsi_id -gu
77 name = phyname
79 for hctl, devname, sg, scsi_id in scsi_devices:
80 if name in [devname, sg, scsi_id]:
81 return (hctl, devname)
83 return (None, None)
86 def _vscsi_get_scsiid(sg):
87 for scsi_id_command in SCSI_ID_COMMANDS:
88 scsi_id = os.popen(scsi_id_command % sg).read().split()
89 if len(scsi_id):
90 return scsi_id[0]
91 return None
94 def _vscsi_get_scsidevices_by_lsscsi(option = ""):
95 """ get all scsi devices information by lsscsi """
97 devices = []
99 for scsiinfo in os.popen('{ lsscsi -g %s; } 2>/dev/null' % option).readlines():
100 s = scsiinfo.split()
101 hctl = s[0][1:-1]
102 try:
103 devname = s[-2].split('/dev/')[1]
104 except IndexError:
105 devname = None
106 try:
107 sg = s[-1].split('/dev/')[1]
108 scsi_id = _vscsi_get_scsiid(sg)
109 except IndexError:
110 sg = None
111 scsi_id = None
112 devices.append([hctl, devname, sg, scsi_id])
114 return devices
117 def _vscsi_get_scsidevices_by_sysfs():
118 """ get all scsi devices information by sysfs """
120 devices = []
121 try:
122 sysfs_mnt = utils.find_sysfs_mount()
123 except:
124 return devices
126 for dirpath, dirnames, files in os.walk(sysfs_mnt + SYSFS_SCSI_PATH):
127 for hctl in dirnames:
128 paths = os.path.join(dirpath, hctl)
129 devname = None
130 sg = None
131 scsi_id = None
132 for f in os.listdir(paths):
133 realpath = os.path.realpath(os.path.join(paths, f))
134 if re.match('^block', f) or \
135 re.match('^tape', f) or \
136 re.match('^scsi_changer', f) or \
137 re.match('^onstream_tape', f):
138 devname = os.path.basename(realpath)
140 if re.match('^scsi_generic', f):
141 sg = os.path.basename(realpath)
142 scsi_id = _vscsi_get_scsiid(sg)
143 devices.append([hctl, devname, sg, scsi_id])
145 return devices
148 def vscsi_get_scsidevices():
149 """ get all scsi devices information """
151 devices = _vscsi_get_scsidevices_by_lsscsi("")
152 if devices:
153 return devices
154 return _vscsi_get_scsidevices_by_sysfs()
157 def vscsi_get_hctl_and_devname_by(target, scsi_devices = None):
158 if scsi_devices is None:
159 if len(target.split(':')) == 4:
160 scsi_devices = _vscsi_get_scsidevices_by_lsscsi(target)
161 elif target.startswith('/dev/'):
162 scsi_devices = _vscsi_get_scsidevices_by_lsscsi("| grep %s" % target)
163 else:
164 scsi_devices = _vscsi_get_scsidevices_by_lsscsi("")
165 if not scsi_devices:
166 scsi_devices = _vscsi_get_scsidevices_by_sysfs()
168 if len(target.split(':')) == 4:
169 return _vscsi_get_devname_by(target, scsi_devices)
170 else:
171 return _vscsi_get_hctl_by(target, scsi_devices)
174 def get_scsi_vendor(pHCTL):
175 try:
176 sysfs_mnt = utils.find_sysfs_mount()
177 sysfs_scsi_dev_path = \
178 os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL)
179 scsi_vendor = \
180 os.popen('cat ' + sysfs_scsi_dev_path + \
181 SYSFS_SCSI_DEV_VENDOR_PATH).read()
182 return scsi_vendor.splitlines()[0]
183 except:
184 return None
186 def get_scsi_model(pHCTL):
187 try:
188 sysfs_mnt = utils.find_sysfs_mount()
189 sysfs_scsi_dev_path = \
190 os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL)
191 scsi_model = \
192 os.popen('cat ' + sysfs_scsi_dev_path + \
193 SYSFS_SCSI_DEV_MODEL_PATH).read()
194 return scsi_model.splitlines()[0]
195 except:
196 return None
198 def get_scsi_typeid(pHCTL):
199 try:
200 sysfs_mnt = utils.find_sysfs_mount()
201 sysfs_scsi_dev_path = \
202 os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL)
203 scsi_typeid = \
204 os.popen('cat ' + sysfs_scsi_dev_path + \
205 SYSFS_SCSI_DEV_TYPEID_PATH).read()
206 return int(scsi_typeid.splitlines()[0])
207 except:
208 return None
210 def get_scsi_revision(pHCTL):
211 try:
212 sysfs_mnt = utils.find_sysfs_mount()
213 sysfs_scsi_dev_path = \
214 os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL)
215 scsi_revision = \
216 os.popen('cat ' + sysfs_scsi_dev_path + \
217 SYSFS_SCSI_DEV_REVISION_PATH).read()
218 return scsi_revision.splitlines()[0]
219 except:
220 return None
222 def get_scsi_scsilevel(pHCTL):
223 try:
224 sysfs_mnt = utils.find_sysfs_mount()
225 sysfs_scsi_dev_path = \
226 os.path.join(sysfs_mnt + SYSFS_SCSI_PATH, pHCTL)
227 scsi_scsilevel = \
228 os.popen('cat ' + sysfs_scsi_dev_path + \
229 SYSFS_SCSI_DEV_SCSILEVEL_PATH).read()
230 return int(scsi_scsilevel.splitlines()[0])
231 except:
232 return None
234 def get_all_scsi_devices():
236 scsi_devs = []
238 for scsi_info in vscsi_get_scsidevices():
239 scsi_dev = {
240 'physical_HCTL': scsi_info[0],
241 'dev_name': None,
242 'sg_name': scsi_info[2],
243 'scsi_id': None
244 }
245 if scsi_info[1] is not None:
246 scsi_dev['dev_name'] = scsi_info[1]
247 if scsi_info[3] is not None:
248 scsi_dev['scsi_id'] = scsi_info[3]
250 scsi_dev['vendor_name'] = \
251 get_scsi_vendor(scsi_dev['physical_HCTL'])
252 scsi_dev['model'] = \
253 get_scsi_model(scsi_dev['physical_HCTL'])
254 scsi_dev['type_id'] = \
255 get_scsi_typeid(scsi_dev['physical_HCTL'])
256 scsi_dev['revision'] = \
257 get_scsi_revision(scsi_dev['physical_HCTL'])
258 scsi_dev['scsi_level'] = \
259 get_scsi_scsilevel(scsi_dev['physical_HCTL'])
261 try:
262 lsscsi_info = os.popen('lsscsi %s 2>/dev/null' % scsi_dev['physical_HCTL']).read().split()
263 scsi_dev['type'] = lsscsi_info[1]
264 except:
265 scsi_dev['type'] = None
267 scsi_devs.append(scsi_dev)
269 return scsi_devs