]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ieee1394/sbp2.c
PCI: Let PCI_MULTITHREAD_PROBE depend on BROKEN
[linux-2.6-omap-h63xx.git] / drivers / ieee1394 / sbp2.c
index 07030be0ef2a6296e7e948162d7362cbfaeb68a7..6986ac188281745eda188c9b1c26110a9fe7f62f 100644 (file)
  *       but the code needs additional debugging.
  */
 
+#include <linux/blkdev.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/blkdev.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/wait.h>
 
-#include <asm/current.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
 #include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
+#include <asm/errno.h>
+#include <asm/param.h>
 #include <asm/scatterlist.h>
+#include <asm/system.h>
+#include <asm/types.h>
+
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+#include <asm/io.h> /* for bus_to_virt */
+#endif
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 
 #include "csr1212.h"
+#include "highlevel.h"
+#include "hosts.h"
 #include "ieee1394.h"
-#include "ieee1394_types.h"
 #include "ieee1394_core.h"
-#include "nodemgr.h"
-#include "hosts.h"
-#include "highlevel.h"
+#include "ieee1394_hotplug.h"
 #include "ieee1394_transactions.h"
+#include "ieee1394_types.h"
+#include "nodemgr.h"
 #include "sbp2.h"
 
 /*
@@ -173,11 +179,6 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
        ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
        ", or a combination)");
 
-/* legacy parameter */
-static int force_inquiry_hack;
-module_param(force_inquiry_hack, int, 0644);
-MODULE_PARM_DESC(force_inquiry_hack, "Deprecated, use 'workarounds'");
-
 /*
  * Export information about protocols/devices supported by this driver.
  */
@@ -208,9 +209,9 @@ static u32 global_outstanding_command_orbs = 0;
 #define outstanding_orb_incr global_outstanding_command_orbs++
 #define outstanding_orb_decr global_outstanding_command_orbs--
 #else
-#define SBP2_ORB_DEBUG(fmt, args...)
-#define outstanding_orb_incr
-#define outstanding_orb_decr
+#define SBP2_ORB_DEBUG(fmt, args...)   do {} while (0)
+#define outstanding_orb_incr           do {} while (0)
+#define outstanding_orb_decr           do {} while (0)
 #endif
 
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
@@ -222,8 +223,8 @@ static u32 global_outstanding_command_orbs = 0;
                 --global_outstanding_dmas, ## args)
 static u32 global_outstanding_dmas = 0;
 #else
-#define SBP2_DMA_ALLOC(fmt, args...)
-#define SBP2_DMA_FREE(fmt, args...)
+#define SBP2_DMA_ALLOC(fmt, args...)   do {} while (0)
+#define SBP2_DMA_FREE(fmt, args...)    do {} while (0)
 #endif
 
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 2
@@ -237,7 +238,7 @@ static u32 global_outstanding_dmas = 0;
 #define SBP2_NOTICE(fmt, args...)      HPSB_NOTICE("sbp2: "fmt, ## args)
 #define SBP2_WARN(fmt, args...)                HPSB_WARN("sbp2: "fmt, ## args)
 #else
-#define SBP2_DEBUG(fmt, args...)
+#define SBP2_DEBUG(fmt, args...)       do {} while (0)
 #define SBP2_INFO(fmt, args...)                HPSB_INFO("sbp2: "fmt, ## args)
 #define SBP2_NOTICE(fmt, args...)       HPSB_NOTICE("sbp2: "fmt, ## args)
 #define SBP2_WARN(fmt, args...)         HPSB_WARN("sbp2: "fmt, ## args)
@@ -380,8 +381,8 @@ static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
 }
 #else /* BIG_ENDIAN */
 /* Why waste the cpu cycles? */
-#define sbp2util_be32_to_cpu_buffer(x,y)
-#define sbp2util_cpu_to_be32_buffer(x,y)
+#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
+#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
 #endif
 
 #ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP
@@ -417,24 +418,26 @@ static void sbp2util_packet_dump(void *buffer, int length, char *dump_name,
        return;
 }
 #else
-#define sbp2util_packet_dump(w,x,y,z)
+#define sbp2util_packet_dump(w,x,y,z) do {} while (0)
 #endif
 
+static DECLARE_WAIT_QUEUE_HEAD(access_wq);
+
 /*
- * Goofy routine that basically does a down_timeout function.
+ * Waits for completion of an SBP-2 access request.
+ * Returns nonzero if timed out or prematurely interrupted.
  */
