Skip to content

Commit de21c7b

Browse files
vashanmuroot
authored andcommitted
Update scsi host and added scsi devices with scsiinfo module
Signed-off-by: Rajan Shanmugavelu <[email protected]
1 parent 936d1f3 commit de21c7b

File tree

1 file changed

+212
-22
lines changed

1 file changed

+212
-22
lines changed

drgn_tools/scsi.py

Lines changed: 212 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
1-
# Copyright (c) 2023, Oracle and/or its affiliates.
1+
# Copyright (c) 2025, Oracle and/or its affiliates.
22
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
33
"""
4-
Helper to print scsi hosts
4+
Helper to print IO substem useful information from the vmcore or
5+
live system.
56
"""
67
import argparse
78
from typing import Iterator
89

9-
import drgn
10+
from drgn import cast
1011
from drgn import container_of
11-
from drgn import FaultError
1212
from drgn import Object
1313
from drgn import Program
14-
from drgn.helpers.linux.list import list_for_each_entry
1514

16-
from drgn_tools.corelens import CorelensModule
17-
from drgn_tools.device import class_to_subsys
18-
from drgn_tools.table import print_table
1915
from drgn_tools.util import has_member
16+
from drgn_tools.table import print_table
17+
from drgn_tools.module import KernelModule
18+
from drgn_tools.module import ensure_debuginfo
19+
from drgn_tools.corelens import CorelensModule
20+
#from drgn_tools.lpfcinfo import print_lpfc_shost_info
21+
#from drgn_tools.qla2info import print_qla2xxx_shost_info
2022

23+
from drgn.helpers.linux.list import list_for_each_entry
24+
from drgn.helpers.linux.block import for_each_disk
25+
from drgn.helpers.linux.block import _class_to_subsys
26+
27+
"""
28+
Dictionary of gendisks being used as hashmap with request_queue address as the key,
29+
this is need to lookup the disk names for UEK6 or older kernel where gendisk is not
30+
part of the request_queue structure.
31+
"""
32+
gendisk_map = {}
2133

2234
def for_each_scsi_host(prog: Program) -> Iterator[Object]:
2335
"""
@@ -29,7 +41,7 @@ def for_each_scsi_host(prog: Program) -> Iterator[Object]:
2941
"knode_class"
3042
)
3143

32-
subsys_p = class_to_subsys(prog["shost_class"].address_of_())
44+
subsys_p = _class_to_subsys(prog["shost_class"].address_of_())
3345
devices = subsys_p.klist_devices.k_list.address_of_()
3446

3547
if class_in_private:
@@ -44,7 +56,6 @@ def for_each_scsi_host(prog: Program) -> Iterator[Object]:
4456
):
4557
yield container_of(dev, "struct Scsi_Host", "shost_dev")
4658

47-
4859
def host_module_name(shost: Object) -> str:
4960
"""
5061
Fetch the module name associated with the scsi host.
@@ -56,18 +67,13 @@ def host_module_name(shost: Object) -> str:
5667
name = "unknown"
5768
return name
5869

59-
60-
def for_each_scsi_host_device(
61-
prog: Program, shost: Object
62-
) -> Iterator[Object]:
70+
def for_each_scsi_host_device(shost: Object) -> Iterator[Object]:
6371
"""
64-
Get a list of scsi_device associated with a Scsi_Host.
65-
:returns: an iterator of ``struct scsi_device *``
72+
Iterates thru all scsi device and returns a scsi_device address
6673
"""
67-
return list_for_each_entry(
68-
"struct scsi_device", shost.__devices.address_of_(), "siblings"
69-
)
70-
74+
for scsi_dev in list_for_each_entry("struct scsi_device",
75+
shost.__devices.address_of_(), "siblings"):
76+
yield scsi_dev
7177

