Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/python3 

2# 

3# Copyright (C) Citrix Systems Inc. 

4# 

5# This program is free software; you can redistribute it and/or modify 

6# it under the terms of the GNU Lesser General Public License as published 

7# by the Free Software Foundation; version 2.1 only. 

8# 

9# This program 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 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program; if not, write to the Free Software Foundation, Inc., 

16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

17# 

18# Miscellaneous scsi utility functions 

19# 

20 

21import util 

22import os 

23import re 

24import xs_errors 

25import base64 

26import time 

27import errno 

28import glob 

29import mpath_cli 

30 

31PREFIX_LEN = 4 

32SUFFIX_LEN = 12 

33SECTOR_SHIFT = 9 

34SCSI_ID_BIN = '/usr/lib/udev/scsi_id' 

35 

36 

37def gen_hash(st, len): 

38 hs = 0 

39 for i in st: 

40 hs = ord(i) + (hs << 6) + (hs << 16) - hs 

41 return str(hs)[0:len] 

42 

43 

44def gen_uuid_from_serial(iqn, serial): 

45 if len(serial) < SUFFIX_LEN: 

46 raise util.CommandException(1) 

47 prefix = gen_hash(iqn, PREFIX_LEN) 

48 suffix = gen_hash(serial, SUFFIX_LEN) 

49 str = prefix.encode("hex") + suffix.encode("hex") 

50 return str[0:8] + '-' + str[8:12] + '-' + str[12:16] + '-' + str[16:20] + '-' + str[20:32] 

51 

52 

53def gen_serial_from_uuid(iqn, uuid): 

54 str = uuid.replace('-', '') 

55 prefix = gen_hash(iqn, PREFIX_LEN) 

56 if str[0:(PREFIX_LEN * 2)].decode("hex") != prefix: 

57 raise util.CommandException(1) 

58 return str[(PREFIX_LEN * 2):].decode("hex") 

59 

60 

61def getsize(path): 

62 dev = getdev(path) 

63 sysfs = os.path.join('/sys/block', dev, 'size') 

64 size = 0 

65 if os.path.exists(sysfs): 

66 try: 

67 f = open(sysfs, 'r') 

68 size = (int(f.readline()) << SECTOR_SHIFT) 

69 f.close() 

70 except: 

71 pass 

72 return size 

73 

74 

75def getuniqueserial(path): 

76 dev = getdev(path) 

77 try: 

78 cmd = ["md5sum"] 

79 txt = util.pread3(cmd, getSCSIid(path)) 

80 return txt.split(' ')[0] 

81 except: 

82 return '' 

83 

84 

85def gen_uuid_from_string(src_string): 

86 if len(src_string) < (PREFIX_LEN + SUFFIX_LEN): 

87 raise util.CommandException(1) 

88 return (src_string[0:8] + '-' + 

89 src_string[8:12] + '-' + 

90 src_string[12:16] + '-' + 

91 src_string[16:20] + '-' + 

92 src_string[20:32]) 

93 

94 

95def SCSIid_sanitise(str): 

96 text = str.strip() 

97 return re.sub(r"\s+", "_", text) 

98 

99 

100def getSCSIid(path): 

101 """Get the SCSI id of a block device 

102 

103 Input: 

104 path -- (str) path to block device; can be symlink 

105 

106 Return: 

107 scsi_id -- (str) the device's SCSI id 

108 

109 Raise: 

110 util.CommandException 

111 """ 

112 

113 if not path.startswith('/dev/'): 113 ↛ 114line 113 didn't jump to line 114, because the condition on line 113 was never true

114 util.SMlog("getSCSIid: fixing invalid input {}".format(path), 

115 priority=util.LOG_WARNING) 

116 path = '/dev/' + path.lstrip('/') 

117 

118 stdout = util.pread2([SCSI_ID_BIN, '-g', '--device', path]) 

119 

120 return SCSIid_sanitise(stdout) 

121 

122 

123def compareSCSIid_2_6_18(SCSIid, path): 

