diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-05-20 11:59:13 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-07-16 17:25:56 -0700 |
commit | 88455ec4be02c395820b1ff57656b0844ec03ac3 (patch) | |
tree | 3f8a7feda6180fea2e0aa832014d743dee853441 /drivers/target/target_core_spc.c | |
parent | 9b3b804101db067c3889948f57031f852186ea11 (diff) |
target: split parsing of SPC commands into a separate helper
(nab: Add EXPORT_SYMBOL usage for spc_parse_cdb)
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_spc.c')
-rw-r--r-- | drivers/target/target_core_spc.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c new file mode 100644 index 000000000000..ec2108667d65 --- /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 <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: + 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); |