Move aicasm to its own subdirectory.
Separate our platform independent hooks from core driver functionality shared between platforms (FreeBSD and Linux at this time). Add sequencer workarounds for several chip->chipset interactions. Correct external SCB corruption problem on aic7895 based cards (3940AUW). Lots of cleanups resulting from the port to another OS.
This commit is contained in:
parent
b4ec565e1f
commit
7691c1f500
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Interface for the 93C66/56/46/26/06 serial eeprom parts.
|
||||
*
|
||||
* Copyright (c) 1995, 1996 Daniel M. Eischen
|
||||
* 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. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Absolutely no warranty of function or purpose is made by the author
|
||||
* Daniel M. Eischen.
|
||||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* The instruction set of the 93C66/56/46/26/06 chips are as follows:
|
||||
*
|
||||
* Start OP *
|
||||
* Function Bit Code Address** Data Description
|
||||
* -------------------------------------------------------------------
|
||||
* READ 1 10 A5 - A0 Reads data stored in memory,
|
||||
* starting at specified address
|
||||
* EWEN 1 00 11XXXX Write enable must preceed
|
||||
* all programming modes
|
||||
* ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
|
||||
* WRITE 1 01 A5 - A0 D15 - D0 Writes register
|
||||
* ERAL 1 00 10XXXX Erase all registers
|
||||
* WRAL 1 00 01XXXX D15 - D0 Writes to all registers
|
||||
* EWDS 1 00 00XXXX Disables all programming
|
||||
* instructions
|
||||
* *Note: A value of X for address is a don't care condition.
|
||||
* **Note: There are 8 address bits for the 93C56/66 chips unlike
|
||||
* the 93C46/26/06 chips which have 6 address bits.
|
||||
*
|
||||
* The 93C46 has a four wire interface: clock, chip select, data in, and
|
||||
* data out. In order to perform one of the above functions, you need
|
||||
* to enable the chip select for a clock period (typically a minimum of
|
||||
* 1 usec, with the clock high and low a minimum of 750 and 250 nsec
|
||||
* respectively). While the chip select remains high, you can clock in
|
||||
* the instructions (above) starting with the start bit, followed by the
|
||||
* OP code, Address, and Data (if needed). For the READ instruction, the
|
||||
* requested 16-bit register contents is read from the data out line but
|
||||
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB
|
||||
* first). The clock cycling from low to high initiates the next data
|
||||
* bit to be sent from the chip.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opt_aic7xxx.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <machine/bus_memio.h>
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <dev/aic7xxx/93cx6.h>
|
||||
|
||||
/*
|
||||
* Right now, we only have to read the SEEPROM. But we make it easier to
|
||||
* add other 93Cx6 functions.
|
||||
*/
|
||||
static struct seeprom_cmd {
|
||||
unsigned char len;
|
||||
unsigned char bits[3];
|
||||
} seeprom_read = {3, {1, 1, 0}};
|
||||
|
||||
/*
|
||||
* Wait for the SEERDY to go high; about 800 ns.
|
||||
*/
|
||||
#define CLOCK_PULSE(sd, rdy) \
|
||||
while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \
|
||||
; /* Do nothing */ \
|
||||
} \
|
||||
(void)SEEPROM_INB(sd); /* Clear clock */
|
||||
|
||||
/*
|
||||
* Read the serial EEPROM and returns 1 if successful and 0 if
|
||||
* not successful.
|
||||
*/
|
||||
int
|
||||
read_seeprom(sd, buf, start_addr, count)
|
||||
struct seeprom_descriptor *sd;
|
||||
uint16_t *buf;
|
||||
bus_size_t start_addr;
|
||||
bus_size_t count;
|
||||
{
|
||||
int i = 0;
|
||||
u_int k = 0;
|
||||
uint16_t v;
|
||||
uint8_t temp;
|
||||
|
||||
/*
|
||||
* Read the requested registers of the seeprom. The loop
|
||||
* will range from 0 to count-1.
|
||||
*/
|
||||
for (k = start_addr; k < count + start_addr; k++) {
|
||||
/* Send chip select for one clock cycle. */
|
||||
temp = sd->sd_MS ^ sd->sd_CS;
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
|
||||
/*
|
||||
* Now we're ready to send the read command followed by the
|
||||
* address of the 16-bit register we want to read.
|
||||
*/
|
||||
for (i = 0; i < seeprom_read.len; i++) {
|
||||
if (seeprom_read.bits[i] != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if (seeprom_read.bits[i] != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
/* Send the 6 or 8 bit address (MSB first, LSB last). */
|
||||
for (i = (sd->sd_chip - 1); i >= 0; i--) {
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now read the 16 bit register. An initial 0 precedes the
|
||||
* register contents which begins with bit 15 (MSB) and ends
|
||||
* with bit 0 (LSB). The initial 0 will be shifted off the
|
||||
* top of our word as we let the loop run from 0 to 16.
|
||||
*/
|
||||
v = 0;
|
||||
for (i = 16; i >= 0; i--) {
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
v <<= 1;
|
||||
if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
|
||||
v |= 1;
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
}
|
||||
|
||||
buf[k - start_addr] = v;
|
||||
|
||||
/* Reset the chip select for the next command cycle. */
|
||||
temp = sd->sd_MS;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
}
|
||||
#ifdef AHC_DUMP_EEPROM
|
||||
printf("\nSerial EEPROM:\n\t");
|
||||
for (k = 0; k < count; k = k + 1) {
|
||||
if (((k % 8) == 0) && (k != 0)) {
|
||||
printf ("\n\t");
|
||||
}
|
||||
printf (" 0x%x", buf[k]);
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
return (1);
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Interface to the 93C46 serial EEPROM that is used to store BIOS
|
||||
* settings for the aic7xxx based adaptec SCSI controllers. It can
|
||||
* also be used for 93C26 and 93C06 serial EEPROMS.
|
||||
*
|
||||
* Copyright (c) 1994, 1995 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#if !defined(__NetBSD__)
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
typedef enum {
|
||||
C46 = 6,
|
||||
C56_66 = 8
|
||||
} seeprom_chip_t;
|
||||
|
||||
struct seeprom_descriptor {
|
||||
bus_space_tag_t sd_tag;
|
||||
bus_space_handle_t sd_bsh;
|
||||
bus_size_t sd_control_offset;
|
||||
bus_size_t sd_status_offset;
|
||||
bus_size_t sd_dataout_offset;
|
||||
seeprom_chip_t sd_chip;
|
||||
uint16_t sd_MS;
|
||||
uint16_t sd_RDY;
|
||||
uint16_t sd_CS;
|
||||
uint16_t sd_CK;
|
||||
uint16_t sd_DO;
|
||||
uint16_t sd_DI;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function will read count 16-bit words from the serial EEPROM and
|
||||
* return their value in buf. The port address of the aic7xxx serial EEPROM
|
||||
* control register is passed in as offset. The following parameters are
|
||||
* also passed in:
|
||||
*
|
||||
* CS - Chip select
|
||||
* CK - Clock
|
||||
* DO - Data out
|
||||
* DI - Data in
|
||||
* RDY - SEEPROM ready
|
||||
* MS - Memory port mode select
|
||||
*
|
||||
* A failed read attempt returns 0, and a successful read returns 1.
|
||||
*/
|
||||
|
||||
#define SEEPROM_INB(sd) \
|
||||
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset)
|
||||
#define SEEPROM_OUTB(sd, value) \
|
||||
bus_space_write_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset, value)
|
||||
#define SEEPROM_STATUS_INB(sd) \
|
||||
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_status_offset)
|
||||
#define SEEPROM_DATA_INB(sd) \
|
||||
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_dataout_offset)
|
||||
|
||||
int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
bus_size_t start_addr, bus_size_t count);
|
||||
|
||||
#endif /* _KERNEL */
|
@ -1,31 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= aicasm
|
||||
|
||||
CSRCS= aicasm.c aicasm_symbol.c
|
||||
GENSRCS= aicasm_gram.c aicasm_scan.c
|
||||
|
||||
GENHDRS= y.tab.h
|
||||
|
||||
SRCS= ${GENSRCS} ${CSRCS}
|
||||
CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output
|
||||
DPADD+= ${LIBL}
|
||||
LDADD+= -ll
|
||||
|
||||
# Correct path for kernel builds
|
||||
# Don't rely on the kernel's .depend file
|
||||
.ifdef MAKESRCPATH
|
||||
.PATH: ${MAKESRCPATH}
|
||||
DEPENDFILE=
|
||||
.endif
|
||||
|
||||
CFLAGS+= -nostdinc -I${.CURDIR}/../.. -I. -I/usr/include
|
||||
NOMAN= noman
|
||||
|
||||
.ifdef DEBUG
|
||||
CFLAGS+= -DDEBUG -g
|
||||
YFLAGS+= -t
|
||||
LFLAGS+= -d
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Product specific probe and attach routines for:
|
||||
* 27/284X and aic7770 motherboard SCSI controllers
|
||||
* FreeBSD, EISA product support functions
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1994, 1995, 1996, 1997, 1998 Justin T. Gibbs.
|
||||
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 2000 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -26,92 +26,60 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
|
||||
#include <dev/eisa/eisaconf.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_sim.h>
|
||||
#include <cam/cam_xpt_sim.h>
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
|
||||
#include <dev/aic7xxx/aic7xxx.h>
|
||||
#include <dev/aic7xxx/93cx6.h>
|
||||
|
||||
#include <aic7xxx_reg.h>
|
||||
|
||||
#define EISA_DEVICE_ID_ADAPTEC_AIC7770 0x04907770
|
||||
#define EISA_DEVICE_ID_ADAPTEC_274x 0x04907771
|
||||
#define EISA_DEVICE_ID_ADAPTEC_284xB 0x04907756 /* BIOS enabled */
|
||||
#define EISA_DEVICE_ID_ADAPTEC_284x 0x04907757 /* BIOS disabled*/
|
||||
|
||||
#define AHC_EISA_SLOT_OFFSET 0xc00
|
||||
#define AHC_EISA_IOSIZE 0x100
|
||||
#define INTDEF 0x5cul /* Interrupt Definition Register */
|
||||
|
||||
static void aha2840_load_seeprom(struct ahc_softc *ahc);
|
||||
|
||||
static const char *aic7770_match(eisa_id_t type);
|
||||
|
||||
static const char*
|
||||
aic7770_match(eisa_id_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case EISA_DEVICE_ID_ADAPTEC_AIC7770:
|
||||
return ("Adaptec aic7770 SCSI host adapter");
|
||||
break;
|
||||
case EISA_DEVICE_ID_ADAPTEC_274x:
|
||||
return ("Adaptec 274X SCSI host adapter");
|
||||
break;
|
||||
case EISA_DEVICE_ID_ADAPTEC_284xB:
|
||||
case EISA_DEVICE_ID_ADAPTEC_284x:
|
||||
return ("Adaptec 284X SCSI host adapter");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
aic7770_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
struct aic7770_identity *entry;
|
||||
struct resource *regs;
|
||||
uint32_t iobase;
|
||||
uint32_t irq;
|
||||
uint8_t intdef;
|
||||
uint8_t hcntrl;
|
||||
int shared;
|
||||
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;
|
||||
|
||||
desc = aic7770_match(eisa_get_id(dev));
|
||||
if (!desc)
|
||||
entry = aic7770_find_device(eisa_get_id(dev));
|
||||
if (entry == NULL)
|
||||
return (ENXIO);
|
||||
device_set_desc(dev, desc);
|
||||
device_set_desc(dev, entry->name);
|
||||
|
||||
iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + AHC_EISA_SLOT_OFFSET;
|
||||
|
||||
/* Pause the card preseving the IRQ type */
|
||||
hcntrl = inb(iobase + HCNTRL) & IRQMS;
|
||||
|
||||
outb(iobase + HCNTRL, hcntrl | PAUSE);
|
||||
|
||||
eisa_add_iospace(dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE);
|
||||
intdef = inb(INTDEF + iobase);
|
||||
shared = (intdef & 0x80) ? EISA_TRIGGER_EDGE : EISA_TRIGGER_LEVEL;
|
||||
irq = intdef & 0xf;
|
||||
|
||||
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:
|
||||
@ -119,342 +87,107 @@ aic7770_probe(device_t dev)
|
||||
case 12:
|
||||
case 14:
|
||||
case 15:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
printf("aic7770 at slot %d: illegal "
|
||||
"irq setting %d\n", eisa_get_slot(dev),
|
||||
intdef);
|
||||
irq = 0;
|
||||
break;
|
||||
printf("aic7770 at slot %d: illegal irq setting %d\n",
|
||||
eisa_get_slot(dev), intdef);
|
||||
error = ENXIO;
|
||||
}
|
||||
if (irq == 0)
|
||||
return ENXIO;
|
||||
|
||||
eisa_add_intr(dev, irq, shared);
|
||||
if (error == 0)
|
||||
eisa_add_intr(dev, irq, shared);
|
||||
|
||||
return 0;
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, rid, regs);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
aic7770_attach(device_t dev)
|
||||
{
|
||||
struct ahc_probe_config probe_config;
|
||||
bus_dma_tag_t parent_dmat;
|
||||
struct ahc_softc *ahc;
|
||||
struct resource *io;
|
||||
int error, rid;
|
||||
struct aic7770_identity *entry;
|
||||
struct ahc_softc *ahc;
|
||||
char *name;
|
||||
int error;
|
||||
|
||||
rid = 0;
|
||||
io = NULL;
|
||||
ahc = NULL;
|
||||
ahc_init_probe_config(&probe_config);
|
||||
switch (eisa_get_id(dev)) {
|
||||
case EISA_DEVICE_ID_ADAPTEC_274x:
|
||||
case EISA_DEVICE_ID_ADAPTEC_AIC7770:
|
||||
probe_config.chip = AHC_AIC7770|AHC_EISA;
|
||||
break;
|
||||
case EISA_DEVICE_ID_ADAPTEC_284xB:
|
||||
case EISA_DEVICE_ID_ADAPTEC_284x:
|
||||
probe_config.chip = AHC_AIC7770|AHC_VL;
|
||||
break;
|
||||
default:
|
||||
printf("aic7770_attach: Unknown device type!\n");
|
||||
goto bad;
|
||||
}
|
||||
entry = aic7770_find_device(eisa_get_id(dev));
|
||||
if (entry == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
probe_config.description = aic7770_match(eisa_get_id(dev));
|
||||
probe_config.channel = 'A';
|
||||
probe_config.channel_b = 'B';
|
||||
probe_config.features = AHC_AIC7770_FE;
|
||||
probe_config.bugs |= AHC_TMODE_WIDEODD_BUG;
|
||||
probe_config.flags |= AHC_PAGESCBS;
|
||||
/* XXX Should be a child of the EISA bus dma tag */
|
||||
/*
|
||||
* 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,
|
||||
/*boundary*/0,
|
||||
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||
/*filter*/NULL, /*filterarg*/NULL,
|
||||
/*maxsize*/MAXBSIZE,
|
||||
/*nsegments*/AHC_NSEG,
|
||||
/*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
|
||||
/*maxsegsz*/AHC_MAXTRANSFER_SIZE,
|
||||
/*flags*/BUS_DMA_ALLOCNOW, &parent_dmat);
|
||||
/*flags*/BUS_DMA_ALLOCNOW,
|
||||
&ahc->parent_dmat);
|
||||
|
||||
if (error != 0) {
|
||||
printf("ahc_eisa_attach: Could not allocate DMA tag "
|
||||
"- error %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (!io) {
|
||||
device_printf(dev, "No I/O space?!\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (!(ahc = ahc_alloc(dev, io, SYS_RES_IOPORT, rid,
|
||||
parent_dmat, &probe_config, NULL)))
|
||||
goto bad;
|
||||
|
||||
io = NULL;
|
||||
|
||||
if (ahc_reset(ahc) != 0) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* The IRQMS bit enables level sensitive interrupts. Only allow
|
||||
* IRQ sharing if it's set.
|
||||
*/
|
||||
rid = 0;
|
||||
ahc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (ahc->irq == NULL) {
|
||||
device_printf(dev, "Can't allocate interrupt\n");
|
||||
goto bad;
|
||||
}
|
||||
ahc->irq_res_type = SYS_RES_IRQ;
|
||||
|
||||
/*
|
||||
* Tell the user what type of interrupts we're using.
|
||||
* usefull for debugging irq problems
|
||||
*/
|
||||
if (bootverbose) {
|
||||
printf("%s: Using %s Interrupts\n",
|
||||
ahc_name(ahc),
|
||||
ahc->pause & IRQMS ?
|
||||
"Level Sensitive" : "Edge Triggered");
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we know we own the resources we need, do the
|
||||
* card initialization.
|
||||
*
|
||||
* First, the aic7770 card specific setup.
|
||||
*/
|
||||
switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
|
||||
case AHC_EISA:
|
||||
{
|
||||
u_int biosctrl;
|
||||
u_int scsiconf;
|
||||
u_int scsiconf1;
|
||||
#if DEBUG
|
||||
int i;
|
||||
#endif
|
||||
|
||||
biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
|
||||
scsiconf = ahc_inb(ahc, SCSICONF);
|
||||
scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
|
||||
|
||||
#if DEBUG
|
||||
for (i = TARG_SCSIRATE; i <= HA_274_BIOSCTRL; i+=8) {
|
||||
printf("0x%x, 0x%x, 0x%x, 0x%x, "
|
||||
"0x%x, 0x%x, 0x%x, 0x%x\n",
|
||||
ahc_inb(ahc, i),
|
||||
ahc_inb(ahc, i+1),
|
||||
ahc_inb(ahc, i+2),
|
||||
ahc_inb(ahc, i+3),
|
||||
ahc_inb(ahc, i+4),
|
||||
ahc_inb(ahc, i+5),
|
||||
ahc_inb(ahc, i+6),
|
||||
ahc_inb(ahc, i+7));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get the primary channel information */
|
||||
if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
|
||||
ahc->flags |= AHC_CHANNEL_B_PRIMARY;
|
||||
|
||||
if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
if ((ahc->features & AHC_WIDE) != 0) {
|
||||
ahc->our_id = scsiconf1 & HWSCSIID;
|
||||
if (scsiconf & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
} else {
|
||||
ahc->our_id = scsiconf & HSCSIID;
|
||||
ahc->our_id_b = scsiconf1 & HSCSIID;
|
||||
if (scsiconf & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
if (scsiconf1 & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_B;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We have no way to tell, so assume extended
|
||||
* translation is enabled.
|
||||
*/
|
||||
ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
|
||||
break;
|
||||
}
|
||||
case AHC_VL:
|
||||
{
|
||||
aha2840_load_seeprom(ahc);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if we have a Rev E or higher aic7770. Anything below a
|
||||
* Rev E will have a R/O autoflush disable configuration bit.
|
||||
*/
|
||||
{
|
||||
char *id_string;
|
||||
uint8_t sblkctl;
|
||||
uint8_t sblkctl_orig;
|
||||
|
||||
sblkctl_orig = ahc_inb(ahc, SBLKCTL);
|
||||
sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
|
||||
ahc_outb(ahc, SBLKCTL, sblkctl);
|
||||
sblkctl = ahc_inb(ahc, SBLKCTL);
|
||||
if (sblkctl != sblkctl_orig) {
|
||||
id_string = "aic7770 >= Rev E, ";
|
||||
/*
|
||||
* Ensure autoflush is enabled
|
||||
*/
|
||||
sblkctl &= ~AUTOFLUSHDIS;
|
||||
ahc_outb(ahc, SBLKCTL, sblkctl);
|
||||
|
||||
} else
|
||||
id_string = "aic7770 <= Rev C, ";
|
||||
|
||||
printf("%s: %s", ahc_name(ahc), id_string);
|
||||
}
|
||||
|
||||
/* Setup the FIFO threshold and the bus off time */
|
||||
{
|
||||
uint8_t hostconf = ahc_inb(ahc, HOSTCONF);
|
||||
ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
|
||||
ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic aic7xxx initialization.
|
||||
*/
|
||||
if (ahc_init(ahc)) {
|
||||
/*
|
||||
* The board's IRQ line is not yet enabled so it's safe
|
||||
* to release the irq.
|
||||
*/
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the board's BUS drivers
|
||||
*/
|
||||
ahc_outb(ahc, BCTL, ENABLE);
|
||||
|
||||
/* Attach sub-devices - always succeeds */
|
||||
ahc_attach(ahc);
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
if (ahc != NULL)
|
||||
ahc_free(ahc);
|
||||
|
||||
if (io != NULL)
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
|
||||
return (ENOMEM);
|
||||
}
|
||||
ahc->dev_softc = dev;
|
||||
error = aic7770_config(ahc, entry);
|
||||
if (error != 0) {
|
||||
ahc_free(ahc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return -1;
|
||||
ahc_attach(ahc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the 284x SEEPROM.
|
||||
*/
|
||||
static void
|
||||
aha2840_load_seeprom(struct ahc_softc *ahc)
|
||||
int
|
||||
aic7770_map_registers(struct ahc_softc *ahc)
|
||||
{
|
||||
struct seeprom_descriptor sd;
|
||||
struct seeprom_config sc;
|
||||
uint16_t checksum = 0;
|
||||
uint8_t scsi_conf;
|
||||
int have_seeprom;
|
||||
struct resource *regs;
|
||||
int rid;
|
||||
|
||||
sd.sd_tag = ahc->tag;
|
||||
sd.sd_bsh = ahc->bsh;
|
||||
sd.sd_control_offset = SEECTL_2840;
|
||||
sd.sd_status_offset = STATUS_2840;
|
||||
sd.sd_dataout_offset = STATUS_2840;
|
||||
sd.sd_chip = C46;
|
||||
sd.sd_MS = 0;
|
||||
sd.sd_RDY = EEPROM_TF;
|
||||
sd.sd_CS = CS_2840;
|
||||
sd.sd_CK = CK_2840;
|
||||
sd.sd_DO = DO_2840;
|
||||
sd.sd_DI = DI_2840;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Reading SEEPROM...", ahc_name(ahc));
|
||||
have_seeprom = read_seeprom(&sd,
|
||||
(uint16_t *)&sc,
|
||||
/*start_addr*/0,
|
||||
sizeof(sc)/2);
|
||||
|
||||
if (have_seeprom) {
|
||||
/* Check checksum */
|
||||
int i;
|
||||
int maxaddr = (sizeof(sc)/2) - 1;
|
||||
uint16_t *scarray = (uint16_t *)≻
|
||||
|
||||
for (i = 0; i < maxaddr; i++)
|
||||
checksum = checksum + scarray[i];
|
||||
if (checksum != sc.checksum) {
|
||||
if(bootverbose)
|
||||
printf ("checksum error\n");
|
||||
have_seeprom = 0;
|
||||
} else if (bootverbose) {
|
||||
printf("done.\n");
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
if (!have_seeprom) {
|
||||
if (bootverbose)
|
||||
printf("%s: No SEEPROM available\n", ahc_name(ahc));
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
/*
|
||||
* Put the data we've collected down into SRAM
|
||||
* where ahc_init will find it.
|
||||
*/
|
||||
int i;
|
||||
int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
|
||||
uint16_t discenable;
|
||||
int
|
||||
aic7770_map_int(struct ahc_softc *ahc)
|
||||
{
|
||||
int zero;
|
||||
|
||||
discenable = 0;
|
||||
for (i = 0; i < max_targ; i++){
|
||||
uint8_t target_settings;
|
||||
target_settings = (sc.device_flags[i] & CFXFER) << 4;
|
||||
if (sc.device_flags[i] & CFSYNCH)
|
||||
target_settings |= SOFS;
|
||||
if (sc.device_flags[i] & CFWIDEB)
|
||||
target_settings |= WIDEXFER;
|
||||
if (sc.device_flags[i] & CFDISC)
|
||||
discenable |= (0x01 << i);
|
||||
ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
|
||||
}
|
||||
ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
|
||||
ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
|
||||
|
||||
ahc->our_id = sc.brtime_id & CFSCSIID;
|
||||
|
||||
scsi_conf = (ahc->our_id & 0x7);
|
||||
if (sc.adapter_control & CFSPARITY)
|
||||
scsi_conf |= ENSPCHK;
|
||||
if (sc.adapter_control & CFRESETB)
|
||||
scsi_conf |= RESET_SCSI;
|
||||
|
||||
if (sc.bios_control & CF284XEXTEND)
|
||||
ahc->flags |= AHC_EXTENDED_TRANS_A;
|
||||
/* Set SCSICONF info */
|
||||
ahc_outb(ahc, SCSICONF, scsi_conf);
|
||||
|
||||
if (sc.adapter_control & CF284XSTERM)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static device_method_t ahc_eisa_methods[] = {
|
||||
|
File diff suppressed because it is too large
Load Diff
319
sys/dev/aic7xxx/aic7770.c
Normal file
319
sys/dev/aic7xxx/aic7770.c
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Product specific probe and attach routines for:
|
||||
* 27/284X and aic7770 motherboard SCSI controllers
|
||||
*
|
||||
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 2000 Justin T. Gibbs.
|
||||
* 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$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_linux.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
#define ID_AIC7770 0x04907770
|
||||
#define ID_AHA_274x 0x04907771
|
||||
#define ID_AHA_284xB 0x04907756 /* BIOS enabled */
|
||||
#define ID_AHA_284x 0x04907757 /* BIOS disabled*/
|
||||
|
||||
static void aha2840_load_seeprom(struct ahc_softc *ahc);
|
||||
static ahc_device_setup_t ahc_aic7770_VL_setup;
|
||||
static ahc_device_setup_t ahc_aic7770_EISA_setup;;
|
||||
static ahc_device_setup_t ahc_aic7770_setup;
|
||||
|
||||
|
||||
struct aic7770_identity aic7770_ident_table [] =
|
||||
{
|
||||
{
|
||||
ID_AHA_274x,
|
||||
0xFFFFFFFF,
|
||||
"Adaptec 274X SCSI adapter",
|
||||
ahc_aic7770_EISA_setup
|
||||
},
|
||||
{
|
||||
ID_AHA_284xB,
|
||||
0xFFFFFFFE,
|
||||
"Adaptec 284X SCSI adapter",
|
||||
ahc_aic7770_VL_setup
|
||||
},
|
||||
/* Generic chip probes for devices we don't know 'exactly' */
|
||||
{
|
||||
ID_AIC7770,
|
||||
0xFFFFFFFF,
|
||||
"Adaptec aic7770 SCSI adapter",
|
||||
ahc_aic7770_EISA_setup
|
||||
}
|
||||
};
|
||||
const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table);
|
||||
|
||||
struct aic7770_identity *
|
||||
aic7770_find_device(uint32_t id)
|
||||
{
|
||||
struct aic7770_identity *entry;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ahc_num_aic7770_devs; i++) {
|
||||
entry = &aic7770_ident_table[i];
|
||||
if (entry->full_id == (id & entry->id_mask))
|
||||
return (entry);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
|
||||
{
|
||||
struct ahc_probe_config probe_config;
|
||||
int error;
|
||||
u_int hostconf;
|
||||
|
||||
ahc_init_probe_config(&probe_config);
|
||||
error = entry->setup(ahc->dev_softc, &probe_config);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = aic7770_map_registers(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
probe_config.description = entry->name;
|
||||
error = ahc_softc_init(ahc, &probe_config);
|
||||
|
||||
error = aic7770_map_int(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = ahc_reset(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
|
||||
case AHC_EISA:
|
||||
{
|
||||
u_int biosctrl;
|
||||
u_int scsiconf;
|
||||
u_int scsiconf1;
|
||||
|
||||
biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
|
||||
scsiconf = ahc_inb(ahc, SCSICONF);
|
||||
scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
|
||||
|
||||
/* Get the primary channel information */
|
||||
if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
|
||||
ahc->flags |= AHC_CHANNEL_B_PRIMARY;
|
||||
|
||||
if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
if ((ahc->features & AHC_WIDE) != 0) {
|
||||
ahc->our_id = scsiconf1 & HWSCSIID;
|
||||
if (scsiconf & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
} else {
|
||||
ahc->our_id = scsiconf & HSCSIID;
|
||||
ahc->our_id_b = scsiconf1 & HSCSIID;
|
||||
if (scsiconf & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
if (scsiconf1 & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_B;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We have no way to tell, so assume extended
|
||||
* translation is enabled.
|
||||
*/
|
||||
ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
|
||||
break;
|
||||
}
|
||||
case AHC_VL:
|
||||
{
|
||||
aha2840_load_seeprom(ahc);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure autoflush is enabled
|
||||
*/
|
||||
ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
|
||||
|
||||
/* Setup the FIFO threshold and the bus off time */
|
||||
hostconf = ahc_inb(ahc, HOSTCONF);
|
||||
ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
|
||||
ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
|
||||
|
||||
/*
|
||||
* Generic aic7xxx initialization.
|
||||
*/
|
||||
error = ahc_init(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Enable the board's BUS drivers
|
||||
*/
|
||||
ahc_outb(ahc, BCTL, ENABLE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the 284x SEEPROM.
|
||||
*/
|
||||
static void
|
||||
aha2840_load_seeprom(struct ahc_softc *ahc)
|
||||
{
|
||||
struct seeprom_descriptor sd;
|
||||
struct seeprom_config sc;
|
||||
uint16_t checksum = 0;
|
||||
uint8_t scsi_conf;
|
||||
int have_seeprom;
|
||||
|
||||
sd.sd_ahc = ahc;
|
||||
sd.sd_control_offset = SEECTL_2840;
|
||||
sd.sd_status_offset = STATUS_2840;
|
||||
sd.sd_dataout_offset = STATUS_2840;
|
||||
sd.sd_chip = C46;
|
||||
sd.sd_MS = 0;
|
||||
sd.sd_RDY = EEPROM_TF;
|
||||
sd.sd_CS = CS_2840;
|
||||
sd.sd_CK = CK_2840;
|
||||
sd.sd_DO = DO_2840;
|
||||
sd.sd_DI = DI_2840;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Reading SEEPROM...", ahc_name(ahc));
|
||||
have_seeprom = read_seeprom(&sd,
|
||||
(uint16_t *)&sc,
|
||||
/*start_addr*/0,
|
||||
sizeof(sc)/2);
|
||||
|
||||
if (have_seeprom) {
|
||||
/* Check checksum */
|
||||
int i;
|
||||
int maxaddr = (sizeof(sc)/2) - 1;
|
||||
uint16_t *scarray = (uint16_t *)≻
|
||||
|
||||
for (i = 0; i < maxaddr; i++)
|
||||
checksum = checksum + scarray[i];
|
||||
if (checksum != sc.checksum) {
|
||||
if(bootverbose)
|
||||
printf ("checksum error\n");
|
||||
have_seeprom = 0;
|
||||
} else if (bootverbose) {
|
||||
printf("done.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_seeprom) {
|
||||
if (bootverbose)
|
||||
printf("%s: No SEEPROM available\n", ahc_name(ahc));
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
/*
|
||||
* Put the data we've collected down into SRAM
|
||||
* where ahc_init will find it.
|
||||
*/
|
||||
int i;
|
||||
int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
|
||||
uint16_t discenable;
|
||||
|
||||
discenable = 0;
|
||||
for (i = 0; i < max_targ; i++){
|
||||
uint8_t target_settings;
|
||||
target_settings = (sc.device_flags[i] & CFXFER) << 4;
|
||||
if (sc.device_flags[i] & CFSYNCH)
|
||||
target_settings |= SOFS;
|
||||
if (sc.device_flags[i] & CFWIDEB)
|
||||
target_settings |= WIDEXFER;
|
||||
if (sc.device_flags[i] & CFDISC)
|
||||
discenable |= (0x01 << i);
|
||||
ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
|
||||
}
|
||||
ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
|
||||
ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
|
||||
|
||||
ahc->our_id = sc.brtime_id & CFSCSIID;
|
||||
|
||||
scsi_conf = (ahc->our_id & 0x7);
|
||||
if (sc.adapter_control & CFSPARITY)
|
||||
scsi_conf |= ENSPCHK;
|
||||
if (sc.adapter_control & CFRESETB)
|
||||
scsi_conf |= RESET_SCSI;
|
||||
|
||||
if (sc.bios_control & CF284XEXTEND)
|
||||
ahc->flags |= AHC_EXTENDED_TRANS_A;
|
||||
/* Set SCSICONF info */
|
||||
ahc_outb(ahc, SCSICONF, scsi_conf);
|
||||
|
||||
if (sc.adapter_control & CF284XSTERM)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ahc_aic7770_setup(dev, probe_config);
|
||||
probe_config->chip |= AHC_VL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic7770_EISA_setup(ahc_dev_softc_t dev,
|
||||
struct ahc_probe_config *probe_config)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ahc_aic7770_setup(dev, probe_config);
|
||||
probe_config->chip |= AHC_EISA;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
|
||||
{
|
||||
probe_config->channel = 'A';
|
||||
probe_config->channel_b = 'B';
|
||||
probe_config->chip = AHC_AIC7770;
|
||||
probe_config->features = AHC_AIC7770_FE;
|
||||
probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
|
||||
probe_config->flags |= AHC_PAGESCBS;
|
||||
return (0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,8 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
@ -52,18 +54,6 @@
|
||||
* automatically consume the entries.
|
||||
*/
|
||||
|
||||
reset:
|
||||
clr SCSISIGO; /* De-assert BSY */
|
||||
mvi MSG_OUT, MSG_NOOP; /* No message to send */
|
||||
and SXFRCTL1, ~BITBUCKET;
|
||||
/* Always allow reselection */
|
||||
and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
/* Ensure that no DMA operations are in progress */
|
||||
clr CCSGCTL;
|
||||
clr CCSCBCTL;
|
||||
}
|
||||
|
||||
poll_for_work:
|
||||
call clear_target_state;
|
||||
and SXFRCTL0, ~SPIOEN;
|
||||
@ -82,7 +72,7 @@ poll_for_work_loop:
|
||||
*/
|
||||
xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
|
||||
test SSTAT0, SELDO|SELDI jnz selection;
|
||||
test SCSISEQ, ENSELO jnz poll_for_work_loop;
|
||||
xor SBLKCTL,SELBUSB; /* Toggle back */
|
||||
}
|
||||
cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
|
||||
test_queue:
|
||||
@ -119,7 +109,6 @@ dma_queued_scb:
|
||||
*/
|
||||
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
|
||||
mov RETURN_2 call dma_scb;
|
||||
|
||||
start_scb:
|
||||
/*
|
||||
* Place us on the waiting list in case our selection
|
||||
@ -133,7 +122,7 @@ start_waiting:
|
||||
*/
|
||||
mov SCBPTR, WAITING_SCBH;
|
||||
call start_selection;
|
||||
jmp poll_for_work;
|
||||
jmp poll_for_work_loop;
|
||||
|
||||
start_selection:
|
||||
if ((ahc->features & AHC_TWIN) != 0) {
|
||||
@ -708,6 +697,40 @@ idle_sg_avail:
|
||||
ret;
|
||||
}
|
||||
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
|
||||
/*
|
||||
* Calculate the trailing portion of this S/G segment that cannot
|
||||
* be transferred using memory write and invalidate PCI transactions.
|
||||
* XXX Can we optimize this for PCI writes only???
|
||||
*/
|
||||
calc_mwi_residual:
|
||||
/*
|
||||
* If the ending address is on a cacheline boundary,
|
||||
* there is no need for an extra segment.
|
||||
*/
|
||||
mov A, HCNT[0];
|
||||
add A, A, HADDR[0];
|
||||
and A, CACHESIZE_MASK;
|
||||
test A, 0xFF jz return;
|
||||
|
||||
/*
|
||||
* If the transfer is less than a cachline,
|
||||
* there is no need for an extra segment.
|
||||
*/
|
||||
test HCNT[1], 0xFF jnz calc_mwi_residual_final;
|
||||
test HCNT[2], 0xFF jnz calc_mwi_residual_final;
|
||||
add NONE, INVERTED_CACHESIZE_MASK, HCNT[0];
|
||||
jnc return;
|
||||
|
||||
calc_mwi_residual_final:
|
||||
mov MWI_RESIDUAL, A;
|
||||
not A;
|
||||
inc A;
|
||||
add HCNT[0], A;
|
||||
adc HCNT[1], -1;
|
||||
adc HCNT[2], -1 ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we re-enter the data phase after going through another phase, the
|
||||
* STCNT may have been cleared, so restore it from the residual field.
|
||||
@ -767,8 +790,11 @@ p_data:
|
||||
mvi DINDEX, SCB_RESIDUAL_DATACNT + 3;
|
||||
mvi SCB_DATACNT + 3 call bcopy_5;
|
||||
}
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
|
||||
call calc_mwi_residual;
|
||||
}
|
||||
and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
|
||||
and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
|
||||
and DATA_COUNT_ODD, 0x1, HCNT[0];
|
||||
|
||||
if ((ahc->features & AHC_ULTRA2) == 0) {
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
@ -792,7 +818,7 @@ data_phase_loop:
|
||||
and DMAPARAMS, ~(HDMAEN|SDMAEN);
|
||||
if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
bmov HCNT, ALLONES, 3;
|
||||
or SXFRCTL0, CLRCHN; /* Ensure FIFO empty */
|
||||
or SXFRCTL0, CLRCHN|CLRSTCNT;/* Ensure FIFO empty */
|
||||
} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov STCNT, ALLONES, 3;
|
||||
} else {
|
||||
@ -907,6 +933,10 @@ sgptr_fixup_done:
|
||||
clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
|
||||
} else {
|
||||
/* If we are the last SG block, tell the hardware. */
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
|
||||
&& ahc->pci_cachesize != 0) {
|
||||
test MWI_RESIDUAL, 0xFF jnz dma_mid_sg;
|
||||
}
|
||||
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
|
||||
if ((ahc->flags & AHC_TARGETMODE) != 0) {
|
||||
test SSTAT0, TARGET jz dma_last_sg;
|
||||
@ -952,13 +982,15 @@ dma_dmadone:
|
||||
and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
|
||||
dma_halt:
|
||||
/*
|
||||
* Some revisions of the aic7880 have a problem where, if the
|
||||
* Some revisions of the aic78XX have a problem where, if the
|
||||
* data fifo is full, but the PCI input latch is not empty,
|
||||
* HDMAEN cannot be cleared. The fix used here is to drain
|
||||
* the prefetched but unused data from the data fifo until
|
||||
* there is space for the input latch to drain.
|
||||
*/
|
||||
mov NONE, DFDAT;
|
||||
if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
|
||||
mov NONE, DFDAT;
|
||||
}
|
||||
test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
|
||||
|
||||
/* See if we have completed this last segment */
|
||||
@ -969,6 +1001,26 @@ dma_halt:
|
||||
/*
|
||||
* Advance the scatter-gather pointers if needed
|
||||
*/
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
|
||||
&& ahc->pci_cachesize != 0) {
|
||||
test MWI_RESIDUAL, 0xFF jz no_mwi_resid;
|
||||
/*
|
||||
* Reload HADDR from SHADDR and setup the
|
||||
* count to be the size of our residual.
|
||||
*/
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov HADDR, SHADDR, 4;
|
||||
mov HCNT, MWI_RESIDUAL;
|
||||
bmov HCNT[1], ALLZEROS, 2;
|
||||
} else {
|
||||
mvi DINDEX, HADDR;
|
||||
mvi SHADDR call bcopy_4;
|
||||
mov MWI_RESIDUAL call set_hcnt;
|
||||
}
|
||||
clr MWI_RESIDUAL;
|
||||
jmp sg_load_done;
|
||||
no_mwi_resid:
|
||||
}
|
||||
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
|
||||
or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
|
||||
jmp data_phase_finish;
|
||||
@ -985,8 +1037,8 @@ sg_load:
|
||||
call idle_loop;
|
||||
test CCSGCTL, CCSGEN jnz . - 1;
|
||||
bmov HADDR, CCSGRAM, 7;
|
||||
bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
|
||||
bmov STCNT, HCNT, 3;
|
||||
test CCSGRAM, SG_LAST_SEG jz . + 2;
|
||||
or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
|
||||
} else {
|
||||
mvi DINDEX, HADDR;
|
||||
mvi SCB_RESIDUAL_SGPTR call bcopy_4;
|
||||
@ -997,18 +1049,29 @@ sg_load:
|
||||
|
||||
call dma_finish;
|
||||
|
||||
mvi HADDR call dfdat_in_7;
|
||||
mvi DINDEX, HADDR;
|
||||
call dfdat_in_7;
|
||||
mov SCB_RESIDUAL_DATACNT[3], DFDAT;
|
||||
call set_stcnt_from_hcnt;
|
||||
}
|
||||
|
||||
/* Track odd'ness */
|
||||
test HCNT[0], 0x1 jz . + 2;
|
||||
xor DATA_COUNT_ODD, 0x1;
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
|
||||
&& ahc->pci_cachesize != 0) {
|
||||
call calc_mwi_residual;
|
||||
}
|
||||
|
||||
/* Point to the new next sg in memory */
|
||||
call sg_advance;
|
||||
|
||||
sg_load_done:
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov STCNT, HCNT, 3;
|
||||
} else {
|
||||
call set_stcnt_from_hcnt;
|
||||
}
|
||||
/* Track odd'ness */
|
||||
test HCNT[0], 0x1 jz . + 2;
|
||||
xor DATA_COUNT_ODD, 0x1;
|
||||
|
||||
if ((ahc->flags & AHC_TARGETMODE) != 0) {
|
||||
test SSTAT0, TARGET jnz data_phase_loop;
|
||||
}
|
||||
@ -1055,12 +1118,30 @@ data_phase_done:
|
||||
/* Kill off any pending prefetch */
|
||||
clr CCSGCTL;
|
||||
test CCSGCTL, CCSGEN jnz .;
|
||||
}
|
||||
|
||||
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
|
||||
&& ahc->pci_cachesize != 0) {
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
test MWI_RESIDUAL, 0xFF jz bmov_resid;
|
||||
}
|
||||
mov A, MWI_RESIDUAL;
|
||||
add SCB_RESIDUAL_DATACNT[0], A, STCNT[0];
|
||||
clr A;
|
||||
adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1];
|
||||
adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2];
|
||||
clr MWI_RESIDUAL;
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
jmp . + 2;
|
||||
bmov_resid:
|
||||
bmov SCB_RESIDUAL_DATACNT, STCNT, 3;
|
||||
}
|
||||
} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov SCB_RESIDUAL_DATACNT, STCNT, 3;
|
||||
} else {
|
||||
mov SCB_RESIDUAL_DATACNT[0],STCNT[0];
|
||||
mov SCB_RESIDUAL_DATACNT[1],STCNT[1];
|
||||
mov SCB_RESIDUAL_DATACNT[2],STCNT[2];
|
||||
mov SCB_RESIDUAL_DATACNT[0], STCNT[0];
|
||||
mov SCB_RESIDUAL_DATACNT[1], STCNT[1];
|
||||
mov SCB_RESIDUAL_DATACNT[2], STCNT[2];
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1108,7 +1189,7 @@ p_command:
|
||||
clr STCNT[2];
|
||||
}
|
||||
add NONE, -13, SCB_CDB_LEN;
|
||||
mvi SCB_CDB_STORE jnc p_command_embedded;
|
||||
mvi SCB_CDB_STORE jnc p_command_embedded;
|
||||
p_command_from_host:
|
||||
if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
bmov HADDR[0], SCB_CDB_PTR, 4;
|
||||
@ -1116,7 +1197,7 @@ p_command_from_host:
|
||||
} else {
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov HADDR[0], SCB_CDB_PTR, 4;
|
||||
bmov HCNT[0], STCNT[0], 3;
|
||||
bmov HCNT, STCNT, 3;
|
||||
} else {
|
||||
mvi DINDEX, HADDR;
|
||||
mvi SCB_CDB_PTR call bcopy_5;
|
||||
@ -1135,15 +1216,29 @@ p_command_embedded:
|
||||
clr HADDR[0];
|
||||
if ((ahc->features & AHC_ULTRA2) != 0) {
|
||||
mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
|
||||
} else {
|
||||
mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
|
||||
}
|
||||
if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
bmov DFDAT, SCB_CDB_STORE, 12;
|
||||
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
|
||||
} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
|
||||
if ((ahc->features & AHC_SCB_BTT) != 0) {
|
||||
/*
|
||||
* On the 7895 the data FIFO will
|
||||
* get corrupted if you try to dump
|
||||
* data from external SCB memory into
|
||||
* the FIFO while it is enabled. So,
|
||||
* fill the fifo and then enable SCSI
|
||||
* transfers.
|
||||
*/
|
||||
mvi DFCNTRL, (DIRECTION|FIFORESET);
|
||||
} else {
|
||||
mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
|
||||
}
|
||||
bmov DFDAT, SCB_CDB_STORE, 12;
|
||||
if ((ahc->features & AHC_SCB_BTT) != 0) {
|
||||
mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH);
|
||||
} else {
|
||||
or DFCNTRL, FIFOFLUSH;
|
||||
}
|
||||
} else {
|
||||
mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
|
||||
call copy_to_fifo_6;
|
||||
call copy_to_fifo_6;
|
||||
or DFCNTRL, FIFOFLUSH;
|
||||
@ -1437,11 +1532,11 @@ mesgin_rdptrs:
|
||||
* upon return. SCBPTR may be modified by this action.
|
||||
*/
|
||||
index_busy_target:
|
||||
shr SINDEX, 4;
|
||||
if ((ahc->features & AHC_SCB_BTT) != 0) {
|
||||
mov SCBPTR, SAVED_LUN;
|
||||
add SINDEX, SCB_64_BTT;
|
||||
} else {
|
||||
shr SINDEX, 4;
|
||||
add SINDEX, BUSY_TARGETS;
|
||||
}
|
||||
mov DINDEX, SINDEX ret;
|
||||
@ -1629,6 +1724,7 @@ assert:
|
||||
* preceding SCB in the disconnected list which can be used to speed up
|
||||
* removal of the found SCB from the disconnected list.
|
||||
*/
|
||||
if ((ahc->flags & AHC_PAGESCBS) != 0) {
|
||||
findSCB:
|
||||
mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */
|
||||
mov A, SINDEX; /* Tag passed in SINDEX */
|
||||
@ -1654,6 +1750,7 @@ findSCB_notFound:
|
||||
/* Jump instead of call as we want to return anyway */
|
||||
test SCB_CONTROL, DISCONNECTED jnz add_scb_to_disc_list;
|
||||
jmp add_scb_to_free_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine expects SINDEX to contain the index of the SCB to be
|
||||
@ -1822,17 +1919,27 @@ dma_scb:
|
||||
mvi HSCB_ADDR call set_64byte_addr;
|
||||
mov CCSCBPTR, SCBPTR;
|
||||
test DMAPARAMS, DIRECTION jz dma_scb_tohost;
|
||||
mvi CCHCNT, SCB_64BYTE_SIZE;
|
||||
if ((ahc->features & AHC_SCB_BTT) != 0) {
|
||||
mvi CCHCNT, SCB_DOWNLOAD_SIZE_64;
|
||||
} else {
|
||||
mvi CCHCNT, SCB_DOWNLOAD_SIZE;
|
||||
}
|
||||
mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
|
||||
cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
|
||||
jmp dma_scb_finish;
|
||||
dma_scb_tohost:
|
||||
mvi CCHCNT, SCB_32BYTE_SIZE;
|
||||
if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
|
||||
mvi CCHCNT, SCB_UPLOAD_SIZE;
|
||||
if ((ahc->features & AHC_ULTRA2) == 0) {
|
||||
mvi CCSCBCTL, CCSCBRESET;
|
||||
bmov CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE;
|
||||
bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE;
|
||||
or CCSCBCTL, CCSCBEN|CCSCBRESET;
|
||||
test CCSCBCTL, CCSCBDONE jz .;
|
||||
} else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) {
|
||||
mvi CCSCBCTL, CCARREN|CCSCBRESET;
|
||||
cmp CCSCBCTL, ARRDONE|CCARREN jne .;
|
||||
mvi CCHCNT, SCB_UPLOAD_SIZE;
|
||||
mvi CCSCBCTL, CCSCBEN|CCSCBRESET;
|
||||
cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
|
||||
} else {
|
||||
mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
|
||||
cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
|
||||
@ -1844,39 +1951,90 @@ dma_scb_finish:
|
||||
} else {
|
||||
mvi DINDEX, HADDR;
|
||||
mvi HSCB_ADDR call set_64byte_addr;
|
||||
mvi SCB_32BYTE_SIZE call set_hcnt;
|
||||
mvi SCB_DOWNLOAD_SIZE call set_hcnt;
|
||||
mov DFCNTRL, DMAPARAMS;
|
||||
test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
|
||||
/* Fill it with the SCB data */
|
||||
copy_scb_tofifo:
|
||||
mvi SINDEX, SCB_CONTROL;
|
||||
add A, SCB_32BYTE_SIZE, SINDEX;
|
||||
mvi SINDEX, SCB_BASE;
|
||||
add A, SCB_DOWNLOAD_SIZE, SINDEX;
|
||||
copy_scb_tofifo_loop:
|
||||
call copy_to_fifo_6;
|
||||
call copy_to_fifo_8;
|
||||
cmp SINDEX, A jne copy_scb_tofifo_loop;
|
||||
or DFCNTRL, HDMAEN|FIFOFLUSH;
|
||||
jmp dma_finish;
|
||||
dma_scb_fromhost:
|
||||
call dma_finish;
|
||||
/* If we were putting the SCB, we are done */
|
||||
test DMAPARAMS, DIRECTION jz return;
|
||||
mvi SCB_CONTROL call dfdat_in_7;
|
||||
call dfdat_in_7_continued;
|
||||
call dfdat_in_7_continued;
|
||||
call dfdat_in_7_continued;
|
||||
jmp dfdat_in_2_continued;
|
||||
mvi DINDEX, SCB_BASE;
|
||||
if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
|
||||
/*
|
||||
* The PCI module will only issue a PCI
|
||||
* retry if the data FIFO is empty. If the
|
||||
* host disconnects in the middle of a
|
||||
* transfer, we must empty the fifo of all
|
||||
* available data to force the chip to
|
||||
* continue the transfer. This does not
|
||||
* happen for SCSI transfers as the SCSI module
|
||||
* will drain the FIFO as data is made available.
|
||||
* When the hang occurs, we know that at least
|
||||
* 8 bytes are in the FIFO because the PCI
|
||||
* module has an 8 byte input latch that only
|
||||
* dumps to the FIFO when HCNT == 0 or the
|
||||
* latch is full.
|
||||
*/
|
||||
mvi A, -24;
|
||||
/* Wait for some data to arrive. */
|
||||
dma_scb_hang_fifo:
|
||||
test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo;
|
||||
dma_scb_hang_wait:
|
||||
test DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
|
||||
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
|
||||
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
|
||||
test DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
|
||||
/*
|
||||
* The PCI no longer intends to perform a PCI
|
||||
* transaction and HDONE has not come true.
|
||||
* We are hung. Drain the fifo.
|
||||
*/
|
||||
dma_scb_hang_empty_fifo:
|
||||
call dfdat_in_8;
|
||||
add A, 8;
|
||||
add SINDEX, A, HCNT;
|
||||
/*
|
||||
* The result will be <= 0 (carry set) if at
|
||||
* least 8 bytes of data have been placed
|
||||
* into the fifo.
|
||||
*/
|
||||
jc dma_scb_hang_empty_fifo;
|
||||
jmp dma_scb_hang_fifo;
|
||||
dma_scb_hang_dma_done:
|
||||
and DFCNTRL, ~HDMAEN;
|
||||
test DFCNTRL, HDMAEN jnz .;
|
||||
call dfdat_in_8;
|
||||
add A, 8;
|
||||
cmp A, 8 jne . - 2;
|
||||
} else {
|
||||
call dma_finish;
|
||||
/* If we were putting the SCB, we are done */
|
||||
call dfdat_in_8;
|
||||
call dfdat_in_8;
|
||||
call dfdat_in_8;
|
||||
}
|
||||
dfdat_in_8:
|
||||
mov DINDIR,DFDAT;
|
||||
dfdat_in_7:
|
||||
mov DINDEX,SINDEX;
|
||||
dfdat_in_7_continued:
|
||||
mov DINDIR,DFDAT;
|
||||
mov DINDIR,DFDAT;
|
||||
mov DINDIR,DFDAT;
|
||||
mov DINDIR,DFDAT;
|
||||
mov DINDIR,DFDAT;
|
||||
dfdat_in_2_continued:
|
||||
dfdat_in_2:
|
||||
mov DINDIR,DFDAT;
|
||||
mov DINDIR,DFDAT ret;
|
||||
}
|
||||
|
||||
copy_to_fifo_8:
|
||||
mov DFDAT,SINDIR;
|
||||
mov DFDAT,SINDIR;
|
||||
copy_to_fifo_6:
|
||||
mov DFDAT,SINDIR;
|
||||
copy_to_fifo_5:
|
||||
@ -1923,7 +2081,6 @@ unlink_disc_scb:
|
||||
dequeue_free_scb:
|
||||
mov SCBPTR, FREE_SCBH;
|
||||
mov FREE_SCBH, SCB_NEXT ret;
|
||||
}
|
||||
|
||||
add_scb_to_disc_list:
|
||||
/*
|
||||
@ -1933,5 +2090,6 @@ add_scb_to_disc_list:
|
||||
*/
|
||||
mov SCB_NEXT, DISCONNECTED_SCBH;
|
||||
mov DISCONNECTED_SCBH, SCBPTR ret;
|
||||
}
|
||||
return:
|
||||
ret;
|
||||
|
@ -8,15 +8,27 @@
|
||||
* 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. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Absolutely no warranty of function or purpose is made by the author
|
||||
* Daniel M. Eischen.
|
||||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
* 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -55,22 +67,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opt_aic7xxx.h"
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_linux.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <machine/bus_memio.h>
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <dev/aic7xxx/93cx6.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <dev/aic7xxx/aic7xxx_freebsd.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Right now, we only have to read the SEEPROM. But we make it easier to
|
||||
* add other 93Cx6 functions.
|
||||
*/
|
||||
static struct seeprom_cmd {
|
||||
unsigned char len;
|
||||
unsigned char bits[3];
|
||||
uint8_t len;
|
||||
uint8_t bits[3];
|
||||
} seeprom_read = {3, {1, 1, 0}};
|
||||
|
||||
/*
|
||||
@ -90,8 +105,8 @@ int
|
||||
read_seeprom(sd, buf, start_addr, count)
|
||||
struct seeprom_descriptor *sd;
|
||||
uint16_t *buf;
|
||||
bus_size_t start_addr;
|
||||
bus_size_t count;
|
||||
u_int start_addr;
|
||||
u_int count;
|
||||
{
|
||||
int i = 0;
|
||||
u_int k = 0;
|
||||
@ -174,3 +189,25 @@ read_seeprom(sd, buf, start_addr, count)
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
verify_cksum(struct seeprom_config *sc)
|
||||
{
|
||||
int i;
|
||||
int maxaddr;
|
||||
uint32_t checksum;
|
||||
uint16_t *scarray;
|
||||
|
||||
maxaddr = (sizeof(*sc)/2) - 1;
|
||||
checksum = 0;
|
||||
scarray = (uint16_t *)sc;
|
||||
|
||||
for (i = 0; i < maxaddr; i++)
|
||||
checksum = checksum + scarray[i];
|
||||
if (checksum == 0
|
||||
|| (checksum & 0xFFFF) != sc->checksum) {
|
||||
return (0);
|
||||
} else {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Interface to the 93C46 serial EEPROM that is used to store BIOS
|
||||
* Interface to the 93C46/56 serial EEPROM that is used to store BIOS
|
||||
* settings for the aic7xxx based adaptec SCSI controllers. It can
|
||||
* also be used for 93C26 and 93C06 serial EEPROMS.
|
||||
*
|
||||
* Copyright (c) 1994, 1995 Justin T. Gibbs.
|
||||
* Copyright (c) 1994, 1995, 2000 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -30,15 +30,12 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#if !defined(__NetBSD__)
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
|
||||
#ifdef _KERNEL
|
||||
#ifndef _AIC7XXX_93CX6_H_
|
||||
#define _AIC7XXX_93CX6_H_
|
||||
|
||||
typedef enum {
|
||||
C46 = 6,
|
||||
@ -46,11 +43,10 @@ typedef enum {
|
||||
} seeprom_chip_t;
|
||||
|
||||
struct seeprom_descriptor {
|
||||
bus_space_tag_t sd_tag;
|
||||
bus_space_handle_t sd_bsh;
|
||||
bus_size_t sd_control_offset;
|
||||
bus_size_t sd_status_offset;
|
||||
bus_size_t sd_dataout_offset;
|
||||
struct ahc_softc *sd_ahc;
|
||||
u_int sd_control_offset;
|
||||
u_int sd_status_offset;
|
||||
u_int sd_dataout_offset;
|
||||
seeprom_chip_t sd_chip;
|
||||
uint16_t sd_MS;
|
||||
uint16_t sd_RDY;
|
||||
@ -77,15 +73,20 @@ struct seeprom_descriptor {
|
||||
*/
|
||||
|
||||
#define SEEPROM_INB(sd) \
|
||||
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset)
|
||||
#define SEEPROM_OUTB(sd, value) \
|
||||
bus_space_write_1(sd->sd_tag, sd->sd_bsh, sd->sd_control_offset, value)
|
||||
ahc_inb(sd->sd_ahc, sd->sd_control_offset)
|
||||
#define SEEPROM_OUTB(sd, value) \
|
||||
do { \
|
||||
ahc_outb(sd->sd_ahc, sd->sd_control_offset, value); \
|
||||
ahc_flush_device_writes(sd->sd_ahc); \
|
||||
} while(0)
|
||||
|
||||
#define SEEPROM_STATUS_INB(sd) \
|
||||
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_status_offset)
|
||||
ahc_inb(sd->sd_ahc, sd->sd_status_offset)
|
||||
#define SEEPROM_DATA_INB(sd) \
|
||||
bus_space_read_1(sd->sd_tag, sd->sd_bsh, sd->sd_dataout_offset)
|
||||
ahc_inb(sd->sd_ahc, sd->sd_dataout_offset)
|
||||
|
||||
int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
bus_size_t start_addr, bus_size_t count);
|
||||
u_int start_addr, u_int count);
|
||||
int verify_cksum(struct seeprom_config *sc);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _AIC7XXX_93CX6_H_ */
|
||||
|
1823
sys/dev/aic7xxx/aic7xxx_freebsd.c
Normal file
1823
sys/dev/aic7xxx/aic7xxx_freebsd.c
Normal file
File diff suppressed because it is too large
Load Diff
451
sys/dev/aic7xxx/aic7xxx_freebsd.h
Normal file
451
sys/dev/aic7xxx/aic7xxx_freebsd.h
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* FreeBSD platform specific driver option settings, data structures,
|
||||
* function declarations and includes.
|
||||
*
|
||||
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_FREEBSD_H_
|
||||
#define _AIC7XXX_FREEBSD_H_
|
||||
|
||||
#include <opt_aic7xxx.h> /* for config options */
|
||||
#include <pci.h> /* for NPCI */
|
||||
|
||||
#include <stddef.h> /* For offsetof */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h> /* For device_t */
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#if NPCI > 0
|
||||
#define AHC_SUPPORT_PCI 1
|
||||
#include <machine/bus_memio.h>
|
||||
#endif
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <sys/rman.h>
|
||||
|
||||
#if NPCI > 0
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
#endif
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_debug.h>
|
||||
#include <cam/cam_sim.h>
|
||||
#include <cam/cam_xpt_sim.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
|
||||
/****************************** Platform Macros *******************************/
|
||||
#define SIM_IS_SCSIBUS_B(ahc, sim) \
|
||||
((sim) == ahc->platform_data->sim_b)
|
||||
#define SIM_CHANNEL(ahc, sim) \
|
||||
(((sim) == ahc->platform_data->sim_b) ? 'B' : 'A')
|
||||
#define SIM_SCSI_ID(ahc, sim) \
|
||||
(((sim) == ahc->platform_data->sim_b) ? ahc->our_id_b : ahc->our_id)
|
||||
#define SIM_PATH(ahc, sim) \
|
||||
(((sim) == ahc->platform_data->sim_b) ? ahc->platform_data->path_b \
|
||||
: ahc->platform_data->path)
|
||||
#define BUILD_SCSIID(ahc, sim, target_id, our_id) \
|
||||
((((target_id) << TID_SHIFT) & TID) | (our_id) \
|
||||
| (SIM_IS_SCSIBUS_B(ahc, sim) ? TWIN_CHNLB : 0))
|
||||
|
||||
#define SCB_GET_SIM(ahc, scb) \
|
||||
(SCB_GET_CHANNEL(ahc, scb) == 'A' ? (ahc)->platform_data->sim \
|
||||
: (ahc)->platform_data->sim_b)
|
||||
|
||||
/************************* Forward Declarations *******************************/
|
||||
typedef device_t ahc_dev_softc_t;
|
||||
typedef union ccb *ahc_io_ctx_t;
|
||||
|
||||
/***************************** Bus Space/DMA **********************************/
|
||||
#define ahc_dma_tag_create(ahc, parent_tag, alignment, boundary, \
|
||||
lowaddr, highaddr, filter, filterarg, \
|
||||
maxsize, nsegments, maxsegsz, flags, \
|
||||
dma_tagp) \
|
||||
bus_dma_tag_create(parent_tag, alignment, boundary, \
|
||||
lowaddr, highaddr, filter, filterarg, \
|
||||
maxsize, nsegments, maxsegsz, flags, \
|
||||
dma_tagp)
|
||||
|
||||
#define ahc_dma_tag_destroy(ahc, tag) \
|
||||
bus_dma_tag_destroy(tag)
|
||||
|
||||
#define ahc_dmamem_alloc(ahc, dmat, vaddr, flags, mapp) \
|
||||
bus_dmamem_alloc(dmat, vaddr, flags, mapp)
|
||||
|
||||
#define ahc_dmamem_free(ahc, dmat, vaddr, map) \
|
||||
bus_dmamem_free(dmat, vaddr, map)
|
||||
|
||||
#define ahc_dmamap_create(ahc, tag, flags, mapp) \
|
||||
bus_dmamap_create(tag, flags, mapp)
|
||||
|
||||
#define ahc_dmamap_destroy(ahc, tag, map) \
|
||||
bus_dmamap_destroy(tag, map)
|
||||
|
||||
#define ahc_dmamap_load(ahc, dmat, map, addr, buflen, callback, \
|
||||
callback_arg, flags) \
|
||||
bus_dmamap_load(dmat, map, addr, buflen, callback, callback_arg, flags)
|
||||
|
||||
#define ahc_dmamap_unload(ahc, tag, map) \
|
||||
bus_dmamap_unload(tag, map)
|
||||
|
||||
#define ahc_dmamap_sync(ahc, dma_tag, dmamap, op) \
|
||||
bus_dmamap_sync(dma_tag_dmamap, op)
|
||||
|
||||
/************************ Tunable Driver Parameters **************************/
|
||||
/*
|
||||
* The number of dma segments supported. The sequencer can handle any number
|
||||
* of physically contiguous S/G entrys. To reduce the driver's memory
|
||||
* consumption, we limit the number supported to be sufficient to handle
|
||||
* the largest mapping supported by the kernel, MAXPHYS. Assuming the
|
||||
* transfer is as fragmented as possible and unaligned, this turns out to
|
||||
* be the number of paged sized transfers in MAXPHYS plus an extra element
|
||||
* to handle any unaligned residual. The sequencer fetches SG elements
|
||||
* in 128 byte chucks, so make the number per-transaction a nice multiple
|
||||
* of 16 (8 byte S/G elements).
|
||||
*/
|
||||
/* XXX Worth the space??? */
|
||||
#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
|
||||
|
||||
/* This driver supports target mode */
|
||||
#define AHC_TARGET_MODE 1
|
||||
|
||||
/************************** Softc/SCB Platform Data ***************************/
|
||||
struct ahc_platform_data {
|
||||
/*
|
||||
* Hooks into the XPT.
|
||||
*/
|
||||
struct cam_sim *sim;
|
||||
struct cam_sim *sim_b;
|
||||
struct cam_path *path;
|
||||
struct cam_path *path_b;
|
||||
|
||||
int regs_res_type;
|
||||
int regs_res_id;
|
||||
int irq_res_type;
|
||||
struct resource *regs;
|
||||
struct resource *irq;
|
||||
void *ih;
|
||||
};
|
||||
|
||||
struct scb_platform_data {
|
||||
};
|
||||
|
||||
/***************************** Core Includes **********************************/
|
||||
#include <dev/aic7xxx/aic7xxx.h>
|
||||
|
||||
/*************************** Device Access ************************************/
|
||||
#define ahc_inb(ahc, port) \
|
||||
bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
|
||||
|
||||
#define ahc_outb(ahc, port, value) \
|
||||
bus_space_write_1((ahc)->tag, (ahc)->bsh, port, value)
|
||||
|
||||
#define ahc_outsb(ahc, port, valp, count) \
|
||||
bus_space_write_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
|
||||
|
||||
#define ahc_insb(ahc, port, valp, count) \
|
||||
bus_space_read_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
|
||||
|
||||
static __inline void ahc_flush_device_writes(struct ahc_softc *);
|
||||
|
||||
static __inline void
|
||||
ahc_flush_device_writes(struct ahc_softc *ahc)
|
||||
{
|
||||
/* XXX Is this sufficient for all architectures??? */
|
||||
ahc_inb(ahc, INTSTAT);
|
||||
}
|
||||
|
||||
/**************************** Locking Primitives ******************************/
|
||||
/* Lock protecting internal data structures */
|
||||
static __inline void ahc_lockinit(struct ahc_softc *);
|
||||
static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags);
|
||||
static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags);
|
||||
|
||||
/* Lock held during command compeletion to the upper layer */
|
||||
static __inline void ahc_done_lockinit(struct ahc_softc *);
|
||||
static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags);
|
||||
static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags);
|
||||
|
||||
static __inline void
|
||||
ahc_lockinit(struct ahc_softc *ahc)
|
||||
{
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
*flags = splcam();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
splx(*flags);
|
||||
}
|
||||
|
||||
/* Lock held during command compeletion to the upper layer */
|
||||
static __inline void
|
||||
ahc_done_lockinit(struct ahc_softc *ahc)
|
||||
{
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************** OS Primitives *********************************/
|
||||
#define ahc_delay DELAY
|
||||
|
||||
/************************** Transaction Operations ****************************/
|
||||
static __inline void ahc_set_transaction_status(struct scb *, uint32_t);
|
||||
static __inline void ahc_set_scsi_status(struct scb *, uint32_t);
|
||||
static __inline uint32_t ahc_get_transaction_status(struct scb *);
|
||||
static __inline uint32_t ahc_get_scsi_status(struct scb *);
|
||||
static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
|
||||
static __inline u_long ahc_get_transfer_length(struct scb *);
|
||||
static __inline int ahc_get_transfer_dir(struct scb *);
|
||||
static __inline void ahc_set_residual(struct scb *, u_long);
|
||||
static __inline void ahc_set_sense_residual(struct scb *, u_long);
|
||||
static __inline u_long ahc_get_residual(struct scb *);
|
||||
static __inline int ahc_perform_autosense(struct scb *);
|
||||
static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc*, struct scb*);
|
||||
static __inline void ahc_freeze_ccb(union ccb *ccb);
|
||||
static __inline void ahc_freeze_scb(struct scb *scb);
|
||||
static __inline void ahc_platform_freeze_devq(struct ahc_softc *, struct scb *);
|
||||
static __inline int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status);
|
||||
|
||||
static __inline
|
||||
void ahc_set_transaction_status(struct scb *scb, uint32_t status)
|
||||
{
|
||||
scb->io_ctx->ccb_h.status &= ~CAM_STATUS_MASK;
|
||||
scb->io_ctx->ccb_h.status |= status;
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_scsi_status(struct scb *scb, uint32_t status)
|
||||
{
|
||||
scb->io_ctx->csio.scsi_status = status;
|
||||
}
|
||||
|
||||
static __inline
|
||||
uint32_t ahc_get_transaction_status(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->ccb_h.status & CAM_STATUS_MASK);
|
||||
}
|
||||
|
||||
static __inline
|
||||
uint32_t ahc_get_scsi_status(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->csio.scsi_status);
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type)
|
||||
{
|
||||
scb->io_ctx->csio.tag_action = type;
|
||||
if (enabled)
|
||||
scb->io_ctx->ccb_h.flags |= CAM_TAG_ACTION_VALID;
|
||||
else
|
||||
scb->io_ctx->ccb_h.flags &= ~CAM_TAG_ACTION_VALID;
|
||||
}
|
||||
|
||||
static __inline
|
||||
u_long ahc_get_transfer_length(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->csio.dxfer_len);
|
||||
}
|
||||
|
||||
static __inline
|
||||
int ahc_get_transfer_dir(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->ccb_h.flags & CAM_DIR_MASK);
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_residual(struct scb *scb, u_long resid)
|
||||
{
|
||||
scb->io_ctx->csio.resid = resid;
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_sense_residual(struct scb *scb, u_long resid)
|
||||
{
|
||||
scb->io_ctx->csio.sense_resid = resid;
|
||||
}
|
||||
|
||||
static __inline
|
||||
u_long ahc_get_residual(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->csio.resid);
|
||||
}
|
||||
|
||||
static __inline
|
||||
int ahc_perform_autosense(struct scb *scb)
|
||||
{
|
||||
return (!(scb->io_ctx->ccb_h.flags & CAM_DIS_AUTOSENSE));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
return (sizeof(struct scsi_sense_data));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_freeze_ccb(union ccb *ccb)
|
||||
{
|
||||
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
|
||||
ccb->ccb_h.status |= CAM_DEV_QFRZN;
|
||||
xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_freeze_scb(struct scb *scb)
|
||||
{
|
||||
ahc_freeze_ccb(scb->io_ctx);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
/* Nothing to do here for FreeBSD */
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status)
|
||||
{
|
||||
/* Nothing to do here for FreeBSD */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/********************************** PCI ***************************************/
|
||||
#ifdef AHC_SUPPORT_PCI
|
||||
static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
|
||||
int reg, int width);
|
||||
static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
|
||||
int reg, uint32_t value,
|
||||
int width);
|
||||
static __inline int ahc_get_pci_function(ahc_dev_softc_t);
|
||||
static __inline int ahc_get_pci_slot(ahc_dev_softc_t);
|
||||
static __inline int ahc_get_pci_bus(ahc_dev_softc_t);
|
||||
|
||||
int ahc_pci_map_registers(struct ahc_softc *ahc);
|
||||
int ahc_pci_map_int(struct ahc_softc *ahc);
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
|
||||
{
|
||||
return (pci_read_config(pci, reg, width));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
|
||||
{
|
||||
pci_write_config(pci, reg, value, width);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_get_pci_function(ahc_dev_softc_t pci)
|
||||
{
|
||||
return (pci_get_function(pci));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_get_pci_slot(ahc_dev_softc_t pci)
|
||||
{
|
||||
return (pci_get_slot(pci));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_get_pci_bus(ahc_dev_softc_t pci)
|
||||
{
|
||||
return (pci_get_bus(pci));
|
||||
}
|
||||
#endif
|
||||
/******************************** VL/EISA *************************************/
|
||||
int aic7770_map_registers(struct ahc_softc *ahc);
|
||||
int aic7770_map_int(struct ahc_softc *ahc);
|
||||
|
||||
/********************************* Debug **************************************/
|
||||
static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
|
||||
static __inline void ahc_platform_dump_card_state(struct ahc_softc *ahc);
|
||||
|
||||
static __inline void
|
||||
ahc_print_path(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
xpt_print_path(scb->io_ctx->ccb_h.path);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_platform_dump_card_state(struct ahc_softc *ahc)
|
||||
{
|
||||
/* Nothing to do here for FreeBSD */
|
||||
}
|
||||
/**************************** Transfer Settings *******************************/
|
||||
void ahc_notify_xfer_settings_change(struct ahc_softc *,
|
||||
struct ahc_devinfo *);
|
||||
void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *,
|
||||
int /*enable*/);
|
||||
|
||||
/***************************** Initialization *********************************/
|
||||
int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
|
||||
void ahc_platform_free(struct ahc_softc *ahc);
|
||||
int ahc_attach(struct ahc_softc *);
|
||||
int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
|
||||
|
||||
/************************ Misc Function Declarations **************************/
|
||||
timeout_t ahc_timeout;
|
||||
void ahc_done(struct ahc_softc *ahc, struct scb *scb);
|
||||
void ahc_send_async(struct ahc_softc *, struct ahc_devinfo *, ac_code);
|
||||
#endif /* _AIC7XXX_FREEBSD_H_ */
|
366
sys/dev/aic7xxx/aic7xxx_inline.h
Normal file
366
sys/dev/aic7xxx/aic7xxx_inline.h
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Inline routines shareable across OS platforms.
|
||||
*
|
||||
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_INLINE_H_
|
||||
#define _AIC7XXX_INLINE_H_
|
||||
|
||||
/************************* Sequencer Execution Control ************************/
|
||||
static __inline int sequencer_paused(struct ahc_softc *ahc);
|
||||
static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
|
||||
static __inline void pause_sequencer(struct ahc_softc *ahc);
|
||||
static __inline void unpause_sequencer(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Work around any chip bugs related to halting sequencer execution.
|
||||
* On Ultra2 controllers, we must clear the CIOBUS stretch signal by
|
||||
* reading a register that will set this signal and deassert it.
|
||||
* Without this workaround, if the chip is paused, by an interrupt or
|
||||
* manual pause while accessing scb ram, accesses to certain registers
|
||||
* will hang the system (infinite pci retries).
|
||||
*/
|
||||
static __inline void
|
||||
ahc_pause_bug_fix(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
(void)ahc_inb(ahc, CCSCBCTL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
static __inline int
|
||||
sequencer_paused(struct ahc_softc *ahc)
|
||||
{
|
||||
return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
static __inline void
|
||||
pause_sequencer(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc_outb(ahc, HCNTRL, ahc->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (sequencer_paused(ahc) == 0)
|
||||
;
|
||||
|
||||
ahc_pause_bug_fix(ahc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
static __inline void
|
||||
unpause_sequencer(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
|
||||
ahc_outb(ahc, HCNTRL, ahc->unpause);
|
||||
}
|
||||
|
||||
/*********************** Untagged Transaction Routines ************************/
|
||||
u_int ahc_index_busy_tcl(struct ahc_softc *ahc,
|
||||
u_int tcl, int unbusy);
|
||||
static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
|
||||
static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Block our completion routine from starting the next untagged
|
||||
* transaction for this target or target lun.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_freeze_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->features & AHC_SCB_BTT) == 0)
|
||||
ahc->untagged_queue_lock++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the next untagged transaction for this target or target lun
|
||||
* to be executed. We use a counting semaphore to allow the lock
|
||||
* to be acquired recursively. Once the count drops to zero, the
|
||||
* transaction queues will be run.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_release_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->features & AHC_SCB_BTT) == 0) {
|
||||
ahc->untagged_queue_lock--;
|
||||
if (ahc->untagged_queue_lock == 0)
|
||||
ahc_run_untagged_queues(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static __inline struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb,
|
||||
uint32_t sg_busaddr);
|
||||
static __inline uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb,
|
||||
struct ahc_dma_seg *sg);
|
||||
static __inline uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
|
||||
|
||||
static __inline struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index++;
|
||||
|
||||
return (&scb->sg_list[sg_index]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index = sg - &scb->sg_list[1];
|
||||
|
||||
return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (ahc->scb_data->hscb_busaddr
|
||||
+ (sizeof(struct hardware_scb) * index));
|
||||
}
|
||||
|
||||
/******************************** Debugging ***********************************/
|
||||
static __inline char *ahc_name(struct ahc_softc *ahc);
|
||||
|
||||
static __inline char *
|
||||
ahc_name(struct ahc_softc *ahc)
|
||||
{
|
||||
return (ahc->name);
|
||||
}
|
||||
|
||||
/*********************** Miscelaneous Support Functions ***********************/
|
||||
|
||||
static __inline int ahc_check_residual(struct scb *scb);
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct tmode_tstate **tstate);
|
||||
static __inline struct scb*
|
||||
ahc_get_scb(struct ahc_softc *ahc);
|
||||
static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer reported a residual
|
||||
* for this SCB/transaction.
|
||||
*/
|
||||
static __inline int
|
||||
ahc_check_residual(struct scb *scb)
|
||||
{
|
||||
struct status_pkt *sp;
|
||||
|
||||
sp = &scb->hscb->shared_data.status;
|
||||
if ((scb->hscb->sgptr & SG_RESID_VALID) != 0)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
|
||||
u_int remote_id, struct tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahc->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free scb. If there are none, see if we can allocate a new SCB.
|
||||
*/
|
||||
static __inline struct scb *
|
||||
ahc_get_scb(struct ahc_softc *ahc)
|
||||
{
|
||||
struct scb *scbp;
|
||||
|
||||
if ((scbp = SLIST_FIRST(&ahc->scb_data->free_scbs))) {
|
||||
SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
|
||||
} else {
|
||||
ahc_alloc_scbs(ahc);
|
||||
scbp = SLIST_FIRST(&ahc->scb_data->free_scbs);
|
||||
if (scbp != NULL)
|
||||
SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
|
||||
}
|
||||
|
||||
return (scbp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an SCB resource to the free list.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb;
|
||||
|
||||
hscb = scb->hscb;
|
||||
#if 0
|
||||
/* What do we do to generically handle driver resource shortages??? */
|
||||
if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0
|
||||
&& (scb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
|
||||
scb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
|
||||
ahc->flags &= ~AHC_RESOURCE_SHORTAGE;
|
||||
}
|
||||
#endif
|
||||
/* Clean up for the next user */
|
||||
scb->flags = SCB_FREE;
|
||||
hscb->control = 0;
|
||||
|
||||
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
|
||||
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
|
||||
ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
|
||||
} else {
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
pause_sequencer(ahc);
|
||||
ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
unpause_sequencer(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static __inline void ahc_intr(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
static __inline void
|
||||
ahc_intr(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
intstat = ahc_inb(ahc, INTSTAT);
|
||||
|
||||
/*
|
||||
* Any interrupts to process?
|
||||
*/
|
||||
#if AHC_PCI_CONFIG > 0
|
||||
if ((intstat & INT_PEND) == 0) {
|
||||
if ((ahc->chip & AHC_PCI) != 0
|
||||
&& (ahc->unsolicited_ints > 500)) {
|
||||
if ((ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
|
||||
ahc_pci_intr(ahc);
|
||||
ahc->unsolicited_ints = 0;
|
||||
} else {
|
||||
ahc->unsolicited_ints++;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
ahc->unsolicited_ints = 0;
|
||||
}
|
||||
#else
|
||||
if ((intstat & INT_PEND) == 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahc_outb(ahc, CLRINT, CLRCMDINT);
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
ahc_flush_device_writes(ahc);
|
||||
ahc_run_qoutfifo(ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETMODE) != 0)
|
||||
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
if (intstat & BRKADRINT)
|
||||
ahc_handle_brkadrint(ahc);
|
||||
|
||||
if ((intstat & (SEQINT|SCSIINT)) != 0)
|
||||
ahc_pause_bug_fix(ahc);
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahc_handle_seqint(ahc, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahc_handle_scsiint(ahc, intstat);
|
||||
}
|
||||
|
||||
#endif /* _AIC7XXX_INLINE_H_ */
|
1823
sys/dev/aic7xxx/aic7xxx_osm.c
Normal file
1823
sys/dev/aic7xxx/aic7xxx_osm.c
Normal file
File diff suppressed because it is too large
Load Diff
451
sys/dev/aic7xxx/aic7xxx_osm.h
Normal file
451
sys/dev/aic7xxx/aic7xxx_osm.h
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* FreeBSD platform specific driver option settings, data structures,
|
||||
* function declarations and includes.
|
||||
*
|
||||
* Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_FREEBSD_H_
|
||||
#define _AIC7XXX_FREEBSD_H_
|
||||
|
||||
#include <opt_aic7xxx.h> /* for config options */
|
||||
#include <pci.h> /* for NPCI */
|
||||
|
||||
#include <stddef.h> /* For offsetof */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h> /* For device_t */
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#if NPCI > 0
|
||||
#define AHC_SUPPORT_PCI 1
|
||||
#include <machine/bus_memio.h>
|
||||
#endif
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <sys/rman.h>
|
||||
|
||||
#if NPCI > 0
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
#endif
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_debug.h>
|
||||
#include <cam/cam_sim.h>
|
||||
#include <cam/cam_xpt_sim.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
|
||||
/****************************** Platform Macros *******************************/
|
||||
#define SIM_IS_SCSIBUS_B(ahc, sim) \
|
||||
((sim) == ahc->platform_data->sim_b)
|
||||
#define SIM_CHANNEL(ahc, sim) \
|
||||
(((sim) == ahc->platform_data->sim_b) ? 'B' : 'A')
|
||||
#define SIM_SCSI_ID(ahc, sim) \
|
||||
(((sim) == ahc->platform_data->sim_b) ? ahc->our_id_b : ahc->our_id)
|
||||
#define SIM_PATH(ahc, sim) \
|
||||
(((sim) == ahc->platform_data->sim_b) ? ahc->platform_data->path_b \
|
||||
: ahc->platform_data->path)
|
||||
#define BUILD_SCSIID(ahc, sim, target_id, our_id) \
|
||||
((((target_id) << TID_SHIFT) & TID) | (our_id) \
|
||||
| (SIM_IS_SCSIBUS_B(ahc, sim) ? TWIN_CHNLB : 0))
|
||||
|
||||
#define SCB_GET_SIM(ahc, scb) \
|
||||
(SCB_GET_CHANNEL(ahc, scb) == 'A' ? (ahc)->platform_data->sim \
|
||||
: (ahc)->platform_data->sim_b)
|
||||
|
||||
/************************* Forward Declarations *******************************/
|
||||
typedef device_t ahc_dev_softc_t;
|
||||
typedef union ccb *ahc_io_ctx_t;
|
||||
|
||||
/***************************** Bus Space/DMA **********************************/
|
||||
#define ahc_dma_tag_create(ahc, parent_tag, alignment, boundary, \
|
||||
lowaddr, highaddr, filter, filterarg, \
|
||||
maxsize, nsegments, maxsegsz, flags, \
|
||||
dma_tagp) \
|
||||
bus_dma_tag_create(parent_tag, alignment, boundary, \
|
||||
lowaddr, highaddr, filter, filterarg, \
|
||||
maxsize, nsegments, maxsegsz, flags, \
|
||||
dma_tagp)
|
||||
|
||||
#define ahc_dma_tag_destroy(ahc, tag) \
|
||||
bus_dma_tag_destroy(tag)
|
||||
|
||||
#define ahc_dmamem_alloc(ahc, dmat, vaddr, flags, mapp) \
|
||||
bus_dmamem_alloc(dmat, vaddr, flags, mapp)
|
||||
|
||||
#define ahc_dmamem_free(ahc, dmat, vaddr, map) \
|
||||
bus_dmamem_free(dmat, vaddr, map)
|
||||
|
||||
#define ahc_dmamap_create(ahc, tag, flags, mapp) \
|
||||
bus_dmamap_create(tag, flags, mapp)
|
||||
|
||||
#define ahc_dmamap_destroy(ahc, tag, map) \
|
||||
bus_dmamap_destroy(tag, map)
|
||||
|
||||
#define ahc_dmamap_load(ahc, dmat, map, addr, buflen, callback, \
|
||||
callback_arg, flags) \
|
||||
bus_dmamap_load(dmat, map, addr, buflen, callback, callback_arg, flags)
|
||||
|
||||
#define ahc_dmamap_unload(ahc, tag, map) \
|
||||
bus_dmamap_unload(tag, map)
|
||||
|
||||
#define ahc_dmamap_sync(ahc, dma_tag, dmamap, op) \
|
||||
bus_dmamap_sync(dma_tag_dmamap, op)
|
||||
|
||||
/************************ Tunable Driver Parameters **************************/
|
||||
/*
|
||||
* The number of dma segments supported. The sequencer can handle any number
|
||||
* of physically contiguous S/G entrys. To reduce the driver's memory
|
||||
* consumption, we limit the number supported to be sufficient to handle
|
||||
* the largest mapping supported by the kernel, MAXPHYS. Assuming the
|
||||
* transfer is as fragmented as possible and unaligned, this turns out to
|
||||
* be the number of paged sized transfers in MAXPHYS plus an extra element
|
||||
* to handle any unaligned residual. The sequencer fetches SG elements
|
||||
* in 128 byte chucks, so make the number per-transaction a nice multiple
|
||||
* of 16 (8 byte S/G elements).
|
||||
*/
|
||||
/* XXX Worth the space??? */
|
||||
#define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16))
|
||||
|
||||
/* This driver supports target mode */
|
||||
#define AHC_TARGET_MODE 1
|
||||
|
||||
/************************** Softc/SCB Platform Data ***************************/
|
||||
struct ahc_platform_data {
|
||||
/*
|
||||
* Hooks into the XPT.
|
||||
*/
|
||||
struct cam_sim *sim;
|
||||
struct cam_sim *sim_b;
|
||||
struct cam_path *path;
|
||||
struct cam_path *path_b;
|
||||
|
||||
int regs_res_type;
|
||||
int regs_res_id;
|
||||
int irq_res_type;
|
||||
struct resource *regs;
|
||||
struct resource *irq;
|
||||
void *ih;
|
||||
};
|
||||
|
||||
struct scb_platform_data {
|
||||
};
|
||||
|
||||
/***************************** Core Includes **********************************/
|
||||
#include <dev/aic7xxx/aic7xxx.h>
|
||||
|
||||
/*************************** Device Access ************************************/
|
||||
#define ahc_inb(ahc, port) \
|
||||
bus_space_read_1((ahc)->tag, (ahc)->bsh, port)
|
||||
|
||||
#define ahc_outb(ahc, port, value) \
|
||||
bus_space_write_1((ahc)->tag, (ahc)->bsh, port, value)
|
||||
|
||||
#define ahc_outsb(ahc, port, valp, count) \
|
||||
bus_space_write_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
|
||||
|
||||
#define ahc_insb(ahc, port, valp, count) \
|
||||
bus_space_read_multi_1((ahc)->tag, (ahc)->bsh, port, valp, count)
|
||||
|
||||
static __inline void ahc_flush_device_writes(struct ahc_softc *);
|
||||
|
||||
static __inline void
|
||||
ahc_flush_device_writes(struct ahc_softc *ahc)
|
||||
{
|
||||
/* XXX Is this sufficient for all architectures??? */
|
||||
ahc_inb(ahc, INTSTAT);
|
||||
}
|
||||
|
||||
/**************************** Locking Primitives ******************************/
|
||||
/* Lock protecting internal data structures */
|
||||
static __inline void ahc_lockinit(struct ahc_softc *);
|
||||
static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags);
|
||||
static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags);
|
||||
|
||||
/* Lock held during command compeletion to the upper layer */
|
||||
static __inline void ahc_done_lockinit(struct ahc_softc *);
|
||||
static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags);
|
||||
static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags);
|
||||
|
||||
static __inline void
|
||||
ahc_lockinit(struct ahc_softc *ahc)
|
||||
{
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
*flags = splcam();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
splx(*flags);
|
||||
}
|
||||
|
||||
/* Lock held during command compeletion to the upper layer */
|
||||
static __inline void
|
||||
ahc_done_lockinit(struct ahc_softc *ahc)
|
||||
{
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************** OS Primitives *********************************/
|
||||
#define ahc_delay DELAY
|
||||
|
||||
/************************** Transaction Operations ****************************/
|
||||
static __inline void ahc_set_transaction_status(struct scb *, uint32_t);
|
||||
static __inline void ahc_set_scsi_status(struct scb *, uint32_t);
|
||||
static __inline uint32_t ahc_get_transaction_status(struct scb *);
|
||||
static __inline uint32_t ahc_get_scsi_status(struct scb *);
|
||||
static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
|
||||
static __inline u_long ahc_get_transfer_length(struct scb *);
|
||||
static __inline int ahc_get_transfer_dir(struct scb *);
|
||||
static __inline void ahc_set_residual(struct scb *, u_long);
|
||||
static __inline void ahc_set_sense_residual(struct scb *, u_long);
|
||||
static __inline u_long ahc_get_residual(struct scb *);
|
||||
static __inline int ahc_perform_autosense(struct scb *);
|
||||
static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc*, struct scb*);
|
||||
static __inline void ahc_freeze_ccb(union ccb *ccb);
|
||||
static __inline void ahc_freeze_scb(struct scb *scb);
|
||||
static __inline void ahc_platform_freeze_devq(struct ahc_softc *, struct scb *);
|
||||
static __inline int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status);
|
||||
|
||||
static __inline
|
||||
void ahc_set_transaction_status(struct scb *scb, uint32_t status)
|
||||
{
|
||||
scb->io_ctx->ccb_h.status &= ~CAM_STATUS_MASK;
|
||||
scb->io_ctx->ccb_h.status |= status;
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_scsi_status(struct scb *scb, uint32_t status)
|
||||
{
|
||||
scb->io_ctx->csio.scsi_status = status;
|
||||
}
|
||||
|
||||
static __inline
|
||||
uint32_t ahc_get_transaction_status(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->ccb_h.status & CAM_STATUS_MASK);
|
||||
}
|
||||
|
||||
static __inline
|
||||
uint32_t ahc_get_scsi_status(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->csio.scsi_status);
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type)
|
||||
{
|
||||
scb->io_ctx->csio.tag_action = type;
|
||||
if (enabled)
|
||||
scb->io_ctx->ccb_h.flags |= CAM_TAG_ACTION_VALID;
|
||||
else
|
||||
scb->io_ctx->ccb_h.flags &= ~CAM_TAG_ACTION_VALID;
|
||||
}
|
||||
|
||||
static __inline
|
||||
u_long ahc_get_transfer_length(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->csio.dxfer_len);
|
||||
}
|
||||
|
||||
static __inline
|
||||
int ahc_get_transfer_dir(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->ccb_h.flags & CAM_DIR_MASK);
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_residual(struct scb *scb, u_long resid)
|
||||
{
|
||||
scb->io_ctx->csio.resid = resid;
|
||||
}
|
||||
|
||||
static __inline
|
||||
void ahc_set_sense_residual(struct scb *scb, u_long resid)
|
||||
{
|
||||
scb->io_ctx->csio.sense_resid = resid;
|
||||
}
|
||||
|
||||
static __inline
|
||||
u_long ahc_get_residual(struct scb *scb)
|
||||
{
|
||||
return (scb->io_ctx->csio.resid);
|
||||
}
|
||||
|
||||
static __inline
|
||||
int ahc_perform_autosense(struct scb *scb)
|
||||
{
|
||||
return (!(scb->io_ctx->ccb_h.flags & CAM_DIS_AUTOSENSE));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
return (sizeof(struct scsi_sense_data));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_freeze_ccb(union ccb *ccb)
|
||||
{
|
||||
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
|
||||
ccb->ccb_h.status |= CAM_DEV_QFRZN;
|
||||
xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_freeze_scb(struct scb *scb)
|
||||
{
|
||||
ahc_freeze_ccb(scb->io_ctx);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
/* Nothing to do here for FreeBSD */
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status)
|
||||
{
|
||||
/* Nothing to do here for FreeBSD */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/********************************** PCI ***************************************/
|
||||
#ifdef AHC_SUPPORT_PCI
|
||||
static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
|
||||
int reg, int width);
|
||||
static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
|
||||
int reg, uint32_t value,
|
||||
int width);
|
||||
static __inline int ahc_get_pci_function(ahc_dev_softc_t);
|
||||
static __inline int ahc_get_pci_slot(ahc_dev_softc_t);
|
||||
static __inline int ahc_get_pci_bus(ahc_dev_softc_t);
|
||||
|
||||
int ahc_pci_map_registers(struct ahc_softc *ahc);
|
||||
int ahc_pci_map_int(struct ahc_softc *ahc);
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
|
||||
{
|
||||
return (pci_read_config(pci, reg, width));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
|
||||
{
|
||||
pci_write_config(pci, reg, value, width);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_get_pci_function(ahc_dev_softc_t pci)
|
||||
{
|
||||
return (pci_get_function(pci));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_get_pci_slot(ahc_dev_softc_t pci)
|
||||
{
|
||||
return (pci_get_slot(pci));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ahc_get_pci_bus(ahc_dev_softc_t pci)
|
||||
{
|
||||
return (pci_get_bus(pci));
|
||||
}
|
||||
#endif
|
||||
/******************************** VL/EISA *************************************/
|
||||
int aic7770_map_registers(struct ahc_softc *ahc);
|
||||
int aic7770_map_int(struct ahc_softc *ahc);
|
||||
|
||||
/********************************* Debug **************************************/
|
||||
static __inline void ahc_print_path(struct ahc_softc *, struct scb *);
|
||||
static __inline void ahc_platform_dump_card_state(struct ahc_softc *ahc);
|
||||
|
||||
static __inline void
|
||||
ahc_print_path(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
xpt_print_path(scb->io_ctx->ccb_h.path);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_platform_dump_card_state(struct ahc_softc *ahc)
|
||||
{
|
||||
/* Nothing to do here for FreeBSD */
|
||||
}
|
||||
/**************************** Transfer Settings *******************************/
|
||||
void ahc_notify_xfer_settings_change(struct ahc_softc *,
|
||||
struct ahc_devinfo *);
|
||||
void ahc_platform_set_tags(struct ahc_softc *, struct ahc_devinfo *,
|
||||
int /*enable*/);
|
||||
|
||||
/***************************** Initialization *********************************/
|
||||
int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
|
||||
void ahc_platform_free(struct ahc_softc *ahc);
|
||||
int ahc_attach(struct ahc_softc *);
|
||||
int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc);
|
||||
|
||||
/************************ Misc Function Declarations **************************/
|
||||
timeout_t ahc_timeout;
|
||||
void ahc_done(struct ahc_softc *ahc, struct scb *scb);
|
||||
void ahc_send_async(struct ahc_softc *, struct ahc_devinfo *, ac_code);
|
||||
#endif /* _AIC7XXX_FREEBSD_H_ */
|
1921
sys/dev/aic7xxx/aic7xxx_pci.c
Normal file
1921
sys/dev/aic7xxx/aic7xxx_pci.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,736 +0,0 @@
|
||||
/*
|
||||
* Aic7xxx SCSI host adapter firmware asssembler
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
|
||||
* 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, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. The name of the author may not 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 Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "aicasm.h"
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm_insformat.h"
|
||||
|
||||
typedef struct patch {
|
||||
STAILQ_ENTRY(patch) links;
|
||||
int patch_func;
|
||||
u_int begin;
|
||||
u_int skip_instr;
|
||||
u_int skip_patch;
|
||||
} patch_t;
|
||||
|
||||
STAILQ_HEAD(patch_list, patch) patches;
|
||||
|
||||
static void usage(void);
|
||||
static void back_patch(void);
|
||||
static void output_code(void);
|
||||
static void output_listing(char *ifilename);
|
||||
static void dump_scope(scope_t *scope);
|
||||
static void emit_patch(scope_t *scope, int patch);
|
||||
static int check_patch(patch_t **start_patch, int start_instr,
|
||||
int *skip_addr, int *func_vals);
|
||||
|
||||
struct path_list search_path;
|
||||
int includes_search_curdir;
|
||||
char *appname;
|
||||
FILE *ofile;
|
||||
char *ofilename;
|
||||
char *regfilename;
|
||||
FILE *regfile;
|
||||
char *listfilename;
|
||||
FILE *listfile;
|
||||
|
||||
static STAILQ_HEAD(,instruction) seq_program;
|
||||
struct scope_list scope_stack;
|
||||
symlist_t patch_functions;
|
||||
|
||||
#if DEBUG
|
||||
extern int yy_flex_debug;
|
||||
extern int yydebug;
|
||||
#endif
|
||||
extern FILE *yyin;
|
||||
extern int yyparse __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
int ch;
|
||||
int retval;
|
||||
char *inputfilename;
|
||||
scope_t *sentinal;
|
||||
|
||||
STAILQ_INIT(&patches);
|
||||
SLIST_INIT(&search_path);
|
||||
STAILQ_INIT(&seq_program);
|
||||
SLIST_INIT(&scope_stack);
|
||||
|
||||
/* Set Sentinal scope node */
|
||||
sentinal = scope_alloc();
|
||||
sentinal->type = SCOPE_ROOT;
|
||||
|
||||
includes_search_curdir = 1;
|
||||
appname = *argv;
|
||||
regfile = NULL;
|
||||
listfile = NULL;
|
||||
#if DEBUG
|
||||
yy_flex_debug = 0;
|
||||
yydebug = 0;
|
||||
#endif
|
||||
while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) {
|
||||
switch(ch) {
|
||||
case 'd':
|
||||
#if DEBUG
|
||||
if (strcmp(optarg, "s") == 0) {
|
||||
yy_flex_debug = 1;
|
||||
} else if (strcmp(optarg, "p") == 0) {
|
||||
yydebug = 1;
|
||||
} else {
|
||||
fprintf(stderr, "%s: -d Requires either an "
|
||||
"'s' or 'p' argument\n", appname);
|
||||
usage();
|
||||
}
|
||||
#else
|
||||
stop("-d: Assembler not built with debugging "
|
||||
"information", EX_SOFTWARE);
|
||||
#endif
|
||||
break;
|
||||
case 'l':
|
||||
/* Create a program listing */
|
||||
if ((listfile = fopen(optarg, "w")) == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_CANTCREAT);
|
||||
}
|
||||
listfilename = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
/* Don't complain about the -nostdinc directrive */
|
||||
if (strcmp(optarg, "ostdinc")) {
|
||||
fprintf(stderr, "%s: Unknown option -%c%s\n",
|
||||
appname, ch, optarg);
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if ((ofile = fopen(optarg, "w")) == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_CANTCREAT);
|
||||
}
|
||||
ofilename = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
if ((regfile = fopen(optarg, "w")) == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_CANTCREAT);
|
||||
}
|
||||
regfilename = optarg;
|
||||
break;
|
||||
case 'I':
|
||||
{
|
||||
path_entry_t include_dir;
|
||||
|
||||
if (strcmp(optarg, "-") == 0) {
|
||||
if (includes_search_curdir == 0) {
|
||||
fprintf(stderr, "%s: Warning - '-I-' "
|
||||
"specified multiple "
|
||||
"times\n", appname);
|
||||
}
|
||||
includes_search_curdir = 0;
|
||||
for (include_dir = search_path.slh_first;
|
||||
include_dir != NULL;
|
||||
include_dir = include_dir->links.sle_next)
|
||||
/*
|
||||
* All entries before a '-I-' only
|
||||
* apply to includes specified with
|
||||
* quotes instead of "<>".
|
||||
*/
|
||||
include_dir->quoted_includes_only = 1;
|
||||
} else {
|
||||
include_dir =
|
||||
(path_entry_t)malloc(sizeof(*include_dir));
|
||||
if (include_dir == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_OSERR);
|
||||
}
|
||||
include_dir->directory = strdup(optarg);
|
||||
if (include_dir->directory == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_OSERR);
|
||||
}
|
||||
include_dir->quoted_includes_only = 0;
|
||||
SLIST_INSERT_HEAD(&search_path, include_dir,
|
||||
links);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "%s: No input file specifiled\n", appname);
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
symtable_open();
|
||||
inputfilename = *argv;
|
||||
include_file(*argv, SOURCE_FILE);
|
||||
retval = yyparse();
|
||||
if (retval == 0) {
|
||||
if (SLIST_FIRST(&scope_stack) == NULL
|
||||
|| SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
|
||||
stop("Unterminated conditional expression",
|
||||
EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Process outmost scope */
|
||||
process_scope(SLIST_FIRST(&scope_stack));
|
||||
/*
|
||||
* Decend the tree of scopes and insert/emit
|
||||
* patches as appropriate. We perform a depth first
|
||||
* tranversal, recursively handling each scope.
|
||||
*/
|
||||
/* start at the root scope */
|
||||
dump_scope(SLIST_FIRST(&scope_stack));
|
||||
|
||||
/* Patch up forward jump addresses */
|
||||
back_patch();
|
||||
|
||||
if (ofile != NULL)
|
||||
output_code();
|
||||
if (regfile != NULL) {
|
||||
symtable_dump(regfile);
|
||||
}
|
||||
if (listfile != NULL)
|
||||
output_listing(inputfilename);
|
||||
}
|
||||
|
||||
stop(NULL, 0);
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
|
||||
[-r register_output_file] [-l program_list_file]
|
||||
input_file\n",
|
||||
appname);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
back_patch()
|
||||
{
|
||||
struct instruction *cur_instr;
|
||||
|
||||
for(cur_instr = seq_program.stqh_first;
|
||||
cur_instr != NULL;
|
||||
cur_instr = cur_instr->links.stqe_next) {
|
||||
if (cur_instr->patch_label != NULL) {
|
||||
struct ins_format3 *f3_instr;
|
||||
u_int address;
|
||||
|
||||
if (cur_instr->patch_label->type != LABEL) {
|
||||
char buf[255];
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"Undefined label %s",
|
||||
cur_instr->patch_label->name);
|
||||
stop(buf, EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
f3_instr = &cur_instr->format.format3;
|
||||
address = f3_instr->address;
|
||||
address += cur_instr->patch_label->info.linfo->address;
|
||||
f3_instr->address = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
output_code()
|
||||
{
|
||||
struct instruction *cur_instr;
|
||||
patch_t *cur_patch;
|
||||
symbol_node_t *cur_node;
|
||||
int instrcount;
|
||||
|
||||
instrcount = 0;
|
||||
fprintf(ofile,
|
||||
"/*
|
||||
* DO NOT EDIT - This file is automatically generated.
|
||||
*/\n");
|
||||
|
||||
fprintf(ofile, "static uint8_t seqprog[] = {\n");
|
||||
for(cur_instr = seq_program.stqh_first;
|
||||
cur_instr != NULL;
|
||||
cur_instr = cur_instr->links.stqe_next) {
|
||||
|
||||
fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
cur_instr->format.bytes[0],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[3]);
|
||||
#else
|
||||
cur_instr->format.bytes[3],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[0]);
|
||||
#endif
|
||||
instrcount++;
|
||||
}
|
||||
fprintf(ofile, "};\n\n");
|
||||
|
||||
/*
|
||||
* Output patch information. Patch functions first.
|
||||
*/
|
||||
for(cur_node = SLIST_FIRST(&patch_functions);
|
||||
cur_node != NULL;
|
||||
cur_node = SLIST_NEXT(cur_node,links)) {
|
||||
fprintf(ofile,
|
||||
"static int ahc_patch%d_func(struct ahc_softc *ahc);
|
||||
|
||||
static int
|
||||
ahc_patch%d_func(struct ahc_softc *ahc)
|
||||
{
|
||||
return (%s);
|
||||
}\n\n",
|
||||
cur_node->symbol->info.condinfo->func_num,
|
||||
cur_node->symbol->info.condinfo->func_num,
|
||||
cur_node->symbol->name);
|
||||
}
|
||||
|
||||
fprintf(ofile,
|
||||
"typedef int patch_func_t __P((struct ahc_softc *));
|
||||
struct patch {
|
||||
patch_func_t *patch_func;
|
||||
uint32_t begin :10,
|
||||
skip_instr :10,
|
||||
skip_patch :12;
|
||||
} patches[] = {\n");
|
||||
|
||||
for(cur_patch = STAILQ_FIRST(&patches);
|
||||
cur_patch != NULL;
|
||||
cur_patch = STAILQ_NEXT(cur_patch,links)) {
|
||||
fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n",
|
||||
cur_patch->patch_func, cur_patch->begin,
|
||||
cur_patch->skip_instr, cur_patch->skip_patch);
|
||||
}
|
||||
|
||||
fprintf(ofile, "\n};\n");
|
||||
|
||||
fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_scope(scope_t *scope)
|
||||
{
|
||||
scope_t *cur_scope;
|
||||
|
||||
/*
|
||||
* Emit the first patch for this scope
|
||||
*/
|
||||
emit_patch(scope, 0);
|
||||
|
||||
/*
|
||||
* Dump each scope within this one.
|
||||
*/
|
||||
cur_scope = TAILQ_FIRST(&scope->inner_scope);
|
||||
|
||||
while (cur_scope != NULL) {
|
||||
|
||||
dump_scope(cur_scope);
|
||||
|
||||
cur_scope = TAILQ_NEXT(cur_scope, scope_links);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit the second, closing, patch for this scope
|
||||
*/
|
||||
emit_patch(scope, 1);
|
||||
}
|
||||
|
||||
void
|
||||
emit_patch(scope_t *scope, int patch)
|
||||
{
|
||||
patch_info_t *pinfo;
|
||||
patch_t *new_patch;
|
||||
|
||||
pinfo = &scope->patches[patch];
|
||||
|
||||
if (pinfo->skip_instr == 0)
|
||||
/* No-Op patch */
|
||||
return;
|
||||
|
||||
new_patch = (patch_t *)malloc(sizeof(*new_patch));
|
||||
|
||||
if (new_patch == NULL)
|
||||
stop("Could not malloc patch structure", EX_OSERR);
|
||||
|
||||
memset(new_patch, 0, sizeof(*new_patch));
|
||||
|
||||
if (patch == 0) {
|
||||
new_patch->patch_func = scope->func_num;
|
||||
new_patch->begin = scope->begin_addr;
|
||||
} else {
|
||||
new_patch->patch_func = 0;
|
||||
new_patch->begin = scope->end_addr;
|
||||
}
|
||||
new_patch->skip_instr = pinfo->skip_instr;
|
||||
new_patch->skip_patch = pinfo->skip_patch;
|
||||
STAILQ_INSERT_TAIL(&patches, new_patch, links);
|
||||
}
|
||||
|
||||
void
|
||||
output_listing(char *ifilename)
|
||||
{
|
||||
char buf[1024];
|
||||
FILE *ifile;
|
||||
struct instruction *cur_instr;
|
||||
patch_t *cur_patch;
|
||||
symbol_node_t *cur_func;
|
||||
int *func_values;
|
||||
int instrcount;
|
||||
int instrptr;
|
||||
int line;
|
||||
int func_count;
|
||||
int skip_addr;
|
||||
|
||||
instrcount = 0;
|
||||
instrptr = 0;
|
||||
line = 1;
|
||||
skip_addr = 0;
|
||||
if ((ifile = fopen(ifilename, "r")) == NULL) {
|
||||
perror(ifilename);
|
||||
stop(NULL, EX_DATAERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine which options to apply to this listing.
|
||||
*/
|
||||
for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
|
||||
cur_func != NULL;
|
||||
cur_func = SLIST_NEXT(cur_func, links))
|
||||
func_count++;
|
||||
|
||||
if (func_count != 0) {
|
||||
func_values = (int *)malloc(func_count * sizeof(int));
|
||||
|
||||
if (func_values == NULL)
|
||||
stop("Could not malloc", EX_OSERR);
|
||||
|
||||
func_values[0] = 0; /* FALSE func */
|
||||
func_count--;
|
||||
|
||||
/*
|
||||
* Ask the user to fill in the return values for
|
||||
* the rest of the functions.
|
||||
*/
|
||||
|
||||
|
||||
for (cur_func = SLIST_FIRST(&patch_functions);
|
||||
cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
|
||||
cur_func = SLIST_NEXT(cur_func, links), func_count--) {
|
||||
int input;
|
||||
|
||||
fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
|
||||
fprintf(stdout,
|
||||
"Enter the return value for "
|
||||
"this expression[T/F]:");
|
||||
|
||||
while (1) {
|
||||
|
||||
input = getchar();
|
||||
input = toupper(input);
|
||||
|
||||
if (input == 'T') {
|
||||
func_values[func_count] = 1;
|
||||
break;
|
||||
} else if (input == 'F') {
|
||||
func_values[func_count] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isatty(fileno(stdin)) == 0)
|
||||
putchar(input);
|
||||
}
|
||||
fprintf(stdout, "\nThanks!\n");
|
||||
}
|
||||
|
||||
/* Now output the listing */
|
||||
cur_patch = STAILQ_FIRST(&patches);
|
||||
for(cur_instr = STAILQ_FIRST(&seq_program);
|
||||
cur_instr != NULL;
|
||||
cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
|
||||
|
||||
if (check_patch(&cur_patch, instrcount,
|
||||
&skip_addr, func_values) == 0) {
|
||||
/* Don't count this instruction as it is in a patch
|
||||
* that was removed.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
while (line < cur_instr->srcline) {
|
||||
fgets(buf, sizeof(buf), ifile);
|
||||
fprintf(listfile, "\t\t%s", buf);
|
||||
line++;
|
||||
}
|
||||
fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
cur_instr->format.bytes[0],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[3]);
|
||||
#else
|
||||
cur_instr->format.bytes[3],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[0]);
|
||||
#endif
|
||||
fgets(buf, sizeof(buf), ifile);
|
||||
fprintf(listfile, "\t%s", buf);
|
||||
line++;
|
||||
instrptr++;
|
||||
}
|
||||
/* Dump the remainder of the file */
|
||||
while(fgets(buf, sizeof(buf), ifile) != NULL)
|
||||
fprintf(listfile, "\t\t%s", buf);
|
||||
|
||||
fclose(ifile);
|
||||
}
|
||||
|
||||
static int
|
||||
check_patch(patch_t **start_patch, int start_instr,
|
||||
int *skip_addr, int *func_vals)
|
||||
{
|
||||
patch_t *cur_patch;
|
||||
|
||||
cur_patch = *start_patch;
|
||||
|
||||
while (cur_patch != NULL && start_instr == cur_patch->begin) {
|
||||
if (func_vals[cur_patch->patch_func] == 0) {
|
||||
int skip;
|
||||
|
||||
/* Start rejecting code */
|
||||
*skip_addr = start_instr + cur_patch->skip_instr;
|
||||
for (skip = cur_patch->skip_patch;
|
||||
skip > 0 && cur_patch != NULL;
|
||||
skip--)
|
||||
cur_patch = STAILQ_NEXT(cur_patch, links);
|
||||
} else {
|
||||
/* Accepted this patch. Advance to the next
|
||||
* one and wait for our intruction pointer to
|
||||
* hit this point.
|
||||
*/
|
||||
cur_patch = STAILQ_NEXT(cur_patch, links);
|
||||
}
|
||||
}
|
||||
|
||||
*start_patch = cur_patch;
|
||||
if (start_instr < *skip_addr)
|
||||
/* Still skipping */
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out error information if appropriate, and clean up before
|
||||
* terminating the program.
|
||||
*/
|
||||
void
|
||||
stop(string, err_code)
|
||||
const char *string;
|
||||
int err_code;
|
||||
{
|
||||
if (string != NULL) {
|
||||
fprintf(stderr, "%s: ", appname);
|
||||
if (yyfilename != NULL) {
|
||||
fprintf(stderr, "Stopped at file %s, line %d - ",
|
||||
yyfilename, yylineno);
|
||||
}
|
||||
fprintf(stderr, "%s\n", string);
|
||||
}
|
||||
|
||||
if (ofile != NULL) {
|
||||
fclose(ofile);
|
||||
if (err_code != 0) {
|
||||
fprintf(stderr, "%s: Removing %s due to error\n",
|
||||
appname, ofilename);
|
||||
unlink(ofilename);
|
||||
}
|
||||
}
|
||||
|
||||
if (regfile != NULL) {
|
||||
fclose(regfile);
|
||||
if (err_code != 0) {
|
||||
fprintf(stderr, "%s: Removing %s due to error\n",
|
||||
appname, regfilename);
|
||||
unlink(regfilename);
|
||||
}
|
||||
}
|
||||
|
||||
if (listfile != NULL) {
|
||||
fclose(listfile);
|
||||
if (err_code != 0) {
|
||||
fprintf(stderr, "%s: Removing %s due to error\n",
|
||||
appname, listfilename);
|
||||
unlink(listfilename);
|
||||
}
|
||||
}
|
||||
|
||||
symlist_free(&patch_functions);
|
||||
symtable_close();
|
||||
|
||||
exit(err_code);
|
||||
}
|
||||
|
||||
struct instruction *
|
||||
seq_alloc()
|
||||
{
|
||||
struct instruction *new_instr;
|
||||
|
||||
new_instr = (struct instruction *)malloc(sizeof(struct instruction));
|
||||
if (new_instr == NULL)
|
||||
stop("Unable to malloc instruction object", EX_SOFTWARE);
|
||||
memset(new_instr, 0, sizeof(*new_instr));
|
||||
STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
|
||||
new_instr->srcline = yylineno;
|
||||
return new_instr;
|
||||
}
|
||||
|
||||
scope_t *
|
||||
scope_alloc()
|
||||
{
|
||||
scope_t *new_scope;
|
||||
|
||||
new_scope = (scope_t *)malloc(sizeof(scope_t));
|
||||
if (new_scope == NULL)
|
||||
stop("Unable to malloc scope object", EX_SOFTWARE);
|
||||
memset(new_scope, 0, sizeof(*new_scope));
|
||||
TAILQ_INIT(&new_scope->inner_scope);
|
||||
|
||||
if (SLIST_FIRST(&scope_stack) != NULL) {
|
||||
TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
|
||||
new_scope, scope_links);
|
||||
}
|
||||
/* This patch is now the current scope */
|
||||
SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
|
||||
return new_scope;
|
||||
}
|
||||
|
||||
void
|
||||
process_scope(scope_t *scope)
|
||||
{
|
||||
/*
|
||||
* We are "leaving" this scope. We should now have
|
||||
* enough information to process the lists of scopes
|
||||
* we encapsulate.
|
||||
*/
|
||||
scope_t *cur_scope;
|
||||
u_int skip_patch_count;
|
||||
u_int skip_instr_count;
|
||||
|
||||
cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
|
||||
skip_patch_count = 0;
|
||||
skip_instr_count = 0;
|
||||
while (cur_scope != NULL) {
|
||||
u_int patch0_patch_skip;
|
||||
|
||||
patch0_patch_skip = 0;
|
||||
switch (cur_scope->type) {
|
||||
case SCOPE_IF:
|
||||
case SCOPE_ELSE_IF:
|
||||
if (skip_instr_count != 0) {
|
||||
/* Create a tail patch */
|
||||
patch0_patch_skip++;
|
||||
cur_scope->patches[1].skip_patch =
|
||||
skip_patch_count + 1;
|
||||
cur_scope->patches[1].skip_instr =
|
||||
skip_instr_count;
|
||||
}
|
||||
|
||||
/* Count Head patch */
|
||||
patch0_patch_skip++;
|
||||
|
||||
/* Count any patches contained in our inner scope */
|
||||
patch0_patch_skip += cur_scope->inner_scope_patches;
|
||||
|
||||
cur_scope->patches[0].skip_patch = patch0_patch_skip;
|
||||
cur_scope->patches[0].skip_instr =
|
||||
cur_scope->end_addr - cur_scope->begin_addr;
|
||||
|
||||
skip_instr_count += cur_scope->patches[0].skip_instr;
|
||||
|
||||
skip_patch_count += patch0_patch_skip;
|
||||
if (cur_scope->type == SCOPE_IF) {
|
||||
scope->inner_scope_patches += skip_patch_count;
|
||||
skip_patch_count = 0;
|
||||
skip_instr_count = 0;
|
||||
}
|
||||
break;
|
||||
case SCOPE_ELSE:
|
||||
/* Count any patches contained in our innter scope */
|
||||
skip_patch_count += cur_scope->inner_scope_patches;
|
||||
|
||||
skip_instr_count += cur_scope->end_addr
|
||||
- cur_scope->begin_addr;
|
||||
break;
|
||||
case SCOPE_ROOT:
|
||||
stop("Unexpected scope type encountered", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef struct path_entry {
|
||||
char *directory;
|
||||
int quoted_includes_only;
|
||||
SLIST_ENTRY(path_entry) links;
|
||||
} *path_entry_t;
|
||||
|
||||
typedef enum {
|
||||
QUOTED_INCLUDE,
|
||||
BRACKETED_INCLUDE,
|
||||
SOURCE_FILE
|
||||
} include_type;
|
||||
|
||||
SLIST_HEAD(path_list, path_entry);
|
||||
|
||||
extern struct path_list search_path;
|
||||
extern struct scope_list scope_stack;
|
||||
extern struct symlist patch_functions;
|
||||
extern int includes_search_curdir; /* False if we've seen -I- */
|
||||
extern char *appname;
|
||||
extern int yylineno;
|
||||
extern char *yyfilename;
|
||||
|
||||
void stop(const char *errstring, int err_code);
|
||||
void include_file(char *file_name, include_type type);
|
||||
struct instruction *seq_alloc(void);
|
||||
struct scope *scope_alloc(void);
|
||||
void process_scope(struct scope *);
|
File diff suppressed because it is too large
Load Diff
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Instruction formats for the sequencer program downloaded to
|
||||
* Aic7xxx SCSI host adapters
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <machine/endian.h>
|
||||
|
||||
struct ins_format1 {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint32_t immediate : 8,
|
||||
source : 9,
|
||||
destination : 9,
|
||||
ret : 1,
|
||||
opcode : 4,
|
||||
parity : 1;
|
||||
#else
|
||||
uint32_t parity : 1,
|
||||
opcode : 4,
|
||||
ret : 1,
|
||||
destination : 9,
|
||||
source : 9,
|
||||
immediate : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ins_format2 {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint32_t shift_control : 8,
|
||||
source : 9,
|
||||
destination : 9,
|
||||
ret : 1,
|
||||
opcode : 4,
|
||||
parity : 1;
|
||||
#else
|
||||
uint32_t parity : 1,
|
||||
opcode : 4,
|
||||
ret : 1,
|
||||
destination : 9,
|
||||
source : 9,
|
||||
shift_control : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ins_format3 {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint32_t immediate : 8,
|
||||
source : 9,
|
||||
address : 10,
|
||||
opcode : 4,
|
||||
parity : 1;
|
||||
#else
|
||||
uint32_t parity : 1,
|
||||
opcode : 4,
|
||||
address : 10,
|
||||
source : 9,
|
||||
immediate : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
union ins_formats {
|
||||
struct ins_format1 format1;
|
||||
struct ins_format2 format2;
|
||||
struct ins_format3 format3;
|
||||
uint8_t bytes[4];
|
||||
uint32_t integer;
|
||||
};
|
||||
struct instruction {
|
||||
union ins_formats format;
|
||||
u_int srcline;
|
||||
struct symbol *patch_label;
|
||||
STAILQ_ENTRY(instruction) links;
|
||||
};
|
||||
|
||||
#define AIC_OP_OR 0x0
|
||||
#define AIC_OP_AND 0x1
|
||||
#define AIC_OP_XOR 0x2
|
||||
#define AIC_OP_ADD 0x3
|
||||
#define AIC_OP_ADC 0x4
|
||||
#define AIC_OP_ROL 0x5
|
||||
#define AIC_OP_BMOV 0x6
|
||||
|
||||
#define AIC_OP_JMP 0x8
|
||||
#define AIC_OP_JC 0x9
|
||||
#define AIC_OP_JNC 0xa
|
||||
#define AIC_OP_CALL 0xb
|
||||
#define AIC_OP_JNE 0xc
|
||||
#define AIC_OP_JNZ 0xd
|
||||
#define AIC_OP_JE 0xe
|
||||
#define AIC_OP_JZ 0xf
|
||||
|
||||
/* Pseudo Ops */
|
||||
#define AIC_OP_SHL 0x10
|
||||
#define AIC_OP_SHR 0x20
|
||||
#define AIC_OP_ROR 0x30
|
@ -1,287 +0,0 @@
|
||||
%{
|
||||
/*
|
||||
* Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
|
||||
*
|
||||
* Copyright (c) 1997, 1998 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "aicasm.h"
|
||||
#include "aicasm_symbol.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
#define MAX_STR_CONST 256
|
||||
char string_buf[MAX_STR_CONST];
|
||||
char *string_buf_ptr;
|
||||
int parren_count;
|
||||
%}
|
||||
|
||||
PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
|
||||
WORD [A-Za-z_][-A-Za-z_0-9]*
|
||||
SPACE [ \t]+
|
||||
|
||||
%x COMMENT
|
||||
%x CEXPR
|
||||
%x INCLUDE
|
||||
|
||||
%%
|
||||
\n { ++yylineno; }
|
||||
"/*" { BEGIN COMMENT; /* Enter comment eating state */ }
|
||||
<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); }
|
||||
<COMMENT>\n { ++yylineno; }
|
||||
<COMMENT>[^*/\n]* ;
|
||||
<COMMENT>"*"+[^*/\n]* ;
|
||||
<COMMENT>"/"+[^*/\n]* ;
|
||||
<COMMENT>"*"+"/" { BEGIN INITIAL; }
|
||||
if[ \t]*\( {
|
||||
string_buf_ptr = string_buf;
|
||||
parren_count = 1;
|
||||
BEGIN CEXPR;
|
||||
return T_IF;
|
||||
}
|
||||
<CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; }
|
||||
<CEXPR>\) {
|
||||
parren_count--;
|
||||
if (parren_count == 0) {
|
||||
/* All done */
|
||||
BEGIN INITIAL;
|
||||
*string_buf_ptr = '\0';
|
||||
yylval.sym = symtable_get(string_buf);
|
||||
return T_CEXPR;
|
||||
} else {
|
||||
*string_buf_ptr++ = ')';
|
||||
}
|
||||
}
|
||||
<CEXPR>\n { ++yylineno; }
|
||||
<CEXPR>[^()\n]+ {
|
||||
char *yptr = yytext;
|
||||
|
||||
while (*yptr != '\0')
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
}
|
||||
|
||||
{SPACE} ;
|
||||
|
||||
/* Register/SCB/SRAM definition keywords */
|
||||
register { return T_REGISTER; }
|
||||
const { yylval.value = FALSE; return T_CONST; }
|
||||
download { return T_DOWNLOAD; }
|
||||
address { return T_ADDRESS; }
|
||||
access_mode { return T_ACCESS_MODE; }
|
||||
RW|RO|WO {
|
||||
if (strcmp(yytext, "RW") == 0)
|
||||
yylval.value = RW;
|
||||
else if (strcmp(yytext, "RO") == 0)
|
||||
yylval.value = RO;
|
||||
else
|
||||
yylval.value = WO;
|
||||
return T_MODE;
|
||||
}
|
||||
bit { return T_BIT; }
|
||||
mask { return T_MASK; }
|
||||
alias { return T_ALIAS; }
|
||||
size { return T_SIZE; }
|
||||
scb { return T_SCB; }
|
||||
scratch_ram { return T_SRAM; }
|
||||
accumulator { return T_ACCUM; }
|
||||
allones { return T_ALLONES; }
|
||||
allzeros { return T_ALLZEROS; }
|
||||
none { return T_NONE; }
|
||||
sindex { return T_SINDEX; }
|
||||
A { return T_A; }
|
||||
|
||||
/* Opcodes */
|
||||
shl { return T_SHL; }
|
||||
shr { return T_SHR; }
|
||||
ror { return T_ROR; }
|
||||
rol { return T_ROL; }
|
||||
mvi { return T_MVI; }
|
||||
mov { return T_MOV; }
|
||||
clr { return T_CLR; }
|
||||
jmp { return T_JMP; }
|
||||
jc { return T_JC; }
|
||||
jnc { return T_JNC; }
|
||||
je { return T_JE; }
|
||||
jne { return T_JNE; }
|
||||
jz { return T_JZ; }
|
||||
jnz { return T_JNZ; }
|
||||
call { return T_CALL; }
|
||||
add { return T_ADD; }
|
||||
adc { return T_ADC; }
|
||||
bmov { return T_BMOV; }
|
||||
inc { return T_INC; }
|
||||
dec { return T_DEC; }
|
||||
stc { return T_STC; }
|
||||
clc { return T_CLC; }
|
||||
cmp { return T_CMP; }
|
||||
not { return T_NOT; }
|
||||
xor { return T_XOR; }
|
||||
test { return T_TEST;}
|
||||
and { return T_AND; }
|
||||
or { return T_OR; }
|
||||
ret { return T_RET; }
|
||||
nop { return T_NOP; }
|
||||
else { return T_ELSE; }
|
||||
|
||||
/* Allowed Symbols */
|
||||
[-+,:()~|&."{};<>[\]!] { return yytext[0]; }
|
||||
|
||||
/* Number processing */
|
||||
0[0-7]* {
|
||||
yylval.value = strtol(yytext, NULL, 8);
|
||||
return T_NUMBER;
|
||||
}
|
||||
|
||||
0[xX][0-9a-fA-F]+ {
|
||||
yylval.value = strtoul(yytext + 2, NULL, 16);
|
||||
return T_NUMBER;
|
||||
}
|
||||
|
||||
[1-9][0-9]* {
|
||||
yylval.value = strtol(yytext, NULL, 10);
|
||||
return T_NUMBER;
|
||||
}
|
||||
|
||||
/* Include Files */
|
||||
#include { return T_INCLUDE; BEGIN INCLUDE;}
|
||||
<INCLUDE>[<>\"] { return yytext[0]; }
|
||||
<INCLUDE>{PATH} { yylval.str = strdup(yytext); return T_PATH; }
|
||||
<INCLUDE>; { BEGIN INITIAL; return yytext[0]; }
|
||||
<INCLUDE>. { stop("Invalid include line", EX_DATAERR); }
|
||||
|
||||
/* For parsing C include files with #define foo */
|
||||
#define { yylval.value = TRUE; return T_CONST; }
|
||||
/* Throw away macros */
|
||||
#define[^\n]*[()]+[^\n]* ;
|
||||
{PATH} { yylval.str = strdup(yytext); return T_PATH; }
|
||||
|
||||
{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; }
|
||||
|
||||
. {
|
||||
char buf[255];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Invalid character "
|
||||
"'%c'", yytext[0]);
|
||||
stop(buf, EX_DATAERR);
|
||||
}
|
||||
%%
|
||||
|
||||
typedef struct include {
|
||||
YY_BUFFER_STATE buffer;
|
||||
int lineno;
|
||||
char *filename;
|
||||
SLIST_ENTRY(include) links;
|
||||
}include_t;
|
||||
|
||||
SLIST_HEAD(, include) include_stack;
|
||||
|
||||
void
|
||||
include_file(file_name, type)
|
||||
char *file_name;
|
||||
include_type type;
|
||||
{
|
||||
FILE *newfile;
|
||||
include_t *include;
|
||||
|
||||
newfile = NULL;
|
||||
/* Try the current directory first */
|
||||
if (includes_search_curdir != 0 || type == SOURCE_FILE)
|
||||
newfile = fopen(file_name, "r");
|
||||
|
||||
if (newfile == NULL && type != SOURCE_FILE) {
|
||||
path_entry_t include_dir;
|
||||
for (include_dir = search_path.slh_first;
|
||||
include_dir != NULL;
|
||||
include_dir = include_dir->links.sle_next) {
|
||||
char fullname[PATH_MAX];
|
||||
|
||||
if ((include_dir->quoted_includes_only == TRUE)
|
||||
&& (type != QUOTED_INCLUDE))
|
||||
continue;
|
||||
|
||||
snprintf(fullname, sizeof(fullname),
|
||||
"%s/%s", include_dir->directory, file_name);
|
||||
|
||||
if ((newfile = fopen(fullname, "r")) != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newfile == NULL) {
|
||||
perror(file_name);
|
||||
stop("Unable to open input file", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (type != SOURCE_FILE) {
|
||||
include = (include_t *)malloc(sizeof(include_t));
|
||||
if (include == NULL) {
|
||||
stop("Unable to allocate include stack entry",
|
||||
EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
include->buffer = YY_CURRENT_BUFFER;
|
||||
include->lineno = yylineno;
|
||||
include->filename = yyfilename;
|
||||
SLIST_INSERT_HEAD(&include_stack, include, links);
|
||||
}
|
||||
yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
|
||||
yylineno = 1;
|
||||
yyfilename = strdup(file_name);
|
||||
}
|
||||
|
||||
int
|
||||
yywrap()
|
||||
{
|
||||
include_t *include;
|
||||
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
(void)fclose(yyin);
|
||||
if (yyfilename != NULL)
|
||||
free(yyfilename);
|
||||
yyfilename = NULL;
|
||||
include = include_stack.slh_first;
|
||||
if (include != NULL) {
|
||||
yy_switch_to_buffer(include->buffer);
|
||||
yylineno = include->lineno;
|
||||
yyfilename = include->filename;
|
||||
SLIST_REMOVE_HEAD(&include_stack, links);
|
||||
free(include);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
@ -1,475 +0,0 @@
|
||||
/*
|
||||
* Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <db.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm.h"
|
||||
|
||||
static DB *symtable;
|
||||
|
||||
symbol_t *
|
||||
symbol_create(name)
|
||||
char *name;
|
||||
{
|
||||
symbol_t *new_symbol;
|
||||
|
||||
new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
|
||||
if (new_symbol == NULL) {
|
||||
perror("Unable to create new symbol");
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
memset(new_symbol, 0, sizeof(*new_symbol));
|
||||
new_symbol->name = strdup(name);
|
||||
new_symbol->type = UNINITIALIZED;
|
||||
return (new_symbol);
|
||||
}
|
||||
|
||||
void
|
||||
symbol_delete(symbol)
|
||||
symbol_t *symbol;
|
||||
{
|
||||
if (symtable != NULL) {
|
||||
DBT key;
|
||||
|
||||
key.data = symbol->name;
|
||||
key.size = strlen(symbol->name);
|
||||
symtable->del(symtable, &key, /*flags*/0);
|
||||
}
|
||||
switch(symbol->type) {
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
case REGISTER:
|
||||
if (symbol->info.rinfo != NULL)
|
||||
free(symbol->info.rinfo);
|
||||
break;
|
||||
case ALIAS:
|
||||
if (symbol->info.ainfo != NULL)
|
||||
free(symbol->info.ainfo);
|
||||
break;
|
||||
case MASK:
|
||||
case BIT:
|
||||
if (symbol->info.minfo != NULL) {
|
||||
symlist_free(&symbol->info.minfo->symrefs);
|
||||
free(symbol->info.minfo);
|
||||
}
|
||||
break;
|
||||
case DOWNLOAD_CONST:
|
||||
case CONST:
|
||||
if (symbol->info.cinfo != NULL)
|
||||
free(symbol->info.cinfo);
|
||||
break;
|
||||
case LABEL:
|
||||
if (symbol->info.linfo != NULL)
|
||||
free(symbol->info.linfo);
|
||||
break;
|
||||
case UNINITIALIZED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(symbol->name);
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
void
|
||||
symtable_open()
|
||||
{
|
||||
symtable = dbopen(/*filename*/NULL,
|
||||
O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
|
||||
/*openinfo*/NULL);
|
||||
|
||||
if (symtable == NULL) {
|
||||
perror("Symbol table creation failed");
|
||||
exit(EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
symtable_close()
|
||||
{
|
||||
if (symtable != NULL) {
|
||||
DBT key;
|
||||
DBT data;
|
||||
|
||||
while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
|
||||
symbol_t *stored_ptr;
|
||||
|
||||
memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
|
||||
symbol_delete(stored_ptr);
|
||||
}
|
||||
symtable->close(symtable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The semantics of get is to return an uninitialized symbol entry
|
||||
* if a lookup fails.
|
||||
*/
|
||||
symbol_t *
|
||||
symtable_get(name)
|
||||
char *name;
|
||||
{
|
||||
symbol_t *stored_ptr;
|
||||
DBT key;
|
||||
DBT data;
|
||||
int retval;
|
||||
|
||||
key.data = (void *)name;
|
||||
key.size = strlen(name);
|
||||
|
||||
if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
|
||||
if (retval == -1) {
|
||||
perror("Symbol table get operation failed");
|
||||
exit(EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
} else if (retval == 1) {
|
||||
/* Symbol wasn't found, so create a new one */
|
||||
symbol_t *new_symbol;
|
||||
|
||||
new_symbol = symbol_create(name);
|
||||
data.data = &new_symbol;
|
||||
data.size = sizeof(new_symbol);
|
||||
if (symtable->put(symtable, &key, &data,
|
||||
/*flags*/0) !=0) {
|
||||
perror("Symtable put failed");
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
return (new_symbol);
|
||||
} else {
|
||||
perror("Unexpected return value from db get routine");
|
||||
exit(EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
|
||||
return (stored_ptr);
|
||||
}
|
||||
|
||||
symbol_node_t *
|
||||
symlist_search(symlist, symname)
|
||||
symlist_t *symlist;
|
||||
char *symname;
|
||||
{
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = symlist->slh_first;
|
||||
while(curnode != NULL) {
|
||||
if (strcmp(symname, curnode->symbol->name) == 0)
|
||||
break;
|
||||
curnode = curnode->links.sle_next;
|
||||
}
|
||||
return (curnode);
|
||||
}
|
||||
|
||||
void
|
||||
symlist_add(symlist, symbol, how)
|
||||
symlist_t *symlist;
|
||||
symbol_t *symbol;
|
||||
int how;
|
||||
{
|
||||
symbol_node_t *newnode;
|
||||
|
||||
newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
|
||||
if (newnode == NULL) {
|
||||
stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
newnode->symbol = symbol;
|
||||
if (how == SYMLIST_SORT) {
|
||||
symbol_node_t *curnode;
|
||||
int mask;
|
||||
|
||||
mask = FALSE;
|
||||
switch(symbol->type) {
|
||||
case REGISTER:
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
break;
|
||||
case BIT:
|
||||
case MASK:
|
||||
mask = TRUE;
|
||||
break;
|
||||
default:
|
||||
stop("symlist_add: Invalid symbol type for sorting",
|
||||
EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
curnode = symlist->slh_first;
|
||||
if (curnode == NULL
|
||||
|| (mask && (curnode->symbol->info.minfo->mask >
|
||||
newnode->symbol->info.minfo->mask))
|
||||
|| (!mask && (curnode->symbol->info.rinfo->address >
|
||||
newnode->symbol->info.rinfo->address))) {
|
||||
SLIST_INSERT_HEAD(symlist, newnode, links);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (curnode->links.sle_next == NULL) {
|
||||
SLIST_INSERT_AFTER(curnode, newnode,
|
||||
links);
|
||||
break;
|
||||
} else {
|
||||
symbol_t *cursymbol;
|
||||
|
||||
cursymbol = curnode->links.sle_next->symbol;
|
||||
if ((mask && (cursymbol->info.minfo->mask >
|
||||
symbol->info.minfo->mask))
|
||||
|| (!mask &&(cursymbol->info.rinfo->address >
|
||||
symbol->info.rinfo->address))){
|
||||
SLIST_INSERT_AFTER(curnode, newnode,
|
||||
links);
|
||||
break;
|
||||
}
|
||||
}
|
||||
curnode = curnode->links.sle_next;
|
||||
}
|
||||
} else {
|
||||
SLIST_INSERT_HEAD(symlist, newnode, links);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
symlist_free(symlist)
|
||||
symlist_t *symlist;
|
||||
{
|
||||
symbol_node_t *node1, *node2;
|
||||
|
||||
node1 = symlist->slh_first;
|
||||
while (node1 != NULL) {
|
||||
node2 = node1->links.sle_next;
|
||||
free(node1);
|
||||
node1 = node2;
|
||||
}
|
||||
SLIST_INIT(symlist);
|
||||
}
|
||||
|
||||
void
|
||||
symlist_merge(symlist_dest, symlist_src1, symlist_src2)
|
||||
symlist_t *symlist_dest;
|
||||
symlist_t *symlist_src1;
|
||||
symlist_t *symlist_src2;
|
||||
{
|
||||
symbol_node_t *node;
|
||||
|
||||
*symlist_dest = *symlist_src1;
|
||||
while((node = symlist_src2->slh_first) != NULL) {
|
||||
SLIST_REMOVE_HEAD(symlist_src2, links);
|
||||
SLIST_INSERT_HEAD(symlist_dest, node, links);
|
||||
}
|
||||
|
||||
/* These are now empty */
|
||||
SLIST_INIT(symlist_src1);
|
||||
SLIST_INIT(symlist_src2);
|
||||
}
|
||||
|
||||
void
|
||||
symtable_dump(ofile)
|
||||
FILE *ofile;
|
||||
{
|
||||
/*
|
||||
* Sort the registers by address with a simple insertion sort.
|
||||
* Put bitmasks next to the first register that defines them.
|
||||
* Put constants at the end.
|
||||
*/
|
||||
symlist_t registers;
|
||||
symlist_t masks;
|
||||
symlist_t constants;
|
||||
symlist_t download_constants;
|
||||
symlist_t aliases;
|
||||
|
||||
SLIST_INIT(®isters);
|
||||
SLIST_INIT(&masks);
|
||||
SLIST_INIT(&constants);
|
||||
SLIST_INIT(&download_constants);
|
||||
SLIST_INIT(&aliases);
|
||||
|
||||
if (symtable != NULL) {
|
||||
DBT key;
|
||||
DBT data;
|
||||
int flag = R_FIRST;
|
||||
|
||||
while (symtable->seq(symtable, &key, &data, flag) == 0) {
|
||||
symbol_t *cursym;
|
||||
|
||||
memcpy(&cursym, data.data, sizeof(cursym));
|
||||
switch(cursym->type) {
|
||||
case REGISTER:
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
symlist_add(®isters, cursym, SYMLIST_SORT);
|
||||
break;
|
||||
case MASK:
|
||||
case BIT:
|
||||
symlist_add(&masks, cursym, SYMLIST_SORT);
|
||||
break;
|
||||
case CONST:
|
||||
if (cursym->info.cinfo->define == FALSE) {
|
||||
symlist_add(&constants, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
}
|
||||
break;
|
||||
case DOWNLOAD_CONST:
|
||||
symlist_add(&download_constants, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
break;
|
||||
case ALIAS:
|
||||
symlist_add(&aliases, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flag = R_NEXT;
|
||||
}
|
||||
|
||||
/* Put in the masks and bits */
|
||||
while (masks.slh_first != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
symbol_node_t *regnode;
|
||||
char *regname;
|
||||
|
||||
curnode = masks.slh_first;
|
||||
SLIST_REMOVE_HEAD(&masks, links);
|
||||
|
||||
regnode =
|
||||
curnode->symbol->info.minfo->symrefs.slh_first;
|
||||
regname = regnode->symbol->name;
|
||||
regnode = symlist_search(®isters, regname);
|
||||
SLIST_INSERT_AFTER(regnode, curnode, links);
|
||||
}
|
||||
|
||||
/* Add the aliases */
|
||||
while (aliases.slh_first != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
symbol_node_t *regnode;
|
||||
char *regname;
|
||||
|
||||
curnode = aliases.slh_first;
|
||||
SLIST_REMOVE_HEAD(&aliases, links);
|
||||
|
||||
regname = curnode->symbol->info.ainfo->parent->name;
|
||||
regnode = symlist_search(®isters, regname);
|
||||
SLIST_INSERT_AFTER(regnode, curnode, links);
|
||||
}
|
||||
|
||||
/* Output what we have */
|
||||
fprintf(ofile,
|
||||
"/*
|
||||
* DO NOT EDIT - This file is automatically generated.
|
||||
*/\n");
|
||||
while (registers.slh_first != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
uint8_t value;
|
||||
char *tab_str;
|
||||
char *tab_str2;
|
||||
|
||||
curnode = registers.slh_first;
|
||||
SLIST_REMOVE_HEAD(®isters, links);
|
||||
switch(curnode->symbol->type) {
|
||||
case REGISTER:
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
fprintf(ofile, "\n");
|
||||
value = curnode->symbol->info.rinfo->address;
|
||||
tab_str = "\t";
|
||||
tab_str2 = "\t\t";
|
||||
break;
|
||||
case ALIAS:
|
||||
{
|
||||
symbol_t *parent;
|
||||
|
||||
parent = curnode->symbol->info.ainfo->parent;
|
||||
value = parent->info.rinfo->address;
|
||||
tab_str = "\t";
|
||||
tab_str2 = "\t\t";
|
||||
break;
|
||||
}
|
||||
case MASK:
|
||||
case BIT:
|
||||
value = curnode->symbol->info.minfo->mask;
|
||||
tab_str = "\t\t";
|
||||
tab_str2 = "\t";
|
||||
break;
|
||||
default:
|
||||
value = 0; /* Quiet compiler */
|
||||
tab_str = NULL;
|
||||
tab_str2 = NULL;
|
||||
stop("symtable_dump: Invalid symbol type "
|
||||
"encountered", EX_SOFTWARE);
|
||||
break;
|
||||
}
|
||||
fprintf(ofile, "#define%s%-16s%s0x%02x\n",
|
||||
tab_str, curnode->symbol->name, tab_str2,
|
||||
value);
|
||||
free(curnode);
|
||||
}
|
||||
fprintf(ofile, "\n\n");
|
||||
|
||||
while (constants.slh_first != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = constants.slh_first;
|
||||
SLIST_REMOVE_HEAD(&constants, links);
|
||||
fprintf(ofile, "#define\t%-8s\t0x%02x\n",
|
||||
curnode->symbol->name,
|
||||
curnode->symbol->info.cinfo->value);
|
||||
free(curnode);
|
||||
}
|
||||
|
||||
|
||||
fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
|
||||
|
||||
while (download_constants.slh_first != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = download_constants.slh_first;
|
||||
SLIST_REMOVE_HEAD(&download_constants, links);
|
||||
fprintf(ofile, "#define\t%-8s\t0x%02x\n",
|
||||
curnode->symbol->name,
|
||||
curnode->symbol->info.cinfo->value);
|
||||
free(curnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* 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, 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.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
typedef enum {
|
||||
UNINITIALIZED,
|
||||
REGISTER,
|
||||
ALIAS,
|
||||
SCBLOC,
|
||||
SRAMLOC,
|
||||
MASK,
|
||||
BIT,
|
||||
CONST,
|
||||
DOWNLOAD_CONST,
|
||||
LABEL,
|
||||
CONDITIONAL
|
||||
}symtype;
|
||||
|
||||
typedef enum {
|
||||
RO = 0x01,
|
||||
WO = 0x02,
|
||||
RW = 0x03
|
||||
}amode_t;
|
||||
|
||||
struct reg_info {
|
||||
uint8_t address;
|
||||
int size;
|
||||
amode_t mode;
|
||||
uint8_t valid_bitmask;
|
||||
int typecheck_masks;
|
||||
};
|
||||
|
||||
typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
|
||||
|
||||
struct mask_info {
|
||||
symlist_t symrefs;
|
||||
uint8_t mask;
|
||||
};
|
||||
|
||||
struct const_info {
|
||||
uint8_t value;
|
||||
int define;
|
||||
};
|
||||
|
||||
struct alias_info {
|
||||
struct symbol *parent;
|
||||
};
|
||||
|
||||
struct label_info {
|
||||
int address;
|
||||
};
|
||||
|
||||
struct cond_info {
|
||||
int func_num;
|
||||
};
|
||||
|
||||
typedef struct expression_info {
|
||||
symlist_t referenced_syms;
|
||||
int value;
|
||||
} expression_t;
|
||||
|
||||
typedef struct symbol {
|
||||
char *name;
|
||||
symtype type;
|
||||
union {
|
||||
struct reg_info *rinfo;
|
||||
struct mask_info *minfo;
|
||||
struct const_info *cinfo;
|
||||
struct alias_info *ainfo;
|
||||
struct label_info *linfo;
|
||||
struct cond_info *condinfo;
|
||||
}info;
|
||||
} symbol_t;
|
||||
|
||||
typedef struct symbol_ref {
|
||||
symbol_t *symbol;
|
||||
int offset;
|
||||
} symbol_ref_t;
|
||||
|
||||
typedef struct symbol_node {
|
||||
SLIST_ENTRY(symbol_node) links;
|
||||
symbol_t *symbol;
|
||||
}symbol_node_t;
|
||||
|
||||
typedef enum {
|
||||
SCOPE_ROOT,
|
||||
SCOPE_IF,
|
||||
SCOPE_ELSE_IF,
|
||||
SCOPE_ELSE
|
||||
} scope_type;
|
||||
|
||||
typedef struct patch_info {
|
||||
int skip_patch;
|
||||
int skip_instr;
|
||||
} patch_info_t;
|
||||
|
||||
typedef struct scope {
|
||||
SLIST_ENTRY(scope) scope_stack_links;
|
||||
TAILQ_ENTRY(scope) scope_links;
|
||||
TAILQ_HEAD(, scope) inner_scope;
|
||||
scope_type type;
|
||||
int inner_scope_patches;
|
||||
int begin_addr;
|
||||
int end_addr;
|
||||
patch_info_t patches[2];
|
||||
int func_num;
|
||||
} scope_t;
|
||||
|
||||
SLIST_HEAD(scope_list, scope);
|
||||
TAILQ_HEAD(scope_tailq, scope);
|
||||
|
||||
void symbol_delete __P((symbol_t *symbol));
|
||||
|
||||
void symtable_open __P((void));
|
||||
|
||||
void symtable_close __P((void));
|
||||
|
||||
symbol_t *
|
||||
symtable_get __P((char *name));
|
||||
|
||||
symbol_node_t *
|
||||
symlist_search __P((symlist_t *symlist, char *symname));
|
||||
|
||||
void
|
||||
symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
|
||||
#define SYMLIST_INSERT_HEAD 0x00
|
||||
#define SYMLIST_SORT 0x01
|
||||
|
||||
void symlist_free __P((symlist_t *symlist));
|
||||
|
||||
void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
|
||||
symlist_t *symlist_src2));
|
||||
void symtable_dump __P((FILE *ofile));
|
Loading…
x
Reference in New Issue
Block a user