[coreboot] r86 - in trunk/filo: . drivers fs include main main/grub
svn at coreboot.org
svn at coreboot.org
Wed Mar 11 04:07:08 CET 2009
Author: stepan
Date: 2009-03-11 04:07:08 +0100 (Wed, 11 Mar 2009)
New Revision: 86
Added:
trunk/filo/drivers/hdreg.h
trunk/filo/drivers/ide_new.c
trunk/filo/drivers/ide_new.h
Modified:
trunk/filo/Config.in
trunk/filo/Makefile
trunk/filo/drivers/Makefile.inc
trunk/filo/drivers/ide.c
trunk/filo/drivers/intel.c
trunk/filo/fs/blockdev.c
trunk/filo/include/fs.h
trunk/filo/main/Makefile.inc
trunk/filo/main/grub/builtins.c
Log:
* move openbios IDE driver over to filo. It works a lot more reliable than the
old one. (Lacks PCI BAR reading though)
* some helper commands
* push version to 0.6.0 final
Modified: trunk/filo/Config.in
===================================================================
--- trunk/filo/Config.in 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/Config.in 2009-03-11 03:07:08 UTC (rev 86)
@@ -118,15 +118,23 @@
Use PCMCIA compact flash on Via Epia MII10000 and MII6000E
This device is referred to as hde.
+config IDE_NEW_DISK
+ bool "New IDE driver"
+ default n
+ depends on !IDE_DISK
+ help
+ Jens Axboe's fine IDE driver
+
config USB_NEW_DISK
- bool "new USB Stack"
+ bool "USB Stack"
default y
help
Driver for USB Storage
config USB_DISK
- bool "USB Stack (obsolete?)"
+ bool "Old USB Stack (obsolete?)"
default n
+ depends on !USB_NEW_DISK
help
Driver for USB Storage
Modified: trunk/filo/Makefile
===================================================================
--- trunk/filo/Makefile 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/Makefile 2009-03-11 03:07:08 UTC (rev 86)
@@ -17,7 +17,7 @@
#
export PROGRAM_NAME := FILO
-export PROGRAM_VERSION := 0.6.0rc1
+export PROGRAM_VERSION := 0.6.0
export src := $(shell pwd)
export srctree := $(src)
Modified: trunk/filo/drivers/Makefile.inc
===================================================================
--- trunk/filo/drivers/Makefile.inc 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/drivers/Makefile.inc 2009-03-11 03:07:08 UTC (rev 86)
@@ -17,6 +17,7 @@
#
TARGETS-$(CONFIG_IDE_DISK) += drivers/ide.o
+TARGETS-$(CONFIG_IDE_NEW_DISK) += drivers/ide_new.o
TARGETS-$(CONFIG_VIA_SOUND) += drivers/via-sound.o
TARGETS-y += drivers/intel.o
Added: trunk/filo/drivers/hdreg.h
===================================================================
--- trunk/filo/drivers/hdreg.h (rev 0)
+++ trunk/filo/drivers/hdreg.h 2009-03-11 03:07:08 UTC (rev 86)
@@ -0,0 +1,297 @@
+/*
+ * this header holds data structures as dictated by spec
+ */
+#ifndef HDREG_H
+#define HDREG_H
+#include <arch/types.h>
+//#include <misc.h>
+
+#define CONFIG_LITTLE_ENDIAN
+
+#define u8 uint8_t
+#define u16 uint16_t
+#define u32 uint32_t
+
+struct hd_driveid {
+ unsigned short config; /* lots of obsolete bit flags */
+ unsigned short cyls; /* Obsolete, "physical" cyls */
+ unsigned short reserved2; /* reserved (word 2) */
+ unsigned short heads; /* Obsolete, "physical" heads */
+ unsigned short track_bytes; /* unformatted bytes per track */
+ unsigned short sector_bytes; /* unformatted bytes per sector */
+ unsigned short sectors; /* Obsolete, "physical" sectors per track */
+ unsigned short vendor0; /* vendor unique */
+ unsigned short vendor1; /* vendor unique */
+ unsigned short vendor2; /* Retired vendor unique */
+ unsigned char serial_no[20]; /* 0 = not_specified */
+ unsigned short buf_type; /* Retired */
+ unsigned short buf_size; /* Retired, 512 byte increments
+ * 0 = not_specified
+ */
+ unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */
+ unsigned char fw_rev[8]; /* 0 = not_specified */
+ unsigned char model[40]; /* 0 = not_specified */
+ unsigned char max_multsect; /* 0=not_implemented */
+ unsigned char vendor3; /* vendor unique */
+ unsigned short dword_io; /* 0=not_implemented; 1=implemented */
+ unsigned char vendor4; /* vendor unique */
+ unsigned char capability; /* (upper byte of word 49)
+ * 3: IORDYsup
+ * 2: IORDYsw
+ * 1: LBA
+ * 0: DMA
+ */
+ unsigned short reserved50; /* reserved (word 50) */
+ unsigned char vendor5; /* Obsolete, vendor unique */
+ unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */
+ unsigned char vendor6; /* Obsolete, vendor unique */
+ unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */
+ unsigned short field_valid; /* (word 53)
+ * 2: ultra_ok word 88
+ * 1: eide_ok words 64-70
+ * 0: cur_ok words 54-58
+ */
+ unsigned short cur_cyls; /* Obsolete, logical cylinders */
+ unsigned short cur_heads; /* Obsolete, l heads */
+ unsigned short cur_sectors; /* Obsolete, l sectors per track */
+ unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */
+ unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */
+ unsigned char multsect; /* current multiple sector count */
+ unsigned char multsect_valid; /* when (bit0==1) multsect is ok */
+ unsigned int lba_capacity; /* Obsolete, total number of sectors */
+ unsigned short dma_1word; /* Obsolete, single-word dma info */
+ unsigned short dma_mword; /* multiple-word dma info */
+ unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */
+ unsigned short eide_dma_min; /* min mword dma cycle time (ns) */
+ unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */
+ unsigned short eide_pio; /* min cycle time (ns), no IORDY */
+ unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */
+ unsigned short words69_70[2]; /* reserved words 69-70
+ * future command overlap and queuing
+ */
+ /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+ unsigned short words71_74[4]; /* reserved words 71-74
+ * for IDENTIFY PACKET DEVICE command
+ */
+ unsigned short queue_depth; /* (word 75)
+ * 15:5 reserved
+ * 4:0 Maximum queue depth -1
+ */
+ unsigned short words76_79[4]; /* reserved words 76-79 */
+ unsigned short major_rev_num; /* (word 80) */
+ unsigned short minor_rev_num; /* (word 81) */
+ unsigned short command_set_1; /* (word 82) supported
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ unsigned short command_set_2; /* (word 83)
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ unsigned short cfsse; /* (word 84)
+ * cmd set-feature supported extensions
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:6 reserved
+ * 5: General Purpose Logging
+ * 4: Streaming Feature Set
+ * 3: Media Card Pass Through
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ unsigned short cfs_enable_1; /* (word 85)
+ * command set-feature enabled
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ unsigned short cfs_enable_2; /* (word 86)
+ * command set-feature enabled
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ unsigned short csf_default; /* (word 87)
+ * command set-feature default
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:6 reserved
+ * 5: General Purpose Logging enabled
+ * 4: Valid CONFIGURE STREAM executed
+ * 3: Media Card Pass Through enabled
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ unsigned short dma_ultra; /* (word 88) */
+ unsigned short trseuc; /* time required for security erase */
+ unsigned short trsEuc; /* time required for enhanced erase */
+ unsigned short CurAPMvalues; /* current APM values */
+ unsigned short mprc; /* master password revision code */
+ unsigned short hw_config; /* hardware config (word 93)
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:
+ * 12:
+ * 11:
+ * 10:
+ * 9:
+ * 8:
+ * 7:
+ * 6:
+ * 5:
+ * 4:
+ * 3:
+ * 2:
+ * 1:
+ * 0: Shall be ONE
+ */
+ unsigned short acoustic; /* (word 94)
+ * 15:8 Vendor's recommended value
+ * 7:0 current value
+ */
+ unsigned short msrqs; /* min stream request size */
+ unsigned short sxfert; /* stream transfer time */
+ unsigned short sal; /* stream access latency */
+ unsigned int spg; /* stream performance granularity */
+ unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+ unsigned short words104_125[22];/* reserved words 104-125 */
+ unsigned short last_lun; /* (word 126) */
+ unsigned short word127; /* (word 127) Feature Set
+ * Removable Media Notification
+ * 15:2 reserved
+ * 1:0 00 = not supported
+ * 01 = supported
+ * 10 = reserved
+ * 11 = reserved
+ */
+ unsigned short dlf; /* (word 128)
+ * device lock function
+ * 15:9 reserved
+ * 8 security level 1:max 0:high
+ * 7:6 reserved
+ * 5 enhanced erase
+ * 4 expire
+ * 3 frozen
+ * 2 locked
+ * 1 en/disabled
+ * 0 capability
+ */
+ unsigned short csfo; /* (word 129)
+ * current set features options
+ * 15:4 reserved
+ * 3: auto reassign
+ * 2: reverting
+ * 1: read-look-ahead
+ * 0: write cache
+ */
+ unsigned short words130_155[26];/* reserved vendor words 130-155 */
+ unsigned short word156; /* reserved vendor word 156 */
+ unsigned short words157_159[3];/* reserved vendor words 157-159 */
+ unsigned short cfa_power; /* (word 160) CFA Power Mode
+ * 15 word 160 supported
+ * 14 reserved
+ * 13
+ * 12
+ * 11:0
+ */
+ unsigned short words161_175[15];/* Reserved for CFA */
+ unsigned short words176_205[30];/* Current Media Serial Number */
+ unsigned short words206_254[49];/* reserved words 206-254 */
+ unsigned short integrity_word; /* (word 255)
+ * 15:8 Checksum
+ * 7:0 Signature
+ */
+};
+
+struct request_sense {
+#if defined(CONFIG_BIG_ENDIAN)
+ u8 valid : 1;
+ u8 error_code : 7;
+#elif defined(CONFIG_LITTLE_ENDIAN)
+ u8 error_code : 7;
+ u8 valid : 1;
+#endif
+ u8 segment_number;
+#if defined(CONFIG_BIG_ENDIAN)
+ u8 reserved1 : 2;
+ u8 ili : 1;
+ u8 reserved2 : 1;
+ u8 sense_key : 4;
+#elif defined(CONFIG_LITTLE_ENDIAN)
+ u8 sense_key : 4;
+ u8 reserved2 : 1;
+ u8 ili : 1;
+ u8 reserved1 : 2;
+#endif
+ u8 information[4];
+ u8 add_sense_len;
+ u8 command_info[4];
+ u8 asc;
+ u8 ascq;
+ u8 fruc;
+ u8 sks[3];
+ u8 asb[46];
+};
+
+struct atapi_capacity {
+ u32 lba;
+ u32 block_size;
+};
+
+#endif
Modified: trunk/filo/drivers/ide.c
===================================================================
--- trunk/filo/drivers/ide.c 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/drivers/ide.c 2009-03-11 03:07:08 UTC (rev 86)
@@ -1132,6 +1132,11 @@
if (hdr == HEADER_TYPE_BRIDGE || hdr == HEADER_TYPE_CARDBUS) {
unsigned int new_bus;
new_bus = (pci_read_config32(currdev, REG_PRIMARY_BUS) >> 8) & 0xff;
+ if (new_bus == 0) {
+ debug("Misconfigured bridge at %02x:%02x.%02x skipped.\n",
+ bus, slot, func);
+ continue;
+ }
if (pci_find_ata_device_on_bus(new_bus, dev, index, sata, pata))
return 1;
}
Added: trunk/filo/drivers/ide_new.c
===================================================================
--- trunk/filo/drivers/ide_new.c (rev 0)
+++ trunk/filo/drivers/ide_new.c 2009-03-11 03:07:08 UTC (rev 86)
@@ -0,0 +1,1302 @@
+/*
+ * OpenBIOS polled ide driver
+ *
+ * Copyright (C) 2004 Jens Axboe <axboe at suse.de>
+ * Copyright (C) 2005 Stefan Reinauer <stepan at openbios.org>
+ *
+ * Credit goes to Hale Landis for his excellent ata demo software
+ * OF node handling and some fixes by Stefan Reinauer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+/*
+ * TODO:
+ * - Really probe for interfaces, don't just rely on legacy
+ */
+
+#define GRUB
+
+#include <libpayload.h>
+#include <config.h>
+#include <arch/byteorder.h>
+
+#include <fs.h>
+#include <debug.h>
+#include "ide_new.h"
+#include "hdreg.h"
+
+#if 0
+#define dprintf printf
+#else
+#define dprintf(x...)
+#endif
+
+/*
+ * define to 2 for the standard 2 channels only
+ */
+#ifndef CONFIG_IDE_NUM_CHANNELS
+#define IDE_NUM_CHANNELS 4
+#else
+#define IDE_NUM_CHANNELS CONFIG_IDE_NUM_CHANNELS
+#endif
+#define IDE_MAX_CHANNELS 4
+
+static struct ide_channel ob_ide_channels[IDE_MAX_CHANNELS];
+
+/*
+ * FIXME: probe, we just hardwire legacy ports for now
+ */
+static const int io_ports[IDE_MAX_CHANNELS] = { 0x1f0, 0x170, 0x1e8, 0x168 };
+static const int ctl_ports[IDE_MAX_CHANNELS] = { 0x3f6, 0x376, 0x3ee, 0x36e };
+
+/*
+ * don't be pedantic
+ */
+#undef ATA_PEDANTIC
+
+static void dump_drive(struct ide_drive *drive)
+{
+#ifdef CONFIG_DEBUG_IDE
+ printk("IDE DRIVE @%lx:\n", (unsigned long)drive);
+ printk("unit: %d\n",drive->unit);
+ printk("present: %d\n",drive->present);
+ printk("type: %d\n",drive->type);
+ printk("media: %d\n",drive->media);
+ printk("model: %s\n",drive->model);
+ printk("nr: %d\n",drive->nr);
+ printk("cyl: %d\n",drive->cyl);
+ printk("head: %d\n",drive->head);
+ printk("sect: %d\n",drive->sect);
+ printk("bs: %d\n",drive->bs);
+#endif
+}
+
+/*
+ * old style io port operations
+ */
+static unsigned char
+ob_ide_inb(unsigned long port)
+{
+ return inb(port);
+}
+
+static void
+ob_ide_outb(unsigned char data, unsigned long port)
+{
+ outb(data, port);
+}
+
+static void
+ob_ide_insw(unsigned long port, unsigned char *addr, unsigned int count)
+{
+ insw(port, addr, count);
+}
+
+static void
+ob_ide_outsw(unsigned long port, unsigned char *addr, unsigned int count)
+{
+ outsw(port, addr, count);
+}
+
+static inline unsigned char
+ob_ide_pio_readb(struct ide_drive *drive, unsigned int offset)
+{
+ struct ide_channel *chan = drive->channel;
+
+ return chan->obide_inb(chan->io_regs[offset]);
+}
+
+static inline void
+ob_ide_pio_writeb(struct ide_drive *drive, unsigned int offset,
+ unsigned char data)
+{
+ struct ide_channel *chan = drive->channel;
+
+ chan->obide_outb(data, chan->io_regs[offset]);
+}
+
+static inline void
+ob_ide_pio_insw(struct ide_drive *drive, unsigned int offset,
+ unsigned char *addr, unsigned int len)
+{
+ struct ide_channel *chan = drive->channel;
+
+ if (len & 1) {
+ printf("%d: command not word aligned\n", drive->nr);
+ return;
+ }
+
+ chan->obide_insw(chan->io_regs[offset], addr, len / 2);
+}
+
+static inline void
+ob_ide_pio_outsw(struct ide_drive *drive, unsigned int offset,
+ unsigned char *addr, unsigned int len)
+{
+ struct ide_channel *chan = drive->channel;
+
+ if (len & 1) {
+ printf("%d: command not word aligned\n", drive->nr);
+ return;
+ }
+
+ chan->obide_outsw(chan->io_regs[offset], addr, len / 2);
+}
+
+static void
+ob_ide_400ns_delay(struct ide_drive *drive)
+{
+ (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+ (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+ (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+ (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+
+ udelay(1);
+}
+
+static void
+ob_ide_error(struct ide_drive *drive, unsigned char stat, char *msg)
+{
+ struct ide_channel *chan = drive->channel;
+ unsigned char err;
+
+ if (!stat)
+ stat = ob_ide_pio_readb(drive, IDEREG_STATUS);
+
+ printf("ob_ide_error drive<%d>: %s:\n", drive->nr, msg);
+ printf(" cmd=%x, stat=%x", chan->ata_cmd.command, stat);
+
+ if ((stat & (BUSY_STAT | ERR_STAT)) == ERR_STAT) {
+ err = ob_ide_pio_readb(drive, IDEREG_ERROR);
+ printf(", err=%x", err);
+ }
+ printf("\n");
+
+ /*
+ * see if sense is valid and dump that
+ */
+ if (chan->ata_cmd.command == WIN_PACKET) {
+ struct atapi_command *cmd = &chan->atapi_cmd;
+ unsigned char old_cdb = cmd->cdb[0];
+
+ if (cmd->cdb[0] == ATAPI_REQ_SENSE) {
+ old_cdb = cmd->old_cdb;
+
+ printf(" atapi opcode=%02x", old_cdb);
+ } else {
+ int i;
+
+ printf(" cdb: ");
+ for (i = 0; i < sizeof(cmd->cdb); i++)
+ printf("%02x ", cmd->cdb[i]);
+ }
+ if (cmd->sense_valid)
+ printf(", sense: %02x/%02x/%02x", cmd->sense.sense_key, cmd->sense.asc, cmd->sense.ascq);
+ else
+ printf(", no sense");
+ printf("\n");
+ }
+}
+
+/*
+ * wait for 'stat' to be set. returns 1 if failed, 0 if succesful
+ */
+static int
+ob_ide_wait_stat(struct ide_drive *drive, unsigned char ok_stat,
+ unsigned char bad_stat, unsigned char *ret_stat)
+{
+ unsigned char stat;
+ int i;
+
+ ob_ide_400ns_delay(drive);
+
+ for (i = 0; i < 5000; i++) {
+ stat = ob_ide_pio_readb(drive, IDEREG_STATUS);
+ if (!(stat & BUSY_STAT))
+ break;
+
+ udelay(1000);
+ }
+
+ if (ret_stat)
+ *ret_stat = stat;
+
+ if (stat & bad_stat)
+ return 1;
+
+ if ((stat & ok_stat) || !ok_stat)
+ return 0;
+
+ return 1;
+}
+
+static int
+ob_ide_select_drive(struct ide_drive *drive)
+{
+ struct ide_channel *chan = drive->channel;
+ unsigned char control = IDEHEAD_DEV0;
+
+ if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) {
+ printf("select_drive: timed out\n");
+ return 1;
+ }
+
+ /*
+ * don't select drive if already active. Note: we always
+ * wait for BUSY clear
+ */
+ if (drive->unit == chan->selected)
+ return 0;
+
+ if (drive->unit)
+ control = IDEHEAD_DEV1;
+
+ ob_ide_pio_writeb(drive, IDEREG_CURRENT, control);
+ ob_ide_400ns_delay(drive);
+
+ if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) {
+ printf("select_drive: timed out\n");
+ return 1;
+ }
+
+ chan->selected = drive->unit;
+ return 0;
+}
+
+static void
+ob_ide_write_tasklet(struct ide_drive *drive, struct ata_command *cmd)
+{
+ ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[1]);
+ ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[3]);
+ ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[7]);
+ ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[8]);
+ ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[9]);
+
+ ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[0]);
+ ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[2]);
+ ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[4]);
+ ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[5]);
+ ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[6]);
+
+ if (drive->unit)
+ cmd->device_head |= IDEHEAD_DEV1;
+
+ ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head);
+
+ ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command);
+ ob_ide_400ns_delay(drive);
+}
+
+static void
+ob_ide_write_registers(struct ide_drive *drive, struct ata_command *cmd)
+{
+ /*
+ * we are _always_ polled
+ */
+ ob_ide_pio_writeb(drive, IDEREG_CONTROL, cmd->control | IDECON_NIEN);
+
+ ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->feature);
+ ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->nsector);
+ ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->sector);
+ ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->lcyl);
+ ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->hcyl);
+
+ if (drive->unit)
+ cmd->device_head |= IDEHEAD_DEV1;
+
+ ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head);
+
+ ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command);
+ ob_ide_400ns_delay(drive);
+}
+
+/*
+ * execute given command with a pio data-in phase.
+ */
+static int
+ob_ide_pio_data_in(struct ide_drive *drive, struct ata_command *cmd)
+{
+ unsigned char stat;
+ unsigned int bytes, timeout;
+
+ if (ob_ide_select_drive(drive))
+ return 1;
+
+ /*
+ * ATA must set ready and seek stat, ATAPI need only clear busy
+ */
+ timeout = 0;
+ do {
+ stat = ob_ide_pio_readb(drive, IDEREG_STATUS);
+
+ if (drive->type == ide_type_ata) {
+ /*
+ * this is BIOS code, don't be too pedantic
+ */
+#ifdef ATA_PEDANTIC
+ if ((stat & (BUSY_STAT | READY_STAT | SEEK_STAT)) ==
+ (READY_STAT | SEEK_STAT))
+ break;
+#else
+ if ((stat & (BUSY_STAT | READY_STAT)) == READY_STAT)
+ break;
+#endif
+ } else {
+ if (!(stat & BUSY_STAT))
+ break;
+ }
+ ob_ide_400ns_delay(drive);
+ } while (timeout++ < 1000);
+
+ if (timeout >= 1000) {
+ ob_ide_error(drive, stat, "drive timed out");
+ cmd->stat = stat;
+ return 1;
+ }
+
+ ob_ide_write_registers(drive, cmd);
+
+ /*
+ * now read the data
+ */
+ bytes = cmd->buflen;
+ do {
+ unsigned count = cmd->buflen;
+
+ if (count > drive->bs)
+ count = drive->bs;
+
+ /* delay 100ms for ATAPI? */
+
+ /*
+ * wait for BUSY clear
+ */
+ if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) {
+ ob_ide_error(drive, stat, "timed out waiting for BUSY clear");
+ cmd->stat = stat;
+ break;
+ }
+
+ /*
+ * transfer the data
+ */
+ if ((stat & (BUSY_STAT | DRQ_STAT)) == DRQ_STAT) {
+ ob_ide_pio_insw(drive, IDEREG_DATA, cmd->buffer, count);
+ cmd->bytes -= count;
+ cmd->buffer += count;
+ bytes -= count;
+
+ ob_ide_400ns_delay(drive);
+ }
+
+ if (stat & (BUSY_STAT | WRERR_STAT | ERR_STAT)) {
+ cmd->stat = stat;
+ break;
+ }
+
+ if (!(stat & DRQ_STAT)) {
+ cmd->stat = stat;
+ break;
+ }
+ } while (bytes);
+
+ if (bytes)
+ printf("bytes=%d, stat=%x\n", bytes, stat);
+
+ return bytes ? 1 : 0;
+}
+
+/*
+ * execute ata command with pio packet protocol
+ */
+static int
+ob_ide_pio_packet(struct ide_drive *drive, struct atapi_command *cmd)
+{
+ unsigned char stat, reason, lcyl, hcyl;
+ struct ata_command *acmd = &drive->channel->ata_cmd;
+ unsigned char *buffer;
+ unsigned int bytes;
+
+ if (ob_ide_select_drive(drive))
+ return 1;
+
+ if (cmd->buflen && cmd->data_direction == atapi_ddir_none)
+ printf("non-zero buflen but no data direction\n");
+
+ memset(acmd, 0, sizeof(*acmd));
+ acmd->lcyl = cmd->buflen & 0xff;
+ acmd->hcyl = (cmd->buflen >> 8) & 0xff;
+ acmd->command = WIN_PACKET;
+ ob_ide_write_registers(drive, acmd);
+
+ /*
+ * BUSY must be set, _or_ DRQ | ERR
+ */
+ stat = ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+ if ((stat & BUSY_STAT) == 0) {
+ if (!(stat & (DRQ_STAT | ERR_STAT))) {
+ ob_ide_error(drive, stat, "bad stat in atapi cmd");
+ cmd->stat = stat;
+ return 1;
+ }
+ }
+
+ if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) {
+ ob_ide_error(drive, stat, "timeout, ATAPI BUSY clear");
+ cmd->stat = stat;
+ return 1;
+ }
+
+ if ((stat & (BUSY_STAT | DRQ_STAT | ERR_STAT)) != DRQ_STAT) {
+ /*
+ * if command isn't request sense, then we have a problem. if
+ * we are doing a sense, ERR_STAT == CHECK_CONDITION
+ */
+ if (cmd->cdb[0] != ATAPI_REQ_SENSE) {
+ printf("odd, drive didn't want to transfer %x\n", stat);
+ return 1;
+ }
+ }
+
+ /*
+ * transfer cdb
+ */
+ ob_ide_pio_outsw(drive, IDEREG_DATA, cmd->cdb,sizeof(cmd->cdb));
+ ob_ide_400ns_delay(drive);
+
+ /*
+ * ok, cdb was sent to drive, now do data transfer (if any)
+ */
+ bytes = cmd->buflen;
+ buffer = cmd->buffer;
+ do {
+ unsigned int bc;
+
+ if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) {
+ ob_ide_error(drive, stat, "busy not clear after cdb");
+ cmd->stat = stat;
+ break;
+ }
+
+ /*
+ * transfer complete!
+ */
+ if ((stat & (BUSY_STAT | DRQ_STAT)) == 0)
+ break;
+
+ if ((stat & (BUSY_STAT | DRQ_STAT)) != DRQ_STAT)
+ break;
+
+ reason = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+ lcyl = ob_ide_pio_readb(drive, IDEREG_LCYL);
+ hcyl = ob_ide_pio_readb(drive, IDEREG_HCYL);
+
+ /*
+ * check if the drive wants to transfer data in the same
+ * direction as we do...
+ */
+ if ((reason & IREASON_CD) && cmd->data_direction != atapi_ddir_read) {
+ ob_ide_error(drive, stat, "atapi, bad transfer ddir");
+ break;
+ }
+
+ bc = (hcyl << 8) | lcyl;
+ if (!bc)
+ break;
+
+ if (bc > bytes)
+ bc = bytes;
+
+ if (cmd->data_direction == atapi_ddir_read)
+ ob_ide_pio_insw(drive, IDEREG_DATA, buffer, bc);
+ else
+ ob_ide_pio_outsw(drive, IDEREG_DATA, buffer, bc);
+
+ bytes -= bc;
+ buffer += bc;
+
+ ob_ide_400ns_delay(drive);
+ } while (bytes);
+
+ if (cmd->data_direction != atapi_ddir_none)
+ (void) ob_ide_wait_stat(drive, 0, BUSY_STAT, &stat);
+
+ if (bytes)
+ printf("cdb failed, bytes=%d, stat=%x\n", bytes, stat);
+
+ return (stat & ERR_STAT) || bytes;
+}
+
+/*
+ * execute a packet command, with retries if appropriate
+ */
+static int
+ob_ide_atapi_packet(struct ide_drive *drive, struct atapi_command *cmd)
+{
+ int retries = 5, ret;
+
+ if (drive->type != ide_type_atapi)
+ return 1;
+ if (cmd->buflen > 0xffff)
+ return 1;
+
+ /*
+ * retry loop
+ */
+ do {
+ ret = ob_ide_pio_packet(drive, cmd);
+ if (!ret)
+ break;
+
+ /*
+ * request sense failed, bummer
+ */
+ if (cmd->cdb[0] == ATAPI_REQ_SENSE)
+ break;
+
+ if (ob_ide_atapi_request_sense(drive))
+ break;
+
+ /*
+ * we know sense is valid. retry if the drive isn't ready,
+ * otherwise don't bother.
+ */
+ if (cmd->sense.sense_key != ATAPI_SENSE_NOT_READY)
+ break;
+ /*
+ * ... except 'medium not present'
+ */
+ if (cmd->sense.asc == 0x3a)
+ break;
+
+ udelay(1000000);
+ } while (retries--);
+
+ if (ret)
+ ob_ide_error(drive, 0, "atapi command");
+
+ return ret;
+}
+
+static int
+ob_ide_atapi_request_sense(struct ide_drive *drive)
+{
+ struct atapi_command *cmd = &drive->channel->atapi_cmd;
+ unsigned char old_cdb;
+
+ /*
+ * save old cdb for debug error
+ */
+ old_cdb = cmd->cdb[0];
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->cdb[0] = ATAPI_REQ_SENSE;
+ cmd->cdb[4] = 18;
+ cmd->buffer = (unsigned char *) &cmd->sense;
+ cmd->buflen = 18;
+ cmd->data_direction = atapi_ddir_read;
+ cmd->old_cdb = old_cdb;
+
+ if (ob_ide_atapi_packet(drive, cmd))
+ return 1;
+
+ cmd->sense_valid = 1;
+ return 0;
+}
+
+/*
+ * make sure drive is ready and media loaded
+ */
+static int
+ob_ide_atapi_drive_ready(struct ide_drive *drive)
+{
+ struct atapi_command *cmd = &drive->channel->atapi_cmd;
+ struct atapi_capacity cap;
+
+ /*
+ * Test Unit Ready is like a ping
+ */
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->cdb[0] = ATAPI_TUR;
+
+ if (ob_ide_atapi_packet(drive, cmd)) {
+ printf("%d: TUR failed\n", drive->nr);
+ return 1;
+ }
+
+ /*
+ * don't force load of tray (bit 2 in byte 4 of cdb), it's
+ * annoying and we don't want to deal with errors from drives
+ * that cannot do it
+ */
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->cdb[0] = ATAPI_START_STOP_UNIT;
+ cmd->cdb[4] = 0x01;
+
+ if (ob_ide_atapi_packet(drive, cmd)) {
+ printf("%d: START_STOP unit failed\n", drive->nr);
+ return 1;
+ }
+
+ /*
+ * finally, get capacity and block size
+ */
+ memset(cmd, 0, sizeof(*cmd));
+ memset(&cap, 0, sizeof(cap));
+
+ cmd->cdb[0] = ATAPI_READ_CAPACITY;
+ cmd->buffer = (unsigned char *) ∩
+ cmd->buflen = sizeof(cap);
+ cmd->data_direction = atapi_ddir_read;
+
+ if (ob_ide_atapi_packet(drive, cmd)) {
+ drive->sectors = 0x1fffff;
+ drive->bs = 2048;
+ return 1;
+ }
+
+ drive->sectors = __be32_to_cpu(cap.lba) + 1;
+ drive->bs = __be32_to_cpu(cap.block_size);
+ return 0;
+}
+
+/*
+ * read from an atapi device, using READ_10
+ */
+static int
+ob_ide_read_atapi(struct ide_drive *drive, unsigned long long block, char *buf,
+ unsigned int sectors)
+{
+ struct atapi_command *cmd = &drive->channel->atapi_cmd;
+
+ if (ob_ide_atapi_drive_ready(drive))
+ return 1;
+
+ memset(cmd, 0, sizeof(*cmd));
+
+ /*
+ * READ_10 should work on generally any atapi device
+ */
+ cmd->cdb[0] = ATAPI_READ_10;
+ cmd->cdb[2] = (block >> 24) & 0xff;
+ cmd->cdb[3] = (block >> 16) & 0xff;
+ cmd->cdb[4] = (block >> 8) & 0xff;
+ cmd->cdb[5] = block & 0xff;
+ cmd->cdb[7] = (sectors >> 8) & 0xff;
+ cmd->cdb[8] = sectors & 0xff;
+
+ cmd->buffer = buf;
+ cmd->buflen = sectors * 2048;
+ cmd->data_direction = atapi_ddir_read;
+
+ return ob_ide_atapi_packet(drive, cmd);
+}
+
+static int
+ob_ide_read_ata_chs(struct ide_drive *drive, unsigned long long block,
+ char *buf, unsigned int sectors)
+{
+ struct ata_command *cmd = &drive->channel->ata_cmd;
+ unsigned int track = (block / drive->sect);
+ unsigned int sect = (block % drive->sect) + 1;
+ unsigned int head = (track % drive->head);
+ unsigned int cyl = (track / drive->head);
+ struct ata_sector ata_sector;
+
+ /*
+ * fill in chs command to read from disk at given location
+ */
+ cmd->buffer = buf;
+ cmd->buflen = sectors * 512;
+
+ ata_sector.all = sectors;
+ cmd->nsector = ata_sector.low;
+ cmd->sector = sect;
+ cmd->lcyl = cyl;
+ cmd->hcyl = cyl >> 8;
+ cmd->device_head = head;
+
+ cmd->command = WIN_READ;
+
+ return ob_ide_pio_data_in(drive, cmd);
+}
+
+static int
+ob_ide_read_ata_lba28(struct ide_drive *drive, unsigned long long block,
+ char *buf, unsigned int sectors)
+{
+ struct ata_command *cmd = &drive->channel->ata_cmd;
+
+ memset(cmd, 0, sizeof(*cmd));
+
+ /*
+ * fill in 28-bit lba command to read from disk at given location
+ */
+ cmd->buffer = buf;
+ cmd->buflen = sectors * 512;
+
+ cmd->nsector = sectors;
+ cmd->sector = block;
+ cmd->lcyl = block >>= 8;
+ cmd->hcyl = block >>= 8;
+ cmd->device_head = ((block >> 8) & 0x0f);
+ cmd->device_head |= (1 << 6);
+
+ cmd->command = WIN_READ;
+
+ return ob_ide_pio_data_in(drive, cmd);
+}
+
+static int
+ob_ide_read_ata_lba48(struct ide_drive *drive, unsigned long long block,
+ char *buf, unsigned int sectors)
+{
+ struct ata_command *cmd = &drive->channel->ata_cmd;
+ struct ata_sector ata_sector;
+
+ memset(cmd, 0, sizeof(*cmd));
+
+ cmd->buffer = buf;
+ cmd->buflen = sectors * 512;
+ ata_sector.all = sectors;
+
+ /*
+ * we are using tasklet addressing here
+ */
+ cmd->task[2] = ata_sector.low;
+ cmd->task[3] = ata_sector.high;
+ cmd->task[4] = block;
+ cmd->task[5] = block >> 8;
+ cmd->task[6] = block >> 16;
+ cmd->task[7] = block >> 24;
+ cmd->task[8] = (u64) block >> 32;
+ cmd->task[9] = (u64) block >> 40;
+
+ cmd->command = WIN_READ_EXT;
+
+ ob_ide_write_tasklet(drive, cmd);
+
+ return ob_ide_pio_data_in(drive, cmd);
+}
+/*
+ * read 'sectors' sectors from ata device
+ */
+static int
+ob_ide_read_ata(struct ide_drive *drive, unsigned long long block, char *buf,
+ unsigned int sectors)
+{
+ unsigned long long end_block = block + sectors;
+ const int need_lba48 = (end_block > (1ULL << 28)) || (sectors > 255);
+
+ if (end_block > drive->sectors)
+ return 1;
+ if (need_lba48 && drive->addressing != ide_lba48)
+ return 1;
+
+ /*
+ * use lba48 if we have to, otherwise use the faster lba28
+ */
+ if (need_lba48)
+ return ob_ide_read_ata_lba48(drive, block, buf, sectors);
+ else if (drive->addressing != ide_chs)
+ return ob_ide_read_ata_lba28(drive, block, buf, sectors);
+
+ return ob_ide_read_ata_chs(drive, block, buf, sectors);
+}
+
+static int
+ob_ide_read_sectors(struct ide_drive *drive, unsigned long long block,
+ char *buf, unsigned int sectors)
+{
+ if (!sectors)
+ return 1;
+ if (block + sectors > drive->sectors)
+ return 1;
+
+#ifdef CONFIG_DEBUG_IDE
+ printf("ob_ide_read_sectors: block=%Ld sectors=%u\n", (unsigned long) block, sectors);
+#endif
+
+ if (drive->type == ide_type_ata)
+ return ob_ide_read_ata(drive, block, buf, sectors);
+ else
+ return ob_ide_read_atapi(drive, block, buf, sectors);
+}
+
+/*
+ * byte swap the string if necessay, and strip leading/trailing blanks
+ */
+static void
+ob_ide_fixup_string(unsigned char *s, unsigned int len)
+{
+ unsigned char *p = s, *end = &s[len & ~1];
+
+ /*
+ * if little endian arch, byte swap the string
+ */
+#ifdef CONFIG_LITTLE_ENDIAN
+ for (p = end ; p != s;) {
+ unsigned short *pp = (unsigned short *) (p -= 2);
+ *pp = __be16_to_cpu(*pp);
+ }
+#endif
+
+ while (s != end && *s == ' ')
+ ++s;
+ while (s != end && *s)
+ if (*s++ != ' ' || (s != end && *s && *s != ' '))
+ *p++ = *(s-1);
+ while (p != end)
+ *p++ = '\0';
+}
+
+/*
+ * it's big endian, we need to swap (if on little endian) the items we use
+ */
+static int
+ob_ide_fixup_id(struct hd_driveid *id)
+{
+ ob_ide_fixup_string(id->model, 40);
+ id->config = __le16_to_cpu(id->config);
+ id->lba_capacity = __le32_to_cpu(id->lba_capacity);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->heads = __le16_to_cpu(id->heads);
+ id->sectors = __le16_to_cpu(id->sectors);
+ id->command_set_2 = __le16_to_cpu(id->command_set_2);
+ id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2);
+
+ return 0;
+}
+
+static int
+ob_ide_identify_drive(struct ide_drive *drive)
+{
+ struct ata_command *cmd = &drive->channel->ata_cmd;
+ struct hd_driveid id;
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->buffer = (unsigned char *) &id;
+ cmd->buflen = 512;
+
+ if (drive->type == ide_type_ata)
+ cmd->command = WIN_IDENTIFY;
+ else if (drive->type == ide_type_atapi)
+ cmd->command = WIN_IDENTIFY_PACKET;
+ else {
+ printf("%s: called with bad device type %d\n", __FUNCTION__, drive->type);
+ return 1;
+ }
+
+ if (ob_ide_pio_data_in(drive, cmd))
+ return 1;
+
+ ob_ide_fixup_id(&id);
+
+ if (drive->type == ide_type_atapi) {
+ drive->media = (id.config >> 8) & 0x1f;
+ drive->sectors = 0x7fffffff;
+ drive->bs = 2048;
+ drive->max_sectors = 31;
+ } else {
+ drive->media = ide_media_disk;
+ drive->sectors = id.lba_capacity;
+ drive->bs = 512;
+ drive->max_sectors = 255;
+
+#ifdef CONFIG_IDE_LBA48
+ if ((id.command_set_2 & 0x0400) && (id.cfs_enable_2 & 0x0400)) {
+ drive->addressing = ide_lba48;
+ drive->max_sectors = 65535;
+ } else
+#endif
+ if (id.capability & 2)
+ drive->addressing = ide_lba28;
+ else {
+ drive->addressing = ide_chs;
+ }
+
+ /* only set these in chs mode? */
+ drive->cyl = id.cyls;
+ drive->head = id.heads;
+ drive->sect = id.sectors;
+ }
+
+ strcpy(drive->model, id.model);
+ return 0;
+}
+
+/*
+ * identify type of devices on channel. must have already been probed.
+ */
+static void
+ob_ide_identify_drives(struct ide_channel *chan)
+{
+ struct ide_drive *drive;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ drive = &chan->drives[i];
+
+ if (!drive->present)
+ continue;
+
+ ob_ide_identify_drive(drive);
+ }
+}
+
+/*
+ * software reset (ATA-4, section 8.3)
+ */
+static void
+ob_ide_software_reset(struct ide_drive *drive)
+{
+ struct ide_channel *chan = drive->channel;
+
+ ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN | IDECON_SRST);
+ ob_ide_400ns_delay(drive);
+ ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN);
+ ob_ide_400ns_delay(drive);
+
+ /*
+ * if master is present, wait for BUSY clear
+ */
+ if (chan->drives[0].present)
+ ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL);
+
+ /*
+ * if slave is present, wait until it allows register access
+ */
+ if (chan->drives[1].present) {
+ unsigned char sectorn, sectorc;
+ int timeout = 1000;
+
+ do {
+ /*
+ * select it
+ */
+ ob_ide_pio_writeb(drive, IDEREG_CURRENT, IDEHEAD_DEV1);
+ ob_ide_400ns_delay(drive);
+
+ sectorn = ob_ide_pio_readb(drive, IDEREG_SECTOR);
+ sectorc = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+
+ if (sectorc == 0x01 && sectorn == 0x01)
+ break;
+
+ } while (--timeout);
+ }
+
+ /*
+ * reset done, reselect original device
+ */
+ drive->channel->selected = -1;
+ ob_ide_select_drive(drive);
+}
+
+/*
+ * this serves as both a device check, and also to verify that the drives
+ * we initially "found" are really there
+ */
+static void
+ob_ide_device_type_check(struct ide_drive *drive)
+{
+ unsigned char sc, sn, cl, ch, st;
+
+ if (ob_ide_select_drive(drive))
+ return;
+
+ sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+ sn = ob_ide_pio_readb(drive, IDEREG_SECTOR);
+
+ if (sc == 0x01 && sn == 0x01) {
+ /*
+ * read device signature
+ */
+ cl = ob_ide_pio_readb(drive, IDEREG_LCYL);
+ ch = ob_ide_pio_readb(drive, IDEREG_HCYL);
+ st = ob_ide_pio_readb(drive, IDEREG_STATUS);
+ if (cl == 0x14 && ch == 0xeb)
+ drive->type = ide_type_atapi;
+ else if (cl == 0x00 && ch == 0x00 && st != 0x00)
+ drive->type = ide_type_ata;
+ else
+ drive->present = 0;
+ } else
+ drive->present = 0;
+}
+
+/*
+ * pure magic
+ */
+static void
+ob_ide_device_check(struct ide_drive *drive)
+{
+ unsigned char sc, sn;
+
+ /*
+ * non-existing io port should return 0xff, don't probe this
+ * channel at all then
+ */
+ if (ob_ide_pio_readb(drive, IDEREG_STATUS) == 0xff) {
+ drive->channel->present = 0;
+ return;
+ }
+
+ if (ob_ide_select_drive(drive))
+ return;
+
+ ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55);
+ ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa);
+ ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0xaa);
+ ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0x55);
+ ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55);
+ ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa);
+
+ sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+ sn = ob_ide_pio_readb(drive, IDEREG_SECTOR);
+
+ /*
+ * we _think_ the device is there, we will make sure later
+ */
+ if (sc == 0x55 && sn == 0xaa) {
+ drive->present = 1;
+ drive->type = ide_type_unknown;
+ }
+}
+
+/*
+ * probe the legacy ide ports and find attached devices.
+ */
+static void
+ob_ide_probe(struct ide_channel *chan)
+{
+ struct ide_drive *drive;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ drive = &chan->drives[i];
+
+ ob_ide_device_check(drive);
+
+ /*
+ * no point in continuing
+ */
+ if (!chan->present)
+ break;
+
+ if (!drive->present)
+ continue;
+
+ /*
+ * select and reset device
+ */
+ if (ob_ide_select_drive(drive))
+ continue;
+
+ ob_ide_software_reset(drive);
+
+ ob_ide_device_type_check(drive);
+ }
+}
+
+/*
+ * The following functions are interfacing with OpenBIOS. They
+ * are device node methods. Thus they have to do proper stack handling.
+ *
+ */
+
+/*
+ * 255 sectors for ata lba28, 65535 for lba48, and 31 sectors for atapi
+ */
+static int
+ob_ide_max_transfer(int *idx)
+{
+ struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]];
+
+ return (drive->max_sectors * drive->bs);
+}
+
+int
+ob_ide_read_blocks(struct ide_drive *drive, int n, u32 blk, char* dest)
+{
+ int cnt = n;
+ while (n) {
+ int len = n;
+ if (len > drive->max_sectors)
+ len = drive->max_sectors;
+
+ dprintf("reading %d sectors from blk %d\n",len, blk);
+ if (ob_ide_read_sectors(drive, blk, dest, len)) {
+ return n-1;
+ }
+ dprintf("done\n");
+
+ dest += len * drive->bs;
+ n -= len;
+ blk += len;
+ }
+
+ return (cnt);
+}
+
+static int
+ob_ide_block_size(int *idx)
+{
+ struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]];
+ return(drive->bs);
+}
+
+//int ob_ide_init(int (*func)(struct ide_drive*))
+int ob_ide_init(void)
+{
+ int i, j;
+
+ for (i = 0; i < IDE_NUM_CHANNELS; i++) {
+ struct ide_channel *chan = &ob_ide_channels[i];
+
+ chan->mmio = 0;
+
+ for (j = 0; j < 8; j++)
+ chan->io_regs[j] = io_ports[i] + j;
+
+ chan->io_regs[8] = ctl_ports[i];
+ chan->io_regs[9] = ctl_ports[i] + 1;
+
+ chan->obide_inb = ob_ide_inb;
+ chan->obide_insw = ob_ide_insw;
+ chan->obide_outb = ob_ide_outb;
+ chan->obide_outsw = ob_ide_outsw;
+
+ chan->selected = -1;
+
+ /*
+ * assume it's there, if not io port dead check will clear
+ */
+ chan->present = 1;
+
+ for (j = 0; j < 2; j++) {
+ chan->drives[j].present = 0;
+ chan->drives[j].unit = j;
+ chan->drives[j].channel = chan;
+ /* init with a decent value */
+ chan->drives[j].bs = 512;
+
+ chan->drives[j].nr = i * 2 + j;
+ }
+
+ ob_ide_probe(chan);
+
+ if (!chan->present)
+ continue;
+
+ ob_ide_identify_drives(chan);
+
+ printf("ata-%d: [io ports 0x%x-0x%x,0x%x]\n", i,
+ chan->io_regs[0], chan->io_regs[0] + 7,
+ chan->io_regs[8]);
+
+ for (j = 0; j < 2; j++) {
+ struct ide_drive *drive = &chan->drives[j];
+ char *media = "UNKNOWN";
+ if (!drive->present)
+ continue;
+ printf(" drive%d [ATA%s ", j, drive->type == ide_type_atapi ? "PI" : "");
+ switch (drive->media) {
+ case ide_media_floppy:
+ media = "floppy";
+ break;
+ case ide_media_cdrom:
+ media = "cdrom";
+ break;
+ case ide_media_optical:
+ media = "mo";
+ break;
+ case ide_media_disk:
+ media = "disk";
+ break;
+ }
+ printf("%s]: %s\n", media, drive->model);
+ }
+
+ }
+
+ return 0;
+}
+
+static int inited=0;
+
+int ide_probe(int drive)
+{
+ struct ide_drive *curr_drive = & ob_ide_channels[drive / 2].drives[drive % 2];
+ if (!inited) {
+ ob_ide_init();
+ inited = 1;
+ }
+
+ if (!curr_drive->present)
+ return -1;
+
+ return 0;
+
+}
+
+int ide_probe_verbose(int drive)
+{
+ struct ide_drive *curr_drive = & ob_ide_channels[drive / 2].drives[drive % 2];
+ char *media = "UNKNOWN";
+
+ if (!inited) {
+ ob_ide_init();
+ inited = 1;
+ }
+
+ if (!curr_drive->present) {
+ return -1;
+ }
+ printf("ata%d %s ", drive / 2, (drive % 2)?"slave ":"master");
+
+
+ printf("[ATA%s ", curr_drive->type == ide_type_atapi ? "PI" : "");
+ switch (curr_drive->media) {
+ case ide_media_floppy:
+ media = "Floppy";
+ break;
+ case ide_media_cdrom:
+ media = "CDROM/DVD";
+ break;
+ case ide_media_optical:
+ media = "MO";
+ break;
+ case ide_media_disk:
+ media = "DISK";
+ break;
+ }
+ printf("%s]: %s\n", media, curr_drive->model);
+
+ return 0;
+}
+
+int ide_read(int drive, sector_t sector, void *buffer)
+{
+ int ret;
+ ret = ob_ide_read_blocks(&ob_ide_channels[drive / 2].drives[drive % 2], 1, sector, buffer);
+ if (ret!=1) { // right now only one block at a time.. bummer
+ return -1;
+ }
+ return 0;
+}
+
+int ide_read_blocks(int drive, sector_t sector, int count, void *buffer)
+{
+ int ret;
+ ret = ob_ide_read_blocks(&ob_ide_channels[drive / 2].drives[drive % 2],
+ count, sector, buffer);
+ if (ret!=count) { // right now only one block at a time.. bummer
+ return -1;
+ }
+ return 0;
+}
Added: trunk/filo/drivers/ide_new.h
===================================================================
--- trunk/filo/drivers/ide_new.h (rev 0)
+++ trunk/filo/drivers/ide_new.h 2009-03-11 03:07:08 UTC (rev 86)
@@ -0,0 +1,233 @@
+#ifndef IDE_H
+#define IDE_H
+
+#include <arch/io.h>
+#include "hdreg.h"
+
+/*
+ * legacy ide ports
+ */
+#define IDEREG_DATA 0x00
+#define IDEREG_ERROR 0x01
+#define IDEREG_FEATURE IDEREG_ERROR
+#define IDEREG_NSECTOR 0x02
+#define IDEREG_SECTOR 0x03
+#define IDEREG_LCYL 0x04
+#define IDEREG_HCYL 0x05
+#define IDEREG_CURRENT 0x06
+#define IDEREG_STATUS 0x07
+#define IDEREG_COMMAND IDEREG_STATUS
+#define IDEREG_CONTROL 0x08
+#define IDEREG_ASTATUS IDEREG_CONTROL
+
+/*
+ * device control bits
+ */
+#define IDECON_NIEN 0x02
+#define IDECON_SRST 0x04
+
+/*
+ * device head bits
+ */
+#define IDEHEAD_LBA 0x40
+#define IDEHEAD_DEV0 0x00
+#define IDEHEAD_DEV1 0x10
+
+/*
+ * status bytes
+ */
+#define ERR_STAT 0x01
+#define DRQ_STAT 0x08
+#define SEEK_STAT 0x10
+#define WRERR_STAT 0x20
+#define READY_STAT 0x40
+#define BUSY_STAT 0x80
+
+#define IREASON_CD 0x01
+#define IREASON_IO 0x02
+
+/*
+ * ATA opcodes
+ */
+#define WIN_READ 0x20
+#define WIN_READ_EXT 0x24
+#define WIN_IDENTIFY 0xEC
+#define WIN_PACKET 0xA0
+#define WIN_IDENTIFY_PACKET 0xA1
+
+/*
+ * ATAPI opcodes
+ */
+#define ATAPI_TUR 0x00
+#define ATAPI_READ_10 0x28
+#define ATAPI_REQ_SENSE 0x03
+#define ATAPI_START_STOP_UNIT 0x1b
+#define ATAPI_READ_CAPACITY 0x25
+
+/*
+ * atapi sense keys
+ */
+#define ATAPI_SENSE_NOT_READY 0x02
+
+/*
+ * supported device types
+ */
+enum {
+ ide_type_unknown,
+ ide_type_ata,
+ ide_type_atapi,
+};
+
+enum {
+ ide_media_floppy = 0x00,
+ ide_media_cdrom = 0x05,
+ ide_media_optical = 0x07,
+ ide_media_disk = 0x20,
+};
+
+/*
+ * drive addressing
+ */
+enum {
+ ide_chs = 1,
+ ide_lba28,
+ ide_lba48,
+};
+
+/*
+ * simple ata command that works for everything (except 48-bit lba commands)
+ */
+struct ata_command {
+ char *buffer;
+ unsigned int buflen;
+
+ /*
+ * data register
+ */
+ unsigned char data;
+ unsigned char feature;
+ unsigned char nsector;
+ unsigned char sector;
+ unsigned char lcyl;
+ unsigned char hcyl;
+ unsigned char device_head;
+ unsigned char command;
+ unsigned char control;
+
+ /*
+ * or tasklet, just for lba48 for now (above could be scrapped)
+ */
+ unsigned char task[10];
+
+ /*
+ * output
+ */
+ unsigned char stat;
+ unsigned int bytes;
+};
+
+struct atapi_command {
+ unsigned char cdb[12];
+ unsigned char *buffer;
+ unsigned int buflen;
+ unsigned char data_direction;
+
+ unsigned char stat;
+ unsigned char sense_valid;
+ struct request_sense sense;
+ unsigned char old_cdb;
+};
+
+struct ide_channel;
+
+struct ide_drive {
+ char unit; /* 0: master, 1: slave */
+ char present; /* there or not */
+ char type; /* ata or atapi */
+ char media; /* disk, cdrom, etc */
+ char addressing; /* chs/lba28/lba48 */
+
+ char model[40]; /* name */
+ int nr;
+
+ unsigned long sectors;
+
+ unsigned int max_sectors;
+
+ /*
+ * for legacy chs crap
+ */
+ unsigned int cyl;
+ unsigned int head;
+ unsigned int sect;
+
+ unsigned int bs; /* block size */
+
+ struct ide_channel *channel;
+};
+
+struct ide_channel {
+ /*
+ * either mmio or io_regs is set to indicate mmio or not
+ */
+ int mmio;
+ int io_regs[10];
+
+ /*
+ * can be set to a mmio hook, default it legacy outb/inb
+ */
+ void (*obide_outb)(unsigned char addr, unsigned long port);
+ unsigned char (*obide_inb)(unsigned long port);
+ void (*obide_insw)(unsigned long port, unsigned char *addr, unsigned int count);
+ void (*obide_outsw)(unsigned long port, unsigned char *addr, unsigned int count);
+
+ struct ide_drive drives[2];
+ char selected;
+ char present;
+
+ /*
+ * only one can be busy per channel
+ */
+ struct ata_command ata_cmd;
+ struct atapi_command atapi_cmd;
+
+};
+
+enum {
+ atapi_ddir_none,
+ atapi_ddir_read,
+ atapi_ddir_write,
+};
+
+struct ata_sector {
+ u16 all;
+ union {
+#ifdef CONFIG_BIG_ENDIAN
+ u8 high;
+ u8 low;
+#endif
+#ifdef CONFIG_LITTLE_ENDIAN
+ u8 low;
+ u8 high;
+#endif
+ };
+};
+
+int
+ob_ide_read_blocks(struct ide_drive *drive, int n, u32 blk, char* dest);
+static int
+ob_ide_atapi_request_sense(struct ide_drive *drive);
+//int ob_ide_init(int (*func)(struct ide_drive*));
+int ob_ide_init(void);
+
+
+/* FILO compat */
+#define CONFIG_LITTLE_ENDIAN
+#define CONFIG_IDE_LBA48
+
+#define __be32_to_cpu be32_to_cpu
+#define __be16_to_cpu be16_to_cpu
+#define __le32_to_cpu le32_to_cpu
+#define __le16_to_cpu le16_to_cpu
+
+#endif
Modified: trunk/filo/drivers/intel.c
===================================================================
--- trunk/filo/drivers/intel.c 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/drivers/intel.c 2009-03-11 03:07:08 UTC (rev 86)
@@ -1,7 +1,7 @@
/*
* This file is part of FILO.
*
- * Copyright (C) 2008 coresystems GmbH
+ * Copyright (C) 2008-2009 coresystems GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,8 +30,10 @@
void platform_poweroff(void)
{
- int pmbase = 0x800;
+ int pmbase;
+ pmbase = pci_read_config16(PCI_DEV(0,0x1f, 0), 0x40) & 0xfffe;
+
/* XXX The sequence is correct; It works fine under Linux.
* Yet, it does not power off the system in FILO.
* Some initialization is missing
Modified: trunk/filo/fs/blockdev.c
===================================================================
--- trunk/filo/fs/blockdev.c 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/fs/blockdev.c 2009-03-11 03:07:08 UTC (rev 86)
@@ -247,7 +247,7 @@
}
switch (type) {
-#ifdef CONFIG_IDE_DISK
+#if defined(CONFIG_IDE_DISK) || defined(CONFIG_IDE_NEW_DISK)
case DISK_IDE:
if (ide_probe(drive) != 0) {
debug("Failed to open IDE.\n");
@@ -384,12 +384,24 @@
if (cache_sect[hash] != sector) {
cache_sect[hash] = (unsigned long) -1;
switch (dev_type) {
-#ifdef CONFIG_IDE_DISK
+#if defined(CONFIG_IDE_DISK)
case DISK_IDE:
if (ide_read(dev_drive, sector, buf) != 0)
goto readerr;
break;
#endif
+#if defined(CONFIG_IDE_NEW_DISK)
+ case DISK_IDE:
+ {
+ int count = (NUM_CACHE-hash>8)?8:(NUM_CACHE-hash);
+ if (ide_read_blocks(dev_drive, sector, count, buf) != 0)
+ goto readerr;
+ while (--count>0) {
+ cache_sect[hash+count] = sector + count;
+ }
+ break;
+ }
+#endif
#if defined(CONFIG_USB_NEW_DISK) && defined(CONFIG_USB)
case DISK_NEW_USB:
{
Modified: trunk/filo/include/fs.h
===================================================================
--- trunk/filo/include/fs.h 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/include/fs.h 2009-03-11 03:07:08 UTC (rev 86)
@@ -27,11 +27,17 @@
#define DEV_SECTOR_SIZE (1<<9)
#define DEV_SECTOR_MASK (DEV_SECTOR_SIZE-1)
-#ifdef CONFIG_IDE_DISK
+#if defined(CONFIG_IDE_DISK)
int ide_probe(int drive);
int ide_read(int drive, sector_t sector, void *buffer);
#endif
+#if defined(CONFIG_IDE_NEW_DISK)
+int ide_probe(int drive);
+int ide_probe_verbose(int drive);
+int ide_read_blocks(const int drive, const sector_t sector, const int size, void *buffer);
+#endif
+
#ifdef CONFIG_USB_DISK
int usb_probe(int drive);
int usb_read(int drive, sector_t sector, void *buffer);
Modified: trunk/filo/main/Makefile.inc
===================================================================
--- trunk/filo/main/Makefile.inc 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/main/Makefile.inc 2009-03-11 03:07:08 UTC (rev 86)
@@ -16,6 +16,7 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
-TARGETS-y += main/filo.o main/elfload.o main/elfnote.o main/ipchecksum.o main/strtox.o
+TARGETS-y += main/filo.o main/strtox.o
+TARGETS-y += main/elfload.o main/elfnote.o main/ipchecksum.o
TARGETS-$(CONFIG_SUPPORT_SOUND) += main/sound.o
Modified: trunk/filo/main/grub/builtins.c
===================================================================
--- trunk/filo/main/grub/builtins.c 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/main/grub/builtins.c 2009-03-11 03:07:08 UTC (rev 86)
@@ -319,6 +319,56 @@
#endif
};
+#if CONFIG_DEVELOPER_TOOLS
+/* default */
+static int dumppm_func(char *arg, int flags)
+{
+ u16 pmbase;
+
+ pmbase = pci_read_config16(PCI_DEV(0,0x1f, 0), 0x40) & 0xfffe;
+
+ grub_printf("pmbase+0x0000: 0x%04x (PM1_STS)\n", inw(pmbase+0x0000));
+ grub_printf("pmbase+0x0002: 0x%04x (PM1_EN)\n", inw(pmbase+0x0002));
+ grub_printf("pmbase+0x0004: 0x%08x (PM1_CNT)\n", inl(pmbase+0x0004));
+ grub_printf("pmbase+0x0008: 0x%08x (PM1_TMR)\n", inl(pmbase+0x0008));
+ grub_printf("pmbase+0x0010: 0x%08x (PROC_CNT)\n", inl(pmbase+0x0010));
+ grub_printf("pmbase+0x0020: 0x%08x (PM2_CNT)\n", inl(pmbase+0x0020));
+ grub_printf("pmbase+0x0028: 0x%08x (GPE0_STS)\n", inl(pmbase+0x0028));
+ grub_printf("pmbase+0x002c: 0x%08x (GPE0_EN)\n", inl(pmbase+0x002c));
+ grub_printf("pmbase+0x0030: 0x%08x (SMI_EN)\n", inl(pmbase+0x0030));
+ grub_printf("pmbase+0x0034: 0x%08x (SMI_STS)\n", inl(pmbase+0x0034));
+ grub_printf("pmbase+0x0038: 0x%04x (ALT_GP_SMI_EN)\n", inw(pmbase+0x0038));
+ grub_printf("pmbase+0x003a: 0x%04x (ALT_GP_SMI_STS)\n", inw(pmbase+0x003a));
+ grub_printf("pmbase+0x0042: 0x%02x (GPE_CNTL)\n", inb(pmbase+0x0042));
+ grub_printf("pmbase+0x0044: 0x%04x (DEVACT_STS)\n", inw(pmbase+0x0044));
+ grub_printf("pmbase+0x0050: 0x%02x (SS_CNT)\n", inb(pmbase+0x0050));
+ grub_printf("pmbase+0x0054: 0x%08x (C3_RES)\n", inl(pmbase+0x0054));
+#if 0
+ // TCO
+ grub_printf("pmbase+0x0060: 0x%04x (TCO_RLD)\n", inw(pmbase+0x0060));
+ grub_printf("pmbase+0x0062: 0x%02x (TCO_DAT_IN)\n", inb(pmbase+0x0062));
+ grub_printf("pmbase+0x0063: 0x%02x (TCO_DAT_OUT)\n", inb(pmbase+0x0063));
+ grub_printf("pmbase+0x0064: 0x%04x (TCO1_STS)\n", inw(pmbase+0x0064));
+ grub_printf("pmbase+0x0066: 0x%04x (TCO2_STS)\n", inw(pmbase+0x0066));
+ grub_printf("pmbase+0x0068: 0x%04x (TCO1_CNT)\n", inw(pmbase+0x0068));
+ grub_printf("pmbase+0x006a: 0x%04x (TCO2_CNT)\n", inw(pmbase+0x006a));
+ grub_printf("pmbase+0x006c: 0x%04x (TCO_MESSAGE)\n", inw(pmbase+0x006c));
+ grub_printf("pmbase+0x006e: 0x%02x (TCO_WDCNT)\n", inb(pmbase+0x006e));
+ grub_printf("pmbase+0x0070: 0x%02x (TCO_SW_IRQ_GEN)\n", inb(pmbase+0x0070));
+ grub_printf("pmbase+0x0072: 0x%04x (TCO_TMR)\n", inw(pmbase+0x0072));
+#endif
+ return 0;
+}
+
+static struct builtin builtin_dumppm = {
+ "dumppm",
+ dumppm_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "dumppm",
+ "Dump Powermanagement registers"
+};
+#endif
+
#if CONFIG_EXPERIMENTAL
#warning "FIND not implemented yet."
/* find */
@@ -1059,11 +1109,16 @@
#ifdef CONFIG_DEVELOPER_TOOLS
static int probe_func(char *arg, int flags)
{
-#if CONFIG_IDE_DISK
+#if CONFIG_IDE_DISK
int i;
for (i=0; i<8; i++)
ide_probe(i);
+#elif CONFIG_IDE_NEW_DISK
+ int i;
+
+ for (i=0; i<8; i++)
+ ide_probe_verbose(i);
#else
grub_printf("No IDE driver.\n");
#endif
@@ -1566,14 +1621,52 @@
#endif
};
+static int cat_func(char *arg, int flags)
+{
+ char buf[4096];
+ int len;
+ temp_space[0]=0;
+ copy_path_to_filo_bootline(arg, temp_space, 1);
+ if (temp_space[0]==0) {
+ return help_func("cat",0);
+ }
+ if (!file_open(temp_space)) {
+ errnum = ERR_FILE_NOT_FOUND;
+ return 1;
+ }
+
+ while ((len = file_read(buf, sizeof(buf))) != 0) {
+ int cnt;
+ for (cnt = 0; cnt < len; cnt++) {
+ grub_putchar(buf[cnt]);
+ }
+ }
+
+ file_close();
+
+ return 0;
+}
+
+static struct builtin builtin_cat = {
+ "cat",
+ cat_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "cat FILENAME",
+ "Print the content of FILENAME to the terminal."
+};
+
/* README !!! XXX !!! This list has to be alphabetically ordered !!! */
struct builtin *builtin_table[] = {
&builtin_boot,
+ &builtin_cat,
&builtin_color,
&builtin_configfile,
&builtin_default,
+#ifdef CONFIG_DEVELOPER_TOOLS
+ &builtin_dumppm,
+#endif
#ifdef CONFIG_EXPERIMENTAL
&builtin_find,
#endif
More information about the coreboot
mailing list