Decoding SCSI CDB

George Shuklin
OpsOps
Published in
2 min readFeb 22, 2017

Abstract: How to intercept and decode CDB SCSI codes.

Intro

SCSI (which later become foundation for SAS) is an industrial standard for block devices. I need to see what exactly goes into block devices when Ceph performs write operations (we’ve got in a bit of a quarrel with our SSDs vendor and I need to provide precise description of my problem without relying on ‘install Ceph and run benchmark’ argument).

CDB — command descriptor block, basically, ‘machine code’ for SCSI operations without actual data (without payload).

Obtaining CDB

That was easy. Just run (as root)

# echo -1 > /proc/sys/dev/scsi/logging_level

And you will receive a flood of messages in dmesg:

sd 0:0:1:0: [sdb] tag#0 sd_done: completed 4096 of 4096 bytes
sd 0:0:1:0: [sdb] tag#0 8 sectors total, 4096 bytes done.
sd 0:0:1:0: [sdb] tag#0 Send: scmd 0xffff882373458d80
sd 0:0:1:0: [sdb] tag#0 CDB: Synchronize Cache(10) 35 00 00 00 00 00 00 00 00 00
sd 0:0:1:0: [sdb] tag#0 Done: SUCCESS Result: hostbyte=DID_OK driverbyte=DRIVER_OK
sd 0:0:1:0: [sdb] tag#0 CDB: Synchronize Cache(10) 35 00 00 00 00 00 00 00 00 00
sd 0:0:1:0: [sdb] tag#0 scsi host busy 1 failed 0

‘CDB’ is the CDB we wants. Initial decoding was performed by the kernel: ‘Synchronize Cache(10)’. But I want it be decoded completely.

Decoding

I searched through internet for ‘cdb decoder’ and found almost nothing, except this nodeJS (!) library. Not like I’m a big fan of node, but like if I have options….

We need to install whole crapparade of node and grunt:

# (skip git clone part)
sudo apt-get install nodejs node-grunt node-grunt-cli npm
npm install
grunt

That was easy. Now we need to use this library. It has no CLI, so we may write one or just use it through node CLI. I opted for second option.

$ node> var x=require ("../build/scsi-cdb.min.js")
> var cdb = new x()
> cdb.decode('2a 08 5d 7b f8 83 00 00 02 00'.replace(' ', ''))

(please note that our line should not have any spaces)

Output is very informative:

{ name: 'SYNCHRONIZE CACHE (10)',
fields:
[ { name: 'OPERATION CODE',
value: '35',
reserved: false,
obsolete: false },
{ name: 'Obsolete', value: '0', reserved: false, obsolete: true },
{ name: 'IMMED', value: '0', reserved: false, obsolete: false },
{ name: 'Obsolete', value: '0', reserved: false, obsolete: true },
{ name: 'Reserved', value: '0', reserved: true, obsolete: false },
{ name: 'LOGICAL BLOCK ADDRESS',
value: '0',
reserved: false,
obsolete: false },
{ name: 'GROUP NUMBER',
value: '0',
reserved: false,
obsolete: false },
{ name: 'Reserved', value: '0', reserved: false, obsolete: false },
{ name: 'NUMBER OF LOGICAL BLOCKS',
value: '0',
reserved: false,
obsolete: false },
{ name: 'CONTROL', value: '0', reserved: false, obsolete: false } ],
truncated: false }

Problem solved. Mostly. Now I just need to perform one Ceph write and cut only related commands from dmesg and decode those and than write a precise complain about SSDs to the vendor.

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.