Skip to contentSkip to conversation

Display SPI transfer agreement in common code

PATCH New Matthew Wilcox 1 participant 1 message Feb 23, 2005 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Display SPI transfer agreement in common code

Introduce a generic SPI function to print the negotiated transfer agreement. It's based on the implementation in sym53c8xx_2/sym_misc.c.

Quoted 1 line

From a quick look, 53c700, ncr53c8xx and sym2 can use it easily.

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.10

drivers/scsi/scsi_transport_spi.c +101 -58
diff -u -p -r1.10 scsi_transport_spi.c
@@ -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,22 +59,22 @@ 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 */
@@ -261,7 +257,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 picosec;
 	struct spi_internal *i = to_spi_internal(shost->transportt);
 
 	tp = (struct spi_transport_attrs *)&starget->starget_data;
@@ -269,22 +265,19 @@ 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");
+	if (picosec % 1000 == 0)
+		return sprintf(buf, "%d\n", picosec / 1000);
+	return sprintf(buf, "%d.%d\n", picosec / 1000, picosec % 1000);
 }
 
 static ssize_t
@@ -294,34 +287,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;
@@ -794,6 +783,60 @@ 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-?";
+
+		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;
+
+		dev_info(&starget->dev,
+			"%s %sSCSI %d.%d MB/s %s%s%s (%d.%d ns, offset %d)\n",
+			scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
+			tp->dt ? "DT" : "ST", tp->iu ? " IU" : "",
+			tp->qas  ? " QAS" : "", picosec / 1000, picosec % 1000,
+			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.5

include/scsi/scsi_transport_spi.h +1 -0
diff -u -p -r1.5 scsi_transport_spi.h
@@ -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