bt_pci.c revision 127135
1275970Scy/*- 2275970Scy * Product specific probe and attach routines for: 3275970Scy * Buslogic BT946, BT948, BT956, BT958 SCSI controllers 4275970Scy * 5275970Scy * Copyright (c) 1995, 1997, 1998 Justin T. Gibbs 6275970Scy * All rights reserved. 7275970Scy * 8275970Scy * Redistribution and use in source and binary forms, with or without 9275970Scy * modification, are permitted provided that the following conditions 10275970Scy * are met: 11275970Scy * 1. Redistributions of source code must retain the above copyright 12275970Scy * notice, this list of conditions, and the following disclaimer, 13275970Scy * without modification, immediately at the beginning of the file. 14275970Scy * 2. The name of the author may not be used to endorse or promote products 15275970Scy * derived from this software without specific prior written permission. 16275970Scy * 17275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20275970Scy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21275970Scy * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27275970Scy * SUCH DAMAGE. 28275970Scy */ 29275970Scy 30275970Scy#include <sys/cdefs.h> 31275970Scy__FBSDID("$FreeBSD: head/sys/dev/buslogic/bt_pci.c 127135 2004-03-17 17:50:55Z njl $"); 32275970Scy 33275970Scy#include <sys/param.h> 34275970Scy#include <sys/systm.h> 35275970Scy#include <sys/kernel.h> 36275970Scy#include <sys/lock.h> 37275970Scy#include <sys/mutex.h> 38275970Scy#include <sys/bus.h> 39275970Scy 40275970Scy#include <dev/pci/pcireg.h> 41275970Scy#include <dev/pci/pcivar.h> 42275970Scy 43275970Scy#include <machine/bus_memio.h> 44275970Scy#include <machine/bus_pio.h> 45275970Scy#include <machine/bus.h> 46275970Scy#include <machine/resource.h> 47275970Scy#include <sys/rman.h> 48275970Scy 49275970Scy#include <dev/buslogic/btreg.h> 50275970Scy 51275970Scy#define BT_PCI_IOADDR PCIR_BAR(0) 52275970Scy#define BT_PCI_MEMADDR PCIR_BAR(1) 53275970Scy 54275970Scy#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040104Bul 55275970Scy#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140104Bul 56275970Scy#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130104Bul 57275970Scy 58275970Scystatic int 59275970Scybt_pci_alloc_resources(device_t dev) 60275970Scy{ 61275970Scy int command, type = 0, rid, zero; 62275970Scy struct resource *regs = 0; 63275970Scy struct resource *irq = 0; 64275970Scy 65275970Scy command = pci_read_config(dev, PCIR_COMMAND, /*bytes*/1); 66275970Scy#if 0 67275970Scy /* XXX Memory Mapped I/O seems to cause problems */ 68275970Scy if (command & PCIM_CMD_MEMEN) { 69275970Scy type = SYS_RES_MEMORY; 70275970Scy rid = BT_PCI_MEMADDR; 71275970Scy regs = bus_alloc_resource_any(dev, type, &rid, RF_ACTIVE); 72275970Scy } 73275970Scy#else 74275970Scy if (!regs && (command & PCIM_CMD_PORTEN)) { 75275970Scy type = SYS_RES_IOPORT; 76275970Scy rid = BT_PCI_IOADDR; 77275970Scy regs = bus_alloc_resource_any(dev, type, &rid, RF_ACTIVE); 78275970Scy } 79275970Scy#endif 80275970Scy if (!regs) 81275970Scy return (ENOMEM); 82275970Scy 83275970Scy zero = 0; 84275970Scy irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &zero, 85275970Scy RF_ACTIVE | RF_SHAREABLE); 86275970Scy if (!irq) { 87275970Scy bus_release_resource(dev, type, rid, regs); 88275970Scy return (ENOMEM); 89275970Scy } 90275970Scy 91275970Scy bt_init_softc(dev, regs, irq, 0); 92275970Scy 93275970Scy return (0); 94275970Scy} 95275970Scy 96275970Scystatic void 97275970Scybt_pci_release_resources(device_t dev) 98275970Scy{ 99275970Scy struct bt_softc *bt = device_get_softc(dev); 100275970Scy 101275970Scy if (bt->port) 102275970Scy /* XXX can't cope with memory registers anyway */ 103275970Scy bus_release_resource(dev, SYS_RES_IOPORT, 104275970Scy BT_PCI_IOADDR, bt->port); 105275970Scy if (bt->irq) 106275970Scy bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 107275970Scy bt_free_softc(dev); 108275970Scy} 109275970Scy 110275970Scystatic int 111275970Scybt_pci_probe(device_t dev) 112275970Scy{ 113275970Scy switch (pci_get_devid(dev)) { 114275970Scy case PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER: 115275970Scy case PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC: 116275970Scy { 117275970Scy struct bt_softc *bt = device_get_softc(dev); 118275970Scy pci_info_data_t pci_info; 119275970Scy int error; 120275970Scy 121275970Scy error = bt_pci_alloc_resources(dev); 122275970Scy if (error) 123275970Scy return (error); 124275970Scy 125275970Scy /* 126275970Scy * Determine if an ISA compatible I/O port has been 127275970Scy * enabled. If so, record the port so it will not 128275970Scy * be probed by our ISA probe. If the PCI I/O port 129275970Scy * was not set to the compatibility port, disable it. 130275970Scy */ 131275970Scy error = bt_cmd(bt, BOP_INQUIRE_PCI_INFO, 132275970Scy /*param*/NULL, /*paramlen*/0, 133275970Scy (u_int8_t*)&pci_info, sizeof(pci_info), 134275970Scy DEFAULT_CMD_TIMEOUT); 135275970Scy if (error == 0 136275970Scy && pci_info.io_port < BIO_DISABLED) { 137275970Scy bt_mark_probed_bio(pci_info.io_port); 138275970Scy if (rman_get_start(bt->port) != 139275970Scy bt_iop_from_bio(pci_info.io_port)) { 140275970Scy u_int8_t new_addr; 141275970Scy 142275970Scy new_addr = BIO_DISABLED; 143275970Scy bt_cmd(bt, BOP_MODIFY_IO_ADDR, 144275970Scy /*param*/&new_addr, 145275970Scy /*paramlen*/1, /*reply_buf*/NULL, 146275970Scy /*reply_len*/0, 147275970Scy DEFAULT_CMD_TIMEOUT); 148275970Scy } 149275970Scy } 150275970Scy bt_pci_release_resources(dev); 151275970Scy device_set_desc(dev, "Buslogic Multi-Master SCSI Host Adapter"); 152275970Scy return (0); 153275970Scy } 154275970Scy default: 155275970Scy break; 156275970Scy } 157275970Scy 158275970Scy return (ENXIO); 159275970Scy} 160275970Scy 161275970Scystatic int 162275970Scybt_pci_attach(device_t dev) 163275970Scy{ 164275970Scy struct bt_softc *bt = device_get_softc(dev); 165275970Scy int opri; 166275970Scy int error; 167275970Scy 168275970Scy /* Initialize softc */ 169275970Scy error = bt_pci_alloc_resources(dev); 170275970Scy if (error) { 171275970Scy device_printf(dev, "can't allocate resources in bt_pci_attach\n"); 172275970Scy return error; 173275970Scy } 174275970Scy 175275970Scy /* Allocate a dmatag for our CCB DMA maps */ 176275970Scy /* XXX Should be a child of the PCI bus dma tag */ 177275970Scy if (bus_dma_tag_create( /* parent */ NULL, 178275970Scy /* alignemnt */ 1, 179275970Scy /* boundary */ 0, 180275970Scy /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 181275970Scy /* highaddr */ BUS_SPACE_MAXADDR, 182275970Scy /* filter */ NULL, 183275970Scy /* filterarg */ NULL, 184275970Scy /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 185275970Scy /* nsegments */ ~0, 186275970Scy /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 187275970Scy /* flags */ 0, 188275970Scy /* lockfunc */ busdma_lock_mutex, 189275970Scy /* lockarg */ &Giant, 190275970Scy &bt->parent_dmat) != 0) { 191275970Scy bt_pci_release_resources(dev); 192275970Scy return (ENOMEM); 193275970Scy } 194275970Scy 195275970Scy /* 196275970Scy * Protect ourself from spurrious interrupts during 197275970Scy * intialization and attach. We should really rely 198275970Scy * on interrupts during attach, but we don't have 199275970Scy * access to our interrupts during ISA probes, so until 200275970Scy * that changes, we mask our interrupts during attach 201275970Scy * too. 202275970Scy */ 203275970Scy opri = splcam(); 204275970Scy 205275970Scy if (bt_probe(dev) || bt_fetch_adapter_info(dev) || bt_init(dev)) { 206275970Scy bt_pci_release_resources(dev); 207275970Scy splx(opri); 208275970Scy return (ENXIO); 209275970Scy } 210275970Scy 211275970Scy error = bt_attach(dev); 212275970Scy splx(opri); 213275970Scy 214275970Scy if (error) { 215275970Scy bt_pci_release_resources(dev); 216275970Scy return (error); 217275970Scy } 218275970Scy 219275970Scy return (0); 220275970Scy} 221275970Scy 222275970Scystatic device_method_t bt_pci_methods[] = { 223275970Scy /* Device interface */ 224275970Scy DEVMETHOD(device_probe, bt_pci_probe), 225275970Scy DEVMETHOD(device_attach, bt_pci_attach), 226275970Scy 227275970Scy { 0, 0 } 228275970Scy}; 229275970Scy 230275970Scystatic driver_t bt_pci_driver = { 231275970Scy "bt", 232275970Scy bt_pci_methods, 233275970Scy sizeof(struct bt_softc), 234275970Scy}; 235275970Scy 236275970Scystatic devclass_t bt_devclass; 237275970Scy 238275970ScyDRIVER_MODULE(bt, pci, bt_pci_driver, bt_devclass, 0, 0); 239275970Scy