blob: 60b6a874885f66f1be72fe0cb453826f3afc056a [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 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
Linus Nielsen Feltzinge14e13d2002-05-13 19:22:38 +000019#include <stdbool.h>
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000020#include "ata.h"
21#include "kernel.h"
Björn Stenberg11968a42002-07-16 14:07:47 +000022#include "thread.h"
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000023#include "led.h"
Linus Nielsen Feltzingd6810872004-10-07 07:09:49 +000024#include "cpu.h"
Björn Stenberg2cf3b5d2002-04-27 20:14:01 +000025#include "system.h"
Linus Nielsen Feltzingdc4977d2002-05-07 22:59:03 +000026#include "debug.h"
Linus Nielsen Feltzinga422b832002-06-18 12:53:02 +000027#include "panic.h"
Björn Stenberg11968a42002-07-16 14:07:47 +000028#include "usb.h"
Linus Nielsen Feltzing9d589402002-08-01 12:00:03 +000029#include "power.h"
Björn Stenberg6ee90d92002-08-15 12:54:52 +000030#include "string.h"
Jörg Hohensohn118d45e2003-09-01 05:48:42 +000031#include "hwcompat.h"
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000032
Linus Nielsen Feltzingd6810872004-10-07 07:09:49 +000033#if CONFIG_CPU == MCF5249
Jörg Hohensohndee17f72004-02-15 08:44:02 +000034
Björn Stenberg65bf8512004-09-17 11:28:07 +000035/* don't use sh7034 assembler routines */
36#define PREFER_C_READING
37#define PREFER_C_WRITING
38
39#define ATA_IOBASE 0x20000000
40#define ATA_DATA (*((volatile unsigned short*)ATA_IOBASE))
41#define ATA_CONTROL (*((volatile unsigned short*)ATA_IOBASE + 0xe))
42
Jörg Hohensohn593cc002004-09-28 22:13:26 +000043#elif CONFIG_CPU == SH7034
Björn Stenberg65bf8512004-09-17 11:28:07 +000044
45#define ATA_IOBASE 0x06100100
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000046#define ATA_DATA (*((volatile unsigned short*)0x06104100))
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +000047#define ATA_CONTROL1 ((volatile unsigned char*)0x06200206)
48#define ATA_CONTROL2 ((volatile unsigned char*)0x06200306)
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +000049#define ATA_CONTROL (*ata_control)
Björn Stenberg65bf8512004-09-17 11:28:07 +000050#endif
51
52/* generic registers */
53#define ATA_ERROR (*((volatile unsigned char*)ATA_IOBASE + 1))
54#define ATA_NSECTOR (*((volatile unsigned char*)ATA_IOBASE + 2))
55#define ATA_SECTOR (*((volatile unsigned char*)ATA_IOBASE + 3))
56#define ATA_LCYL (*((volatile unsigned char*)ATA_IOBASE + 4))
57#define ATA_HCYL (*((volatile unsigned char*)ATA_IOBASE + 5))
58#define ATA_SELECT (*((volatile unsigned char*)ATA_IOBASE + 6))
59#define ATA_COMMAND (*((volatile unsigned char*)ATA_IOBASE + 7))
60#define ATA_FEATURE ATA_ERROR
61#define ATA_STATUS ATA_COMMAND
Björn Stenberg6c9e5782002-04-27 14:19:00 +000062#define ATA_ALT_STATUS ATA_CONTROL
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000063
Björn Stenberg65bf8512004-09-17 11:28:07 +000064
65
Björn Stenberg5c7847c2002-05-22 14:37:36 +000066#define SELECT_DEVICE1 0x10
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000067#define SELECT_LBA 0x40
68
69#define STATUS_BSY 0x80
70#define STATUS_RDY 0x40
Björn Stenbergc909b4b2002-09-24 17:10:03 +000071#define STATUS_DF 0x20
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000072#define STATUS_DRQ 0x08
73#define STATUS_ERR 0x01
74
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +000075#define ERROR_ABRT 0x04
76
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000077#define CONTROL_nIEN 0x02
78#define CONTROL_SRST 0x04
79
80#define CMD_READ_SECTORS 0x20
81#define CMD_WRITE_SECTORS 0x30
Björn Stenberg8ccbc762002-09-05 15:25:08 +000082#define CMD_READ_MULTIPLE 0xC4
83#define CMD_WRITE_MULTIPLE 0xC5
84#define CMD_SET_MULTIPLE_MODE 0xC6
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000085#define CMD_STANDBY_IMMEDIATE 0xE0
86#define CMD_STANDBY 0xE2
Björn Stenberg8ccbc762002-09-05 15:25:08 +000087#define CMD_IDENTIFY 0xEC
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000088#define CMD_SLEEP 0xE6
Björn Stenberga53afc02004-01-14 13:15:19 +000089#define CMD_SET_FEATURES 0xEF
Björn Stenberg1acfd6b2002-04-21 22:06:12 +000090#define CMD_SECURITY_FREEZE_LOCK 0xF5
91
Björn Stenberg11968a42002-07-16 14:07:47 +000092#define Q_SLEEP 0
93
Björn Stenberg70747f92002-09-24 14:23:18 +000094#define READ_TIMEOUT 5*HZ
95
Björn Stenberg65bf8512004-09-17 11:28:07 +000096#define SECTOR_SIZE 512
97
Björn Stenberg5c7847c2002-05-22 14:37:36 +000098static struct mutex ata_mtx;
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +000099char ata_device; /* device 0 (master) or 1 (slave) */
100int ata_io_address; /* 0x300 or 0x200, only valid on recorder */
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000101static volatile unsigned char* ata_control;
102
Linus Nielsen Feltzing1a5032e2002-06-26 12:36:29 +0000103bool old_recorder = false;
Björn Stenbergb070dd52002-12-04 14:58:48 +0000104int ata_spinup_time = 0;
Björn Stenbergefd90772002-12-06 15:17:30 +0000105static bool spinup = false;
Jörg Hohensohnf4b677e2003-07-18 21:55:06 +0000106static bool sleeping = true;
Björn Stenberg11968a42002-07-16 14:07:47 +0000107static int sleep_timeout = 5*HZ;
Björn Stenberg494d2612002-11-27 15:55:47 +0000108static bool poweroff = false;
Daniel Stenbergcf136812002-11-29 07:05:27 +0000109#ifdef HAVE_ATA_POWER_OFF
Björn Stenberg494d2612002-11-27 15:55:47 +0000110static int poweroff_timeout = 2*HZ;
111#endif
Björn Stenberg11968a42002-07-16 14:07:47 +0000112static char ata_stack[DEFAULT_STACK_SIZE];
Jens Arnold2b0694c2004-08-03 05:58:46 +0000113static const char ata_thread_name[] = "ata";
Björn Stenberg11968a42002-07-16 14:07:47 +0000114static struct event_queue ata_queue;
115static bool initialized = false;
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000116static bool delayed_write = false;
117static unsigned char delayed_sector[SECTOR_SIZE];
118static int delayed_sector_num;
Linus Nielsen Feltzing1a5032e2002-06-26 12:36:29 +0000119
Björn Stenberg457b8a02002-08-26 13:21:14 +0000120static long last_user_activity = -1;
Linus Nielsen Feltzing040e80c2002-09-23 11:39:21 +0000121long last_disk_activity = -1;
Björn Stenberg457b8a02002-08-26 13:21:14 +0000122
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000123static int multisectors; /* number of supported multisectors */
124static unsigned short identify_info[SECTOR_SIZE];
125
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000126static int ata_power_on(void);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000127static int perform_soft_reset(void);
Björn Stenberg7249c882002-12-02 10:30:40 +0000128static int set_multiple_mode(int sectors);
Linus Nielsen Feltzing97955a72004-02-17 01:31:50 +0000129static int set_features(void);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000130
Linus Nielsen Feltzing364783a2002-08-01 08:15:58 +0000131static int wait_for_bsy(void) __attribute__ ((section (".icode")));
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000132static int wait_for_bsy(void)
133{
Linus Nielsen Feltzing8bda0e12004-03-19 13:26:43 +0000134 int timeout = current_tick + HZ*30;
Björn Stenbergc695f262003-07-10 13:32:15 +0000135 while (TIME_BEFORE(current_tick, timeout) && (ATA_STATUS & STATUS_BSY)) {
136 last_disk_activity = current_tick;
Björn Stenbergcf92db12003-04-11 07:43:04 +0000137 yield();
Björn Stenbergc695f262003-07-10 13:32:15 +0000138 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000139
140 if (TIME_BEFORE(current_tick, timeout))
141 return 1;
142 else
143 return 0; /* timeout */
144}
145
Linus Nielsen Feltzing364783a2002-08-01 08:15:58 +0000146static int wait_for_rdy(void) __attribute__ ((section (".icode")));
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000147static int wait_for_rdy(void)
148{
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000149 int timeout;
150
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000151 if (!wait_for_bsy())
152 return 0;
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000153
Björn Stenberge65b65e2002-09-04 20:15:45 +0000154 timeout = current_tick + HZ*10;
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000155
Björn Stenbergc695f262003-07-10 13:32:15 +0000156 while (TIME_BEFORE(current_tick, timeout) &&
157 !(ATA_ALT_STATUS & STATUS_RDY)) {
158 last_disk_activity = current_tick;
Björn Stenbergcf92db12003-04-11 07:43:04 +0000159 yield();
Björn Stenbergc695f262003-07-10 13:32:15 +0000160 }
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000161
162 if (TIME_BEFORE(current_tick, timeout))
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000163 return STATUS_RDY;
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000164 else
Linus Nielsen Feltzing5d154f92002-08-29 11:50:57 +0000165 return 0; /* timeout */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000166}
167
Linus Nielsen Feltzing364783a2002-08-01 08:15:58 +0000168static int wait_for_start_of_transfer(void) __attribute__ ((section (".icode")));
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000169static int wait_for_start_of_transfer(void)
170{
171 if (!wait_for_bsy())
172 return 0;
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000173 return (ATA_ALT_STATUS & (STATUS_BSY|STATUS_DRQ)) == STATUS_DRQ;
174}
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000175
Linus Nielsen Feltzing364783a2002-08-01 08:15:58 +0000176static int wait_for_end_of_transfer(void) __attribute__ ((section (".icode")));
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000177static int wait_for_end_of_transfer(void)
178{
179 if (!wait_for_bsy())
180 return 0;
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000181 return (ATA_ALT_STATUS & (STATUS_RDY|STATUS_DRQ)) == STATUS_RDY;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000182}
183
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000184
185/* the tight loop of ata_read_sectors(), to avoid the whole in IRAM */
186static void copy_read_sectors(unsigned char* buf,
187 int wordcount)
188 __attribute__ ((section (".icode")));
189static void copy_read_sectors(unsigned char* buf, int wordcount)
190{
Jens Arnoldb4059192004-07-05 13:44:53 +0000191#ifdef PREFER_C_READING
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000192 unsigned short tmp = 0;
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000193
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000194 if ( (unsigned int)buf & 1)
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000195 { /* not 16-bit aligned, copy byte by byte */
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000196 unsigned char* bufend = buf + wordcount*2;
197 do
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000198 { /* loop compiles to 9 assembler instructions */
Jens Arnold44e76cf2004-06-11 06:56:51 +0000199 /* takes 14 clock cycles (2 pipeline stalls, 1 wait) */
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000200 tmp = ATA_DATA;
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000201 *buf++ = tmp & 0xff; /* I assume big endian */
202 *buf++ = tmp >> 8; /* and don't use the SWAB16 macro */
203 } while (buf < bufend); /* tail loop is faster */
204 }
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000205 else
Jörg Hohensohncb570b92004-01-27 09:12:51 +0000206 { /* 16-bit aligned, can do faster copy */
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000207 unsigned short* wbuf = (unsigned short*)buf;
208 unsigned short* wbufend = wbuf + wordcount;
209 do
210 { /* loop compiles to 7 assembler instructions */
Jens Arnold44e76cf2004-06-11 06:56:51 +0000211 /* takes 12 clock cycles (2 pipeline stalls, 1 wait) */
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000212 *wbuf = SWAB16(ATA_DATA);
213 } while (++wbuf < wbufend); /* tail loop is faster */
214 }
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000215#else
216 /* turbo-charged assembler version */
217 /* this assumes wordcount to be a multiple of 4 */
218 asm (
219 "add %1,%1 \n" /* wordcount -> bytecount */
220 "add %0,%1 \n" /* bytecount -> bufend */
221 "mov %0,r0 \n"
222 "tst #1,r0 \n" /* 16-bit aligned ? */
223 "bt .aligned \n" /* yes, do word copy */
224
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000225 /* not 16-bit aligned */
226 "mov #-1,r3 \n" /* prepare a bit mask for high byte */
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000227 "shll8 r3 \n" /* r3 = 0xFFFFFF00 */
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000228
229 "mov.w @%2,r2 \n" /* read first word (1st round) */
230 "add #-12,%1 \n" /* adjust end address for offsets */
231 "mov.b r2,@%0 \n" /* store low byte of first word */
232 "bra .start4_b \n" /* jump into loop after next instr. */
233 "add #-5,%0 \n" /* adjust for dest. offsets; now even */
234
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000235 ".align 2 \n"
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000236 ".loop4_b: \n" /* main loop: copy 4 words in a row */
237 "mov.w @%2,r2 \n" /* read first word (2+ round) */
238 "and r3,r1 \n" /* get high byte of fourth word (2+ round) */
239 "extu.b r2,r0 \n" /* get low byte of first word (2+ round) */
240 "or r1,r0 \n" /* combine with high byte of fourth word */
241 "mov.w r0,@(4,%0) \n" /* store at buf[4] */
242 "nop \n" /* maintain alignment */
243 ".start4_b: \n"
244 "mov.w @%2,r1 \n" /* read second word */
245 "and r3,r2 \n" /* get high byte of first word */
246 "extu.b r1,r0 \n" /* get low byte of second word */
247 "or r2,r0 \n" /* combine with high byte of first word */
248 "mov.w r0,@(6,%0) \n" /* store at buf[6] */
249 "add #8,%0 \n" /* buf += 8 */
250 "mov.w @%2,r2 \n" /* read third word */
251 "and r3,r1 \n" /* get high byte of second word */
252 "extu.b r2,r0 \n" /* get low byte of third word */
253 "or r1,r0 \n" /* combine with high byte of second word */
254 "mov.w r0,@%0 \n" /* store at buf[0] */
255 "cmp/hi %0,%1 \n" /* check for end */
256 "mov.w @%2,r1 \n" /* read fourth word */
257 "and r3,r2 \n" /* get high byte of third word */
258 "extu.b r1,r0 \n" /* get low byte of fourth word */
259 "or r2,r0 \n" /* combine with high byte of third word */
260 "mov.w r0,@(2,%0) \n" /* store at buf[2] */
261 "bt .loop4_b \n"
Jens Arnold44e76cf2004-06-11 06:56:51 +0000262 /* 24 instructions for 4 copies, takes 30 clock cycles (4 wait) */
263 /* avg. 7.5 cycles per word - 86% faster */
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000264
265 "swap.b r1,r0 \n" /* get high byte of last word */
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000266 "bra .exit \n"
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000267 "mov.b r0,@(4,%0) \n" /* and store it */
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000268
269 ".align 2 \n"
270 /* 16-bit aligned, loop(read and store word) */
271 ".aligned: \n"
272 "mov.w @%2,r2 \n" /* read first word (1st round) */
273 "add #-12,%1 \n" /* adjust end address for offsets */
274 "bra .start4_w \n" /* jump into loop after next instr. */
275 "add #-6,%0 \n" /* adjust for destination offsets */
276
277 ".loop4_w: \n" /* main loop: copy 4 words in a row */
278 "mov.w @%2,r2 \n" /* read first word (2+ round) */
279 "swap.b r1,r0 \n" /* swap fourth word (2+ round) */
280 "mov.w r0,@(4,%0) \n" /* store fourth word (2+ round) */
281 "nop \n" /* maintain alignment */
282 ".start4_w: \n"
283 "mov.w @%2,r1 \n" /* read second word */
284 "swap.b r2,r0 \n" /* swap first word */
285 "mov.w r0,@(6,%0) \n" /* store first word in buf[6] */
286 "add #8,%0 \n" /* buf += 8 */
287 "mov.w @%2,r2 \n" /* read third word */
288 "swap.b r1,r0 \n" /* swap second word */
289 "mov.w r0,@%0 \n" /* store second word in buf[0] */
290 "cmp/hi %0,%1 \n" /* check for end */
291 "mov.w @%2,r1 \n" /* read fourth word */
292 "swap.b r2,r0 \n" /* swap third word */
293 "mov.w r0,@(2,%0) \n" /* store third word */
294 "bt .loop4_w \n"
Jens Arnold44e76cf2004-06-11 06:56:51 +0000295 /* 16 instructions for 4 copies, takes 22 clock cycles (4 wait) */
296 /* avg. 5.5 cycles per word - 118% faster */
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000297
298 "swap.b r1,r0 \n" /* swap fourth word (last round) */
299 "mov.w r0,@(4,%0) \n" /* and store it */
300
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000301 ".exit: \n"
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +0000302 : /* outputs */
303 : /* inputs */
304 /* %0 */ "r"(buf),
305 /* %1 */ "r"(wordcount),
306 /* %2 */ "r"(&ATA_DATA)
307 : /*trashed */
308 "r0","r1","r2","r3"
309 );
310#endif
Jörg Hohensohn88faf382004-01-16 09:02:21 +0000311}
312
Linus Nielsen Feltzing364783a2002-08-01 08:15:58 +0000313int ata_read_sectors(unsigned long start,
Björn Stenberg7526cf72002-09-25 14:10:50 +0000314 int incount,
315 void* inbuf)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000316{
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000317 int ret = 0;
Björn Stenberg70747f92002-09-24 14:23:18 +0000318 int timeout;
Björn Stenberg7526cf72002-09-25 14:10:50 +0000319 int count;
320 void* buf;
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000321 int spinup_start;
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000322
323 mutex_lock(&ata_mtx);
324
Björn Stenbergba0438e2002-12-05 09:35:01 +0000325 last_disk_activity = current_tick;
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000326 spinup_start = current_tick;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000327
Björn Stenberg494d2612002-11-27 15:55:47 +0000328 led(true);
329
Björn Stenbergc4b28502002-07-16 12:18:17 +0000330 if ( sleeping ) {
Björn Stenbergefd90772002-12-06 15:17:30 +0000331 spinup = true;
Björn Stenberg494d2612002-11-27 15:55:47 +0000332 if (poweroff) {
333 if (ata_power_on()) {
334 mutex_unlock(&ata_mtx);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000335 led(false);
Björn Stenberg494d2612002-11-27 15:55:47 +0000336 return -1;
337 }
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000338 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000339 else {
340 if (perform_soft_reset()) {
341 mutex_unlock(&ata_mtx);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000342 led(false);
Björn Stenberg494d2612002-11-27 15:55:47 +0000343 return -1;
344 }
Björn Stenbergc4b28502002-07-16 12:18:17 +0000345 }
346 }
Björn Stenberg11968a42002-07-16 14:07:47 +0000347
Björn Stenberg6a581062003-02-27 13:26:09 +0000348 timeout = current_tick + READ_TIMEOUT;
349
Björn Stenbergc032e652002-12-03 13:29:35 +0000350 ATA_SELECT = ata_device;
Linus Nielsen Feltzingb900a832002-05-08 08:27:44 +0000351 if (!wait_for_rdy())
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000352 {
353 mutex_unlock(&ata_mtx);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000354 led(false);
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000355 return -2;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000356 }
Linus Nielsen Feltzingb900a832002-05-08 08:27:44 +0000357
Björn Stenberg674b6322003-04-28 12:02:14 +0000358 retry:
Björn Stenberg7526cf72002-09-25 14:10:50 +0000359 buf = inbuf;
360 count = incount;
Björn Stenberg70747f92002-09-24 14:23:18 +0000361 while (TIME_BEFORE(current_tick, timeout)) {
Björn Stenbergb12401b2003-03-13 15:45:38 +0000362 ret = 0;
Björn Stenberg7682d462003-03-17 13:42:30 +0000363 last_disk_activity = current_tick;
Björn Stenbergf0599be2002-08-26 22:05:47 +0000364
Björn Stenberg70747f92002-09-24 14:23:18 +0000365 if ( count == 256 )
366 ATA_NSECTOR = 0; /* 0 means 256 sectors */
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000367 else
Björn Stenberg70747f92002-09-24 14:23:18 +0000368 ATA_NSECTOR = (unsigned char)count;
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000369
Björn Stenberg70747f92002-09-24 14:23:18 +0000370 ATA_SECTOR = start & 0xff;
371 ATA_LCYL = (start >> 8) & 0xff;
372 ATA_HCYL = (start >> 16) & 0xff;
373 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA | ata_device;
374 ATA_COMMAND = CMD_READ_MULTIPLE;
Linus Nielsen Feltzinge82f7012002-09-06 16:02:19 +0000375
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000376 /* wait at least 400ns between writing command and reading status */
377 asm volatile ("nop");
378 asm volatile ("nop");
379 asm volatile ("nop");
380 asm volatile ("nop");
381 asm volatile ("nop");
382
Björn Stenberg70747f92002-09-24 14:23:18 +0000383 while (count) {
Björn Stenberg70747f92002-09-24 14:23:18 +0000384 int sectors;
385 int wordcount;
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000386 int status;
Björn Stenberg70747f92002-09-24 14:23:18 +0000387
388 if (!wait_for_start_of_transfer()) {
Linus Nielsen Feltzing8bda0e12004-03-19 13:26:43 +0000389 /* We have timed out waiting for RDY and/or DRQ, possibly
390 because the hard drive is shaking and has problems reading
391 the data. We have two options:
392 1) Wait some more
393 2) Perform a soft reset and try again.
394
395 We choose alternative 2.
396 */
397 ata_soft_reset();
Björn Stenberg70747f92002-09-24 14:23:18 +0000398 ret = -4;
Björn Stenberg7526cf72002-09-25 14:10:50 +0000399 goto retry;
Björn Stenberged027a92002-08-14 14:34:54 +0000400 }
Björn Stenberg70747f92002-09-24 14:23:18 +0000401
Björn Stenbergbd0da0e2002-12-06 13:08:42 +0000402 if (spinup) {
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000403 ata_spinup_time = current_tick - spinup_start;
Björn Stenbergbd0da0e2002-12-06 13:08:42 +0000404 spinup = false;
405 sleeping = false;
406 poweroff = false;
407 }
408
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000409 /* read the status register exactly once per loop */
410 status = ATA_STATUS;
411
Björn Stenberg70747f92002-09-24 14:23:18 +0000412 /* if destination address is odd, use byte copying,
413 otherwise use word copying */
414
415 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) ) {
Linus Nielsen Feltzing8bda0e12004-03-19 13:26:43 +0000432 ata_soft_reset();
Björn Stenbergbb6e51a2003-03-14 16:06:09 +0000433 ret = -5;
434 goto retry;
435 }
436
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()) {
Linus Nielsen Feltzing8bda0e12004-03-19 13:26:43 +0000444 ata_soft_reset();
Björn Stenberg70747f92002-09-24 14:23:18 +0000445 ret = -3;
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 }
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000450 led(false);
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000451
452 mutex_unlock(&ata_mtx);
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000453
Björn Stenbergb12401b2003-03-13 15:45:38 +0000454 /* only flush if reading went ok */
455 if ( (ret == 0) && delayed_write )
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000456 ata_flush();
457
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000458 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000459}
460
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000461/* the tight loop of ata_write_sectors(), to avoid the whole in IRAM */
Jens Arnold0ceaa5e2004-08-17 01:45:48 +0000462static void copy_write_sectors(const unsigned char* buf,
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000463 int wordcount)
464 __attribute__ ((section (".icode")));
465
Jens Arnold0ceaa5e2004-08-17 01:45:48 +0000466static void copy_write_sectors(const unsigned char* buf, int wordcount)
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000467{
468#ifdef PREFER_C_WRITING
469
470 if ( (unsigned int)buf & 1)
471 { /* not 16-bit aligned, copy byte by byte */
472 unsigned short tmp = 0;
Jens Arnold8eedc942004-10-08 19:20:20 +0000473 const unsigned char* bufend = buf + wordcount*2;
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000474 do
Jens Arnold44e76cf2004-06-11 06:56:51 +0000475 { /* loop compiles to 9 assembler instructions */
476 /* takes 13 clock cycles (2 pipeline stalls) */
477 tmp = (unsigned short) *buf++;
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000478 tmp |= (unsigned short) *buf++ << 8; /* I assume big endian */
479 ATA_DATA = tmp; /* and don't use the SWAB16 macro */
480 } while (buf < bufend); /* tail loop is faster */
481 }
482 else
483 { /* 16-bit aligned, can do faster copy */
484 unsigned short* wbuf = (unsigned short*)buf;
485 unsigned short* wbufend = wbuf + wordcount;
486 do
Jens Arnold44e76cf2004-06-11 06:56:51 +0000487 { /* loop compiles to 6 assembler instructions */
488 /* takes 10 clock cycles (2 pipeline stalls) */
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000489 ATA_DATA = SWAB16(*wbuf);
490 } while (++wbuf < wbufend); /* tail loop is faster */
491 }
492#else
493 /* optimized assembler version */
494 /* this assumes wordcount to be a multiple of 2 */
495
496/* writing is not unrolled as much as reading, for several reasons:
497 * - a similar instruction sequence is faster for writing than for reading
498 * because the auto-incrementing load inctructions can be used
499 * - writing profits from warp mode
500 * Both of these add up to have writing faster than the more unrolled reading.
501 */
502 asm (
503 "add %1,%1 \n" /* wordcount -> bytecount */
504 "add %0,%1 \n" /* bytecount -> bufend */
505 "mov %0,r0 \n"
506 "tst #1,r0 \n" /* 16-bit aligned ? */
507 "bt .w_aligned \n" /* yes, do word copy */
508
509 /* not 16-bit aligned */
510 "mov #-1,r6 \n" /* prepare a bit mask for high byte */
511 "shll8 r6 \n" /* r6 = 0xFFFFFF00 */
512
513 "mov.b @%0+,r2 \n" /* load (initial old second) first byte */
514 "add #-4,%1 \n" /* adjust end address for early check */
515 "mov.w @%0+,r3 \n" /* load (initial) first word */
516 "bra .w_start2_b \n"
517 "extu.b r2,r0 \n" /* extend unsigned */
518
519 ".align 2 \n"
520 ".w_loop2_b: \n" /* main loop: copy 2 words in a row */
521 "mov.w @%0+,r3 \n" /* load first word (2+ round) */
522 "extu.b r2,r0 \n" /* put away low byte of second word (2+ round) */
523 "and r6,r2 \n" /* get high byte of second word (2+ round) */
524 "or r1,r2 \n" /* combine with low byte of old first word */
525 "mov.w r2,@%2 \n" /* write that */
526 ".w_start2_b: \n"
527 "cmp/hi %0,%1 \n" /* check for end */
528 "mov.w @%0+,r2 \n" /* load second word */
529 "extu.b r3,r1 \n" /* put away low byte of first word */
530 "and r6,r3 \n" /* get high byte of first word */
531 "or r0,r3 \n" /* combine with high byte of old second word */
532 "mov.w r3,@%2 \n" /* write that */
533 "bt .w_loop2_b \n"
534 /* 12 instructions for 2 copies, takes 14 clock cycles */
Jens Arnold44e76cf2004-06-11 06:56:51 +0000535 /* avg. 7 cycles per word - 85% faster */
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000536
537 /* the loop "overreads" 1 byte past the buffer end, however, the last */
538 /* byte is not written to disk */
539 "and r6,r2 \n" /* get high byte of last word */
540 "or r1,r2 \n" /* combine with low byte of old first word */
541 "bra .w_exit \n"
542 "mov.w r2,@%2 \n" /* write last word */
543
544 /* 16-bit aligned, loop(load and write word) */
545 ".w_aligned: \n"
546 "mov.w @%0+,r2 \n" /* load first word (1st round) */
547 "bra .w_start2_w \n" /* jump into loop after next instr. */
548 "add #-4,%1 \n" /* adjust end address for early check */
549
550 ".align 2 \n"
551 ".w_loop2_w: \n" /* main loop: copy 2 words in a row */
552 "mov.w @%0+,r2 \n" /* load first word (2+ round) */
553 "swap.b r1,r0 \n" /* swap second word (2+ round) */
554 "mov.w r0,@%2 \n" /* write second word (2+ round) */
555 ".w_start2_w: \n"
556 "cmp/hi %0,%1 \n" /* check for end */
557 "mov.w @%0+,r1 \n" /* load second word */
558 "swap.b r2,r0 \n" /* swap first word */
559 "mov.w r0,@%2 \n" /* write first word */
560 "bt .w_loop2_w \n"
561 /* 8 instructions for 2 copies, takes 10 clock cycles */
Jens Arnold44e76cf2004-06-11 06:56:51 +0000562 /* avg. 5 cycles per word - 100% faster */
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000563
564 "swap.b r1,r0 \n" /* swap second word (last round) */
565 "mov.w r0,@%2 \n" /* and write it */
566
567 ".w_exit: \n"
568 : /* outputs */
569 : /* inputs */
570 /* %0 */ "r"(buf),
571 /* %1 */ "r"(wordcount),
572 /* %2 */ "r"(&ATA_DATA)
573 : /*trashed */
574 "r0","r1","r2","r3","r6"
575 );
576#endif
577}
578
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000579int ata_write_sectors(unsigned long start,
Björn Stenberg63457c52002-08-14 16:37:28 +0000580 int count,
Jens Arnold0ceaa5e2004-08-17 01:45:48 +0000581 const void* buf)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000582{
583 int i;
Björn Stenbergf9fed812002-11-07 22:40:24 +0000584 int ret = 0;
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000585 int spinup_start;
Björn Stenberg457b8a02002-08-26 13:21:14 +0000586
Björn Stenberg099a6b52002-11-12 20:02:23 +0000587 if (start == 0)
588 panicf("Writing on sector 0\n");
589
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000590 mutex_lock(&ata_mtx);
591
Björn Stenbergba0438e2002-12-05 09:35:01 +0000592 last_disk_activity = current_tick;
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000593 spinup_start = current_tick;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000594
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000595 led(true);
596
Björn Stenbergf0599be2002-08-26 22:05:47 +0000597 if ( sleeping ) {
Björn Stenbergefd90772002-12-06 15:17:30 +0000598 spinup = true;
Björn Stenberg494d2612002-11-27 15:55:47 +0000599 if (poweroff) {
600 if (ata_power_on()) {
601 mutex_unlock(&ata_mtx);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000602 led(false);
Björn Stenberg494d2612002-11-27 15:55:47 +0000603 return -1;
604 }
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000605 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000606 else {
607 if (perform_soft_reset()) {
608 mutex_unlock(&ata_mtx);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000609 led(false);
Björn Stenberg494d2612002-11-27 15:55:47 +0000610 return -1;
611 }
Björn Stenbergc4b28502002-07-16 12:18:17 +0000612 }
Björn Stenbergf0599be2002-08-26 22:05:47 +0000613 }
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000614
Björn Stenbergc032e652002-12-03 13:29:35 +0000615 ATA_SELECT = ata_device;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000616 if (!wait_for_rdy())
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000617 {
618 mutex_unlock(&ata_mtx);
Björn Stenbergfd9ce902003-03-31 14:14:07 +0000619 led(false);
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000620 return -2;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000621 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000622
Björn Stenberg63457c52002-08-14 16:37:28 +0000623 if ( count == 256 )
624 ATA_NSECTOR = 0; /* 0 means 256 sectors */
625 else
626 ATA_NSECTOR = (unsigned char)count;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000627 ATA_SECTOR = start & 0xff;
628 ATA_LCYL = (start >> 8) & 0xff;
629 ATA_HCYL = (start >> 16) & 0xff;
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +0000630 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA | ata_device;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000631 ATA_COMMAND = CMD_WRITE_SECTORS;
632
633 for (i=0; i<count; i++) {
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000634
Björn Stenberg674b6322003-04-28 12:02:14 +0000635 if (!wait_for_start_of_transfer()) {
636 ret = -3;
637 break;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000638 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000639
Björn Stenbergba0438e2002-12-05 09:35:01 +0000640 if (spinup) {
Linus Nielsen Feltzing4502e982003-04-05 22:25:21 +0000641 ata_spinup_time = current_tick - spinup_start;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000642 spinup = false;
Björn Stenbergbd0da0e2002-12-06 13:08:42 +0000643 sleeping = false;
644 poweroff = false;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000645 }
646
Jörg Hohensohn9c52b242004-04-01 05:46:31 +0000647 copy_write_sectors(buf, SECTOR_SIZE/2);
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000648
649#ifdef USE_INTERRUPT
650 /* reading the status register clears the interrupt */
651 j = ATA_STATUS;
652#endif
Linus Nielsen Feltzinga4058ec2002-06-12 09:28:22 +0000653 buf += SECTOR_SIZE;
Björn Stenbergba0438e2002-12-05 09:35:01 +0000654
655 last_disk_activity = current_tick;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000656 }
657
Björn Stenberg674b6322003-04-28 12:02:14 +0000658 if(!ret && !wait_for_end_of_transfer())
659 ret = -4;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000660
Björn Stenberg5c530c52002-09-23 06:45:46 +0000661 led(false);
662
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000663 mutex_unlock(&ata_mtx);
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000664
Björn Stenbergb12401b2003-03-13 15:45:38 +0000665 /* only flush if writing went ok */
666 if ( (ret == 0) && delayed_write )
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000667 ata_flush();
668
Björn Stenbergf9fed812002-11-07 22:40:24 +0000669 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000670}
671
Jens Arnold0ceaa5e2004-08-17 01:45:48 +0000672extern void ata_delayed_write(unsigned long sector, const void* buf)
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000673{
674 memcpy(delayed_sector, buf, SECTOR_SIZE);
675 delayed_sector_num = sector;
676 delayed_write = true;
677}
678
679extern void ata_flush(void)
680{
681 if ( delayed_write ) {
Björn Stenberg6224cdb2002-08-16 14:41:47 +0000682 DEBUGF("ata_flush()\n");
Björn Stenbergc9d98ca2002-08-15 12:42:37 +0000683 delayed_write = false;
684 ata_write_sectors(delayed_sector_num, 1, delayed_sector);
685 }
686}
687
688
689
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000690static int check_registers(void)
691{
Jörg Hohensohnadef8fb2003-07-08 06:33:30 +0000692 if ( ATA_STATUS & STATUS_BSY )
Jörg Hohensohnd1a3a3e2003-07-03 00:02:15 +0000693 return -1;
694
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000695 ATA_NSECTOR = 0xa5;
696 ATA_SECTOR = 0x5a;
697 ATA_LCYL = 0xaa;
698 ATA_HCYL = 0x55;
699
700 if ((ATA_NSECTOR == 0xa5) &&
701 (ATA_SECTOR == 0x5a) &&
702 (ATA_LCYL == 0xaa) &&
703 (ATA_HCYL == 0x55))
Björn Stenberga97c4412002-05-24 11:25:24 +0000704 return 0;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000705
Björn Stenberga97c4412002-05-24 11:25:24 +0000706 return -2;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000707}
708
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000709static int freeze_lock(void)
710{
Björn Stenberg65bf8512004-09-17 11:28:07 +0000711 /* does the disk support Security Mode feature set? */
712 if (identify_info[82] & 2)
713 {
714 ATA_SELECT = ata_device;
Björn Stenbergc032e652002-12-03 13:29:35 +0000715
Björn Stenberg65bf8512004-09-17 11:28:07 +0000716 if (!wait_for_rdy())
717 return -1;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000718
Björn Stenberg65bf8512004-09-17 11:28:07 +0000719 ATA_COMMAND = CMD_SECURITY_FREEZE_LOCK;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000720
Björn Stenberg65bf8512004-09-17 11:28:07 +0000721 if (!wait_for_rdy())
722 return -2;
723 }
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000724
725 return 0;
726}
727
Björn Stenberg11968a42002-07-16 14:07:47 +0000728void ata_spindown(int seconds)
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000729{
Björn Stenberg11968a42002-07-16 14:07:47 +0000730 sleep_timeout = seconds * HZ;
Björn Stenberg6c9e5782002-04-27 14:19:00 +0000731}
732
Daniel Stenbergcf136812002-11-29 07:05:27 +0000733#ifdef HAVE_ATA_POWER_OFF
Björn Stenberg2b77b4f2002-11-28 22:46:19 +0000734void ata_poweroff(bool enable)
735{
736 if (enable)
737 poweroff_timeout = 2*HZ;
738 else
739 poweroff_timeout = 0;
740}
Daniel Stenbergcf136812002-11-29 07:05:27 +0000741#endif
Björn Stenberg2b77b4f2002-11-28 22:46:19 +0000742
Linus Nielsen Feltzingad8ac5c2002-07-28 15:16:36 +0000743bool ata_disk_is_active(void)
744{
745 return !sleeping;
746}
747
Björn Stenberg11968a42002-07-16 14:07:47 +0000748static int ata_perform_sleep(void)
Björn Stenbergc4b28502002-07-16 12:18:17 +0000749{
750 int ret = 0;
751
752 mutex_lock(&ata_mtx);
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000753
Björn Stenbergc032e652002-12-03 13:29:35 +0000754 ATA_SELECT = ata_device;
755
Björn Stenbergc4b28502002-07-16 12:18:17 +0000756 if(!wait_for_rdy()) {
Linus Nielsen Feltzingc0a53ea2002-09-02 06:26:00 +0000757 DEBUGF("ata_perform_sleep() - not RDY\n");
Björn Stenbergc4b28502002-07-16 12:18:17 +0000758 mutex_unlock(&ata_mtx);
759 return -1;
760 }
761
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000762 ATA_COMMAND = CMD_SLEEP;
Björn Stenbergc4b28502002-07-16 12:18:17 +0000763
764 if (!wait_for_rdy())
Linus Nielsen Feltzingc0a53ea2002-09-02 06:26:00 +0000765 {
766 DEBUGF("ata_perform_sleep() - CMD failed\n");
Björn Stenberg8ccbc762002-09-05 15:25:08 +0000767 ret = -2;
Linus Nielsen Feltzingc0a53ea2002-09-02 06:26:00 +0000768 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000769
Björn Stenbergc4b28502002-07-16 12:18:17 +0000770 sleeping = true;
771 mutex_unlock(&ata_mtx);
772 return ret;
773}
774
Linus Nielsen Feltzing159d04d2003-05-10 01:55:23 +0000775int ata_standby(int time)
776{
777 int ret = 0;
778
779 mutex_lock(&ata_mtx);
780
781 ATA_SELECT = ata_device;
782
783 if(!wait_for_rdy()) {
784 DEBUGF("ata_standby() - not RDY\n");
785 mutex_unlock(&ata_mtx);
786 return -1;
787 }
788
Linus Nielsen Feltzingc3b97202004-02-16 23:25:01 +0000789 if(time)
790 ATA_NSECTOR = ((time + 5) / 5) & 0xff; /* Round up to nearest 5 secs */
791 else
792 ATA_NSECTOR = 0; /* Disable standby */
793
Linus Nielsen Feltzing159d04d2003-05-10 01:55:23 +0000794 ATA_COMMAND = CMD_STANDBY;
795
796 if (!wait_for_rdy())
797 {
798 DEBUGF("ata_standby() - CMD failed\n");
799 ret = -2;
800 }
801
802 mutex_unlock(&ata_mtx);
803 return ret;
804}
805
Björn Stenberg11968a42002-07-16 14:07:47 +0000806int ata_sleep(void)
807{
808 queue_post(&ata_queue, Q_SLEEP, NULL);
809 return 0;
810}
811
Björn Stenberg457b8a02002-08-26 13:21:14 +0000812void ata_spin(void)
813{
814 last_user_activity = current_tick;
815}
816
Björn Stenberg11968a42002-07-16 14:07:47 +0000817static void ata_thread(void)
818{
Björn Stenberg494d2612002-11-27 15:55:47 +0000819 static long last_sleep = 0;
Björn Stenberg11968a42002-07-16 14:07:47 +0000820 struct event ev;
821
822 while (1) {
Björn Stenberg457b8a02002-08-26 13:21:14 +0000823 while ( queue_empty( &ata_queue ) ) {
Björn Stenbergefd90772002-12-06 15:17:30 +0000824 if ( !spinup && sleep_timeout && !sleeping &&
Björn Stenberg457b8a02002-08-26 13:21:14 +0000825 TIME_AFTER( current_tick,
826 last_user_activity + sleep_timeout ) &&
827 TIME_AFTER( current_tick,
828 last_disk_activity + sleep_timeout ) )
Björn Stenberg494d2612002-11-27 15:55:47 +0000829 {
Björn Stenberg457b8a02002-08-26 13:21:14 +0000830 ata_perform_sleep();
Björn Stenberg494d2612002-11-27 15:55:47 +0000831 last_sleep = current_tick;
832 }
833
Daniel Stenberg2094d452002-12-03 12:02:26 +0000834#ifdef HAVE_ATA_POWER_OFF
Björn Stenbergefd90772002-12-06 15:17:30 +0000835 if ( !spinup && sleeping && poweroff_timeout && !poweroff &&
Björn Stenberg494d2612002-11-27 15:55:47 +0000836 TIME_AFTER( current_tick, last_sleep + poweroff_timeout ))
837 {
838 mutex_lock(&ata_mtx);
839 ide_power_enable(false);
840 mutex_unlock(&ata_mtx);
841 poweroff = true;
842 }
843#endif
844
Björn Stenberg457b8a02002-08-26 13:21:14 +0000845 sleep(HZ/4);
846 }
Björn Stenberg11968a42002-07-16 14:07:47 +0000847 queue_wait(&ata_queue, &ev);
848 switch ( ev.id ) {
Daniel Stenberg006b2c12003-12-12 13:23:33 +0000849#ifndef USB_NONE
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000850 case SYS_USB_CONNECTED:
Björn Stenberg2b77b4f2002-11-28 22:46:19 +0000851 if (poweroff) {
852 mutex_lock(&ata_mtx);
853 led(true);
Björn Stenberg494d2612002-11-27 15:55:47 +0000854 ata_power_on();
Björn Stenberg2b77b4f2002-11-28 22:46:19 +0000855 led(false);
856 mutex_unlock(&ata_mtx);
857 }
Björn Stenberg494d2612002-11-27 15:55:47 +0000858
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000859 /* Tell the USB thread that we are safe */
Linus Nielsen Feltzing01fd2a02002-07-27 22:44:52 +0000860 DEBUGF("ata_thread got SYS_USB_CONNECTED\n");
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000861 usb_acknowledge(SYS_USB_CONNECTED_ACK);
Björn Stenberg11968a42002-07-16 14:07:47 +0000862
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000863 /* Wait until the USB cable is extracted again */
864 usb_wait_for_disconnect(&ata_queue);
865 break;
Daniel Stenberg006b2c12003-12-12 13:23:33 +0000866#endif
Björn Stenberg11968a42002-07-16 14:07:47 +0000867 case Q_SLEEP:
Björn Stenberg8e96c472002-09-06 23:55:52 +0000868 last_disk_activity = current_tick - sleep_timeout + (HZ/2);
Björn Stenberg11968a42002-07-16 14:07:47 +0000869 break;
870 }
871 }
872}
873
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000874/* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000875int ata_hard_reset(void)
876{
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000877 int ret;
Björn Stenberg65bf8512004-09-17 11:28:07 +0000878
Jörg Hohensohn593cc002004-09-28 22:13:26 +0000879#if CONFIG_CPU == SH7034
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000880 /* state HRR0 */
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +0000881 and_b(~0x02, &PADRH); /* assert _RESET */
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000882 sleep(1); /* > 25us */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000883
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000884 /* state HRR1 */
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +0000885 or_b(0x02, &PADRH); /* negate _RESET */
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000886 sleep(1); /* > 2ms */
Björn Stenberg65bf8512004-09-17 11:28:07 +0000887#elif defined HAVE_SCF5249
888#endif
Linus Nielsen Feltzingdc4977d2002-05-07 22:59:03 +0000889
Björn Stenberg1ea00d12002-12-03 11:26:39 +0000890 /* state HRR2 */
Björn Stenbergc032e652002-12-03 13:29:35 +0000891 ATA_SELECT = ata_device; /* select the right device */
Björn Stenberg7249c882002-12-02 10:30:40 +0000892 ret = wait_for_bsy();
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000893
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000894 /* Massage the return code so it is 0 on success and -1 on failure */
895 ret = ret?0:-1;
896
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000897 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000898}
899
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000900static int perform_soft_reset(void)
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000901{
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000902 int ret;
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000903 int retry_count;
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000904
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +0000905 ATA_SELECT = SELECT_LBA | ata_device;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000906 ATA_CONTROL = CONTROL_nIEN|CONTROL_SRST;
Björn Stenberg1fe97ec2003-12-17 20:15:12 +0000907 sleep(1); /* >= 5us */
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000908
909 ATA_CONTROL = CONTROL_nIEN;
Björn Stenberg1fe97ec2003-12-17 20:15:12 +0000910 sleep(1); /* >2ms */
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000911
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000912 /* This little sucker can take up to 30 seconds */
913 retry_count = 8;
914 do
915 {
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +0000916 ret = wait_for_rdy();
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000917 } while(!ret && retry_count--);
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000918
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000919 /* Massage the return code so it is 0 on success and -1 on failure */
920 ret = ret?0:-1;
Björn Stenbergc4b28502002-07-16 12:18:17 +0000921
Linus Nielsen Feltzing39224662002-05-16 21:28:21 +0000922 return ret;
Björn Stenberg1acfd6b2002-04-21 22:06:12 +0000923}
924
Linus Nielsen Feltzing22e09a32002-08-27 21:06:48 +0000925int ata_soft_reset(void)
926{
927 int ret;
928
929 mutex_lock(&ata_mtx);
930
931 ret = perform_soft_reset();
932
933 mutex_unlock(&ata_mtx);
934 return ret;
935}
936
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000937static int ata_power_on(void)
938{
Linus Nielsen Feltzing97955a72004-02-17 01:31:50 +0000939 int rc;
940
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000941 ide_power_enable(true);
Björn Stenberg7249c882002-12-02 10:30:40 +0000942 if( ata_hard_reset() )
943 return -1;
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000944
Linus Nielsen Feltzing867415b2004-02-17 01:30:25 +0000945 rc = set_features();
946 if (rc)
947 return rc * 10 - 2;
948
Björn Stenberg7249c882002-12-02 10:30:40 +0000949 if (set_multiple_mode(multisectors))
Linus Nielsen Feltzing867415b2004-02-17 01:30:25 +0000950 return -3;
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000951
Björn Stenbergc032e652002-12-03 13:29:35 +0000952 if (freeze_lock())
Linus Nielsen Feltzing867415b2004-02-17 01:30:25 +0000953 return -4;
Björn Stenbergc032e652002-12-03 13:29:35 +0000954
Björn Stenberg7249c882002-12-02 10:30:40 +0000955 return 0;
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000956}
Linus Nielsen Feltzing513e8512002-08-02 06:01:22 +0000957
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000958static int master_slave_detect(void)
Björn Stenberg5c7847c2002-05-22 14:37:36 +0000959{
960 /* master? */
961 ATA_SELECT = 0;
Björn Stenberg9f372f12003-07-09 22:04:31 +0000962 if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +0000963 ata_device = 0;
Björn Stenberg5c7847c2002-05-22 14:37:36 +0000964 DEBUGF("Found master harddisk\n");
965 }
966 else {
967 /* slave? */
968 ATA_SELECT = SELECT_DEVICE1;
Björn Stenberg9f372f12003-07-09 22:04:31 +0000969 if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +0000970 ata_device = SELECT_DEVICE1;
Björn Stenberg5c7847c2002-05-22 14:37:36 +0000971 DEBUGF("Found slave harddisk\n");
972 }
973 else
974 return -1;
975 }
976 return 0;
977}
978
Jörg Hohensohn593cc002004-09-28 22:13:26 +0000979#if CONFIG_CPU == SH7034 /* special archos quirk */
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000980static int io_address_detect(void)
Jörg Hohensohn118d45e2003-09-01 05:48:42 +0000981{ /* now, use the HW mask instead of probing */
982 if (read_hw_mask() & ATA_ADDRESS_200)
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000983 {
Linus Nielsen Feltzing1639e982002-07-02 14:23:30 +0000984 ata_io_address = 0x200; /* For debug purposes only */
Linus Nielsen Feltzing1a5032e2002-06-26 12:36:29 +0000985 old_recorder = false;
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000986 ata_control = ATA_CONTROL1;
987 }
Jörg Hohensohn118d45e2003-09-01 05:48:42 +0000988 else
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000989 {
Jörg Hohensohn118d45e2003-09-01 05:48:42 +0000990 ata_io_address = 0x300; /* For debug purposes only */
991 old_recorder = true;
992 ata_control = ATA_CONTROL2;
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000993 }
Jörg Hohensohn118d45e2003-09-01 05:48:42 +0000994
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000995 return 0;
996}
Björn Stenberg65bf8512004-09-17 11:28:07 +0000997#endif
Linus Nielsen Feltzing8169c8f2002-06-12 13:51:31 +0000998
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +0000999void ata_enable(bool on)
1000{
Jörg Hohensohn593cc002004-09-28 22:13:26 +00001001#if CONFIG_CPU == SH7034
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001002 if(on)
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +00001003 and_b(~0x80, &PADRL); /* enable ATA */
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001004 else
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +00001005 or_b(0x80, &PADRL); /* disable ATA */
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001006
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +00001007 or_b(0x80, &PAIORL);
Björn Stenberg65bf8512004-09-17 11:28:07 +00001008#elif defined HAVE_SCF5249
1009#endif
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001010}
1011
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001012static int identify(void)
1013{
1014 int i;
1015
Björn Stenbergc032e652002-12-03 13:29:35 +00001016 ATA_SELECT = ata_device;
1017
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001018 if(!wait_for_rdy()) {
1019 DEBUGF("identify() - not RDY\n");
1020 return -1;
1021 }
1022
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001023 ATA_COMMAND = CMD_IDENTIFY;
1024
1025 if (!wait_for_start_of_transfer())
1026 {
1027 DEBUGF("identify() - CMD failed\n");
1028 return -2;
1029 }
1030
1031 for (i=0; i<SECTOR_SIZE/2; i++)
1032 /* the IDENTIFY words are already swapped */
1033 identify_info[i] = ATA_DATA;
1034
1035 return 0;
1036}
1037
Björn Stenberg34fa70e2002-09-06 17:20:44 +00001038static int set_multiple_mode(int sectors)
1039{
Björn Stenbergc032e652002-12-03 13:29:35 +00001040 ATA_SELECT = ata_device;
1041
Björn Stenberg34fa70e2002-09-06 17:20:44 +00001042 if(!wait_for_rdy()) {
1043 DEBUGF("set_multiple_mode() - not RDY\n");
1044 return -1;
1045 }
1046
Björn Stenberg34fa70e2002-09-06 17:20:44 +00001047 ATA_NSECTOR = sectors;
1048 ATA_COMMAND = CMD_SET_MULTIPLE_MODE;
1049
1050 if (!wait_for_rdy())
1051 {
1052 DEBUGF("set_multiple_mode() - CMD failed\n");
1053 return -2;
1054 }
1055
1056 return 0;
1057}
1058
Björn Stenberga53afc02004-01-14 13:15:19 +00001059static int set_features(void)
1060{
1061 struct {
1062 unsigned char id_word;
1063 unsigned char id_bit;
1064 unsigned char subcommand;
1065 unsigned char parameter;
1066 } features[] = {
Jens Arnold44e76cf2004-06-11 06:56:51 +00001067 { 83, 3, 0x05, 0x80 }, /* power management: lowest power without standby */
Björn Stenberga53afc02004-01-14 13:15:19 +00001068 { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */
1069 { 82, 6, 0xaa, 0 }, /* enable read look-ahead */
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001070 { 83, 14, 0x03, 0 }, /* force PIO mode */
Björn Stenberga53afc02004-01-14 13:15:19 +00001071 { 0, 0, 0, 0 } /* <end of list> */
1072 };
1073 int i;
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001074 int pio_mode = 2;
Björn Stenberga53afc02004-01-14 13:15:19 +00001075
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001076 /* Find out the highest supported PIO mode */
1077 if(identify_info[64] & 2)
1078 pio_mode = 4;
1079 else
1080 if(identify_info[64] & 1)
1081 pio_mode = 3;
1082
1083 /* Update the table */
1084 features[3].parameter = 8 + pio_mode;
1085
Björn Stenberga53afc02004-01-14 13:15:19 +00001086 ATA_SELECT = ata_device;
1087
1088 if (!wait_for_rdy()) {
1089 DEBUGF("set_features() - not RDY\n");
1090 return -1;
1091 }
1092
1093 for (i=0; features[i].id_word; i++) {
1094 if (identify_info[features[i].id_word] & (1 << features[i].id_bit)) {
1095 ATA_FEATURE = features[i].subcommand;
1096 ATA_NSECTOR = features[i].parameter;
1097 ATA_COMMAND = CMD_SET_FEATURES;
1098
1099 if (!wait_for_rdy()) {
1100 DEBUGF("set_features() - CMD failed\n");
Linus Nielsen Feltzing68331ff2004-03-02 09:55:23 +00001101 return -10 - i;
1102 }
1103
1104 if(ATA_ALT_STATUS & STATUS_ERR) {
1105 if(ATA_ERROR & ERROR_ABRT) {
1106 return -20 - i;
1107 }
Björn Stenberga53afc02004-01-14 13:15:19 +00001108 }
1109 }
1110 }
1111
1112 return 0;
1113}
1114
Björn Stenberg45d32ce2002-12-03 13:12:55 +00001115unsigned short* ata_get_identify(void)
1116{
1117 return identify_info;
1118}
1119
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001120int ata_init(void)
1121{
Björn Stenberg9f372f12003-07-09 22:04:31 +00001122 int rc;
1123 bool coldstart = (PACR2 & 0x4000) != 0;
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001124
Björn Stenberg9f372f12003-07-09 22:04:31 +00001125 mutex_init(&ata_mtx);
Björn Stenberg11968a42002-07-16 14:07:47 +00001126
Linus Nielsen Feltzinge14e13d2002-05-13 19:22:38 +00001127 led(false);
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001128
Jörg Hohensohn593cc002004-09-28 22:13:26 +00001129#if CONFIG_CPU == SH7034
Jörg Hohensohnd1a3a3e2003-07-03 00:02:15 +00001130 /* Port A setup */
Linus Nielsen Feltzingbef7ab02003-11-07 12:15:24 +00001131 or_b(0x02, &PAIORH); /* output for ATA reset */
1132 or_b(0x02, &PADRH); /* release ATA reset */
Jörg Hohensohnd1a3a3e2003-07-03 00:02:15 +00001133 PACR2 &= 0xBFFF; /* GPIO function for PA7 (IDE enable) */
Björn Stenberg65bf8512004-09-17 11:28:07 +00001134#elif defined HAVE_SCF5249
1135#endif
Jörg Hohensohn545efb62003-06-26 21:29:13 +00001136
Jörg Hohensohnf4b677e2003-07-18 21:55:06 +00001137 sleeping = false;
Linus Nielsen Feltzing2012e1e2002-06-30 13:10:42 +00001138 ata_enable(true);
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001139
Björn Stenberg11968a42002-07-16 14:07:47 +00001140 if ( !initialized ) {
Jörg Hohensohn44298162003-12-03 01:03:54 +00001141 if (!ide_powered()) /* somebody has switched it off */
1142 {
1143 ide_power_enable(true);
1144 sleep(HZ); /* allow voltage to build up */
1145 }
1146
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001147 if (coldstart)
Jörg Hohensohnadef8fb2003-07-08 06:33:30 +00001148 {
Jörg Hohensohn5fb1e102004-03-10 14:15:14 +00001149 /* This should reset both master and slave, we don't yet know what's in */
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001150 ata_device = 0;
1151 if (ata_hard_reset())
1152 return -1;
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001153 }
Jörg Hohensohnadef8fb2003-07-08 06:33:30 +00001154
Björn Stenbergefd2f352003-07-09 16:46:46 +00001155 rc = master_slave_detect();
1156 if (rc)
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001157 return -10 + rc;
Björn Stenbergefd2f352003-07-09 16:46:46 +00001158
Jörg Hohensohn593cc002004-09-28 22:13:26 +00001159#if CONFIG_CPU == SH7034
Björn Stenbergefd2f352003-07-09 16:46:46 +00001160 rc = io_address_detect();
1161 if (rc)
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001162 return -20 + rc;
Björn Stenberg65bf8512004-09-17 11:28:07 +00001163#endif
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001164
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001165 /* symptom fix: else check_registers() below may fail */
1166 if (coldstart && !wait_for_bsy())
1167 {
1168 return -29;
1169 }
1170
Björn Stenbergefd2f352003-07-09 16:46:46 +00001171 rc = check_registers();
1172 if (rc)
Jörg Hohensohnbbfaf262003-07-09 07:18:47 +00001173 return -30 + rc;
Björn Stenbergefd2f352003-07-09 16:46:46 +00001174
Björn Stenbergefd2f352003-07-09 16:46:46 +00001175 rc = identify();
1176 if (rc)
Björn Stenberg65bf8512004-09-17 11:28:07 +00001177 return -40 + rc;
Björn Stenberg8ccbc762002-09-05 15:25:08 +00001178 multisectors = identify_info[47] & 0xff;
1179 DEBUGF("ata: %d sectors per ata request\n",multisectors);
Linus Nielsen Feltzing2f4b88e2002-07-23 15:02:25 +00001180
Björn Stenberg65bf8512004-09-17 11:28:07 +00001181 rc = freeze_lock();
1182 if (rc)
1183 return -50 + rc;
1184
Björn Stenberga53afc02004-01-14 13:15:19 +00001185 rc = set_features();
1186 if (rc)
1187 return -60 + rc;
1188
Björn Stenberg11968a42002-07-16 14:07:47 +00001189 queue_init(&ata_queue);
Björn Stenberg9cb5e0e2003-07-11 19:11:06 +00001190
1191 last_disk_activity = current_tick;
Björn Stenberg11968a42002-07-16 14:07:47 +00001192 create_thread(ata_thread, ata_stack,
1193 sizeof(ata_stack), ata_thread_name);
Björn Stenberg11968a42002-07-16 14:07:47 +00001194 initialized = true;
1195 }
Björn Stenbergefd2f352003-07-09 16:46:46 +00001196 rc = set_multiple_mode(multisectors);
1197 if (rc)
Björn Stenberga53afc02004-01-14 13:15:19 +00001198 return -70 + rc;
Björn Stenberg5c7847c2002-05-22 14:37:36 +00001199
Björn Stenberg1acfd6b2002-04-21 22:06:12 +00001200 return 0;
1201}