[stgt] [PATCH] Initial SANITIZE support

Dan Mick dan.mick at inktank.com
Tue Jul 23 09:27:47 CEST 2013


Seems like this ought to apply to bs_rbd.c as well, unless the sanitize 
code can be moved out of the backend into the common code...do you need 
a hand with that?

On 07/21/2013 11:34 AM, Ronnie Sahlberg wrote:
> Add support for the SANITIZE opcode and implement
> BLOCK_ERASE (similar to UNMAP) OVERWRITE and EXIT_FAILURE_MODE
> service actions.
>
> All commands except INQUIRY, REPORT_LUNS and REQUEST SENSE are failed
> with NOT_READY/SANITIZE_IN_PGROGRESS while a sanitize is
> active or a SANITIZE has failed but not yet been cleared.
>
> Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
> ---
>   usr/bs_rdwr.c |  181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   usr/sbc.c     |  188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>   usr/scsi.c    |    5 ++
>   usr/scsi.h    |    8 +++
>   usr/spc.c     |   48 +++++++++++++++
>   usr/spc.h     |    5 +-
>   usr/target.c  |    6 ++
>   usr/tgtd.h    |    9 +++
>   8 files changed, 444 insertions(+), 6 deletions(-)
>
> diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
> index 47d2d99..148fc72 100644
> --- a/usr/bs_rdwr.c
> +++ b/usr/bs_rdwr.c
> @@ -58,6 +58,170 @@ static void bs_sync_sync_range(struct scsi_cmd *cmd, uint32_t length,
>   		set_medium_error(result, key, asc);
>   }
>
> +static void sanitize_write_buffer(struct scsi_cmd *cmd,
> +		int buf_size, const char *buf,
> +		int *result, uint8_t *key, uint16_t *asc)
> +{
> +	uint64_t offset = 0;
> +
> +	while (offset != cmd->dev->size) {
> +		size_t count, pos;
> +
> +		if (cmd->dev->size - offset > buf_size)
> +			count = buf_size;
> +		else
> +			count = cmd->dev->size - offset;
> +
> +		pos = 0;
> +		while (pos != count) {
> +			size_t written;
> +
> +			written = pwrite64(cmd->dev->fd,
> +					buf + pos, count - pos, offset + pos);
> +			if (written == -1) {
> +				eprintf("Write failed during sanitize\n");
> +				*result = SAM_STAT_CHECK_CONDITION;
> +				*key = MEDIUM_ERROR;
> +				*asc = ASC_WRITE_ERROR;
> +				return;
> +			}
> +			pos += written;
> +			fdatasync(cmd->dev->fd);
> +		}
> +		offset += count;
> +	}
> +}
> +
> +static void sanitize_block_erase(struct scsi_cmd *cmd,
> +		int *result, uint8_t *key, uint16_t *asc)
> +{
> +	int fd = cmd->dev->fd;
> +
> +	cmd->dev->sanitize_state = LU_SANITIZE_RUNNING;
> +	if (unmap_file_region(fd, 0, cmd->dev->size) != 0) {
> +		eprintf("Failed to punch hole for"
> +			" SANITIZE"
> +			" length:%" PRIu64 "\n",
> +			cmd->dev->size);
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = HARDWARE_ERROR;
> +		*asc = ASC_INTERNAL_TGT_FAILURE;
> +		cmd->dev->sanitize_state = LU_SANITIZE_FAILURE;
> +		return;
> +	}
> +	cmd->dev->sanitize_state = LU_SANITIZE_NONE;
> +}
> +
> +#define SANITIZE_BATCHSIZE 16384
> +
> +static void sanitize_overwrite(struct scsi_cmd *cmd,
> +		int *result, uint8_t *key, uint16_t *asc)
> +{
> +	int blocksize = 1 << cmd->dev->blk_shift;
> +	char *buf;
> +	int param_len;
> +	char *param = scsi_get_out_buffer(cmd);
> +	int invert, ocount, pattern_len;
> +	int i, offset;
> +
> +	param_len = scsi_get_out_length(cmd);
> +	if (param_len <= 4 || param_len >= blocksize + 5) {
> +		eprintf("Invalid data-out size for sanitize overwrite:%d\n",
> +			param_len);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	invert = !!(param[0] & 0x80);
> +	ocount = param[0] & 0x1f;
> +	pattern_len = get_unaligned_be16(&param[2]);
> +
> +	if (!ocount) {
> +		eprintf("Invalid overwrite count for sanitize overwrite:%d\n",
> +			ocount);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	if (!pattern_len) {
> +		eprintf("Initialization pattern length was 0\n");
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	if (pattern_len > blocksize) {
> +		eprintf("Initialization pattern length was > blocksize. " \
> +			"%d > %d\n", pattern_len, blocksize);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	if (pattern_len + 4 != param_len) {
> +		eprintf("Initialization pattern length does not match"
> +			" data-out size. %d but data-out is %d\n",
> +			pattern_len, param_len);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +
> +	cmd->dev->sanitize_state = LU_SANITIZE_RUNNING;
> +
> +	/* allocate a bunch of blocks so we can batch
> +	 * writes to the medium.
> +	 */
> +	buf = malloc(blocksize * SANITIZE_BATCHSIZE);
> +
> +	/* and fill it with the initialization pattern */
> +	offset = 0;
> +	while (offset != blocksize * SANITIZE_BATCHSIZE) {
> +		int count;
> +
> +		count = blocksize * SANITIZE_BATCHSIZE - offset;
> +		if (count > pattern_len)
> +			count = pattern_len;
> +
> +		memcpy(buf + offset, param + 4, count);
> +		offset += count;
> +	}
> +
> +	if (invert && !(ocount & 0x01)) {
> +		int j;
> +		for (j = 0; j < blocksize * SANITIZE_BATCHSIZE; j++)
> +			buf[j] = ~buf[j];
> +	}
> +
> +	for (i = 0; i < ocount; i++) {
> +		sanitize_write_buffer(cmd, blocksize * SANITIZE_BATCHSIZE,
> +			buf,
> +			result, key, asc);
> +
> +		if (invert) {
> +			int j;
> +			for (j = 0; j < blocksize * SANITIZE_BATCHSIZE; j++)
> +				buf[j] = ~buf[j];
> +		}
> +	}
> +
> +	free(buf);
> +	cmd->dev->sanitize_state = LU_SANITIZE_NONE;
> +}
> +
>   static void bs_rdwr_request(struct scsi_cmd *cmd)
>   {
>   	int ret, fd = cmd->dev->fd;
> @@ -357,6 +521,23 @@ verify:
>   			tmpbuf += 16;
>   		}
>   		break;
> +	case SANITIZE:
> +		switch (cmd->scb[1] & 0x1f) {
> +		case SA_BLOCK_ERASE:
> +			sanitize_block_erase(cmd, &result, &key, &asc);
> +			break;
> +		case SA_OVERWRITE:
> +			sanitize_overwrite(cmd, &result, &key, &asc);
> +			break;
> +		default:
> +			eprintf("Invalid sanitize service action %d",
> +				cmd->scb[1] & 0x1f);
> +
> +			result = SAM_STAT_CHECK_CONDITION;
> +			key = ILLEGAL_REQUEST;
> +			asc = ASC_INVALID_FIELD_IN_CDB;
> +		}
> +		break;
>   	default:
>   		break;
>   	}
> diff --git a/usr/sbc.c b/usr/sbc.c
> index c4f012c..1a2af48 100644
> --- a/usr/sbc.c
> +++ b/usr/sbc.c
> @@ -66,6 +66,118 @@ static off_t find_next_hole(struct scsi_lu *dev, off_t offset)
>   #endif
>   }
>
> +static int sbc_sanitize_overwrite(int host_no, struct scsi_cmd *cmd)
> +{
> +	int ret;
> +	uint16_t param_len;
> +	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
> +	uint8_t key = ILLEGAL_REQUEST;
> +
> +	ret = device_reserved(cmd);
> +	if (ret)
> +		return SAM_STAT_RESERVATION_CONFLICT;
> +
> +	if (!cmd->dev->attrs.online) {
> +		key = NOT_READY;
> +		asc = ASC_MEDIUM_NOT_PRESENT;
> +		goto sense;
> +	}
> +
> +	if (cmd->dev->attrs.readonly || cmd->dev->attrs.swp) {
> +		key = DATA_PROTECT;
> +		asc = ASC_WRITE_PROTECT;
> +		goto sense;
> +	}
> +
> +	if (cmd->scb[1] & 0x40
> +	    || cmd->scb[2]
> +	    || cmd->scb[3]
> +	    || cmd->scb[4]
> +	    || cmd->scb[5]
> +	    || cmd->scb[6])
> +		goto sense;
> +
> +	param_len = (uint16_t)get_unaligned_be16(&cmd->scb[7]);
> +	if (param_len <= 4)
> +		goto sense;
> +	if (param_len >=  (1 << cmd->dev->blk_shift) + 5)
> +		goto sense;
> +
> +	if (scsi_get_out_length(cmd) != param_len)
> +		goto sense;
> +
> +	scsi_set_out_resid_by_actual(cmd, param_len);
> +
> +	ret = cmd->dev->bst->bs_cmd_submit(cmd);
> +	if (ret) {
> +		key = HARDWARE_ERROR;
> +		asc = ASC_INTERNAL_TGT_FAILURE;
> +	} else
> +		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 sbc_sanitize_block_erase(int host_no, struct scsi_cmd *cmd)
> +{
> +	int ret;
> +	uint16_t param_len;
> +	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
> +	uint8_t key = ILLEGAL_REQUEST;
> +
> +	ret = device_reserved(cmd);
> +	if (ret)
> +		return SAM_STAT_RESERVATION_CONFLICT;
> +
> +	if (!cmd->dev->attrs.online) {
> +		key = NOT_READY;
> +		asc = ASC_MEDIUM_NOT_PRESENT;
> +		goto sense;
> +	}
> +
> +	if (cmd->scb[1] & 0x40
> +	    || cmd->scb[2]
> +	    || cmd->scb[3]
> +	    || cmd->scb[4]
> +	    || cmd->scb[5]
> +	    || cmd->scb[6])
> +		goto sense;
> +
> +	if (cmd->dev->attrs.readonly || cmd->dev->attrs.swp) {
> +		key = DATA_PROTECT;
> +		asc = ASC_WRITE_PROTECT;
> +		goto sense;
> +	}
> +
> +	param_len = (uint16_t)get_unaligned_be16(&cmd->scb[7]);
> +	if (param_len != 0)
> +		goto sense;
> +
> +	if (scsi_get_in_length(cmd) != param_len)
> +		goto sense;
> +
> +	ret = cmd->dev->bst->bs_cmd_submit(cmd);
> +	if (ret) {
> +		key = HARDWARE_ERROR;
> +		asc = ASC_INTERNAL_TGT_FAILURE;
> +	} else
> +		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 sanitize_actions[] = {
> +	{SA_OVERWRITE, sbc_sanitize_overwrite},
> +	{SA_BLOCK_ERASE, sbc_sanitize_block_erase},
> +	{0, NULL},
> +};
> +
>   static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *changed)
>   {
>   	uint8_t pcode = data[0] & 0x3f;
> @@ -114,6 +226,11 @@ static int sbc_mode_page_update(struct scsi_cmd *cmd, uint8_t *data, int *change
>
>   static int sbc_mode_select(int host_no, struct scsi_cmd *cmd)
>   {
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	return spc_mode_select(host_no, cmd, sbc_mode_page_update);
>   }
>
> @@ -121,6 +238,11 @@ static int sbc_mode_sense(int host_no, struct scsi_cmd *cmd)
>   {
>   	int ret;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	ret = spc_mode_sense(host_no, cmd);
>
>   	/*
> @@ -149,6 +271,11 @@ static int sbc_format_unit(int host_no, struct scsi_cmd *cmd)
>   	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>   	int ret;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	ret = device_reserved(cmd);
>   	if (ret)
>   		return SAM_STAT_RESERVATION_CONFLICT;
> @@ -193,6 +320,11 @@ static int sbc_unmap(int host_no, struct scsi_cmd *cmd)
>   	struct scsi_lu *lu = cmd->dev;
>   	int anchor;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	ret = device_reserved(cmd);
>   	if (ret)
>   		return SAM_STAT_RESERVATION_CONFLICT;
> @@ -248,6 +380,11 @@ static int sbc_rw(int host_no, struct scsi_cmd *cmd)
>   	uint16_t asc = ASC_LUN_NOT_SUPPORTED;
>   	struct scsi_lu *lu = cmd->dev;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	ret = device_reserved(cmd);
>   	if (ret)
>   		return SAM_STAT_RESERVATION_CONFLICT;
> @@ -401,6 +538,11 @@ sense:
>
>   static int sbc_reserve(int host_no, struct scsi_cmd *cmd)
>   {
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	if (device_reserve(cmd))
>   		return SAM_STAT_RESERVATION_CONFLICT ;
>   	else
> @@ -411,6 +553,11 @@ static int sbc_release(int host_no, struct scsi_cmd *cmd)
>   {
>   	int ret;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	ret = device_release(cmd->c_target->tid, cmd->cmd_itn_id,
>   			     cmd->dev->lun, 0);
>
> @@ -426,6 +573,11 @@ static int sbc_read_capacity(int host_no, struct scsi_cmd *cmd)
>   	unsigned char key = ILLEGAL_REQUEST;
>   	uint16_t asc = ASC_LUN_NOT_SUPPORTED;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	if (cmd->dev->attrs.removable && !cmd->dev->attrs.online) {
>   		key = NOT_READY;
>   		asc = ASC_MEDIUM_NOT_PRESENT;
> @@ -466,6 +618,11 @@ static int sbc_verify(int host_no, struct scsi_cmd *cmd)
>   	uint64_t lba;
>   	uint32_t tl;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	if (cmd->dev->attrs.removable && !cmd->dev->attrs.online) {
>   		key = NOT_READY;
>   		asc = ASC_MEDIUM_NOT_PRESENT;
> @@ -661,6 +818,24 @@ static int sbc_service_action(int host_no, struct scsi_cmd *cmd)
>   	struct service_action *service_action, *actions;
>
>   	action = cmd->scb[1] & 0x1f;
> +
> +	/* Active or failed sanitize operation */
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		/* Allow SANITIZE/EXIT_FAILURE_MODE to clear a failure
> +		 * but fail everything else.
> +		 */
> +		if (cmd->dev->sanitize_state == LU_SANITIZE_FAILURE
> +		&& op == SANITIZE && action == SA_EXIT_FAILURE_MODE) {
> +			cmd->dev->sanitize_state = LU_SANITIZE_NONE;
> +			return SAM_STAT_GOOD;
> +		} else {
> +			sense_data_build(cmd, NOT_READY,
> +				ASC_SANITIZE_IN_PROGRESS);
> +			return SAM_STAT_CHECK_CONDITION;
> +		}
> +	}
> +
> +
>   	actions = cmd->dev->dev_type_template.ops[op].service_actions;
>
>   	service_action = find_service_action(actions, action);
> @@ -681,6 +856,11 @@ static int sbc_sync_cache(int host_no, struct scsi_cmd *cmd)
>   	uint8_t key = ILLEGAL_REQUEST;
>   	uint16_t asc = ASC_LUN_NOT_SUPPORTED;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	if (device_reserved(cmd))
>   		return SAM_STAT_RESERVATION_CONFLICT;
>
> @@ -864,7 +1044,7 @@ static struct device_type_template sbc_template = {
>   		{spc_illegal_op,},
>   		{spc_illegal_op,},
>
> -		{spc_illegal_op,},
> +		{sbc_service_action, sanitize_actions,},
>   		{spc_illegal_op,},
>   		{spc_illegal_op,},
>   		{spc_illegal_op,},
> @@ -889,8 +1069,8 @@ static struct device_type_template sbc_template = {
>   		{spc_illegal_op,},
>   		{spc_illegal_op,},
>   		{spc_illegal_op,},
> -		{spc_service_action, persistent_reserve_in_actions,},
> -		{spc_service_action, persistent_reserve_out_actions,},
> +		{sbc_service_action, persistent_reserve_in_actions,},
> +		{sbc_service_action, persistent_reserve_out_actions,},
>
>   		[0x60 ... 0x7f] = {spc_illegal_op,},
>
> @@ -937,7 +1117,7 @@ static struct device_type_template sbc_template = {
>   		{spc_report_luns,},
>   		{spc_illegal_op,},
>   		{spc_illegal_op,},
> -		{spc_service_action, maint_in_service_actions,},
> +		{sbc_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 2636a5c..78701be 100644
> --- a/usr/scsi.c
> +++ b/usr/scsi.c
> @@ -119,6 +119,9 @@ const unsigned char *get_scsi_cdb_usage_data(unsigned char op, unsigned char sa)
>   	static const unsigned char read_capacity[] = {
>   	       0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>   	       0x00, 0x07};
> +	static const unsigned char sanitize[] = {
> +	       0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
> +	       0xff, 0x07};
>
>   	static const unsigned char verify_12[] = {
>   	       0xff, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
> @@ -165,6 +168,8 @@ const unsigned char *get_scsi_cdb_usage_data(unsigned char op, unsigned char sa)
>   	       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
>
>   	switch (op) {
> +	case SANITIZE:
> +		return sanitize;
>   	case TEST_UNIT_READY:
>   		return test_unit_ready;
>   	case REQUEST_SENSE:
> diff --git a/usr/scsi.h b/usr/scsi.h
> index 1edcfd7..9dbd9f3 100644
> --- a/usr/scsi.h
> +++ b/usr/scsi.h
> @@ -62,6 +62,7 @@
>   #define WRITE_SAME            0x41
>   #define UNMAP		      0x42
>   #define READ_TOC              0x43
> +#define SANITIZE              0x48
>   #define LOG_SELECT            0x4c
>   #define LOG_SENSE             0x4d
>   #define MODE_SELECT_10        0x55
> @@ -178,6 +179,7 @@
>   #define ASC_CAUSE_NOT_REPORTABLE		0x0400
>   #define ASC_BECOMING_READY			0x0401
>   #define ASC_INITIALIZING_REQUIRED		0x0402
> +#define ASC_SANITIZE_IN_PROGRESS		0x041b
>   #define ASC_CLEANING_CART_INSTALLED		0x3003
>   #define ASC_CLEANING_FAILURE			0x3007
>   #define ASC_MEDIUM_NOT_PRESENT			0x3a00
> @@ -270,4 +272,10 @@
>   #define PR_TYPE_WRITE_EXCLUSIVE_ALLREG		0x07
>   #define PR_TYPE_EXCLUSIVE_ACCESS_ALLREG		0x08
>
> +/* Sanitize service actions */
> +#define SA_OVERWRITE				0x01
> +#define SA_BLOCK_ERASE				0x02
> +#define SA_CRYPTO_ERASE				0x03
> +#define SA_EXIT_FAILURE_MODE			0x1f
> +
>   #endif
> diff --git a/usr/spc.c b/usr/spc.c
> index 15077ca..8551ea2 100644
> --- a/usr/spc.c
> +++ b/usr/spc.c
> @@ -180,6 +180,26 @@ static void update_vpd_b2(struct scsi_lu *lu, void *id)
>   	}
>   }
>
> +static void update_vpd_b1(struct scsi_lu *lu, void *id)
> +{
> +	struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb1)];
> +	uint8_t	*data = vpd_pg->data;
> +
> +	/* medium rotation rate */
> +	data[0] = 0;
> +	data[1] = 0;
> +
> +	/* product type */
> +	data[2] = 0;
> +
> +	/* wabereq == 01b */
> +	data[3] = 0x40;
> +
> +	/* fuab == 1  vbuls == 1 */
> +	data[4] = 0x03;
> +
> +}
> +
>   static void update_vpd_b0(struct scsi_lu *lu, void *id)
>   {
>   	struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb0)];
> @@ -373,6 +393,11 @@ int spc_start_stop(int host_no, struct scsi_cmd *cmd)
>   	uint8_t *scb = cmd->scb;
>   	int start, loej, pwrcnd;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	scsi_set_in_resid_by_actual(cmd, 0);
>
>   	if (device_reserved(cmd))
> @@ -410,6 +435,10 @@ int spc_test_unit(int host_no, struct scsi_cmd *cmd)
>   {
>   	/* how should we test a backing-storage file? */
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
>   	if (device_reserved(cmd))
>   		return SAM_STAT_RESERVATION_CONFLICT;
>   	if (cmd->dev->attrs.online)
> @@ -427,6 +456,11 @@ int spc_prevent_allow_media_removal(int host_no, struct scsi_cmd *cmd)
>   	uint8_t *scb = cmd->scb;
>   	struct it_nexus_lu_info *itn_lu_info = cmd->itn_lu_info;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		sense_data_build(cmd, NOT_READY, ASC_SANITIZE_IN_PROGRESS);
> +		return SAM_STAT_CHECK_CONDITION;
> +	}
> +
>   	if (device_reserved(cmd))
>   		return SAM_STAT_RESERVATION_CONFLICT;
>
> @@ -934,6 +968,12 @@ int spc_send_diagnostics(int host_no, struct scsi_cmd *cmd)
>   	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
>   	uint8_t key = ILLEGAL_REQUEST;
>
> +	if (cmd->dev->sanitize_state != LU_SANITIZE_NONE) {
> +		key = NOT_READY;
> +		asc = ASC_SANITIZE_IN_PROGRESS;
> +		goto sense;
> +	}
> +
>   	/* we only support SELF-TEST==1 */
>   	if (!(cmd->scb[1] & 0x04))
>   		goto sense;
> @@ -2067,6 +2107,14 @@ int spc_lu_init(struct scsi_lu *lu)
>   	lu_vpd[pg]->vpd_update = update_vpd_b0;
>   	lu_vpd[pg]->vpd_update(lu, NULL);
>
> +	/* VPD page 0xb1 BLOCK DEVICE CHARACTERISTICS*/
> +	pg = PCODE_OFFSET(0xb1);
> +	lu_vpd[pg] = alloc_vpd(BDC_VPD_LEN);
> +	if (!lu_vpd[pg])
> +		return -ENOMEM;
> +	lu_vpd[pg]->vpd_update = update_vpd_b1;
> +	lu_vpd[pg]->vpd_update(lu, NULL);
> +
>   	/* VPD page 0xb2 LOGICAL BLOCK PROVISIONING*/
>   	pg = PCODE_OFFSET(0xb2);
>   	lu_vpd[pg] = alloc_vpd(LBP_VPD_LEN);
> diff --git a/usr/spc.h b/usr/spc.h
> index 0c537e1..43d4ac6 100644
> --- a/usr/spc.h
> +++ b/usr/spc.h
> @@ -1,8 +1,9 @@
>   #ifndef __SPC_H
>   #define __SPC_H
>
> -extern struct service_action maint_in_service_actions[],
> -	persistent_reserve_in_actions[], persistent_reserve_out_actions[];
> +extern struct service_action maint_in_service_actions[];
> +extern struct service_action persistent_reserve_in_actions[];
> +extern struct service_action 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);
> diff --git a/usr/target.c b/usr/target.c
> index b1729b3..c7d210b 100644
> --- a/usr/target.c
> +++ b/usr/target.c
> @@ -588,6 +588,12 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
>   	lu->prgeneration = 0;
>   	lu->pr_holder = NULL;
>
> +	/* TODO: Here we should really read this from stable storage since
> +	 * active/failed sanitize state are supposed to survive across
> +	 * target resets/reboots.
> +	 */
> +	lu->sanitize_state = LU_SANITIZE_NONE;
> +
>   	lu->cmd_perform = &target_cmd_perform;
>   	lu->cmd_done = &__cmd_done;
>
> diff --git a/usr/tgtd.h b/usr/tgtd.h
> index 484e6e9..2b795a5 100644
> --- a/usr/tgtd.h
> +++ b/usr/tgtd.h
> @@ -14,6 +14,7 @@ struct concat_buf;
>   #define PRODUCT_ID_LEN		16
>   #define PRODUCT_REV_LEN		4
>   #define BLOCK_LIMITS_VPD_LEN	0x3C
> +#define BDC_VPD_LEN		0x3C
>   #define LBP_VPD_LEN		4
>
>   #define PCODE_SHIFT		7
> @@ -187,6 +188,12 @@ struct registration {
>   	uint8_t pr_type;
>   };
>
> +enum lu_sanitize_state {
> +     LU_SANITIZE_NONE = 1,
> +     LU_SANITIZE_RUNNING,
> +     LU_SANITIZE_FAILURE,
> +};
> +
>   struct scsi_lu {
>   	int fd;
>   	uint64_t addr; /* persistent mapped address */
> @@ -217,6 +224,8 @@ struct scsi_lu {
>
>   	struct lu_phy_attr attrs;
>
> +	enum lu_sanitize_state sanitize_state;
> +
>   	struct list_head registration_list;
>   	uint32_t prgeneration;
>   	struct registration *pr_holder;
>
--
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