diff options
Diffstat (limited to 'sys/dev/ic/nvme.c')
-rw-r--r-- | sys/dev/ic/nvme.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/sys/dev/ic/nvme.c b/sys/dev/ic/nvme.c index 6753072..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) { @@ -425,7 +454,7 @@ nvme_dev_rw(dev_t dev, struct sio_txn *sio, bool write) */ ns = nvme_get_ns(dev); if (__unlikely(ns == NULL)) - return -EIO; + return -ENODEV; /* Calculate the block count and offset */ block_count = ALIGN_UP(sio->len, ns->lba_bsize); @@ -470,6 +499,12 @@ nvme_dev_read(dev_t dev, struct sio_txn *sio, int flags) return nvme_dev_rw(dev, sio, false); } +static int +nvme_dev_write(dev_t dev, struct sio_txn *sio, int flags) +{ + return nvme_dev_rw(dev, sio, true); +} + /* * Initializes an NVMe namespace. * @@ -543,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; @@ -566,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; } @@ -581,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; @@ -607,6 +662,7 @@ nvme_init_ctrl(struct nvme_bar *bar) dynfree(id); dynfree(nsids); + dynfree(smart); return 0; } @@ -659,7 +715,7 @@ nvme_init(void) static struct bdevsw nvme_bdevsw = { .read = nvme_dev_read, - .write = nowrite + .write = nvme_dev_write }; -DRIVER_EXPORT(nvme_init); +DRIVER_EXPORT(nvme_init, "nvme"); |