patch-2.4.9 linux/drivers/scsi/aic7xxx/aic7xxx.c
Next file: linux/drivers/scsi/aic7xxx/aic7xxx.h
Previous file: linux/drivers/scsi/aic7xxx/aic7770_linux.c
Back to the patch index
Back to the overall index
- Lines: 677
- Date:
Sun Aug 12 17:37:53 2001
- Orig file:
v2.4.8/linux/drivers/scsi/aic7xxx/aic7xxx.c
- Orig date:
Sun Aug 12 13:28:00 2001
diff -u --recursive --new-file v2.4.8/linux/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c
@@ -14,7 +14,7 @@
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -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#44 $
*
* $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $
*/
@@ -179,6 +179,7 @@
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 @@
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];
@@ -290,13 +292,17 @@
/*
* Clear 32bits of QOUTFIFO at a time
- * so that we don't clobber an incomming
+ * so that we don't clobber an incoming
* byte DMA to the array on architectures
* that only support 32bit load and store
* operations.
*/
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 @@
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_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_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:
@@ -1049,7 +1081,7 @@
/*
* Although the driver does not care about the
* 'Selection in Progress' status bit, the busy
- * LED does. SELINGO is only cleared by a sucessful
+ * LED does. SELINGO is only cleared by a sucessfull
* selection, so we must manually clear it to insure
* the LED turns off just incase no future successful
* selections occur (e.g. no devices on the bus).
@@ -1269,6 +1301,13 @@
seqaddr = ahc_inb(ahc, SEQADDR0)
| (ahc_inb(ahc, SEQADDR1) << 8);
+ /*
+ * Seqaddr represents the next instruction to execute,
+ * so we are really executing the instruction just
+ * before it.
+ */
+ if (seqaddr != 0)
+ seqaddr -= 1;
cs = ahc->critical_sections;
for (i = 0; i < ahc->num_critical_sections; i++, cs++) {
@@ -1338,7 +1377,7 @@
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,
@@ -1365,8 +1404,10 @@
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));
}
@@ -1470,8 +1511,7 @@
/* Can't do DT on an SE bus */
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
}
- } else if ((ahc->features & AHC_ULTRA) != 0
- && (ahc->flags & AHC_ULTRA_DISABLED) == 0) {
+ } else if ((ahc->features & AHC_ULTRA) != 0) {
maxsync = AHC_SYNCRATE_ULTRA;
} else {
maxsync = AHC_SYNCRATE_FAST;
@@ -1911,7 +1951,7 @@
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 +1967,8 @@
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 +2223,9 @@
*/
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;
@@ -2615,7 +2660,7 @@
}
/*
- * Wait for a complete incomming message, parse it, and respond accordingly.
+ * Wait for a complete incoming message, parse it, and respond accordingly.
*/
static int
ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
@@ -3208,13 +3253,15 @@
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 +3279,19 @@
* 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 +3308,72 @@
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 +3479,14 @@
/* 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,21 +3497,14 @@
}
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;
ahc->pause = ahc->unpause | PAUSE;
- /* XXX The shared scb data stuff should be depricated */
+ /* XXX The shared scb data stuff should be deprecated */
if (ahc->scb_data == NULL) {
ahc->scb_data = malloc(sizeof(*ahc->scb_data),
M_DEVBUF, M_NOWAIT);
@@ -3697,18 +3792,6 @@
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 +3877,8 @@
/* 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 +3890,7 @@
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 +3909,8 @@
/* 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 +3941,8 @@
/* 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 +4085,7 @@
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 +4213,8 @@
#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 +4241,8 @@
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 +4276,7 @@
/* 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);
@@ -4306,8 +4396,6 @@
ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8)
| ahc_inb(ahc, ULTRA_ENB);
}
- if ((ahc->flags & AHC_ULTRA_DISABLED) != 0)
- ultraenb = 0;
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
max_targ = 7;
@@ -4433,6 +4521,7 @@
/* 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;
@@ -4898,12 +4987,16 @@
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
@@ -4967,6 +5060,12 @@
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.
@@ -5028,6 +5127,11 @@
*/
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
@@ -5069,6 +5173,11 @@
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)) {
/*
@@ -5442,7 +5551,7 @@
* Go through the pending CCB list and look for
* commands for this target that are still active.
* These are other tagged commands that were
- * disconnected when the reset occured.
+ * disconnected when the reset occurred.
*/
scbp_next = LIST_FIRST(&ahc->pending_scbs);
while (scbp_next != NULL) {
@@ -5492,6 +5601,8 @@
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;
@@ -5528,31 +5639,48 @@
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;
}
@@ -5704,7 +5832,7 @@
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);
}
@@ -6107,6 +6235,10 @@
printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n",
ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg,
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+ printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
+ ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX),
+ ahc_inb(ahc, ARG_2));
+ printf("HCNT = 0x%x\n", ahc_inb(ahc, HCNT));
printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n",
ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL));
printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n",
@@ -6159,6 +6291,7 @@
}
printf("\n");
+ ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
printf("QOUTFIFO entries: ");
qoutpos = ahc->qoutfifonext;
i = 0;
@@ -6183,7 +6316,14 @@
LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
if (i++ > 256)
break;
- printf("%d ", scb->hscb->tag);
+ if (scb != LIST_FIRST(&ahc->pending_scbs))
+ printf(", ");
+ printf("%d", scb->hscb->tag);
+ if ((ahc->flags & AHC_PAGESCBS) == 0) {
+ ahc_outb(ahc, SCBPTR, scb->hscb->tag);
+ printf("(0x%x, 0x%x)", ahc_inb(ahc, SCB_CONTROL),
+ ahc_inb(ahc, SCB_TAG));
+ }
}
printf("\n");
@@ -6631,6 +6771,7 @@
if ((ahc->features & AHC_AUTOPAUSE) != 0)
paused = TRUE;
+ ahc_sync_tqinfifo(ahc, BUS_DMASYNC_POSTREAD);
while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) {
/*
@@ -6640,11 +6781,16 @@
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 incomming
+ * Lazily update our position in the target mode incoming
* command queue as seen by the sequencer.
*/
if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)