#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/dmi.h>
+#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#define DRV_NAME "ahci"
#define DRV_VERSION "3.0"
+/* Enclosure Management Control */
+#define EM_CTRL_MSG_TYPE 0x000f0000
+
+/* Enclosure Management LED Message Type */
+#define EM_MSG_LED_HBA_PORT 0x0000000f
+#define EM_MSG_LED_PMP_SLOT 0x0000ff00
+#define EM_MSG_LED_VALUE 0xffff0000
+#define EM_MSG_LED_VALUE_ACTIVITY 0x00070000
+#define EM_MSG_LED_VALUE_OFF 0xfff80000
+#define EM_MSG_LED_VALUE_ON 0x00010000
+
static int ahci_skip_host_reset;
+static int ahci_ignore_sss;
+
module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
+module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
+MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
+
static int ahci_enable_alpm(struct ata_port *ap,
enum link_pm policy);
static void ahci_disable_alpm(struct ata_port *ap);
size_t size);
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
ssize_t size);
-#define MAX_SLOTS 8
enum {
AHCI_PCI_BAR = 5,
AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
AHCI_RX_FIS_SZ,
+ AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ +
+ AHCI_CMD_TBL_AR_SZ +
+ (AHCI_RX_FIS_SZ * 16),
AHCI_IRQ_ON_SG = (1 << 31),
AHCI_CMD_ATAPI = (1 << 5),
AHCI_CMD_WRITE = (1 << 6),
board_ahci_ign_iferr = 2,
board_ahci_sb600 = 3,
board_ahci_mv = 4,
- board_ahci_sb700 = 5,
+ board_ahci_sb700 = 5, /* for SB700 and SB800 */
board_ahci_mcp65 = 6,
board_ahci_nopmp = 7,
+ board_ahci_yesncq = 8,
+ board_ahci_nosntf = 9,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
HOST_EM_LOC = 0x1c, /* Enclosure Management location */
HOST_EM_CTL = 0x20, /* Enclosure Management Control */
+ HOST_CAP2 = 0x24, /* host capabilities, extended */
/* HOST_CTL bits */
HOST_RESET = (1 << 0), /* reset controller; self-clear */
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */
+ HOST_CAP_SXS = (1 << 5), /* Supports External SATA */
HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
- HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */
+ HOST_CAP_PART = (1 << 13), /* Partial state capable */
+ HOST_CAP_SSC = (1 << 14), /* Slumber state capable */
+ HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */
+ HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */
HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
+ HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_LED = (1 << 25), /* Supports activity LED */
HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */
HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+ /* HOST_CAP2 bits */
+ HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
+ HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
+ HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
+
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
+ PORT_FBS = 0x40, /* FIS-based Switching */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */
PORT_CMD_PMP = (1 << 17), /* PMP attached */
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+ PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */
+ PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */
+ PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */
+ PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */
+ PORT_FBS_SDE = (1 << 2), /* FBS single device error */
+ PORT_FBS_DEC = (1 << 1), /* FBS device error clear */
+ PORT_FBS_EN = (1 << 0), /* Enable FBS */
+
/* hpriv->flags bits */
AHCI_HFLAG_NO_NCQ = (1 << 0),
AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
+ AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
+ AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as
+ link offline */
+ AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */
/* ap->flags bits */
ICH_MAP = 0x90, /* ICH MAP register */
+ /* em constants */
+ EM_MAX_SLOTS = 8,
+ EM_MAX_RETRY = 5,
+
/* em_ctl bits */
EM_CTL_RST = (1 << 9), /* Reset */
EM_CTL_TM = (1 << 8), /* Transmit Message */
struct ahci_host_priv {
unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
u32 saved_port_map; /* saved initial port_map */
u32 em_loc; /* enclosure management location */
};
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
u32 intr_mask; /* interrupts to enable */
- struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info
- * per PM slot */
+ bool fbs_supported; /* set iff FBS is supported */
+ bool fbs_enabled; /* set iff FBS is enabled */
+ int fbs_last_dev; /* save FBS.DEV of last FIS */
+ /* enclosure management info per PM slot */
+ struct ahci_em_priv em_priv[EM_MAX_SLOTS];
};
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+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 int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
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);
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
+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,
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 unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
u32 opts);
#ifdef CONFIG_PM
enum sw_activity val);
static void ahci_init_sw_activity(struct ata_link *link);
+static ssize_t ahci_show_host_caps(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_host_version(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_port_cmd(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);
+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 struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_policy,
&dev_attr_em_message_type,
&dev_attr_em_message,
+ &dev_attr_ahci_host_caps,
+ &dev_attr_ahci_host_cap2,
+ &dev_attr_ahci_host_version,
+ &dev_attr_ahci_port_cmd,
NULL
};
static struct device_attribute *ahci_sdev_attrs[] = {
&dev_attr_sw_activity,
+ &dev_attr_unload_heads,
NULL
};
static struct ata_port_operations ahci_ops = {
.inherits = &sata_pmp_port_ops,
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
+ .qc_defer = ahci_pmp_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.qc_fill_rtf = ahci_qc_fill_rtf,
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
static const struct ata_port_info ahci_port_info[] = {
- /* board_ahci */
+ [board_ahci] =
{
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_vt8251 */
+ [board_ahci_vt8251] =
{
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_vt8251_ops,
},
- /* board_ahci_ign_iferr */
+ [board_ahci_ign_iferr] =
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_sb600 */
+ [board_ahci_sb600] =
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
- AHCI_HFLAG_SECT255),
+ AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
+ AHCI_HFLAG_32BIT_ONLY),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_sb600_ops,
},
- /* board_ahci_mv */
+ [board_ahci_mv] =
{
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
- AHCI_HFLAG_MV_PATA),
+ AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_sb700 */
+ [board_ahci_sb700] = /* for SB700 and SB800 */
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_sb600_ops,
},
- /* board_ahci_mcp65 */
+ [board_ahci_mcp65] =
{
AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_nopmp */
+ [board_ahci_nopmp] =
{
AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ [board_ahci_yesncq] =
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ [board_ahci_nosntf] =
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+ { PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
+ { PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
+ /* AMD */
+ { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
+ /* AMD is using RAID class only for ahci controllers */
+ { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
+
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */
{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */
{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_yesncq }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq }, /* MCP73 */
{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci }, /* MCP89 */
/* SiS */
- { PCI_VDEVICE(SI, 0x1184), board_ahci_nopmp }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x1185), board_ahci_nopmp }, /* SiS 968 */
- { PCI_VDEVICE(SI, 0x0186), board_ahci_nopmp }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
/* Marvell */
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
+ /* Promise */
+ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */
+
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
MODULE_PARM_DESC(ahci_em_messages,
"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
+#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
+static int marvell_enable;
+#else
+static int marvell_enable = 1;
+#endif
+module_param(marvell_enable, int, 0644);
+MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
+
+
static inline int ahci_nr_ports(u32 cap)
{
return (cap & 0x1f) + 1;
WARN_ON(1);
}
+static ssize_t ahci_show_host_caps(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;
+
+ return sprintf(buf, "%x\n", hpriv->cap);
+}
+
+static ssize_t ahci_show_host_cap2(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;
+
+ return sprintf(buf, "%x\n", hpriv->cap2);
+}
+
+static ssize_t ahci_show_host_version(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);
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+
+ return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION));
+}
+
+static ssize_t ahci_show_port_cmd(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);
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
+}
+
/**
* ahci_save_initial_config - Save and fixup initial config values
* @pdev: target PCI device
struct ahci_host_priv *hpriv)
{
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
- u32 cap, port_map;
+ u32 cap, cap2, vers, port_map;
int i;
int mv;
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+ /* CAP2 register is only defined for AHCI 1.2 and later */
+ vers = readl(mmio + HOST_VERSION);
+ if ((vers >> 16) > 1 ||
+ ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
+ hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
+ else
+ hpriv->saved_cap2 = cap2 = 0;
+
/* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
cap &= ~HOST_CAP_PMP;
}
+ if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do SNTF, turning off CAP_SNTF\n");
+ cap &= ~HOST_CAP_SNTF;
+ }
+
if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
port_map != 1) {
dev_printk(KERN_INFO, &pdev->dev,
"MV_AHCI HACK: port_map %x -> %x\n",
port_map,
port_map & mv);
+ dev_printk(KERN_ERR, &pdev->dev,
+ "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
port_map &= mv;
}
/* record values to use during operation */
hpriv->cap = cap;
+ hpriv->cap2 = cap2;
hpriv->port_map = port_map;
}
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
writel(hpriv->saved_cap, mmio + HOST_CAP);
+ if (hpriv->saved_cap2)
+ writel(hpriv->saved_cap2, mmio + HOST_CAP2);
writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
return 0;
}
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
- void __iomem *port_mmio = ahci_port_base(ap);
- int offset = ahci_scr_offset(ap, sc_reg);
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) {
*val = readl(port_mmio + offset);
return -EINVAL;
}
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
- void __iomem *port_mmio = ahci_port_base(ap);
- int offset = ahci_scr_offset(ap, sc_reg);
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) {
writel(val, port_mmio + offset);
writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
/* go ahead and clean out PhyRdy Change from Serror too */
- ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
+ ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
/*
* Clear flag to indicate that we should ignore all PhyRdy
struct ahci_port_priv *pp = ap->private_data;
struct ata_link *link;
struct ahci_em_priv *emp;
+ ssize_t rc;
+ int i;
/* enable FIS reception */
ahci_start_fis_rx(ap);
/* turn on LEDs */
if (ap->flags & ATA_FLAG_EM) {
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
emp = &pp->em_priv[link->pmp];
- ahci_transmit_led_message(ap, emp->led_state, 4);
+
+ /* EM Transmit bit maybe busy during init */
+ for (i = 0; i < EM_MAX_RETRY; i++) {
+ rc = ahci_transmit_led_message(ap,
+ emp->led_state,
+ 4);
+ if (rc == -EBUSY)
+ msleep(1);
+ else
+ break;
+ }
}
}
if (ap->flags & ATA_FLAG_SW_ACTIVITY)
- ata_port_for_each_link(link, ap)
+ ata_for_each_link(link, ap, EDGE)
ahci_init_sw_activity(link);
}
readl(mmio + HOST_CTL); /* flush */
}
- /* reset must complete within 1 second, or
+ /*
+ * to perform host reset, OS should set HOST_RESET
+ * and poll until this bit is read to be "0".
+ * reset must complete within 1 second, or
* the hardware should be considered fried.
*/
- ssleep(1);
+ tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
+ HOST_RESET, 10, 1000);
- tmp = readl(mmio + HOST_CTL);
if (tmp & HOST_RESET) {
dev_printk(KERN_ERR, host->dev,
"controller reset failed (0x%x)\n", tmp);
struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
unsigned long led_message = emp->led_state;
u32 activity_led_state;
+ unsigned long flags;
- led_message &= 0xffff0000;
+ led_message &= EM_MSG_LED_VALUE;
led_message |= ap->port_no | (link->pmp << 8);
/* check to see if we've had activity. If so,
* toggle state of LED and reset timer. If not,
* turn LED to desired idle state.
*/
+ spin_lock_irqsave(ap->lock, flags);
if (emp->saved_activity != emp->activity) {
emp->saved_activity = emp->activity;
/* get the current LED state */
- activity_led_state = led_message & 0x00010000;
+ activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
if (activity_led_state)
activity_led_state = 0;
activity_led_state = 1;
/* clear old state */
- led_message &= 0xfff8ffff;
+ led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
/* toggle state */
led_message |= (activity_led_state << 16);
mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
} else {
/* switch to idle */
- led_message &= 0xfff8ffff;
+ led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
if (emp->blink_policy == BLINK_OFF)
led_message |= (1 << 16);
}
+ spin_unlock_irqrestore(ap->lock, flags);
ahci_transmit_led_message(ap, led_message, 4);
}
void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
u32 em_ctl;
u32 message[] = {0, 0};
- unsigned int flags;
+ unsigned long flags;
int pmp;
struct ahci_em_priv *emp;
/* get the slot number from the message */
- pmp = (state & 0x0000ff00) >> 8;
- if (pmp < MAX_SLOTS)
+ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+ if (pmp < EM_MAX_SLOTS)
emp = &pp->em_priv[pmp];
else
return -EINVAL;
em_ctl = readl(mmio + HOST_EM_CTL);
if (em_ctl & EM_CTL_TM) {
spin_unlock_irqrestore(ap->lock, flags);
- return -EINVAL;
+ return -EBUSY;
}
/*
message[0] |= (4 << 8);
/* ignore 0:4 of byte zero, fill in port info yourself */
- message[1] = ((state & 0xfffffff0) | ap->port_no);
+ message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
/* write message to EM_LOC */
writel(message[0], mmio + hpriv->em_loc);
writel(message[1], mmio + hpriv->em_loc+4);
/* save off new led state for port/slot */
- emp->led_state = message[1];
+ emp->led_state = state;
/*
* tell hardware to transmit the message
struct ahci_em_priv *emp;
int rc = 0;
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
emp = &pp->em_priv[link->pmp];
rc += sprintf(buf, "%lx\n", emp->led_state);
}
state = simple_strtoul(buf, NULL, 0);
/* get the slot number from the message */
- pmp = (state & 0x0000ff00) >> 8;
- if (pmp < MAX_SLOTS)
+ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+ if (pmp < EM_MAX_SLOTS)
emp = &pp->em_priv[pmp];
else
return -EINVAL;
* activity led through em_message
*/
if (emp->blink_policy)
- state &= 0xfff8ffff;
+ state &= ~EM_MSG_LED_VALUE_ACTIVITY;
return ahci_transmit_led_message(ap, state, size);
}
link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
/* set the LED to OFF */
- port_led_state &= 0xfff80000;
+ 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);
} else {
link->flags |= ATA_LFLAG_SW_ACTIVITY;
if (val == BLINK_OFF) {
/* set LED to ON for idle */
- port_led_state &= 0xfff80000;
+ port_led_state &= EM_MSG_LED_VALUE_OFF;
port_led_state |= (ap->port_no | (link->pmp << 8));
- port_led_state |= 0x00010000; /* check this */
+ port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
ahci_transmit_led_message(ap, port_led_state, 4);
}
}
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
-static int ahci_kick_engine(struct ata_port *ap, int force_restart)
+static int ahci_kick_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
int busy, rc;
- /* do we need to kick the port? */
- busy = status & (ATA_BUSY | ATA_DRQ);
- if (!busy && !force_restart)
- return 0;
-
/* stop engine */
rc = ahci_stop_engine(ap);
if (rc)
goto out_restart;
- /* need to do CLO? */
- if (!busy) {
+ /* need to do CLO?
+ * always do CLO if PMP is attached (AHCI-1.3 9.2)
+ */
+ busy = status & (ATA_BUSY | ATA_DRQ);
+ if (!busy && !sata_pmp_attached(ap)) {
rc = 0;
goto out_restart;
}
tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
1, timeout_msec);
if (tmp & 0x1) {
- ahci_kick_engine(ap, 1);
+ ahci_kick_engine(ap);
return -EBUSY;
}
} else
int (*check_ready)(struct ata_link *link))
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
DPRINTK("ENTER\n");
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_kick_engine(ap, 1);
+ rc = ahci_kick_engine(ap);
if (rc && rc != -EOPNOTSUPP)
ata_link_printk(link, KERN_WARNING,
"failed to reset engine (errno=%d)\n", rc);
/* wait for link to become ready */
rc = ata_wait_after_reset(link, deadline, check_ready);
- /* link occupied, -ENODEV too is an error */
- if (rc) {
+ if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
+ /*
+ * Workaround for cases where link online status can't
+ * be trusted. Treat device readiness timeout as link
+ * offline.
+ */
+ ata_link_printk(link, KERN_INFO,
+ "device not ready, treating as offline\n");
+ *class = ATA_DEV_NONE;
+ } else if (rc) {
+ /* link occupied, -ENODEV too is an error */
reason = "device not ready";
goto fail;
- }
- *class = ahci_dev_classify(ap);
+ } else
+ *class = ahci_dev_classify(ap);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
irq_sts = readl(port_mmio + PORT_IRQ_STAT);
if (irq_sts & PORT_IRQ_BAD_PMP) {
ata_link_printk(link, KERN_WARNING,
- "failed due to HW bug, retry pmp=0\n");
+ "applying SB600 PMP SRST workaround "
+ "and retrying\n");
rc = ahci_do_softreset(link, class, 0, deadline,
ahci_check_ready);
}
rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
ahci_check_ready);
if (rc)
- ahci_kick_engine(ap, 0);
+ ahci_kick_engine(ap);
}
return rc;
}
return si;
}
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+
+ if (!sata_pmp_attached(ap) || pp->fbs_enabled)
+ return ata_std_qc_defer(qc);
+ else
+ return sata_pmp_qc_defer_cmd_switch(qc);
+}
+
static void ahci_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
ahci_fill_cmd_slot(pp, qc->tag, opts);
}
+static void ahci_fbs_dec_intr(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ int retries = 3;
+
+ DPRINTK("ENTER\n");
+ BUG_ON(!pp->fbs_enabled);
+
+ /* time to wait for DEC is not specified by AHCI spec,
+ * add a retry loop for safety.
+ */
+ writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ while ((fbs & PORT_FBS_DEC) && retries--) {
+ udelay(1);
+ fbs = readl(port_mmio + PORT_FBS);
+ }
+
+ if (fbs & PORT_FBS_DEC)
+ dev_printk(KERN_ERR, ap->host->dev,
+ "failed to clear device error\n");
+}
+
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ata_link *link = NULL;
struct ata_queued_cmd *active_qc;
struct ata_eh_info *active_ehi;
+ bool fbs_need_dec = false;
u32 serror;
- /* determine active link */
- ata_port_for_each_link(link, ap)
- if (ata_link_active(link))
- break;
+ /* determine active link with error */
+ if (pp->fbs_enabled) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ 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])) {
+ link = &ap->pmp_link[pmp];
+ fbs_need_dec = true;
+ }
+
+ } else
+ ata_for_each_link(link, ap, EDGE)
+ if (ata_link_active(link))
+ break;
+
if (!link)
link = &ap->link;
ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
/* AHCI needs SError cleared; otherwise, it might lock up */
- ahci_scr_read(ap, SCR_ERROR, &serror);
- ahci_scr_write(ap, SCR_ERROR, serror);
+ ahci_scr_read(&ap->link, SCR_ERROR, &serror);
+ ahci_scr_write(&ap->link, SCR_ERROR, serror);
host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */
}
if (irq_stat & PORT_IRQ_IF_ERR) {
- host_ehi->err_mask |= AC_ERR_ATA_BUS;
- host_ehi->action |= ATA_EH_RESET;
+ if (fbs_need_dec)
+ active_ehi->err_mask |= AC_ERR_DEV;
+ else {
+ host_ehi->err_mask |= AC_ERR_ATA_BUS;
+ host_ehi->action |= ATA_EH_RESET;
+ }
+
ata_ehi_push_desc(host_ehi, "interface fatal error");
}
if (irq_stat & PORT_IRQ_FREEZE)
ata_port_freeze(ap);
- else
+ else if (fbs_need_dec) {
+ ata_link_abort(link);
+ ahci_fbs_dec_intr(ap);
+ } else
ata_port_abort(ap);
}
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;
+ u32 status, qc_active = 0;
int rc;
status = readl(port_mmio + PORT_IRQ_STAT);
if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
(status & PORT_IRQ_PHYRDY)) {
status &= ~PORT_IRQ_PHYRDY;
- ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
+ ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
}
if (unlikely(status & PORT_IRQ_ERROR)) {
/* If the 'N' bit in word 0 of the FIS is set,
* we just received asynchronous notification.
* Tell libata about it.
+ *
+ * Lack of SNotification should not appear in
+ * ahci 1.2, so the workaround is unnecessary
+ * when FBS is enabled.
*/
- const __le32 *f = pp->rx_fis + RX_FIS_SDB;
- u32 f0 = le32_to_cpu(f[0]);
-
- if (f0 & (1 << 15))
- sata_async_notification(ap);
+ if (pp->fbs_enabled)
+ WARN_ON_ONCE(1);
+ else {
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
}
}
- /* pp->active_link is valid iff any command is in flight */
- if (ap->qc_active && pp->active_link->sactive)
- qc_active = readl(port_mmio + PORT_SCR_ACT);
- else
- qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+ /* pp->active_link is not reliable once FBS is enabled, both
+ * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
+ * NCQ and non-NCQ commands may be in flight at the same time.
+ */
+ if (pp->fbs_enabled) {
+ if (ap->qc_active) {
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
+ }
+ } else {
+ /* pp->active_link is valid iff any command is in flight */
+ if (ap->qc_active && pp->active_link->sactive)
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ else
+ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+ }
rc = ata_qc_complete_multiple(ap, qc_active);
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+
+ if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+ fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
+ writel(fbs, port_mmio + PORT_FBS);
+ pp->fbs_last_dev = qc->dev->link->pmp;
+ }
+
writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
ahci_sw_activity(qc->dev->link);
struct ahci_port_priv *pp = qc->ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ if (pp->fbs_enabled)
+ d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+
ata_tf_from_fis(d2h_fis, &qc->result_tf);
return true;
}
/* make DMA engine forget about the failed command */
if (qc->flags & ATA_QCFLAG_FAILED)
- ahci_kick_engine(ap, 1);
+ ahci_kick_engine(ap);
+}
+
+static void ahci_enable_fbs(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+ int rc;
+
+ if (!pp->fbs_supported)
+ return;
+
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN) {
+ pp->fbs_enabled = true;
+ pp->fbs_last_dev = -1; /* initialization */
+ return;
+ }
+
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ 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");
+ pp->fbs_enabled = true;
+ pp->fbs_last_dev = -1; /* initialization */
+ } else
+ dev_printk(KERN_ERR, ap->host->dev, "Failed to enable FBS\n");
+
+ ahci_start_engine(ap);
+}
+
+static void ahci_disable_fbs(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+ int rc;
+
+ if (!pp->fbs_supported)
+ return;
+
+ fbs = readl(port_mmio + PORT_FBS);
+ if ((fbs & PORT_FBS_EN) == 0) {
+ pp->fbs_enabled = false;
+ return;
+ }
+
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ 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");
+ else {
+ dev_printk(KERN_INFO, ap->host->dev, "FBS is disabled.\n");
+ pp->fbs_enabled = false;
+ }
+
+ ahci_start_engine(ap);
}
static void ahci_pmp_attach(struct ata_port *ap)
cmd |= PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
+ ahci_enable_fbs(ap);
+
pp->intr_mask |= PORT_IRQ_BAD_PMP;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
struct ahci_port_priv *pp = ap->private_data;
u32 cmd;
+ ahci_disable_fbs(ap);
+
cmd = readl(port_mmio + PORT_CMD);
cmd &= ~PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 ctl;
+ if (mesg.event & PM_EVENT_SUSPEND &&
+ hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "BIOS update required for suspend/resume\n");
+ return -EIO;
+ }
+
if (mesg.event & PM_EVENT_SLEEP) {
/* AHCI spec rev1.1 section 8.3.3:
* Software must disable interrupts prior to requesting a
static int ahci_port_start(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct device *dev = ap->host->dev;
struct ahci_port_priv *pp;
void *mem;
dma_addr_t mem_dma;
+ size_t dma_sz, rx_fis_sz;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
- mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
+ /* check FBS capability */
+ if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd = readl(port_mmio + PORT_CMD);
+ if (cmd & PORT_CMD_FBSCP)
+ pp->fbs_supported = true;
+ else
+ dev_printk(KERN_WARNING, dev,
+ "The port is not capable of FBS\n");
+ }
+
+ if (pp->fbs_supported) {
+ dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+ rx_fis_sz = AHCI_RX_FIS_SZ * 16;
+ } else {
+ dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+ rx_fis_sz = AHCI_RX_FIS_SZ;
+ }
+
+ mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+ memset(mem, 0, dma_sz);
/*
* First item in chunk of DMA memory: 32-slot command table,
pp->rx_fis = mem;
pp->rx_fis_dma = mem_dma;
- mem += AHCI_RX_FIS_SZ;
- mem_dma += AHCI_RX_FIS_SZ;
+ mem += rx_fis_sz;
+ mem_dma += rx_fis_sz;
/*
* Third item: data area for storing a single command
int rc;
if (using_dac &&
- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"64-bit DMA enable failed\n");
}
}
} else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit consistent DMA enable failed\n");
struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 vers, cap, impl, speed;
+ u32 vers, cap, cap2, impl, speed;
const char *speed_s;
u16 cc;
const char *scc_s;
vers = readl(mmio + HOST_VERSION);
cap = hpriv->cap;
+ cap2 = hpriv->cap2;
impl = hpriv->port_map;
speed = (cap >> 20) & 0xf;
speed_s = "1.5";
else if (speed == 2)
speed_s = "3";
+ else if (speed == 3)
+ speed_s = "6";
else
speed_s = "?";
"flags: "
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s"
- "%s\n"
+ "%s%s%s%s%s%s\n"
,
- cap & (1 << 31) ? "64bit " : "",
- cap & (1 << 30) ? "ncq " : "",
- cap & (1 << 29) ? "sntf " : "",
- cap & (1 << 28) ? "ilck " : "",
- cap & (1 << 27) ? "stag " : "",
- cap & (1 << 26) ? "pm " : "",
- cap & (1 << 25) ? "led " : "",
-
- cap & (1 << 24) ? "clo " : "",
- cap & (1 << 19) ? "nz " : "",
- cap & (1 << 18) ? "only " : "",
- cap & (1 << 17) ? "pmp " : "",
- cap & (1 << 15) ? "pio " : "",
- cap & (1 << 14) ? "slum " : "",
- cap & (1 << 13) ? "part " : "",
- cap & (1 << 6) ? "ems ": ""
+ cap & HOST_CAP_64 ? "64bit " : "",
+ cap & HOST_CAP_NCQ ? "ncq " : "",
+ cap & HOST_CAP_SNTF ? "sntf " : "",
+ cap & HOST_CAP_MPS ? "ilck " : "",
+ cap & HOST_CAP_SSS ? "stag " : "",
+ cap & HOST_CAP_ALPM ? "pm " : "",
+ cap & HOST_CAP_LED ? "led " : "",
+ cap & HOST_CAP_CLO ? "clo " : "",
+ cap & HOST_CAP_ONLY ? "only " : "",
+ cap & HOST_CAP_PMP ? "pmp " : "",
+ cap & HOST_CAP_FBS ? "fbs " : "",
+ cap & HOST_CAP_PIO_MULTI ? "pio " : "",
+ cap & HOST_CAP_SSC ? "slum " : "",
+ cap & HOST_CAP_PART ? "part " : "",
+ cap & HOST_CAP_CCC ? "ccc " : "",
+ cap & HOST_CAP_EMS ? "ems " : "",
+ cap & HOST_CAP_SXS ? "sxs " : "",
+ cap2 & HOST_CAP2_APST ? "apst " : "",
+ cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
+ cap2 & HOST_CAP2_BOH ? "boh " : ""
);
}
}
}
+/* only some SB600 ahci controllers can do 64bit DMA */
+static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * The oldest version known to be broken is 0901 and
+ * working is 1501 which was released on 2007-10-26.
+ * Enable 64bit DMA on 1501 and anything newer.
+ *
+ * Please read bko#9412 for more info.
+ */
+ {
+ .ident = "ASUS M2A-VM",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
+ },
+ .driver_data = "20071026", /* yyyymmdd */
+ },
+ /*
+ * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
+ * support 64bit DMA.
+ *
+ * BIOS versions earlier than 1.5 had the Manufacturer DMI
+ * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
+ * This spelling mistake was fixed in BIOS version 1.5, so
+ * 1.5 and later have the Manufacturer as
+ * "MICRO-STAR INTERNATIONAL CO.,LTD".
+ * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
+ *
+ * BIOS versions earlier than 1.9 had a Board Product Name
+ * DMI field of "MS-7376". This was changed to be
+ * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
+ * match on DMI_BOARD_NAME of "MS-7376".
+ */
+ {
+ .ident = "MSI K9A2 Platinum",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "MICRO-STAR INTER"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
+ },
+ },
+ { }
+ };
+ const struct dmi_system_id *match;
+ int year, month, date;
+ char buf[9];
+
+ match = dmi_first_match(sysids);
+ if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
+ !match)
+ return false;
+
+ if (!match->driver_data)
+ goto enable_64bit;
+
+ dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+
+ if (strcmp(buf, match->driver_data) >= 0)
+ goto enable_64bit;
+ else {
+ dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, "
+ "forcing 32bit DMA, update BIOS\n", match->ident);
+ return false;
+ }
+
+enable_64bit:
+ dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n",
+ match->ident);
+ return true;
+}
+
+static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id broken_systems[] = {
+ {
+ .ident = "HP Compaq nx6310",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x1FUL,
+ },
+ {
+ .ident = "HP Compaq 6720s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x1FUL,
+ },
+
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
+
+ if (dmi) {
+ unsigned long slot = (unsigned long)dmi->driver_data;
+ /* apply the quirk only to on-board controllers */
+ return slot == PCI_SLOT(pdev->devfn);
+ }
+
+ return false;
+}
+
+static bool ahci_broken_suspend(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * On HP dv[4-6] and HDX18 with earlier BIOSen, link
+ * to the harddisk doesn't become online after
+ * resuming from STR. Warn and fail suspend.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=12276
+ *
+ * Use dates instead of versions to match as HP is
+ * apparently recycling both product and version
+ * strings.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=15462
+ */
+ {
+ .ident = "dv4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP Pavilion dv4 Notebook PC"),
+ },
+ .driver_data = "20090105", /* F.30 */
+ },
+ {
+ .ident = "dv5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP Pavilion dv5 Notebook PC"),
+ },
+ .driver_data = "20090506", /* F.16 */
+ },
+ {
+ .ident = "dv6",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP Pavilion dv6 Notebook PC"),
+ },
+ .driver_data = "20090423", /* F.21 */
+ },
+ {
+ .ident = "HDX18",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP HDX18 Notebook PC"),
+ },
+ .driver_data = "20090430", /* F.23 */
+ },
+ /*
+ * Acer eMachines G725 has the same problem. BIOS
+ * V1.03 is known to be broken. V3.04 is known to
+ * work. Inbetween, there are V1.06, V2.06 and V3.03
+ * that we don't have much idea about. For now,
+ * blacklist anything older than V3.04.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=15104
+ */
+ {
+ .ident = "G725",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
+ },
+ .driver_data = "20091216", /* V3.04 */
+ },
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ int year, month, date;
+ char buf[9];
+
+ if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
+ return false;
+
+ dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+
+ return strcmp(buf, dmi->driver_data) < 0;
+}
+
+static bool ahci_broken_online(struct pci_dev *pdev)
+{
+#define ENCODE_BUSDEVFN(bus, slot, func) \
+ (void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * There are several gigabyte boards which use
+ * SIMG5723s configured as hardware RAID. Certain
+ * 5723 firmware revisions shipped there keep the link
+ * online but fail to answer properly to SRST or
+ * IDENTIFY when no device is attached downstream
+ * causing libata to retry quite a few times leading
+ * to excessive detection delay.
+ *
+ * As these firmwares respond to the second reset try
+ * with invalid device signature, considering unknown
+ * sig as offline works around the problem acceptably.
+ */
+ {
+ .ident = "EP45-DQ6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
+ },
+ .driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
+ },
+ {
+ .ident = "EP45-DS5",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
+ },
+ .driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
+ },
+ { } /* terminate list */
+ };
+#undef ENCODE_BUSDEVFN
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int val;
+
+ if (!dmi)
+ return false;
+
+ val = (unsigned long)dmi->driver_data;
+
+ return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
+}
+
+#ifdef CONFIG_ATA_ACPI
+static void ahci_gtf_filter_workaround(struct ata_host *host)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * Aspire 3810T issues a bunch of SATA enable commands
+ * via _GTF including an invalid one and one which is
+ * rejected by the device. Among the successful ones
+ * is FPDMA non-zero offset enable which when enabled
+ * only on the drive side leads to NCQ command
+ * failures. Filter it out.
+ */
+ {
+ .ident = "Aspire 3810T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
+ },
+ .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
+ },
+ { }
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int filter;
+ int i;
+
+ if (!dmi)
+ return;
+
+ filter = (unsigned long)dmi->driver_data;
+ dev_printk(KERN_INFO, host->dev,
+ "applying extra ACPI _GTF filter 0x%x for %s\n",
+ filter, dmi->ident);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
+ struct ata_device *dev;
+
+ ata_for_each_link(link, ap, EDGE)
+ ata_for_each_dev(dev, link, ALL)
+ dev->gtf_filter |= filter;
+ }
+}
+#else
+static inline void ahci_gtf_filter_workaround(struct ata_host *host)
+{}
+#endif
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* The AHCI driver can only drive the SATA ports, the PATA driver
+ can drive them all so if both drivers are selected make sure
+ AHCI stays out of the way */
+ if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
+ return -ENODEV;
+
+ /* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
+ * At the moment, we can only use the AHCI mode. Let the users know
+ * that for SAS drives they're out of luck.
+ */
+ if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
+ dev_printk(KERN_INFO, &pdev->dev, "PDC42819 "
+ "can only drive SATA devices with this driver\n");
+
/* acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
(pdev->revision == 0xa1 || pdev->revision == 0xa2))
hpriv->flags |= AHCI_HFLAG_NO_MSI;
+ /* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
+ if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
+ hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
+
+ /* only some SB600s can do 64bit DMA */
+ if (ahci_sb600_enable_64bit(pdev))
+ hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
+
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
pci_intx(pdev, 1);
ahci_save_initial_config(pdev, hpriv);
/* prepare host */
- if (hpriv->cap & HOST_CAP_NCQ)
+ if (hpriv->cap & HOST_CAP_NCQ) {
pi.flags |= ATA_FLAG_NCQ;
+ /* Auto-activate optimization is supposed to be supported on
+ all AHCI controllers indicating NCQ support, but it seems
+ to be broken at least on some NVIDIA MCP79 chipsets.
+ Until we get info on which NVIDIA chipsets don't have this
+ issue, if any, disable AA on all NVIDIA AHCIs. */
+ if (pdev->vendor != PCI_VENDOR_ID_NVIDIA)
+ pi.flags |= ATA_FLAG_FPDMA_AA;
+ }
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
u32 em_loc = readl(mmio + HOST_EM_LOC);
u32 em_ctl = readl(mmio + HOST_EM_CTL);
- messages = (em_ctl & 0x000f0000) >> 16;
+ messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
/* we only support LED message type right now */
if ((messages & 0x01) && (ahci_em_messages == 1)) {
}
}
+ if (ahci_broken_system_poweroff(pdev)) {
+ pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
+ dev_info(&pdev->dev,
+ "quirky BIOS, skipping spindown on poweroff\n");
+ }
+
+ if (ahci_broken_suspend(pdev)) {
+ hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "BIOS update required for suspend/resume\n");
+ }
+
+ if (ahci_broken_online(pdev)) {
+ hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
+ dev_info(&pdev->dev,
+ "online status unreliable, applying workaround\n");
+ }
+
/* CAP.NP sometimes indicate the index of the last enabled
* port, at other times, that of the last possible port, so
* determining the maximum port number requires looking at
host->iomap = pcim_iomap_table(pdev);
host->private_data = hpriv;
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+
if (pi.flags & ATA_FLAG_EM)
ahci_reset_em(host);
/* apply workaround for ASUS P5W DH Deluxe mainboard */
ahci_p5wdh_workaround(host);
+ /* apply gtf filter quirk */
+ ahci_gtf_filter_workaround(host);
+
/* initialize adapter */
rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)