OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [redboot/] [v2_0/] [src/] [fs/] [ide.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1254 phoenix
//==========================================================================
2
//
3
//      ide.c
4
//
5
//      RedBoot IDE support
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
// Copyright (C) 2003 Gary Thomas <gary@mind.be>
13
//
14
// eCos is free software; you can redistribute it and/or modify it under
15
// the terms of the GNU General Public License as published by the Free
16
// Software Foundation; either version 2 or (at your option) any later version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
// for more details.
22
//
23
// You should have received a copy of the GNU General Public License along
24
// with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
//
27
// As a special exception, if other files instantiate templates or use macros
28
// or inline functions from this file, or you compile this file and link it
29
// with other works to produce a work based on this file, this file does not
30
// by itself cause the resulting work to be covered by the GNU General Public
31
// License. However the source code for this file must still be made available
32
// in accordance with section (3) of the GNU General Public License.
33
//
34
// This exception does not invalidate any other reasons why a work based on
35
// this file might be covered by the GNU General Public License.
36
//
37
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38
// at http://sources.redhat.com/ecos/ecos-license/
39
// -------------------------------------------
40
//####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):    msalter
45
// Contributors: msalter
46
// Date:         2001-07-14
47
// Purpose:      
48
// Description:  
49
//              
50
// This code is part of RedBoot (tm).
51
//
52
//####DESCRIPTIONEND####
53
//
54
//==========================================================================
55
 
56
#include <redboot.h>
57
#include <cyg/hal/hal_io.h>
58
#include <fs/disk.h>
59
#include <fs/ide.h>
60
 
61
static int ide_read(struct disk *d,
62
                    cyg_uint32 start_sector,
63
                    cyg_uint32 *buf,
64
                    cyg_uint8  nr_sectors);
65
 
66
static disk_funs_t ide_funs = { ide_read };
67
 
68
static struct ide_priv ide_privs[HAL_IDE_NUM_CONTROLLERS * 2];
69
 
70
static inline void
71
__wait_for_ready(int ctlr)
72
{
73
    cyg_uint8 status;
74
    do {
75
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
76
    } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
77
}
78
 
79
static inline int
80
__wait_for_drq(int ctlr)
81
{
82
    cyg_uint8 status;
83
 
84
    CYGACC_CALL_IF_DELAY_US(10);
85
    do {
86
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
87
        if (status & IDE_STAT_DRQ)
88
            return 1;
89
    } while (status & IDE_STAT_BSY);
90
 
91
    return 0;
92
}
93
 
94
static int
95
ide_reset(int ctlr)
96
{
97
    cyg_uint8 status;
98
    int delay;
99
 
100
    HAL_IDE_WRITE_CONTROL(ctlr, 6);     // polled mode, reset asserted
101
    CYGACC_CALL_IF_DELAY_US(5000);
102
    HAL_IDE_WRITE_CONTROL(ctlr, 2);     // polled mode, reset cleared
103
    CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
104
 
105
    // wait 30 seconds max for not busy
106
    for (delay = 0; delay < 300; ++delay) {
107
        CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
108
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
109
        // bail out early on bogus status
110
        if ((status & (IDE_STAT_BSY|IDE_STAT_DRDY)) == (IDE_STAT_BSY|IDE_STAT_DRDY))
111
            break;
112
        if (!(status & IDE_STAT_BSY))
113
            return 1;
114
    }
115
    return 0;
116
}
117
 
118
static int
119
ide_ident(int ctlr, int dev, int is_packet_dev, cyg_uint16 *buf)
120
{
121
    int i;
122
 
123
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
124
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, is_packet_dev ? 0xA1 : 0xEC);
125
    CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
126
 
127
    if (!__wait_for_drq(ctlr))
128
        return 0;
129
 
130
    for (i = 0; i < (SECTOR_SIZE / sizeof(cyg_uint16)); i++, buf++)
131
        HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
132
 
133
    return 1;
134
}
135
 
136
static int
137
ide_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
138
{
139
    int  i, j;
140
    cyg_uint16 *p;
141
 
142
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, count);
143
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
144
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >>  8) & 0xff);
145
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (start >> 16) & 0xff);
146
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
147
                        ((start >> 24) & 0xf) | (dev << 4) | 0x40);
