class CliCmdSas(CliCmd): def __init__(self, ptdev, expanderid=None): """ pt is a SCSI passthrough device file name expanderid can have one of the values 0x01: SBB Canister A 0x02: SBB Canister B 0x03: FEM Canister A SAS Expander 1 0x04: FEM Canister A SAS Expander 2 0x05: FEM Canister B SAS Expander 1 0x06: FEM Canister B SAS Expander 2 Alternately, the first parameter may be a sequence of (ptdev,expanderid). """ super(CliCmdSas, self).__init__() if not isinstance(ptdev, str): # If it's not a string, assume it's a sequence. ptdev, expanderid = ptdev self.ses = SesPageSas(ptdev) self.pt = ScsiPT(ptdev) self.expanderid = expanderid def close(self): pass def __del__(self): #del self.ses pass def execute(self, command): """ Send a CLI command through SES page 0xe8. """ cmd = Cmd.clicommandout(self.expanderid, command) cdb = CDB(cmd.cdb) cdb.set_data_out(cmd.dat) self.pt.sendcdb(cdb) page = self.ses.parse(self.ses.readpage(0xe8)) return page["data"].response.val
class CliCmdSas(CliCmd): def __init__(self, ptdev, expanderid=None): """ pt is a SCSI passthrough device file name expanderid can have one of the values 0x01: SBB Canister A 0x02: SBB Canister B 0x03: FEM Canister A SAS Expander 1 0x04: FEM Canister A SAS Expander 2 0x05: FEM Canister B SAS Expander 1 0x06: FEM Canister B SAS Expander 2 Alternately, the first parameter may be a sequence of (ptdev,expanderid). """ super(CliCmdSas, self).__init__() if not isinstance(ptdev, str): # If it's not a string, assume it's a sequence. ptdev, expanderid = ptdev self.ses = SesPageSas(ptdev) self.pt = ScsiPT(ptdev) self.expanderid = expanderid def close(self): pass def __del__(self): #del self.ses pass def execute(self, command): """ Send a CLI command through SES page 0xe8. """ cmd = Cmd.clicommandout(self.expanderid, command) cdb = CDB(cmd.cdb) cdb.set_data_out(cmd.dat) self.pt.sendcdb(cdb) page = self.ses.parse(self.ses.readpage(0xe8)) return page["data"].response.val
class FirmwareSes: """ Update firmware on one device. """ chunksize = 4096 # Maximum number of bytes to send to device at one time. def __init__(self, devicename, expanderid, filename, verbosity=0): self.devicename = devicename self.expanderid = expanderid self.filename = filename self.verbosity = verbosity if os.geteuid() != 0: raise Exception("You must be running as root.") self.sp = SesPageSas(devicename) def set_filename(self, filename): self.filename = filename def update(self, callback=None): def mycallback(total_packets, success_count, error_count): if cb: cb(total_packets, success_count, error_count, file_packets) self.previous_line = '' def statuscallback(total_packets, success_count, error_count, file_packets): #global previous_line this_line = " %d%% %d err\r" % (total_packets * 100 / file_packets, error_count) if this_line != self.previous_line: self.previous_line = this_line sys.stdout.write(this_line) sys.stdout.flush() if callback: cb = callback else: if self.verbosity >= 1: cb = statuscallback else: cb = None file_packets = (os.path.getsize(self.filename) - 1) / FirmwareSes.chunksize + 1 fwfile = open(self.filename, 'rb') offset = 0 # We're at the beginning of the file. microcode = fwfile.read() for offset in range(0, len(microcode), FirmwareSes.chunksize): mycallback(offset / FirmwareSes.chunksize, 0, 0) sesdat = self.sp.page_0e_fill( { "mode": 0x0e, "buf_offset": offset, "data_len": min(FirmwareSes.chunksize, len(microcode[offset:])), "firmware_image_id": 1, "sas_expander_id": self.expanderid, }, microcode) result = self.sp.writepage(sesdat) if result != 0: print "aborting; result =", result break page0e_desc = self.sp.parse( self.sp.readpage(0x0e))["data"].descriptors.val[0] if page0e_desc.status.val not in (0x01, 0x13): print "aborting; status =", page0e_desc.status.val break if page0e_desc.status.val == 0x13: print "done? status =", page0e_desc.status.val sesdat = self.sp.page_0e_fill( { "mode": 0x0f, "buf_offset": offset, "data_len": min(FirmwareSes.chunksize, len( microcode[offset:])), "firmware_image_id": 1, "sas_expander_id": self.expanderid, }, microcode) result = self.sp.writepage(sesdat) if result != 0: print "result =", result page0e = self.sp.parse(self.sp.readpage(0x0e))["data"] for descriptor in page0e.descriptors.val: print "Enclosure #" + str(descriptor.subid.val) print " status : %.2X - %s" % ( descriptor.status.val, descriptor.status_text.val) print " additional status : %.2X" % descriptor.additional_status.val print " maximum size : %s" % format( descriptor.maxsize.val, ",d") print " expected buffer id : %.2X" % descriptor.expected_id.val print " expected buffer offset: %.8X" % descriptor.expected_offset.val def identifyfile(self): """ Attempt to determine version and productid of a firmware file. """ return FirmwareFile("").identifyfile(self.filename)
class FirmwareSes: """ Update firmware on one device. """ chunksize = 4096 # Maximum number of bytes to send to device at one time. def __init__(self, devicename, expanderid, filename, verbosity=0): self.devicename = devicename self.expanderid = expanderid self.filename = filename self.verbosity = verbosity if os.geteuid() != 0: raise Exception("You must be running as root.") self.sp = SesPageSas(devicename) def set_filename(self, filename): self.filename = filename def update(self, callback=None): def mycallback(total_packets, success_count, error_count): if cb: cb(total_packets, success_count, error_count, file_packets) self.previous_line = '' def statuscallback(total_packets, success_count, error_count, file_packets): #global previous_line this_line = " %d%% %d err\r" % (total_packets*100/file_packets, error_count) if this_line != self.previous_line: self.previous_line = this_line sys.stdout.write(this_line) sys.stdout.flush() if callback: cb = callback else: if self.verbosity >= 1: cb = statuscallback else: cb = None file_packets = (os.path.getsize(self.filename)-1)/FirmwareSes.chunksize+1 fwfile = open(self.filename, 'rb') offset = 0 # We're at the beginning of the file. microcode = fwfile.read() for offset in range(0, len(microcode), FirmwareSes.chunksize): mycallback(offset/FirmwareSes.chunksize, 0, 0) sesdat = self.sp.page_0e_fill({ "mode":0x0e, "buf_offset":offset, "data_len":min(FirmwareSes.chunksize, len(microcode[offset:])), "firmware_image_id":1, "sas_expander_id":self.expanderid, }, microcode) result = self.sp.writepage(sesdat) if result != 0: print "aborting; result =", result break page0e_desc = self.sp.parse(self.sp.readpage(0x0e))["data"].descriptors.val[0] if page0e_desc.status.val not in (0x01, 0x13): print "aborting; status =", page0e_desc.status.val break if page0e_desc.status.val == 0x13: print "done? status =", page0e_desc.status.val sesdat = self.sp.page_0e_fill({ "mode":0x0f, "buf_offset":offset, "data_len":min(FirmwareSes.chunksize, len(microcode[offset:])), "firmware_image_id":1, "sas_expander_id":self.expanderid, }, microcode) result = self.sp.writepage(sesdat) if result != 0: print "result =", result page0e = self.sp.parse(self.sp.readpage(0x0e))["data"] for descriptor in page0e.descriptors.val: print "Enclosure #" + str(descriptor.subid.val) print " status : %.2X - %s" % (descriptor.status.val, descriptor.status_text.val) print " additional status : %.2X" % descriptor.additional_status.val print " maximum size : %s" % format(descriptor.maxsize.val, ",d") print " expected buffer id : %.2X" % descriptor.expected_id.val print " expected buffer offset: %.8X" % descriptor.expected_offset.val def identifyfile(self): """ Attempt to determine version and productid of a firmware file. """ return FirmwareFile("").identifyfile(self.filename)