[stgt] [PATCH] persistent reservation support

Mark Harvey markh794 at gmail.com
Wed Nov 4 10:41:37 CET 2009


Mark Harvey wrote:
> I'll be testing over the next few days and will advise of any success/failures.
>
> Many thanks
> Mark
>   

Sorry for taking so long...

Went looking for a script I wrote to put PR thru its paces using 
sg_persist.. Can't find it :(

Anyway, started to relearn sg_persist and just when things got 
interesting, my battery died..

One report:
- Incorrectly attempting to set a registration results in a RESERVATION 
CONFLICT instead of (insert correct sense code here)???

The 'script' (start thereof) until I can re-learn sg_persist.
#!/bin/bash

KEY1=ABC123
KEY2=BAD123
DEV=`lsscsi -g|awk '/HD100/ {print $7}'`

# Use sg_persist to put SCSI Persistent Reservation thru its paces.
echo "Should report 'no keys'"
sg_persist --no-inquiry -i -k $DEV

echo "Should report 'key' ABC123"
sg_persist -n -o --register --param-rk $KEY1 --param-sark 0 $DEV
sg_persist -n -i -k $DEV

More testing tomorrow with a charged battery..

Mark
> On Mon, Oct 26, 2009 at 12:16 AM, FUJITA Tomonori
> <fujita.tomonori at lab.ntt.co.jp> wrote:
>   
>> This is the initial try to support persistent reservation
>>
>> I finished only READ_KEYS, READ_RESERVATION, REPORT_CAPABILITIES, and
>> REGISTER, RESERVE, RELEASE (and they are not complete).
>>
>> So I guess that this enables you to only play sg_persist and see if
>> commands are rejected properly. But I'd really appreciate any input
>> (comments, test results, patches, etc). As I wrote before, I'd like to
>> add persistent reservation support and release 1.0.0 this year.
>>
>> =
>> From: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
>> Date: Sun, 25 Oct 2009 22:03:41 +0900
>> Subject: [PATCH] persistent reservation support
>>
>> Signed-off-by: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
>> ---
>>  usr/sbc.c    |   38 +++---
>>  usr/scc.c    |    2 +-
>>  usr/scsi.c   |   40 +++++
>>  usr/scsi.h   |   31 ++++
>>  usr/smc.c    |    2 +-
>>  usr/spc.c    |  488 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  usr/spc.h    |    8 +-
>>  usr/ssc.c    |    2 +-
>>  usr/target.c |   10 ++
>>  usr/tgtd.h   |   21 +++
>>  10 files changed, 611 insertions(+), 31 deletions(-)
>>
>> diff --git a/usr/sbc.c b/usr/sbc.c
>> index 710165d..f443508 100644
>> --- a/usr/sbc.c
>> +++ b/usr/sbc.c
>> @@ -284,9 +284,9 @@ static struct device_type_template sbc_template = {
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>
>> -               {sbc_rw,},
>> +               {sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
>>                {spc_illegal_op,},
>> -               {sbc_rw,},
>> +               {sbc_rw, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> @@ -299,14 +299,14 @@ static struct device_type_template sbc_template = {
>>                {spc_inquiry,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {sbc_mode_select},
>> +               {sbc_mode_select, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {sbc_reserve,},
>>                {sbc_release,},
>>
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {spc_mode_sense,},
>> -               {spc_start_stop,},
>> +               {spc_mode_sense, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>> +               {spc_start_stop, NULL, PR_SPECIAL},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> @@ -322,14 +322,14 @@ static struct device_type_template sbc_template = {
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>
>> -               {sbc_rw},
>> +               {sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
>>                {spc_illegal_op,},
>> -               {sbc_rw},
>> +               {sbc_rw, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {sbc_verify,},
>> +               {sbc_verify, NULL, PR_EA_FA|PR_EA_FN},
>>
>>                /* 0x30 */
>>                {spc_illegal_op,},
>> @@ -337,7 +337,7 @@ static struct device_type_template sbc_template = {
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {sbc_sync_cache,},
>> +               {sbc_sync_cache, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>
>> @@ -358,18 +358,18 @@ static struct device_type_template sbc_template = {
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {sbc_mode_select,},
>> +               {sbc_mode_select, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {spc_mode_sense,},
>> -               {spc_illegal_op,},
>> -               {spc_illegal_op,},
>> +               {spc_mode_sense, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> +               {spc_service_action, persistent_reserve_in_actions,},
>> +               {spc_service_action, persistent_reserve_out_actions,},
>>
>>                [0x60 ... 0x7f] = {spc_illegal_op,},
>>
>> @@ -383,9 +383,9 @@ static struct device_type_template sbc_template = {
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>
>> -               {sbc_rw,},
>> +               {sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
>>                {spc_illegal_op,},
>> -               {sbc_rw,},
>> +               {sbc_rw, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> @@ -394,7 +394,7 @@ static struct device_type_template sbc_template = {
>>
>>                /* 0x90 */
>>                {spc_illegal_op,},
>> -               {sbc_sync_cache,},
>> +               {sbc_sync_cache, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> @@ -415,15 +415,15 @@ static struct device_type_template sbc_template = {
>>                {spc_report_luns,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {spc_maint_in, maint_in_service_actions,},
>> +               {spc_service_action, maint_in_service_actions,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>
>> -               {sbc_rw,},
>> +               {sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
>>                {spc_illegal_op,},
>> -               {sbc_rw,},
>> +               {sbc_rw, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> diff --git a/usr/scc.c b/usr/scc.c
>> index eed48a0..27bc07b 100644
>> --- a/usr/scc.c
>> +++ b/usr/scc.c
>> @@ -143,7 +143,7 @@ static struct device_type_template scc_template = {
>>                {spc_report_luns,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {spc_maint_in, maint_in_service_actions,},
>> +               {spc_service_action, maint_in_service_actions,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> diff --git a/usr/scsi.c b/usr/scsi.c
>> index daf4aef..61a2d7e 100644
>> --- a/usr/scsi.c
>> +++ b/usr/scsi.c
>> @@ -183,6 +183,43 @@ uint32_t scsi_rw_count(uint8_t *scb)
>>        return cnt;
>>  }
>>
>> +static int scsi_pr_access_check(struct scsi_cmd *cmd)
>> +{
>> +       unsigned char op = cmd->scb[0];
>> +       uint8_t bits;
>> +       uint8_t pr_type;
>> +       struct registration *reg;
>> +       int conflict = 0;
>> +
>> +       if (!cmd->dev->pr_holder)
>> +               return 0;
>> +
>> +       reg = lookup_registration_by_nexus(cmd->dev, cmd->cmd_itn_id);
>> +
>> +       if (reg == cmd->dev->pr_holder)
>> +               return 0;
>> +
>> +       pr_type = cmd->dev->pr_holder->pr_type;
>> +       bits = cmd->dev->dev_type_template.ops[op].pr_conflict_bits;
>> +
>> +       if (pr_type == PR_TYPE_WRITE_EXCLUSIVE ||
>> +           pr_type == PR_TYPE_EXCLUSIVE_ACCESS)
>> +               conflict = bits & (PR_WE_FA|PR_EA_FA);
>> +       else {
>> +               if (reg)
>> +                       conflict = bits & PR_RR_FR;
>> +               else {
>> +                       if (pr_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
>> +                           pr_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG)
>> +                               conflict = bits & PR_WE_FN;
>> +                       else
>> +                               conflict = bits & PR_EA_FN;
>> +               }
>> +       }
>> +
>> +       return conflict;
>> +}
>> +
>>  int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd)
>>  {
>>        int ret;
>> @@ -227,6 +264,9 @@ int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd)
>>                        return SAM_STAT_CHECK_CONDITION;
>>        }
>>
>> +       if (scsi_pr_access_check(cmd))
>> +               return SAM_STAT_RESERVATION_CONFLICT;
>> +
>>        return cmd->dev->dev_type_template.ops[op].cmd_perform(host_no, cmd);
>>  }
>>
>> diff --git a/usr/scsi.h b/usr/scsi.h
>> index 84fadff..9fd78fd 100644
>> --- a/usr/scsi.h
>> +++ b/usr/scsi.h
>> @@ -201,12 +201,14 @@
>>  #define ASC_INVALID_FIELD_IN_CDB               0x2400
>>  #define ASC_LUN_NOT_SUPPORTED                  0x2500
>>  #define ASC_INVALID_FIELD_IN_PARMS             0x2600
>> +#define ASC_INVALID_RELEASE_OF_PERSISTENT_RESERVATION  0x2604
>>  #define ASC_INCOMPATIBLE_FORMAT                        0x3005
>>  #define ASC_SAVING_PARMS_UNSUP                 0x3900
>>  #define ASC_MEDIUM_DEST_FULL                   0x3b0d
>>  #define ASC_MEDIUM_SRC_EMPTY                   0x3b0e
>>  #define ASC_POSITION_PAST_BOM                  0x3b0c
>>  #define ASC_MEDIUM_REMOVAL_PREVENTED           0x5302
>> +#define ASC_INSUFFICENT_REGISTRATION_RESOURCES 0x5504
>>  #define ASC_BAD_MICROCODE_DETECTED             0x8283
>>
>>  /* Key 6: Unit Attention */
>> @@ -214,6 +216,7 @@
>>  #define ASC_POWERON_RESET                      0x2900
>>  #define ASC_I_T_NEXUS_LOSS_OCCURRED            0x2907
>>  #define ASC_MODE_PARAMETERS_CHANGED            0x2a01
>> +#define ASC_RESERVATIONS_RELEASED              0x2a04
>>  #define ASC_INSUFFICIENT_TIME_FOR_OPERATION    0x2e00
>>  #define ASC_COMMANDS_CLEARED_BY_ANOTHOR_INI    0x2f00
>>  #define ASC_MICROCODE_DOWNLOADED               0x3f01
>> @@ -225,4 +228,32 @@
>>  #define ASC_WRITE_PROTECT                      0x2700
>>  #define ASC_MEDIUM_OVERWRITE_ATTEMPTED         0x300c
>>
>> +
>> +/* PERSISTENT_RESERVE_IN service action codes */
>> +#define PR_IN_READ_KEYS                                0x00
>> +#define PR_IN_READ_RESERVATION                 0x01
>> +#define PR_IN_REPORT_CAPABILITIES              0x02
>> +#define PR_IN_READ_FULL_STATUS                 0x03
>> +
>> +/* PERSISTENT_RESERVE_OUT service action codes */
>> +#define PR_OUT_REGISTER                                0x00
>> +#define PR_OUT_RESERVE                         0x01
>> +#define PR_OUT_RELEASE                         0x02
>> +#define PR_OUT_CLEAR                           0x03
>> +#define PR_OUT_PREEMPT                         0x04
>> +#define PR_OUT_PREEMPT_AND_ABORT               0x05
>> +#define PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY        0x06
>> +#define PR_OUT_REGISTER_AND_MOVE               0x07
>> +
>> +/* Persistent Reservation scope */
>> +#define PR_LU_SCOPE                            0x00
>> +
>> +/* Persistent Reservation Type Mask format */
>> +#define PR_TYPE_WRITE_EXCLUSIVE                        0x01
>> +#define PR_TYPE_EXCLUSIVE_ACCESS               0x03
>> +#define PR_TYPE_WRITE_EXCLUSIVE_REGONLY                0x05
>> +#define PR_TYPE_EXCLUSIVE_ACCESS_REGONLY       0x06
>> +#define PR_TYPE_WRITE_EXCLUSIVE_ALLREG         0x07
>> +#define PR_TYPE_EXCLUSIVE_ACCESS_ALLREG                0x08
>> +
>>  #endif
>> diff --git a/usr/smc.c b/usr/smc.c
>> index ab36e9c..6430882 100644
>> --- a/usr/smc.c
>> +++ b/usr/smc.c
>> @@ -861,7 +861,7 @@ struct device_type_template smc_template = {
>>                {spc_report_luns,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {spc_maint_in, maint_in_service_actions,},
>> +               {spc_service_action, maint_in_service_actions,},
>>                {spc_illegal_op,},
>>                {smc_move_medium,},
>>                {spc_illegal_op,},
>> diff --git a/usr/spc.c b/usr/spc.c
>> index 1a75766..96ac8db 100644
>> --- a/usr/spc.c
>> +++ b/usr/spc.c
>> @@ -720,7 +720,7 @@ struct service_action maint_in_service_actions[] = {
>>        {0, NULL}
>>  };
>>
>> -struct service_action *
>> +static struct service_action *
>>  find_service_action(struct service_action *service_action, uint32_t action)
>>  {
>>        while (service_action->cmd_perform) {
>> @@ -731,16 +731,20 @@ find_service_action(struct service_action *service_action, uint32_t action)
>>        return NULL;
>>  }
>>
>> -/**
>> - * This functions emulates the various commands using the 0xa3 cdb opcode
>> +/*
>> + * This is useful for the various commands using the SERVICE ACTION
>> + * format.
>>  */
>> -int spc_maint_in(int host_no, struct scsi_cmd *cmd)
>> +int spc_service_action(int host_no, struct scsi_cmd *cmd)
>>  {
>>        uint8_t action;
>> -       struct service_action *service_action;
>> +       unsigned char op = cmd->scb[0];
>> +       struct service_action *service_action, *actions;
>>
>>        action = cmd->scb[1] & 0x1f;
>> -       service_action = find_service_action(maint_in_service_actions, action);
>> +       actions = cmd->dev->dev_type_template.ops[op].service_actions;
>> +
>> +       service_action = find_service_action(actions, action);
>>
>>        if (!service_action) {
>>                scsi_set_in_resid_by_actual(cmd, 0);
>> @@ -752,6 +756,477 @@ int spc_maint_in(int host_no, struct scsi_cmd *cmd)
>>        return service_action->cmd_perform(host_no, cmd);
>>  }
>>
>> +static int spc_pr_read_keys(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint8_t key = ILLEGAL_REQUEST;
>> +       struct registration *reg;
>> +       uint16_t len;
>> +       uint32_t keys;
>> +       uint8_t *buf;
>> +       int off;
>> +
>> +       len = get_unaligned_be16(cmd->scb + 7);
>> +       if (len < 8)
>> +               goto sense;
>> +
>> +       if (scsi_get_in_length(cmd) < len)
>> +               goto sense;
>> +
>> +       buf = scsi_get_in_buffer(cmd);
>> +       memset(buf, 0, len);
>> +
>> +       len &= ~(8 - 1);
>> +       keys = 0;
>> +       off = 8;
>> +
>> +       put_unaligned_be32(cmd->dev->prgeneration, &buf[0]);
>> +
>> +       list_for_each_entry(reg, &cmd->dev->registration_list,
>> +                           registration_siblings) {
>> +               if (!len)
>> +                       continue;
>> +               put_unaligned_be64(reg->key, &buf[off]);
>> +
>> +               len -= 8;
>> +               keys++;
>> +       }
>> +
>> +       put_unaligned_be32(keys * 8, &buf[4]);
>> +
>> +       scsi_set_in_resid_by_actual(cmd, keys * 8 + 8);
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +static int spc_pr_read_reservation(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint8_t key = ILLEGAL_REQUEST;
>> +       struct registration *reg;
>> +       uint16_t len;
>> +       uint8_t *buf;
>> +       uint64_t res_key;
>> +
>> +       reg = cmd->dev->pr_holder;
>> +
>> +       if (reg)
>> +               len = 24;
>> +       else
>> +               len = 8;
>> +
>> +       if (get_unaligned_be16(cmd->scb + 7) < len)
>> +               goto sense;
>> +
>> +       if (scsi_get_in_length(cmd) < len)
>> +               goto sense;
>> +
>> +       buf = scsi_get_in_buffer(cmd);
>> +       memset(buf, 0, len);
>> +
>> +       put_unaligned_be32(cmd->dev->prgeneration, &buf[0]);
>> +
>> +       if (reg) {
>> +               put_unaligned_be32(16, &buf[4]);
>> +
>> +               if (reg->pr_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
>> +                   reg->pr_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)
>> +                       res_key = 0;
>> +               else
>> +                       res_key = reg->key;
>> +
>> +               put_unaligned_be32(res_key, &buf[8]);
>> +               buf[21] = ((reg->pr_scope << 4) & 0xf0) | (reg->pr_type & 0x0f);
>> +       } else
>> +               put_unaligned_be32(0, &buf[4]);
>> +
>> +       scsi_set_in_resid_by_actual(cmd, len);
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +static int spc_pr_report_capabilities(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint8_t key = ILLEGAL_REQUEST;
>> +       uint8_t *buf;
>> +       uint16_t len;
>> +
>> +       len = get_unaligned_be16(cmd->scb + 7);
>> +       if (len < 8)
>> +               goto sense;
>> +
>> +       if (scsi_get_in_length(cmd) < len)
>> +               goto sense;
>> +
>> +       buf = scsi_get_in_buffer(cmd);
>> +
>> +       len = 8;
>> +
>> +       memset(buf, 0, len);
>> +
>> +       put_unaligned_be16(len, &buf[0]);
>> +
>> +       /* we don't set any capability for now */
>> +
>> +       /* Persistent Reservation Type Mask format */
>> +       buf[4] |= 0x80; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
>> +       buf[4] |= 0x40; /* PR_TYPE_EXCLUSIVE_ACCESS_REGONLY */
>> +       buf[4] |= 0x20; /* PR_TYPE_WRITE_EXCLUSIVE_REGONLY */
>> +       buf[4] |= 0x08; /* PR_TYPE_EXCLUSIVE_ACCESS */
>> +       buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */
>> +       buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +static int spc_pr_read_full_status(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint8_t key = ILLEGAL_REQUEST;
>> +       struct registration *reg;
>> +       uint16_t len;
>> +       uint32_t keys;
>> +       uint8_t *buf;
>> +       int off;
>> +
>> +       len = get_unaligned_be16(cmd->scb + 7);
>> +       if (len < 8)
>> +               goto sense;
>> +       if (scsi_get_in_length(cmd) < len)
>> +               goto sense;
>> +
>> +       buf = scsi_get_in_buffer(cmd);
>> +       memset(buf, 0, len);
>> +
>> +       put_unaligned_be32(cmd->dev->prgeneration, &buf[0]);
>> +
>> +       len &= ~(24 - 1);
>> +       off = 8;
>> +       keys = 0;
>> +
>> +       list_for_each_entry(reg, &cmd->dev->registration_list,
>> +                           registration_siblings) {
>> +
>> +               if (!len)
>> +                       continue;
>> +
>> +               put_unaligned_be64(reg->key, &buf[off + 0]);
>> +
>> +               /* TODO */
>> +
>> +               put_unaligned_be32(0, &buf[off + 20]);
>> +
>> +               keys++;
>> +               len -= 24;
>> +               off += 24;
>> +       }
>> +
>> +       put_unaligned_be32(keys * 24, &buf[4]);
>> +
>> +       scsi_set_in_resid_by_actual(cmd, keys * 24 + 8);
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +struct service_action persistent_reserve_in_actions[] = {
>> +       {PR_IN_READ_KEYS, spc_pr_read_keys},
>> +       {PR_IN_READ_RESERVATION, spc_pr_read_reservation},
>> +       {PR_IN_REPORT_CAPABILITIES, spc_pr_report_capabilities},
>> +       {PR_IN_READ_FULL_STATUS, spc_pr_read_full_status},
>> +       {0, NULL},
>> +};
>> +
>> +struct registration *lookup_registration_by_nexus(struct scsi_lu *lu,
>> +                                                 uint64_t nexus_id)
>> +{
>> +       struct registration *reg;
>> +
>> +       list_for_each_entry(reg, &lu->registration_list, registration_siblings) {
>> +               if (reg->nexus_id == nexus_id)
>> +                       return reg;
>> +       }
>> +
>> +       return NULL;
>> +}
>> +
>> +static int check_pr_out_basic_parameter(struct scsi_cmd *cmd)
>> +{
>> +       uint8_t spec_i_pt, all_tg_pt, aptpl;
>> +       uint8_t *buf;
>> +       uint16_t len = 24;
>> +
>> +       if (get_unaligned_be16(cmd->scb + 7) < len)
>> +               return 1;
>> +
>> +       if (scsi_get_out_length(cmd) < len)
>> +               return 1;
>> +
>> +       buf = scsi_get_out_buffer(cmd);
>> +
>> +       spec_i_pt = buf[20] & (1U << 3);
>> +       all_tg_pt = buf[20] & (1U << 2);
>> +       aptpl = buf[20] & (1U << 0);
>> +
>> +       if (spec_i_pt | all_tg_pt | aptpl) {
>> +               /*
>> +                * for now, we say that we don't support these bits
>> +                * via REPORT CAPABILITIES.
>> +                */
>> +               return 1;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int spc_pr_register(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint8_t force, key = ILLEGAL_REQUEST;
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint64_t res_key, sa_res_key;
>> +       int ret;
>> +       uint8_t *buf;
>> +       struct registration *reg;
>> +
>> +       force = ((cmd->scb[1] & 0x1f) == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY);
>> +
>> +       ret = check_pr_out_basic_parameter(cmd);
>> +       if (ret)
>> +               goto sense;
>> +
>> +       buf = scsi_get_out_buffer(cmd);
>> +
>> +       res_key = get_unaligned_be64(buf);
>> +       sa_res_key = get_unaligned_be64(buf + 8);
>> +
>> +       reg = lookup_registration_by_nexus(cmd->dev, cmd->cmd_itn_id);
>> +       if (reg) {
>> +               if (force || reg->key == res_key) {
>> +                       if (sa_res_key)
>> +                               reg->key = sa_res_key;
>> +                       else {
>> +                               /* unregister */
>> +                               list_del(&reg->registration_siblings);
>> +                               free(reg);
>> +                       }
>> +               } else
>> +                       return SAM_STAT_RESERVATION_CONFLICT;
>> +       } else {
>> +               if (force || !res_key) {
>> +                       if (sa_res_key) {
>> +                               reg = zalloc(sizeof(*reg));
>> +                               if (!reg) {
>> +                                       key = ILLEGAL_REQUEST;
>> +                                       asc = ASC_INSUFFICENT_REGISTRATION_RESOURCES;
>> +                                       goto sense;
>> +                               }
>> +                               reg->key = sa_res_key;
>> +                               reg->nexus_id = cmd->cmd_itn_id;
>> +                               list_add_tail(&reg->registration_siblings,
>> +                                             &cmd->dev->registration_list);
>> +                       } else
>> +                               ; /* do nothing */
>> +               } else
>> +                       return SAM_STAT_RESERVATION_CONFLICT;
>> +       }
>> +
>> +       cmd->dev->prgeneration++;
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +static int spc_pr_reserve(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint8_t key = ILLEGAL_REQUEST;
>> +       uint8_t pr_scope, pr_type;
>> +       uint8_t *buf;
>> +       uint64_t res_key, sa_res_key;
>> +       int ret;
>> +       struct registration *reg, *holder;
>> +
>> +       ret = check_pr_out_basic_parameter(cmd);
>> +       if (ret)
>> +               goto sense;
>> +
>> +       pr_scope = (cmd->scb[2] & 0xf0) >> 4;
>> +       pr_type = cmd->scb[2] & 0x0f;
>> +
>> +       buf = scsi_get_out_buffer(cmd);
>> +
>> +       res_key = get_unaligned_be64(buf);
>> +       sa_res_key = get_unaligned_be64(buf + 8);
>> +
>> +       switch (pr_type) {
>> +       case PR_TYPE_WRITE_EXCLUSIVE:
>> +       case PR_TYPE_EXCLUSIVE_ACCESS:
>> +       case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
>> +       case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
>> +       case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
>> +       case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
>> +               break;
>> +       default:
>> +               goto sense;
>> +       }
>> +
>> +       if (pr_scope != PR_LU_SCOPE)
>> +               goto sense;
>> +
>> +       reg = lookup_registration_by_nexus(cmd->dev, cmd->cmd_itn_id);
>> +       if (!reg)
>> +               return SAM_STAT_RESERVATION_CONFLICT;
>> +
>> +       holder = cmd->dev->pr_holder;
>> +       if (holder) {
>> +               if (holder != reg)
>> +                       return SAM_STAT_RESERVATION_CONFLICT;
>> +
>> +               if (holder->pr_type != pr_type ||
>> +                   holder->pr_scope != pr_scope)
>> +                       return SAM_STAT_RESERVATION_CONFLICT;
>> +
>> +               return SAM_STAT_GOOD;
>> +       }
>> +
>> +       reg->pr_scope = pr_scope;
>> +       reg->pr_type = pr_type;
>> +       cmd->dev->pr_holder = reg;
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +static int spc_pr_release(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>> +       uint8_t key = ILLEGAL_REQUEST;
>> +       uint8_t pr_scope, pr_type;
>> +       uint8_t *buf;
>> +       uint64_t res_key, sa_res_key;
>> +       int ret;
>> +       struct registration *reg, *holder, *sibling;
>> +
>> +       ret = check_pr_out_basic_parameter(cmd);
>> +       if (ret)
>> +               goto sense;
>> +
>> +       pr_scope = (cmd->scb[2] & 0xf0) >> 4;
>> +       pr_type = cmd->scb[2] & 0x0f;
>> +
>> +       buf = scsi_get_out_buffer(cmd);
>> +
>> +       res_key = get_unaligned_be64(buf);
>> +       sa_res_key = get_unaligned_be64(buf + 8);
>> +
>> +       reg = lookup_registration_by_nexus(cmd->dev, cmd->cmd_itn_id);
>> +       if (!reg)
>> +               return SAM_STAT_RESERVATION_CONFLICT;
>> +
>> +       holder = cmd->dev->pr_holder;
>> +       if (!holder)
>> +               return SAM_STAT_GOOD;
>> +
>> +       if (holder != reg)
>> +               return SAM_STAT_GOOD;
>> +
>> +       if (res_key != reg->key)
>> +               return SAM_STAT_RESERVATION_CONFLICT;
>> +
>> +       if (reg->pr_scope != pr_scope || reg->pr_type != pr_type) {
>> +               asc = ASC_INVALID_RELEASE_OF_PERSISTENT_RESERVATION;
>> +               goto sense;
>> +       }
>> +
>> +       cmd->dev->pr_holder = NULL;
>> +       reg->pr_scope = 0;
>> +       reg->pr_type = 0;
>> +
>> +       switch (pr_type) {
>> +       case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
>> +       case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
>> +       case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
>> +       case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
>> +               return SAM_STAT_GOOD;
>> +       default:
>> +               ;
>> +       }
>> +
>> +       list_for_each_entry(sibling, &cmd->dev->registration_list,
>> +                           registration_siblings) {
>> +               /* we don't send myself */
>> +               if (sibling == reg)
>> +                       continue;
>> +
>> +               ua_sense_add_other_it_nexus(sibling->nexus_id,
>> +                                           cmd->dev, ASC_RESERVATIONS_RELEASED);
>> +       }
>> +
>> +       return SAM_STAT_GOOD;
>> +sense:
>> +       scsi_set_in_resid_by_actual(cmd, 0);
>> +       sense_data_build(cmd, key, asc);
>> +       return SAM_STAT_CHECK_CONDITION;
>> +}
>> +
>> +#if 0
>> +static int spc_pr_clear(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       return SAM_STAT_GOOD;
>> +}
>> +
>> +static int spc_pr_preempt(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       return SAM_STAT_GOOD;
>> +}
>> +
>> +static int spc_pr_preempt_and_abort(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       return SAM_STAT_GOOD;
>> +}
>> +
>> +static int spc_pr_register_and_move(int host_no, struct scsi_cmd *cmd)
>> +{
>> +       return SAM_STAT_GOOD;
>> +}
>> +#endif
>> +
>> +struct service_action persistent_reserve_out_actions[] = {
>> +       {PR_OUT_REGISTER, spc_pr_register},
>> +       {PR_OUT_RESERVE, spc_pr_reserve},
>> +       {PR_OUT_RELEASE, spc_pr_release},
>> +#if 0
>> +       {PR_OUT_CLEAR, spc_pr_clear},
>> +       {PR_OUT_PREEMPT, spc_pr_preempt},
>> +       {PR_OUT_PREEMPT_AND_ABORT, spc_pr_preempt_and_abort},
>> +       {PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY, spc_pr_register},
>> +       {PR_OUT_REGISTER_AND_MOVE, spc_pr_register_and_move},
>> +#endif
>> +       {0, NULL},
>> +};
>> +
>>  int spc_request_sense(int host_no, struct scsi_cmd *cmd)
>>  {
>>        uint8_t *data;
>> @@ -1065,4 +1540,3 @@ void spc_lu_exit(struct scsi_lu *lu)
>>                if (lu->mode_pgs[i])
>>                        free(lu->mode_pgs[i]);
>>  }
>> -
>> diff --git a/usr/spc.h b/usr/spc.h
>> index cfc9cf3..a731b94 100644
>> --- a/usr/spc.h
>> +++ b/usr/spc.h
>> @@ -1,8 +1,10 @@
>>  #ifndef __SPC_H
>>  #define __SPC_H
>>
>> -extern struct service_action maint_in_service_actions[];
>> -extern int spc_maint_in(int host_no, struct scsi_cmd *cmd);
>> +extern struct service_action maint_in_service_actions[],
>> +       persistent_reserve_in_actions[], persistent_reserve_out_actions[];
>> +
>> +extern int spc_service_action(int host_no, struct scsi_cmd *cmd);
>>  extern int spc_inquiry(int host_no, struct scsi_cmd *cmd);
>>  extern int spc_report_luns(int host_no, struct scsi_cmd *cmd);
>>  extern int spc_start_stop(int host_no, struct scsi_cmd *cmd);
>> @@ -27,4 +29,6 @@ extern struct vpd *alloc_vpd(uint16_t size);
>>  extern int spc_lu_online(struct scsi_lu *lu);
>>  extern int spc_lu_offline(struct scsi_lu *lu);
>>
>> +struct registration *lookup_registration_by_nexus(struct scsi_lu *lu,
>> +                                                 uint64_t nexus_id);
>>  #endif
>> diff --git a/usr/ssc.c b/usr/ssc.c
>> index 834ec16..84fa317 100644
>> --- a/usr/ssc.c
>> +++ b/usr/ssc.c
>> @@ -310,7 +310,7 @@ static struct device_type_template ssc_template = {
>>                {spc_report_luns,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> -               {spc_maint_in, maint_in_service_actions,},
>> +               {spc_service_action, maint_in_service_actions,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>>                {spc_illegal_op,},
>> diff --git a/usr/target.c b/usr/target.c
>> index 14e3632..3f4f05c 100644
>> --- a/usr/target.c
>> +++ b/usr/target.c
>> @@ -490,6 +490,9 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
>>        lu->tgt = target;
>>        lu->lun = lun;
>>        tgt_cmd_queue_init(&lu->cmd_queue);
>> +       INIT_LIST_HEAD(&lu->registration_list);
>> +       lu->prgeneration = 0;
>> +       lu->pr_holder = NULL;
>>
>>        if (lu->dev_type_template.lu_init) {
>>                ret = lu->dev_type_template.lu_init(lu);
>> @@ -567,6 +570,7 @@ int tgt_device_destroy(int tid, uint64_t lun, int force)
>>        struct scsi_lu *lu;
>>        struct it_nexus *itn;
>>        struct it_nexus_lu_info *itn_lu, *next;
>> +       struct registration *reg, *reg_next;
>>        int ret;
>>
>>        dprintf("%u %" PRIu64 "\n", tid, lun);
>> @@ -606,6 +610,12 @@ int tgt_device_destroy(int tid, uint64_t lun, int force)
>>        }
>>
>>        list_del(&lu->device_siblings);
>> +
>> +       list_for_each_entry_safe(reg, reg_next, &lu->registration_list,
>> +                                registration_siblings) {
>> +               free(reg);
>> +       }
>> +
>>        free(lu);
>>
>>        list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) {
>> diff --git a/usr/tgtd.h b/usr/tgtd.h
>> index febaed7..96c744f 100644
>> --- a/usr/tgtd.h
>> +++ b/usr/tgtd.h
>> @@ -90,8 +90,16 @@ struct service_action {
>>  struct device_type_operations {
>>        int (*cmd_perform)(int host_no, struct scsi_cmd *cmd);
>>        struct service_action *service_actions;
>> +       uint8_t pr_conflict_bits;
>>  };
>>
>> +#define PR_SPECIAL     (1U << 5)
>> +#define PR_WE_FA       (1U << 4)
>> +#define PR_EA_FA       (1U << 3)
>> +#define PR_RR_FR       (1U << 2)
>> +#define PR_WE_FN       (1U << 1)
>> +#define PR_EA_FN       (1U << 0)
>> +
>>  struct device_type_template {
>>        unsigned char type;
>>
>> @@ -126,6 +134,15 @@ struct mode_pg {
>>        uint8_t mode_data[0];   /* Rest of mode page info */
>>  };
>>
>> +struct registration {
>> +       uint64_t key;
>> +       uint64_t nexus_id;
>> +       struct list_head registration_siblings;
>> +
>> +       uint8_t pr_scope;
>> +       uint8_t pr_type;
>> +};
>> +
>>  struct scsi_lu {
>>        int fd;
>>        uint64_t addr; /* persistent mapped address */
>> @@ -152,6 +169,10 @@ struct scsi_lu {
>>
>>        struct lu_phy_attr attrs;
>>
>> +       struct list_head registration_list;
>> +       uint32_t prgeneration;
>> +       struct registration *pr_holder;
>> +
>>        /* A pointer for each modules private use.
>>         * Currently used by ssc, smc and mmc modules.
>>         */
>> --
>> 1.5.6.5
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe stgt" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>>     
>
>   

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list