Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 Mar 2013 21:05:16 +0000 (UTC)
From:      Jim Harris <jimharris@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r248759 - head/sys/dev/nvme
Message-ID:  <201303262105.r2QL5GNS011377@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jimharris
Date: Tue Mar 26 21:05:15 2013
New Revision: 248759
URL: http://svnweb.freebsd.org/changeset/base/248759

Log:
  When an asynchronous event request is completed, automatically fetch the
  specified log page.
  
  This satisfies the spec condition that future async events of the same type
  will not be sent until the associated log page is fetched.
  
  Sponsored by:	Intel
  Reviewed by:	carl

Modified:
  head/sys/dev/nvme/nvme_ctrlr.c
  head/sys/dev/nvme/nvme_private.h

Modified: head/sys/dev/nvme/nvme_ctrlr.c
==============================================================================
--- head/sys/dev/nvme/nvme_ctrlr.c	Tue Mar 26 21:03:03 2013	(r248758)
+++ head/sys/dev/nvme/nvme_ctrlr.c	Tue Mar 26 21:05:15 2013	(r248759)
@@ -557,10 +557,65 @@ nvme_ctrlr_construct_namespaces(struct n
 	return (0);
 }
 
+static boolean_t
+is_log_page_id_valid(uint8_t page_id)
+{
+
+	switch (page_id) {
+	case NVME_LOG_ERROR:
+	case NVME_LOG_HEALTH_INFORMATION:
+	case NVME_LOG_FIRMWARE_SLOT:
+		return (TRUE);
+	}
+
+	return (FALSE);
+}
+
+static uint32_t
+nvme_ctrlr_get_log_page_size(struct nvme_controller *ctrlr, uint8_t page_id)
+{
+	uint32_t	log_page_size;
+
+	switch (page_id) {
+	case NVME_LOG_ERROR:
+		log_page_size = min(
+		    sizeof(struct nvme_error_information_entry) *
+		    ctrlr->cdata.elpe,
+		    NVME_MAX_AER_LOG_SIZE);
+		break;
+	case NVME_LOG_HEALTH_INFORMATION:
+		log_page_size = sizeof(struct nvme_health_information_page);
+		break;
+	case NVME_LOG_FIRMWARE_SLOT:
+		log_page_size = sizeof(struct nvme_firmware_page);
+		break;
+	default:
+		log_page_size = 0;
+		break;
+	}
+
+	return (log_page_size);
+}
+
+static void
+nvme_ctrlr_async_event_log_page_cb(void *arg, const struct nvme_completion *cpl)
+{
+	struct nvme_async_event_request	*aer = arg;
+
+	nvme_notify_async_consumers(aer->ctrlr, &aer->cpl);
+
+	/*
+	 * Repost another asynchronous event request to replace the one
+	 *  that just completed.
+	 */
+	nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
+}
+
 static void
 nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl)
 {
-	struct nvme_async_event_request *aer = arg;
+	struct nvme_async_event_request	*aer = arg;
+	uint8_t				log_page_id;
 
 	if (cpl->status.sc == NVME_SC_ABORTED_SQ_DELETION) {
 		/*
@@ -572,16 +627,29 @@ nvme_ctrlr_async_event_cb(void *arg, con
 		return;
 	}
 
-	nvme_notify_async_consumers(aer->ctrlr, cpl);
+	printf("Asynchronous event occurred.\n");
 
-	/* TODO: decode async event type based on status */
+	/* Associated log page is in bits 23:16 of completion entry dw0. */
+	log_page_id = (cpl->cdw0 & 0xFF0000) >> 16;
 
-	/*
-	 * Repost another asynchronous event request to replace the one that
-	 *  just completed.
-	 */
-	printf("Asynchronous event occurred.\n");
-	nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
+	if (is_log_page_id_valid(log_page_id)) {
+		aer->log_page_size = nvme_ctrlr_get_log_page_size(aer->ctrlr,
+		    log_page_id);
+		memcpy(&aer->cpl, cpl, sizeof(*cpl));
+		nvme_ctrlr_cmd_get_log_page(aer->ctrlr, log_page_id,
+		    NVME_GLOBAL_NAMESPACE_TAG, aer->log_page_buffer,
+		    aer->log_page_size, nvme_ctrlr_async_event_log_page_cb,
+		    aer);
+		/* Wait to notify consumers until after log page is fetched. */
+	} else {
+		nvme_notify_async_consumers(aer->ctrlr, cpl);
+
+		/*
+		 * Repost another asynchronous event request to replace the one
+		 *  that just completed.
+		 */
+		nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
+	}
 }
 
 static void

Modified: head/sys/dev/nvme/nvme_private.h
==============================================================================
--- head/sys/dev/nvme/nvme_private.h	Tue Mar 26 21:03:03 2013	(r248758)
+++ head/sys/dev/nvme/nvme_private.h	Tue Mar 26 21:05:15 2013	(r248759)
@@ -104,6 +104,9 @@ MALLOC_DECLARE(M_NVME);
 #define NVME_MIN_TIMEOUT_PERIOD		(5)
 #define NVME_MAX_TIMEOUT_PERIOD		(120)
 
+/* Maximum log page size to fetch for AERs. */
+#define NVME_MAX_AER_LOG_SIZE		(4096)
+
 #ifndef CACHE_LINE_SIZE
 #define CACHE_LINE_SIZE		(64)
 #endif
@@ -126,6 +129,9 @@ struct nvme_async_event_request {
 
 	struct nvme_controller		*ctrlr;
 	struct nvme_request		*req;
+	struct nvme_completion		cpl;
+	uint32_t			log_page_size;
+	uint8_t				log_page_buffer[NVME_MAX_AER_LOG_SIZE];
 };
 
 struct nvme_tracker {



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