Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[cascardo/linux.git] / drivers / scsi / aic94xx / aic94xx_task.c
index 285e70d..f2b23e0 100644 (file)
@@ -53,7 +53,7 @@ static const u8 data_dir_flags[] = {
 
 static inline int asd_map_scatterlist(struct sas_task *task,
                                      struct sg_el *sg_arr,
-                                     unsigned long gfp_flags)
+                                     gfp_t gfp_flags)
 {
        struct asd_ascb *ascb = task->lldd_task;
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -74,8 +74,13 @@ static inline int asd_map_scatterlist(struct sas_task *task,
                return 0;
        }
 
-       num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
-                           task->data_dir);
+       /* STP tasks come from libata which has already mapped
+        * the SG list */
+       if (sas_protocol_ata(task->task_proto))
+               num_sg = task->num_scatter;
+       else
+               num_sg = pci_map_sg(asd_ha->pcidev, task->scatter,
+                                   task->num_scatter, task->data_dir);
        if (num_sg == 0)
                return -ENOMEM;
 
@@ -120,8 +125,9 @@ static inline int asd_map_scatterlist(struct sas_task *task,
 
        return 0;
 err_unmap:
-       pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
-                    task->data_dir);
+       if (sas_protocol_ata(task->task_proto))
+               pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+                            task->data_dir);
        return res;
 }
 
@@ -142,8 +148,9 @@ static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
        }
 
        asd_free_coherent(asd_ha, ascb->sg_arr);
-       pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
-                    task->data_dir);
+       if (task->task_proto != SAS_PROTOCOL_STP)
+               pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+                            task->data_dir);
 }
 
 /* ---------- Task complete tasklet ---------- */
@@ -200,7 +207,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
                                            "stat(0x%x) is not CHECK_CONDITION"
                                            "\n",
                                            SAS_ADDR(task->dev->sas_addr),
-                                           ts->stat);
+                                           iu->status);
                        }
                }
        }  else {
@@ -349,6 +356,7 @@ Again:
 
        spin_lock_irqsave(&task->task_state_lock, flags);
        task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+       task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
        task->task_state_flags |= SAS_TASK_STATE_DONE;
        if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
                spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -368,7 +376,7 @@ Again:
 /* ---------- ATA ---------- */
 
 static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
-                             unsigned long gfp_flags)
+                             gfp_t gfp_flags)
 {
        struct domain_device *dev = task->dev;
        struct scb *scb;
@@ -390,7 +398,6 @@ static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
 
        scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
        scb->ata_task.fis = task->ata_task.fis;
-       scb->ata_task.fis.fis_type = 0x27;
        if (likely(!task->ata_task.device_control_reg_update))
                scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
        scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
@@ -437,14 +444,14 @@ static void asd_unbuild_ata_ascb(struct asd_ascb *a)
 /* ---------- SMP ---------- */
 
 static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
-                             unsigned long gfp_flags)
+                             gfp_t gfp_flags)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
        struct domain_device *dev = task->dev;
        struct scb *scb;
 
        pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
-                  PCI_DMA_FROMDEVICE);
+                  PCI_DMA_TODEVICE);
        pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
                   PCI_DMA_FROMDEVICE);
 
@@ -479,7 +486,7 @@ static void asd_unbuild_smp_ascb(struct asd_ascb *a)
 
        BUG_ON(!task);
        pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
-                    PCI_DMA_FROMDEVICE);
+                    PCI_DMA_TODEVICE);
        pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
                     PCI_DMA_FROMDEVICE);
 }
@@ -487,7 +494,7 @@ static void asd_unbuild_smp_ascb(struct asd_ascb *a)
 /* ---------- SSP ---------- */
 
 static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,
-                             unsigned long gfp_flags)
+                             gfp_t gfp_flags)
 {
        struct domain_device *dev = task->dev;
        struct scb *scb;
@@ -550,13 +557,14 @@ static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
 }
 
 int asd_execute_task(struct sas_task *task, const int num,
-                    unsigned long gfp_flags)
+                    gfp_t gfp_flags)
 {
        int res = 0;
        LIST_HEAD(alist);
        struct sas_task *t = task;
        struct asd_ascb *ascb = NULL, *a;
        struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+       unsigned long flags;
 
        res = asd_can_queue(asd_ha, num);
        if (res)
@@ -599,6 +607,10 @@ int asd_execute_task(struct sas_task *task, const int num,
                }
                if (res)
                        goto out_err_unmap;
+
+               spin_lock_irqsave(&t->task_state_lock, flags);
+               t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+               spin_unlock_irqrestore(&t->task_state_lock, flags);
        }
        list_del_init(&alist);
 
@@ -617,6 +629,9 @@ out_err_unmap:
                        if (a == b)
                                break;
                        t = a->uldd_task;
+                       spin_lock_irqsave(&t->task_state_lock, flags);
+                       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+                       spin_unlock_irqrestore(&t->task_state_lock, flags);
                        switch (t->task_proto) {
                        case SATA_PROTO:
                        case SAS_PROTO_STP: