diff options
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 113 |
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 }; | |||
74 | const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; | 74 | const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; |
75 | const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; | 75 | const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; |
76 | 76 | ||
77 | const struct ata_port_operations ata_base_port_ops = { | ||
78 | .irq_clear = ata_noop_irq_clear, | ||
79 | }; | ||
80 | |||
81 | const 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 | |||
88 | const struct ata_port_operations sata_pmp_port_ops = { | ||
89 | .inherits = &sata_port_ops, | ||
90 | }; | ||
91 | |||
92 | const 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 | |||
115 | const 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 | |||
77 | static unsigned int ata_dev_init_params(struct ata_device *dev, | 127 | static unsigned int ata_dev_init_params(struct ata_device *dev, |
78 | u16 heads, u16 sectors); | 128 | u16 heads, u16 sectors); |
79 | static unsigned int ata_dev_set_xfermode(struct ata_device *dev); | 129 | static 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 | */ | ||
7044 | static 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 */ |
7062 | void ata_host_init(struct ata_host *host, struct device *dev, | 7166 | void 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 | ||
7752 | const struct ata_port_operations ata_dummy_port_ops = { | 7856 | struct 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 = { | |||
7777 | EXPORT_SYMBOL_GPL(sata_deb_timing_normal); | 7881 | EXPORT_SYMBOL_GPL(sata_deb_timing_normal); |
7778 | EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); | 7882 | EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); |
7779 | EXPORT_SYMBOL_GPL(sata_deb_timing_long); | 7883 | EXPORT_SYMBOL_GPL(sata_deb_timing_long); |
7884 | EXPORT_SYMBOL_GPL(ata_base_port_ops); | ||
7885 | EXPORT_SYMBOL_GPL(sata_port_ops); | ||
7886 | EXPORT_SYMBOL_GPL(sata_pmp_port_ops); | ||
7887 | EXPORT_SYMBOL_GPL(ata_sff_port_ops); | ||
7888 | EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); | ||
7780 | EXPORT_SYMBOL_GPL(ata_dummy_port_ops); | 7889 | EXPORT_SYMBOL_GPL(ata_dummy_port_ops); |
7781 | EXPORT_SYMBOL_GPL(ata_dummy_port_info); | 7890 | EXPORT_SYMBOL_GPL(ata_dummy_port_info); |
7782 | EXPORT_SYMBOL_GPL(ata_std_bios_param); | 7891 | EXPORT_SYMBOL_GPL(ata_std_bios_param); |