Skip to content

Commit

Permalink
[libata] change ata_qc_complete() to take error mask as second arg
Browse files Browse the repository at this point in the history
The second argument to ata_qc_complete() was being used for two
purposes: communicate the ATA Status register to the completion
function, and indicate an error.  On legacy PCI IDE hardware, the latter
is often implicit in the former.  On more modern hardware, the driver
often completely emulated a Status register value, passing ATA_ERR as an
indication that something went wrong.

Now that previous code changes have eliminated the need to use drv_stat
arg to communicate the ATA Status register value, we can convert it to a
mask of possible error classes.

This will lead to more flexible error handling in the future.
  • Loading branch information
Jeff Garzik committed Oct 30, 2005
1 parent 81cfb88 commit a7dac44
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 71 deletions.
4 changes: 2 additions & 2 deletions drivers/scsi/ahci.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ static void ahci_eng_timeout(struct ata_port *ap)
* not being called from the SCSI EH.
*/
qc->scsidone = scsi_finish_command;
ata_qc_complete(qc, ATA_ERR);
ata_qc_complete(qc, AC_ERR_OTHER);
}

spin_unlock_irqrestore(&host_set->lock, flags);
Expand Down Expand Up @@ -629,7 +629,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (status & PORT_IRQ_FATAL) {
ahci_intr_error(ap, status);
if (qc)
ata_qc_complete(qc, ATA_ERR);
ata_qc_complete(qc, AC_ERR_OTHER);
}

return 1;
Expand Down
31 changes: 15 additions & 16 deletions drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2663,15 +2663,15 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
* None. (grabs host lock)
*/

void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
{
struct ata_port *ap = qc->ap;
unsigned long flags;

spin_lock_irqsave(&ap->host_set->lock, flags);
ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc, drv_stat);
ata_qc_complete(qc, err_mask);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
}

Expand Down Expand Up @@ -2768,7 +2768,7 @@ static int ata_pio_complete (struct ata_port *ap)

ap->hsm_task_state = HSM_ST_IDLE;

ata_poll_qc_complete(qc, drv_stat);
ata_poll_qc_complete(qc, 0);

/* another command may start at this point */

Expand Down Expand Up @@ -3136,18 +3136,15 @@ static void ata_pio_block(struct ata_port *ap)
static void ata_pio_error(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
u8 drv_stat;

printk(KERN_WARNING "ata%u: PIO error\n", ap->id);

qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);

drv_stat = ata_chk_status(ap);
printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
ap->id, drv_stat);

ap->hsm_task_state = HSM_ST_IDLE;

ata_poll_qc_complete(qc, drv_stat | ATA_ERR);
ata_poll_qc_complete(qc, AC_ERR_ATA_BUS);
}

static void ata_pio_task(void *_data)
Expand Down Expand Up @@ -3270,7 +3267,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
ap->id, qc->tf.command, drv_stat, host_stat);

/* complete taskfile transaction */
ata_qc_complete(qc, drv_stat);
ata_qc_complete(qc, ac_err_mask(drv_stat));
break;
}

Expand Down Expand Up @@ -3375,7 +3372,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
return qc;
}

int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask)
{
return 0;
}
Expand Down Expand Up @@ -3434,7 +3431,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
* spin_lock_irqsave(host_set lock)
*/

void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
{
int rc;

Expand All @@ -3451,7 +3448,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
qc->flags &= ~ATA_QCFLAG_ACTIVE;

/* call completion callback */
rc = qc->complete_fn(qc, drv_stat);
rc = qc->complete_fn(qc, err_mask);

/* if callback indicates not to complete command (non-zero),
* return immediately
Expand Down Expand Up @@ -3889,7 +3886,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
ap->ops->irq_clear(ap);

/* complete taskfile transaction */
ata_qc_complete(qc, status);
ata_qc_complete(qc, ac_err_mask(status));
break;

default:
Expand Down Expand Up @@ -3984,7 +3981,7 @@ static void atapi_packet_task(void *_data)
/* sleep-wait for BSY to clear */
DPRINTK("busy wait\n");
if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
goto err_out;
goto err_out_status;

/* make sure DRQ is set */
status = ata_chk_status(ap);
Expand Down Expand Up @@ -4021,8 +4018,10 @@ static void atapi_packet_task(void *_data)

return;

err_out_status:
status = ata_chk_status(ap);
err_out:
ata_poll_qc_complete(qc, ATA_ERR);
ata_poll_qc_complete(qc, __ac_err_mask(status));
}


Expand Down
46 changes: 28 additions & 18 deletions drivers/scsi/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
* Use ata_to_sense_error() to map status register bits
* onto sense key, asc & ascq.
*/
if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) {
if (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] &= 0x0f;
Expand Down Expand Up @@ -635,7 +635,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
* Use ata_to_sense_error() to map status register bits
* onto sense key, asc & ascq.
*/
if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) {
if (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] &= 0x0f;
Expand All @@ -644,14 +644,22 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
sb[0] = 0x70;
sb[7] = 0x0a;

if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) {
if (tf->flags & ATA_TFLAG_LBA48) {
/* TODO: find solution for LBA48 descriptors */
}

else if (tf->flags & ATA_TFLAG_LBA) {
/* A small (28b) LBA will fit in the 32b info field */
sb[0] |= 0x80; /* set valid bit */
sb[3] = tf->device & 0x0f;
sb[4] = tf->lbah;
sb[5] = tf->lbam;
sb[6] = tf->lbal;
}

else {
/* TODO: C/H/S */
}
}

