[libata] Add ATA transport class
[deliverable/linux.git] / drivers / ata / libata-core.c
index 7ef7c4f216fa58567e161c82118155411d070074..4012b33e8b8a4e1598c2f62604b316ccc6cd9aca 100644 (file)
@@ -68,7 +68,7 @@
 #include <linux/ratelimit.h>
 
 #include "libata.h"
-
+#include "libata-transport.h"
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
 const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
@@ -1017,7 +1017,7 @@ const char *ata_mode_string(unsigned long xfer_mask)
        return "<n/a>";
 }
 
-static const char *sata_spd_string(unsigned int spd)
+const char *sata_spd_string(unsigned int spd)
 {
        static const char * const spd_str[] = {
                "1.5 Gbps",
@@ -5111,15 +5111,18 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
        qc->flags |= ATA_QCFLAG_ACTIVE;
        ap->qc_active |= 1 << qc->tag;
 
-       /* We guarantee to LLDs that they will have at least one
+       /*
+        * We guarantee to LLDs that they will have at least one
         * non-zero sg if the command is a data command.
         */
-       BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes));
+       if (WARN_ON_ONCE(ata_is_data(prot) &&
+                        (!qc->sg || !qc->n_elem || !qc->nbytes)))
+               goto sys_err;
 
        if (ata_is_dma(prot) || (ata_is_pio(prot) &&
                                 (ap->flags & ATA_FLAG_PIO_DMA)))
                if (ata_sg_setup(qc))
-                       goto sg_err;
+                       goto sys_err;
 
        /* if device is sleeping, schedule reset and abort the link */
        if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) {
@@ -5136,7 +5139,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
                goto err;
        return;
 
-sg_err:
+sys_err:
        qc->err_mask |= AC_ERR_SYSTEM;
 err:
        ata_qc_complete(qc);
@@ -5415,6 +5418,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
  */
 int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
 {
+       unsigned int ehi_flags = ATA_EHI_QUIET;
        int rc;
 
        /*
@@ -5423,7 +5427,18 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
         */
        ata_lpm_enable(host);
 
-       rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
+       /*
+        * On some hardware, device fails to respond after spun down
+        * for suspend.  As the device won't be used before being
+        * resumed, we don't need to touch the device.  Ask EH to skip
+        * the usual stuff and proceed directly to suspend.
+        *
+        * http://thread.gmane.org/gmane.linux.ide/46764
+        */
+       if (mesg.event == PM_EVENT_SUSPEND)
+               ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
+
+       rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1);
        if (rc == 0)
                host->dev->power.power_state = mesg;
        return rc;
@@ -5502,7 +5517,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
        int i;
 
        /* clear everything except for devices */
-       memset(link, 0, offsetof(struct ata_link, device[0]));
+       memset((void *)link + ATA_LINK_CLEAR_BEGIN, 0,
+              ATA_LINK_CLEAR_END - ATA_LINK_CLEAR_BEGIN);
 
        link->ap = ap;
        link->pmp = pmp;
@@ -5576,7 +5592,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        ap = kzalloc(sizeof(*ap), GFP_KERNEL);
        if (!ap)
                return NULL;
-
+       
        ap->pflags |= ATA_PFLAG_INITIALIZING;
        ap->lock = &host->lock;
        ap->print_id = -1;
@@ -6078,9 +6094,18 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        for (i = 0; i < host->n_ports; i++)
                host->ports[i]->print_id = ata_print_id++;
 
+       
+       /* Create associated sysfs transport objects  */
+       for (i = 0; i < host->n_ports; i++) {
+               rc = ata_tport_add(host->dev,host->ports[i]);
+               if (rc) {
+                       goto err_tadd;
+               }
+       }
+
        rc = ata_scsi_add_hosts(host, sht);
        if (rc)
-               return rc;
+               goto err_tadd;
 
        /* associate with ACPI nodes */
        ata_acpi_associate(host);
@@ -6121,6 +6146,13 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        }
 
        return 0;
+
+ err_tadd:
+       while (--i >= 0) {
+               ata_tport_delete(host->ports[i]);
+       }
+       return rc;
+
 }
 
 /**
@@ -6211,6 +6243,13 @@ static void ata_port_detach(struct ata_port *ap)
        cancel_rearming_delayed_work(&ap->hotplug_task);
 
  skip_eh:
+       if (ap->pmp_link) {
+               int i;
+               for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+                       ata_tlink_delete(&ap->pmp_link[i]);
+       }
+       ata_tport_delete(ap);
+
        /* remove the associated SCSI host */
        scsi_remove_host(ap->scsi_host);
 }
@@ -6527,7 +6566,7 @@ static void __init ata_parse_force_param(void)
 
 static int __init ata_init(void)
 {
-       int rc = -ENOMEM;
+       int rc;
 
        ata_parse_force_param();
 
@@ -6537,12 +6576,25 @@ static int __init ata_init(void)
                return rc;
        }
 
+       libata_transport_init();
+       ata_scsi_transport_template = ata_attach_transport();
+       if (!ata_scsi_transport_template) {
+               ata_sff_exit();
+               rc = -ENOMEM;
+               goto err_out;
+       }               
+
        printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
        return 0;
+
+err_out:
+       return rc;
 }
 
 static void __exit ata_exit(void)
 {
+       ata_release_transport(ata_scsi_transport_template);
+       libata_transport_exit();
        ata_sff_exit();
        kfree(ata_force_tbl);
 }
This page took 0.048119 seconds and 5 git commands to generate.