aboutsummaryrefslogtreecommitdiff
path: root/sys/cam/ctl/ctl_tpc.c
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2016-12-25 09:40:44 +0000
committerAlexander Motin <mav@FreeBSD.org>2016-12-25 09:40:44 +0000
commita3dd83789208adb6ace2c4bd2588526d0ed0a110 (patch)
tree52204d755eb7a8b0d83c7ed747bf5d00f6591de6 /sys/cam/ctl/ctl_tpc.c
parent8fd1ba2a5ecefa54c35c79271e7a6a24b5015309 (diff)
downloadsrc-a3dd83789208adb6ace2c4bd2588526d0ed0a110.tar.gz
src-a3dd83789208adb6ace2c4bd2588526d0ed0a110.zip
Improve third-party copy error reporting.
For EXTENDED COPY: - improve parameters checking to report some errors before copy start; - forward sense data from copy target as descriptor in case of error; - report which CSCD reported error in sense key specific information. For WRITE USING TOKEN: - pass through real sense data from copy target instead of reporting our copy error, since for initiator its a "simple" write, not a copy. MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=310534
Diffstat (limited to 'sys/cam/ctl/ctl_tpc.c')
-rw-r--r--sys/cam/ctl/ctl_tpc.c194
1 files changed, 155 insertions, 39 deletions
diff --git a/sys/cam/ctl/ctl_tpc.c b/sys/cam/ctl/ctl_tpc.c
index 8efff1704138..484293b5bcee 100644
--- a/sys/cam/ctl/ctl_tpc.c
+++ b/sys/cam/ctl/ctl_tpc.c
@@ -82,6 +82,8 @@ struct tpc_list;
TAILQ_HEAD(runl, tpc_io);
struct tpc_io {
union ctl_io *io;
+ uint8_t target;
+ uint32_t cscd;
uint64_t lun;
struct tpc_list *list;
struct runl run;
@@ -134,6 +136,11 @@ struct tpc_list {
int completed;
time_t last_active;
TAILQ_HEAD(, tpc_io) allio;
+ struct scsi_sense_data fwd_sense_data;
+ uint8_t fwd_sense_len;
+ uint8_t fwd_scsi_status;
+ uint8_t fwd_target;
+ uint16_t fwd_cscd;
struct scsi_sense_data sense_data;
uint8_t sense_len;
uint8_t scsi_status;
@@ -809,6 +816,44 @@ tpc_resolve(struct tpc_list *list, uint16_t idx, uint32_t *ss,
list->init_port, &list->cscd[idx], ss, pb, pbo));
}
+static void
+tpc_set_io_error_sense(struct tpc_list *list)
+{
+ int flen;
+ uint8_t csi[4];
+ uint8_t sks[3];
+ uint8_t fbuf[4 + 64];
+
+ scsi_ulto4b(list->curseg, csi);
+ if (list->fwd_cscd <= 0x07ff) {
+ sks[0] = SSD_SKS_SEGMENT_VALID;
+ scsi_ulto2b((uint8_t *)&list->cscd[list->fwd_cscd] -
+ list->params, &sks[1]);
+ } else
+ sks[0] = 0;
+ if (list->fwd_scsi_status) {
+ fbuf[0] = 0x0c;
+ fbuf[2] = list->fwd_target;
+ flen = list->fwd_sense_len;
+ if (flen > 64) {
+ flen = 64;
+ fbuf[2] |= SSD_FORWARDED_FSDT;
+ }
+ fbuf[1] = 2 + flen;
+ fbuf[3] = list->fwd_scsi_status;
+ bcopy(&list->fwd_sense_data, &fbuf[4], flen);
+ flen += 4;
+ } else
+ flen = 0;
+ ctl_set_sense(list->ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_COPY_ABORTED,
+ /*asc*/ 0x0d, /*ascq*/ 0x01,
+ SSD_ELEM_COMMAND, sizeof(csi), csi,
+ sks[0] ? SSD_ELEM_SKS : SSD_ELEM_SKIP, sizeof(sks), sks,
+ flen ? SSD_ELEM_DESC : SSD_ELEM_SKIP, flen, fbuf,
+ SSD_ELEM_NONE);
+}
+
static int
tpc_process_b2b(struct tpc_list *list)
{
@@ -820,6 +865,7 @@ tpc_process_b2b(struct tpc_list *list)
off_t srclba, dstlba, numbytes, donebytes, roundbytes;
int numlba;
uint32_t srcblock, dstblock, pb, pbo, adj;
+ uint16_t scscd, dcscd;
uint8_t csi[4];
scsi_ulto4b(list->curseg, csi);
@@ -834,11 +880,7 @@ tpc_process_b2b(struct tpc_list *list)
ctl_set_task_aborted(list->ctsio);
return (CTL_RETVAL_ERROR);
} else if (list->error) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x0d, /*ascq*/ 0x01,
- SSD_ELEM_COMMAND, sizeof(csi), csi,
- SSD_ELEM_NONE);
+ tpc_set_io_error_sense(list);
return (CTL_RETVAL_ERROR);
}
list->cursectors += list->segsectors;
@@ -848,8 +890,10 @@ 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, NULL, NULL);
- dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), &dstblock, &pb, &pbo);
+ scscd = scsi_2btoul(seg->src_cscd);
+ dcscd = scsi_2btoul(seg->dst_cscd);
+ sl = tpc_resolve(list, scscd, &srcblock, NULL, NULL);
+ dl = tpc_resolve(list, dcscd, &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,
@@ -860,10 +904,10 @@ tpc_process_b2b(struct tpc_list *list)
}
if (pbo > 0)
pbo = pb - pbo;
- sdstp = &list->cscd[scsi_2btoul(seg->src_cscd)].dtsp;
+ sdstp = &list->cscd[scscd].dtsp;
if (scsi_3btoul(sdstp->block_length) != 0)
srcblock = scsi_3btoul(sdstp->block_length);
- ddstp = &list->cscd[scsi_2btoul(seg->dst_cscd)].dtsp;
+ ddstp = &list->cscd[dcscd].dtsp;
if (scsi_3btoul(ddstp->block_length) != 0)
dstblock = scsi_3btoul(ddstp->block_length);
numlba = scsi_2btoul(seg->number_of_blocks);
@@ -924,6 +968,8 @@ tpc_process_b2b(struct tpc_list *list)
/*tag_type*/ CTL_TAG_SIMPLE,
/*control*/ 0);
tior->io->io_hdr.retries = 3;
+ tior->target = SSD_FORWARDED_SDS_EXSRC;
+ tior->cscd = scscd;
tior->lun = sl;
tior->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior;
@@ -943,6 +989,8 @@ tpc_process_b2b(struct tpc_list *list)
/*tag_type*/ CTL_TAG_SIMPLE,
/*control*/ 0);
tiow->io->io_hdr.retries = 3;
+ tiow->target = SSD_FORWARDED_SDS_EXDST;
+ tiow->cscd = dcscd;
tiow->lun = dl;
tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow;
@@ -970,6 +1018,7 @@ tpc_process_verify(struct tpc_list *list)
struct scsi_ec_segment_verify *seg;
struct tpc_io *tio;
uint64_t sl;
+ uint16_t cscd;
uint8_t csi[4];
scsi_ulto4b(list->curseg, csi);
@@ -983,11 +1032,7 @@ tpc_process_verify(struct tpc_list *list)
ctl_set_task_aborted(list->ctsio);
return (CTL_RETVAL_ERROR);
} else if (list->error) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x0d, /*ascq*/ 0x01,
- SSD_ELEM_COMMAND, sizeof(csi), csi,
- SSD_ELEM_NONE);
+ tpc_set_io_error_sense(list);
return (CTL_RETVAL_ERROR);
} else
return (CTL_RETVAL_COMPLETE);
@@ -995,7 +1040,8 @@ 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, NULL, NULL);
+ cscd = scsi_2btoul(seg->src_cscd);
+ sl = tpc_resolve(list, cscd, NULL, NULL, NULL);
if (sl >= CTL_MAX_LUNS) {
ctl_set_sense(list->ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_COPY_ABORTED,
@@ -1018,6 +1064,8 @@ tpc_process_verify(struct tpc_list *list)
tio->io = tpcl_alloc_io();
ctl_scsi_tur(tio->io, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0);
tio->io->io_hdr.retries = 3;
+ tio->target = SSD_FORWARDED_SDS_EXSRC;
+ tio->cscd = cscd;
tio->lun = sl;
tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio;
list->stage++;
@@ -1033,6 +1081,7 @@ tpc_process_register_key(struct tpc_list *list)
struct tpc_io *tio;
uint64_t dl;
int datalen;
+ uint16_t cscd;
uint8_t csi[4];
scsi_ulto4b(list->curseg, csi);
@@ -1047,11 +1096,7 @@ tpc_process_register_key(struct tpc_list *list)
ctl_set_task_aborted(list->ctsio);
return (CTL_RETVAL_ERROR);
} else if (list->error) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x0d, /*ascq*/ 0x01,
- SSD_ELEM_COMMAND, sizeof(csi), csi,
- SSD_ELEM_NONE);
+ tpc_set_io_error_sense(list);
return (CTL_RETVAL_ERROR);
} else
return (CTL_RETVAL_COMPLETE);
@@ -1059,7 +1104,8 @@ 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, NULL, NULL);
+ cscd = scsi_2btoul(seg->dst_cscd);
+ dl = tpc_resolve(list, cscd, NULL, NULL, NULL);
if (dl >= CTL_MAX_LUNS) {
ctl_set_sense(list->ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_COPY_ABORTED,
@@ -1084,6 +1130,8 @@ tpc_process_register_key(struct tpc_list *list)
scsi_8btou64(seg->res_key), scsi_8btou64(seg->sa_res_key),
/*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0);
tio->io->io_hdr.retries = 3;
+ tio->target = SSD_FORWARDED_SDS_EXDST;
+ tio->cscd = cscd;
tio->lun = dl;
tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio;
list->stage++;
@@ -1185,9 +1233,17 @@ tpc_process_wut(struct tpc_list *list)
ctl_set_task_aborted(list->ctsio);
return (CTL_RETVAL_ERROR);
} else if (list->error) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x0d, /*ascq*/ 0x01, SSD_ELEM_NONE);
+ if (list->fwd_scsi_status) {
+ list->ctsio->io_hdr.status =
+ CTL_SCSI_ERROR | CTL_AUTOSENSE;
+ list->ctsio->scsi_status = list->fwd_scsi_status;
+ list->ctsio->sense_data = list->fwd_sense_data;
+ list->ctsio->sense_len = list->fwd_sense_len;
+ } else {
+ ctl_set_invalid_field(list->ctsio,
+ /*sks_valid*/ 0, /*command*/ 0,
+ /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0);
+ }
return (CTL_RETVAL_ERROR);
}
list->cursectors += list->segsectors;
@@ -1210,9 +1266,8 @@ tpc_process_wut(struct tpc_list *list)
if (tpc_skip_ranges(list->token->range, list->token->nrange,
list->offset_into_rod + list->cursectors * dstblock / srcblock,
&srange, &soffset) != 0) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x0d, /*ascq*/ 0x04, SSD_ELEM_NONE);
+ ctl_set_invalid_field(list->ctsio, /*sks_valid*/ 0,
+ /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0);
return (CTL_RETVAL_ERROR);
}
@@ -1233,9 +1288,8 @@ tpc_process_wut(struct tpc_list *list)
}
if (numbytes % srcblock != 0 || numbytes % dstblock != 0) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x26, /*ascq*/ 0x0A, SSD_ELEM_NONE);
+ ctl_set_invalid_field(list->ctsio, /*sks_valid*/ 0,
+ /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0);
return (CTL_RETVAL_ERROR);
}
@@ -1337,9 +1391,17 @@ complete:
ctl_set_task_aborted(list->ctsio);
return (CTL_RETVAL_ERROR);
} else if (list->error) {
- ctl_set_sense(list->ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_COPY_ABORTED,
- /*asc*/ 0x0d, /*ascq*/ 0x01, SSD_ELEM_NONE);
+ if (list->fwd_scsi_status) {
+ list->ctsio->io_hdr.status =
+ CTL_SCSI_ERROR | CTL_AUTOSENSE;
+ list->ctsio->scsi_status = list->fwd_scsi_status;
+ list->ctsio->sense_data = list->fwd_sense_data;
+ list->ctsio->sense_len = list->fwd_sense_len;
+ } else {
+ ctl_set_invalid_field(list->ctsio,
+ /*sks_valid*/ 0, /*command*/ 0,
+ /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0);
+ }
return (CTL_RETVAL_ERROR);
}
list->cursectors += list->segsectors;
@@ -1616,9 +1678,17 @@ tpc_done(union ctl_io *io)
}
}
- if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
+ if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) {
tio->list->error = 1;
- else
+ if (io->io_hdr.io_type == CTL_IO_SCSI &&
+ (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR) {
+ tio->list->fwd_scsi_status = io->scsiio.scsi_status;
+ tio->list->fwd_sense_data = io->scsiio.sense_data;
+ tio->list->fwd_sense_len = io->scsiio.sense_len;
+ tio->list->fwd_target = tio->target;
+ tio->list->fwd_cscd = tio->cscd;
+ }
+ } else
atomic_add_int(&tio->list->curops, 1);
if (!tio->list->error && !tio->list->abort) {
while ((tior = TAILQ_FIRST(&tio->run)) != NULL) {
@@ -1637,6 +1707,8 @@ ctl_extended_copy_lid1(struct ctl_scsiio *ctsio)
{
struct scsi_extended_copy *cdb;
struct scsi_extended_copy_lid1_data *data;
+ struct scsi_ec_cscd *cscd;
+ struct scsi_ec_segment *seg;
struct ctl_lun *lun;
struct tpc_list *list, *tlist;
uint8_t *ptr;
@@ -1715,6 +1787,17 @@ ctl_extended_copy_lid1(struct ctl_scsiio *ctsio)
list->flags = data->flags;
list->params = ctsio->kern_data_ptr;
list->cscd = (struct scsi_ec_cscd *)&data->data[0];
+ ptr = &data->data[0];
+ for (off = 0; off < lencscd; off += sizeof(struct scsi_ec_cscd)) {
+ cscd = (struct scsi_ec_cscd *)(ptr + off);
+ if (cscd->type_code != EC_CSCD_ID) {
+ free(list, M_CTL);
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/ 0x26, /*ascq*/ 0x07, SSD_ELEM_NONE);
+ goto done;
+ }
+ }
ptr = &data->data[lencscd];
for (nseg = 0, off = 0; off < lenseg; nseg++) {
if (nseg >= TPC_MAX_SEGS) {
@@ -1724,9 +1807,19 @@ ctl_extended_copy_lid1(struct ctl_scsiio *ctsio)
/*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE);
goto done;
}
- list->seg[nseg] = (struct scsi_ec_segment *)(ptr + off);
+ seg = (struct scsi_ec_segment *)(ptr + off);
+ if (seg->type_code != EC_SEG_B2B &&
+ seg->type_code != EC_SEG_VERIFY &&
+ seg->type_code != EC_SEG_REGISTER_KEY) {
+ free(list, M_CTL);
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE);
+ goto done;
+ }
+ list->seg[nseg] = seg;
off += sizeof(struct scsi_ec_segment) +
- scsi_2btoul(list->seg[nseg]->descr_length);
+ scsi_2btoul(seg->descr_length);
}
list->inl = &data->data[lencscd + lenseg];
list->ncscd = lencscd / sizeof(struct scsi_ec_cscd);
@@ -1770,6 +1863,8 @@ ctl_extended_copy_lid4(struct ctl_scsiio *ctsio)
{
struct scsi_extended_copy *cdb;
struct scsi_extended_copy_lid4_data *data;
+ struct scsi_ec_cscd *cscd;
+ struct scsi_ec_segment *seg;
struct ctl_lun *lun;
struct tpc_list *list, *tlist;
uint8_t *ptr;
@@ -1848,6 +1943,17 @@ ctl_extended_copy_lid4(struct ctl_scsiio *ctsio)
list->flags = data->flags;
list->params = ctsio->kern_data_ptr;
list->cscd = (struct scsi_ec_cscd *)&data->data[0];
+ ptr = &data->data[0];
+ for (off = 0; off < lencscd; off += sizeof(struct scsi_ec_cscd)) {
+ cscd = (struct scsi_ec_cscd *)(ptr + off);
+ if (cscd->type_code != EC_CSCD_ID) {
+ free(list, M_CTL);
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/ 0x26, /*ascq*/ 0x07, SSD_ELEM_NONE);
+ goto done;
+ }
+ }
ptr = &data->data[lencscd];
for (nseg = 0, off = 0; off < lenseg; nseg++) {
if (nseg >= TPC_MAX_SEGS) {
@@ -1857,9 +1963,19 @@ ctl_extended_copy_lid4(struct ctl_scsiio *ctsio)
/*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE);
goto done;
}
- list->seg[nseg] = (struct scsi_ec_segment *)(ptr + off);
+ seg = (struct scsi_ec_segment *)(ptr + off);
+ if (seg->type_code != EC_SEG_B2B &&
+ seg->type_code != EC_SEG_VERIFY &&
+ seg->type_code != EC_SEG_REGISTER_KEY) {
+ free(list, M_CTL);
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE);
+ goto done;
+ }
+ list->seg[nseg] = seg;
off += sizeof(struct scsi_ec_segment) +
- scsi_2btoul(list->seg[nseg]->descr_length);
+ scsi_2btoul(seg->descr_length);
}
list->inl = &data->data[lencscd + lenseg];
list->ncscd = lencscd / sizeof(struct scsi_ec_cscd);