Skip to content

Commit 69cd476

Browse files
committed
Update scsi host and added scsi devices with scsiinfo module
Signed-off-by: Rajan Shanmugavelu <[email protected]
1 parent 52872c8 commit 69cd476

File tree

2 files changed

+189
-21
lines changed

2 files changed

+189
-21
lines changed

drgn_tools/iscsi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ def print_iscsi_sessions(prog: Program) -> None:
121121
)
122122
)
123123

124-
for scsi_dev in for_each_scsi_host_device(prog, session.host):
125-
name = scsi_device_name(prog, scsi_dev)
124+
for scsi_dev in for_each_scsi_host_device(session.host):
125+
name = scsi_device_name(scsi_dev)
126126
print(
127127
"scsi{} Channel {} Id {} Lun: {}".format(
128128
session.host.host_no.value_(),

drgn_tools/scsi.py

Lines changed: 187 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
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 SCSI subsytem useful information from the vmcore or
5+
live system.
56
"""
67
import argparse
8+
import enum
79
from typing import Iterator
810

9-
import drgn
1011
from drgn import container_of
1112
from drgn import FaultError
1213
from drgn import Object
@@ -15,14 +16,24 @@
1516

1617
from drgn_tools.corelens import CorelensModule
1718
from drgn_tools.device import class_to_subsys
19+
from drgn_tools.module import ensure_debuginfo
1820
from drgn_tools.table import print_table
1921
from drgn_tools.util import has_member
2022

2123

24+
class Opcode(enum.Enum):
25+
TUR = 0x00
26+
READ_6 = 0x8
27+
WRITE_6 = 0xA
28+
INQUIRY = 0x12
29+
READ_10 = 0x28
30+
WRITE_10 = 0x2A
31+
32+
2233
def for_each_scsi_host(prog: Program) -> Iterator[Object]:
2334
"""
24-
Iterate through all scsi hosts and returns an
25-
iterator.
35+
Iterate through all scsi hosts and returns an iterator.
36+
2637
:returns: an iterator of ``struct Scsi_Host *``
2738
"""
2839
class_in_private = prog.type("struct device_private").has_member(
@@ -48,48 +59,96 @@ def for_each_scsi_host(prog: Program) -> Iterator[Object]:
4859
def host_module_name(shost: Object) -> str:
4960
"""
5061
Fetch the module name associated with the scsi host.
51-
returns: the module name string.
62+
63+
:param shost: ``struct Scsi_Host *``
64+
:returns: the module name string.
5265
"""
5366
try:
5467
name = shost.hostt.module.name.string_().decode()
55-
except drgn.FaultError:
68+
except FaultError:
5669
name = "unknown"
5770
return name
5871

5972

60-
def for_each_scsi_host_device(
61-
prog: Program, shost: Object
62-
) -> Iterator[Object]:
73+
def for_each_scsi_host_device(shost: Object) -> Iterator[Object]:
6374
"""
64-
Get a list of scsi_device associated with a Scsi_Host.
75+
Iterates thru all scsi device and returns a scsi_device address
76+
77+
:param shost: ``struct Scsi_Host *``
6578
:returns: an iterator of ``struct scsi_device *``
6679
"""
67-
return list_for_each_entry(
80+
for scsi_dev in list_for_each_entry(
6881
"struct scsi_device", shost.__devices.address_of_(), "siblings"
69-
)
82+
):
83+
yield scsi_dev
7084

7185

72-
def scsi_device_name(prog: Program, sdev: Object) -> str:
86+
def scsi_device_name(sdev: Object) -> str:
7387
"""
7488
Get the device name associated with scsi_device.
75-
:return ``str``
89+
90+
:param sdev: ``struct scsi_device *``
91+
:returns: ``str``
7692
"""
7793
rq = sdev.request_queue
78-
dev = container_of(rq.kobj.parent, "struct device", "kobj")
94+
if has_member(rq, "mq_kobj"):
95+
# uek5 thru uek8 has mq_obj with upstream commit id 320ae51fee
96+
dev = container_of(rq.mq_kobj.parent, "struct device", "kobj")
97+
if has_member(rq, "kobj"):
98+
dev = container_of(rq.kobj.parent, "struct device", "kobj")
7999
try:
80100
return dev.kobj.name.string_().decode()
81101
except FaultError:
82102
return ""
83103

84104

105+
def scsi_id(scsi_dev: Object) -> str:
106+
"""
107+
Fetch SCSI id of the device.
108+
109+
:param scsi_dev: ``struct scsi_device *``
110+
:returns: ``str``
111+
"""
112+
if not scsi_dev:
113+
return "<unknown>"
114+
hctl = (
115+
"["
116+
+ str(scsi_dev.host.host_no.value_())
117+
+ ":"
118+
+ str(scsi_dev.channel.value_())
119+
+ ":"
120+
+ str(scsi_dev.id.value_())
121+
+ ":"
122+
+ str(scsi_dev.lun.value_())
123+
+ "]"
124+
)
125+
return hctl
126+
127+
85128
def print_scsi_hosts(prog: Program) -> None:
86129
"""
87130
Prints scsi host information
88131
"""
89132
output = [
90-
["SCSI_HOST", "NAME", "DRIVER", "Busy", "Blocked", "Fail", "State"]
133+
[
134+
"SCSI_HOST",
135+
"NAME",
136+
"DRIVER",
137+
"Version",
138+
"Busy",
139+
"Blocked",
140+
"Fail",
141+
"State",
142+
"EH val",
143+
]
91144
]
145+
92146
for shost in for_each_scsi_host(prog):
147+
if shost.hostt.module.version:
148+
modver = shost.hostt.module.version.string_().decode()
149+
else:
150+
modver = "n/a"
151+
93152
"""
94153
Since 6eb045e092ef ("scsi: core: avoid host-wide host_busy counter for scsi_mq"),
95154
host_busy is no longer a member of struct Scsi_Host.
@@ -98,18 +157,101 @@ def print_scsi_hosts(prog: Program) -> None:
98157
host_busy = shost.host_busy.counter.value_()
99158
else:
100159
host_busy = "n/a"
160+
161+
if has_member(shost, "eh_deadline"):
162+
eh_deadline = shost.eh_deadline.value_()
163+
else:
164+
eh_deadline = "n/a"
165+
101166
output.append(
102167
[
103168
hex(shost.value_()),
104-
f"host{shost.host_no.value_()}",
169+
f"host{shost.host_no.value_():>}",
105170
host_module_name(shost),
171+
modver,
106172
host_busy,
107173
shost.host_blocked.counter.value_(),
108174
shost.host_failed.value_(),
109175
shost.shost_state.format_(type_name=False),
176+
eh_deadline,
110177
]
111178
)
112179
print_table(output)
180+
return
181+
182+
183+
def print_shost_header(shost: Object) -> None:
184+
"""
185+
print scsi host header.
186+
"""
187+
print("-" * 110)
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("-" * 110)
211+
return
212+
213+
214+
def print_shost_devs(prog: Program) -> None:
215+
"""
216+
print all scsi devices for a Scsi_Host
217+
"""
218+
msg = ensure_debuginfo(prog, ["sd_mod"])
219+
if msg:
220+
print(msg)
221+
return
222+
223+
for shost in for_each_scsi_host(prog):
224+
print_shost_header(shost)
225+
output = [
226+
[
227+
"Device",
228+
"H:C:T:L",
229+
"Scsi Device Addr",
230+
"Vendor",
231+
"State",
232+
"IO Req",
233+
"IO Done",
234+
"IO Error",
235+
]
236+
]
237+
238+
for scsi_dev in for_each_scsi_host_device(shost):
239+
vendor = scsi_dev.vendor.string_().decode()
240+
devstate = str(scsi_dev.sdev_state.format_(type_name=False))
241+
242+
output.append(
243+
[
244+
scsi_device_name(scsi_dev),
245+
scsi_id(scsi_dev),
246+
hex(scsi_dev),
247+
str(vendor),
248+
devstate,
249+
f"{scsi_dev.iorequest_cnt.counter.value_():>7}",
250+
f"{scsi_dev.iodone_cnt.counter.value_():>7}",
251+
f"{scsi_dev.ioerr_cnt.counter.value_():>4}",
252+
]
253+
)
254+
print_table(output)
113255

114256

115257
class ScsiInfo(CorelensModule):
@@ -119,5 +261,31 @@ class ScsiInfo(CorelensModule):
119261

120262
name = "scsiinfo"
121263

264+
debuginfo_kmods = ["sd_mod"]
265+
266+
default_args = [
267+
[
268+
"--hosts",
269+
"--devices",
270+
]
271+
]
272+
273+
def add_args(self, parser: argparse.ArgumentParser) -> None:
274+
parser.add_argument(
275+
"--hosts",
276+
action="store_true",
277+
help="Print Scsi Hosts",
278+
)
279+
parser.add_argument(
280+
"--devices",
281+
action="store_true",
282+
help="Print Scsi Devices",
283+
)
284+
122285
def run(self, prog: Program, args: argparse.Namespace) -> None:
123-
print_scsi_hosts(prog)
286+
if args.hosts:
287+
print_scsi_hosts(prog)
288+
elif args.devices:
289+
print_shost_devs(prog)
290+
else:
291+
print_scsi_hosts(prog)

0 commit comments

Comments
 (0)