Merge branch 'for-jeff' of git://htj.dyndns.org/libata-tj into tejun-merge
This commit is contained in:
Коммит
efa6e7e9d4
|
@ -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));
|
||||
ata_ehi_clear_desc(ehi);
|
||||
|
||||
/* stop DMA */
|
||||
ahci_stop_engine(ap);
|
||||
/* AHCI needs SError cleared; otherwise, it might lock up */
|
||||
serror = ahci_scr_read(ap, SCR_ERROR);
|
||||
ahci_scr_write(ap, SCR_ERROR, serror);
|
||||
|
||||
/* clear SATA phy error, if any */
|
||||
tmp = readl(port_mmio + PORT_SCR_ERR);
|
||||
writel(tmp, port_mmio + PORT_SCR_ERR);
|
||||
/* analyze @irq_stat */
|
||||
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
|
||||
|
||||
/* 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 */
|
||||
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]);
|
||||
}
|
||||
|
||||
/* okay, let's hand over to EH */
|
||||
ehi->serror |= serror;
|
||||
ehi->action |= action;
|
||||
|
||||
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;
|
||||
if (qc)
|
||||
qc->err_mask |= err_mask;
|
||||
else
|
||||
ehi->err_mask |= err_mask;
|
||||
|
||||
spin_unlock_irqrestore(&host_set->lock, flags);
|
||||
|
||||
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;
|
||||
if (ap->sactive)
|
||||
qc_active = readl(port_mmio + PORT_SCR_ACT);
|
||||
else
|
||||
qc_active = readl(port_mmio + PORT_CMD_ISSUE);
|
||||
|
||||
/* command processing has stopped due to error; restart */
|
||||
ahci_restart_port(ap, status);
|
||||
|
||||
if (qc) {
|
||||
qc->err_mask |= err_mask;
|
||||
ata_qc_complete(qc);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -41,6 +41,7 @@
|
|||
#include <scsi/scsi_eh.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_request.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/hdreg.h>
|
||||
|
@ -302,7 +303,6 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
|
|||
|
||||
/**
|
||||
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
|
||||
* @ap: ATA port to which the new command is attached
|
||||
* @dev: ATA device to which the new command is attached
|
||||
* @cmd: SCSI command that originated this ATA command
|
||||
* @done: SCSI command completion function
|
||||
|
@ -321,14 +321,13 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
|
|||
* RETURNS:
|
||||
* Command allocated, or %NULL if none available.
|
||||
*/
|
||||
struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap,
|
||||
struct ata_device *dev,
|
||||
struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
|
||||
struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
qc = ata_qc_new_init(ap, dev);
|
||||
qc = ata_qc_new_init(dev);
|
||||
if (qc) {
|
||||
qc->scsicmd = cmd;
|
||||
qc->scsidone = done;
|
||||
|
@ -398,7 +397,7 @@ int ata_scsi_device_resume(struct scsi_device *sdev)
|
|||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
struct ata_device *dev = &ap->device[sdev->id];
|
||||
|
||||
return ata_device_resume(ap, dev);
|
||||
return ata_device_resume(dev);
|
||||
}
|
||||
|
||||
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
|
||||
|
@ -406,7 +405,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
|
|||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
struct ata_device *dev = &ap->device[sdev->id];
|
||||
|
||||
return ata_device_suspend(ap, dev, state);
|
||||
return ata_device_suspend(dev, state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -417,6 +416,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
|
|||
* @sk: the sense key we'll fill out
|
||||
* @asc: the additional sense code we'll fill out
|
||||
* @ascq: the additional sense code qualifier we'll fill out
|
||||
* @verbose: be verbose
|
||||
*
|
||||
* Converts an ATA error into a SCSI error. Fill out pointers to
|
||||
* SK, ASC, and ASCQ bytes for later use in fixed or descriptor
|
||||
|
@ -426,7 +426,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
|
|||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
|
||||
u8 *ascq)
|
||||
u8 *ascq, int verbose)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -491,8 +491,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
|
|||
}
|
||||
}
|
||||
/* No immediate match */
|
||||
printk(KERN_WARNING "ata%u: no sense translation for "
|
||||
"error 0x%02x\n", id, drv_err);
|
||||
if (verbose)
|
||||
printk(KERN_WARNING "ata%u: no sense translation for "
|
||||
"error 0x%02x\n", id, drv_err);
|
||||
}
|
||||
|
||||
/* Fall back to interpreting status bits */
|
||||
|
@ -505,8 +506,9 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
|
|||
}
|
||||
}
|
||||
/* No error? Undecoded? */
|
||||
printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n",
|
||||
id, drv_stat);
|
||||
if (verbose)
|
||||
printk(KERN_WARNING "ata%u: no sense translation for "
|
||||
"status: 0x%02x\n", id, drv_stat);
|
||||
|
||||
/* We need a sensible error return here, which is tricky, and one
|
||||
that won't cause people to do things like return a disk wrongly */
|
||||
|
@ -515,9 +517,10 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
|
|||
*ascq = 0x00;
|
||||
|
||||
translate_done:
|
||||
printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to "
|
||||
"SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err,
|
||||
*sk, *asc, *ascq);
|
||||
if (verbose)
|
||||
printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
|
||||
"to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
|
||||
id, drv_stat, drv_err, *sk, *asc, *ascq);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -537,9 +540,10 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
|
|||
void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
struct ata_taskfile *tf = &qc->tf;
|
||||
struct ata_taskfile *tf = &qc->result_tf;
|
||||
unsigned char *sb = cmd->sense_buffer;
|
||||
unsigned char *desc = sb + 8;
|
||||
int verbose = qc->ap->ops->error_handler == NULL;
|
||||
|
||||
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
|
||||
|
@ -552,7 +556,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
|
|||
if (qc->err_mask ||
|
||||
tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
|
||||
ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
|
||||
&sb[1], &sb[2], &sb[3]);
|
||||
&sb[1], &sb[2], &sb[3], verbose);
|
||||
sb[1] &= 0x0f;
|
||||
}
|
||||
|
||||
|
@ -608,8 +612,9 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
|
|||
void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
struct ata_taskfile *tf = &qc->tf;
|
||||
struct ata_taskfile *tf = &qc->result_tf;
|
||||
unsigned char *sb = cmd->sense_buffer;
|
||||
int verbose = qc->ap->ops->error_handler == NULL;
|
||||
|
||||
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
|
||||
|
@ -622,7 +627,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
|
|||
if (qc->err_mask ||
|
||||
tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
|
||||
ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
|
||||
&sb[2], &sb[12], &sb[13]);
|
||||
&sb[2], &sb[12], &sb[13], verbose);
|
||||
sb[2] &= 0x0f;
|
||||
}
|
||||
|
||||
|
@ -680,6 +685,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
|
|||
request_queue_t *q = sdev->request_queue;
|
||||
blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
|
||||
}
|
||||
|
||||
if (dev->flags & ATA_DFLAG_NCQ) {
|
||||
int depth;
|
||||
|
||||
depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
|
||||
depth = min(ATA_MAX_QUEUE - 1, depth);
|
||||
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -713,6 +726,43 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
|
|||
return 0; /* scsi layer doesn't check return value, sigh */
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_change_queue_depth - SCSI callback for queue depth config
|
||||
* @sdev: SCSI device to configure queue depth for
|
||||
* @queue_depth: new queue depth
|
||||
*
|
||||
* This is libata standard hostt->change_queue_depth callback.
|
||||
* SCSI will call into this callback when user tries to set queue
|
||||
* depth via sysfs.
|
||||
*
|
||||
* LOCKING:
|
||||
* SCSI layer (we don't care)
|
||||
*
|
||||
* RETURNS:
|
||||
* Newly configured queue depth.
|
||||
*/
|
||||
int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
struct ata_device *dev;
|
||||
int max_depth;
|
||||
|
||||
if (queue_depth < 1)
|
||||
return sdev->queue_depth;
|
||||
|
||||
dev = ata_scsi_find_dev(ap, sdev);
|
||||
if (!dev || !ata_dev_enabled(dev))
|
||||
return sdev->queue_depth;
|
||||
|
||||
max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
|
||||
max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
|
||||
if (queue_depth > max_depth)
|
||||
queue_depth = max_depth;
|
||||
|
||||
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
|
||||
return queue_depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
|
||||
* @qc: Storage for translated ATA taskfile
|
||||
|
@ -748,7 +798,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
|
|||
tf->nsect = 1; /* 1 sector, lba=0 */
|
||||
|
||||
if (qc->dev->flags & ATA_DFLAG_LBA) {
|
||||
qc->tf.flags |= ATA_TFLAG_LBA;
|
||||
tf->flags |= ATA_TFLAG_LBA;
|
||||
|
||||
tf->lbah = 0x0;
|
||||
tf->lbam = 0x0;
|
||||
|
@ -1099,7 +1149,36 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
|
|||
*/
|
||||
goto nothing_to_do;
|
||||
|
||||
if (dev->flags & ATA_DFLAG_LBA) {
|
||||
if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
|
||||
/* yay, NCQ */
|
||||
if (!lba_48_ok(block, n_block))
|
||||
goto out_of_range;
|
||||
|
||||
tf->protocol = ATA_PROT_NCQ;
|
||||
tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
|
||||
|
||||
if (tf->flags & ATA_TFLAG_WRITE)
|
||||
tf->command = ATA_CMD_FPDMA_WRITE;
|
||||
else
|
||||
tf->command = ATA_CMD_FPDMA_READ;
|
||||
|
||||
qc->nsect = n_block;
|
||||
|
||||
tf->nsect = qc->tag << 3;
|
||||
tf->hob_feature = (n_block >> 8) & 0xff;
|
||||
tf->feature = n_block & 0xff;
|
||||
|
||||
tf->hob_lbah = (block >> 40) & 0xff;
|
||||
tf->hob_lbam = (block >> 32) & 0xff;
|
||||
tf->hob_lbal = (block >> 24) & 0xff;
|
||||
tf->lbah = (block >> 16) & 0xff;
|
||||
tf->lbam = (block >> 8) & 0xff;
|
||||
tf->lbal = block & 0xff;
|
||||
|
||||
tf->device = 1 << 6;
|
||||
if (tf->flags & ATA_TFLAG_FUA)
|
||||
tf->device |= 1 << 7;
|
||||
} else if (dev->flags & ATA_DFLAG_LBA) {
|
||||
tf->flags |= ATA_TFLAG_LBA;
|
||||
|
||||
if (lba_28_ok(block, n_block)) {
|
||||
|
@ -1199,14 +1278,11 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
|||
*/
|
||||
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
|
||||
((cdb[2] & 0x20) || need_sense)) {
|
||||
qc->ap->ops->tf_read(qc->ap, &qc->tf);
|
||||
ata_gen_ata_desc_sense(qc);
|
||||
} else {
|
||||
if (!need_sense) {
|
||||
cmd->result = SAM_STAT_GOOD;
|
||||
} else {
|
||||
qc->ap->ops->tf_read(qc->ap, &qc->tf);
|
||||
|
||||
/* TODO: decide which descriptor format to use
|
||||
* for 48b LBA devices and call that here
|
||||
* instead of the fixed desc, which is only
|
||||
|
@ -1217,19 +1293,49 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
|||
}
|
||||
}
|
||||
|
||||
if (need_sense) {
|
||||
/* The ata_gen_..._sense routines fill in tf */
|
||||
ata_dump_status(qc->ap->id, &qc->tf);
|
||||
}
|
||||
if (need_sense && !qc->ap->ops->error_handler)
|
||||
ata_dump_status(qc->ap->id, &qc->result_tf);
|
||||
|
||||
qc->scsidone(cmd);
|
||||
|
||||
ata_qc_free(qc);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scmd_need_defer - Check whether we need to defer scmd
|
||||
* @dev: ATA device to which the command is addressed
|
||||
* @is_io: Is the command IO (and thus possibly NCQ)?
|
||||
*
|
||||
* NCQ and non-NCQ commands cannot run together. As upper layer
|
||||
* only knows the queue depth, we are responsible for maintaining
|
||||
* exclusion. This function checks whether a new command can be
|
||||
* issued to @dev.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
* RETURNS:
|
||||
* 1 if deferring is needed, 0 otherwise.
|
||||
*/
|
||||
static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
|
||||
{
|
||||
struct ata_port *ap = dev->ap;
|
||||
|
||||
if (!(dev->flags & ATA_DFLAG_NCQ))
|
||||
return 0;
|
||||
|
||||
if (is_io) {
|
||||
if (!ata_tag_valid(ap->active_tag))
|
||||
return 0;
|
||||
} else {
|
||||
if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_translate - Translate then issue SCSI command to ATA device
|
||||
* @ap: ATA port to which the command is addressed
|
||||
* @dev: ATA device to which the command is addressed
|
||||
* @cmd: SCSI command to execute
|
||||
* @done: SCSI command completion function
|
||||
|
@ -1250,19 +1356,25 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
|||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
|
||||
* needs to be deferred.
|
||||
*/
|
||||
|
||||
static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
|
||||
struct scsi_cmnd *cmd,
|
||||
static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *),
|
||||
ata_xlat_func_t xlat_func)
|
||||
{
|
||||
struct ata_queued_cmd *qc;
|
||||
u8 *scsicmd = cmd->cmnd;
|
||||
int is_io = xlat_func == ata_scsi_rw_xlat;
|
||||
|
||||
VPRINTK("ENTER\n");
|
||||
|
||||
qc = ata_scsi_qc_new(ap, dev, cmd, done);
|
||||
if (unlikely(ata_scmd_need_defer(dev, is_io)))
|
||||
goto defer;
|
||||
|
||||
qc = ata_scsi_qc_new(dev, cmd, done);
|
||||
if (!qc)
|
||||
goto err_mem;
|
||||
|
||||
|
@ -1270,8 +1382,8 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
|
|||
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
|
||||
cmd->sc_data_direction == DMA_TO_DEVICE) {
|
||||
if (unlikely(cmd->request_bufflen < 1)) {
|
||||
printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n",
|
||||
ap->id, dev->devno);
|
||||
ata_dev_printk(dev, KERN_WARNING,
|
||||
"WARNING: zero len r/w req\n");
|
||||
goto err_did;
|
||||
}
|
||||
|
||||
|
@ -1293,13 +1405,13 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
|
|||
ata_qc_issue(qc);
|
||||
|
||||
VPRINTK("EXIT\n");
|
||||
return;
|
||||
return 0;
|
||||
|
||||
early_finish:
|
||||
ata_qc_free(qc);
|
||||
done(cmd);
|
||||
DPRINTK("EXIT - early finish (good or error)\n");
|
||||
return;
|
||||
return 0;
|
||||
|
||||
err_did:
|
||||
ata_qc_free(qc);
|
||||
|
@ -1307,7 +1419,11 @@ err_mem:
|
|||
cmd->result = (DID_ERROR << 16);
|
||||
done(cmd);
|
||||
DPRINTK("EXIT - internal\n");
|
||||
return;
|
||||
return 0;
|
||||
|
||||
defer:
|
||||
DPRINTK("EXIT - defer\n");
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2004,7 +2120,6 @@ static void atapi_sense_complete(struct ata_queued_cmd *qc)
|
|||
* a sense descriptors, since that's only
|
||||
* correct for ATA, not ATAPI
|
||||
*/
|
||||
qc->ap->ops->tf_read(qc->ap, &qc->tf);
|
||||
ata_gen_ata_desc_sense(qc);
|
||||
}
|
||||
|
||||
|
@ -2070,6 +2185,26 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
|||
|
||||
VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
|
||||
|
||||
/* handle completion from new EH */
|
||||
if (unlikely(qc->ap->ops->error_handler &&
|
||||
(err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
|
||||
|
||||
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
|
||||
/* FIXME: not quite right; we don't want the
|
||||
* translation of taskfile registers into a
|
||||
* sense descriptors, since that's only
|
||||
* correct for ATA, not ATAPI
|
||||
*/
|
||||
ata_gen_ata_desc_sense(qc);
|
||||
}
|
||||
|
||||
qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
|
||||
qc->scsidone(cmd);
|
||||
ata_qc_free(qc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* successful completion or old EH failure path */
|
||||
if (unlikely(err_mask & AC_ERR_DEV)) {
|
||||
cmd->result = SAM_STAT_CHECK_CONDITION;
|
||||
atapi_request_sense(qc);
|
||||
|
@ -2080,7 +2215,6 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
|||
* a sense descriptors, since that's only
|
||||
* correct for ATA, not ATAPI
|
||||
*/
|
||||
qc->ap->ops->tf_read(qc->ap, &qc->tf);
|
||||
ata_gen_ata_desc_sense(qc);
|
||||
} else {
|
||||
u8 *scsicmd = cmd->cmnd;
|
||||
|
@ -2211,8 +2345,9 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
|
|||
|
||||
if (!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) {
|
||||
if (unlikely(dev->class == ATA_DEV_ATAPI)) {
|
||||
printk(KERN_WARNING "ata%u(%u): WARNING: ATAPI is %s, device ignored.\n",
|
||||
ap->id, dev->devno, atapi_enabled ? "not supported with this driver" : "disabled");
|
||||
ata_dev_printk(dev, KERN_WARNING,
|
||||
"WARNING: ATAPI is %s, device ignored.\n",
|
||||
atapi_enabled ? "not supported with this driver" : "disabled");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -2361,6 +2496,9 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
|
|||
*/
|
||||
qc->nsect = cmd->bufflen / ATA_SECT_SIZE;
|
||||
|
||||
/* request result TF */
|
||||
qc->flags |= ATA_QCFLAG_RESULT_TF;
|
||||
|
||||
return 0;
|
||||
|
||||
invalid_fld:
|
||||
|
@ -2437,19 +2575,24 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
|
||||
struct ata_port *ap, struct ata_device *dev)
|
||||
static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *),
|
||||
struct ata_device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (dev->class == ATA_DEV_ATA) {
|
||||
ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
|
||||
cmd->cmnd[0]);
|
||||
|
||||
if (xlat_func)
|
||||
ata_scsi_translate(ap, dev, cmd, done, xlat_func);
|
||||
rc = ata_scsi_translate(dev, cmd, done, xlat_func);
|
||||
else
|
||||
ata_scsi_simulate(ap, dev, cmd, done);
|
||||
ata_scsi_simulate(dev, cmd, done);
|
||||
} else
|
||||
ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
|
||||
rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2468,15 +2611,16 @@ static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struc
|
|||
* Releases scsi-layer-held lock, and obtains host_set lock.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero.
|
||||
* Return value from __ata_scsi_queuecmd() if @cmd can be queued,
|
||||
* 0 otherwise.
|
||||
*/
|
||||
|
||||
int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
struct ata_port *ap;
|
||||
struct ata_device *dev;
|
||||
struct scsi_device *scsidev = cmd->device;
|
||||
struct Scsi_Host *shost = scsidev->host;
|
||||
int rc = 0;
|
||||
|
||||
ap = ata_shost_to_port(shost);
|
||||
|
||||
|
@ -2487,7 +2631,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
|||
|
||||
dev = ata_scsi_find_dev(ap, scsidev);
|
||||
if (likely(dev))
|
||||
__ata_scsi_queuecmd(cmd, done, ap, dev);
|
||||
rc = __ata_scsi_queuecmd(cmd, done, dev);
|
||||
else {
|
||||
cmd->result = (DID_BAD_TARGET << 16);
|
||||
done(cmd);
|
||||
|
@ -2495,12 +2639,11 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
|||
|
||||
spin_unlock(&ap->host_set->lock);
|
||||
spin_lock(shost->host_lock);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_simulate - simulate SCSI command on ATA device
|
||||
* @ap: port the device is connected to
|
||||
* @dev: the target device
|
||||
* @cmd: SCSI command being sent to device.
|
||||
* @done: SCSI command completion function.
|
||||
|
@ -2512,14 +2655,12 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
|||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
|
||||
void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
|
||||
struct scsi_cmnd *cmd,
|
||||
void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
struct ata_scsi_args args;
|
||||
const u8 *scsicmd = cmd->cmnd;
|
||||
|
||||
args.ap = ap;
|
||||
args.dev = dev;
|
||||
args.id = dev->id;
|
||||
args.cmd = cmd;
|
||||
|
@ -2605,3 +2746,26 @@ void ata_scsi_scan_host(struct ata_port *ap)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_schedule_scsi_eh - schedule EH for SCSI host
|
||||
* @shost: SCSI host to invoke error handling on.
|
||||
*
|
||||
* Schedule SCSI EH without scmd. This is a hack.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
**/
|
||||
void ata_schedule_scsi_eh(struct Scsi_Host *shost)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
|
||||
if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
|
||||
scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
|
||||
shost->host_eh_scheduled++;
|
||||
scsi_eh_wakeup(shost);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#define DRV_VERSION "1.30" /* must be exactly four chars */
|
||||
|
||||
struct ata_scsi_args {
|
||||
struct ata_port *ap;
|
||||
struct ata_device *dev;
|
||||
u16 *id;
|
||||
struct scsi_cmnd *cmd;
|
||||
|
@ -43,23 +42,22 @@ struct ata_scsi_args {
|
|||
extern int atapi_enabled;
|
||||
extern int atapi_dmadir;
|
||||
extern int libata_fua;
|
||||
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
|
||||
struct ata_device *dev);
|
||||
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
|
||||
extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
|
||||
extern void ata_dev_disable(struct ata_port *ap, struct ata_device *dev);
|
||||
extern void ata_dev_disable(struct ata_device *dev);
|
||||
extern void ata_port_flush_task(struct ata_port *ap);
|
||||
extern unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
|
||||
extern unsigned ata_exec_internal(struct ata_device *dev,
|
||||
struct ata_taskfile *tf, const u8 *cdb,
|
||||
int dma_dir, void *buf, unsigned int buflen);
|
||||
extern int ata_down_sata_spd_limit(struct ata_port *ap);
|
||||
extern int ata_set_sata_spd_needed(struct ata_port *ap);
|
||||
extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev,
|
||||
int force_pio0);
|
||||
extern int sata_down_spd_limit(struct ata_port *ap);
|
||||
extern int sata_set_spd_needed(struct ata_port *ap);
|
||||
extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
|
||||
extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
|
||||
extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
|
||||
ata_postreset_fn_t postreset, unsigned int *classes);
|
||||
unsigned int *classes);
|
||||
extern void ata_qc_free(struct ata_queued_cmd *qc);
|
||||
extern void ata_qc_issue(struct ata_queued_cmd *qc);
|
||||
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
|
||||
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
|
||||
extern void ata_dev_select(struct ata_port *ap, unsigned int device,
|
||||
unsigned int wait, unsigned int can_sleep);
|
||||
|
@ -100,9 +98,11 @@ extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
|
|||
extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
|
||||
unsigned int (*actor) (struct ata_scsi_args *args,
|
||||
u8 *rbuf, unsigned int buflen));
|
||||
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
|
||||
|
||||
/* libata-eh.c */
|
||||
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
|
||||
extern void ata_scsi_error(struct Scsi_Host *host);
|
||||
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
|
||||
|
||||
#endif /* __LIBATA_H__ */
|
||||
|
|
|
@ -455,13 +455,13 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
|
|||
continue;
|
||||
handled = 1;
|
||||
adma_enter_reg_mode(ap);
|
||||
if (ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))
|
||||
if (ap->flags & ATA_FLAG_DISABLED)
|
||||
continue;
|
||||
pp = ap->private_data;
|
||||
if (!pp || pp->state != adma_state_pkt)
|
||||
continue;
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
|
||||
if ((status & (aPERR | aPSD | aUIRQ)))
|
||||
qc->err_mask |= AC_ERR_OTHER;
|
||||
else if (pp->pkt[0] != cDONE)
|
||||
|
@ -480,13 +480,13 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
|
|||
for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
|
||||
struct ata_port *ap;
|
||||
ap = host_set->ports[port_no];
|
||||
if (ap && (!(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR)))) {
|
||||
if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
|
||||
struct ata_queued_cmd *qc;
|
||||
struct adma_port_priv *pp = ap->private_data;
|
||||
if (!pp || pp->state != adma_state_mmio)
|
||||
continue;
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
|
||||
|
||||
/* check main status, clearing INTRQ */
|
||||
u8 status = ata_check_status(ap);
|
||||
|
|
|
@ -87,7 +87,7 @@ enum {
|
|||
MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
|
||||
MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
|
||||
ATA_FLAG_NO_ATAPI),
|
||||
ATA_FLAG_PIO_POLLING),
|
||||
MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
|
||||
|
||||
CRQB_FLAG_READ = (1 << 0),
|
||||
|
@ -680,7 +680,7 @@ static void mv_stop_dma(struct ata_port *ap)
|
|||
}
|
||||
|
||||
if (EDMA_EN & reg) {
|
||||
printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id);
|
||||
ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
|
||||
/* FIXME: Consider doing a reset here to recover */
|
||||
}
|
||||
}
|
||||
|
@ -1309,8 +1309,8 @@ static void mv_err_intr(struct ata_port *ap)
|
|||
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
|
||||
|
||||
if (EDMA_ERR_SERR & edma_err_cause) {
|
||||
serr = scr_read(ap, SCR_ERROR);
|
||||
scr_write_flush(ap, SCR_ERROR, serr);
|
||||
sata_scr_read(ap, SCR_ERROR, &serr);
|
||||
sata_scr_write_flush(ap, SCR_ERROR, serr);
|
||||
}
|
||||
if (EDMA_ERR_SELF_DIS & edma_err_cause) {
|
||||
struct mv_port_priv *pp = ap->private_data;
|
||||
|
@ -1396,7 +1396,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
|
|||
}
|
||||
}
|
||||
|
||||
if (ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))
|
||||
if (ap && (ap->flags & ATA_FLAG_DISABLED))
|
||||
continue;
|
||||
|
||||
err_mask = ac_err_mask(ata_status);
|
||||
|
@ -1417,7 +1417,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
|
|||
VPRINTK("port %u IRQ found for qc, "
|
||||
"ata_status 0x%x\n", port,ata_status);
|
||||
/* mark qc status appropriately */
|
||||
if (!(qc->tf.ctl & ATA_NIEN)) {
|
||||
if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
|
||||
qc->err_mask |= err_mask;
|
||||
ata_qc_complete(qc);
|
||||
}
|
||||
|
@ -1934,15 +1934,16 @@ static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
|
|||
|
||||
/* Issue COMRESET via SControl */
|
||||
comreset_retry:
|
||||
scr_write_flush(ap, SCR_CONTROL, 0x301);
|
||||
sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
|
||||
__msleep(1, can_sleep);
|
||||
|
||||
scr_write_flush(ap, SCR_CONTROL, 0x300);
|
||||
sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
|
||||
__msleep(20, can_sleep);
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(200);
|
||||
do {
|
||||
sstatus = scr_read(ap, SCR_STATUS) & 0x3;
|
||||
sata_scr_read(ap, SCR_STATUS, &sstatus);
|
||||
sstatus &= 0x3;
|
||||
if ((sstatus == 3) || (sstatus == 0))
|
||||
break;
|
||||
|
||||
|
@ -1959,11 +1960,12 @@ comreset_retry:
|
|||
"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
|
||||
mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
|
||||
|
||||
if (sata_dev_present(ap)) {
|
||||
if (ata_port_online(ap)) {
|
||||
ata_port_probe(ap);
|
||||
} else {
|
||||
printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n",
|
||||
ap->id, scr_read(ap, SCR_STATUS));
|
||||
sata_scr_read(ap, SCR_STATUS, &sstatus);
|
||||
ata_port_printk(ap, KERN_INFO,
|
||||
"no device found (phy stat %08x)\n", sstatus);
|
||||
ata_port_disable(ap);
|
||||
return;
|
||||
}
|
||||
|
@ -2021,7 +2023,7 @@ static void mv_eng_timeout(struct ata_port *ap)
|
|||
{
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
|
||||
ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
|
||||
DPRINTK("All regs @ start of eng_timeout\n");
|
||||
mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no,
|
||||
to_pci_dev(ap->host_set->dev));
|
||||
|
|
|
@ -279,11 +279,11 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
|
|||
|
||||
ap = host_set->ports[i];
|
||||
if (ap &&
|
||||
!(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) {
|
||||
!(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN)))
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
|
||||
handled += ata_host_intr(ap, qc);
|
||||
else
|
||||
// No request pending? Clear interrupt status
|
||||
|
|
|
@ -76,7 +76,8 @@ enum {
|
|||
PDC_RESET = (1 << 11), /* HDMA reset */
|
||||
|
||||
PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
|
||||
ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI,
|
||||
ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
|
||||
ATA_FLAG_PIO_POLLING,
|
||||
};
|
||||
|
||||
|
||||
|
@ -435,7 +436,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
|
|||
switch (qc->tf.protocol) {
|
||||
case ATA_PROT_DMA:
|
||||
case ATA_PROT_NODATA:
|
||||
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
|
||||
ata_port_printk(ap, KERN_ERR, "command timeout\n");
|
||||
drv_stat = ata_wait_idle(ap);
|
||||
qc->err_mask |= __ac_err_mask(drv_stat);
|
||||
break;
|
||||
|
@ -443,8 +444,9 @@ static void pdc_eng_timeout(struct ata_port *ap)
|
|||
default:
|
||||
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
|
||||
|
||||
printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
|
||||
ap->id, qc->tf.command, drv_stat);
|
||||
ata_port_printk(ap, KERN_ERR,
|
||||
"unknown timeout, cmd 0x%x stat 0x%x\n",
|
||||
qc->tf.command, drv_stat);
|
||||
|
||||
qc->err_mask |= ac_err_mask(drv_stat);
|
||||
break;
|
||||
|
@ -533,11 +535,11 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
|
|||
ap = host_set->ports[i];
|
||||
tmp = mask & (1 << (i + 1));
|
||||
if (tmp && ap &&
|
||||
!(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) {
|
||||
!(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN)))
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
|
||||
handled += pdc_host_intr(ap, qc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ static const struct ata_port_info qs_port_info[] = {
|
|||
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_SATA_RESET |
|
||||
//FIXME ATA_FLAG_SRST |
|
||||
ATA_FLAG_MMIO,
|
||||
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
|
||||
.pio_mask = 0x10, /* pio4 */
|
||||
.udma_mask = 0x7f, /* udma0-6 */
|
||||
.port_ops = &qs_ata_ops,
|
||||
|
@ -394,14 +394,13 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
|
|||
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
|
||||
sff1, sff0, port_no, sHST, sDST);
|
||||
handled = 1;
|
||||
if (ap && !(ap->flags &
|
||||
(ATA_FLAG_DISABLED|ATA_FLAG_NOINTR))) {
|
||||
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
struct ata_queued_cmd *qc;
|
||||
struct qs_port_priv *pp = ap->private_data;
|
||||
if (!pp || pp->state != qs_state_pkt)
|
||||
continue;
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
|
||||
switch (sHST) {
|
||||
case 0: /* successful CPB */
|
||||
case 3: /* device error */
|
||||
|
@ -428,13 +427,13 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
|
|||
struct ata_port *ap;
|
||||
ap = host_set->ports[port_no];
|
||||
if (ap &&
|
||||
!(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) {
|
||||
!(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
struct ata_queued_cmd *qc;
|
||||
struct qs_port_priv *pp = ap->private_data;
|
||||
if (!pp || pp->state != qs_state_mmio)
|
||||
continue;
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
|
||||
|
||||
/* check main status, clearing INTRQ */
|
||||
u8 status = ata_check_status(ap);
|
||||
|
|
|
@ -96,6 +96,8 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
|
|||
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
|
||||
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
|
||||
static void sil_post_set_mode (struct ata_port *ap);
|
||||
static void sil_freeze(struct ata_port *ap);
|
||||
static void sil_thaw(struct ata_port *ap);
|
||||
|
||||
|
||||
static const struct pci_device_id sil_pci_tbl[] = {
|
||||
|
@ -174,7 +176,10 @@ static const struct ata_port_operations sil_ops = {
|
|||
.bmdma_status = ata_bmdma_status,
|
||||
.qc_prep = ata_qc_prep,
|
||||
.qc_issue = ata_qc_issue_prot,
|
||||
.eng_timeout = ata_eng_timeout,
|
||||
.freeze = sil_freeze,
|
||||
.thaw = sil_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,
|
||||
.scr_read = sil_scr_read,
|
||||
|
@ -314,6 +319,33 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
|
|||
writel(val, mmio);
|
||||
}
|
||||
|
||||
static void sil_freeze(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mmio_base = ap->host_set->mmio_base;
|
||||
u32 tmp;
|
||||
|
||||
/* plug IRQ */
|
||||
tmp = readl(mmio_base + SIL_SYSCFG);
|
||||
tmp |= SIL_MASK_IDE0_INT << ap->port_no;
|
||||
writel(tmp, mmio_base + SIL_SYSCFG);
|
||||
readl(mmio_base + SIL_SYSCFG); /* flush */
|
||||
}
|
||||
|
||||
static void sil_thaw(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mmio_base = ap->host_set->mmio_base;
|
||||
u32 tmp;
|
||||
|
||||
/* clear IRQ */
|
||||
ata_chk_status(ap);
|
||||
ata_bmdma_irq_clear(ap);
|
||||
|
||||
/* turn on IRQ */
|
||||
tmp = readl(mmio_base + SIL_SYSCFG);
|
||||
tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
|
||||
writel(tmp, mmio_base + SIL_SYSCFG);
|
||||
}
|
||||
|
||||
/**
|
||||
* sil_dev_config - Apply device/host-specific errata fixups
|
||||
* @ap: Port containing device to be examined
|
||||
|
@ -360,16 +392,16 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
|
|||
if (slow_down ||
|
||||
((ap->flags & SIL_FLAG_MOD15WRITE) &&
|
||||
(quirks & SIL_QUIRK_MOD15WRITE))) {
|
||||
printk(KERN_INFO "ata%u(%u): applying Seagate errata fix (mod15write workaround)\n",
|
||||
ap->id, dev->devno);
|
||||
ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix "
|
||||
"(mod15write workaround)\n");
|
||||
dev->max_sectors = 15;
|
||||
return;
|
||||
}
|
||||
|
||||
/* limit to udma5 */
|
||||
if (quirks & SIL_QUIRK_UDMA5MAX) {
|
||||
printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
|
||||
ap->id, dev->devno, model_num);
|
||||
ata_dev_printk(dev, KERN_INFO,
|
||||
"applying Maxtor errata fix %s\n", model_num);
|
||||
dev->udma_mask &= ATA_UDMA5;
|
||||
return;
|
||||
}
|
||||
|
@ -384,7 +416,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
int rc;
|
||||
unsigned int i;
|
||||
int pci_dev_busy = 0;
|
||||
u32 tmp, irq_mask;
|
||||
u32 tmp;
|
||||
u8 cls;
|
||||
|
||||
if (!printed_version++)
|
||||
|
@ -474,24 +506,11 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
}
|
||||
|
||||
if (ent->driver_data == sil_3114) {
|
||||
irq_mask = SIL_MASK_4PORT;
|
||||
|
||||
/* flip the magic "make 4 ports work" bit */
|
||||
tmp = readl(mmio_base + sil_port[2].bmdma);
|
||||
if ((tmp & SIL_INTR_STEERING) == 0)
|
||||
writel(tmp | SIL_INTR_STEERING,
|
||||
mmio_base + sil_port[2].bmdma);
|
||||
|
||||
} else {
|
||||
irq_mask = SIL_MASK_2PORT;
|
||||
}
|
||||
|
||||
/* make sure IDE0/1/2/3 interrupts are not masked */
|
||||
tmp = readl(mmio_base + SIL_SYSCFG);
|
||||
if (tmp & irq_mask) {
|
||||
tmp &= ~irq_mask;
|
||||
writel(tmp, mmio_base + SIL_SYSCFG);
|
||||
readl(mmio_base + SIL_SYSCFG); /* flush */
|
||||
}
|
||||
|
||||
/* mask all SATA phy-related interrupts */
|
||||
|
|
|
@ -156,6 +156,9 @@ enum {
|
|||
PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */
|
||||
PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
|
||||
|
||||
DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
|
||||
PORT_IRQ_DEV_XCHG | PORT_IRQ_UNK_FIS,
|
||||
|
||||
/* bits[27:16] are unmasked (raw) */
|
||||
PORT_IRQ_RAW_SHIFT = 16,
|
||||
PORT_IRQ_MASKED_MASK = 0x7ff,
|
||||
|
@ -213,6 +216,8 @@ enum {
|
|||
SGE_DRD = (1 << 29), /* discard data read (/dev/null)
|
||||
data address ignored */
|
||||
|
||||
SIL24_MAX_CMDS = 31,
|
||||
|
||||
/* board id */
|
||||
BID_SIL3124 = 0,
|
||||
BID_SIL3132 = 1,
|
||||
|
@ -220,7 +225,8 @@ enum {
|
|||
|
||||
/* host flags */
|
||||
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
|
||||
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
|
||||
ATA_FLAG_NCQ,
|
||||
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
|
||||
|
||||
IRQ_STAT_4PORTS = 0xf,
|
||||
|
@ -242,6 +248,58 @@ union sil24_cmd_block {
|
|||
struct sil24_atapi_block atapi;
|
||||
};
|
||||
|
||||
static struct sil24_cerr_info {
|
||||
unsigned int err_mask, action;
|
||||
const char *desc;
|
||||
} sil24_cerr_db[] = {
|
||||
[0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
|
||||
"device error" },
|
||||
[PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
|
||||
"device error via D2H FIS" },
|
||||
[PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
|
||||
"device error via SDB FIS" },
|
||||
[PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
|
||||
"error in data FIS" },
|
||||
[PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
|
||||
"failed to transmit command FIS" },
|
||||
[PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
|
||||
"protocol mismatch" },
|
||||
[PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
|
||||
"data directon mismatch" },
|
||||
[PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
|
||||
"ran out of SGEs while writing" },
|
||||
[PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
|
||||
"ran out of SGEs while reading" },
|
||||
[PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
|
||||
"invalid data directon for ATAPI CDB" },
|
||||
[PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
|
||||
"SGT no on qword boundary" },
|
||||
[PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI target abort while fetching SGT" },
|
||||
[PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI master abort while fetching SGT" },
|
||||
[PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI parity error while fetching SGT" },
|
||||
[PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
|
||||
"PRB not on qword boundary" },
|
||||
[PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI target abort while fetching PRB" },
|
||||
[PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI master abort while fetching PRB" },
|
||||
[PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI parity error while fetching PRB" },
|
||||
[PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"undefined error while transferring data" },
|
||||
[PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI target abort while transferring data" },
|
||||
[PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI master abort while transferring data" },
|
||||
[PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
|
||||
"PCI parity error while transferring data" },
|
||||
[PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
|
||||
"FIS received while sending service FIS" },
|
||||
};
|
||||
|
||||
/*
|
||||
* ap->private_data
|
||||
*
|
||||
|
@ -269,8 +327,11 @@ static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
|
|||
static void sil24_qc_prep(struct ata_queued_cmd *qc);
|
||||
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
|
||||
static void sil24_irq_clear(struct ata_port *ap);
|
||||
static void sil24_eng_timeout(struct ata_port *ap);
|
||||
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
|
||||
static void sil24_freeze(struct ata_port *ap);
|
||||
static void sil24_thaw(struct ata_port *ap);
|
||||
static void sil24_error_handler(struct ata_port *ap);
|
||||
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
|
||||
static int sil24_port_start(struct ata_port *ap);
|
||||
static void sil24_port_stop(struct ata_port *ap);
|
||||
static void sil24_host_stop(struct ata_host_set *host_set);
|
||||
|
@ -297,7 +358,8 @@ static struct scsi_host_template sil24_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 = SIL24_MAX_CMDS,
|
||||
.this_id = ATA_SHT_THIS_ID,
|
||||
.sg_tablesize = LIBATA_MAX_PRD,
|
||||
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
||||
|
@ -325,14 +387,17 @@ static const struct ata_port_operations sil24_ops = {
|
|||
.qc_prep = sil24_qc_prep,
|
||||
.qc_issue = sil24_qc_issue,
|
||||
|
||||
.eng_timeout = sil24_eng_timeout,
|
||||
|
||||
.irq_handler = sil24_interrupt,
|
||||
.irq_clear = sil24_irq_clear,
|
||||
|
||||
.scr_read = sil24_scr_read,
|
||||
.scr_write = sil24_scr_write,
|
||||
|
||||
.freeze = sil24_freeze,
|
||||
.thaw = sil24_thaw,
|
||||
.error_handler = sil24_error_handler,
|
||||
.post_internal_cmd = sil24_post_internal_cmd,
|
||||
|
||||
.port_start = sil24_port_start,
|
||||
.port_stop = sil24_port_stop,
|
||||
.host_stop = sil24_host_stop,
|
||||
|
@ -376,6 +441,13 @@ static struct ata_port_info sil24_port_info[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int sil24_tag(int tag)
|
||||
{
|
||||
if (unlikely(ata_tag_internal(tag)))
|
||||
return 0;
|
||||
return tag;
|
||||
}
|
||||
|
||||
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
|
||||
{
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
|
@ -459,21 +531,17 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
|
|||
struct sil24_port_priv *pp = ap->private_data;
|
||||
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
|
||||
dma_addr_t paddr = pp->cmd_block_dma;
|
||||
u32 mask, irq_enable, irq_stat;
|
||||
u32 mask, irq_stat;
|
||||
const char *reason;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
if (!sata_dev_present(ap)) {
|
||||
if (ata_port_offline(ap)) {
|
||||
DPRINTK("PHY reports no device\n");
|
||||
*class = ATA_DEV_NONE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* temporarily turn off IRQs during SRST */
|
||||
irq_enable = readl(port + PORT_IRQ_ENABLE_SET);
|
||||
writel(irq_enable, port + PORT_IRQ_ENABLE_CLR);
|
||||
|
||||
/* put the port into known state */
|
||||
if (sil24_init_port(ap)) {
|
||||
reason ="port not ready";
|
||||
|
@ -494,9 +562,6 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
|
|||
writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
|
||||
irq_stat >>= PORT_IRQ_RAW_SHIFT;
|
||||
|
||||
/* restore IRQs */
|
||||
writel(irq_enable, port + PORT_IRQ_ENABLE_SET);
|
||||
|
||||
if (!(irq_stat & PORT_IRQ_COMPLETE)) {
|
||||
if (irq_stat & PORT_IRQ_ERROR)
|
||||
reason = "SRST command error";
|
||||
|
@ -516,7 +581,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
printk(KERN_ERR "ata%u: softreset failed (%s)\n", ap->id, reason);
|
||||
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -528,10 +593,10 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
|
|||
u32 tmp;
|
||||
|
||||
/* sil24 does the right thing(tm) without any protection */
|
||||
ata_set_sata_spd(ap);
|
||||
sata_set_spd(ap);
|
||||
|
||||
tout_msec = 100;
|
||||
if (sata_dev_present(ap))
|
||||
if (ata_port_online(ap))
|
||||
tout_msec = 5000;
|
||||
|
||||
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
|
||||
|
@ -544,7 +609,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
|
|||
msleep(100);
|
||||
|
||||
if (tmp & PORT_CS_DEV_RST) {
|
||||
if (!sata_dev_present(ap))
|
||||
if (ata_port_offline(ap))
|
||||
return 0;
|
||||
reason = "link not ready";
|
||||
goto err;
|
||||
|
@ -561,7 +626,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
|
|||
return 0;
|
||||
|
||||
err:
|
||||
printk(KERN_ERR "ata%u: hardreset failed (%s)\n", ap->id, reason);
|
||||
ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -595,14 +660,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
|
|||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
struct sil24_port_priv *pp = ap->private_data;
|
||||
union sil24_cmd_block *cb = pp->cmd_block + qc->tag;
|
||||
union sil24_cmd_block *cb;
|
||||
struct sil24_prb *prb;
|
||||
struct sil24_sge *sge;
|
||||
u16 ctrl = 0;
|
||||
|
||||
cb = &pp->cmd_block[sil24_tag(qc->tag)];
|
||||
|
||||
switch (qc->tf.protocol) {
|
||||
case ATA_PROT_PIO:
|
||||
case ATA_PROT_DMA:
|
||||
case ATA_PROT_NCQ:
|
||||
case ATA_PROT_NODATA:
|
||||
prb = &cb->ata.prb;
|
||||
sge = cb->ata.sge;
|
||||
|
@ -640,12 +708,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
|
|||
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
struct sil24_port_priv *pp = ap->private_data;
|
||||
dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block);
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
unsigned int tag = sil24_tag(qc->tag);
|
||||
dma_addr_t paddr;
|
||||
void __iomem *activate;
|
||||
|
||||
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
|
||||
writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
|
||||
paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
|
||||
activate = port + PORT_CMD_ACTIVATE + tag * 8;
|
||||
|
||||
writel((u32)paddr, activate);
|
||||
writel((u64)paddr >> 32, activate + 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -655,166 +728,141 @@ static void sil24_irq_clear(struct ata_port *ap)
|
|||
/* unused */
|
||||
}
|
||||
|
||||
static int __sil24_restart_controller(void __iomem *port)
|
||||
static void sil24_freeze(struct ata_port *ap)
|
||||
{
|
||||
u32 tmp;
|
||||
int cnt;
|
||||
|
||||
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
|
||||
|
||||
/* Max ~10ms */
|
||||
for (cnt = 0; cnt < 10000; cnt++) {
|
||||
tmp = readl(port + PORT_CTRL_STAT);
|
||||
if (tmp & PORT_CS_RDY)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void sil24_restart_controller(struct ata_port *ap)
|
||||
{
|
||||
if (__sil24_restart_controller((void __iomem *)ap->ioaddr.cmd_addr))
|
||||
printk(KERN_ERR DRV_NAME
|
||||
" ata%u: failed to restart controller\n", ap->id);
|
||||
}
|
||||
|
||||
static int __sil24_reset_controller(void __iomem *port)
|
||||
{
|
||||
int cnt;
|
||||
u32 tmp;
|
||||
|
||||
/* Reset controller state. Is this correct? */
|
||||
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
|
||||
readl(port + PORT_CTRL_STAT); /* sync */
|
||||
|
||||
/* Max ~100ms */
|
||||
for (cnt = 0; cnt < 1000; cnt++) {
|
||||
udelay(100);
|
||||
tmp = readl(port + PORT_CTRL_STAT);
|
||||
if (!(tmp & PORT_CS_DEV_RST))
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp & PORT_CS_DEV_RST)
|
||||
return -1;
|
||||
|
||||
if (tmp & PORT_CS_RDY)
|
||||
return 0;
|
||||
|
||||
return __sil24_restart_controller(port);
|
||||
}
|
||||
|
||||
static void sil24_reset_controller(struct ata_port *ap)
|
||||
{
|
||||
printk(KERN_NOTICE DRV_NAME
|
||||
" ata%u: resetting controller...\n", ap->id);
|
||||
if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr))
|
||||
printk(KERN_ERR DRV_NAME
|
||||
" ata%u: failed to reset controller\n", ap->id);
|
||||
}
|
||||
|
||||
static void sil24_eng_timeout(struct ata_port *ap)
|
||||
{
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
|
||||
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
|
||||
qc->err_mask |= AC_ERR_TIMEOUT;
|
||||
ata_eh_qc_complete(qc);
|
||||
|
||||
sil24_reset_controller(ap);
|
||||
}
|
||||
|
||||
static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
|
||||
{
|
||||
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
struct sil24_port_priv *pp = ap->private_data;
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
u32 irq_stat, cmd_err, sstatus, serror;
|
||||
unsigned int err_mask;
|
||||
|
||||
irq_stat = readl(port + PORT_IRQ_STAT);
|
||||
writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */
|
||||
|
||||
if (!(irq_stat & PORT_IRQ_ERROR)) {
|
||||
/* ignore non-completion, non-error irqs for now */
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"ata%u: non-error exception irq (irq_stat %x)\n",
|
||||
ap->id, irq_stat);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd_err = readl(port + PORT_CMD_ERR);
|
||||
sstatus = readl(port + PORT_SSTATUS);
|
||||
serror = readl(port + PORT_SERROR);
|
||||
if (serror)
|
||||
writel(serror, port + PORT_SERROR);
|
||||
|
||||
/*
|
||||
* Don't log ATAPI device errors. They're supposed to happen
|
||||
* and any serious errors will be logged using sense data by
|
||||
* the SCSI layer.
|
||||
/* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
|
||||
* PORT_IRQ_ENABLE instead.
|
||||
*/
|
||||
if (ap->device[0].class != ATA_DEV_ATAPI || cmd_err > PORT_CERR_SDB)
|
||||
printk("ata%u: error interrupt on port%d\n"
|
||||
" stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n",
|
||||
ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror);
|
||||
writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
|
||||
}
|
||||
|
||||
if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) {
|
||||
/*
|
||||
* Device is reporting error, tf registers are valid.
|
||||
static void sil24_thaw(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
u32 tmp;
|
||||
|
||||
/* clear IRQ */
|
||||
tmp = readl(port + PORT_IRQ_STAT);
|
||||
writel(tmp, port + PORT_IRQ_STAT);
|
||||
|
||||
/* turn IRQ back on */
|
||||
writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET);
|
||||
}
|
||||
|
||||
static void sil24_error_intr(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
struct ata_eh_info *ehi = &ap->eh_info;
|
||||
int freeze = 0;
|
||||
u32 irq_stat;
|
||||
|
||||
/* on error, we need to clear IRQ explicitly */
|
||||
irq_stat = readl(port + PORT_IRQ_STAT);
|
||||
writel(irq_stat, port + PORT_IRQ_STAT);
|
||||
|
||||
/* first, analyze and record host port events */
|
||||
ata_ehi_clear_desc(ehi);
|
||||
|
||||
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
|
||||
|
||||
if (irq_stat & PORT_IRQ_DEV_XCHG) {
|
||||
ehi->err_mask |= AC_ERR_ATA_BUS;
|
||||
/* sil24 doesn't recover very well from phy
|
||||
* disconnection with a softreset. Force hardreset.
|
||||
*/
|
||||
sil24_update_tf(ap);
|
||||
err_mask = ac_err_mask(pp->tf.command);
|
||||
sil24_restart_controller(ap);
|
||||
} else {
|
||||
/*
|
||||
* Other errors. libata currently doesn't have any
|
||||
* mechanism to report these errors. Just turn on
|
||||
* ATA_ERR.
|
||||
*/
|
||||
err_mask = AC_ERR_OTHER;
|
||||
sil24_reset_controller(ap);
|
||||
ehi->action |= ATA_EH_HARDRESET;
|
||||
ata_ehi_push_desc(ehi, ", device_exchanged");
|
||||
freeze = 1;
|
||||
}
|
||||
|
||||
if (qc) {
|
||||
qc->err_mask |= err_mask;
|
||||
ata_qc_complete(qc);
|
||||
if (irq_stat & PORT_IRQ_UNK_FIS) {
|
||||
ehi->err_mask |= AC_ERR_HSM;
|
||||
ehi->action |= ATA_EH_SOFTRESET;
|
||||
ata_ehi_push_desc(ehi , ", unknown FIS");
|
||||
freeze = 1;
|
||||
}
|
||||
|
||||
/* deal with command error */
|
||||
if (irq_stat & PORT_IRQ_ERROR) {
|
||||
struct sil24_cerr_info *ci = NULL;
|
||||
unsigned int err_mask = 0, action = 0;
|
||||
struct ata_queued_cmd *qc;
|
||||
u32 cerr;
|
||||
|
||||
/* analyze CMD_ERR */
|
||||
cerr = readl(port + PORT_CMD_ERR);
|
||||
if (cerr < ARRAY_SIZE(sil24_cerr_db))
|
||||
ci = &sil24_cerr_db[cerr];
|
||||
|
||||
if (ci && ci->desc) {
|
||||
err_mask |= ci->err_mask;
|
||||
action |= ci->action;
|
||||
ata_ehi_push_desc(ehi, ", %s", ci->desc);
|
||||
} else {
|
||||
err_mask |= AC_ERR_OTHER;
|
||||
action |= ATA_EH_SOFTRESET;
|
||||
ata_ehi_push_desc(ehi, ", unknown command error %d",
|
||||
cerr);
|
||||
}
|
||||
|
||||
/* record error info */
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc) {
|
||||
sil24_update_tf(ap);
|
||||
qc->err_mask |= err_mask;
|
||||
} else
|
||||
ehi->err_mask |= err_mask;
|
||||
|
||||
ehi->action |= action;
|
||||
}
|
||||
|
||||
/* freeze or abort */
|
||||
if (freeze)
|
||||
ata_port_freeze(ap);
|
||||
else
|
||||
ata_port_abort(ap);
|
||||
}
|
||||
|
||||
static void sil24_finish_qc(struct ata_queued_cmd *qc)
|
||||
{
|
||||
if (qc->flags & ATA_QCFLAG_RESULT_TF)
|
||||
sil24_update_tf(qc->ap);
|
||||
}
|
||||
|
||||
static inline void sil24_host_intr(struct ata_port *ap)
|
||||
{
|
||||
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||
u32 slot_stat;
|
||||
u32 slot_stat, qc_active;
|
||||
int rc;
|
||||
|
||||
slot_stat = readl(port + PORT_SLOT_STAT);
|
||||
if (!(slot_stat & HOST_SSTAT_ATTN)) {
|
||||
struct sil24_port_priv *pp = ap->private_data;
|
||||
|
||||
if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
|
||||
writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
|
||||
if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
|
||||
sil24_error_intr(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* !HOST_SSAT_ATTN guarantees successful completion,
|
||||
* so reading back tf registers is unnecessary for
|
||||
* most commands. TODO: read tf registers for
|
||||
* commands which require these values on successful
|
||||
* completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER,
|
||||
* DEVICE RESET and READ PORT MULTIPLIER (any more?).
|
||||
*/
|
||||
sil24_update_tf(ap);
|
||||
if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
|
||||
writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
|
||||
|
||||
if (qc) {
|
||||
qc->err_mask |= ac_err_mask(pp->tf.command);
|
||||
ata_qc_complete(qc);
|
||||
}
|
||||
} else
|
||||
sil24_error_intr(ap, slot_stat);
|
||||
qc_active = slot_stat & ~HOST_SSTAT_ATTN;
|
||||
rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
|
||||
if (rc > 0)
|
||||
return;
|
||||
if (rc < 0) {
|
||||
struct ata_eh_info *ehi = &ap->eh_info;
|
||||
ehi->err_mask |= AC_ERR_HSM;
|
||||
ehi->action |= ATA_EH_SOFTRESET;
|
||||
ata_port_freeze(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ata_ratelimit())
|
||||
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
|
||||
"(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
|
||||
slot_stat, ap->active_tag, ap->sactive);
|
||||
}
|
||||
|
||||
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
|
@ -854,9 +902,34 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *
|
|||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static void sil24_error_handler(struct ata_port *ap)
|
||||
{
|
||||
struct ata_eh_context *ehc = &ap->eh_context;
|
||||
|
||||
if (sil24_init_port(ap)) {
|
||||
ata_eh_freeze_port(ap);
|
||||
ehc->i.action |= ATA_EH_HARDRESET;
|
||||
}
|
||||
|
||||
/* perform recovery */
|
||||
ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset);
|
||||
}
|
||||
|
||||
static void sil24_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;
|
||||
|
||||
/* make DMA engine forget about the failed command */
|
||||
if (qc->err_mask)
|
||||
sil24_init_port(ap);
|
||||
}
|
||||
|
||||
static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
|
||||
{
|
||||
const size_t cb_size = sizeof(*pp->cmd_block);
|
||||
const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
|
||||
|
||||
dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
|
||||
}
|
||||
|
@ -866,7 +939,7 @@ static int sil24_port_start(struct ata_port *ap)
|
|||
struct device *dev = ap->host_set->dev;
|
||||
struct sil24_port_priv *pp;
|
||||
union sil24_cmd_block *cb;
|
||||
size_t cb_size = sizeof(*cb);
|
||||
size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
|
||||
dma_addr_t cb_dma;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
|
@ -1066,15 +1139,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
/* Always use 64bit activation */
|
||||
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
|
||||
|
||||
/* Configure interrupts */
|
||||
writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
|
||||
writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
|
||||
PORT_IRQ_SDB_NOTIFY, port + PORT_IRQ_ENABLE_SET);
|
||||
|
||||
/* Clear interrupts */
|
||||
writel(0x0fff0fff, port + PORT_IRQ_STAT);
|
||||
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
|
||||
|
||||
/* Clear port multiplier enable and resume bits */
|
||||
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
|||
.sht = &pdc_sata_sht,
|
||||
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_SRST | ATA_FLAG_MMIO |
|
||||
ATA_FLAG_NO_ATAPI,
|
||||
ATA_FLAG_PIO_POLLING,
|
||||
.pio_mask = 0x1f, /* pio0-4 */
|
||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
|
||||
|
@ -833,11 +833,11 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
|
|||
tmp = mask & (1 << i);
|
||||
VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
|
||||
if (tmp && ap &&
|
||||
!(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) {
|
||||
!(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN)))
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
|
||||
handled += pdc20621_host_intr(ap, qc, (i > 4),
|
||||
mmio_base);
|
||||
}
|
||||
|
@ -868,15 +868,16 @@ static void pdc_eng_timeout(struct ata_port *ap)
|
|||
switch (qc->tf.protocol) {
|
||||
case ATA_PROT_DMA:
|
||||
case ATA_PROT_NODATA:
|
||||
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
|
||||
ata_port_printk(ap, KERN_ERR, "command timeout\n");
|
||||
qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
|
||||
break;
|
||||
|
||||
default:
|
||||
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
|
||||
|
||||
printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
|
||||
ap->id, qc->tf.command, drv_stat);
|
||||
ata_port_printk(ap, KERN_ERR,
|
||||
"unknown timeout, cmd 0x%x stat 0x%x\n",
|
||||
qc->tf.command, drv_stat);
|
||||
|
||||
qc->err_mask |= ac_err_mask(drv_stat);
|
||||
break;
|
||||
|
|
|
@ -221,14 +221,21 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
|
|||
|
||||
ap = host_set->ports[i];
|
||||
|
||||
if (ap && !(ap->flags &
|
||||
(ATA_FLAG_DISABLED|ATA_FLAG_NOINTR))) {
|
||||
if (is_vsc_sata_int_err(i, int_status)) {
|
||||
u32 err_status;
|
||||
printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
|
||||
err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
|
||||
vsc_sata_scr_write(ap, SCR_ERROR, err_status);
|
||||
handled++;
|
||||
}
|
||||
|
||||
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
|
||||
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
|
||||
handled += ata_host_intr(ap, qc);
|
||||
} else if (is_vsc_sata_int_err(i, int_status)) {
|
||||
else if (is_vsc_sata_int_err(i, int_status)) {
|
||||
/*
|
||||
* On some chips (i.e. Intel 31244), an error
|
||||
* interrupt will sneak in at initialization
|
||||
|
|
|
@ -719,6 +719,24 @@ void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq)
|
|||
*/
|
||||
static DEFINE_PER_CPU(struct list_head, scsi_done_q);
|
||||
|
||||
/**
|
||||
* scsi_req_abort_cmd -- Request command recovery for the specified command
|
||||
* cmd: pointer to the SCSI command of interest
|
||||
*
|
||||
* This function requests that SCSI Core start recovery for the
|
||||
* command by deleting the timer and adding the command to the eh
|
||||
* queue. It can be called by either LLDDs or SCSI Core. LLDDs who
|
||||
* implement their own error recovery MAY ignore the timeout event if
|
||||
* they generated scsi_req_abort_cmd.
|
||||
*/
|
||||
void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
if (!scsi_delete_timer(cmd))
|
||||
return;
|
||||
scsi_times_out(cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_req_abort_cmd);
|
||||
|
||||
/**
|
||||
* scsi_done - Enqueue the finished SCSI command into the done queue.
|
||||
* @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
|
||||
|
|
|
@ -56,6 +56,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
|
|||
printk("Waking error handler thread\n"));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_eh_wakeup);
|
||||
|
||||
/**
|
||||
* scsi_eh_scmd_add - add scsi cmd to error handling.
|
||||
|
@ -1517,7 +1518,7 @@ int scsi_error_handler(void *data)
|
|||
*/
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (!kthread_should_stop()) {
|
||||
if (shost->host_failed == 0 ||
|
||||
if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
|
||||
shost->host_failed != shost->host_busy) {
|
||||
SCSI_LOG_ERROR_RECOVERY(1,
|
||||
printk("Error handler scsi_eh_%d sleeping\n",
|
||||
|
|
|
@ -566,7 +566,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
|
|||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
shost->host_busy--;
|
||||
if (unlikely(scsi_host_in_recovery(shost) &&
|
||||
shost->host_failed))
|
||||
(shost->host_failed || shost->host_eh_scheduled)))
|
||||
scsi_eh_wakeup(shost);
|
||||
spin_unlock(shost->host_lock);
|
||||
spin_lock(sdev->request_queue->queue_lock);
|
||||
|
|
|
@ -63,7 +63,6 @@ extern int scsi_delete_timer(struct scsi_cmnd *);
|
|||
extern void scsi_times_out(struct scsi_cmnd *cmd);
|
||||
extern int scsi_error_handler(void *host);
|
||||
extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
|
||||
extern void scsi_eh_wakeup(struct Scsi_Host *shost);
|
||||
extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
|
||||
|
||||
/* scsi_lib.c */
|
||||
|
|
|
@ -97,6 +97,9 @@ enum {
|
|||
ATA_DRQ = (1 << 3), /* data request i/o */
|
||||
ATA_ERR = (1 << 0), /* have an error */
|
||||
ATA_SRST = (1 << 2), /* software reset */
|
||||
ATA_ICRC = (1 << 7), /* interface CRC error */
|
||||
ATA_UNC = (1 << 6), /* uncorrectable media error */
|
||||
ATA_IDNF = (1 << 4), /* ID not found */
|
||||
ATA_ABORTED = (1 << 2), /* command aborted */
|
||||
|
||||
/* ATA command block registers */
|
||||
|
@ -130,6 +133,8 @@ enum {
|
|||
ATA_CMD_WRITE = 0xCA,
|
||||
ATA_CMD_WRITE_EXT = 0x35,
|
||||
ATA_CMD_WRITE_FUA_EXT = 0x3D,
|
||||
ATA_CMD_FPDMA_READ = 0x60,
|
||||
ATA_CMD_FPDMA_WRITE = 0x61,
|
||||
ATA_CMD_PIO_READ = 0x20,
|
||||
ATA_CMD_PIO_READ_EXT = 0x24,
|
||||
ATA_CMD_PIO_WRITE = 0x30,
|
||||
|
@ -148,6 +153,10 @@ enum {
|
|||
ATA_CMD_INIT_DEV_PARAMS = 0x91,
|
||||
ATA_CMD_READ_NATIVE_MAX = 0xF8,
|
||||
ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
|
||||
ATA_CMD_READ_LOG_EXT = 0x2f,
|
||||
|
||||
/* READ_LOG_EXT pages */
|
||||
ATA_LOG_SATA_NCQ = 0x10,
|
||||
|
||||
/* SETFEATURES stuff */
|
||||
SETFEATURES_XFER = 0x03,
|
||||
|
@ -192,6 +201,16 @@ enum {
|
|||
SCR_ACTIVE = 3,
|
||||
SCR_NOTIFICATION = 4,
|
||||
|
||||
/* SError bits */
|
||||
SERR_DATA_RECOVERED = (1 << 0), /* recovered data error */
|
||||
SERR_COMM_RECOVERED = (1 << 1), /* recovered comm failure */
|
||||
SERR_DATA = (1 << 8), /* unrecovered data error */
|
||||
SERR_PERSISTENT = (1 << 9), /* persistent data/comm error */
|
||||
SERR_PROTOCOL = (1 << 10), /* protocol violation */
|
||||
SERR_INTERNAL = (1 << 11), /* host internal error */
|
||||
SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */
|
||||
SERR_DEV_XCHG = (1 << 26), /* device exchanged */
|
||||
|
||||
/* struct ata_taskfile flags */
|
||||
ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */
|
||||
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
|
||||
|
@ -199,6 +218,7 @@ enum {
|
|||
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
|
||||
ATA_TFLAG_LBA = (1 << 4), /* enable LBA */
|
||||
ATA_TFLAG_FUA = (1 << 5), /* enable FUA */
|
||||
ATA_TFLAG_POLLING = (1 << 6), /* set nIEN to 1 and use polling */
|
||||
};
|
||||
|
||||
enum ata_tf_protocols {
|
||||
|
@ -207,6 +227,7 @@ enum ata_tf_protocols {
|
|||
ATA_PROT_NODATA, /* no data */
|
||||
ATA_PROT_PIO, /* PIO single sector */
|
||||
ATA_PROT_DMA, /* DMA */
|
||||
ATA_PROT_NCQ, /* NCQ */
|
||||
ATA_PROT_ATAPI, /* packet command, PIO data xfer*/
|
||||
ATA_PROT_ATAPI_NODATA, /* packet command, no data */
|
||||
ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */
|
||||
|
@ -262,6 +283,8 @@ struct ata_taskfile {
|
|||
#define ata_id_has_pm(id) ((id)[82] & (1 << 3))
|
||||
#define ata_id_has_lba(id) ((id)[49] & (1 << 9))
|
||||
#define ata_id_has_dma(id) ((id)[49] & (1 << 8))
|
||||
#define ata_id_has_ncq(id) ((id)[76] & (1 << 8))
|
||||
#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
|
||||
#define ata_id_removeable(id) ((id)[0] & (1 << 7))
|
||||
#define ata_id_has_dword_io(id) ((id)[50] & (1 << 0))
|
||||
#define ata_id_u32(id,n) \
|
||||
|
@ -272,6 +295,8 @@ struct ata_taskfile {
|
|||
((u64) (id)[(n) + 1] << 16) | \
|
||||
((u64) (id)[(n) + 0]) )
|
||||
|
||||
#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20)
|
||||
|
||||
static inline unsigned int ata_id_major_version(const u16 *id)
|
||||
{
|
||||
unsigned int mver;
|
||||
|
@ -311,6 +336,15 @@ static inline int is_atapi_taskfile(const struct ata_taskfile *tf)
|
|||
(tf->protocol == ATA_PROT_ATAPI_DMA);
|
||||
}
|
||||
|
||||
static inline int is_multi_taskfile(struct ata_taskfile *tf)
|
||||
{
|
||||
return (tf->command == ATA_CMD_READ_MULTI) ||
|
||||
(tf->command == ATA_CMD_WRITE_MULTI) ||
|
||||
(tf->command == ATA_CMD_READ_MULTI_EXT) ||
|
||||
(tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
|
||||
(tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
|
||||
}
|
||||
|
||||
static inline int ata_ok(u8 status)
|
||||
{
|
||||
return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
|
||||
|
|
|
@ -108,7 +108,9 @@ enum {
|
|||
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
|
||||
ATA_MAX_PORTS = 8,
|
||||
ATA_DEF_QUEUE = 1,
|
||||
ATA_MAX_QUEUE = 1,
|
||||
/* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */
|
||||
ATA_MAX_QUEUE = 32,
|
||||
ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1,
|
||||
ATA_MAX_SECTORS = 200, /* FIXME */
|
||||
ATA_MAX_BUS = 2,
|
||||
ATA_DEF_BUSY_WAIT = 10000,
|
||||
|
@ -122,6 +124,8 @@ enum {
|
|||
/* struct ata_device stuff */
|
||||
ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */
|
||||
ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */
|
||||
ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */
|
||||
ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
|
||||
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
|
||||
|
||||
ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
|
||||
|
@ -145,14 +149,19 @@ enum {
|
|||
ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */
|
||||
ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */
|
||||
ATA_FLAG_IRQ_MASK = (1 << 9), /* Mask IRQ in PIO xfers */
|
||||
ATA_FLAG_PIO_POLLING = (1 << 10), /* use polling PIO if LLD
|
||||
* doesn't handle PIO interrupts */
|
||||
ATA_FLAG_NCQ = (1 << 11), /* host supports NCQ */
|
||||
|
||||
ATA_FLAG_NOINTR = (1 << 16), /* FIXME: Remove this once
|
||||
* proper HSM is in place. */
|
||||
ATA_FLAG_DEBUGMSG = (1 << 17),
|
||||
ATA_FLAG_FLUSH_PORT_TASK = (1 << 18), /* flush port task */
|
||||
ATA_FLAG_DEBUGMSG = (1 << 14),
|
||||
ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* flush port task */
|
||||
|
||||
ATA_FLAG_DISABLED = (1 << 19), /* port is disabled, ignore it */
|
||||
ATA_FLAG_SUSPENDED = (1 << 20), /* port is suspended */
|
||||
ATA_FLAG_EH_PENDING = (1 << 16), /* EH pending */
|
||||
ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
|
||||
ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
|
||||
|
||||
ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */
|
||||
ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */
|
||||
|
||||
/* bits 24:31 of ap->flags are reserved for LLDD specific flags */
|
||||
|
||||
|
@ -162,17 +171,18 @@ enum {
|
|||
ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */
|
||||
ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
|
||||
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
|
||||
ATA_QCFLAG_EH_SCHEDULED = (1 << 4), /* EH scheduled */
|
||||
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
|
||||
|
||||
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
|
||||
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
|
||||
ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */
|
||||
|
||||
/* host set flags */
|
||||
ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */
|
||||
|
||||
/* various lengths of time */
|
||||
ATA_TMOUT_PIO = 30 * HZ,
|
||||
ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
|
||||
ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */
|
||||
ATA_TMOUT_CDB = 30 * HZ,
|
||||
ATA_TMOUT_CDB_QUICK = 5 * HZ,
|
||||
ATA_TMOUT_INTERNAL = 30 * HZ,
|
||||
ATA_TMOUT_INTERNAL_QUICK = 5 * HZ,
|
||||
|
||||
|
@ -216,19 +226,39 @@ enum {
|
|||
ATA_PORT_PRIMARY = (1 << 0),
|
||||
ATA_PORT_SECONDARY = (1 << 1),
|
||||
|
||||
/* ering size */
|
||||
ATA_ERING_SIZE = 32,
|
||||
|
||||
/* desc_len for ata_eh_info and context */
|
||||
ATA_EH_DESC_LEN = 80,
|
||||
|
||||
/* reset / recovery action types */
|
||||
ATA_EH_REVALIDATE = (1 << 0),
|
||||
ATA_EH_SOFTRESET = (1 << 1),
|
||||
ATA_EH_HARDRESET = (1 << 2),
|
||||
|
||||
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
|
||||
|
||||
/* ata_eh_info->flags */
|
||||
ATA_EHI_DID_RESET = (1 << 0), /* already reset this port */
|
||||
|
||||
/* max repeat if error condition is still set after ->error_handler */
|
||||
ATA_EH_MAX_REPEAT = 5,
|
||||
|
||||
/* how hard are we gonna try to probe/recover devices */
|
||||
ATA_PROBE_MAX_TRIES = 3,
|
||||
ATA_EH_RESET_TRIES = 3,
|
||||
ATA_EH_DEV_TRIES = 3,
|
||||
};
|
||||
|
||||
enum hsm_task_states {
|
||||
HSM_ST_UNKNOWN,
|
||||
HSM_ST_IDLE,
|
||||
HSM_ST_POLL,
|
||||
HSM_ST_TMOUT,
|
||||
HSM_ST,
|
||||
HSM_ST_LAST,
|
||||
HSM_ST_LAST_POLL,
|
||||
HSM_ST_ERR,
|
||||
HSM_ST_UNKNOWN, /* state unknown */
|
||||
HSM_ST_IDLE, /* no command on going */
|
||||
HSM_ST, /* (waiting the device to) transfer data */
|
||||
HSM_ST_LAST, /* (waiting the device to) complete command */
|
||||
HSM_ST_ERR, /* error */
|
||||
HSM_ST_FIRST, /* (waiting the device to)
|
||||
write CDB or first data block */
|
||||
};
|
||||
|
||||
enum ata_completion_errors {
|
||||
|
@ -343,7 +373,7 @@ struct ata_queued_cmd {
|
|||
struct scatterlist *__sg;
|
||||
|
||||
unsigned int err_mask;
|
||||
|
||||
struct ata_taskfile result_tf;
|
||||
ata_qc_cb_t complete_fn;
|
||||
|
||||
void *private_data;
|
||||
|
@ -355,12 +385,24 @@ struct ata_host_stats {
|
|||
unsigned long rw_reqbuf;
|
||||
};
|
||||
|
||||
struct ata_ering_entry {
|
||||
int is_io;
|
||||
unsigned int err_mask;
|
||||
u64 timestamp;
|
||||
};
|
||||
|
||||
struct ata_ering {
|
||||
int cursor;
|
||||
struct ata_ering_entry ring[ATA_ERING_SIZE];
|
||||
};
|
||||
|
||||
struct ata_device {
|
||||
struct ata_port *ap;
|
||||
u64 n_sectors; /* size of device, if ATA */
|
||||
unsigned long flags; /* ATA_DFLAG_xxx */
|
||||
unsigned int class; /* ATA_DEV_xxx */
|
||||
unsigned int devno; /* 0 or 1 */
|
||||
u16 *id; /* IDENTIFY xxx DEVICE data */
|
||||
u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
|
||||
u8 pio_mode;
|
||||
u8 dma_mode;
|
||||
u8 xfer_mode;
|
||||
|
@ -380,6 +422,24 @@ struct ata_device {
|
|||
u16 cylinders; /* Number of cylinders */
|
||||
u16 heads; /* Number of heads */
|
||||
u16 sectors; /* Number of sectors per track */
|
||||
|
||||
/* error history */
|
||||
struct ata_ering ering;
|
||||
};
|
||||
|
||||
struct ata_eh_info {
|
||||
struct ata_device *dev; /* offending device */
|
||||
u32 serror; /* SError from LLDD */
|
||||
unsigned int err_mask; /* port-wide err_mask */
|
||||
unsigned int action; /* ATA_EH_* action mask */
|
||||
unsigned int flags; /* ATA_EHI_* flags */
|
||||
char desc[ATA_EH_DESC_LEN];
|
||||
int desc_len;
|
||||
};
|
||||
|
||||
struct ata_eh_context {
|
||||
struct ata_eh_info i;
|
||||
int tries[ATA_MAX_DEVICES];
|
||||
};
|
||||
|
||||
struct ata_port {
|
||||
|
@ -406,11 +466,19 @@ struct ata_port {
|
|||
unsigned int cbl; /* cable type; ATA_CBL_xxx */
|
||||
unsigned int sata_spd_limit; /* SATA PHY speed limit */
|
||||
|
||||
/* record runtime error info, protected by host_set lock */
|
||||
struct ata_eh_info eh_info;
|
||||
/* EH context owned by EH */
|
||||
struct ata_eh_context eh_context;
|
||||
|
||||
struct ata_device device[ATA_MAX_DEVICES];
|
||||
|
||||
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
|
||||
unsigned long qactive;
|
||||
unsigned long qc_allocated;
|
||||
unsigned int qc_active;
|
||||
|
||||
unsigned int active_tag;
|
||||
u32 sactive;
|
||||
|
||||
struct ata_host_stats stats;
|
||||
struct ata_host_set *host_set;
|
||||
|
@ -419,12 +487,13 @@ struct ata_port {
|
|||
struct work_struct port_task;
|
||||
|
||||
unsigned int hsm_task_state;
|
||||
unsigned long pio_task_timeout;
|
||||
|
||||
u32 msg_enable;
|
||||
struct list_head eh_done_q;
|
||||
|
||||
void *private_data;
|
||||
|
||||
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
|
||||
};
|
||||
|
||||
struct ata_port_operations {
|
||||
|
@ -458,7 +527,15 @@ struct ata_port_operations {
|
|||
void (*qc_prep) (struct ata_queued_cmd *qc);
|
||||
unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
|
||||
|
||||
void (*eng_timeout) (struct ata_port *ap);
|
||||
/* Error handlers. ->error_handler overrides ->eng_timeout and
|
||||
* indicates that new-style EH is in place.
|
||||
*/
|
||||
void (*eng_timeout) (struct ata_port *ap); /* obsolete */
|
||||
|
||||
void (*freeze) (struct ata_port *ap);
|
||||
void (*thaw) (struct ata_port *ap);
|
||||
void (*error_handler) (struct ata_port *ap);
|
||||
void (*post_internal_cmd) (struct ata_queued_cmd *qc);
|
||||
|
||||
irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
|
||||
void (*irq_clear) (struct ata_port *);
|
||||
|
@ -504,7 +581,7 @@ extern void ata_port_probe(struct ata_port *);
|
|||
extern void __sata_phy_reset(struct ata_port *ap);
|
||||
extern void sata_phy_reset(struct ata_port *ap);
|
||||
extern void ata_bus_reset(struct ata_port *ap);
|
||||
extern int ata_set_sata_spd(struct ata_port *ap);
|
||||
extern int sata_set_spd(struct ata_port *ap);
|
||||
extern int ata_drive_probe_reset(struct ata_port *ap,
|
||||
ata_probeinit_fn_t probeinit,
|
||||
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
|
||||
|
@ -513,8 +590,7 @@ extern void ata_std_probeinit(struct ata_port *ap);
|
|||
extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
|
||||
extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
|
||||
extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
|
||||
extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
|
||||
int post_reset);
|
||||
extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
|
||||
extern void ata_port_disable(struct ata_port *);
|
||||
extern void ata_std_ports(struct ata_ioports *ioaddr);
|
||||
#ifdef CONFIG_PCI
|
||||
|
@ -530,14 +606,18 @@ extern void ata_host_set_remove(struct ata_host_set *host_set);
|
|||
extern int ata_scsi_detect(struct scsi_host_template *sht);
|
||||
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
|
||||
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
|
||||
extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
|
||||
extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
|
||||
extern int ata_scsi_release(struct Scsi_Host *host);
|
||||
extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
|
||||
extern int sata_scr_valid(struct ata_port *ap);
|
||||
extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
|
||||
extern int sata_scr_write(struct ata_port *ap, int reg, u32 val);
|
||||
extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
|
||||
extern int ata_port_online(struct ata_port *ap);
|
||||
extern int ata_port_offline(struct ata_port *ap);
|
||||
extern int ata_scsi_device_resume(struct scsi_device *);
|
||||
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
|
||||
extern int ata_device_resume(struct ata_port *, struct ata_device *);
|
||||
extern int ata_device_suspend(struct ata_port *, struct ata_device *, pm_message_t state);
|
||||
extern int ata_device_resume(struct ata_device *);
|
||||
extern int ata_device_suspend(struct ata_device *, pm_message_t state);
|
||||
extern int ata_ratelimit(void);
|
||||
extern unsigned int ata_busy_sleep(struct ata_port *ap,
|
||||
unsigned long timeout_pat,
|
||||
|
@ -582,16 +662,26 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc);
|
|||
extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
|
||||
extern u8 ata_bmdma_status(struct ata_port *ap);
|
||||
extern void ata_bmdma_irq_clear(struct ata_port *ap);
|
||||
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
|
||||
extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
|
||||
struct scsi_cmnd *cmd,
|
||||
extern void ata_bmdma_freeze(struct ata_port *ap);
|
||||
extern void ata_bmdma_thaw(struct ata_port *ap);
|
||||
extern void ata_bmdma_drive_eh(struct ata_port *ap,
|
||||
ata_reset_fn_t softreset,
|
||||
ata_reset_fn_t hardreset,
|
||||
ata_postreset_fn_t postreset);
|
||||
extern void ata_bmdma_error_handler(struct ata_port *ap);
|
||||
extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
|
||||
extern void ata_qc_complete(struct ata_queued_cmd *qc);
|
||||
extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
|
||||
void (*finish_qc)(struct ata_queued_cmd *));
|
||||
extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
extern int ata_std_bios_param(struct scsi_device *sdev,
|
||||
struct block_device *bdev,
|
||||
sector_t capacity, int geom[]);
|
||||
extern int ata_scsi_slave_config(struct scsi_device *sdev);
|
||||
extern struct ata_device *ata_dev_pair(struct ata_port *ap,
|
||||
struct ata_device *adev);
|
||||
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
|
||||
int queue_depth);
|
||||
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
|
||||
|
||||
/*
|
||||
* Timing helpers
|
||||
|
@ -641,10 +731,46 @@ extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_
|
|||
* EH
|
||||
*/
|
||||
extern void ata_eng_timeout(struct ata_port *ap);
|
||||
|
||||
extern void ata_port_schedule_eh(struct ata_port *ap);
|
||||
extern int ata_port_abort(struct ata_port *ap);
|
||||
extern int ata_port_freeze(struct ata_port *ap);
|
||||
|
||||
extern void ata_eh_freeze_port(struct ata_port *ap);
|
||||
extern void ata_eh_thaw_port(struct ata_port *ap);
|
||||
|
||||
extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
|
||||
extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
|
||||
|
||||
extern void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset,
|
||||
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
|
||||
|
||||
/*
|
||||
* printk helpers
|
||||
*/
|
||||
#define ata_port_printk(ap, lv, fmt, args...) \
|
||||
printk(lv"ata%u: "fmt, (ap)->id , ##args)
|
||||
|
||||
#define ata_dev_printk(dev, lv, fmt, args...) \
|
||||
printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args)
|
||||
|
||||
/*
|
||||
* ata_eh_info helpers
|
||||
*/
|
||||
#define ata_ehi_push_desc(ehi, fmt, args...) do { \
|
||||
(ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \
|
||||
ATA_EH_DESC_LEN - (ehi)->desc_len, \
|
||||
fmt , ##args); \
|
||||
} while (0)
|
||||
|
||||
#define ata_ehi_clear_desc(ehi) do { \
|
||||
(ehi)->desc[0] = '\0'; \
|
||||
(ehi)->desc_len = 0; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* qc helpers
|
||||
*/
|
||||
static inline int
|
||||
ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc)
|
||||
{
|
||||
|
@ -687,6 +813,11 @@ static inline unsigned int ata_tag_valid(unsigned int tag)
|
|||
return (tag < ATA_MAX_QUEUE) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline unsigned int ata_tag_internal(unsigned int tag)
|
||||
{
|
||||
return tag == ATA_MAX_QUEUE - 1;
|
||||
}
|
||||
|
||||
static inline unsigned int ata_class_enabled(unsigned int class)
|
||||
{
|
||||
return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
|
||||
|
@ -795,20 +926,35 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc)
|
|||
qc->tf.ctl |= ATA_NIEN;
|
||||
}
|
||||
|
||||
static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap,
|
||||
unsigned int tag)
|
||||
static inline struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap,
|
||||
unsigned int tag)
|
||||
{
|
||||
if (likely(ata_tag_valid(tag)))
|
||||
return &ap->qcmd[tag];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, unsigned int device)
|
||||
static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap,
|
||||
unsigned int tag)
|
||||
{
|
||||
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
|
||||
|
||||
if (unlikely(!qc) || !ap->ops->error_handler)
|
||||
return qc;
|
||||
|
||||
if ((qc->flags & (ATA_QCFLAG_ACTIVE |
|
||||
ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE)
|
||||
return qc;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
|
||||
{
|
||||
memset(tf, 0, sizeof(*tf));
|
||||
|
||||
tf->ctl = ap->ctl;
|
||||
if (device == 0)
|
||||
tf->ctl = dev->ap->ctl;
|
||||
if (dev->devno == 0)
|
||||
tf->device = ATA_DEVICE_OBS;
|
||||
else
|
||||
tf->device = ATA_DEVICE_OBS | ATA_DEV1;
|
||||
|
@ -823,26 +969,11 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
|
|||
qc->nbytes = qc->curbytes = 0;
|
||||
qc->err_mask = 0;
|
||||
|
||||
ata_tf_init(qc->ap, &qc->tf, qc->dev->devno);
|
||||
}
|
||||
ata_tf_init(qc->dev, &qc->tf);
|
||||
|
||||
/**
|
||||
* ata_qc_complete - Complete an active ATA command
|
||||
* @qc: Command to complete
|
||||
* @err_mask: ATA Status register contents
|
||||
*
|
||||
* Indicate to the mid and upper layers that an ATA
|
||||
* command has completed, with either an ok or not-ok status.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host_set lock)
|
||||
*/
|
||||
static inline void ata_qc_complete(struct ata_queued_cmd *qc)
|
||||
{
|
||||
if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED))
|
||||
return;
|
||||
|
||||
__ata_qc_complete(qc);
|
||||
/* init result_tf such that it indicates normal completion */
|
||||
qc->result_tf.command = ATA_DRDY;
|
||||
qc->result_tf.feature = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -921,28 +1052,6 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
|
|||
return status;
|
||||
}
|
||||
|
||||
static inline u32 scr_read(struct ata_port *ap, unsigned int reg)
|
||||
{
|
||||
return ap->ops->scr_read(ap, reg);
|
||||
}
|
||||
|
||||
static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val)
|
||||
{
|
||||
ap->ops->scr_write(ap, reg, val);
|
||||
}
|
||||
|
||||
static inline void scr_write_flush(struct ata_port *ap, unsigned int reg,
|
||||
u32 val)
|
||||
{
|
||||
ap->ops->scr_write(ap, reg, val);
|
||||
(void) ap->ops->scr_read(ap, reg);
|
||||
}
|
||||
|
||||
static inline unsigned int sata_dev_present(struct ata_port *ap)
|
||||
{
|
||||
return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int ata_try_flush_cache(const struct ata_device *dev)
|
||||
{
|
||||
return ata_id_wcache_enabled(dev->id) ||
|
||||
|
|
|
@ -151,5 +151,6 @@ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
|
|||
extern void scsi_put_command(struct scsi_cmnd *);
|
||||
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
|
||||
extern void scsi_finish_command(struct scsi_cmnd *cmd);
|
||||
extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
|
||||
|
||||
#endif /* _SCSI_SCSI_CMND_H */
|
||||
|
|
|
@ -35,6 +35,7 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
|
|||
}
|
||||
|
||||
|
||||
extern void scsi_eh_wakeup(struct Scsi_Host *shost);
|
||||
extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
|
||||
struct list_head *done_q);
|
||||
extern void scsi_eh_flush_done_q(struct list_head *done_q);
|
||||
|
|
|
@ -472,6 +472,7 @@ struct Scsi_Host {
|
|||
*/
|
||||
unsigned int host_busy; /* commands actually active on low-level */
|
||||
unsigned int host_failed; /* commands that failed. */
|
||||
unsigned int host_eh_scheduled; /* EH scheduled without command */
|
||||
|
||||
unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
|
||||
int resetting; /* if set, it means that last_reset is a valid value */
|
||||
|
|
Загрузка…
Ссылка в новой задаче