1212from drgn import FaultError
1313from drgn import Object
1414from drgn import Program
15+ from drgn import sizeof
1516from 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
1722from drgn_tools .corelens import CorelensModule
1823from drgn_tools .device import class_to_subsys
1924from drgn_tools .module import ensure_debuginfo
2025from drgn_tools .table import print_table
2126from drgn_tools .util import has_member
27+ from drgn_tools .util import timestamp_str
2228
2329
2430class 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+
105172def 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 \t SCSI Device Addr : { hex (scsi_dev .value_ ())} "
357+ )
358+ print (
359+ f" Vendor : { vendor } \t Device 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+
257418class 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