148
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
149
 
150
    for(p = buf, i = 0; i < count; i++) {
151
 
152
        if (!__wait_for_drq(ctlr)) {
153
            diag_printf("%s: NO DRQ for ide%d, device %d.\n",
154
                        __FUNCTION__, ctlr, dev);
155
            return 0;
156
        }
157
 
158
        for (j = 0; j < (SECTOR_SIZE / sizeof(cyg_uint16)); j++, p++)
159
            HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *p);
160
    }
161
    return 1;
162
}
163
 
164
// max number of sectors to xfer during a single packet command
165
#define MAX_CD_XFER 16
166
 
167
static inline int
168
send_packet_command(int ctlr, int dev, cyg_uint16 len, cyg_uint16 *pkt, int pktlen)
169
{
170
    int i;
171
    cyg_uint8 status, reason;
172
 
173
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0);
174
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 0);
175
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, 0);
176
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, len & 0xff);
177
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (len >> 8) & 0xff);
178
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
179
    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xA0);
180
 
181
    if (!__wait_for_drq(ctlr)) {
182
        diag_printf("%s: NO DRQ for ide%d, device %d.\n",
183
                    __FUNCTION__, ctlr, dev);
184
        return 0;
185
    }
186
 
187
    // send packet
188
    for (i = 0; i < (pktlen/sizeof(cyg_uint16)); i++)
189
        HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, pkt[i]);
190
 
191
    // wait for not busy transferring packet
192
    do {
193
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
194
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
195
 
196
        if ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ)
197
            if (reason & IDE_REASON_COD)
198
                continue;  // still wanting packet data (should timeout here)
199
 
200
    } while (status & IDE_STAT_BSY);
201
 
202
    return 1;
203
}
204
 
205
#define READ_COUNT(x)                                    \
206
        { unsigned char tmp;                             \
207
          HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAMID, tmp); \
208
          (x) = tmp;                                     \
209
          HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAHI, tmp);  \
210
          (x) = cdcount |= (tmp << 8);                   \
211
        }
212
 
213
 
214
// Read the sense data
215
static int
216
request_sense(int ctlr, int dev, cyg_uint16 count, cyg_uint16 *buf)
217
{
218
    int i;
219
    cyg_uint16 cdcount, pkt[6];
220
    unsigned char status, *cpkt = (unsigned char *)pkt;
221
 
222
 
223
    // Fill in REQUEST SENSE packet command block
224
    memset(cpkt, 0, sizeof(pkt));
225
    cpkt[0] = 0x03;
226
    cpkt[4] = 254;  // allocation length
227
 
228
    if (!send_packet_command(ctlr, dev, count, pkt, sizeof(pkt)))
229
        return 0;
230
 
231
    HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
232
    if (!(status & IDE_STAT_DRQ)) {
233
        if (status & IDE_STAT_SERVICE) {
234
            unsigned char reason;
235
            HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
236
            diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
237
                        __FUNCTION__, ctlr, dev, status, reason);
238
        }
239
        return 0;
240
    }
241
 
242
    READ_COUNT(cdcount);
243
    if (cdcount != count)
244
        diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
245
                    __FUNCTION__, ctlr, dev, cdcount, count);
246
 
247
    for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
248
        HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
249
 
250
    // wait for not busy transferring data
251
    do {
252
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
253
    } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
254
 
255
    return cdcount;
256
}
257
 
258
// Interpret the sense data
259
static int
260
handle_sense(int ctlr, int dev, cyg_uint8 count, cyg_uint16 *buf)
261
{
262
#if 0
263
    unsigned char *p = (char *)buf;
264
 
265
    diag_printf("%s: %d bytes:\n", __FUNCTION__, count);
266
    diag_printf("sense key[%02x] additional sense[%02x]\n",
267
                p[2], p[12]);
268
#endif
269
    return 1;
270
}
271
 
