[SCSI] libsas: fix timeout vs completion race
[linux-2.6.git] / include / scsi / libsas.h
index 3b58685..aa7192f 100644 (file)
@@ -86,7 +86,9 @@ enum discover_event {
        DISCE_DISCOVER_DOMAIN   = 0U,
        DISCE_REVALIDATE_DOMAIN = 1,
        DISCE_PORT_GONE         = 2,
-       DISC_NUM_EVENTS         = 3,
+       DISCE_PROBE             = 3,
+       DISCE_DESTRUCT          = 4,
+       DISC_NUM_EVENTS         = 5,
 };
 
 /* ---------- Expander Devices ---------- */
@@ -142,8 +144,11 @@ struct expander_device {
        u16    ex_change_count;
        u16    max_route_indexes;
        u8     num_phys;
+
+       u8     t2t_supp:1;
        u8     configuring:1;
        u8     conf_route_table:1;
+
        u8     enclosure_logical_id[8];
 
        struct ex_phy *ex_phy;
@@ -159,22 +164,21 @@ enum ata_command_set {
 struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
-        __le16 *identify_device;
-        __le16 *identify_packet_device;
-
         u8     port_no;        /* port number, if this is a PM (Port) */
         struct list_head children; /* PM Ports if this is a PM */
 
        struct ata_port *ap;
        struct ata_host ata_host;
        struct ata_taskfile tf;
-       u32 sstatus;
-       u32 serror;
-       u32 scontrol;
 };
 
-/* ---------- Domain device ---------- */
+enum {
+       SAS_DEV_GONE,
+       SAS_DEV_DESTROY,
+};
+
 struct domain_device {
+       spinlock_t done_lock;
         enum sas_dev_type dev_type;
 
         enum sas_linkrate linkrate;
@@ -188,6 +192,7 @@ struct domain_device {
         struct asd_sas_port *port;        /* shortcut to root of the tree */
 
         struct list_head dev_list_node;
+       struct list_head disco_list_node; /* awaiting probe or destruct */
 
         enum sas_protocol    iproto;
         enum sas_protocol    tproto;
@@ -205,6 +210,8 @@ struct domain_device {
         };
 
         void *lldd_dev;
+       unsigned long state;
+       struct kref kref;
 };
 
 struct sas_discovery_event {
@@ -213,7 +220,6 @@ struct sas_discovery_event {
 };
 
 struct sas_discovery {
-       spinlock_t disc_event_lock;
        struct sas_discovery_event disc_work[DISC_NUM_EVENTS];
        unsigned long    pending;
        u8     fanout_sas_addr[8];
@@ -222,7 +228,6 @@ struct sas_discovery {
        int    max_level;
 };
 
-
 /* The port struct is Class:RW, driver:RO */
 struct asd_sas_port {
 /* private: */
@@ -232,6 +237,8 @@ struct asd_sas_port {
        struct domain_device *port_dev;
        spinlock_t dev_list_lock;
        struct list_head dev_list;
+       struct list_head disco_list;
+       struct list_head destroy_list;
        enum   sas_linkrate linkrate;
 
        struct sas_phy *phy;
@@ -270,7 +277,6 @@ struct asd_sas_event {
  */
 struct asd_sas_phy {
 /* private: */
-       /* protected by ha->event_lock */
        struct asd_sas_event   port_events[PORT_NUM_EVENTS];
        struct asd_sas_event   phy_events[PHY_NUM_EVENTS];
 
@@ -316,6 +322,7 @@ struct asd_sas_phy {
 struct scsi_core {
        struct Scsi_Host *shost;
 
+       struct mutex      task_queue_flush;
        spinlock_t        task_queue_lock;
        struct list_head  task_queue;
        int               task_queue_size;
@@ -330,18 +337,23 @@ struct sas_ha_event {
 
 enum sas_ha_state {
        SAS_HA_REGISTERED,
-       SAS_HA_UNREGISTERED
+       SAS_HA_DRAINING,
+       SAS_HA_ATA_EH_ACTIVE,
+       SAS_HA_FROZEN,
 };
 
 struct sas_ha_struct {
 /* private: */
-       spinlock_t       event_lock;
        struct sas_ha_event ha_events[HA_NUM_EVENTS];
        unsigned long    pending;
 
-       enum sas_ha_state state;
+       struct list_head  defer_q; /* work queued while draining */
+       struct mutex      drain_mutex;
+       unsigned long     state;
        spinlock_t        state_lock;
 
+       struct mutex disco_mutex;
+
        struct scsi_core core;
 
 /* public: */
@@ -360,6 +372,8 @@ struct sas_ha_struct {
        /* The class calls this to send a task for execution. */
        int lldd_max_execute_num;
        int lldd_queue_size;
+       int strict_wide_ports; /* both sas_addr and attached_sas_addr must match
+                               * their siblings when forming wide ports */
 
        /* LLDD calls these to notify the class of an event. */
        void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
@@ -383,6 +397,11 @@ sdev_to_domain_dev(struct scsi_device *sdev) {
        return starget_to_domain_dev(sdev->sdev_target);
 }
 
+static inline struct ata_device *sas_to_ata_dev(struct domain_device *dev)
+{
+       return &dev->sata_dev.ap->link.device[0];
+}
+
 static inline struct domain_device *
 cmd_to_domain_dev(struct scsi_cmnd *cmd)
 {
@@ -402,6 +421,20 @@ static inline void sas_phy_disconnected(struct asd_sas_phy *phy)
        phy->linkrate = SAS_LINK_RATE_UNKNOWN;
 }
 
+static inline unsigned int to_sas_gpio_od(int device, int bit)
+{
+       return 3 * device + bit;
+}
+
+#ifdef CONFIG_SCSI_SAS_HOST_SMP
+int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count);
+#else
+static inline int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count)
+{
+       return -1;
+}
+#endif
+
 /* ---------- Tasks ---------- */
 /*
       service_response |  SAS_TASK_COMPLETE  |  SAS_TASK_UNDELIVERED |
@@ -422,16 +455,10 @@ enum service_response {
 };
 
 enum exec_status {
-       SAM_GOOD         = 0,
-       SAM_CHECK_COND   = 2,
-       SAM_COND_MET     = 4,
-       SAM_BUSY         = 8,
-       SAM_INTERMEDIATE = 0x10,
-       SAM_IM_COND_MET  = 0x12,
-       SAM_RESV_CONFLICT= 0x14,
-       SAM_TASK_SET_FULL= 0x28,
-       SAM_ACA_ACTIVE   = 0x30,
-       SAM_TASK_ABORTED = 0x40,
+       /* The SAM_STAT_.. codes fit in the lower 6 bits, alias some of
+        * them here to silence 'case value not in enumerated type' warnings
+        */
+       __SAM_STAT_CHECK_CONDITION = SAM_STAT_CHECK_CONDITION,
 
        SAS_DEV_NO_RESPONSE = 0x80,
        SAS_DATA_UNDERRUN,
@@ -471,10 +498,6 @@ enum exec_status {
 struct ata_task_resp {
        u16  frame_len;
        u8   ending_fis[24];      /* dev to host or data-in */
-       u32  sstatus;
-       u32  serror;
-       u32  scontrol;
-       u32  sactive;
 };
 
 #define SAS_STATUS_BUF_SIZE 96
@@ -561,36 +584,14 @@ struct sas_task {
        struct work_struct abort_work;
 };
 
-extern struct kmem_cache *sas_task_cache;
-
 #define SAS_TASK_STATE_PENDING      1
 #define SAS_TASK_STATE_DONE         2
 #define SAS_TASK_STATE_ABORTED      4
 #define SAS_TASK_NEED_DEV_RESET     8
 #define SAS_TASK_AT_INITIATOR       16
 
-static inline struct sas_task *sas_alloc_task(gfp_t flags)
-{
-       struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags);
-
-       if (task) {
-               INIT_LIST_HEAD(&task->list);
-               spin_lock_init(&task->task_state_lock);
-               task->task_state_flags = SAS_TASK_STATE_PENDING;
-               init_timer(&task->timer);
-               init_completion(&task->completion);
-       }
-
-       return task;
-}
-
-static inline void sas_free_task(struct sas_task *task)
-{
-       if (task) {
-               BUG_ON(!list_empty(&task->list));
-               kmem_cache_free(sas_task_cache, task);
-       }
-}
+extern struct sas_task *sas_alloc_task(gfp_t flags);
+extern void sas_free_task(struct sas_task *task);
 
 struct sas_domain_function_template {
        /* The class calls these to notify the LLDD of an event. */
@@ -610,6 +611,8 @@ struct sas_domain_function_template {
        int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
        int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
        int (*lldd_I_T_nexus_reset)(struct domain_device *);
+       int (*lldd_ata_soft_reset)(struct domain_device *);
+       void (*lldd_ata_set_dmamode)(struct domain_device *);
        int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
        int (*lldd_query_task)(struct sas_task *);
 
@@ -619,6 +622,10 @@ struct sas_domain_function_template {
 
        /* Phy management */
        int (*lldd_control_phy)(struct asd_sas_phy *, enum phy_func, void *);
+
+       /* GPIO support */
+       int (*lldd_write_gpio)(struct sas_ha_struct *, u8 reg_type,
+                              u8 reg_index, u8 reg_count, u8 *write_data);
 };
 
 extern int sas_register_ha(struct sas_ha_struct *);
@@ -629,12 +636,10 @@ int sas_set_phy_speed(struct sas_phy *phy,
 int sas_phy_enable(struct sas_phy *phy, int enabled);
 int sas_phy_reset(struct sas_phy *phy, int hard_reset);
 int sas_queue_up(struct sas_task *task);
-extern int sas_queuecommand(struct scsi_cmnd *,
-                    void (*scsi_done)(struct scsi_cmnd *));
+extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);
 extern int sas_target_alloc(struct scsi_target *);
 extern int sas_slave_alloc(struct scsi_device *);
 extern int sas_slave_configure(struct scsi_device *);
-extern void sas_slave_destroy(struct scsi_device *);
 extern int sas_change_queue_depth(struct scsi_device *, int new_depth,
                                  int reason);
 extern int sas_change_queue_type(struct scsi_device *, int qt);
@@ -658,18 +663,18 @@ int  sas_discover_event(struct asd_sas_port *, enum discover_event ev);
 int  sas_discover_sata(struct domain_device *);
 int  sas_discover_end_dev(struct domain_device *);
 
-void sas_unregister_dev(struct domain_device *);
+void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *);
 
 void sas_init_dev(struct domain_device *);
 
 void sas_task_abort(struct sas_task *);
-int __sas_task_abort(struct sas_task *);
 int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
 int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
 
 extern void sas_target_destroy(struct scsi_target *);
 extern int sas_slave_alloc(struct scsi_device *);
 extern int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
+extern int sas_drain_work(struct sas_ha_struct *ha);
 
 extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                           struct request *req);