svn commit: r310257 - in head/sys/cam: ctl scsi

Alexander Motin mav at FreeBSD.org
Mon Dec 19 10:25:49 UTC 2016


Author: mav
Date: Mon Dec 19 10:25:47 2016
New Revision: 310257
URL: https://svnweb.freebsd.org/changeset/base/310257

Log:
  Improve support for informational exceptions.
  
  While CTL still has no real events to report in this way (like SMART),
  it is possible to trigger false event by manually setting TEST bit in
  Informational Exceptions Control mode page, that can be useful for
  initiator testing.  This code supports all flavours of IE reporting:
  UNIT ATTENTION, RECOVERED ERROR and NO SENSE sense keys, REQUEST SENSE
  command and Informational Exceptions log page.
  
  MFC after:	2 weeks
  Sponsored by:	iXsystems, Inc.

Modified:
  head/sys/cam/ctl/ctl.c
  head/sys/cam/ctl/ctl.h
  head/sys/cam/ctl/ctl_error.c
  head/sys/cam/ctl/ctl_private.h
  head/sys/cam/scsi/scsi_all.h
  head/sys/cam/scsi/scsi_da.h

Modified: head/sys/cam/ctl/ctl.c
==============================================================================
--- head/sys/cam/ctl/ctl.c	Mon Dec 19 10:00:56 2016	(r310256)
+++ head/sys/cam/ctl/ctl.c	Mon Dec 19 10:25:47 2016	(r310257)
@@ -93,25 +93,6 @@ struct ctl_softc *control_softc = NULL;
  * Note that these are default values only.  The actual values will be
  * filled in when the user does a mode sense.
  */
