libata: implement PMP helpers

Implement helpers to test whether PMP is supported, attached and
determine pmp number to use when issuing SRST to a link.  While at it,
move ata_is_host_link() so that it's together with the two new PMP
helpers.

This change simplifies LLDs and helps making PMP support optional.

Signed-off-by: Tejun Heo <htejun@gmail.com>
This commit is contained in:
Tejun Heo 2008-04-07 22:47:22 +09:00 committed by Jeff Garzik
parent 48515f6c00
commit 071f44b1d2
8 changed files with 58 additions and 69 deletions

View File

@ -260,8 +260,6 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline); unsigned long deadline);
static void ahci_postreset(struct ata_link *link, unsigned int *class); static void ahci_postreset(struct ata_link *link, unsigned int *class);
static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static void ahci_error_handler(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static int ahci_port_resume(struct ata_port *ap); static int ahci_port_resume(struct ata_port *ap);
@ -301,7 +299,7 @@ static struct ata_port_operations ahci_ops = {
.softreset = ahci_softreset, .softreset = ahci_softreset,
.hardreset = ahci_hardreset, .hardreset = ahci_hardreset,
.postreset = ahci_postreset, .postreset = ahci_postreset,
.pmp_softreset = ahci_pmp_softreset, .pmp_softreset = ahci_softreset,
.error_handler = ahci_error_handler, .error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd, .post_internal_cmd = ahci_post_internal_cmd,
.dev_config = ahci_dev_config, .dev_config = ahci_dev_config,
@ -1263,10 +1261,11 @@ static int ahci_check_ready(struct ata_link *link)
return 0; return 0;
} }
static int ahci_do_softreset(struct ata_link *link, unsigned int *class, static int ahci_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline) unsigned long deadline)
{ {
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
int pmp = sata_srst_pmp(link);
const char *reason = NULL; const char *reason = NULL;
unsigned long now, msecs; unsigned long now, msecs;
struct ata_taskfile tf; struct ata_taskfile tf;
@ -1326,17 +1325,6 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
return rc; return rc;
} }
static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
int pmp = 0;
if (link->ap->flags & ATA_FLAG_PMP)
pmp = SATA_PMP_CTRL_PORT;
return ahci_do_softreset(link, class, pmp, deadline);
}
static int ahci_hardreset(struct ata_link *link, unsigned int *class, static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline) unsigned long deadline)
{ {
@ -1457,12 +1445,6 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class)
} }
} }
static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
return ahci_do_softreset(link, class, link->pmp, deadline);
}
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
{ {
struct scatterlist *sg; struct scatterlist *sg;
@ -1581,7 +1563,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
unk[0], unk[1], unk[2], unk[3]); unk[0], unk[1], unk[2], unk[3]);
} }
if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
active_ehi->err_mask |= AC_ERR_HSM; active_ehi->err_mask |= AC_ERR_HSM;
active_ehi->action |= ATA_EH_RESET; active_ehi->action |= ATA_EH_RESET;
ata_ehi_push_desc(active_ehi, "incorrect PMP"); ata_ehi_push_desc(active_ehi, "incorrect PMP");
@ -1847,7 +1829,7 @@ static int ahci_port_resume(struct ata_port *ap)
ahci_power_up(ap); ahci_power_up(ap);
ahci_start_port(ap); ahci_start_port(ap);
if (ap->nr_pmp_links) if (sata_pmp_attached(ap))
ahci_pmp_attach(ap); ahci_pmp_attach(ap);
else else
ahci_pmp_detach(ap); ahci_pmp_detach(ap);

View File

