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

Signed-off-by: Matthew Wilcox <[EMAIL PROTECTED]>

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
diff -u -p -r1.12.2.1 -r1.14
--- ./drivers/scsi/scsi_transport_spi.c 2 Mar 2005 11:19:13 -0000       1.12.2.1
+++ ./drivers/scsi/scsi_transport_spi.c 6 Mar 2005 17:11:18 -0000       1.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
diff -u -p -r1.6.4.1 -r1.6
--- ./include/scsi/scsi_transport_spi.h 2 Mar 2005 11:19:23 -0000       1.6.4.1
+++ ./include/scsi/scsi_transport_spi.h 23 Feb 2005 18:31:37 -0000      1.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 */

-- 
"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
-
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

Reply via email to