ide_disk.c revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
#include "etherboot.h"
#include "timer.h"
#include "pci.h"
#include "isa.h"
#include "disk.h"
#define BSY_SET_DURING_SPINUP 1
/*
* UBL, The Universal Talkware Boot Loader
* Copyright (C) 2000 Universal Talkware Inc.
* Copyright (C) 2002 Eric Biederman
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*/
struct controller {
};
struct harddisk_info {
struct controller *ctrl;
int address_mode; /* am i lba (0x40) or chs (0x00) */
#define ADDRESS_MODE_CHS 0
#define ADDRESS_MODE_LBA 1
#define ADDRESS_MODE_LBA48 2
int drive_exists;
int slave_absent;
int basedrive;
};
#define IDE_SECTOR_SIZE 0x200
#define IDE_REG_EXTENDED_OFFSET (0x204u)
struct ide_pio_command
{
# define IDE_DH_DEFAULT (0xA0)
# define IDE_DH_HEAD(x) ((x) & 0x0F)
# define IDE_DH_MASTER (0x00)
# define IDE_DH_SLAVE (0x10)
# define IDE_DH_LBA (0x40)
# define IDE_DH_CHS (0x00)
};
/* Most mandtory and optional ATA commands (from ATA-3), */
#define IDE_CMD_CFA_ERASE_SECTORS 0xC0
#define IDE_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
#define IDE_CMD_CFA_TRANSLATE_SECTOR 0x87
#define IDE_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
#define IDE_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
#define IDE_CMD_CHECK_POWER_MODE1 0xE5
#define IDE_CMD_CHECK_POWER_MODE2 0x98
#define IDE_CMD_DEVICE_RESET 0x08
#define IDE_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
#define IDE_CMD_FLUSH_CACHE 0xE7
#define IDE_CMD_FORMAT_TRACK 0x50
#define IDE_CMD_IDENTIFY_DEVICE 0xEC
#define IDE_CMD_IDENTIFY_DEVICE_PACKET 0xA1
#define IDE_CMD_IDENTIFY_PACKET_DEVICE 0xA1
#define IDE_CMD_IDLE1 0xE3
#define IDE_CMD_IDLE2 0x97
#define IDE_CMD_IDLE_IMMEDIATE1 0xE1
#define IDE_CMD_IDLE_IMMEDIATE2 0x95
#define IDE_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
#define IDE_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
#define IDE_CMD_NOP 0x00
#define IDE_CMD_PACKET 0xA0
#define IDE_CMD_READ_BUFFER 0xE4
#define IDE_CMD_READ_DMA 0xC8
#define IDE_CMD_READ_DMA_QUEUED 0xC7
#define IDE_CMD_READ_MULTIPLE 0xC4
#define IDE_CMD_READ_SECTORS 0x20
#define IDE_CMD_READ_SECTORS_EXT 0x24
#define IDE_CMD_READ_VERIFY_SECTORS 0x40
#define IDE_CMD_RECALIBRATE 0x10
#define IDE_CMD_SEEK 0x70
#define IDE_CMD_SET_FEATURES 0xEF
#define IDE_CMD_SET_MAX_ADDR_EXT 0x24
#define IDE_CMD_SET_MULTIPLE_MODE 0xC6
#define IDE_CMD_SLEEP1 0xE6
#define IDE_CMD_SLEEP2 0x99
#define IDE_CMD_STANDBY1 0xE2
#define IDE_CMD_STANDBY2 0x96
#define IDE_CMD_STANDBY_IMMEDIATE1 0xE0
#define IDE_CMD_STANDBY_IMMEDIATE2 0x94
#define IDE_CMD_WRITE_BUFFER 0xE8
#define IDE_CMD_WRITE_DMA 0xCA
#define IDE_CMD_WRITE_DMA_QUEUED 0xCC
#define IDE_CMD_WRITE_MULTIPLE 0xC5
#define IDE_CMD_WRITE_SECTORS 0x30
#define IDE_CMD_WRITE_VERIFY 0x3C
/* IDE_CMD_SET_FEATURE sub commands */
#define IDE_FEATURE_CFA_ENABLE_8BIT_PIO 0x01
#define IDE_FEATURE_ENABLE_WRITE_CACHE 0x02
#define IDE_FEATURE_SET_TRANSFER_MODE 0x03
#define IDE_FEATURE_ENABLE_POWER_MANAGEMENT 0x05
#define IDE_FEATURE_ENABLE_POWERUP_IN_STANDBY 0x06
#define IDE_FEATURE_STANDBY_SPINUP_DRIVE 0x07
#define IDE_FEATURE_CFA_ENABLE_POWER_MODE1 0x0A
#define IDE_FEATURE_DISABLE_MEDIA_STATUS_NOTIFICATION 0x31
#define IDE_FEATURE_ENABLE_AUTOMATIC_ACOUSTIC_MANAGEMENT 0x42
#define IDE_FEATURE_SET_MAXIMUM_HOST_INTERFACE_SECTOR_TIMES 0x43
#define IDE_FEATURE_DISABLE_READ_LOOKAHEAD 0x55
#define IDE_FEATURE_ENABLE_RELEASE_INTERRUPT 0x5D
#define IDE_FEATURE_ENABLE_SERVICE_INTERRUPT 0x5E
#define IDE_FEATURE_DISABLE_REVERTING_TO_POWERON_DEFAULTS 0x66
#define IDE_FEATURE_CFA_DISABLE_8BIT_PIO 0x81
#define IDE_FEATURE_DISABLE_WRITE_CACHE 0x82
#define IDE_FEATURE_DISABLE_POWER_MANAGEMENT 0x85
#define IDE_FEATURE_DISABLE_POWERUP_IN_STANDBY 0x86
#define IDE_FEATURE_CFA_DISABLE_POWER_MODE1 0x8A
#define IDE_FEATURE_ENABLE_MEDIA_STATUS_NOTIFICATION 0x95
#define IDE_FEATURE_ENABLE_READ_LOOKAHEAD 0xAA
#define IDE_FEATURE_DISABLE_AUTOMATIC_ACOUSTIC_MANAGEMENT 0xC2
#define IDE_FEATURE_ENABLE_REVERTING_TO_POWERON_DEFAULTS 0xCC
#define IDE_FEATURE_DISABLE_SERVICE_INTERRUPT 0xDE
struct controller controller;
{
int result;
for(;;) {
if (result) {
return 0;
}
break;
}
}
return -1;
}
/* The maximum time any IDE command can last 31 seconds,
* So if any IDE commands takes this long we know we have problems.
*/
{
}
{
return 0;
}
#endif
{
/* Wait a little bit in case this is immediately after
* hardware reset.
*/
mdelay(2);
/* A software reset should not be delivered while the bsy bit
* is set. If the bsy bit does not clear in a reasonable
* amount of time give up.
*/
return -1;
}
/* Disable Interrupts and reset the ide bus */
udelay(5);
mdelay(2);
return -1;
}
return 0;
}
static void pio_set_registers(
{
/* Disable Interrupts */
/* Possibly switch selected device */
/* Allow time for the selected drive to switch,
* The linux ide code suggests 50ms is the right
* amount of time to use here.
*/
mdelay(50);
}
}
{
/* Wait until the busy bit is clear */
return -1;
}
return -1;
}
/* FIXME is there more error checking I could do here? */
return 0;
}
{
unsigned int status;
/* FIXME handle commands with multiple blocks */
/* Wait until the busy bit is clear */
return -1;
}
/* How do I tell if INTRQ is asserted? */
return -1;
}
if (!(status & IDE_STATUS_DRQ)) {
return -1;
}
if (status & IDE_STATUS_DRQ) {
return -1;
}
return 0;
}
#if 0
const void *packet, int packet_len,
void *buffer, int buffer_len)
{
unsigned int status;
struct ide_pio_command cmd;
/* Wait until the busy bit is clear */
return -1;
}
ndelay(400);
return -1;
}
if (!(status & IDE_STATUS_DRQ)) {
return -1;
}
while(packet_len > 1) {
pbuf++;
packet_len -= 1;
}
if (await_ide){}
/*FIXME finish this function */
}
#endif
static inline int ide_read_sector_chs(
{
struct ide_pio_command cmd;
unsigned int track;
unsigned int offset;
unsigned int cylinder;
/* Sector number */
}
static inline int ide_read_sector_lba(
{
struct ide_pio_command cmd;
}
static inline int ide_read_sector_lba48(
{
struct ide_pio_command cmd;
}
{
int result;
/* Report the buffer is empty */
return -1;
}
}
}
}
else {
result = -1;
}
/* On success report the buffer has data */
if (result != -1) {
}
return result;
}
{
struct ide_pio_command cmd;
int i;
info->sectors_per_track = 0u;
info->drive_exists = 0;
info->slave_absent = 0;
#if 0
#endif
/* Select the drive that we are testing */
mdelay(50);
/* Test to see if the drive registers exist,
* In many cases this quickly rules out a missing drive.
*/
for(i = 0; i < 4; i++) {
}
for(i = 0; i < 4; i++) {
return 1;
}
}
for(i = 0; i < 4; i++) {
}
for(i = 0; i < 4; i++) {
return 1;
}
}
#if 0
#endif
/* Well, if that command didn't work, we probably don't have drive. */
return 1;
}
/* Now suck the data out */
/* If the response is incomplete spin up the drive... */
/* If the command doesn't work give up on the drive */
return 1;
}
}
/* The response is incomplete retry the drive info command */
/* If the command didn't work give up on the drive. */
return 1;
}
}
return 1;
}
for(i = 27; i < 47; i++) {
}
/* See if LBA is supported */
/* Enable LBA48 mode if it is present */
/* Should LBA48 depend on LBA? */
printf("LBA48 mode\n");
}
} else {
printf( "%s sectors_per_track=[%d], heads=[%d], cylinders=[%d]\n",
}
/* See if we have a slave */
}
/* See if we need to put the device in CFA power mode 1 */
((1 << 15) | (1 << 13)| (1 << 12))) {
/* If I need to power up the drive, and I can't
* give up.
*/
printf("Cannot power up CFA device\n");
return 1;
}
}
printf("disk%d %dk cap: %hx\n",
drive_info[49]);
return 0;
}
{
struct harddisk_info *info;
/* Intialize the harddisk_info structures */
/* Put the drives ide channel in a know state and wait
* for the drives to spinup.
*
* In practice IDE disks tend not to respond to commands until
* they have spun up. This makes IDE hard to deal with
* immediately after power up, as the delays can be quite
* long, so we must be very careful here.
*
* There are two pathological cases that must be dealt with:
*
* - The BSY bit not being set while the IDE drives spin up.
* In this cases only a hard coded delay will work. As
* I have not reproduced it, and this is out of spec for
* IDE drives the work around can be enabled by setting
* BSY_SET_DURING_SPINUP to 0.
*
* - The BSY bit floats high when no drives are plugged in.
* This case will not be detected except by timing out but
* we avoid the problems by only probing devices we are
* supposed to boot from. If we don't do the probe we
* will not experience the problem.
*
* So speed wise I am only slow if the BSY bit is not set
* or not reported by the IDE controller during spinup, which
* is quite rare.
*
*/
return -1;
}
#endif
if (ide_software_reset(ctrl) < 0) {
return -1;
}
/* Note: I have just done a software reset. It may be
* reasonable to just read the boot time signatures
* off of the drives to see if they are present.
*
* For now I will go with just sending commands to the drives
* and assuming filtering out missing drives by detecting registers
* that won't set and commands that fail to execute properly.
*/
/* Now initialize the individual drives */
info = &harddisk_info[0];
basedrive++;
info++;
}
return 0;
}
{
}
#ifdef CONFIG_PCI
{
struct harddisk_info *info;
int index;
index++;
}
unsigned mask;
/* IDE special pci mode */
} else {
/* IDE normal pci mode */
if (index < 2) {
} else {
}
}
/* nothing behind the controller */
continue;
}
}
if (!info->drive_exists) {
/* unknown drive */
continue;
}
return 1;
}
/* past all of the drives */
return 0;
}
#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b
static struct pci_id ide_controllers[] = {
#if 0 /* Currently I don't need any entries in this table so ignore it */
{ 0x3388, 0x8013, "HINT_IDE" },
#endif
};
.type = DISK_DRIVER,
.name = "IDE",
.probe = ide_pci_probe,
.ids = ide_controllers,
};
#endif
/* The isa driver works but it causes disks to show up twice.
* comment it out for now.
*/
#if 0 && defined(CONFIG_ISA)
{
int index;
unsigned short addr;
struct harddisk_info *info;
index--;
}
if ((index & 1) == 0) {
/* nothing behind the controller */
continue;
}
}
if (!info->drive_exists) {
/* unknown drive */
return 0;
}
return 1;
}
/* past all of the drives */
return 0;
}
static unsigned short ide_base[] = {
0
};
.type = DISK_DRIVER,
.probe = ide_isa_probe,
};
#endif