1 /* 2 * Copyright (c) 2016 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Primary device interface for NVME driver, for DragonFlyBSD 36 */ 37 38 #include "nvme.h" 39 40 /* 41 * Device bus methods 42 */ 43 static int nvme_probe (device_t dev); 44 static int nvme_attach (device_t dev); 45 static int nvme_detach (device_t dev); 46 static int nvme_shutdown (device_t dev); 47 #if 0 48 static int nvme_suspend (device_t dev); 49 static int nvme_resume (device_t dev); 50 #endif 51 52 static device_method_t nvme_methods[] = { 53 DEVMETHOD(device_probe, nvme_probe), 54 DEVMETHOD(device_attach, nvme_attach), 55 DEVMETHOD(device_detach, nvme_detach), 56 DEVMETHOD(device_shutdown, nvme_shutdown), 57 #if 0 58 DEVMETHOD(device_suspend, nvme_suspend), 59 DEVMETHOD(device_resume, nvme_resume), 60 #endif 61 62 DEVMETHOD(bus_print_child, bus_generic_print_child), 63 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 64 DEVMETHOD_END 65 }; 66 67 static devclass_t nvme_devclass; 68 69 static driver_t nvme_driver = { 70 "nvme", 71 nvme_methods, 72 sizeof(nvme_softc_t) 73 }; 74 75 DRIVER_MODULE(nvme, pci, nvme_driver, nvme_devclass, NULL, NULL); 76 MODULE_VERSION(nvme, 1); 77 78 /* 79 * Device bus method procedures 80 */ 81 static int 82 nvme_probe(device_t dev) 83 { 84 const nvme_device_t *ad; 85 86 if (kgetenv("hint.nvme.disabled")) 87 return(ENXIO); 88 89 ad = nvme_lookup_device(dev); 90 if (ad) { 91 device_set_desc(dev, ad->name); 92 return(-5); /* higher priority the NATA */ 93 } 94 return(ENXIO); 95 } 96 97 static int 98 nvme_attach(device_t dev) 99 { 100 nvme_softc_t *sc = device_get_softc(dev); 101 int error; 102 103 sc->dev = dev; 104 sc->ad = nvme_lookup_device(dev); 105 if (sc->ad == NULL) 106 return(ENXIO); 107 108 /* sanity check critical structure sizes */ 109 KKASSERT(sizeof(nvme_admin_data_t) == NVME_MAX_ADMIN_BUFFER); 110 KKASSERT(sizeof(nvme_allres_t) == 16); 111 KKASSERT(sizeof(nvme_allcmd_t) == 64); 112 113 error = sc->ad->attach(dev); 114 115 return error; 116 } 117 118 static int 119 nvme_detach(device_t dev) 120 { 121 nvme_softc_t *sc = device_get_softc(dev); 122 int error = 0; 123 124 if (sc->ad) { 125 error = sc->ad->detach(dev); 126 sc->ad = NULL; 127 } 128 return(error); 129 } 130 131 /* 132 * System halt/reboot 133 */ 134 static int 135 nvme_shutdown(device_t dev) 136 { 137 return nvme_detach(dev); 138 } 139 140 #if 0 141 142 static int 143 nvme_suspend(device_t dev) 144 { 145 return (0); 146 } 147 148 static int 149 nvme_resume(device_t dev) 150 { 151 return (0); 152 } 153 154 #endif 155 156 /* 157 * Chipset register accesses (NVME_REG_*) 158 */ 159 u_int32_t 160 nvme_read(nvme_softc_t *sc, bus_size_t r) 161 { 162 bus_space_barrier(sc->iot, sc->ioh, r, 4, 163 BUS_SPACE_BARRIER_READ); 164 return (bus_space_read_4(sc->iot, sc->ioh, r)); 165 } 166 167 u_int64_t 168 nvme_read8(nvme_softc_t *sc, bus_size_t r) 169 { 170 bus_space_barrier(sc->iot, sc->ioh, r, 8, 171 BUS_SPACE_BARRIER_READ); 172 return (bus_space_read_8(sc->iot, sc->ioh, r)); 173 } 174 175 void 176 nvme_write(nvme_softc_t *sc, bus_size_t r, u_int32_t v) 177 { 178 bus_space_write_4(sc->iot, sc->ioh, r, v); 179 bus_space_barrier(sc->iot, sc->ioh, r, 4, 180 BUS_SPACE_BARRIER_WRITE); 181 } 182 183 void 184 nvme_write8(nvme_softc_t *sc, bus_size_t r, u_int64_t v) 185 { 186 bus_space_write_8(sc->iot, sc->ioh, r, v); 187 bus_space_barrier(sc->iot, sc->ioh, r, 8, 188 BUS_SPACE_BARRIER_WRITE); 189 } 190 191 /* 192 * Sleep (ms) milliseconds, error on the side of caution. 193 */ 194 void 195 nvme_os_sleep(int ms) 196 { 197 int slpticks; 198 199 slpticks = hz * ms / 1000 + 1; 200 tsleep(&slpticks, 0, "nvslp", slpticks); 201 } 202 203 /* 204 * Sleep for a minimum interval and return the number of milliseconds 205 * that was. The minimum value returned is 1 206 */ 207 int 208 nvme_os_softsleep(void) 209 { 210 int slpticks = 0; 211 212 if (hz >= 1000) { 213 tsleep(&slpticks, 0, "nvslp", hz / 1000); 214 return(1); 215 } else { 216 tsleep(&slpticks, 0, "nvslp", 1); 217 return(1000 / hz); 218 } 219 } 220 221 void 222 nvme_os_hardsleep(int us) 223 { 224 DELAY(us); 225 } 226