1 /*- 2 * Copyright (c) 2006 IronPort Systems 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /*- 27 * Copyright (c) 2007 LSI Corp. 28 * Copyright (c) 2007 Rajesh Prabhakaran. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 * 52 * $FreeBSD: src/sys/dev/mfi/mfi_pci.c,v 1.16 2010/03/02 17:34:11 kib Exp $ 53 * FreeBSD projects/head_mfi/ r232888 54 */ 55 56 /* PCI/PCI-X/PCIe bus interface for the LSI MegaSAS controllers */ 57 58 #include "opt_mfi.h" 59 60 #include <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/kernel.h> 63 #include <sys/module.h> 64 #include <sys/bus.h> 65 #include <sys/conf.h> 66 #include <sys/buf2.h> 67 #include <sys/malloc.h> 68 #include <sys/uio.h> 69 #include <sys/eventhandler.h> 70 #include <sys/rman.h> 71 72 #include <bus/pci/pcireg.h> 73 #include <bus/pci/pcivar.h> 74 75 #include <dev/raid/mfi/mfireg.h> 76 #include <dev/raid/mfi/mfi_ioctl.h> 77 #include <dev/raid/mfi/mfivar.h> 78 79 static int mfi_pci_probe(device_t); 80 static int mfi_pci_attach(device_t); 81 static int mfi_pci_detach(device_t); 82 static int mfi_pci_suspend(device_t); 83 static int mfi_pci_resume(device_t); 84 static void mfi_pci_free(struct mfi_softc *); 85 86 static device_method_t mfi_methods[] = { 87 DEVMETHOD(device_probe, mfi_pci_probe), 88 DEVMETHOD(device_attach, mfi_pci_attach), 89 DEVMETHOD(device_detach, mfi_pci_detach), 90 DEVMETHOD(device_suspend, mfi_pci_suspend), 91 DEVMETHOD(device_resume, mfi_pci_resume), 92 DEVMETHOD(bus_print_child, bus_generic_print_child), 93 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 94 DEVMETHOD_END 95 }; 96 97 static driver_t mfi_pci_driver = { 98 "mfi", 99 mfi_methods, 100 sizeof(struct mfi_softc) 101 }; 102 103 static devclass_t mfi_devclass; 104 DRIVER_MODULE(mfi, pci, mfi_pci_driver, mfi_devclass, NULL, NULL); 105 MODULE_VERSION(mfi, 1); 106 107 static int mfi_msi_enable = 1; 108 TUNABLE_INT("hw.mfi.msi.enable", &mfi_msi_enable); 109 110 struct mfi_ident { 111 uint16_t vendor; 112 uint16_t device; 113 uint16_t subvendor; 114 uint16_t subdevice; 115 int flags; 116 const char *desc; 117 } mfi_identifiers[] = { 118 { 0x1000, 0x005b, 0x1028, 0x1f2d, 119 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 120 "Dell PERC H810 Adapter" }, 121 { 0x1000, 0x005b, 0x1028, 0x1f30, 122 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 123 "Dell PERC H710 Embedded" }, 124 { 0x1000, 0x005b, 0x1028, 0x1f31, 125 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 126 "Dell PERC H710P Adapter" }, 127 { 0x1000, 0x005b, 0x1028, 0x1f33, 128 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 129 "Dell PERC H710P Mini (blades)" }, 130 { 0x1000, 0x005b, 0x1028, 0x1f34, 131 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 132 "Dell PERC H710P Mini (monolithics)" }, 133 { 0x1000, 0x005b, 0x1028, 0x1f35, 134 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 135 "Dell PERC H710 Adapter" }, 136 { 0x1000, 0x005b, 0x1028, 0x1f37, 137 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 138 "Dell PERC H710 Mini (blades)" }, 139 { 0x1000, 0x005b, 0x1028, 0x1f38, 140 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 141 "Dell PERC H710 Mini (monolithics)" }, 142 { 0x1000, 0x005b, 0x8086, 0x9265, 143 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 144 "Intel (R) RAID Controller RS25DB080" }, 145 { 0x1000, 0x005b, 0x8086, 0x9285, 146 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 147 "Intel (R) RAID Controller RS25NB008" }, 148 { 0x1000, 0x005b, 0xffff, 0xffff, 149 MFI_FLAGS_SKINNY | MFI_FLAGS_TBOLT, 150 "ThunderBolt" }, 151 { 0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078, 152 "Dell PERC 6" }, 153 { 0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, 154 "LSI MegaSAS 1078" }, 155 { 0x1000, 0x0071, 0xffff, 0xffff, MFI_FLAGS_SKINNY, 156 "Drake Skinny" }, 157 { 0x1000, 0x0073, 0xffff, 0xffff, MFI_FLAGS_SKINNY, 158 "Drake Skinny" }, 159 { 0x1000, 0x0078, 0xffff, 0xffff, MFI_FLAGS_GEN2, 160 "LSI MegaSAS Gen2" }, 161 { 0x1000, 0x0079, 0x1028, 0x1f15, MFI_FLAGS_GEN2, 162 "Dell PERC H800 Adapter" }, 163 { 0x1000, 0x0079, 0x1028, 0x1f16, MFI_FLAGS_GEN2, 164 "Dell PERC H700 Adapter" }, 165 { 0x1000, 0x0079, 0x1028, 0x1f17, MFI_FLAGS_GEN2, 166 "Dell PERC H700 Integrated" }, 167 { 0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2, 168 "Dell PERC H700 Modular" }, 169 { 0x1000, 0x0079, 0x1028, 0x1f19, MFI_FLAGS_GEN2, 170 "Dell PERC H700" }, 171 { 0x1000, 0x0079, 0x1028, 0x1f1a, MFI_FLAGS_GEN2, 172 "Dell PERC H800 Proto Adapter" }, 173 { 0x1000, 0x0079, 0x1028, 0x1f1b, MFI_FLAGS_GEN2, 174 "Dell PERC H800" }, 175 { 0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2, 176 "Dell PERC Gen2" }, 177 { 0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2, 178 "LSI MegaSAS Gen2" }, 179 { 0x1000, 0x007c, 0xffff, 0xffff, MFI_FLAGS_1078, 180 "LSI MegaSAS 1078" }, 181 { 0x1000, 0x0411, 0xffff, 0xffff, MFI_FLAGS_1064R, /* Brocton IOP */ 182 "LSI MegaSAS 1064R" }, 183 { 0x1000, 0x0413, 0xffff, 0xffff, MFI_FLAGS_1064R, /* Verde ZCR */ 184 "LSI MegaSAS 1064R" }, 185 { 0x1028, 0x0015, 0xffff, 0xffff, MFI_FLAGS_1064R, 186 "Dell PERC 5/i" }, 187 {0, 0, 0, 0, 0, NULL} 188 }; 189 190 static struct mfi_ident * 191 mfi_find_ident(device_t dev) 192 { 193 struct mfi_ident *m; 194 195 for (m = mfi_identifiers; m->vendor != 0; m++) { 196 if ((m->vendor == pci_get_vendor(dev)) && 197 (m->device == pci_get_device(dev)) && 198 ((m->subvendor == pci_get_subvendor(dev)) || 199 (m->subvendor == 0xffff)) && 200 ((m->subdevice == pci_get_subdevice(dev)) || 201 (m->subdevice == 0xffff))) 202 return (m); 203 } 204 205 return (NULL); 206 } 207 208 static int 209 mfi_pci_probe(device_t dev) 210 { 211 struct mfi_ident *id; 212 213 if ((id = mfi_find_ident(dev)) != NULL) { 214 device_set_desc(dev, id->desc); 215 return (BUS_PROBE_DEFAULT); 216 } 217 return (ENXIO); 218 } 219 220 static int 221 mfi_pci_attach(device_t dev) 222 { 223 struct mfi_softc *sc; 224 struct mfi_ident *m; 225 uint32_t command; 226 int error; 227 u_int irq_flags; 228 229 sc = device_get_softc(dev); 230 bzero(sc, sizeof(*sc)); 231 sc->mfi_dev = dev; 232 m = mfi_find_ident(dev); 233 sc->mfi_flags = m->flags; 234 235 /* Verify that the adapter can be set up in PCI space */ 236 command = pci_read_config(dev, PCIR_COMMAND, 2); 237 command |= PCIM_CMD_BUSMASTEREN; 238 pci_write_config(dev, PCIR_COMMAND, command, 2); 239 command = pci_read_config(dev, PCIR_COMMAND, 2); 240 if ((command & PCIM_CMD_BUSMASTEREN) == 0) { 241 device_printf(dev, "Can't enable PCI busmaster\n"); 242 return (ENXIO); 243 } 244 if ((command & PCIM_CMD_MEMEN) == 0) { 245 device_printf(dev, "PCI memory window not available\n"); 246 return (ENXIO); 247 } 248 249 /* Allocate PCI registers */ 250 if ((sc->mfi_flags & MFI_FLAGS_1064R) || 251 (sc->mfi_flags & MFI_FLAGS_1078)) { 252 /* 1068/1078: Memory mapped BAR is at offset 0x10 */ 253 sc->mfi_regs_rid = PCIR_BAR(0); 254 } else if ((sc->mfi_flags & MFI_FLAGS_GEN2) || 255 (sc->mfi_flags & MFI_FLAGS_SKINNY) || 256 (sc->mfi_flags & MFI_FLAGS_TBOLT)) { 257 /* GEN2/Skinny: Memory mapped BAR is at offset 0x14 */ 258 sc->mfi_regs_rid = PCIR_BAR(1); 259 } 260 if ((sc->mfi_regs_resource = bus_alloc_resource_any(sc->mfi_dev, 261 SYS_RES_MEMORY, &sc->mfi_regs_rid, RF_ACTIVE)) == NULL) { 262 device_printf(dev, "Cannot allocate PCI registers\n"); 263 return (ENXIO); 264 } 265 sc->mfi_btag = rman_get_bustag(sc->mfi_regs_resource); 266 sc->mfi_bhandle = rman_get_bushandle(sc->mfi_regs_resource); 267 268 error = ENOMEM; 269 270 /* Allocate parent DMA tag */ 271 if (bus_dma_tag_create( NULL, /* parent */ 272 1, 0, /* algnmnt, boundary */ 273 BUS_SPACE_MAXADDR, /* lowaddr */ 274 BUS_SPACE_MAXADDR, /* highaddr */ 275 NULL, NULL, /* filter, filterarg */ 276 BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 277 BUS_SPACE_UNRESTRICTED, /* nsegments */ 278 BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 279 0, /* flags */ 280 &sc->mfi_parent_dmat)) { 281 device_printf(dev, "Cannot allocate parent DMA tag\n"); 282 goto out; 283 } 284 285 /* Allocate IRQ resource. */ 286 sc->mfi_irq_rid = 0; 287 sc->mfi_irq_type = pci_alloc_1intr(sc->mfi_dev, mfi_msi_enable, 288 &sc->mfi_irq_rid, &irq_flags); 289 if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ, 290 &sc->mfi_irq_rid, irq_flags)) == NULL) { 291 device_printf(sc->mfi_dev, "Cannot allocate interrupt\n"); 292 return (EINVAL); 293 } 294 295 error = mfi_attach(sc); 296 out: 297 if (error) { 298 mfi_free(sc); 299 mfi_pci_free(sc); 300 } 301 302 return (error); 303 } 304 305 static int 306 mfi_pci_detach(device_t dev) 307 { 308 struct mfi_softc *sc; 309 device_t *devlist; 310 int error, devcount, i; 311 312 sc = device_get_softc(dev); 313 314 lockmgr(&sc->mfi_config_lock, LK_EXCLUSIVE); 315 lockmgr(&sc->mfi_io_lock, LK_EXCLUSIVE); 316 if ((sc->mfi_flags & MFI_FLAGS_OPEN) != 0) { 317 lockmgr(&sc->mfi_io_lock, LK_RELEASE); 318 lockmgr(&sc->mfi_config_lock, LK_RELEASE); 319 return (EBUSY); 320 } 321 sc->mfi_detaching = 1; 322 lockmgr(&sc->mfi_io_lock, LK_RELEASE); 323 324 if ((error = device_get_children(sc->mfi_dev, &devlist, &devcount)) != 0) { 325 lockmgr(&sc->mfi_config_lock, LK_RELEASE); 326 return error; 327 } 328 for (i = 0; i < devcount; i++) 329 device_delete_child(sc->mfi_dev, devlist[i]); 330 kfree(devlist, M_TEMP); 331 lockmgr(&sc->mfi_config_lock, LK_RELEASE); 332 333 EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh); 334 335 mfi_shutdown(sc); 336 mfi_free(sc); 337 mfi_pci_free(sc); 338 return (0); 339 } 340 341 static void 342 mfi_pci_free(struct mfi_softc *sc) 343 { 344 345 if (sc->mfi_regs_resource != NULL) { 346 bus_release_resource(sc->mfi_dev, SYS_RES_MEMORY, 347 sc->mfi_regs_rid, sc->mfi_regs_resource); 348 } 349 if (sc->mfi_irq_type == PCI_INTR_TYPE_MSI) 350 pci_release_msi(sc->mfi_dev); 351 } 352 353 static int 354 mfi_pci_suspend(device_t dev) 355 { 356 357 return (EINVAL); 358 } 359 360 static int 361 mfi_pci_resume(device_t dev) 362 { 363 364 return (EINVAL); 365 } 366