2017-01-08 03:01:03 +03:00
/*
* Copyright ( c ) 2015 Bart Van Assche < bart . vanassche @ sandisk . com >
* Copyright ( c ) 2015 - 2017 Dmitry V . Levin < ldv @ altlinux . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
# ifdef HAVE_LINUX_BSG_H
2017-07-14 06:59:13 +03:00
# include "print_fields.h"
2017-01-08 03:01:03 +03:00
# include <linux / bsg.h>
# include "xlat / bsg_protocol.h"
# include "xlat / bsg_subprotocol.h"
2017-01-08 04:20:59 +03:00
# include "xlat / bsg_flags.h"
2017-01-08 03:01:03 +03:00
static void
print_sg_io_buffer ( struct tcb * const tcp , const kernel_ulong_t addr ,
2017-01-08 21:31:51 +03:00
const unsigned int data_size , const unsigned int iovec_count )
2017-01-08 03:01:03 +03:00
{
2017-01-08 21:31:51 +03:00
if ( iovec_count ) {
tprint_iov_upto ( tcp , iovec_count , addr , IOV_DECODE_STR ,
data_size ) ;
} else {
printstr_ex ( tcp , addr , data_size , QUOTE_FORCE_HEX ) ;
}
2017-01-08 03:01:03 +03:00
}
2017-07-14 06:59:13 +03:00
# define PRINT_FIELD_SG_IO_BUFFER(prefix_, where_, field_, size_, count_, tcp_) \
do { \
STRACE_PRINTF ( " %s%s= " , ( prefix_ ) , # field_ ) ; \
print_sg_io_buffer ( ( tcp_ ) , ( where_ ) . field_ , ( size_ ) , ( count_ ) ) ; \
} while ( 0 )
2017-01-08 03:01:03 +03:00
static int
decode_request ( struct tcb * const tcp , const kernel_ulong_t arg )
{
struct sg_io_v4 sg_io ;
static const size_t skip_iid = offsetof ( struct sg_io_v4 , protocol ) ;
tprints ( " {guard='Q', " ) ;
if ( umoven_or_printaddr ( tcp , arg + skip_iid , sizeof ( sg_io ) - skip_iid ,
& sg_io . protocol ) ) {
tprints ( " } " ) ;
2017-08-28 03:39:15 +03:00
return RVAL_IOCTL_DECODED ;
2017-01-08 03:01:03 +03:00
}
2017-07-14 06:59:13 +03:00
PRINT_FIELD_XVAL ( " " , sg_io , protocol , bsg_protocol , " BSG_PROTOCOL_??? " ) ;
PRINT_FIELD_XVAL ( " , " , sg_io , subprotocol , bsg_subprotocol ,
" BSG_SUB_PROTOCOL_??? " ) ;
PRINT_FIELD_U ( " , " , sg_io , request_len ) ;
PRINT_FIELD_SG_IO_BUFFER ( " , " , sg_io , request , sg_io . request_len ,
0 , tcp ) ;
PRINT_FIELD_X ( " , " , sg_io , request_tag ) ;
PRINT_FIELD_U ( " , " , sg_io , request_attr ) ;
PRINT_FIELD_U ( " , " , sg_io , request_priority ) ;
PRINT_FIELD_U ( " , " , sg_io , request_extra ) ;
PRINT_FIELD_U ( " , " , sg_io , max_response_len ) ;
PRINT_FIELD_U ( " , " , sg_io , dout_iovec_count ) ;
PRINT_FIELD_U ( " , " , sg_io , dout_xfer_len ) ;
PRINT_FIELD_U ( " , " , sg_io , din_iovec_count ) ;
PRINT_FIELD_U ( " , " , sg_io , din_xfer_len ) ;
PRINT_FIELD_SG_IO_BUFFER ( " , " , sg_io , dout_xferp , sg_io . dout_xfer_len ,
sg_io . dout_iovec_count , tcp ) ;
PRINT_FIELD_U ( " , " , sg_io , timeout ) ;
PRINT_FIELD_FLAGS ( " , " , sg_io , flags , bsg_flags , " BSG_FLAG_??? " ) ;
PRINT_FIELD_X ( " , " , sg_io , usr_ptr ) ;
2017-01-08 20:43:21 +03:00
struct sg_io_v4 * entering_sg_io = malloc ( sizeof ( * entering_sg_io ) ) ;
if ( entering_sg_io ) {
memcpy ( entering_sg_io , & sg_io , sizeof ( sg_io ) ) ;
entering_sg_io - > guard = ( unsigned char ) ' Q ' ;
set_tcb_priv_data ( tcp , entering_sg_io , free ) ;
}
2017-08-27 01:18:27 +03:00
return 0 ;
2017-01-08 03:01:03 +03:00
}
static int
decode_response ( struct tcb * const tcp , const kernel_ulong_t arg )
{
2017-01-08 20:43:21 +03:00
struct sg_io_v4 * entering_sg_io = get_tcb_priv_data ( tcp ) ;
2017-01-08 03:01:03 +03:00
struct sg_io_v4 sg_io ;
uint32_t din_len ;
if ( umove ( tcp , arg , & sg_io ) < 0 ) {
2017-01-08 20:43:21 +03:00
/* print i/o fields fetched on entering syscall */
2017-07-14 06:59:13 +03:00
PRINT_FIELD_X ( " , " , * entering_sg_io , response ) ;
PRINT_FIELD_X ( " , " , * entering_sg_io , din_xferp ) ;
2017-08-28 03:39:15 +03:00
return RVAL_IOCTL_DECODED ;
2017-01-08 03:01:03 +03:00
}
2017-01-08 20:43:21 +03:00
if ( sg_io . guard ! = entering_sg_io - > guard ) {
2017-07-14 06:59:13 +03:00
PRINT_FIELD_U ( " => " , sg_io , guard ) ;
2017-08-28 03:39:15 +03:00
return RVAL_IOCTL_DECODED ;
2017-01-08 03:01:03 +03:00
}
2017-07-14 06:59:13 +03:00
PRINT_FIELD_U ( " , " , sg_io , response_len ) ;
PRINT_FIELD_SG_IO_BUFFER ( " , " , sg_io , response , sg_io . response_len ,
0 , tcp ) ;
2017-01-08 03:01:03 +03:00
din_len = sg_io . din_xfer_len ;
2017-01-08 20:43:21 +03:00
if ( sg_io . din_resid > 0 & & ( unsigned int ) sg_io . din_resid < = din_len )
2017-01-08 03:01:03 +03:00
din_len - = sg_io . din_resid ;
2017-07-14 06:59:13 +03:00
PRINT_FIELD_SG_IO_BUFFER ( " , " , sg_io , din_xferp , din_len ,
sg_io . din_iovec_count , tcp ) ;
PRINT_FIELD_X ( " , " , sg_io , driver_status ) ;
PRINT_FIELD_X ( " , " , sg_io , transport_status ) ;
PRINT_FIELD_X ( " , " , sg_io , device_status ) ;
PRINT_FIELD_U ( " , " , sg_io , retry_delay ) ;
PRINT_FIELD_FLAGS ( " , " , sg_io , info , sg_io_info , " SG_INFO_??? " ) ;
PRINT_FIELD_U ( " , " , sg_io , duration ) ;
PRINT_FIELD_U ( " , " , sg_io , response_len ) ;
PRINT_FIELD_D ( " , " , sg_io , din_resid ) ;
PRINT_FIELD_D ( " , " , sg_io , dout_resid ) ;
PRINT_FIELD_X ( " , " , sg_io , generated_tag ) ;
2017-01-08 03:01:03 +03:00
2017-08-28 03:39:15 +03:00
return RVAL_IOCTL_DECODED ;
2017-01-08 03:01:03 +03:00
}
# else /* !HAVE_LINUX_BSG_H */
static int
decode_request ( struct tcb * const tcp , const kernel_ulong_t arg )
{
tprints ( " {guard='Q', ...} " ) ;
2017-08-28 03:39:15 +03:00
return RVAL_IOCTL_DECODED ;
2017-01-08 03:01:03 +03:00
}
static int
decode_response ( struct tcb * const tcp , const kernel_ulong_t arg )
{
return 0 ;
}
# endif
int
decode_sg_io_v4 ( struct tcb * const tcp , const kernel_ulong_t arg )
{
return entering ( tcp ) ? decode_request ( tcp , arg )
: decode_response ( tcp , arg ) ;
}