On Tue, Jul 23, 2013 at 12:27 AM, Dan Mick <dan.mick@xxxxxxxxxxx> wrote: > 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? Yes, please do. Lets get the initial patch in first, then great if you can merge it into RDB too. > > > 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@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; >> +} >> + >> 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html