272
static int
273
do_packet_read(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
274
{
275
    int i, retry_cnt;
276
    cyg_uint16 cdcount, pkt[6], sense[127];
277
    unsigned char status, *cpkt = (unsigned char *)pkt;
278
 
279
    // get count number of whole cdrom sectors
280
    while (count) {
281
 
282
        retry_cnt = 3;
283
 
284
        i = (count > MAX_CD_XFER) ? MAX_CD_XFER : count;
285
 
286
    retry:
287
        // Fill in READ(10) packet command block
288
        memset(cpkt, 0, sizeof(pkt));
289
        cpkt[0] = 0x28;  // READ(10)
290
        cpkt[2] = (start >> 24) & 0xff;
291
        cpkt[3] = (start >> 16) & 0xff;
292
        cpkt[4] = (start >>  8) & 0xff;
293
        cpkt[5] = (start >>  0) & 0xff;
294
        cpkt[7] = (i >> 8) & 0xff;
295
        cpkt[8] = i & 0xff;
296
 
297
        if (!send_packet_command(ctlr, dev, i * CDROM_SECTOR_SIZE,
298
                                 pkt, sizeof(pkt)))
299
            return 0;
300
 
301
        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
302
        if (!(status & IDE_STAT_DRQ)) {
303
            if (status & IDE_STAT_SERVICE) {
304
                unsigned char reason;
305
                int sense_count;
306
                HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
307
#if 1
308
                diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
309
                            __FUNCTION__, ctlr, dev, status, reason);
310
#endif
311
                sense_count = request_sense(ctlr, dev, sizeof(sense), sense);
312
                if (sense_count) {
313
                    handle_sense(ctlr, dev, sense_count, sense);
314
                    if (retry_cnt--)
315
                        goto retry;
316
                }
317
            }
318
            return 0;
319
        }
320
 
321
        count -= i;
322
        start += i;
323
 
324
        READ_COUNT(cdcount);
325
        if (cdcount != (i * CDROM_SECTOR_SIZE))
326
            diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
327
                        __FUNCTION__, ctlr, dev,
328
                        cdcount, i * CDROM_SECTOR_SIZE);
329
 
330
        for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
331
            HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
332
 
333
        // wait for not busy transferring data
334
        do {
335
            HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
336
        } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
337
    }
338
    return 1;
339
}
340
 
341
 
342
static int
343
ide_packet_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
344
{
345
    int  i, extra;
346
    cyg_uint32 cdstart;
347
    static cyg_uint16 cdsec_buf[CDROM_SECTOR_SIZE/sizeof(cyg_uint16)];
348
 
349
    cdstart = (start + SECTORS_PER_CDROM_SECTOR-1) / SECTORS_PER_CDROM_SECTOR;
350
 
351
    // align to cdrom sector boundary.
352
    if (start % SECTORS_PER_CDROM_SECTOR) {
353
        if (!ide_packet_read_sectors(ctlr, dev,
354
                                     cdstart * SECTORS_PER_CDROM_SECTOR,
355
                                     SECTORS_PER_CDROM_SECTOR, cdsec_buf))
356
            return 0;
357
 
358
        i = SECTORS_PER_CDROM_SECTOR - (start % SECTORS_PER_CDROM_SECTOR);
359
        if (i > count)
360
            i = count;
361
        memcpy(buf, cdsec_buf + ((start % CDROM_SECTOR_SIZE) * SECTOR_SIZE),
362
               i * SECTOR_SIZE);
363
 
364
        count -= i;
365
        buf += (i * SECTOR_SIZE) / sizeof(*buf);
366
        ++cdstart;
367
    }
368
 
369
    extra = count % SECTORS_PER_CDROM_SECTOR;
370
    count /= SECTORS_PER_CDROM_SECTOR;
371
 
372
    if (count) {
373
        if (!do_packet_read(ctlr, dev, cdstart, count, buf))
374
            return 0;
375
        buf += count * SECTORS_PER_CDROM_SECTOR * SECTOR_SIZE;
376
    }
377
 
378
    if (extra) {
379
        // read cdrom sector 
380
        if (!ide_packet_read_sectors(ctlr, dev,
381
                                     cdstart * SECTORS_PER_CDROM_SECTOR,
382
                                     extra, cdsec_buf))
383
            return 0;
384
        memcpy(buf, cdsec_buf, extra * SECTOR_SIZE);
385
    }
386
 
387
    return 1;
388
}
389
 
