[stgt] [PATCH] COMPARE_AND_WRITE: Fix this opcode so it works according to SBC

Ronnie Sahlberg ronniesahlberg at gmail.com
Sat Nov 17 03:26:52 CET 2012


After reading SBC again it becomes a lot more clear how this
opcode works.
Reactivate the opcode and implement it properly.
Compare the first "number of blocks" from DATA-OUT with the existing
content of these blocks on the LUN.
If it compare ok, then overwrite these block on the lun with the
next "number of blocks" from the DATA-OUT buffer.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
---
 usr/bs_rdwr.c |   21 +++++++++++++++++----
 usr/sbc.c     |    2 +-
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
index c9ab48d..b59fe7b 100644
--- a/usr/bs_rdwr.c
+++ b/usr/bs_rdwr.c
@@ -73,7 +73,7 @@ static void bs_rdwr_request(struct scsi_cmd *cmd)
 	int do_verify = 0;
 	int i;
 	char *ptr;
-
+	const char *write_buf = NULL;
 	ret = length = 0;
 	key = asc = 0;
 
@@ -104,9 +104,20 @@ static void bs_rdwr_request(struct scsi_cmd *cmd)
 
 		free(tmpbuf);
 
+		write_buf = scsi_get_out_buffer(cmd);
 		goto write;
 	case COMPARE_AND_WRITE:
-		length = scsi_get_out_length(cmd);
+		/* Blocks are transferred twice, first the set that
+		 * we compare to the existing data, and second the set
+		 * to write if the compare was successful.
+		 */
+		length = scsi_get_out_length(cmd) / 2;
+		if (length != cmd->tl) {
+			result = SAM_STAT_CHECK_CONDITION;
+			key = ILLEGAL_REQUEST;
+			asc = ASC_INVALID_FIELD_IN_CDB;
+			break;
+		}
 
 		tmpbuf = malloc(length);
 		if (!tmpbuf) {
@@ -152,6 +163,7 @@ static void bs_rdwr_request(struct scsi_cmd *cmd)
 
 		free(tmpbuf);
 
+		write_buf = scsi_get_out_buffer(cmd) + length;
 		goto write;
 	case SYNCHRONIZE_CACHE:
 	case SYNCHRONIZE_CACHE_16:
@@ -173,9 +185,10 @@ static void bs_rdwr_request(struct scsi_cmd *cmd)
 	case WRITE_10:
 	case WRITE_12:
 	case WRITE_16:
-write:
 		length = scsi_get_out_length(cmd);
-		ret = pwrite64(fd, scsi_get_out_buffer(cmd), length,
+		write_buf = scsi_get_out_buffer(cmd);
+write:
+		ret = pwrite64(fd, write_buf, length,
 			       offset);
 		if (ret == length) {
 			struct mode_pg *pg;
diff --git a/usr/sbc.c b/usr/sbc.c
index c059c37..d839a8f 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -842,7 +842,7 @@ static struct device_type_template sbc_template = {
 		{spc_illegal_op,},
 
 		{sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
-		/* {sbc_rw, NULL, PR_EA_FA|PR_EA_FN}, */
+		{sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
 		{spc_illegal_op,},
 		{sbc_rw, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN},
 		{sbc_rw, NULL, PR_EA_FA|PR_EA_FN},
-- 
1.7.3.1

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list