Skip to contentSkip to conversation

Display SPI transfer agreement in common code

PATCH In review Matthew Wilcox 1 participant 2 messages Mar 6, 2005 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Display SPI transfer agreement in common code

[ This is an updated version of
http://marc.theaimsgroup.com/?l=linux-scsi&m=110918302718178&w=2
Relative to that patch, it prints the period in a nicer way; exactly the same way as the strings in the original version of this file. ]

Introduce a generic SPI function to print the negotiated transfer agreement. It's based on the implementation in sym53c8xx_2/sym_misc.c. I have changes in my tree to make 53c700, ncr53c8xx and sym2 use it. Other drivers need to be converted to use the SPI transport layer first.

In order to calculate the speed I needed to be able to convert from period factor to period in picoseconds. That required changing (show|store)_spi_transport_period to work in picoseconds rather than a string.

Index: ./drivers/scsi/scsi_transport_spi.c
===================================================================
RCS file: /var/lib/cvs/linux-2.6/drivers/scsi/scsi_transport_spi.c,v retrieving revision 1.12.2.1
retrieving revision 1.14

drivers/scsi/scsi_transport_spi.c +124 -59
diff -u -p -r1.12.2.1 -r1.14
@@ -18,15 +18,11 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/module.h>
+#include <linux/ctype.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/workqueue.h>
-#include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <asm/semaphore.h>
 #include <scsi/scsi.h>
 #include "scsi_priv.h"
 #include <scsi/scsi_device.h>
