summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/ata.c20
-rw-r--r--firmware/export/ata.h3
2 files changed, 20 insertions, 3 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 910d42d3b5..1c85b7bd5f 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -155,7 +155,8 @@ static inline bool ata_sleep_timed_out(void)
static inline void schedule_ata_power_off(void)
{
#ifdef HAVE_ATA_POWER_OFF
- power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT;
+ if (!ata_disk_can_poweroff())
+ power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT;
#endif
}
@@ -399,8 +400,8 @@ int ata_disk_isssd(void)
However, this is a relatively recent change, and we can't rely on it,
especially for the FC1307A CF->SD adapters!
- Offset 167 is "Nominal Form Factor"
- all values >= 0x06 are guaranteed to be solid State.
+ Offset 168 is "Nominal Form Factor"
+ all values >= 0x06 are guaranteed to be Solid State (mSATA, m.2, etc)
Offset 83 b2 and/or 86 b2 is set to show device implementes CFA commands
@@ -414,6 +415,19 @@ int ata_disk_isssd(void)
identify_info[217] == 0x0001 || identify_info[217] == 0x0100);
}
+int ata_disk_can_poweroff(void)
+{
+ /* Some SSDs don't like getting powered off, presumably because
+ in the real world they're not in removable form factors and
+ don't expect to have power removed.
+
+ In particular, mSATA, m.2, and MicroSSD are suspect.
+ */
+
+ return ((identify_info[168] & 0x0f) < 0x06 ||
+ (identify_info[168] & 0x0f) > 0x08);
+}
+
static int ata_transfer_sectors(unsigned long start,
int incount,
void* inbuf,
diff --git a/firmware/export/ata.h b/firmware/export/ata.h
index 7c5fd3a8d0..7c7c60e898 100644
--- a/firmware/export/ata.h
+++ b/firmware/export/ata.h
@@ -168,6 +168,9 @@ int ata_spinup_time(void); /* ticks */
/* Returns 1 if drive is solid-state */
int ata_disk_isssd(void);
+/* Returns 1 if the drive can be powered off safely */
+int ata_disk_can_poweroff(void);
+
#ifdef HAVE_ATA_DMA
/* Returns current DMA mode */
int ata_get_dma_mode(void);