124 serial = getserial(path) 

125 len_serial = len(serial) 

126 if (len_serial == 0) or (len_serial > (len(SCSIid) - 1)): 

127 return False 

128 list_SCSIid = list(SCSIid) 

129 list_serial = list_SCSIid[1:(len_serial + 1)] 

130 serial_2_6_18 = ''.join(list_serial) 

131 if (serial == serial_2_6_18): 

132 return True 

133 else: 

134 return False 

135 

136 

137def getserial(path): 

138 dev = os.path.join('/dev', getdev(path)) 

139 try: 

140 cmd = ["sginfo", "-s", dev] 

141 text = re.sub(r"\s+", "", util.pread2(cmd)) 

142 except: 

143 raise xs_errors.XenError('EIO', \ 

144 opterr='An error occured querying device serial number [%s]' \ 

145 % dev) 

146 try: 

147 return text.split("'")[1] 

148 except: 

149 return '' 

150 

151 

152def getmanufacturer(path): 

153 cmd = ["sginfo", "-M", path] 

154 try: 

155 for line in filter(match_vendor, util.pread2(cmd).split('\n')): 

156 return line.replace(' ', '').split(':')[-1] 

157 except: 

158 return '' 

159 

160 

161def cacheSCSIidentifiers(): 

162 SCSI = {} 

163 SYS_PATH = "/dev/disk/by-scsibus/*" 

164 for node in glob.glob(SYS_PATH): 

165 if not re.match(r'.*-\d+:\d+:\d+:\d+$', node): 165 ↛ 166line 165 didn't jump to line 166, because the condition on line 165 was never true

166 continue 

167 dev = os.path.realpath(node) 

168 HBTL = os.path.basename(node).split("-")[-1].split(":") 

169 line = "NONE %s %s %s %s 0 %s" % \ 

170 (HBTL[0], HBTL[1], HBTL[2], HBTL[3], dev) 

171 ids = line.split() 

172 SCSI[ids[6]] = ids 

173 return SCSI 

174 

175 

176def scsi_dev_ctrl(ids, cmd): 

177 f = None 

178 for i in range(0, 10): 

179 try: 

180 str = "scsi %s-single-device %s %s %s %s" % \ 

181 (cmd, ids[1], ids[2], ids[3], ids[4]) 

182 util.SMlog(str) 

183 f = open('/proc/scsi/scsi', 'w') 

184 print(str, file=f) 

185 f.close() 

186 return 

187 except IOError as e: 

188 util.SMlog("SCSI_DEV_CTRL: Failure, %s [%d]" % (e.strerror, e.errno)) 

189 if f is not None: 

190 f.close() 

191 f = None 

192 if e.errno == errno.ENXIO: 

193 util.SMlog("Device has disappeared already") 

194 return 

195 time.sleep(6) 

196 continue 

197 raise xs_errors.XenError('EIO', \ 

198 opterr='An error occured during the scsi operation') 

199 

200 

201def getdev(path): 

202 realpath = os.path.realpath(path) 

203 if match_dm(realpath): 203 ↛ 204line 203 didn't jump to line 204, because the condition on line 203 was never true

204 newpath = realpath.replace("/dev/mapper/", "/dev/disk/by-id/scsi-") 

205 else: 

206 newpath = path 

207 return os.path.realpath(newpath).split('/')[-1] 

208 

209 

210def get_devices_by_SCSIid(SCSIid): 

211 devices = os.listdir(os.path.join('/dev/disk/by-scsid', SCSIid)) 

212 if 'mapper' in devices: 

213 devices.remove('mapper') 

214 return devices 

215 

216 

217def rawdev(dev): 

218 device = getdev(dev) 

219 if device.startswith('dm-') and device[3:].isdigit(): 

220 return device 

221 

222 return re.sub('[0-9]*$', '', device) 

223 

224 

225def getSessionID(path): 

226 for line in filter(match_session, util.listdir(path)): 

227 return line.split('-')[-1] 

