[stgt] RFC [PATCH] Implement PERSISTENT RESERVE IN/OUT

ronnie sahlberg ronniesahlberg at gmail.com
Wed Aug 20 07:27:07 CEST 2008


Mark,

I played a little with persistent reservations a long time ago for a
different project.

If you download the tarball for ctdb and build it
http://ctdb.samba.org/packages/redhat/RHEL5/

it will build a command called 'scsi_io'

With this command you can issue many different persistent reservation
calls to a device and it will (mostly) print the data you get back in
a very nice and easy
to read format.
It might be useful.


regards
ronnie sahlberg



On Wed, Aug 20, 2008 at 3:23 PM, Mark Harvey <markh794 at gmail.com> wrote:
> On Wed, Aug 20, 2008 at 3:18 PM, ronnie sahlberg
> <ronniesahlberg at gmail.com> wrote:
>> Hi Mark
>>
>> Just one suggestion.
>> These two commands take service actions, and are thus reported in
>> "ReportSupportedOperactionCodes" with one entry for each
>> opcode/service_action combination.
>>
>>
>> Please have a look at how I implemented service actions by looking at
>> the maint_in_service_actions example :
>> sbc.c:          {spc_maint_in, maint_in_service_actions,},
>>
>> If you add a similar structure for your service actions it means that
>> ReportedSupportedOperationCodes will return correct
>> data for your PersistentReservation opcode.
>
> Many thanks.
>
> I'll check it out.
>
>>
>> regards
>> ronnie sahlberg
>>
>>
>>
>> On Wed, Aug 20, 2008 at 3:01 PM, Mark Harvey <markh794 at gmail.com> wrote:
>>> Apologies for sending as an attachment... gmail and all.
>>>
>>> This is an initial attempt to implement PERSISTENT RESERVE IN and
>>> PERSISTENT RESERVE OUT.
>>>
>>> Currently only READ KEY service action will actually return anything.
>>> It returns a hard-coded 'ABC1234'.
>>>
>>> This post is a request for comment before I get too far into coding effort.
>>>
>>> # lsscsi -g
>>> [3:0:0:0]    disk    USB-HS   HTS726060M9AT00  0.01  /dev/sda  /dev/sg0
>>> [7:0:0:0]    storage IET      Controller       0001  -         /dev/sg1
>>> [7:0:0:1]    disk    QUANTUM  HD100            0010  /dev/sdb  /dev/sg2
>>> [7:0:0:2]    tape    QUANTUM  DLT6000          0010  /dev/st0  /dev/sg3
>>> [7:0:0:3]    tape    QUANTUM  DLT6000          0010  /dev/st1  /dev/sg4
>>> [7:0:0:4]    tape    QUANTUM  DLT6000          0010  /dev/st2  /dev/sg5
>>> [7:0:0:5]    mediumx STK      L700             0010  -         /dev/sg6
>>>
>>> # sg_persist -i /dev/sg3
>>>>> No service action given; assume Persistent Reservations In command
>>>>> with Read Keys service action
>>>  QUANTUM  DLT6000  0010
>>>  Peripheral device type: tape
>>>  PR generation=0x0, 4 registered reservation keys follow:
>>>    0x4142433132333400
>>>    0x0
>>>    0x0
>>>    0x0
>>>
>>>
>>> I'll include in-line for viewing pleasure :)
>>>
>>> [PATCH 1/2]
>>> From 11ad9ee209708f51bd2884598d309b1e7079cdce Mon Sep 17 00:00:00 2001
>>> From: Mark Harvey <markh794 at gmail.com>
>>> Date: Wed, 20 Aug 2008 14:42:27 +1000
>>> Subject: RFC - Implement PERSISTENT RESERVE IN/OUT
>>>
>>> Implement service action 'READ KEY' which returns
>>> a hard-coded string 'ABC1234'
>>>
>>> Signed-off-by: Mark Harvey <markh794 at gmail.com>
>>> ---
>>>  usr/scsi.h |    5 ++
>>>  usr/spc.c  |  231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  usr/spc.h  |    2 +
>>>  usr/tgtd.h |   13 ++++
>>>  4 files changed, 251 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/usr/scsi.h b/usr/scsi.h
>>> index 84fadff..a9481a1 100644
>>> --- a/usr/scsi.h
>>> +++ b/usr/scsi.h
>>> @@ -208,6 +208,11 @@
>>>  #define ASC_POSITION_PAST_BOM                  0x3b0c
>>>  #define ASC_MEDIUM_REMOVAL_PREVENTED           0x5302
>>>  #define ASC_BAD_MICROCODE_DETECTED             0x8283
>>> +#define ASC_INSUFFICENT_RESERVE_RESOURCE       0x5502
>>> +#define ASC_INSUFFICENT_RESOURCE               0x5503
>>> +#define ASC_INSUFFICENT_REGISTRAT_RESOURCE     0x5504
>>> +#define ASC_INSUFFICENT_AC_RESOURCE            0x5505
>>> +#define ASC_AUX_MEMORY_OUT_OF_SPACE            0x5506
>>>
>>>  /* Key 6: Unit Attention */
>>>  #define ASC_NOT_READY_TO_TRANSITION            0x2800
>>> diff --git a/usr/spc.c b/usr/spc.c
>>> index bd2c975..cc088bf 100644
>>> --- a/usr/spc.c
>>> +++ b/usr/spc.c
>>> @@ -880,6 +880,237 @@ void dump_cdb(struct scsi_cmd *cmd)
>>>        }
>>>  }
>>>
>>> +/**
>>> + * SCSI Persistent Reservation
>>> + *
>>> + * Reference: spc4r16 Ch 5.7
>>> + *
>>> + * Interesting points:
>>> + *  - Persistent reservations are not reset by hard reset, lu reset ot I_T loss
>>> + *  - Optionally, may be retained when power to target is lost
>>> + */
>>> +
>>> +/**
>>> + * PERSISTENT RESERVE IN - 5Eh
>>> + * Ref: 6.13
>>> + *
>>> + */
>>> +#define PR_IN_READ_KEYS 0
>>> +#define PR_IN_READ_RESERVATION 1
>>> +#define PR_IN_REPORT_CAPABILITIES 2
>>> +#define PR_IN_READ_FULL_STATUS 3
>>> +static int spc_pr_read_keys(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       uint8_t *buf;
>>> +       int len;
>>> +       int cdb_alloc_len;
>>> +       struct scsi_pr *pr;
>>> +
>>> +       cdb_alloc_len = ((cmd->scb[7] & 0xff) << 8) | (cmd->scb[8] & 0xff);
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +
>>> +       buf = scsi_get_in_buffer(cmd);
>>> +       len = sizeof(cmd->dev->pr.pr_key);
>>> +       memset(buf, 0, len + 8);
>>> +
>>> +       dprintf("Buf: %p, len: %d, cdb_alloc_len: %d\n",
>>> +                        buf, len, cdb_alloc_len);
>>> +
>>> +       buf[0] = (pr->PRgeneration >> 24) & 0xff;
>>> +       buf[1] = (pr->PRgeneration >> 16) & 0xff;
>>> +       buf[2] = (pr->PRgeneration >>  8) & 0xff;
>>> +       buf[3] = pr->PRgeneration & 0xff;
>>> +       buf[4] = (len >> 24) & 0xff;
>>> +       buf[5] = (len >> 16) & 0xff;
>>> +       buf[6] = (len >>  8) & 0xff;
>>> +       buf[7] = len & 0xff;
>>> +
>>> +       strcpy(buf + 8, "ABC1234");
>>> +       memcpy(scsi_get_in_buffer(cmd), buf, min(cdb_alloc_len, len + 8));
>>> +
>>> +       scsi_set_in_resid_by_actual(cmd, len + 8);
>>> +
>>> +       return SAM_STAT_GOOD;
>>> +}
>>> +
>>> +static int spc_pr_read_reservation(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       dprintf("**** Called ****\n");
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_report_capabilities(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       dprintf("**** Called ****\n");
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_read_full_status(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       dprintf("**** Called ****\n");
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +struct service_action pr_in_service_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}
>>> +};
>>> +
>>> +int persistent_reserve_in(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       uint8_t action;
>>> +       struct service_action *service_action;
>>> +
>>> +       action = cmd->scb[1] & 0x1f;
>>> +       service_action = find_service_action(pr_in_service_actions, action);
>>> +
>>> +       if (!service_action) {
>>> +               scsi_set_in_resid_by_actual(cmd, 0);
>>> +               sense_data_build(cmd, ILLEGAL_REQUEST,
>>> +                               ASC_INVALID_FIELD_IN_CDB);
>>> +               return SAM_STAT_CHECK_CONDITION;
>>> +       }
>>> +
>>> +       return service_action->cmd_perform(host_no, cmd);
>>> +}
>>> +
>>> +/**
>>> + * PERSISTENT RESERVE OUT - 5Fh
>>> + * Ref: 6.14
>>> + */
>>> +#define PR_OUT_REGISTER 0
>>> +#define PR_OUT_RESERVE 1
>>> +#define PR_OUT_RELEASE 2
>>> +#define PR_OUT_CLEAR 3
>>> +#define PR_OUT_PREEMPT 4
>>> +#define PR_OUT_PREEMPT_ABORT 5
>>> +#define PR_OUT_REGISTER_IGNORE 6
>>> +#define PR_OUT_REGISTER_MOVE 7
>>> +
>>> +static int spc_pr_register(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       struct scsi_pr *pr;
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +       pr->PRgeneration += 1;
>>> +
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_reserve(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       dprintf("**** Called ****\n");
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_release(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       dprintf("**** Called ****\n");
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_clear(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       struct scsi_pr *pr;
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +       pr->PRgeneration += 1;
>>> +
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_preempt(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       struct scsi_pr *pr;
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +       pr->PRgeneration += 1;
>>> +
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_preempt_abort(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       struct scsi_pr *pr;
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +       pr->PRgeneration += 1;
>>> +
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_register_ignore(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       struct scsi_pr *pr;
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +       pr->PRgeneration += 1;
>>> +
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +static int spc_pr_register_move(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       struct scsi_pr *pr;
>>> +
>>> +       dprintf("**** Called ****\n");
>>> +       pr = &cmd->dev->pr;
>>> +       pr->PRgeneration += 1;
>>> +
>>> +       sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE);
>>> +       return SAM_STAT_CHECK_CONDITION;
>>> +}
>>> +
>>> +struct service_action pr_out_service_actions[] = {
>>> +       {PR_OUT_REGISTER, spc_pr_register},
>>> +       {PR_OUT_RESERVE, spc_pr_reserve},
>>> +       {PR_OUT_RELEASE, spc_pr_release},
>>> +       {PR_OUT_CLEAR, spc_pr_clear},
>>> +       {PR_OUT_PREEMPT, spc_pr_preempt},
>>> +       {PR_OUT_PREEMPT_ABORT, spc_pr_preempt_abort},
>>> +       {PR_OUT_REGISTER_IGNORE, spc_pr_register_ignore},
>>> +       {PR_OUT_REGISTER_MOVE, spc_pr_register_move},
>>> +       {0, NULL}
>>> +};
>>> +
>>> +int persistent_reserve_out(int host_no, struct scsi_cmd *cmd)
>>> +{
>>> +       uint8_t action;
>>> +       struct service_action *service_action;
>>> +
>>> +       action = cmd->scb[1] & 0x1f;
>>> +       service_action = find_service_action(pr_out_service_actions, action);
>>> +
>>> +       if (!service_action) {
>>> +               scsi_set_in_resid_by_actual(cmd, 0);
>>> +               sense_data_build(cmd, ILLEGAL_REQUEST,
>>> +                               ASC_INVALID_FIELD_IN_CDB);
>>> +               return SAM_STAT_CHECK_CONDITION;
>>> +       }
>>> +
>>> +       return service_action->cmd_perform(host_no, cmd);
>>> +}
>>> +
>>>  int spc_illegal_op(int host_no, struct scsi_cmd *cmd)
>>>  {
>>>        dump_cdb(cmd);
>>> diff --git a/usr/spc.h b/usr/spc.h
>>> index 8fe3e3c..bdc3c1f 100644
>>> --- a/usr/spc.h
>>> +++ b/usr/spc.h
>>> @@ -9,6 +9,8 @@ extern int spc_start_stop(int host_no, struct scsi_cmd *cmd);
>>>  extern int spc_test_unit(int host_no, struct scsi_cmd *cmd);
>>>  extern int spc_request_sense(int host_no, struct scsi_cmd *cmd);
>>>  extern int spc_illegal_op(int host_no, struct scsi_cmd *cmd);
>>> +extern int persistent_reserve_in(int host_no, struct scsi_cmd *cmd);
>>> +extern int persistent_reserve_out(int host_no, struct scsi_cmd *cmd);
>>>  extern int spc_lu_init(struct scsi_lu *lu);
>>>
>>>  typedef int (match_fn_t)(struct scsi_lu *lu, char *params);
>>> diff --git a/usr/tgtd.h b/usr/tgtd.h
>>> index 4febcd3..d2c7135 100644
>>> --- a/usr/tgtd.h
>>> +++ b/usr/tgtd.h
>>> @@ -19,6 +19,11 @@
>>>
>>>  #define VENDOR_ID      "IET"
>>>
>>> +/* 8 byte reservation key size */
>>> +#define PR_KEY_SZ 8
>>> +/* Number of PR keys we can store at any one time */
>>> +#define PR_RESERVATION_SZ 4
>>> +
>>>  #define _TAB1 "    "
>>>  #define _TAB2 _TAB1 _TAB1
>>>  #define _TAB3 _TAB1 _TAB1 _TAB1
>>> @@ -126,6 +131,12 @@ struct mode_pg {
>>>        uint8_t mode_data[0];   /* Rest of mode page info */
>>>  };
>>>
>>> +struct scsi_pr {
>>> +       /* Persistent Reservation Generation */
>>> +       uint32_t PRgeneration;
>>> +       uint8_t pr_key[PR_RESERVATION_SZ][PR_KEY_SZ];
>>> +};
>>> +
>>>  struct scsi_lu {
>>>        int fd;
>>>        uint64_t addr; /* persistent mapped address */
>>> @@ -150,6 +161,8 @@ struct scsi_lu {
>>>        uint8_t mode_block_descriptor[BLOCK_DESCRIPTOR_LEN];
>>>        struct mode_pg *mode_pgs[0x3f];
>>>
>>> +       struct scsi_pr pr;
>>> +
>>>        struct lu_phy_attr attrs;
>>>
>>>        /* A pointer for each modules private use.
>>> --
>>> 1.5.6
>>>
>>> [PATCH 2/2]
>>> From 68c454d2d7f1b64f9dbce9410e5c2c8500d6ceb3 Mon Sep 17 00:00:00 2001
>>> From: Mark Harvey <markh794 at gmail.com>
>>> Date: Wed, 20 Aug 2008 14:45:30 +1000
>>> Subject: Add persistent reserve in/out to ssc module
>>>
>>> Signed-off-by: Mark Harvey <markh794 at gmail.com>
>>> ---
>>>  usr/ssc.c |    4 ++--
>>>  1 files changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/usr/ssc.c b/usr/ssc.c
>>> index 2630a6a..6dbdc0b 100644
>>> --- a/usr/ssc.c
>>> +++ b/usr/ssc.c
>>> @@ -251,8 +251,8 @@ static struct device_type_template ssc_template = {
>>>                {spc_illegal_op,},
>>>                {spc_illegal_op,},
>>>                {spc_illegal_op,},
>>> -               {spc_illegal_op,},
>>> -               {spc_illegal_op,},
>>> +               {persistent_reserve_in,},
>>> +               {persistent_reserve_out,},
>>>
>>>                [0x60 ... 0x7f] = {spc_illegal_op,},
>>>
>>> --
>>> 1.5.6
>>>
>>
>
--
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