1
- # Copyright (c) 2023 , Oracle and/or its affiliates.
1
+ # Copyright (c) 2025 , Oracle and/or its affiliates.
2
2
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
3
"""
4
- Helper to print scsi hosts
4
+ Helper to print IO substem useful information from the vmcore or
5
+ live system.
5
6
"""
6
7
import argparse
7
8
from typing import Iterator
8
9
9
- import drgn
10
+ from drgn import cast
10
11
from drgn import container_of
11
12
from drgn import FaultError
12
13
from drgn import Object
13
14
from drgn import Program
15
+ from drgn .helpers .linux .block import _class_to_subsys
16
+ from drgn .helpers .linux .block import for_each_disk
14
17
from drgn .helpers .linux .list import list_for_each_entry
15
18
16
19
from drgn_tools .corelens import CorelensModule
17
- from drgn_tools .device import class_to_subsys
20
+ from drgn_tools .module import ensure_debuginfo
18
21
from drgn_tools .table import print_table
19
22
from drgn_tools .util import has_member
20
23
21
24
25
+ """
26
+ Dictionary of gendisks being used as hashmap with request_queue address as the key,
27
+ this is need to lookup the disk names for UEK6 or older kernel where gendisk is not
28
+ part of the request_queue structure.
29
+ """
30
+ gendisk_map = {}
31
+
32
+
22
33
def for_each_scsi_host (prog : Program ) -> Iterator [Object ]:
23
34
"""
24
35
Iterate through all scsi hosts and returns an
@@ -29,7 +40,7 @@ def for_each_scsi_host(prog: Program) -> Iterator[Object]:
29
40
"knode_class"
30
41
)
31
42
32
- subsys_p = class_to_subsys (prog ["shost_class" ].address_of_ ())
43
+ subsys_p = _class_to_subsys (prog ["shost_class" ].address_of_ ())
33
44
devices = subsys_p .klist_devices .k_list .address_of_ ()
34
45
35
46
if class_in_private :
@@ -52,21 +63,20 @@ def host_module_name(shost: Object) -> str:
52
63
"""
53
64
try :
54
65
name = shost .hostt .module .name .string_ ().decode ()
55
- except drgn . FaultError :
66
+ except FaultError :
56
67
name = "unknown"
57
68
return name
58
69
59
70
60
- def for_each_scsi_host_device (
61
- prog : Program , shost : Object
62
- ) -> Iterator [Object ]:
71
+ def for_each_scsi_host_device (shost : Object ) -> Iterator [Object ]:
63
72
"""
64
- Get a list of scsi_device associated with a Scsi_Host.
65
- :returns: an iterator of ``struct scsi_device *``
73
+ Iterates thru all scsi device and returns a scsi_device address
66
74
"""
67
- return list_for_each_entry (
68
- "struct scsi_device" , shost .__devices .address_of_ (), "siblings"
69
- )
75
+ for scsi_dev in list_for_each_entry (
76
+ "struct scsi_device" ,
77
+ shost .__devices .address_of_ (),
78
+ "siblings" ):
79
+ yield scsi_dev
70
80
71
81
72
82
def scsi_device_name (prog : Program , sdev : Object ) -> str :
@@ -82,42 +92,212 @@ def scsi_device_name(prog: Program, sdev: Object) -> str:
82
92
return ""
83
93
84
94
95
+ def load_gendisk (prog : Program ) -> None :
96
+ """
97
+ This method loads the all the gendisk into the global hashmap.
98
+ """
99
+ msg = ensure_debuginfo (prog , ["sd_mod" ])
100
+ if msg :
101
+ print (msg )
102
+ return
103
+
104
+ for disk in for_each_disk (prog ):
105
+ disk_rq = hex (disk .queue )
106
+ gendisk_map [disk_rq ] = disk
107
+ return
108
+
109
+
110
+ def scsi_id (scsi_dev : Object ) -> str :
111
+ """
112
+ Return Host:Controller:Target:Lun as a string.
113
+ """
114
+ if not scsi_dev :
115
+ return "<unknown>"
116
+ hctl = "[" + str (scsi_dev .host .host_no .value_ ()) + ":" + \
117
+ str (scsi_dev .channel .value_ ()) + ":" + \
118
+ str (scsi_dev .id .value_ ()) + ":" + \
119
+ str (scsi_dev .lun .value_ ()) + "]"
120
+ return hctl
121
+
122
+
85
123
def print_scsi_hosts (prog : Program ) -> None :
86
124
"""
87
125
Prints scsi host information
88
126
"""
89
127
output = [
90
- ["SCSI_HOST" , "NAME" , "DRIVER" , "Busy" , "Blocked" , "Fail" , "State" ]
128
+ [
129
+ "SCSI_HOST" ,
130
+ "NAME" ,
131
+ "DRIVER" ,
132
+ "Version" ,
133
+ "Busy" ,
134
+ "Blocked" ,
135
+ "Fail" ,
136
+ "State" ,
137
+ "EH val" ,
138
+ ]
91
139
]
140
+
92
141
for shost in for_each_scsi_host (prog ):
93
142
"""
94
143
Since 6eb045e092ef ("scsi: core: avoid host-wide host_busy counter for scsi_mq"),
95
144
host_busy is no longer a member of struct Scsi_Host.
96
145
"""
146
+ if host_module_name (shost ) == "ahci" :
147
+ continue
148
+
149
+ if shost .hostt .module .version :
150
+ modver = shost .hostt .module .version .string_ ().decode ()
151
+ else :
152
+ modver = "n/a"
153
+
97
154
if has_member (shost , "host_busy" ):
98
155
host_busy = shost .host_busy .counter .value_ ()
99
156
else :
100
157
host_busy = "n/a"
158
+
159
+ if has_member (shost , "eh_deadline" ):
160
+ eh_deadline = shost .eh_deadline .value_ ()
161
+ else :
162
+ eh_deadline = "n/a"
163
+
101
164
output .append (
102
165
[
103
166
hex (shost .value_ ()),
104
167
f"host{ shost .host_no .value_ ()} " ,
105
168
host_module_name (shost ),
169
+ modver ,
106
170
host_busy ,
107
171
shost .host_blocked .counter .value_ (),
108
172
shost .host_failed .value_ (),
109
173
shost .shost_state .format_ (type_name = False ),
174
+ eh_deadline ,
110
175
]
111
176
)
112
177
print_table (output )
113
178
114
179
180
+ def print_shost_header (shost : Object ) -> None :
181
+ """
182
+ print scsi host header.
183
+ """
184
+ print (
185
+ "--------------------------------------------------"
186
+ "-------------------------------------------------"
187
+ )
188
+ output = [
189
+ [
190
+ "HOST" ,
191
+ "DRIVER" ,
192
+ "Scsi_Host" ,
193
+ "shost_data" ,
194
+ "hostdata" ,
195
+ ]
196
+ ]
197
+
198
+ shostdata = hex (shost .shost_data .address_of_ ().value_ ())
199
+ hostdata = hex (shost .hostdata .address_of_ ().value_ ())
200
+ output .append (
201
+ [
202
+ shost .shost_gendev .kobj .name .string_ ().decode (),
203
+ host_module_name (shost ),
204
+ hex (shost ),
205
+ shostdata ,
206
+ hostdata ,
207
+ ]
208
+ )
209
+ print_table (output )
210
+ print (
211
+ "--------------------------------------------------"
212
+ "-------------------------------------------------"
213
+ )
214
+ return
215
+
216
+
217
+ def print_shost_devs (prog : Program ) -> None :
218
+ """
219
+ print all scsi devices for a Scsi_Host
220
+ """
221
+ msg = ensure_debuginfo (prog , ["sd_mod" ])
222
+ if msg :
223
+ print (msg )
224
+ return
225
+
226
+ for shost in for_each_scsi_host (prog ):
227
+ if host_module_name (shost ) == "ahci" :
228
+ continue
229
+ print_shost_header (shost )
230
+ output = [
231
+ [
232
+ "Device" ,
233
+ "H:C:T:L" ,
234
+ "Scsi Device Addr" ,
235
+ "Vendor" ,
236
+ "State" ,
237
+ "IO Req" ,
238
+ "IO Done" ,
239
+ "IO Error" ,
240
+ ]
241
+ ]
242
+
243
+ for scsi_dev in for_each_scsi_host_device (shost ):
244
+ if prog .type ("struct request_queue" ).has_member ("disk" ):
245
+ gendisk = cast ("struct gendisk *" , scsi_dev .request_queue .disk )
246
+ if not gendisk :
247
+ continue
248
+ diskname = gendisk .disk_name .address_of_ ().string_ ().decode ()
249
+ else :
250
+ diskname = gendisk_map [hex (scsi_dev .request_queue )].disk_name .string_ ().decode ()
251
+
252
+ vendor = scsi_dev .vendor .string_ ().decode ()
253
+ devstate = str (scsi_dev .sdev_state .format_ (type_name = False ))
254
+
255
+ output .append (
256
+ [
257
+ str (diskname ),
258
+ scsi_id (scsi_dev ),
259
+ hex (scsi_dev ),
260
+ str (vendor ),
261
+ devstate ,
262
+ scsi_dev .iorequest_cnt .counter .value_ (),
263
+ scsi_dev .iodone_cnt .counter .value_ (),
264
+ scsi_dev .ioerr_cnt .counter .value_ (),
265
+ ]
266
+ )
267
+ print_table (output )
268
+
269
+
115
270
class ScsiInfo (CorelensModule ):
116
271
"""
117
272
Corelens Module for scsi device information
118
273
"""
119
274
120
275
name = "scsiinfo"
121
276
277
+ debuginfo_kmods = ["sd_mod" ]
278
+
279
+ default_args = [
280
+ [
281
+ "--hosts" ,
282
+ "--devices" ,
283
+ ]
284
+ ]
285
+
286
+ def add_args (self , parser : argparse .ArgumentParser ) -> None :
287
+ parser .add_argument (
288
+ "--hosts" ,
289
+ action = "store_true" ,
290
+ help = "Print Scsi Hosts" ,
291
+ )
292
+ parser .add_argument (
293
+ "--devices" ,
294
+ action = "store_true" ,
295
+ help = "Print Scsi Devices" ,
296
+ )
297
+
122
298
def run (self , prog : Program , args : argparse .Namespace ) -> None :
123
- print_scsi_hosts (prog )
299
+ if args .hosts :
300
+ print_scsi_hosts (prog )
301
+ if args .devices :
302
+ load_gendisk (prog )
303
+ print_shost_devs (prog )
0 commit comments