Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 110255
b: refs/heads/master
c: b1c7291
h: refs/heads/master
i:
  110253: d461844
  110251: 04f0a42
  110247: a5781d3
  110239: d18ca30
v: v3
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Sep 29, 2008
1 parent ffd3058 commit b3e1369
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 53 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b5b3fa386b8f96c7fa92e507e5deddc2637924b4
refs/heads/master: b1c72916abbdd0a55015c87358536ca0ebaf6735
202 changes: 179 additions & 23 deletions trunk/drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,51 @@ struct ata_link *__ata_port_next_link(struct ata_port *ap,
return &ap->link;
}

/* we just iterated over the host link, what's next? */
if (ata_is_host_link(link)) {
if (!sata_pmp_attached(ap))
/* we just iterated over the host master link, what's next? */
if (link == &ap->link) {
if (!sata_pmp_attached(ap)) {
if (unlikely(ap->slave_link) && !dev_only)
return ap->slave_link;
return NULL;
}
return ap->pmp_link;
}

/* slave_link excludes PMP */
if (unlikely(link == ap->slave_link))
return NULL;

/* iterate to the next PMP link */
if (++link < ap->pmp_link + ap->nr_pmp_links)
return link;
return NULL;
}

/**
* ata_dev_phys_link - find physical link for a device
* @dev: ATA device to look up physical link for
*
* Look up physical link which @dev is attached to. Note that
* this is different from @dev->link only when @dev is on slave
* link. For all other cases, it's the same as @dev->link.
*
* LOCKING:
* Don't care.
*
* RETURNS:
* Pointer to the found physical link.
*/
struct ata_link *ata_dev_phys_link(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;

if (!ap->slave_link)
return dev->link;
if (!dev->devno)
return &ap->link;
return ap->slave_link;
}

/**
* ata_force_cbl - force cable type according to libata.force
* @ap: ATA port of interest
Expand Down Expand Up @@ -235,20 +267,20 @@ void ata_force_cbl(struct ata_port *ap)
* the host link and all fan-out ports connected via PMP. If the
* device part is specified as 0 (e.g. 1.00:), it specifies the
* first fan-out link not the host link. Device number 15 always
* points to the host link whether PMP is attached or not.
* points to the host link whether PMP is attached or not. If the
* controller has slave link, device number 16 points to it.
*
* LOCKING:
* EH context.
*/
static void ata_force_link_limits(struct ata_link *link)
{
bool did_spd = false;
int linkno, i;
int linkno = link->pmp;
int i;

if (ata_is_host_link(link))
linkno = 15;
else
linkno = link->pmp;
linkno += 15;

for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
Expand Down Expand Up @@ -295,9 +327,9 @@ static void ata_force_xfermask(struct ata_device *dev)
int alt_devno = devno;
int i;

/* allow n.15 for the first device attached to host port */
if (ata_is_host_link(dev->link) && devno == 0)
alt_devno = 15;
/* allow n.15/16 for devices attached to host port */
if (ata_is_host_link(dev->link))
alt_devno += 15;

for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
Expand Down Expand Up @@ -349,9 +381,9 @@ static void ata_force_horkage(struct ata_device *dev)
int alt_devno = devno;
int i;

/* allow n.15 for the first device attached to host port */
if (ata_is_host_link(dev->link) && devno == 0)
alt_devno = 15;
/* allow n.15/16 for devices attached to host port */
if (ata_is_host_link(dev->link))
alt_devno += 15;

for (i = 0; i < ata_force_tbl_size; i++) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
Expand Down Expand Up @@ -2710,7 +2742,7 @@ static void sata_print_link_status(struct ata_link *link)
return;
sata_scr_read(link, SCR_CONTROL, &scontrol);

if (ata_link_online(link)) {
if (ata_phys_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
ata_link_printk(link, KERN_INFO,
"SATA link up %s (SStatus %X SControl %X)\n",
Expand Down Expand Up @@ -3401,6 +3433,12 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
unsigned long nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT);
int warned = 0;

/* Slave readiness can't be tested separately from master. On
* M/S emulation configuration, this function should be called
* only on the master and it will handle both master and slave.
*/
WARN_ON(link == link->ap->slave_link);

if (time_after(nodev_deadline, deadline))
nodev_deadline = deadline;

Expand Down Expand Up @@ -3622,7 +3660,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
}

/* no point in trying softreset on offline link */
if (ata_link_offline(link))
if (ata_phys_link_offline(link))
ehc->i.action &= ~ATA_EH_SOFTRESET;

return 0;
Expand Down Expand Up @@ -3700,7 +3738,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (rc)
goto out;
/* if link is offline nothing more to do */
if (ata_link_offline(link))
if (ata_phys_link_offline(link))
goto out;

/* Link is online. From this point, -ENODEV too is an error. */
Expand Down Expand Up @@ -4965,7 +5003,7 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
}

/**
* ata_link_online - test whether the given link is online
* ata_phys_link_online - test whether the given link is online
* @link: ATA link to test
*
* Test whether @link is online. Note that this function returns
Expand All @@ -4978,7 +5016,7 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
* RETURNS:
* True if the port online status is available and online.
*/
bool ata_link_online(struct ata_link *link)
bool ata_phys_link_online(struct ata_link *link)
{
u32 sstatus;

Expand All @@ -4989,7 +5027,7 @@ bool ata_link_online(struct ata_link *link)
}

/**
* ata_link_offline - test whether the given link is offline
* ata_phys_link_offline - test whether the given link is offline
* @link: ATA link to test
*
* Test whether @link is offline. Note that this function
Expand All @@ -5002,7 +5040,7 @@ bool ata_link_online(struct ata_link *link)
* RETURNS:
* True if the port offline status is available and offline.
*/
bool ata_link_offline(struct ata_link *link)
bool ata_phys_link_offline(struct ata_link *link)
{
u32 sstatus;

Expand All @@ -5012,6 +5050,58 @@ bool ata_link_offline(struct ata_link *link)
return false;
}

/**
* ata_link_online - test whether the given link is online
* @link: ATA link to test
*
* Test whether @link is online. This is identical to
* ata_phys_link_online() when there's no slave link. When
* there's a slave link, this function should only be called on
* the master link and will return true if any of M/S links is
* online.
*
* LOCKING:
* None.
*
* RETURNS:
* True if the port online status is available and online.
*/
bool ata_link_online(struct ata_link *link)
{
struct ata_link *slave = link->ap->slave_link;

WARN_ON(link == slave); /* shouldn't be called on slave link */

return ata_phys_link_online(link) ||
(slave && ata_phys_link_online(slave));
}

/**
* ata_link_offline - test whether the given link is offline
* @link: ATA link to test
*
* Test whether @link is offline. This is identical to
* ata_phys_link_offline() when there's no slave link. When
* there's a slave link, this function should only be called on
* the master link and will return true if both M/S links are
* offline.
*
* LOCKING:
* None.
*
* RETURNS:
* True if the port offline status is available and offline.
*/
bool ata_link_offline(struct ata_link *link)
{
struct ata_link *slave = link->ap->slave_link;

WARN_ON(link == slave); /* shouldn't be called on slave link */

return ata_phys_link_offline(link) &&
(!slave || ata_phys_link_offline(slave));
}

#ifdef CONFIG_PM
static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
unsigned int action, unsigned int ehi_flags,
Expand Down Expand Up @@ -5151,11 +5241,11 @@ int ata_port_start(struct ata_port *ap)
*/
void ata_dev_init(struct ata_device *dev)
{
struct ata_link *link = dev->link;
struct ata_link *link = ata_dev_phys_link(dev);
struct ata_port *ap = link->ap;
unsigned long flags;

/* SATA spd limit is bound to the first device */
/* SATA spd limit is bound to the attached device, reset together */
link->sata_spd_limit = link->hw_sata_spd_limit;
link->sata_spd = 0;

Expand Down Expand Up @@ -5318,6 +5408,7 @@ static void ata_host_release(struct device *gendev, void *res)
scsi_host_put(ap->scsi_host);

kfree(ap->pmp_link);
kfree(ap->slave_link);
kfree(ap);
host->ports[i] = NULL;
}
Expand Down Expand Up @@ -5438,6 +5529,68 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
return host;
}

