aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 07:58:03 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 07:58:03 -0400
commitf69499f42caf74194df678c9c293f2ee0fe90bc3 (patch)
tree642f3d5792eb6561fd01116f6a247d26f9e3e304
parent2ab7db1ff1d64a2ba389d0692d532f42a15f1f72 (diff)
[PATCH] libata-eh-fw: update ata_qc_from_tag() to enforce normal/EH qc ownership
New EH framework has clear distinction about who owns a qc. Every qc starts owned by normal execution path - PIO, interrupt or whatever. When an exception condition occurs which affects the qc, the qc gets scheduled for EH. Note that some events (say, link lost and regained, command timeout) may schedule qc's which are not directly related but could have been affected for EH too. Scheduling for EH is atomic w.r.t. ap->host_set->lock and once schedule for EH, normal execution path is not allowed to access the qc in whatever way. (PIO synchronization acts a bit different and will be dealt with later) This patch make ata_qc_from_tag() check whether a qc is active and owned by normal path before returning it. If conditions don't match, NULL is returned and thus access to the qc is denied. __ata_qc_from_tag() is the original ata_qc_from_tag() and is used by libata core/EH layers to access inactive/failed qc's. This change is applied only if the associated LLDD implements new EH as indicated by non-NULL ->error_handler Signed-off-by: Tejun Heo <htejun@gmail.com>
-rw-r--r--drivers/scsi/libata-core.c4
-rw-r--r--include/linux/libata.h19
2 files changed, 19 insertions, 4 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 966abb5f423e..1c34c1427aa3 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1001,7 +1001,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
1001 1001
1002 if (test_and_set_bit(tag, &ap->qactive)) 1002 if (test_and_set_bit(tag, &ap->qactive))
1003 BUG(); 1003 BUG();
1004 qc = ata_qc_from_tag(ap, tag); 1004 qc = __ata_qc_from_tag(ap, tag);
1005 1005
1006 qc->tag = tag; 1006 qc->tag = tag;
1007 qc->scsicmd = NULL; 1007 qc->scsicmd = NULL;
@@ -4042,7 +4042,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
4042 /* the last tag is reserved for internal command. */ 4042 /* the last tag is reserved for internal command. */
4043 for (i = 0; i < ATA_MAX_QUEUE - 1; i++) 4043 for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
4044 if (!test_and_set_bit(i, &ap->qactive)) { 4044 if (!test_and_set_bit(i, &ap->qactive)) {
4045 qc = ata_qc_from_tag(ap, i); 4045 qc = __ata_qc_from_tag(ap, i);
4046 break; 4046 break;
4047 } 4047 }
4048 4048
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 5a403e434ff8..bfcefdca0616 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -832,14 +832,29 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc)
832 qc->tf.ctl |= ATA_NIEN; 832 qc->tf.ctl |= ATA_NIEN;
833} 833}
834 834
835static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap, 835static inline struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap,
836 unsigned int tag) 836 unsigned int tag)
837{ 837{
838 if (likely(ata_tag_valid(tag))) 838 if (likely(ata_tag_valid(tag)))
839 return &ap->qcmd[tag]; 839 return &ap->qcmd[tag];
840 return NULL; 840 return NULL;
841} 841}
842 842
843static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap,
844 unsigned int tag)
845{
846 struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
847
848 if (unlikely(!qc) || !ap->ops->error_handler)
849 return qc;
850
851 if ((qc->flags & (ATA_QCFLAG_ACTIVE |
852 ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE)
853 return qc;
854
855 return NULL;
856}
857
843static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) 858static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf)
844{ 859{
845 memset(tf, 0, sizeof(*tf)); 860 memset(tf, 0, sizeof(*tf));