Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 29303
b: refs/heads/master
c: f686bcb
h: refs/heads/master
i:
  29301: 764c62f
  29299: a018ccb
  29295: 6c06e0f
v: v3
  • Loading branch information
Tejun Heo committed May 15, 2006
1 parent 0a48c06 commit 5467ae4
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 28 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f69499f42caf74194df678c9c293f2ee0fe90bc3
refs/heads/master: f686bcb8078ac7505ec88818886c2c72639f4fc5
62 changes: 61 additions & 1 deletion trunk/drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4123,6 +4123,66 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
qc->complete_fn(qc);
}

/**
* 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)
*/
void ata_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;

/* XXX: New EH and old EH use different mechanisms to
* synchronize EH with regular execution path.
*
* In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
* Normal execution path is responsible for not accessing a
* failed qc. libata core enforces the rule by returning NULL
* from ata_qc_from_tag() for failed qcs.
*
* Old EH depends on ata_qc_complete() nullifying completion
* requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
* not synchronize with interrupt handler. Only PIO task is
* taken care of.
*/
if (ap->ops->error_handler) {
WARN_ON(ap->flags & ATA_FLAG_FROZEN);

if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;

if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
if (!ata_tag_internal(qc->tag)) {
/* always fill result TF for failed qc */
ap->ops->tf_read(ap, &qc->result_tf);
ata_qc_schedule_eh(qc);
return;
}
}

/* read result TF if requested */
if (qc->flags & ATA_QCFLAG_RESULT_TF)
ap->ops->tf_read(ap, &qc->result_tf);

__ata_qc_complete(qc);
} else {
if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
return;

/* read result TF if failed or requested */
if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
ap->ops->tf_read(ap, &qc->result_tf);

__ata_qc_complete(qc);
}
}

static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
Expand Down Expand Up @@ -5245,7 +5305,7 @@ EXPORT_SYMBOL_GPL(ata_device_add);
EXPORT_SYMBOL_GPL(ata_host_set_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(__ata_qc_complete);
EXPORT_SYMBOL_GPL(ata_qc_complete);
EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
EXPORT_SYMBOL_GPL(ata_tf_load);
EXPORT_SYMBOL_GPL(ata_tf_read);
Expand Down
27 changes: 27 additions & 0 deletions trunk/drivers/scsi/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,33 @@ void ata_eng_timeout(struct ata_port *ap)
DPRINTK("EXIT\n");
}

/**
* ata_qc_schedule_eh - schedule qc for error handling
* @qc: command to schedule error handling for
*
* Schedule error handling for @qc. EH will kick in as soon as
* other commands are drained.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;

WARN_ON(!ap->ops->error_handler);

qc->flags |= ATA_QCFLAG_FAILED;
qc->ap->flags |= ATA_FLAG_EH_PENDING;

/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
* Note that ATA_QCFLAG_FAILED is unconditionally set after
* this function completes.
*/
scsi_req_abort_cmd(qc->scsicmd);
}

static void ata_eh_scsidone(struct scsi_cmnd *scmd)
{
/* nada */
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/scsi/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
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);
Expand Down Expand Up @@ -101,5 +102,6 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
/* 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__ */
27 changes: 1 addition & 26 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ 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_qc_complete(struct ata_queued_cmd *qc);
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,
Expand Down Expand Up @@ -882,31 +882,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
qc->result_tf.feature = 0;
}

/**
* 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)
{
struct ata_port *ap = qc->ap;

if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED))
return;

/* read result TF if failed or requested */
if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
ap->ops->tf_read(ap, &qc->result_tf);

__ata_qc_complete(qc);
}

/**
* ata_irq_on - Enable interrupts on a port.
* @ap: Port on which interrupts are enabled.
Expand Down

0 comments on commit 5467ae4

Please sign in to comment.