228 

229 

230def match_session(s): 

231 regex = re.compile("^SESSIONID-") 

232 return regex.search(s, 0) 

233 

234 

235def match_vendor(s): 

236 regex = re.compile("^Vendor:") 

237 return regex.search(s, 0) 

238 

239 

240def match_dm(s): 

241 regex = re.compile("mapper/") 

242 return regex.search(s, 0) 

243 

244 

245def match_sd(s): 

246 regex = re.compile("/dev/sd") 

247 return regex.search(s, 0) 

248 

249 

250def _isSCSIdev(dev): 

251 if match_dm(dev): 

252 path = dev.replace("/dev/mapper/", "/dev/disk/by-id/scsi-") 

253 else: 

254 path = dev 

255 return match_sd(os.path.realpath(path)) 

256 

257 

258def add_serial_record(session, sr_ref, devstring): 

259 try: 

260 conf = session.xenapi.SR.get_sm_config(sr_ref) 

261 conf['devserial'] = devstring 

262 session.xenapi.SR.set_sm_config(sr_ref, conf) 

263 except: 

264 pass 

265 

266 

267def get_serial_record(session, sr_ref): 

268 try: 

269 conf = session.xenapi.SR.get_sm_config(sr_ref) 

270 return conf['devserial'] 

271 except: 

272 return "" 

273 

274 

275def devlist_to_serialstring(devlist): 

276 serial = '' 

277 for dev in devlist: 

278 try: 

279 devserial = "scsi-%s" % getSCSIid(dev) 

280 if not len(devserial) > 0: 

281 continue 

282 if len(serial): 

283 serial += ',' 

284 serial += devserial 

285 except: 

286 pass 

287 

288 return serial 

289 

290 

291def gen_synthetic_page_data(uuid): 

292 # For generating synthetic page data for non-raw LUNs 

293 # we set the vendor ID to XENSRC 

294 # Note that the Page 80 serial number must be limited 

295 # to 16 characters 

296 page80 = "" 

297 page80 += "\x00\x80" 

298 page80 += "\x00\x12" 

299 page80 += uuid[0:16] 

300 page80 += " " 

301 

302 page83 = "" 

303 page83 += "\x00\x83" 

304 page83 += "\x00\x31" 

305 page83 += "\x02\x01\x00\x2d" 

306 page83 += "XENSRC " 

307 page83 += uuid 

308 page83 += " " 

309 return ["", base64.b64encode(str.encode(page80)).decode(), 

310 base64.b64encode(str.encode(page83)).decode()] 

311 

312 

313def gen_raw_page_data(path): 

314 default = "" 

315 page80 = "" 

316 page83 = "" 

317 try: 

318 cmd = ["sg_inq", "-r", path] 

319 text = util.pread2(cmd) 

320 default = base64.b64encode(text) 

321 

322 cmd = ["sg_inq", "--page=0x80", "-r", path] 

323 text = util.pread2(cmd) 

324 page80 = base64.b64encode(text) 

325 

326 cmd = ["sg_inq", "--page=0x83", "-r", path] 

327 text = util.pread2(cmd) 

328 page83 = base64.b64encode(text) 

329 except: 

330 pass 

331 return [default, page80, page83] 

332 

333 

334def update_XS_SCSIdata(vdi_uuid, data): 

335 # XXX: PR-1255: passing through SCSI data doesn't make sense when 

336 # it will change over storage migration. It also doesn't make sense 

337 # to preserve one array's identity and copy it when a VM moves to 

338 # a new array because the drivers in the VM may attempt to contact 

339 # the original array, fail and bluescreen. 

340 

341 xenstore_data = {} 

342 xenstore_data["vdi-uuid"] = vdi_uuid 

343 if len(data[0]): 343 ↛ 344line 343 didn't jump to line 344, because the condition on line 343 was never true

344 xenstore_data["scsi/0x12/default"] = data[0] 

345 

346 if len(data[1]): 346 ↛ 349line 346 didn't jump to line 349, because the condition on line 346 was never false

