1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009 Yahoo! Inc. 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 /* PCI/PCI-X/PCIe bus interface for the Avago Tech (LSI) MPT2 controllers */ 30 31 /* TODO Move headers to mpsvar */ 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/bus.h> 38 #include <sys/conf.h> 39 #include <sys/malloc.h> 40 #include <sys/sysctl.h> 41 #include <sys/uio.h> 42 43 #include <machine/bus.h> 44 #include <machine/resource.h> 45 #include <sys/rman.h> 46 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcivar.h> 49 #include <dev/pci/pci_private.h> 50 51 #include <dev/mps/mpi/mpi2_type.h> 52 #include <dev/mps/mpi/mpi2.h> 53 #include <dev/mps/mpi/mpi2_ioc.h> 54 #include <dev/mps/mpi/mpi2_cnfg.h> 55 #include <dev/mps/mpi/mpi2_tool.h> 56 57 #include <sys/queue.h> 58 #include <sys/kthread.h> 59 #include <dev/mps/mps_ioctl.h> 60 #include <dev/mps/mpsvar.h> 61 62 static int mps_pci_probe(device_t); 63 static int mps_pci_attach(device_t); 64 static int mps_pci_detach(device_t); 65 static int mps_pci_suspend(device_t); 66 static int mps_pci_resume(device_t); 67 static void mps_pci_free(struct mps_softc *); 68 static int mps_alloc_msix(struct mps_softc *sc, int msgs); 69 static int mps_alloc_msi(struct mps_softc *sc, int msgs); 70 static int mps_pci_alloc_interrupts(struct mps_softc *sc); 71 72 static device_method_t mps_methods[] = { 73 DEVMETHOD(device_probe, mps_pci_probe), 74 DEVMETHOD(device_attach, mps_pci_attach), 75 DEVMETHOD(device_detach, mps_pci_detach), 76 DEVMETHOD(device_suspend, mps_pci_suspend), 77 DEVMETHOD(device_resume, mps_pci_resume), 78 79 DEVMETHOD_END 80 }; 81 82 static driver_t mps_pci_driver = { 83 "mps", 84 mps_methods, 85 sizeof(struct mps_softc) 86 }; 87 88 struct mps_ident { 89 uint16_t vendor; 90 uint16_t device; 91 uint16_t subvendor; 92 uint16_t subdevice; 93 u_int flags; 94 const char *desc; 95 } mps_identifiers[] = { 96 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, 97 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2004" }, 98 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, 99 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2008" }, 100 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, 101 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2108" }, 102 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, 103 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2108" }, 104 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, 105 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2108" }, 106 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, 107 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2116" }, 108 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, 109 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2116" }, 110 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, 111 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" }, 112 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, 113 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" }, 114 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, 115 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" }, 116 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, 117 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" }, 118 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, 119 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" }, 120 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, 121 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" }, 122 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, 123 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2308" }, 124 // Add Customer specific vendor/subdevice id before generic 125 // (0xffff) vendor/subdevice id. 126 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, 127 0x8086, 0x3516, 0, "Intel(R) Integrated RAID Module RMS25JB080" }, 128 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, 129 0x8086, 0x3517, 0, "Intel(R) Integrated RAID Module RMS25JB040" }, 130 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, 131 0x8086, 0x3518, 0, "Intel(R) Integrated RAID Module RMS25KB080" }, 132 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, 133 0x8086, 0x3519, 0, "Intel(R) Integrated RAID Module RMS25KB040" }, 134 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, 135 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2308" }, 136 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, 137 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2308" }, 138 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, 139 0xffff, 0xffff, 0, "Avago Technologies (LSI) SSS6200" }, 140 { 0, 0, 0, 0, 0, NULL } 141 }; 142 143 DRIVER_MODULE(mps, pci, mps_pci_driver, 0, 0); 144 MODULE_DEPEND(mps, cam, 1, 1, 1); 145 MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice", pci, mps, 146 mps_identifiers, nitems(mps_identifiers) - 1); 147 static struct mps_ident * 148 mps_find_ident(device_t dev) 149 { 150 struct mps_ident *m; 151 152 for (m = mps_identifiers; m->vendor != 0; m++) { 153 if (m->vendor != pci_get_vendor(dev)) 154 continue; 155 if (m->device != pci_get_device(dev)) 156 continue; 157 if ((m->subvendor != 0xffff) && 158 (m->subvendor != pci_get_subvendor(dev))) 159 continue; 160 if ((m->subdevice != 0xffff) && 161 (m->subdevice != pci_get_subdevice(dev))) 162 continue; 163 return (m); 164 } 165 166 return (NULL); 167 } 168 169 static int 170 mps_pci_probe(device_t dev) 171 { 172 struct mps_ident *id; 173 174 if ((id = mps_find_ident(dev)) != NULL) { 175 device_set_desc(dev, id->desc); 176 return (BUS_PROBE_DEFAULT); 177 } 178 return (ENXIO); 179 } 180 181 static int 182 mps_pci_attach(device_t dev) 183 { 184 bus_dma_template_t t; 185 struct mps_softc *sc; 186 struct mps_ident *m; 187 int error; 188 189 sc = device_get_softc(dev); 190 bzero(sc, sizeof(*sc)); 191 sc->mps_dev = dev; 192 m = mps_find_ident(dev); 193 sc->mps_flags = m->flags; 194 195 mps_get_tunables(sc); 196 197 /* Twiddle basic PCI config bits for a sanity check */ 198 pci_enable_busmaster(dev); 199 200 /* Allocate the System Interface Register Set */ 201 sc->mps_regs_rid = PCIR_BAR(1); 202 if ((sc->mps_regs_resource = bus_alloc_resource_any(dev, 203 SYS_RES_MEMORY, &sc->mps_regs_rid, RF_ACTIVE)) == NULL) { 204 mps_printf(sc, "Cannot allocate PCI registers\n"); 205 return (ENXIO); 206 } 207 sc->mps_btag = rman_get_bustag(sc->mps_regs_resource); 208 sc->mps_bhandle = rman_get_bushandle(sc->mps_regs_resource); 209 210 /* Allocate the parent DMA tag */ 211 bus_dma_template_init(&t, bus_get_dma_tag(dev)); 212 if (bus_dma_template_tag(&t, &sc->mps_parent_dmat)) { 213 mps_printf(sc, "Cannot allocate parent DMA tag\n"); 214 mps_pci_free(sc); 215 return (ENOMEM); 216 } 217 218 if (((error = mps_pci_alloc_interrupts(sc)) != 0) || 219 ((error = mps_attach(sc)) != 0)) 220 mps_pci_free(sc); 221 222 return (error); 223 } 224 225 /* 226 * Allocate, but don't assign interrupts early. Doing it before requesting 227 * the IOCFacts message informs the firmware that we want to do MSI-X 228 * multiqueue. We might not use all of the available messages, but there's 229 * no reason to re-alloc if we don't. 230 */ 231 static int 232 mps_pci_alloc_interrupts(struct mps_softc *sc) 233 { 234 device_t dev; 235 int error, msgs; 236 237 dev = sc->mps_dev; 238 error = 0; 239 msgs = 0; 240 241 if (sc->disable_msix == 0) { 242 msgs = pci_msix_count(dev); 243 mps_dprint(sc, MPS_INIT, "Counted %d MSI-X messages\n", msgs); 244 msgs = min(msgs, sc->max_msix); 245 msgs = min(msgs, MPS_MSIX_MAX); 246 msgs = min(msgs, 1); /* XXX */ 247 if (msgs != 0) { 248 mps_dprint(sc, MPS_INIT, "Attempting to allocate %d " 249 "MSI-X messages\n", msgs); 250 error = mps_alloc_msix(sc, msgs); 251 } 252 } 253 if (((error != 0) || (msgs == 0)) && (sc->disable_msi == 0)) { 254 msgs = pci_msi_count(dev); 255 mps_dprint(sc, MPS_INIT, "Counted %d MSI messages\n", msgs); 256 msgs = min(msgs, MPS_MSI_MAX); 257 if (msgs != 0) { 258 mps_dprint(sc, MPS_INIT, "Attempting to allocate %d " 259 "MSI messages\n", MPS_MSI_MAX); 260 error = mps_alloc_msi(sc, MPS_MSI_MAX); 261 } 262 } 263 if ((error != 0) || (msgs == 0)) { 264 /* 265 * If neither MSI or MSI-X are avaiable, assume legacy INTx. 266 * This also implies that there will be only 1 queue. 267 */ 268 mps_dprint(sc, MPS_INIT, "Falling back to legacy INTx\n"); 269 sc->mps_flags |= MPS_FLAGS_INTX; 270 msgs = 1; 271 } else 272 sc->mps_flags |= MPS_FLAGS_MSI; 273 274 sc->msi_msgs = msgs; 275 mps_dprint(sc, MPS_INIT, "Allocated %d interrupts\n", msgs); 276 277 return (error); 278 } 279 280 int 281 mps_pci_setup_interrupts(struct mps_softc *sc) 282 { 283 device_t dev; 284 struct mps_queue *q; 285 void *ihandler; 286 int i, error, rid, initial_rid; 287 288 dev = sc->mps_dev; 289 error = ENXIO; 290 291 if (sc->mps_flags & MPS_FLAGS_INTX) { 292 initial_rid = 0; 293 ihandler = mps_intr; 294 } else if (sc->mps_flags & MPS_FLAGS_MSI) { 295 initial_rid = 1; 296 ihandler = mps_intr_msi; 297 } else { 298 mps_dprint(sc, MPS_ERROR|MPS_INIT, 299 "Unable to set up interrupts\n"); 300 return (EINVAL); 301 } 302 303 for (i = 0; i < sc->msi_msgs; i++) { 304 q = &sc->queues[i]; 305 rid = i + initial_rid; 306 q->irq_rid = rid; 307 q->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 308 &q->irq_rid, RF_ACTIVE); 309 if (q->irq == NULL) { 310 mps_dprint(sc, MPS_ERROR|MPS_INIT, 311 "Cannot allocate interrupt RID %d\n", rid); 312 sc->msi_msgs = i; 313 break; 314 } 315 error = bus_setup_intr(dev, q->irq, 316 INTR_TYPE_BIO | INTR_MPSAFE, NULL, ihandler, 317 sc, &q->intrhand); 318 if (error) { 319 mps_dprint(sc, MPS_ERROR|MPS_INIT, 320 "Cannot setup interrupt RID %d\n", rid); 321 sc->msi_msgs = i; 322 break; 323 } 324 } 325 326 mps_dprint(sc, MPS_INIT, "Set up %d interrupts\n", sc->msi_msgs); 327 328 return (error); 329 } 330 331 static int 332 mps_pci_detach(device_t dev) 333 { 334 struct mps_softc *sc; 335 int error; 336 337 sc = device_get_softc(dev); 338 339 if ((error = mps_free(sc)) != 0) 340 return (error); 341 342 mps_pci_free(sc); 343 return (0); 344 } 345 346 void 347 mps_pci_free_interrupts(struct mps_softc *sc) 348 { 349 struct mps_queue *q; 350 int i; 351 352 if (sc->queues == NULL) 353 return; 354 355 for (i = 0; i < sc->msi_msgs; i++) { 356 q = &sc->queues[i]; 357 if (q->irq != NULL) { 358 bus_teardown_intr(sc->mps_dev, q->irq, 359 q->intrhand); 360 bus_release_resource(sc->mps_dev, SYS_RES_IRQ, 361 q->irq_rid, q->irq); 362 } 363 } 364 } 365 366 static void 367 mps_pci_free(struct mps_softc *sc) 368 { 369 370 if (sc->mps_parent_dmat != NULL) { 371 bus_dma_tag_destroy(sc->mps_parent_dmat); 372 } 373 374 mps_pci_free_interrupts(sc); 375 376 if (sc->mps_flags & MPS_FLAGS_MSI) 377 pci_release_msi(sc->mps_dev); 378 379 if (sc->mps_regs_resource != NULL) { 380 bus_release_resource(sc->mps_dev, SYS_RES_MEMORY, 381 sc->mps_regs_rid, sc->mps_regs_resource); 382 } 383 384 return; 385 } 386 387 static int 388 mps_pci_suspend(device_t dev) 389 { 390 return (EINVAL); 391 } 392 393 static int 394 mps_pci_resume(device_t dev) 395 { 396 return (EINVAL); 397 } 398 399 static int 400 mps_alloc_msix(struct mps_softc *sc, int msgs) 401 { 402 int error; 403 404 error = pci_alloc_msix(sc->mps_dev, &msgs); 405 return (error); 406 } 407 408 static int 409 mps_alloc_msi(struct mps_softc *sc, int msgs) 410 { 411 int error; 412 413 error = pci_alloc_msi(sc->mps_dev, &msgs); 414 return (error); 415 } 416 417 int 418 mps_pci_restore(struct mps_softc *sc) 419 { 420 struct pci_devinfo *dinfo; 421 422 mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 423 424 dinfo = device_get_ivars(sc->mps_dev); 425 if (dinfo == NULL) { 426 mps_dprint(sc, MPS_FAULT, "%s: NULL dinfo\n", __func__); 427 return (EINVAL); 428 } 429 430 pci_cfg_restore(sc->mps_dev, dinfo); 431 return (0); 432 } 433