Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[pandora-kernel.git] / drivers / scsi / libsas / sas_ata.c
index 4d3b704..31fc21f 100644 (file)
@@ -71,13 +71,13 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
                case SAS_SG_ERR:
                        return AC_ERR_INVALID;
 
-               case SAM_STAT_CHECK_CONDITION:
                case SAS_OPEN_TO:
                case SAS_OPEN_REJECT:
                        SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
                                    __func__, ts->stat);
                        return AC_ERR_OTHER;
 
+               case SAM_STAT_CHECK_CONDITION:
                case SAS_ABORTED_TASK:
                        return AC_ERR_DEV;
 
@@ -107,13 +107,15 @@ static void sas_ata_task_done(struct sas_task *task)
        sas_ha = dev->port->ha;
 
        spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
-       if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD) {
+       if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
+           ((stat->stat == SAM_STAT_CHECK_CONDITION &&
+             dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
                ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
                qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
                dev->sata_dev.sstatus = resp->sstatus;
                dev->sata_dev.serror = resp->serror;
                dev->sata_dev.scontrol = resp->scontrol;
-       } else if (stat->stat != SAM_STAT_GOOD) {
+       } else {
                ac = sas_to_ata_err(stat);
                if (ac) {
                        SAS_DPRINTK("%s: SAS error %x\n", __func__,
@@ -305,55 +307,6 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
        }
 }
 
-static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in,
-                             u32 val)
-{
-       struct domain_device *dev = link->ap->private_data;
-
-       SAS_DPRINTK("STUB %s\n", __func__);
-       switch (sc_reg_in) {
-               case SCR_STATUS:
-                       dev->sata_dev.sstatus = val;
-                       break;
-               case SCR_CONTROL:
-                       dev->sata_dev.scontrol = val;
-                       break;
-               case SCR_ERROR:
-                       dev->sata_dev.serror = val;
-                       break;
-               case SCR_ACTIVE:
-                       dev->sata_dev.ap->link.sactive = val;
-                       break;
-               default:
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in,
-                           u32 *val)
-{
-       struct domain_device *dev = link->ap->private_data;
-
-       SAS_DPRINTK("STUB %s\n", __func__);
-       switch (sc_reg_in) {
-               case SCR_STATUS:
-                       *val = dev->sata_dev.sstatus;
-                       return 0;
-               case SCR_CONTROL:
-                       *val = dev->sata_dev.scontrol;
-                       return 0;
-               case SCR_ERROR:
-                       *val = dev->sata_dev.serror;
-                       return 0;
-               case SCR_ACTIVE:
-                       *val = dev->sata_dev.ap->link.sactive;
-                       return 0;
-               default:
-                       return -EINVAL;
-       }
-}
-
 static struct ata_port_operations sas_sata_ops = {
        .prereset               = ata_std_prereset,
        .softreset              = NULL,
@@ -367,8 +320,6 @@ static struct ata_port_operations sas_sata_ops = {
        .qc_fill_rtf            = sas_ata_qc_fill_rtf,
        .port_start             = ata_sas_port_start,
        .port_stop              = ata_sas_port_stop,
-       .scr_read               = sas_ata_scr_read,
-       .scr_write              = sas_ata_scr_write
 };
 
 static struct ata_port_info sata_port_info = {
@@ -801,7 +752,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost)
 
                if (!dev_is_sata(ddev))
                        continue;
-               
+
                ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler");
                ata_scsi_port_error_handler(shost, ap);
        }
@@ -834,13 +785,13 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
                LIST_HEAD(sata_q);
 
                ap = NULL;
-               
+
                list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
                        struct domain_device *ddev = cmd_to_domain_dev(cmd);
 
                        if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd))
                                continue;
-                       if(ap && ap != ddev->sata_dev.ap)
+                       if (ap && ap != ddev->sata_dev.ap)
                                continue;
                        ap = ddev->sata_dev.ap;
                        rtn = 1;
@@ -848,8 +799,21 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
                }
 
                if (!list_empty(&sata_q)) {
-                       ata_port_printk(ap, KERN_DEBUG,"sas eh calling libata cmd error handler\n");
+                       ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n");
                        ata_scsi_cmd_error_handler(shost, ap, &sata_q);
+                       /*
+                        * ata's error handler may leave the cmd on the list
+                        * so make sure they don't remain on a stack list
+                        * about to go out of scope.
+                        *
+                        * This looks strange, since the commands are
+                        * now part of no list, but the next error
+                        * action will be ata_port_error_handler()
+                        * which takes no list and sweeps them up
+                        * anyway from the ata tag array.
+                        */
+                       while (!list_empty(&sata_q))
+                               list_del_init(sata_q.next);
                }
        } while (ap);