@ -77,7 +77,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap)
{ {
WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
if (!ap->nr_pmp_links) { if (!sata_pmp_attached(ap)) {
acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
ap->link.device->acpi_handle = ap->link.device->acpi_handle =

View File

@ -2278,7 +2278,7 @@ int ata_dev_configure(struct ata_device *dev)
* changed notifications and ATAPI ANs. * changed notifications and ATAPI ANs.
*/ */
if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) && if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
(!ap->nr_pmp_links || (!sata_pmp_attached(ap) ||
sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) { sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
unsigned int err_mask; unsigned int err_mask;
@ -3623,7 +3623,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (online) if (online)
*online = true; *online = true;
if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) { if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) {
/* If PMP is supported, we have to do follow-up SRST. /* If PMP is supported, we have to do follow-up SRST.
* Some PMPs don't send D2H Reg FIS after hardreset if * Some PMPs don't send D2H Reg FIS after hardreset if
* the first port is empty. Wait only for * the first port is empty. Wait only for

View File

@ -873,9 +873,9 @@ int sata_async_notification(struct ata_port *ap)
if (rc == 0) if (rc == 0)
sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
if (!ap->nr_pmp_links || rc) { if (!sata_pmp_attached(ap) || rc) {
/* PMP is not attached or SNTF is not available */ /* PMP is not attached or SNTF is not available */
if (!ap->nr_pmp_links) { if (!sata_pmp_attached(ap)) {
/* PMP is not attached. Check whether ATAPI /* PMP is not attached. Check whether ATAPI
* AN is configured. If so, notify media * AN is configured. If so, notify media
* change. * change.
@ -1853,7 +1853,7 @@ void ata_eh_autopsy(struct ata_port *ap)
/* Autopsy of fanout ports can affect host link autopsy. /* Autopsy of fanout ports can affect host link autopsy.
* Perform host link autopsy last. * Perform host link autopsy last.
*/ */
if (ap->nr_pmp_links) if (sata_pmp_attached(ap))
ata_eh_link_autopsy(&ap->link); ata_eh_link_autopsy(&ap->link);
} }
@ -2076,7 +2076,7 @@ static int ata_eh_followup_srst_needed(struct ata_link *link,
} }
if (rc != 0) if (rc != 0)
return 0; return 0;
if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) if (sata_pmp_supported(link->ap) && ata_is_host_link(link))
return 1; return 1;
return 0; return 0;
} }
@ -2668,7 +2668,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
/* if PMP is attached, this function only deals with /* if PMP is attached, this function only deals with
* downstream links, port should stay thawed. * downstream links, port should stay thawed.
*/ */
if (!ap->nr_pmp_links) if (!sata_pmp_attached(ap))
ata_eh_freeze_port(ap); ata_eh_freeze_port(ap);
ata_port_for_each_link(link, ap) { ata_port_for_each_link(link, ap) {
@ -2687,7 +2687,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
} }
} }
if (!ap->nr_pmp_links) if (!sata_pmp_attached(ap))
ata_eh_thaw_port(ap); ata_eh_thaw_port(ap);
} }
@ -2731,7 +2731,7 @@ dev_fail:
/* PMP reset requires working host port. /* PMP reset requires working host port.
* Can't retry if it's frozen. * Can't retry if it's frozen.
*/ */
if (ap->nr_pmp_links) if (sata_pmp_attached(ap))
goto out; goto out;
break; break;
} }

View File

