patch-2.4.14 linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
Next file: linux/drivers/scsi/aic7xxx/aic7xxx_osm.h
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
Back to the patch index
Back to the overall index
- Lines: 372
- Date:
Thu Oct 25 13:53:49 2001
- Orig file:
v2.4.13/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
- Orig date:
Mon Aug 27 12:41:44 2001
diff -u --recursive --new-file v2.4.13/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
@@ -1,7 +1,7 @@
/*
* Linux driver attachment glue for PCI based controllers.
*
- * Copyright (c) 2000, 2001 Adaptec Inc.
+ * Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -10,25 +10,33 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL").
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#23 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#27 $
*/
#include "aic7xxx_osm.h"
@@ -41,6 +49,11 @@
static int ahc_linux_pci_dev_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
+static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
+ u_long *base);
+static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
+ u_long *bus_addr,
+ uint8_t **maddr);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
@@ -56,6 +69,7 @@
},
{ 0 }
};
+MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
struct pci_driver aic7xxx_pci_driver = {
name: "aic7xxx",
@@ -88,12 +102,28 @@
static int
ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- char buf[80];
- struct ahc_softc *ahc;
- ahc_dev_softc_t pci;
- struct ahc_pci_identity *entry;
- char *name;
- int error;
+ char buf[80];
+ struct ahc_softc *ahc;
+ ahc_dev_softc_t pci;
+ struct ahc_pci_identity *entry;
+ char *name;
+ int error;
+
+ /*
+ * Some BIOSen report the same device multiple times.
+ */
+ TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+ struct pci_dev *probed_pdev;
+
+ probed_pdev = ahc->dev_softc;
+ if (probed_pdev->bus->number == pdev->bus->number
+ && probed_pdev->devfn == pdev->devfn)
+ break;
+ }
+ if (ahc != NULL) {
+ /* Skip duplicate. */
+ return (-ENODEV);
+ }
pci = pdev;
entry = ahc_find_pci_device(pci);
@@ -129,14 +159,13 @@
&& pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
#else
&& ahc_linux_get_memsize() > 0x80000000) {
+
ahc->dev_softc->dma_mask =
- (bus_addr_t)(0x7FFFFFFFFFULL
- & ((1ULL << (sizeof(bus_addr_t) * 8))-1));
+ (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
#endif
ahc->flags |= AHC_39BIT_ADDRESSING;
ahc->platform_data->hw_dma_mask =
- (bus_addr_t)(0x7FFFFFFFFFULL
- & ((1ULL << (sizeof(bus_addr_t) * 8))-1));
+ (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
}
#endif
ahc->dev_softc = pci;
@@ -172,28 +201,10 @@
pdev = NULL;
class = PCI_CLASS_STORAGE_SCSI << 8;
while ((pdev = pci_find_class(class, pdev)) != NULL) {
- struct ahc_softc *ahc;
ahc_dev_softc_t pci;
int error;
pci = pdev;
-
- /*
- * Some BIOSen report the same device multiple times.
- */
- TAILQ_FOREACH(ahc, &ahc_tailq, links) {
- struct pci_dev *probed_pdev;
-
- probed_pdev = ahc->dev_softc;
- if (probed_pdev->bus->number == pdev->bus->number
- && probed_pdev->devfn == pdev->devfn)
- break;
- }
- if (ahc != NULL) {
- /* Skip duplicate. */
- continue;
- }
-
error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
if (error == 0)
found++;
@@ -202,22 +213,40 @@
#endif
}
-int
-ahc_pci_map_registers(struct ahc_softc *ahc)
+static int
+ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
{
- uint32_t command;
- u_long base;
-#ifdef MMAPIO
- u_long start;
- u_long base_page;
- u_long base_offset;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ *base = pci_resource_start(ahc->dev_softc, 0);
+#else
+ *base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
+ *base &= PCI_BASE_ADDRESS_IO_MASK;
#endif
- uint8_t *maddr;
+ if (base == 0)
+ return (ENOMEM);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+ if (check_region(*base, 256) != 0)
+ return (ENOMEM);
+ else
+ request_region(*base, 256, "aic7xxx");
+#else
+ if (request_region(*base, 256, "aic7xxx") == 0)
+ return (ENOMEM);
+#endif
+ return (0);
+}
- command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
- base = 0;
- maddr = NULL;
-#ifdef MMAPIO
+static int
+ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
+ u_long *bus_addr,
+ uint8_t **maddr)
+{
+ u_long start;
+ u_long base_page;
+ u_long base_offset;
+ int error;
+
+ error = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
start = pci_resource_start(ahc->dev_softc, 1);
base_page = start & PAGE_MASK;
@@ -229,43 +258,70 @@
base_offset -= base_page;
#endif
if (start != 0) {
- ahc->platform_data->mem_busaddr = start;
+ *bus_addr = start;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- if (request_mem_region(start, 0x1000, "aic7xxx") == 0) {
- printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
- "in use. Cannot map device.\n",
+ if (request_mem_region(start, 0x1000, "aic7xxx") == 0)
+ error = ENOMEM;
+#endif
+ if (error == 0) {
+ *maddr = ioremap_nocache(base_page, base_offset + 256);
+ if (*maddr == NULL)
+ error = ENOMEM;
+ else
+ *maddr += base_offset;
+ }
+ } else
+ error = ENOMEM;
+ return (error);
+}
+
+int
+ahc_pci_map_registers(struct ahc_softc *ahc)
+{
+ uint32_t command;
+ u_long base;
+ uint8_t *maddr;
+ int error;
+ int io_error;
+
+ /*
+ * We always reserve both our register spaces to avoid
+ * other devices claiming them.
+ */
+ command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
+ command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
+ base = 0;
+ maddr = NULL;
+#ifdef MMAPIO
+ error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr);
+ if (error == 0) {
+ ahc->platform_data->mem_busaddr = base;
+ ahc->tag = BUS_SPACE_MEMIO;
+ ahc->bsh.maddr = maddr;
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+ command | PCIM_CMD_MEMEN, 4);
+
+ /*
+ * Do a quick test to see if memory mapped
+ * I/O is functioning correctly.
+ */
+ if (ahc_inb(ahc, HCNTRL) == 0xFF) {
+
+ printf("aic7xxx: PCI Device %d:%d:%d "
+ "failed memory mapped test\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
- ahc_get_pci_function(ahc->dev_softc),
- start);
+ ahc_get_pci_function(ahc->dev_softc));
+ maddr = NULL;
} else
-#endif
- maddr = ioremap_nocache(base_page, base_offset + 256);
- if (maddr != NULL) {
- ahc->tag = BUS_SPACE_MEMIO;
- ahc->bsh.maddr = maddr + base_offset;
command |= PCIM_CMD_MEMEN;
- ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
- command, 4);
-
- /*
- * Do a quick test to see if memory mapped
- * I/O is functioning correctly.
- */
- if (ahc_inb(ahc, HCNTRL) == 0xFF) {
- printf("aic7xxx: PCI Device %d:%d:%d "
- "failed memory mapped test\n",
- ahc_get_pci_bus(ahc->dev_softc),
- ahc_get_pci_slot(ahc->dev_softc),
- ahc_get_pci_function(ahc->dev_softc));
- iounmap((void *)base_page);
- maddr = NULL;
- } else {
- command &= ~PCIM_CMD_PORTEN;
- ahc_pci_write_config(ahc->dev_softc,
- PCIR_COMMAND, command, 4);
- }
- }
+ } else {
+ printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
+ "unavailable. Cannot map device.\n",
+ ahc_get_pci_bus(ahc->dev_softc),
+ ahc_get_pci_slot(ahc->dev_softc),
+ ahc_get_pci_function(ahc->dev_softc),
+ base);
}
#endif
@@ -274,46 +330,25 @@
* complain about our ioport conflicting with
* another device if we are going to use it.
*/
+ io_error = ahc_linux_pci_reserve_io_region(ahc, &base);
if (maddr == NULL) {
- ahc->tag = BUS_SPACE_PIO;
- command &= ~(PCIM_CMD_MEMEN|PCIM_CMD_PORTEN);
- ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
- base = pci_resource_start(ahc->dev_softc, 0);
-#else
- base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
- base &= PCI_BASE_ADDRESS_IO_MASK;
-#endif
- if (base == 0) {
- printf("aic7xxx: PCI%d:%d:%d No mapping available. "
- "Cannot map device.\n",
- ahc_get_pci_bus(ahc->dev_softc),
- ahc_get_pci_slot(ahc->dev_softc),
- ahc_get_pci_function(ahc->dev_softc));
- return (ENXIO);
- }
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
- if (check_region(base, 256) != 0) {
-#else
- if (request_region(base, 256, "aic7xxx") == 0) {
-#endif
+ error = io_error;
+ if (error != 0) {
printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
- "in use. Cannot map device.\n",
+ "unavailable. Cannot map device.\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
ahc_get_pci_function(ahc->dev_softc),
base);
base = 0;
- return (EBUSY);
+ } else {
+ ahc->tag = BUS_SPACE_PIO;
+ ahc->bsh.ioport = base;
+ command |= PCIM_CMD_PORTEN;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
- request_region(base, 256, "aic7xxx");
-#endif
- ahc->bsh.ioport = base;
- command |= PCIM_CMD_PORTEN;
- ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
}
- return (0);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
+ return (error);
}
int
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)