[stgt] [PATCH] Add support for SBC GET_LBA_STATUS opcode

FUJITA Tomonori fujita.tomonori at lab.ntt.co.jp
Sun Jun 3 01:38:47 CEST 2012


On Thu, 31 May 2012 17:00:45 +1000
ronnie sahlberg <ronniesahlberg at gmail.com> wrote:

> Tomo, please use this patch instead.
> 
> It adds proper check for starting-lba so we return the right sense
> code if it is out of range.
> 
> It also adds proper service action handling so that we will report
> that we support both varients (reacapacity16 and getlbastatus)
> of opcoe 0x9e
> 
> 
> That way sg_opcodes show them both properly, like this :
> sg_opcodes iscsi://10.1.1.125/iqn.ronnie.test/1
>   IET       VIRTUAL-DISK  0001
>   Peripheral device type: disk
> 
> Opcode  Service    CDB    Name
> (hex)   action(h)  size
> -----------------------------------------------
>  00                  6    Test Unit Ready
>  03                  6    Request Sense
>  04                  6    Format Unit
>  08                  6    Read(6)
>  0a                  6    Write(6)
>  12                  6    Inquiry
>  15                  6    Mode select(6)
>  16                  6    Reserve(6)
>  17                  6    Release(6)
>  1a                  6    Mode sense(6)
>  1b                  6    Start stop unit
>  1d                  6    Send diagnostic
>  1e                  6    Prevent allow medium removal
>  25                 10    Read capacity(10)
>  28                 10    Read(10)
>  2a                 10    Write(10)
>  2f                 10    Verify(10)
>  34                 10    Pre-fetch(10)
>  35                 10    Synchronize cache(10)
>  41                 10    Write same(10)
>  42                 10    Unmap
>  55                 10    Mode select(10)
>  5a                 10    Mode sense(10)
>  5e        0        10    Persistent reserve in, read keys
>  5e        1        10    Persistent reserve in, read reservation
>  5e        2        10    Persistent reserve in, report capabilities
>  5f        0        10    Persistent reserve out, register
>  5f        1        10    Persistent reserve out, reserve
>  5f        2        10    Persistent reserve out, release
>  5f        3        10    Persistent reserve out, clear
>  5f        4        10    Persistent reserve out, preempt
>  5f        6        10    Persistent reserve out, register and ignore
> existing key
>  5f        7        10    Persistent reserve out, register and move
>  88                 16    Read(16)
>  8a                 16    Write(16)
>  8f                 16    Verify(16)
>  90                 16    Pre-fetch(16)
>  91                 16    Synchronize cache(16)
>  93                 16    Write same(16)
>  9e       10        16    Read capacity(16)
>  9e       12        16    Get LBA status
>  a0                 12    Report luns
>  a3        c        12    Report supported operation codes
>  a8                 12    Read(12)
>  aa                 12    Write(12)
>  af                 12    Verify(12)
> 
> tgtd does support a pretty fair number of opcodes !

Looks great. Thanks a lot.

I have some minor comments.