347 xenstore_data["scsi/0x12/0x80"] = data[1] 

348 

349 if len(data[2]): 349 ↛ 352line 349 didn't jump to line 352, because the condition on line 349 was never false

350 xenstore_data["scsi/0x12/0x83"] = data[2] 

351 

352 return xenstore_data 

353 

354 

355def rescan(ids, fullrescan=True): 

356 for id in ids: 

357 refresh_HostID(id, fullrescan) 

358 

359 

360def _genArrayIdentifier(dev): 

361 try: 

362 cmd = ["sg_inq", "--page=0xc8", "-r", dev] 

363 id = util.pread2(cmd) 

364 return id.encode("hex")[180:212] 

365 except: 

366 return "" 

367 

368 

369def _genHostList(procname): 

370 # loop through and check all adapters 

371 ids = [] 

372 try: 

373 for dir in util.listdir('/sys/class/scsi_host'): 

374 filename = os.path.join('/sys/class/scsi_host', dir, 'proc_name') 

375 if os.path.exists(filename): 

376 f = open(filename, 'r') 

377 if f.readline().find(procname) != -1: 

378 ids.append(dir.replace("host", "")) 

379 f.close() 

380 except: 

381 pass 

382 return ids 

383 

384 

385def _genReverseSCSIidmap(SCSIid, pathname="scsibus"): 

386 util.SMlog("map_by_scsibus: sid=%s" % SCSIid) 

387 

388 devices = [] 

389 for link in glob.glob('/dev/disk/by-%s/%s-*' % (pathname, SCSIid)): 

390 realpath = os.path.realpath(link) 

391 if os.path.exists(realpath): 

392 devices.append(realpath) 

393 return devices 

394 

395 

396def _genReverseSCSidtoLUNidmap(SCSIid): 

397 devices = [] 

398 for link in glob.glob('/dev/disk/by-scsibus/%s-*' % SCSIid): 

399 devices.append(link.split('-')[-1]) 

400 return devices 

401 

402 

403def _dosgscan(): 

404 regex = re.compile(r"([^:]*):\s+scsi([0-9]+)\s+channel=([0-9]+)\s+id=([0-9]+)\s+lun=([0-9]+)") 

405 scan = util.pread2(["/usr/bin/sg_scan"]).split('\n') 

406 sgs = [] 

407 for line in scan: 

408 m = regex.match(line) 

409 if m: 

410 device = m.group(1) 

411 host = m.group(2) 

412 channel = m.group(3) 

413 sid = m.group(4) 

414 lun = m.group(5) 

415 sgs.append([device, host, channel, sid, lun]) 

416 return sgs 

417 

418 

419def refresh_HostID(HostID, fullrescan): 

420 LUNs = glob.glob('/sys/class/scsi_disk/%s*' % HostID) 

421 li = [] 

422 for l in LUNs: 

423 chan = re.sub(":[0-9]*$", '', os.path.basename(l)) 

424 if chan not in li: 424 ↛ 422line 424 didn't jump to line 422, because the condition on line 424 was never false

425 li.append(chan) 

426 

427 if len(li) and not fullrescan: 427 ↛ 428line 427 didn't jump to line 428, because the condition on line 427 was never true

428 for c in li: 

429 if not refresh_scsi_channel(c): 

430 fullrescan = True 

431 

432 if fullrescan: 432 ↛ exitline 432 didn't return from function 'refresh_HostID', because the condition on line 432 was never false

433 util.SMlog("Full rescan of HostID %s" % HostID) 

434 path = '/sys/class/scsi_host/host%s/scan' % HostID 

435 if os.path.exists(path): 435 ↛ 436line 435 didn't jump to line 436, because the condition on line 435 was never true

436 try: 

437 scanstring = "- - -" 

438 f = open(path, 'w') 

439 f.write('%s\n' % scanstring) 

440 f.close() 

441 if len(li): 

442 # Channels already exist, allow some time for 

