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:
Justin T. Gibbs 2000-09-16 20:02:28 +00:00
parent 0562034333
commit 717d424718
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=65942
25 changed files with 11674 additions and 11364 deletions

View File

@ -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);
}

View File

@ -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 */

View File

@ -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>

View File

@ -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 *)&sc;
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
View 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 *)&sc;
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

View File

@ -28,6 +28,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*
* $FreeBSD$
*/

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

View 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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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(&registers);
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(&registers, 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(&registers, 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(&registers, 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(&registers, 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);
}
}
}

View File

@ -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));