From a3dd83789208adb6ace2c4bd2588526d0ed0a110 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sun, 25 Dec 2016 09:40:44 +0000 Subject: 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 --- sys/cam/ctl/ctl_tpc.c | 194 ++++++++++++++++++++++++++++++++++++++++---------- 1 file 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); -- cgit v1.2.3