diff options
Diffstat (limited to 'drivers/ata/libahci.c')
| -rw-r--r-- | drivers/ata/libahci.c | 538 | 
1 files changed, 440 insertions, 98 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index ebc08d65b3d..d72ce047030 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1,7 +1,7 @@  /*   *  libahci.c - Common AHCI SATA low-level routines   * - *  Maintained by:  Jeff Garzik <jgarzik@pobox.com> + *  Maintained by:  Tejun Heo <tj@kernel.org>   *    		    Please ALWAYS copy linux-ide@vger.kernel.org   *		    on emails.   * @@ -35,7 +35,6 @@  #include <linux/kernel.h>  #include <linux/gfp.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/blkdev.h>  #include <linux/delay.h>  #include <linux/interrupt.h> @@ -45,6 +44,7 @@  #include <scsi/scsi_cmnd.h>  #include <linux/libata.h>  #include "ahci.h" +#include "libata.h"  static int ahci_skip_host_reset;  int ahci_ignore_sss; @@ -68,7 +68,6 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,  static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);  static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);  static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);  static int ahci_port_start(struct ata_port *ap);  static void ahci_port_stop(struct ata_port *ap); @@ -76,21 +75,20 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);  static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);  static void ahci_freeze(struct ata_port *ap);  static void ahci_thaw(struct ata_port *ap); +static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep);  static void ahci_enable_fbs(struct ata_port *ap);  static void ahci_disable_fbs(struct ata_port *ap);  static void ahci_pmp_attach(struct ata_port *ap);  static void ahci_pmp_detach(struct ata_port *ap);  static int ahci_softreset(struct ata_link *link, unsigned int *class,  			  unsigned long deadline); +static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, +			  unsigned long deadline);  static int ahci_hardreset(struct ata_link *link, unsigned int *class,  			  unsigned long deadline);  static void ahci_postreset(struct ata_link *link, unsigned int *class); -static void ahci_error_handler(struct ata_port *ap);  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); -static int ahci_port_resume(struct ata_port *ap);  static void ahci_dev_config(struct ata_device *dev); -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, -			       u32 opts);  #ifdef CONFIG_PM  static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);  #endif @@ -112,6 +110,8 @@ static ssize_t ahci_read_em_buffer(struct device *dev,  static ssize_t ahci_store_em_buffer(struct device *dev,  				    struct device_attribute *attr,  				    const char *buf, size_t size); +static ssize_t ahci_show_em_supported(struct device *dev, +				      struct device_attribute *attr, char *buf);  static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);  static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); @@ -119,6 +119,7 @@ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);  static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);  static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,  		   ahci_read_em_buffer, ahci_store_em_buffer); +static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);  struct device_attribute *ahci_shost_attrs[] = {  	&dev_attr_link_power_management_policy, @@ -129,6 +130,7 @@ struct device_attribute *ahci_shost_attrs[] = {  	&dev_attr_ahci_host_version,  	&dev_attr_ahci_port_cmd,  	&dev_attr_em_buffer, +	&dev_attr_em_message_supported,  	NULL  };  EXPORT_SYMBOL_GPL(ahci_shost_attrs); @@ -168,6 +170,7 @@ struct ata_port_operations ahci_ops = {  	.em_store		= ahci_led_store,  	.sw_activity_show	= ahci_activity_show,  	.sw_activity_store	= ahci_activity_store, +	.transmit_led_message	= ahci_transmit_led_message,  #ifdef CONFIG_PM  	.port_suspend		= ahci_port_suspend,  	.port_resume		= ahci_port_resume, @@ -177,13 +180,24 @@ struct ata_port_operations ahci_ops = {  };  EXPORT_SYMBOL_GPL(ahci_ops); -int ahci_em_messages = 1; +struct ata_port_operations ahci_pmp_retry_srst_ops = { +	.inherits		= &ahci_ops, +	.softreset		= ahci_pmp_retry_softreset, +}; +EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); + +static bool ahci_em_messages __read_mostly = true;  EXPORT_SYMBOL_GPL(ahci_em_messages); -module_param(ahci_em_messages, int, 0444); +module_param(ahci_em_messages, bool, 0444);  /* add other LED protocol types when they become supported */  MODULE_PARM_DESC(ahci_em_messages,  	"AHCI Enclosure Management Message control (0 = off, 1 = on)"); +/* device sleep idle timeout in ms */ +static int devslp_idle_timeout __read_mostly = 1000; +module_param(devslp_idle_timeout, int, 0644); +MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout"); +  static void ahci_enable_ahci(void __iomem *mmio)  {  	int i; @@ -285,10 +299,10 @@ static ssize_t ahci_read_em_buffer(struct device *dev,  	/* the count should not be larger than PAGE_SIZE */  	if (count > PAGE_SIZE) {  		if (printk_ratelimit()) -			ata_port_printk(ap, KERN_WARNING, -					"EM read buffer size too large: " -					"buffer size %u, page size %lu\n", -					hpriv->em_buf_sz, PAGE_SIZE); +			ata_port_warn(ap, +				      "EM read buffer size too large: " +				      "buffer size %u, page size %lu\n", +				      hpriv->em_buf_sz, PAGE_SIZE);  		count = PAGE_SIZE;  	} @@ -346,6 +360,24 @@ static ssize_t ahci_store_em_buffer(struct device *dev,  	return size;  } +static ssize_t ahci_show_em_supported(struct device *dev, +				      struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct ata_port *ap = ata_shost_to_port(shost); +	struct ahci_host_priv *hpriv = ap->host->private_data; +	void __iomem *mmio = hpriv->mmio; +	u32 em_ctl; + +	em_ctl = readl(mmio + HOST_EM_CTL); + +	return sprintf(buf, "%s%s%s%s\n", +		       em_ctl & EM_CTL_LED ? "led " : "", +		       em_ctl & EM_CTL_SAFTE ? "saf-te " : "", +		       em_ctl & EM_CTL_SES ? "ses-2 " : "", +		       em_ctl & EM_CTL_SGPIO ? "sgpio " : ""); +} +  /**   *	ahci_save_initial_config - Save and fixup initial config values   *	@dev: target AHCI device @@ -360,6 +392,9 @@ static ssize_t ahci_store_em_buffer(struct device *dev,   *   *	If inconsistent, config values are fixed up by this function.   * + *	If it is not set already this function sets hpriv->start_engine to + *	ahci_start_engine. + *   *	LOCKING:   *	None.   */ @@ -391,51 +426,58 @@ void ahci_save_initial_config(struct device *dev,  	/* some chips have errata preventing 64bit use */  	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { -		dev_printk(KERN_INFO, dev, -			   "controller can't do 64bit DMA, forcing 32bit\n"); +		dev_info(dev, "controller can't do 64bit DMA, forcing 32bit\n");  		cap &= ~HOST_CAP_64;  	}  	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { -		dev_printk(KERN_INFO, dev, -			   "controller can't do NCQ, turning off CAP_NCQ\n"); +		dev_info(dev, "controller can't do NCQ, turning off CAP_NCQ\n");  		cap &= ~HOST_CAP_NCQ;  	}  	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { -		dev_printk(KERN_INFO, dev, -			   "controller can do NCQ, turning on CAP_NCQ\n"); +		dev_info(dev, "controller can do NCQ, turning on CAP_NCQ\n");  		cap |= HOST_CAP_NCQ;  	}  	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { -		dev_printk(KERN_INFO, dev, -			   "controller can't do PMP, turning off CAP_PMP\n"); +		dev_info(dev, "controller can't do PMP, turning off CAP_PMP\n");  		cap &= ~HOST_CAP_PMP;  	}  	if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) { -		dev_printk(KERN_INFO, dev, -			   "controller can't do SNTF, turning off CAP_SNTF\n"); +		dev_info(dev, +			 "controller can't do SNTF, turning off CAP_SNTF\n");  		cap &= ~HOST_CAP_SNTF;  	} +	if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) { +		dev_info(dev, +			 "controller can't do DEVSLP, turning off\n"); +		cap2 &= ~HOST_CAP2_SDS; +		cap2 &= ~HOST_CAP2_SADM; +	} +  	if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) { -		dev_printk(KERN_INFO, dev, -			   "controller can do FBS, turning on CAP_FBS\n"); +		dev_info(dev, "controller can do FBS, turning on CAP_FBS\n");  		cap |= HOST_CAP_FBS;  	} +	if ((cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_NO_FBS)) { +		dev_info(dev, "controller can't do FBS, turning off CAP_FBS\n"); +		cap &= ~HOST_CAP_FBS; +	} +  	if (force_port_map && port_map != force_port_map) { -		dev_printk(KERN_INFO, dev, "forcing port_map 0x%x -> 0x%x\n", -			   port_map, force_port_map); +		dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", +			 port_map, force_port_map);  		port_map = force_port_map;  	}  	if (mask_port_map) { -		dev_printk(KERN_ERR, dev, "masking port_map 0x%x -> 0x%x\n", -			   port_map, -			   port_map & mask_port_map); +		dev_warn(dev, "masking port_map 0x%x -> 0x%x\n", +			port_map, +			port_map & mask_port_map);  		port_map &= mask_port_map;  	} @@ -451,10 +493,9 @@ void ahci_save_initial_config(struct device *dev,  		 * port_map and let it be generated from n_ports.  		 */  		if (map_ports > ahci_nr_ports(cap)) { -			dev_printk(KERN_WARNING, dev, -				   "implemented port map (0x%x) contains more " -				   "ports than nr_ports (%u), using nr_ports\n", -				   port_map, ahci_nr_ports(cap)); +			dev_warn(dev, +				 "implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports\n", +				 port_map, ahci_nr_ports(cap));  			port_map = 0;  		}  	} @@ -462,8 +503,7 @@ void ahci_save_initial_config(struct device *dev,  	/* fabricate port_map from cap.nr_ports */  	if (!port_map) {  		port_map = (1 << ahci_nr_ports(cap)) - 1; -		dev_printk(KERN_WARNING, dev, -			   "forcing PORTS_IMPL to 0x%x\n", port_map); +		dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);  		/* write the fixed up value to the PI register */  		hpriv->saved_port_map = port_map; @@ -473,6 +513,9 @@ void ahci_save_initial_config(struct device *dev,  	hpriv->cap = cap;  	hpriv->cap2 = cap2;  	hpriv->port_map = port_map; + +	if (!hpriv->start_engine) +		hpriv->start_engine = ahci_start_engine;  }  EXPORT_SYMBOL_GPL(ahci_save_initial_config); @@ -576,7 +619,7 @@ int ahci_stop_engine(struct ata_port *ap)  }  EXPORT_SYMBOL_GPL(ahci_stop_engine); -static void ahci_start_fis_rx(struct ata_port *ap) +void ahci_start_fis_rx(struct ata_port *ap)  {  	void __iomem *port_mmio = ahci_port_base(ap);  	struct ahci_host_priv *hpriv = ap->host->private_data; @@ -602,6 +645,7 @@ static void ahci_start_fis_rx(struct ata_port *ap)  	/* flush */  	readl(port_mmio + PORT_CMD);  } +EXPORT_SYMBOL_GPL(ahci_start_fis_rx);  static int ahci_stop_fis_rx(struct ata_port *ap)  { @@ -682,6 +726,16 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,  		}  	} +	/* set aggressive device sleep */ +	if ((hpriv->cap2 & HOST_CAP2_SDS) && +	    (hpriv->cap2 & HOST_CAP2_SADM) && +	    (link->device->flags & ATA_DFLAG_DEVSLP)) { +		if (policy == ATA_LPM_MIN_POWER) +			ahci_set_aggressive_devslp(ap, true); +		else +			ahci_set_aggressive_devslp(ap, false); +	} +  	if (policy == ATA_LPM_MAX_POWER) {  		sata_link_scr_lpm(link, policy, false); @@ -717,6 +771,7 @@ static void ahci_power_down(struct ata_port *ap)  static void ahci_start_port(struct ata_port *ap)  { +	struct ahci_host_priv *hpriv = ap->host->private_data;  	struct ahci_port_priv *pp = ap->private_data;  	struct ata_link *link;  	struct ahci_em_priv *emp; @@ -727,7 +782,8 @@ static void ahci_start_port(struct ata_port *ap)  	ahci_start_fis_rx(ap);  	/* enable DMA */ -	ahci_start_engine(ap); +	if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) +		hpriv->start_engine(ap);  	/* turn on LEDs */  	if (ap->flags & ATA_FLAG_EM) { @@ -736,11 +792,19 @@ static void ahci_start_port(struct ata_port *ap)  			/* EM Transmit bit maybe busy during init */  			for (i = 0; i < EM_MAX_RETRY; i++) { -				rc = ahci_transmit_led_message(ap, +				rc = ap->ops->transmit_led_message(ap,  							       emp->led_state,  							       4); +				/* +				 * If busy, give a breather but do not +				 * release EH ownership by using msleep() +				 * instead of ata_msleep().  EM Transmit +				 * bit is busy for the whole host and +				 * releasing ownership will cause other +				 * ports to fail the same way. +				 */  				if (rc == -EBUSY) -					ata_msleep(ap, 1); +					msleep(1);  				else  					break;  			} @@ -803,8 +867,8 @@ int ahci_reset_controller(struct ata_host *host)  					HOST_RESET, 10, 1000);  		if (tmp & HOST_RESET) { -			dev_printk(KERN_ERR, host->dev, -				   "controller reset failed (0x%x)\n", tmp); +			dev_err(host->dev, "controller reset failed (0x%x)\n", +				tmp);  			return -EIO;  		} @@ -816,8 +880,7 @@ int ahci_reset_controller(struct ata_host *host)  		 */  		ahci_restore_initial_config(host);  	} else -		dev_printk(KERN_INFO, host->dev, -			   "skipping global host reset\n"); +		dev_info(host->dev, "skipping global host reset\n");  	return 0;  } @@ -878,7 +941,7 @@ static void ahci_sw_activity_blink(unsigned long arg)  			led_message |= (1 << 16);  	}  	spin_unlock_irqrestore(ap->lock, flags); -	ahci_transmit_led_message(ap, led_message, 4); +	ap->ops->transmit_led_message(ap, led_message, 4);  }  static void ahci_init_sw_activity(struct ata_link *link) @@ -986,12 +1049,13 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)  static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,  				size_t size)  { -	int state; +	unsigned int state;  	int pmp;  	struct ahci_port_priv *pp = ap->private_data;  	struct ahci_em_priv *emp; -	state = simple_strtoul(buf, NULL, 0); +	if (kstrtouint(buf, 0, &state) < 0) +		return -EINVAL;  	/* get the slot number from the message */  	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; @@ -1007,7 +1071,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,  	if (emp->blink_policy)  		state &= ~EM_MSG_LED_VALUE_ACTIVITY; -	return ahci_transmit_led_message(ap, state, size); +	return ap->ops->transmit_led_message(ap, state, size);  }  static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val) @@ -1026,7 +1090,7 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)  		/* set the LED to OFF */  		port_led_state &= EM_MSG_LED_VALUE_OFF;  		port_led_state |= (ap->port_no | (link->pmp << 8)); -		ahci_transmit_led_message(ap, port_led_state, 4); +		ap->ops->transmit_led_message(ap, port_led_state, 4);  	} else {  		link->flags |= ATA_LFLAG_SW_ACTIVITY;  		if (val == BLINK_OFF) { @@ -1034,7 +1098,7 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)  			port_led_state &= EM_MSG_LED_VALUE_OFF;  			port_led_state |= (ap->port_no | (link->pmp << 8));  			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */ -			ahci_transmit_led_message(ap, port_led_state, 4); +			ap->ops->transmit_led_message(ap, port_led_state, 4);  		}  	}  	emp->blink_policy = val; @@ -1113,12 +1177,12 @@ static void ahci_dev_config(struct ata_device *dev)  	if (hpriv->flags & AHCI_HFLAG_SECT255) {  		dev->max_sectors = 255; -		ata_dev_printk(dev, KERN_INFO, -			       "SB600 AHCI: limiting to 255 sectors per cmd\n"); +		ata_dev_info(dev, +			     "SB600 AHCI: limiting to 255 sectors per cmd\n");  	}  } -static unsigned int ahci_dev_classify(struct ata_port *ap) +unsigned int ahci_dev_classify(struct ata_port *ap)  {  	void __iomem *port_mmio = ahci_port_base(ap);  	struct ata_taskfile tf; @@ -1132,9 +1196,10 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)  	return ata_dev_classify(&tf);  } +EXPORT_SYMBOL_GPL(ahci_dev_classify); -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, -			       u32 opts) +void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, +			u32 opts)  {  	dma_addr_t cmd_tbl_dma; @@ -1145,6 +1210,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,  	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);  	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);  } +EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot);  int ahci_kick_engine(struct ata_port *ap)  { @@ -1186,7 +1252,7 @@ int ahci_kick_engine(struct ata_port *ap)  	/* restart engine */   out_restart: -	ahci_start_engine(ap); +	hpriv->start_engine(ap);  	return rc;  }  EXPORT_SYMBOL_GPL(ahci_kick_engine); @@ -1227,9 +1293,11 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  {  	struct ata_port *ap = link->ap;  	struct ahci_host_priv *hpriv = ap->host->private_data; +	struct ahci_port_priv *pp = ap->private_data;  	const char *reason = NULL;  	unsigned long now, msecs;  	struct ata_taskfile tf; +	bool fbs_disabled = false;  	int rc;  	DPRINTK("ENTER\n"); @@ -1237,8 +1305,17 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  	/* prepare for SRST (AHCI-1.1 10.4.1) */  	rc = ahci_kick_engine(ap);  	if (rc && rc != -EOPNOTSUPP) -		ata_link_printk(link, KERN_WARNING, -				"failed to reset engine (errno=%d)\n", rc); +		ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc); + +	/* +	 * According to AHCI-1.2 9.3.9: if FBS is enable, software shall +	 * clear PxFBS.EN to '0' prior to issuing software reset to devices +	 * that is attached to port multiplier. +	 */ +	if (!ata_is_host_link(link) && pp->fbs_enabled) { +		ahci_disable_fbs(ap); +		fbs_disabled = true; +	}  	ata_tf_init(link->device, &tf); @@ -1271,8 +1348,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  		 * be trusted.  Treat device readiness timeout as link  		 * offline.  		 */ -		ata_link_printk(link, KERN_INFO, -				"device not ready, treating as offline\n"); +		ata_link_info(link, "device not ready, treating as offline\n");  		*class = ATA_DEV_NONE;  	} else if (rc) {  		/* link occupied, -ENODEV too is an error */ @@ -1281,11 +1357,15 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,  	} else  		*class = ahci_dev_classify(ap); +	/* re-enable FBS if disabled before */ +	if (fbs_disabled) +		ahci_enable_fbs(ap); +  	DPRINTK("EXIT, class=%u\n", *class);  	return 0;   fail: -	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); +	ata_link_err(link, "softreset failed (%s)\n", reason);  	return rc;  } @@ -1309,12 +1389,62 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,  }  EXPORT_SYMBOL_GPL(ahci_do_softreset); +static int ahci_bad_pmp_check_ready(struct ata_link *link) +{ +	void __iomem *port_mmio = ahci_port_base(link->ap); +	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; +	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); + +	/* +	 * There is no need to check TFDATA if BAD PMP is found due to HW bug, +	 * which can save timeout delay. +	 */ +	if (irq_status & PORT_IRQ_BAD_PMP) +		return -EIO; + +	return ata_check_ready(status); +} + +static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, +				    unsigned long deadline) +{ +	struct ata_port *ap = link->ap; +	void __iomem *port_mmio = ahci_port_base(ap); +	int pmp = sata_srst_pmp(link); +	int rc; +	u32 irq_sts; + +	DPRINTK("ENTER\n"); + +	rc = ahci_do_softreset(link, class, pmp, deadline, +			       ahci_bad_pmp_check_ready); + +	/* +	 * Soft reset fails with IPMS set when PMP is enabled but +	 * SATA HDD/ODD is connected to SATA port, do soft reset +	 * again to port 0. +	 */ +	if (rc == -EIO) { +		irq_sts = readl(port_mmio + PORT_IRQ_STAT); +		if (irq_sts & PORT_IRQ_BAD_PMP) { +			ata_link_warn(link, +					"applying PMP SRST workaround " +					"and retrying\n"); +			rc = ahci_do_softreset(link, class, 0, deadline, +					       ahci_check_ready); +		} +	} + +	return rc; +} +  static int ahci_hardreset(struct ata_link *link, unsigned int *class,  			  unsigned long deadline)  {  	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);  	struct ata_port *ap = link->ap;  	struct ahci_port_priv *pp = ap->private_data; +	struct ahci_host_priv *hpriv = ap->host->private_data;  	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;  	struct ata_taskfile tf;  	bool online; @@ -1326,13 +1456,13 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,  	/* clear D2H reception area to properly wait for D2H FIS */  	ata_tf_init(link->device, &tf); -	tf.command = 0x80; +	tf.command = ATA_BUSY;  	ata_tf_to_fis(&tf, 0, 0, d2h_fis);  	rc = sata_link_hardreset(link, timing, deadline, &online,  				 ahci_check_ready); -	ahci_start_engine(ap); +	hpriv->start_engine(ap);  	if (online)  		*class = ahci_dev_classify(ap); @@ -1454,8 +1584,7 @@ static void ahci_fbs_dec_intr(struct ata_port *ap)  	}  	if (fbs & PORT_FBS_DEC) -		dev_printk(KERN_ERR, ap->host->dev, -			   "failed to clear device error\n"); +		dev_err(ap->host->dev, "failed to clear device error\n");  }  static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) @@ -1475,8 +1604,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)  		u32 fbs = readl(port_mmio + PORT_FBS);  		int pmp = fbs >> PORT_FBS_DWE_OFFSET; -		if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) && -		    ata_link_online(&ap->pmp_link[pmp])) { +		if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {  			link = &ap->pmp_link[pmp];  			fbs_need_dec = true;  		} @@ -1520,7 +1648,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)  	}  	if (irq_stat & PORT_IRQ_UNK_FIS) { -		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); +		u32 *unk = pp->rx_fis + RX_FIS_UNK;  		active_ehi->err_mask |= AC_ERR_HSM;  		active_ehi->action |= ATA_EH_RESET; @@ -1570,19 +1698,16 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)  		ata_port_abort(ap);  } -static void ahci_port_intr(struct ata_port *ap) +static void ahci_handle_port_interrupt(struct ata_port *ap, +				       void __iomem *port_mmio, u32 status)  { -	void __iomem *port_mmio = ahci_port_base(ap);  	struct ata_eh_info *ehi = &ap->link.eh_info;  	struct ahci_port_priv *pp = ap->private_data;  	struct ahci_host_priv *hpriv = ap->host->private_data;  	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); -	u32 status, qc_active = 0; +	u32 qc_active = 0;  	int rc; -	status = readl(port_mmio + PORT_IRQ_STAT); -	writel(status, port_mmio + PORT_IRQ_STAT); -  	/* ignore BAD_PMP while resetting */  	if (unlikely(resetting))  		status &= ~PORT_IRQ_BAD_PMP; @@ -1658,6 +1783,107 @@ static void ahci_port_intr(struct ata_port *ap)  	}  } +static void ahci_port_intr(struct ata_port *ap) +{ +	void __iomem *port_mmio = ahci_port_base(ap); +	u32 status; + +	status = readl(port_mmio + PORT_IRQ_STAT); +	writel(status, port_mmio + PORT_IRQ_STAT); + +	ahci_handle_port_interrupt(ap, port_mmio, status); +} + +irqreturn_t ahci_thread_fn(int irq, void *dev_instance) +{ +	struct ata_port *ap = dev_instance; +	struct ahci_port_priv *pp = ap->private_data; +	void __iomem *port_mmio = ahci_port_base(ap); +	unsigned long flags; +	u32 status; + +	spin_lock_irqsave(&ap->host->lock, flags); +	status = pp->intr_status; +	if (status) +		pp->intr_status = 0; +	spin_unlock_irqrestore(&ap->host->lock, flags); + +	spin_lock_bh(ap->lock); +	ahci_handle_port_interrupt(ap, port_mmio, status); +	spin_unlock_bh(ap->lock); + +	return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(ahci_thread_fn); + +static void ahci_hw_port_interrupt(struct ata_port *ap) +{ +	void __iomem *port_mmio = ahci_port_base(ap); +	struct ahci_port_priv *pp = ap->private_data; +	u32 status; + +	status = readl(port_mmio + PORT_IRQ_STAT); +	writel(status, port_mmio + PORT_IRQ_STAT); + +	pp->intr_status |= status; +} + +irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) +{ +	struct ata_port *ap_this = dev_instance; +	struct ahci_port_priv *pp = ap_this->private_data; +	struct ata_host *host = ap_this->host; +	struct ahci_host_priv *hpriv = host->private_data; +	void __iomem *mmio = hpriv->mmio; +	unsigned int i; +	u32 irq_stat, irq_masked; + +	VPRINTK("ENTER\n"); + +	spin_lock(&host->lock); + +	irq_stat = readl(mmio + HOST_IRQ_STAT); + +	if (!irq_stat) { +		u32 status = pp->intr_status; + +		spin_unlock(&host->lock); + +		VPRINTK("EXIT\n"); + +		return status ? IRQ_WAKE_THREAD : IRQ_NONE; +	} + +	irq_masked = irq_stat & hpriv->port_map; + +	for (i = 0; i < host->n_ports; i++) { +		struct ata_port *ap; + +		if (!(irq_masked & (1 << i))) +			continue; + +		ap = host->ports[i]; +		if (ap) { +			ahci_hw_port_interrupt(ap); +			VPRINTK("port %u\n", i); +		} else { +			VPRINTK("port %u (no irq)\n", i); +			if (ata_ratelimit()) +				dev_warn(host->dev, +					 "interrupt on disabled port %u\n", i); +		} +	} + +	writel(irq_stat, mmio + HOST_IRQ_STAT); + +	spin_unlock(&host->lock); + +	VPRINTK("EXIT\n"); + +	return IRQ_WAKE_THREAD; +} +EXPORT_SYMBOL_GPL(ahci_hw_interrupt); +  irqreturn_t ahci_interrupt(int irq, void *dev_instance)  {  	struct ata_host *host = dev_instance; @@ -1693,8 +1919,8 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)  		} else {  			VPRINTK("port %u (no irq)\n", i);  			if (ata_ratelimit()) -				dev_printk(KERN_WARNING, host->dev, -					"interrupt on disabled port %u\n", i); +				dev_warn(host->dev, +					 "interrupt on disabled port %u\n", i);  		}  		handled = 1; @@ -1719,7 +1945,7 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)  }  EXPORT_SYMBOL_GPL(ahci_interrupt); -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) +unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)  {  	struct ata_port *ap = qc->ap;  	void __iomem *port_mmio = ahci_port_base(ap); @@ -1748,6 +1974,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)  	return 0;  } +EXPORT_SYMBOL_GPL(ahci_qc_issue);  static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)  { @@ -1798,12 +2025,14 @@ static void ahci_thaw(struct ata_port *ap)  	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);  } -static void ahci_error_handler(struct ata_port *ap) +void ahci_error_handler(struct ata_port *ap)  { +	struct ahci_host_priv *hpriv = ap->host->private_data; +  	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {  		/* restart engine */  		ahci_stop_engine(ap); -		ahci_start_engine(ap); +		hpriv->start_engine(ap);  	}  	sata_pmp_error_handler(ap); @@ -1811,6 +2040,7 @@ static void ahci_error_handler(struct ata_port *ap)  	if (!ata_dev_enabled(ap->link.device))  		ahci_stop_engine(ap);  } +EXPORT_SYMBOL_GPL(ahci_error_handler);  static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)  { @@ -1821,8 +2051,85 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)  		ahci_kick_engine(ap);  } +static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) +{ +	struct ahci_host_priv *hpriv = ap->host->private_data; +	void __iomem *port_mmio = ahci_port_base(ap); +	struct ata_device *dev = ap->link.device; +	u32 devslp, dm, dito, mdat, deto; +	int rc; +	unsigned int err_mask; + +	devslp = readl(port_mmio + PORT_DEVSLP); +	if (!(devslp & PORT_DEVSLP_DSP)) { +		dev_err(ap->host->dev, "port does not support device sleep\n"); +		return; +	} + +	/* disable device sleep */ +	if (!sleep) { +		if (devslp & PORT_DEVSLP_ADSE) { +			writel(devslp & ~PORT_DEVSLP_ADSE, +			       port_mmio + PORT_DEVSLP); +			err_mask = ata_dev_set_feature(dev, +						       SETFEATURES_SATA_DISABLE, +						       SATA_DEVSLP); +			if (err_mask && err_mask != AC_ERR_DEV) +				ata_dev_warn(dev, "failed to disable DEVSLP\n"); +		} +		return; +	} + +	/* device sleep was already enabled */ +	if (devslp & PORT_DEVSLP_ADSE) +		return; + +	/* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ +	rc = ahci_stop_engine(ap); +	if (rc) +		return; + +	dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; +	dito = devslp_idle_timeout / (dm + 1); +	if (dito > 0x3ff) +		dito = 0x3ff; + +	/* Use the nominal value 10 ms if the read MDAT is zero, +	 * the nominal value of DETO is 20 ms. +	 */ +	if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] & +	    ATA_LOG_DEVSLP_VALID_MASK) { +		mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] & +		       ATA_LOG_DEVSLP_MDAT_MASK; +		if (!mdat) +			mdat = 10; +		deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO]; +		if (!deto) +			deto = 20; +	} else { +		mdat = 10; +		deto = 20; +	} + +	devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | +		   (mdat << PORT_DEVSLP_MDAT_OFFSET) | +		   (deto << PORT_DEVSLP_DETO_OFFSET) | +		   PORT_DEVSLP_ADSE); +	writel(devslp, port_mmio + PORT_DEVSLP); + +	hpriv->start_engine(ap); + +	/* enable device sleep feature for the drive */ +	err_mask = ata_dev_set_feature(dev, +				       SETFEATURES_SATA_ENABLE, +				       SATA_DEVSLP); +	if (err_mask && err_mask != AC_ERR_DEV) +		ata_dev_warn(dev, "failed to enable DEVSLP\n"); +} +  static void ahci_enable_fbs(struct ata_port *ap)  { +	struct ahci_host_priv *hpriv = ap->host->private_data;  	struct ahci_port_priv *pp = ap->private_data;  	void __iomem *port_mmio = ahci_port_base(ap);  	u32 fbs; @@ -1845,17 +2152,18 @@ static void ahci_enable_fbs(struct ata_port *ap)  	writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);  	fbs = readl(port_mmio + PORT_FBS);  	if (fbs & PORT_FBS_EN) { -		dev_printk(KERN_INFO, ap->host->dev, "FBS is enabled.\n"); +		dev_info(ap->host->dev, "FBS is enabled\n");  		pp->fbs_enabled = true;  		pp->fbs_last_dev = -1; /* initialization */  	} else -		dev_printk(KERN_ERR, ap->host->dev, "Failed to enable FBS\n"); +		dev_err(ap->host->dev, "Failed to enable FBS\n"); -	ahci_start_engine(ap); +	hpriv->start_engine(ap);  }  static void ahci_disable_fbs(struct ata_port *ap)  { +	struct ahci_host_priv *hpriv = ap->host->private_data;  	struct ahci_port_priv *pp = ap->private_data;  	void __iomem *port_mmio = ahci_port_base(ap);  	u32 fbs; @@ -1877,13 +2185,13 @@ static void ahci_disable_fbs(struct ata_port *ap)  	writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS);  	fbs = readl(port_mmio + PORT_FBS);  	if (fbs & PORT_FBS_EN) -		dev_printk(KERN_ERR, ap->host->dev, "Failed to disable FBS\n"); +		dev_err(ap->host->dev, "Failed to disable FBS\n");  	else { -		dev_printk(KERN_INFO, ap->host->dev, "FBS is disabled.\n"); +		dev_info(ap->host->dev, "FBS is disabled\n");  		pp->fbs_enabled = false;  	} -	ahci_start_engine(ap); +	hpriv->start_engine(ap);  }  static void ahci_pmp_attach(struct ata_port *ap) @@ -1899,7 +2207,17 @@ static void ahci_pmp_attach(struct ata_port *ap)  	ahci_enable_fbs(ap);  	pp->intr_mask |= PORT_IRQ_BAD_PMP; -	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + +	/* +	 * We must not change the port interrupt mask register if the +	 * port is marked frozen, the value in pp->intr_mask will be +	 * restored later when the port is thawed. +	 * +	 * Note that during initialization, the port is marked as +	 * frozen since the irq handler is not yet registered. +	 */ +	if (!(ap->pflags & ATA_PFLAG_FROZEN)) +		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);  }  static void ahci_pmp_detach(struct ata_port *ap) @@ -1915,10 +2233,13 @@ static void ahci_pmp_detach(struct ata_port *ap)  	writel(cmd, port_mmio + PORT_CMD);  	pp->intr_mask &= ~PORT_IRQ_BAD_PMP; -	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + +	/* see comment above in ahci_pmp_attach() */ +	if (!(ap->pflags & ATA_PFLAG_FROZEN)) +		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);  } -static int ahci_port_resume(struct ata_port *ap) +int ahci_port_resume(struct ata_port *ap)  {  	ahci_power_up(ap);  	ahci_start_port(ap); @@ -1930,6 +2251,7 @@ static int ahci_port_resume(struct ata_port *ap)  	return 0;  } +EXPORT_SYMBOL_GPL(ahci_port_resume);  #ifdef CONFIG_PM  static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) @@ -1941,8 +2263,8 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)  	if (rc == 0)  		ahci_power_down(ap);  	else { -		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); -		ahci_start_port(ap); +		ata_port_err(ap, "%s (%d)\n", emsg, rc); +		ata_port_freeze(ap);  	}  	return rc; @@ -1962,6 +2284,16 @@ static int ahci_port_start(struct ata_port *ap)  	if (!pp)  		return -ENOMEM; +	if (ap->host->n_ports > 1) { +		pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL); +		if (!pp->irq_desc) { +			devm_kfree(dev, pp); +			return -ENOMEM; +		} +		snprintf(pp->irq_desc, 8, +			 "%s%d", dev_driver_string(dev), ap->port_no); +	} +  	/* check FBS capability */  	if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {  		void __iomem *port_mmio = ahci_port_base(ap); @@ -1969,14 +2301,12 @@ static int ahci_port_start(struct ata_port *ap)  		if (cmd & PORT_CMD_FBSCP)  			pp->fbs_supported = true;  		else if (hpriv->flags & AHCI_HFLAG_YES_FBS) { -			dev_printk(KERN_INFO, dev, -				   "port %d can do FBS, forcing FBSCP\n", -				   ap->port_no); +			dev_info(dev, "port %d can do FBS, forcing FBSCP\n", +				 ap->port_no);  			pp->fbs_supported = true;  		} else -			dev_printk(KERN_WARNING, dev, -				   "port %d is not capable of FBS\n", -				   ap->port_no); +			dev_warn(dev, "port %d is not capable of FBS\n", +				 ap->port_no);  	}  	if (pp->fbs_supported) { @@ -2024,6 +2354,14 @@ static int ahci_port_start(struct ata_port *ap)  	 */  	pp->intr_mask = DEF_PORT_IRQ; +	/* +	 * Switch to per-port locking in case each port has its own MSI vector. +	 */ +	if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) { +		spin_lock_init(&pp->lock); +		ap->lock = &pp->lock; +	} +  	ap->private_data = pp;  	/* engage engines, captain */ @@ -2038,7 +2376,7 @@ static void ahci_port_stop(struct ata_port *ap)  	/* de-initialize port */  	rc = ahci_deinit_port(ap, &emsg);  	if (rc) -		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); +		ata_port_warn(ap, "%s (%d)\n", emsg, rc);  }  void ahci_print_info(struct ata_host *host, const char *scc_s) @@ -2083,7 +2421,8 @@ void ahci_print_info(struct ata_host *host, const char *scc_s)  		"flags: "  		"%s%s%s%s%s%s%s"  		"%s%s%s%s%s%s%s" -		"%s%s%s%s%s%s\n" +		"%s%s%s%s%s%s%s" +		"%s%s\n"  		,  		cap & HOST_CAP_64 ? "64bit " : "", @@ -2103,6 +2442,9 @@ void ahci_print_info(struct ata_host *host, const char *scc_s)  		cap & HOST_CAP_CCC ? "ccc " : "",  		cap & HOST_CAP_EMS ? "ems " : "",  		cap & HOST_CAP_SXS ? "sxs " : "", +		cap2 & HOST_CAP2_DESO ? "deso " : "", +		cap2 & HOST_CAP2_SADM ? "sadm " : "", +		cap2 & HOST_CAP2_SDS ? "sds " : "",  		cap2 & HOST_CAP2_APST ? "apst " : "",  		cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",  		cap2 & HOST_CAP2_BOH ? "boh " : ""  | 
