Commit dd5b06c4 authored by Tejun Heo's avatar Tejun Heo

[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: default avatarTejun Heo <htejun@gmail.com>
parent 2ec7df04
...@@ -5311,7 +5311,6 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, ...@@ -5311,7 +5311,6 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
{ {
struct Scsi_Host *shost; struct Scsi_Host *shost;
struct ata_port *ap; struct ata_port *ap;
int rc;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
...@@ -5333,15 +5332,7 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, ...@@ -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(ap, host_set, ent, port_no);
ata_port_init_shost(ap, shost); ata_port_init_shost(ap, shost);
rc = ap->ops->port_start(ap);
if (rc)
goto err_out;
return ap; return ap;
err_out:
scsi_host_put(shost);
return NULL;
} }
/** /**
...@@ -5415,11 +5406,27 @@ int ata_device_add(const struct ata_probe_ent *ent) ...@@ -5415,11 +5406,27 @@ int ata_device_add(const struct ata_probe_ent *ent)
if (!ap) if (!ap)
goto err_out; 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 */ /* Report the secondary IRQ for second channel legacy */
if (i == 1 && ent->irq2) if (i == 1 && ent->irq2)
irq_line = ent->irq2; irq_line = ent->irq2;
host_set->ports[i] = ap;
xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
(ap->mwdma_mask << ATA_SHIFT_MWDMA) | (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
(ap->pio_mask << ATA_SHIFT_PIO); (ap->pio_mask << ATA_SHIFT_PIO);
...@@ -5940,6 +5947,39 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, ...@@ -5940,6 +5947,39 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
return tmp; 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 * libata is essentially a library of internal helper functions for
* low-level ATA host controller drivers. As such, the API/ABI is * 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, ...@@ -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_normal);
EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
EXPORT_SYMBOL_GPL(sata_deb_timing_long); 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_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_host_set_init); EXPORT_SYMBOL_GPL(ata_host_set_init);
......
...@@ -353,6 +353,7 @@ struct ata_probe_ent { ...@@ -353,6 +353,7 @@ struct ata_probe_ent {
struct ata_ioports port[ATA_MAX_PORTS]; struct ata_ioports port[ATA_MAX_PORTS];
unsigned int n_ports; unsigned int n_ports;
unsigned int hard_port_no; unsigned int hard_port_no;
unsigned int dummy_port_mask;
unsigned int pio_mask; unsigned int pio_mask;
unsigned int mwdma_mask; unsigned int mwdma_mask;
unsigned int udma_mask; unsigned int udma_mask;
...@@ -652,6 +653,8 @@ extern const unsigned long sata_deb_timing_normal[]; ...@@ -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_hotplug[];
extern const unsigned long sata_deb_timing_long[]; extern const unsigned long sata_deb_timing_long[];
extern const struct ata_port_operations ata_dummy_port_ops;
static inline const unsigned long * static inline const unsigned long *
sata_ehc_deb_timing(struct ata_eh_context *ehc) sata_ehc_deb_timing(struct ata_eh_context *ehc)
{ {
...@@ -661,6 +664,11 @@ 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; 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 ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap); extern void __sata_phy_reset(struct ata_port *ap);
extern void sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment