diff --git a/scst/src/kunit/lib/suites/scst_kunit_write_same.c b/scst/src/kunit/lib/suites/scst_kunit_write_same.c index 664e34ace..4c95fcdac 100644 --- a/scst/src/kunit/lib/suites/scst_kunit_write_same.c +++ b/scst/src/kunit/lib/suites/scst_kunit_write_same.c @@ -227,10 +227,59 @@ static void write_same_app_tag_mask(struct kunit *test) } } +struct write_same_flags_case { + const char *name; + int cdb_len; + bool needs_dif; + u8 flags; + u8 other_byte; + u8 expected; +}; + +static const struct write_same_flags_case write_same_flags_cases[] = { + { "ws16_to_write32_default", 16, true, 0x00, 0xa5, 0x20 }, + { "ws16_to_write32_protected", 16, true, 0x40, 0xa5, 0x40 }, + { "ws32_to_write16", 32, false, 0x00, 0xa5, 0x00 }, + { "ws16_to_write16", 16, false, 0x00, 0xa5, 0x00 }, + { "ws32_to_write32", 32, true, 0x40, 0xa5, 0x40 }, +}; + +static void write_same_flags_desc(const struct write_same_flags_case *p, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", p->name); +} + +KUNIT_ARRAY_PARAM(write_same_flags, write_same_flags_cases, write_same_flags_desc); + +static void write_same_flags(struct kunit *test) +{ + const struct write_same_flags_case *p = test->param_value; + struct write_same_fixture *f = test->priv; + u8 cdb[32]; + int len; + + f->cmd.cdb_len = p->cdb_len; + f->cdb[0] = p->cdb_len == 16 ? WRITE_SAME_16 : VARIABLE_LENGTH_CMD; + f->cdb[p->cdb_len == 32 ? 10 : 1] = p->flags; + /* A short command's transfer length and a long one's control are not flags. */ + f->cdb[p->cdb_len == 32 ? 1 : 10] = p->other_byte; + if (p->cdb_len == 32) { + f->cdb[7] = 0x18; + put_unaligned_be16(SUBCODE_WRITE_SAME_32, &f->cdb[8]); + } + f->wsp.dif_valid = p->needs_dif; + + len = scst_ws_build_write_cdb(&f->wsp, cdb, 1, 1); + + KUNIT_ASSERT_EQ(test, len, p->needs_dif ? 32 : 16); + KUNIT_EXPECT_EQ(test, cdb[p->needs_dif ? 10 : 1], p->expected); +} + static struct kunit_case write_same_cases[] = { KUNIT_CASE_PARAM(write_same_app_tag, write_same_tag_gen_params), KUNIT_CASE_PARAM(write_same_cdb_image, write_same_cdb_gen_params), KUNIT_CASE_PARAM(write_same_app_tag_mask, write_same_mask_gen_params), + KUNIT_CASE_PARAM(write_same_flags, write_same_flags_gen_params), {} }; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index f17e3f89d..e496d5f7f 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6413,15 +6413,16 @@ int scst_ws_build_write_cdb(const struct scst_write_same_priv *wsp, const struct scst_cmd *ws_cmd = wsp->ws_orig_cmd; const struct scst_device *dev = ws_cmd->dev; bool needs_dif = wsp->dif_valid; + u8 flags = ws_cmd->cdb[ws_cmd->cdb_len == 32 ? 10 : 1]; int write_cdb_len; memset(write_cdb, 0, 32); if (!needs_dif || dev->dev_dif_type != 2) { write_cdb[0] = WRITE_16; write_cdb_len = 16; - write_cdb[1] = ws_cmd->cdb[1]; + write_cdb[1] = flags; if (needs_dif) { - u8 wrprotect = ws_cmd->cdb[1] & 0xE0; + u8 wrprotect = flags & 0xE0; if (wrprotect == 0) wrprotect = 0x20; @@ -6431,19 +6432,15 @@ int scst_ws_build_write_cdb(const struct scst_write_same_priv *wsp, put_unaligned_be32(blocks, &write_cdb[10]); } else { /* There might be WRITE SAME(16) with WRPROTECT 0 here */ - u8 wrprotect; + u8 wrprotect = flags & 0xE0; - if (ws_cmd->cdb_len != 32) - wrprotect = ws_cmd->cdb[1] & 0xE0; - else - wrprotect = ws_cmd->cdb[10] & 0xE0; if (wrprotect == 0) wrprotect = 0x20; write_cdb[0] = VARIABLE_LENGTH_CMD; put_unaligned_be16(SUBCODE_WRITE_32, &write_cdb[8]); write_cdb[7] = 0x18; write_cdb_len = 32; - write_cdb[10] = ws_cmd->cdb[10]; + write_cdb[10] = flags; write_cdb[10] |= wrprotect; put_unaligned_be64(lba, &write_cdb[12]); put_unaligned_be32(blocks, &write_cdb[28]);