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 |