summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2015-10-05 09:25:04 +0000
committermav <mav@FreeBSD.org>2015-10-05 09:25:04 +0000
commit2ddbc805cd7d34853759754a0c0dc1ce1694b1a8 (patch)
treeb58b2c7d968122ca6fbbc5bb98006d429ad46bb0
parent940d22f32ea86db81428d39777706f83ebb8c947 (diff)
downloadFreeBSD-src-2ddbc805cd7d34853759754a0c0dc1ce1694b1a8.zip
FreeBSD-src-2ddbc805cd7d34853759754a0c0dc1ce1694b1a8.tar.gz
MFC r287868: Make COMPARE AND WRITE report offset of difference.
-rw-r--r--sys/cam/ctl/ctl_backend_block.c59
1 files changed, 43 insertions, 16 deletions
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index 48c5333..c80304e 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -354,6 +354,48 @@ ctl_complete_beio(struct ctl_be_block_io *beio)
}
}
+static size_t
+cmp(uint8_t *a, uint8_t *b, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (a[i] != b[i])
+ break;
+ }
+ return (i);
+}
+
+static void
+ctl_be_block_compare(union ctl_io *io)
+{
+ struct ctl_be_block_io *beio;
+ uint64_t off, res;
+ int i;
+ uint8_t info[8];
+
+ beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
+ off = 0;
+ for (i = 0; i < beio->num_segs; i++) {
+ res = cmp(beio->sg_segs[i].addr,
+ beio->sg_segs[i + CTLBLK_HALF_SEGS].addr,
+ beio->sg_segs[i].len);
+ off += res;
+ if (res < beio->sg_segs[i].len)
+ break;
+ }
+ if (i < beio->num_segs) {
+ scsi_u64to8b(off, info);
+ ctl_set_sense(&io->scsiio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_MISCOMPARE,
+ /*asc*/ 0x1D, /*ascq*/ 0x00,
+ /*type*/ SSD_ELEM_INFO,
+ /*size*/ sizeof(info), /*data*/ &info,
+ /*type*/ SSD_ELEM_NONE);
+ } else
+ ctl_set_success(&io->scsiio);
+}
+
static int
ctl_be_block_move_done(union ctl_io *io)
{
@@ -363,7 +405,6 @@ ctl_be_block_move_done(union ctl_io *io)
#ifdef CTL_TIME_IO
struct bintime cur_bt;
#endif
- int i;
beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
be_lun = beio->lun;
@@ -391,21 +432,7 @@ ctl_be_block_move_done(union ctl_io *io)
ctl_set_success(&io->scsiio);
} else if (lbalen->flags & CTL_LLF_COMPARE) {
/* We have two data blocks ready for comparison. */
- for (i = 0; i < beio->num_segs; i++) {
- if (memcmp(beio->sg_segs[i].addr,
- beio->sg_segs[i + CTLBLK_HALF_SEGS].addr,
- beio->sg_segs[i].len) != 0)
- break;
- }
- if (i < beio->num_segs)
- ctl_set_sense(&io->scsiio,
- /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_MISCOMPARE,
- /*asc*/ 0x1D,
- /*ascq*/ 0x00,
- SSD_ELEM_NONE);
- else
- ctl_set_success(&io->scsiio);
+ ctl_be_block_compare(io);
}
} else if ((io->io_hdr.port_status != 0) &&
((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
OpenPOWER on IntegriCloud