Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[sfrench/cifs-2.6.git] / drivers / scsi / libsas / sas_scsi_host.c
index 897a5e2c55e438a806c6e93072547a7386922832..f869fba8680721ed8365c0fed872fd4915ed7a84 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#include <linux/kthread.h>
+
 #include "sas_internal.h"
 
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_sas.h>
+#include <scsi/sas_ata.h>
 #include "../scsi_sas_internal.h"
 #include "../scsi_transport_api.h"
 #include "../scsi_priv.h"
 
 #include <linux/err.h>
 #include <linux/blkdev.h>
+#include <linux/freezer.h>
 #include <linux/scatterlist.h>
+#include <linux/libata.h>
 
 /* ---------- SCSI Host glue ---------- */
 
-#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 void sas_scsi_task_done(struct sas_task *task)
 {
        struct task_status_struct *ts = &task->task_status;
@@ -74,8 +76,8 @@ static void sas_scsi_task_done(struct sas_task *task)
                        hs = DID_NO_CONNECT;
                        break;
                case SAS_DATA_UNDERRUN:
-                       sc->resid = ts->residual;
-                       if (sc->request_bufflen - sc->resid < sc->underflow)
+                       scsi_set_resid(sc, ts->residual);
+                       if (scsi_bufflen(sc) - scsi_get_resid(sc) < sc->underflow)
                                hs = DID_ERROR;
                        break;
                case SAS_DATA_OVERRUN:
@@ -106,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task)
                        break;
                case SAM_CHECK_COND:
                        memcpy(sc->sense_buffer, ts->buf,
-                              max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+                              min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
                        stat = SAM_CHECK_COND;
                        break;
                default:
@@ -146,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
        if (!task)
                return NULL;
 
-       *(u32 *)cmd->sense_buffer = 0;
        task->uldd_task = cmd;
        ASSIGN_SAS_TASK(cmd, task);
 
@@ -159,9 +160,9 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
        task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
        memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
 
-       task->scatter = cmd->request_buffer;
-       task->num_scatter = cmd->use_sg;
-       task->total_xfer_len = cmd->request_bufflen;
+       task->scatter = scsi_sglist(cmd);
+       task->num_scatter = scsi_sg_count(cmd);
+       task->total_xfer_len = scsi_bufflen(cmd);
        task->data_dir = cmd->sc_data_direction;
 
        task->task_done = sas_scsi_task_done;
@@ -169,7 +170,7 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
        return task;
 }
 
-static int sas_queue_up(struct sas_task *task)
+int sas_queue_up(struct sas_task *task)
 {
        struct sas_ha_struct *sas_ha = task->dev->port->ha;
        struct scsi_core *core = &sas_ha->core;
@@ -184,7 +185,7 @@ static int sas_queue_up(struct sas_task *task)
        list_add_tail(&task->list, &core->task_queue);
        core->task_queue_size += 1;
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
-       up(&core->queue_thread_sema);
+       wake_up_process(core->queue_thread);
 
        return 0;
 }
@@ -198,6 +199,10 @@ static int sas_queue_up(struct sas_task *task)
  */
 int sas_queuecommand(struct scsi_cmnd *cmd,
                     void (*scsi_done)(struct scsi_cmnd *))
+       __releases(host->host_lock)
+       __acquires(dev->sata_dev.ap->lock)
+       __releases(dev->sata_dev.ap->lock)
+       __acquires(host->host_lock)
 {
        int res = 0;
        struct domain_device *dev = cmd_to_domain_dev(cmd);
@@ -210,6 +215,16 @@ int sas_queuecommand(struct scsi_cmnd *cmd,
                struct sas_ha_struct *sas_ha = dev->port->ha;
                struct sas_task *task;
 
+               if (dev_is_sata(dev)) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+                       res = ata_sas_queuecmd(cmd, scsi_done,
+                                              dev->sata_dev.ap);
+                       spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+                       goto out;
+               }
+
                res = -ENOMEM;
                task = sas_create_task(cmd, dev, GFP_ATOMIC);
                if (!task)
@@ -398,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev)
 }
 
 /* Find the sas_phy that's attached to this device */
-struct sas_phy *find_local_sas_phy(struct domain_device *dev)
+static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
 {
        struct domain_device *pdev = dev->parent;
        struct ex_phy *exphy = NULL;
@@ -452,7 +467,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
        res = sas_phy_reset(phy, 1);
        if (res)
                SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
-                           phy->dev.kobj.k_name,
+                           kobject_name(&phy->dev.kobj),
                            res);
        if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
                return SUCCESS;
@@ -681,6 +696,16 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
        return EH_NOT_HANDLED;
 }
 
