Skip to contentSkip to conversation

Update aic79xx

PATCH In review Hannes Reinecke 3 participants 6 messages Jul 22, 2005 – Aug 1, 2005

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Update aic79xx

Hi James,

I've finished the update of aic79xx to make use of the scsi_transport_spi infrastructure.
The first patch is actually jgarzik's one, with some additions to make it work :-)
The second patch is the integration proper. patch made a mess of it, however, so better to compare the files by hand ...

Hope it finds your blessing.
Comments etc welcome.

target27:0:10: FAST-160 WIDE SCSI 320.0 MB/s ST IU (6.25 ns, offset 127)

Cool, eh?

Cheers,

Hannes

Signature · 9 lines
Dr. Hannes Reinecke			[email protected]
SuSE Linux Products GmbH		S390 & zSeries
Maxfeldstraße 5				+49 911 74053 688
90409 Nürnberg				http://www.suse.de

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#1 lore raw
Quoted 8 lines · Hannes Reinecke

Hi James,

I've finished the update of aic79xx to make use of the scsi_transport_spi infrastructure.
The first patch is actually jgarzik's one, with some additions to make it work :-)
The second patch is the integration proper. patch made a mess of it, however, so better to compare the files by hand ...

nice!

Jeff

#2 lore raw
In reply to Hannes Reinecke
Quoted 9 lines · Hannes Reinecke

I've finished the update of aic79xx to make use of the scsi_transport_spi infrastructure.
The first patch is actually jgarzik's one, with some additions to make it work :-)
The second patch is the integration proper. patch made a mess of it, however, so better to compare the files by hand ...

Hope it finds your blessing.
Comments etc welcome.

This looks very good, thank you for doing it!

Quoted 1 line

target27:0:10: FAST-160 WIDE SCSI 320.0 MB/s ST IU (6.25 ns, offset 127)

There is a slight problem here: ST IU isn't a legal SCSI setting (DT is a requirement for IU), so there's something slightly wrong in the parameter setting somewhere. I'll take a look through the code and see if I can spot it (probably post OLS).

James

#3 lore raw
Quoted 11 lines · James Bottomley
Quoted 9 lines · Hannes Reinecke

I've finished the update of aic79xx to make use of the scsi_transport_spi infrastructure.
The first patch is actually jgarzik's one, with some additions to make it work :-)
The second patch is the integration proper. patch made a mess of it, however, so better to compare the files by hand ...

Hope it finds your blessing.
Comments etc welcome.

Quoted 9 lines

This looks very good, thank you for doing it!

Quoted 1 line

target27:0:10: FAST-160 WIDE SCSI 320.0 MB/s ST IU (6.25 ns, offset 127)

There is a slight problem here: ST IU isn't a legal SCSI setting (DT is a requirement for IU), so there's something slightly wrong in the parameter setting somewhere. I'll take a look through the code and see if I can spot it (probably post OLS).