-static int sbp2util_down_timeout(atomic_t *done, int timeout)
+static int sbp2util_access_timeout(struct scsi_id_instance_data *scsi_id,
+                                  int timeout)
 {
-       int i;
+       long leftover = wait_event_interruptible_timeout(
+                               access_wq, scsi_id->access_complete, timeout);
 
-       for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
-               if (msleep_interruptible(100))  /* 100ms */
-                       return 1;
-       }
-       return (i > 0) ? 0 : 1;
+       scsi_id->access_complete = 0;
+       return leftover <= 0;
 }
 
-/* Free's an allocated packet */
+/* Frees an allocated packet */
 static void sbp2_free_packet(struct hpsb_packet *packet)
 {
        hpsb_free_tlabel(packet);
@@ -468,6 +471,44 @@ static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
        return 0;
 }
 
+static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id,
+                                       u64 offset, quadlet_t *data, size_t len)
+{
+       /*
+        * There is a small window after a bus reset within which the node
+        * entry's generation is current but the reconnect wasn't completed.
+        */
+       if (unlikely(atomic_read(&scsi_id->state) == SBP2LU_STATE_IN_RESET))
+               return;
+
+       if (hpsb_node_write(scsi_id->ne,
+                           scsi_id->sbp2_command_block_agent_addr + offset,
+                           data, len))
+               SBP2_ERR("sbp2util_notify_fetch_agent failed.");
+       /*
+        * Now accept new SCSI commands, unless a bus reset happended during
+        * hpsb_node_write.
+        */
+       if (likely(atomic_read(&scsi_id->state) != SBP2LU_STATE_IN_RESET))
+               scsi_unblock_requests(scsi_id->scsi_host);
+}
+
+static void sbp2util_write_orb_pointer(void *p)
+{
+       quadlet_t data[2];
+
+       data[0] = ORB_SET_NODE_ID(
+                       ((struct scsi_id_instance_data *)p)->hi->host->node_id);
+       data[1] = ((struct scsi_id_instance_data *)p)->last_orb_dma;
+       sbp2util_cpu_to_be32_buffer(data, 8);
+       sbp2util_notify_fetch_agent(p, SBP2_ORB_POINTER_OFFSET, data, 8);
+}
+
+static void sbp2util_write_doorbell(void *p)
+{
+       sbp2util_notify_fetch_agent(p, SBP2_DOORBELL_OFFSET, NULL, 4);
+}
+
 /*
  * This function is called to create a pool of command orbs used for
  * command processing. It is called when a new sbp2 device is detected.
@@ -715,6 +756,7 @@ static int sbp2_remove(struct device *dev)
                        sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);
                /* scsi_remove_device() will trigger shutdown functions of SCSI
                 * highlevel drivers which would deadlock if blocked. */
+               atomic_set(&scsi_id->state, SBP2LU_STATE_IN_SHUTDOWN);
                scsi_unblock_requests(scsi_id->scsi_host);
        }
        sdev = scsi_id->sdev;
@@ -766,10 +808,12 @@ static int sbp2_update(struct unit_directory *ud)
         */
        sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
 
-       /* Make sure we unblock requests (since this is likely after a bus
-        * reset). */
-       scsi_unblock_requests(scsi_id->scsi_host);
-
+       /* Accept new commands unless there was another bus reset in the
+        * meantime. */
+       if (hpsb_node_entry_valid(scsi_id->ne)) {
+               atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
+               scsi_unblock_requests(scsi_id->scsi_host);
+       }
        return 0;
 }
 
@@ -794,11 +838,12 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud
        scsi_id->speed_code = IEEE1394_SPEED_100;
        scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
        scsi_id->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
-       atomic_set(&scsi_id->sbp2_login_complete, 0);
        INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
        INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
        INIT_LIST_HEAD(&scsi_id->scsi_list);
        spin_lock_init(&scsi_id->sbp2_command_orb_lock);
+       atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
+       INIT_WORK(&scsi_id->protocol_work, NULL, NULL);
 
        ud->device.driver_data = scsi_id;
 
@@ -881,11 +926,14 @@ static void sbp2_host_reset(struct hpsb_host *host)
        struct scsi_id_instance_data *scsi_id;
 
        hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-
-       if (hi) {
-               list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
+       if (!hi)
+               return;
+       list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
+               if (likely(atomic_read(&scsi_id->state) !=
+                          SBP2LU_STATE_IN_SHUTDOWN)) {
+                       atomic_set(&scsi_id->state, SBP2LU_STATE_IN_RESET);
                        scsi_block_requests(scsi_id->scsi_host);
-       }
+               }
 }
 
 /*
@@ -970,8 +1018,7 @@ static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
         * connected to the sbp2 device being removed. That host would
         * have a certain amount of time to relogin before the sbp2 device
         * allows someone else to login instead. One second makes sense. */