443 # undiscovered LUNs/channels to appear 

444 time.sleep(2) 

445 except: 

446 pass 

447 # Host Bus scan issued, now try to detect channels 

448 if util.wait_for_path("/sys/class/scsi_disk/%s*" % HostID, 5): 448 ↛ exitline 448 didn't return from function 'refresh_HostID', because the condition on line 448 was never false

449 # At least one LUN is mapped 

450 LUNs = glob.glob('/sys/class/scsi_disk/%s*' % HostID) 

451 li = [] 

452 for l in LUNs: 

453 chan = re.sub(":[0-9]*$", '', os.path.basename(l)) 

454 if chan not in li: 454 ↛ 452line 454 didn't jump to line 452, because the condition on line 454 was never false

455 li.append(chan) 

456 for c in li: 

457 refresh_scsi_channel(c) 

458 

459 

460def refresh_scsi_channel(channel): 

461 DEV_WAIT = 5 

462 util.SMlog("Refreshing channel %s" % channel) 

463 util.wait_for_path('/dev/disk/by-scsibus/*-%s*' % channel, DEV_WAIT) 

464 LUNs = glob.glob('/dev/disk/by-scsibus/*-%s*' % channel) 

465 try: 

466 rootdevs = util.dom0_disks() 

467 except: 

468 util.SMlog("Failed to query root disk, failing operation") 

469 return False 

470 

471 # a) Find a LUN to issue a Query LUNs command 

472 li = [] 

473 Query = False 

474 for lun in LUNs: 

475 try: 

476 hbtl = lun.split('-')[-1] 

477 h = hbtl.split(':') 

478 l = util.pread2(["/usr/bin/sg_luns", "-q", lun]).split('\n') 

479 li = [] 

480 for i in l: 

481 if len(i): 

482 li.append(int(i[0:4], 16)) 

483 util.SMlog("sg_luns query returned %s" % li) 

484 Query = True 

485 break 

486 except: 

487 pass 

488 if not Query: 

489 util.SMlog("Failed to detect or query LUN on Channel %s" % channel) 

490 return False 

491 

492 # b) Remove stale LUNs 

493 current = glob.glob('/dev/disk/by-scsibus/*-%s:%s:%s*' % (h[0], h[1], h[2])) 

494 for cur in current: 

495 lunID = int(cur.split(':')[-1]) 

496 newhbtl = ['', h[0], h[1], h[2], str(lunID)] 

497 if os.path.realpath(cur) in rootdevs: 

498 # Don't touch the rootdev 

499 if lunID in li: 

500 li.remove(lunID) 

501 continue 

502 

503 # Check if LUN is stale, and remove it 

504 if not lunID in li: 

505 util.SMlog("Stale LUN detected. Removing HBTL: %s" % newhbtl) 

506 scsi_dev_ctrl(newhbtl, "remove") 

507 util.wait_for_nopath(cur, DEV_WAIT) 

508 continue 

509 else: 

510 li.remove(lunID) 

511 

512 # Check if the device is still present 

513 if not os.path.exists(cur): 

514 continue 

515 

516 # Query SCSIid, check it matches, if not, re-probe 

517 cur_SCSIid = os.path.basename(cur).split("-%s:%s:%s" % (h[0], h[1], h[2]))[0] 

518 real_SCSIid = getSCSIid(cur) 

519 if cur_SCSIid != real_SCSIid: 

520 util.SMlog("HBTL %s does not match, re-probing" % newhbtl) 

521 scsi_dev_ctrl(newhbtl, "remove") 

522 util.wait_for_nopath(cur, DEV_WAIT) 

523 scsi_dev_ctrl(newhbtl, "add") 

524 util.wait_for_path('/dev/disk/by-scsibus/%s-%s' % (real_SCSIid, hbtl), DEV_WAIT) 

525 pass 

526 

527 # c) Probe for any LUNs that are not present in the system 

528 for l in li: 

529 newhbtl = ['', h[0], h[1], h[2], str(l)] 

