1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2012-2014 Intel Corporation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/conf.h>
32 #include <sys/module.h>
33
34 #include <vm/uma.h>
35
36 #include "nvme_private.h"
37 #include "nvme_if.h"
38
39 int32_t nvme_retry_count;
40
41 MALLOC_DEFINE(M_NVME, "nvme", "nvme(4) memory allocations");
42
43 int
nvme_shutdown(device_t dev)44 nvme_shutdown(device_t dev)
45 {
46 struct nvme_controller *ctrlr;
47
48 ctrlr = DEVICE2SOFTC(dev);
49 nvme_ctrlr_shutdown(ctrlr);
50
51 return (0);
52 }
53
54 int
nvme_attach(device_t dev)55 nvme_attach(device_t dev)
56 {
57 struct nvme_controller *ctrlr = DEVICE2SOFTC(dev);
58 int status;
59
60 status = nvme_ctrlr_construct(ctrlr, dev);
61 if (status != 0) {
62 nvme_ctrlr_destruct(ctrlr, dev);
63 return (status);
64 }
65
66 ctrlr->config_hook.ich_func = nvme_ctrlr_start_config_hook;
67 ctrlr->config_hook.ich_arg = ctrlr;
68
69 if (config_intrhook_establish(&ctrlr->config_hook) != 0)
70 return (ENOMEM);
71
72 return (0);
73 }
74
75 int
nvme_detach(device_t dev)76 nvme_detach(device_t dev)
77 {
78 struct nvme_controller *ctrlr = DEVICE2SOFTC(dev);
79 int error;
80
81 config_intrhook_drain(&ctrlr->config_hook);
82
83 error = bus_generic_detach(dev);
84 if (error)
85 return (error);
86
87 nvme_ctrlr_destruct(ctrlr, dev);
88 return (0);
89 }
90
91 void
nvme_notify_async(struct nvme_controller * ctrlr,const struct nvme_completion * async_cpl,uint32_t log_page_id,void * log_page_buffer,uint32_t log_page_size)92 nvme_notify_async(struct nvme_controller *ctrlr,
93 const struct nvme_completion *async_cpl,
94 uint32_t log_page_id, void *log_page_buffer, uint32_t log_page_size)
95 {
96 device_t *children;
97 int n_children;
98
99 if (device_get_children(ctrlr->dev, &children, &n_children) != 0)
100 return;
101
102 for (int i = 0; i < n_children; i++)
103 NVME_HANDLE_AEN(children[i], async_cpl, log_page_id,
104 log_page_buffer, log_page_size);
105
106 free(children, M_TEMP);
107 }
108
109 void
nvme_notify_fail(struct nvme_controller * ctrlr)110 nvme_notify_fail(struct nvme_controller *ctrlr)
111 {
112 device_t *children;
113 int n_children;
114
115 /*
116 * This controller failed during initialization (i.e. IDENTIFY
117 * command failed or timed out). Do not notify any nvme
118 * consumers of the failure here, since the consumer does not
119 * even know about the controller yet.
120 */
121 if (!ctrlr->is_initialized)
122 return;
123
124 if (device_get_children(ctrlr->dev, &children, &n_children) != 0)
125 return;
126
127 for (int i = 0; i < n_children; i++)
128 NVME_CONTROLLER_FAILED(children[i]);
129
130 free(children, M_TEMP);
131 }
132
133 void
nvme_completion_poll_cb(void * arg,const struct nvme_completion * cpl)134 nvme_completion_poll_cb(void *arg, const struct nvme_completion *cpl)
135 {
136 struct nvme_completion_poll_status *status = arg;
137
138 /*
139 * Copy status into the argument passed by the caller, so that
140 * the caller can check the status to determine if the
141 * the request passed or failed.
142 */
143 memcpy(&status->cpl, cpl, sizeof(*cpl));
144 atomic_store_rel_int(&status->done, 1);
145 }
146
147 static int
nvme_modevent(module_t mod __unused,int type __unused,void * argp __unused)148 nvme_modevent(module_t mod __unused, int type __unused, void *argp __unused)
149 {
150 return (0);
151 }
152
153 static moduledata_t nvme_mod = {
154 "nvme",
155 nvme_modevent,
156 0
157 };
158
159 DECLARE_MODULE(nvme, nvme_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
160 MODULE_VERSION(nvme, 1);
161 MODULE_DEPEND(nvme, cam, 1, 1, 1);
162