-       msleep_interruptible(1000);
-       if (signal_pending(current)) {
+       if (msleep_interruptible(1000)) {
                sbp2_remove_device(scsi_id);
                return -EINTR;
        }
@@ -1036,7 +1083,7 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
                scsi_remove_host(scsi_id->scsi_host);
                scsi_host_put(scsi_id->scsi_host);
        }
-
+       flush_scheduled_work();
        sbp2util_remove_command_orb_pool(scsi_id);
 
        list_del(&scsi_id->scsi_list);
@@ -1187,11 +1234,9 @@ static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
        data[1] = scsi_id->query_logins_orb_dma;
        sbp2util_cpu_to_be32_buffer(data, 8);
 
-       atomic_set(&scsi_id->sbp2_login_complete, 0);
-
        hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
-       if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
+       if (sbp2util_access_timeout(scsi_id, 2*HZ)) {
                SBP2_INFO("Error querying logins to SBP-2 device - timed out");
                return -EIO;
        }
@@ -1279,15 +1324,13 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
        data[1] = scsi_id->login_orb_dma;
        sbp2util_cpu_to_be32_buffer(data, 8);
 
-       atomic_set(&scsi_id->sbp2_login_complete, 0);
-
        hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
        /*
         * Wait for login status (up to 20 seconds)...
         */
-       if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) {
-               SBP2_ERR("Error logging into SBP-2 device - login timed-out");
+       if (sbp2util_access_timeout(scsi_id, 20*HZ)) {
+               SBP2_ERR("Error logging into SBP-2 device - timed out");
                return -EIO;
        }
 
@@ -1374,21 +1417,17 @@ static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id)
        data[1] = scsi_id->logout_orb_dma;
        sbp2util_cpu_to_be32_buffer(data, 8);
 
-       atomic_set(&scsi_id->sbp2_login_complete, 0);
-
        error = hpsb_node_write(scsi_id->ne,
                                scsi_id->sbp2_management_agent_addr, data, 8);
        if (error)
                return error;
 
        /* Wait for device to logout...1 second. */
-       if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ))
+       if (sbp2util_access_timeout(scsi_id, HZ))
                return -EIO;
 
        SBP2_INFO("Logged out of SBP-2 device");
-
        return 0;
-
 }
 
 /*
@@ -1436,8 +1475,6 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
        data[1] = scsi_id->reconnect_orb_dma;
        sbp2util_cpu_to_be32_buffer(data, 8);
 
-       atomic_set(&scsi_id->sbp2_login_complete, 0);
-
        error = hpsb_node_write(scsi_id->ne,
                                scsi_id->sbp2_management_agent_addr, data, 8);
        if (error)
@@ -1446,8 +1483,8 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
        /*
         * Wait for reconnect status (up to 1 second)...
         */
-       if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {
-               SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
+       if (sbp2util_access_timeout(scsi_id, HZ)) {
+               SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
                return -EIO;
        }
 
@@ -1563,11 +1600,6 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
        }
 
        workarounds = sbp2_default_workarounds;
-       if (force_inquiry_hack) {
-               SBP2_WARN("force_inquiry_hack is deprecated. "
-                         "Use parameter 'workarounds' instead.");
-               workarounds |= SBP2_WORKAROUND_INQUIRY_36;
-       }
 
        if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
                for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
@@ -1680,6 +1712,10 @@ static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait)
 
        SBP2_DEBUG_ENTER();
 
+       cancel_delayed_work(&scsi_id->protocol_work);
+       if (wait)
+               flush_scheduled_work();
+
        data = ntohl(SBP2_AGENT_RESET_DATA);
        addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
 
@@ -2001,9 +2037,22 @@ static void sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
 
        SBP2_ORB_DEBUG("write to %s register, command orb %p",
                        last_orb ? "DOORBELL" : "ORB_POINTER", command_orb);
