diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 61648d84fbb6c8eb93c92f7a63a44971cf71415c..70cab2a138d1b791eb03a744b8ac6a850eab0e5a 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -10,6 +10,7 @@ target_core_mod-y := target_core_configfs.o \ target_core_tpg.o \ target_core_transport.o \ target_core_cdb.o \ + target_core_spc.o \ target_core_ua.o \ target_core_rd.o \ target_core_stat.o diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 165e82429687a49978c368598e20851ec91df0ae..6bbf18dc9e0de41d6288167330c6fab497a8e54e 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -96,6 +96,9 @@ int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun); int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); +/* target_core_spc.c */ +int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough); + /* target_core_transport.c */ extern struct kmem_cache *se_tmr_req_cache; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c new file mode 100644 index 0000000000000000000000000000000000000000..ec2108667d658c15373e8ea6e9b9a64d16fb6eac --- /dev/null +++ b/drivers/target/target_core_spc.c @@ -0,0 +1,169 @@ +/* + * 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 + * + * 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 +#include +#include + +#include +#include + +#include +#include +#include + +#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: + 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); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 23657a02766601ec3cce36968676f4c9a100635b..a8a3d1544e65282bdf39743135cba0e0fdcb1a58 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2658,26 +2658,8 @@ static int transport_generic_cmd_sequencer( size = (cdb[8] << 8) + cdb[9]; } break; - 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 GPCMD_READ_BUFFER_CAPACITY: case GPCMD_SEND_OPC: - case LOG_SELECT: - case LOG_SENSE: size = (cdb[7] << 8) + cdb[8]; break; case READ_BLOCK_LIMITS: @@ -2689,16 +2671,6 @@ static int transport_generic_cmd_sequencer( case GPCMD_READ_TRACK_RZONE_INFO: 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 GPCMD_MECHANISM_STATUS: case GPCMD_READ_DVD_STRUCTURE: size = (cdb[8] << 8) + cdb[9]; @@ -2725,17 +2697,6 @@ static int transport_generic_cmd_sequencer( size = (cdb[8] << 8) + cdb[9]; } 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 READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; break; @@ -2745,10 +2706,6 @@ static int transport_generic_cmd_sequencer( cmd->execute_cmd = target_emulate_readcapacity; break; case READ_MEDIA_SERIAL_NUMBER: - case SECURITY_PROTOCOL_IN: - case SECURITY_PROTOCOL_OUT: - size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - break; case SERVICE_ACTION_IN: switch (cmd->t_task_cdb[1] & 0x1f) { case SAI_READ_CAPACITY_16: @@ -2767,17 +2724,9 @@ static int transport_generic_cmd_sequencer( /*FALLTHROUGH*/ case ACCESS_CONTROL_IN: case ACCESS_CONTROL_OUT: - 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; /* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ #if 0 case GPCMD_READ_CD: @@ -2788,52 +2737,9 @@ static int transport_generic_cmd_sequencer( case READ_TOC: size = cdb[8]; break; - case REQUEST_SENSE: - size = cdb[4]; - if (!passthrough) - cmd->execute_cmd = target_emulate_request_sense; - break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; break; - case WRITE_BUFFER: - size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; - 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 RELEASE: - case RELEASE_10: - /* - * The SPC-2 RELEASE does not contain a size in the SCSI CDB. - * Assume the passthrough or $FABRIC_MOD will tell us about it. - */ - 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 SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: /* @@ -2916,7 +2822,6 @@ static int transport_generic_cmd_sequencer( case SEEK_10: case SPACE: case START_STOP: - case TEST_UNIT_READY: case VERIFY: case WRITE_FILEMARKS: if (!passthrough) @@ -2928,16 +2833,6 @@ static int transport_generic_cmd_sequencer( case GPCMD_SET_SPEED: case MOVE_MEDIUM: 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 GET_EVENT_STATUS_NOTIFICATION: size = (cdb[7] << 8) | cdb[8]; break; @@ -2973,10 +2868,9 @@ static int transport_generic_cmd_sequencer( } break; default: - pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" - " 0x%02x, sending CHECK_CONDITION.\n", - cmd->se_tfo->get_fabric_name(), cdb[0]); - goto out_unsupported_cdb; + ret = spc_parse_cdb(cmd, &size, passthrough); + if (ret) + return ret; } ret = target_cmd_size_check(cmd, size);