/**
Expand Down Expand Up @@ -1199,10 +1207,12 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
return 1;
}

static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
static int ata_scsi_qc_complete(struct ata_queued_cmd *qc,
unsigned int err_mask)
{
struct scsi_cmnd *cmd = qc->scsicmd;
int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ);
u8 *cdb = cmd->cmnd;
int need_sense = (err_mask != 0);

/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there's an error. Note that if we
Expand All @@ -1211,8 +1221,8 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
* whether the command completed successfully or not. If there
* was no error, SK, ASC and ASCQ will all be zero.
*/
if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) &&
((cmd->cmnd[2] & 0x20) || need_sense)) {
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
((cdb[2] & 0x20) || need_sense)) {
ata_gen_ata_desc_sense(qc);
} else {
if (!need_sense) {
Expand Down Expand Up @@ -1995,21 +2005,13 @@ void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
DPRINTK("EXIT\n");
}

static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
{
struct scsi_cmnd *cmd = qc->scsicmd;

VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat);

if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ)))
/* 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);
VPRINTK("ENTER, err_mask 0x%X\n", err_mask);

else if (unlikely(drv_stat & ATA_ERR)) {
if (unlikely(err_mask & AC_ERR_DEV)) {
DPRINTK("request check condition\n");

/* FIXME: command completion with check condition
Expand All @@ -2026,6 +2028,14 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
return 1;
}

else if (unlikely(err_mask))
/* 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);

else {
u8 *scsicmd = cmd->cmnd;

Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct ata_scsi_args {

/* libata-core.c */
extern int atapi_enabled;
extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
Expand Down
13 changes: 8 additions & 5 deletions drivers/scsi/pdc_adma.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
struct adma_port_priv *pp;
struct ata_queued_cmd *qc;
void __iomem *chan = ADMA_REGS(mmio_base, port_no);
u8 drv_stat = 0, status = readb(chan + ADMA_STATUS);
u8 status = readb(chan + ADMA_STATUS);

if (status == 0)
continue;
Expand All @@ -464,11 +464,14 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
continue;
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
unsigned int err_mask = 0;

if ((status & (aPERR | aPSD | aUIRQ)))
drv_stat = ATA_ERR;
err_mask = AC_ERR_OTHER;
else if (pp->pkt[0] != cDONE)
drv_stat = ATA_ERR;
ata_qc_complete(qc, drv_stat);
err_mask = AC_ERR_OTHER;

ata_qc_complete(qc, err_mask);
}
}
return handled;
Expand Down Expand Up @@ -498,7 +501,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)

/* complete taskfile transaction */
pp->state = adma_state_idle;
ata_qc_complete(qc, status);
ata_qc_complete(qc, ac_err_mask(status));
handled = 1;
}
}
Expand Down
11 changes: 6 additions & 5 deletions drivers/scsi/sata_mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
struct ata_queued_cmd *qc;
u32 hc_irq_cause;
int shift, port, port0, hard_port, handled;
unsigned int err_mask;
u8 ata_status = 0;

if (hc == 0) {
Expand Down Expand Up @@ -1100,15 +1101,15 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
handled++;
}

err_mask = ac_err_mask(ata_status);

shift = port << 1; /* (port * 2) */
if (port >= MV_PORTS_PER_HC) {
shift++; /* skip bit 8 in the HC Main IRQ reg */
}
if ((PORT0_ERR << shift) & relevant) {
mv_err_intr(ap);
/* OR in ATA_ERR to ensure libata knows we took one */
ata_status = readb((void __iomem *)
ap->ioaddr.status_addr) | ATA_ERR;
err_mask |= AC_ERR_OTHER;
handled++;
}

Expand All @@ -1118,7 +1119,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 */
ata_qc_complete(qc, ata_status);
ata_qc_complete(qc, err_mask);
}
}
}
Expand Down Expand Up @@ -1294,7 +1295,7 @@ static void mv_eng_timeout(struct ata_port *ap)
*/
spin_lock_irqsave(&ap->host_set->lock, flags);
qc->scsidone = scsi_finish_command;
ata_qc_complete(qc, ATA_ERR);
ata_qc_complete(qc, AC_ERR_OTHER);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
}
}
Expand Down
16 changes: 7 additions & 9 deletions drivers/scsi/sata_promise.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,8 @@ static void pdc_eng_timeout(struct ata_port *ap)
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
printk(KERN_ERR "ata%u: command timeout\n", ap->id);
ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
drv_stat = ata_wait_idle(ap);
ata_qc_complete(qc, __ac_err_mask(drv_stat));
break;

default:
Expand All @@ -408,7 +409,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
ap->id, qc->tf.command, drv_stat);

ata_qc_complete(qc, drv_stat);
ata_qc_complete(qc, ac_err_mask(drv_stat));
break;
}

Expand All @@ -420,24 +421,21 @@ static void pdc_eng_timeout(struct ata_port *ap)
static inline unsigned int pdc_host_intr( struct ata_port *ap,
struct ata_queued_cmd *qc)
{
u8 status;
unsigned int handled = 0, have_err = 0;
unsigned int handled = 0, err_mask = 0;
u32 tmp;
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;

tmp = readl(mmio);
if (tmp & PDC_ERR_MASK) {
have_err = 1;
err_mask = AC_ERR_DEV;
pdc_reset_port(ap);
}

switch (qc->tf.protocol) {
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
status = ata_wait_idle(ap);
if (have_err)
status |= ATA_ERR;
ata_qc_complete(qc, status);
err_mask |= ac_err_mask(ata_wait_idle(ap));
ata_qc_complete(qc, err_mask);
handled = 1;
break;

Expand Down
Loading

0 comments on commit a7dac44

Please sign in to comment.