summaryrefslogtreecommitdiff
path: root/drivers/ps3/ps3stor_lib.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-15 20:51:09 +0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-15 20:51:09 +0400
commit723e9db7a46e328527cc3da2b478b831184fe828 (patch)
treecdeda255633057dcb4c84097bed27b2bbf76970f /drivers/ps3/ps3stor_lib.c
parentada3fa15057205b7d3f727bba5cd26b5912e350f (diff)
parentd331d8305cba713605854aab63a000fb892353a7 (diff)
downloadlinux-723e9db7a46e328527cc3da2b478b831184fe828.tar.xz
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (134 commits) powerpc/nvram: Enable use Generic NVRAM driver for different size chips powerpc/iseries: Fix oops reading from /proc/iSeries/mf/*/cmdline powerpc/ps3: Workaround for flash memory I/O error powerpc/booke: Don't set DABR on 64-bit BookE, use DAC1 instead powerpc/perf_counters: Reduce stack usage of power_check_constraints powerpc: Fix bug where perf_counters breaks oprofile powerpc/85xx: Fix SMP compile error and allow NULL for smp_ops powerpc/irq: Improve nanodoc powerpc: Fix some late PowerMac G5 with PCIe ATI graphics powerpc/fsl-booke: Use HW PTE format if CONFIG_PTE_64BIT powerpc/book3e: Add missing page sizes powerpc/pseries: Fix to handle slb resize across migration powerpc/powermac: Thermal control turns system off too eagerly powerpc/pci: Merge ppc32 and ppc64 versions of phb_scan() powerpc/405ex: support cuImage via included dtb powerpc/405ex: provide necessary fixup function to support cuImage powerpc/40x: Add support for the ESTeem 195E (PPC405EP) SBC powerpc/44x: Add Eiger AMCC (AppliedMicro) PPC460SX evaluation board support. powerpc/44x: Update Arches defconfig powerpc/44x: Update Arches dts ... Fix up conflicts in drivers/char/agp/uninorth-agp.c
Diffstat (limited to 'drivers/ps3/ps3stor_lib.c')
-rw-r--r--drivers/ps3/ps3stor_lib.c65
1 files changed, 62 insertions, 3 deletions
diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c
index 18066d555397..af0afa1db4a8 100644
--- a/drivers/ps3/ps3stor_lib.c
+++ b/drivers/ps3/ps3stor_lib.c
@@ -23,6 +23,65 @@
#include <asm/lv1call.h>
#include <asm/ps3stor.h>
+/*
+ * A workaround for flash memory I/O errors when the internal hard disk
+ * has not been formatted for OtherOS use. Delay disk close until flash
+ * memory is closed.
+ */
+
+static struct ps3_flash_workaround {
+ int flash_open;
+ int disk_open;
+ struct ps3_system_bus_device *disk_sbd;
+} ps3_flash_workaround;
+
+static int ps3stor_open_hv_device(struct ps3_system_bus_device *sbd)
+{
+ int error = ps3_open_hv_device(sbd);
+
+ if (error)
+ return error;
+
+ if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH)
+ ps3_flash_workaround.flash_open = 1;
+
+ if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
+ ps3_flash_workaround.disk_open = 1;
+
+ return 0;
+}
+
+static int ps3stor_close_hv_device(struct ps3_system_bus_device *sbd)
+{
+ int error;
+
+ if (sbd->match_id == PS3_MATCH_ID_STOR_DISK
+ && ps3_flash_workaround.disk_open
+ && ps3_flash_workaround.flash_open) {
+ ps3_flash_workaround.disk_sbd = sbd;
+ return 0;
+ }
+
+ error = ps3_close_hv_device(sbd);
+
+ if (error)
+ return error;
+
+ if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
+ ps3_flash_workaround.disk_open = 0;
+
+ if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) {
+ ps3_flash_workaround.flash_open = 0;
+
+ if (ps3_flash_workaround.disk_sbd) {
+ ps3_close_hv_device(ps3_flash_workaround.disk_sbd);
+ ps3_flash_workaround.disk_open = 0;
+ ps3_flash_workaround.disk_sbd = NULL;
+ }
+ }
+
+ return 0;
+}
static int ps3stor_probe_access(struct ps3_storage_device *dev)
{
@@ -90,7 +149,7 @@ int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
int error, res, alignment;
enum ps3_dma_page_size page_size;
- error = ps3_open_hv_device(&dev->sbd);
+ error = ps3stor_open_hv_device(&dev->sbd);
if (error) {
dev_err(&dev->sbd.core,
"%s:%u: ps3_open_hv_device failed %d\n", __func__,
@@ -166,7 +225,7 @@ fail_free_irq:
fail_sb_event_receive_port_destroy:
ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
fail_close_device:
- ps3_close_hv_device(&dev->sbd);
+ ps3stor_close_hv_device(&dev->sbd);
fail:
return error;
}
@@ -193,7 +252,7 @@ void ps3stor_teardown(struct ps3_storage_device *dev)
"%s:%u: destroy event receive port failed %d\n",
__func__, __LINE__, error);
- error = ps3_close_hv_device(&dev->sbd);
+ error = ps3stor_close_hv_device(&dev->sbd);
if (error)
dev_err(&dev->sbd.core,
"%s:%u: ps3_close_hv_device failed %d\n", __func__,