-       if (sbp2util_node_write_no_wait(scsi_id->ne, addr, data, length))
-               SBP2_ERR("sbp2util_node_write_no_wait failed.\n");
-       /* We rely on SCSI EH to deal with _node_write_ failures. */
+       if (sbp2util_node_write_no_wait(scsi_id->ne, addr, data, length)) {
+               /*
+                * sbp2util_node_write_no_wait failed. We certainly ran out
+                * of transaction labels, perhaps just because there were no
+                * context switches which gave khpsbpkt a chance to collect
+                * free tlabels. Try again in non-atomic context. If necessary,
+                * the workqueue job will sleep to guaranteedly get a tlabel.
+                * We do not accept new commands until the job is over.
+                */
+               scsi_block_requests(scsi_id->scsi_host);
+               PREPARE_WORK(&scsi_id->protocol_work,
+                            last_orb ? sbp2util_write_doorbell:
+                                       sbp2util_write_orb_pointer,
+                            scsi_id);
+               schedule_work(&scsi_id->protocol_work);
+       }
 }
 
 /*
@@ -2170,28 +2219,34 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
                spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 
                if (SCpnt) {
-                       if (STATUS_TEST_RS(sb->ORB_offset_hi_misc))
+                       u32 h = sb->ORB_offset_hi_misc;
+                       u32 r = STATUS_GET_RESP(h);
+
+                       if (r != RESP_STATUS_REQUEST_COMPLETE) {
+                               SBP2_WARN("resp 0x%x, sbp_status 0x%x",
+                                         r, STATUS_GET_SBP_STATUS(h));
                                scsi_status =
+                                       r == RESP_STATUS_TRANSPORT_FAILURE ?
+                                       SBP2_SCSI_STATUS_BUSY :
                                        SBP2_SCSI_STATUS_COMMAND_TERMINATED;
+                       }
                        /*
                         * See if the target stored any scsi status information.
                         */
-                       if (STATUS_GET_LEN(sb->ORB_offset_hi_misc) > 1) {
+                       if (STATUS_GET_LEN(h) > 1) {
                                SBP2_DEBUG("CHECK CONDITION");
                                scsi_status = sbp2_status_to_sense_data(
                                        (unchar *)sb, SCpnt->sense_buffer);
                        }
-
                        /*
                         * Check to see if the dead bit is set. If so, we'll
                         * have to initiate a fetch agent reset.
                         */
-                       if (STATUS_TEST_D(sb->ORB_offset_hi_misc)) {
+                       if (STATUS_TEST_DEAD(h)) {
                                SBP2_DEBUG("Dead bit set - "
                                           "initiating fetch agent reset");
                                 sbp2_agent_reset(scsi_id, 0);
                        }
-
                        SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
                }
 
@@ -2215,8 +2270,10 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
                if ((sb->ORB_offset_lo == scsi_id->reconnect_orb_dma) ||
                    (sb->ORB_offset_lo == scsi_id->login_orb_dma) ||
                    (sb->ORB_offset_lo == scsi_id->query_logins_orb_dma) ||
-                   (sb->ORB_offset_lo == scsi_id->logout_orb_dma))
-                       atomic_set(&scsi_id->sbp2_login_complete, 1);
+                   (sb->ORB_offset_lo == scsi_id->logout_orb_dma)) {
+                       scsi_id->access_complete = 1;
+                       wake_up_interruptible(&access_wq);
+               }
        }
 
        if (SCpnt) {
@@ -2458,6 +2515,7 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
                (struct scsi_id_instance_data *)sdev->host->hostdata[0];
 
        scsi_id->sdev = sdev;
+       sdev->allow_restart = 1;
 
        if (scsi_id->workarounds & SBP2_WORKAROUND_INQUIRY_36)
                sdev->inquiry_len = 36;
@@ -2471,16 +2529,12 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
 
        blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
        sdev->use_10_for_rw = 1;
-       sdev->use_10_for_ms = 1;
 
        if (sdev->type == TYPE_DISK &&
            scsi_id->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
                sdev->skip_ms_page_8 = 1;
        if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
                sdev->fix_capacity = 1;
-       if (scsi_id->ne->guid_vendor_id == 0x0010b9 && /* Maxtor's OUI */
-           (sdev->type == TYPE_DISK || sdev->type == TYPE_RBC))
-               sdev->allow_restart = 1;
        return 0;
 }
 
@@ -2534,7 +2588,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
                /*
                 * Initiate a fetch agent reset.
                 */
-               sbp2_agent_reset(scsi_id, 0);
+               sbp2_agent_reset(scsi_id, 1);
                sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
        }
 
@@ -2553,7 +2607,7 @@ static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
 
        if (sbp2util_node_is_available(scsi_id)) {
                SBP2_ERR("Generating sbp2 fetch agent reset");
-               sbp2_agent_reset(scsi_id, 0);
+               sbp2_agent_reset(scsi_id, 1);
        }
 
        return SUCCESS;