summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-11-03 20:03:17 +0900
committerJeff Garzik <jgarzik@redhat.com>2008-12-28 22:43:20 -0500
commit1eca4365be25c540650693e941bc06a66cf38f94 (patch)
treee3ed82850da00308180bf166118f9f9e69d92898 /include
parent3c92ec8ae91ecf59d88c798301833d7cf83f2179 (diff)
libata: beef up iterators
There currently are the following looping constructs. * __ata_port_for_each_link() for all available links * ata_port_for_each_link() for edge links * ata_link_for_each_dev() for all devices * ata_link_for_each_dev_reverse() for all devices in reverse order Now there's a need for looping construct which is similar to __ata_port_for_each_link() but iterates over PMP links before the host link. Instead of adding another one with long name, do the following cleanup. * Implement and export ata_link_next() and ata_dev_next() which take @mode parameter and can be used to build custom loop. * Implement ata_for_each_link() and ata_for_each_dev() which take looping mode explicitly. The following iteration modes are implemented. * ATA_LITER_EDGE : loop over edge links * ATA_LITER_HOST_FIRST : loop over all links, host link first * ATA_LITER_PMP_FIRST : loop over all links, PMP links first * ATA_DITER_ENABLED : loop over enabled devices * ATA_DITER_ENABLED_REVERSE : loop over enabled devices in reverse order * ATA_DITER_ALL : loop over all devices * ATA_DITER_ALL_REVERSE : loop over all devices in reverse order This change removes exlicit device enabledness checks from many loops and makes it clear which ones are iterated over in which direction. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'include')
-rw-r--r--include/linux/libata.h76
1 files changed, 56 insertions, 20 deletions
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ed3f26eb5df..3b2a0c6444e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1285,26 +1285,62 @@ static inline int ata_link_active(struct ata_link *link)
return ata_tag_valid(link->active_tag) || link->sactive;
}
-extern struct ata_link *__ata_port_next_link(struct ata_port *ap,
- struct ata_link *link,
- bool dev_only);
-
-#define __ata_port_for_each_link(link, ap) \
- for ((link) = __ata_port_next_link((ap), NULL, false); (link); \
- (link) = __ata_port_next_link((ap), (link), false))
-
-#define ata_port_for_each_link(link, ap) \
- for ((link) = __ata_port_next_link((ap), NULL, true); (link); \
- (link) = __ata_port_next_link((ap), (link), true))
-
-#define ata_link_for_each_dev(dev, link) \
- for ((dev) = (link)->device; \
- (dev) < (link)->device + ata_link_max_devices(link) || ((dev) = NULL); \
- (dev)++)
-
-#define ata_link_for_each_dev_reverse(dev, link) \
- for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \
- (dev) >= (link)->device || ((dev) = NULL); (dev)--)
+/*
+ * Iterators
+ *
+ * ATA_LITER_* constants are used to select link iteration mode and
+ * ATA_DITER_* device iteration mode.
+ *
+ * For a custom iteration directly using ata_{link|dev}_next(), if
+ * @link or @dev, respectively, is NULL, the first element is
+ * returned. @dev and @link can be any valid device or link and the
+ * next element according to the iteration mode will be returned.
+ * After the last element, NULL is returned.
+ */
+enum ata_link_iter_mode {
+ ATA_LITER_EDGE, /* if present, PMP links only; otherwise,
+ * host link. no slave link */
+ ATA_LITER_HOST_FIRST, /* host link followed by PMP or slave links */
+ ATA_LITER_PMP_FIRST, /* PMP links followed by host link,
+ * slave link still comes after host link */
+};
+
+enum ata_dev_iter_mode {
+ ATA_DITER_ENABLED,
+ ATA_DITER_ENABLED_REVERSE,
+ ATA_DITER_ALL,
+ ATA_DITER_ALL_REVERSE,
+};
+
+extern struct ata_link *ata_link_next(struct ata_link *link,
+ struct ata_port *ap,
+ enum ata_link_iter_mode mode);
+
+extern struct ata_device *ata_dev_next(struct ata_device *dev,
+ struct ata_link *link,
+ enum ata_dev_iter_mode mode);
+
+/*
+ * Shortcut notation for iterations
+ *
+ * ata_for_each_link() iterates over each link of @ap according to
+ * @mode. @link points to the current link in the loop. @link is
+ * NULL after loop termination. ata_for_each_dev() works the same way
+ * except that it iterates over each device of @link.
+ *
+ * Note that the mode prefixes ATA_{L|D}ITER_ shouldn't need to be
+ * specified when using the following shorthand notations. Only the
+ * mode itself (EDGE, HOST_FIRST, ENABLED, etc...) should be
+ * specified. This not only increases brevity but also makes it
+ * impossible to use ATA_LITER_* for device iteration or vice-versa.
+ */
+#define ata_for_each_link(link, ap, mode) \
+ for ((link) = ata_link_next(NULL, (ap), ATA_LITER_##mode); (link); \
+ (link) = ata_link_next((link), (ap), ATA_LITER_##mode))
+
+#define ata_for_each_dev(dev, link, mode) \
+ for ((dev) = ata_dev_next(NULL, (link), ATA_DITER_##mode); (dev); \
+ (dev) = ata_dev_next((dev), (link), ATA_DITER_##mode))
/**
* ata_ncq_enabled - Test whether NCQ is enabled