-const static struct copan_debugconf_subpage debugconf_page_default = {
-	DBGCNF_PAGE_CODE | SMPH_SPF,	/* page_code */
-	DBGCNF_SUBPAGE_CODE,		/* subpage */
-	{(sizeof(struct copan_debugconf_subpage) - 4) >> 8,
-	 (sizeof(struct copan_debugconf_subpage) - 4) >> 0}, /* page_length */
-	DBGCNF_VERSION,			/* page_version */
-	{CTL_TIME_IO_DEFAULT_SECS>>8,
-	 CTL_TIME_IO_DEFAULT_SECS>>0},	/* ctl_time_io_secs */
-};
-
-const static struct copan_debugconf_subpage debugconf_page_changeable = {
-	DBGCNF_PAGE_CODE | SMPH_SPF,	/* page_code */
-	DBGCNF_SUBPAGE_CODE,		/* subpage */
-	{(sizeof(struct copan_debugconf_subpage) - 4) >> 8,
-	 (sizeof(struct copan_debugconf_subpage) - 4) >> 0}, /* page_length */
-	0,				/* page_version */
-	{0xff,0xff},			/* ctl_time_io_secs */
-};
-
 const static struct scsi_da_rw_recovery_page rw_er_page_default = {
 	/*page_code*/SMS_RW_ERROR_RECOVERY_PAGE,
 	/*page_length*/sizeof(struct scsi_da_rw_recovery_page) - 2,
@@ -129,12 +110,12 @@ const static struct scsi_da_rw_recovery_
 const static struct scsi_da_rw_recovery_page rw_er_page_changeable = {
 	/*page_code*/SMS_RW_ERROR_RECOVERY_PAGE,
 	/*page_length*/sizeof(struct scsi_da_rw_recovery_page) - 2,
-	/*byte3*/0,
+	/*byte3*/SMS_RWER_PER,
 	/*read_retry_count*/0,
 	/*correction_span*/0,
 	/*head_offset_count*/0,
 	/*data_strobe_offset_cnt*/0,
-	/*byte8*/0,
+	/*byte8*/SMS_RWER_LBPERE,
 	/*write_retry_count*/0,
 	/*reserved2*/0,
 	/*recovery_time_limit*/{0, 0},
@@ -206,6 +187,24 @@ const static struct scsi_rigid_disk_page
 	/*reserved2*/ {0, 0}
 };
 
+const static struct scsi_da_verify_recovery_page verify_er_page_default = {
+	/*page_code*/SMS_VERIFY_ERROR_RECOVERY_PAGE,
+	/*page_length*/sizeof(struct scsi_da_verify_recovery_page) - 2,
+	/*byte3*/0,
+	/*read_retry_count*/0,
+	/*reserved*/{ 0, 0, 0, 0, 0, 0 },
+	/*recovery_time_limit*/{0, 0},
+};
+
+const static struct scsi_da_verify_recovery_page verify_er_page_changeable = {
+	/*page_code*/SMS_VERIFY_ERROR_RECOVERY_PAGE,
+	/*page_length*/sizeof(struct scsi_da_verify_recovery_page) - 2,
+	/*byte3*/SMS_VER_PER,
+	/*read_retry_count*/0,
+	/*reserved*/{ 0, 0, 0, 0, 0, 0 },
+	/*recovery_time_limit*/{0, 0},
+};
+
 const static struct scsi_caching_page caching_page_default = {
 	/*page_code*/SMS_CACHING_PAGE,
 	/*page_length*/sizeof(struct scsi_caching_page) - 2,
@@ -285,19 +284,20 @@ const static struct scsi_control_ext_pag
 const static struct scsi_info_exceptions_page ie_page_default = {
 	/*page_code*/SMS_INFO_EXCEPTIONS_PAGE,
 	/*page_length*/sizeof(struct scsi_info_exceptions_page) - 2,
-	/*info_flags*/SIEP_FLAGS_DEXCPT,
-	/*mrie*/0,
+	/*info_flags*/SIEP_FLAGS_EWASC,
+	/*mrie*/SIEP_MRIE_NO,
 	/*interval_timer*/{0, 0, 0, 0},
-	/*report_count*/{0, 0, 0, 0}
+	/*report_count*/{0, 0, 0, 1}
 };
 
 const static struct scsi_info_exceptions_page ie_page_changeable = {
 	/*page_code*/SMS_INFO_EXCEPTIONS_PAGE,
 	/*page_length*/sizeof(struct scsi_info_exceptions_page) - 2,
-	/*info_flags*/0,
-	/*mrie*/0,
-	/*interval_timer*/{0, 0, 0, 0},
-	/*report_count*/{0, 0, 0, 0}
+	/*info_flags*/SIEP_FLAGS_EWASC | SIEP_FLAGS_DEXCPT | SIEP_FLAGS_TEST |
+	    SIEP_FLAGS_LOGERR,
+	/*mrie*/0x0f,
+	/*interval_timer*/{0xff, 0xff, 0xff, 0xff},
+	/*report_count*/{0xff, 0xff, 0xff, 0xff}
 };
 
 #define CTL_LBPM_LEN	(sizeof(struct ctl_logical_block_provisioning_page) - 4)
@@ -4070,6 +4070,26 @@ ctl_init_page_index(struct ctl_lun *lun)
 				(uint8_t *)lun->mode_pages.rigid_disk_page;
 			break;
 		}
+		case SMS_VERIFY_ERROR_RECOVERY_PAGE: {
+			KASSERT(page_index->subpage == SMS_SUBPAGE_PAGE_0,
+			    ("subpage %#x for page %#x is incorrect!",
+			    page_index->subpage, page_code));
+			memcpy(&lun->mode_pages.verify_er_page[CTL_PAGE_CURRENT],
+			       &verify_er_page_default,
+			       sizeof(verify_er_page_default));
+			memcpy(&lun->mode_pages.verify_er_page[CTL_PAGE_CHANGEABLE],
+			       &verify_er_page_changeable,
+			       sizeof(verify_er_page_changeable));
+			memcpy(&lun->mode_pages.verify_er_page[CTL_PAGE_DEFAULT],
+			       &verify_er_page_default,
+			       sizeof(verify_er_page_default));
+			memcpy(&lun->mode_pages.verify_er_page[CTL_PAGE_SAVED],
+			       &verify_er_page_default,
+			       sizeof(verify_er_page_default));
+			page_index->page_data =
+				(uint8_t *)lun->mode_pages.verify_er_page;
+			break;
+		}
 		case SMS_CACHING_PAGE: {
 			struct scsi_caching_page *caching_page;
 
@@ -4280,35 +4300,6 @@ ctl_init_page_index(struct ctl_lun *lun)
 				(uint8_t *)lun->mode_pages.cddvd_page;
 			break;
 		}
-		case SMS_VENDOR_SPECIFIC_PAGE:{
-			switch (page_index->subpage) {
-			case DBGCNF_SUBPAGE_CODE: {
-				memcpy(&lun->mode_pages.debugconf_subpage[
-				       CTL_PAGE_CURRENT],
-				       &debugconf_page_default,
-				       sizeof(debugconf_page_default));
-				memcpy(&lun->mode_pages.debugconf_subpage[
-				       CTL_PAGE_CHANGEABLE],
-				       &debugconf_page_changeable,
-				       sizeof(debugconf_page_changeable));
-				memcpy(&lun->mode_pages.debugconf_subpage[
-				       CTL_PAGE_DEFAULT],
-				       &debugconf_page_default,
-				       sizeof(debugconf_page_default));
-				memcpy(&lun->mode_pages.debugconf_subpage[
-				       CTL_PAGE_SAVED],
-				       &debugconf_page_default,
-				       sizeof(debugconf_page_default));
-				page_index->page_data =
-				    (uint8_t *)lun->mode_pages.debugconf_subpage;
-				break;
-			}
-			default:
-				panic("subpage %#x for page %#x is incorrect!",
-				      page_index->subpage, page_code);
-			}
-			break;
-		}
 		default:
 			panic("invalid page code value %#x", page_code);
 		}
@@ -4361,6 +4352,8 @@ ctl_init_log_page_index(struct ctl_lun *
 	lun->log_pages.index[2].page_len = 12*CTL_NUM_LBP_PARAMS;
 	lun->log_pages.index[3].page_data = (uint8_t *)&lun->log_pages.stat_page;
 	lun->log_pages.index[3].page_len = sizeof(lun->log_pages.stat_page);
+	lun->log_pages.index[4].page_data = (uint8_t *)&lun->log_pages.ie_page;
+	lun->log_pages.index[4].page_len = sizeof(lun->log_pages.ie_page);
 
 	return (CTL_RETVAL_COMPLETE);
 }
