aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-pmp.c
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 /drivers/ata/libata-pmp.c
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>
Diffstat (limited to 'drivers/ata/libata-pmp.c')
-rw-r--r--drivers/ata/libata-pmp.c48
1 files changed, 44 insertions, 4 deletions
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;