From a513bfc04f35656f99cf3ae9ac888377a1d105c0 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Fri, 14 Aug 2026 23:48:19 +0200 Subject: [PATCH] Read the sdr partial read codes from the exception raw_command raises on any nonzero completion code, so the 0xCA and 0xC5 checks in get_sdr could not run: a bmc that will not return a whole record in one go, or whose reservation went stale, failed the sensor load outright instead of being retried. Read the code from the exception, which carries it. The back off also had a fixed point, size // 2 + 2 being 3 for a size of 3, so a bmc that kept refusing would have been asked the same question for ever. Give up when the request cannot get any smaller. A header read cannot go under 5 bytes either, since that is where the record length sits, so give up there rather than parse a reply too short to index. The stale reservation retry could not end on its own either: it cleared the id and left taking a new one to the top of the loop, which only reserves for a partial read. Take one where the code is handled. --- confluent_server/aiohmi/ipmi/sdr.py | 41 ++++++++++++++++++----------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/confluent_server/aiohmi/ipmi/sdr.py b/confluent_server/aiohmi/ipmi/sdr.py index fcf05d3c..923bb810 100644 --- a/confluent_server/aiohmi/ipmi/sdr.py +++ b/confluent_server/aiohmi/ipmi/sdr.py @@ -769,24 +769,35 @@ class SDR(object): rqdata = [rsvid & 0xff, rsvid >> 8, recid & 0xff, recid >> 8, offset, size] - sdrrec = await self.ipmicmd.raw_command(netfn=0x0a, command=0x23, - data=rqdata) - if sdrrec['code'] == 0xca: - if size == 0xff: # get just 5 to get header to know length - size = 5 - elif size > 5: - size //= 2 + try: + sdrrec = await self.ipmicmd.raw_command( + netfn=0x0a, command=0x23, data=rqdata) + except exc.IpmiException as ie: + # The two codes this loop negotiates with, rather than + # failures: more asked for than the bmc will return at once, + # and a reservation that has gone stale + if ie.ipmicode == 0xca: + if size == 0xff: # get just 5 to get header to know length + size = 5 + continue # push things over such that it's less # likely to be just 1 short of a read # and incur a whole new request - size += 2 - chunksize = size - continue - if sdrrec['code'] == 0xc5: # need a new reservation id - rsvid = 0 - continue - if sdrrec['code'] != 0: - raise exc.IpmiException(sdrrec['error']) + smaller = size // 2 + 2 + if smaller >= size or (currlen == 0 and smaller < 5): + # Nothing left to give up, and asking again + # unchanged would never end. A header read has to + # be 5 bytes to carry the record length, so a + # smaller one could not be parsed either + raise + size = chunksize = smaller + continue + if ie.ipmicode == 0xc5: # need a new reservation id + # Take one here rather than leaving it to the top of + # the loop, which only reserves for a partial read + rsvid = await self.get_sdr_reservation() + continue + raise if newrecid == 0: newrecid = (sdrrec['data'][1] << 8) + sdrrec['data'][0] if currlen == 0: