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