source: SVN/cambria/redboot/packages/redboot/current/src/fs/ide.c @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 15.5 KB
Line 
1//==========================================================================
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, 2004 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
61static int ide_read(struct disk *d,
62                    cyg_uint32 start_sector,
63                    cyg_uint32 *buf,
64                    cyg_uint8  nr_sectors);
65
66static disk_funs_t ide_funs = { ide_read };
67
68static struct ide_priv ide_privs[HAL_IDE_NUM_CONTROLLERS * 2];
69
70static inline void
71__wait_for_ready(int ctlr)
72{
73    cyg_uint8 status;
74
75    do {
76        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
77    } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
78}
79
80static inline int
81__wait_for_drq(int ctlr)
82{
83    cyg_uint8 status;
84    cyg_ucount32 tries;
85
86    CYGACC_CALL_IF_DELAY_US(10);
87
88    for (tries=0; tries<1000000; tries++) {
89                        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
90   
91                    if (!(status & IDE_STAT_BSY)) {
92                                        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); 
93                        if (status & IDE_STAT_DRQ)
94                return 1;
95            else
96                return 0;
97
98
99        }
100    }
101
102}
103
104
105
106
107static int
108ide_reset(int ctlr)
109{
110    cyg_uint8 status;
111    int delay;
112
113    HAL_IDE_WRITE_CONTROL(ctlr, 6);     // polled mode, reset asserted
114    CYGACC_CALL_IF_DELAY_US(5000);
115    HAL_IDE_WRITE_CONTROL(ctlr, 2);     // polled mode, reset cleared
116    CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
117
118    // wait 30 seconds max for not busy and drive ready
119    for (delay = 0; delay < 300; ++delay) {
120        CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
121        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
122          if (!(status & IDE_STAT_BSY)) {
123                if (status & IDE_STAT_DRDY) {
124            return 1;
125    }
126          }
127    }
128    return 0;
129}
130
131// Return true if any devices attached to controller
132static int
133ide_presence_detect(int ctlr)
134{
135
136    cyg_uint8 sel, val;
137    int i;
138
139    sel = (i << 4) | 0xA0;
140
141
142    for(i=0;i<5;i++) {
143
144      CYGACC_CALL_IF_DELAY_US((cyg_uint32)(80000*i));
145      HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel);
146
147      CYGACC_CALL_IF_DELAY_US((cyg_uint32)(100*i));
148      HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val);
149
150      if (val == sel)
151          return 1;
152
153    }
154
155    return 0;
156
157
158}
159
160
161
162static int
163ide_ident(int ctlr, int dev, int is_packet_dev, cyg_uint16 *buf)
164{
165    int i;
166
167    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
168    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, is_packet_dev ? 0xA1 : 0xEC);
169    CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
170
171    if (!__wait_for_drq(ctlr))
172        return 0;
173
174    for (i = 0; i < (SECTOR_SIZE / sizeof(cyg_uint16)); i++, buf++)
175        HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
176
177    return 1;
178}
179
180static int
181ide_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
182{
183    int  i, j;
184    cyg_uint16 *p;
185
186
187    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, count);
188    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
189    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >>  8) & 0xff);
190    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (start >> 16) & 0xff);
191    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
192                        ((start >> 24) & 0xf) | (dev << 4) | 0x40);
193    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
194
195    for(p = buf, i = 0; i < count; i++) {
196
197        if (!__wait_for_drq(ctlr)) {
198            diag_printf("%s: NO DRQ for ide%d, device %d.\n",
199                        __FUNCTION__, ctlr, dev);
200            return 0;
201        }
202
203        for (j = 0; j < (SECTOR_SIZE / sizeof(cyg_uint16)); j++, p++)
204            HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *p);
205    }
206    return 1;
207}
208
209// max number of sectors to xfer during a single packet command
210#define MAX_CD_XFER 16
211
212static inline int
213send_packet_command(int ctlr, int dev, cyg_uint16 len, cyg_uint16 *pkt, int pktlen)
214{
215    int i;
216    cyg_uint8 status, reason;
217
218    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0);
219    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 0);
220    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, 0);
221    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, len & 0xff);
222    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (len >> 8) & 0xff);
223    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
224    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xA0);
225
226    if (!__wait_for_drq(ctlr)) {
227        diag_printf("%s: NO DRQ for ide%d, device %d.\n",
228                    __FUNCTION__, ctlr, dev);
229        return 0;
230    }
231
232    // send packet
233    for (i = 0; i < (pktlen/sizeof(cyg_uint16)); i++)
234        HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, pkt[i]);
235
236    // wait for not busy transferring packet
237    do {
238        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
239        HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
240
241        if ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ)
242            if (reason & IDE_REASON_COD)
243                continue;  // still wanting packet data (should timeout here)
244
245    } while (status & IDE_STAT_BSY);
246
247    return 1;
248}
249
250#define READ_COUNT(x)                                    \
251        { unsigned char tmp;                             \
252          HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAMID, tmp); \
253          (x) = tmp;                                     \
254          HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAHI, tmp);  \
255          (x) = (x) | (tmp << 8);                        \
256        }
257
258
259// Read the sense data
260static int
261request_sense(int ctlr, int dev, cyg_uint16 count, cyg_uint16 *buf)
262{
263    int i;
264    cyg_uint16 cdcount, pkt[6];
265    unsigned char status, *cpkt = (unsigned char *)pkt;
266
267
268    // Fill in REQUEST SENSE packet command block
269    memset(cpkt, 0, sizeof(pkt));
270    cpkt[0] = 0x03;
271    cpkt[4] = 254;  // allocation length
272       
273    if (!send_packet_command(ctlr, dev, count, pkt, sizeof(pkt)))
274        return 0;
275
276    HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
277    if (!(status & IDE_STAT_DRQ)) {
278        if (status & IDE_STAT_SERVICE) {
279            unsigned char reason;
280            HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
281            diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
282                        __FUNCTION__, ctlr, dev, status, reason);
283        }
284        return 0;
285    }
286
287    READ_COUNT(cdcount);
288    if (cdcount != count)
289        diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
290                    __FUNCTION__, ctlr, dev, cdcount, count);
291
292    for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
293        HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
294
295    // wait for not busy transferring data
296    do {
297        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
298    } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
299
300    return cdcount;
301}
302
303// Interpret the sense data
304static int
305handle_sense(int ctlr, int dev, cyg_uint8 count, cyg_uint16 *buf)
306{
307#if 0
308    unsigned char *p = (char *)buf;
309
310    diag_printf("%s: %d bytes:\n", __FUNCTION__, count);
311    diag_printf("sense key[%02x] additional sense[%02x]\n",
312                p[2], p[12]);
313#endif
314    return 1;
315}
316
317static int
318do_packet_read(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
319{
320    int i, retry_cnt;
321    cyg_uint16 cdcount, pkt[6], sense[127];
322    unsigned char status, *cpkt = (unsigned char *)pkt;
323
324    // get count number of whole cdrom sectors
325    while (count) {
326
327        retry_cnt = 3;
328
329        i = (count > MAX_CD_XFER) ? MAX_CD_XFER : count;
330
331    retry:
332        // Fill in READ(10) packet command block
333        memset(cpkt, 0, sizeof(pkt));
334        cpkt[0] = 0x28;  // READ(10)
335        cpkt[2] = (start >> 24) & 0xff;
336        cpkt[3] = (start >> 16) & 0xff;
337        cpkt[4] = (start >>  8) & 0xff;
338        cpkt[5] = (start >>  0) & 0xff;
339        cpkt[7] = (i >> 8) & 0xff;
340        cpkt[8] = i & 0xff;
341       
342        if (!send_packet_command(ctlr, dev, i * CDROM_SECTOR_SIZE,
343                                 pkt, sizeof(pkt)))
344            return 0;
345
346        HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
347        if (!(status & IDE_STAT_DRQ)) {
348            if (status & IDE_STAT_SERVICE) {
349                unsigned char reason;
350                int sense_count;
351                HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
352#if 1
353                diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
354                            __FUNCTION__, ctlr, dev, status, reason);
355#endif
356                sense_count = request_sense(ctlr, dev, sizeof(sense), sense);
357                if (sense_count) {
358                    handle_sense(ctlr, dev, sense_count, sense);
359                    if (retry_cnt--)
360                        goto retry;
361                }
362            }
363            return 0;
364        }
365
366        count -= i;
367        start += i;
368
369        READ_COUNT(cdcount);
370        if (cdcount != (i * CDROM_SECTOR_SIZE))
371            diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
372                        __FUNCTION__, ctlr, dev,
373                        cdcount, i * CDROM_SECTOR_SIZE);
374
375        for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
376            HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
377
378        // wait for not busy transferring data
379        do {
380            HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
381        } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
382    }
383    return 1;
384}
385
386
387static int
388ide_packet_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
389{
390    int  i, extra;
391    cyg_uint32 cdstart;
392    static cyg_uint16 cdsec_buf[CDROM_SECTOR_SIZE/sizeof(cyg_uint16)];
393
394
395    cdstart = (start + SECTORS_PER_CDROM_SECTOR-1) / SECTORS_PER_CDROM_SECTOR;
396   
397    // align to cdrom sector boundary.
398    if (start % SECTORS_PER_CDROM_SECTOR) {
399        if (!ide_packet_read_sectors(ctlr, dev,
400                                     cdstart * SECTORS_PER_CDROM_SECTOR,
401                                     SECTORS_PER_CDROM_SECTOR, cdsec_buf))
402            return 0;
403
404        i = SECTORS_PER_CDROM_SECTOR - (start % SECTORS_PER_CDROM_SECTOR);
405        if (i > count)
406            i = count;
407        memcpy(buf, cdsec_buf + ((start % CDROM_SECTOR_SIZE) * SECTOR_SIZE),
408               i * SECTOR_SIZE);
409
410        count -= i;
411        buf += (i * SECTOR_SIZE) / sizeof(*buf);
412        ++cdstart;
413    }
414
415    extra = count % SECTORS_PER_CDROM_SECTOR;
416    count /= SECTORS_PER_CDROM_SECTOR;
417
418    if (count) {
419        if (!do_packet_read(ctlr, dev, cdstart, count, buf))
420            return 0;
421        buf += count * SECTORS_PER_CDROM_SECTOR * SECTOR_SIZE;
422    }
423
424    if (extra) {
425        // read cdrom sector
426        if (!ide_packet_read_sectors(ctlr, dev,
427                                     cdstart * SECTORS_PER_CDROM_SECTOR,
428                                     extra, cdsec_buf))
429            return 0;
430        memcpy(buf, cdsec_buf, extra * SECTOR_SIZE);
431    }
432
433    return 1;
434}
435
436static int
437ide_read(struct disk *d,
438         cyg_uint32 start_sec, cyg_uint32 *buf, cyg_uint8 nr_secs)
439{
440    struct ide_priv *p = (struct ide_priv *)(d->private);
441
442    if (p->flags & IDE_DEV_PACKET)
443        return ide_packet_read_sectors(p->controller, p->drive,
444                                     start_sec, nr_secs, (cyg_uint16 *)buf);
445
446    return ide_read_sectors(p->controller, p->drive,
447                            start_sec, nr_secs, (cyg_uint16 *)buf);
448}
449
450
451static void
452ide_init(void)
453{
454    cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], u32;
455    cyg_uint16 u16;
456    cyg_uint8 u8;
457    int i, j, num_controllers;
458    disk_t disk;
459    struct ide_priv *priv;
460                cyg_uint8 eeprom[1];
461                unsigned int pio_mask;
462
463
464#define DEV_INIT_VAL ((j << 4) | 0xA0)
465
466                eeprom_read(0x134, eeprom, 1);
467                if (eeprom[0] == 01){
468                        return;
469                }else{
470        num_controllers = HAL_IDE_INIT();
471                }
472
473    CYGACC_CALL_IF_DELAY_US(5);
474
475    priv = ide_privs;
476    for (i = 0; i < num_controllers; i++) {
477
478
479        if (!ide_presence_detect(i)) {
480            diag_printf("No devices on IDE controller %d\n", i);
481            continue;
482        }
483
484        // soft reset the devices on this controller
485        if (!ide_reset(i))
486            continue;
487
488        // 2 devices per controller
489        for (j = 0; j < 1; j++, priv++) {
490            priv->controller = i;
491            priv->drive = j;
492            priv->flags = 0;
493                        priv->mode = 0;
494           
495            // This is reminiscent of a memory test. We write a value
496            // to a certain location (device register), then write a
497            // different value somewhere else so that the first value
498            // is not hanging on the bus, then we read back the first
499            // value to see if the write was succesful.
500            //
501            HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, DEV_INIT_VAL);
502            HAL_IDE_WRITE_UINT8(i, IDE_REG_FEATURES, 0);
503            CYGACC_CALL_IF_DELAY_US(50000);
504            HAL_IDE_READ_UINT8(i, IDE_REG_DEVICE, u8);
505            if (u8 != DEV_INIT_VAL) {
506                diag_printf("IDE failed to identify unit %d - wrote: %x, read: %x\n", 
507                            i, DEV_INIT_VAL, u8);
508                continue;
509            }
510
511            // device present
512            priv->flags |= IDE_DEV_PRESENT;
513
514            if (ide_ident(i, j, 0, (cyg_uint16 *)buf) <= 0) {
515                if (ide_ident(i, j, 1, (cyg_uint16 *)buf) <= 0) {
516                    priv->flags = 0;
517                    continue;  // can't identify device
518                } else {
519                    u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
520                    if (((u16 >> 8) & 0x1f) != 5) {
521                        diag_printf("Non-CDROM ATAPI device #%d - skipped\n", i);
522                        continue;
523                    }
524                    priv->flags |= IDE_DEV_PACKET;
525                }
526            }
527   
528            memset(&disk, 0, sizeof(disk));
529            disk.funs = &ide_funs;
530
531            disk.kind = DISK_IDE_HD;  // until proven otherwise
532
533            if (priv->flags & IDE_DEV_PACKET) {
534                u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
535                if (((u16 >> 8) & 0x1f) == 5)
536                    disk.kind = DISK_IDE_CDROM;
537            } else {
538                u32 = *(cyg_uint32 *)((char *)buf + IDE_DEVID_LBA_CAPACITY);
539                disk.nr_sectors = u32;
540            }
541
542                        u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_VALID);
543                        if ((u16 >> 8) & (1 << 1)){ 
544                                u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_PIO_MODE);
545                                if ((u16 >> 8) & (1 << 1)){
546                                        priv->mode = 4;
547                                        *IXP425_EXP_CS3 = 0x80403c43;
548                                }else{
549                                        priv->mode = 3;
550                                        *IXP425_EXP_CS3 = 0x80823c43;
551                                }
552                        }else{
553                                u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_OLD_PIO_MODE);
554                                priv->mode = (u16 & 0xf);
555                                if (priv->mode == 2){
556                                        *IXP425_EXP_CS3 = 0x82413c43;
557                                }else if (priv->mode == 1){
558                                        *IXP425_EXP_CS3 = 0x86433c43;
559                                }else{
560                                        *IXP425_EXP_CS3 = 0x8a473c43;
561                                }
562                        }
563
564            disk.private = priv;
565            if (!disk_register(&disk))
566                return;
567        }
568    }
569}
570
571RedBoot_init(ide_init, RedBoot_INIT_FIRST);
572
Note: See TracBrowser for help on using the repository browser.