390
static int
391
ide_read(struct disk *d,
392
         cyg_uint32 start_sec, cyg_uint32 *buf, cyg_uint8 nr_secs)
393
{
394
    struct ide_priv *p = (struct ide_priv *)(d->private);
395
 
396
    if (p->flags & IDE_DEV_PACKET)
397
        return ide_packet_read_sectors(p->controller, p->drive,
398
                                     start_sec, nr_secs, (cyg_uint16 *)buf);
399
 
400
    return ide_read_sectors(p->controller, p->drive,
401
                            start_sec, nr_secs, (cyg_uint16 *)buf);
402
}
403
 
404
 
405
static void
406
ide_init(void)
407
{
408
    cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], u32;
409
    cyg_uint16 u16;
410
    cyg_uint8 u8;
411
    int i, j;
412
    disk_t disk;
413
    struct ide_priv *priv;
414
 
415
#define DEV_INIT_VAL ((j << 4) | 0xA0)
416
 
417
    HAL_IDE_INIT();
418
 
419
    CYGACC_CALL_IF_DELAY_US(5);
420
 
421
    priv = ide_privs;
422
    for (i = 0; i < HAL_IDE_NUM_CONTROLLERS; i++) {
423
 
424
        // soft reset the devices on this controller
425
        if (!ide_reset(i))
426
            continue;
427
 
428
        // 2 devices per controller
429
        for (j = 0; j < 2; j++, priv++) {
430
 
431
            priv->controller = i;
432
            priv->drive = j;
433
            priv->flags = 0;
434
 
435
            // This is reminiscent of a memory test. We write a value
436
            // to a certain location (device register), then write a
437
            // different value somewhere else so that the first value
438
            // is not hanging on the bus, then we read back the first
439
            // value to see if the write was succesful.
440
            //
441
            HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, DEV_INIT_VAL);
442
            HAL_IDE_WRITE_UINT8(i, IDE_REG_FEATURES, 0);
443
            CYGACC_CALL_IF_DELAY_US(50000);
444
            HAL_IDE_READ_UINT8(i, IDE_REG_DEVICE, u8);
445
            if (u8 != DEV_INIT_VAL) {
446
                diag_printf("IDE failed to identify unit %d - wrote: %x, read: %x\n",
447
                            i, DEV_INIT_VAL, u8);
448
                continue;
449
            }
450
 
451
            // device present
452
            priv->flags |= IDE_DEV_PRESENT;
453
 
454
            if (ide_ident(i, j, 0, (cyg_uint16 *)buf) <= 0) {
455
                if (ide_ident(i, j, 1, (cyg_uint16 *)buf) <= 0) {
456
                    priv->flags = 0;
457
                    continue;  // can't identify device
458
                } else {
459
                    u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
460
                    if (((u16 >> 8) & 0x1f) != 5) {
461
                        diag_printf("Non-CDROM ATAPI device #%d - skipped\n", i);
462
                        continue;
463
                    }
464
                    priv->flags |= IDE_DEV_PACKET;
465
                }
466
            }
467
 
468
            memset(&disk, 0, sizeof(disk));
469
            disk.funs = &ide_funs;
470
            disk.private = priv;
471
 
472
            disk.kind = DISK_IDE_HD;  // until proven otherwise
473
 
474
            if (priv->flags & IDE_DEV_PACKET) {
475
                u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
476
                if (((u16 >> 8) & 0x1f) == 5)
477
                    disk.kind = DISK_IDE_CDROM;
478
            } else {
479
                u32 = *(cyg_uint32 *)((char *)buf + IDE_DEVID_LBA_CAPACITY);
480
                disk.nr_sectors = u32;
481
            }
482
 
483
            if (!disk_register(&disk))
484
                return;
485
        }
486
    }
487
}
488
 
489
RedBoot_init(ide_init, RedBoot_INIT_FIRST);
490
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.