@@ -4591,6 +4584,8 @@ ctl_alloc_lun(struct ctl_softc *ctl_soft
 	TAILQ_INIT(&lun->ooa_queue);
 	TAILQ_INIT(&lun->blocked_queue);
 	STAILQ_INIT(&lun->error_list);
+	lun->ie_reported = 1;
+	callout_init_mtx(&lun->ie_callout, &lun->lun_lock, 0);
 	ctl_tpc_lun_init(lun);
 
 	/*
@@ -4664,6 +4659,9 @@ ctl_free_lun(struct ctl_lun *lun)
 	atomic_subtract_int(&lun->be_lun->be->num_luns, 1);
 	lun->be_lun->lun_shutdown(lun->be_lun->be_lun);
 
+	lun->ie_reportcnt = UINT32_MAX;
+	callout_drain(&lun->ie_callout);
+
 	ctl_tpc_lun_shutdown(lun);
 	mtx_destroy(&lun->lun_lock);
 	free(lun->lun_devid, M_CTL);
@@ -5832,25 +5830,12 @@ done:
 	return (CTL_RETVAL_COMPLETE);
 }
 
-/*
- * Note that this function currently doesn't actually do anything inside
- * CTL to enforce things if the DQue bit is turned on.
- *
- * Also note that this function can't be used in the default case, because
- * the DQue bit isn't set in the changeable mask for the control mode page
- * anyway.  This is just here as an example for how to implement a page
- * handler, and a placeholder in case we want to allow the user to turn
- * tagged queueing on and off.
- *
- * The D_SENSE bit handling is functional, however, and will turn
- * descriptor sense on and off for a given LUN.
- */
 int
-ctl_control_page_handler(struct ctl_scsiio *ctsio,
+ctl_default_page_handler(struct ctl_scsiio *ctsio,
 			 struct ctl_page_index *page_index, uint8_t *page_ptr)
 {
-	struct scsi_control_page *current_cp, *saved_cp, *user_cp;
 	struct ctl_lun *lun;
+	uint8_t *current_cp, *saved_cp;
 	int set_ua;
 	uint32_t initidx;
 
@@ -5858,50 +5843,15 @@ ctl_control_page_handler(struct ctl_scsi
 	initidx = ctl_get_initindex(&ctsio->io_hdr.nexus);
 	set_ua = 0;
 
-	user_cp = (struct scsi_control_page *)page_ptr;
-	current_cp = (struct scsi_control_page *)
-		(page_index->page_data + (page_index->page_len *
-		CTL_PAGE_CURRENT));
-	saved_cp = (struct scsi_control_page *)
-		(page_index->page_data + (page_index->page_len *
-		CTL_PAGE_SAVED));
+	current_cp = (page_index->page_data + (page_index->page_len *
+	    CTL_PAGE_CURRENT));
+	saved_cp = (page_index->page_data + (page_index->page_len *
+	    CTL_PAGE_SAVED));
 
 	mtx_lock(&lun->lun_lock);
-	if (((current_cp->rlec & SCP_DSENSE) == 0)
-	 && ((user_cp->rlec & SCP_DSENSE) != 0)) {
-		/*
-		 * Descriptor sense is currently turned off and the user
-		 * wants to turn it on.
-		 */
-		current_cp->rlec |= SCP_DSENSE;
-		saved_cp->rlec |= SCP_DSENSE;
-		lun->flags |= CTL_LUN_SENSE_DESC;
-		set_ua = 1;
-	} else if (((current_cp->rlec & SCP_DSENSE) != 0)
-		&& ((user_cp->rlec & SCP_DSENSE) == 0)) {
-		/*
-		 * Descriptor sense is currently turned on, and the user
-		 * wants to turn it off.
-		 */
-		current_cp->rlec &= ~SCP_DSENSE;
-		saved_cp->rlec &= ~SCP_DSENSE;
-		lun->flags &= ~CTL_LUN_SENSE_DESC;
-		set_ua = 1;
-	}
-	if ((current_cp->queue_flags & SCP_QUEUE_ALG_MASK) !=
-	    (user_cp->queue_flags & SCP_QUEUE_ALG_MASK)) {
-		current_cp->queue_flags &= ~SCP_QUEUE_ALG_MASK;
-		current_cp->queue_flags |= user_cp->queue_flags & SCP_QUEUE_ALG_MASK;
-		saved_cp->queue_flags &= ~SCP_QUEUE_ALG_MASK;
-		saved_cp->queue_flags |= user_cp->queue_flags & SCP_QUEUE_ALG_MASK;
-		set_ua = 1;
-	}
-	if ((current_cp->eca_and_aen & SCP_SWP) !=
-	    (user_cp->eca_and_aen & SCP_SWP)) {
-		current_cp->eca_and_aen &= ~SCP_SWP;
-		current_cp->eca_and_aen |= user_cp->eca_and_aen & SCP_SWP;
-		saved_cp->eca_and_aen &= ~SCP_SWP;
-		saved_cp->eca_and_aen |= user_cp->eca_and_aen & SCP_SWP;
+	if (memcmp(current_cp, page_ptr, page_index->page_len)) {
+		memcpy(current_cp, page_ptr, page_index->page_len);
+		memcpy(saved_cp, page_ptr, page_index->page_len);
 		set_ua = 1;
 	}
 	if (set_ua != 0)
@@ -5912,101 +5862,78 @@ ctl_control_page_handler(struct ctl_scsi
 		    ctl_get_initindex(&ctsio->io_hdr.nexus),
 		    page_index->page_code, page_index->subpage);
 	}
-	return (0);
+	return (CTL_RETVAL_COMPLETE);
 }
 
-int
-ctl_caching_sp_handler(struct ctl_scsiio *ctsio,
-		     struct ctl_page_index *page_index, uint8_t *page_ptr)
+static void
+ctl_ie_timer(void *arg)
 {
-	struct scsi_caching_page *current_cp, *saved_cp, *user_cp;
-	struct ctl_lun *lun;
-	int set_ua;
-	uint32_t initidx;
+	struct ctl_lun *lun = arg;
+	struct scsi_info_exceptions_page *pg;
+	uint64_t t;
 
-	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
-	initidx = ctl_get_initindex(&ctsio->io_hdr.nexus);
-	set_ua = 0;
+	if (lun->ie_asc == 0)
+		return;
 
-	user_cp = (struct scsi_caching_page *)page_ptr;
-	current_cp = (struct scsi_caching_page *)
-		(page_index->page_data + (page_index->page_len *
-		CTL_PAGE_CURRENT));
-	saved_cp = (struct scsi_caching_page *)
-		(page_index->page_data + (page_index->page_len *
-		CTL_PAGE_SAVED));
+	pg = &lun->mode_pages.ie_page[CTL_PAGE_CURRENT];
+	if (pg->mrie == SIEP_MRIE_UA)
+		ctl_est_ua_all(lun, -1, CTL_UA_IE);
+	else
+		lun->ie_reported = 0;
 
-	mtx_lock(&lun->lun_lock);
-	if ((current_cp->flags1 & (SCP_WCE | SCP_RCD)) !=
-	    (user_cp->flags1 & (SCP_WCE | SCP_RCD))) {
-		current_cp->flags1 &= ~(SCP_WCE | SCP_RCD);
-		current_cp->flags1 |= user_cp->flags1 & (SCP_WCE | SCP_RCD);
-		saved_cp->flags1 &= ~(SCP_WCE | SCP_RCD);
-		saved_cp->flags1 |= user_cp->flags1 & (SCP_WCE | SCP_RCD);
-		set_ua = 1;
+	if (lun->ie_reportcnt < scsi_4btoul(pg->report_count)) {
+		lun->ie_reportcnt++;
+		t = scsi_4btoul(pg->interval_timer);
+		if (t == 0 || t == UINT32_MAX)
+			t = 3000;  /* 5 min */
+		callout_schedule(&lun->ie_callout, t * hz / 10);
 	}
-	if (set_ua != 0)
-		ctl_est_ua_all(lun, initidx, CTL_UA_MODE_CHANGE);
-	mtx_unlock(&lun->lun_lock);
-	if (set_ua) {
-		ctl_isc_announce_mode(lun,
-		    ctl_get_initindex(&ctsio->io_hdr.nexus),
-		    page_index->page_code, page_index->subpage);
-	}
-	return (0);
 }
 
 int
-ctl_debugconf_sp_select_handler(struct ctl_scsiio *ctsio,
-				struct ctl_page_index *page_index,
-				uint8_t *page_ptr)
-{
-	uint8_t *c;
-	int i;
-
-	c = ((struct copan_debugconf_subpage *)page_ptr)->ctl_time_io_secs;
-	ctl_time_io_secs =
-		(c[0] << 8) |
-		(c[1] << 0) |
-		0;
-	CTL_DEBUG_PRINT(("set ctl_time_io_secs to %d\n", ctl_time_io_secs));
-	printf("set ctl_time_io_secs to %d\n", ctl_time_io_secs);
-	printf("page data:");
-	for (i=0; i<8; i++)
-		printf(" %.2x",page_ptr[i]);
-	printf("\n");
-	return (0);
-}
-
-int
-ctl_debugconf_sp_sense_handler(struct ctl_scsiio *ctsio,
-			       struct ctl_page_index *page_index,
-			       int pc)
+ctl_ie_page_handler(struct ctl_scsiio *ctsio,
+			 struct ctl_page_index *page_index, uint8_t *page_ptr)
 {
-	struct copan_debugconf_subpage *page;
+	struct scsi_info_exceptions_page *pg;
+	struct ctl_lun *lun;
+	uint64_t t;
 
-	page = (struct copan_debugconf_subpage *)page_index->page_data +
-		(page_index->page_len * pc);
+	(void)ctl_default_page_handler(ctsio, page_index, page_ptr);
 
-	switch (pc) {
-	case SMS_PAGE_CTRL_CHANGEABLE >> 6:
-	case SMS_PAGE_CTRL_DEFAULT >> 6:
-	case SMS_PAGE_CTRL_SAVED >> 6:
-		/*
-		 * We don't update the changeable or default bits for this page.
-		 */
-		break;
-	case SMS_PAGE_CTRL_CURRENT >> 6:
-		page->ctl_time_io_secs[0] = ctl_time_io_secs >> 8;
-		page->ctl_time_io_secs[1] = ctl_time_io_secs >> 0;
-		break;
-	default:
-		break;
+	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+	pg = (struct scsi_info_exceptions_page *)page_ptr;
+	mtx_lock(&lun->lun_lock);
+	if (pg->info_flags & SIEP_FLAGS_TEST) {
+		lun->ie_asc = 0x5d;
+		lun->ie_ascq = 0xff;
+		if (pg->mrie == SIEP_MRIE_UA) {
+			ctl_est_ua_all(lun, -1, CTL_UA_IE);
+			lun->ie_reported = 1;
+		} else {
+			ctl_clr_ua_all(lun, -1, CTL_UA_IE);
+			lun->ie_reported = -1;
+		}
+		lun->ie_reportcnt = 1;
+		if (lun->ie_reportcnt < scsi_4btoul(pg->report_count)) {
+			lun->ie_reportcnt++;
+			t = scsi_4btoul(pg->interval_timer);
+			if (t == 0 || t == UINT32_MAX)
+				t = 3000;  /* 5 min */
+			callout_reset(&lun->ie_callout, t * hz / 10,
+			    ctl_ie_timer, lun);
+		}
+	} else {
+		lun->ie_asc = 0;
+		lun->ie_ascq = 0;
+		lun->ie_reported = 1;
+		ctl_clr_ua_all(lun, -1, CTL_UA_IE);
+		lun->ie_reportcnt = UINT32_MAX;
+		callout_stop(&lun->ie_callout);
 	}
-	return (0);
+	mtx_unlock(&lun->lun_lock);
+	return (CTL_RETVAL_COMPLETE);
 }
 
-
 static int
 ctl_do_mode_select(union ctl_io *io)
 {
@@ -6824,8 +6751,27 @@ ctl_sap_log_sense_handler(struct ctl_scs
 	    sizeof(struct scsi_log_param_header);
 	scsi_ulto4b(3, data->ti.exponent);
 	scsi_ulto4b(1, data->ti.integer);
+	return (0);
+}
 
-	page_index->page_len = sizeof(*data);
+int
+ctl_ie_log_sense_handler(struct ctl_scsiio *ctsio,
+			       struct ctl_page_index *page_index,
+			       int pc)
+{
+	struct ctl_lun *lun;
+	struct scsi_log_informational_exceptions *data;
+
+	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+	data = (struct scsi_log_informational_exceptions *)page_index->page_data;
+
+	scsi_ulto2b(SLP_IE_GEN, data->hdr.param_code);
+	data->hdr.param_control = SLP_LBIN;
+	data->hdr.param_len = sizeof(struct scsi_log_informational_exceptions) -
+	    sizeof(struct scsi_log_param_header);
+	data->ie_asc = lun->ie_asc;
+	data->ie_ascq = lun->ie_ascq;
+	data->temperature = 0xff;
 	return (0);
 }
 
@@ -9265,6 +9211,7 @@ ctl_request_sense(struct ctl_scsiio *cts
 	int have_error;
 	scsi_sense_data_type sense_format;
 	ctl_ua_type ua_type;
+	uint8_t asc = 0, ascq = 0;
 
 	cdb = (struct scsi_request_sense *)ctsio->cdb;
 
@@ -9383,19 +9330,23 @@ ctl_request_sense(struct ctl_scsiio *cts
 		return (CTL_RETVAL_COMPLETE);
 	}
 
-no_sense:
-
 	/*
 	 * No sense information to report, so we report that everything is
-	 * okay.
+	 * okay, unless we have allowed Informational Exception.
 	 */
+	if (lun->mode_pages.ie_page[CTL_PAGE_CURRENT].mrie != SIEP_MRIE_NO) {
+		asc = lun->ie_asc;
+		ascq = lun->ie_ascq;
+	}
+
+no_sense:
 	ctl_set_sense_data(sense_ptr,
 			   lun,
 			   sense_format,
 			   /*current_error*/ 1,
 			   /*sense_key*/ SSD_KEY_NO_SENSE,
-			   /*asc*/ 0x00,
-			   /*ascq*/ 0x00,
+			   /*asc*/ asc,
+			   /*ascq*/ ascq,
 			   SSD_ELEM_NONE);
 
 	/*
@@ -13265,6 +13216,37 @@ ctl_process_done(union ctl_io *io)
 	mtx_lock(&lun->lun_lock);
 
 	/*
+	 * Check to see if we have any informational exception and status
+	 * of this command can be modified to report it in form of either
+	 * RECOVERED ERROR or NO SENSE, depending on MRIE mode page field.
+	 */
+	if (lun->ie_reported == 0 && lun->ie_asc != 0 &&
+	    io->io_hdr.status == CTL_SUCCESS &&
+	    (io->io_hdr.flags & CTL_FLAG_STATUS_SENT) == 0) {
+		uint8_t mrie = lun->mode_pages.ie_page[CTL_PAGE_CURRENT].mrie;
+		uint8_t per =
+		    ((lun->mode_pages.rw_er_page[CTL_PAGE_CURRENT].byte3 &
+		      SMS_RWER_PER) ||
+		     (lun->mode_pages.verify_er_page[CTL_PAGE_CURRENT].byte3 &
+		      SMS_VER_PER));
+		if (((mrie == SIEP_MRIE_REC_COND && per) ||
+		     mrie == SIEP_MRIE_REC_UNCOND ||
+		     mrie == SIEP_MRIE_NO_SENSE) &&
+		    (ctl_get_cmd_entry(&io->scsiio, NULL)->flags &
+		     CTL_CMD_FLAG_NO_SENSE) == 0) {
+			ctl_set_sense(&io->scsiio,
+			      /*current_error*/ 1,
+			      /*sense_key*/ (mrie == SIEP_MRIE_NO_SENSE) ?
+			        SSD_KEY_NO_SENSE : SSD_KEY_RECOVERED_ERROR,
+			      /*asc*/ lun->ie_asc,
+			      /*ascq*/ lun->ie_ascq,
+			      SSD_ELEM_NONE);
+			lun->ie_reported = 1;
+		}
+	} else if (lun->ie_reported < 0)
+		lun->ie_reported = 0;
+
+	/*
 	 * Check to see if we have any errors to inject here.  We only
 	 * inject errors for commands that don't already have errors set.
 	 */
@@ -13537,10 +13519,6 @@ ctl_done(union ctl_io *io)
 
 #ifdef CTL_IO_DELAY
 	if (io->io_hdr.flags & CTL_FLAG_DELAY_DONE) {
-		struct ctl_lun *lun;
-
-		lun =(struct ctl_lun *)io->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
-
 		io->io_hdr.flags &= ~CTL_FLAG_DELAY_DONE;
 	} else {
 		struct ctl_lun *lun;

Modified: head/sys/cam/ctl/ctl.h
==============================================================================
--- head/sys/cam/ctl/ctl.h	Mon Dec 19 10:00:56 2016	(r310256)
+++ head/sys/cam/ctl/ctl.h	Mon Dec 19 10:25:47 2016	(r310257)
@@ -127,7 +127,8 @@ typedef enum {
 	CTL_UA_ASYM_ACC_CHANGE	= 0x2000,
 	CTL_UA_CAPACITY_CHANGE	= 0x4000,
 	CTL_UA_THIN_PROV_THRES	= 0x8000,
-	CTL_UA_MEDIUM_CHANGE	= 0x10000
+	CTL_UA_MEDIUM_CHANGE	= 0x10000,
+	CTL_UA_IE		= 0x20000
 } ctl_ua_type;
 
 #ifdef	_KERNEL
@@ -154,23 +155,21 @@ int ctl_ffz(uint32_t *mask, uint32_t fir
 int ctl_set_mask(uint32_t *mask, uint32_t bit);
 int ctl_clear_mask(uint32_t *mask, uint32_t bit);
 int ctl_is_set(uint32_t *mask, uint32_t bit);
-int ctl_caching_sp_handler(struct ctl_scsiio *ctsio,
-			 struct ctl_page_index *page_index, uint8_t *page_ptr);
-int ctl_control_page_handler(struct ctl_scsiio *ctsio,
+int ctl_default_page_handler(struct ctl_scsiio *ctsio,
 			     struct ctl_page_index *page_index,
 			     uint8_t *page_ptr);
-int ctl_debugconf_sp_sense_handler(struct ctl_scsiio *ctsio,
-				   struct ctl_page_index *page_index,
-				   int pc);
-int ctl_debugconf_sp_select_handler(struct ctl_scsiio *ctsio,
-				    struct ctl_page_index *page_index,
-				    uint8_t *page_ptr);
+int ctl_ie_page_handler(struct ctl_scsiio *ctsio,
+			struct ctl_page_index *page_index,
+			uint8_t *page_ptr);
 int ctl_lbp_log_sense_handler(struct ctl_scsiio *ctsio,
 				   struct ctl_page_index *page_index,
 				   int pc);
 int ctl_sap_log_sense_handler(struct ctl_scsiio *ctsio,
 				   struct ctl_page_index *page_index,
 				   int pc);
+int ctl_ie_log_sense_handler(struct ctl_scsiio *ctsio,
+				   struct ctl_page_index *page_index,
+				   int pc);
 int ctl_config_move_done(union ctl_io *io);
 void ctl_datamove(union ctl_io *io);
 void ctl_serseq_done(union ctl_io *io);

Modified: head/sys/cam/ctl/ctl_error.c
==============================================================================
--- head/sys/cam/ctl/ctl_error.c	Mon Dec 19 10:00:56 2016	(r310256)
+++ head/sys/cam/ctl/ctl_error.c	Mon Dec 19 10:25:47 2016	(r310257)
@@ -84,7 +84,8 @@ ctl_set_sense_data_va(struct scsi_sense_
 		 * on for that LUN.
 		 */
 		if ((lun != NULL)
-		 && (lun->flags & CTL_LUN_SENSE_DESC))
+		 && (lun->mode_pages.control_page[CTL_PAGE_CURRENT].rlec &
+		    SCP_DSENSE))
 			sense_format = SSD_TYPE_DESC;
 		else
 			sense_format = SSD_TYPE_FIXED;
@@ -461,6 +462,11 @@ ctl_ua_to_acsq(struct ctl_lun *lun, ctl_
 		*asc = 0x28;
 		*ascq = 0x00;
 		break;
+	case CTL_UA_IE:
+		/* Informational exception */
+		*asc = lun->ie_asc;
+		*ascq = lun->ie_ascq;
+		break;
 	default:
 		panic("%s: Unknown UA %x", __func__, ua_to_build);
 	}

Modified: head/sys/cam/ctl/ctl_private.h
==============================================================================
--- head/sys/cam/ctl/ctl_private.h	Mon Dec 19 10:00:56 2016	(r310256)
+++ head/sys/cam/ctl/ctl_private.h	Mon Dec 19 10:25:47 2016	(r310257)
@@ -151,7 +151,6 @@ typedef enum {
 	CTL_LUN_EJECTED		= 0x080,
 	CTL_LUN_PR_RESERVED	= 0x100,
 	CTL_LUN_PRIMARY_SC	= 0x200,
-	CTL_LUN_SENSE_DESC	= 0x400,
 	CTL_LUN_READONLY	= 0x800,
 	CTL_LUN_PEER_SC_PRIMARY	= 0x1000,
 	CTL_LUN_REMOVABLE	= 0x2000
@@ -272,30 +271,29 @@ struct ctl_logical_block_provisioning_pa
 
 static const struct ctl_page_index page_index_template[] = {
 	{SMS_RW_ERROR_RECOVERY_PAGE, 0, sizeof(struct scsi_da_rw_recovery_page), NULL,
-	 CTL_PAGE_FLAG_DIRECT | CTL_PAGE_FLAG_CDROM, NULL, NULL},
+	 CTL_PAGE_FLAG_DIRECT | CTL_PAGE_FLAG_CDROM, NULL, ctl_default_page_handler},
 	{SMS_FORMAT_DEVICE_PAGE, 0, sizeof(struct scsi_format_page), NULL,
 	 CTL_PAGE_FLAG_DIRECT, NULL, NULL},
 	{SMS_RIGID_DISK_PAGE, 0, sizeof(struct scsi_rigid_disk_page), NULL,
 	 CTL_PAGE_FLAG_DIRECT, NULL, NULL},
+	{SMS_VERIFY_ERROR_RECOVERY_PAGE, 0, sizeof(struct scsi_da_verify_recovery_page), NULL,
+	 CTL_PAGE_FLAG_DIRECT | CTL_PAGE_FLAG_CDROM, NULL, ctl_default_page_handler},
 	{SMS_CACHING_PAGE, 0, sizeof(struct scsi_caching_page), NULL,
 	 CTL_PAGE_FLAG_DIRECT | CTL_PAGE_FLAG_CDROM,
-	 NULL, ctl_caching_sp_handler},
+	 NULL, ctl_default_page_handler},
 	{SMS_CONTROL_MODE_PAGE, 0, sizeof(struct scsi_control_page), NULL,
-	 CTL_PAGE_FLAG_ALL, NULL, ctl_control_page_handler},
+	 CTL_PAGE_FLAG_ALL, NULL, ctl_default_page_handler},
 	{SMS_CONTROL_MODE_PAGE | SMPH_SPF, 0x01,
 	 sizeof(struct scsi_control_ext_page), NULL,
 	 CTL_PAGE_FLAG_ALL, NULL, NULL},
 	{SMS_INFO_EXCEPTIONS_PAGE, 0, sizeof(struct scsi_info_exceptions_page), NULL,
-	 CTL_PAGE_FLAG_ALL, NULL, NULL},
+	 CTL_PAGE_FLAG_ALL, NULL, ctl_ie_page_handler},
 	{SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF, 0x02,
 	 sizeof(struct ctl_logical_block_provisioning_page), NULL,
 	 CTL_PAGE_FLAG_DIRECT, NULL, NULL},
 	{SMS_CDDVD_CAPS_PAGE, 0,
 	 sizeof(struct scsi_cddvd_capabilities_page), NULL,
 	 CTL_PAGE_FLAG_CDROM, NULL, NULL},
-	{SMS_VENDOR_SPECIFIC_PAGE | SMPH_SPF, DBGCNF_SUBPAGE_CODE,
-	 sizeof(struct copan_debugconf_subpage), NULL, CTL_PAGE_FLAG_ALL,
-	 ctl_debugconf_sp_sense_handler, ctl_debugconf_sp_select_handler},
 };
 
 #define	CTL_NUM_MODE_PAGES sizeof(page_index_template)/   \
@@ -305,13 +303,13 @@ struct ctl_mode_pages {
 	struct scsi_da_rw_recovery_page	rw_er_page[4];
 	struct scsi_format_page		format_page[4];
 	struct scsi_rigid_disk_page	rigid_disk_page[4];
+	struct scsi_da_verify_recovery_page	verify_er_page[4];
 	struct scsi_caching_page	caching_page[4];
 	struct scsi_control_page	control_page[4];
 	struct scsi_control_ext_page	control_ext_page[4];
 	struct scsi_info_exceptions_page ie_page[4];
 	struct ctl_logical_block_provisioning_page lbp_page[4];
 	struct scsi_cddvd_capabilities_page cddvd_page[4];
-	struct copan_debugconf_subpage	debugconf_subpage[4];
 	struct ctl_page_index		index[CTL_NUM_MODE_PAGES];
 };
 
@@ -324,6 +322,8 @@ static const struct ctl_page_index log_p
 	 CTL_PAGE_FLAG_DIRECT, ctl_lbp_log_sense_handler, NULL},
 	{SLS_STAT_AND_PERF, 0, 0, NULL,
 	 CTL_PAGE_FLAG_ALL, ctl_sap_log_sense_handler, NULL},
+	{SLS_IE_PAGE, 0, 0, NULL,
+	 CTL_PAGE_FLAG_ALL, ctl_ie_log_sense_handler, NULL},
 };
 
 #define	CTL_NUM_LOG_PAGES sizeof(log_page_index_template)/   \
@@ -338,6 +338,7 @@ struct ctl_log_pages {
 		struct scsi_log_idle_time it;
 		struct scsi_log_time_interval ti;
 	} stat_page;
+	struct scsi_log_informational_exceptions	ie_page;
 	struct ctl_page_index		index[CTL_NUM_LOG_PAGES];
 };
 
@@ -385,6 +386,11 @@ struct ctl_lun {
 	ctl_ua_type			*pending_ua[CTL_MAX_PORTS];
 	uint8_t				ua_tpt_info[8];
 	time_t				lasttpt;
+	uint8_t				ie_asc;	/* Informational exceptions */
+	uint8_t				ie_ascq;
+	int				ie_reported;	/* Already reported */
+	uint32_t			ie_reportcnt;	/* REPORT COUNT */
+	struct callout			ie_callout;	/* INTERVAL TIMER */
 	struct ctl_mode_pages		mode_pages;
 	struct ctl_log_pages		log_pages;
 	struct ctl_lun_io_stats		stats;

Modified: head/sys/cam/scsi/scsi_all.h
==============================================================================
--- head/sys/cam/scsi/scsi_all.h	Mon Dec 19 10:00:56 2016	(r310256)
+++ head/sys/cam/scsi/scsi_all.h	Mon Dec 19 10:25:47 2016	(r310257)
@@ -662,6 +662,14 @@ struct scsi_log_fua_stat_and_perf {
 	uint8_t	fuanv_write_int[8];
 };
 
+struct scsi_log_informational_exceptions {
+	struct scsi_log_param_header hdr;
+#define	SLP_IE_GEN			0x0000
+	uint8_t	ie_asc;
+	uint8_t	ie_ascq;
+	uint8_t	temperature;
+};
+
 struct scsi_control_page {
 	u_int8_t page_code;
 	u_int8_t page_length;
@@ -765,21 +773,6 @@ struct scsi_caching_page {
 	uint8_t non_cache_seg_size[3];
 };
 
-/*
- * XXX KDM move this off to a vendor shim.
- */
-struct copan_debugconf_subpage {
-	uint8_t page_code;
-#define DBGCNF_PAGE_CODE		0x00
-	uint8_t subpage;
-#define DBGCNF_SUBPAGE_CODE	0xF0
-	uint8_t page_length[2];
-	uint8_t page_version;
-#define DBGCNF_VERSION			0x00
-	uint8_t ctl_time_io_secs[2];
-};
-
-
 struct scsi_info_exceptions_page {
 	u_int8_t page_code;
 #define	SIEP_PAGE_SAVABLE		0x80	/* Page is savable */
@@ -793,6 +786,12 @@ struct scsi_info_exceptions_page {
 #define	SIEP_FLAGS_EBACKERR		0x02
 #define	SIEP_FLAGS_LOGERR		0x01
 	u_int8_t mrie;
+#define	SIEP_MRIE_NO		0x00
+#define	SIEP_MRIE_UA		0x02
+#define	SIEP_MRIE_REC_COND	0x03
+#define	SIEP_MRIE_REC_UNCOND	0x04
+#define	SIEP_MRIE_NO_SENSE	0x05
+#define	SIEP_MRIE_ON_REQ	0x06
 	u_int8_t interval_timer[4];
 	u_int8_t report_count[4];
 };

Modified: head/sys/cam/scsi/scsi_da.h
==============================================================================
--- head/sys/cam/scsi/scsi_da.h	Mon Dec 19 10:00:56 2016	(r310256)
+++ head/sys/cam/scsi/scsi_da.h	Mon Dec 19 10:25:47 2016	(r310257)
@@ -634,6 +634,20 @@ struct scsi_da_rw_recovery_page {
 	u_int8_t recovery_time_limit[2];
 };
 
+struct scsi_da_verify_recovery_page {
+	u_int8_t page_code;
+#define SMS_VERIFY_ERROR_RECOVERY_PAGE	0x07
+	u_int8_t page_length;
+	u_int8_t byte3;
+#define SMS_VER_EER			0x08
+#define SMS_VER_PER			0x04
+#define SMS_VER_DTE			0x02
+#define SMS_VER_DCR			0x01
+	u_int8_t read_retry_count;
+	u_int8_t reserved[6];
+	u_int8_t recovery_time_limit[2];
+};
+
 __BEGIN_DECLS
 /*
  * XXX These are only left out of the kernel build to silence warnings.  If,


More information about the svn-src-all mailing list