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 20:25:56 -0400 |
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 @@ | |||
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 | |||
42 | int 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 | } | ||
169 | EXPORT_SYMBOL(spc_parse_cdb); | ||