530 newhbtlstr = "%s:%s:%s:%s" % (h[0], h[1], h[2], str(l)) 

531 util.SMlog("Probing new HBTL: %s" % newhbtl) 

532 scsi_dev_ctrl(newhbtl, "add") 

533 util.wait_for_path('/dev/disk/by-scsibus/*-%s' % newhbtlstr, DEV_WAIT) 

534 

535 return True 

536 

537 

538def refreshdev(pathlist): 

539 """ 

540 Refresh block devices given a path list 

541 """ 

542 for path in pathlist: 

543 dev = getdev(path) 

544 sysfs = os.path.join('/sys/block', dev, 'device/rescan') 

545 if os.path.exists(sysfs): 

546 try: 

547 with open(sysfs, 'w') as f: 

548 f.write('1') 

549 except: 

550 pass 

551 

552 

553def refresh_lun_size_by_SCSIid(SCSIid): 

554 """ 

555 Refresh all devices for the SCSIid. 

556 Returns True if all known devices and the mapper device are up to date. 

557 """ 

558 

559 def get_primary_device(SCSIid): 

560 mapperdevice = os.path.join('/dev/mapper', SCSIid) 

561 if os.path.exists(mapperdevice): 

562 return mapperdevice 

563 else: 

564 devices = get_devices_by_SCSIid(SCSIid) 

565 if devices: 

566 return devices[0] 

567 else: 

568 return None 

569 

570 def get_outdated_size_devices(currentcapacity, devices): 

571 devicesthatneedrefresh = [] 

572 for device in devices: 

573 if getsize(device) != currentcapacity: 

574 devicesthatneedrefresh.append(device) 

575 return devicesthatneedrefresh 

576 

577 def refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity): 

578 devices = get_devices_by_SCSIid(SCSIid) 

579 if "/dev/mapper/" in primarydevice: 

580 devices = set(devices + mpath_cli.list_paths(SCSIid)) 

581 devicesthatneedrefresh = get_outdated_size_devices(currentcapacity, 

582 devices) 

583 if devicesthatneedrefresh: 

584 # timing out avoids waiting for min(dev_loss_tmo, fast_io_fail_tmo) 

585 # if one or multiple devices don't answer 

586 util.timeout_call(10, refreshdev, devicesthatneedrefresh) 

587 if get_outdated_size_devices(currentcapacity, 

588 devicesthatneedrefresh): 

589 # in this state we shouldn't force resizing the mapper dev 

590 raise util.SMException("Failed to get %s to agree on the " 

591 "current capacity." 

592 % devicesthatneedrefresh) 

593 

594 def refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity): 

595 if "/dev/mapper/" in primarydevice \ 

596 and get_outdated_size_devices(currentcapacity, [primarydevice]): 

597 mpath_cli.resize_map(SCSIid) 

598 if get_outdated_size_devices(currentcapacity, [primarydevice]): 

599 raise util.SMException("Failed to get the mapper dev to agree " 

600 "on the current capacity.") 

601 

602 try: 

603 primarydevice = get_primary_device(SCSIid) 

604 if primarydevice: 

605 currentcapacity = sg_readcap(primarydevice) 

606 refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity) 

607 refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity) 

608 else: 

609 util.SMlog("scsiutil.refresh_lun_size_by_SCSIid(%s) could not " 

610 "find any devices for the SCSIid." % SCSIid) 

611 return True 

612 except: 

613 util.logException("Error in scsiutil.refresh_lun_size_by_SCSIid(%s)" 

614 % SCSIid) 

615 return False 

616 

617 

618def refresh_lun_size_by_SCSIid_on_slaves(session, SCSIid): 

619 for slave in util.get_all_slaves(session): 

620 util.SMlog("Calling on-slave.refresh_lun_size_by_SCSIid(%s) on %s." 

621 % (SCSIid, slave)) 