You are, again, correct.
The implied flags setting from SPI-3 is not taken into account. The applied patch (relative to the other two I've already sent) fixes this.

But this is not the root problem.

target5:0:10: FAST-160 WIDE SCSI 320.0 MB/s ST IU (6.25 ns, offset 127)
scsi5: target 10 synchronous with period = 0x8, offset = 0x7f(RDSTRM|DT|IU|QAS)

So, the ppr_options (which have generated the second line) are set ok, but they somehow haven't been transferred into the scsi_transport attribute.

It appears that the fallback sequence doesn't quite work.

But that'll warrant a new mail.

Cheers,

Hannes

Signature · 4 lines
Dr. Hannes Reinecke			[email protected]
SuSE Linux Products GmbH		S390 & zSeries
Maxfeldstraße 5				+49 911 74053 688
90409 Nürnberg				http://www.suse.de
drivers/scsi/aic7xxx/aic79xx_osm.c renamed from drivers/scsi/aic7xxx/aic79xx_osm.c.jejb +32 -10
@@ -2343,6 +2343,7 @@ static void ahd_linux_set_period(struct 
 				      shost->this_id, starget->id, &tstate);
 	struct ahd_devinfo devinfo;
 	unsigned int ppr_options = tinfo->goal.ppr_options;
+	unsigned int dt;
 	unsigned long flags;
 	unsigned long offset = tinfo->goal.offset;
 
@@ -2357,6 +2358,8 @@ static void ahd_linux_set_period(struct 
 			ppr_options |= MSG_EXT_PPR_IU_REQ;
 	}
 
+	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 
@@ -2366,7 +2369,8 @@ static void ahd_linux_set_period(struct 
 			ppr_options &= MSG_EXT_PPR_QAS_REQ;
 	}
 
-	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
+	ahd_find_syncrate(ahd, &period, &ppr_options,
+			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, offset,
 			 ppr_options, AHD_TRANS_GOAL, FALSE);
@@ -2385,6 +2389,7 @@ static void ahd_linux_set_offset(struct 
 	struct ahd_devinfo devinfo;
 	unsigned int ppr_options = 0;
 	unsigned int period = 0;
+	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 	unsigned long flags;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2392,7 +2397,8 @@ static void ahd_linux_set_offset(struct 
 	if (offset != 0) {
 		period = tinfo->goal.period;
 		ppr_options = tinfo->goal.ppr_options;
-		ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
+		ahd_find_syncrate(ahd, &period, &ppr_options, 
+				  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
 	}
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options,
@@ -2419,9 +2425,13 @@ static void ahd_linux_set_dt(struct scsi
 		ppr_options |= MSG_EXT_PPR_DT_REQ;
 		if (period > 9)
 			period = 9; /* at least 12.5ns for DT */
-	} else if (period <= 9)
-		period = 10; /* If resetting DT, period must be >= 25ns */
-
+	} else {
+		if (period <= 9)
+			period = 10; /* If resetting DT, period must be >= 25ns */
+		/* QAS and IU are invalid without DT set */
+		ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+		ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
+	}
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 	ahd_find_syncrate(ahd, &period, &ppr_options,
@@ -2445,11 +2455,17 @@ static void ahd_linux_set_qas(struct scs
 	unsigned int ppr_options = tinfo->goal.ppr_options
 		& ~MSG_EXT_PPR_QAS_REQ;
 	unsigned int period = tinfo->goal.period;
-	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned int dt;
 	unsigned long flags;
 
-	if (qas)
-		ppr_options |= MSG_EXT_PPR_QAS_REQ;
+	if (qas) {
+		/* QAS requires IU and DT to be set */
+		ppr_options |= MSG_EXT_PPR_QAS_REQ; 
+		ppr_options |= MSG_EXT_PPR_IU_REQ;
+		ppr_options |= MSG_EXT_PPR_DT_REQ;
+	}
+
+	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
@@ -2474,11 +2490,17 @@ static void ahd_linux_set_iu(struct scsi
 	unsigned int ppr_options = tinfo->goal.ppr_options
 		& ~MSG_EXT_PPR_IU_REQ;
 	unsigned int period = tinfo->goal.period;
-	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned int dt;
 	unsigned long flags;
 
-	if (iu)
+	if (iu) {
 		ppr_options |= MSG_EXT_PPR_IU_REQ;
+		ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */
+	} else {
+		ppr_options &= ~MSG_EXT_PPR_QAS_REQ; /* No QAS without IU */
+	}
+
+	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
#4 lore raw
Quoted 8 lines · Hannes Reinecke

But this is not the root problem.

target5:0:10: FAST-160 WIDE SCSI 320.0 MB/s ST IU (6.25 ns, offset 127)
scsi5: target 10 synchronous with period = 0x8, offset = 0x7f(RDSTRM|DT|IU|QAS)

So, the ppr_options (which have generated the second line) are set ok, but they somehow haven't been transferred into the scsi_transport attribute.

Fortunately, HP gave me a U160 AIC card at OLS, so I can now boot it up and see that the aic7xxx driver has the same problem. Attached is the fix (basically it was a single bit variable rounding error).

James

drivers/scsi/aic7xxx/aic7xxx_osm.c +6 -4
@@ -1635,9 +1635,9 @@ ahc_send_async(struct ahc_softc *ahc, ch
 		spi_period(starget) = tinfo->curr.period;
 		spi_width(starget) = tinfo->curr.width;
 		spi_offset(starget) = tinfo->curr.offset;
-		spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ;
-		spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ;
-		spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ;
+		spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0;
+		spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0;
+		spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0;
 		spi_display_xfer_agreement(starget);
 		break;
 	}
@@ -2435,8 +2435,10 @@ static void ahc_linux_set_dt(struct scsi
 	if (dt) {
 		period = 9;	/* 12.5ns is the only period valid for DT */
 		ppr_options |= MSG_EXT_PPR_DT_REQ;
-	} else if (period == 9)
+	} else if (period == 9) {
 		period = 10;	/* if resetting DT, period must be >= 25ns */
+		ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+	}
 
 	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
#5 lore raw
Quoted 7 lines · James Bottomley
Quoted 6 lines · Hannes Reinecke

But this is not the root problem.

target5:0:10: FAST-160 WIDE SCSI 320.0 MB/s ST IU (6.25 ns, offset 127)
scsi5: target 10 synchronous with period = 0x8, offset = 0x7f(RDSTRM|DT|IU|QAS)

Quoted 7 lines
Quoted 2 lines

So, the ppr_options (which have generated the second line) are set ok, but they somehow haven't been transferred into the scsi_transport attribute.

Fortunately, HP gave me a U160 AIC card at OLS, so I can now boot it up and see that the aic7xxx driver has the same problem. Attached is the fix (basically it was a single bit variable rounding error).

Yes, figured out that much. But there was also quite some bits and pieces missing (RDSTRM settings eg.) so a new patch is in place. To be applied after the other two.

target11:0:8: FAST-40 WIDE SCSI 80.0 MB/s ST (25 ns, offset 15)
scsi11: target 8 synchronous with period = 0xa, offset = 0xf

target11:0:10: FAST-160 WIDE SCSI 320.0 MB/s DT IU QAS (6.25 ns, offset
127)
scsi11: target 10 synchronous with period = 0x8, offset = 0x7f(RDSTRM|DT|IU|QAS)

Seems to have it fixed, now.

Please apply.

Cheers,

Hannes

Signature · 4 lines
Dr. Hannes Reinecke			[email protected]
SuSE Linux Products GmbH		S390 & zSeries
Maxfeldstraße 5				+49 911 74053 688
90409 Nürnberg				http://www.suse.de

From: Hannes Reinecke <[email protected]>
Subject: Update DV parameter settings

This patch updates various scsi_transport_spi parameters with the actual parameters used by the driver internally.
Domain Validation for all devices should now work properly.

drivers/scsi/aic7xxx/aic79xx_osm.c renamed from drivers/scsi/aic7xxx/aic79xx_osm.c.orig +218 -13
@@ -1636,9 +1636,9 @@ ahd_send_async(struct ahd_softc *ahd, ch
 		spi_period(starget) = tinfo->curr.period;
 		spi_width(starget) = tinfo->curr.width;
 		spi_offset(starget) = tinfo->curr.offset;
-		spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ;
-		spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ;
-		spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ;
+		spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0;
+		spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0;
+		spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0;
 		spi_display_xfer_agreement(starget);
 		break;
 	}
@@ -2318,6 +2318,18 @@ done:
 
 static void ahd_linux_exit(void);
 
+static void ahd_linux_set_xferflags(struct scsi_target *starget, unsigned int ppr_options, unsigned int period)
+{
+	spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0;
+	spi_dt(starget) = (ppr_options & MSG_EXT_PPR_DT_REQ)? 1 : 0;
+	spi_iu(starget) = (ppr_options & MSG_EXT_PPR_IU_REQ) ? 1 : 0;
+	spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0;
+	spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0;
+	spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0;
+	spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0;
+	spi_period(starget) = period;
+}
+
 static void ahd_linux_set_width(struct scsi_target *starget, int width)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
@@ -2343,9 +2355,14 @@ static void ahd_linux_set_period(struct 
 				      shost->this_id, starget->id, &tstate);
 	struct ahd_devinfo devinfo;
 	unsigned int ppr_options = tinfo->goal.ppr_options;
+	unsigned int dt;
 	unsigned long flags;
 	unsigned long offset = tinfo->goal.offset;
 
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: set period to %d\n", ahd_name(ahd), period);
+#endif
 	if (offset == 0)
 		offset = MAX_OFFSET;
 
@@ -2357,6 +2374,8 @@ static void ahd_linux_set_period(struct 
 			ppr_options |= MSG_EXT_PPR_IU_REQ;
 	}
 
+	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 
@@ -2366,7 +2385,11 @@ static void ahd_linux_set_period(struct 
 			ppr_options &= MSG_EXT_PPR_QAS_REQ;
 	}
 
-	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
+	ahd_find_syncrate(ahd, &period, &ppr_options,
+			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	ahd_linux_set_xferflags(starget, ppr_options, period);
+
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, offset,
 			 ppr_options, AHD_TRANS_GOAL, FALSE);
@@ -2385,15 +2408,24 @@ static void ahd_linux_set_offset(struct 
 	struct ahd_devinfo devinfo;
 	unsigned int ppr_options = 0;
 	unsigned int period = 0;
+	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 	unsigned long flags;
 
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: set offset to %d\n", ahd_name(ahd), offset);
+#endif
+
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 	if (offset != 0) {
 		period = tinfo->goal.period;
 		ppr_options = tinfo->goal.ppr_options;
-		ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
+		ahd_find_syncrate(ahd, &period, &ppr_options, 
+				  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
 	}
+	ahd_linux_set_xferflags(starget, ppr_options, period);
+
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options,
 			 AHD_TRANS_GOAL, FALSE);
@@ -2415,17 +2447,28 @@ static void ahd_linux_set_dt(struct scsi
 	unsigned int period = tinfo->goal.period;
 	unsigned long flags;
 
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s DT\n", ahd_name(ahd), 
+		       dt ? "enabling" : "disabling");
+#endif
 	if (dt) {
 		ppr_options |= MSG_EXT_PPR_DT_REQ;
 		if (period > 9)
 			period = 9; /* at least 12.5ns for DT */
-	} else if (period <= 9)
-		period = 10; /* If resetting DT, period must be >= 25ns */
-
+	} else {
+		if (period <= 9)
+			period = 10; /* If resetting DT, period must be >= 25ns */
+		/* IU is invalid without DT set */
+		ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+	}
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 	ahd_find_syncrate(ahd, &period, &ppr_options,
 			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	ahd_linux_set_xferflags(starget, ppr_options, period);
+
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
 			 ppr_options, AHD_TRANS_GOAL, FALSE);
@@ -2445,16 +2488,28 @@ static void ahd_linux_set_qas(struct scs
 	unsigned int ppr_options = tinfo->goal.ppr_options
 		& ~MSG_EXT_PPR_QAS_REQ;
 	unsigned int period = tinfo->goal.period;
-	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned int dt;
 	unsigned long flags;
 
-	if (qas)
-		ppr_options |= MSG_EXT_PPR_QAS_REQ;
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s QAS\n", ahd_name(ahd), 
+		       qas ? "enabling" : "disabling");
+#endif
+
+	if (qas) {
+		ppr_options |= MSG_EXT_PPR_QAS_REQ; 
+	}
+
+	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 	ahd_find_syncrate(ahd, &period, &ppr_options,
 			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0;
+
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
 			 ppr_options, AHD_TRANS_GOAL, FALSE);
@@ -2474,16 +2529,29 @@ static void ahd_linux_set_iu(struct scsi
 	unsigned int ppr_options = tinfo->goal.ppr_options
 		& ~MSG_EXT_PPR_IU_REQ;
 	unsigned int period = tinfo->goal.period;
-	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned int dt;
 	unsigned long flags;
 
-	if (iu)
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s IU\n", ahd_name(ahd),
+		       iu ? "enabling" : "disabling");
+#endif
+
+	if (iu) {
 		ppr_options |= MSG_EXT_PPR_IU_REQ;
+		ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */
+	}
+
+	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
 	ahd_find_syncrate(ahd, &period, &ppr_options,
 			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	ahd_linux_set_xferflags(starget, ppr_options, period);
+
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
 			 ppr_options, AHD_TRANS_GOAL, FALSE);
@@ -2506,6 +2574,12 @@ static void ahd_linux_set_rd_strm(struct
 	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 	unsigned long flags;
 
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s Read Streaming\n", ahd_name(ahd), 
+		       rdstrm  ? "enabling" : "disabling");
+#endif
+
 	if (rdstrm)
 		ppr_options |= MSG_EXT_PPR_RD_STRM;
 
@@ -2513,6 +2587,131 @@ static void ahd_linux_set_rd_strm(struct
 			    starget->channel + 'A', ROLE_INITIATOR);
 	ahd_find_syncrate(ahd, &period, &ppr_options,
 			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0;
+
+	ahd_lock(ahd, &flags);
+	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+			 ppr_options, AHD_TRANS_GOAL, FALSE);
+	ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+	struct ahd_tmode_tstate *tstate;
+	struct ahd_initiator_tinfo *tinfo 
+		= ahd_fetch_transinfo(ahd,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahd_devinfo devinfo;
+	unsigned int ppr_options = tinfo->goal.ppr_options
+		& ~MSG_EXT_PPR_WR_FLOW;
+	unsigned int period = tinfo->goal.period;
+	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned long flags;
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s Write Flow Control\n", ahd_name(ahd),
+		       wrflow ? "enabling" : "disabling");
+#endif
+
+	if (wrflow)
+		ppr_options |= MSG_EXT_PPR_WR_FLOW;
+
+	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	ahd_find_syncrate(ahd, &period, &ppr_options,
+			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0;
+
+	ahd_lock(ahd, &flags);
+	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+			 ppr_options, AHD_TRANS_GOAL, FALSE);
+	ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_rti(struct scsi_target *starget, int rti)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+	struct ahd_tmode_tstate *tstate;
+	struct ahd_initiator_tinfo *tinfo 
+		= ahd_fetch_transinfo(ahd,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahd_devinfo devinfo;
+	unsigned int ppr_options = tinfo->goal.ppr_options
+		& ~MSG_EXT_PPR_RTI;
+	unsigned int period = tinfo->goal.period;
+	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned long flags;
+
+	if ((ahd->features & AHD_RTI) == 0) {
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_DV) != 0)
+			printf("%s: RTI not available\n", ahd_name(ahd));
+#endif
+		return;
+	}
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s RTI\n", ahd_name(ahd),
+		       rti ? "enabling" : "disabling");
+#endif
+
+	if (rti)
+		ppr_options |= MSG_EXT_PPR_RTI;
+
+	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	ahd_find_syncrate(ahd, &period, &ppr_options,
+			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0;
+
+	ahd_lock(ahd, &flags);
+	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
+			 ppr_options, AHD_TRANS_GOAL, FALSE);
+	ahd_unlock(ahd, &flags);
+}
+
+static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata);
+	struct ahd_tmode_tstate *tstate;
+	struct ahd_initiator_tinfo *tinfo 
+		= ahd_fetch_transinfo(ahd,
+				      starget->channel + 'A',
+				      shost->this_id, starget->id, &tstate);
+	struct ahd_devinfo devinfo;
+	unsigned int ppr_options = tinfo->goal.ppr_options
+		& ~MSG_EXT_PPR_PCOMP_EN;
+	unsigned int period = tinfo->goal.period;
+	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
+	unsigned long flags;
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_DV) != 0)
+		printf("%s: %s Precompensation\n", ahd_name(ahd), 
+		       pcomp ? "Enable" : "Disable");
+#endif
+
+	if (pcomp)
+		ppr_options |= MSG_EXT_PPR_PCOMP_EN;
+
+	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
+			    starget->channel + 'A', ROLE_INITIATOR);
+	ahd_find_syncrate(ahd, &period, &ppr_options,
+			  dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2);
+
+	spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0;
+
 	ahd_lock(ahd, &flags);
 	ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset,
 			 ppr_options, AHD_TRANS_GOAL, FALSE);
@@ -2534,6 +2733,12 @@ static struct spi_function_template ahd_
 	.show_qas	= 1,
 	.set_rd_strm	= ahd_linux_set_rd_strm,
 	.show_rd_strm	= 1,
+	.set_wr_flow	= ahd_linux_set_wr_flow,
+	.show_wr_flow	= 1,
+	.set_rti	= ahd_linux_set_rti,
+	.show_rti	= 1,
+	.set_pcomp_en	= ahd_linux_set_pcomp_en,
+	.show_pcomp_en	= 1,
 };