4 from collections
import OrderedDict
11 logical_sector_size
= 512
18 self
._start
= time
.time()
21 self
._stop
= time
.time()
22 self
.value
= max(self
._stop
- self
._start
, 1/1000000)
24 class LiteSATABISTUnitDriver
:
25 def __init__(self
, regs
, name
):
28 self
.frequency
= regs
.identifier_frequency
.read()
30 for s
in ["start", "sector", "count", "loops", "random", "done", "aborted", "errors", "cycles"]:
31 setattr(self
, s
, getattr(regs
, name
+ "_"+ s
))
33 def run(self
, sector
, count
, loops
, random
, blocking
=True, hw_timer
=True):
34 self
.sector
.write(sector
)
35 self
.count
.write(count
)
36 self
.loops
.write(loops
)
37 self
.random
.write(random
)
42 while (self
.done
.read() == 0):
45 aborted
= self
.aborted
.read()
48 self
.time
= self
.cycles
.read()/self
.frequency
50 self
.time
= timer
.value
51 speed
= (loops
*count
*logical_sector_size
)/self
.time
52 errors
= self
.errors
.read()
56 return (aborted
, errors
, speed
)
58 class LiteSATABISTGeneratorDriver(LiteSATABISTUnitDriver
):
59 def __init__(self
, regs
, name
):
60 LiteSATABISTUnitDriver
.__init
__(self
, regs
, name
+ "_generator")
62 class LiteSATABISTCheckerDriver(LiteSATABISTUnitDriver
):
63 def __init__(self
, regs
, name
):
64 LiteSATABISTUnitDriver
.__init
__(self
, regs
, name
+ "_checker")
66 class LiteSATABISTIdentifyDriver
:
67 def __init__(self
, regs
, name
):
70 for s
in ["start", "done", "source_stb", "source_ack", "source_data"]:
71 setattr(self
, s
, getattr(regs
, name
+ "_identify_"+ s
))
76 while self
.source_stb
.read():
77 dword
= self
.source_data
.read()
78 word_lsb
= dword
& 0xffff
79 word_msb
= (dword
>> 16) & 0xffff
80 self
.data
+= [word_lsb
, word_msb
]
81 self
.source_ack
.write(1)
83 def run(self
, blocking
=True):
84 self
.read_fifo() # flush the fifo before we start
87 while (self
.done
.read() == 0):
93 self
.serial_number
= ""
94 for i
, word
in enumerate(self
.data
[10:20]):
95 s
= word
.to_bytes(2, byteorder
='big').decode("utf-8")
96 self
.serial_number
+= s
97 self
.firmware_revision
= ""
98 for i
, word
in enumerate(self
.data
[23:27]):
99 s
= word
.to_bytes(2, byteorder
='big').decode("utf-8")
100 self
.firmware_revision
+= s
101 self
.model_number
= ""
102 for i
, word
in enumerate(self
.data
[27:46]):
103 s
= word
.to_bytes(2, byteorder
='big').decode("utf-8")
104 self
.model_number
+= s
106 self
.total_sectors
= self
.data
[100]
107 self
.total_sectors
+= (self
.data
[101] << 16)
108 self
.total_sectors
+= (self
.data
[102] << 32)
109 self
.total_sectors
+= (self
.data
[103] << 48)
111 self
.capabilities
= OrderedDict()
112 self
.capabilities
["SATA Gen1"] = (self
.data
[76] >> 1) & 0x1
113 self
.capabilities
["SATA Gen2"] = (self
.data
[76] >> 2) & 0x1
114 self
.capabilities
["SATA Gen3"] = (self
.data
[76] >> 3) & 0x1
115 self
.capabilities
["48 bits LBA supported"] = (self
.data
[83] >> 10) & 0x1
118 info
= "Serial Number: " + self
.serial_number
+ "\n"
119 info
+= "Firmware Revision: " + self
.firmware_revision
+ "\n"
120 info
+= "Model Number: " + self
.model_number
+ "\n"
121 info
+= "Capacity: %3.2f GB\n" %((self
.total_sectors
*logical_sector_size
)/GB
)
122 for k
, v
in self
.capabilities
.items():
123 info
+= k
+ ": " + str(v
) + "\n"
127 parser
= argparse
.ArgumentParser(formatter_class
=argparse
.RawDescriptionHelpFormatter
,
131 parser
.add_argument("-s", "--transfer_size", default
=1024, help="transfer sizes (in KB, up to 16MB)")
132 parser
.add_argument("-l", "--total_length", default
=256, help="total transfer length (in MB, up to HDD capacity)")
133 parser
.add_argument("-n", "--loops", default
=1, help="number of loop per transfer (allow more precision on speed calculation for small transfers)")
134 parser
.add_argument("-r", "--random", action
="store_true", help="use random data")
135 parser
.add_argument("-c", "--continuous", action
="store_true", help="continuous mode (Escape to exit)")
136 parser
.add_argument("-i", "--identify", action
="store_true", help="only run identify")
137 parser
.add_argument("-t", "--software_timer", action
="store_true", help="use software timer")
138 parser
.add_argument("-a", "--random_addressing", action
="store_true", help="use random addressing")
139 return parser
.parse_args()
141 if __name__
== "__main__":
145 identify
= LiteSATABISTIdentifyDriver(wb
.regs
, "sata_bist")
146 generator
= LiteSATABISTGeneratorDriver(wb
.regs
, "sata_bist")
147 checker
= LiteSATABISTCheckerDriver(wb
.regs
, "sata_bist")
152 if not int(args
.identify
):
154 count
= int(args
.transfer_size
)*KB
//logical_sector_size
155 loops
= int(args
.loops
)
156 length
= int(args
.total_length
)*MB
157 random
= int(args
.random
)
158 continuous
= int(args
.continuous
)
159 sw_timer
= int(args
.software_timer
)
160 random_addressing
= int(args
.random_addressing
)
164 while ((run_sectors
*logical_sector_size
< length
) or continuous
) and (sector
< identify
.total_sectors
):
166 # generator (write data to HDD)
168 while not write_done
:
169 write_aborted
, write_errors
, write_speed
= generator
.run(sector
, count
, loops
, random
, True, not sw_timer
)
170 write_done
= not write_aborted
174 # checker (read and check data from HDD)
177 read_aborted
, read_errors
, read_speed
= checker
.run(sector
, count
, loops
, random
, True, not sw_timer
)
178 read_done
= not read_aborted
182 print("sector=%d(%dMB) wr_speed=%4.2fMB/s rd_speed=%4.2fMB/s errors=%d retry=%d" %(
184 run_sectors
*logical_sector_size
/MB
,
187 write_errors
+ read_errors
,
189 if random_addressing
:
190 sector
= rand
.randint(0, identify
.total_sectors
//(256*2))*256
195 except KeyboardInterrupt: