]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/libsas/sas_ata.c
[SCSI] libsas: convert to libata new error handler
[karo-tx-linux.git] / drivers / scsi / libsas / sas_ata.c
index e1a395b438eeddfef4e266aedfce0aa3edbe9c5b..16c5094bc86ca952f1dc14f9356f45bd38dc0fa4 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__,
@@ -238,37 +240,43 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
        return true;
 }
 
-static void sas_ata_phy_reset(struct ata_port *ap)
+static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
+                              unsigned long deadline)
 {
+       struct ata_port *ap = link->ap;
        struct domain_device *dev = ap->private_data;
        struct sas_internal *i =
                to_sas_internal(dev->port->ha->core.shost->transportt);
        int res = TMF_RESP_FUNC_FAILED;
+       int ret = 0;
 
        if (i->dft->lldd_I_T_nexus_reset)
                res = i->dft->lldd_I_T_nexus_reset(dev);
 
-       if (res != TMF_RESP_FUNC_COMPLETE)
+       if (res != TMF_RESP_FUNC_COMPLETE) {
                SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__);
+               ret = -EAGAIN;
+       }
 
        switch (dev->sata_dev.command_set) {
                case ATA_COMMAND_SET:
                        SAS_DPRINTK("%s: Found ATA device.\n", __func__);
-                       ap->link.device[0].class = ATA_DEV_ATA;
+                       *class = ATA_DEV_ATA;
                        break;
                case ATAPI_COMMAND_SET:
                        SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
-                       ap->link.device[0].class = ATA_DEV_ATAPI;
+                       *class = ATA_DEV_ATAPI;
                        break;
                default:
                        SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
                                    __func__,
                                    dev->sata_dev.command_set);
-                       ap->link.device[0].class = ATA_DEV_UNKNOWN;
+                       *class = ATA_DEV_UNKNOWN;
                        break;
        }
 
        ap->cbl = ATA_CBL_SATA;
+       return ret;
 }
 
 static void sas_ata_post_internal(struct ata_queued_cmd *qc)
@@ -299,57 +307,12 @@ 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 = {
-       .phy_reset              = sas_ata_phy_reset,
+       .prereset               = ata_std_prereset,
+       .softreset              = NULL,
+       .hardreset              = sas_ata_hard_reset,
+       .postreset              = ata_std_postreset,
+       .error_handler          = ata_std_error_handler,
        .post_internal_cmd      = sas_ata_post_internal,
        .qc_defer               = ata_std_qc_defer,
        .qc_prep                = ata_noop_qc_prep,
@@ -357,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 = {
@@ -781,3 +742,68 @@ int sas_discover_sata(struct domain_device *dev)
 
        return res;
 }
+
+void sas_ata_strategy_handler(struct Scsi_Host *shost)
+{
+       struct scsi_device *sdev;
+
+       shost_for_each_device(sdev, shost) {
+               struct domain_device *ddev = sdev_to_domain_dev(sdev);
+               struct ata_port *ap = ddev->sata_dev.ap;
+
+               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);
+       }
+}
+
+int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task,
+                     enum blk_eh_timer_return *rtn)
+{
+       struct domain_device *ddev = cmd_to_domain_dev(cmd);
+
+       if (!dev_is_sata(ddev) || task)
+               return 0;
+
+       /* we're a sata device with no task, so this must be a libata
+        * eh timeout.  Ideally should hook into libata timeout
+        * handling, but there's no point, it just wants to activate
+        * the eh thread */
+       *rtn = BLK_EH_NOT_HANDLED;
+       return 1;
+}
+
+int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
+              struct list_head *done_q)
+{
+       int rtn = 0;
+       struct scsi_cmnd *cmd, *n;
+       struct ata_port *ap;
+
+       do {
+               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)
+                               continue;
+                       ap = ddev->sata_dev.ap;
+                       rtn = 1;
+                       list_move(&cmd->eh_entry, &sata_q);
+               }
+
+               if (!list_empty(&sata_q)) {
+                       ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n");
+                       ata_scsi_cmd_error_handler(shost, ap, &sata_q);
+               }
+       } while (ap);
+
+       return rtn;
+}