#! /usr/bin/env stap

global devices, reads, writes

/* data collection: SCSI disk */
%(kernel_v<"2.6.24" %?
probe module("sd_mod").function("sd_init_command") !, kernel.function("sd_init_command") {
  device=kernel_string($SCpnt->request->rq_disk->disk_name)
  sector_size=$SCpnt->device->sector_size
  nr_sectors=$SCpnt->request->nr_sectors
  devices[device] = 1
%(kernel_v>="2.6.19" %?
  if ($SCpnt->request->cmd_flags & 1)
%:
  if ($SCpnt->request->flags & 1)
%)
    writes[device] <<< nr_sectors * sector_size
  else
    reads[device] <<< nr_sectors * sector_size
}
%:

function get_sector_size:long (data:long) { 
  return @cast(data, "scsi_device", "kernel<scsi/scsi_device.h>")->sector_size
}

%(kernel_v>="2.6.31" %?
%{
#include <linux/blkdev.h>
%}

function get_nr_sectors:long(rq:long) %{ /* pure */
  STAP_RETVALUE = blk_rq_sectors((const struct request *)(long)STAP_ARG_rq);
%}
%)

probe module("sd_mod").function("sd_prep_fn") !, kernel.function("sd_prep_fn") {
  device=kernel_string($rq->rq_disk->disk_name)
  sector_size=get_sector_size($q->queuedata)
%(kernel_v>="2.6.31" %?
  nr_sectors=get_nr_sectors($rq)
%:
  nr_sectors=$rq->nr_sectors
%)
  devices[device] = 1
  if ($rq->cmd_flags & 1)
    writes[device] <<< nr_sectors * sector_size
  else
    reads[device] <<< nr_sectors * sector_size
}
%)

/* data collection: SCSI tape */
probe module("st").function("st_do_scsi") !, kernel.function("st_do_scsi") {
  device=kernel_string($STp->disk->disk_name)
  devices[device] = 1
  if ($direction)
    writes[device] <<< $bytes
  else
    reads[device] <<< $bytes
}


/* reporting */
global blksize=512
global hdrcount
probe timer.s($1) {
  if ((hdrcount++ % 10) == 0)
    printf("%9s %9s %9s %9s %9s %9s\n",
           "Device:","tps","blk_read/s","blk_wrtn/s","blk_read","blk_wrtn")

  foreach (dev in devices) {
    rdcount=@count(reads[dev])
    wrcount=@count(writes[dev])
    tps=(rdcount+wrcount)*100/$1
    rdblkcount=rdcount ? @sum(reads[dev])/blksize : 0
    wrblkcount=wrcount ? @sum(writes[dev])/blksize : 0
    rdblkrate=rdblkcount*100/$1
    wrblkrate=wrblkcount*100/$1
    printf("%9s %6d.%02d %6d.%02d %6d.%02d %9d %9d\n",
           dev, tps/100,tps%100,
           rdblkrate/100,rdblkrate%100,
           wrblkrate/100,wrblkrate%100,
           rdblkcount, wrblkcount)
  }
  printf ("\n")
  delete devices
  delete reads
  delete writes
}
