1
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
2
# coding=utf8
3
3
4
- # Copyright 2013 IBM Corporation
4
+ # Copyright 2014 IBM Corporation
5
5
#
6
6
# Licensed under the Apache License, Version 2.0 (the "License");
7
7
# you may not use this file except in compliance with the License.
@@ -383,7 +383,7 @@ def _decode_state(self, state):
383
383
desc = "Unknown state %d for reading type %d/sensor type %d" % (
384
384
state , self .reading_type , self .sensor_type_number )
385
385
health = const .Health .Warning
386
- return ( desc , health )
386
+ return desc , health
387
387
388
388
def decode_sensor_reading (self , reading ):
389
389
numeric = None
@@ -505,18 +505,18 @@ def decode_formula(self, entry):
505
505
506
506
def tlv_decode (self , tlv , data ):
507
507
# Per IPMI 'type/length byte format
508
- type = (tlv & 0b11000000 ) >> 6
508
+ ipmitype = (tlv & 0b11000000 ) >> 6
509
509
if not len (data ):
510
510
return ""
511
- if type == 0 : # Unicode per 43.15 in ipmi 2.0 spec
511
+ if ipmitype == 0 : # Unicode per 43.15 in ipmi 2.0 spec
512
512
# the spec is not specific about encoding, assuming utf8
513
513
return unicode (struct .pack ("%dB" % len (data ), * data ), "utf_8" )
514
- elif type == 1 : # BCD '+'
514
+ elif ipmitype == 1 : # BCD '+'
515
515
tmpl = "%02X" * len (data )
516
516
tstr = tmpl % tuple (data )
517
517
tstr = tstr .replace ("A" , " " ).replace ("B" , "-" ).replace ("C" , "." )
518
518
return tstr .replace ("D" , ":" ).replace ("E" , "," ).replace ("F" , "_" )
519
- elif type == 2 : # 6 bit ascii, start at 0x20 and stop when out of bits
519
+ elif ipmitype == 2 : # 6 bit ascii, start at 0x20
520
520
# the ordering is very peculiar and is best understood from
521
521
# IPMI SPEC "6-bit packed ascii example
522
522
tstr = ""
@@ -528,7 +528,7 @@ def tlv_decode(self, tlv, data):
528
528
(data [1 ] >> 4 ) + 0x20 )
529
529
tstr += chr ((data [2 ] >> 2 ) + 0x20 )
530
530
return tstr
531
- elif type == 3 : # ACSII+LATIN1
531
+ elif ipmitype == 3 : # ACSII+LATIN1
532
532
return struct .pack ("%dB" % len (data ), * data )
533
533
534
534
@@ -569,9 +569,15 @@ def read_info(self):
569
569
self .aux_fw = self .decode_aux (rsp ['data' ][11 :15 ])
570
570
self .get_sdr ()
571
571
572
+ def get_sdr_reservation (self ):
573
+ rsp = self .ipmicmd .raw_command (netfn = 0x0a , command = 0x22 )
574
+ if rsp ['code' ] != 0 :
575
+ raise exc .IpmiException (rsp ['error' ])
576
+ return rsp ['data' ][0 ] + (rsp ['data' ][1 ] << 8 )
577
+
572
578
def get_sdr (self ):
573
- rsp = self .ipmicmd .raw_command (netfn = 0x0a , command = 0x20 )
574
- if (rsp ['data' ][0 ] != 0x51 ):
579
+ repinfo = self .ipmicmd .raw_command (netfn = 0x0a , command = 0x20 )
580
+ if (repinfo ['data' ][0 ] != 0x51 ):
575
581
# we only understand SDR version 51h, the only version defined
576
582
# at time of this writing
577
583
raise NotImplementedError
@@ -589,14 +595,54 @@ def get_sdr(self):
589
595
rsvid = 0 # partial 'get sdr' will require this
590
596
offset = 0
591
597
size = 0xff
598
+ chunksize = 128
592
599
while recid != 0xffff : # per 33.12 Get SDR command, 0xffff marks end
593
- rqdata = [rsvid & 0xff , rsvid >> 8 ,
594
- recid & 0xff , recid >> 8 ,
595
- offset , size ]
596
- rsp = self .ipmicmd .raw_command (netfn = 0x0a , command = 0x23 ,
597
- data = rqdata )
598
- newrecid = (rsp ['data' ][1 ] << 8 ) + rsp ['data' ][0 ]
599
- self .add_sdr (rsp ['data' ][2 :])
600
+ newrecid = 0
601
+ currlen = 0
602
+ sdrdata = bytearray ()
603
+ while True : # loop until SDR fetched wholly
604
+ if size != 0xff and rsvid == 0 :
605
+ rsvid = self .get_sdr_reservation ()
606
+ rqdata = [rsvid & 0xff , rsvid >> 8 ,
607
+ recid & 0xff , recid >> 8 ,
608
+ offset , size ]
609
+ sdrrec = self .ipmicmd .raw_command (netfn = 0x0a , command = 0x23 ,
610
+ data = rqdata )
611
+ if sdrrec ['code' ] == 0xca :
612
+ if size == 0xff : # get just 5 to get header to know length
613
+ size = 5
614
+ elif size > 5 :
615
+ size /= 2
616
+ # push things over such that it's less
617
+ # likely to be just 1 short of a read
618
+ # and incur a whole new request
619
+ size += 2
620
+ chunksize = size
621
+ continue
622
+ if sdrrec ['code' ] == 0xc5 : # need a new reservation id
623
+ rsvid = 0
624
+ continue
625
+ if sdrrec ['code' ] != 0 :
626
+ raise exc .IpmiException (sdrrec ['error' ])
627
+ if newrecid == 0 :
628
+ newrecid = (sdrrec ['data' ][1 ] << 8 ) + sdrrec ['data' ][0 ]
629
+ if currlen == 0 :
630
+ currlen = sdrrec ['data' ][6 ] + 5 # compensate for header
631
+ sdrdata .extend (sdrrec ['data' ][2 :])
632
+ # determine next offset to use based on current offset and the
633
+ # size used last time.
634
+ offset += size
635
+ if offset >= currlen :
636
+ break
637
+ if size == 5 and offset == 5 :
638
+ # bump up size after header retrieval
639
+ size = chunksize
640
+ if (offset + size ) > currlen :
641
+ size = currlen - offset
642
+ self .add_sdr (sdrdata )
643
+ offset = 0
644
+ if size != 0xff :
645
+ size = 5
600
646
if newrecid == recid :
601
647
raise exc .BmcErrorException ("Incorrect SDR record id from BMC" )
602
648
recid = newrecid
0 commit comments