1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  * Copyright (c) 2022 Intel Corp.
4  */
5 
6 #include <zephyr/logging/log.h>
7 LOG_MODULE_DECLARE(nvme, CONFIG_NVME_LOG_LEVEL);
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/byteorder.h>
11 
12 #include <stdio.h>
13 
14 #include "nvme.h"
15 
nvme_namespace_get_sector_size(struct nvme_namespace * ns)16 uint32_t nvme_namespace_get_sector_size(struct nvme_namespace *ns)
17 {
18 	uint8_t flbas_fmt, lbads;
19 
20 	flbas_fmt = (ns->data.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
21 		NVME_NS_DATA_FLBAS_FORMAT_MASK;
22 	lbads = (ns->data.lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) &
23 		NVME_NS_DATA_LBAF_LBADS_MASK;
24 
25 	return 1 << lbads;
26 }
27 
nvme_namespace_get_num_sectors(struct nvme_namespace * ns)28 uint64_t nvme_namespace_get_num_sectors(struct nvme_namespace *ns)
29 {
30 	return ns->data.nsze;
31 }
32 
nvme_namespace_get_size(struct nvme_namespace * ns)33 uint64_t nvme_namespace_get_size(struct nvme_namespace *ns)
34 {
35 	return nvme_namespace_get_num_sectors(ns) *
36 		nvme_namespace_get_sector_size(ns);
37 }
38 
nvme_namespace_get_flags(struct nvme_namespace * ns)39 uint32_t nvme_namespace_get_flags(struct nvme_namespace *ns)
40 {
41 	return ns->flags;
42 }
43 
nvme_namespace_get_serial_number(struct nvme_namespace * ns)44 const char *nvme_namespace_get_serial_number(struct nvme_namespace *ns)
45 {
46 	return (const char *)ns->ctrlr->cdata.sn;
47 }
48 
nvme_namespace_get_model_number(struct nvme_namespace * ns)49 const char *nvme_namespace_get_model_number(struct nvme_namespace *ns)
50 {
51 	return (const char *)ns->ctrlr->cdata.mn;
52 }
53 
54 const struct nvme_namespace_data *
nvme_namespace_get_data(struct nvme_namespace * ns)55 nvme_namespace_get_data(struct nvme_namespace *ns)
56 {
57 	return &ns->data;
58 }
59 
nvme_namespace_get_stripesize(struct nvme_namespace * ns)60 uint32_t nvme_namespace_get_stripesize(struct nvme_namespace *ns)
61 {
62 	if (((ns->data.nsfeat >> NVME_NS_DATA_NSFEAT_NPVALID_SHIFT) &
63 	     NVME_NS_DATA_NSFEAT_NPVALID_MASK) != 0) {
64 		uint32_t ss = nvme_namespace_get_sector_size(ns);
65 
66 		if (ns->data.npwa != 0) {
67 			return (ns->data.npwa + 1) * ss;
68 		} else if (ns->data.npwg != 0) {
69 			return (ns->data.npwg + 1) * ss;
70 		}
71 	}
72 
73 	return ns->boundary;
74 }
75 
nvme_namespace_construct(struct nvme_namespace * ns,uint32_t id,struct nvme_controller * ctrlr)76 int nvme_namespace_construct(struct nvme_namespace *ns,
77 			     uint32_t id,
78 			     struct nvme_controller *ctrlr)
79 {
80 	struct nvme_completion_poll_status status =
81 		NVME_CPL_STATUS_POLL_INIT(status);
82 	uint8_t flbas_fmt;
83 	uint8_t vwc_present;
84 
85 	ns->ctrlr = ctrlr;
86 	ns->id = id;
87 
88 	nvme_ctrlr_cmd_identify_namespace(ctrlr, id, &ns->data,
89 					  nvme_completion_poll_cb,
90 					  &status);
91 	nvme_completion_poll(&status);
92 
93 	if (nvme_cpl_status_is_error(&status)) {
94 		LOG_DBG("Identifying NS id %d failed", id);
95 		return -EIO;
96 	}
97 
98 	nvme_namespace_data_swapbytes(&ns->data);
99 
100 	if (nvme_namespace_get_num_sectors(ns) == 0) {
101 		LOG_DBG("Namespace %d not present", id);
102 		return -ENODEV;
103 	}
104 
105 	flbas_fmt = (ns->data.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
106 		NVME_NS_DATA_FLBAS_FORMAT_MASK;
107 
108 	/* Note: format is a 0-based value, so > is appropriate here not >=. */
109 	if (flbas_fmt > ns->data.nlbaf) {
110 		LOG_DBG("NS id %d: lba format %d exceeds number supported (%d)",
111 			id, flbas_fmt, ns->data.nlbaf + 1);
112 		return -EIO;
113 	}
114 
115 	ns->boundary = ns->data.noiob * nvme_namespace_get_sector_size(ns);
116 
117 	if (nvme_controller_has_dataset_mgmt(ctrlr)) {
118 		ns->flags |= NVME_NS_DEALLOCATE_SUPPORTED;
119 	}
120 
121 	vwc_present = (ctrlr->cdata.vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) &
122 		NVME_CTRLR_DATA_VWC_PRESENT_MASK;
123 	if (vwc_present) {
124 		ns->flags |= NVME_NS_FLUSH_SUPPORTED;
125 	}
126 
127 	snprintf(ns->name, NVME_NAMESPACE_NAME_MAX_LENGTH, "nvme%dn%d",
128 		 ctrlr->id, ns->id-1);
129 
130 	if (nvme_namespace_disk_setup(ns, &ns->disk) != 0) {
131 		LOG_ERR("Could not register no disk subsystem");
132 	}
133 
134 	return 0;
135 }
136