]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_transport_spi.c
[APPLETALK]: warning fix
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_transport_spi.c
index ef577c8c21826b082c0bac3f81b8ea97d96f650c..7ee95eb83ddaa52c5fe1aa50a52642b150293eba 100644 (file)
  *  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/config.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/workqueue.h>
 #include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <scsi/scsi.h>
 #include "scsi_priv.h"
 #include <scsi/scsi_device.h>
@@ -33,8 +34,6 @@
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_spi.h>
 
-#define SPI_PRINTK(x, l, f, a...)      dev_printk(l, &(x)->dev, f , ##a)
-
 #define SPI_NUM_ATTRS 14       /* increase this if you add attributes */
 #define SPI_OTHER_ATTRS 1      /* Increase this if you add "always
                                 * on" attributes */
@@ -49,7 +48,7 @@
 
 /* Private data accessors (keep these out of the header file) */
 #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
-#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
+#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
 
 struct spi_internal {
        struct scsi_transport_template t;
@@ -243,7 +242,7 @@ static int spi_setup_transport_attrs(struct transport_container *tc,
        spi_hold_mcs(starget) = 0;
        spi_dv_pending(starget) = 0;
        spi_initial_dv(starget) = 0;
-       init_MUTEX(&spi_dv_sem(starget));
+       mutex_init(&spi_dv_mutex(starget));
 
        return 0;
 }
@@ -380,9 +379,7 @@ static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate);
 
 /* Translate the period into ns according to the current spec
  * for SDTR/PPR messages */
-static ssize_t
-show_spi_transport_period_helper(struct class_device *cdev, char *buf,
-                                int period)
+static int period_to_str(char *buf, int period)
 {
        int len, picosec;
 
@@ -400,6 +397,14 @@ show_spi_transport_period_helper(struct class_device *cdev, char *buf,
                len = sprint_frac(buf, picosec, 1000);
        }
 
+       return len;
+}
+
+static ssize_t
+show_spi_transport_period_helper(struct class_device *cdev, char *buf,
+                                int period)
+{
+       int len = period_to_str(buf, period);
        buf[len++] = '\n';
        buf[len] = '\0';
        return len;
@@ -618,7 +623,7 @@ spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer,
                                return SPI_COMPARE_SKIP_TEST;
 
 
-                       SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", result);
+                       sdev_printk(KERN_ERR, sdev, "Write Buffer failure %x\n", result);
                        return SPI_COMPARE_FAILURE;
                }
 
@@ -702,10 +707,10 @@ spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr,
                 * IU, then QAS (if we can control them), then finally
                 * fall down the periods */
                if (i->f->set_iu && spi_iu(starget)) {
-                       SPI_PRINTK(starget, KERN_ERR, "Domain Validation Disabing Information Units\n");
+                       starget_printk(KERN_ERR, starget, "Domain Validation Disabing Information Units\n");
                        DV_SET(iu, 0);
                } else if (i->f->set_qas && spi_qas(starget)) {
-                       SPI_PRINTK(starget, KERN_ERR, "Domain Validation Disabing Quick Arbitration and Selection\n");
+                       starget_printk(KERN_ERR, starget, "Domain Validation Disabing Quick Arbitration and Selection\n");
                        DV_SET(qas, 0);
                } else {
                        newperiod = spi_period(starget);
@@ -717,11 +722,11 @@ spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr,
 
                        if (unlikely(period > 0xff || period == prevperiod)) {
                                /* Total failure; set to async and return */
-                               SPI_PRINTK(starget, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
+                               starget_printk(KERN_ERR, starget, "Domain Validation Failure, dropping back to Asynchronous\n");
                                DV_SET(offset, 0);
                                return SPI_COMPARE_FAILURE;
                        }
-                       SPI_PRINTK(starget, KERN_ERR, "Domain Validation detected failure, dropping back\n");
+                       starget_printk(KERN_ERR, starget, "Domain Validation detected failure, dropping back\n");
                        DV_SET(period, period);
                        prevperiod = period;
                }
@@ -788,7 +793,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
        
        if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
            != SPI_COMPARE_SUCCESS) {
-               SPI_PRINTK(starget, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
+               starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n");
                /* FIXME: should probably offline the device here? */
                return;
        }
@@ -802,7 +807,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                                                   buffer + len,
                                                   DV_LOOPS)
                    != SPI_COMPARE_SUCCESS) {
-                       SPI_PRINTK(starget, KERN_ERR, "Wide Transfers Fail\n");
+                       starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n");
                        i->f->set_width(starget, 0);
                }
        }
