Decouple libsas and sas_ata so that the latter can be provided as a
plug-in module for the former.  Any module wishing to provide SATL
services registers itself with libsas; when SATA devices are
discovered, libsas will module_get/put as necessary to ensure that
the module cannot go away accidentally.  At this time, the ability
to start a SAS HBA without a SATL, load a SATL later, and then
rerun device discovery; that may be addressed in a later patch.

Signed-off-by: Darrick J. Wong <[EMAIL PROTECTED]>
---

 drivers/scsi/libsas/Kconfig         |   11 +++
 drivers/scsi/libsas/sas_discover.c  |    6 --
 drivers/scsi/libsas/sas_scsi_host.c |  134 ++++++++++++++++++++++++++++++++---
 include/scsi/libsas.h               |   30 +-------
 include/scsi/sas_ata.h              |   37 +++++++++-
 5 files changed, 174 insertions(+), 44 deletions(-)

diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index b64e391..9c06eec 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -24,12 +24,21 @@ #
 
 config SCSI_SAS_LIBSAS
        tristate "SAS Domain Transport Attributes"
-       depends on SCSI && ATA
+       depends on SCSI
        select SCSI_SAS_ATTRS
        help
          This provides transport specific helpers for SAS drivers which
          use the domain device construct (like the aic94xxx).
 
+config SCSI_SAS_SATL
+       tristate "Serial ATA Translation Layer (SATL) on SAS controllers"
+       depends on SCSI_SAS_LIBSAS && ATA
+       default y
+       help
+         This provides an ATA translation layer between libsas and
+         libata to load SATA devices that are connected to SAS
+         controllers.
+
 config SCSI_SAS_LIBSAS_DEBUG
        bool "Compile the SAS Domain Transport Attributes in debug mode"
        default y
diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 758b153..01ff15c 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -476,12 +476,6 @@ cont1:
        if (!dev->parent)
                sas_sata_propagate_sas_addr(dev);
 
-       /* XXX Hint: register this SATA device with SATL.
-          When this returns, dev->sata_dev->lu is alive and
-          present.
-       sas_satl_register_dev(dev);
-       */
-
        sas_fill_in_rphy(dev, dev->rphy);
 
        return 0;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c 
b/drivers/scsi/libsas/sas_scsi_host.c
index 59409be..c1a1e06 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -46,6 +46,9 @@ #include <linux/libata.h>
 #define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
 #define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } 
while (0)
 
