From: Jia Jia <physicalmtea@gmail.com>
To: "Martin K . Petersen" <mkp@kernel.org>
Cc: Jan Engelhardt <jengelh@inai.de>, Hannes Reinecke <hare@suse.de>,
Paolo Bonzini <pbonzini@redhat.com>,
Akinobu Mita <akinobu.mita@gmail.com>,
James Bottomley <James.Bottomley@suse.de>,
linux-scsi@vger.kernel.org, target-devel@vger.kernel.org,
linux-kernel@vger.kernel.org, Jia Jia <physicalmtea@gmail.com>
Subject: [PATCH 7/8] scsi: target: keep pscsi mode bytes inside the data sgs
Date: Tue, 6 Oct 2026 17:33:37 +0800 [thread overview]
Message-ID: <20261006093338.27342-8-physicalmtea@gmail.com> (raw)
In-Reply-To: <20261006093338.27342-1-physicalmtea@gmail.com>
pscsi_complete_cmd() writes the write-protect bit at a fixed header
offset. MODE SENSE uses byte 2 and MODE SENSE (10) uses byte 3. The
allocation length is allowed to be shorter than that header. One byte
at page offset 4095 makes the store the next physical page.
On a tape device the same function then reads the MODE SELECT block
descriptor through sg_virt() of the first sg. MODE SELECT needs byte
11 and MODE SELECT (10) needs byte 15. A short first sg is not checked.
Read and write those bytes across the whole data sg list. A header
that spans entries is still applied. A buffer that ends first is left
unchanged.
Fixes: c66ac9db8d4a ("[SCSI] target: Add LIO target core v4.0.0-rc6")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
---
drivers/target/target_core_pscsi.c | 98 +++++++++++++++++++++---------
1 file changed, 70 insertions(+), 28 deletions(-)
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index fd1b82fc7290..0e37a44f1e30 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -21,6 +21,7 @@
#include <linux/ratelimit.h>
#include <linux/module.h>
#include <linux/unaligned.h>
+#include <linux/highmem.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
@@ -585,6 +586,51 @@ static void pscsi_destroy_device(struct se_device *dev)
}
}
+/*
+ * Copy @len bytes at data-buffer offset @off. @to_sg writes @buf into
+ * the sg. Stop when the command buffer or an sg runs out.
+ */
+static bool
+pscsi_copy_buf(struct se_cmd *cmd, unsigned int off, void *buf,
+ unsigned int len, bool to_sg)
+{
+ struct scatterlist *sg;
+ unsigned int i, skip = off;
+ u8 *p = buf;
+
+ if (!len)
+ return true;
+ if (!cmd->t_data_nents || !cmd->t_data_sg || off >= cmd->data_length ||
+ len > cmd->data_length - off)
+ return false;
+
+ for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) {
+ unsigned int take;
+ void *addr;
+
+ if (!len)
+ return true;
+ if (skip >= sg->length) {
+ skip -= sg->length;
+ continue;
+ }
+
+ take = min_t(unsigned int, len, sg->length - skip);
+ addr = kmap_local_page(sg_page(sg));
+ addr += sg->offset + skip;
+ if (to_sg)
+ memcpy(addr, p, take);
+ else
+ memcpy(p, addr, take);
+ kunmap_local(addr);
+ p += take;
+ len -= take;
+ skip = 0;
+ }
+
+ return !len;
+}
+
static void pscsi_complete_cmd(struct se_cmd *cmd, u8 scsi_status,
unsigned char *req_sense, int valid_data)
{
@@ -610,21 +656,13 @@ static void pscsi_complete_cmd(struct se_cmd *cmd, u8 scsi_status,
bool read_only = target_lun_is_rdonly(cmd);
if (read_only) {
- unsigned char *buf;
-
- buf = transport_kmap_data_sg(cmd);
- if (!buf) {
- ; /* XXX: TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE */
- } else {
- if (cdb[0] == MODE_SENSE_10) {
- if (!(buf[3] & 0x80))
- buf[3] |= 0x80;
- } else {
- if (!(buf[2] & 0x80))
- buf[2] |= 0x80;
- }
+ unsigned char wp;
+ unsigned int wp_off = (cdb[0] == MODE_SENSE_10) ? 3 : 2;
- transport_kunmap_data_sg(cmd);
+ if (pscsi_copy_buf(cmd, wp_off, &wp, 1, false) &&
+ !(wp & 0x80)) {
+ wp |= 0x80;
+ pscsi_copy_buf(cmd, wp_off, &wp, 1, true);
}
}
}
@@ -643,28 +681,32 @@ static void pscsi_complete_cmd(struct se_cmd *cmd, u8 scsi_status,
*/
if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) &&
scsi_status == SAM_STAT_GOOD) {
- unsigned char *buf;
+ unsigned char bdl_buf[2];
+ unsigned char bl[3];
u16 bdl;
u32 blocksize;
- buf = sg_virt(&cmd->t_data_sg[0]);
- if (!buf) {
- pr_err("Unable to get buf for scatterlist\n");
- goto after_mode_select;
+ if (cdb[0] == MODE_SELECT) {
+ if (!pscsi_copy_buf(cmd, 3, bdl_buf, 1, false))
+ goto after_mode_select;
+ bdl = bdl_buf[0];
+ } else {
+ if (!pscsi_copy_buf(cmd, 6, bdl_buf, 2, false))
+ goto after_mode_select;
+ bdl = get_unaligned_be16(bdl_buf);
}
- if (cdb[0] == MODE_SELECT)
- bdl = buf[3];
- else
- bdl = get_unaligned_be16(&buf[6]);
-
if (!bdl)
goto after_mode_select;
- if (cdb[0] == MODE_SELECT)
- blocksize = get_unaligned_be24(&buf[9]);
- else
- blocksize = get_unaligned_be24(&buf[13]);
+ if (cdb[0] == MODE_SELECT) {
+ if (!pscsi_copy_buf(cmd, 9, bl, 3, false))
+ goto after_mode_select;
+ } else {
+ if (!pscsi_copy_buf(cmd, 13, bl, 3, false))
+ goto after_mode_select;
+ }
+ blocksize = get_unaligned_be24(bl);
sd->sector_size = blocksize;
}
--
2.34.1
next prev parent reply other threads:[~2026-10-06 9:34 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-06 9:33 [PATCH 0/8] scsi: target: keep command bytes inside the sg Jia Jia
2026-10-06 9:33 ` [PATCH 1/8] scsi: target: take COMPARE AND WRITE data from the write half Jia Jia
2026-10-06 9:33 ` [PATCH 2/8] scsi: target: keep REPORT REFERRALS stores inside the buffer Jia Jia
2026-10-06 9:33 ` [PATCH 3/8] scsi: target: reject a short SET TARGET PORT GROUPS list Jia Jia
2026-10-06 9:33 ` [PATCH 4/8] scsi: target: copy a DIF insert tuple across prot sgs Jia Jia
2026-10-06 9:33 ` [PATCH 5/8] scsi: target: copy a DIF verify " Jia Jia
2026-10-06 9:33 ` [PATCH 6/8] scsi: target: limit DIF block CRC to each data sg Jia Jia
2026-10-06 9:33 ` Jia Jia [this message]
2026-10-06 9:33 ` [PATCH 8/8] scsi: target: skip an escaped DIF block inside the " Jia Jia
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261006093338.27342-8-physicalmtea@gmail.com \
--to=physicalmtea@gmail.com \
--cc=James.Bottomley@suse.de \
--cc=akinobu.mita@gmail.com \
--cc=hare@suse.de \
--cc=jengelh@inai.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=mkp@kernel.org \
--cc=pbonzini@redhat.com \
--cc=target-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®