isci: cleanup silicon revision detection
[pandora-kernel.git] / drivers / scsi / isci / host.h
index 421d3de..062101a 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
-
-#if !defined(_SCI_HOST_H_)
+#ifndef _SCI_HOST_H_
 #define _SCI_HOST_H_
 
-#include "phy.h"
-/*#include "task.h"*/
-#include "timers.h"
 #include "remote_device.h"
-#include "scic_user_callback.h"
-
-#define DRV_NAME "isci"
-#define SCI_PCI_BAR_COUNT 2
-#define SCI_NUM_MSI_X_INT 2
-#define SCI_SMU_BAR       0
-#define SCI_SMU_BAR_SIZE  (16*1024)
-#define SCI_SCU_BAR       1
-#define SCI_SCU_BAR_SIZE  (4*1024*1024)
-#define SCI_IO_SPACE_BAR0 2
-#define SCI_IO_SPACE_BAR1 3
-#define ISCI_CAN_QUEUE_VAL 250 /* < SCI_MAX_IO_REQUESTS ? */
-#define SCIC_CONTROLLER_STOP_TIMEOUT 5000
-
-struct coherent_memory_info {
-       struct list_head node;
-       dma_addr_t dma_handle;
-       void *vaddr;
-       size_t size;
-       struct sci_physical_memory_descriptor *mde;
+#include "phy.h"
+#include "isci.h"
+#include "remote_node_table.h"
+#include "registers.h"
+#include "unsolicited_frame_control.h"
+#include "probe_roms.h"
+
+struct isci_request;
+struct scu_task_context;
+
+
+/**
+ * struct sci_power_control -
+ *
+ * This structure defines the fields for managing power control for direct
+ * attached disk devices.
+ */
+struct sci_power_control {
+       /**
+        * This field is set when the power control timer is running and cleared when
+        * it is not.
+        */
+       bool timer_started;
+
+       /**
+        * Timer to control when the directed attached disks can consume power.
+        */
+       struct sci_timer timer;
+
+       /**
+        * This field is used to keep track of how many phys are put into the
+        * requesters field.
+        */
+       u8 phys_waiting;
+
+       /**
+        * This field is used to keep track of how many phys have been granted to consume power
+        */
+       u8 phys_granted_power;
+
+       /**
+        * This field is an array of phys that we are waiting on. The phys are direct
+        * mapped into requesters via struct sci_phy.phy_index
+        */
+       struct isci_phy *requesters[SCI_MAX_PHYS];
+
 };
 
+struct sci_port_configuration_agent;
+typedef void (*port_config_fn)(struct isci_host *,
+                              struct sci_port_configuration_agent *,
+                              struct isci_port *, struct isci_phy *);
+
+struct sci_port_configuration_agent {
+       u16 phy_configured_mask;
+       u16 phy_ready_mask;
+       struct {
+               u8 min_index;
+               u8 max_index;
+       } phy_valid_port_range[SCI_MAX_PHYS];
+       bool timer_pending;
+       port_config_fn link_up_handler;
+       port_config_fn link_down_handler;
+       struct sci_timer        timer;
+};
+
+/**
+ * isci_host - primary host/controller object
+ * @timer: timeout start/stop operations
+ * @device_table: rni (hw remote node index) to remote device lookup table
+ * @available_remote_nodes: rni allocator
+ * @power_control: manage device spin up
+ * @io_request_sequence: generation number for tci's (task contexts)
+ * @task_context_table: hw task context table
+ * @remote_node_context_table: hw remote node context table
+ * @completion_queue: hw-producer driver-consumer communication ring
+ * @completion_queue_get: tracks the driver 'head' of the ring to notify hw
+ * @logical_port_entries: min({driver|silicon}-supported-port-count)
+ * @remote_node_entries: min({driver|silicon}-supported-node-count)
+ * @task_context_entries: min({driver|silicon}-supported-task-count)
+ * @phy_timer: phy startup timer
+ * @invalid_phy_mask: if an invalid_link_up notification is reported a bit for
+ *                   the phy index is set so further notifications are not
+ *                   made.  Once the phy reports link up and is made part of a
+ *                   port then this bit is cleared.
+
+ */
 struct isci_host {
-       struct scic_sds_controller *core_controller;
-       union scic_oem_parameters oem_parameters;
+       struct sci_base_state_machine sm;
+       /* XXX can we time this externally */
+       struct sci_timer timer;
+       /* XXX drop reference module params directly */
+       struct sci_user_parameters user_parameters;
+       /* XXX no need to be a union */
+       struct sci_oem_params oem_parameters;
+       struct sci_port_configuration_agent port_agent;
+       struct isci_remote_device *device_table[SCI_MAX_REMOTE_DEVICES];
+       struct sci_remote_node_table available_remote_nodes;
+       struct sci_power_control power_control;
+       u8 io_request_sequence[SCI_MAX_IO_REQUESTS];
+       struct scu_task_context *task_context_table;
+       dma_addr_t task_context_dma;
+       union scu_remote_node_context *remote_node_context_table;
+       u32 *completion_queue;
+       u32 completion_queue_get;
+       u32 logical_port_entries;
+       u32 remote_node_entries;
+       u32 task_context_entries;
+       struct sci_unsolicited_frame_control uf_control;
+
+       /* phy startup */
+       struct sci_timer phy_timer;
+       /* XXX kill */
+       bool phy_startup_timer_pending;
+       u32 next_phy_to_start;
+       /* XXX convert to unsigned long and use bitops */
+       u8 invalid_phy_mask;
+
+       /* TODO attempt dynamic interrupt coalescing scheme */
+       u16 interrupt_coalesce_number;
+       u32 interrupt_coalesce_timeout;
+       struct smu_registers __iomem *smu_registers;
+       struct scu_registers __iomem *scu_registers;
+
+       u16 tci_head;
+       u16 tci_tail;
+       u16 tci_pool[SCI_MAX_IO_REQUESTS];
 
        int id; /* unique within a given pci device */
-       struct isci_timer_list timer_list_struct;
-       void *core_ctrl_memory;
-       struct dma_pool *dma_pool;
-       unsigned int dma_pool_alloc_size;
        struct isci_phy phys[SCI_MAX_PHYS];
-
-       /* isci_ports and sas_ports are implicitly parallel to the
-        * ports maintained by the core
-        */
-       struct isci_port isci_ports[SCI_MAX_PORTS];
-       struct asd_sas_port sas_ports[SCI_MAX_PORTS];
+       struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */
        struct sas_ha_struct sas_ha;
 
-       int can_queue;
-       spinlock_t queue_lock;
        spinlock_t state_lock;
-
        struct pci_dev *pdev;
-       u8 sas_addr[SAS_ADDR_SIZE];
-
        enum isci_status status;
+       #define IHOST_START_PENDING 0
+       #define IHOST_STOP_PENDING 1
+       unsigned long flags;
+       wait_queue_head_t eventq;
        struct Scsi_Host *shost;
        struct tasklet_struct completion_tasklet;
-       struct list_head mdl_struct_list;
        struct list_head requests_to_complete;
-       struct list_head requests_to_abort;
-       struct completion stop_complete;
-       struct completion start_complete;
+       struct list_head requests_to_errorback;
        spinlock_t scic_lock;
-       struct isci_host *next;
+       struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
+       struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
 };
 
+/**
+ * enum sci_controller_states - This enumeration depicts all the states
+ *    for the common controller state machine.
+ */
+enum sci_controller_states {
+       /**
+        * Simply the initial state for the base controller state machine.
+        */
+       SCIC_INITIAL = 0,
+
+       /**
+        * This state indicates that the controller is reset.  The memory for
+        * the controller is in it's initial state, but the controller requires
+        * initialization.
+        * This state is entered from the INITIAL state.
+        * This state is entered from the RESETTING state.
+        */
+       SCIC_RESET,
+
+       /**
+        * This state is typically an action state that indicates the controller
+        * is in the process of initialization.  In this state no new IO operations
+        * are permitted.
+        * This state is entered from the RESET state.
+        */
+       SCIC_INITIALIZING,
+
+       /**
+        * This state indicates that the controller has been successfully
+        * initialized.  In this state no new IO operations are permitted.
+        * This state is entered from the INITIALIZING state.
+        */
+       SCIC_INITIALIZED,
+
+       /**
+        * This state indicates the the controller is in the process of becoming
+        * ready (i.e. starting).  In this state no new IO operations are permitted.
+        * This state is entered from the INITIALIZED state.
+        */
+       SCIC_STARTING,
+
+       /**
+        * This state indicates the controller is now ready.  Thus, the user
+        * is able to perform IO operations on the controller.
+        * This state is entered from the STARTING state.
+        */
+       SCIC_READY,
+
+       /**
+        * This state is typically an action state that indicates the controller
+        * is in the process of resetting.  Thus, the user is unable to perform
+        * IO operations on the controller.  A reset is considered destructive in
+        * most cases.
+        * This state is entered from the READY state.
+        * This state is entered from the FAILED state.
+        * This state is entered from the STOPPED state.
+        */
+       SCIC_RESETTING,
+
+       /**
+        * This state indicates that the controller is in the process of stopping.
+        * In this state no new IO operations are permitted, but existing IO
+        * operations are allowed to complete.
+        * This state is entered from the READY state.
+        */
+       SCIC_STOPPING,
+
+       /**
+        * This state indicates that the controller has successfully been stopped.
+        * In this state no new IO operations are permitted.
+        * This state is entered from the STOPPING state.
+        */
+       SCIC_STOPPED,
+
+       /**
+        * This state indicates that the controller could not successfully be
+        * initialized.  In this state no new IO operations are permitted.
+        * This state is entered from the INITIALIZING state.
+        * This state is entered from the STARTING state.
+        * This state is entered from the STOPPING state.
+        * This state is entered from the RESETTING state.
+        */
+       SCIC_FAILED,
+};
 
 /**
  * struct isci_pci_info - This class represents the pci function containing the
@@ -130,8 +299,8 @@ struct isci_host {
 
 struct isci_pci_info {
        struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
-       int core_lib_array_index;
-       struct isci_host *hosts;
+       struct isci_host *hosts[SCI_MAX_CONTROLLERS];
+       struct isci_orom *orom;
 };
 
 static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
@@ -139,21 +308,18 @@ static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
        return pci_get_drvdata(pdev);
 }
 
-#define for_each_isci_host(isci_host, pdev) \
-       for (isci_host = to_pci_info(pdev)->hosts;\
-            isci_host; isci_host = isci_host->next)
+#define for_each_isci_host(id, ihost, pdev) \
+       for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
+            id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
+            ihost = to_pci_info(pdev)->hosts[++id])
 
-static inline
-enum isci_status isci_host_get_state(
-       struct isci_host *isci_host)
+static inline enum isci_status isci_host_get_state(struct isci_host *isci_host)
 {
        return isci_host->status;
 }
 
-
-static inline void isci_host_change_state(
-       struct isci_host *isci_host,
-       enum isci_status status)
+static inline void isci_host_change_state(struct isci_host *isci_host,
+                                         enum isci_status status)
 {
        unsigned long flags;
 
@@ -168,84 +334,161 @@ static inline void isci_host_change_state(
 
 }
 
-static inline int isci_host_can_queue(
-       struct isci_host *isci_host,
-       int num)
+static inline void wait_for_start(struct isci_host *ihost)
 {
-       int ret = 0;
-       unsigned long flags;
+       wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags));
+}
 
-       spin_lock_irqsave(&isci_host->queue_lock, flags);
-       if ((isci_host->can_queue - num) < 0) {
-               dev_dbg(&isci_host->pdev->dev,
-                       "%s: isci_host->can_queue = %d\n",
-                       __func__,
-                       isci_host->can_queue);
-               ret = -SAS_QUEUE_FULL;
+static inline void wait_for_stop(struct isci_host *ihost)
+{
+       wait_event(ihost->eventq, !test_bit(IHOST_STOP_PENDING, &ihost->flags));
+}
 
-       } else
-               isci_host->can_queue -= num;
+static inline void wait_for_device_start(struct isci_host *ihost, struct isci_remote_device *idev)
+{
+       wait_event(ihost->eventq, !test_bit(IDEV_START_PENDING, &idev->flags));
+}
 
-       spin_unlock_irqrestore(&isci_host->queue_lock, flags);
+static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev)
+{
+       wait_event(ihost->eventq, !test_bit(IDEV_STOP_PENDING, &idev->flags));
+}
 
-       return ret;
+static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
+{
+       return dev->port->ha->lldd_ha;
 }
 
-static inline void isci_host_can_dequeue(
-       struct isci_host *isci_host,
-       int num)
+/* we always use protocol engine group zero */
+#define ISCI_PEG 0
+
+/* see sci_controller_io_tag_allocate|free for how seq and tci are built */
+#define ISCI_TAG(seq, tci) (((u16) (seq)) << 12 | tci)
+
+/* these are returned by the hardware, so sanitize them */
+#define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1))
+#define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1))
+
+/* expander attached sata devices require 3 rnc slots */
+static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
 {
-       unsigned long flags;
+       struct domain_device *dev = idev->domain_dev;
 
-       spin_lock_irqsave(&isci_host->queue_lock, flags);
-       isci_host->can_queue += num;
-       spin_unlock_irqrestore(&isci_host->queue_lock, flags);
+       if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
+           !idev->is_direct_attached)
+               return SCU_STP_REMOTE_NODE_COUNT;
+       return SCU_SSP_REMOTE_NODE_COUNT;
 }
 
 /**
- * isci_host_from_sas_ha() - This accessor retrieves the isci_host object
- *    reference from the Linux sas_ha_struct reference.
- * @ha_struct,: This parameter points to the Linux sas_ha_struct object
+ * sci_controller_clear_invalid_phy() -
  *
- * A reference to the associated isci_host structure.
+ * This macro will clear the bit in the invalid phy mask for this controller
+ * object.  This is used to control messages reported for invalid link up
+ * notifications.
  */
