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