+static DEFINE_SPINLOCK(satl_ops_lock);
+static struct satl_operations *satl_ops;
+
 static void sas_scsi_task_done(struct sas_task *task)
 {
        struct task_status_struct *ts = &task->task_status;
@@ -215,8 +218,8 @@ int sas_queuecommand(struct scsi_cmnd *c
                        unsigned long flags;
 
                        spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
-                       res = ata_sas_queuecmd(cmd, scsi_done,
-                                              dev->sata_dev.ap);
+                       res = satl_ops->queuecommand(cmd, scsi_done,
+                                                    dev->sata_dev.ap);
                        spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
                        goto out;
                }
@@ -574,8 +577,9 @@ int sas_ioctl(struct scsi_device *sdev, 
 {
        struct domain_device *dev = sdev_to_domain_dev(sdev);
 
-       if (dev_is_sata(dev))
-               return ata_scsi_ioctl(sdev, cmd, arg);
+       if (dev_is_sata(dev)) {
+               return satl_ops->ioctl(sdev, cmd, arg);
+       }
 
        return -EINVAL;
 }
@@ -615,6 +619,29 @@ static inline struct domain_device *sas_
        return sas_find_dev_by_rphy(rphy);
 }
 
+static int sas_target_alloc_sata(struct domain_device *dev,
+                                struct scsi_target *starget)
+{
+       int res = -ENODEV;
+
+       /* Do we have a SATL available? */
+       if (!get_satl())
+               goto satl_found;
+
+       request_module("sas_ata");
+       if (!get_satl())
+               goto satl_found;
+
+       SAS_DPRINTK("sas_ata not loaded, ignoring SATA devices\n");
+       goto no_satl;
+
+satl_found:
+       res = satl_ops->init_target(dev, starget);
+
+no_satl:
+       return res;
+}
+
 int sas_target_alloc(struct scsi_target *starget)
 {
        struct domain_device *found_dev = sas_find_target(starget);
@@ -624,7 +651,7 @@ int sas_target_alloc(struct scsi_target 
                return -ENODEV;
 
        if (dev_is_sata(found_dev)) {
-               res = sas_ata_init_host_and_port(found_dev, starget);
+               res = sas_target_alloc_sata(found_dev, starget);
                if (res)
                        return res;
        }
@@ -644,7 +671,7 @@ int sas_slave_configure(struct scsi_devi
        BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
 
        if (dev_is_sata(dev)) {
-               ata_sas_slave_configure(scsi_dev, dev->sata_dev.ap);
+               satl_ops->configure_port(scsi_dev, dev->sata_dev.ap);
                return 0;
        }
 
@@ -672,7 +699,7 @@ void sas_slave_destroy(struct scsi_devic
        struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
 
        if (dev_is_sata(dev))
-               ata_port_disable(dev->sata_dev.ap);
+               satl_ops->deactivate_port(dev->sata_dev.ap);
 }
 
 int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
@@ -849,7 +876,7 @@ int sas_slave_alloc(struct scsi_device *
        struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
 
        if (dev_is_sata(dev))
-               return ata_sas_port_init(dev->sata_dev.ap);
+               return satl_ops->init_port(dev->sata_dev.ap);
 
        return 0;
 }
@@ -861,8 +888,11 @@ void sas_target_destroy(struct scsi_targ
        if (!found_dev)
                return;
 
-       if (dev_is_sata(found_dev))
-               ata_sas_port_destroy(found_dev->sata_dev.ap);
+       if (dev_is_sata(found_dev)) {
+               if (found_dev->sata_dev.ap)
+                       satl_ops->destroy_port(found_dev->sata_dev.ap);
+               put_satl();
+       }
 
        return;
 }
@@ -925,6 +955,85 @@ void sas_task_abort(struct sas_task *tas
        SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__);
 }
 
+struct sas_task *sas_alloc_task(gfp_t flags)
+{
+       extern kmem_cache_t *sas_task_cache;
+       struct sas_task *task = kmem_cache_alloc(sas_task_cache, flags);
+
+       if (task) {
+               memset(task, 0, sizeof(*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;
+}
+
+void sas_free_task(struct sas_task *task)
+{
+       if (task) {
+               extern kmem_cache_t *sas_task_cache;
+               BUG_ON(!list_empty(&task->list));
+               kmem_cache_free(sas_task_cache, task);
+       }
+}
+
+/* Jump table to ATA translation layer functions */
+int sas_register_satl(struct satl_operations *ops)
+{
+       int res = -ENODEV;
+
+       spin_lock(&satl_ops_lock);
+       if (satl_ops)
+               goto out;
+       satl_ops = ops;
+       res = 0;
+out:
+       spin_unlock(&satl_ops_lock);
+       return res;
+}
+
+int sas_unregister_satl(struct satl_operations *ops)
+{
+       int res = -ENODEV;
+
+       spin_lock(&satl_ops_lock);
+       if (satl_ops != ops)
+               goto out;
+       satl_ops = NULL;
+       res = 0;
+out:
+       spin_unlock(&satl_ops_lock);
+       return res;
+}
+
+int get_satl(void)
+{
+       int res = -ENODEV;
+
+       spin_lock(&satl_ops_lock);
+
+       if (!satl_ops)
+               goto out;
+       if (!try_module_get(satl_ops->owner))
+               goto out;
+       res = 0;
+
+out:
+       spin_unlock(&satl_ops_lock);
+       return res;
+}
+
+void put_satl(void)
+{
+       spin_lock(&satl_ops_lock);
+       module_put(satl_ops->owner);
+       spin_unlock(&satl_ops_lock);
+}
+
 EXPORT_SYMBOL_GPL(sas_queuecommand);
 EXPORT_SYMBOL_GPL(sas_target_alloc);
 EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -939,3 +1048,8 @@ EXPORT_SYMBOL_GPL(sas_task_abort);
 EXPORT_SYMBOL_GPL(sas_phy_reset);
 EXPORT_SYMBOL_GPL(sas_phy_enable);
 EXPORT_SYMBOL_GPL(sas_set_phy_speed);
+EXPORT_SYMBOL_GPL(sas_register_satl);
+EXPORT_SYMBOL_GPL(sas_unregister_satl);
+EXPORT_SYMBOL_GPL(sas_queue_up);
+EXPORT_SYMBOL_GPL(sas_alloc_task);
+EXPORT_SYMBOL_GPL(sas_free_task);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 7dcf593..90748ce 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -549,31 +549,8 @@ #define SAS_TASK_STATE_ABORTED      4
 #define SAS_TASK_INITIATOR_ABORTED  8
 #define SAS_TASK_AT_INITIATOR       16
 
-static inline struct sas_task *sas_alloc_task(gfp_t flags)
-{
-       extern kmem_cache_t *sas_task_cache;
-       struct sas_task *task = kmem_cache_alloc(sas_task_cache, flags);
-
-       if (task) {
-               memset(task, 0, sizeof(*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) {
-               extern kmem_cache_t *sas_task_cache;
-               BUG_ON(!list_empty(&task->list));
-               kmem_cache_free(sas_task_cache, task);
-       }
-}
+struct sas_task *sas_alloc_task(gfp_t flags);
+void sas_free_task(struct sas_task *task);
 
 struct sas_domain_function_template {
        /* The class calls these to notify the LLDD of an event. */
@@ -649,4 +626,7 @@ extern int sas_slave_alloc(struct scsi_d
 extern int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
 void sas_task_abort(struct sas_task *task);
 
+int get_satl(void);
+void put_satl(void);
+
 #endif /* _SASLIB_H_ */
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index 72a1904..bb4a1cb 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -28,12 +28,45 @@ #define _SAS_ATA_H_
 #include <linux/libata.h>
 #include <scsi/libsas.h>
 
+struct satl_operations {
+       struct module *owner;
+
+       int (*init_target) (struct domain_device *found_dev,
+                           struct scsi_target *starget);
+       int  (*queuecommand) (struct scsi_cmnd *cmd,
+                             void (*done)(struct scsi_cmnd *),
+                             struct ata_port *ap);
+       int  (*ioctl) (struct scsi_device *dev, int cmd,
+                      void __user *arg);
+       int  (*configure_port) (struct scsi_device *,
+                               struct ata_port *);
+       void (*deactivate_port) (struct ata_port *);
+       void (*destroy_port) (struct ata_port *);
+       int  (*init_port) (struct ata_port *);
+};
+
+int sas_register_satl(struct satl_operations *satl_ops);
+int sas_unregister_satl(struct satl_operations *satl_ops);
+
+#ifdef CONFIG_SCSI_SAS_SATL_MODULE
+# define SAS_ATA_AVAILABLE
+#endif
+
+#ifdef CONFIG_SCSI_SAS_SATL
+# define SAS_ATA_AVAILABLE
+#endif
+
+#ifdef SAS_ATA_AVAILABLE
+
 static inline int dev_is_sata(struct domain_device *dev)
 {
        return (dev->rphy->identify.target_port_protocols & SAS_PROTOCOL_SATA);
 }
 
-int sas_ata_init_host_and_port(struct domain_device *found_dev,
-                              struct scsi_target *starget);
+#else
+
+#define dev_is_sata(x) (0)
+
+#endif /* SAS_ATA_AVAILABLE */
 
 #endif /* _SAS_ATA_H_ */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to