summaryrefslogtreecommitdiff
path: root/sys/dev/ic/nvme.c
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-07-07 02:40:33 -0400
committerIan Moffett <ian@osmora.org>2025-07-07 02:41:01 -0400
commit45c3cbf482005e430e4d207410c7b5bc398cd87a (patch)
tree2fd7e6d42e3c36e8bf7db553b588685895aa07f3 /sys/dev/ic/nvme.c
parente1593e14b7bba75c9c369db25cedb6c3eb507cd3 (diff)
kernel: nvme: Add SMART + logpage supportexpt
- Implement nvme_get_logpage() routine - Add SMART data structure - Implement basic controller + namespace temperature detection Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys/dev/ic/nvme.c')
-rw-r--r--sys/dev/ic/nvme.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/sys/dev/ic/nvme.c b/sys/dev/ic/nvme.c
index fe04caf..c65d7e0 100644
--- a/sys/dev/ic/nvme.c
+++ b/sys/dev/ic/nvme.c
@@ -309,6 +309,35 @@ nvme_poll_submit_cmd(struct nvme_queue *q, struct nvme_cmd cmd)
return 0;
}
+/*
+ * Get NVMe log page
+ *
+ * @ctrl: NVMe controller to target
+ * @buf: Data buffer
+ * @lid: Log identifier
+ * @len: Length (in bytes)
+ */
+static int
+nvme_get_logpage(struct nvme_ctrl *ctrl, void *buf, uint8_t lid, uint32_t len)
+{
+ struct nvme_cmd cmd = {0};
+ struct nvme_get_logpage_cmd *cmdp;
+
+ if (!is_4k_aligned(buf)) {
+ return -1;
+ }
+
+ cmdp = &cmd.get_logpage;
+ cmdp->opcode = NVME_OP_GET_LOGPAGE;
+ cmdp->nsid = 0xFFFFFFFF;
+ cmdp->lid = lid;
+ cmdp->numdl = len / 4;
+ cmdp->numdu = 0;
+ cmdp->prp1 = VIRT_TO_PHYS(buf);
+ cmdp->prp2 = 0;
+ return nvme_poll_submit_cmd(&ctrl->adminq, cmd);
+}
+
static int
nvme_identify(struct nvme_ctrl *ctrl, void *buf, uint32_t nsid, uint8_t cns)
{
@@ -549,6 +578,7 @@ nvme_init_ctrl(struct nvme_bar *bar)
uint16_t mqes;
uint8_t *nsids;
struct nvme_ctrl ctrl = { .bar = bar };
+ struct nvme_smart_data *smart;
struct nvme_queue *adminq;
struct nvme_id *id;
@@ -572,14 +602,21 @@ nvme_init_ctrl(struct nvme_bar *bar)
return error;
}
+ smart = dynalloc_memalign(sizeof(*smart), 0x1000);
+ if (smart == NULL) {
+ return -ENOMEM;
+ }
+
id = dynalloc_memalign(sizeof(*id), 0x1000);
if (id == NULL) {
+ dynfree(smart);
return -ENOMEM;
}
nsids = dynalloc_memalign(0x1000, 0x1000);
if (nsids == NULL) {
dynfree(id);
+ dynfree(smart);
return -ENOMEM;
}
@@ -587,6 +624,18 @@ nvme_init_ctrl(struct nvme_bar *bar)
nvme_log_ctrl_id(id);
nvme_identify(&ctrl, nsids, 0, ID_CNS_NSID_LIST);
+ /*
+ * Attempt to read some SMART data but don't bother
+ * if it fails in any way.
+ */
+ error = nvme_get_logpage(&ctrl, smart, NVME_LOGPAGE_SMART, sizeof(*smart));
+ if (error == 0) {
+ if (smart->temp != 0 && smart->temp > 283)
+ pr_trace("temp: %d K\n", smart->temp);
+
+ pr_trace("%d%% used\n", smart->percent_used);
+ }
+
ctrl.sqes = id->sqes >> 4;
ctrl.cqes = id->cqes >> 4;
@@ -613,6 +662,7 @@ nvme_init_ctrl(struct nvme_bar *bar)
dynfree(id);
dynfree(nsids);
+ dynfree(smart);
return 0;
}