aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-09-01 11:50:07 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-10-21 20:21:04 -0400
commit6c8ea89cecd780faa4f4c8ed8b3b6ab88f9fa841 (patch)
treea38ecca3c52cd4ca021137086b39d7dcd8b042cc
parent6b7ae9545ad9875a289f4191c0216b473e313cb9 (diff)
libata: implement LPM support for port multipliers
Port multipliers can do DIPM on fan-out links fine. Implement support for it. Tested w/ SIMG 57xx and marvell PMPs. Both the host and fan-out links enter power save modes nicely. SIMG 37xx and 47xx report link offline on SStatus causing EH to detach the devices. Blacklisted. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/ata/libata-eh.c21
-rw-r--r--drivers/ata/libata-pmp.c48
-rw-r--r--drivers/ata/libata.h8
3 files changed, 67 insertions, 10 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a645cd3ab163..06a4db1ec10e 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -3232,7 +3232,7 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
3232static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, 3232static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
3233 struct ata_device **r_failed_dev) 3233 struct ata_device **r_failed_dev)
3234{ 3234{
3235 struct ata_port *ap = link->ap; 3235 struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
3236 struct ata_eh_context *ehc = &link->eh_context; 3236 struct ata_eh_context *ehc = &link->eh_context;
3237 struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; 3237 struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
3238 unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; 3238 unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
@@ -3278,9 +3278,12 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
3278 } 3278 }
3279 } 3279 }
3280 3280
3281 rc = ap->ops->set_lpm(link, policy, hints); 3281 if (ap) {
3282 if (!rc && ap->slave_link) 3282 rc = ap->ops->set_lpm(link, policy, hints);
3283 rc = ap->ops->set_lpm(ap->slave_link, policy, hints); 3283 if (!rc && ap->slave_link)
3284 rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
3285 } else
3286 rc = sata_pmp_set_lpm(link, policy, hints);
3284 3287
3285 /* 3288 /*
3286 * Attribute link config failure to the first (LPM) enabled 3289 * Attribute link config failure to the first (LPM) enabled
@@ -3412,8 +3415,14 @@ static int ata_eh_schedule_probe(struct ata_device *dev)
3412 ehc->saved_ncq_enabled &= ~(1 << dev->devno); 3415 ehc->saved_ncq_enabled &= ~(1 << dev->devno);
3413 3416
3414 /* the link maybe in a deep sleep, wake it up */ 3417 /* the link maybe in a deep sleep, wake it up */
3415 if (link->lpm_policy > ATA_LPM_MAX_POWER) 3418 if (link->lpm_policy > ATA_LPM_MAX_POWER) {
3416 link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER, ATA_LPM_EMPTY); 3419 if (ata_is_host_link(link))
3420 link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER,
3421 ATA_LPM_EMPTY);
3422 else
3423 sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER,
3424 ATA_LPM_EMPTY);
3425 }
3417 3426
3418 /* Record and count probe trials on the ering. The specific 3427 /* Record and count probe trials on the ering. The specific
3419 * error mask used is irrelevant. Because a successful device 3428 * error mask used is irrelevant. Because a successful device
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 505470237d79..3120596d4afc 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -186,6 +186,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
186} 186}
187 187
188/** 188/**
189 * sata_pmp_set_lpm - configure LPM for a PMP link
190 * @link: PMP link to configure LPM for
191 * @policy: target LPM policy
192 * @hints: LPM hints
193 *
194 * Configure LPM for @link. This function will contain any PMP
195 * specific workarounds if necessary.
196 *
197 * LOCKING:
198 * EH context.
199 *
200 * RETURNS:
201 * 0 on success, -errno on failure.
202 */
203int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
204 unsigned hints)
205{
206 return sata_link_scr_lpm(link, policy, true);
207}
208
209/**
189 * sata_pmp_read_gscr - read GSCR block of SATA PMP 210 * sata_pmp_read_gscr - read GSCR block of SATA PMP
190 * @dev: PMP device 211 * @dev: PMP device
191 * @gscr: buffer to read GSCR block into 212 * @gscr: buffer to read GSCR block into
@@ -365,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
365 if (vendor == 0x1095 && devid == 0x3726) { 386 if (vendor == 0x1095 && devid == 0x3726) {
366 /* sil3726 quirks */ 387 /* sil3726 quirks */
367 ata_for_each_link(link, ap, EDGE) { 388 ata_for_each_link(link, ap, EDGE) {
389 /* link reports offline after LPM */
390 link->flags |= ATA_LFLAG_NO_LPM;
391
368 /* Class code report is unreliable and SRST 392 /* Class code report is unreliable and SRST
369 * times out under certain configurations. 393 * times out under certain configurations.
370 */ 394 */
@@ -380,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
380 } else if (vendor == 0x1095 && devid == 0x4723) { 404 } else if (vendor == 0x1095 && devid == 0x4723) {
381 /* sil4723 quirks */ 405 /* sil4723 quirks */
382 ata_for_each_link(link, ap, EDGE) { 406 ata_for_each_link(link, ap, EDGE) {
407 /* link reports offline after LPM */
408 link->flags |= ATA_LFLAG_NO_LPM;
409
383 /* class code report is unreliable */ 410 /* class code report is unreliable */
384 if (link->pmp < 2) 411 if (link->pmp < 2)
385 link->flags |= ATA_LFLAG_ASSUME_ATA; 412 link->flags |= ATA_LFLAG_ASSUME_ATA;
@@ -392,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
392 } else if (vendor == 0x1095 && devid == 0x4726) { 419 } else if (vendor == 0x1095 && devid == 0x4726) {
393 /* sil4726 quirks */ 420 /* sil4726 quirks */
394 ata_for_each_link(link, ap, EDGE) { 421 ata_for_each_link(link, ap, EDGE) {
422 /* link reports offline after LPM */
423 link->flags |= ATA_LFLAG_NO_LPM;
424
395 /* Class code report is unreliable and SRST 425 /* Class code report is unreliable and SRST
396 * times out under certain configurations. 426 * times out under certain configurations.
397 * Config device can be at port 0 or 5 and 427 * Config device can be at port 0 or 5 and
@@ -952,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
952 if (rc) 982 if (rc)
953 goto link_fail; 983 goto link_fail;
954 984
955 /* Connection status might have changed while resetting other
956 * links, check SATA_PMP_GSCR_ERROR before returning.
957 */
958
959 /* clear SNotification */ 985 /* clear SNotification */
960 rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); 986 rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
961 if (rc == 0) 987 if (rc == 0)
962 sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); 988 sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
963 989
990 /*
991 * If LPM is active on any fan-out port, hotplug wouldn't
992 * work. Return w/ PHY event notification disabled.
993 */
994 ata_for_each_link(link, ap, EDGE)
995 if (link->lpm_policy > ATA_LPM_MAX_POWER)
996 return 0;
997
998 /*
999 * Connection status might have changed while resetting other
1000 * links, enable notification and check SATA_PMP_GSCR_ERROR
1001 * before returning.
1002 */
1003
964 /* enable notification */ 1004 /* enable notification */
965 if (pmp_dev->flags & ATA_DFLAG_AN) { 1005 if (pmp_dev->flags & ATA_DFLAG_AN) {
966 gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; 1006 gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 55a6f413a550..7c070a4b1c08 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -176,6 +176,8 @@ extern int ata_ering_map(struct ata_ering *ering,
176#ifdef CONFIG_SATA_PMP 176#ifdef CONFIG_SATA_PMP
177extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); 177extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
178extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); 178extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
179extern int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
180 unsigned hints);
179extern int sata_pmp_attach(struct ata_device *dev); 181extern int sata_pmp_attach(struct ata_device *dev);
180#else /* CONFIG_SATA_PMP */ 182#else /* CONFIG_SATA_PMP */
181static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val) 183static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val)
@@ -188,6 +190,12 @@ static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
188 return -EINVAL; 190 return -EINVAL;
189} 191}
190 192
193static inline int sata_pmp_set_lpm(struct ata_link *link,
194 enum ata_lpm_policy policy, unsigned hints)
195{
196 return -EINVAL;
197}
198
191static inline int sata_pmp_attach(struct ata_device *dev) 199static inline int sata_pmp_attach(struct ata_device *dev)
192{ 200{
193 return -EINVAL; 201 return -EINVAL;