@@ -63,27 +59,47 @@ struct spi_internal {
 
 #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
 
-static const char *const ppr_to_ns[] = {
+static const int ppr_to_ps[] = {
 	/* The PPR values 0-6 are reserved, fill them in when
 	 * the committee defines them */
-	NULL,			/* 0x00 */
-	NULL,			/* 0x01 */
-	NULL,			/* 0x02 */
-	NULL,			/* 0x03 */
-	NULL,			/* 0x04 */
-	NULL,			/* 0x05 */
-	NULL,			/* 0x06 */
-	"3.125",		/* 0x07 */
-	"6.25",			/* 0x08 */
-	"12.5",			/* 0x09 */
-	"25",			/* 0x0a */
-	"30.3",			/* 0x0b */
-	"50",			/* 0x0c */
+	-1,			/* 0x00 */
+	-1,			/* 0x01 */
+	-1,			/* 0x02 */
+	-1,			/* 0x03 */
+	-1,			/* 0x04 */
+	-1,			/* 0x05 */
+	-1,			/* 0x06 */
+	 3125,			/* 0x07 */
+	 6250,			/* 0x08 */
+	12500,			/* 0x09 */
+	25000,			/* 0x0a */
+	30300,			/* 0x0b */
+	50000,			/* 0x0c */
 };
 /* The PPR values at which you calculate the period in ns by multiplying
  * by 4 */
 #define SPI_STATIC_PPR	0x0c
 
+static int sprint_frac(char *dest, int value, int denom)
+{
+	int frac = value % denom;
+	int result = sprintf(dest, "%d", value / denom);
+
+	if (frac == 0)
+		return result;
+	dest[result++] = '.';
+
+	do {
+		denom /= 10;
+		sprintf(dest + result, "%d", frac / denom);
+		result++;
+		frac %= denom;
+	} while (frac);
+
+	dest[result++] = '\0';
+	return result;
+}
+
 static struct {
 	enum spi_signal_type	value;
 	char			*name;
@@ -261,7 +277,7 @@ static ssize_t show_spi_transport_period
 	struct scsi_target *starget = transport_class_to_starget(cdev);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct spi_transport_attrs *tp;
-	const char *str;
+	int len, picosec;
 	struct spi_internal *i = to_spi_internal(shost->transportt);
 
 	tp = (struct spi_transport_attrs *)&starget->starget_data;
@@ -269,22 +285,20 @@ static ssize_t show_spi_transport_period
 	if (i->f->get_period)
 		i->f->get_period(starget);
 
-	switch(tp->period) {
-
-	case 0x07 ... SPI_STATIC_PPR:
-		str = ppr_to_ns[tp->period];
-		if(!str)
-			str = "reserved";
-		break;
-
-
-	case (SPI_STATIC_PPR+1) ... 0xff:
-		return sprintf(buf, "%d\n", tp->period * 4);
-
-	default:
-		str = "unknown";
+	if (tp->period < 0 || tp->period > 0xff) {
+		picosec = -1;
+	} else if (tp->period <= SPI_STATIC_PPR) {
+		picosec = ppr_to_ps[tp->period];
+	} else {
+		picosec = tp->period * 4000;
 	}
-	return sprintf(buf, "%s\n", str);
+
+	if (picosec == -1)
+		return sprintf(buf, "reserved");
+	len = sprint_frac(buf, picosec, 1000);
+	buf[len++] = '\n';
+	buf[len] = '\0';
+	return len;
 }
 
 static ssize_t
@@ -294,34 +308,30 @@ store_spi_transport_period(struct class_
 	struct scsi_target *starget = transport_class_to_starget(cdev);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct spi_internal *i = to_spi_internal(shost->transportt);
-	int j, period = -1;
+	int j, picosec, period = -1;
+	char *endp;
 
-	for (j = 0; j < SPI_STATIC_PPR; j++) {
-		int len;
-
-		if(ppr_to_ns[j] == NULL)
-			continue;
-
-		len = strlen(ppr_to_ns[j]);
-
-		if(strncmp(ppr_to_ns[j], buf, len) != 0)
-			continue;
+	picosec = simple_strtoul(buf, &endp, 10) * 1000;
+	if (*endp == '.') {
+		int mult = 100;
+		do {
+			endp++;
+			if (!isdigit(*endp))
+				break;
+			picosec += (*endp - '0') * mult;
+			mult /= 10;
+		} while (mult > 0);
+	}
 
-		if(buf[len] != '\n')
+	for (j = 0; j <= SPI_STATIC_PPR; j++) {
+		if (ppr_to_ps[j] < picosec)
 			continue;
-		
 		period = j;
 		break;
 	}
 
-	if (period == -1) {
-		int val = simple_strtoul(buf, NULL, 0);
-
-
-		/* Should probably check limits here, but this
-		 * gets reasonably close to OK for most things */
-		period = val/4;
-	}
+	if (period == -1)
+		period = picosec / 4000;
 
 	if (period > 0xff)
 		period = 0xff;
@@ -330,7 +340,7 @@ store_spi_transport_period(struct class_
 
 	return count;
 }
-	
+
 static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
 			 show_spi_transport_period,
 			 store_spi_transport_period);
@@ -794,6 +804,61 @@ spi_schedule_dv_device(struct scsi_devic
 	schedule_work(&wqw->work);
 }
 EXPORT_SYMBOL(spi_schedule_dv_device);
+
+/**
+ * spi_display_xfer_agreement - Print the current target transfer agreement
+ * @starget: The target for which to display the agreement
+ *
+ * Each SPI port is required to maintain a transfer agreement for each
+ * other port on the bus.  This function prints a one-line summary of
+ * the current agreement; more detailed information is available in sysfs.
+ */
+void spi_display_xfer_agreement(struct scsi_target *starget)
+{
+	struct spi_transport_attrs *tp;
+	tp = (struct spi_transport_attrs *)&starget->starget_data;
+
+	if (tp->offset > 0 && tp->period > 0) {
+		unsigned int picosec, kb100;
+		char *scsi = "FAST-?";
+		char tmp[8];
+
+		if (tp->period <= SPI_STATIC_PPR) {
+			picosec = ppr_to_ps[tp->period];
+			switch (tp->period) {
+				case  7: scsi = "FAST-320"; break;
+				case  8: scsi = "FAST-160"; break;
+				case  9: scsi = "FAST-80"; break;
+				case 10:
+				case 11: scsi = "FAST-40"; break;
+				case 12: scsi = "FAST-20"; break;
+			}
+		} else {
+			picosec = tp->period * 4000;
+			if (tp->period < 25)
+				scsi = "FAST-20";
+			else if (tp->period < 50)
+				scsi = "FAST-10";
+			else
+				scsi = "FAST-5";
+		}
+
+		kb100 = (10000000 + picosec / 2) / picosec;
+		if (tp->width)
+			kb100 *= 2;
+		sprint_frac(tmp, picosec, 1000);
+
+		dev_info(&starget->dev,
+			"%s %sSCSI %d.%d MB/s %s%s%s (%s ns, offset %d)\n",
+			scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
+			tp->dt ? "DT" : "ST", tp->iu ? " IU" : "",
+			tp->qas  ? " QAS" : "", tmp, tp->offset);
+	} else {
+		dev_info(&starget->dev, "%sasynchronous.\n",
+				tp->width ? "wide " : "");
+	}
+}
+EXPORT_SYMBOL(spi_display_xfer_agreement);
 
 #define SETUP_ATTRIBUTE(field)						\
 	i->private_attrs[count] = class_device_attr_##field;		\

Index: ./include/scsi/scsi_transport_spi.h
===================================================================
RCS file: /var/lib/cvs/linux-2.6/include/scsi/scsi_transport_spi.h,v retrieving revision 1.6.4.1
retrieving revision 1.6

include/scsi/scsi_transport_spi.h +1 -0
diff -u -p -r1.6.4.1 -r1.6
@@ -130,5 +130,6 @@ struct scsi_transport_template *spi_atta
 void spi_release_transport(struct scsi_transport_template *);
 void spi_schedule_dv_device(struct scsi_device *);
 void spi_dv_device(struct scsi_device *);
+void spi_display_xfer_agreement(struct scsi_target *);
 
 #endif /* SCSI_TRANSPORT_SPI_H */
Signature · 6 lines
"Next the statesmen will invent cheap lies, putting the blame upon 
the nation that is attacked, and every man will be glad of those
conscience-soothing falsities, and will diligently study them, and refuse
to examine any refutations of them; and thus he will by and by convince 
himself that the war is just, and will thank God for the better sleep 
he enjoys after this process of grotesque self-deception." -- Mark Twain
#1 lore raw
Quoted 4 lines · Matthew Wilcox

Introduce a generic SPI function to print the negotiated transfer agreement. It's based on the implementation in sym53c8xx_2/sym_misc.c. I have changes in my tree to make 53c700, ncr53c8xx and sym2 use it. Other drivers need to be converted to use the SPI transport layer first.

I'd just like to have a quick discussion about this actually. I'd like to reduce the SCSI verbosity at boot. Currently, the sym2 driver does something like this:

scsi1 : sym-2.2.0
Vendor: SEAGATE Model: ST39204LC Rev: HP04
Type: Direct-Access ANSI SCSI revision: 03
target1:0:6: tagged command queuing enabled, command queue depth 16. target1:0:6: Beginning Domain Validation
target1:0:6: asynchronous.
target1:0:6: wide asynchronous.
target1:0:6: FAST-20 WIDE SCSI 40.0 MB/s ST (50 ns, offset 16) target1:0:6: Ending Domain Validation

I don't think it's terribly useful to print out all the intermediate steps, so I'd like to introduce a flag that would inhibit printing the transfer agreement and then print it once at the end, leaving to messages more like:

scsi1 : sym-2.2.0
Vendor: SEAGATE Model: ST39204LC Rev: HP04
Type: Direct-Access ANSI SCSI revision: 03
target1:0:6: tagged command queuing enabled, command queue depth 16. target1:0:6: FAST-20 WIDE SCSI 40.0 MB/s ST (50 ns, offset 16)

My impression is that James originally added the Beginning and Ending messages to indicate that messages in between were produced as a result of doing DV, and if no messages are produced, we don't need to print them any more. That saves us 4 lines per target.

Signature · 6 lines
"Next the statesmen will invent cheap lies, putting the blame upon 
the nation that is attacked, and every man will be glad of those
conscience-soothing falsities, and will diligently study them, and refuse
to examine any refutations of them; and thus he will by and by convince 
himself that the war is just, and will thank God for the better sleep 
he enjoys after this process of grotesque self-deception." -- Mark Twain