From c5b905ae7e161f3fb623fdfc7404185d574df446 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Tue, 20 Oct 2026 14:58:16 +0300 Subject: [PATCH] scst_lib: Select WRITE SAME flags from the input CDB format WRITE SAME emulation chooses WRITE(16) or WRITE(32) from the required DIF handling, independently of the input CDB length. The builder nevertheless copies the flags from the output format's offset in the input command. For WRITE SAME(16) converted to WRITE(32), that is byte 10 of the transfer length; for a long command converted to WRITE(16), it is the control byte. An unrelated value can therefore change WRPROTECT and other output flags. Select the input flags once using the original CDB length and use that value in both output formats. Preserve the existing WRPROTECT defaulting. Add KUnit cases with different flag and unrelated-byte values for both conversions and for commands that retain their format. Fixes: 906f4dfefb2e ("Merge t10-pi branch back") --- .../kunit/lib/suites/scst_kunit_write_same.c | 49 +++++++++++++++++++ scst/src/scst_lib.c | 13 ++--- 2 files changed, 54 insertions(+), 8 deletions(-) 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]);