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

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)