xref: /spdk/lib/scsi/scsi_pr.c (revision cdb0726b95631d46eaf4f2e39ddb6533f150fd27)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 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 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 	TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
19 		if (initiator_port == reg->initiator_port &&
20 		    target_port == reg->target_port) {
21 			return reg;
22 		}
23 	}
24 
25 	return NULL;
26 }
27 
28 static bool
29 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 	struct spdk_scsi_pr_registrant *reg = lun->reservation.holder;
34 
35 	assert(reg != NULL);
36 
37 	if ((reg->initiator_port == initiator_port) &&
38 	    (reg->target_port == target_port)) {
39 		return true;
40 	}
41 
42 	return false;
43 }
44 
45 /* Reservation type is all registrants or not */
46 static inline bool
47 scsi_pr_is_all_registrants_type(struct spdk_scsi_lun *lun)
48 {
49 	return (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS ||
50 		lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS);
51 }
52 
53 /* Registrant is reservation holder or not */
54 static inline bool
55 scsi_pr_registrant_is_holder(struct spdk_scsi_lun *lun,
56 			     struct spdk_scsi_pr_registrant *reg)
57 {
58 	if (scsi_pr_is_all_registrants_type(lun)) {
59 		return true;
60 	}
61 
62 	return (lun->reservation.holder == reg);
63 }
64 
65 /* LUN holds a reservation or not */
66 static inline bool
67 scsi_pr_has_reservation(struct spdk_scsi_lun *lun)
68 {
69 	return !(lun->reservation.holder == NULL);
70 }
71 
72 static int
73 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 	reg = calloc(1, sizeof(*reg));
82 	if (!reg) {
83 		return -ENOMEM;
84 	}
85 
86 	SPDK_DEBUGLOG(scsi, "REGISTER: new registrant registered "
87 		      "with key 0x%"PRIx64"\n", sa_rkey);
88 
89 	/* New I_T nexus */
90 	reg->initiator_port = initiator_port;
91 	if (initiator_port) {
92 		snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s",
93 			 initiator_port->name);
94 		reg->transport_id_len = initiator_port->transport_id_len;
95 		memcpy(reg->transport_id, initiator_port->transport_id, reg->transport_id_len);
96 	}
97 	reg->target_port = target_port;
98 	if (target_port) {
99 		snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s",
100 			 target_port->name);
101 		reg->relative_target_port_id = target_port->index;
102 	}
103 	reg->rkey = sa_rkey;
104 	TAILQ_INSERT_TAIL(&lun->reg_head, reg, link);
105 	lun->pr_generation++;
106 
107 	return 0;
108 }
109 
110 static void
111 scsi_pr_release_reservation(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_registrant *reg)
112 {
113 	bool all_regs = false;
114 
115 	SPDK_DEBUGLOG(scsi, "REGISTER: release reservation "
116 		      "with type %u\n", lun->reservation.rtype);
117 
118 	/* TODO: Unit Attention */
119 	all_regs = scsi_pr_is_all_registrants_type(lun);
120 	if (all_regs && !TAILQ_EMPTY(&lun->reg_head)) {
121 		lun->reservation.holder = TAILQ_FIRST(&lun->reg_head);
122 		return;
123 	}
124 
125 	memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
126 }
127 
128 static void
129 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 	lun->reservation.rtype = type;
135 	lun->reservation.crkey = rkey;
136 	lun->reservation.holder = holder;
137 }
138 
139 static void
140 scsi_pr_unregister_registrant(struct spdk_scsi_lun *lun,
141 			      struct spdk_scsi_pr_registrant *reg)
142 {
143 	SPDK_DEBUGLOG(scsi, "REGISTER: unregister registrant\n");
144 
145 	TAILQ_REMOVE(&lun->reg_head, reg, link);
146 	if (scsi_pr_registrant_is_holder(lun, reg)) {
147 		scsi_pr_release_reservation(lun, reg);
148 	}
149 
150 	free(reg);
151 	lun->pr_generation++;
152 }
153 
154 static void
155 scsi_pr_replace_registrant_key(struct spdk_scsi_lun *lun,
156 			       struct spdk_scsi_pr_registrant *reg,
157 			       uint64_t sa_rkey)
158 {
159 	SPDK_DEBUGLOG(scsi, "REGISTER: replace with new "
160 		      "reservation key 0x%"PRIx64"\n", sa_rkey);
161 	reg->rkey = sa_rkey;
162 	lun->pr_generation++;
163 }
164 
165 static int
166 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 	struct spdk_scsi_lun *lun = task->lun;
171 	struct spdk_scsi_pr_registrant *reg;
172 
173 	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 	if (spec_i_pt || all_tg_pt || aptpl) {
178 		SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt fields "
179 			    "or invalid aptpl field\n");
180 		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 		return -EINVAL;
185 	}
186 
187 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
188 	/* No registration for the I_T nexus */
189 	if (!reg) {
190 		SPDK_ERRLOG("No registration\n");
191 		goto conflict;
192 	}
193 
194 	/* invalid reservation key */
195 	if (reg->rkey != rkey) {
196 		SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match 0x%"PRIx64"\n",
197 			    rkey, reg->rkey);
198 		goto conflict;
199 	}
200 
201 	/* reservation holder already exists */
202 	if (scsi_pr_has_reservation(lun)) {
203 		if (rtype != lun->reservation.rtype) {
204 			SPDK_ERRLOG("Reservation type doesn't match\n");
205 			goto conflict;
206 		}
207 
208 		if (!scsi_pr_registrant_is_holder(lun, reg)) {
209 			SPDK_ERRLOG("Only 1 holder is allowed for type %u\n", rtype);
210 			goto conflict;
211 		}
212 	} else {
213 		/* current I_T nexus is the first reservation holder */
214 		scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
215 	}
216 
217 	return 0;
218 
219 conflict:
220 	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 	return -EINVAL;
225 }
226 
227 static int
228 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 	struct spdk_scsi_lun *lun = task->lun;
234 	struct spdk_scsi_pr_registrant *reg;
235 	int sc, sk, asc;
236 
237 	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 	if (spec_i_pt || all_tg_pt || aptpl) {
242 		SPDK_ERRLOG("Unsupported spec_i_pt/all_tg_pt/aptpl field\n");
243 		sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
244 		sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
245 		asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
246 		goto error_exit;
247 	}
248 
249 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
250 	/* an unregistered I_T nexus session */
251 	if (!reg) {
252 		if (rkey && (action == SPDK_SCSI_PR_OUT_REGISTER)) {
253 			SPDK_ERRLOG("Reservation key field is not empty\n");
254 			sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
255 			sk = SPDK_SCSI_SENSE_NO_SENSE;
256 			asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
257 			goto error_exit;
258 		}
259 
260 		if (!sa_rkey) {
261 			/* Do nothing except return GOOD status */
262 			SPDK_DEBUGLOG(scsi, "REGISTER: service action "
263 				      "reservation key is zero, do noting\n");
264 			return 0;
265 		}
266 		/* Add a new registrant for the I_T nexus */
267 		return scsi_pr_register_registrant(lun, task->initiator_port,
268 						   task->target_port, sa_rkey);
269 	} else {
270 		/* a registered I_T nexus */
271 		if (rkey != reg->rkey && action == SPDK_SCSI_PR_OUT_REGISTER) {
272 			SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match "
273 				    "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
274 			sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
275 			sk = SPDK_SCSI_SENSE_NO_SENSE;
276 			asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
277 			goto error_exit;
278 		}
279 
280 		if (!sa_rkey) {
281 			/* unregister */
282 			scsi_pr_unregister_registrant(lun, reg);
283 		} else {
284 			/* replace */
285 			scsi_pr_replace_registrant_key(lun, reg, sa_rkey);
286 		}
287 	}
288 
289 	return 0;
290 
291 error_exit:
292 	spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
293 	return -EINVAL;
294 }
295 
296 static int
297 scsi_pr_out_release(struct spdk_scsi_task *task,
298 		    enum spdk_scsi_pr_type_code rtype, uint64_t rkey)
299 {
300 	struct spdk_scsi_lun *lun = task->lun;
301 	struct spdk_scsi_pr_registrant *reg;
302 	int sk, asc;
303 
304 	SPDK_DEBUGLOG(scsi, "PR OUT RELEASE: rkey 0x%"PRIx64", "
305 		      "reservation type %u\n", rkey, rtype);
306 
307 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
308 	if (!reg) {
309 		SPDK_ERRLOG("No registration\n");
310 		sk = SPDK_SCSI_SENSE_NOT_READY;
311 		asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
312 		goto check_condition;
313 	}
314 
315 	/* no reservation holder */
316 	if (!scsi_pr_has_reservation(lun)) {
317 		SPDK_DEBUGLOG(scsi, "RELEASE: no reservation holder\n");
318 		return 0;
319 	}
320 
321 	if (lun->reservation.rtype != rtype || rkey != lun->reservation.crkey) {
322 		sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
323 		asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
324 		goto check_condition;
325 	}
326 
327 	/* I_T nexus is not a persistent reservation holder */
328 	if (!scsi_pr_registrant_is_holder(lun, reg)) {
329 		SPDK_DEBUGLOG(scsi, "RELEASE: current I_T nexus is not holder\n");
330 		return 0;
331 	}
332 
333 	scsi_pr_release_reservation(lun, reg);
334 
335 	return 0;
336 
337 check_condition:
338 	spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, sk, asc,
339 				  SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
340 	return -EINVAL;
341 }
342 
343 static int
344 scsi_pr_out_clear(struct spdk_scsi_task *task, uint64_t rkey)
345 {
346 	struct spdk_scsi_lun *lun = task->lun;
347 	struct spdk_scsi_pr_registrant *reg, *tmp;
348 	int sc, sk, asc;
349 
350 	SPDK_DEBUGLOG(scsi, "PR OUT CLEAR: rkey 0x%"PRIx64"\n", rkey);
351 
352 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
353 	if (!reg) {
354 		SPDK_ERRLOG("No registration\n");
355 		sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
356 		sk = SPDK_SCSI_SENSE_NOT_READY;
357 		asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
358 		goto error_exit;
359 	}
360 
361 	if (rkey != reg->rkey) {
362 		SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match "
363 			    "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
364 		sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
365 		sk = SPDK_SCSI_SENSE_NO_SENSE;
366 		asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
367 		goto error_exit;
368 	}
369 
370 	TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
371 		scsi_pr_unregister_registrant(lun, reg);
372 	}
373 
374 	return 0;
375 
376 error_exit:
377 	spdk_scsi_task_set_status(task, sc, sk, asc, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
378 	return -EINVAL;
379 }
380 
381 static void
382 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 	TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
387 		if (reg->rkey == sa_rkey) {
388 			scsi_pr_unregister_registrant(lun, reg);
389 		}
390 	}
391 }
392 
393 static void
394 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 	TAILQ_FOREACH_SAFE(reg_tmp, &lun->reg_head, link, reg_tmp2) {
399 		if (reg_tmp != reg) {
400 			scsi_pr_unregister_registrant(lun, reg_tmp);
401 		}
402 	}
403 }
404 
405 static int
406 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 	struct spdk_scsi_lun *lun = task->lun;
412 	struct spdk_scsi_pr_registrant *reg;
413 	bool all_regs = false;
414 
415 	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 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
421 	if (!reg) {
422 		SPDK_ERRLOG("No registration\n");
423 		goto conflict;
424 	}
425 	if (rkey != reg->rkey) {
426 		SPDK_ERRLOG("Reservation key 0x%"PRIx64" doesn't match "
427 			    "registrant's key 0x%"PRIx64"\n", rkey, reg->rkey);
428 		goto conflict;
429 	}
430 
431 	/* no persistent reservation */
432 	if (!scsi_pr_has_reservation(lun)) {
433 		scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
434 		SPDK_DEBUGLOG(scsi, "PREEMPT: no persistent reservation\n");
435 		goto exit;
436 	}
437 
438 	all_regs = scsi_pr_is_all_registrants_type(lun);
439 
440 	if (all_regs) {
441 		if (sa_rkey != 0) {
442 			scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
443 			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 			scsi_pr_remove_all_other_regs(lun, reg);
447 			/* create persistent reservation using new type and scope */
448 			scsi_pr_reserve_reservation(lun, rtype, 0, reg);
449 			SPDK_DEBUGLOG(scsi, "PREEMPT: All registrants type with sa_rkey zeroed\n");
450 		}
451 		goto exit;
452 	}
453 
454 	assert(lun->reservation.crkey != 0);
455 
456 	if (sa_rkey != lun->reservation.crkey) {
457 		if (!sa_rkey) {
458 			SPDK_ERRLOG("Zeroed sa_rkey\n");
459 			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 			return -EINVAL;
464 		}
465 		scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
466 		goto exit;
467 	}
468 
469 	if (scsi_pr_registrant_is_holder(lun, reg)) {
470 		scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
471 		SPDK_DEBUGLOG(scsi, "PREEMPT: preempt itself with type %u\n", rtype);
472 		goto exit;
473 	}
474 
475 	/* unregister registrants if any */
476 	scsi_pr_remove_all_regs_by_key(lun, sa_rkey);
477 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
478 	if (!reg) {
479 		SPDK_ERRLOG("Current I_T nexus registrant was removed\n");
480 		goto conflict;
481 	}
482 
483 	/* preempt the holder */
484 	scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
485 
486 exit:
487 	lun->pr_generation++;
488 	return 0;
489 
490 conflict:
491 	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 	return -EINVAL;
496 }
497 
498 int
499 scsi_pr_out(struct spdk_scsi_task *task, uint8_t *cdb,
500 	    uint8_t *data, uint16_t data_len)
501 {
502 	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 	struct spdk_scsi_pr_out_param_list *param = (struct spdk_scsi_pr_out_param_list *)data;
509 
510 	action = cdb[1] & 0x0f;
511 	scope = (cdb[2] >> 4) & 0x0f;
512 	rtype = cdb[2] & 0x0f;
513 
514 	rkey = from_be64(&param->rkey);
515 	sa_rkey = from_be64(&param->sa_rkey);
516 	aptpl = param->aptpl;
517 	spec_i_pt = param->spec_i_pt;
518 	all_tg_pt = param->all_tg_pt;
519 
520 	switch (action) {
521 	case SPDK_SCSI_PR_OUT_REGISTER:
522 	case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
523 		rc = scsi_pr_out_register(task, action, rkey, sa_rkey,
524 					  spec_i_pt, all_tg_pt, aptpl);
525 		break;
526 	case SPDK_SCSI_PR_OUT_RESERVE:
527 		if (scope != SPDK_SCSI_PR_LU_SCOPE) {
528 			goto invalid;
529 		}
530 		rc = scsi_pr_out_reserve(task, rtype, rkey,
531 					 spec_i_pt, all_tg_pt, aptpl);
532 		break;
533 	case SPDK_SCSI_PR_OUT_RELEASE:
534 		if (scope != SPDK_SCSI_PR_LU_SCOPE) {
535 			goto invalid;
536 		}
537 		rc = scsi_pr_out_release(task, rtype, rkey);
538 		break;
539 	case SPDK_SCSI_PR_OUT_CLEAR:
540 		rc = scsi_pr_out_clear(task, rkey);
541 		break;
542 	case SPDK_SCSI_PR_OUT_PREEMPT:
543 		if (scope != SPDK_SCSI_PR_LU_SCOPE) {
544 			goto invalid;
545 		}
546 		rc = scsi_pr_out_preempt(task, action, rtype, rkey, sa_rkey);
547 		break;
548 	default:
549 		SPDK_ERRLOG("Invalid service action code %u\n", action);
550 		goto invalid;
551 	}
552 
553 	return rc;
554 
555 invalid:
556 	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 	return -EINVAL;
561 }
562 
563 static int
564 scsi_pr_in_read_keys(struct spdk_scsi_task *task, uint8_t *data,
565 		     uint16_t data_len)
566 {
567 	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 	uint16_t count = 0;
571 
572 	SPDK_DEBUGLOG(scsi, "PR IN READ KEYS\n");
573 	keys = (struct spdk_scsi_pr_in_read_keys_data *)data;
574 
575 	to_be32(&keys->header.pr_generation, lun->pr_generation);
576 	TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
577 		if (((count + 1) * 8 + sizeof(keys->header)) > data_len) {
578 			break;
579 		}
580 		to_be64(&keys->rkeys[count], reg->rkey);
581 		count++;
582 	}
583 	to_be32(&keys->header.additional_len, count * 8);
584 
585 	return (sizeof(keys->header) + count * 8);
586 }
587 
588 static int
589 scsi_pr_in_read_reservations(struct spdk_scsi_task *task,
590 			     uint8_t *data, uint16_t data_len)
591 {
592 	struct spdk_scsi_lun *lun = task->lun;
593 	struct spdk_scsi_pr_in_read_reservations_data *param;
594 	bool all_regs = false;
595 
596 	SPDK_DEBUGLOG(scsi, "PR IN READ RESERVATIONS\n");
597 	param = (struct spdk_scsi_pr_in_read_reservations_data *)(data);
598 
599 	to_be32(&param->header.pr_generation, lun->pr_generation);
600 	if (scsi_pr_has_reservation(lun)) {
601 		all_regs = scsi_pr_is_all_registrants_type(lun);
602 		if (all_regs) {
603 			to_be64(&param->rkey, 0);
604 		} else {
605 			to_be64(&param->rkey, lun->reservation.crkey);
606 		}
607 		to_be32(&param->header.additional_len, 16);
608 		param->scope = SPDK_SCSI_PR_LU_SCOPE;
609 		param->type = lun->reservation.rtype;
610 		SPDK_DEBUGLOG(scsi, "READ RESERVATIONS with valid reservation\n");
611 		return sizeof(*param);
612 	}
613 
614 	/* no reservation */
615 	to_be32(&param->header.additional_len, 0);
616 	SPDK_DEBUGLOG(scsi, "READ RESERVATIONS no reservation\n");
617 	return sizeof(param->header);
618 }
619 
620 static int
621 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 	SPDK_DEBUGLOG(scsi, "PR IN REPORT CAPABILITIES\n");
627 	param = (struct spdk_scsi_pr_in_report_capabilities_data *)data;
628 
629 	memset(param, 0, sizeof(*param));
630 	to_be16(&param->length, sizeof(*param));
631 	/* Compatible reservation handling to support RESERVE/RELEASE defined in SPC-2 */
632 	param->crh = 1;
633 	param->tmv = 1;
634 	param->wr_ex = 1;
635 	param->ex_ac = 1;
636 	param->wr_ex_ro = 1;
637 	param->ex_ac_ro = 1;
638 	param->wr_ex_ar = 1;
639 	param->ex_ac_ar = 1;
640 
641 	return sizeof(*param);
642 }
643 
644 static int
645 scsi_pr_in_read_full_status(struct spdk_scsi_task *task,
646 			    uint8_t *data, uint16_t data_len)
647 {
648 	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 	bool all_regs = false;
653 	uint32_t add_len = 0;
654 
655 	SPDK_DEBUGLOG(scsi, "PR IN READ FULL STATUS\n");
656 
657 	all_regs = scsi_pr_is_all_registrants_type(lun);
658 	param = (struct spdk_scsi_pr_in_full_status_data *)data;
659 	to_be32(&param->header.pr_generation, lun->pr_generation);
660 
661 	TAILQ_FOREACH_SAFE(reg, &lun->reg_head, link, tmp) {
662 		desc = (struct spdk_scsi_pr_in_full_status_desc *)
663 		       ((uint8_t *)param->desc_list + add_len);
664 		if (add_len + sizeof(*desc) + sizeof(param->header) > data_len) {
665 			break;
666 		}
667 		add_len += sizeof(*desc);
668 		desc->rkey = reg->rkey;
669 		if (all_regs || lun->reservation.holder == reg) {
670 			desc->r_holder = true;
671 			desc->type = lun->reservation.rtype;
672 		} else {
673 			desc->r_holder = false;
674 			desc->type = 0;
675 		}
676 		desc->all_tg_pt = 0;
677 		desc->scope = SPDK_SCSI_PR_LU_SCOPE;
678 		desc->relative_target_port_id = reg->relative_target_port_id;
679 		if (add_len + reg->transport_id_len + sizeof(param->header) > data_len) {
680 			break;
681 		}
682 		add_len += reg->transport_id_len;
683 		memcpy(&desc->transport_id, reg->transport_id, reg->transport_id_len);
684 		to_be32(&desc->desc_len, reg->transport_id_len);
685 	}
686 	to_be32(&param->header.additional_len, add_len);
687 
688 	return (sizeof(param->header) + add_len);
689 }
690 
691 int
692 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 	int rc = 0;
697 
698 	action = cdb[1] & 0x1f;
699 	if (data_len < sizeof(struct spdk_scsi_pr_in_read_header)) {
700 		goto invalid;
701 	}
702 
703 	switch (action) {
704 	case SPDK_SCSI_PR_IN_READ_KEYS:
705 		rc = scsi_pr_in_read_keys(task, data, data_len);
706 		break;
707 	case SPDK_SCSI_PR_IN_READ_RESERVATION:
708 		if (data_len < sizeof(struct spdk_scsi_pr_in_read_reservations_data)) {
709 			goto invalid;
710 		}
711 		rc = scsi_pr_in_read_reservations(task, data, data_len);
712 		break;
713 	case SPDK_SCSI_PR_IN_REPORT_CAPABILITIES:
714 		rc = scsi_pr_in_report_capabilities(task, data, data_len);
715 		break;
716 	case SPDK_SCSI_PR_IN_READ_FULL_STATUS:
717 		rc = scsi_pr_in_read_full_status(task, data, data_len);
718 		break;
719 	default:
720 		goto invalid;
721 	}
722 
723 	return rc;
724 
725 invalid:
726 	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 	return -EINVAL;
731 }
732 
733 int
734 scsi_pr_check(struct spdk_scsi_task *task)
735 {
736 	struct spdk_scsi_lun *lun = task->lun;
737 	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 	bool dma_to_device = false;
742 
743 	/* no reservation holders */
744 	if (!scsi_pr_has_reservation(lun)) {
745 		return 0;
746 	}
747 
748 	rtype = lun->reservation.rtype;
749 	assert(rtype != 0);
750 
751 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
752 	/* current I_T nexus hold the reservation */
753 	if (scsi_pr_registrant_is_holder(lun, reg)) {
754 		return 0;
755 	}
756 
757 	/* reservation is held by other I_T nexus */
758 	switch (cdb[0]) {
759 	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 		return 0;
775 	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 		if (!reg) {
782 			SPDK_DEBUGLOG(scsi, "CHECK: current I_T nexus "
783 				      "is not registered, cdb 0x%x\n", cdb[0]);
784 			goto conflict;
785 		}
786 		return 0;
787 	case SPDK_SPC_PERSISTENT_RESERVE_OUT:
788 		action = cdb[1] & 0x1f;
789 		SPDK_DEBUGLOG(scsi, "CHECK: PR OUT action %u\n", action);
790 		switch (action) {
791 		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 			if (!reg) {
796 				SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
797 				goto conflict;
798 			}
799 			return 0;
800 		case SPDK_SCSI_PR_OUT_REGISTER:
801 		case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
802 			return 0;
803 		case SPDK_SCSI_PR_OUT_REG_AND_MOVE:
804 			SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
805 			goto conflict;
806 		default:
807 			SPDK_ERRLOG("CHECK: PR OUT invalid action %u\n", action);
808 			goto conflict;
809 		}
810 
811 	/* For most SBC R/W commands */
812 	default:
813 		break;
814 	}
815 
816 	switch (cdb[0]) {
817 	case SPDK_SBC_READ_6:
818 	case SPDK_SBC_READ_10:
819 	case SPDK_SBC_READ_12:
820 	case SPDK_SBC_READ_16:
821 		break;
822 	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 		dma_to_device = true;
830 		break;
831 	default:
832 		SPDK_ERRLOG("CHECK: unsupported SCSI command cdb 0x%x\n", cdb[0]);
833 		goto conflict;
834 	}
835 
836 	switch (rtype) {
837 	case SPDK_SCSI_PR_WRITE_EXCLUSIVE:
838 		if (dma_to_device) {
839 			SPDK_ERRLOG("CHECK: Write Exclusive reservation type "
840 				    "rejects command 0x%x\n", cdb[0]);
841 			goto conflict;
842 		}
843 		break;
844 	case SPDK_SCSI_PR_EXCLUSIVE_ACCESS:
845 		SPDK_ERRLOG("CHECK: Exclusive Access reservation type "
846 			    "rejects command 0x%x\n", cdb[0]);
847 		goto conflict;
848 	case SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY:
849 	case SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
850 		if (!reg && dma_to_device) {
851 			SPDK_ERRLOG("CHECK: Registrants only reservation "
852 				    "type  reject command 0x%x\n", cdb[0]);
853 			goto conflict;
854 		}
855 		break;
856 	case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY:
857 	case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
858 		if (!reg) {
859 			SPDK_ERRLOG("CHECK: All Registrants reservation "
860 				    "type  reject command 0x%x\n", cdb[0]);
861 			goto conflict;
862 		}
863 		break;
864 	default:
865 		break;
866 	}
867 
868 	return 0;
869 
870 conflict:
871 	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 	return -1;
876 }
877 
878 static int
879 scsi2_check_reservation_conflict(struct spdk_scsi_task *task)
880 {
881 	struct spdk_scsi_lun *lun = task->lun;
882 	struct spdk_scsi_pr_registrant *reg;
883 	bool conflict = false;
884 
885 	reg = scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
886 	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 		if (scsi_pr_registrant_is_holder(lun, reg)) {
909 			return 1;
910 		}
911 
912 		if (lun->reservation.rtype == SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY ||
913 		    lun->reservation.rtype == SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY) {
914 			return 1;
915 		}
916 
917 		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 		conflict = TAILQ_EMPTY(&lun->reg_head) ? false : true;
930 	}
931 
932 	if (conflict) {
933 		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 		return -1;
938 	}
939 
940 	return 0;
941 }
942 
943 int
944 scsi2_reserve(struct spdk_scsi_task *task, uint8_t *cdb)
945 {
946 	struct spdk_scsi_lun *lun = task->lun;
947 	struct spdk_scsi_pr_registrant *reg = &lun->scsi2_holder;
948 	int ret;
949 
950 	/* Obsolete Bits and LongID set, returning ILLEGAL_REQUEST */
951 	if (cdb[1] & 0x3) {
952 		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 		return -1;
957 	}
958 
959 	ret = scsi2_check_reservation_conflict(task);
960 	/* PERSISTENT RESERVE is enabled */
961 	if (ret == 1) {
962 		return 0;
963 	} else if (ret < 0) {
964 		return ret;
965 	}
966 
967 	/* SPC2 RESERVE */
968 	reg->initiator_port = task->initiator_port;
969 	if (task->initiator_port) {
970 		snprintf(reg->initiator_port_name, sizeof(reg->initiator_port_name), "%s",
971 			 task->initiator_port->name);
972 		reg->transport_id_len = task->initiator_port->transport_id_len;
973 		memcpy(reg->transport_id, task->initiator_port->transport_id,
974 		       reg->transport_id_len);
975 	}
976 	reg->target_port = task->target_port;
977 	if (task->target_port) {
978 		snprintf(reg->target_port_name, sizeof(reg->target_port_name), "%s",
979 			 task->target_port->name);
980 	}
981 
982 	lun->reservation.flags = SCSI_SPC2_RESERVE;
983 	lun->reservation.holder = &lun->scsi2_holder;
984 
985 	return 0;
986 }
987 
988 int
989 scsi2_release(struct spdk_scsi_task *task)
990 {
991 	struct spdk_scsi_lun *lun = task->lun;
992 	int ret;
993 
994 	ret = scsi2_check_reservation_conflict(task);
995 	/* PERSISTENT RESERVE is enabled */
996 	if (ret == 1) {
997 		return 0;
998 	} else if (ret < 0) {
999 		return ret;
1000 	}
1001 
1002 	if (!(lun->reservation.flags & SCSI_SPC2_RESERVE)) {
1003 		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 		return -EINVAL;
1008 	}
1009 
1010 	memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
1011 	memset(&lun->scsi2_holder, 0, sizeof(struct spdk_scsi_pr_registrant));
1012 
1013 	return 0;
1014 }
1015 
1016 int
1017 scsi2_reserve_check(struct spdk_scsi_task *task)
1018 {
1019 	struct spdk_scsi_lun *lun = task->lun;
1020 	uint8_t *cdb = task->cdb;
1021 
1022 	switch (cdb[0]) {
1023 	case SPDK_SPC_INQUIRY:
1024 	case SPDK_SPC2_RELEASE_6:
1025 	case SPDK_SPC2_RELEASE_10:
1026 		return 0;
1027 
1028 	default:
1029 		break;
1030 	}
1031 
1032 	/* no reservation holders */
1033 	if (!scsi_pr_has_reservation(lun)) {
1034 		return 0;
1035 	}
1036 
1037 	if (scsi2_it_nexus_is_holder(lun, task->initiator_port, task->target_port)) {
1038 		return 0;
1039 	}
1040 
1041 	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 	return -1;
1046 }
1047