freebsd-skq/sys/dev/aic7xxx/ahc_eisa.c

210 lines
5.4 KiB
C
Raw Normal View History

1998-09-15 07:24:58 +00:00
/*
* FreeBSD, EISA product support functions
*
1998-09-15 07:24:58 +00:00
*
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 2000 Justin T. Gibbs.
1998-09-15 07:24:58 +00:00
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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
* 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.
*
* $Id$
*
1999-08-28 01:08:13 +00:00
* $FreeBSD$
1998-09-15 07:24:58 +00:00
*/
#include <dev/aic7xxx/aic7xxx_freebsd.h>
1998-09-15 07:24:58 +00:00
#include <dev/eisa/eisaconf.h>
1998-09-15 07:24:58 +00:00
static int
aic7770_probe(device_t dev)
1998-09-15 07:24:58 +00:00
{
struct aic7770_identity *entry;
struct resource *regs;
o Convert to <inttypes.h> style fixed sized types to facilitate porting to other systems. o Normalize copyright text. o Clean up probe code function interfaces by passing around a single structure of common arguments instead of passing "too many" args in each function call. o Add support for the AAA-131 as a SCSI adapter. o Add support for the AHA-4944 courtesy of "Matthew N. Dodd" <winter@jurai.net o Correct manual termination support for PCI cards. The bit definitions for manual termination control in the SEEPROM were incorrect. o Add support for extracting NVRAM information from SCB 2 for BIOSen that use this mechanism to pass this data to OS drivers. o Properly set the STPWLEVEL bit in PCI config space based on the setting in an SEEPROM. o Go back to useing 32byte SCBs for all controllers. The current firmware allows us to embed 12byte cdbs on all controllers in a 32byte SCB, and larger cdbs are rarely used, so it is a better use of this space to offer more SCBs (32). o Add support for U160 transfers. o Add an idle loop executed during data transfers that prefetches S/G segments on controllers that have a secondary DMA engine (aic789X). o Improve the performance of reselections by avoiding an extra one byte DMA in the case of an SCB lookup miss for the reselecting target. We now keep a 16byte "untagged target" array on the card for dealing with untagged reselections. If the controller has external SCB ram and can support 64byte SCBs, then we use an "untagged target/lun" array to maximize concurrency. Without external SCB ram, the controller is limited to one untagged transaction per target, auto-request sense operations excluded. o Correct the setup of the STPWEN bit in SXFRCTL1. This control line is tri-stated until set to one, so set it to one and then set it to the desired value. o Add tagged queuing support to our target role implementation. o Handle the common cases of the ignore wide residue message in firmware. o Add preliminary support for 39bit addressing. o Add support for assembling on big-endian machines. Big-endian support is not complete in the driver. o Correctly remove SCBs in the waiting for selection queue when freezing a device queue. o Now that we understand more about the autoflush bug on the aic7890, only use the workaround on devices that need it. o Add a workaround for the "aic7890 hangs the system when you attempt to pause it" problem. We can now pause the aic7890 safely regardless of what instruction it is executing.
2000-07-18 20:12:14 +00:00
uint32_t iobase;
bus_space_handle_t bsh;
bus_space_tag_t tag;
u_int irq;
u_int intdef;
u_int hcntrl;
int shared;
int rid;
int error;
entry = aic7770_find_device(eisa_get_id(dev));
if (entry == NULL)
return (ENXIO);
device_set_desc(dev, entry->name);
iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + AHC_EISA_SLOT_OFFSET;
1998-09-15 07:24:58 +00:00
eisa_add_iospace(dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE);
regs = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
0, ~0, 1, RF_ACTIVE);
if (regs == NULL) {
device_printf(dev, "Unable to map I/O space?!\n");
return ENOMEM;
}
tag = rman_get_bustag(regs);
bsh = rman_get_bushandle(regs);
error = 0;
/* Pause the card preseving the IRQ type */
hcntrl = bus_space_read_1(tag, bsh, HCNTRL) & IRQMS;
bus_space_write_1(tag, bsh, HCNTRL, hcntrl | PAUSE);
while ((bus_space_read_1(tag, bsh, HCNTRL) & PAUSE) == 0)
;
/* Make sure we have a valid interrupt vector */
intdef = bus_space_read_1(tag, bsh, INTDEF);
shared = (intdef & EDGE_TRIG) ? EISA_TRIGGER_EDGE : EISA_TRIGGER_LEVEL;
irq = intdef & VECTOR;
switch (irq) {
case 9:
case 10:
case 11:
case 12:
case 14:
case 15:
break;
default:
printf("aic7770 at slot %d: illegal irq setting %d\n",
eisa_get_slot(dev), intdef);
error = ENXIO;
1998-09-15 07:24:58 +00:00
}
if (error == 0)
eisa_add_intr(dev, irq, shared);
bus_release_resource(dev, SYS_RES_IOPORT, rid, regs);
return (error);
1998-09-15 07:24:58 +00:00
}
static int
aic7770_attach(device_t dev)
1998-09-15 07:24:58 +00:00
{
struct aic7770_identity *entry;
struct ahc_softc *ahc;
char *name;
int error;
entry = aic7770_find_device(eisa_get_id(dev));
if (entry == NULL)
return (ENXIO);
1998-09-15 07:24:58 +00:00
/*
* Allocate a softc for this card and
* set it up for attachment by our
* common detect routine.
*/
name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
if (name == NULL)
return (ENOMEM);
strcpy(name, device_get_nameunit(dev));
ahc = ahc_alloc(NULL, name);
if (ahc == NULL)
return (ENOMEM);
/* Allocate a dmatag for our SCB DMA maps */
/* XXX Should be a child of the PCI bus dma tag */
error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
1998-09-15 07:24:58 +00:00
/*boundary*/0,
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
1998-09-15 07:24:58 +00:00
/*maxsegsz*/AHC_MAXTRANSFER_SIZE,
/*flags*/BUS_DMA_ALLOCNOW,
&ahc->parent_dmat);
1998-09-15 07:24:58 +00:00
if (error != 0) {
printf("ahc_eisa_attach: Could not allocate DMA tag "
"- error %d\n", error);
ahc_free(ahc);
return (ENOMEM);
1998-09-15 07:24:58 +00:00
}
ahc->dev_softc = dev;
error = aic7770_config(ahc, entry);
if (error != 0) {
ahc_free(ahc);
return (error);
1998-09-15 07:24:58 +00:00
}
ahc_attach(ahc);
return (0);
1998-09-15 07:24:58 +00:00
}
int
aic7770_map_registers(struct ahc_softc *ahc)
1998-09-15 07:24:58 +00:00
{
struct resource *regs;
int rid;
1998-09-15 07:24:58 +00:00
regs = bus_alloc_resource(ahc->dev_softc, SYS_RES_IOPORT,
&rid, 0, ~0, 1, RF_ACTIVE);
if (regs == NULL) {
device_printf(ahc->dev_softc, "Unable to map I/O space?!\n");
return ENOMEM;
1998-09-15 07:24:58 +00:00
}
ahc->platform_data->regs_res_type = SYS_RES_IOPORT;
ahc->platform_data->regs_res_id = rid,
ahc->platform_data->regs = regs;
ahc->tag = rman_get_bustag(regs);
ahc->bsh = rman_get_bushandle(regs);
return (0);
}
1998-09-15 07:24:58 +00:00
int
aic7770_map_int(struct ahc_softc *ahc)
{
int zero;
zero = 0;
ahc->platform_data->irq =
bus_alloc_resource(ahc->dev_softc, SYS_RES_IRQ, &zero,
0, ~0, 1, RF_ACTIVE);
if (ahc->platform_data->irq == NULL)
return (ENOMEM);
ahc->platform_data->irq_res_type = SYS_RES_IRQ;
return (0);
1998-09-15 07:24:58 +00:00
}
static device_method_t ahc_eisa_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, aic7770_probe),
DEVMETHOD(device_attach, aic7770_attach),
{ 0, 0 }
};
static driver_t ahc_eisa_driver = {
"ahc",
ahc_eisa_methods,
1, /* unused */
};
static devclass_t ahc_devclass;
DRIVER_MODULE(ahc, eisa, ahc_eisa_driver, ahc_devclass, 0, 0);