[stgt] [PATCH] MODE_SENSE: add support for mode subpages

ronnie sahlberg ronniesahlberg at gmail.com
Fri Jul 27 08:32:33 CEST 2012


ping ?


On Sun, Jul 22, 2012 at 2:13 PM, Ronnie Sahlberg
<ronniesahlberg at gmail.com> wrote:
> Add support for mode subpages.
> Change the modepages from an array of pointers to a linked list
> so that we can store an arbitrary number od mode pages with the same
> page code (but different subpage codes)
>
> Add a simple modepage with a subpage code 0x0a/0x01 which is the
> ControlExtensions subpage.
> Have TCMOS set to 1 in this subpage.
> This value has the following meaning (SPC):
>     A timestamp changeable by methods outside this standard (TCMOS)
>     bit set to one specifies that the timestamp may
>     be initialized by methods outside the scope of this standard.
>
> Which sounds appropriate since root or ntpd can change the
> local time on linux without first asking TGTD and SPC for permission first :-)
>
> Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
> ---
>  usr/bs_rdwr.c |   12 +++++++-
>  usr/mmc.c     |    4 ++-
>  usr/sbc.c     |   15 +++++++++--
>  usr/smc.c     |    8 +++--
>  usr/spc.c     |   76 +++++++++++++++++++++++++++++++++++++-------------------
>  usr/spc.h     |    4 ++-
>  usr/ssc.c     |    4 ++-
>  usr/target.c  |    1 +
>  usr/tgtd.h    |    3 +-
>  9 files changed, 89 insertions(+), 38 deletions(-)
>
> diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
> index 981ab65..a79dd02 100644
> --- a/usr/bs_rdwr.c
> +++ b/usr/bs_rdwr.c
> @@ -38,6 +38,7 @@
>  #include "util.h"
>  #include "tgtd.h"
>  #include "scsi.h"
> +#include "spc.h"
>  #include "bs_thread.h"
>
>  static void set_medium_error(int *result, uint8_t *key, uint16_t *asc)
> @@ -156,12 +157,19 @@ write:
>                 ret = pwrite64(fd, scsi_get_out_buffer(cmd), length,
>                                offset);
>                 if (ret == length) {
> +                       struct mode_pg *pg;
> +
>                         /*
>                          * it would be better not to access to pg
>                          * directy.
>                          */
> -                       struct mode_pg *pg = cmd->dev->mode_pgs[0x8];
> -
> +                       pg = find_mode_page(cmd->dev, 0x08, 0);
> +                       if (pg == NULL) {
> +                               result = SAM_STAT_CHECK_CONDITION;
> +                               key = ILLEGAL_REQUEST;
> +                               asc = ASC_INVALID_FIELD_IN_CDB;
> +                               break;
> +                       }
>                         if (((cmd->scb[0] != WRITE_6) && (cmd->scb[1] & 0x8)) ||
>                             !(pg->mode_data[0] & 0x04))
>                                 bs_sync_sync_range(cmd, length, &result, &key,
> diff --git a/usr/mmc.c b/usr/mmc.c
> index 4d81426..d8d4a7b 100644
> --- a/usr/mmc.c
> +++ b/usr/mmc.c
> @@ -2243,7 +2243,9 @@ static tgtadm_err mmc_lu_init(struct scsi_lu *lu)
>         /* Caching Page */
>         add_mode_page(lu, "8:0:10:0:0:0:0:0:0:0:0:0:0");
>         /* Control page */
> -       add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
> +       add_mode_page(lu, "0x0a:0:10:2:0:0:0:0:0:0:0:2:0");
> +       /* Control Extensions mode page:  TCMOS:1 */
> +       add_mode_page(lu, "0x0a:1:0x00:0x1c:0x00:0x00:0x00");
>         /* Power Condition */
>         add_mode_page(lu, "0x1a:0:10:8:0:0:0:0:0:0:0:0:0");
>         /* Informational Exceptions Control page */
> diff --git a/usr/sbc.c b/usr/sbc.c
> index 7a643e1..77f32c4 100644
> --- a/usr/sbc.c
> +++ b/usr/sbc.c
> @@ -69,9 +69,14 @@ static off_t find_next_hole(struct scsi_lu *dev, off_t offset)
>  static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *changed)
>  {
>         uint8_t pcode = data[0] & 0x3f;
> -       struct mode_pg *pg = cmd->dev->mode_pgs[pcode];
> +       uint8_t subpcode = data[1];
> +       struct mode_pg *pg;
>         uint8_t old;
>
> +       pg = find_mode_page(cmd->dev, pcode, subpcode);
> +       if (pg == NULL)
> +               return 1;
> +
>         eprintf("%x %x\n", pg->mode_data[0], data[2]);
>
>         if (pcode == 0x08) {
> @@ -688,11 +693,15 @@ static tgtadm_err sbc_lu_init(struct scsi_lu *lu)
>                 memset(mask, 0, sizeof(mask));
>                 mask[0] = 0x4;
>
> -               set_mode_page_changeable_mask(lu, 8, mask);
> +               set_mode_page_changeable_mask(lu, 8, 0, mask);
>         }
>
>         /* Control page */
> -       add_mode_page(lu, "10:0:10:2:0x10:0:0:0:0:0:0:2:0");
> +       add_mode_page(lu, "0x0a:0:10:2:0x10:0:0:0:0:0:0:2:0");
> +
> +       /* Control Extensions mode page:  TCMOS:1 */
> +       add_mode_page(lu, "0x0a:1:5:0x00:0x1c:0x00:0x00:0x00");
> +
>         /* Informational Exceptions Control page */
>         add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0");
>
> diff --git a/usr/smc.c b/usr/smc.c
> index bbfbfcd..c31a7c7 100644
> --- a/usr/smc.c
> +++ b/usr/smc.c
> @@ -514,7 +514,9 @@ static tgtadm_err smc_lu_init(struct scsi_lu *lu)
>         /* Vendor uniq - However most apps seem to call for mode page 0*/
>         add_mode_page(lu, "0:0:0");
>         /* Control page */
> -       add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
> +       add_mode_page(lu, "0x0a:0:10:2:0:0:0:0:0:0:0:2:0");
> +       /* Control Extensions mode page:  TCMOS:1 */
> +       add_mode_page(lu, "0x0a:1:0x00:0x1c:0x00:0x00:0x00");
>         /* Power Condition */
>         add_mode_page(lu, "0x1a:0:10:8:0:0:0:0:0:0:0:0:0");
>         /* Informational Exceptions Control page */
> @@ -625,7 +627,7 @@ static tgtadm_err add_slt(struct scsi_lu *lu, struct tmp_param *tmp)
>         int qnty_save;
>         int i;
>
> -       pg = lu->mode_pgs[0x1d];
> +       pg = find_mode_page(lu, 0x1d, 0);
>         if (!pg) {
>                 dprintf("Failed to find Element Address Assignment mode pg\n");
>                 return TGTADM_UNKNOWN_ERR;
> @@ -692,7 +694,7 @@ static tgtadm_err config_slot(struct scsi_lu *lu, struct tmp_param *tmp)
>         switch(tmp->element_type) {
>         case ELEMENT_MEDIUM_TRANSPORT:
>                 /* If medium has more than one side, set the 'rotate' bit */
> -               m = lu->mode_pgs[0x1e];
> +               m = find_mode_page(lu, 0x1e, 0);
>                 if (m) {
>                         m->mode_data[0] = (tmp->sides > 1) ? 1 : 0;
>                         adm_err = TGTADM_SUCCESS;
> diff --git a/usr/spc.c b/usr/spc.c
> index c3b4052..1c1f187 100644
> --- a/usr/spc.c
> +++ b/usr/spc.c
> @@ -480,7 +480,7 @@ int spc_mode_select(int host_no, struct scsi_cmd *cmd,
>
>                 pcode = data[offset] & 0x3f;
>
> -               pg = cmd->dev->mode_pgs[pcode];
> +               pg = find_mode_page(cmd->dev, pcode, 0);
>                 if (!pg)
>                         goto sense;
>
> @@ -525,10 +525,22 @@ sense:
>         return SAM_STAT_CHECK_CONDITION;
>  }
>
> +struct mode_pg *find_mode_page(struct scsi_lu *lu, uint8_t pcode,
> +                              uint8_t subpcode)
> +{
> +       struct mode_pg *pg;
> +
> +       list_for_each_entry(pg, &lu->mode_pages, mode_pg_siblings) {
> +               if (pg->pcode == pcode && pg->subpcode == subpcode)
> +                       return pg;
> +       }
> +       return NULL;
> +}
> +
>  int set_mode_page_changeable_mask(struct scsi_lu *lu, uint8_t pcode,
> -                                 uint8_t *mask)
> +                                 uint8_t subpcode, uint8_t *mask)
>  {
> -       struct mode_pg *pg = lu->mode_pgs[pcode];
> +       struct mode_pg *pg = find_mode_page(lu, pcode, subpcode);
>
>         if (pg) {
>                 memcpy(pg->mode_data + pg->pcode_size, mask, pg->pcode_size);
> @@ -551,18 +563,27 @@ static int build_mode_page(uint8_t *data, struct mode_pg *pg,
>                            uint8_t pc, uint16_t *alloc_len)
>  {
>         uint8_t *p;
> -       int len;
> +       int len, hdr_size;
>         uint8_t *mode_data;
>
>         len = pg->pcode_size;
>         if (*alloc_len >= 2) {
> -               data[0] = pg->pcode;
> -               data[1] = len;
> +               if (!pg->subpcode) {
> +                       data[0] = pg->pcode;
> +                       data[1] = len;
> +                       hdr_size = 2;
> +               } else {
> +                       data[0] = pg->pcode | 0x40;
> +                       data[1] = pg->subpcode;
> +                       data[2] = len >> 8;
> +                       data[3] = len & 0xff;
> +                       hdr_size = 4;
> +               }
>         }
> -       *alloc_len -= min_t(uint16_t, *alloc_len, 2);
> +       *alloc_len -= min_t(uint16_t, *alloc_len, hdr_size);
>
> -       p = &data[2];
> -       len += 2;
> +       p = &data[hdr_size];
> +       len += hdr_size;
>         if (*alloc_len >= pg->pcode_size) {
>                 if (pc == 1)
>                         mode_data = pg->mode_data + pg->pcode_size;
> @@ -599,10 +620,6 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
>         pctrl = (scb[2] & 0xc0) >> 6;
>         subpcode = scb[3];
>
> -       /* Currently not implemented */
> -       if (subpcode)
> -               goto sense;
> -
>         if (pctrl == 3) {
>                 asc = ASC_SAVING_PARMS_UNSUP;
>                 goto sense;
> @@ -633,15 +650,14 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
>         }
>
>         if (pcode == 0x3f) {
> -               int i;
> -               for (i = 0; i < ARRAY_SIZE(cmd->dev->mode_pgs); i++) {
> -                       pg = cmd->dev->mode_pgs[i];
> -                       if (pg)
> -                               len += build_mode_page(data + len, pg, pctrl,
> -                                                      &alloc_len);
> +               list_for_each_entry(pg,
> +                                   &cmd->dev->mode_pages,
> +                                   mode_pg_siblings) {
> +                       len += build_mode_page(data + len, pg, pctrl,
> +                                              &alloc_len);
>                 }
>         } else {
> -               pg = cmd->dev->mode_pgs[pcode];
> +               pg = find_mode_page(cmd->dev, pcode, subpcode);
>                 if (!pg)
>                         goto sense;
>                 len += build_mode_page(data + len, pg, pctrl, &alloc_len);
> @@ -1595,8 +1611,11 @@ tgtadm_err add_mode_page(struct scsi_lu *lu, char *p)
>                 case 2:
>                         size = strtol(p, NULL, 0);
>
> -                       if (lu->mode_pgs[pcode])
> -                               free(lu->mode_pgs[pcode]);
> +                       pg = find_mode_page(lu, pcode, subpcode);
> +                       if (pg) {
> +                               list_del(&pg->mode_pg_siblings);
> +                               free(pg);
> +                       }
>
>                         pg = alloc_mode_pg(pcode, subpcode, size);
>                         if (!pg) {
> @@ -1604,7 +1623,7 @@ tgtadm_err add_mode_page(struct scsi_lu *lu, char *p)
>                                 goto exit;
>                         }
>
> -                       lu->mode_pgs[pcode] = pg;
> +                       list_add_tail(&pg->mode_pg_siblings, &lu->mode_pages);
>                         data = pg->mode_data;
>                         break;
>                 default:
> @@ -1898,7 +1917,12 @@ void spc_lu_exit(struct scsi_lu *lu)
>                 if (lu_vpd[i])
>                         free(lu_vpd[i]);
>
> -       for (i = 0; i < ARRAY_SIZE(lu->mode_pgs); i++)
> -               if (lu->mode_pgs[i])
> -                       free(lu->mode_pgs[i]);
> +       while (!list_empty(&lu->mode_pages)) {
> +               struct mode_pg *pg;
> +               pg = list_first_entry(&lu->mode_pages,
> +                                      struct mode_pg,
> +                                      mode_pg_siblings);
> +               list_del(&pg->mode_pg_siblings);
> +               free(pg);
> +       }
>  }
> diff --git a/usr/spc.h b/usr/spc.h
> index 5b88542..0c537e1 100644
> --- a/usr/spc.h
> +++ b/usr/spc.h
> @@ -23,7 +23,9 @@ extern void dump_cdb(struct scsi_cmd *cmd);
>  extern int spc_mode_sense(int host_no, struct scsi_cmd *cmd);
>  extern tgtadm_err add_mode_page(struct scsi_lu *lu, char *params);
>  extern int set_mode_page_changeable_mask(struct scsi_lu *lu, uint8_t pcode,
> -                                        uint8_t *mask);
> +                                        uint8_t subpcode, uint8_t *mask);
> +extern struct mode_pg *find_mode_page(struct scsi_lu *lu,
> +                                     uint8_t pcode, uint8_t subpcode);
>  extern int spc_mode_select(int host_no, struct scsi_cmd *cmd,
>                            int (*update)(struct scsi_cmd *, uint8_t *, int *));
>  extern struct vpd *alloc_vpd(uint16_t size);
> diff --git a/usr/ssc.c b/usr/ssc.c
> index 59d2e15..549cba9 100644
> --- a/usr/ssc.c
> +++ b/usr/ssc.c
> @@ -193,7 +193,9 @@ static tgtadm_err ssc_lu_init(struct scsi_lu *lu)
>         /* Disconnect page - Mandatory - SPC-4 */
>         add_mode_page(lu, "2:0:14:0x80:0x80:0:0xa:0:0:0:0:0:0:0:0:0:0");
>         /* Control page - Mandatory - SPC-4 */
> -       add_mode_page(lu, "10:0:10:2:0:0:0:0:0:0:0:2:0");
> +       add_mode_page(lu, "0x0a:0:10:2:0:0:0:0:0:0:0:2:0");
> +       /* Control Extensions mode page:  TCMOS:1 */
> +       add_mode_page(lu, "0x0a:1:0x00:0x1c:0x00:0x00:0x00");
>         /* Data Compression - Mandatory - SSC3 8.3.2 */
>         add_mode_page(lu, "15:0:14:0:0:0:0:0:0:0:0:0:0:0:0:0:0");
>         /* Device Configuration - Mandatory - SSC3 8.3.3 */
> diff --git a/usr/target.c b/usr/target.c
> index e94c3ed..05d8c59 100644
> --- a/usr/target.c
> +++ b/usr/target.c
> @@ -579,6 +579,7 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
>         tgt_cmd_queue_init(&lu->cmd_queue);
>         INIT_LIST_HEAD(&lu->registration_list);
>         INIT_LIST_HEAD(&lu->lu_itl_info_list);
> +       INIT_LIST_HEAD(&lu->mode_pages);
>         lu->prgeneration = 0;
>         lu->pr_holder = NULL;
>
> diff --git a/usr/tgtd.h b/usr/tgtd.h
> index 8bee2e3..07cd971 100644
> --- a/usr/tgtd.h
> +++ b/usr/tgtd.h
> @@ -168,6 +168,7 @@ struct backingstore_template {
>  };
>
>  struct mode_pg {
> +       struct list_head mode_pg_siblings;
>         uint8_t pcode;          /* Page code */
>         uint8_t subpcode;       /* Sub page code */
>         int16_t pcode_size;     /* Size of page code data. */
> @@ -210,7 +211,7 @@ struct scsi_lu {
>         struct target *tgt;
>
>         uint8_t mode_block_descriptor[BLOCK_DESCRIPTOR_LEN];
> -       struct mode_pg *mode_pgs[0x3f];
> +       struct list_head mode_pages;
>
>         struct lu_phy_attr attrs;
>
> --
> 1.7.3.1
>
--
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