summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/aic7xxx/ahc_pci.c20
-rw-r--r--sys/dev/aic7xxx/aic7770.c39
-rw-r--r--sys/dev/aic7xxx/aic7xxx.c264
-rw-r--r--sys/dev/aic7xxx/aic7xxx.h44
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg21
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq175
-rw-r--r--sys/dev/aic7xxx/aic7xxx_93cx6.c2
-rw-r--r--sys/dev/aic7xxx/aic7xxx_freebsd.c19
-rw-r--r--sys/dev/aic7xxx/aic7xxx_freebsd.h5
-rw-r--r--sys/dev/aic7xxx/aic7xxx_inline.h147
-rw-r--r--sys/dev/aic7xxx/aic7xxx_osm.c19
-rw-r--r--sys/dev/aic7xxx/aic7xxx_osm.h5
-rw-r--r--sys/dev/aic7xxx/aic7xxx_pci.c296
13 files changed, 696 insertions, 360 deletions
diff --git a/sys/dev/aic7xxx/ahc_pci.c b/sys/dev/aic7xxx/ahc_pci.c
index 01772a0..b76d232 100644
--- a/sys/dev/aic7xxx/ahc_pci.c
+++ b/sys/dev/aic7xxx/ahc_pci.c
@@ -102,11 +102,20 @@ ahc_pci_attach(device_t dev)
ahc_set_unit(ahc, device_get_unit(dev));
+ /*
+ * Should we bother disabling 39Bit addressing
+ * based on installed memory?
+ */
+ if (sizeof(bus_addr_t) > 4)
+ ahc->flags |= AHC_39BIT_ADDRESSING;
+
/* 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,
+ (ahc->flags & AHC_39BIT_ADDRESSING)
+ ? 0x7FFFFFFFFF
+ : BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
@@ -182,7 +191,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
regs_id = AHC_PCI_IOADDR;
regs = bus_alloc_resource(ahc->dev_softc, regs_type,
&regs_id, 0, ~0, 1, RF_ACTIVE);
- if (regs) {
+ if (regs != NULL) {
ahc->tag = rman_get_bustag(regs);
ahc->bsh = rman_get_bushandle(regs);
command &= ~PCIM_CMD_MEMEN;
@@ -190,15 +199,14 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
command, /*bytes*/1);
}
}
- ahc->platform_data->regs_res_type = regs_type;
- ahc->platform_data->regs_res_id = regs_id;
- ahc->platform_data->regs = regs;
-
if (regs == NULL) {
device_printf(ahc->dev_softc,
"can't allocate register resources\n");
return (ENOMEM);
}
+ ahc->platform_data->regs_res_type = regs_type;
+ ahc->platform_data->regs_res_id = regs_id;
+ ahc->platform_data->regs = regs;
return (0);
}
diff --git a/sys/dev/aic7xxx/aic7770.c b/sys/dev/aic7xxx/aic7770.c
index d717882..8383762 100644
--- a/sys/dev/aic7xxx/aic7770.c
+++ b/sys/dev/aic7xxx/aic7770.c
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7770.c#11 $
+ * $Id: //depot/src/aic7xxx/aic7770.c#12 $
*
* $FreeBSD$
*/
@@ -90,14 +90,12 @@ aic7770_find_device(uint32_t id)
int
aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
{
- struct ahc_probe_config probe_config;
int error;
u_int hostconf;
u_int irq;
u_int intdef;
- ahc_init_probe_config(&probe_config);
- error = entry->setup(ahc->dev_softc, &probe_config);
+ error = entry->setup(ahc);
if (error != 0)
return (error);
@@ -105,8 +103,8 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
if (error != 0)
return (error);
- probe_config.description = entry->name;
- error = ahc_softc_init(ahc, &probe_config);
+ ahc->description = entry->name;
+ error = ahc_softc_init(ahc);
error = ahc_reset(ahc);
if (error != 0)
@@ -131,7 +129,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
if ((intdef & EDGE_TRIG) != 0)
ahc->flags |= AHC_EDGE_INTERRUPT;
- switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
+ switch (ahc->chip & (AHC_EISA|AHC_VL)) {
case AHC_EISA:
{
u_int biosctrl;
@@ -312,34 +310,33 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
}
static int
-ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
+ahc_aic7770_VL_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7770_setup(dev, probe_config);
- probe_config->chip |= AHC_VL;
+ error = ahc_aic7770_setup(ahc);
+ ahc->chip |= AHC_VL;
return (error);
}
static int
-ahc_aic7770_EISA_setup(ahc_dev_softc_t dev,
- struct ahc_probe_config *probe_config)
+ahc_aic7770_EISA_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7770_setup(dev, probe_config);
- probe_config->chip |= AHC_EISA;
+ error = ahc_aic7770_setup(ahc);
+ ahc->chip |= AHC_EISA;
return (error);
}
static int
-ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
+ahc_aic7770_setup(struct ahc_softc *ahc)
{
- 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;
+ ahc->channel = 'A';
+ ahc->channel_b = 'B';
+ ahc->chip = AHC_AIC7770;
+ ahc->features = AHC_AIC7770_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
+ ahc->flags |= AHC_PAGESCBS;
return (0);
}
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c
index 829f609..4f0ac4f 100644
--- a/sys/dev/aic7xxx/aic7xxx.c
+++ b/sys/dev/aic7xxx/aic7xxx.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx.c#39 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.c#43 $
*
* $FreeBSD$
*/
@@ -179,6 +179,7 @@ static int ahc_handle_msg_reject(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo);
static void ahc_handle_ign_wide_residue(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo);
+static void ahc_reinitialize_dataptrs(struct ahc_softc *ahc);
static void ahc_handle_devreset(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
cam_status status, char *message,
@@ -282,6 +283,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
struct scb *scb;
u_int scb_index;
+ ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) {
scb_index = ahc->qoutfifo[ahc->qoutfifonext];
@@ -297,6 +299,10 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
*/
modnext = ahc->qoutfifonext & ~0x3;
*((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL;
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ /*offset*/modnext, /*len*/4,
+ BUS_DMASYNC_PREREAD);
}
ahc->qoutfifonext++;
@@ -624,6 +630,9 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
case IGN_WIDE_RES:
ahc_handle_ign_wide_residue(ahc, &devinfo);
break;
+ case PDATA_REINIT:
+ ahc_reinitialize_dataptrs(ahc);
+ break;
case BAD_PHASE:
{
u_int lastphase;
@@ -777,8 +786,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_get_transfer_length(scb), scb->sg_count);
if (scb->sg_count > 0) {
for (i = 0; i < scb->sg_count; i++) {
- printf("sg[%d] - Addr 0x%x : Length %d\n",
+
+ printf("sg[%d] - Addr 0x%x%x : Length %d\n",
i,
+ (ahc_le32toh(scb->sg_list[i].len) >> 24
+ & SG_HIGH_ADDR_BITS),
ahc_le32toh(scb->sg_list[i].addr),
ahc_le32toh(scb->sg_list[i].len)
& AHC_SG_LEN_MASK);
@@ -791,6 +803,26 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_freeze_devq(ahc, scb);
ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
ahc_freeze_scb(scb);
+
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ /*
+ * Clear the channel in case we return
+ * to data phase later.
+ */
+ ahc_outb(ahc, SXFRCTL0,
+ ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN);
+ ahc_outb(ahc, SXFRCTL0,
+ ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN);
+ }
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ u_int dscommand1;
+
+ /* Ensure HHADDR is 0 for future DMA operations. */
+ dscommand1 = ahc_inb(ahc, DSCOMMAND1);
+ ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0);
+ ahc_outb(ahc, HADDR, 0);
+ ahc_outb(ahc, DSCOMMAND1, dscommand1);
+ }
break;
}
case MKMSG_FAILED:
@@ -1338,7 +1370,7 @@ ahc_print_scb(struct scb *scb)
struct hardware_scb *hscb = scb->hscb;
printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
- scb,
+ (void *)scb,
hscb->control,
hscb->scsiid,
hscb->lun,
@@ -1366,8 +1398,10 @@ ahc_print_scb(struct scb *scb)
hscb->tag);
if (scb->sg_count > 0) {
for (i = 0; i < scb->sg_count; i++) {
- printf("sg[%d] - Addr 0x%x : Length %d\n",
+ printf("sg[%d] - Addr 0x%x%x : Length %d\n",
i,
+ (ahc_le32toh(scb->sg_list[i].len) >> 24
+ & SG_HIGH_ADDR_BITS),
ahc_le32toh(scb->sg_list[i].addr),
ahc_le32toh(scb->sg_list[i].len));
}
@@ -1911,7 +1945,7 @@ ahc_update_pending_scbs(struct ahc_softc *ahc)
struct hardware_scb *pending_hscb;
struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
-
+
ahc_scb_devinfo(ahc, &devinfo, pending_scb);
tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
devinfo.our_scsiid,
@@ -1927,6 +1961,8 @@ ahc_update_pending_scbs(struct ahc_softc *ahc)
pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;
pending_hscb->control &= ~MK_MESSAGE;
}
+ ahc_sync_scb(ahc, pending_scb,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
pending_scb_count++;
}
@@ -2181,6 +2217,9 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
*/
period = tinfo->goal.period;
ppr_options = tinfo->goal.ppr_options;
+ /* Target initiated PPR is not allowed in the SCSI spec */
+ if (devinfo->role == ROLE_TARGET)
+ ppr_options = 0;
rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
&ppr_options, devinfo->role);
dowide = tinfo->curr.width != tinfo->goal.width;
@@ -3208,13 +3247,15 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
struct ahc_dma_seg *sg;
uint32_t data_cnt;
uint32_t data_addr;
+ uint32_t sglen;
/* Pull in the rest of the sgptr */
sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24)
| (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
| (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8);
sgptr &= SG_PTR_MASK;
- data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16)
+ data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+3) << 24)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16)
| (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8)
| (ahc_inb(ahc, SCB_RESIDUAL_DATACNT));
@@ -3232,13 +3273,19 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* to load so we must go back one.
*/
sg--;
+ sglen = ahc_le32toh(sg->len) & AHC_SG_LEN_MASK;
if (sg != scb->sg_list
- && (sg->len & AHC_SG_LEN_MASK) < data_cnt) {
+ && sglen < (data_cnt & AHC_SG_LEN_MASK)) {
sg--;
- data_cnt = 1 | (sg->len & AHC_DMA_LAST_SEG);
- data_addr = sg->addr
- + (sg->len & AHC_SG_LEN_MASK) - 1;
+ sglen = ahc_le32toh(sg->len);
+ /*
+ * Preserve High Address and SG_LIST bits
+ * while setting the count to 1.
+ */
+ data_cnt = 1 | (sglen & (~AHC_SG_LEN_MASK));
+ data_addr = ahc_le32toh(sg->addr)
+ + (sglen & AHC_SG_LEN_MASK) - 1;
/*
* Increment sg so it points to the
@@ -3255,31 +3302,72 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr);
}
-/* XXX What about high address byte??? */
ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24);
ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16);
ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8);
ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt);
-
-/* XXX Perhaps better to just keep the saved address in sram */
- if ((ahc->features & AHC_ULTRA2) != 0) {
- ahc_outb(ahc, HADDR + 3, data_addr >> 24);
- ahc_outb(ahc, HADDR + 2, data_addr >> 16);
- ahc_outb(ahc, HADDR + 1, data_addr >> 8);
- ahc_outb(ahc, HADDR, data_addr);
- ahc_outb(ahc, DFCNTRL, PRELOADEN);
- ahc_outb(ahc, SXFRCTL0,
- ahc_inb(ahc, SXFRCTL0) | CLRCHN);
- } else {
- ahc_outb(ahc, HADDR + 3, data_addr >> 24);
- ahc_outb(ahc, HADDR + 2, data_addr >> 16);
- ahc_outb(ahc, HADDR + 1, data_addr >> 8);
- ahc_outb(ahc, HADDR, data_addr);
- }
}
}
}
+
+/*
+ * Reinitialize the data pointers for the active transfer
+ * based on its current residual.
+ */
+static void
+ahc_reinitialize_dataptrs(struct ahc_softc *ahc)
+{
+ struct scb *scb;
+ struct ahc_dma_seg *sg;
+ u_int scb_index;
+ uint32_t sgptr;
+ uint32_t resid;
+ uint32_t dataptr;
+
+ scb_index = ahc_inb(ahc, SCB_TAG);
+ scb = ahc_lookup_scb(ahc, scb_index);
+ sgptr = (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
+ | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8)
+ | ahc_inb(ahc, SCB_RESIDUAL_SGPTR);
+
+ sgptr &= SG_PTR_MASK;
+ sg = ahc_sg_bus_to_virt(scb, sgptr);
+
+ /* The residual sg_ptr always points to the next sg */
+ sg--;
+
+ resid = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16)
+ | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8)
+ | ahc_inb(ahc, SCB_RESIDUAL_DATACNT);
+
+ dataptr = ahc_le32toh(sg->addr)
+ + (ahc_le32toh(sg->len) & AHC_SG_LEN_MASK)
+ - resid;
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ u_int dscommand1;
+
+ dscommand1 = ahc_inb(ahc, DSCOMMAND1);
+ ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0);
+ ahc_outb(ahc, HADDR,
+ (ahc_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS);
+ ahc_outb(ahc, DSCOMMAND1, dscommand1);
+ }
+ ahc_outb(ahc, HADDR + 3, dataptr >> 24);
+ ahc_outb(ahc, HADDR + 2, dataptr >> 16);
+ ahc_outb(ahc, HADDR + 1, dataptr >> 8);
+ ahc_outb(ahc, HADDR, dataptr);
+ ahc_outb(ahc, HCNT + 2, resid >> 16);
+ ahc_outb(ahc, HCNT + 1, resid >> 8);
+ ahc_outb(ahc, HCNT, resid);
+ if ((ahc->features & AHC_ULTRA2) == 0) {
+ ahc_outb(ahc, STCNT + 2, resid >> 16);
+ ahc_outb(ahc, STCNT + 1, resid >> 8);
+ ahc_outb(ahc, STCNT, resid);
+ }
+}
+
/*
* Handle the effects of issuing a bus device reset message.
*/
@@ -3385,6 +3473,14 @@ ahc_alloc(void *platform_arg, char *name)
/* We don't know our unit number until the OSM sets it */
ahc->name = name;
ahc->unit = -1;
+ ahc->description = NULL;
+ ahc->channel = 'A';
+ ahc->channel_b = 'B';
+ ahc->chip = AHC_NONE;
+ ahc->features = AHC_FENONE;
+ ahc->bugs = AHC_BUGNONE;
+ ahc->flags = AHC_FNONE;
+
for (i = 0; i < 16; i++)
TAILQ_INIT(&ahc->untagged_queues[i]);
if (ahc_platform_alloc(ahc, platform_arg) != 0) {
@@ -3395,16 +3491,9 @@ ahc_alloc(void *platform_arg, char *name)
}
int
-ahc_softc_init(struct ahc_softc *ahc, struct ahc_probe_config *config)
+ahc_softc_init(struct ahc_softc *ahc)
{
- ahc->chip = config->chip;
- ahc->features = config->features;
- ahc->bugs = config->bugs;
- ahc->flags = config->flags;
- ahc->channel = config->channel;
- ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS);
- ahc->description = config->description;
/* The IRQMS bit is only valid on VL and EISA chips */
if ((ahc->chip & AHC_PCI) != 0)
ahc->unpause &= ~IRQMS;
@@ -3697,18 +3786,6 @@ ahc_probe_scbs(struct ahc_softc *ahc) {
return (i);
}
-void
-ahc_init_probe_config(struct ahc_probe_config *probe_config)
-{
- probe_config->description = NULL;
- probe_config->channel = 'A';
- probe_config->channel_b = 'B';
- probe_config->chip = AHC_NONE;
- probe_config->features = AHC_FENONE;
- probe_config->bugs = AHC_BUGNONE;
- probe_config->flags = AHC_FNONE;
-}
-
static void
ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
@@ -3794,7 +3871,8 @@ ahc_init_scbdata(struct ahc_softc *ahc)
/* DMA tag for our hardware scb structures */
if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
AHC_SCB_MAX * sizeof(struct hardware_scb),
@@ -3806,7 +3884,7 @@ ahc_init_scbdata(struct ahc_softc *ahc)
scb_data->init_level++;
- /* Allocation for our ccbs */
+ /* Allocation for our hscbs */
if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat,
(void **)&scb_data->hscbs,
BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) {
@@ -3825,7 +3903,8 @@ ahc_init_scbdata(struct ahc_softc *ahc)
/* DMA tag for our sense buffers */
if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
AHC_SCB_MAX * sizeof(struct scsi_sense_data),
@@ -3856,7 +3935,8 @@ ahc_init_scbdata(struct ahc_softc *ahc)
/* DMA tag for our S/G structures. We allocate in page sized chunks */
if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
PAGE_SIZE, /*nsegments*/1,
@@ -3999,6 +4079,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
if (pdata == NULL)
break;
next_scb->platform_data = pdata;
+ next_scb->sg_map = sg_map;
next_scb->sg_list = segs;
/*
* The sequencer always starts with the second entry.
@@ -4126,7 +4207,8 @@ ahc_init(struct ahc_softc *ahc)
#ifndef __linux__
/* DMA tag for mapping buffers into device visible space. */
if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+ /*lowaddr*/BUS_SPACE_MAXADDR,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
@@ -4153,7 +4235,8 @@ ahc_init(struct ahc_softc *ahc)
driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd)
+ /*DMA WideOdd Bug Buffer*/1;
if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
driver_data_size,
@@ -4187,6 +4270,7 @@ ahc_init(struct ahc_softc *ahc)
/* All target command blocks start out invalid. */
for (i = 0; i < AHC_TMODE_CMDS; i++)
ahc->targetcmds[i].cmd_valid = 0;
+ ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD);
ahc->tqinfifonext = 1;
ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
@@ -4431,6 +4515,7 @@ ahc_init(struct ahc_softc *ahc)
/* All of our queues are empty */
for (i = 0; i < 256; i++)
ahc->qoutfifo[i] = SCB_LIST_NULL;
+ ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
for (i = 0; i < 256; i++)
ahc->qinfifo[i] = SCB_LIST_NULL;
@@ -4896,12 +4981,16 @@ static void
ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb,
struct scb *scb)
{
- if (prev_scb == NULL)
+ if (prev_scb == NULL) {
ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag);
- else
+ } else {
prev_scb->hscb->next = scb->hscb->tag;
+ ahc_sync_scb(ahc, prev_scb,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
scb->hscb->next = ahc->next_queued_scb->hscb->tag;
+ ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
}
static int
@@ -4948,6 +5037,9 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
found = 0;
prev_scb = NULL;
+ if (bootverbose)
+ printf("qinpos = %d, qintail = %d\n", qinpos, qintail);
+
if (action == SEARCH_COMPLETE) {
/*
* Don't attempt to run any queued untagged transactions
@@ -4965,6 +5057,12 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
while (qinpos != qintail) {
scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]);
+ if (scb == NULL) {
+ printf("qinpos = %d, SCB index = %d\n",
+ qinpos, ahc->qinfifo[qinpos]);
+ panic("Loop 1\n");
+ }
+
if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) {
/*
* We found an scb that needs to be acted on.
@@ -5026,6 +5124,11 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
*/
scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);
+ if (scb == NULL) {
+ printf("found = %d, qinstart = %d, qinfifionext = %d\n",
+ found, qinstart, ahc->qinfifonext);
+ panic("First/Second Qinfifo fixup\n");
+ }
/*
* ahc_swap_with_next_hscb forces our next pointer to
* point to the reserved SCB for future commands. Save
@@ -5067,6 +5170,11 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
panic("for safety");
}
scb = ahc_lookup_scb(ahc, scb_index);
+ if (scb == NULL) {
+ printf("scb_index = %d, next = %d\n",
+ scb_index, next);
+ panic("Waiting List traversal\n");
+ }
if (ahc_match_scb(ahc, scb, target, channel,
lun, SCB_LIST_NULL, role)) {
/*
@@ -5490,6 +5598,8 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
struct ahc_devinfo devinfo;
u_int initiator, target, max_scsiid;
u_int sblkctl;
+ u_int scsiseq;
+ u_int simode1;
int found;
int restart_needed;
char cur_channel;
@@ -5526,31 +5636,48 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
if ((ahc->features & AHC_TWIN) != 0
&& ((sblkctl & SELBUSB) != 0))
cur_channel = 'B';
+ scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
if (cur_channel != channel) {
/* Case 1: Command for another bus is active
* Stealthily reset the other bus without
* upsetting the current bus.
*/
ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
- ahc_outb(ahc, SIMODE1,
- ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
- ahc_outb(ahc, SCSISEQ,
- ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+ simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
+ ahc_outb(ahc, SIMODE1, simode1);
if (initiate_reset)
ahc_reset_current_bus(ahc);
ahc_clear_intstat(ahc);
+#if AHC_TARGET_MODE
+ /*
+ * Bus resets clear ENSELI, so we cannot
+ * defer re-enabling bus reset interrupts
+ * if we are in target mode.
+ */
+ if ((ahc->flags & AHC_TARGETROLE) != 0)
+ ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST);
+#endif
+ ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
ahc_outb(ahc, SBLKCTL, sblkctl);
restart_needed = FALSE;
} else {
/* Case 2: A command from this bus is active or we're idle */
ahc_clear_msg_state(ahc);
- ahc_outb(ahc, SIMODE1,
- ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
- ahc_outb(ahc, SCSISEQ,
- ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+ simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
+ ahc_outb(ahc, SIMODE1, simode1);
if (initiate_reset)
ahc_reset_current_bus(ahc);
ahc_clear_intstat(ahc);
+#if AHC_TARGET_MODE
+ /*
+ * Bus resets clear ENSELI, so we cannot
+ * defer re-enabling bus reset interrupts
+ * if we are in target mode.
+ */
+ if ((ahc->flags & AHC_TARGETROLE) != 0)
+ ahc_outb(ahc, SIMODE1, simode1 | ENSCSIRST);
+#endif
+ ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
restart_needed = TRUE;
}
@@ -5702,7 +5829,7 @@ ahc_calc_residual(struct scb *scb)
ahc_set_sense_residual(scb, resid);
#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWMISC) {
+ if ((ahc_debug & AHC_SHOWMISC) != 0) {
ahc_print_path(ahc, scb);
printf("Handled Residual of %d bytes\n", resid);
}
@@ -6157,6 +6284,7 @@ ahc_dump_card_state(struct ahc_softc *ahc)
}
printf("\n");
+ ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
printf("QOUTFIFO entries: ");
qoutpos = ahc->qoutfifonext;
i = 0;
@@ -6629,6 +6757,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
if ((ahc->features & AHC_AUTOPAUSE) != 0)
paused = TRUE;
+ ahc_sync_tqinfifo(ahc, BUS_DMASYNC_POSTREAD);
while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) {
/*
@@ -6638,8 +6767,13 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
if (ahc_handle_target_cmd(ahc, cmd) != 0)
break;
- ahc->tqinfifonext++;
cmd->cmd_valid = 0;
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, ahc->tqinfifonext),
+ sizeof(struct target_cmd),
+ BUS_DMASYNC_PREREAD);
+ ahc->tqinfifonext++;
/*
* Lazily update our position in the target mode incoming
diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h
index 4eded92..cc5bf76 100644
--- a/sys/dev/aic7xxx/aic7xxx.h
+++ b/sys/dev/aic7xxx/aic7xxx.h
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx.h#27 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.h#29 $
*
* $FreeBSD$
*/
@@ -335,22 +335,10 @@ typedef enum {
AHC_BIOS_ENABLED = 0x80000,
AHC_ALL_INTERRUPTS = 0x100000,
AHC_PAGESCBS = 0x400000, /* Enable SCB paging */
- AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */
+ AHC_EDGE_INTERRUPT = 0x800000, /* Device uses edge triggered ints */
+ AHC_39BIT_ADDRESSING = 0x1000000 /* Use 39 bit addressing scheme. */
} ahc_flag;
-/*
- * Controller Information composed at probe time.
- */
-struct ahc_probe_config {
- const char *description;
- char channel;
- char channel_b;
- ahc_chip chip;
- ahc_feature features;
- ahc_bug bugs;
- ahc_flag flags;
-};
-
/************************* Hardware SCB Definition ***************************/
/*
@@ -499,6 +487,13 @@ struct ahc_dma_seg {
#define AHC_SG_LEN_MASK 0x00FFFFFF
};
+struct sg_map_node {
+ bus_dmamap_t sg_dmamap;
+ bus_addr_t sg_physaddr;
+ struct ahc_dma_seg* sg_vaddr;
+ SLIST_ENTRY(sg_map_node) links;
+};
+
/*
* The current state of this SCB.
*/
@@ -538,18 +533,12 @@ struct scb {
bus_dmamap_t dmamap;
#endif
struct scb_platform_data *platform_data;
- struct ahc_dma_seg *sg_list;
+ struct sg_map_node *sg_map;
+ struct ahc_dma_seg *sg_list;
bus_addr_t sg_list_phys;
u_int sg_count;/* How full ahc_dma_seg is */
};
-struct sg_map_node {
- bus_dmamap_t sg_dmamap;
- bus_addr_t sg_physaddr;
- struct ahc_dma_seg* sg_vaddr;
- SLIST_ENTRY(sg_map_node) links;
-};
-
struct scb_data {
SLIST_HEAD(, scb) free_scbs; /*
* Pool of SCBs ready to be assigned
@@ -865,7 +854,7 @@ struct ahc_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ LIST_HEAD(, scb) pending_scbs;
/*
* Counting lock for deferring the release of additional
@@ -1039,8 +1028,7 @@ struct ahc_devinfo {
};
/****************************** PCI Structures ********************************/
-typedef int (ahc_device_setup_t)(ahc_dev_softc_t,
- struct ahc_probe_config *);
+typedef int (ahc_device_setup_t)(struct ahc_softc *);
struct ahc_pci_identity {
uint64_t full_id;
@@ -1093,10 +1081,8 @@ int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
u_int tag, role_t role);
/****************************** Initialization ********************************/
-void ahc_init_probe_config(struct ahc_probe_config *);
struct ahc_softc *ahc_alloc(void *platform_arg, char *name);
-int ahc_softc_init(struct ahc_softc *,
- struct ahc_probe_config*);
+int ahc_softc_init(struct ahc_softc *);
void ahc_controller_info(struct ahc_softc *ahc, char *buf);
int ahc_init(struct ahc_softc *ahc);
void ahc_intr_enable(struct ahc_softc *ahc, int enable);
diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg
index 91c6b8a..6d44293 100644
--- a/sys/dev/aic7xxx/aic7xxx.reg
+++ b/sys/dev/aic7xxx/aic7xxx.reg
@@ -28,10 +28,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $
- *
* $FreeBSD$
*/
+VERSION = "$Id: //depot/src/aic7xxx/aic7xxx.reg#19 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@@ -683,8 +682,16 @@ register DSCOMMAND0 {
bit CIOPARCKEN 0x01 /* Internal bus parity error enable */
}
+register DSCOMMAND1 {
+ address 0x085
+ access_mode RW
+ mask DSLATT 0xfc /* PCI latency timer (non-ultra2) */
+ bit HADDLDSEL1 0x02 /* Host Address Load Select Bits */
+ bit HADDLDSEL0 0x01
+}
+
/*
- * Bus On/Off Time (p. 3-44)
+ * Bus On/Off Time (p. 3-44) aic7770 only
*/
register BUSTIME {
address 0x085
@@ -781,7 +788,13 @@ register INTSTAT {
mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */
- mask RESIDUAL 0x50|SEQINT /* Residual byte count != 0 */
+ mask PDATA_REINIT 0x50|SEQINT /*
+ * Returned to data phase
+ * that requires data
+ * transfer pointers to be
+ * recalculated from the
+ * transfer residual.
+ */
mask HOST_MSG_LOOP 0x60|SEQINT /*
* The bus is ready for the
* host to perform another
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index c50a99c..179445c 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -28,11 +28,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $
- *
* $FreeBSD$
*/
+VERSION = "$Id: //depot/src/aic7xxx/aic7xxx.seq#32 $"
+
#include "aic7xxx.reg"
#include "scsi_message.h"
@@ -175,16 +175,7 @@ select_in:
* We've just been selected. Assert BSY and
* setup the phase for receiving messages
* from the target.
- *
- * If bus reset interrupts have been disabled (from a
- * previous reset), re-enable them now. Resets are only
- * of interest when we have outstanding transactions, so
- * we can safely defer re-enabling the interrupt until,
- * as a target, we start receiving transactions again.
*/
- test SIMODE1, ENSCSIRST jnz . + 3;
- mvi CLRSINT1, CLRSCSIRSTI;
- or SIMODE1, ENSCSIRST;
mvi SCSISIGO, P_MESGOUT|BSYO;
/*
@@ -749,13 +740,13 @@ idle_sg_avail:
if ((ahc->features & AHC_ULTRA2) != 0) {
/* Does the hardware have space for another SG entry? */
test DFSTATUS, PRELOAD_AVAIL jz return;
- bmov HADDR, CCSGRAM, 4;
- bmov SINDEX, CCSGRAM, 1;
- test SINDEX, 0x1 jz . + 2;
+ bmov HADDR, CCSGRAM, 7;
+ test HCNT[0], 0x1 jz . + 2;
xor DATA_COUNT_ODD, 0x1;
- bmov HCNT[0], SINDEX, 1;
- bmov HCNT[1], CCSGRAM, 2;
bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
+ }
call sg_advance;
mov SINDEX, SCB_RESIDUAL_SGPTR[0];
test DATA_COUNT_ODD, 0x1 jz . + 2;
@@ -803,29 +794,10 @@ calc_mwi_residual_final:
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.
- */
-data_phase_reinit:
- if ((ahc->features & AHC_ULTRA2) != 0) {
- /*
- * The preload circuitry requires us to
- * reload the address too, so pull it from
- * the shaddow address.
- */
- bmov HADDR, SHADDR, 4;
- bmov HCNT, SCB_RESIDUAL_DATACNT, 3;
- } else if ((ahc->features & AHC_CMD_CHAN) != 0) {
- bmov STCNT, SCB_RESIDUAL_DATACNT, 3;
- } else {
- mvi DINDEX, STCNT;
- mvi SCB_RESIDUAL_DATACNT call bcopy_3;
- }
- and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0];
- jmp data_phase_loop;
-
p_data:
+ test SEQ_FLAGS,IDENTIFY_SEEN jnz p_data_okay;
+ mvi NO_IDENT jmp set_seqint;
+p_data_okay:
if ((ahc->features & AHC_ULTRA2) != 0) {
mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
} else {
@@ -833,17 +805,23 @@ p_data:
}
test LASTPHASE, IOI jnz . + 2;
or DMAPARAMS, DIRECTION;
- call assert; /*
- * Ensure entering a data
- * phase is okay - seen identify, etc.
- */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
/* We don't have any valid S/G elements */
mvi CCSGADDR, SG_PREFETCH_CNT;
}
- test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
+ test SEQ_FLAGS, DPHASE jz data_phase_initialize;
- /* We have seen a data phase */
+ /*
+ * If we re-enter the data phase after going through another
+ * phase, our transfer location has almost certainly been
+ * corrupted by the interveining, non-data, transfers. Ask
+ * the host driver to fix us up based on the transfer residual.
+ */
+ mvi PDATA_REINIT call set_seqint;
+ jmp data_phase_loop;
+
+data_phase_initialize:
+ /* We have seen a data phase for the first time */
or SEQ_FLAGS, DPHASE;
/*
@@ -853,6 +831,10 @@ p_data:
* modify the saved values in the SCB until we see a save
* data pointers message.
*/
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ /* The lowest address byte must be loaded last. */
+ mov SCB_DATACNT[3] call set_hhaddr;
+ }
if ((ahc->features & AHC_CMD_CHAN) != 0) {
bmov HADDR, SCB_DATAPTR, 7;
bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
@@ -1057,6 +1039,29 @@ ultra2_fifoempty:
ultra2_dmahalt:
and DFCNTRL, ~(SCSIEN|HDMAEN);
test DFCNTRL, SCSIEN|HDMAEN jnz .;
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ /*
+ * Keep HHADDR cleared for future, 32bit addressed
+ * only, DMA operations.
+ *
+ * Due to bayonette style S/G handling, our residual
+ * data must be "fixed up" once the transfer is halted.
+ * Here we fixup the HSHADDR stored in the high byte
+ * of the residual data cnt. By postponing the fixup,
+ * we can batch the clearing of HADDR with the fixup.
+ * If we halted on the last segment, the residual is
+ * already correct. If we are not on the last
+ * segment, copy the high address directly from HSHADDR.
+ * We don't need to worry about maintaining the
+ * SG_LAST_SEG flag as it will always be false in the
+ * case where an update is required.
+ */
+ or DSCOMMAND1, HADDLDSEL0;
+ test SG_CACHE_SHADOW, LAST_SEG jnz . + 2;
+ mov SCB_RESIDUAL_DATACNT[3], SHADDR;
+ clr HADDR;
+ and DSCOMMAND1, ~HADDLDSEL0;
+ }
} else {
/* If we are the last SG block, tell the hardware. */
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
@@ -1163,9 +1168,18 @@ sg_load:
call idle_loop;
test CCSGCTL, CCSGEN jnz . - 1;
bmov HADDR, CCSGRAM, 7;
- test CCSGRAM, SG_LAST_SEG jz . + 2;
- or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
+ /*
+ * Workaround for flaky external SCB RAM
+ * on certain aic7895 setups. It seems
+ * unable to handle direct transfers from
+ * S/G ram to certain SCB locations.
+ */
+ mov SINDEX, CCSGRAM;
+ mov SCB_RESIDUAL_DATACNT[3], SINDEX;
} else {
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ mov ALLZEROS call set_hhaddr;
+ }
mvi DINDEX, HADDR;
mvi SCB_RESIDUAL_SGPTR call bcopy_4;
@@ -1180,6 +1194,17 @@ sg_load:
mov SCB_RESIDUAL_DATACNT[3], DFDAT;
}
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
+
+ /*
+ * The lowest address byte must be loaded
+ * last as it triggers the computation of
+ * some items in the PCI block. The ULTRA2
+ * chips do this on PRELOAD.
+ */
+ mov HADDR, HADDR;
+ }
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
&& ahc->pci_cachesize != 0) {
call calc_mwi_residual;
@@ -1234,6 +1259,24 @@ data_phase_done:
call disable_ccsgen;
}
+ if ((ahc->features & AHC_ULTRA2) == 0) {
+ /*
+ * Clear the high address byte so that all other DMA
+ * operations, which use 32bit addressing, can assume
+ * HHADDR is 0.
+ */
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ mov ALLZEROS call set_hhaddr;
+ }
+ }
+
+ /*
+ * Update our residual information before the information is
+ * lost by some other type of SCSI I/O (e.g. PIO). If we have
+ * transferred all data, no update is needed.
+ *
+ */
+ test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done;
if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
&& ahc->pci_cachesize != 0) {
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -1257,7 +1300,7 @@ bmov_resid:
mov SCB_RESIDUAL_DATACNT[1], STCNT[1];
mov SCB_RESIDUAL_DATACNT[2], STCNT[2];
}
-
+residual_update_done:
/*
* Since we've been through a data phase, the SCB_RESID* fields
* are now initialized. Clear the full residual flag.
@@ -1289,7 +1332,9 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) {
* Command phase. Set up the DMA registers and let 'er rip.
*/
p_command:
- call assert;
+ test SEQ_FLAGS,IDENTIFY_SEEN jnz p_command_okay;
+ mvi NO_IDENT jmp set_seqint;
+p_command_okay:
if ((ahc->features & AHC_ULTRA2) != 0) {
bmov HCNT[0], SCB_CDB_LEN, 1;
@@ -1383,8 +1428,9 @@ p_command_loop:
* and store it into the SCB.
*/
p_status:
- call assert;
-
+ test SEQ_FLAGS,IDENTIFY_SEEN jnz p_status_okay;
+ mvi NO_IDENT jmp set_seqint;
+p_status_okay:
mov SCB_SCSI_STATUS, SCSIDATL;
jmp ITloop;
@@ -1626,6 +1672,18 @@ mesgin_sdptrs:
} else {
test SEQ_FLAGS, DPHASE jz mesgin_done;
}
+
+ /*
+ * If we are asked to save our position at the end of the
+ * transfer, just mark us at the end rather than perform a
+ * full save.
+ */
+ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full;
+ or SCB_SGPTR, SG_LIST_NULL;
+ jmp mesgin_done;
+
+mesgin_sdptrs_full:
+
/*
* The SCB_SGPTR becomes the next one we'll download,
* and the SCB_DATAPTR becomes the current SHADDR.
@@ -1907,16 +1965,6 @@ target_outb:
and SXFRCTL0, ~SPIOEN ret;
}
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
- test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */
-
- mvi NO_IDENT jmp set_seqint; /* no - tell the kernel */
-
/*
* Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will
* be set to the position of the SCB. If the SCB cannot be found locally,
@@ -2250,6 +2298,13 @@ END_CRITICAL
mvi SCB_TAG, SCB_LIST_NULL ret;
}
+if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+set_hhaddr:
+ or DSCOMMAND1, HADDLDSEL0;
+ and HADDR, SG_HIGH_ADDR_BITS, SINDEX;
+ and DSCOMMAND1, ~HADDLDSEL0 ret;
+}
+
if ((ahc->flags & AHC_PAGESCBS) != 0) {
get_free_or_disc_scb:
BEGIN_CRITICAL
diff --git a/sys/dev/aic7xxx/aic7xxx_93cx6.c b/sys/dev/aic7xxx/aic7xxx_93cx6.c
index e3eaedd..c2a216d 100644
--- a/sys/dev/aic7xxx/aic7xxx_93cx6.c
+++ b/sys/dev/aic7xxx/aic7xxx_93cx6.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.c#7 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.c#8 $
*
* $FreeBSD$
*/
diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.c b/sys/dev/aic7xxx/aic7xxx_freebsd.c
index e06a1d6..6582f8c 100644
--- a/sys/dev/aic7xxx/aic7xxx_freebsd.c
+++ b/sys/dev/aic7xxx/aic7xxx_freebsd.c
@@ -1106,9 +1106,12 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
/* Copy the segments into our SG list */
sg = scb->sg_list;
while (dm_segs < end_seg) {
- sg->addr = dm_segs->ds_addr;
-/* XXX Add in the 5th byte of the address later. */
- sg->len = dm_segs->ds_len;
+ uint32_t len;
+
+ sg->addr = ahc_htole32(dm_segs->ds_addr);
+ len = dm_segs->ds_len
+ | ((dm_segs->ds_addr >> 8) & 0x7F000000);
+ sg->len = ahc_htole32(len);
sg++;
dm_segs++;
}
@@ -1119,7 +1122,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
* sequencer will clear as soon as a data transfer
* occurs.
*/
- scb->hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
+ scb->hscb->sgptr = ahc_htole32(scb->sg_list_phys|SG_FULL_RESID);
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
op = BUS_DMASYNC_PREREAD;
@@ -1165,13 +1168,13 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
xpt_done(ccb);
return;
}
- sg->addr = ahc->dma_bug_buf;
- sg->len = 1;
+ sg->addr = ahc_htole32(ahc->dma_bug_buf);
+ sg->len = ahc_htole32(1);
sg++;
}
}
sg--;
- sg->len |= AHC_DMA_LAST_SEG;
+ sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
/* Copy the first SG into the "current" data pointer area */
scb->hscb->dataptr = scb->sg_list->addr;
@@ -1297,6 +1300,8 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
hscb = scb->hscb;
ccb_h = &csio->ccb_h;
+ csio->resid = 0;
+ csio->sense_resid = 0;
if (ccb_h->func_code == XPT_SCSI_IO) {
hscb->cdb_len = csio->cdb_len;
if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.h b/sys/dev/aic7xxx/aic7xxx_freebsd.h
index f90caba..b12a2d6 100644
--- a/sys/dev/aic7xxx/aic7xxx_freebsd.h
+++ b/sys/dev/aic7xxx/aic7xxx_freebsd.h
@@ -138,8 +138,9 @@ typedef union ccb *ahc_io_ctx_t;
#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)
+/* XXX Need to update Bus DMA for partial map syncs */
+#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) \
+ bus_dmamap_sync(dma_tag, dmamap, op)
/************************ Tunable Driver Parameters **************************/
/*
diff --git a/sys/dev/aic7xxx/aic7xxx_inline.h b/sys/dev/aic7xxx/aic7xxx_inline.h
index ddf1bb5..c5db614 100644
--- a/sys/dev/aic7xxx/aic7xxx_inline.h
+++ b/sys/dev/aic7xxx/aic7xxx_inline.h
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#27 $
*
* $FreeBSD$
*/
@@ -37,8 +37,8 @@
#define _AIC7XXX_INLINE_H_
/************************* Sequencer Execution Control ************************/
-static __inline int ahc_is_paused(struct ahc_softc *ahc);
static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
+static __inline int ahc_is_paused(struct ahc_softc *ahc);
static __inline void ahc_pause(struct ahc_softc *ahc);
static __inline void ahc_unpause(struct ahc_softc *ahc);
@@ -146,6 +146,13 @@ static __inline uint32_t
struct ahc_dma_seg *sg);
static __inline uint32_t
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
+static __inline void ahc_sync_scb(struct ahc_softc *ahc,
+ struct scb *scb, int op);
+static __inline void ahc_sync_sglist(struct ahc_softc *ahc,
+ struct scb *scb, int op);
+static __inline uint32_t
+ ahc_targetcmd_offset(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)
@@ -177,6 +184,33 @@ ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
+ (sizeof(struct hardware_scb) * index));
}
+static __inline void
+ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
+{
+ ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
+ ahc->scb_data->hscb_dmamap,
+ /*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
+ /*len*/sizeof(*scb->hscb), op);
+}
+
+static __inline void
+ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
+{
+ if (scb->sg_count == 0)
+ return;
+
+ ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
+ /*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
+ * sizeof(struct ahc_dma_seg),
+ /*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
+}
+
+static __inline uint32_t
+ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
+{
+ return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
+}
+
/******************************** Debugging ***********************************/
static __inline char *ahc_name(struct ahc_softc *ahc);
@@ -219,8 +253,6 @@ ahc_update_residual(struct scb *scb)
sgptr = ahc_le32toh(scb->hscb->sgptr);
if ((sgptr & SG_RESID_VALID) != 0)
ahc_calc_residual(scb);
- else
- ahc_set_residual(scb, 0);
}
/*
@@ -284,8 +316,13 @@ ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
static __inline struct scb *
ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
{
- return (ahc->scb_data->scbindex[tag]);
+ struct scb* scb;
+ scb = ahc->scb_data->scbindex[tag];
+ if (scb != NULL)
+ ahc_sync_scb(ahc, scb,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ return (scb);
}
static __inline void
@@ -342,6 +379,14 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
* Keep a history of SCBs we've downloaded in the qinfifo.
*/
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+
+ /*
+ * Make sure our data is consistant from the
+ * perspective of the adapter.
+ */
+ ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Tell the adapter about the newly queued SCB */
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
} else {
@@ -373,8 +418,31 @@ ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
}
/************************** Interrupt Processing ******************************/
-static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
-static __inline void ahc_intr(struct ahc_softc *ahc);
+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 void
+ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
+{
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ /*offset*/0, /*len*/256, op);
+}
+
+static __inline void
+ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
+{
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0) {
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, 0),
+ sizeof(struct target_cmd) * AHC_TMODE_CMDS,
+ op);
+ }
+#endif
+}
/*
* See if the firmware has posted any completed commands
@@ -388,12 +456,21 @@ ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
u_int retval;
retval = 0;
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ /*offset*/ahc->qoutfifonext, /*len*/1,
+ BUS_DMASYNC_POSTREAD);
if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
retval |= AHC_RUN_QOUTFIFO;
#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0
- && ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
- retval |= AHC_RUN_TQINFIFO;
+ if ((ahc->flags & AHC_TARGETROLE) != 0) {
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
+ /*len*/sizeof(struct target_cmd),
+ BUS_DMASYNC_POSTREAD);
+ if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
+ retval |= AHC_RUN_TQINFIFO;
+ }
#endif
return (retval);
}
@@ -418,36 +495,13 @@ ahc_intr(struct ahc_softc *ahc)
intstat = CMDCMPLT;
else {
intstat = ahc_inb(ahc, INTSTAT);
- /*
- * We can't generate queuestat once above
- * or we are exposed to a race when our
- * interrupt is shared with another device.
- * if instat showed a command complete interrupt,
- * but our first generation of queue stat
- * "just missed" the delivery of this transaction,
- * we would clear the command complete interrupt
- * below without ever servicing the completed
- * command.
- */
- queuestat = ahc_check_cmdcmpltqueues(ahc);
-#if AHC_PCI_CONFIG > 0
- if (ahc->unsolicited_ints > 500
- && (ahc->chip & AHC_PCI) != 0
- && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
- ahc->bus_intr(ahc);
+ queuestat = AHC_RUN_QOUTFIFO;
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0)
+ queuestat |= AHC_RUN_TQINFIFO;
#endif
}
- if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
- /* Hot eject */
- return;
-
- if ((intstat & INT_PEND) == 0) {
- ahc->unsolicited_ints++;
- return;
- }
- ahc->unsolicited_ints = 0;
-
if (intstat & CMDCMPLT) {
ahc_outb(ahc, CLRINT, CLRCMDINT);
@@ -469,6 +523,25 @@ ahc_intr(struct ahc_softc *ahc)
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
#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) {
ahc_handle_brkadrint(ahc);
/* Fatal error, no more interrupts to handle. */
diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c
index e06a1d6..6582f8c 100644
--- a/sys/dev/aic7xxx/aic7xxx_osm.c
+++ b/sys/dev/aic7xxx/aic7xxx_osm.c
@@ -1106,9 +1106,12 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
/* Copy the segments into our SG list */
sg = scb->sg_list;
while (dm_segs < end_seg) {
- sg->addr = dm_segs->ds_addr;
-/* XXX Add in the 5th byte of the address later. */
- sg->len = dm_segs->ds_len;
+ uint32_t len;
+
+ sg->addr = ahc_htole32(dm_segs->ds_addr);
+ len = dm_segs->ds_len
+ | ((dm_segs->ds_addr >> 8) & 0x7F000000);
+ sg->len = ahc_htole32(len);
sg++;
dm_segs++;
}
@@ -1119,7 +1122,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
* sequencer will clear as soon as a data transfer
* occurs.
*/
- scb->hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
+ scb->hscb->sgptr = ahc_htole32(scb->sg_list_phys|SG_FULL_RESID);
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
op = BUS_DMASYNC_PREREAD;
@@ -1165,13 +1168,13 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
xpt_done(ccb);
return;
}
- sg->addr = ahc->dma_bug_buf;
- sg->len = 1;
+ sg->addr = ahc_htole32(ahc->dma_bug_buf);
+ sg->len = ahc_htole32(1);
sg++;
}
}
sg--;
- sg->len |= AHC_DMA_LAST_SEG;
+ sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
/* Copy the first SG into the "current" data pointer area */
scb->hscb->dataptr = scb->sg_list->addr;
@@ -1297,6 +1300,8 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
hscb = scb->hscb;
ccb_h = &csio->ccb_h;
+ csio->resid = 0;
+ csio->sense_resid = 0;
if (ccb_h->func_code == XPT_SCSI_IO) {
hscb->cdb_len = csio->cdb_len;
if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
diff --git a/sys/dev/aic7xxx/aic7xxx_osm.h b/sys/dev/aic7xxx/aic7xxx_osm.h
index f90caba..b12a2d6 100644
--- a/sys/dev/aic7xxx/aic7xxx_osm.h
+++ b/sys/dev/aic7xxx/aic7xxx_osm.h
@@ -138,8 +138,9 @@ typedef union ccb *ahc_io_ctx_t;
#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)
+/* XXX Need to update Bus DMA for partial map syncs */
+#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) \
+ bus_dmamap_sync(dma_tag, dmamap, op)
/************************ Tunable Driver Parameters **************************/
/*
diff --git a/sys/dev/aic7xxx/aic7xxx_pci.c b/sys/dev/aic7xxx/aic7xxx_pci.c
index 0a7b4f3..bee6caf 100644
--- a/sys/dev/aic7xxx/aic7xxx_pci.c
+++ b/sys/dev/aic7xxx/aic7xxx_pci.c
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#27 $
*
* $FreeBSD$
*/
@@ -628,9 +628,10 @@ const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
#define DEVCONFIG 0x40
#define SCBSIZE32 0x00010000ul /* aic789X only */
#define REXTVALID 0x00001000ul /* ultra cards only */
-#define MPORTMODE 0x00000400ul /* aic7870 only */
-#define RAMPSM 0x00000200ul /* aic7870 only */
+#define MPORTMODE 0x00000400ul /* aic7870+ only */
+#define RAMPSM 0x00000200ul /* aic7870+ only */
#define VOLSENSE 0x00000100ul
+#define PCI64BIT 0x00000080ul /* 64Bit PCI bus (Ultra2 Only)*/
#define SCBRAMSEL 0x00000080ul
#define MRDCEN 0x00000040ul
#define EXTSCBTIME 0x00000020ul /* aic7870 only */
@@ -693,9 +694,16 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
subdevice,
subvendor);
- /* If the second function is not hooked up, ignore it. */
+ /*
+ * If the second function is not hooked up, ignore it.
+ * Unfortunately, not all MB vendors implement the
+ * subdevice ID as per the Adaptec spec, so do our best
+ * to sanity check it prior to accepting the subdevice
+ * ID as valid.
+ */
if (ahc_get_pci_function(pci) > 0
&& subvendor == 0x9005
+ && subdevice != device
&& SUBID_9005_TYPE_KNOWN(subdevice) != 0
&& SUBID_9005_MFUNCENB(subdevice) == 0)
return (NULL);
@@ -715,7 +723,6 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
int
ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
{
- struct ahc_probe_config probe_config;
struct scb_data *shared_scb_data;
u_int command;
u_int our_id = 0;
@@ -726,12 +733,11 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
uint8_t sblkctl;
shared_scb_data = NULL;
- ahc_init_probe_config(&probe_config);
- error = entry->setup(ahc->dev_softc, &probe_config);
+ error = entry->setup(ahc);
if (error != 0)
return (error);
- probe_config.chip |= AHC_PCI;
- probe_config.description = entry->name;
+ ahc->chip |= AHC_PCI;
+ ahc->description = entry->name;
error = ahc_pci_map_registers(ahc);
if (error != 0)
@@ -739,15 +745,34 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+ /*
+ * If we need to support high memory, enable dual
+ * address cycles. This bit must be set to enable
+ * high address bit generation even if we are on a
+ * 64bit bus (PCI64BIT set in devconfig).
+ */
+ if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+ uint32_t devconfig;
+
+ if (bootverbose)
+ printf("%s: Enabling 39Bit Addressing\n",
+ ahc_name(ahc));
+ devconfig = ahc_pci_read_config(ahc->dev_softc,
+ DEVCONFIG, /*bytes*/4);
+ devconfig |= DACEN;
+ 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 |= PCIM_CMD_BUSMASTEREN;
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
/* On all PCI adapters, we allow SCB paging */
- probe_config.flags |= AHC_PAGESCBS;
+ ahc->flags |= AHC_PAGESCBS;
- error = ahc_softc_init(ahc, &probe_config);
+ error = ahc_softc_init(ahc);
if (error != 0)
return (error);
@@ -1764,14 +1789,15 @@ ahc_pci_intr(struct ahc_softc *ahc)
printf("%s: Data Parity Error has been reported via PERR#\n",
ahc_name(ahc));
}
- if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
- printf("%s: Latched PCIERR interrupt with "
- "no status bits set\n", ahc_name(ahc));
- }
+
+ /* Clear latched errors. */
ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,
status1, /*bytes*/1);
- if (status1 & (DPR|RMA|RTA)) {
+ if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
+ printf("%s: Latched PCIERR interrupt with "
+ "no status bits set\n", ahc_name(ahc));
+ } else {
ahc_outb(ahc, CLRINT, CLRPARERR);
}
@@ -1779,187 +1805,204 @@ ahc_pci_intr(struct ahc_softc *ahc)
}
static int
-ahc_aic785X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic785X_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
uint8_t rev;
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7850;
- probe_config->features = AHC_AIC7850_FE;
- probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
- | AHC_PCI_MWI_BUG;
+ pci = ahc->dev_softc;
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7850;
+ ahc->features = AHC_AIC7850_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev >= 1)
- probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
return (0);
}
static int
-ahc_aic7860_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7860_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
uint8_t rev;
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7860;
- probe_config->features = AHC_AIC7860_FE;
- probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
- | AHC_PCI_MWI_BUG;
+ pci = ahc->dev_softc;
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7860;
+ ahc->features = AHC_AIC7860_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev >= 1)
- probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
return (0);
}
static int
-ahc_apa1480_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_apa1480_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
int error;
- error = ahc_aic7860_setup(pci, probe_config);
+ pci = ahc->dev_softc;
+ error = ahc_aic7860_setup(ahc);
if (error != 0)
return (error);
- probe_config->features |= AHC_REMOVABLE;
+ ahc->features |= AHC_REMOVABLE;
return (0);
}
static int
-ahc_aic7870_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7870_setup(struct ahc_softc *ahc)
{
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7870;
- probe_config->features = AHC_AIC7870_FE;
- probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
- | AHC_PCI_MWI_BUG;
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7870;
+ ahc->features = AHC_AIC7870_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
return (0);
}
static int
-ahc_aha394X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha394X_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7870_setup(pci, probe_config);
+ error = ahc_aic7870_setup(ahc);
if (error == 0)
- error = ahc_aha394XX_setup(pci, probe_config);
+ error = ahc_aha394XX_setup(ahc);
return (error);
}
static int
-ahc_aha398X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha398X_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7870_setup(pci, probe_config);
+ error = ahc_aic7870_setup(ahc);
if (error == 0)
- error = ahc_aha398XX_setup(pci, probe_config);
+ error = ahc_aha398XX_setup(ahc);
return (error);
}
static int
-ahc_aha494X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha494X_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7870_setup(pci, probe_config);
+ error = ahc_aic7870_setup(ahc);
if (error == 0)
- error = ahc_aha494XX_setup(pci, probe_config);
+ error = ahc_aha494XX_setup(ahc);
return (error);
}
static int
-ahc_aic7880_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7880_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
uint8_t rev;
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7880;
- probe_config->features = AHC_AIC7880_FE;
- probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
+ pci = ahc->dev_softc;
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7880;
+ ahc->features = AHC_AIC7880_FE;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev >= 1) {
- probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
+ ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
} else {
- probe_config->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+ ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
}
return (0);
}
static int
-ahc_aha2940Pro_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha2940Pro_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
int error;
- probe_config->flags |= AHC_INT50_SPEEDFLEX;
- error = ahc_aic7880_setup(pci, probe_config);
+ pci = ahc->dev_softc;
+ ahc->flags |= AHC_INT50_SPEEDFLEX;
+ error = ahc_aic7880_setup(ahc);
return (0);
}
static int
-ahc_aha394XU_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha394XU_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7880_setup(pci, probe_config);
+ error = ahc_aic7880_setup(ahc);
if (error == 0)
- error = ahc_aha394XX_setup(pci, probe_config);
+ error = ahc_aha394XX_setup(ahc);
return (error);
}
static int
-ahc_aha398XU_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha398XU_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7880_setup(pci, probe_config);
+ error = ahc_aic7880_setup(ahc);
if (error == 0)
- error = ahc_aha398XX_setup(pci, probe_config);
+ error = ahc_aha398XX_setup(ahc);
return (error);
}
static int
-ahc_aic7890_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7890_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
uint8_t rev;
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7890;
- probe_config->features = AHC_AIC7890_FE;
- probe_config->flags |= AHC_NEWEEPROM_FMT;
+ pci = ahc->dev_softc;
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7890;
+ ahc->features = AHC_AIC7890_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev == 0)
- probe_config->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
+ ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
return (0);
}
static int
-ahc_aic7892_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7892_setup(struct ahc_softc *ahc)
{
- probe_config->channel = 'A';
- probe_config->chip = AHC_AIC7892;
- probe_config->features = AHC_AIC7892_FE;
- probe_config->flags |= AHC_NEWEEPROM_FMT;
- probe_config->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
+ ahc->channel = 'A';
+ ahc->chip = AHC_AIC7892;
+ ahc->features = AHC_AIC7892_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
return (0);
}
static int
-ahc_aic7895_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7895_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
uint8_t rev;
- probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+ pci = ahc->dev_softc;
+ ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
/*
* The 'C' revision of the aic7895 has a few additional features.
*/
rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev >= 4) {
- probe_config->chip = AHC_AIC7895C;
- probe_config->features = AHC_AIC7895C_FE;
+ ahc->chip = AHC_AIC7895C;
+ ahc->features = AHC_AIC7895C_FE;
} else {
u_int command;
- probe_config->chip = AHC_AIC7895;
- probe_config->features = AHC_AIC7895_FE;
+ ahc->chip = AHC_AIC7895;
+ ahc->features = AHC_AIC7895_FE;
/*
* The BIOS disables the use of MWI transactions
@@ -1970,14 +2013,14 @@ ahc_aic7895_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
command = ahc_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1);
command |= PCIM_CMD_MWRICEN;
ahc_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1);
- probe_config->bugs |= AHC_PCI_MWI_BUG;
+ ahc->bugs |= AHC_PCI_MWI_BUG;
}
/*
* XXX Does CACHETHEN really not work??? What about PCI retry?
* on C level chips. Need to test, but for now, play it safe.
*/
- probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
- | AHC_CACHETHEN_BUG;
+ ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
+ | AHC_CACHETHEN_BUG;
#if 0
uint32_t devconfig;
@@ -1991,116 +2034,131 @@ ahc_aic7895_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
devconfig |= MRDCEN;
ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1);
#endif
- probe_config->flags |= AHC_NEWEEPROM_FMT;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
return (0);
}
static int
-ahc_aic7896_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7896_setup(struct ahc_softc *ahc)
{
- probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
- probe_config->chip = AHC_AIC7896;
- probe_config->features = AHC_AIC7896_FE;
- probe_config->flags |= AHC_NEWEEPROM_FMT;
- probe_config->bugs |= AHC_CACHETHEN_DIS_BUG;
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
+ ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+ ahc->chip = AHC_AIC7896;
+ ahc->features = AHC_AIC7896_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
return (0);
}
static int
-ahc_aic7899_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aic7899_setup(struct ahc_softc *ahc)
{
- probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
- probe_config->chip = AHC_AIC7899;
- probe_config->features = AHC_AIC7899_FE;
- probe_config->flags |= AHC_NEWEEPROM_FMT;
- probe_config->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
+ ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+ ahc->chip = AHC_AIC7899;
+ ahc->features = AHC_AIC7899_FE;
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
return (0);
}
static int
-ahc_aha29160C_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha29160C_setup(struct ahc_softc *ahc)
{
int error;
- error = ahc_aic7899_setup(pci, probe_config);
+ error = ahc_aic7899_setup(ahc);
if (error != 0)
return (error);
- probe_config->features |= AHC_REMOVABLE;
+ ahc->features |= AHC_REMOVABLE;
return (0);
}
static int
-ahc_raid_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_raid_setup(struct ahc_softc *ahc)
{
printf("RAID functionality unsupported\n");
return (ENXIO);
}
static int
-ahc_aha394XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha394XX_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
switch (ahc_get_pci_slot(pci)) {
case AHC_394X_SLOT_CHANNEL_A:
- probe_config->channel = 'A';
+ ahc->channel = 'A';
break;
case AHC_394X_SLOT_CHANNEL_B:
- probe_config->channel = 'B';
+ ahc->channel = 'B';
break;
default:
printf("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
ahc_get_pci_slot(pci));
- probe_config->channel = 'A';
+ ahc->channel = 'A';
}
return (0);
}
static int
-ahc_aha398XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha398XX_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
switch (ahc_get_pci_slot(pci)) {
case AHC_398X_SLOT_CHANNEL_A:
- probe_config->channel = 'A';
+ ahc->channel = 'A';
break;
case AHC_398X_SLOT_CHANNEL_B:
- probe_config->channel = 'B';
+ ahc->channel = 'B';
break;
case AHC_398X_SLOT_CHANNEL_C:
- probe_config->channel = 'C';
+ ahc->channel = 'C';
break;
default:
printf("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
ahc_get_pci_slot(pci));
- probe_config->channel = 'A';
+ ahc->channel = 'A';
break;
}
- probe_config->flags |= AHC_LARGE_SEEPROM;
+ ahc->flags |= AHC_LARGE_SEEPROM;
return (0);
}
static int
-ahc_aha494XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+ahc_aha494XX_setup(struct ahc_softc *ahc)
{
+ ahc_dev_softc_t pci;
+
+ pci = ahc->dev_softc;
switch (ahc_get_pci_slot(pci)) {
case AHC_494X_SLOT_CHANNEL_A:
- probe_config->channel = 'A';
+ ahc->channel = 'A';
break;
case AHC_494X_SLOT_CHANNEL_B:
- probe_config->channel = 'B';
+ ahc->channel = 'B';
break;
case AHC_494X_SLOT_CHANNEL_C:
- probe_config->channel = 'C';
+ ahc->channel = 'C';
break;
case AHC_494X_SLOT_CHANNEL_D:
- probe_config->channel = 'D';
+ ahc->channel = 'D';
break;
default:
printf("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
ahc_get_pci_slot(pci));
- probe_config->channel = 'A';
+ ahc->channel = 'A';
}
- probe_config->flags |= AHC_LARGE_SEEPROM;
+ ahc->flags |= AHC_LARGE_SEEPROM;
return (0);
}
OpenPOWER on IntegriCloud