aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_spc.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-05-20 11:59:13 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-07-16 20:25:56 -0400
commit88455ec4be02c395820b1ff57656b0844ec03ac3 (patch)
tree3f8a7feda6180fea2e0aa832014d743dee853441 /drivers/target/target_core_spc.c
parent9b3b804101db067c3889948f57031f852186ea11 (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.c169
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 @@
1/*
2 * SCSI Primary Commands (SPC) parsing and emulation.
3 *
4 * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
5 * Copyright (c) 2005, 2006, 2007 SBE, Inc.
6 * Copyright (c) 2007-2010 Rising Tide Systems
7 * Copyright (c) 2008-2010 Linux-iSCSI.org
8 *
9 * Nicholas A. Bellinger <nab@kernel.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <asm/unaligned.h>
29
30#include <scsi/scsi.h>
31#include <scsi/scsi_tcq.h>
32
33#include <target/target_core_base.h>
34#include <target/target_core_backend.h>
35#include <target/target_core_fabric.h>
36
37#include "target_core_internal.h"
38#include "target_core_pr.h"
39#include "target_core_ua.h"
40
41
42int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size, bool passthrough)
43{
44 struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
45 unsigned char *cdb = cmd->t_task_cdb;
46
47 switch (cdb[0]) {
48 case MODE_SELECT:
49 *size = cdb[4];
50 break;
51 case MODE_SELECT_10:
52 *size = (cdb[7] << 8) + cdb[8];
53 break;
54 case MODE_SENSE:
55 *size = cdb[4];
56 if (!passthrough)
57 cmd->execute_cmd = target_emulate_modesense;
58 break;
59 case MODE_SENSE_10:
60 *size = (cdb[7] << 8) + cdb[8];
61 if (!passthrough)
62 cmd->execute_cmd = target_emulate_modesense;
63 break;
64 case LOG_SELECT:
65 case LOG_SENSE:
66 *size = (cdb[7] << 8) + cdb[8];
67 break;
68 case PERSISTENT_RESERVE_IN:
69 if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
70 cmd->execute_cmd = target_scsi3_emulate_pr_in;
71 *size = (cdb[7] << 8) + cdb[8];
72 break;
73 case PERSISTENT_RESERVE_OUT:
74 if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
75 cmd->execute_cmd = target_scsi3_emulate_pr_out;
76 *size = (cdb[7] << 8) + cdb[8];
77 break;
78 case RELEASE:
79 case RELEASE_10:
80 if (cdb[0] == RELEASE_10)
81 *size = (cdb[7] << 8) | cdb[8];
82 else
83 *size = cmd->data_length;
84
85 if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
86 cmd->execute_cmd = target_scsi2_reservation_release;
87 break;
88 case RESERVE:
89 case RESERVE_10:
90 /*
91 * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
92 * Assume the passthrough or $FABRIC_MOD will tell us about it.
93 */
94 if (cdb[0] == RESERVE_10)
95 *size = (cdb[7] << 8) | cdb[8];
96 else
97 *size = cmd->data_length;
98
99 /*
100 * Setup the legacy emulated handler for SPC-2 and
101 * >= SPC-3 compatible reservation handling (CRH=1)
102 * Otherwise, we assume the underlying SCSI logic is
103 * is running in SPC_PASSTHROUGH, and wants reservations
104 * emulation disabled.
105 */
106 if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
107 cmd->execute_cmd = target_scsi2_reservation_reserve;
108 break;
109 case REQUEST_SENSE:
110 *size = cdb[4];
111 if (!passthrough)
112 cmd->execute_cmd = target_emulate_request_sense;
113 break;
114 case INQUIRY:
115 *size = (cdb[3] << 8) + cdb[4];
116
117 /*
118 * Do implict HEAD_OF_QUEUE processing for INQUIRY.
119 * See spc4r17 section 5.3
120 */
121 if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
122 cmd->sam_task_attr = MSG_HEAD_TAG;
123 if (!passthrough)
124 cmd->execute_cmd = target_emulate_inquiry;
125 break;
126 case SECURITY_PROTOCOL_IN:
127 case SECURITY_PROTOCOL_OUT:
128 *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
129 break;
130 case EXTENDED_COPY:
131 case READ_ATTRIBUTE:
132 case RECEIVE_COPY_RESULTS:
133 case WRITE_ATTRIBUTE:
134 *size = (cdb[10] << 24) | (cdb[11] << 16) |
135 (cdb[12] << 8) | cdb[13];
136 break;
137 case RECEIVE_DIAGNOSTIC:
138 case SEND_DIAGNOSTIC:
139 *size = (cdb[3] << 8) | cdb[4];
140 break;
141 case WRITE_BUFFER:
142 *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
143 break;
144 case REPORT_LUNS:
145 cmd->execute_cmd = target_report_luns;
146 *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
147 /*
148 * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
149 * See spc4r17 section 5.3
150 */
151 if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
152 cmd->sam_task_attr = MSG_HEAD_TAG;
153 break;
154 case TEST_UNIT_READY:
155 if (!passthrough)
156 cmd->execute_cmd = target_emulate_noop;
157 break;
158 default:
159 pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
160 " 0x%02x, sending CHECK_CONDITION.\n",
161 cmd->se_tfo->get_fabric_name(), cdb[0]);
162 cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
163 cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
164 return -EINVAL;
165 }
166
167 return 0;
168}
169EXPORT_SYMBOL(spc_parse_cdb);