Author: mav
Date: Sun Dec 25 09:40:44 2016
New Revision: 310534
URL: https://svnweb.freebsd.org/changeset/base/310534

Log:
  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

Modified:
  head/sys/cam/ctl/ctl_tpc.c

Modified: head/sys/cam/ctl/ctl_tpc.c
==============================================================================
--- head/sys/cam/ctl/ctl_tpc.c  Sun Dec 25 08:02:37 2016        (r310533)
+++ head/sys/cam/ctl/ctl_tpc.c  Sun Dec 25 09:40:44 2016        (r310534)
@@ -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, uint1
            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
        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
                        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
 
        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
            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
 {
        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
        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
                            /*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
 {
        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
        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
                            /*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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to