aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2008-03-24 23:22:49 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-04-17 15:44:17 -0400
commit029cfd6b74fc5c517865fad78cf4a3ea8d9b664a (patch)
tree4a40f44f29321e433497a51d2f6cfe1922ae1d58 /drivers/ata/libata-core.c
parent68d1d07b510bb57a504588adc2bd2758adea0965 (diff)
libata: implement and use ops inheritance
libata lets low level drivers build ata_port_operations table and register it with libata core layer. This allows low level drivers high level of flexibility but also burdens them with lots of boilerplate entries. This becomes worse for drivers which support related similar controllers which differ slightly. They share most of the operations except for a few. However, the driver still needs to list all operations for each variant. This results in large number of duplicate entries, which is not only inefficient but also error-prone as it becomes very difficult to tell what the actual differences are. This duplicate boilerplates all over the low level drivers also make updating the core layer exteremely difficult and error-prone. When compounded with multi-branched development model, it ends up accumulating inconsistencies over time. Some of those inconsistencies cause immediate problems and fixed. Others just remain there dormant making maintenance increasingly difficult. To rectify the problem, this patch implements ata_port_operations inheritance. To allow LLDs to easily re-use their own ops tables overriding only specific methods, this patch implements poor man's class inheritance. An ops table has ->inherits field which can be set to any ops table as long as it doesn't create a loop. When the host is started, the inheritance chain is followed and any operation which isn't specified is taken from the nearest ancestor which has it specified. This operation is called finalization and done only once per an ops table and the LLD doesn't have to do anything special about it other than making the ops table non-const such that libata can update it. libata provides four base ops tables lower drivers can inherit from - base, sata, pmp, sff and bmdma. To avoid overriding these ops accidentaly, these ops are declared const and LLDs should always inherit these instead of using them directly. After finalization, all the ops table are identical before and after the patch except for setting .irq_handler to ata_interrupt in drivers which didn't use to. The .irq_handler doesn't have any actual effect and the field will soon be removed by later patch. * sata_sx4 is still using old style EH and currently doesn't take advantage of ops inheritance. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c113
1 files changed, 111 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 394edf937cf2..32fa9ee397b6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -74,6 +74,56 @@ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
74const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; 74const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
75const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; 75const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
76 76
77const struct ata_port_operations ata_base_port_ops = {
78 .irq_clear = ata_noop_irq_clear,
79};
80
81const struct ata_port_operations sata_port_ops = {
82 .inherits = &ata_base_port_ops,
83
84 .qc_defer = ata_std_qc_defer,
85 .dev_select = ata_noop_dev_select,
86};
87
88const struct ata_port_operations sata_pmp_port_ops = {
89 .inherits = &sata_port_ops,
90};
91
92const struct ata_port_operations ata_sff_port_ops = {
93 .inherits = &ata_base_port_ops,
94
95 .qc_prep = ata_qc_prep,
96 .qc_issue = ata_qc_issue_prot,
97
98 .freeze = ata_bmdma_freeze,
99 .thaw = ata_bmdma_thaw,
100 .error_handler = ata_bmdma_error_handler,
101 .post_internal_cmd = ata_bmdma_post_internal_cmd,
102
103 .dev_select = ata_std_dev_select,
104 .check_status = ata_check_status,
105 .tf_load = ata_tf_load,
106 .tf_read = ata_tf_read,
107 .exec_command = ata_exec_command,
108 .data_xfer = ata_data_xfer,
109 .irq_on = ata_irq_on,
110
111 .port_start = ata_sff_port_start,
112 .irq_handler = ata_interrupt,
113};
114
115const struct ata_port_operations ata_bmdma_port_ops = {
116 .inherits = &ata_sff_port_ops,
117
118 .mode_filter = ata_pci_default_filter,
119
120 .bmdma_setup = ata_bmdma_setup,
121 .bmdma_start = ata_bmdma_start,
122 .bmdma_stop = ata_bmdma_stop,
123 .bmdma_status = ata_bmdma_status,
124 .irq_clear = ata_bmdma_irq_clear,
125};
126
77static unsigned int ata_dev_init_params(struct ata_device *dev, 127static unsigned int ata_dev_init_params(struct ata_device *dev,
78 u16 heads, u16 sectors); 128 u16 heads, u16 sectors);
79static unsigned int ata_dev_set_xfermode(struct ata_device *dev); 129static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
@@ -6972,6 +7022,56 @@ static void ata_host_stop(struct device *gendev, void *res)
6972} 7022}
6973 7023
6974/** 7024/**
7025 * ata_finalize_port_ops - finalize ata_port_operations
7026 * @ops: ata_port_operations to finalize
7027 *
7028 * An ata_port_operations can inherit from another ops and that
7029 * ops can again inherit from another. This can go on as many
7030 * times as necessary as long as there is no loop in the
7031 * inheritance chain.
7032 *
7033 * Ops tables are finalized when the host is started. NULL or
7034 * unspecified entries are inherited from the closet ancestor
7035 * which has the method and the entry is populated with it.
7036 * After finalization, the ops table directly points to all the
7037 * methods and ->inherits is no longer necessary and cleared.
7038 *
7039 * Using ATA_OP_NULL, inheriting ops can force a method to NULL.
7040 *
7041 * LOCKING:
7042 * None.
7043 */
7044static void ata_finalize_port_ops(struct ata_port_operations *ops)
7045{
7046 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
7047 const struct ata_port_operations *cur;
7048 void **begin = (void **)ops;
7049 void **end = (void **)&ops->inherits;
7050 void **pp;
7051
7052 if (!ops || !ops->inherits)
7053 return;
7054
7055 spin_lock(&lock);
7056
7057 for (cur = ops->inherits; cur; cur = cur->inherits) {
7058 void **inherit = (void **)cur;
7059
7060 for (pp = begin; pp < end; pp++, inherit++)
7061 if (!*pp)
7062 *pp = *inherit;
7063 }
7064
7065 for (pp = begin; pp < end; pp++)
7066 if (IS_ERR(*pp))
7067 *pp = NULL;
7068
7069 ops->inherits = NULL;
7070
7071 spin_unlock(&lock);
7072}
7073
7074/**
6975 * ata_host_start - start and freeze ports of an ATA host 7075 * ata_host_start - start and freeze ports of an ATA host
6976 * @host: ATA host to start ports for 7076 * @host: ATA host to start ports for
6977 * 7077 *
@@ -6996,9 +7096,13 @@ int ata_host_start(struct ata_host *host)
6996 if (host->flags & ATA_HOST_STARTED) 7096 if (host->flags & ATA_HOST_STARTED)
6997 return 0; 7097 return 0;
6998 7098
7099 ata_finalize_port_ops(host->ops);
7100
6999 for (i = 0; i < host->n_ports; i++) { 7101 for (i = 0; i < host->n_ports; i++) {
7000 struct ata_port *ap = host->ports[i]; 7102 struct ata_port *ap = host->ports[i];
7001 7103
7104 ata_finalize_port_ops(ap->ops);
7105
7002 if (!host->ops && !ata_port_is_dummy(ap)) 7106 if (!host->ops && !ata_port_is_dummy(ap))
7003 host->ops = ap->ops; 7107 host->ops = ap->ops;
7004 7108
@@ -7060,7 +7164,7 @@ int ata_host_start(struct ata_host *host)
7060 */ 7164 */
7061/* KILLME - the only user left is ipr */ 7165/* KILLME - the only user left is ipr */
7062void ata_host_init(struct ata_host *host, struct device *dev, 7166void ata_host_init(struct ata_host *host, struct device *dev,
7063 unsigned long flags, const struct ata_port_operations *ops) 7167 unsigned long flags, struct ata_port_operations *ops)
7064{ 7168{
7065 spin_lock_init(&host->lock); 7169 spin_lock_init(&host->lock);
7066 host->dev = dev; 7170 host->dev = dev;
@@ -7749,7 +7853,7 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
7749 return AC_ERR_SYSTEM; 7853 return AC_ERR_SYSTEM;
7750} 7854}
7751 7855
7752const struct ata_port_operations ata_dummy_port_ops = { 7856struct ata_port_operations ata_dummy_port_ops = {
7753 .check_status = ata_dummy_check_status, 7857 .check_status = ata_dummy_check_status,
7754 .check_altstatus = ata_dummy_check_status, 7858 .check_altstatus = ata_dummy_check_status,
7755 .dev_select = ata_noop_dev_select, 7859 .dev_select = ata_noop_dev_select,
@@ -7777,6 +7881,11 @@ const struct ata_port_info ata_dummy_port_info = {
7777EXPORT_SYMBOL_GPL(sata_deb_timing_normal); 7881EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
7778EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); 7882EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
7779EXPORT_SYMBOL_GPL(sata_deb_timing_long); 7883EXPORT_SYMBOL_GPL(sata_deb_timing_long);
7884EXPORT_SYMBOL_GPL(ata_base_port_ops);
7885EXPORT_SYMBOL_GPL(sata_port_ops);
7886EXPORT_SYMBOL_GPL(sata_pmp_port_ops);
7887EXPORT_SYMBOL_GPL(ata_sff_port_ops);
7888EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
7780EXPORT_SYMBOL_GPL(ata_dummy_port_ops); 7889EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
7781EXPORT_SYMBOL_GPL(ata_dummy_port_info); 7890EXPORT_SYMBOL_GPL(ata_dummy_port_info);
7782EXPORT_SYMBOL_GPL(ata_std_bios_param); 7891EXPORT_SYMBOL_GPL(ata_std_bios_param);