diff options
author | gibbs <gibbs@FreeBSD.org> | 2001-07-18 21:39:48 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 2001-07-18 21:39:48 +0000 |
commit | cb6621f7e0e0917b5e39d339e9aa8be17720ea3c (patch) | |
tree | fdd4d55c36494a3c8562af45e6bdd921d7240cf8 | |
parent | 42ab5fc8018c503f657d4badb2ba2ebe64f23768 (diff) | |
download | FreeBSD-src-cb6621f7e0e0917b5e39d339e9aa8be17720ea3c.zip FreeBSD-src-cb6621f7e0e0917b5e39d339e9aa8be17720ea3c.tar.gz |
ahc_pci.c:
If bus_dma will give us addresses > 32 bits, setup our dma tag
to accept up to 39bit addresses.
aic7770.c:
Update the softc directly rather than use an intermediate
"probe_config" structure.
aic7xxx.c:
Complete core work to support 39bit addresses for bulk data
dma operations. Controller data structures still must reside
under the 4GB boundary to reduce code/data size in the sequencer
and related data structures. This has been tested under Linux
IA64 and will be tested on IA64 for FreeBSD as soon as our port
can run there.
Add bus dmamap synchronization calls around manipulation of
all controller/kernel shared host data structures.
Implement data pointer reinitialation for a second data phase
in a single connection in the kernel rather than bloat the
sequencer. This is an extremely rare operation (does it ever
happen?) and the sequencer implementation was flawed for some
of the newest chips.
Don't ever allow our target role to initiate a PPR. This
is forbidden by the SCSI spec.
Add a few missing endian conversions in the ignore wide pointers
code. The core has been tested on the PPC under Linux and should
work for FreeBSD PPC. As soon as I can test the OSM layer for
FreeBSD PPC, I will.
Move some of ahc_softc_init() into ahc_alloc() now that the
probe_config structure is gone.
Add a 4GB boundary condition on all of our dma tags. 32bit
DAC under PCI only works on a single 4GB "page". Although
we can cross 4GB on a true 64bit bus, the card won't always
be installed in one and we can save code space and cost in
implementing high address support by assuming the high DWORD
address will never change.
Add diagnostics to ahc_search_qinfifo().
Correct a target mode issue with bus resets. To avoid an
interrupt storm from a malicious third party holding the
reset line, the sequencer would defer re-enabling the reset
interrupt until either a select-out or select-in. Unfortunately,
the select-in enable bit is cleared by a bus reset, so a second
reset will render the card deaf to an initiator's attempts to
contact it. We now re-enable bus reset interrupts immediately
if the target role is enabled.
aic7xxx.h:
Remove struct ahc_probe_config.
SCB's now contain a pointer to the sg_map_node so we can perfrom
bus dma sync operations on the SG list prior to queuing a command.
aic7xxx.reg:
Register the Perforce ID for this file with the VERSION keyword
so it is printed in generated files.
Add the DSCOMMAND1 register which is used to access the high
DWORD of address bits.
Add the data pointer reinitialize sequencer interrupt code.
aic7xxx.seq:
Register the Perforce ID for this file with the VERSION keyword
so it is printed in generated files.
Remove code to re-enable the bus reset interrupt after a select-in.
In target mode we cannot defer this operation as ENSELI is cleared
by a bus reset.
Complete 39bit support.
Generate a sequencer inteerrupt rather than handle the data
pointers re-initialitation in the sequencer.
Inline the "seen identify" assertion to save a few cycles.
Short circuit the update of our residual data if we have
fully completed a transfer. The residual is correct from
our last S/G load operation.
Short circuit full SDPTR processing if the residual is 0.
Just mark the transfer as complete.
aic7xxx_93cx6.c:
Synchronize perforce IDs.
aic7xxx_freebsd.c:
Complete untested 39bit support.
Add missing endia conversions.
Clear our residuals prior to starting a command. The
update residual code in the core only sets the residual
if there is one.
aic7xxx_freebsd.h:
Modeify ahc_dmamap_sync() macros to take an offset and a length.
This is how sync operations are performed in NetBSD, and we should
update our bus dma implementation to match.
aic7xxx_inline.h:
Add data structure synchronization helper functions.
Fix a bug in ahc_intr() where we would not clear our unsolicited
interrupt counter after running our PCI interrupt handler. This
may have been the cause of the spurious PCI interrupt messages.
aic7xxx_pci.c:
Adjust for loss of probe_config structure.
Guard against bogus 9005 subdevice information as seen on some
IBM MB configurations.
Add 39bit address support.
MFC after: 10 days
-rw-r--r-- | sys/dev/aic7xxx/ahc_pci.c | 20 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7770.c | 39 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.c | 264 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.h | 44 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.reg | 21 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.seq | 175 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_93cx6.c | 2 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_freebsd.c | 19 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_freebsd.h | 5 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_inline.h | 147 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.c | 19 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_osm.h | 5 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_pci.c | 296 |
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, ®s_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); } |