lkml.org 
[lkml]   [2006]   [Nov]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 14/15] libsas: Provide a generic SATL registration function
    Date

    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 <djwong@us.ibm.com>
    ---

    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 majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2006-11-17 22:07    [W:0.039 / U:30.452 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site