aboutsummaryrefslogtreecommitdiffstats
path: root/include
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 /include
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 'include')
-rw-r--r--include/linux/libata.h23
1 files changed, 18 insertions, 5 deletions
diff --git a/include/linux/libata.h b/include/linux/libata.h
index eccc38e17568..46aa4ab64891 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -433,7 +433,7 @@ struct ata_host {
433 void __iomem * const *iomap; 433 void __iomem * const *iomap;
434 unsigned int n_ports; 434 unsigned int n_ports;
435 void *private_data; 435 void *private_data;
436 const struct ata_port_operations *ops; 436 struct ata_port_operations *ops;
437 unsigned long flags; 437 unsigned long flags;
438#ifdef CONFIG_ATA_ACPI 438#ifdef CONFIG_ATA_ACPI
439 acpi_handle acpi_handle; 439 acpi_handle acpi_handle;
@@ -602,7 +602,7 @@ struct ata_link {
602 602
603struct ata_port { 603struct ata_port {
604 struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ 604 struct Scsi_Host *scsi_host; /* our co-allocated scsi host */
605 const struct ata_port_operations *ops; 605 struct ata_port_operations *ops;
606 spinlock_t *lock; 606 spinlock_t *lock;
607 unsigned long flags; /* ATA_FLAG_xxx */ 607 unsigned long flags; /* ATA_FLAG_xxx */
608 unsigned int pflags; /* ATA_PFLAG_xxx */ 608 unsigned int pflags; /* ATA_PFLAG_xxx */
@@ -664,6 +664,13 @@ struct ata_port {
664 u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ 664 u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
665}; 665};
666 666
667/* The following initializer overrides a method to NULL whether one of
668 * its parent has the method defined or not. This is equivalent to
669 * ERR_PTR(-ENOENT). Unfortunately, ERR_PTR doesn't render a constant
670 * expression and thus can't be used as an initializer.
671 */
672#define ATA_OP_NULL (void *)(unsigned long)(-ENOENT)
673
667struct ata_port_operations { 674struct ata_port_operations {
668 /* 675 /*
669 * Command execution 676 * Command execution
@@ -733,6 +740,12 @@ struct ata_port_operations {
733 void (*phy_reset)(struct ata_port *ap); 740 void (*phy_reset)(struct ata_port *ap);
734 void (*eng_timeout)(struct ata_port *ap); 741 void (*eng_timeout)(struct ata_port *ap);
735 irq_handler_t irq_handler; 742 irq_handler_t irq_handler;
743
744 /*
745 * ->inherits must be the last field and all the preceding
746 * fields must be pointers.
747 */
748 const struct ata_port_operations *inherits;
736}; 749};
737 750
738struct ata_port_info { 751struct ata_port_info {
@@ -742,7 +755,7 @@ struct ata_port_info {
742 unsigned long pio_mask; 755 unsigned long pio_mask;
743 unsigned long mwdma_mask; 756 unsigned long mwdma_mask;
744 unsigned long udma_mask; 757 unsigned long udma_mask;
745 const struct ata_port_operations *port_ops; 758 struct ata_port_operations *port_ops;
746 irq_handler_t irq_handler; 759 irq_handler_t irq_handler;
747 void *private_data; 760 void *private_data;
748}; 761};
@@ -765,7 +778,7 @@ extern const unsigned long sata_deb_timing_normal[];
765extern const unsigned long sata_deb_timing_hotplug[]; 778extern const unsigned long sata_deb_timing_hotplug[];
766extern const unsigned long sata_deb_timing_long[]; 779extern const unsigned long sata_deb_timing_long[];
767 780
768extern const struct ata_port_operations ata_dummy_port_ops; 781extern struct ata_port_operations ata_dummy_port_ops;
769extern const struct ata_port_info ata_dummy_port_info; 782extern const struct ata_port_info ata_dummy_port_info;
770 783
771static inline const unsigned long * 784static inline const unsigned long *
@@ -812,7 +825,7 @@ extern int ata_host_activate(struct ata_host *host, int irq,
812 struct scsi_host_template *sht); 825 struct scsi_host_template *sht);
813extern void ata_host_detach(struct ata_host *host); 826extern void ata_host_detach(struct ata_host *host);
814extern void ata_host_init(struct ata_host *, struct device *, 827extern void ata_host_init(struct ata_host *, struct device *,
815 unsigned long, const struct ata_port_operations *); 828 unsigned long, struct ata_port_operations *);
816extern int ata_scsi_detect(struct scsi_host_template *sht); 829extern int ata_scsi_detect(struct scsi_host_template *sht);
817extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); 830extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
818extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); 831extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));