Skip to content

Commit 0873913

Browse files
vashanmubiger410
authored andcommitted
Add SCSI inflight commands sub option
Signed-off-by: Rajan <[email protected]>
1 parent 04f5cbb commit 0873913

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

drgn_tools/scsi.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@
1212
from drgn import FaultError
1313
from drgn import Object
1414
from drgn import Program
15+
from drgn import sizeof
1516
from drgn.helpers.linux.list import list_for_each_entry
1617

18+
from drgn_tools.block import for_each_mq_pending_request
19+
from drgn_tools.block import for_each_sq_pending_request
20+
from drgn_tools.block import is_mq
21+
from drgn_tools.block import request_target
1722
from drgn_tools.corelens import CorelensModule
1823
from drgn_tools.device import class_to_subsys
1924
from drgn_tools.module import ensure_debuginfo
2025
from drgn_tools.table import print_table
2126
from drgn_tools.util import has_member
27+
from drgn_tools.util import timestamp_str
2228

2329

2430
class Opcode(enum.Enum):
@@ -102,6 +108,67 @@ def scsi_device_name(sdev: Object) -> str:
102108
return ""
103109

104110

111+
def for_each_scsi_cmnd(prog: Program, scsi_device: Object) -> Iterator[Object]:
112+
"""
113+
Iterates thru all scsi commands for a given SCSI device.
114+
115+
:param scsi_device: ``struct scsi_device *``
116+
:returns: an iterator of ``struct scsi_cmnd *``
117+
"""
118+
q = scsi_device.request_queue
119+
if is_mq(q):
120+
for scmnd in for_each_scsi_cmd_mq(prog, scsi_device):
121+
yield scmnd
122+
else:
123+
for scmnd in for_each_scsi_cmd_sq(prog, scsi_device):
124+
yield scmnd
125+
126+
127+
def rq_to_scmnd(prog: Program, rq: Object) -> Object:
128+
"""
129+
Fetch the scsi_cmnd from request address
130+
131+
:param rq: ``struct request_queue *``
132+
:returns: Object of ``struct scsi_cmnd *``
133+
"""
134+
scmnd = rq.value_() + sizeof(prog.type("struct request"))
135+
return Object(prog, "struct scsi_cmnd *", value=scmnd)
136+
137+
138+
def for_each_scsi_cmd_sq(prog: Program, dev: Object) -> Iterator[Object]:
139+
"""
140+
Iterates thru all SCSI commands from the block layer pending requests.
141+
142+
:param dev: ``strcut scsi_device *``
143+
:returns: an iterator of ``struct scsi_cmnd *``
144+
"""
145+
q = dev.request_queue
146+
for rq in for_each_sq_pending_request(q):
147+
yield rq_to_scmnd(prog, rq)
148+
149+
150+
def for_each_scsi_cmd_mq(prog: Program, dev: Object) -> Iterator[Object]:
151+
"""
152+
Iterates thru all SCSI commands in all multi hardware queue.
153+
154+
:param dev: ``strcut scsi_device *``
155+
:returns: an iterator of ``struct scsi_cmnd *``
156+
"""
157+
try:
158+
BLK_MQ_F_TAG_SHARED = prog.constant("BLK_MQ_F_TAG_SHARED")
159+
except LookupError:
160+
BLK_MQ_F_TAG_SHARED = prog.constant("BLK_MQ_F_TAG_QUEUE_SHARED")
161+
162+
q = dev.request_queue
163+
disk = dev.request_queue.disk
164+
for hwq, rq in for_each_mq_pending_request(q):
165+
if (hwq.flags & BLK_MQ_F_TAG_SHARED) != 0 and request_target(
166+
rq
167+
).value_() != disk.value_():
168+
continue
169+
yield rq_to_scmnd(prog, rq)
170+
171+
105172
def scsi_id(scsi_dev: Object) -> str:
106173
"""
107174
Fetch SCSI id of the device.
@@ -254,6 +321,100 @@ def print_shost_devs(prog: Program) -> None:
254321
print_table(output)
255322

256323

324+
def print_inflight_scsi_cmnds(prog: Program):
325+
"""
326+
print all inflight SCSI commands for all SCSI devices.
327+
"""
328+
TotalInflight = 0
329+
for shost in for_each_scsi_host(prog):
330+
for scsi_dev in for_each_scsi_host_device(shost):
331+
diskname = scsi_device_name(scsi_dev)
332+
333+
counter = 0
334+
output = [
335+
[
336+
"Count",
337+
"Request",
338+
"Bio",
339+
"SCSI Cmnd",
340+
"Opcode",
341+
"Length",
342+
"Age",
343+
"Sector",
344+
]
345+
]
346+
347+
for scsi_cmnd in for_each_scsi_cmnd(prog, scsi_dev):
348+
if counter == 0:
349+
vendor = scsi_dev.vendor.string_().decode()
350+
devstate = str(
351+
scsi_dev.sdev_state.format_(type_name=False)
352+
)
353+
scsiid = scsi_id(scsi_dev)
354+
355+
print(
356+
f" Diskname : {diskname} {scsiid}\t\t\tSCSI Device Addr : {hex(scsi_dev.value_())}"
357+
)
358+
print(
359+
f" Vendor : {vendor} \tDevice State\t : {devstate}"
360+
)
361+
print("-" * 115)
362+
363+
if has_member(scsi_cmnd, "request"):
364+
req = scsi_cmnd.request
365+
else:
366+
reqp = scsi_cmnd.value_() - sizeof(
367+
prog.type("struct request")
368+
)
369+
req = Object(prog, "struct request *", value=reqp)
370+
371+
try:
372+
opcode = Opcode(scsi_cmnd.cmnd[0].value_()).name
373+
except ValueError:
374+
opcode = str(hex(scsi_cmnd.cmnd[0].value_()))
375+
376+
if scsi_cmnd.cmnd[0] == 0x2A or scsi_cmnd.cmnd[0] == 0x28:
377+
xfer_len = (
378+
scsi_cmnd.cmnd[7] << 8 | scsi_cmnd.cmnd[8]
379+
) * scsi_cmnd.transfersize
380+
else:
381+
xfer_len = 0
382+
383+
if req.bio:
384+
if has_member(req.bio, "bi_sector"):
385+
sector = req.bio.bi_sector
386+
else:
387+
sector = req.bio.bi_iter.bi_sector
388+
else:
389+
sector = 0
390+
391+
age = (
392+
prog["jiffies"] - scsi_cmnd.jiffies_at_alloc
393+
).value_() * 1000000
394+
counter += 1
395+
396+
output.append(
397+
[
398+
f"{counter:>4}",
399+
hex(req.value_()),
400+
hex(req.bio.value_()),
401+
hex(scsi_cmnd.value_()),
402+
opcode,
403+
f"{int(xfer_len):>7}",
404+
timestamp_str(age),
405+
f"{int(sector):>11}",
406+
]
407+
)
408+
409+
if counter > 1:
410+
TotalInflight += counter
411+
print_table(output)
412+
print("-" * 115)
413+
print(f" Total inflight commands across all disks : {TotalInflight}")
414+
print("-" * 115)
415+
return
416+
417+
257418
class ScsiInfo(CorelensModule):
258419
"""
259420
Corelens Module for scsi device information
@@ -267,6 +428,7 @@ class ScsiInfo(CorelensModule):
267428
[
268429
"--hosts",
269430
"--devices",
431+
"--queue",
270432
]
271433
]
272434

@@ -281,11 +443,18 @@ def add_args(self, parser: argparse.ArgumentParser) -> None:
281443
action="store_true",
282444
help="Print Scsi Devices",
283445
)
446+
parser.add_argument(
447+
"--queue",
448+
action="store_true",
449+
help="Print Inflight SCSI commands",
450+
)
284451

285452
def run(self, prog: Program, args: argparse.Namespace) -> None:
286453
if args.hosts:
287454
print_scsi_hosts(prog)
288455
elif args.devices:
289456
print_shost_devs(prog)
457+
elif args.queue:
458+
print_inflight_scsi_cmnds(prog)
290459
else:
291460
print_scsi_hosts(prog)

0 commit comments

Comments
 (0)