Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "scsi_internal.h"
7 : :
8 : : #include "spdk/endian.h"
9 : :
10 : : /* Get registrant by I_T nexus */
11 : : static struct spdk_scsi_pr_registrant *
12 : 505 : scsi_pr_get_registrant(struct spdk_scsi_lun *lun,
13 : : struct spdk_scsi_port *initiator_port,
14 : : struct spdk_scsi_port *target_port)
15 : : {
16 : : struct spdk_scsi_pr_registrant *reg, *tmp;
17 : :
18 [ + + ]: 850 : TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
19 [ + + ]: 685 : if (initiator_port == reg->initiator_port &&
20 [ + - ]: 340 : target_port == reg->target_port) {
21 : 340 : return reg;
22 : : }
23 : : }
24 : :
25 : 165 : return NULL;
26 : : }
27 : :
28 : : static bool
29 : 10 : scsi2_it_nexus_is_holder(struct spdk_scsi_lun *lun,
30 : : struct spdk_scsi_port *initiator_port,
31 : : struct spdk_scsi_port *target_port)
32 : : {
33 : 10 : struct spdk_scsi_pr_registrant *reg = lun->reservation.holder;
34 : :
35 [ - + ]: 10 : assert(reg != NULL);
36 : :
37 [ + + ]: 10 : if ((reg->initiator_port == initiator_port) &&
38 [ + - ]: 5 : (reg->target_port == target_port)) {
39 : 5 : return true;
40 : : }
41 : :
42 : 5 : return false;
43 : : }
44 : :
45 : : /* Reservation type is all registrants or not */
46 : : static inline bool
47 : 155 : scsi_pr_is_all_registrants_type(struct spdk_scsi_lun *lun)
48 : : {
49 [ + + ]: 290 : return (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS ||
50 [ - + ]: 135 : lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
51 : : }
52 : :
53 : : /* Registrant is reservation holder or not */
54 : : static inline bool
55 : 110 : scsi_pr_registrant_is_holder(struct spdk_scsi_lun *lun,
56 : : struct spdk_scsi_pr_registrant *reg)
57 : : {
58 [ + + ]: 110 : if (scsi_pr_is_all_registrants_type(lun)) {
59 : 10 : return true;
60 : : }
61 : :
62 : 100 : return (lun->reservation.holder == reg);
63 : : }
64 : :
65 : : /* LUN holds a reservation or not */
66 : : static inline bool
67 : 31026857 : scsi_pr_has_reservation(struct spdk_scsi_lun *lun)
68 : : {
69 : 31026857 : return !(lun->reservation.holder == NULL);
70 : : }
71 : :
72 : : static int
73 : 90 : scsi_pr_register_registrant(struct spdk_scsi_lun *lun,
74 : : struct spdk_scsi_port *initiator_port,
75 : : struct spdk_scsi_port *target_port,
76 : : uint64_t sa_rkey)
77 : : {
78 : : struct spdk_scsi_pr_registrant *reg;
79 : :
80 : : /* Register sa_rkey with the I_T nexus */
81 : 90 : reg = calloc(1, sizeof(*reg));
82 [ - + ]: 90 : if (!reg) {
83 : 0 : return -ENOMEM;
84 : : }
85 : :
86 [ - + - + ]: 90 : SPDK_DEBUGLOG(scsi, "REGISTER: new registrant registered "
87 : : "with key 0x%"PRIx64"\n", sa_rkey);
88 : :
89 : : /* New I_T nexus */
90 : 90 : reg->initiator_port = initiator_port;
91 [ + - ]: 90 : if (initiator_port) {
92 [ - + ]: 90 : snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s",
93 : 90 : initiator_port->name);
94 : 90 : reg->transport_id_len = initiator_port->transport_id_len;
95 [ - + - + ]: 90 : memcpy(reg->transport_id, initiator_port->transport_id, reg->transport_id_len);
96 : : }
97 : 90 : reg->target_port = target_port;
98 [ + - ]: 90 : if (target_port) {
99 [ - + ]: 90 : snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s",
100 : 90 : target_port->name);
101 : 90 : reg->relative_target_port_id = target_port->index;
102 : : }
103 : 90 : reg->rkey = sa_rkey;
104 : 90 : TAILQ_INSERT_TAIL(&lun->reg_head, reg, link);
105 : 90 : lun->pr_generation++;
106 : :
107 : 90 : return 0;
108 : : }
109 : :
110 : : static void
111 : 15 : scsi_pr_release_reservation(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg)
112 : : {
113 : 15 : bool all_regs = false;
114 : :
115 [ - + - + ]: 15 : SPDK_DEBUGLOG(scsi, "REGISTER: release reservation "
116 : : "with type %u\n", lun->reservation.rtype);
117 : :
118 : : /* TODO: Unit Attention */
119 : 15 : all_regs = scsi_pr_is_all_registrants_type(lun);
120 [ + + + - ]: 15 : if (all_regs && !TAILQ_EMPTY(&lun->reg_head)) {
121 : 5 : lun->reservation.holder = TAILQ_FIRST(&lun->reg_head);
122 : 5 : return;
123 : : }
124 : :
125 [ - + ]: 10 : memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
126 : : }
127 : :
128 : : static void
129 : 50 : scsi_pr_reserve_reservation(struct spdk_scsi_lun *lun,
130 : : enum spdk_scsi_pr_type_code type,
131 : : uint64_t rkey,
132 : : struct spdk_scsi_pr_registrant *holder)
133 : : {
134 : 50 : lun->reservation.rtype = type;
135 : 50 : lun->reservation.crkey = rkey;
136 : 50 : lun->reservation.holder = holder;
137 : 50 : }
138 : :
139 : : static void
140 : 30 : scsi_pr_unregister_registrant(struct spdk_scsi_lun *lun,
141 : : struct spdk_scsi_pr_registrant *reg)
142 : : {
143 [ - + - + ]: 30 : SPDK_DEBUGLOG(scsi, "REGISTER: unregister registrant\n");
144 : :
145 [ + + ]: 30 : TAILQ_REMOVE(&lun->reg_head, reg, link);
146 [ + + ]: 30 : if (scsi_pr_registrant_is_holder(lun, reg)) {
147 : 15 : scsi_pr_release_reservation(lun, reg);
148 : : }
149 : :
150 : 30 : free(reg);
151 : 30 : lun->pr_generation++;
152 : 30 : }
153 : :
154 : : static void
155 : 30 : scsi_pr_replace_registrant_key(struct spdk_scsi_lun *lun,
156 : : struct spdk_scsi_pr_registrant *reg,
157 : : uint64_t sa_rkey)
158 : : {
159 [ - + - + ]: 30 : SPDK_DEBUGLOG(scsi, "REGISTER: replace with new "
160 : : "reservation key 0x%"PRIx64"\n", sa_rkey);
161 : 30 : reg->rkey = sa_rkey;
162 : 30 : lun->pr_generation++;
163 : 30 : }
164 : :
165 : : static int
166 : 45 : scsi_pr_out_reserve(struct spdk_scsi_task *task,
167 : : enum spdk_scsi_pr_type_code rtype, uint64_t rkey,
168 : : uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl)
169 : : {
170 : 45 : struct spdk_scsi_lun *lun = task->lun;
171 : : struct spdk_scsi_pr_registrant *reg;
172 : :
173 [ - + - + ]: 45 : SPDK_DEBUGLOG(scsi, "PR OUT RESERVE: rkey 0x%"PRIx64", requested "
174 : : "reservation type %u, type %u\n", rkey, rtype, lun->reservation.rtype);
175 : :
176 : : /* TODO: don't support now */
177 [ + - + - : 45 : if (spec_i_pt || all_tg_pt || aptpl) {
- + ]
178 : 0 : SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt fields "
179 : : "or invalid aptpl field\n");
180 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
181 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
182 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
183 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
184 : 0 : return -EINVAL;
185 : : }
186 : :
187 : 45 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
188 : : /* No registration for the I_T nexus */
189 [ - + ]: 45 : if (!reg) {
190 : 0 : SPDK_ERRLOG("No registration\n");
191 : 0 : goto conflict;
192 : : }
193 : :
194 : : /* invalid reservation key */
195 [ - + ]: 45 : if (reg->rkey != rkey) {
196 : 0 : SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match 0x%"PRIx64"\n",
197 : : rkey, reg->rkey);
198 : 0 : goto conflict;
199 : : }
200 : :
201 : : /* reservation holder already exists */
202 [ + + ]: 45 : if (scsi_pr_has_reservation(lun)) {
203 [ + + ]: 15 : if (rtype != lun->reservation.rtype) {
204 : 5 : SPDK_ERRLOG("Reservation type doesn't match\n");
205 : 5 : goto conflict;
206 : : }
207 : :
208 [ + + ]: 10 : if (!scsi_pr_registrant_is_holder(lun, reg)) {
209 : 5 : SPDK_ERRLOG("Only 1 holder is allowed for type %u\n", rtype);
210 : 5 : goto conflict;
211 : : }
212 : : } else {
213 : : /* current I_T nexus is the first reservation holder */
214 : 30 : scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
215 : : }
216 : :
217 : 35 : return 0;
218 : :
219 : 10 : conflict:
220 : 10 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
221 : : SPDK_SCSI_SENSE_NO_SENSE,
222 : : SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
223 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
224 : 10 : return -EINVAL;
225 : : }
226 : :
227 : : static int
228 : 160 : scsi_pr_out_register(struct spdk_scsi_task *task,
229 : : enum spdk_scsi_pr_out_service_action_code action,
230 : : uint64_t rkey, uint64_t sa_rkey,
231 : : uint8_t spec_i_pt, uint8_t all_tg_pt, uint8_t aptpl)
232 : : {
233 : 160 : struct spdk_scsi_lun *lun = task->lun;
234 : : struct spdk_scsi_pr_registrant *reg;
235 : : int sc, sk, asc;
236 : :
237 [ - + - + ]: 160 : SPDK_DEBUGLOG(scsi, "PR OUT REGISTER: rkey 0x%"PRIx64", "
238 : : "sa_key 0x%"PRIx64", reservation type %u\n", rkey, sa_rkey, lun->reservation.rtype);
239 : :
240 : : /* TODO: don't support now */
241 [ + - + - : 160 : if (spec_i_pt || all_tg_pt || aptpl) {
- + ]
242 : 0 : SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt/aptpl field\n");
243 : 0 : sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
244 : 0 : sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
245 : 0 : asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
246 : 0 : goto error_exit;
247 : : }
248 : :
249 : 160 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
250 : : /* an unregistered I_T nexus session */
251 [ + + ]: 160 : if (!reg) {
252 [ - + - - ]: 90 : if (rkey && (action == SPDK_SCSI_PR_OUT_REGISTER)) {
253 : 0 : SPDK_ERRLOG("Reservation key field is not empty\n");
254 : 0 : sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
255 : 0 : sk = SPDK_SCSI_SENSE_NO_SENSE;
256 : 0 : asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
257 : 0 : goto error_exit;
258 : : }
259 : :
260 [ - + ]: 90 : if (!sa_rkey) {
261 : : /* Do nothing except return GOOD status */
262 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "REGISTER: service action "
263 : : "reservation key is zero, do noting\n");
264 : 0 : return 0;
265 : : }
266 : : /* Add a new registrant for the I_T nexus */
267 : 90 : return scsi_pr_register_registrant(lun, task->initiator_port,
268 : : task->target_port, sa_rkey);
269 : : } else {
270 : : /* a registered I_T nexus */
271 [ + + + - ]: 70 : if (rkey != reg->rkey && action == SPDK_SCSI_PR_OUT_REGISTER) {
272 : 30 : SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match "
273 : : "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
274 : 30 : sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
275 : 30 : sk = SPDK_SCSI_SENSE_NO_SENSE;
276 : 30 : asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
277 : 30 : goto error_exit;
278 : : }
279 : :
280 [ + + ]: 40 : if (!sa_rkey) {
281 : : /* unregister */
282 : 10 : scsi_pr_unregister_registrant(lun, reg);
283 : : } else {
284 : : /* replace */
285 : 30 : scsi_pr_replace_registrant_key(lun, reg, sa_rkey);
286 : : }
287 : : }
288 : :
289 : 40 : return 0;
290 : :
291 : 30 : error_exit:
292 : 30 : spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
293 : 30 : return -EINVAL;
294 : : }
295 : :
296 : : static int
297 : 0 : scsi_pr_out_release(struct spdk_scsi_task *task,
298 : : enum spdk_scsi_pr_type_code rtype, uint64_t rkey)
299 : : {
300 : 0 : struct spdk_scsi_lun *lun = task->lun;
301 : : struct spdk_scsi_pr_registrant *reg;
302 : : int sk, asc;
303 : :
304 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PR OUT RELEASE: rkey 0x%"PRIx64", "
305 : : "reservation type %u\n", rkey, rtype);
306 : :
307 : 0 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
308 [ # # ]: 0 : if (!reg) {
309 : 0 : SPDK_ERRLOG("No registration\n");
310 : 0 : sk = SPDK_SCSI_SENSE_NOT_READY;
311 : 0 : asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
312 : 0 : goto check_condition;
313 : : }
314 : :
315 : : /* no reservation holder */
316 [ # # ]: 0 : if (!scsi_pr_has_reservation(lun)) {
317 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "RELEASE: no reservation holder\n");
318 : 0 : return 0;
319 : : }
320 : :
321 [ # # # # ]: 0 : if (lun->reservation.rtype != rtype || rkey != lun->reservation.crkey) {
322 : 0 : sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
323 : 0 : asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
324 : 0 : goto check_condition;
325 : : }
326 : :
327 : : /* I_T nexus is not a persistent reservation holder */
328 [ # # ]: 0 : if (!scsi_pr_registrant_is_holder(lun, reg)) {
329 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "RELEASE: current I_T nexus is not holder\n");
330 : 0 : return 0;
331 : : }
332 : :
333 : 0 : scsi_pr_release_reservation(lun, reg);
334 : :
335 : 0 : return 0;
336 : :
337 : 0 : check_condition:
338 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, sk, asc,
339 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
340 : 0 : return -EINVAL;
341 : : }
342 : :
343 : : static int
344 : 0 : scsi_pr_out_clear(struct spdk_scsi_task *task, uint64_t rkey)
345 : : {
346 : 0 : struct spdk_scsi_lun *lun = task->lun;
347 : : struct spdk_scsi_pr_registrant *reg, *tmp;
348 : : int sc, sk, asc;
349 : :
350 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PR OUT CLEAR: rkey 0x%"PRIx64"\n", rkey);
351 : :
352 : 0 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
353 [ # # ]: 0 : if (!reg) {
354 : 0 : SPDK_ERRLOG("No registration\n");
355 : 0 : sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
356 : 0 : sk = SPDK_SCSI_SENSE_NOT_READY;
357 : 0 : asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
358 : 0 : goto error_exit;
359 : : }
360 : :
361 [ # # ]: 0 : if (rkey != reg->rkey) {
362 : 0 : SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match "
363 : : "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
364 : 0 : sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
365 : 0 : sk = SPDK_SCSI_SENSE_NO_SENSE;
366 : 0 : asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
367 : 0 : goto error_exit;
368 : : }
369 : :
370 [ # # ]: 0 : TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
371 : 0 : scsi_pr_unregister_registrant(lun, reg);
372 : : }
373 : :
374 : 0 : return 0;
375 : :
376 : 0 : error_exit:
377 : 0 : spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
378 : 0 : return -EINVAL;
379 : : }
380 : :
381 : : static void
382 : 15 : scsi_pr_remove_all_regs_by_key(struct spdk_scsi_lun *lun, uint64_t sa_rkey)
383 : : {
384 : : struct spdk_scsi_pr_registrant *reg, *tmp;
385 : :
386 [ + + ]: 55 : TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
387 [ + + ]: 40 : if (reg->rkey == sa_rkey) {
388 : 15 : scsi_pr_unregister_registrant(lun, reg);
389 : : }
390 : : }
391 : 15 : }
392 : :
393 : : static void
394 : 5 : scsi_pr_remove_all_other_regs(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg)
395 : : {
396 : : struct spdk_scsi_pr_registrant *reg_tmp, *reg_tmp2;
397 : :
398 [ + + ]: 15 : TAILQ_FOREACH_SAFE(reg_tmp, &lun->reg_head, link, reg_tmp2) {
399 [ + + ]: 10 : if (reg_tmp != reg) {
400 : 5 : scsi_pr_unregister_registrant(lun, reg_tmp);
401 : : }
402 : : }
403 : 5 : }
404 : :
405 : : static int
406 : 35 : scsi_pr_out_preempt(struct spdk_scsi_task *task,
407 : : enum spdk_scsi_pr_out_service_action_code action,
408 : : enum spdk_scsi_pr_type_code rtype,
409 : : uint64_t rkey, uint64_t sa_rkey)
410 : : {
411 : 35 : struct spdk_scsi_lun *lun = task->lun;
412 : : struct spdk_scsi_pr_registrant *reg;
413 : 35 : bool all_regs = false;
414 : :
415 [ - + - + ]: 35 : SPDK_DEBUGLOG(scsi, "PR OUT PREEMPT: rkey 0x%"PRIx64", sa_rkey 0x%"PRIx64" "
416 : : "action %u, type %u, reservation type %u\n",
417 : : rkey, sa_rkey, action, rtype, lun->reservation.rtype);
418 : :
419 : : /* I_T nexus is not registered */
420 : 35 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
421 [ - + ]: 35 : if (!reg) {
422 : 0 : SPDK_ERRLOG("No registration\n");
423 : 0 : goto conflict;
424 : : }
425 [ - + ]: 35 : if (rkey != reg->rkey) {
426 : 0 : SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match "
427 : : "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
428 : 0 : goto conflict;
429 : : }
430 : :
431 : : /* no persistent reservation */
432 [ + + ]: 35 : if (!scsi_pr_has_reservation(lun)) {
433 : 5 : scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
434 [ - + - + ]: 5 : SPDK_DEBUGLOG(scsi, "PREEMPT: no persistent reservation\n");
435 : 5 : goto exit;
436 : : }
437 : :
438 : 30 : all_regs = scsi_pr_is_all_registrants_type(lun);
439 : :
440 [ + + ]: 30 : if (all_regs) {
441 [ - + ]: 5 : if (sa_rkey != 0) {
442 : 0 : scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
443 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey\n");
444 : : } else {
445 : : /* remove all other registrants and release persistent reservation if any */
446 : 5 : scsi_pr_remove_all_other_regs(lun, reg);
447 : : /* create persistent reservation using new type and scope */
448 : 5 : scsi_pr_reserve_reservation(lun, rtype, 0, reg);
449 [ - + - + ]: 5 : SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey zeroed\n");
450 : : }
451 : 5 : goto exit;
452 : : }
453 : :
454 [ - + ]: 25 : assert(lun->reservation.crkey != 0);
455 : :
456 [ + + ]: 25 : if (sa_rkey != lun->reservation.crkey) {
457 [ + + ]: 10 : if (!sa_rkey) {
458 : 5 : SPDK_ERRLOG("Zeroed sa_rkey\n");
459 : 5 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
460 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
461 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
462 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
463 : 5 : return -EINVAL;
464 : : }
465 : 5 : scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
466 : 5 : goto exit;
467 : : }
468 : :
469 [ + + ]: 15 : if (scsi_pr_registrant_is_holder(lun, reg)) {
470 : 10 : scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
471 [ - + - + ]: 10 : SPDK_DEBUGLOG(scsi, "PREEMPT: preempt itself with type %u\n", rtype);
472 : 10 : goto exit;
473 : : }
474 : :
475 : : /* unregister registrants if any */
476 : 5 : scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
477 : 5 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
478 [ - + ]: 5 : if (!reg) {
479 : 0 : SPDK_ERRLOG("Current I_T nexus registrant was removed\n");
480 : 0 : goto conflict;
481 : : }
482 : :
483 : : /* preempt the holder */
484 : 5 : scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
485 : :
486 : 30 : exit:
487 : 30 : lun->pr_generation++;
488 : 30 : return 0;
489 : :
490 : 0 : conflict:
491 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
492 : : SPDK_SCSI_SENSE_NO_SENSE,
493 : : SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
494 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
495 : 0 : return -EINVAL;
496 : : }
497 : :
498 : : int
499 : 0 : scsi_pr_out(struct spdk_scsi_task *task, uint8_t *cdb,
500 : : uint8_t *data, uint16_t data_len)
501 : : {
502 : 0 : int rc = -1;
503 : : uint64_t rkey, sa_rkey;
504 : : uint8_t spec_i_pt, all_tg_pt, aptpl;
505 : : enum spdk_scsi_pr_out_service_action_code action;
506 : : enum spdk_scsi_pr_scope_code scope;
507 : : enum spdk_scsi_pr_type_code rtype;
508 : 0 : struct spdk_scsi_pr_out_param_list *param = (struct spdk_scsi_pr_out_param_list *)data;
509 : :
510 : 0 : action = cdb[1] & 0x0f;
511 : 0 : scope = (cdb[2] >> 4) & 0x0f;
512 : 0 : rtype = cdb[2] & 0x0f;
513 : :
514 : 0 : rkey = from_be64(¶m->rkey);
515 : 0 : sa_rkey = from_be64(¶m->sa_rkey);
516 : 0 : aptpl = param->aptpl;
517 : 0 : spec_i_pt = param->spec_i_pt;
518 : 0 : all_tg_pt = param->all_tg_pt;
519 : :
520 [ # # # # : 0 : switch (action) {
# # ]
521 : 0 : case SPDK_SCSI_PR_OUT_REGISTER:
522 : : case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
523 : 0 : rc = scsi_pr_out_register(task, action, rkey, sa_rkey,
524 : : spec_i_pt, all_tg_pt, aptpl);
525 : 0 : break;
526 : 0 : case SPDK_SCSI_PR_OUT_RESERVE:
527 [ # # ]: 0 : if (scope != SPDK_SCSI_PR_LU_SCOPE) {
528 : 0 : goto invalid;
529 : : }
530 : 0 : rc = scsi_pr_out_reserve(task, rtype, rkey,
531 : : spec_i_pt, all_tg_pt, aptpl);
532 : 0 : break;
533 : 0 : case SPDK_SCSI_PR_OUT_RELEASE:
534 [ # # ]: 0 : if (scope != SPDK_SCSI_PR_LU_SCOPE) {
535 : 0 : goto invalid;
536 : : }
537 : 0 : rc = scsi_pr_out_release(task, rtype, rkey);
538 : 0 : break;
539 : 0 : case SPDK_SCSI_PR_OUT_CLEAR:
540 : 0 : rc = scsi_pr_out_clear(task, rkey);
541 : 0 : break;
542 : 0 : case SPDK_SCSI_PR_OUT_PREEMPT:
543 [ # # ]: 0 : if (scope != SPDK_SCSI_PR_LU_SCOPE) {
544 : 0 : goto invalid;
545 : : }
546 : 0 : rc = scsi_pr_out_preempt(task, action, rtype, rkey, sa_rkey);
547 : 0 : break;
548 : 0 : default:
549 : 0 : SPDK_ERRLOG("Invalid service action code %u\n", action);
550 : 0 : goto invalid;
551 : : }
552 : :
553 : 0 : return rc;
554 : :
555 : 0 : invalid:
556 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
557 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
558 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
559 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
560 : 0 : return -EINVAL;
561 : : }
562 : :
563 : : static int
564 : 0 : scsi_pr_in_read_keys(struct spdk_scsi_task *task, uint8_t *data,
565 : : uint16_t data_len)
566 : : {
567 : 0 : struct spdk_scsi_lun *lun = task->lun;
568 : : struct spdk_scsi_pr_in_read_keys_data *keys;
569 : : struct spdk_scsi_pr_registrant *reg, *tmp;
570 : 0 : uint16_t count = 0;
571 : :
572 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PR IN READ KEYS\n");
573 : 0 : keys = (struct spdk_scsi_pr_in_read_keys_data *)data;
574 : :
575 : 0 : to_be32(&keys->header.pr_generation, lun->pr_generation);
576 [ # # ]: 0 : TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
577 [ # # ]: 0 : if (((count + 1) * 8 + sizeof(keys->header)) > data_len) {
578 : 0 : break;
579 : : }
580 : 0 : to_be64(&keys->rkeys[count], reg->rkey);
581 : 0 : count++;
582 : : }
583 : 0 : to_be32(&keys->header.additional_len, count * 8);
584 : :
585 : 0 : return (sizeof(keys->header) + count * 8);
586 : : }
587 : :
588 : : static int
589 : 0 : scsi_pr_in_read_reservations(struct spdk_scsi_task *task,
590 : : uint8_t *data, uint16_t data_len)
591 : : {
592 : 0 : struct spdk_scsi_lun *lun = task->lun;
593 : : struct spdk_scsi_pr_in_read_reservations_data *param;
594 : 0 : bool all_regs = false;
595 : :
596 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PR IN READ RESERVATIONS\n");
597 : 0 : param = (struct spdk_scsi_pr_in_read_reservations_data *)(data);
598 : :
599 : 0 : to_be32(¶m->header.pr_generation, lun->pr_generation);
600 [ # # ]: 0 : if (scsi_pr_has_reservation(lun)) {
601 : 0 : all_regs = scsi_pr_is_all_registrants_type(lun);
602 [ # # ]: 0 : if (all_regs) {
603 : 0 : to_be64(¶m->rkey, 0);
604 : : } else {
605 : 0 : to_be64(¶m->rkey, lun->reservation.crkey);
606 : : }
607 : 0 : to_be32(¶m->header.additional_len, 16);
608 : 0 : param->scope = SPDK_SCSI_PR_LU_SCOPE;
609 : 0 : param->type = lun->reservation.rtype;
610 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "READ RESERVATIONS with valid reservation\n");
611 : 0 : return sizeof(*param);
612 : : }
613 : :
614 : : /* no reservation */
615 : 0 : to_be32(¶m->header.additional_len, 0);
616 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "READ RESERVATIONS no reservation\n");
617 : 0 : return sizeof(param->header);
618 : : }
619 : :
620 : : static int
621 : 0 : scsi_pr_in_report_capabilities(struct spdk_scsi_task *task,
622 : : uint8_t *data, uint16_t data_len)
623 : : {
624 : : struct spdk_scsi_pr_in_report_capabilities_data *param;
625 : :
626 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PR IN REPORT CAPABILITIES\n");
627 : 0 : param = (struct spdk_scsi_pr_in_report_capabilities_data *)data;
628 : :
629 [ # # ]: 0 : memset(param, 0, sizeof(*param));
630 : 0 : to_be16(¶m->length, sizeof(*param));
631 : : /* Compatible reservation handling to support RESERVE/RELEASE defined in SPC-2 */
632 : 0 : param->crh = 1;
633 : 0 : param->tmv = 1;
634 : 0 : param->wr_ex = 1;
635 : 0 : param->ex_ac = 1;
636 : 0 : param->wr_ex_ro = 1;
637 : 0 : param->ex_ac_ro = 1;
638 : 0 : param->wr_ex_ar = 1;
639 : 0 : param->ex_ac_ar = 1;
640 : :
641 : 0 : return sizeof(*param);
642 : : }
643 : :
644 : : static int
645 : 0 : scsi_pr_in_read_full_status(struct spdk_scsi_task *task,
646 : : uint8_t *data, uint16_t data_len)
647 : : {
648 : 0 : struct spdk_scsi_lun *lun = task->lun;
649 : : struct spdk_scsi_pr_in_full_status_data *param;
650 : : struct spdk_scsi_pr_in_full_status_desc *desc;
651 : : struct spdk_scsi_pr_registrant *reg, *tmp;
652 : 0 : bool all_regs = false;
653 : 0 : uint32_t add_len = 0;
654 : :
655 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "PR IN READ FULL STATUS\n");
656 : :
657 : 0 : all_regs = scsi_pr_is_all_registrants_type(lun);
658 : 0 : param = (struct spdk_scsi_pr_in_full_status_data *)data;
659 : 0 : to_be32(¶m->header.pr_generation, lun->pr_generation);
660 : :
661 [ # # ]: 0 : TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
662 : 0 : desc = (struct spdk_scsi_pr_in_full_status_desc *)
663 : 0 : ((uint8_t *)param->desc_list + add_len);
664 [ # # ]: 0 : if (add_len + sizeof(*desc) + sizeof(param->header) > data_len) {
665 : 0 : break;
666 : : }
667 : 0 : add_len += sizeof(*desc);
668 : 0 : desc->rkey = reg->rkey;
669 [ # # # # ]: 0 : if (all_regs || lun->reservation.holder == reg) {
670 : 0 : desc->r_holder = true;
671 : 0 : desc->type = lun->reservation.rtype;
672 : : } else {
673 : 0 : desc->r_holder = false;
674 : 0 : desc->type = 0;
675 : : }
676 : 0 : desc->all_tg_pt = 0;
677 : 0 : desc->scope = SPDK_SCSI_PR_LU_SCOPE;
678 : 0 : desc->relative_target_port_id = reg->relative_target_port_id;
679 [ # # ]: 0 : if (add_len + reg->transport_id_len + sizeof(param->header) > data_len) {
680 : 0 : break;
681 : : }
682 : 0 : add_len += reg->transport_id_len;
683 [ # # # # ]: 0 : memcpy(&desc->transport_id, reg->transport_id, reg->transport_id_len);
684 : 0 : to_be32(&desc->desc_len, reg->transport_id_len);
685 : : }
686 : 0 : to_be32(¶m->header.additional_len, add_len);
687 : :
688 : 0 : return (sizeof(param->header) + add_len);
689 : : }
690 : :
691 : : int
692 : 0 : scsi_pr_in(struct spdk_scsi_task *task, uint8_t *cdb,
693 : : uint8_t *data, uint16_t data_len)
694 : : {
695 : : enum spdk_scsi_pr_in_action_code action;
696 : 0 : int rc = 0;
697 : :
698 : 0 : action = cdb[1] & 0x1f;
699 [ # # ]: 0 : if (data_len < sizeof(struct spdk_scsi_pr_in_read_header)) {
700 : 0 : goto invalid;
701 : : }
702 : :
703 [ # # # # : 0 : switch (action) {
# ]
704 : 0 : case SPDK_SCSI_PR_IN_READ_KEYS:
705 : 0 : rc = scsi_pr_in_read_keys(task, data, data_len);
706 : 0 : break;
707 : 0 : case SPDK_SCSI_PR_IN_READ_RESERVATION:
708 [ # # ]: 0 : if (data_len < sizeof(struct spdk_scsi_pr_in_read_reservations_data)) {
709 : 0 : goto invalid;
710 : : }
711 : 0 : rc = scsi_pr_in_read_reservations(task, data, data_len);
712 : 0 : break;
713 : 0 : case SPDK_SCSI_PR_IN_REPORT_CAPABILITIES:
714 : 0 : rc = scsi_pr_in_report_capabilities(task, data, data_len);
715 : 0 : break;
716 : 0 : case SPDK_SCSI_PR_IN_READ_FULL_STATUS:
717 : 0 : rc = scsi_pr_in_read_full_status(task, data, data_len);
718 : 0 : break;
719 : 0 : default:
720 : 0 : goto invalid;
721 : : }
722 : :
723 : 0 : return rc;
724 : :
725 : 0 : invalid:
726 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
727 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
728 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
729 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
730 : 0 : return -EINVAL;
731 : : }
732 : :
733 : : int
734 : 31026767 : scsi_pr_check(struct spdk_scsi_task *task)
735 : : {
736 : 31026767 : struct spdk_scsi_lun *lun = task->lun;
737 : 31026767 : uint8_t *cdb = task->cdb;
738 : : enum spdk_scsi_pr_type_code rtype;
739 : : enum spdk_scsi_pr_out_service_action_code action;
740 : : struct spdk_scsi_pr_registrant *reg;
741 : 31026767 : bool dma_to_device = false;
742 : :
743 : : /* no reservation holders */
744 [ + + ]: 31026767 : if (!scsi_pr_has_reservation(lun)) {
745 : 31026722 : return 0;
746 : : }
747 : :
748 : 45 : rtype = lun->reservation.rtype;
749 [ - + ]: 45 : assert(rtype != 0);
750 : :
751 : 45 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
752 : : /* current I_T nexus hold the reservation */
753 [ - + ]: 45 : if (scsi_pr_registrant_is_holder(lun, reg)) {
754 : 0 : return 0;
755 : : }
756 : :
757 : : /* reservation is held by other I_T nexus */
758 [ + - - + ]: 45 : switch (cdb[0]) {
759 : 5 : case SPDK_SPC_INQUIRY:
760 : : case SPDK_SPC_REPORT_LUNS:
761 : : case SPDK_SPC_REQUEST_SENSE:
762 : : case SPDK_SPC_LOG_SENSE:
763 : : case SPDK_SPC_TEST_UNIT_READY:
764 : : case SPDK_SBC_START_STOP_UNIT:
765 : : case SPDK_SBC_READ_CAPACITY_10:
766 : : case SPDK_SPC_PERSISTENT_RESERVE_IN:
767 : : case SPDK_SPC_SERVICE_ACTION_IN_16:
768 : : /* CRH enabled, processed by scsi2_reserve() */
769 : : case SPDK_SPC2_RESERVE_6:
770 : : case SPDK_SPC2_RESERVE_10:
771 : : /* CRH enabled, processed by scsi2_release() */
772 : : case SPDK_SPC2_RELEASE_6:
773 : : case SPDK_SPC2_RELEASE_10:
774 : 5 : return 0;
775 : 0 : case SPDK_SPC_MODE_SELECT_6:
776 : : case SPDK_SPC_MODE_SELECT_10:
777 : : case SPDK_SPC_MODE_SENSE_6:
778 : : case SPDK_SPC_MODE_SENSE_10:
779 : : case SPDK_SPC_LOG_SELECT:
780 : : /* I_T nexus is registrant but not holder */
781 [ # # ]: 0 : if (!reg) {
782 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "CHECK: current I_T nexus "
783 : : "is not registered, cdb 0x%x\n", cdb[0]);
784 : 0 : goto conflict;
785 : : }
786 : 0 : return 0;
787 : 0 : case SPDK_SPC_PERSISTENT_RESERVE_OUT:
788 : 0 : action = cdb[1] & 0x1f;
789 [ # # # # ]: 0 : SPDK_DEBUGLOG(scsi, "CHECK: PR OUT action %u\n", action);
790 [ # # # # ]: 0 : switch (action) {
791 : 0 : case SPDK_SCSI_PR_OUT_RELEASE:
792 : : case SPDK_SCSI_PR_OUT_CLEAR:
793 : : case SPDK_SCSI_PR_OUT_PREEMPT:
794 : : case SPDK_SCSI_PR_OUT_PREEMPT_AND_ABORT:
795 [ # # ]: 0 : if (!reg) {
796 : 0 : SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
797 : 0 : goto conflict;
798 : : }
799 : 0 : return 0;
800 : 0 : case SPDK_SCSI_PR_OUT_REGISTER:
801 : : case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
802 : 0 : return 0;
803 : 0 : case SPDK_SCSI_PR_OUT_REG_AND_MOVE:
804 : 0 : SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
805 : 0 : goto conflict;
806 : 0 : default:
807 : 0 : SPDK_ERRLOG("CHECK: PR OUT invalid action %u\n", action);
808 : 0 : goto conflict;
809 : : }
810 : :
811 : : /* For most SBC R/W commands */
812 : 40 : default:
813 : 40 : break;
814 : : }
815 : :
816 [ + + - ]: 40 : switch (cdb[0]) {
817 : 20 : case SPDK_SBC_READ_6:
818 : : case SPDK_SBC_READ_10:
819 : : case SPDK_SBC_READ_12:
820 : : case SPDK_SBC_READ_16:
821 : 20 : break;
822 : 20 : case SPDK_SBC_WRITE_6:
823 : : case SPDK_SBC_WRITE_10:
824 : : case SPDK_SBC_WRITE_12:
825 : : case SPDK_SBC_WRITE_16:
826 : : case SPDK_SBC_UNMAP:
827 : : case SPDK_SBC_SYNCHRONIZE_CACHE_10:
828 : : case SPDK_SBC_SYNCHRONIZE_CACHE_16:
829 : 20 : dma_to_device = true;
830 : 20 : break;
831 : 0 : default:
832 : 0 : SPDK_ERRLOG("CHECK: unsupported SCSI command cdb 0x%x\n", cdb[0]);
833 : 0 : goto conflict;
834 : : }
835 : :
836 [ - + + - : 40 : switch (rtype) {
- ]
837 : 0 : case SPDK_SCSI_PR_WRITE_EXCLUSIVE:
838 [ # # ]: 0 : if (dma_to_device) {
839 : 0 : SPDK_ERRLOG("CHECK: Write Exclusive reservation type "
840 : : "rejects command 0x%x\n", cdb[0]);
841 : 0 : goto conflict;
842 : : }
843 : 0 : break;
844 : 20 : case SPDK_SCSI_PR_EXCLUSIVE_ACCESS:
845 : 20 : SPDK_ERRLOG("CHECK: Exclusive Access reservation type "
846 : : "rejects command 0x%x\n", cdb[0]);
847 : 20 : goto conflict;
848 : 20 : case SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY:
849 : : case SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
850 [ + + + + ]: 20 : if (!reg && dma_to_device) {
851 : 5 : SPDK_ERRLOG("CHECK: Registrants only reservation "
852 : : "type reject command 0x%x\n", cdb[0]);
853 : 5 : goto conflict;
854 : : }
855 : 15 : break;
856 : 0 : case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY:
857 : : case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
858 [ # # ]: 0 : if (!reg) {
859 : 0 : SPDK_ERRLOG("CHECK: All Registrants reservation "
860 : : "type reject command 0x%x\n", cdb[0]);
861 : 0 : goto conflict;
862 : : }
863 : 0 : break;
864 : 0 : default:
865 : 0 : break;
866 : : }
867 : :
868 : 15 : return 0;
869 : :
870 : 25 : conflict:
871 : 25 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
872 : : SPDK_SCSI_SENSE_NO_SENSE,
873 : : SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
874 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
875 : 25 : return -1;
876 : : }
877 : :
878 : : static int
879 : 35 : scsi2_check_reservation_conflict(struct spdk_scsi_task *task)
880 : : {
881 : 35 : struct spdk_scsi_lun *lun = task->lun;
882 : : struct spdk_scsi_pr_registrant *reg;
883 : 35 : bool conflict = false;
884 : :
885 : 35 : reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
886 [ + + ]: 35 : if (reg) {
887 : : /*
888 : : * From spc4r31 5.9.3 Exceptions to SPC-2 RESERVE and RELEASE
889 : : * behavior
890 : : *
891 : : * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
892 : : * status, but no reservation shall be established and the
893 : : * persistent reservation shall not be changed, if the command
894 : : * is received from a) and b) below.
895 : : *
896 : : * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
897 : : * status, but the persistent reservation shall not be released,
898 : : * if the command is received from a) and b)
899 : : *
900 : : * a) An I_T nexus that is a persistent reservation holder; or
901 : : * b) An I_T nexus that is registered if a registrants only or
902 : : * all registrants type persistent reservation is present.
903 : : *
904 : : * In all other cases, a RESERVE(6) command, RESERVE(10) command,
905 : : * RELEASE(6) command, or RELEASE(10) command shall be processed
906 : : * as defined in SPC-2.
907 : : */
908 [ - + ]: 10 : if (scsi_pr_registrant_is_holder(lun, reg)) {
909 : 0 : return 1;
910 : : }
911 : :
912 [ - + ]: 10 : if (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY ||
913 [ # # ]: 0 : lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY) {
914 : 10 : return 1;
915 : : }
916 : :
917 : 0 : conflict = true;
918 : : } else {
919 : : /*
920 : : * From spc2r20 5.5.1 Reservations overview:
921 : : *
922 : : * If a logical unit has executed a PERSISTENT RESERVE OUT
923 : : * command with the REGISTER or the REGISTER AND IGNORE
924 : : * EXISTING KEY service action and is still registered by any
925 : : * initiator, all RESERVE commands and all RELEASE commands
926 : : * regardless of initiator shall conflict and shall terminate
927 : : * with a RESERVATION CONFLICT status.
928 : : */
929 : 25 : conflict = TAILQ_EMPTY(&lun->reg_head) ? false : true;
930 : : }
931 : :
932 [ - + ]: 25 : if (conflict) {
933 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
934 : : SPDK_SCSI_SENSE_NO_SENSE,
935 : : SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
936 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
937 : 0 : return -1;
938 : : }
939 : :
940 : 25 : return 0;
941 : : }
942 : :
943 : : int
944 : 15 : scsi2_reserve(struct spdk_scsi_task *task, uint8_t *cdb)
945 : : {
946 : 15 : struct spdk_scsi_lun *lun = task->lun;
947 : 15 : struct spdk_scsi_pr_registrant *reg = &lun->scsi2_holder;
948 : : int ret;
949 : :
950 : : /* Obsolete Bits and LongID set, returning ILLEGAL_REQUEST */
951 [ - + ]: 15 : if (cdb[1] & 0x3) {
952 : 0 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
953 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
954 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
955 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
956 : 0 : return -1;
957 : : }
958 : :
959 : 15 : ret = scsi2_check_reservation_conflict(task);
960 : : /* PERSISTENT RESERVE is enabled */
961 [ + + ]: 15 : if (ret == 1) {
962 : 5 : return 0;
963 [ - + ]: 10 : } else if (ret < 0) {
964 : 0 : return ret;
965 : : }
966 : :
967 : : /* SPC2 RESERVE */
968 : 10 : reg->initiator_port = task->initiator_port;
969 [ + - ]: 10 : if (task->initiator_port) {
970 [ - + ]: 10 : snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s",
971 : 10 : task->initiator_port->name);
972 : 10 : reg->transport_id_len = task->initiator_port->transport_id_len;
973 [ - + - + ]: 10 : memcpy(reg->transport_id, task->initiator_port->transport_id,
974 : 10 : reg->transport_id_len);
975 : : }
976 : 10 : reg->target_port = task->target_port;
977 [ + - ]: 10 : if (task->target_port) {
978 [ - + ]: 10 : snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s",
979 : 10 : task->target_port->name);
980 : : }
981 : :
982 : 10 : lun->reservation.flags = SCSI_SPC2_RESERVE;
983 : 10 : lun->reservation.holder = &lun->scsi2_holder;
984 : :
985 : 10 : return 0;
986 : : }
987 : :
988 : : int
989 : 20 : scsi2_release(struct spdk_scsi_task *task)
990 : : {
991 : 20 : struct spdk_scsi_lun *lun = task->lun;
992 : : int ret;
993 : :
994 : 20 : ret = scsi2_check_reservation_conflict(task);
995 : : /* PERSISTENT RESERVE is enabled */
996 [ + + ]: 20 : if (ret == 1) {
997 : 5 : return 0;
998 [ - + ]: 15 : } else if (ret < 0) {
999 : 0 : return ret;
1000 : : }
1001 : :
1002 [ + + ]: 15 : if (!(lun->reservation.flags & SCSI_SPC2_RESERVE)) {
1003 : 5 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
1004 : : SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
1005 : : SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
1006 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
1007 : 5 : return -EINVAL;
1008 : : }
1009 : :
1010 [ - + ]: 10 : memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
1011 [ - + ]: 10 : memset(&lun->scsi2_holder, 0, sizeof(struct spdk_scsi_pr_registrant));
1012 : :
1013 : 10 : return 0;
1014 : : }
1015 : :
1016 : : int
1017 : 15 : scsi2_reserve_check(struct spdk_scsi_task *task)
1018 : : {
1019 : 15 : struct spdk_scsi_lun *lun = task->lun;
1020 : 15 : uint8_t *cdb = task->cdb;
1021 : :
1022 [ + + ]: 15 : switch (cdb[0]) {
1023 : 5 : case SPDK_SPC_INQUIRY:
1024 : : case SPDK_SPC2_RELEASE_6:
1025 : : case SPDK_SPC2_RELEASE_10:
1026 : 5 : return 0;
1027 : :
1028 : 10 : default:
1029 : 10 : break;
1030 : : }
1031 : :
1032 : : /* no reservation holders */
1033 [ - + ]: 10 : if (!scsi_pr_has_reservation(lun)) {
1034 : 0 : return 0;
1035 : : }
1036 : :
1037 [ + + ]: 10 : if (scsi2_it_nexus_is_holder(lun, task->initiator_port, task->target_port)) {
1038 : 5 : return 0;
1039 : : }
1040 : :
1041 : 5 : spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
1042 : : SPDK_SCSI_SENSE_NO_SENSE,
1043 : : SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
1044 : : SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
1045 : 5 : return -1;
1046 : : }
|