diff options
author | Tejun Heo <tj@kernel.org> | 2010-09-01 11:50:07 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-10-21 20:21:04 -0400 |
commit | 6c8ea89cecd780faa4f4c8ed8b3b6ab88f9fa841 (patch) | |
tree | a38ecca3c52cd4ca021137086b39d7dcd8b042cc /drivers/ata/libata-pmp.c | |
parent | 6b7ae9545ad9875a289f4191c0216b473e313cb9 (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.c | 48 |
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 | */ | ||
203 | int 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; |