@ -411,7 +411,7 @@ int sata_pmp_attach(struct ata_device *dev)
int rc; int rc;
/* is it hanging off the right place? */ /* is it hanging off the right place? */
if (!(ap->flags & ATA_FLAG_PMP)) { if (!sata_pmp_supported(ap)) {
ata_dev_printk(dev, KERN_ERR, ata_dev_printk(dev, KERN_ERR,
"host does not support Port Multiplier\n"); "host does not support Port Multiplier\n");
return -EINVAL; return -EINVAL;
@ -876,7 +876,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
retry: retry:
/* PMP attached? */ /* PMP attached? */
if (!ap->nr_pmp_links) { if (!sata_pmp_attached(ap)) {
rc = ata_eh_recover(ap, ops->prereset, ops->softreset, rc = ata_eh_recover(ap, ops->prereset, ops->softreset,
ops->hardreset, ops->postreset, NULL); ops->hardreset, ops->postreset, NULL);
if (rc) { if (rc) {
@ -983,7 +983,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_UNLOADING) if (ap->pflags & ATA_PFLAG_UNLOADING)
return rc; return rc;
if (!ap->nr_pmp_links) if (!sata_pmp_attached(ap))
goto retry; goto retry;
if (--pmp_tries) { if (--pmp_tries) {

View File

@ -2617,7 +2617,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
{ {
if (ap->nr_pmp_links == 0) { if (!sata_pmp_attached(ap)) {
if (likely(devno < ata_link_max_devices(&ap->link))) if (likely(devno < ata_link_max_devices(&ap->link)))
return &ap->link.device[devno]; return &ap->link.device[devno];
} else { } else {
@ -2634,7 +2634,7 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
int devno; int devno;
/* skip commands not addressed to targets we simulate */ /* skip commands not addressed to targets we simulate */
if (ap->nr_pmp_links == 0) { if (!sata_pmp_attached(ap)) {
if (unlikely(scsidev->channel || scsidev->lun)) if (unlikely(scsidev->channel || scsidev->lun))
return NULL; return NULL;
devno = scsidev->id; devno = scsidev->id;
@ -3492,7 +3492,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (lun != SCAN_WILD_CARD && lun) if (lun != SCAN_WILD_CARD && lun)
return -EINVAL; return -EINVAL;
if (ap->nr_pmp_links == 0) { if (!sata_pmp_attached(ap)) {
if (channel != SCAN_WILD_CARD && channel) if (channel != SCAN_WILD_CARD && channel)
return -EINVAL; return -EINVAL;
devno = id; devno = id;

View File

@ -354,8 +354,6 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline); unsigned long deadline);
static int sil24_hardreset(struct ata_link *link, unsigned int *class, static int sil24_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline); unsigned long deadline);
static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline); unsigned long deadline);
static void sil24_error_handler(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap);
@ -408,7 +406,7 @@ static struct ata_port_operations sil24_ops = {
.thaw = sil24_thaw, .thaw = sil24_thaw,
.softreset = sil24_softreset, .softreset = sil24_softreset,
.hardreset = sil24_hardreset, .hardreset = sil24_hardreset,
.pmp_softreset = sil24_pmp_softreset, .pmp_softreset = sil24_softreset,
.pmp_hardreset = sil24_pmp_hardreset, .pmp_hardreset = sil24_pmp_hardreset,
.error_handler = sil24_error_handler, .error_handler = sil24_error_handler,
.post_internal_cmd = sil24_post_internal_cmd, .post_internal_cmd = sil24_post_internal_cmd,
@ -588,7 +586,7 @@ static int sil24_init_port(struct ata_port *ap)
u32 tmp; u32 tmp;
/* clear PMP error status */ /* clear PMP error status */
if (ap->nr_pmp_links) if (sata_pmp_attached(ap))
sil24_clear_pmp(ap); sil24_clear_pmp(ap);
writel(PORT_CS_INIT, port + PORT_CTRL_STAT); writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
@ -653,10 +651,11 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
return rc; return rc;
} }
static int sil24_do_softreset(struct ata_link *link, unsigned int *class, static int sil24_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline) unsigned long deadline)
{ {
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
int pmp = sata_srst_pmp(link);
unsigned long timeout_msec = 0; unsigned long timeout_msec = 0;
struct ata_taskfile tf; struct ata_taskfile tf;
const char *reason; const char *reason;
@ -706,12 +705,6 @@ static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
return -EIO; return -EIO;
} }
static int sil24_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
}
static int sil24_hardreset(struct ata_link *link, unsigned int *class, static int sil24_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline) unsigned long deadline)
{ {
@ -926,12 +919,6 @@ static void sil24_pmp_detach(struct ata_port *ap)
sil24_config_pmp(ap, 0); sil24_config_pmp(ap, 0);
} }
static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
return sil24_do_softreset(link, class, link->pmp, deadline);
}
static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline) unsigned long deadline)
{ {
@ -1034,7 +1021,7 @@ static void sil24_error_intr(struct ata_port *ap)
} }
/* find out the offending link and qc */ /* find out the offending link and qc */
if (ap->nr_pmp_links) { if (sata_pmp_attached(ap)) {
context = readl(port + PORT_CONTEXT); context = readl(port + PORT_CONTEXT);
pmp = (context >> 5) & 0xf; pmp = (context >> 5) & 0xf;
@ -1082,7 +1069,7 @@ static void sil24_error_intr(struct ata_port *ap)
ehi->action |= action; ehi->action |= action;
/* if PMP, resume */ /* if PMP, resume */
if (ap->nr_pmp_links) if (sata_pmp_attached(ap))
writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT); writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
} }

View File

@ -1089,6 +1089,31 @@ extern const struct ata_port_operations sata_port_ops;
ATA_BASE_SHT(drv_name), \ ATA_BASE_SHT(drv_name), \
.change_queue_depth = ata_scsi_change_queue_depth .change_queue_depth = ata_scsi_change_queue_depth
/*
* PMP helpers
*/
static inline bool sata_pmp_supported(struct ata_port *ap)
{
return ap->flags & ATA_FLAG_PMP;
}
static inline bool sata_pmp_attached(struct ata_port *ap)
{
return ap->nr_pmp_links != 0;
}
static inline int ata_is_host_link(const struct ata_link *link)
{
return link == &link->ap->link;
}
static inline int sata_srst_pmp(struct ata_link *link)
{
if (sata_pmp_supported(link->ap) && ata_is_host_link(link))
return SATA_PMP_CTRL_PORT;
return link->pmp;
}
/* /*
* printk helpers * printk helpers
*/ */
@ -1096,7 +1121,7 @@ extern const struct ata_port_operations sata_port_ops;
printk("%sata%u: "fmt, lv, (ap)->print_id , ##args) printk("%sata%u: "fmt, lv, (ap)->print_id , ##args)
#define ata_link_printk(link, lv, fmt, args...) do { \ #define ata_link_printk(link, lv, fmt, args...) do { \
if ((link)->ap->nr_pmp_links) \ if (sata_pmp_attached((link)->ap)) \
printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \ printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \
(link)->pmp , ##args); \ (link)->pmp , ##args); \
else \ else \
@ -1182,11 +1207,6 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
/* /*
* link helpers * link helpers
*/ */
static inline int ata_is_host_link(const struct ata_link *link)
{
return link == &link->ap->link;
}
static inline int ata_link_max_devices(const struct ata_link *link) static inline int ata_link_max_devices(const struct ata_link *link)
{ {
if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS) if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS)
@ -1201,7 +1221,7 @@ static inline int ata_link_active(struct ata_link *link)
static inline struct ata_link *ata_port_first_link(struct ata_port *ap) static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
{ {
if (ap->nr_pmp_links) if (sata_pmp_attached(ap))
return ap->pmp_link; return ap->pmp_link;
return &ap->link; return &ap->link;
} }
@ -1210,8 +1230,8 @@ static inline struct ata_link *ata_port_next_link(struct ata_link *link)
{ {
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
if (link == &ap->link) { if (ata_is_host_link(link)) {
if (!ap->nr_pmp_links) if (!sata_pmp_attached(ap))
return NULL; return NULL;
return ap->pmp_link; return ap->pmp_link;
} }