Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Dec 2016 09:40:45 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310534 - head/sys/cam/ctl
Message-ID:  <201612250940.uBP9ej60031054@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612250940.uBP9ej60031054>