2012-05-20 19:59:13 +04:00
/*
* SCSI Primary Commands ( SPC ) parsing and emulation .
*
* Copyright ( c ) 2002 , 2003 , 2004 , 2005 PyX Technologies , Inc .
* Copyright ( c ) 2005 , 2006 , 2007 SBE , Inc .
* Copyright ( c ) 2007 - 2010 Rising Tide Systems
* Copyright ( c ) 2008 - 2010 Linux - iSCSI . org
*
* Nicholas A . Bellinger < nab @ kernel . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <asm/unaligned.h>
# include <scsi/scsi.h>
# include <scsi/scsi_tcq.h>
# include <target/target_core_base.h>
# include <target/target_core_backend.h>
# include <target/target_core_fabric.h>
# include "target_core_internal.h"
# include "target_core_pr.h"
# include "target_core_ua.h"
int spc_parse_cdb ( struct se_cmd * cmd , unsigned int * size , bool passthrough )
{
struct se_subsystem_dev * su_dev = cmd - > se_dev - > se_sub_dev ;
unsigned char * cdb = cmd - > t_task_cdb ;
switch ( cdb [ 0 ] ) {
case MODE_SELECT :
* size = cdb [ 4 ] ;
break ;
case MODE_SELECT_10 :
* size = ( cdb [ 7 ] < < 8 ) + cdb [ 8 ] ;
break ;
case MODE_SENSE :
* size = cdb [ 4 ] ;
if ( ! passthrough )
cmd - > execute_cmd = target_emulate_modesense ;
break ;
case MODE_SENSE_10 :
* size = ( cdb [ 7 ] < < 8 ) + cdb [ 8 ] ;
if ( ! passthrough )
cmd - > execute_cmd = target_emulate_modesense ;
break ;
case LOG_SELECT :
case LOG_SENSE :
* size = ( cdb [ 7 ] < < 8 ) + cdb [ 8 ] ;
break ;
case PERSISTENT_RESERVE_IN :
if ( su_dev - > t10_pr . res_type = = SPC3_PERSISTENT_RESERVATIONS )
cmd - > execute_cmd = target_scsi3_emulate_pr_in ;
* size = ( cdb [ 7 ] < < 8 ) + cdb [ 8 ] ;
break ;
case PERSISTENT_RESERVE_OUT :
if ( su_dev - > t10_pr . res_type = = SPC3_PERSISTENT_RESERVATIONS )
cmd - > execute_cmd = target_scsi3_emulate_pr_out ;
* size = ( cdb [ 7 ] < < 8 ) + cdb [ 8 ] ;
break ;
case RELEASE :
case RELEASE_10 :
if ( cdb [ 0 ] = = RELEASE_10 )
* size = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
else
* size = cmd - > data_length ;
if ( su_dev - > t10_pr . res_type ! = SPC_PASSTHROUGH )
cmd - > execute_cmd = target_scsi2_reservation_release ;
break ;
case RESERVE :
case RESERVE_10 :
/*
* The SPC - 2 RESERVE does not contain a size in the SCSI CDB .
* Assume the passthrough or $ FABRIC_MOD will tell us about it .
*/
if ( cdb [ 0 ] = = RESERVE_10 )
* size = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
else
* size = cmd - > data_length ;
/*
* Setup the legacy emulated handler for SPC - 2 and
* > = SPC - 3 compatible reservation handling ( CRH = 1 )
* Otherwise , we assume the underlying SCSI logic is
* is running in SPC_PASSTHROUGH , and wants reservations
* emulation disabled .
*/
if ( su_dev - > t10_pr . res_type ! = SPC_PASSTHROUGH )
cmd - > execute_cmd = target_scsi2_reservation_reserve ;
break ;
case REQUEST_SENSE :
* size = cdb [ 4 ] ;
if ( ! passthrough )
cmd - > execute_cmd = target_emulate_request_sense ;
break ;
case INQUIRY :
* size = ( cdb [ 3 ] < < 8 ) + cdb [ 4 ] ;
/*
* Do implict HEAD_OF_QUEUE processing for INQUIRY .
* See spc4r17 section 5.3
*/
if ( cmd - > se_dev - > dev_task_attr_type = = SAM_TASK_ATTR_EMULATED )
cmd - > sam_task_attr = MSG_HEAD_TAG ;
if ( ! passthrough )
cmd - > execute_cmd = target_emulate_inquiry ;
break ;
case SECURITY_PROTOCOL_IN :
case SECURITY_PROTOCOL_OUT :
* size = ( cdb [ 6 ] < < 24 ) | ( cdb [ 7 ] < < 16 ) | ( cdb [ 8 ] < < 8 ) | cdb [ 9 ] ;
break ;
case EXTENDED_COPY :
case READ_ATTRIBUTE :
case RECEIVE_COPY_RESULTS :
case WRITE_ATTRIBUTE :
* size = ( cdb [ 10 ] < < 24 ) | ( cdb [ 11 ] < < 16 ) |
( cdb [ 12 ] < < 8 ) | cdb [ 13 ] ;
break ;
case RECEIVE_DIAGNOSTIC :
case SEND_DIAGNOSTIC :
* size = ( cdb [ 3 ] < < 8 ) | cdb [ 4 ] ;
break ;
case WRITE_BUFFER :
* size = ( cdb [ 6 ] < < 16 ) + ( cdb [ 7 ] < < 8 ) + cdb [ 8 ] ;
break ;
case REPORT_LUNS :
cmd - > execute_cmd = target_report_luns ;
* size = ( cdb [ 6 ] < < 24 ) | ( cdb [ 7 ] < < 16 ) | ( cdb [ 8 ] < < 8 ) | cdb [ 9 ] ;
/*
* Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
* See spc4r17 section 5.3
*/
if ( cmd - > se_dev - > dev_task_attr_type = = SAM_TASK_ATTR_EMULATED )
cmd - > sam_task_attr = MSG_HEAD_TAG ;
break ;
case TEST_UNIT_READY :
2012-05-20 19:59:14 +04:00
* size = 0 ;
2012-05-20 19:59:13 +04:00
if ( ! passthrough )
cmd - > execute_cmd = target_emulate_noop ;
break ;
default :
pr_warn ( " TARGET_CORE[%s]: Unsupported SCSI Opcode "
" 0x%02x, sending CHECK_CONDITION. \n " ,
cmd - > se_tfo - > get_fabric_name ( ) , cdb [ 0 ] ) ;
cmd - > se_cmd_flags | = SCF_SCSI_CDB_EXCEPTION ;
cmd - > scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE ;
return - EINVAL ;
}
return 0 ;
}
EXPORT_SYMBOL ( spc_parse_cdb ) ;