xref: /freebsd/sys/dev/nvme/nvme.c (revision 848602856f49c3937b8c6d168fd988263954b43a)
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