> Add GET_LBA_STATUS for thin provisioned luns if SEEK_DATA/SEEK_HOLE
> is available.
> 
> Update get lba status to return proper sense code if starting-lba
> is out of range.
> 
> Break readcapacity16 and getlbastatus that are both using opcode 0x9e into
> using the service-handle mechanism.
> This means that the sg_opcoes now also reports both these opcodes correctly.
> They are both opcoe 0x9e but different service actions.
> 
> Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
> ---
>  usr/sbc.c  |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  usr/scsi.h |    1 +
>  usr/spc.c  |    2 +-
>  usr/tgtd.h |    4 ++
>  4 files changed, 130 insertions(+), 6 deletions(-)
> 
> diff --git a/usr/sbc.c b/usr/sbc.c
> index cf2b609..a480a16 100644
> --- a/usr/sbc.c
> +++ b/usr/sbc.c
> @@ -23,6 +23,9 @@
>   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
>   * 02110-1301 USA
>   */
> +#define _FILE_OFFSET_BITS 64
> +#define __USE_GNU
> +
>  #include <errno.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -30,6 +33,7 @@
>  #include <stdint.h>
>  #include <unistd.h>
>  #include <linux/fs.h>
> +#include <sys/types.h>
>  
>  #include "list.h"
>  #include "util.h"
> @@ -45,6 +49,23 @@
>  
>  static unsigned int blk_shift = DEFAULT_BLK_SHIFT;
>  
> +static off_t find_next_data(struct scsi_lu *dev, off_t offset)
> +{
> +#ifdef SEEK_DATA
> +	return lseek64(dev->fd, offset, SEEK_DATA);
> +#else
> +	return offset;
> +#endif
> +}
> +static off_t find_next_hole(struct scsi_lu *dev, off_t offset)
> +{
> +#ifdef SEEK_HOLE
> +	return lseek64(dev->fd, offset, SEEK_HOLE);
> +#else
> +	return dev->size;
> +#endif
> +}
> +
>  static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *changed)
>  {
>  	uint8_t pcode = data[0] & 0x3f;
> @@ -421,7 +442,7 @@ sense:
>  	return SAM_STAT_CHECK_CONDITION;
>  }
>  
> -static int sbc_service_action(int host_no, struct scsi_cmd *cmd)
> +static int sbc_readcapacity16(int host_no, struct scsi_cmd *cmd)
>  {
>  	uint32_t *data;
>  	unsigned int bshift;
> @@ -437,9 +458,6 @@ static int sbc_service_action(int host_no, struct scsi_cmd *cmd)
>  		goto sense;
>  	}
>  
> -	if (cmd->scb[1] != SAI_READ_CAPACITY_16)
> -		goto sense;
> -
>  	if (scsi_get_in_length(cmd) < 12)
>  		goto overflow;
>  
> @@ -468,6 +486,107 @@ sense:
>  	return SAM_STAT_CHECK_CONDITION;
>  }
>  
> +static int sbc_getlbastatus(int host_no, struct scsi_cmd *cmd)
> +{
> +	int len = 32;
> +	uint64_t offset;
> +	uint32_t pdl;
> +	int type;
> +	char *buf;
> +	unsigned char key = ILLEGAL_REQUEST;
> +	uint16_t asc = ASC_INVALID_OP_CODE;
> +
> +	if (cmd->dev->attrs.removable && !cmd->dev->attrs.online) {
> +		key = NOT_READY;
> +		asc = ASC_MEDIUM_NOT_PRESENT;
> +		goto sense;
> +	}
> +
> +	if (scsi_get_in_length(cmd) < 24)
> +		goto overflow;
> +
> +	len = scsi_get_in_length(cmd);
> +	buf = scsi_get_in_buffer(cmd);
> +	memset(buf, 0, len);
> +
> +	offset = __be64_to_cpu(*(uint64_t *)&cmd->scb[2])
> +			<< cmd->dev->blk_shift;

Can you use put/get_unaligend_* helper functions? I don't replace the
existing such code with the helper functions but I want to use the
functions for new code.


> +	if (offset >= cmd->dev->size) {
> +		key = ILLEGAL_REQUEST;
> +		asc = ASC_LBA_OUT_OF_RANGE;
> +		goto sense;
> +	}
> +
> +	pdl = 4;
> +	*(uint32_t *)&buf[0] = __cpu_to_be32(pdl);

Ditto.

> +	type = 0;
> +	while (len >= 4 + pdl + 16) {
> +		off_t next_offset;
> +
> +		*(uint32_t *)&buf[0] = __cpu_to_be32(pdl + 16);

Ditto.

> +		if (offset >= cmd->dev->size)
> +			break;
> +
> +		next_offset = (type == 0) ?
> +			find_next_hole(cmd->dev, offset) :
> +			find_next_data(cmd->dev, offset);
> +		if (next_offset == offset) {
> +			type = 1 - type;
> +			continue;
> +		}
> +
> +		*(uint64_t *)&buf[4 + pdl +  0] =
> +			__cpu_to_be64(offset >> cmd->dev->blk_shift);
> +		*(uint64_t *)&buf[4 + pdl +  8] =
> +			__cpu_to_be32((next_offset - offset)
> +				>> cmd->dev->blk_shift);

Ditto.

> +		buf[4 + pdl + 12] = type;

Ditto.

> +		pdl += 16;
> +		type = 1 - type;
> +		offset = next_offset;
> +	}
> +	len = 4 + pdl;
> +
> +overflow:
> +	scsi_set_in_resid_by_actual(cmd, len);
> +	return SAM_STAT_GOOD;
> +
> +sense:
> +	sense_data_build(cmd, key, asc);
> +	return SAM_STAT_CHECK_CONDITION;
> +}
> +
> +struct service_action sbc_service_actions[] = {
> +	{0x10, sbc_readcapacity16},
> +	{0x12, sbc_getlbastatus},

better to use SAI_*?

> +	{0, NULL}
> +};
> +
> +
> +static int sbc_service_action(int host_no, struct scsi_cmd *cmd)
> +{
> +	uint8_t action;
> +	unsigned char op = cmd->scb[0];
> +	struct service_action *service_action, *actions;
> +
> +	action = cmd->scb[1] & 0x1f;
> +	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);
> +		sense_data_build(cmd, ILLEGAL_REQUEST,
> +				ASC_INVALID_FIELD_IN_CDB);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
> +	return service_action->cmd_perform(host_no, cmd);
> +}
> +
>  static int sbc_sync_cache(int host_no, struct scsi_cmd *cmd)
>  {
>  	int ret;
> @@ -711,7 +830,7 @@ static struct device_type_template sbc_template = {
>  		{spc_illegal_op,},
>  		{spc_illegal_op,},
>  		{spc_illegal_op,},
> -		{sbc_service_action,},
> +		{sbc_service_action, sbc_service_actions,},
>  		{spc_illegal_op,},
>  
>  		/* 0xA0 */
> diff --git a/usr/scsi.h b/usr/scsi.h
> index 0a02c36..2b994f9 100644
> --- a/usr/scsi.h
> +++ b/usr/scsi.h
> @@ -80,6 +80,7 @@
>  #define WRITE_SAME_16         0x93
>  #define SERVICE_ACTION_IN     0x9e
>  #define	SAI_READ_CAPACITY_16  0x10
> +#define	SAI_GET_LBA_STATUS    0x12
>  #define REPORT_LUNS           0xa0
>  #define MOVE_MEDIUM           0xa5
>  #define EXCHANGE_MEDIUM       0xa6
> diff --git a/usr/spc.c b/usr/spc.c
> index a7f9a36..117c9f3 100644
> --- a/usr/spc.c
> +++ b/usr/spc.c
> @@ -794,7 +794,7 @@ struct service_action maint_in_service_actions[] = {
>  	{0, NULL}
>  };
>  
> -static struct service_action *
> +struct service_action *
>  find_service_action(struct service_action *service_action, uint32_t action)
>  {
>  	while (service_action->cmd_perform) {
> diff --git a/usr/tgtd.h b/usr/tgtd.h
> index b303e21..aa9b9d5 100644
> --- a/usr/tgtd.h
> +++ b/usr/tgtd.h
> @@ -353,4 +353,8 @@ int call_program(const char *cmd,
>  
>  void update_lbppbe(struct scsi_lu *lu, int blksize);
>  
> +struct service_action *
> +find_service_action(struct service_action *service_action,
> +		    uint32_t action);
> +
>  #endif
> -- 
> 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