aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/cam/ctl/ctl_backend_block.c10
-rw-r--r--sys/cam/ctl/ctl_tpc.c82
-rw-r--r--sys/cam/ctl/ctl_tpc.h2
-rw-r--r--sys/cam/ctl/ctl_tpc_local.c8
4 files changed, 78 insertions, 24 deletions
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index 6b5f703a5bff..37ba5a8f481e 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -1187,7 +1187,8 @@ ctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio;
struct ctl_be_block_softc *softc;
struct ctl_lba_len_flags *lbalen;
- uint64_t len_left, lba, pb, pbo, adj;
+ uint64_t len_left, lba;
+ uint32_t pb, pbo, adj;
int i, seglen;
uint8_t *buf, *end;
@@ -1241,8 +1242,11 @@ ctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun,
DPRINTF("WRITE SAME at LBA %jx len %u\n",
(uintmax_t)lbalen->lba, lbalen->len);
- pb = (uint64_t)be_lun->blocksize << be_lun->pblockexp;
- pbo = pb - (uint64_t)be_lun->blocksize * be_lun->pblockoff;
+ pb = be_lun->blocksize << be_lun->pblockexp;
+ if (be_lun->pblockoff > 0)
+ pbo = pb - be_lun->blocksize * be_lun->pblockoff;
+ else
+ pbo = 0;
len_left = (uint64_t)lbalen->len * be_lun->blocksize;
for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) {
diff --git a/sys/cam/ctl/ctl_tpc.c b/sys/cam/ctl/ctl_tpc.c
index 63aee278bb96..fee5b90bd4f6 100644
--- a/sys/cam/ctl/ctl_tpc.c
+++ b/sys/cam/ctl/ctl_tpc.c
@@ -785,18 +785,25 @@ ctl_copy_operation_abort(struct ctl_scsiio *ctsio)
}
static uint64_t
-tpc_resolve(struct tpc_list *list, uint16_t idx, uint32_t *ss)
+tpc_resolve(struct tpc_list *list, uint16_t idx, uint32_t *ss,
+ uint32_t *pb, uint32_t *pbo)
{
if (idx == 0xffff) {
if (ss && list->lun->be_lun)
*ss = list->lun->be_lun->blocksize;
+ if (pb && list->lun->be_lun)
+ *pb = list->lun->be_lun->blocksize <<
+ list->lun->be_lun->pblockexp;
+ if (pbo && list->lun->be_lun)
+ *pbo = list->lun->be_lun->blocksize *
+ list->lun->be_lun->pblockoff;
return (list->lun->lun);
}
if (idx >= list->ncscd)
return (UINT64_MAX);
return (tpcl_resolve(list->lun->ctl_softc,
- list->init_port, &list->cscd[idx], ss));
+ list->init_port, &list->cscd[idx], ss, pb, pbo));
}
static int
@@ -809,7 +816,7 @@ tpc_process_b2b(struct tpc_list *list)
uint64_t sl, dl;
off_t srclba, dstlba, numbytes, donebytes, roundbytes;
int numlba;
- uint32_t srcblock, dstblock;
+ uint32_t srcblock, dstblock, pb, pbo, adj;
if (list->stage == 1) {
while ((tior = TAILQ_FIRST(&list->allio)) != NULL) {
@@ -834,14 +841,16 @@ tpc_process_b2b(struct tpc_list *list)
TAILQ_INIT(&list->allio);
seg = (struct scsi_ec_segment_b2b *)list->seg[list->curseg];
- sl = tpc_resolve(list, scsi_2btoul(seg->src_cscd), &srcblock);
- dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), &dstblock);
+ sl = tpc_resolve(list, scsi_2btoul(seg->src_cscd), &srcblock, NULL, NULL);
+ dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), &dstblock, &pb, &pbo);
if (sl >= CTL_MAX_LUNS || dl >= CTL_MAX_LUNS) {
ctl_set_sense(list->ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_COPY_ABORTED,
/*asc*/ 0x08, /*ascq*/ 0x04, SSD_ELEM_NONE);
return (CTL_RETVAL_ERROR);
}
+ if (pbo > 0)
+ pbo = pb - pbo;
sdstp = &list->cscd[scsi_2btoul(seg->src_cscd)].dtsp;
if (scsi_3btoul(sdstp->block_length) != 0)
srcblock = scsi_3btoul(sdstp->block_length);
@@ -878,7 +887,16 @@ tpc_process_b2b(struct tpc_list *list)
prun = &run;
list->tbdio = 1;
while (donebytes < numbytes) {
- roundbytes = MIN(numbytes - donebytes, TPC_MAX_IO_SIZE);
+ roundbytes = numbytes - donebytes;
+ if (roundbytes > TPC_MAX_IO_SIZE) {
+ roundbytes = TPC_MAX_IO_SIZE;
+ roundbytes -= roundbytes % dstblock;
+ if (pb > dstblock) {
+ adj = (dstlba * dstblock + roundbytes - pbo) % pb;
+ if (roundbytes > adj)
+ roundbytes -= adj;
+ }
+ }
tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO);
TAILQ_INIT(&tior->run);
@@ -891,7 +909,7 @@ tpc_process_b2b(struct tpc_list *list)
/*read_op*/ 1,
/*byte2*/ 0,
/*minimum_cdb_size*/ 0,
- /*lba*/ srclba + donebytes / srcblock,
+ /*lba*/ srclba,
/*num_blocks*/ roundbytes / srcblock,
/*tag_type*/ CTL_TAG_SIMPLE,
/*control*/ 0);
@@ -910,7 +928,7 @@ tpc_process_b2b(struct tpc_list *list)
/*read_op*/ 0,
/*byte2*/ 0,
/*minimum_cdb_size*/ 0,
- /*lba*/ dstlba + donebytes / dstblock,
+ /*lba*/ dstlba,
/*num_blocks*/ roundbytes / dstblock,
/*tag_type*/ CTL_TAG_SIMPLE,
/*control*/ 0);
@@ -922,6 +940,8 @@ tpc_process_b2b(struct tpc_list *list)
TAILQ_INSERT_TAIL(prun, tior, rlinks);
prun = &tior->run;
donebytes += roundbytes;
+ srclba += roundbytes / srcblock;
+ dstlba += roundbytes / dstblock;
}
while ((tior = TAILQ_FIRST(&run)) != NULL) {
@@ -961,7 +981,7 @@ tpc_process_verify(struct tpc_list *list)
TAILQ_INIT(&list->allio);
seg = (struct scsi_ec_segment_verify *)list->seg[list->curseg];
- sl = tpc_resolve(list, scsi_2btoul(seg->src_cscd), NULL);
+ sl = tpc_resolve(list, scsi_2btoul(seg->src_cscd), NULL, NULL, NULL);
if (sl >= CTL_MAX_LUNS) {
ctl_set_sense(list->ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_COPY_ABORTED,
@@ -1019,7 +1039,7 @@ tpc_process_register_key(struct tpc_list *list)
TAILQ_INIT(&list->allio);
seg = (struct scsi_ec_segment_register_key *)list->seg[list->curseg];
- dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), NULL);
+ dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), NULL, NULL, NULL);
if (dl >= CTL_MAX_LUNS) {
ctl_set_sense(list->ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_COPY_ABORTED,
@@ -1090,7 +1110,7 @@ tpc_process_wut(struct tpc_list *list)
int drange, srange;
off_t doffset, soffset;
off_t srclba, dstlba, numbytes, donebytes, roundbytes;
- uint32_t srcblock, dstblock;
+ uint32_t srcblock, dstblock, pb, pbo, adj;
if (list->stage > 0) {
/* Cleanup after previous rounds. */
@@ -1118,6 +1138,11 @@ tpc_process_wut(struct tpc_list *list)
&drange, &doffset) != 0)
return (CTL_RETVAL_COMPLETE);
dstblock = list->lun->be_lun->blocksize;
+ pb = dstblock << list->lun->be_lun->pblockexp;
+ if (list->lun->be_lun->pblockoff > 0)
+ pbo = pb - dstblock * list->lun->be_lun->pblockoff;
+ else
+ pbo = 0;
/* Check where we are on source ranges list. */
srcblock = list->token->blocksize;
@@ -1131,12 +1156,20 @@ tpc_process_wut(struct tpc_list *list)
}
srclba = scsi_8btou64(list->token->range[srange].lba) + soffset;
- numbytes = srcblock * omin(TPC_MAX_IOCHUNK_SIZE / srcblock,
- (scsi_4btoul(list->token->range[srange].length) - soffset));
dstlba = scsi_8btou64(list->range[drange].lba) + doffset;
- numbytes = omin(numbytes,
- dstblock * omin(TPC_MAX_IOCHUNK_SIZE / dstblock,
- (scsi_4btoul(list->range[drange].length) - doffset)));
+ numbytes = srcblock *
+ (scsi_4btoul(list->token->range[srange].length) - soffset);
+ numbytes = omin(numbytes, dstblock *
+ (scsi_4btoul(list->range[drange].length) - doffset));
+ if (numbytes > TPC_MAX_IOCHUNK_SIZE) {
+ numbytes = TPC_MAX_IOCHUNK_SIZE;
+ numbytes -= numbytes % dstblock;
+ if (pb > dstblock) {
+ adj = (dstlba * dstblock + numbytes - pbo) % pb;
+ if (numbytes > adj)
+ numbytes -= adj;
+ }
+ }
if (numbytes % srcblock != 0 || numbytes % dstblock != 0) {
ctl_set_sense(list->ctsio, /*current_error*/ 1,
@@ -1157,7 +1190,16 @@ tpc_process_wut(struct tpc_list *list)
list->tbdio = 1;
TAILQ_INIT(&list->allio);
while (donebytes < numbytes) {
- roundbytes = MIN(numbytes - donebytes, TPC_MAX_IO_SIZE);
+ roundbytes = numbytes - donebytes;
+ if (roundbytes > TPC_MAX_IO_SIZE) {
+ roundbytes = TPC_MAX_IO_SIZE;
+ roundbytes -= roundbytes % dstblock;
+ if (pb > dstblock) {
+ adj = (dstlba * dstblock + roundbytes - pbo) % pb;
+ if (roundbytes > adj)
+ roundbytes -= adj;
+ }
+ }
tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO);
TAILQ_INIT(&tior->run);
@@ -1170,7 +1212,7 @@ tpc_process_wut(struct tpc_list *list)
/*read_op*/ 1,
/*byte2*/ 0,
/*minimum_cdb_size*/ 0,
- /*lba*/ srclba + donebytes / srcblock,
+ /*lba*/ srclba,
/*num_blocks*/ roundbytes / srcblock,
/*tag_type*/ CTL_TAG_SIMPLE,
/*control*/ 0);
@@ -1189,7 +1231,7 @@ tpc_process_wut(struct tpc_list *list)
/*read_op*/ 0,
/*byte2*/ 0,
/*minimum_cdb_size*/ 0,
- /*lba*/ dstlba + donebytes / dstblock,
+ /*lba*/ dstlba,
/*num_blocks*/ roundbytes / dstblock,
/*tag_type*/ CTL_TAG_SIMPLE,
/*control*/ 0);
@@ -1201,6 +1243,8 @@ tpc_process_wut(struct tpc_list *list)
TAILQ_INSERT_TAIL(prun, tior, rlinks);
prun = &tior->run;
donebytes += roundbytes;
+ srclba += roundbytes / srcblock;
+ dstlba += roundbytes / dstblock;
}
while ((tior = TAILQ_FIRST(&run)) != NULL) {
diff --git a/sys/cam/ctl/ctl_tpc.h b/sys/cam/ctl/ctl_tpc.h
index ffdab5a44b90..a02183ba6bfc 100644
--- a/sys/cam/ctl/ctl_tpc.h
+++ b/sys/cam/ctl/ctl_tpc.h
@@ -32,7 +32,7 @@
void tpc_done(union ctl_io *io);
uint64_t tpcl_resolve(struct ctl_softc *softc, int init_port,
- struct scsi_ec_cscd *cscd, uint32_t *ss);
+ struct scsi_ec_cscd *cscd, uint32_t *ss, uint32_t *ps, uint32_t *pso);
union ctl_io * tpcl_alloc_io(void);
int tpcl_queue(union ctl_io *io, uint64_t lun);
diff --git a/sys/cam/ctl/ctl_tpc_local.c b/sys/cam/ctl/ctl_tpc_local.c
index a2544187cdae..a8f675b278e6 100644
--- a/sys/cam/ctl/ctl_tpc_local.c
+++ b/sys/cam/ctl/ctl_tpc_local.c
@@ -309,7 +309,7 @@ tpcl_done(union ctl_io *io)
uint64_t
tpcl_resolve(struct ctl_softc *softc, int init_port,
- struct scsi_ec_cscd *cscd, uint32_t *ss)
+ struct scsi_ec_cscd *cscd, uint32_t *ss, uint32_t *ps, uint32_t *pso)
{
struct scsi_ec_cscd_id *cscdid;
struct ctl_port *port;
@@ -337,6 +337,12 @@ tpcl_resolve(struct ctl_softc *softc, int init_port,
lunid = lun->lun;
if (ss && lun->be_lun)
*ss = lun->be_lun->blocksize;
+ if (ps && lun->be_lun)
+ *ps = lun->be_lun->blocksize <<
+ lun->be_lun->pblockexp;
+ if (pso && lun->be_lun)
+ *pso = lun->be_lun->blocksize *
+ lun->be_lun->pblockoff;
break;
}
}