diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/ata/libata-pmp.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/ata/libata-pmp.c')
-rw-r--r-- | drivers/ata/libata-pmp.c | 76 |
1 files changed, 70 insertions, 6 deletions
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 224faabd7b7e..f06b7ea590d3 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/libata.h> | 11 | #include <linux/libata.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include "libata.h" | 13 | #include "libata.h" |
14 | #include "libata-transport.h" | ||
14 | 15 | ||
15 | const struct ata_port_operations sata_pmp_port_ops = { | 16 | const struct ata_port_operations sata_pmp_port_ops = { |
16 | .inherits = &sata_port_ops, | 17 | .inherits = &sata_port_ops, |
@@ -185,6 +186,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) | |||
185 | } | 186 | } |
186 | 187 | ||
187 | /** | 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 | /** | ||
188 | * sata_pmp_read_gscr - read GSCR block of SATA PMP | 210 | * sata_pmp_read_gscr - read GSCR block of SATA PMP |
189 | * @dev: PMP device | 211 | * @dev: PMP device |
190 | * @gscr: buffer to read GSCR block into | 212 | * @gscr: buffer to read GSCR block into |
@@ -312,10 +334,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) | |||
312 | return rc; | 334 | return rc; |
313 | } | 335 | } |
314 | 336 | ||
315 | static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) | 337 | static int sata_pmp_init_links (struct ata_port *ap, int nr_ports) |
316 | { | 338 | { |
317 | struct ata_link *pmp_link = ap->pmp_link; | 339 | struct ata_link *pmp_link = ap->pmp_link; |
318 | int i; | 340 | int i, err; |
319 | 341 | ||
320 | if (!pmp_link) { | 342 | if (!pmp_link) { |
321 | pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, | 343 | pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, |
@@ -327,6 +349,13 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) | |||
327 | ata_link_init(ap, &pmp_link[i], i); | 349 | ata_link_init(ap, &pmp_link[i], i); |
328 | 350 | ||
329 | ap->pmp_link = pmp_link; | 351 | ap->pmp_link = pmp_link; |
352 | |||
353 | for (i = 0; i < SATA_PMP_MAX_PORTS; i++) { | ||
354 | err = ata_tlink_add(&pmp_link[i]); | ||
355 | if (err) { | ||
356 | goto err_tlink; | ||
357 | } | ||
358 | } | ||
330 | } | 359 | } |
331 | 360 | ||
332 | for (i = 0; i < nr_ports; i++) { | 361 | for (i = 0; i < nr_ports; i++) { |
@@ -339,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) | |||
339 | } | 368 | } |
340 | 369 | ||
341 | return 0; | 370 | return 0; |
371 | err_tlink: | ||
372 | while (--i >= 0) | ||
373 | ata_tlink_delete(&pmp_link[i]); | ||
374 | kfree(pmp_link); | ||
375 | ap->pmp_link = NULL; | ||
376 | return err; | ||
342 | } | 377 | } |
343 | 378 | ||
344 | static void sata_pmp_quirks(struct ata_port *ap) | 379 | static void sata_pmp_quirks(struct ata_port *ap) |
@@ -351,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap) | |||
351 | if (vendor == 0x1095 && devid == 0x3726) { | 386 | if (vendor == 0x1095 && devid == 0x3726) { |
352 | /* sil3726 quirks */ | 387 | /* sil3726 quirks */ |
353 | 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 | |||
354 | /* Class code report is unreliable and SRST | 392 | /* Class code report is unreliable and SRST |
355 | * times out under certain configurations. | 393 | * times out under certain configurations. |
356 | */ | 394 | */ |
@@ -366,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap) | |||
366 | } else if (vendor == 0x1095 && devid == 0x4723) { | 404 | } else if (vendor == 0x1095 && devid == 0x4723) { |
367 | /* sil4723 quirks */ | 405 | /* sil4723 quirks */ |
368 | 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 | |||
369 | /* class code report is unreliable */ | 410 | /* class code report is unreliable */ |
370 | if (link->pmp < 2) | 411 | if (link->pmp < 2) |
371 | link->flags |= ATA_LFLAG_ASSUME_ATA; | 412 | link->flags |= ATA_LFLAG_ASSUME_ATA; |
@@ -378,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap) | |||
378 | } else if (vendor == 0x1095 && devid == 0x4726) { | 419 | } else if (vendor == 0x1095 && devid == 0x4726) { |
379 | /* sil4726 quirks */ | 420 | /* sil4726 quirks */ |
380 | 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 | |||
381 | /* Class code report is unreliable and SRST | 425 | /* Class code report is unreliable and SRST |
382 | * times out under certain configurations. | 426 | * times out under certain configurations. |
383 | * Config device can be at port 0 or 5 and | 427 | * Config device can be at port 0 or 5 and |
@@ -405,6 +449,16 @@ static void sata_pmp_quirks(struct ata_port *ap) | |||
405 | * otherwise. Don't try hard to recover it. | 449 | * otherwise. Don't try hard to recover it. |
406 | */ | 450 | */ |
407 | ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; | 451 | ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; |
452 | } else if (vendor == 0x197b && devid == 0x2352) { | ||
453 | /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ | ||
454 | ata_for_each_link(link, ap, EDGE) { | ||
455 | /* SRST breaks detection and disks get misclassified | ||
456 | * LPM disabled to avoid potential problems | ||
457 | */ | ||
458 | link->flags |= ATA_LFLAG_NO_LPM | | ||
459 | ATA_LFLAG_NO_SRST | | ||
460 | ATA_LFLAG_ASSUME_ATA; | ||
461 | } | ||
408 | } | 462 | } |
409 | } | 463 | } |
410 | 464 | ||
@@ -938,15 +992,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap) | |||
938 | if (rc) | 992 | if (rc) |
939 | goto link_fail; | 993 | goto link_fail; |
940 | 994 | ||
941 | /* Connection status might have changed while resetting other | ||
942 | * links, check SATA_PMP_GSCR_ERROR before returning. | ||
943 | */ | ||
944 | |||
945 | /* clear SNotification */ | 995 | /* clear SNotification */ |
946 | rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); | 996 | rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); |
947 | if (rc == 0) | 997 | if (rc == 0) |
948 | sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); | 998 | sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); |
949 | 999 | ||
1000 | /* | ||
1001 | * If LPM is active on any fan-out port, hotplug wouldn't | ||
1002 | * work. Return w/ PHY event notification disabled. | ||
1003 | */ | ||
1004 | ata_for_each_link(link, ap, EDGE) | ||
1005 | if (link->lpm_policy > ATA_LPM_MAX_POWER) | ||
1006 | return 0; | ||
1007 | |||
1008 | /* | ||
1009 | * Connection status might have changed while resetting other | ||
1010 | * links, enable notification and check SATA_PMP_GSCR_ERROR | ||
1011 | * before returning. | ||
1012 | */ | ||
1013 | |||
950 | /* enable notification */ | 1014 | /* enable notification */ |
951 | if (pmp_dev->flags & ATA_DFLAG_AN) { | 1015 | if (pmp_dev->flags & ATA_DFLAG_AN) { |
952 | gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; | 1016 | gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; |