@@ -814,12 +819,10 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
        if (!scsi_device_sync(sdev) && !scsi_device_dt(sdev))
                return;
 
-       /* see if the device has an echo buffer.  If it does we can
-        * do the SPI pattern write tests */
-
-       len = 0;
-       if (scsi_device_dt(sdev))
-               len = spi_dv_device_get_echo_buffer(sdev, buffer);
+       /* len == -1 is the signal that we need to ascertain the
+        * presence of an echo buffer before trying to use it.  len ==
+        * 0 means we don't have an echo buffer */
+       len = -1;
 
  retry:
 
@@ -842,16 +845,28 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                if (spi_min_period(starget) == 8)
                        DV_SET(pcomp_en, 1);
        }
+       /* Do the read only INQUIRY tests */
+       spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
+                      spi_dv_device_compare_inquiry);
+       /* See if we actually managed to negotiate and sustain DT */
+       if (i->f->get_dt)
+               i->f->get_dt(starget);
+
+       /* see if the device has an echo buffer.  If it does we can do
+        * the SPI pattern write tests.  Because of some broken
+        * devices, we *only* try this on a device that has actually
+        * negotiated DT */
+
+       if (len == -1 && spi_dt(starget))
+               len = spi_dv_device_get_echo_buffer(sdev, buffer);
 
-       if (len == 0) {
-               SPI_PRINTK(starget, KERN_INFO, "Domain Validation skipping write tests\n");
-               spi_dv_retrain(sdev, buffer, buffer + len,
-                              spi_dv_device_compare_inquiry);
+       if (len <= 0) {
+               starget_printk(KERN_INFO, starget, "Domain Validation skipping write tests\n");
                return;
        }
 
        if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
-               SPI_PRINTK(starget, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
+               starget_printk(KERN_WARNING, starget, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
                len = SPI_MAX_ECHO_BUFFER_SIZE;
        }
 
@@ -900,15 +915,15 @@ spi_dv_device(struct scsi_device *sdev)
        scsi_target_quiesce(starget);
 
        spi_dv_pending(starget) = 1;
-       down(&spi_dv_sem(starget));
+       mutex_lock(&spi_dv_mutex(starget));
 
-       SPI_PRINTK(starget, KERN_INFO, "Beginning Domain Validation\n");
+       starget_printk(KERN_INFO, starget, "Beginning Domain Validation\n");
 
        spi_dv_device_internal(sdev, buffer);
 
-       SPI_PRINTK(starget, KERN_INFO, "Ending Domain Validation\n");
+       starget_printk(KERN_INFO, starget, "Ending Domain Validation\n");
 
-       up(&spi_dv_sem(starget));
+       mutex_unlock(&spi_dv_mutex(starget));
        spi_dv_pending(starget) = 0;
 
        scsi_target_resume(starget);
@@ -1033,12 +1048,133 @@ void spi_display_xfer_agreement(struct scsi_target *starget)
                         tp->hold_mcs ? " HMCS" : "",
                         tmp, tp->offset);
        } else {
-               dev_info(&starget->dev, "%sasynchronous.\n",
+               dev_info(&starget->dev, "%sasynchronous\n",
                                tp->width ? "wide " : "");
        }
 }
 EXPORT_SYMBOL(spi_display_xfer_agreement);
 
