scsi: add persistent reservation out with reserve service action support
An application client creates a persistent reservation by issuing a PERSISTENT RESERVE OUT command with RESERVE service action through a registered I_T nexus with RESERVATION KEY and TYPE, and persistent reservation has a scope of LUN, only one persistent reservation is allowed at a time per LUN. Change-Id: I052d0ddd439dd9994c0793218dd5c5d6ed176d2c Signed-off-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/436089 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
d0d19eb82e
commit
601fbbf969
@ -125,6 +125,17 @@ spdk_scsi_pr_release_reservation(struct spdk_scsi_lun *lun, struct spdk_scsi_pr_
|
||||
memset(&lun->reservation, 0, sizeof(struct spdk_scsi_pr_reservation));
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_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)
|
||||
{
|
||||
lun->reservation.rtype = type;
|
||||
lun->reservation.crkey = rkey;
|
||||
lun->reservation.holder = holder;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_scsi_pr_unregister_registrant(struct spdk_scsi_lun *lun,
|
||||
struct spdk_scsi_pr_registrant *reg)
|
||||
@ -151,6 +162,68 @@ spdk_scsi_pr_replace_registrant_key(struct spdk_scsi_lun *lun,
|
||||
lun->pr_generation++;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_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)
|
||||
{
|
||||
struct spdk_scsi_lun *lun = task->lun;
|
||||
struct spdk_scsi_pr_registrant *reg;
|
||||
|
||||
SPDK_DEBUGLOG(SPDK_LOG_SCSI, "PR OUT RESERVE: rkey 0x%"PRIx64", requested "
|
||||
"reservation type %u, type %u\n", rkey, rtype, lun->reservation.rtype);
|
||||
|
||||
/* TODO: don't support now */
|
||||
if (spec_i_pt || all_tg_pt || aptpl) {
|
||||
SPDK_ERRLOG("Unspported spec_i_pt/all_tg_pt fields "
|
||||
"or invalid aptpl field\n");
|
||||
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
||||
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
|
||||
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
|
||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = spdk_scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
|
||||
/* No registration for the I_T nexus */
|
||||
if (!reg) {
|
||||
SPDK_ERRLOG("No registration\n");
|
||||
goto conflict;
|
||||
}
|
||||
|
||||
/* invalid reservation key */
|
||||
if (reg->rkey != rkey) {
|
||||
SPDK_ERRLOG("Reservation key 0x%"PRIx64" don't match 0x%"PRIx64"\n",
|
||||
rkey, reg->rkey);
|
||||
goto conflict;
|
||||
}
|
||||
|
||||
/* reservation holder already exists */
|
||||
if (lun->reservation.holder) {
|
||||
if (rtype != lun->reservation.rtype) {
|
||||
SPDK_ERRLOG("Reservation type doesn't match\n");
|
||||
goto conflict;
|
||||
}
|
||||
|
||||
if (!spdk_scsi_pr_registrant_is_holder(lun, reg)) {
|
||||
SPDK_ERRLOG("Only 1 holder is allowed for type %u\n", rtype);
|
||||
goto conflict;
|
||||
}
|
||||
} else {
|
||||
/* current I_T nexus is the first reservation holder */
|
||||
spdk_scsi_pr_reserve_reservation(lun, rtype, rkey, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
conflict:
|
||||
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
|
||||
SPDK_SCSI_SENSE_NO_SENSE,
|
||||
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
|
||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_scsi_pr_out_register(struct spdk_scsi_task *task,
|
||||
enum spdk_scsi_pr_out_service_action_code action,
|
||||
@ -229,9 +302,13 @@ spdk_scsi_pr_out(struct spdk_scsi_task *task,
|
||||
uint64_t rkey, sa_rkey;
|
||||
uint8_t spec_i_pt, all_tg_pt, aptpl;
|
||||
enum spdk_scsi_pr_out_service_action_code action;
|
||||
enum spdk_scsi_pr_scope_code scope;
|
||||
enum spdk_scsi_pr_type_code rtype;
|
||||
struct spdk_scsi_pr_out_param_list *param = (struct spdk_scsi_pr_out_param_list *)data;
|
||||
|
||||
action = cdb[1] & 0x0f;
|
||||
scope = (cdb[2] >> 4) & 0x0f;
|
||||
rtype = cdb[2] & 0x0f;
|
||||
|
||||
rkey = from_be64(¶m->rkey);
|
||||
sa_rkey = from_be64(¶m->sa_rkey);
|
||||
@ -245,6 +322,13 @@ spdk_scsi_pr_out(struct spdk_scsi_task *task,
|
||||
rc = spdk_scsi_pr_out_register(task, action, rkey, sa_rkey,
|
||||
spec_i_pt, all_tg_pt, aptpl);
|
||||
break;
|
||||
case SPDK_SCSI_PR_OUT_RESERVE:
|
||||
if (scope != SPDK_SCSI_PR_LU_SCOPE) {
|
||||
goto invalid;
|
||||
}
|
||||
rc = spdk_scsi_pr_out_reserve(task, rtype, rkey,
|
||||
spec_i_pt, all_tg_pt, aptpl);
|
||||
break;
|
||||
default:
|
||||
SPDK_ERRLOG("Invalid service action code %u\n", action);
|
||||
goto invalid;
|
||||
|
Loading…
Reference in New Issue
Block a user