622 resulttext = session.xenapi.host.call_plugin( 

623 slave, 

624 "on-slave", 

625 "refresh_lun_size_by_SCSIid", 

626 {'SCSIid': SCSIid}) 

627 if "True" == resulttext: 

628 util.SMlog("Calling on-slave.refresh_lun_size_by_SCSIid(%s) on" 

629 " %s succeeded." % (SCSIid, slave)) 

630 else: 

631 message = ("Failed in on-slave.refresh_lun_size_by_SCSIid(%s) " 

632 "on %s." % (SCSIid, slave)) 

633 raise util.SMException("Slave %s failed in on-slave.refresh_lun_" 

634 "size_by_SCSIid(%s) " % (slave, SCSIid)) 

635 

636 

637def remove_stale_luns(hostids, lunid, expectedPath, mpath): 

638 try: 

639 for hostid in hostids: 

640 # get all LUNs of the format hostid:x:y:lunid 

641 luns = glob.glob('/dev/disk/by-scsibus/*-%s:*:*:%s' % (hostid, lunid)) 

642 

643 # try to get the scsiid for each of these luns 

644 for lun in luns: 

645 try: 

646 getSCSIid(lun) 

647 # if it works, we have a problem as this device should not 

648 # be present and be valid on this system 

649 util.SMlog("Warning! The lun %s should not be present and" \ 

650 " be valid on this system." % lun) 

651 except: 

652 # Now do the rest. 

653 pass 

654 

655 # get the HBTL 

656 basename = os.path.basename(lun) 

657 hbtl_list = basename.split(':') 

658 hbtl = basename.split('-')[1] 

659 

660 # the first one in scsiid-hostid 

661 hbtl_list[0] = hbtl_list[0].split('-')[1] 

662 

663 expectedPath = expectedPath + '*' + hbtl 

664 if not os.path.exists(expectedPath): 

665 # wait for sometime and check if the expected path exists 

666 # check if a rescan was done outside of this process 

667 time.sleep(2) 

668 

669 if os.path.exists(expectedPath): 

670 # do not remove device, this might be dangerous 

671 util.SMlog("Path %s appeared before checking for " \ 

672 "stale LUNs, ignore this LUN %s." % (expectedPath, lun)) 

673 continue 

674 

675 # remove the scsi device 

676 l = [os.path.realpath(lun), hbtl_list[0], hbtl_list[1], \ 

677 hbtl_list[2], hbtl_list[3]] 

678 scsi_dev_ctrl(l, 'remove') 

679 

680 # if multipath is enabled, do a best effort cleanup 

681 if mpath: 

682 try: 

683 path = os.path.basename(os.path.realpath(lun)) 

684 mpath_cli.remove_path(path) 

685 except Exception as e: 

686 util.SMlog("Failed to remove path %s, ignoring " \ 

687 "exception as path may not be present." % path) 

688 except Exception as e: 

689 util.SMlog("Exception removing stale LUNs, new devices may not come" \ 

690 " up properly! Error: %s" % str(e)) 

691 

692 

693def sg_readcap(device): 

694 device = os.path.join('/dev', getdev(device)) 

695 readcapcommand = ['/usr/bin/sg_readcap', '-b', device] 

696 (rc, stdout, stderr) = util.doexec(readcapcommand) 

697 if rc == 6: 

698 # retry one time for "Capacity data has changed" 

699 (rc, stdout, stderr) = util.doexec(readcapcommand) 

700 if rc != 0: 700 ↛ 701line 700 didn't jump to line 701, because the condition on line 700 was never true

701 raise util.SMException("scsiutil.sg_readcap(%s) failed" % (device)) 

702 match = re.search('(^|.*\n)(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)\n$', stdout) 

703 if not match: 703 ↛ 704line 703 didn't jump to line 704, because the condition on line 703 was never true

704 raise util.SMException("scsiutil.sg_readcap(%s) failed to parse: %s" 

705 % (device, stdout)) 

706 (blockcount, blocksize) = match.group(2, 3) 

707 return (int(blockcount, 0) * int(blocksize, 0))