On Sun, 21 Jul 2013 11:34:21 -0700 Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx> 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@xxxxxxxxx> > --- > 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(¶m[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; > +} Instead of adding new functions to usr/bs_rdwr.c, can we use the existing functions for write/sync usr/bs_rdwr.c? With such way, SANITIZE can be implemented easily with other backing store code. -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html