-#define isci_host_from_sas_ha(ha_struct) \
-       ((struct isci_host *)(ha_struct)->lldd_ha)
+#define sci_controller_clear_invalid_phy(controller, phy) \
+       ((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index))
 
-/**
- * isci_host_scan_finished() -
- *
- * This function is one of the SCSI Host Template functions. The SCSI midlayer
- * calls this function during a target scan, approx. once every 10 millisecs.
- */
-int isci_host_scan_finished(
-       struct Scsi_Host *,
-       unsigned long);
+static inline struct device *sciphy_to_dev(struct isci_phy *iphy)
+{
 
+       if (!iphy || !iphy->isci_port || !iphy->isci_port->isci_host)
+               return NULL;
 
-/**
- * isci_host_scan_start() -
- *
- * This function is one of the SCSI Host Template function, called by the SCSI
- * mid layer berfore a target scan begins. The core library controller start
- * routine is called from here.
- */
-void isci_host_scan_start(
-       struct Scsi_Host *);
+       return &iphy->isci_port->isci_host->pdev->dev;
+}
 
-/**
- * isci_host_start_complete() -
- *
- * This function is called by the core library, through the ISCI Module, to
- * indicate controller start status.
- */
-void isci_host_start_complete(
-       struct isci_host *,
-       enum sci_status);
+static inline struct device *sciport_to_dev(struct isci_port *iport)
+{
 
-void isci_host_stop_complete(
-       struct isci_host *isci_host,
-       enum sci_status completion_status);
+       if (!iport || !iport->isci_host)
+               return NULL;
+
+       return &iport->isci_host->pdev->dev;
+}
+
+static inline struct device *scirdev_to_dev(struct isci_remote_device *idev)
+{
+       if (!idev || !idev->isci_port || !idev->isci_port->isci_host)
+               return NULL;
+
+       return &idev->isci_port->isci_host->pdev->dev;
+}
+
+static inline bool is_a2(struct pci_dev *pdev)
+{
+       if (pdev->revision < 4)
+               return true;
+       return false;
+}
+
+static inline bool is_b0(struct pci_dev *pdev)
+{
+       if (pdev->revision == 4)
+               return true;
+       return false;
+}
+
+static inline bool is_c0(struct pci_dev *pdev)
+{
+       if (pdev->revision >= 5)
+               return true;
+       return false;
+}
+
+void sci_controller_post_request(struct isci_host *ihost,
+                                     u32 request);
+void sci_controller_release_frame(struct isci_host *ihost,
+                                      u32 frame_index);
+void sci_controller_copy_sata_response(void *response_buffer,
+                                           void *frame_header,
+                                           void *frame_buffer);
+enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost,
+                                                                struct isci_remote_device *idev,
+                                                                u16 *node_id);
+void sci_controller_free_remote_node_context(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       u16 node_id);
+
+struct isci_request *sci_request_by_tag(struct isci_host *ihost,
+                                            u16 io_tag);
+
+void sci_controller_power_control_queue_insert(
+       struct isci_host *ihost,
+       struct isci_phy *iphy);
+
+void sci_controller_power_control_queue_remove(
+       struct isci_host *ihost,
+       struct isci_phy *iphy);
+
+void sci_controller_link_up(
+       struct isci_host *ihost,
+       struct isci_port *iport,
+       struct isci_phy *iphy);
+
+void sci_controller_link_down(
+       struct isci_host *ihost,
+       struct isci_port *iport,
+       struct isci_phy *iphy);
+
+void sci_controller_remote_device_stopped(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev);
+
+void sci_controller_copy_task_context(
+       struct isci_host *ihost,
+       struct isci_request *ireq);
+
+void sci_controller_register_setup(struct isci_host *ihost);
+
+enum sci_status sci_controller_continue_io(struct isci_request *ireq);
+int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
+void isci_host_scan_start(struct Scsi_Host *);
+u16 isci_alloc_tag(struct isci_host *ihost);
+enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
+void isci_tci_free(struct isci_host *ihost, u16 tci);
 
 int isci_host_init(struct isci_host *);
 
@@ -258,8 +501,8 @@ void isci_host_deinit(
 
 void isci_host_port_link_up(
        struct isci_host *,
-       struct scic_sds_port *,
-       struct scic_sds_phy *);
+       struct isci_port *,
+       struct isci_phy *);
 int isci_host_dev_found(struct domain_device *);
 
 void isci_host_remote_device_start_complete(
@@ -267,4 +510,33 @@ void isci_host_remote_device_start_complete(
        struct isci_remote_device *,
        enum sci_status);
 
-#endif /* !defined(_SCI_HOST_H_) */
+void sci_controller_disable_interrupts(
+       struct isci_host *ihost);
+
+enum sci_status sci_controller_start_io(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       struct isci_request *ireq);
+
+enum sci_task_status sci_controller_start_task(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       struct isci_request *ireq);
+
+enum sci_status sci_controller_terminate_request(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       struct isci_request *ireq);
+
+enum sci_status sci_controller_complete_io(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev,
+       struct isci_request *ireq);
+
+void sci_port_configuration_agent_construct(
+       struct sci_port_configuration_agent *port_agent);
+
+enum sci_status sci_port_configuration_agent_initialize(
+       struct isci_host *ihost,
+       struct sci_port_configuration_agent *port_agent);
+#endif