aic7xxx.c:
aic7xxx.h: Split out core chip initialization into ahc_chip_init(). This will allow us to reset the chip correctly at times other than initial chip setup. aic7770.c aic7xxx_pci.c: Flesh out bus chip init methods for our two bus attachments and use these, in addition to bus suspend/resume hooks to get the core in better shape for handling these events. When disabling PCI parity error checking, use FAILDIS. Although the chip docs indicate that clearing PERRESPEN should also work, it does not. Auto-disable pci parity error checking after informing the user of AHC_PCI_TARGET_PERR_THRESH number of parity errors observed as a target. aic7xxx.h: aic7xxx_pci.c aic7770.c aic7xxx.c Add the instruction_ram_size softc field. Remove the now unused stack_size softc field. Modify ahc_loadseq to return a failure code and to actually check the downloaded instruction count against the limit set in our softc. Modify callers of ahc_loadseq to handle load failures as appropriate. Set instruction RAM sizes for each chip type. aic7xxx_pci.c: Add some delay in the aic785X termination control code. This may fix problems with the 2930. Be consistent in how we access config space registers. 16bit registers are accessed using 16bit ops. aic7xxx.c: Correct spelling errors. Have ahc_force_renegotiation() take a devinfo as is done in the U320 driver. Use this argument to correct a bug in the selection timeout handler where we forced a renegotiation with the last device that had set SAVED_SCSIID. SAVED_SCSIID is only updated once a selection is *sucessfull* and so is stale for any selection timeout. Cleanup the setup of the devinfo for busfree events. We now use this devinfo for a call to ahc_force_renegotiation() at the bottom of the routine, so it must be initialized in all cases. In ahc_pause_and_flushwork(), adjust the loop so that it will exit in the hot-eject case even if the INT_PEND mask is something other than 0xFF (as it is in this driver). Correct a wrapping string constant. Call ahc_fini_scbdata() after shutdown so that any ahc_chip_init() routine that might access SCB data will not access free'd memory. Correctly setup our buffer tag to indicate that 39bit addressing is available if in 39bit addressing mode. Rearrange some variable declarations based on type size. aic7xxx.c aic7xxx.h: aic7xxx.reg: Consistently use MAX_OFFSET for the user max syncrate set from non-volatile storage. This ensures that the offset does not conflict with AHC_OFFSET_UNKNOWN. Change AHC_OFFSET_UNKNOWN to 0xFF. This is a value that the curr->offset can never be, unlike '0' which we previously used. This fixes code that only checks for a non-zero offset to determine if a sync negotiation is required since it will fire in the unknown case even if the goal is async. Change MAX_OFFSET to 0x7f which is the max offset U160 aic7xxx controllers can negotiate. This ensures that curr->offset will not match AHC_OFFSET_UNKNOWN. aic7xxx_inline.h: Have our inline interrupt handler return with a value indicating whether we serviced a real interrupt. This is required for Linux support. Return earlier if the interrupt is not for us.
This commit is contained in:
parent
1b744451fb
commit
c10f64d256
@ -37,7 +37,7 @@
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7770.c#27 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7770.c#30 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -59,6 +59,9 @@
|
||||
#define ID_OLV_274x 0x04907782 /* Olivetti OEM */
|
||||
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
|
||||
|
||||
static int aic7770_chip_init(struct ahc_softc *ahc);
|
||||
static int aic7770_suspend(struct ahc_softc *ahc);
|
||||
static int aic7770_resume(struct ahc_softc *ahc);
|
||||
static int 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;;
|
||||
@ -144,6 +147,12 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
|
||||
|
||||
ahc->description = entry->name;
|
||||
error = ahc_softc_init(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahc->bus_chip_init = aic7770_chip_init;
|
||||
ahc->bus_suspend = aic7770_suspend;
|
||||
ahc->bus_resume = aic7770_resume;
|
||||
|
||||
error = ahc_reset(ahc);
|
||||
if (error != 0)
|
||||
@ -226,6 +235,9 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
|
||||
ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
|
||||
ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
|
||||
|
||||
ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH;
|
||||
ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF;
|
||||
|
||||
/*
|
||||
* Generic aic7xxx initialization.
|
||||
*/
|
||||
@ -253,6 +265,28 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aic7770_chip_init(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd);
|
||||
ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime);
|
||||
ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
|
||||
ahc_outb(ahc, BCTL, ENABLE);
|
||||
return (ahc_chip_init(ahc));
|
||||
}
|
||||
|
||||
static int
|
||||
aic7770_suspend(struct ahc_softc *ahc)
|
||||
{
|
||||
return (ahc_suspend(ahc));
|
||||
}
|
||||
|
||||
static int
|
||||
aic7770_resume(struct ahc_softc *ahc)
|
||||
{
|
||||
return (ahc_resume(ahc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the 284x SEEPROM.
|
||||
*/
|
||||
@ -280,7 +314,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
|
||||
if (bootverbose)
|
||||
printf("%s: Reading SEEPROM...", ahc_name(ahc));
|
||||
have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
|
||||
/*start_addr*/0, sizeof(sc)/2);
|
||||
/*start_addr*/0, sizeof(*sc)/2);
|
||||
|
||||
if (have_seeprom) {
|
||||
|
||||
@ -371,5 +405,6 @@ ahc_aic7770_setup(struct ahc_softc *ahc)
|
||||
ahc->features = AHC_AIC7770_FE;
|
||||
ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
|
||||
ahc->flags |= AHC_PAGESCBS;
|
||||
ahc->instruction_ram_size = 448;
|
||||
return (0);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,7 @@
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#70 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#75 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -365,14 +365,15 @@ typedef enum {
|
||||
AHC_LSCBS_ENABLED = 0x2000000, /* 64Byte SCBs enabled */
|
||||
AHC_SCB_CONFIG_USED = 0x4000000, /* No SEEPROM but SCB2 had info. */
|
||||
AHC_NO_BIOS_INIT = 0x8000000, /* No BIOS left over settings. */
|
||||
AHC_DISABLE_PCI_PERR = 0x10000000
|
||||
AHC_DISABLE_PCI_PERR = 0x10000000,
|
||||
AHC_HAS_TERM_LOGIC = 0x20000000
|
||||
} ahc_flag;
|
||||
|
||||
/************************* Hardware SCB Definition ***************************/
|
||||
|
||||
/*
|
||||
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
|
||||
* consists of a "hardware SCB" mirroring the fields availible on the card
|
||||
* consists of a "hardware SCB" mirroring the fields available on the card
|
||||
* and additional information the kernel stores for each transaction.
|
||||
*
|
||||
* To minimize space utilization, a portion of the hardware scb stores
|
||||
@ -691,7 +692,7 @@ struct ahc_tmode_lstate;
|
||||
|
||||
#define AHC_WIDTH_UNKNOWN 0xFF
|
||||
#define AHC_PERIOD_UNKNOWN 0xFF
|
||||
#define AHC_OFFSET_UNKNOWN 0x0
|
||||
#define AHC_OFFSET_UNKNOWN 0xFF
|
||||
#define AHC_PPR_OPTS_UNKNOWN 0xFF
|
||||
|
||||
/*
|
||||
@ -877,31 +878,39 @@ typedef enum {
|
||||
/*********************** Software Configuration Structure *********************/
|
||||
TAILQ_HEAD(scb_tailq, scb);
|
||||
|
||||
struct ahc_suspend_channel_state {
|
||||
uint8_t scsiseq;
|
||||
uint8_t sxfrctl0;
|
||||
uint8_t sxfrctl1;
|
||||
uint8_t simode0;
|
||||
uint8_t simode1;
|
||||
uint8_t seltimer;
|
||||
uint8_t seqctl;
|
||||
struct ahc_aic7770_softc {
|
||||
/*
|
||||
* Saved register state used for chip_init().
|
||||
*/
|
||||
uint8_t busspd;
|
||||
uint8_t bustime;
|
||||
};
|
||||
|
||||
struct ahc_suspend_state {
|
||||
struct ahc_suspend_channel_state channel[2];
|
||||
uint8_t optionmode;
|
||||
uint8_t dscommand0;
|
||||
uint8_t dspcistatus;
|
||||
/* hsmailbox */
|
||||
uint8_t crccontrol1;
|
||||
uint8_t scbbaddr;
|
||||
/* Host and sequencer SCB counts */
|
||||
uint8_t dff_thrsh;
|
||||
uint8_t *scratch_ram;
|
||||
uint8_t *btt;
|
||||
struct ahc_pci_softc {
|
||||
/*
|
||||
* Saved register state used for chip_init().
|
||||
*/
|
||||
uint32_t devconfig;
|
||||
uint16_t targcrccnt;
|
||||
uint8_t command;
|
||||
uint8_t csize_lattime;
|
||||
uint8_t optionmode;
|
||||
uint8_t crccontrol1;
|
||||
uint8_t dscommand0;
|
||||
uint8_t dspcistatus;
|
||||
uint8_t scbbaddr;
|
||||
uint8_t dff_thrsh;
|
||||
};
|
||||
|
||||
union ahc_bus_softc {
|
||||
struct ahc_aic7770_softc aic7770_softc;
|
||||
struct ahc_pci_softc pci_softc;
|
||||
};
|
||||
|
||||
typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
|
||||
typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
|
||||
typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
|
||||
typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
|
||||
typedef void ahc_callback_t (void *);
|
||||
|
||||
struct ahc_softc {
|
||||
@ -936,6 +945,11 @@ struct ahc_softc {
|
||||
*/
|
||||
struct scb_tailq untagged_queues[AHC_NUM_TARGETS];
|
||||
|
||||
/*
|
||||
* Bus attachment specific data.
|
||||
*/
|
||||
union ahc_bus_softc bus_softc;
|
||||
|
||||
/*
|
||||
* Platform specific data.
|
||||
*/
|
||||
@ -951,6 +965,22 @@ struct ahc_softc {
|
||||
*/
|
||||
ahc_bus_intr_t bus_intr;
|
||||
|
||||
/*
|
||||
* Bus specific initialization required
|
||||
* after a chip reset.
|
||||
*/
|
||||
ahc_bus_chip_init_t bus_chip_init;
|
||||
|
||||
/*
|
||||
* Bus specific suspend routine.
|
||||
*/
|
||||
ahc_bus_suspend_t bus_suspend;
|
||||
|
||||
/*
|
||||
* Bus specific resume routine.
|
||||
*/
|
||||
ahc_bus_resume_t bus_resume;
|
||||
|
||||
/*
|
||||
* Target mode related state kept on a per enabled lun basis.
|
||||
* Targets that are not enabled will have null entries.
|
||||
@ -1043,9 +1073,6 @@ struct ahc_softc {
|
||||
*/
|
||||
bus_addr_t dma_bug_buf;
|
||||
|
||||
/* Information saved through suspend/resume cycles */
|
||||
struct ahc_suspend_state suspend_state;
|
||||
|
||||
/* Number of enabled target mode device on this card */
|
||||
u_int enabled_luns;
|
||||
|
||||
@ -1055,7 +1082,16 @@ struct ahc_softc {
|
||||
/* PCI cacheline size. */
|
||||
u_int pci_cachesize;
|
||||
|
||||
u_int stack_size;
|
||||
/*
|
||||
* Count of parity errors we have seen as a target.
|
||||
* We auto-disable parity error checking after seeing
|
||||
* AHC_PCI_TARGET_PERR_THRESH number of errors.
|
||||
*/
|
||||
u_int pci_target_perr_count;
|
||||
#define AHC_PCI_TARGET_PERR_THRESH 10
|
||||
|
||||
/* Maximum number of sequencer instructions supported. */
|
||||
u_int instruction_ram_size;
|
||||
|
||||
/* Per-Unit descriptive information */
|
||||
const char *description;
|
||||
@ -1152,6 +1188,7 @@ int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
|
||||
struct ahc_softc *ahc_alloc(void *platform_arg, char *name);
|
||||
int ahc_softc_init(struct ahc_softc *);
|
||||
void ahc_controller_info(struct ahc_softc *ahc, char *buf);
|
||||
int ahc_chip_init(struct ahc_softc *ahc);
|
||||
int ahc_init(struct ahc_softc *ahc);
|
||||
void ahc_intr_enable(struct ahc_softc *ahc, int enable);
|
||||
void ahc_pause_and_flushwork(struct ahc_softc *ahc);
|
||||
@ -1167,7 +1204,6 @@ int ahc_reset(struct ahc_softc *ahc);
|
||||
void ahc_shutdown(void *arg);
|
||||
|
||||
/*************************** Interrupt Services *******************************/
|
||||
void ahc_pci_intr(struct ahc_softc *ahc);
|
||||
void ahc_clear_intstat(struct ahc_softc *ahc);
|
||||
void ahc_run_qoutfifo(struct ahc_softc *ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
|
@ -39,7 +39,7 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $"
|
||||
VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $"
|
||||
|
||||
/*
|
||||
* This file is processed by the aic7xxx_asm utility for use in assembling
|
||||
@ -1580,7 +1580,7 @@ const BUS_32_BIT 0x02
|
||||
const MAX_OFFSET_8BIT 0x0f
|
||||
const MAX_OFFSET_16BIT 0x08
|
||||
const MAX_OFFSET_ULTRA2 0x7f
|
||||
const MAX_OFFSET 0xff
|
||||
const MAX_OFFSET 0x7f
|
||||
const HOST_MSG 0xff
|
||||
|
||||
/* Target mode command processing constants */
|
||||
|
@ -37,7 +37,7 @@
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#39 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#42 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -460,7 +460,7 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
|
||||
|
||||
/*
|
||||
* Make sure our data is consistant from the
|
||||
* Make sure our data is consistent from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
@ -500,7 +500,7 @@ ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
|
||||
static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
|
||||
static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
|
||||
static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
|
||||
static __inline void ahc_intr(struct ahc_softc *ahc);
|
||||
static __inline int ahc_intr(struct ahc_softc *ahc);
|
||||
|
||||
static __inline void
|
||||
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
|
||||
@ -558,7 +558,7 @@ ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
static __inline void
|
||||
static __inline int
|
||||
ahc_intr(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int intstat;
|
||||
@ -570,7 +570,7 @@ ahc_intr(struct ahc_softc *ahc)
|
||||
* so just return. This is likely just a shared
|
||||
* interrupt.
|
||||
*/
|
||||
return;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
@ -585,6 +585,20 @@ ahc_intr(struct ahc_softc *ahc)
|
||||
intstat = ahc_inb(ahc, INTSTAT);
|
||||
}
|
||||
|
||||
if ((intstat & INT_PEND) == 0) {
|
||||
#if AHC_PCI_CONFIG > 0
|
||||
if (ahc->unsolicited_ints > 500) {
|
||||
ahc->unsolicited_ints = 0;
|
||||
if ((ahc->chip & AHC_PCI) != 0
|
||||
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
|
||||
ahc->bus_intr(ahc);
|
||||
}
|
||||
#endif
|
||||
ahc->unsolicited_ints++;
|
||||
return (0);
|
||||
}
|
||||
ahc->unsolicited_ints = 0;
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahc_outb(ahc, CLRINT, CLRCMDINT);
|
||||
|
||||
@ -604,38 +618,25 @@ ahc_intr(struct ahc_softc *ahc)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
|
||||
/* Hot eject */
|
||||
return;
|
||||
|
||||
if ((intstat & INT_PEND) == 0) {
|
||||
#if AHC_PCI_CONFIG > 0
|
||||
if (ahc->unsolicited_ints > 500) {
|
||||
ahc->unsolicited_ints = 0;
|
||||
if ((ahc->chip & AHC_PCI) != 0
|
||||
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
|
||||
ahc->bus_intr(ahc);
|
||||
}
|
||||
#endif
|
||||
ahc->unsolicited_ints++;
|
||||
return;
|
||||
}
|
||||
ahc->unsolicited_ints = 0;
|
||||
|
||||
if (intstat & BRKADRINT) {
|
||||
/*
|
||||
* Handle statuses that may invalidate our cached
|
||||
* copy of INTSTAT separately.
|
||||
*/
|
||||
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
|
||||
/* Hot eject. Do nothing */
|
||||
} else if (intstat & BRKADRINT) {
|
||||
ahc_handle_brkadrint(ahc);
|
||||
/* Fatal error, no more interrupts to handle. */
|
||||
return;
|
||||
}
|
||||
} else if ((intstat & (SEQINT|SCSIINT)) != 0) {
|
||||
|
||||
if ((intstat & (SEQINT|SCSIINT)) != 0)
|
||||
ahc_pause_bug_fix(ahc);
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahc_handle_seqint(ahc, intstat);
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahc_handle_seqint(ahc, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahc_handle_scsiint(ahc, intstat);
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahc_handle_scsiint(ahc, intstat);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
#endif /* _AIC7XXX_INLINE_H_ */
|
||||
|
@ -284,7 +284,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
|
||||
untimeout(ahc_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch);
|
||||
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
int op;
|
||||
/*XXX bus_dmasync_op_t*/int op;
|
||||
|
||||
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
|
||||
op = BUS_DMASYNC_POSTREAD;
|
||||
@ -1107,7 +1107,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
|
||||
if (nsegments != 0) {
|
||||
struct ahc_dma_seg *sg;
|
||||
bus_dma_segment_t *end_seg;
|
||||
int op;
|
||||
/*XXX bus_dmasync_op_t*/int op;
|
||||
|
||||
end_seg = dm_segs + nsegments;
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#57 $
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
@ -696,8 +696,12 @@ static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
|
||||
static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
|
||||
int *externalcable_present,
|
||||
int *eeprom_present);
|
||||
static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
|
||||
static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
|
||||
static uint8_t read_brdctl(struct ahc_softc *ahc);
|
||||
static void ahc_pci_intr(struct ahc_softc *ahc);
|
||||
static int ahc_pci_chip_init(struct ahc_softc *ahc);
|
||||
static int ahc_pci_suspend(struct ahc_softc *ahc);
|
||||
static int ahc_pci_resume(struct ahc_softc *ahc);
|
||||
|
||||
static int
|
||||
ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
|
||||
@ -748,10 +752,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
|
||||
device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
|
||||
subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
|
||||
subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
|
||||
full_id = ahc_compose_id(device,
|
||||
vendor,
|
||||
subdevice,
|
||||
subvendor);
|
||||
full_id = ahc_compose_id(device, vendor, subdevice, subvendor);
|
||||
|
||||
/*
|
||||
* If the second function is not hooked up, ignore it.
|
||||
@ -833,18 +834,10 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
|
||||
|
||||
/* Ensure busmastering is enabled */
|
||||
command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
|
||||
command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
|
||||
command |= PCIM_CMD_BUSMASTEREN;
|
||||
|
||||
/*
|
||||
* Disable PCI parity error reporting. Users typically
|
||||
* do this to work around broken PCI chipsets that get
|
||||
* the parity timing wrong and thus generate lots of spurious
|
||||
* errors.
|
||||
*/
|
||||
if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
|
||||
command &= ~PCIM_CMD_PERRESPEN;
|
||||
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
|
||||
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
|
||||
|
||||
/* On all PCI adapters, we allow SCB paging */
|
||||
ahc->flags |= AHC_PAGESCBS;
|
||||
@ -853,7 +846,23 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Disable PCI parity error checking. Users typically
|
||||
* do this to work around broken PCI chipsets that get
|
||||
* the parity timing wrong and thus generate lots of spurious
|
||||
* errors. The chip only allows us to disable *all* parity
|
||||
* error reporting when doing this, so CIO bus, scb ram, and
|
||||
* scratch ram parity errors will be ignored too.
|
||||
*/
|
||||
if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) {
|
||||
ahc->pause |= FAILDIS;
|
||||
ahc->unpause |= FAILDIS;
|
||||
}
|
||||
|
||||
ahc->bus_intr = ahc_pci_intr;
|
||||
ahc->bus_chip_init = ahc_pci_chip_init;
|
||||
ahc->bus_suspend = ahc_pci_suspend;
|
||||
ahc->bus_resume = ahc_pci_resume;
|
||||
|
||||
/* Remeber how the card was setup in case there is no SEEPROM */
|
||||
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
|
||||
@ -993,6 +1002,35 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
if ((sxfrctl1 & STPWEN) != 0)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
|
||||
/*
|
||||
* Save chip register configuration data for chip resets
|
||||
* that occur during runtime and resume events.
|
||||
*/
|
||||
ahc->bus_softc.pci_softc.devconfig =
|
||||
ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
|
||||
ahc->bus_softc.pci_softc.command =
|
||||
ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
|
||||
ahc->bus_softc.pci_softc.csize_lattime =
|
||||
ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);
|
||||
ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
|
||||
ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
|
||||
if ((ahc->features & AHC_DT) != 0) {
|
||||
u_int sfunct;
|
||||
|
||||
sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
|
||||
ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
|
||||
ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);
|
||||
ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);
|
||||
ahc_outb(ahc, SFUNCT, sfunct);
|
||||
ahc->bus_softc.pci_softc.crccontrol1 =
|
||||
ahc_inb(ahc, CRCCONTROL1);
|
||||
}
|
||||
if ((ahc->features & AHC_MULTI_FUNC) != 0)
|
||||
ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);
|
||||
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
|
||||
|
||||
/* Core initialization */
|
||||
error = ahc_init(ahc);
|
||||
if (error != 0)
|
||||
@ -1412,6 +1450,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
|
||||
}
|
||||
|
||||
if (have_autoterm) {
|
||||
ahc->flags |= AHC_HAS_TERM_LOGIC;
|
||||
ahc_acquire_seeprom(ahc, &sd);
|
||||
configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
|
||||
ahc_release_seeprom(&sd);
|
||||
@ -1845,11 +1884,14 @@ aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
|
||||
spiocap |= EXT_BRDCTL;
|
||||
ahc_outb(ahc, SPIOCAP, spiocap);
|
||||
ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
|
||||
ahc_flush_device_writes(ahc);
|
||||
ahc_delay(500);
|
||||
ahc_outb(ahc, BRDCTL, 0);
|
||||
ahc_flush_device_writes(ahc);
|
||||
ahc_delay(500);
|
||||
brdctl = ahc_inb(ahc, BRDCTL);
|
||||
*internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
|
||||
*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
|
||||
|
||||
*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
|
||||
}
|
||||
|
||||
@ -1943,7 +1985,7 @@ read_brdctl(ahc)
|
||||
return (value);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_pci_intr(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int error;
|
||||
@ -1961,6 +2003,7 @@ ahc_pci_intr(struct ahc_softc *ahc)
|
||||
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
|
||||
|
||||
if (status1 & DPE) {
|
||||
ahc->pci_target_perr_count++;
|
||||
printf("%s: Data Parity Error Detected during address "
|
||||
"or write data phase\n", ahc_name(ahc));
|
||||
}
|
||||
@ -1992,9 +2035,89 @@ ahc_pci_intr(struct ahc_softc *ahc)
|
||||
ahc_outb(ahc, CLRINT, CLRPARERR);
|
||||
}
|
||||
|
||||
if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) {
|
||||
printf(
|
||||
"%s: WARNING WARNING WARNING WARNING\n"
|
||||
"%s: Too many PCI parity errors observed as a target.\n"
|
||||
"%s: Some device on this bus is generating bad parity.\n"
|
||||
"%s: This is an error *observed by*, not *generated by*, this controller.\n"
|
||||
"%s: PCI parity error checking has been disabled.\n"
|
||||
"%s: WARNING WARNING WARNING WARNING\n",
|
||||
ahc_name(ahc), ahc_name(ahc), ahc_name(ahc),
|
||||
ahc_name(ahc), ahc_name(ahc), ahc_name(ahc));
|
||||
ahc->pause |= FAILDIS;
|
||||
ahc->unpause |= FAILDIS;
|
||||
}
|
||||
ahc_unpause(ahc);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_pci_chip_init(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc_outb(ahc, DSCOMMAND0, ahc->bus_softc.pci_softc.dscommand0);
|
||||
ahc_outb(ahc, DSPCISTATUS, ahc->bus_softc.pci_softc.dspcistatus);
|
||||
if ((ahc->features & AHC_DT) != 0) {
|
||||
u_int sfunct;
|
||||
|
||||
sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
|
||||
ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
|
||||
ahc_outb(ahc, OPTIONMODE, ahc->bus_softc.pci_softc.optionmode);
|
||||
ahc_outw(ahc, TARGCRCCNT, ahc->bus_softc.pci_softc.targcrccnt);
|
||||
ahc_outb(ahc, SFUNCT, sfunct);
|
||||
ahc_outb(ahc, CRCCONTROL1,
|
||||
ahc->bus_softc.pci_softc.crccontrol1);
|
||||
}
|
||||
if ((ahc->features & AHC_MULTI_FUNC) != 0)
|
||||
ahc_outb(ahc, SCBBADDR, ahc->bus_softc.pci_softc.scbbaddr);
|
||||
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
ahc_outb(ahc, DFF_THRSH, ahc->bus_softc.pci_softc.dff_thrsh);
|
||||
|
||||
return (ahc_chip_init(ahc));
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_pci_suspend(struct ahc_softc *ahc)
|
||||
{
|
||||
return (ahc_suspend(ahc));
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_pci_resume(struct ahc_softc *ahc)
|
||||
{
|
||||
|
||||
ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
|
||||
|
||||
/*
|
||||
* We assume that the OS has restored our register
|
||||
* mappings, etc. Just update the config space registers
|
||||
* that the OS doesn't know about and rely on our chip
|
||||
* reset handler to handle the rest.
|
||||
*/
|
||||
ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
|
||||
ahc->bus_softc.pci_softc.devconfig);
|
||||
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
|
||||
ahc->bus_softc.pci_softc.command);
|
||||
ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
|
||||
ahc->bus_softc.pci_softc.csize_lattime);
|
||||
if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
|
||||
struct seeprom_descriptor sd;
|
||||
u_int sxfrctl1;
|
||||
|
||||
sd.sd_ahc = ahc;
|
||||
sd.sd_control_offset = SEECTL;
|
||||
sd.sd_status_offset = SEECTL;
|
||||
sd.sd_dataout_offset = SEECTL;
|
||||
|
||||
ahc_acquire_seeprom(ahc, &sd);
|
||||
configure_termination(ahc, &sd,
|
||||
ahc->seep_config->adapter_control,
|
||||
&sxfrctl1);
|
||||
ahc_release_seeprom(&sd);
|
||||
}
|
||||
return (ahc_resume(ahc));
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic785X_setup(struct ahc_softc *ahc)
|
||||
{
|
||||
@ -2009,6 +2132,7 @@ ahc_aic785X_setup(struct ahc_softc *ahc)
|
||||
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
|
||||
if (rev >= 1)
|
||||
ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
|
||||
ahc->instruction_ram_size = 512;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2026,6 +2150,7 @@ ahc_aic7860_setup(struct ahc_softc *ahc)
|
||||
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
|
||||
if (rev >= 1)
|
||||
ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
|
||||
ahc->instruction_ram_size = 512;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2049,6 +2174,7 @@ ahc_aic7870_setup(struct ahc_softc *ahc)
|
||||
ahc->chip = AHC_AIC7870;
|
||||
ahc->features = AHC_AIC7870_FE;
|
||||
ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
|
||||
ahc->instruction_ram_size = 512;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2102,6 +2228,7 @@ ahc_aic7880_setup(struct ahc_softc *ahc)
|
||||
} else {
|
||||
ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
|
||||
}
|
||||
ahc->instruction_ram_size = 512;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2149,6 +2276,7 @@ ahc_aic7890_setup(struct ahc_softc *ahc)
|
||||
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
|
||||
if (rev == 0)
|
||||
ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
|
||||
ahc->instruction_ram_size = 768;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2161,6 +2289,7 @@ ahc_aic7892_setup(struct ahc_softc *ahc)
|
||||
ahc->features = AHC_AIC7892_FE;
|
||||
ahc->flags |= AHC_NEWEEPROM_FMT;
|
||||
ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
|
||||
ahc->instruction_ram_size = 1024;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2216,6 +2345,7 @@ ahc_aic7895_setup(struct ahc_softc *ahc)
|
||||
ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1);
|
||||
#endif
|
||||
ahc->flags |= AHC_NEWEEPROM_FMT;
|
||||
ahc->instruction_ram_size = 512;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2230,6 +2360,7 @@ ahc_aic7896_setup(struct ahc_softc *ahc)
|
||||
ahc->features = AHC_AIC7896_FE;
|
||||
ahc->flags |= AHC_NEWEEPROM_FMT;
|
||||
ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
|
||||
ahc->instruction_ram_size = 768;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2244,6 +2375,7 @@ ahc_aic7899_setup(struct ahc_softc *ahc)
|
||||
ahc->features = AHC_AIC7899_FE;
|
||||
ahc->flags |= AHC_NEWEEPROM_FMT;
|
||||
ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
|
||||
ahc->instruction_ram_size = 1024;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user