+int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+       struct domain_device *dev = sdev_to_domain_dev(sdev);
+
+       if (dev_is_sata(dev))
+               return ata_scsi_ioctl(sdev, cmd, arg);
+
+       return -EINVAL;
+}
+
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
 {
        struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
@@ -720,10 +745,17 @@ static inline struct domain_device *sas_find_target(struct scsi_target *starget)
 int sas_target_alloc(struct scsi_target *starget)
 {
        struct domain_device *found_dev = sas_find_target(starget);
+       int res;
 
        if (!found_dev)
                return -ENODEV;
 
+       if (dev_is_sata(found_dev)) {
+               res = sas_ata_init_host_and_port(found_dev, starget);
+               if (res)
+                       return res;
+       }
+
        starget->hostdata = found_dev;
        return 0;
 }
@@ -738,6 +770,11 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
 
        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);
+               return 0;
+       }
+
        sas_ha = dev->port->ha;
 
        sas_read_port_mode_page(scsi_dev);
@@ -761,6 +798,10 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
 
 void sas_slave_destroy(struct scsi_device *scsi_dev)
 {
+       struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+       if (dev_is_sata(dev))
+               ata_port_disable(dev->sata_dev.ap);
 }
 
 int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
@@ -819,7 +860,7 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
        struct sas_internal *i = to_sas_internal(core->shost->transportt);
 
        spin_lock_irqsave(&core->task_queue_lock, flags);
-       while (!core->queue_thread_kill &&
+       while (!kthread_should_stop() &&
               !list_empty(&core->task_queue)) {
 
                can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
@@ -858,8 +899,6 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
 }
 
-static DECLARE_COMPLETION(queue_th_comp);
-
 /**
  * sas_queue_thread -- The Task Collector thread
  * @_sas_ha: pointer to struct sas_ha
@@ -867,40 +906,31 @@ static DECLARE_COMPLETION(queue_th_comp);
 static int sas_queue_thread(void *_sas_ha)
 {
        struct sas_ha_struct *sas_ha = _sas_ha;
-       struct scsi_core *core = &sas_ha->core;
-
-       daemonize("sas_queue_%d", core->shost->host_no);
-       current->flags |= PF_NOFREEZE;
-
-       complete(&queue_th_comp);
 
        while (1) {
-               down_interruptible(&core->queue_thread_sema);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
                sas_queue(sas_ha);
-               if (core->queue_thread_kill)
+               if (kthread_should_stop())
                        break;
        }
 
-       complete(&queue_th_comp);
-
        return 0;
 }
 
 int sas_init_queue(struct sas_ha_struct *sas_ha)
 {
-       int res;
        struct scsi_core *core = &sas_ha->core;
 
        spin_lock_init(&core->task_queue_lock);
        core->task_queue_size = 0;
        INIT_LIST_HEAD(&core->task_queue);
-       init_MUTEX_LOCKED(&core->queue_thread_sema);
-
-       res = kernel_thread(sas_queue_thread, sas_ha, 0);
-       if (res >= 0)
-               wait_for_completion(&queue_th_comp);
 
-       return res < 0 ? res : 0;
+       core->queue_thread = kthread_run(sas_queue_thread, sas_ha,
+                                        "sas_queue_%d", core->shost->host_no);
+       if (IS_ERR(core->queue_thread))
+               return PTR_ERR(core->queue_thread);
+       return 0;
 }
 
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
@@ -909,10 +939,7 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
        struct scsi_core *core = &sas_ha->core;
        struct sas_task *task, *n;
 
-       init_completion(&queue_th_comp);
-       core->queue_thread_kill = 1;
-       up(&core->queue_thread_sema);
-       wait_for_completion(&queue_th_comp);
+       kthread_stop(core->queue_thread);
 
        if (!list_empty(&core->task_queue))
                SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
@@ -991,10 +1018,38 @@ void sas_task_abort(struct sas_task *task)
                return;
        }
 
+       if (dev_is_sata(task->dev)) {
+               sas_ata_task_abort(task);
+               return;
+       }
+
        scsi_req_abort_cmd(sc);
        scsi_schedule_eh(sc->device->host);
 }
 
+int sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+       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 0;
+}
+
+void sas_target_destroy(struct scsi_target *starget)
+{
+       struct domain_device *found_dev = sas_find_target(starget);
+
+       if (!found_dev)
+               return;
+
+       if (dev_is_sata(found_dev))
+               ata_sas_port_destroy(found_dev->sata_dev.ap);
+
+       return;
+}
+
 EXPORT_SYMBOL_GPL(sas_queuecommand);
 EXPORT_SYMBOL_GPL(sas_target_alloc);
 EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -1008,3 +1063,6 @@ EXPORT_SYMBOL_GPL(sas_phy_reset);
 EXPORT_SYMBOL_GPL(sas_phy_enable);
 EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
 EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
+EXPORT_SYMBOL_GPL(sas_slave_alloc);
+EXPORT_SYMBOL_GPL(sas_target_destroy);
+EXPORT_SYMBOL_GPL(sas_ioctl);