2010-04-01 15:41:40 +04:00
/*
* Copyright ( C ) 2010 FUJITSU LIMITED
* Copyright ( C ) 2010 Tomohiro Kusumi < kusumi . tomohiro @ jp . fujitsu . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <linux/kernel.h>
# include <linux/trace_seq.h>
# include <trace/events/scsi.h>
2010-03-23 08:16:57 +03:00
# define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
# define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
2010-04-01 15:41:40 +04:00
static const char *
scsi_trace_misc ( struct trace_seq * , unsigned char * , int ) ;
static const char *
scsi_trace_rw6 ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len ;
sector_t lba = 0 , txlen = 0 ;
lba | = ( ( cdb [ 1 ] & 0x1F ) < < 16 ) ;
lba | = ( cdb [ 2 ] < < 8 ) ;
lba | = cdb [ 3 ] ;
txlen = cdb [ 4 ] ;
trace_seq_printf ( p , " lba=%llu txlen=%llu " ,
( unsigned long long ) lba , ( unsigned long long ) txlen ) ;
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_rw10 ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len ;
sector_t lba = 0 , txlen = 0 ;
lba | = ( cdb [ 2 ] < < 24 ) ;
lba | = ( cdb [ 3 ] < < 16 ) ;
lba | = ( cdb [ 4 ] < < 8 ) ;
lba | = cdb [ 5 ] ;
txlen | = ( cdb [ 7 ] < < 8 ) ;
txlen | = cdb [ 8 ] ;
2010-03-23 08:16:57 +03:00
trace_seq_printf ( p , " lba=%llu txlen=%llu protect=%u " ,
( unsigned long long ) lba , ( unsigned long long ) txlen ,
cdb [ 1 ] > > 5 ) ;
2010-04-01 15:41:40 +04:00
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_rw12 ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len ;
sector_t lba = 0 , txlen = 0 ;
lba | = ( cdb [ 2 ] < < 24 ) ;
lba | = ( cdb [ 3 ] < < 16 ) ;
lba | = ( cdb [ 4 ] < < 8 ) ;
lba | = cdb [ 5 ] ;
txlen | = ( cdb [ 6 ] < < 24 ) ;
txlen | = ( cdb [ 7 ] < < 16 ) ;
txlen | = ( cdb [ 8 ] < < 8 ) ;
txlen | = cdb [ 9 ] ;
2010-03-23 08:16:57 +03:00
trace_seq_printf ( p , " lba=%llu txlen=%llu protect=%u " ,
( unsigned long long ) lba , ( unsigned long long ) txlen ,
cdb [ 1 ] > > 5 ) ;
2010-04-01 15:41:40 +04:00
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_rw16 ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len ;
sector_t lba = 0 , txlen = 0 ;
lba | = ( ( u64 ) cdb [ 2 ] < < 56 ) ;
lba | = ( ( u64 ) cdb [ 3 ] < < 48 ) ;
lba | = ( ( u64 ) cdb [ 4 ] < < 40 ) ;
lba | = ( ( u64 ) cdb [ 5 ] < < 32 ) ;
lba | = ( cdb [ 6 ] < < 24 ) ;
lba | = ( cdb [ 7 ] < < 16 ) ;
lba | = ( cdb [ 8 ] < < 8 ) ;
lba | = cdb [ 9 ] ;
txlen | = ( cdb [ 10 ] < < 24 ) ;
txlen | = ( cdb [ 11 ] < < 16 ) ;
txlen | = ( cdb [ 12 ] < < 8 ) ;
txlen | = cdb [ 13 ] ;
2010-03-23 08:16:57 +03:00
trace_seq_printf ( p , " lba=%llu txlen=%llu protect=%u " ,
( unsigned long long ) lba , ( unsigned long long ) txlen ,
cdb [ 1 ] > > 5 ) ;
if ( cdb [ 0 ] = = WRITE_SAME_16 )
trace_seq_printf ( p , " unmap=%u " , cdb [ 1 ] > > 3 & 1 ) ;
2010-04-01 15:41:40 +04:00
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_rw32 ( struct trace_seq * p , unsigned char * cdb , int len )
{
2010-03-23 08:16:57 +03:00
const char * ret = p - > buffer + p - > len , * cmd ;
2010-04-01 15:41:40 +04:00
sector_t lba = 0 , txlen = 0 ;
2010-03-23 08:16:57 +03:00
u32 ei_lbrt = 0 ;
switch ( SERVICE_ACTION32 ( cdb ) ) {
case READ_32 :
cmd = " READ " ;
break ;
case VERIFY_32 :
cmd = " VERIFY " ;
break ;
case WRITE_32 :
cmd = " WRITE " ;
break ;
case WRITE_SAME_32 :
cmd = " WRITE_SAME " ;
break ;
default :
trace_seq_printf ( p , " UNKNOWN " ) ;
goto out ;
}
2010-04-01 15:41:40 +04:00
lba | = ( ( u64 ) cdb [ 12 ] < < 56 ) ;
lba | = ( ( u64 ) cdb [ 13 ] < < 48 ) ;
lba | = ( ( u64 ) cdb [ 14 ] < < 40 ) ;
lba | = ( ( u64 ) cdb [ 15 ] < < 32 ) ;
lba | = ( cdb [ 16 ] < < 24 ) ;
lba | = ( cdb [ 17 ] < < 16 ) ;
lba | = ( cdb [ 18 ] < < 8 ) ;
lba | = cdb [ 19 ] ;
2010-03-23 08:16:57 +03:00
ei_lbrt | = ( cdb [ 20 ] < < 24 ) ;
ei_lbrt | = ( cdb [ 21 ] < < 16 ) ;
ei_lbrt | = ( cdb [ 22 ] < < 8 ) ;
ei_lbrt | = cdb [ 23 ] ;
2010-04-01 15:41:40 +04:00
txlen | = ( cdb [ 28 ] < < 24 ) ;
txlen | = ( cdb [ 29 ] < < 16 ) ;
txlen | = ( cdb [ 30 ] < < 8 ) ;
txlen | = cdb [ 31 ] ;
2010-03-23 08:16:57 +03:00
trace_seq_printf ( p , " %s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u " ,
cmd , ( unsigned long long ) lba ,
( unsigned long long ) txlen , cdb [ 10 ] > > 5 , ei_lbrt ) ;
if ( SERVICE_ACTION32 ( cdb ) = = WRITE_SAME_32 )
trace_seq_printf ( p , " unmap=%u " , cdb [ 10 ] > > 3 & 1 ) ;
out :
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_unmap ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len ;
unsigned int regions = cdb [ 7 ] < < 8 | cdb [ 8 ] ;
trace_seq_printf ( p , " regions=%u " , ( regions - 8 ) / 16 ) ;
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_service_action_in ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len , * cmd ;
sector_t lba = 0 ;
u32 alloc_len = 0 ;
switch ( SERVICE_ACTION16 ( cdb ) ) {
case SAI_READ_CAPACITY_16 :
cmd = " READ_CAPACITY_16 " ;
break ;
case SAI_GET_LBA_STATUS :
cmd = " GET_LBA_STATUS " ;
break ;
default :
trace_seq_printf ( p , " UNKNOWN " ) ;
goto out ;
}
lba | = ( ( u64 ) cdb [ 2 ] < < 56 ) ;
lba | = ( ( u64 ) cdb [ 3 ] < < 48 ) ;
lba | = ( ( u64 ) cdb [ 4 ] < < 40 ) ;
lba | = ( ( u64 ) cdb [ 5 ] < < 32 ) ;
lba | = ( cdb [ 6 ] < < 24 ) ;
lba | = ( cdb [ 7 ] < < 16 ) ;
lba | = ( cdb [ 8 ] < < 8 ) ;
lba | = cdb [ 9 ] ;
alloc_len | = ( cdb [ 10 ] < < 24 ) ;
alloc_len | = ( cdb [ 11 ] < < 16 ) ;
alloc_len | = ( cdb [ 12 ] < < 8 ) ;
alloc_len | = cdb [ 13 ] ;
trace_seq_printf ( p , " %s lba=%llu alloc_len=%u " , cmd ,
( unsigned long long ) lba , alloc_len ) ;
2010-04-01 15:41:40 +04:00
2010-03-23 08:16:57 +03:00
out :
2010-04-01 15:41:40 +04:00
trace_seq_putc ( p , 0 ) ;
return ret ;
}
static const char *
scsi_trace_varlen ( struct trace_seq * p , unsigned char * cdb , int len )
{
2010-03-23 08:16:57 +03:00
switch ( SERVICE_ACTION32 ( cdb ) ) {
2010-04-01 15:41:40 +04:00
case READ_32 :
2010-03-23 08:16:57 +03:00
case VERIFY_32 :
2010-04-01 15:41:40 +04:00
case WRITE_32 :
2010-03-23 08:16:57 +03:00
case WRITE_SAME_32 :
2010-04-01 15:41:40 +04:00
return scsi_trace_rw32 ( p , cdb , len ) ;
default :
return scsi_trace_misc ( p , cdb , len ) ;
}
}
static const char *
scsi_trace_misc ( struct trace_seq * p , unsigned char * cdb , int len )
{
const char * ret = p - > buffer + p - > len ;
trace_seq_printf ( p , " - " ) ;
trace_seq_putc ( p , 0 ) ;
return ret ;
}
const char *
scsi_trace_parse_cdb ( struct trace_seq * p , unsigned char * cdb , int len )
{
switch ( cdb [ 0 ] ) {
case READ_6 :
case WRITE_6 :
return scsi_trace_rw6 ( p , cdb , len ) ;
case READ_10 :
2010-03-23 08:16:57 +03:00
case VERIFY :
2010-04-01 15:41:40 +04:00
case WRITE_10 :
2010-03-23 08:16:57 +03:00
case WRITE_SAME :
2010-04-01 15:41:40 +04:00
return scsi_trace_rw10 ( p , cdb , len ) ;
case READ_12 :
2010-03-23 08:16:57 +03:00
case VERIFY_12 :
2010-04-01 15:41:40 +04:00
case WRITE_12 :
return scsi_trace_rw12 ( p , cdb , len ) ;
case READ_16 :
2010-03-23 08:16:57 +03:00
case VERIFY_16 :
2010-04-01 15:41:40 +04:00
case WRITE_16 :
2010-03-23 08:16:57 +03:00
case WRITE_SAME_16 :
2010-04-01 15:41:40 +04:00
return scsi_trace_rw16 ( p , cdb , len ) ;
2010-03-23 08:16:57 +03:00
case UNMAP :
return scsi_trace_unmap ( p , cdb , len ) ;
case SERVICE_ACTION_IN :
return scsi_trace_service_action_in ( p , cdb , len ) ;
2010-04-01 15:41:40 +04:00
case VARIABLE_LENGTH_CMD :
return scsi_trace_varlen ( p , cdb , len ) ;
default :
return scsi_trace_misc ( p , cdb , len ) ;
}
}