7278
def scsi_device_name(prog: Program, sdev: Object) -> str:
7379
"""
@@ -81,36 +87,195 @@ def scsi_device_name(prog: Program, sdev: Object) -> str:
8187
except FaultError:
8288
return ""
8389

90+
def load_gendisk(prog: Program) -> None:
91+
"""
92+
This method loads the all the gendisk into the global hashmap.
93+
"""
94+
msg = ensure_debuginfo(prog, ["sd_mod"])
95+
if msg:
96+
print(msg)
97+
return
98+
99+
for disk in for_each_disk(prog):
100+
disk_rq = hex(disk.queue)
101+
gendisk_map[disk_rq] = disk
102+
return
103+
104+
def for_each_scsi_cmnd(scsi_dev: Object) -> Iterator[Object]:
105+
"""
106+
Iterates thru all scsi commands for a given scsi device.
107+
Return each scsi_cmnd for a given scsi device.
108+
"""
109+
if prog.type("struct request_queue").has_member("mq_ops"):
110+
yield for_each_scsi_cmd_mq(scsi_dev.request_queue)
111+
else:
112+
yield for_each_scsi_cmd_sq(scsi_dev)
113+
114+
def for_each_scsi_cmd_sq(scsi_dev: Object) -> Iterator[Object]:
115+
"""
116+
Return each scsi_cmnd for single queue scsi device.
117+
"""
118+
for cmnd in list_for_each_entry("struct scsi_cmnd",
119+
scsi_dev.cmd_list, scsi_dev.list, "list"):
120+
yield cmnd
121+
122+
def scsi_id(scsi_dev: Object) -> str:
123+
"""
124+
Return Host:Controller:Target:Lun as a string.
125+
"""
126+
if not scsi_dev:
127+
return "<unknown>"
128+
hctl = "[" + str(scsi_dev.host.host_no.value_()) + ":" + \
129+
str(scsi_dev.channel.value_()) + ":" + \
130+
str(scsi_dev.id.value_()) + ":" + \
131+
str(scsi_dev.lun.value_()) + "]"
132+
return hctl
133+
84134

85135
def print_scsi_hosts(prog: Program) -> None:
86136
"""
87137
Prints scsi host information
88138
"""
89139
output = [
90-
["SCSI_HOST", "NAME", "DRIVER", "Busy", "Blocked", "Fail", "State"]
140+
[
141+
"SCSI_HOST",
142+
"NAME",
143+
"DRIVER",
144+
"Version",
145+
"Busy",
146+
"Blocked",
147+
"Fail",
148+
"State",
149+
"EH val",
150+
]
91151
]
152+
92153
for shost in for_each_scsi_host(prog):
93154
"""
94155
Since 6eb045e092ef ("scsi: core: avoid host-wide host_busy counter for scsi_mq"),
95156
host_busy is no longer a member of struct Scsi_Host.
96157
"""
158+
if host_module_name(shost) == "ahci":
159+
continue
160+
161+
if shost.hostt.module.version:
162+
modver = shost.hostt.module.version.string_().decode()
163+
else:
164+
modver = "n/a"
165+
97166
if has_member(shost, "host_busy"):
98167
host_busy = shost.host_busy.counter.value_()
99168
else:
100169
host_busy = "n/a"
170+
171+
if has_member(shost, "eh_deadline"):
172+
eh_deadline = shost.eh_deadline.value_()
173+
else:
174+
eh_deadline = "n/a"
175+
101176
output.append(
102177
[
103178
hex(shost.value_()),
104179
f"host{shost.host_no.value_()}",
105180
host_module_name(shost),
181+
modver,
106182
host_busy,
107183
shost.host_blocked.counter.value_(),
108184
shost.host_failed.value_(),
109185
shost.shost_state.format_(type_name=False),
186+
eh_deadline,
110187
]
111188
)
112189
print_table(output)
113190

191+
def print_shost_header(shost: Object) -> None:
192+
"""
193+
print scsi host header.
194+
"""
195+
print(
196+
"--------------------------------------------------"
197+
"-------------------------------------------------"
198+
)
199+
output = [
200+
[
201+
"HOST",
202+
"DRIVER",
203+
"Scsi_Host",
204+
"shost_data",
205+
"hostdata",
206+
]
207+
]
208+
209+
shostdata = hex(shost.shost_data.address_of_().value_())
210+
hostdata = hex(shost.hostdata.address_of_().value_())
211+
output.append(
212+
[
213+
shost.shost_gendev.kobj.name.string_().decode(),
214+
host_module_name(shost),
215+
hex(shost),
216+
shostdata,
217+
hostdata,
218+
]
219+
)
220+
print_table(output)
221+
print(
222+
"--------------------------------------------------"
223+
"-------------------------------------------------"
224+
)
225+
return
226+
227+
228+
def print_shost_devs(prog: Program) -> None:
229+
"""
230+
print all scsi devices for a Scsi_Host
231+
"""
232+
msg = ensure_debuginfo(prog, ["sd_mod"])
233+
if msg:
234+
print(msg)
235+
return
236+
237+
for shost in for_each_scsi_host(prog):
238+
if host_module_name(shost) == "ahci":
239+
continue
240+
print_shost_header(shost)
241+
output = [
242+
[
243+
"Device",
244+
"H:C:T:L",
245+
"Scsi Device Addr",
246+
"Vendor",
247+
"State",
248+
"IO Req",
249+
"IO Done",
250+
"IO Error",
251+
]
252+
]
253+
254+
for scsi_dev in for_each_scsi_host_device(shost):
255+
if prog.type("struct request_queue").has_member("disk"):
256+
gendisk = cast("struct gendisk *", scsi_dev.request_queue.disk)
257+
if not gendisk:
258+
continue
259+
diskname = gendisk.disk_name.address_of_().string_().decode()
260+
else:
261+
diskname = gendisk_map[hex(scsi_dev.request_queue)].disk_name.string_().decode()
262+
263+
vendor = scsi_dev.vendor.string_().decode()
264+
devstate = str(scsi_dev.sdev_state.format_(type_name=False))
265+
266+
output.append(
267+
[
268+
str(diskname),
269+
scsi_id(scsi_dev),
270+
hex(scsi_dev),
271+
str(vendor),
272+
devstate,
273+
scsi_dev.iorequest_cnt.counter.value_(),
274+
scsi_dev.iodone_cnt.counter.value_(),
275+
scsi_dev.ioerr_cnt.counter.value_(),
276+
]
277+
)
278+
print_table(output)
114279

115280
class ScsiInfo(CorelensModule):
116281
"""
@@ -119,5 +284,30 @@ class ScsiInfo(CorelensModule):
119284

120285
name = "scsiinfo"
121286

287+
debuginfo_kmods = ["sd_mod"]
288+
289+
default_args = [
290+
[
291+
"--hosts",
292+
"--devices",
293+
]
294+
]
295+
296+
def add_args(self, parser: argparse.ArgumentParser) -> None:
297+
parser.add_argument(
298+
"--hosts",
299+
action="store_true",
300+
help="Print Scsi Hosts",
301+
)
302+
parser.add_argument(
303+
"--devices",
304+
action="store_true",
305+
help="Print Scsi Devices",
306+
)
307+
122308
def run(self, prog: Program, args: argparse.Namespace) -> None:
123-
print_scsi_hosts(prog)
309+
if args.hosts:
310+
print_scsi_hosts(prog)
311+
if args.devices:
312+
load_gendisk(prog)
313+
print_shost_devs(prog)

0 commit comments

Comments
 (0)