Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: libata: implement and use ATA_QCFLAG_QUIET libata: stop being overjealous about non-IO commands libata: flush is an IO command sata_promise: cleanups sata_promise: ASIC PRD table bug workaround, take 2
This commit is contained in:
commit
8c1ee54cb3
5 changed files with 115 additions and 23 deletions
|
@ -1800,10 +1800,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
|
||||||
qc->err_mask &= ~AC_ERR_OTHER;
|
qc->err_mask &= ~AC_ERR_OTHER;
|
||||||
|
|
||||||
/* SENSE_VALID trumps dev/unknown error and revalidation */
|
/* SENSE_VALID trumps dev/unknown error and revalidation */
|
||||||
if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
|
if (qc->flags & ATA_QCFLAG_SENSE_VALID)
|
||||||
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
|
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
|
||||||
ehc->i.action &= ~ATA_EH_REVALIDATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* accumulate error info */
|
/* accumulate error info */
|
||||||
ehc->i.dev = qc->dev;
|
ehc->i.dev = qc->dev;
|
||||||
|
@ -1816,7 +1814,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
|
||||||
if (ap->pflags & ATA_PFLAG_FROZEN ||
|
if (ap->pflags & ATA_PFLAG_FROZEN ||
|
||||||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
|
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
|
||||||
ehc->i.action |= ATA_EH_SOFTRESET;
|
ehc->i.action |= ATA_EH_SOFTRESET;
|
||||||
else if (all_err_mask)
|
else if ((is_io && all_err_mask) ||
|
||||||
|
(!is_io && (all_err_mask & ~AC_ERR_DEV)))
|
||||||
ehc->i.action |= ATA_EH_REVALIDATE;
|
ehc->i.action |= ATA_EH_REVALIDATE;
|
||||||
|
|
||||||
/* if we have offending qcs and the associated failed device */
|
/* if we have offending qcs and the associated failed device */
|
||||||
|
@ -1879,7 +1878,9 @@ static void ata_eh_link_report(struct ata_link *link)
|
||||||
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
|
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
|
||||||
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
|
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
|
||||||
|
|
||||||
if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
|
if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link ||
|
||||||
|
((qc->flags & ATA_QCFLAG_QUIET) &&
|
||||||
|
qc->err_mask == AC_ERR_DEV))
|
||||||
continue;
|
continue;
|
||||||
if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
|
if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
|
||||||
continue;
|
continue;
|
||||||
|
@ -2697,8 +2698,15 @@ void ata_eh_finish(struct ata_port *ap)
|
||||||
/* FIXME: Once EH migration is complete,
|
/* FIXME: Once EH migration is complete,
|
||||||
* generate sense data in this function,
|
* generate sense data in this function,
|
||||||
* considering both err_mask and tf.
|
* considering both err_mask and tf.
|
||||||
|
*
|
||||||
|
* There's no point in retrying invalid
|
||||||
|
* (detected by libata) and non-IO device
|
||||||
|
* errors (rejected by device). Finish them
|
||||||
|
* immediately.
|
||||||
*/
|
*/
|
||||||
if (qc->err_mask & AC_ERR_INVALID)
|
if ((qc->err_mask & AC_ERR_INVALID) ||
|
||||||
|
(!(qc->flags & ATA_QCFLAG_IO) &&
|
||||||
|
qc->err_mask == AC_ERR_DEV))
|
||||||
ata_eh_qc_complete(qc);
|
ata_eh_qc_complete(qc);
|
||||||
else
|
else
|
||||||
ata_eh_qc_retry(qc);
|
ata_eh_qc_retry(qc);
|
||||||
|
|
|
@ -1108,6 +1108,9 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc)
|
||||||
else
|
else
|
||||||
tf->command = ATA_CMD_FLUSH;
|
tf->command = ATA_CMD_FLUSH;
|
||||||
|
|
||||||
|
/* flush is critical for IO integrity, consider it an IO command */
|
||||||
|
qc->flags |= ATA_QCFLAG_IO;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2764,8 +2767,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
|
||||||
*/
|
*/
|
||||||
qc->nbytes = scsi_bufflen(scmd);
|
qc->nbytes = scsi_bufflen(scmd);
|
||||||
|
|
||||||
/* request result TF */
|
/* request result TF and be quiet about device error */
|
||||||
qc->flags |= ATA_QCFLAG_RESULT_TF;
|
qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* sata_promise.c - Promise SATA
|
* sata_promise.c - Promise SATA
|
||||||
*
|
*
|
||||||
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
|
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
|
||||||
|
* Mikael Pettersson <mikpe@it.uu.se>
|
||||||
* Please ALWAYS copy linux-ide@vger.kernel.org
|
* Please ALWAYS copy linux-ide@vger.kernel.org
|
||||||
* on emails.
|
* on emails.
|
||||||
*
|
*
|
||||||
|
@ -45,11 +46,12 @@
|
||||||
#include "sata_promise.h"
|
#include "sata_promise.h"
|
||||||
|
|
||||||
#define DRV_NAME "sata_promise"
|
#define DRV_NAME "sata_promise"
|
||||||
#define DRV_VERSION "2.10"
|
#define DRV_VERSION "2.11"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PDC_MAX_PORTS = 4,
|
PDC_MAX_PORTS = 4,
|
||||||
PDC_MMIO_BAR = 3,
|
PDC_MMIO_BAR = 3,
|
||||||
|
PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
|
||||||
|
|
||||||
/* register offsets */
|
/* register offsets */
|
||||||
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
|
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
|
||||||
|
@ -157,7 +159,7 @@ static struct scsi_host_template pdc_ata_sht = {
|
||||||
.queuecommand = ata_scsi_queuecmd,
|
.queuecommand = ata_scsi_queuecmd,
|
||||||
.can_queue = ATA_DEF_QUEUE,
|
.can_queue = ATA_DEF_QUEUE,
|
||||||
.this_id = ATA_SHT_THIS_ID,
|
.this_id = ATA_SHT_THIS_ID,
|
||||||
.sg_tablesize = LIBATA_MAX_PRD,
|
.sg_tablesize = PDC_MAX_PRD,
|
||||||
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
|
||||||
.emulated = ATA_SHT_EMULATED,
|
.emulated = ATA_SHT_EMULATED,
|
||||||
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
.use_clustering = ATA_SHT_USE_CLUSTERING,
|
||||||
|
@ -240,7 +242,7 @@ static const struct ata_port_operations pdc_pata_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ata_port_info pdc_port_info[] = {
|
static const struct ata_port_info pdc_port_info[] = {
|
||||||
/* board_2037x */
|
[board_2037x] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
||||||
PDC_FLAG_SATA_PATA,
|
PDC_FLAG_SATA_PATA,
|
||||||
|
@ -250,7 +252,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
||||||
.port_ops = &pdc_old_sata_ops,
|
.port_ops = &pdc_old_sata_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* board_2037x_pata */
|
[board_2037x_pata] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
|
||||||
.pio_mask = 0x1f, /* pio0-4 */
|
.pio_mask = 0x1f, /* pio0-4 */
|
||||||
|
@ -259,7 +261,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
||||||
.port_ops = &pdc_pata_ops,
|
.port_ops = &pdc_pata_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* board_20319 */
|
[board_20319] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
||||||
PDC_FLAG_4_PORTS,
|
PDC_FLAG_4_PORTS,
|
||||||
|
@ -269,7 +271,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
||||||
.port_ops = &pdc_old_sata_ops,
|
.port_ops = &pdc_old_sata_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* board_20619 */
|
[board_20619] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
||||||
PDC_FLAG_4_PORTS,
|
PDC_FLAG_4_PORTS,
|
||||||
|
@ -279,7 +281,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
||||||
.port_ops = &pdc_pata_ops,
|
.port_ops = &pdc_pata_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* board_2057x */
|
[board_2057x] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
||||||
PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
|
PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
|
||||||
|
@ -289,7 +291,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
||||||
.port_ops = &pdc_sata_ops,
|
.port_ops = &pdc_sata_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* board_2057x_pata */
|
[board_2057x_pata] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
|
||||||
PDC_FLAG_GEN_II,
|
PDC_FLAG_GEN_II,
|
||||||
|
@ -299,7 +301,7 @@ static const struct ata_port_info pdc_port_info[] = {
|
||||||
.port_ops = &pdc_pata_ops,
|
.port_ops = &pdc_pata_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* board_40518 */
|
[board_40518] =
|
||||||
{
|
{
|
||||||
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
|
||||||
PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
|
PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
|
||||||
|
@ -523,6 +525,84 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
|
||||||
memcpy(buf+31, cdb, cdb_len);
|
memcpy(buf+31, cdb, cdb_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pdc_fill_sg - Fill PCI IDE PRD table
|
||||||
|
* @qc: Metadata associated with taskfile to be transferred
|
||||||
|
*
|
||||||
|
* Fill PCI IDE PRD (scatter-gather) table with segments
|
||||||
|
* associated with the current disk command.
|
||||||
|
* Make sure hardware does not choke on it.
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* spin_lock_irqsave(host lock)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void pdc_fill_sg(struct ata_queued_cmd *qc)
|
||||||
|
{
|
||||||
|
struct ata_port *ap = qc->ap;
|
||||||
|
struct scatterlist *sg;
|
||||||
|
unsigned int idx;
|
||||||
|
const u32 SG_COUNT_ASIC_BUG = 41*4;
|
||||||
|
|
||||||
|
if (!(qc->flags & ATA_QCFLAG_DMAMAP))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WARN_ON(qc->__sg == NULL);
|
||||||
|
WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
ata_for_each_sg(sg, qc) {
|
||||||
|
u32 addr, offset;
|
||||||
|
u32 sg_len, len;
|
||||||
|
|
||||||
|
/* determine if physical DMA addr spans 64K boundary.
|
||||||
|
* Note h/w doesn't support 64-bit, so we unconditionally
|
||||||
|
* truncate dma_addr_t to u32.
|
||||||
|
*/
|
||||||
|
addr = (u32) sg_dma_address(sg);
|
||||||
|
sg_len = sg_dma_len(sg);
|
||||||
|
|
||||||
|
while (sg_len) {
|
||||||
|
offset = addr & 0xffff;
|
||||||
|
len = sg_len;
|
||||||
|
if ((offset + sg_len) > 0x10000)
|
||||||
|
len = 0x10000 - offset;
|
||||||
|
|
||||||
|
ap->prd[idx].addr = cpu_to_le32(addr);
|
||||||
|
ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
|
||||||
|
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
sg_len -= len;
|
||||||
|
addr += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx) {
|
||||||
|
u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
|
||||||
|
|
||||||
|
if (len > SG_COUNT_ASIC_BUG) {
|
||||||
|
u32 addr;
|
||||||
|
|
||||||
|
VPRINTK("Splitting last PRD.\n");
|
||||||
|
|
||||||
|
addr = le32_to_cpu(ap->prd[idx - 1].addr);
|
||||||
|
ap->prd[idx - 1].flags_len -= cpu_to_le32(SG_COUNT_ASIC_BUG);
|
||||||
|
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
|
||||||
|
|
||||||
|
addr = addr + len - SG_COUNT_ASIC_BUG;
|
||||||
|
len = SG_COUNT_ASIC_BUG;
|
||||||
|
ap->prd[idx].addr = cpu_to_le32(addr);
|
||||||
|
ap->prd[idx].flags_len = cpu_to_le32(len);
|
||||||
|
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct pdc_port_priv *pp = qc->ap->private_data;
|
struct pdc_port_priv *pp = qc->ap->private_data;
|
||||||
|
@ -532,7 +612,7 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
||||||
|
|
||||||
switch (qc->tf.protocol) {
|
switch (qc->tf.protocol) {
|
||||||
case ATA_PROT_DMA:
|
case ATA_PROT_DMA:
|
||||||
ata_qc_prep(qc);
|
pdc_fill_sg(qc);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case ATA_PROT_NODATA:
|
case ATA_PROT_NODATA:
|
||||||
|
@ -548,11 +628,11 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ATA_PROT_ATAPI:
|
case ATA_PROT_ATAPI:
|
||||||
ata_qc_prep(qc);
|
pdc_fill_sg(qc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ATA_PROT_ATAPI_DMA:
|
case ATA_PROT_ATAPI_DMA:
|
||||||
ata_qc_prep(qc);
|
pdc_fill_sg(qc);
|
||||||
/*FALLTHROUGH*/
|
/*FALLTHROUGH*/
|
||||||
case ATA_PROT_ATAPI_NODATA:
|
case ATA_PROT_ATAPI_NODATA:
|
||||||
pdc_atapi_pkt(qc);
|
pdc_atapi_pkt(qc);
|
||||||
|
|
|
@ -265,11 +265,11 @@ static struct sil24_cerr_info {
|
||||||
unsigned int err_mask, action;
|
unsigned int err_mask, action;
|
||||||
const char *desc;
|
const char *desc;
|
||||||
} sil24_cerr_db[] = {
|
} sil24_cerr_db[] = {
|
||||||
[0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
|
[0] = { AC_ERR_DEV, 0,
|
||||||
"device error" },
|
"device error" },
|
||||||
[PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
|
[PORT_CERR_DEV] = { AC_ERR_DEV, 0,
|
||||||
"device error via D2H FIS" },
|
"device error via D2H FIS" },
|
||||||
[PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
|
[PORT_CERR_SDB] = { AC_ERR_DEV, 0,
|
||||||
"device error via SDB FIS" },
|
"device error via SDB FIS" },
|
||||||
[PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
|
[PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
|
||||||
"error in data FIS" },
|
"error in data FIS" },
|
||||||
|
|
|
@ -221,6 +221,7 @@ enum {
|
||||||
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
|
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
|
||||||
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
|
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
|
||||||
ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
|
ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
|
||||||
|
ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */
|
||||||
|
|
||||||
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
|
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
|
||||||
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
|
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
|
||||||
|
|
Loading…
Reference in a new issue