aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-05-15 11:26:53 -0400
committerJeff Garzik <jeff@garzik.org>2006-05-15 11:26:53 -0400
commitefa6e7e9d40fe01406d889a5bed62f2e0da49bff (patch)
tree7f856e4c4264a2e51768610f4b883ef023152f27 /drivers
parent5006ecc2d5073d4e52f54381fd0fee1575d4ce22 (diff)
parentaee10a03eb3e240bfd1a6f91e06ce82df47c5c58 (diff)
Merge branch 'for-jeff' of git://htj.dyndns.org/libata-tj into tejun-merge
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/ahci.c346
-rw-r--r--drivers/scsi/ata_piix.c14
-rw-r--r--drivers/scsi/libata-bmdma.c143
-rw-r--r--drivers/scsi/libata-core.c1857
-rw-r--r--drivers/scsi/libata-eh.c1311
-rw-r--r--drivers/scsi/libata-scsi.c272
-rw-r--r--drivers/scsi/libata.h20
-rw-r--r--drivers/scsi/pdc_adma.c8
-rw-r--r--drivers/scsi/sata_mv.c28
-rw-r--r--drivers/scsi/sata_nv.c4
-rw-r--r--drivers/scsi/sata_promise.c14
-rw-r--r--drivers/scsi/sata_qstor.c11
-rw-r--r--drivers/scsi/sata_sil.c57
-rw-r--r--drivers/scsi/sata_sil24.c394
-rw-r--r--drivers/scsi/sata_sx4.c13
-rw-r--r--drivers/scsi/sata_vsc.c15
-rw-r--r--drivers/scsi/scsi.c18
-rw-r--r--drivers/scsi/scsi_error.c3
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_priv.h1
20 files changed, 3452 insertions, 1079 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index d23f00230a7..45fd71d8012 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -56,12 +56,15 @@ enum {
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
AHCI_USE_CLUSTERING = 0,
- AHCI_CMD_SLOT_SZ = 32 * 32,
+ AHCI_MAX_CMDS = 32,
+ AHCI_CMD_SZ = 32,
+ AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
AHCI_RX_FIS_SZ = 256,
- AHCI_CMD_TBL_HDR = 0x80,
AHCI_CMD_TBL_CDB = 0x40,
- AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
- AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
+ AHCI_CMD_TBL_HDR_SZ = 0x80,
+ AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+ 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_IRQ_ON_SG = (1 << 31),
AHCI_CMD_ATAPI = (1 << 5),
@@ -71,6 +74,7 @@ enum {
AHCI_CMD_CLR_BUSY = (1 << 10),
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
+ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
board_ahci_vt8251 = 1,
@@ -88,8 +92,9 @@ enum {
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */
- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
+ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
@@ -128,15 +133,16 @@ enum {
PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
- PORT_IRQ_FATAL = PORT_IRQ_TF_ERR |
- PORT_IRQ_HBUS_ERR |
- PORT_IRQ_HBUS_DATA_ERR |
- PORT_IRQ_IF_ERR,
- DEF_PORT_IRQ = PORT_IRQ_FATAL | PORT_IRQ_PHYRDY |
- PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE |
- PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS |
- PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS |
- PORT_IRQ_D2H_REG_FIS,
+ PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
+ PORT_IRQ_IF_ERR |
+ PORT_IRQ_CONNECT |
+ PORT_IRQ_UNK_FIS,
+ PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
+ PORT_IRQ_TF_ERR |
+ PORT_IRQ_HBUS_DATA_ERR,
+ DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
/* PORT_CMD bits */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
@@ -185,7 +191,6 @@ struct ahci_port_priv {
dma_addr_t cmd_slot_dma;
void *cmd_tbl;
dma_addr_t cmd_tbl_dma;
- struct ahci_sg *cmd_tbl_sg;
void *rx_fis;
dma_addr_t rx_fis_dma;
};
@@ -197,13 +202,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
static void ahci_irq_clear(struct ata_port *ap);
-static void ahci_eng_timeout(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
-static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+static void ahci_freeze(struct ata_port *ap);
+static void ahci_thaw(struct ata_port *ap);
+static void ahci_error_handler(struct ata_port *ap);
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static void ahci_remove_one (struct pci_dev *pdev);
static struct scsi_host_template ahci_sht = {
@@ -211,7 +218,8 @@ static struct scsi_host_template ahci_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = AHCI_MAX_CMDS - 1,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = AHCI_MAX_SG,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
@@ -237,14 +245,18 @@ static const struct ata_port_operations ahci_ops = {
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
- .eng_timeout = ahci_eng_timeout,
-
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
+ .freeze = ahci_freeze,
+ .thaw = ahci_thaw,
+
+ .error_handler = ahci_error_handler,
+ .post_internal_cmd = ahci_post_internal_cmd,
+
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
@@ -390,8 +402,6 @@ static int ahci_port_start(struct ata_port *ap)
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
- pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR;
-
ap->private_data = pp;
if (hpriv->cap & HOST_CAP_64)
@@ -524,12 +534,17 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts)
{
- pp->cmd_slot[0].opts = cpu_to_le32(opts);
- pp->cmd_slot[0].status = 0;
- pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
- pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+ dma_addr_t cmd_tbl_dma;
+
+ cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
+
+ pp->cmd_slot[tag].opts = cpu_to_le32(opts);
+ pp->cmd_slot[tag].status = 0;
+ 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);
}
static int ahci_clo(struct ata_port *ap)
@@ -567,7 +582,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
DPRINTK("ENTER\n");
- if (!sata_dev_present(ap)) {
+ if (ata_port_offline(ap)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
return 0;
@@ -597,11 +612,12 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
/* restart engine */
ahci_start_engine(ap);
- ata_tf_init(ap, &tf, 0);
+ ata_tf_init(ap->device, &tf);
fis = pp->cmd_tbl;
/* issue the first D2H Register FIS */
- ahci_fill_cmd_slot(pp, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+ ahci_fill_cmd_slot(pp, 0,
+ cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
tf.ctl |= ATA_SRST;
ata_tf_to_fis(&tf, fis, 0);
@@ -620,7 +636,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
msleep(1);
/* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, cmd_fis_len);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
tf.ctl &= ~ATA_SRST;
ata_tf_to_fis(&tf, fis, 0);
@@ -640,7 +656,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
msleep(150);
*class = ATA_DEV_NONE;
- if (sata_dev_present(ap)) {
+ if (ata_port_online(ap)) {
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
rc = -EIO;
reason = "device not ready";
@@ -655,8 +671,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
fail_restart:
ahci_start_engine(ap);
fail:
- printk(KERN_ERR "ata%u: softreset failed (%s)\n",
- ap->id, reason);
+ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
@@ -670,7 +685,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
rc = sata_std_hardreset(ap, class);
ahci_start_engine(ap);
- if (rc == 0)
+ if (rc == 0 && ata_port_online(ap))
*class = ahci_dev_classify(ap);
if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
@@ -726,9 +741,8 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
ata_tf_from_fis(d2h_fis, tf);
}
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
{
- struct ahci_port_priv *pp = qc->ap->private_data;
struct scatterlist *sg;
struct ahci_sg *ahci_sg;
unsigned int n_sg = 0;
@@ -738,7 +752,7 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
/*
* Next, the S/G list.
*/
- ahci_sg = pp->cmd_tbl_sg;
+ ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
ata_for_each_sg(sg, qc) {
dma_addr_t addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
@@ -759,6 +773,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
int is_atapi = is_atapi_taskfile(&qc->tf);
+ void *cmd_tbl;
u32 opts;
const u32 cmd_fis_len = 5; /* five dwords */
unsigned int n_elem;
@@ -767,16 +782,17 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
* Fill in command table information. First, the header,
* a SATA Register - Host to Device command FIS.
*/
- ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
+ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+ ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
if (is_atapi) {
- memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
- memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
- qc->dev->cdb_len);
+ memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+ memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
}
n_elem = 0;
if (qc->flags & ATA_QCFLAG_DMAMAP)
- n_elem = ahci_fill_sg(qc);
+ n_elem = ahci_fill_sg(qc, cmd_tbl);
/*
* Fill in command slot information.
@@ -787,112 +803,123 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
if (is_atapi)
opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
- ahci_fill_cmd_slot(pp, opts);
+ ahci_fill_cmd_slot(pp, qc->tag, opts);
}
-static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
+static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 tmp;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 serror;
- if ((ap->device[0].class != ATA_DEV_ATAPI) ||
- ((irq_stat & PORT_IRQ_TF_ERR) == 0))
- printk(KERN_WARNING "ata%u: port reset, "
- "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n",
- ap->id,
- irq_stat,
- readl(mmio + HOST_IRQ_STAT),
- readl(port_mmio + PORT_IRQ_STAT),
- readl(port_mmio + PORT_CMD),
- readl(port_mmio + PORT_TFDATA),
- readl(port_mmio + PORT_SCR_STAT),
- readl(port_mmio + PORT_SCR_ERR));
-
- /* stop DMA */
- ahci_stop_engine(ap);
+ ata_ehi_clear_desc(ehi);
- /* clear SATA phy error, if any */
- tmp = readl(port_mmio + PORT_SCR_ERR);
- writel(tmp, port_mmio + PORT_SCR_ERR);
+ /* AHCI needs SError cleared; otherwise, it might lock up */
+ serror = ahci_scr_read(ap, SCR_ERROR);
+ ahci_scr_write(ap, SCR_ERROR, serror);
- /* if DRQ/BSY is set, device needs to be reset.
- * if so, issue COMRESET
- */
- tmp = readl(port_mmio + PORT_TFDATA);
- if (tmp & (ATA_BUSY | ATA_DRQ)) {
- writel(0x301, port_mmio + PORT_SCR_CTL);
- readl(port_mmio + PORT_SCR_CTL); /* flush */
- udelay(10);
- writel(0x300, port_mmio + PORT_SCR_CTL);
- readl(port_mmio + PORT_SCR_CTL); /* flush */
+ /* analyze @irq_stat */
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+
+ if (irq_stat & PORT_IRQ_TF_ERR)
+ err_mask |= AC_ERR_DEV;
+
+ if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
+ err_mask |= AC_ERR_HOST_BUS;
+ action |= ATA_EH_SOFTRESET;
}
- /* re-start DMA */
- ahci_start_engine(ap);
-}
+ if (irq_stat & PORT_IRQ_IF_ERR) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", interface fatal error");
+ }
-static void ahci_eng_timeout(struct ata_port *ap)
-{
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- struct ata_queued_cmd *qc;
- unsigned long flags;
+ if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+ "connection status changed" : "PHY RDY changed");
+ }
- printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id);
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
- spin_lock_irqsave(&host_set->lock, flags);
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+ unk[0], unk[1], unk[2], unk[3]);
+ }
- ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
- qc = ata_qc_from_tag(ap, ap->active_tag);
- qc->err_mask |= AC_ERR_TIMEOUT;
+ /* okay, let's hand over to EH */
+ ehi->serror |= serror;
+ ehi->action |= action;
- spin_unlock_irqrestore(&host_set->lock, flags);
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
- ata_eh_qc_complete(qc);
+ if (irq_stat & PORT_IRQ_FREEZE)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
}
-static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+static void ahci_host_intr(struct ata_port *ap)
{
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 status, serr, ci;
-
- serr = readl(port_mmio + PORT_SCR_ERR);
- writel(serr, port_mmio + PORT_SCR_ERR);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ u32 status, qc_active;
+ int rc;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
- ci = readl(port_mmio + PORT_CMD_ISSUE);
- if (likely((ci & 0x1) == 0)) {
- if (qc) {
- WARN_ON(qc->err_mask);
- ata_qc_complete(qc);
- qc = NULL;
- }
+ if (unlikely(status & PORT_IRQ_ERROR)) {
+ ahci_error_intr(ap, status);
+ return;
}
- if (status & PORT_IRQ_FATAL) {
- unsigned int err_mask;
- if (status & PORT_IRQ_TF_ERR)
- err_mask = AC_ERR_DEV;
- else if (status & PORT_IRQ_IF_ERR)
- err_mask = AC_ERR_ATA_BUS;
- else
- err_mask = AC_ERR_HOST_BUS;
-
- /* command processing has stopped due to error; restart */
- ahci_restart_port(ap, status);
-
- if (qc) {
- qc->err_mask |= err_mask;
- ata_qc_complete(qc);
- }
+ if (ap->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, NULL);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
+ }
+
+ /* hmmm... a spurious interupt */
+
+ /* some devices send D2H reg with I bit set during NCQ command phase */
+ if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+ return;
+
+ /* ignore interim PIO setup fis interrupts */
+ if (ata_tag_valid(ap->active_tag)) {
+ struct ata_queued_cmd *qc =
+ ata_qc_from_tag(ap, ap->active_tag);
+
+ if (qc && qc->tf.protocol == ATA_PROT_PIO &&
+ (status & PORT_IRQ_PIOS_FIS))
+ return;
}
- return 1;
+ if (ata_ratelimit())
+ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+ "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
+ status, ap->active_tag, ap->sactive);
}
static void ahci_irq_clear(struct ata_port *ap)
@@ -900,7 +927,7 @@ static void ahci_irq_clear(struct ata_port *ap)
/* TODO */
}
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
struct ahci_host_priv *hpriv;
@@ -929,14 +956,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
ap = host_set->ports[i];
if (ap) {
- struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (!ahci_host_intr(ap, qc))
- if (ata_ratelimit())
- dev_printk(KERN_WARNING, host_set->dev,
- "unhandled interrupt on port %u\n",
- i);
-
+ ahci_host_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
@@ -953,7 +973,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
handled = 1;
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host_set->lock);
VPRINTK("EXIT\n");
@@ -965,12 +985,64 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- writel(1, port_mmio + PORT_CMD_ISSUE);
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+ writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
readl(port_mmio + PORT_CMD_ISSUE); /* flush */
return 0;
}
+static void ahci_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ /* turn IRQ off */
+ writel(0, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ u32 tmp;
+
+ /* clear IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+ writel(1 << ap->id, mmio + HOST_IRQ_STAT);
+
+ /* turn IRQ back on */
+ writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_error_handler(struct ata_port *ap)
+{
+ if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ /* restart engine */
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
+ }
+
+ /* perform recovery */
+ ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset);
+}
+
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask) {
+ /* make DMA engine forget about the failed command */
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
+ }
+}
+
static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
unsigned int port_idx)
{
@@ -1115,9 +1187,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
writel(tmp, port_mmio + PORT_IRQ_STAT);
writel(1 << i, mmio + HOST_IRQ_STAT);
-
- /* set irq mask (enables interrupts) */
- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
}
tmp = readl(mmio + HOST_CTL);
@@ -1215,6 +1284,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
VPRINTK("ENTER\n");
+ WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1282,6 +1353,9 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out_hpriv;
+ if (hpriv->cap & HOST_CAP_NCQ)
+ probe_ent->host_flags |= ATA_FLAG_NCQ;
+
ahci_print_info(probe_ent);
/* FIXME: check ata_device_add return value */
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 62dabf74188..e3184a77a60 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -243,7 +243,10 @@ static const struct ata_port_operations piix_pata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -271,7 +274,10 @@ static const struct ata_port_operations piix_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -484,7 +490,7 @@ static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
return 0;
}
@@ -565,7 +571,7 @@ static unsigned int piix_sata_probe (struct ata_port *ap)
static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
{
if (!piix_sata_probe(ap)) {
- printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
+ ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
return 0;
}
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
index 835dff0bafd..6d30d2c5296 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/scsi/libata-bmdma.c
@@ -652,6 +652,149 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
ata_altstatus(ap); /* dummy read */
}
+/**
+ * ata_bmdma_freeze - Freeze BMDMA controller port
+ * @ap: port to freeze
+ *
+ * Freeze BMDMA controller port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_bmdma_freeze(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
+ else
+ outb(ap->ctl, ioaddr->ctl_addr);
+}
+
+/**
+ * ata_bmdma_thaw - Thaw BMDMA controller port
+ * @ap: port to thaw
+ *
+ * Thaw BMDMA controller port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_bmdma_thaw(struct ata_port *ap)
+{
+ /* clear & re-enable interrupts */
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
+ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+ ata_irq_on(ap);
+}
+
+/**
+ * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
+ * @ap: port to handle error for
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * Handle error for ATA BMDMA controller. It can handle both
+ * PATA and SATA controllers. Many controllers should be able to
+ * use this EH as-is or with some added handling before and
+ * after.
+ *
+ * This function is intended to be used for constructing
+ * ->error_handler callback by low level drivers.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+ struct ata_host_set *host_set = ap->host_set;
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ int thaw = 0;
+
+ qc = __ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+ qc = NULL;
+
+ /* reset PIO HSM and stop DMA engine */
+ spin_lock_irqsave(&host_set->lock, flags);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+ u8 host_stat;
+
+ host_stat = ata_bmdma_status(ap);
+
+ ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);
+
+ /* BMDMA controllers indicate host bus error by
+ * setting DMA_ERR bit and timing out. As it wasn't
+ * really a timeout event, adjust error mask and
+ * cancel frozen state.
+ */
+ if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
+ qc->err_mask = AC_ERR_HOST_BUS;
+ thaw = 1;
+ }
+
+ ap->ops->bmdma_stop(qc);
+ }
+
+ ata_altstatus(ap);
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
+
+ spin_unlock_irqrestore(&host_set->lock, flags);
+
+ if (thaw)
+ ata_eh_thaw_port(ap);
+
+ /* PIO and DMA engines have been stopped, perform recovery */
+ ata_do_eh(ap, softreset, hardreset, postreset);
+}
+
+/**
+ * ata_bmdma_error_handler - Stock error handler for BMDMA controller
+ * @ap: port to handle error for
+ *
+ * Stock error handler for BMDMA controller.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_error_handler(struct ata_port *ap)
+{
+ ata_reset_fn_t hardreset;
+
+ hardreset = NULL;
+ if (sata_scr_valid(ap))
+ hardreset = sata_std_hardreset;
+
+ ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset);
+}
+
+/**
+ * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
+ * BMDMA controller
+ * @qc: internal command to clean up
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+}
+
#ifdef CONFIG_PCI
static struct ata_probe_ent *
ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 509178c3700..9051b6821c1 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -61,13 +61,10 @@
#include "libata.h"
-static unsigned int ata_dev_init_params(struct ata_port *ap,
- struct ata_device *dev,
- u16 heads,
- u16 sectors);
-static unsigned int ata_dev_set_xfermode(struct ata_port *ap,
- struct ata_device *dev);
-static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev);
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors);
+static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static void ata_dev_xfermask(struct ata_device *dev);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
@@ -412,11 +409,10 @@ static const char *sata_spd_string(unsigned int spd)
return spd_str[spd - 1];
}
-void ata_dev_disable(struct ata_port *ap, struct ata_device *dev)
+void ata_dev_disable(struct ata_device *dev)
{
if (ata_dev_enabled(dev)) {
- printk(KERN_WARNING "ata%u: dev %u disabled\n",
- ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_WARNING, "disabled\n");
dev->class++;
}
}
@@ -955,13 +951,11 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc)
{
struct completion *waiting = qc->private_data;
- qc->ap->ops->tf_read(qc->ap, &qc->tf);
complete(waiting);
}
/**
* ata_exec_internal - execute libata internal command
- * @ap: Port to which the command is sent
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
@@ -979,24 +973,62 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc)
* None. Should be called with kernel context, might sleep.
*/
-unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
+unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen)
{
+ struct ata_port *ap = dev->ap;
u8 command = tf->command;
struct ata_queued_cmd *qc;
+ unsigned int tag, preempted_tag;
+ u32 preempted_sactive, preempted_qc_active;
DECLARE_COMPLETION(wait);
unsigned long flags;
unsigned int err_mask;
+ int rc;
spin_lock_irqsave(&ap->host_set->lock, flags);
- qc = ata_qc_new_init(ap, dev);
- BUG_ON(qc == NULL);
+ /* no internal command while frozen */
+ if (ap->flags & ATA_FLAG_FROZEN) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return AC_ERR_SYSTEM;
+ }
+
+ /* initialize internal qc */
+
+ /* XXX: Tag 0 is used for drivers with legacy EH as some
+ * drivers choke if any other tag is given. This breaks
+ * ata_tag_internal() test for those drivers. Don't use new
+ * EH stuff without converting to it.
+ */
+ if (ap->ops->error_handler)
+ tag = ATA_TAG_INTERNAL;
+ else
+ tag = 0;
+
+ if (test_and_set_bit(tag, &ap->qc_allocated))
+ BUG();
+ qc = __ata_qc_from_tag(ap, tag);
+
+ qc->tag = tag;
+ qc->scsicmd = NULL;
+ qc->ap = ap;
+ qc->dev = dev;
+ ata_qc_reinit(qc);
+
+ preempted_tag = ap->active_tag;
+ preempted_sactive = ap->sactive;
+ preempted_qc_active = ap->qc_active;
+ ap->active_tag = ATA_TAG_POISON;
+ ap->sactive = 0;
+ ap->qc_active = 0;
+ /* prepare & issue qc */
qc->tf = *tf;
if (cdb)
memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+ qc->flags |= ATA_QCFLAG_RESULT_TF;
qc->dma_dir = dma_dir;
if (dma_dir != DMA_NONE) {
ata_sg_init_one(qc, buf, buflen);
@@ -1010,31 +1042,53 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
spin_unlock_irqrestore(&ap->host_set->lock, flags);
- if (!wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL)) {
- ata_port_flush_task(ap);
+ rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
+ ata_port_flush_task(ap);
+
+ if (!rc) {
spin_lock_irqsave(&ap->host_set->lock, flags);
/* We're racing with irq here. If we lose, the
* following test prevents us from completing the qc
- * again. If completion irq occurs after here but
- * before the caller cleans up, it will result in a
- * spurious interrupt. We can live with tha