diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-11-03 17:50:40 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-11-04 04:00:08 -0400 |
commit | eacac00ce5bfde8086cd0615fb53c986f7f970fe (patch) | |
tree | e58c10a9f55b3704f1eed16eb3e5cfc5038336eb /drivers/target | |
parent | a17f091d1a7c570804cfc2c77701634da88f8ecf (diff) |
target: split core_scsi2_emulate_crh
Split core_scsi2_emulate_crh into one routine each for the reserve and
release side. The common code now is in a helper called by both
routines.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_pr.c | 189 | ||||
-rw-r--r-- | drivers/target/target_core_pr.h | 3 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 16 |
3 files changed, 102 insertions, 106 deletions
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 0c4f783f924c..830953a743d6 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -116,14 +116,99 @@ static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) | |||
116 | return ret; | 116 | return ret; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int core_scsi2_reservation_release(struct se_cmd *cmd) | 119 | static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, |
120 | struct se_node_acl *, struct se_session *); | ||
121 | static void core_scsi3_put_pr_reg(struct t10_pr_registration *); | ||
122 | |||
123 | static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) | ||
124 | { | ||
125 | struct se_session *se_sess = cmd->se_sess; | ||
126 | struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; | ||
127 | struct t10_pr_registration *pr_reg; | ||
128 | struct t10_reservation *pr_tmpl = &su_dev->t10_pr; | ||
129 | int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); | ||
130 | int conflict = 0; | ||
131 | |||
132 | if (!crh) | ||
133 | return false; | ||
134 | |||
135 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, | ||
136 | se_sess); | ||
137 | if (pr_reg) { | ||
138 | /* | ||
139 | * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE | ||
140 | * behavior | ||
141 | * | ||
142 | * A RESERVE(6) or RESERVE(10) command shall complete with GOOD | ||
143 | * status, but no reservation shall be established and the | ||
144 | * persistent reservation shall not be changed, if the command | ||
145 | * is received from a) and b) below. | ||
146 | * | ||
147 | * A RELEASE(6) or RELEASE(10) command shall complete with GOOD | ||
148 | * status, but the persistent reservation shall not be released, | ||
149 | * if the command is received from a) and b) | ||
150 | * | ||
151 | * a) An I_T nexus that is a persistent reservation holder; or | ||
152 | * b) An I_T nexus that is registered if a registrants only or | ||
153 | * all registrants type persistent reservation is present. | ||
154 | * | ||
155 | * In all other cases, a RESERVE(6) command, RESERVE(10) command, | ||
156 | * RELEASE(6) command, or RELEASE(10) command shall be processed | ||
157 | * as defined in SPC-2. | ||
158 | */ | ||
159 | if (pr_reg->pr_res_holder) { | ||
160 | core_scsi3_put_pr_reg(pr_reg); | ||
161 | *ret = 0; | ||
162 | return false; | ||
163 | } | ||
164 | if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || | ||
165 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || | ||
166 | (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | ||
167 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { | ||
168 | core_scsi3_put_pr_reg(pr_reg); | ||
169 | *ret = 0; | ||
170 | return true; | ||
171 | } | ||
172 | core_scsi3_put_pr_reg(pr_reg); | ||
173 | conflict = 1; | ||
174 | } else { | ||
175 | /* | ||
176 | * Following spc2r20 5.5.1 Reservations overview: | ||
177 | * | ||
178 | * If a logical unit has executed a PERSISTENT RESERVE OUT | ||
179 | * command with the REGISTER or the REGISTER AND IGNORE | ||
180 | * EXISTING KEY service action and is still registered by any | ||
181 | * initiator, all RESERVE commands and all RELEASE commands | ||
182 | * regardless of initiator shall conflict and shall terminate | ||
183 | * with a RESERVATION CONFLICT status. | ||
184 | */ | ||
185 | spin_lock(&pr_tmpl->registration_lock); | ||
186 | conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; | ||
187 | spin_unlock(&pr_tmpl->registration_lock); | ||
188 | } | ||
189 | |||
190 | if (conflict) { | ||
191 | pr_err("Received legacy SPC-2 RESERVE/RELEASE" | ||
192 | " while active SPC-3 registrations exist," | ||
193 | " returning RESERVATION_CONFLICT\n"); | ||
194 | *ret = PYX_TRANSPORT_RESERVATION_CONFLICT; | ||
195 | return true; | ||
196 | } | ||
197 | |||
198 | return false; | ||
199 | } | ||
200 | |||
201 | int target_scsi2_reservation_release(struct se_cmd *cmd) | ||
120 | { | 202 | { |
121 | struct se_device *dev = cmd->se_dev; | 203 | struct se_device *dev = cmd->se_dev; |
122 | struct se_session *sess = cmd->se_sess; | 204 | struct se_session *sess = cmd->se_sess; |
123 | struct se_portal_group *tpg = sess->se_tpg; | 205 | struct se_portal_group *tpg = sess->se_tpg; |
206 | int ret; | ||
124 | 207 | ||
125 | if (!sess || !tpg) | 208 | if (!sess || !tpg) |
126 | return 0; | 209 | return 0; |
210 | if (target_check_scsi2_reservation_conflict(cmd, &ret)) | ||
211 | return ret; | ||
127 | 212 | ||
128 | spin_lock(&dev->dev_reservation_lock); | 213 | spin_lock(&dev->dev_reservation_lock); |
129 | if (!dev->dev_reserved_node_acl || !sess) { | 214 | if (!dev->dev_reserved_node_acl || !sess) { |
@@ -150,11 +235,12 @@ static int core_scsi2_reservation_release(struct se_cmd *cmd) | |||
150 | return 0; | 235 | return 0; |
151 | } | 236 | } |
152 | 237 | ||
153 | static int core_scsi2_reservation_reserve(struct se_cmd *cmd) | 238 | int target_scsi2_reservation_reserve(struct se_cmd *cmd) |
154 | { | 239 | { |
155 | struct se_device *dev = cmd->se_dev; | 240 | struct se_device *dev = cmd->se_dev; |
156 | struct se_session *sess = cmd->se_sess; | 241 | struct se_session *sess = cmd->se_sess; |
157 | struct se_portal_group *tpg = sess->se_tpg; | 242 | struct se_portal_group *tpg = sess->se_tpg; |
243 | int ret; | ||
158 | 244 | ||
159 | if ((cmd->t_task_cdb[1] & 0x01) && | 245 | if ((cmd->t_task_cdb[1] & 0x01) && |
160 | (cmd->t_task_cdb[1] & 0x02)) { | 246 | (cmd->t_task_cdb[1] & 0x02)) { |
@@ -168,6 +254,8 @@ static int core_scsi2_reservation_reserve(struct se_cmd *cmd) | |||
168 | */ | 254 | */ |
169 | if (!sess || !tpg) | 255 | if (!sess || !tpg) |
170 | return 0; | 256 | return 0; |
257 | if (target_check_scsi2_reservation_conflict(cmd, &ret)) | ||
258 | return ret; | ||
171 | 259 | ||
172 | spin_lock(&dev->dev_reservation_lock); | 260 | spin_lock(&dev->dev_reservation_lock); |
173 | if (dev->dev_reserved_node_acl && | 261 | if (dev->dev_reserved_node_acl && |
@@ -200,99 +288,6 @@ static int core_scsi2_reservation_reserve(struct se_cmd *cmd) | |||
200 | return 0; | 288 | return 0; |
201 | } | 289 | } |
202 | 290 | ||
203 | static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, | ||
204 | struct se_node_acl *, struct se_session *); | ||
205 | static void core_scsi3_put_pr_reg(struct t10_pr_registration *); | ||
206 | |||
207 | /* | ||
208 | * Setup in target_core_transport.c:transport_generic_cmd_sequencer() | ||
209 | * and called via struct se_cmd->transport_emulate_cdb() in TCM processing | ||
210 | * thread context. | ||
211 | */ | ||
212 | int core_scsi2_emulate_crh(struct se_cmd *cmd) | ||
213 | { | ||
214 | struct se_session *se_sess = cmd->se_sess; | ||
215 | struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; | ||
216 | struct t10_pr_registration *pr_reg; | ||
217 | struct t10_reservation *pr_tmpl = &su_dev->t10_pr; | ||
218 | unsigned char *cdb = &cmd->t_task_cdb[0]; | ||
219 | int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS); | ||
220 | int conflict = 0; | ||
221 | |||
222 | if (!se_sess) | ||
223 | return 0; | ||
224 | |||
225 | if (!crh) | ||
226 | goto after_crh; | ||
227 | |||
228 | pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, | ||
229 | se_sess); | ||
230 | if (pr_reg) { | ||
231 | /* | ||
232 | * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE | ||
233 | * behavior | ||
234 | * | ||
235 | * A RESERVE(6) or RESERVE(10) command shall complete with GOOD | ||
236 | * status, but no reservation shall be established and the | ||
237 | * persistent reservation shall not be changed, if the command | ||
238 | * is received from a) and b) below. | ||
239 | * | ||
240 | * A RELEASE(6) or RELEASE(10) command shall complete with GOOD | ||
241 | * status, but the persistent reservation shall not be released, | ||
242 | * if the command is received from a) and b) | ||
243 | * | ||
244 | * a) An I_T nexus that is a persistent reservation holder; or | ||
245 | * b) An I_T nexus that is registered if a registrants only or | ||
246 | * all registrants type persistent reservation is present. | ||
247 | * | ||
248 | * In all other cases, a RESERVE(6) command, RESERVE(10) command, | ||
249 | * RELEASE(6) command, or RELEASE(10) command shall be processed | ||
250 | * as defined in SPC-2. | ||
251 | */ | ||
252 | if (pr_reg->pr_res_holder) { | ||
253 | core_scsi3_put_pr_reg(pr_reg); | ||
254 | return 0; | ||
255 | } | ||
256 | if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || | ||
257 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || | ||
258 | (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | ||
259 | (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { | ||
260 | core_scsi3_put_pr_reg(pr_reg); | ||
261 | return 0; | ||
262 | } | ||
263 | core_scsi3_put_pr_reg(pr_reg); | ||
264 | conflict = 1; | ||
265 | } else { | ||
266 | /* | ||
267 | * Following spc2r20 5.5.1 Reservations overview: | ||
268 | * | ||
269 | * If a logical unit has executed a PERSISTENT RESERVE OUT | ||
270 | * command with the REGISTER or the REGISTER AND IGNORE | ||
271 | * EXISTING KEY service action and is still registered by any | ||
272 | * initiator, all RESERVE commands and all RELEASE commands | ||
273 | * regardless of initiator shall conflict and shall terminate | ||
274 | * with a RESERVATION CONFLICT status. | ||
275 | */ | ||
276 | spin_lock(&pr_tmpl->registration_lock); | ||
277 | conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; | ||
278 | spin_unlock(&pr_tmpl->registration_lock); | ||
279 | } | ||
280 | |||
281 | if (conflict) { | ||
282 | pr_err("Received legacy SPC-2 RESERVE/RELEASE" | ||
283 | " while active SPC-3 registrations exist," | ||
284 | " returning RESERVATION_CONFLICT\n"); | ||
285 | return PYX_TRANSPORT_RESERVATION_CONFLICT; | ||
286 | } | ||
287 | |||
288 | after_crh: | ||
289 | if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10)) | ||
290 | return core_scsi2_reservation_reserve(cmd); | ||
291 | else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10)) | ||
292 | return core_scsi2_reservation_release(cmd); | ||
293 | else | ||
294 | return PYX_TRANSPORT_INVALID_CDB_FIELD; | ||
295 | } | ||
296 | 291 | ||
297 | /* | 292 | /* |
298 | * Begin SPC-3/SPC-4 Persistent Reservations emulation support | 293 | * Begin SPC-3/SPC-4 Persistent Reservations emulation support |
@@ -418,12 +413,12 @@ static int core_scsi3_pr_seq_non_holder( | |||
418 | break; | 413 | break; |
419 | case RELEASE: | 414 | case RELEASE: |
420 | case RELEASE_10: | 415 | case RELEASE_10: |
421 | /* Handled by CRH=1 in core_scsi2_emulate_crh() */ | 416 | /* Handled by CRH=1 in target_scsi2_reservation_release() */ |
422 | ret = 0; | 417 | ret = 0; |
423 | break; | 418 | break; |
424 | case RESERVE: | 419 | case RESERVE: |
425 | case RESERVE_10: | 420 | case RESERVE_10: |
426 | /* Handled by CRH=1 in core_scsi2_emulate_crh() */ | 421 | /* Handled by CRH=1 in target_scsi2_reservation_reserve() */ |
427 | ret = 0; | 422 | ret = 0; |
428 | break; | 423 | break; |
429 | case TEST_UNIT_READY: | 424 | case TEST_UNIT_READY: |
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index c8f47d064584..4e94a427e314 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h | |||
@@ -47,7 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; | |||
47 | 47 | ||
48 | extern int core_pr_dump_initiator_port(struct t10_pr_registration *, | 48 | extern int core_pr_dump_initiator_port(struct t10_pr_registration *, |
49 | char *, u32); | 49 | char *, u32); |
50 | extern int core_scsi2_emulate_crh(struct se_cmd *); | 50 | extern int target_scsi2_reservation_release(struct se_cmd *cmd); |
51 | extern int target_scsi2_reservation_reserve(struct se_cmd *cmd); | ||
51 | extern int core_scsi3_alloc_aptpl_registration( | 52 | extern int core_scsi3_alloc_aptpl_registration( |
52 | struct t10_reservation *, u64, | 53 | struct t10_reservation *, u64, |
53 | unsigned char *, unsigned char *, u32, | 54 | unsigned char *, unsigned char *, u32, |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e84b26ffb17b..f4232934bac5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -2963,10 +2963,10 @@ static int transport_generic_cmd_sequencer( | |||
2963 | * is running in SPC_PASSTHROUGH, and wants reservations | 2963 | * is running in SPC_PASSTHROUGH, and wants reservations |
2964 | * emulation disabled. | 2964 | * emulation disabled. |
2965 | */ | 2965 | */ |
2966 | cmd->transport_emulate_cdb = | 2966 | if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) { |
2967 | (su_dev->t10_pr.res_type != | 2967 | cmd->transport_emulate_cdb = |
2968 | SPC_PASSTHROUGH) ? | 2968 | target_scsi2_reservation_reserve; |
2969 | core_scsi2_emulate_crh : NULL; | 2969 | } |
2970 | cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; | 2970 | cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; |
2971 | break; | 2971 | break; |
2972 | case RELEASE: | 2972 | case RELEASE: |
@@ -2980,10 +2980,10 @@ static int transport_generic_cmd_sequencer( | |||
2980 | else | 2980 | else |
2981 | size = cmd->data_length; | 2981 | size = cmd->data_length; |
2982 | 2982 | ||
2983 | cmd->transport_emulate_cdb = | 2983 | if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) { |
2984 | (su_dev->t10_pr.res_type != | 2984 | cmd->transport_emulate_cdb = |
2985 | SPC_PASSTHROUGH) ? | 2985 | target_scsi2_reservation_release; |
2986 | core_scsi2_emulate_crh : NULL; | 2986 | } |
2987 | cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; | 2987 | cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; |
2988 | break; | 2988 | break; |
2989 | case SYNCHRONIZE_CACHE: | 2989 | case SYNCHRONIZE_CACHE: |