Mercurial > ecos
view packages/redboot/current/src/fs/ide.c @ 2257:467fd46113f3
* src/fs/fileio.c (do_list): Use getcwd for current directory,
rather than "." which may not be implemented in the FS.
* src/parse.c (redboot_exec): Conditionalise use of
__mem_fault_handler to only be when stubs are included.
(error_handler): Ditto for this function.
* src/main.c (cyg_start): Conditionalise use of
__mem_fault_handler to only be when stubs are included.
(do_go): Ditto.
(error_handler): Ditto for this function.
* src/fs/fileio.c (do_mkdir, do_deldir, do_del, do_write): Added
some extra argument checking to these functions.
* src/fs/fileio.c (do_mount): Only support -f with "legacy" flash
block devices.
Clear mount table on failure.
(do_move): Silence rename undefined warning.
(do_write): Silence warnings.
(do_info): Support longer device names.
* src/decompress.c (ZLIB_COMPRESSION_OVERHEAD):
Increase substantially if jffs2 is present.
* src/fs/fileio.c: Fixed some bugs in handling of mounts. The
strings used in the mount table must be copied, otherwise the
mount table is corrupted by later commands. Also toughened up some
error testing.
* doc/redboot_cmds.sgml: Added file mode documentation to load
command.
* doc/redboot_cmds.sgml: Added documentation of filesystem access
commands.
* src/fs/fileio.c (do_write): Added O_TRUNC to the open call to
ensure that the file is resized to fit the new data.
* src/fs/fileio.c: Significantly reorganized to present an
interface similar to the fis commands. Added a variety of command
to manipulate files and directories in a filesystem.
* src/parse.c: Added redboot_exec() to provide an internal
interface for executing RedBoot commands. Added err_printf() which
allows an error message to be printed before longjumping out to an
enclosing call to redboot_exec(). Where redboot_exec() is not
involved, it just behaves like diag_printf().
* src/main.c: Removed unnecessary delay during startup. Changed
diag_printf() in do_go() into err_printf().
* src/load.c: Changed some calls to diag_printf() to err_printf().
* src/net/net_io.c: Changed init priority to RedBoot_INIT_NET.
* include/redboot.h: Added some extra initialization
priorities. Added prototypes for redboot_exec() and err_printf().
| author | jlarmour |
|---|---|
| date | Thu, 20 Jul 2006 20:27:47 +0000 |
| parents | a53cbddaeb77 |
| children | 74dbf4c3f2e1 |
line wrap: on
line source
//========================================================================== // // ide.c // // RedBoot IDE support // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc. // Copyright (C) 2003 Gary Thomas <gary@mind.be> // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): msalter // Contributors: msalter // Date: 2001-07-14 // Purpose: // Description: // // This code is part of RedBoot (tm). // //####DESCRIPTIONEND#### // //========================================================================== #include <redboot.h> #include <cyg/hal/hal_io.h> #include <fs/disk.h> #include <fs/ide.h> static int ide_read(struct disk *d, cyg_uint32 start_sector, cyg_uint32 *buf, cyg_uint8 nr_sectors); static disk_funs_t ide_funs = { ide_read }; static struct ide_priv ide_privs[HAL_IDE_NUM_CONTROLLERS * 2]; static inline void __wait_for_ready(int ctlr) { cyg_uint8 status; do { HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ)); } static inline int __wait_for_drq(int ctlr) { cyg_uint8 status; cyg_ucount32 tries; CYGACC_CALL_IF_DELAY_US(10); for (tries=0; tries<1000000; tries++) { HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); if (!(status & IDE_STAT_BSY)) { if (status & IDE_STAT_DRQ) return 1; else return 0; } } } static int ide_reset(int ctlr) { cyg_uint8 status; int delay; // // VMware note: // VMware virtual IDE device handler obviously expects that // the reset and setup functions were already done // by it's bios and complais if one uses reset here... // #ifndef CYGSEM_REDBOOT_DISK_IDE_VMWARE HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted CYGACC_CALL_IF_DELAY_US(5000); HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); #endif // wait 30 seconds max for not busy and drive ready for (delay = 0; delay < 300; ++delay) { CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000); HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); if (!(status & IDE_STAT_BSY)) { if (status & IDE_STAT_DRDY) { return 1; } } } return 0; } // Return true if any devices attached to controller static int ide_presence_detect(int ctlr) { cyg_uint8 sel, val; int i; for (i = 0; i < 2; i++) { sel = (i << 4) | 0xA0; CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel); CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val); if (val == sel) { #ifndef CYGSEM_REDBOOT_DISK_IDE_VMWARE if (i) HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, 0); #endif return 1; } } return 0; } static int ide_ident(int ctlr, int dev, int is_packet_dev, cyg_uint16 *buf) { int i; HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, is_packet_dev ? 0xA1 : 0xEC); CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); if (!__wait_for_drq(ctlr)) return 0; for (i = 0; i < (SECTOR_SIZE / sizeof(cyg_uint16)); i++, buf++) HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf); return 1; } static int ide_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf) { int i, j; cyg_uint16 *p; HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, count); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, ((start >> 24) & 0xf) | (dev << 4) | 0x40); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20); for(p = buf, i = 0; i < count; i++) { if (!__wait_for_drq(ctlr)) { diag_printf("%s: NO DRQ for ide%d, device %d.\n", __FUNCTION__, ctlr, dev); return 0; } for (j = 0; j < (SECTOR_SIZE / sizeof(cyg_uint16)); j++, p++) HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *p); } return 1; } // max number of sectors to xfer during a single packet command #define MAX_CD_XFER 16 static inline int send_packet_command(int ctlr, int dev, cyg_uint16 len, cyg_uint16 *pkt, int pktlen) { int i; cyg_uint8 status, reason; HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 0); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, 0); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, len & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (len >> 8) & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xA0); if (!__wait_for_drq(ctlr)) { diag_printf("%s: NO DRQ for ide%d, device %d.\n", __FUNCTION__, ctlr, dev); return 0; } // send packet for (i = 0; i < (pktlen/sizeof(cyg_uint16)); i++) HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, pkt[i]); // wait for not busy transferring packet do { HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason); if ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ) if (reason & IDE_REASON_COD) continue; // still wanting packet data (should timeout here) } while (status & IDE_STAT_BSY); return 1; } #define READ_COUNT(x) \ { unsigned char tmp; \ HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAMID, tmp); \ (x) = tmp; \ HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAHI, tmp); \ (x) = (x) | (tmp << 8); \ } // Read the sense data static int request_sense(int ctlr, int dev, cyg_uint16 count, cyg_uint16 *buf) { int i; cyg_uint16 cdcount, pkt[6]; unsigned char status, *cpkt = (unsigned char *)pkt; // Fill in REQUEST SENSE packet command block memset(cpkt, 0, sizeof(pkt)); cpkt[0] = 0x03; cpkt[4] = 254; // allocation length if (!send_packet_command(ctlr, dev, count, pkt, sizeof(pkt))) return 0; HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); if (!(status & IDE_STAT_DRQ)) { if (status & IDE_STAT_SERVICE) { unsigned char reason; HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason); diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n", __FUNCTION__, ctlr, dev, status, reason); } return 0; } READ_COUNT(cdcount); if (cdcount != count) diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n", __FUNCTION__, ctlr, dev, cdcount, count); for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++) HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf); // wait for not busy transferring data do { HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ); return cdcount; } // Interpret the sense data static int handle_sense(int ctlr, int dev, cyg_uint8 count, cyg_uint16 *buf) { #if 0 unsigned char *p = (char *)buf; diag_printf("%s: %d bytes:\n", __FUNCTION__, count); diag_printf("sense key[%02x] additional sense[%02x]\n", p[2], p[12]); #endif return 1; } static int do_packet_read(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf) { int i, retry_cnt; cyg_uint16 cdcount, pkt[6], sense[127]; unsigned char status, *cpkt = (unsigned char *)pkt; // get count number of whole cdrom sectors while (count) { retry_cnt = 3; i = (count > MAX_CD_XFER) ? MAX_CD_XFER : count; retry: // Fill in READ(10) packet command block memset(cpkt, 0, sizeof(pkt)); cpkt[0] = 0x28; // READ(10) cpkt[2] = (start >> 24) & 0xff; cpkt[3] = (start >> 16) & 0xff; cpkt[4] = (start >> 8) & 0xff; cpkt[5] = (start >> 0) & 0xff; cpkt[7] = (i >> 8) & 0xff; cpkt[8] = i & 0xff; if (!send_packet_command(ctlr, dev, i * CDROM_SECTOR_SIZE, pkt, sizeof(pkt))) return 0; HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); if (!(status & IDE_STAT_DRQ)) { if (status & IDE_STAT_SERVICE) { unsigned char reason; int sense_count; HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason); #if 1 diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n", __FUNCTION__, ctlr, dev, status, reason); #endif sense_count = request_sense(ctlr, dev, sizeof(sense), sense); if (sense_count) { handle_sense(ctlr, dev, sense_count, sense); if (retry_cnt--) goto retry; } } return 0; } count -= i; start += i; READ_COUNT(cdcount); if (cdcount != (i * CDROM_SECTOR_SIZE)) diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n", __FUNCTION__, ctlr, dev, cdcount, i * CDROM_SECTOR_SIZE); for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++) HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf); // wait for not busy transferring data do { HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ); } return 1; } static int ide_packet_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf) { int i, extra; cyg_uint32 cdstart; static cyg_uint16 cdsec_buf[CDROM_SECTOR_SIZE/sizeof(cyg_uint16)]; cdstart = (start + SECTORS_PER_CDROM_SECTOR-1) / SECTORS_PER_CDROM_SECTOR; // align to cdrom sector boundary. if (start % SECTORS_PER_CDROM_SECTOR) { if (!ide_packet_read_sectors(ctlr, dev, cdstart * SECTORS_PER_CDROM_SECTOR, SECTORS_PER_CDROM_SECTOR, cdsec_buf)) return 0; i = SECTORS_PER_CDROM_SECTOR - (start % SECTORS_PER_CDROM_SECTOR); if (i > count) i = count; memcpy(buf, cdsec_buf + ((start % CDROM_SECTOR_SIZE) * SECTOR_SIZE), i * SECTOR_SIZE); count -= i; buf += (i * SECTOR_SIZE) / sizeof(*buf); ++cdstart; } extra = count % SECTORS_PER_CDROM_SECTOR; count /= SECTORS_PER_CDROM_SECTOR; if (count) { if (!do_packet_read(ctlr, dev, cdstart, count, buf)) return 0; buf += count * SECTORS_PER_CDROM_SECTOR * SECTOR_SIZE; } if (extra) { // read cdrom sector if (!ide_packet_read_sectors(ctlr, dev, cdstart * SECTORS_PER_CDROM_SECTOR, extra, cdsec_buf)) return 0; memcpy(buf, cdsec_buf, extra * SECTOR_SIZE); } return 1; } static int ide_read(struct disk *d, cyg_uint32 start_sec, cyg_uint32 *buf, cyg_uint8 nr_secs) { struct ide_priv *p = (struct ide_priv *)(d->private); if (p->flags & IDE_DEV_PACKET) return ide_packet_read_sectors(p->controller, p->drive, start_sec, nr_secs, (cyg_uint16 *)buf); return ide_read_sectors(p->controller, p->drive, start_sec, nr_secs, (cyg_uint16 *)buf); } static void ide_init(void) { cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], u32; cyg_uint16 u16; cyg_uint8 u8; int i, j, num_controllers; disk_t disk; struct ide_priv *priv; #define DEV_INIT_VAL ((j << 4) | 0xA0) num_controllers = HAL_IDE_INIT(); CYGACC_CALL_IF_DELAY_US(5); priv = ide_privs; for (i = 0; i < num_controllers; i++) { if (!ide_presence_detect(i)) { diag_printf("No devices on IDE controller %d\n", i); continue; } // soft reset the devices on this controller if (!ide_reset(i)) continue; // 2 devices per controller for (j = 0; j < 2; j++, priv++) { priv->controller = i; priv->drive = j; priv->flags = 0; // This is reminiscent of a memory test. We write a value // to a certain location (device register), then write a // different value somewhere else so that the first value // is not hanging on the bus, then we read back the first // value to see if the write was succesful. // HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, DEV_INIT_VAL); HAL_IDE_WRITE_UINT8(i, IDE_REG_FEATURES, 0); CYGACC_CALL_IF_DELAY_US(50000); HAL_IDE_READ_UINT8(i, IDE_REG_DEVICE, u8); if (u8 != DEV_INIT_VAL) { diag_printf("IDE failed to identify unit %d - wrote: %x, read: %x\n", i, DEV_INIT_VAL, u8); continue; } // device present priv->flags |= IDE_DEV_PRESENT; if (ide_ident(i, j, 0, (cyg_uint16 *)buf) <= 0) { if (ide_ident(i, j, 1, (cyg_uint16 *)buf) <= 0) { priv->flags = 0; continue; // can't identify device } else { u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG); if (((u16 >> 8) & 0x1f) != 5) { diag_printf("Non-CDROM ATAPI device #%d - skipped\n", i); continue; } priv->flags |= IDE_DEV_PACKET; } } memset(&disk, 0, sizeof(disk)); disk.funs = &ide_funs; disk.private = priv; disk.kind = DISK_IDE_HD; // until proven otherwise if (priv->flags & IDE_DEV_PACKET) { u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG); if (((u16 >> 8) & 0x1f) == 5) disk.kind = DISK_IDE_CDROM; } else { u32 = *(cyg_uint32 *)((char *)buf + IDE_DEVID_LBA_CAPACITY); disk.nr_sectors = u32; } if (!disk_register(&disk)) return; } } } RedBoot_init(ide_init, RedBoot_INIT_FIRST);
