1 /* 2 * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 * 16 * 17 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 18 * 19 * This code is derived from software contributed to The DragonFly Project 20 * by Matthew Dillon <dillon@backplane.com> 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in 30 * the documentation and/or other materials provided with the 31 * distribution. 32 * 3. Neither the name of The DragonFly Project nor the names of its 33 * contributors may be used to endorse or promote products derived 34 * from this software without specific, prior written permission. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 37 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 38 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 39 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 40 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 41 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 42 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 44 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * 49 * $OpenBSD: sili.c,v 1.147 2009/02/16 21:19:07 miod Exp $ 50 */ 51 52 #include "sili.h" 53 54 static int sili_pci_attach(device_t); 55 static int sili_pci_detach(device_t); 56 57 static const struct sili_device sili_devices[] = { 58 { 59 .ad_vendor = PCI_VENDOR_SII, 60 .ad_product = PCI_PRODUCT_SII_3132, 61 .ad_nports = 2, 62 .ad_attach = sili_pci_attach, 63 .ad_detach = sili_pci_detach, 64 .name = "SiliconImage-3132-SATA" 65 }, 66 { 0, 0, 0, NULL, NULL, NULL } 67 }; 68 69 /* 70 * Match during probe and attach. The device does not yet have a softc. 71 */ 72 const struct sili_device * 73 sili_lookup_device(device_t dev) 74 { 75 const struct sili_device *ad; 76 u_int16_t vendor = pci_get_vendor(dev); 77 u_int16_t product = pci_get_device(dev); 78 #if 0 79 u_int8_t class = pci_get_class(dev); 80 u_int8_t subclass = pci_get_subclass(dev); 81 u_int8_t progif = pci_read_config(dev, PCIR_PROGIF, 1); 82 #endif 83 84 for (ad = &sili_devices[0]; ad->ad_vendor; ++ad) { 85 if (ad->ad_vendor == vendor && ad->ad_product == product) 86 return (ad); 87 } 88 return (NULL); 89 #if 0 90 /* 91 * Last ad is the default match if the PCI device matches SATA. 92 */ 93 if (class == PCIC_STORAGE && subclass == PCIS_STORAGE_SATA && 94 progif == PCIP_STORAGE_SATA_SILI_1_0) { 95 return (ad); 96 } 97 return (NULL); 98 #endif 99 } 100 101 static int 102 sili_pci_attach(device_t dev) 103 { 104 struct sili_softc *sc = device_get_softc(dev); 105 struct sili_port *ap; 106 const char *gen; 107 u_int32_t nports, reg; 108 bus_addr_t addr; 109 int i; 110 int error; 111 112 /* 113 * Map the SILI controller's IRQ, BAR(0) (global regs), 114 * and BAR(1) (port regs and lram). 115 */ 116 sc->sc_dev = dev; 117 sc->sc_rid_irq = SILI_IRQ_RID; 118 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq, 119 RF_SHAREABLE | RF_ACTIVE); 120 if (sc->sc_irq == NULL) { 121 device_printf(dev, "unable to map interrupt\n"); 122 sili_pci_detach(dev); 123 return (ENXIO); 124 } 125 126 /* 127 * When mapping the register window store the tag and handle 128 * separately so we can use the tag with per-port bus handle 129 * sub-spaces. 130 */ 131 sc->sc_rid_regs = PCIR_BAR(0); 132 sc->sc_regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 133 &sc->sc_rid_regs, RF_ACTIVE); 134 if (sc->sc_regs == NULL) { 135 device_printf(dev, "unable to map registers\n"); 136 sili_pci_detach(dev); 137 return (ENXIO); 138 } 139 sc->sc_iot = rman_get_bustag(sc->sc_regs); 140 sc->sc_ioh = rman_get_bushandle(sc->sc_regs); 141 142 sc->sc_rid_pregs = PCIR_BAR(2); 143 sc->sc_pregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 144 &sc->sc_rid_pregs, RF_ACTIVE); 145 if (sc->sc_pregs == NULL) { 146 device_printf(dev, "unable to map port registers\n"); 147 sili_pci_detach(dev); 148 return (ENXIO); 149 } 150 sc->sc_piot = rman_get_bustag(sc->sc_pregs); 151 sc->sc_pioh = rman_get_bushandle(sc->sc_pregs); 152 153 /* 154 * Initialize the chipset and then set the interrupt vector up 155 */ 156 error = sili_init(sc); 157 if (error) { 158 sili_pci_detach(dev); 159 return (ENXIO); 160 } 161 162 /* 163 * We assume at least 4 commands. 164 */ 165 sc->sc_ncmds = SILI_MAX_CMDS; 166 sc->sc_flags |= SILI_F_64BIT; 167 sc->sc_flags |= SILI_F_NCQ; 168 sc->sc_flags |= SILI_F_SSNTF; 169 sc->sc_flags |= SILI_F_SPM; 170 171 addr = (sc->sc_flags & SILI_F_64BIT) ? 172 BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT; 173 174 /* 175 * DMA tags for allocation of DMA memory buffers, lists, and so 176 * forth. These are typically per-port. 177 * 178 * The stuff is mostly built into the BAR mappings. We only need 179 * tags for our external SGE list and data. 180 */ 181 error = 0; 182 error += bus_dma_tag_create( 183 NULL, /* parent tag */ 184 256, /* alignment */ 185 65536, /* boundary */ 186 addr, /* loaddr? */ 187 BUS_SPACE_MAXADDR, /* hiaddr */ 188 NULL, /* filter */ 189 NULL, /* filterarg */ 190 sizeof(struct sili_prb) * SILI_MAX_CMDS, 191 /* [max]size */ 192 1, /* maxsegs */ 193 sizeof(struct sili_prb) * SILI_MAX_CMDS, 194 /* maxsegsz */ 195 0, /* flags */ 196 &sc->sc_tag_prbs); /* return tag */ 197 198 /* 199 * The data tag is used for later dmamaps and not immediately 200 * allocated. 201 */ 202 error += bus_dma_tag_create( 203 NULL, /* parent tag */ 204 4, /* alignment */ 205 0, /* boundary */ 206 addr, /* loaddr? */ 207 BUS_SPACE_MAXADDR, /* hiaddr */ 208 NULL, /* filter */ 209 NULL, /* filterarg */ 210 4096 * 1024, /* maxiosize */ 211 SILI_MAX_SGET, /* maxsegs */ 212 65536, /* maxsegsz */ 213 0, /* flags */ 214 &sc->sc_tag_data); /* return tag */ 215 216 if (error) { 217 device_printf(dev, "unable to create dma tags\n"); 218 sili_pci_detach(dev); 219 return (ENXIO); 220 } 221 222 if (sili_read(sc, SILI_REG_GCTL) & SILI_REG_GCTL_300CAP) { 223 gen = "1 (1.5Gbps) and 2 (3Gbps)"; 224 sc->sc_flags |= SILI_F_300; 225 } else { 226 gen = "1 (1.5Gbps)"; 227 } 228 229 nports = sc->sc_ad->ad_nports; 230 KKASSERT(nports <= SILI_MAX_PORTS); 231 232 device_printf(dev, "ports=%d tags=31, cap=NCQ,FBSS,SPM\n", nports); 233 234 /* 235 * Allocate per-port resources 236 * 237 * All ports are attached in parallel but the CAM scan-bus 238 * is held up until all ports are attached so we get a deterministic 239 * order. 240 */ 241 for (i = 0; error == 0 && i < nports; i++) { 242 error = sili_port_alloc(sc, i); 243 } 244 245 /* 246 * Setup the interrupt vector and enable interrupts. Note that 247 * since the irq may be shared we do not set it up until we are 248 * ready to go. 249 */ 250 if (error == 0) { 251 error = bus_setup_intr(dev, sc->sc_irq, 0, sili_intr, sc, 252 &sc->sc_irq_handle, NULL); 253 } 254 255 if (error) { 256 device_printf(dev, "unable to install interrupt\n"); 257 sili_pci_detach(dev); 258 return (ENXIO); 259 } 260 261 /* 262 * Interrupt subsystem is good to go now, enable all port interrupts 263 */ 264 crit_enter(); 265 reg = sili_read(sc, SILI_REG_GCTL); 266 for (i = 0; i < nports; ++i) 267 reg |= SILI_REG_GCTL_PORTEN(i); 268 sili_write(sc, SILI_REG_GCTL, reg); 269 sc->sc_flags |= SILI_F_INT_GOOD; 270 crit_exit(); 271 sili_intr(sc); 272 273 /* 274 * All ports are probing in parallel. Wait for them to finish 275 * and then issue the cam attachment and bus scan serially so 276 * the 'da' assignments are deterministic. 277 */ 278 for (i = 0; i < nports; i++) { 279 if ((ap = sc->sc_ports[i]) != NULL) { 280 while (ap->ap_signal & AP_SIGF_INIT) 281 tsleep(&ap->ap_signal, 0, "ahprb1", hz); 282 sili_os_lock_port(ap); 283 if (sili_cam_attach(ap) == 0) { 284 sili_cam_changed(ap, NULL, -1); 285 sili_os_unlock_port(ap); 286 while ((ap->ap_flags & AP_F_SCAN_COMPLETED) == 0) { 287 tsleep(&ap->ap_flags, 0, "ahprb2", hz); 288 } 289 } else { 290 sili_os_unlock_port(ap); 291 } 292 } 293 } 294 295 return(0); 296 } 297 298 /* 299 * Device unload / detachment 300 */ 301 static int 302 sili_pci_detach(device_t dev) 303 { 304 struct sili_softc *sc = device_get_softc(dev); 305 struct sili_port *ap; 306 int i; 307 308 /* 309 * Disable the controller and de-register the interrupt, if any. 310 * 311 * XXX interlock last interrupt? 312 */ 313 sc->sc_flags &= ~SILI_F_INT_GOOD; 314 if (sc->sc_regs) 315 sili_write(sc, SILI_REG_GCTL, SILI_REG_GCTL_GRESET); 316 317 if (sc->sc_irq_handle) { 318 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irq_handle); 319 sc->sc_irq_handle = NULL; 320 } 321 322 /* 323 * Free port structures and DMA memory 324 */ 325 for (i = 0; i < SILI_MAX_PORTS; i++) { 326 ap = sc->sc_ports[i]; 327 if (ap) { 328 sili_cam_detach(ap); 329 sili_port_free(sc, i); 330 } 331 } 332 333 /* 334 * Clean up the bus space 335 */ 336 if (sc->sc_irq) { 337 bus_release_resource(dev, SYS_RES_IRQ, 338 sc->sc_rid_irq, sc->sc_irq); 339 sc->sc_irq = NULL; 340 } 341 if (sc->sc_regs) { 342 bus_release_resource(dev, SYS_RES_MEMORY, 343 sc->sc_rid_regs, sc->sc_regs); 344 sc->sc_regs = NULL; 345 } 346 if (sc->sc_pregs) { 347 bus_release_resource(dev, SYS_RES_MEMORY, 348 sc->sc_rid_pregs, sc->sc_pregs); 349 sc->sc_regs = NULL; 350 } 351 352 if (sc->sc_tag_prbs) { 353 bus_dma_tag_destroy(sc->sc_tag_prbs); 354 sc->sc_tag_prbs = NULL; 355 } 356 if (sc->sc_tag_data) { 357 bus_dma_tag_destroy(sc->sc_tag_data); 358 sc->sc_tag_data = NULL; 359 } 360 361 return (0); 362 } 363