/**
* ata_slave_link_init - initialize slave link
* @ap: port to initialize slave link for
*
* Create and initialize slave link for @ap. This enables slave
* link handling on the port.
*
* In libata, a port contains links and a link contains devices.
* There is single host link but if a PMP is attached to it,
* there can be multiple fan-out links. On SATA, there's usually
* a single device connected to a link but PATA and SATA
* controllers emulating TF based interface can have two - master
* and slave.
*
* However, there are a few controllers which don't fit into this
* abstraction too well - SATA controllers which emulate TF
* interface with both master and slave devices but also have
* separate SCR register sets for each device. These controllers
* need separate links for physical link handling
* (e.g. onlineness, link speed) but should be treated like a
* traditional M/S controller for everything else (e.g. command
* issue, softreset).
*
* slave_link is libata's way of handling this class of
* controllers without impacting core layer too much. For
* anything other than physical link handling, the default host
* link is used for both master and slave. For physical link
* handling, separate @ap->slave_link is used. All dirty details
* are implemented inside libata core layer. From LLD's POV, the
* only difference is that prereset, hardreset and postreset are
* called once more for the slave link, so the reset sequence
* looks like the following.
*
* prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
* softreset(M) -> postreset(M) -> postreset(S)
*
* Note that softreset is called only for the master. Softreset
* resets both M/S by definition, so SRST on master should handle
* both (the standard method will work just fine).
*
* LOCKING:
* Should be called before host is registered.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int ata_slave_link_init(struct ata_port *ap)
{
struct ata_link *link;

WARN_ON(ap->slave_link);
WARN_ON(ap->flags & ATA_FLAG_PMP);

link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
return -ENOMEM;

ata_link_init(ap, link, 1);
ap->slave_link = link;
return 0;
}

static void ata_host_stop(struct device *gendev, void *res)
{
struct ata_host *host = dev_get_drvdata(gendev);
Expand Down Expand Up @@ -5664,6 +5817,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)

/* init sata_spd_limit to the current value */
sata_link_init_spd(&ap->link);
if (ap->slave_link)
sata_link_init_spd(ap->slave_link);

/* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
Expand Down Expand Up @@ -6289,6 +6444,7 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_host_alloc);
EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
EXPORT_SYMBOL_GPL(ata_slave_link_init);
EXPORT_SYMBOL_GPL(ata_host_start);
EXPORT_SYMBOL_GPL(ata_host_register);
EXPORT_SYMBOL_GPL(ata_host_activate);
Expand Down
Loading

0 comments on commit b3e1369

Please sign in to comment.