From dd5b06c490de72440ec39f814de99a714a45a1a9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 10 Aug 2006 16:59:12 +0900 Subject: [PATCH] [PATCH] libata: implement dummy port Implement dummy port which can be requested by setting appropriate bit in probe_ent->dummy_port_mask. The dummy port is used as placeholder for stolen legacy port. This allows libata to guarantee that index_of(ap) == ap->port_no == actual_device_port_no, and thus to remove error-prone ap->hard_port_no. As it's used only when one port of a legacy controller is reserved by some other entity (e.g. IDE), the focus is on keeping the added *code* complexity at minimum, so dummy port allocates all libata core resources and acts as a normal port. It just has all dummy port_ops. This patch only implements dummy port. The following patch will make libata use it for stolen legacy ports. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 61 +++++++++++++++++++++++++++++++------- include/linux/libata.h | 8 +++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 3634279d896d..f2e7e2f13db9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5311,7 +5311,6 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, { struct Scsi_Host *shost; struct ata_port *ap; - int rc; DPRINTK("ENTER\n"); @@ -5333,15 +5332,7 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, ata_port_init(ap, host_set, ent, port_no); ata_port_init_shost(ap, shost); - rc = ap->ops->port_start(ap); - if (rc) - goto err_out; - return ap; - -err_out: - scsi_host_put(shost); - return NULL; } /** @@ -5415,11 +5406,27 @@ int ata_device_add(const struct ata_probe_ent *ent) if (!ap) goto err_out; + host_set->ports[i] = ap; + + /* dummy? */ + if (ent->dummy_port_mask & (1 << i)) { + ata_port_printk(ap, KERN_INFO, "DUMMY\n"); + ap->ops = &ata_dummy_port_ops; + continue; + } + + /* start port */ + rc = ap->ops->port_start(ap); + if (rc) { + host_set->ports[i] = NULL; + scsi_host_put(ap->host); + goto err_out; + } + /* Report the secondary IRQ for second channel legacy */ if (i == 1 && ent->irq2) irq_line = ent->irq2; - host_set->ports[i] = ap; xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | (ap->mwdma_mask << ATA_SHIFT_MWDMA) | (ap->pio_mask << ATA_SHIFT_PIO); @@ -5940,6 +5947,39 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, return tmp; } +/* + * Dummy port_ops + */ +static void ata_dummy_noret(struct ata_port *ap) { } +static int ata_dummy_ret0(struct ata_port *ap) { return 0; } +static void ata_dummy_qc_noret(struct ata_queued_cmd *qc) { } + +static u8 ata_dummy_check_status(struct ata_port *ap) +{ + return ATA_DRDY; +} + +static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) +{ + return AC_ERR_SYSTEM; +} + +const struct ata_port_operations ata_dummy_port_ops = { + .port_disable = ata_port_disable, + .check_status = ata_dummy_check_status, + .check_altstatus = ata_dummy_check_status, + .dev_select = ata_noop_dev_select, + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_dummy_qc_issue, + .freeze = ata_dummy_noret, + .thaw = ata_dummy_noret, + .error_handler = ata_dummy_noret, + .post_internal_cmd = ata_dummy_qc_noret, + .irq_clear = ata_dummy_noret, + .port_start = ata_dummy_ret0, + .port_stop = ata_dummy_noret, +}; + /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -5950,6 +5990,7 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, EXPORT_SYMBOL_GPL(sata_deb_timing_normal); EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); EXPORT_SYMBOL_GPL(sata_deb_timing_long); +EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_host_set_init); diff --git a/include/linux/libata.h b/include/linux/libata.h index 4504776570e4..30bfe8f1666e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -353,6 +353,7 @@ struct ata_probe_ent { struct ata_ioports port[ATA_MAX_PORTS]; unsigned int n_ports; unsigned int hard_port_no; + unsigned int dummy_port_mask; unsigned int pio_mask; unsigned int mwdma_mask; unsigned int udma_mask; @@ -652,6 +653,8 @@ extern const unsigned long sata_deb_timing_normal[]; extern const unsigned long sata_deb_timing_hotplug[]; extern const unsigned long sata_deb_timing_long[]; +extern const struct ata_port_operations ata_dummy_port_ops; + static inline const unsigned long * sata_ehc_deb_timing(struct ata_eh_context *ehc) { @@ -661,6 +664,11 @@ sata_ehc_deb_timing(struct ata_eh_context *ehc) return sata_deb_timing_normal; } +static inline int ata_port_is_dummy(struct ata_port *ap) +{ + return ap->ops == &ata_dummy_port_ops; +} + extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); -- 2.39.2