+#ifdef CONFIG_SCSI_CONSTANTS
+static const char * const one_byte_msgs[] = {
+/* 0x00 */ "Command Complete", NULL, "Save Pointers",
+/* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", 
+/* 0x06 */ "Abort", "Message Reject", "Nop", "Message Parity Error",
+/* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag",
+/* 0x0c */ "Bus device reset", "Abort Tag", "Clear Queue", 
+/* 0x0f */ "Initiate Recovery", "Release Recovery"
+};
+
+static const char * const two_byte_msgs[] = {
+/* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag",
+/* 0x23 */ "Ignore Wide Residue"
+};
+
+static const char * const extended_msgs[] = {
+/* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request",
+/* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request",
+/* 0x04 */ "Parallel Protocol Request"
+};
+
+static void print_nego(const unsigned char *msg, int per, int off, int width)
+{
+       if (per) {
+               char buf[20];
+               period_to_str(buf, msg[per]);
+               printk("period = %s ns ", buf);
+       }
+
+       if (off)
+               printk("offset = %d ", msg[off]);
+       if (width)
+               printk("width = %d ", 8 << msg[width]);
+}
+
+int spi_print_msg(const unsigned char *msg)
+{
+       int len = 0, i;
+       if (msg[0] == EXTENDED_MESSAGE) {
+               len = 3 + msg[1];
+               if (msg[2] < ARRAY_SIZE(extended_msgs))
+                       printk ("%s ", extended_msgs[msg[2]]); 
+               else 
+                       printk ("Extended Message, reserved code (0x%02x) ",
+                               (int) msg[2]);
+               switch (msg[2]) {
+               case EXTENDED_MODIFY_DATA_POINTER:
+                       printk("pointer = %d", (int) (msg[3] << 24) |
+                               (msg[4] << 16) | (msg[5] << 8) | msg[6]);
+                       break;
+               case EXTENDED_SDTR:
+                       print_nego(msg, 3, 4, 0);
+                       break;
+               case EXTENDED_WDTR:
+                       print_nego(msg, 0, 0, 3);
+                       break;
+               case EXTENDED_PPR:
+                       print_nego(msg, 3, 5, 6);
+                       break;
+               default:
+               for (i = 2; i < len; ++i) 
+                       printk("%02x ", msg[i]);
+               }
+       /* Identify */
+       } else if (msg[0] & 0x80) {
+               printk("Identify disconnect %sallowed %s %d ",
+                       (msg[0] & 0x40) ? "" : "not ",
+                       (msg[0] & 0x20) ? "target routine" : "lun",
+                       msg[0] & 0x7);
+               len = 1;
+       /* Normal One byte */
+       } else if (msg[0] < 0x1f) {
+               if (msg[0] < ARRAY_SIZE(one_byte_msgs))
+                       printk(one_byte_msgs[msg[0]]);
+               else
+                       printk("reserved (%02x) ", msg[0]);
+               len = 1;
+       /* Two byte */
+       } else if (msg[0] <= 0x2f) {
+               if ((msg[0] - 0x20) < ARRAY_SIZE(two_byte_msgs))
+                       printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], 
+                               msg[1]);
+               else 
+                       printk("reserved two byte (%02x %02x) ", 
+                               msg[0], msg[1]);
+               len = 2;
+       } else 
+               printk("reserved");
+       return len;
+}
+EXPORT_SYMBOL(spi_print_msg);
+
+#else  /* ifndef CONFIG_SCSI_CONSTANTS */
+
+int spi_print_msg(const unsigned char *msg)
+{
+       int len = 0, i;
+
+       if (msg[0] == EXTENDED_MESSAGE) {
+               len = 3 + msg[1];
+               for (i = 0; i < len; ++i)
+                       printk("%02x ", msg[i]);
+       /* Identify */
+       } else if (msg[0] & 0x80) {
+               printk("%02x ", msg[0]);
+               len = 1;
+       /* Normal One byte */
+       } else if (msg[0] < 0x1f) {
+               printk("%02x ", msg[0]);
+               len = 1;
+       /* Two byte */
+       } else if (msg[0] <= 0x2f) {
+               printk("%02x %02x", msg[0], msg[1]);
+               len = 2;
+       } else 
+               printk("%02x ", msg[0]);
+       return len;
+}
+EXPORT_SYMBOL(spi_print_msg);
+#endif /* ! CONFIG_SCSI_CONSTANTS */
+
 #define SETUP_ATTRIBUTE(field)                                         \
        i->private_attrs[count] = class_device_attr_##field;            \
        if (!i->f->set_##field) {                                       \