blob: d208f9dd76ad7240417f55552bf571df8133d6b9 [file] [log] [blame]
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Linus Nielsen Feltzinge14e13d2002-05-13 19:22:38 +000021#include <stdbool.h>
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000022#include "ata.h"
23#include "kernel.h"
Björn Stenberg11968a42002-07-16 14:07:47 +000024#include "thread.h"
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000025#include "led.h"
Linus Nielsen Feltzingd6810872004-10-07 07:09:49 +000026#include "cpu.h"
Björn Stenberg2cf3b5d2002-04-27 20:14:01 +000027#include "system.h"
Linus Nielsen Feltzingdc4977d2002-05-07 22:59:03 +000028#include "debug.h"
Linus Nielsen Feltzinga422b832002-06-18 12:53:02 +000029#include "panic.h"
Björn Stenberg11968a42002-07-16 14:07:47 +000030#include "usb.h"
Linus Nielsen Feltzing9d589402002-08-01 12:00:03 +000031#include "power.h"
Björn Stenberg6ee90d92002-08-15 12:54:52 +000032#include "string.h"
Jonathan Gordon0b227952006-11-06 14:24:18 +000033#include "ata_idle_notify.h"
Linus Nielsen Feltzing838a7022006-03-07 13:25:19 +000034#include "ata-target.h"
Linus Nielsen Feltzing838a7022006-03-07 13:25:19 +000035
Jean-Philippe Bernardy376057d2005-02-22 09:55:40 +000036#define SECTOR_SIZE (512)
37
Björn Stenberg65bf8512004-09-17 11:28:07 +000038#define ATA_FEATURE ATA_ERROR
Marcoen Hirschbergdd754882006-08-12 08:01:54 +000039
Björn Stenberg65bf8512004-09-17 11:28:07 +000040#define ATA_STATUS ATA_COMMAND
Björn Stenberg6c9e5782002-04-27 14:19:00 +000041#define ATA_ALT_STATUS ATA_CONTROL
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000042
Björn Stenberg5c7847c2002-05-22 14:37:36 +000043#define SELECT_DEVICE1 0x10
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000044#define SELECT_LBA 0x40
45
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000046#define CONTROL_nIEN 0x02
47#define CONTROL_SRST 0x04
48
49#define CMD_READ_SECTORS 0x20
50#define CMD_WRITE_SECTORS 0x30
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +000051#define CMD_WRITE_SECTORS_EXT 0x34
Björn Stenberg8ccbc762002-09-05 15:25:08 +000052#define CMD_READ_MULTIPLE 0xC4
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +000053#define CMD_READ_MULTIPLE_EXT 0x29
Björn Stenberg8ccbc762002-09-05 15:25:08 +000054#define CMD_WRITE_MULTIPLE 0xC5
55#define CMD_SET_MULTIPLE_MODE 0xC6
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000056#define CMD_STANDBY_IMMEDIATE 0xE0
57#define CMD_STANDBY 0xE2
Björn Stenberg8ccbc762002-09-05 15:25:08 +000058#define CMD_IDENTIFY 0xEC
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000059#define CMD_SLEEP 0xE6
Björn Stenberga53afc02004-01-14 13:15:19 +000060#define CMD_SET_FEATURES 0xEF
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000061#define CMD_SECURITY_FREEZE_LOCK 0xF5
62
Björn Stenberg11968a42002-07-16 14:07:47 +000063#define Q_SLEEP 0
Michael Sevakis80278e42008-05-10 18:00:11 +000064#define Q_CLOSE 1
Björn Stenberg11968a42002-07-16 14:07:47 +000065
Björn Stenberg70747f92002-09-24 14:23:18 +000066#define READ_TIMEOUT 5*HZ
67
Nils Wallménius1b85f602007-01-23 15:43:37 +000068#ifdef HAVE_ATA_POWER_OFF
69#define ATA_POWER_OFF_TIMEOUT 2*HZ
70#endif
71
Michael Sevakis80278e42008-05-10 18:00:11 +000072#ifdef ATA_DRIVER_CLOSE
73static struct thread_entry *ata_thread_p = NULL;
74#endif
75
Michael Sevakis606d9d02008-06-03 04:23:09 +000076#if defined(MAX_PHYS_SECTOR_SIZE) && MEM == 64
77/* Hack - what's the deal with 5g? */
78struct ata_lock
79{
80 struct thread_entry *thread;
81 int count;
82 volatile unsigned char locked;
83 IF_COP( struct corelock cl; )
84};
85
86static void ata_lock_init(struct ata_lock *l)
87{
88 corelock_init(&l->cl);
89 l->locked = 0;
90 l->count = 0;
91 l->thread = NULL;
92}
93
94static void ata_lock_lock(struct ata_lock *l)
95{
96 struct thread_entry * const current = thread_get_current();
97
98 if (current == l->thread)
99 {
100 l->count++;
101 return;
102 }
103
104 corelock_lock(&l->cl);
105
106 IF_PRIO( current->skip_count = -1; )
107
108 while (l->locked != 0)
109 {
110 corelock_unlock(&l->cl);
111 switch_thread();
112 corelock_lock(&l->cl);
113 }
114
115 l->locked = 1;
116 l->thread = current;
117 corelock_unlock(&l->cl);
118}
119
120static void ata_lock_unlock(struct ata_lock *l)
121{
122 if (l->count > 0)
123 {
124 l->count--;
125 return;
126 }
127
128 corelock_lock(&l->cl);
129
130 IF_PRIO( l->thread->skip_count = 0; )
131
132 l->thread = NULL;
133 l->locked = 0;
134
135 corelock_unlock(&l->cl);
136}
137
138#define mutex ata_lock
139#define mutex_init ata_lock_init
140#define mutex_lock ata_lock_lock
141#define mutex_unlock ata_lock_unlock
142#endif /* MAX_PHYS_SECTOR_SIZE */
143
Michael Sevakis05099142008-04-06 04:34:57 +0000144static struct mutex ata_mtx SHAREDBSS_ATTR;
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000145int ata_device; /* device 0 (master) or 1 (slave) */
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000146
Björn Stenbergb070dd52002-12-04 14:58:48 +0000147int ata_spinup_time = 0;
Jonathan Gordonbd47d482007-02-18 05:07:19 +0000148#if (CONFIG_LED == LED_REAL)
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000149static bool ata_led_enabled = true;
150static bool ata_led_on = false;
Jens Arnold5690f782005-06-04 23:15:52 +0000151#endif
Björn Stenbergefd90772002-12-06 15:17:30 +0000152static bool spinup = false;
Jörg Hohensohnf4b677e2003-07-18 21:55:06 +0000153static bool sleeping = true;
Björn Stenberg494d2612002-11-27 15:55:47 +0000154static bool poweroff = false;
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000155static long sleep_timeout = 5*HZ;
Jörg Hohensohnbb035862006-12-20 22:08:29 +0000156#ifdef HAVE_LBA48
157static bool lba48 = false; /* set for 48 bit addressing */
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000158#endif
Jonathan Gordonb2e50902007-01-23 13:40:44 +0000159static long ata_stack[(DEFAULT_STACK_SIZE*3)/sizeof(long)];
Jens Arnold2b0694c2004-08-03 05:58:46 +0000160static const char ata_thread_name[] = "ata";
Michael Sevakis84f5c5c2007-10-16 22:00:51 +0000161static struct event_queue ata_queue;
Björn Stenberg11968a42002-07-16 14:07:47 +0000162static bool initialized = false;
Linus Nielsen Feltzing1a5032e2002-06-26 12:36:29 +0000163
Björn Stenberg457b8a02002-08-26 13:21:14 +0000164static long last_user_activity = -1;
Linus Nielsen Feltzing040e80c2002-09-23 11:39:21 +0000165long last_disk_activity = -1;
Björn Stenberg457b8a02002-08-26 13:21:14 +0000166
Jens Arnold88e20532008-03-09 00:59:48 +0000167static unsigned long total_sectors;
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000168static int multisectors; /* number of supported multisectors */
Jens Arnold3fd2e522008-02-14 06:52:59 +0000169static unsigned short identify_info[SECTOR_SIZE/2];
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000170
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000171#ifdef MAX_PHYS_SECTOR_SIZE
Michael Sevakis766587e2008-02-22 17:29:37 +0000172
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000173struct sector_cache_entry {
174 bool inuse;
175 unsigned long sectornum; /* logical sector */
176 unsigned char data[MAX_PHYS_SECTOR_SIZE];
177};
178/* buffer for reading and writing large physical sectors */
179#define NUMCACHES 2
180static struct sector_cache_entry sector_cache;
181static int phys_sector_mult = 1;
182#endif
183
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000184static int ata_power_on(void);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000185static int perform_soft_reset(void);
Björn Stenberg7249c882002-12-02 10:30:40 +0000186static int set_multiple_mode(int sectors);
Linus Nielsen Feltzing97955a72004-02-17 01:31:50 +0000187static int set_features(void);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000188
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000189STATICIRAM ICODE_ATTR int wait_for_bsy(void)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000190{
Jean-Philippe Bernardyfc194452005-02-25 18:50:16 +0000191 long timeout = current_tick + HZ*30;
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000192
193 do
194 {
195 if (!(ATA_STATUS & STATUS_BSY))
196 return 1;
Björn Stenbergc695f262003-07-10 13:32:15 +0000197 last_disk_activity = current_tick;
Michael Sevakis27cf6772008-03-25 02:34:12 +0000198 yield();
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000199 } while (TIME_BEFORE(current_tick, timeout));
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000200
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000201 return 0; /* timeout */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000202}
203
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000204STATICIRAM ICODE_ATTR int wait_for_rdy(void)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000205{
Jean-Philippe Bernardyfc194452005-02-25 18:50:16 +0000206 long timeout;
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000207
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000208 if (!wait_for_bsy())
209 return 0;
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000210
Björn Stenberge65b65e2002-09-04 20:15:45 +0000211 timeout = current_tick + HZ*10;
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000212
213 do
214 {
215 if (ATA_ALT_STATUS & STATUS_RDY)
216 return 1;
Björn Stenbergc695f262003-07-10 13:32:15 +0000217 last_disk_activity = current_tick;
Michael Sevakis27cf6772008-03-25 02:34:12 +0000218 yield();
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000219 } while (TIME_BEFORE(current_tick, timeout));
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000220
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000221 return 0; /* timeout */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000222}
223
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000224STATICIRAM ICODE_ATTR int wait_for_start_of_transfer(void)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000225{
226 if (!wait_for_bsy())
227 return 0;
Marcoen Hirschbergdd754882006-08-12 08:01:54 +0000228
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000229 return (ATA_ALT_STATUS & (STATUS_BSY|STATUS_DRQ)) == STATUS_DRQ;
230}
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000231
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000232STATICIRAM ICODE_ATTR int wait_for_end_of_transfer(void)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000233{
234 if (!wait_for_bsy())
235 return 0;
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000236 return (ATA_ALT_STATUS & (STATUS_RDY|STATUS_DRQ)) == STATUS_RDY;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000237}
238
Jonathan Gordonbd47d482007-02-18 05:07:19 +0000239#if (CONFIG_LED == LED_REAL)
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000240/* Conditionally block LED access for the ATA driver, so the LED can be
241 * (mis)used for other purposes */
242static void ata_led(bool on)
243{
244 ata_led_on = on;
245 if (ata_led_enabled)
246 led(ata_led_on);
247}
248#else
249#define ata_led(on) led(on)
250#endif
251
252#ifndef ATA_OPTIMIZED_READING
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000253STATICIRAM ICODE_ATTR void copy_read_sectors(unsigned char* buf, int wordcount)
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000254{
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000255 unsigned short tmp = 0;
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000256
Jean-Philippe Bernardy34d2a712005-01-24 14:26:24 +0000257 if ( (unsigned long)buf & 1)
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000258 { /* not 16-bit aligned, copy byte by byte */
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000259 unsigned char* bufend = buf + wordcount*2;
260 do
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000261 {
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000262 tmp = ATA_DATA;
Dave Chapmancf0e3d32006-01-18 14:04:30 +0000263#if defined(SWAP_WORDS) || defined(ROCKBOX_LITTLE_ENDIAN)
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000264 *buf++ = tmp & 0xff; /* I assume big endian */
265 *buf++ = tmp >> 8; /* and don't use the SWAB16 macro */
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000266#else
267 *buf++ = tmp >> 8;
268 *buf++ = tmp & 0xff;
269#endif
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000270 } while (buf < bufend); /* tail loop is faster */
271 }
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000272 else
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000273 { /* 16-bit aligned, can do faster copy */
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000274 unsigned short* wbuf = (unsigned short*)buf;
275 unsigned short* wbufend = wbuf + wordcount;
276 do
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000277 {
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000278#ifdef SWAP_WORDS
Dave Chapman77372d12005-11-07 23:07:19 +0000279 *wbuf = swap16(ATA_DATA);
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000280#else
281 *wbuf = ATA_DATA;
282#endif
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000283 } while (++wbuf < wbufend); /* tail loop is faster */
284 }
285}
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000286#endif /* !ATA_OPTIMIZED_READING */
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000287
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000288#ifdef MAX_PHYS_SECTOR_SIZE
289static int _read_sectors(unsigned long start,
290 int incount,
291 void* inbuf)
292#else
Jörg Hohensohn575c9042004-12-29 22:37:31 +0000293int ata_read_sectors(IF_MV2(int drive,)
Jörg Hohensohnda848572004-12-28 22:16:07 +0000294 unsigned long start,
Björn Stenberg7526cf72002-09-25 14:10:50 +0000295 int incount,
296 void* inbuf)
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000297#endif
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000298{
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000299 int ret = 0;
Jean-Philippe Bernardyfc194452005-02-25 18:50:16 +0000300 long timeout;
Björn Stenberg7526cf72002-09-25 14:10:50 +0000301 int count;
302 void* buf;
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000303 long spinup_start;
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000304
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000305#ifndef MAX_PHYS_SECTOR_SIZE
Jörg Hohensohn575c9042004-12-29 22:37:31 +0000306#ifdef HAVE_MULTIVOLUME
307 (void)drive; /* unused for now */
308#endif
Michael Sevakis6a837962008-01-18 13:12:33 +0000309 mutex_lock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000310#endif
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000311
Jens Arnold88e20532008-03-09 00:59:48 +0000312 if (start + incount > total_sectors) {
313 ret = -1;
314 goto error;
315 }
316
Björn Stenbergba0438e2002-12-05 09:35:01 +0000317 last_disk_activity = current_tick;
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000318 spinup_start = current_tick;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000319
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000320 ata_led(true);
Björn Stenberg494d2612002-11-27 15:55:47 +0000321
Björn Stenbergc4b28502002-07-16 12:18:17 +0000322 if ( sleeping ) {
Björn Stenbergefd90772002-12-06 15:17:30 +0000323 spinup = true;
Björn Stenberg494d2612002-11-27 15:55:47 +0000324 if (poweroff) {
325 if (ata_power_on()) {
Jens Arnold88e20532008-03-09 00:59:48 +0000326 ret = -2;
327 goto error;
Björn Stenberg494d2612002-11-27 15:55:47 +0000328 }
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000329 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000330 else {
331 if (perform_soft_reset()) {
Jens Arnold88e20532008-03-09 00:59:48 +0000332 ret = -2;
333 goto error;
Björn Stenberg494d2612002-11-27 15:55:47 +0000334 }
Björn Stenbergc4b28502002-07-16 12:18:17 +0000335 }
336 }
Björn Stenberg11968a42002-07-16 14:07:47 +0000337
Björn Stenberg6a581062003-02-27 13:26:09 +0000338 timeout = current_tick + READ_TIMEOUT;
339
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000340 SET_REG(ATA_SELECT, ata_device);
Linus Nielsen Feltzingb900a832002-05-08 08:27:44 +0000341 if (!wait_for_rdy())
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000342 {
Jens Arnold88e20532008-03-09 00:59:48 +0000343 ret = -3;
344 goto error;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000345 }
Linus Nielsen Feltzingb900a832002-05-08 08:27:44 +0000346
Björn Stenberg674b6322003-04-28 12:02:14 +0000347 retry:
Björn Stenberg7526cf72002-09-25 14:10:50 +0000348 buf = inbuf;
349 count = incount;
Björn Stenberg70747f92002-09-24 14:23:18 +0000350 while (TIME_BEFORE(current_tick, timeout)) {
Björn Stenbergb12401b2003-03-13 15:45:38 +0000351 ret = 0;
Björn Stenberg7682d462003-03-17 13:42:30 +0000352 last_disk_activity = current_tick;
Björn Stenbergf0599be2002-08-26 22:05:47 +0000353
Jörg Hohensohnbb035862006-12-20 22:08:29 +0000354#ifdef HAVE_LBA48
355 if (lba48)
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000356 {
357 SET_REG(ATA_NSECTOR, count >> 8);
358 SET_REG(ATA_NSECTOR, count & 0xff);
359 SET_REG(ATA_SECTOR, (start >> 24) & 0xff); /* 31:24 */
360 SET_REG(ATA_SECTOR, start & 0xff); /* 7:0 */
361 SET_REG(ATA_LCYL, 0); /* 39:32 */
362 SET_REG(ATA_LCYL, (start >> 8) & 0xff); /* 15:8 */
363 SET_REG(ATA_HCYL, 0); /* 47:40 */
364 SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */
365 SET_REG(ATA_SELECT, SELECT_LBA | ata_device);
366 SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE_EXT);
367 }
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000368 else
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000369#endif
370 {
Jörg Hohensohnbb035862006-12-20 22:08:29 +0000371 SET_REG(ATA_NSECTOR, count & 0xff); /* 0 means 256 sectors */
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000372 SET_REG(ATA_SECTOR, start & 0xff);
373 SET_REG(ATA_LCYL, (start >> 8) & 0xff);
374 SET_REG(ATA_HCYL, (start >> 16) & 0xff);
375 SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device);
376 SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE);
377 }
Linus Nielsen Feltzinge82f7012002-09-06 16:02:19 +0000378
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000379 /* wait at least 400ns between writing command and reading status */
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000380 __asm__ volatile ("nop");
381 __asm__ volatile ("nop");
382 __asm__ volatile ("nop");
383 __asm__ volatile ("nop");
384 __asm__ volatile ("nop");
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000385
Björn Stenberg70747f92002-09-24 14:23:18 +0000386 while (count) {
Björn Stenberg70747f92002-09-24 14:23:18 +0000387 int sectors;
388 int wordcount;
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000389 int status;
Björn Stenberg70747f92002-09-24 14:23:18 +0000390
391 if (!wait_for_start_of_transfer()) {
Linus Nielsen Feltzing8bda0e12004-03-19 13:26:43 +0000392 /* We have timed out waiting for RDY and/or DRQ, possibly
393 because the hard drive is shaking and has problems reading
394 the data. We have two options:
395 1) Wait some more
396 2) Perform a soft reset and try again.
397
398 We choose alternative 2.
399 */
Jens Arnold97599d32005-05-10 22:39:53 +0000400 perform_soft_reset();
Jens Arnold88e20532008-03-09 00:59:48 +0000401 ret = -5;
Björn Stenberg7526cf72002-09-25 14:10:50 +0000402 goto retry;
Björn Stenberged027a92002-08-14 14:34:54 +0000403 }
Björn Stenberg70747f92002-09-24 14:23:18 +0000404
Björn Stenbergbd0da0e2002-12-06 13:08:42 +0000405 if (spinup) {
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000406 ata_spinup_time = current_tick - spinup_start;
Björn Stenbergbd0da0e2002-12-06 13:08:42 +0000407 spinup = false;
408 sleeping = false;
409 poweroff = false;
410 }
411
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000412 /* read the status register exactly once per loop */
413 status = ATA_STATUS;
414
Björn Stenberg70747f92002-09-24 14:23:18 +0000415 if (count >= multisectors )
416 sectors = multisectors;
417 else
418 sectors = count;
419
420 wordcount = sectors * SECTOR_SIZE / 2;
421
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000422 copy_read_sectors(buf, wordcount);
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000423
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000424 /*
425 "Device errors encountered during READ MULTIPLE commands are
426 posted at the beginning of the block or partial block transfer,
427 but the DRQ bit is still set to one and the data transfer shall
428 take place, including transfer of corrupted data, if any."
429 -- ATA specification
430 */
431 if ( status & (STATUS_BSY | STATUS_ERR | STATUS_DF) ) {
Jens Arnold97599d32005-05-10 22:39:53 +0000432 perform_soft_reset();
Jens Arnold88e20532008-03-09 00:59:48 +0000433 ret = -6;
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000434 goto retry;
435 }
Jens Arnold97599d32005-05-10 22:39:53 +0000436
Björn Stenberg70747f92002-09-24 14:23:18 +0000437 buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */
438 count -= sectors;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000439
440 last_disk_activity = current_tick;
Björn Stenberg70747f92002-09-24 14:23:18 +0000441 }
442
Björn Stenbergaa783242003-03-24 16:19:54 +0000443 if(!ret && !wait_for_end_of_transfer()) {
Jens Arnold97599d32005-05-10 22:39:53 +0000444 perform_soft_reset();
Jens Arnold88e20532008-03-09 00:59:48 +0000445 ret = -4;
Björn Stenberg7526cf72002-09-25 14:10:50 +0000446 goto retry;
Björn Stenberg70747f92002-09-24 14:23:18 +0000447 }
Björn Stenberg70747f92002-09-24 14:23:18 +0000448 break;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000449 }
Jens Arnold8c6920e2008-03-08 23:50:55 +0000450
Jens Arnold88e20532008-03-09 00:59:48 +0000451 error:
452 ata_led(false);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000453#ifndef MAX_PHYS_SECTOR_SIZE
Michael Sevakis6a837962008-01-18 13:12:33 +0000454 mutex_unlock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000455#endif
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000456
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000457 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000458}
459
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000460#ifndef ATA_OPTIMIZED_WRITING
Jens Arnoldf18e4db2008-05-08 05:39:29 +0000461STATICIRAM ICODE_ATTR void copy_write_sectors(const unsigned char* buf,
462 int wordcount)
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000463{
Jean-Philippe Bernardy34d2a712005-01-24 14:26:24 +0000464 if ( (unsigned long)buf & 1)
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000465 { /* not 16-bit aligned, copy byte by byte */
466 unsigned short tmp = 0;
Jens Arnold8eedc942004-10-08 19:20:20 +0000467 const unsigned char* bufend = buf + wordcount*2;
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000468 do
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000469 {
Dave Chapmancf0e3d32006-01-18 14:04:30 +0000470#if defined(SWAP_WORDS) || defined(ROCKBOX_LITTLE_ENDIAN)
Jens Arnold44e76cf2004-06-11 06:56:51 +0000471 tmp = (unsigned short) *buf++;
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000472 tmp |= (unsigned short) *buf++ << 8;
473 SET_16BITREG(ATA_DATA, tmp);
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000474#else
475 tmp = (unsigned short) *buf++ << 8;
476 tmp |= (unsigned short) *buf++;
477 SET_16BITREG(ATA_DATA, tmp);
478#endif
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000479 } while (buf < bufend); /* tail loop is faster */
480 }
481 else
482 { /* 16-bit aligned, can do faster copy */
483 unsigned short* wbuf = (unsigned short*)buf;
484 unsigned short* wbufend = wbuf + wordcount;
485 do
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000486 {
487#ifdef SWAP_WORDS
Dave Chapman77372d12005-11-07 23:07:19 +0000488 SET_16BITREG(ATA_DATA, swap16(*wbuf));
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000489#else
490 SET_16BITREG(ATA_DATA, *wbuf);
491#endif
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000492 } while (++wbuf < wbufend); /* tail loop is faster */
493 }
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000494}
Jens Arnold31ffd7b2006-12-03 22:13:44 +0000495#endif /* !ATA_OPTIMIZED_WRITING */
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000496
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000497#ifdef MAX_PHYS_SECTOR_SIZE
498static int _write_sectors(unsigned long start,
499 int count,
500 const void* buf)
501#else
Jörg Hohensohn575c9042004-12-29 22:37:31 +0000502int ata_write_sectors(IF_MV2(int drive,)
Jörg Hohensohnda848572004-12-28 22:16:07 +0000503 unsigned long start,
Björn Stenberg63457c52002-08-14 16:37:28 +0000504 int count,
Jens Arnold0ceaa5e2004-08-17 01:45:48 +0000505 const void* buf)
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000506#endif
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000507{
508 int i;
Björn Stenbergf9fed812002-11-07 22:40:24 +0000509 int ret = 0;
Jean-Philippe Bernardyfc194452005-02-25 18:50:16 +0000510 long spinup_start;
Björn Stenberg457b8a02002-08-26 13:21:14 +0000511
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000512#ifndef MAX_PHYS_SECTOR_SIZE
513#ifdef HAVE_MULTIVOLUME
514 (void)drive; /* unused for now */
515#endif
Michael Sevakis6a837962008-01-18 13:12:33 +0000516 mutex_lock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000517#endif
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000518
Jens Arnold88e20532008-03-09 00:59:48 +0000519 if (start + count > total_sectors)
520 panicf("Writing past end of disk");
521
Björn Stenbergba0438e2002-12-05 09:35:01 +0000522 last_disk_activity = current_tick;
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000523 spinup_start = current_tick;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000524
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000525 ata_led(true);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000526
Björn Stenbergf0599be2002-08-26 22:05:47 +0000527 if ( sleeping ) {
Björn Stenbergefd90772002-12-06 15:17:30 +0000528 spinup = true;
Björn Stenberg494d2612002-11-27 15:55:47 +0000529 if (poweroff) {
530 if (ata_power_on()) {
Jens Arnold88e20532008-03-09 00:59:48 +0000531 ret = -1;
532 goto error;
Björn Stenberg494d2612002-11-27 15:55:47 +0000533 }
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000534 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000535 else {
536 if (perform_soft_reset()) {
Jens Arnold88e20532008-03-09 00:59:48 +0000537 ret = -1;
538 goto error;
Björn Stenberg494d2612002-11-27 15:55:47 +0000539 }
Björn Stenbergc4b28502002-07-16 12:18:17 +0000540 }
Björn Stenbergf0599be2002-08-26 22:05:47 +0000541 }
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000542
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000543 SET_REG(ATA_SELECT, ata_device);
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000544 if (!wait_for_rdy())
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000545 {
Jens Arnold88e20532008-03-09 00:59:48 +0000546 ret = -2;
547 goto error;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000548 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000549
Jörg Hohensohnbb035862006-12-20 22:08:29 +0000550#ifdef HAVE_LBA48
551 if (lba48)
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000552 {
553 SET_REG(ATA_NSECTOR, count >> 8);
554 SET_REG(ATA_NSECTOR, count & 0xff);
555 SET_REG(ATA_SECTOR, (start >> 24) & 0xff); /* 31:24 */
556 SET_REG(ATA_SECTOR, start & 0xff); /* 7:0 */
557 SET_REG(ATA_LCYL, 0); /* 39:32 */
558 SET_REG(ATA_LCYL, (start >> 8) & 0xff); /* 15:8 */
559 SET_REG(ATA_HCYL, 0); /* 47:40 */
560 SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */
561 SET_REG(ATA_SELECT, SELECT_LBA | ata_device);
562 SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS_EXT);
563 }
Björn Stenberg63457c52002-08-14 16:37:28 +0000564 else
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000565#endif
566 {
Jörg Hohensohnbb035862006-12-20 22:08:29 +0000567 SET_REG(ATA_NSECTOR, count & 0xff); /* 0 means 256 sectors */
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +0000568 SET_REG(ATA_SECTOR, start & 0xff);
569 SET_REG(ATA_LCYL, (start >> 8) & 0xff);
570 SET_REG(ATA_HCYL, (start >> 16) & 0xff);
571 SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device);
572 SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS);
573 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000574
575 for (i=0; i<count; i++) {
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000576
Björn Stenberg674b6322003-04-28 12:02:14 +0000577 if (!wait_for_start_of_transfer()) {
578 ret = -3;
579 break;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000580 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000581
Björn Stenbergba0438e2002-12-05 09:35:01 +0000582 if (spinup) {
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000583 ata_spinup_time = current_tick - spinup_start;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000584 spinup = false;
Björn Stenbergbd0da0e2002-12-06 13:08:42 +0000585 sleeping = false;
586 poweroff = false;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000587 }
588
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000589 copy_write_sectors(buf, SECTOR_SIZE/2);
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000590
591#ifdef USE_INTERRUPT
592 /* reading the status register clears the interrupt */
593 j = ATA_STATUS;
594#endif
Linus Nielsen Feltzinga4058ec2002-06-12 09:28:22 +0000595 buf += SECTOR_SIZE;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000596
597 last_disk_activity = current_tick;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000598 }
599
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000600 if(!ret && !wait_for_end_of_transfer()) {
601 DEBUGF("End on transfer failed. -- jyp");
Björn Stenberg674b6322003-04-28 12:02:14 +0000602 ret = -4;
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000603 }
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000604
Jens Arnold88e20532008-03-09 00:59:48 +0000605 error:
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000606 ata_led(false);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000607#ifndef MAX_PHYS_SECTOR_SIZE
Michael Sevakis6a837962008-01-18 13:12:33 +0000608 mutex_unlock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000609#endif
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000610
Björn Stenbergf9fed812002-11-07 22:40:24 +0000611 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000612}
613
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000614#ifdef MAX_PHYS_SECTOR_SIZE
615static int cache_sector(unsigned long sector)
616{
617 int rc;
618
619 sector &= ~(phys_sector_mult - 1);
620 /* round down to physical sector boundary */
621
622 /* check whether the sector is already cached */
623 if (sector_cache.inuse && (sector_cache.sectornum == sector))
624 return 0;
625
626 /* not found: read the sector */
627 sector_cache.inuse = false;
628 rc = _read_sectors(sector, phys_sector_mult, sector_cache.data);
629 if (!rc)
630 {
631 sector_cache.sectornum = sector;
632 sector_cache.inuse = true;
633 }
634 return rc;
635}
636
637static inline int flush_current_sector(void)
638{
639 return _write_sectors(sector_cache.sectornum, phys_sector_mult,
640 sector_cache.data);
641}
642
643int ata_read_sectors(IF_MV2(int drive,)
644 unsigned long start,
645 int incount,
646 void* inbuf)
647{
648 int rc = 0;
649 int offset;
650
651#ifdef HAVE_MULTIVOLUME
652 (void)drive; /* unused for now */
653#endif
Michael Sevakis6a837962008-01-18 13:12:33 +0000654 mutex_lock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000655
656 offset = start & (phys_sector_mult - 1);
657
658 if (offset) /* first partial sector */
659 {
660 int partcount = MIN(incount, phys_sector_mult - offset);
661
662 rc = cache_sector(start);
663 if (rc)
664 {
665 rc = rc * 10 - 1;
666 goto error;
667 }
668 memcpy(inbuf, sector_cache.data + offset * SECTOR_SIZE,
669 partcount * SECTOR_SIZE);
670
671 start += partcount;
672 inbuf += partcount * SECTOR_SIZE;
673 incount -= partcount;
674 }
675 if (incount)
676 {
677 offset = incount & (phys_sector_mult - 1);
678 incount -= offset;
679
680 if (incount)
681 {
682 rc = _read_sectors(start, incount, inbuf);
683 if (rc)
684 {
685 rc = rc * 10 - 2;
686 goto error;
687 }
688 start += incount;
689 inbuf += incount * SECTOR_SIZE;
690 }
691 if (offset)
692 {
693 rc = cache_sector(start);
694 if (rc)
695 {
696 rc = rc * 10 - 3;
697 goto error;
698 }
699 memcpy(inbuf, sector_cache.data, offset * SECTOR_SIZE);
700 }
701 }
702
703 error:
Michael Sevakis6a837962008-01-18 13:12:33 +0000704 mutex_unlock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000705
706 return rc;
707}
708
709int ata_write_sectors(IF_MV2(int drive,)
710 unsigned long start,
711 int count,
712 const void* buf)
713{
714 int rc = 0;
715 int offset;
716
717#ifdef HAVE_MULTIVOLUME
718 (void)drive; /* unused for now */
719#endif
Michael Sevakis6a837962008-01-18 13:12:33 +0000720 mutex_lock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000721
722 offset = start & (phys_sector_mult - 1);
723
724 if (offset) /* first partial sector */
725 {
726 int partcount = MIN(count, phys_sector_mult - offset);
727
728 rc = cache_sector(start);
729 if (rc)
730 {
731 rc = rc * 10 - 1;
732 goto error;
733 }
734 memcpy(sector_cache.data + offset * SECTOR_SIZE, buf,
735 partcount * SECTOR_SIZE);
736 rc = flush_current_sector();
737 if (rc)
738 {
739 rc = rc * 10 - 2;
740 goto error;
741 }
742 start += partcount;
743 buf += partcount * SECTOR_SIZE;
744 count -= partcount;
745 }
746 if (count)
747 {
748 offset = count & (phys_sector_mult - 1);
749 count -= offset;
750
751 if (count)
752 {
753 rc = _write_sectors(start, count, buf);
754 if (rc)
755 {
756 rc = rc * 10 - 3;
757 goto error;
758 }
759 start += count;
760 buf += count * SECTOR_SIZE;
761 }
762 if (offset)
763 {
764 rc = cache_sector(start);
765 if (rc)
766 {
767 rc = rc * 10 - 4;
768 goto error;
769 }
770 memcpy(sector_cache.data, buf, offset * SECTOR_SIZE);
771 rc = flush_current_sector();
772 if (rc)
773 {
774 rc = rc * 10 - 5;
775 goto error;
776 }
777 }
778 }
779
780 error:
Michael Sevakis6a837962008-01-18 13:12:33 +0000781 mutex_unlock(&ata_mtx);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000782
783 return rc;
784}
785#endif /* MAX_PHYS_SECTOR_SIZE */
786
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000787static int check_registers(void)
788{
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000789 int i;
Jörg Hohensohnadef8fb2003-07-08 06:33:30 +0000790 if ( ATA_STATUS & STATUS_BSY )
Jörg Hohensohnd1a3a3e2003-07-03 00:02:15 +0000791 return -1;
792
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000793 for (i = 0; i<64; i++) {
Marcoen Hirschbergdd754882006-08-12 08:01:54 +0000794 SET_REG(ATA_NSECTOR, WRITE_PATTERN1);
795 SET_REG(ATA_SECTOR, WRITE_PATTERN2);
796 SET_REG(ATA_LCYL, WRITE_PATTERN3);
797 SET_REG(ATA_HCYL, WRITE_PATTERN4);
798
799 if (((ATA_NSECTOR & READ_PATTERN1_MASK) == READ_PATTERN1) &&
800 ((ATA_SECTOR & READ_PATTERN2_MASK) == READ_PATTERN2) &&
801 ((ATA_LCYL & READ_PATTERN3_MASK) == READ_PATTERN3) &&
802 ((ATA_HCYL & READ_PATTERN4_MASK) == READ_PATTERN4))
803 return 0;
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +0000804 }
Björn Stenberga97c4412002-05-24 11:25:24 +0000805 return -2;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000806}
807
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000808static int freeze_lock(void)
809{
Björn Stenberg65bf8512004-09-17 11:28:07 +0000810 /* does the disk support Security Mode feature set? */
811 if (identify_info[82] & 2)
812 {
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000813 SET_REG(ATA_SELECT, ata_device);
Björn Stenbergc032e652002-12-03 13:29:35 +0000814
Björn Stenberg65bf8512004-09-17 11:28:07 +0000815 if (!wait_for_rdy())
816 return -1;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000817
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000818 SET_REG(ATA_COMMAND, CMD_SECURITY_FREEZE_LOCK);
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000819
Björn Stenberg65bf8512004-09-17 11:28:07 +0000820 if (!wait_for_rdy())
821 return -2;
822 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000823
824 return 0;
825}
826
Björn Stenberg11968a42002-07-16 14:07:47 +0000827void ata_spindown(int seconds)
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000828{
Björn Stenberg11968a42002-07-16 14:07:47 +0000829 sleep_timeout = seconds * HZ;
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000830}
831
Linus Nielsen Feltzingad8ac5c2002-07-28 15:16:36 +0000832bool ata_disk_is_active(void)
833{
834 return !sleeping;
835}
836
Björn Stenberg11968a42002-07-16 14:07:47 +0000837static int ata_perform_sleep(void)
Björn Stenbergc4b28502002-07-16 12:18:17 +0000838{
Michael Sevakis6a837962008-01-18 13:12:33 +0000839 mutex_lock(&ata_mtx);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000840
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000841 SET_REG(ATA_SELECT, ata_device);
Björn Stenbergc032e652002-12-03 13:29:35 +0000842
Björn Stenbergc4b28502002-07-16 12:18:17 +0000843 if(!wait_for_rdy()) {
Linus Nielsen Feltzingc0a53ea2002-09-02 06:26:00 +0000844 DEBUGF("ata_perform_sleep() - not RDY\n");
Michael Sevakis6a837962008-01-18 13:12:33 +0000845 mutex_unlock(&ata_mtx);
Björn Stenbergc4b28502002-07-16 12:18:17 +0000846 return -1;
847 }
848
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000849 SET_REG(ATA_COMMAND, CMD_SLEEP);
Björn Stenbergc4b28502002-07-16 12:18:17 +0000850
851 if (!wait_for_rdy())
Linus Nielsen Feltzingc0a53ea2002-09-02 06:26:00 +0000852 {
853 DEBUGF("ata_perform_sleep() - CMD failed\n");
Peter D'Hoyebc092ad2008-03-09 13:24:42 +0000854 mutex_unlock(&ata_mtx);
855 return -2;
Linus Nielsen Feltzingc0a53ea2002-09-02 06:26:00 +0000856 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000857
Björn Stenbergc4b28502002-07-16 12:18:17 +0000858 sleeping = true;
Michael Sevakis6a837962008-01-18 13:12:33 +0000859 mutex_unlock(&ata_mtx);
Peter D'Hoyebc092ad2008-03-09 13:24:42 +0000860 return 0;
Björn Stenbergc4b28502002-07-16 12:18:17 +0000861}
862
Jens Arnolda8c1c202005-11-07 23:19:06 +0000863void ata_sleep(void)
Björn Stenberg11968a42002-07-16 14:07:47 +0000864{
Michael Sevakis4b902672006-12-19 16:50:07 +0000865 queue_post(&ata_queue, Q_SLEEP, 0);
Björn Stenberg11968a42002-07-16 14:07:47 +0000866}
867
Miika Pekkarinen077ed492006-11-29 12:17:26 +0000868void ata_sleepnow(void)
869{
Michael Sevakis6a837962008-01-18 13:12:33 +0000870 if (!spinup && !sleeping && !ata_mtx.locked && initialized)
Miika Pekkarinen077ed492006-11-29 12:17:26 +0000871 {
872 call_ata_idle_notifys(false);
873 ata_perform_sleep();
874 }
875}
876
Björn Stenberg457b8a02002-08-26 13:21:14 +0000877void ata_spin(void)
878{
879 last_user_activity = current_tick;
880}
881
Björn Stenberg11968a42002-07-16 14:07:47 +0000882static void ata_thread(void)
883{
Björn Stenberg494d2612002-11-27 15:55:47 +0000884 static long last_sleep = 0;
Michael Sevakisa9b2fb52007-10-16 01:25:17 +0000885 struct queue_event ev;
Jonathan Gordonf1841522006-11-08 01:55:26 +0000886 static long last_seen_mtx_unlock = 0;
Björn Stenberg11968a42002-07-16 14:07:47 +0000887
888 while (1) {
Michael Sevakis9811fc92008-02-11 07:42:11 +0000889 queue_wait_w_tmo(&ata_queue, &ev, HZ/2);
890
891 switch ( ev.id ) {
892 case SYS_TIMEOUT:
893 if (!spinup && !sleeping)
Jonathan Gordonf1841522006-11-08 01:55:26 +0000894 {
Michael Sevakis9811fc92008-02-11 07:42:11 +0000895 if (!ata_mtx.locked)
Jonathan Gordonf1841522006-11-08 01:55:26 +0000896 {
Michael Sevakis9811fc92008-02-11 07:42:11 +0000897 if (!last_seen_mtx_unlock)
898 last_seen_mtx_unlock = current_tick;
899 if (TIME_AFTER(current_tick, last_seen_mtx_unlock+(HZ*2)))
900 {
901 call_ata_idle_notifys(false);
902 last_seen_mtx_unlock = 0;
903 }
904 }
905 if ( sleep_timeout &&
906 TIME_AFTER( current_tick,
907 last_user_activity + sleep_timeout ) &&
908 TIME_AFTER( current_tick,
909 last_disk_activity + sleep_timeout ) )
910 {
911 call_ata_idle_notifys(true);
912 ata_perform_sleep();
913 last_sleep = current_tick;
Jonathan Gordonf1841522006-11-08 01:55:26 +0000914 }
915 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000916
Michael Sevakis9811fc92008-02-11 07:42:11 +0000917#ifdef HAVE_ATA_POWER_OFF
918 if ( !spinup && sleeping && !poweroff &&
919 TIME_AFTER( current_tick, last_sleep + ATA_POWER_OFF_TIMEOUT ))
920 {
921 mutex_lock(&ata_mtx);
922 ide_power_enable(false);
923 mutex_unlock(&ata_mtx);
924 poweroff = true;
925 }
926#endif
927 break;
928
Jonathan Gordonf1841522006-11-08 01:55:26 +0000929#ifndef USB_NONE
Jonathan Gordonfd0e6402006-11-09 07:02:18 +0000930 case SYS_USB_CONNECTED:
Björn Stenberg2b77b4f2002-11-28 22:46:19 +0000931 if (poweroff) {
Michael Sevakis6a837962008-01-18 13:12:33 +0000932 mutex_lock(&ata_mtx);
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000933 ata_led(true);
Björn Stenberg494d2612002-11-27 15:55:47 +0000934 ata_power_on();
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +0000935 ata_led(false);
Michael Sevakis6a837962008-01-18 13:12:33 +0000936 mutex_unlock(&ata_mtx);
Björn Stenberg2b77b4f2002-11-28 22:46:19 +0000937 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000938
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000939 /* Tell the USB thread that we are safe */
Linus Nielsen Feltzing01fd2a02002-07-27 22:44:52 +0000940 DEBUGF("ata_thread got SYS_USB_CONNECTED\n");
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000941 usb_acknowledge(SYS_USB_CONNECTED_ACK);
Björn Stenberg11968a42002-07-16 14:07:47 +0000942
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000943 /* Wait until the USB cable is extracted again */
944 usb_wait_for_disconnect(&ata_queue);
Jonathan Gordonf1841522006-11-08 01:55:26 +0000945 break;
Jonathan Gordonfd0e6402006-11-09 07:02:18 +0000946#endif
Björn Stenberg11968a42002-07-16 14:07:47 +0000947 case Q_SLEEP:
Jonathan Gordon4049d442006-11-26 09:53:42 +0000948 call_ata_idle_notifys(false);
Björn Stenberg8e96c472002-09-06 23:55:52 +0000949 last_disk_activity = current_tick - sleep_timeout + (HZ/2);
Björn Stenberg11968a42002-07-16 14:07:47 +0000950 break;
Michael Sevakis80278e42008-05-10 18:00:11 +0000951
952#ifdef ATA_DRIVER_CLOSE
953 case Q_CLOSE:
954 return;
955#endif
Björn Stenberg11968a42002-07-16 14:07:47 +0000956 }
957 }
958}
959
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000960/* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000961int ata_hard_reset(void)
962{
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000963 int ret;
Björn Stenberg65bf8512004-09-17 11:28:07 +0000964
Michael Sevakis35e7b252008-05-06 10:12:05 +0000965 mutex_lock(&ata_mtx);
966
Linus Nielsen Feltzing838a7022006-03-07 13:25:19 +0000967 ata_reset();
Linus Nielsen Feltzingdc4977d2002-05-07 22:59:03 +0000968
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000969 /* state HRR2 */
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000970 SET_REG(ATA_SELECT, ata_device); /* select the right device */
Björn Stenberg7249c882002-12-02 10:30:40 +0000971 ret = wait_for_bsy();
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000972
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000973 /* Massage the return code so it is 0 on success and -1 on failure */
974 ret = ret?0:-1;
975
Michael Sevakis35e7b252008-05-06 10:12:05 +0000976 mutex_unlock(&ata_mtx);
977
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000978 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000979}
980
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000981static int perform_soft_reset(void)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000982{
Thom Johansen017b0d72006-10-25 17:31:29 +0000983/* If this code is allowed to run on a Nano, the next reads from the flash will
984 * time out, so we disable it. It shouldn't be necessary anyway, since the
985 * ATA -> Flash interface automatically sleeps almost immediately after the
986 * last command.
987 */
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000988 int ret;
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000989 int retry_count;
Peter D'Hoyebc092ad2008-03-09 13:24:42 +0000990
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000991 SET_REG(ATA_SELECT, SELECT_LBA | ata_device );
992 SET_REG(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST );
Björn Stenberg1fe97ec2003-12-17 20:15:12 +0000993 sleep(1); /* >= 5us */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000994
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +0000995 SET_REG(ATA_CONTROL, CONTROL_nIEN);
Björn Stenberg1fe97ec2003-12-17 20:15:12 +0000996 sleep(1); /* >2ms */
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000997
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000998 /* This little sucker can take up to 30 seconds */
999 retry_count = 8;
1000 do
1001 {
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +00001002 ret = wait_for_rdy();
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001003 } while(!ret && retry_count--);
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +00001004
Peter D'Hoyebc092ad2008-03-09 13:24:42 +00001005 if (!ret)
1006 return -1;
Björn Stenbergc4b28502002-07-16 12:18:17 +00001007
Peter D'Hoyebc092ad2008-03-09 13:24:42 +00001008 if (set_features())
1009 return -2;
1010
1011 if (set_multiple_mode(multisectors))
1012 return -3;
1013
1014 if (freeze_lock())
1015 return -4;
1016
1017 return 0;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001018}
1019
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +00001020int ata_soft_reset(void)
1021{
1022 int ret;
1023
Michael Sevakis6a837962008-01-18 13:12:33 +00001024 mutex_lock(&ata_mtx);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +00001025
1026 ret = perform_soft_reset();
1027
Michael Sevakis6a837962008-01-18 13:12:33 +00001028 mutex_unlock(&ata_mtx);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +00001029 return ret;
1030}
1031
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +00001032static int ata_power_on(void)
1033{
Linus Nielsen Feltzing97955a72004-02-17 01:31:50 +00001034 int rc;
1035
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +00001036 ide_power_enable(true);
Jens Arnold8291cd72008-05-08 21:36:50 +00001037 sleep(HZ/4); /* allow voltage to build up */
1038
1039 /* Accessing the PP IDE controller too early after powering up the disk
1040 * makes the core hang for a short time, causing an audio dropout. This
1041 * also depends on the disk; iPod Mini G2 needs at least HZ/5 to get rid
1042 * of the dropout. Since this time isn't additive (the wait_for_bsy() in
1043 * ata_hard_reset() will shortened by the same amount), it's a good idea
1044 * to do this on all HDD based targets. */
1045
Björn Stenberg7249c882002-12-02 10:30:40 +00001046 if( ata_hard_reset() )
1047 return -1;
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +00001048
Linus Nielsen Feltzing867415b2004-02-17 01:30:25 +00001049 rc = set_features();
1050 if (rc)
1051 return rc * 10 - 2;
1052
Björn Stenberg7249c882002-12-02 10:30:40 +00001053 if (set_multiple_mode(multisectors))
Linus Nielsen Feltzing867415b2004-02-17 01:30:25 +00001054 return -3;
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +00001055
Björn Stenbergc032e652002-12-03 13:29:35 +00001056 if (freeze_lock())
Linus Nielsen Feltzing867415b2004-02-17 01:30:25 +00001057 return -4;
Björn Stenbergc032e652002-12-03 13:29:35 +00001058
Björn Stenberg7249c882002-12-02 10:30:40 +00001059 return 0;
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +00001060}
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +00001061
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +00001062static int master_slave_detect(void)
Björn Stenberg5c7847c2002-05-22 14:37:36 +00001063{
1064 /* master? */
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001065 SET_REG(ATA_SELECT, 0);
Björn Stenberg9f372f12003-07-09 22:04:31 +00001066 if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +00001067 ata_device = 0;
Björn Stenberg5c7847c2002-05-22 14:37:36 +00001068 DEBUGF("Found master harddisk\n");
1069 }
1070 else {
1071 /* slave? */
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001072 SET_REG(ATA_SELECT, SELECT_DEVICE1);
Björn Stenberg9f372f12003-07-09 22:04:31 +00001073 if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +00001074 ata_device = SELECT_DEVICE1;
Björn Stenberg5c7847c2002-05-22 14:37:36 +00001075 DEBUGF("Found slave harddisk\n");
1076 }
1077 else
1078 return -1;
1079 }
1080 return 0;
1081}
1082
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001083static int identify(void)
1084{
1085 int i;
1086
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001087 SET_REG(ATA_SELECT, ata_device);
Björn Stenbergc032e652002-12-03 13:29:35 +00001088
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001089 if(!wait_for_rdy()) {
1090 DEBUGF("identify() - not RDY\n");
1091 return -1;
1092 }
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001093 SET_REG(ATA_COMMAND, CMD_IDENTIFY);
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001094
1095 if (!wait_for_start_of_transfer())
1096 {
1097 DEBUGF("identify() - CMD failed\n");
1098 return -2;
1099 }
1100
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001101 for (i=0; i<SECTOR_SIZE/2; i++) {
1102 /* the IDENTIFY words are already swapped, so we need to treat
1103 this info differently that normal sector data */
Miika Pekkarinenf6c80582005-11-08 11:41:56 +00001104#if defined(ROCKBOX_BIG_ENDIAN) && !defined(SWAP_WORDS)
Dave Chapman77372d12005-11-07 23:07:19 +00001105 identify_info[i] = swap16(ATA_DATA);
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001106#else
Dave Chapman77372d12005-11-07 23:07:19 +00001107 identify_info[i] = ATA_DATA;
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001108#endif
1109 }
Michael Sevakisbe0c7d02008-05-05 10:53:06 +00001110
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001111 return 0;
1112}
1113
Björn Stenberg34fa70e2002-09-06 17:20:44 +00001114static int set_multiple_mode(int sectors)
1115{
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001116 SET_REG(ATA_SELECT, ata_device);
Björn Stenbergc032e652002-12-03 13:29:35 +00001117
Björn Stenberg34fa70e2002-09-06 17:20:44 +00001118 if(!wait_for_rdy()) {
1119 DEBUGF("set_multiple_mode() - not RDY\n");
1120 return -1;
1121 }
1122
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001123 SET_REG(ATA_NSECTOR, sectors);
1124 SET_REG(ATA_COMMAND, CMD_SET_MULTIPLE_MODE);
Björn Stenberg34fa70e2002-09-06 17:20:44 +00001125
1126 if (!wait_for_rdy())
1127 {
1128 DEBUGF("set_multiple_mode() - CMD failed\n");
1129 return -2;
1130 }
1131
1132 return 0;
1133}
1134
Björn Stenberga53afc02004-01-14 13:15:19 +00001135static int set_features(void)
1136{
Jens Arnoldb85e1b92007-02-18 19:28:29 +00001137 static struct {
Björn Stenberga53afc02004-01-14 13:15:19 +00001138 unsigned char id_word;
1139 unsigned char id_bit;
1140 unsigned char subcommand;
1141 unsigned char parameter;
1142 } features[] = {
Peter D'Hoyebc092ad2008-03-09 13:24:42 +00001143 { 83, 14, 0x03, 0 }, /* force PIO mode */
1144 { 83, 3, 0x05, 0x80 }, /* adv. power management: lowest w/o standby */
Björn Stenberga53afc02004-01-14 13:15:19 +00001145 { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */
1146 { 82, 6, 0xaa, 0 }, /* enable read look-ahead */
Björn Stenberga53afc02004-01-14 13:15:19 +00001147 };
1148 int i;
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001149 int pio_mode = 2;
Björn Stenberga53afc02004-01-14 13:15:19 +00001150
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001151 /* Find out the highest supported PIO mode */
1152 if(identify_info[64] & 2)
1153 pio_mode = 4;
1154 else
1155 if(identify_info[64] & 1)
1156 pio_mode = 3;
1157
Peter D'Hoyebc092ad2008-03-09 13:24:42 +00001158 /* Update the table: set highest supported pio mode that we also support */
1159 features[0].parameter = 8 + pio_mode;
1160
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001161 SET_REG(ATA_SELECT, ata_device);
Björn Stenberga53afc02004-01-14 13:15:19 +00001162
1163 if (!wait_for_rdy()) {
1164 DEBUGF("set_features() - not RDY\n");
1165 return -1;
1166 }
1167
Jens Arnoldb85e1b92007-02-18 19:28:29 +00001168 for (i=0; i < (int)(sizeof(features)/sizeof(features[0])); i++) {
Björn Stenberga53afc02004-01-14 13:15:19 +00001169 if (identify_info[features[i].id_word] & (1 << features[i].id_bit)) {
Linus Nielsen Feltzing4058b792005-01-26 12:53:48 +00001170 SET_REG(ATA_FEATURE, features[i].subcommand);
1171 SET_REG(ATA_NSECTOR, features[i].parameter);
1172 SET_REG(ATA_COMMAND, CMD_SET_FEATURES);
Björn Stenberga53afc02004-01-14 13:15:19 +00001173
1174 if (!wait_for_rdy()) {
1175 DEBUGF("set_features() - CMD failed\n");
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001176 return -10 - i;
1177 }
1178
Peter D'Hoyebc092ad2008-03-09 13:24:42 +00001179 if((ATA_ALT_STATUS & STATUS_ERR) && (i != 1)) {
1180 /* some CF cards don't like advanced powermanagement
1181 even if they mark it as supported - go figure... */
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001182 if(ATA_ERROR & ERROR_ABRT) {
1183 return -20 - i;
1184 }
Björn Stenberga53afc02004-01-14 13:15:19 +00001185 }
1186 }
1187 }
1188
Michael Sevakis57cbd772008-05-05 13:00:08 +00001189#ifdef ATA_SET_DEVICE_FEATURES
1190 ata_set_pio_timings(pio_mode);
1191#endif
1192
Björn Stenberga53afc02004-01-14 13:15:19 +00001193 return 0;
1194}
1195
Björn Stenberg45d32ce2002-12-03 13:12:55 +00001196unsigned short* ata_get_identify(void)
1197{
1198 return identify_info;
1199}
1200
Jens Arnoldf05dec52004-11-23 22:00:41 +00001201static int init_and_check(bool hard_reset)
1202{
1203 int rc;
1204
1205 if (hard_reset)
1206 {
1207 /* This should reset both master and slave, we don't yet know what's in */
1208 ata_device = 0;
1209 if (ata_hard_reset())
1210 return -1;
1211 }
1212
1213 rc = master_slave_detect();
1214 if (rc)
1215 return -10 + rc;
1216
1217 /* symptom fix: else check_registers() below may fail */
1218 if (hard_reset && !wait_for_bsy())
1219 return -20;
1220
1221 rc = check_registers();
1222 if (rc)
1223 return -30 + rc;
1224
1225 return 0;
1226}
1227
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001228int ata_init(void)
1229{
Michael Sevakis3b36b982008-01-18 12:32:03 +00001230 int rc = 0;
1231 bool coldstart;
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001232
Michael Sevakis3b36b982008-01-18 12:32:03 +00001233 if ( !initialized ) {
Michael Sevakis6a837962008-01-18 13:12:33 +00001234 mutex_init(&ata_mtx);
Michael Sevakis3b36b982008-01-18 12:32:03 +00001235 queue_init(&ata_queue, true);
1236 }
Björn Stenberg11968a42002-07-16 14:07:47 +00001237
Michael Sevakis6a837962008-01-18 13:12:33 +00001238 mutex_lock(&ata_mtx);
Michael Sevakis3b36b982008-01-18 12:32:03 +00001239
1240 /* must be called before ata_device_init() */
1241 coldstart = ata_is_coldstart();
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +00001242 ata_led(false);
Linus Nielsen Feltzing838a7022006-03-07 13:25:19 +00001243 ata_device_init();
Jörg Hohensohnf4b677e2003-07-18 21:55:06 +00001244 sleeping = false;
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001245 ata_enable(true);
Jens Arnoldc5d71aa2007-05-23 17:51:18 +00001246#ifdef MAX_PHYS_SECTOR_SIZE
1247 memset(&sector_cache, 0, sizeof(sector_cache));
1248#endif
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001249
Björn Stenberg11968a42002-07-16 14:07:47 +00001250 if ( !initialized ) {
Michael Sevakis9811fc92008-02-11 07:42:11 +00001251 /* First call won't have multiple thread contention - this
1252 * may return at any point without having to unlock */
Michael Sevakis6a837962008-01-18 13:12:33 +00001253 mutex_unlock(&ata_mtx);
Michael Sevakis3b36b982008-01-18 12:32:03 +00001254
Jörg Hohensohn44298162003-12-03 01:03:54 +00001255 if (!ide_powered()) /* somebody has switched it off */
1256 {
1257 ide_power_enable(true);
Jens Arnold8291cd72008-05-08 21:36:50 +00001258 sleep(HZ/4); /* allow voltage to build up */
Jörg Hohensohn44298162003-12-03 01:03:54 +00001259 }
1260
Jens Arnoldf05dec52004-11-23 22:00:41 +00001261 /* first try, hard reset at cold start only */
Jens Arnold28fd4b72006-12-19 09:27:41 +00001262 rc = init_and_check(coldstart);
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001263
Jens Arnold28fd4b72006-12-19 09:27:41 +00001264 if (rc)
Jens Arnoldf05dec52004-11-23 22:00:41 +00001265 { /* failed? -> second try, always with hard reset */
1266 DEBUGF("ata: init failed, retrying...\n");
1267 rc = init_and_check(true);
1268 if (rc)
1269 return rc;
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001270 }
1271
Björn Stenbergefd2f352003-07-09 16:46:46 +00001272 rc = identify();
Marcoen Hirschbergdd754882006-08-12 08:01:54 +00001273
Björn Stenbergefd2f352003-07-09 16:46:46 +00001274 if (rc)
Björn Stenberg65bf8512004-09-17 11:28:07 +00001275 return -40 + rc;
Marcoen Hirschbergdd754882006-08-12 08:01:54 +00001276
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001277 multisectors = identify_info[47] & 0xff;
Jens Arnoldc5d71aa2007-05-23 17:51:18 +00001278 if (multisectors == 0) /* Invalid multisector info, try with 16 */
1279 multisectors = 16;
1280
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001281 DEBUGF("ata: %d sectors per ata request\n",multisectors);
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +00001282
Jens Arnoldc5d71aa2007-05-23 17:51:18 +00001283#ifdef MAX_PHYS_SECTOR_SIZE
1284 /* Find out the physical sector size */
1285 if((identify_info[106] & 0xe000) == 0x6000)
1286 phys_sector_mult = 1 << (identify_info[106] & 0x000f);
1287 else
1288 phys_sector_mult = 1;
1289
1290 DEBUGF("ata: %d logical sectors per phys sector", phys_sector_mult);
1291
1292 if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE))
1293 panicf("Unsupported physical sector size: %d",
1294 phys_sector_mult * SECTOR_SIZE);
1295#endif
1296
Jens Arnold88e20532008-03-09 00:59:48 +00001297 total_sectors = identify_info[60] | (identify_info[61] << 16);
1298
Jörg Hohensohnbb035862006-12-20 22:08:29 +00001299#ifdef HAVE_LBA48
Jens Arnold88e20532008-03-09 00:59:48 +00001300 if (identify_info[83] & 0x0400 /* 48 bit address support */
1301 && total_sectors == 0x0FFFFFFF) /* and disk size >= 128 GiB */
1302 { /* (needs BigLBA addressing) */
1303 if (identify_info[102] || identify_info[103])
1304 panicf("Unsupported disk size: >= 2^32 sectors");
1305
1306 total_sectors = identify_info[100] | (identify_info[101] << 16);
Jörg Hohensohnbb035862006-12-20 22:08:29 +00001307 lba48 = true; /* use BigLBA */
Jörg Hohensohnf5bb7662006-12-19 22:40:23 +00001308 }
1309#endif
Björn Stenberg65bf8512004-09-17 11:28:07 +00001310 rc = freeze_lock();
Marcoen Hirschbergdd754882006-08-12 08:01:54 +00001311
Björn Stenberg65bf8512004-09-17 11:28:07 +00001312 if (rc)
1313 return -50 + rc;
1314
Björn Stenberga53afc02004-01-14 13:15:19 +00001315 rc = set_features();
1316 if (rc)
1317 return -60 + rc;
1318
Michael Sevakis9811fc92008-02-11 07:42:11 +00001319 mutex_lock(&ata_mtx); /* Balance unlock below */
1320
Björn Stenberg9cb5e0e2003-07-11 19:11:06 +00001321 last_disk_activity = current_tick;
Michael Sevakis80278e42008-05-10 18:00:11 +00001322#ifdef ATA_DRIVER_CLOSE
1323 ata_thread_p =
1324#endif
Björn Stenberg11968a42002-07-16 14:07:47 +00001325 create_thread(ata_thread, ata_stack,
Michael Sevakisa9b2fb52007-10-16 01:25:17 +00001326 sizeof(ata_stack), 0, ata_thread_name
Michael Sevakis9811fc92008-02-11 07:42:11 +00001327 IF_PRIO(, PRIORITY_USER_INTERFACE)
Michael Sevakisa9b2fb52007-10-16 01:25:17 +00001328 IF_COP(, CPU));
Björn Stenberg11968a42002-07-16 14:07:47 +00001329 initialized = true;
Jean-Philippe Bernardy99e72c82005-01-20 23:00:11 +00001330
Björn Stenberg11968a42002-07-16 14:07:47 +00001331 }
Björn Stenbergefd2f352003-07-09 16:46:46 +00001332 rc = set_multiple_mode(multisectors);
1333 if (rc)
Michael Sevakis3b36b982008-01-18 12:32:03 +00001334 rc = -70 + rc;
Björn Stenberg5c7847c2002-05-22 14:37:36 +00001335
Michael Sevakis6a837962008-01-18 13:12:33 +00001336 mutex_unlock(&ata_mtx);
Michael Sevakis3b36b982008-01-18 12:32:03 +00001337 return rc;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001338}
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +00001339
Michael Sevakis80278e42008-05-10 18:00:11 +00001340#ifdef ATA_DRIVER_CLOSE
1341void ata_close(void)
1342{
1343 struct thread_entry *thread = ata_thread_p;
1344
1345 if (thread == NULL)
1346 return;
1347
1348 ata_thread_p = NULL;
1349
1350 queue_post(&ata_queue, Q_CLOSE, 0);
1351 thread_wait(thread);
1352}
1353#endif /* ATA_DRIVER_CLOSE */
1354
Jonathan Gordonbd47d482007-02-18 05:07:19 +00001355#if (CONFIG_LED == LED_REAL)
Jens Arnold31ffd7b2006-12-03 22:13:44 +00001356void ata_set_led_enabled(bool enabled)
1357{
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +00001358 ata_led_enabled = enabled;
Jens Arnold31ffd7b2006-12-03 22:13:44 +00001359 if (ata_led_enabled)
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +00001360 led(ata_led_on);
Jens Arnold31ffd7b2006-12-03 22:13:44 +00001361 else
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +00001362 led(false);
Linus Nielsen Feltzing68482bb2005-04-04 09:12:12 +00001363}
Jens Arnold5690f782005-06-04 23:15:52 +00001364#endif