📄 ide_disk.c
字号:
#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 * * 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 * 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 { uint16_t cmd_base; uint16_t ctrl_base;};struct harddisk_info { struct controller *ctrl; uint16_t heads; uint16_t cylinders; uint16_t sectors_per_track; uint8_t model_number[41]; uint8_t slave; sector_t sectors; 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_BASE0 (0x1F0u) /* primary controller */#define IDE_BASE1 (0x170u) /* secondary */#define IDE_BASE2 (0x0F0u) /* third */#define IDE_BASE3 (0x070u) /* fourth */#define IDE_REG_EXTENDED_OFFSET (0x204u)#define IDE_REG_DATA(base) ((ctrl)->cmd_base + 0u) /* word register */#define IDE_REG_ERROR(base) ((ctrl)->cmd_base + 1u)#define IDE_REG_PRECOMP(base) ((ctrl)->cmd_base + 1u)#define IDE_REG_FEATURE(base) ((ctrl)->cmd_base + 1u)#define IDE_REG_SECTOR_COUNT(base) ((ctrl)->cmd_base + 2u)#define IDE_REG_SECTOR_NUMBER(base) ((ctrl)->cmd_base + 3u)#define IDE_REG_LBA_LOW(base) ((ctrl)->cmd_base + 3u)#define IDE_REG_CYLINDER_LSB(base) ((ctrl)->cmd_base + 4u)#define IDE_REG_LBA_MID(base) ((ctrl)->cmd_base + 4u)#define IDE_REG_CYLINDER_MSB(base) ((ctrl)->cmd_base + 5u)#define IDE_REG_LBA_HIGH(base) ((ctrl)->cmd_base + 5u)#define IDE_REG_DRIVEHEAD(base) ((ctrl)->cmd_base + 6u)#define IDE_REG_DEVICE(base) ((ctrl)->cmd_base + 6u)#define IDE_REG_STATUS(base) ((ctrl)->cmd_base + 7u)#define IDE_REG_COMMAND(base) ((ctrl)->cmd_base + 7u)#define IDE_REG_ALTSTATUS(base) ((ctrl)->ctrl_base + 2u)#define IDE_REG_DEVICE_CONTROL(base) ((ctrl)->ctrl_base + 2u)struct ide_pio_command{ uint8_t feature; uint8_t sector_count; uint8_t lba_low; uint8_t lba_mid; uint8_t lba_high; uint8_t device;# 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) uint8_t command; uint8_t sector_count2; uint8_t lba_low2; uint8_t lba_mid2; uint8_t lba_high2;};#define IDE_DEFAULT_COMMAND { 0xFFu, 0x01, 0x00, 0x0000, IDE_DH_DEFAULT }#define IDE_ERR_ICRC 0x80 /* ATA Ultra DMA bad CRC */#define IDE_ERR_BBK 0x80 /* ATA bad block */#define IDE_ERR_UNC 0x40 /* ATA uncorrected error */#define IDE_ERR_MC 0x20 /* ATA media change */#define IDE_ERR_IDNF 0x10 /* ATA id not found */#define IDE_ERR_MCR 0x08 /* ATA media change request */#define IDE_ERR_ABRT 0x04 /* ATA command aborted */#define IDE_ERR_NTK0 0x02 /* ATA track 0 not found */#define IDE_ERR_NDAM 0x01 /* ATA address mark not found */#define IDE_STATUS_BSY 0x80 /* busy */#define IDE_STATUS_RDY 0x40 /* ready */#define IDE_STATUS_DF 0x20 /* device fault */#define IDE_STATUS_WFT 0x20 /* write fault (old name) */#define IDE_STATUS_SKC 0x10 /* seek complete */#define IDE_STATUS_DRQ 0x08 /* data request */#define IDE_STATUS_CORR 0x04 /* corrected */#define IDE_STATUS_IDX 0x02 /* index */#define IDE_STATUS_ERR 0x01 /* error (ATA) */#define IDE_STATUS_CHK 0x01 /* check (ATAPI) */#define IDE_CTRL_HD15 0x08 /* bit should always be set to one */#define IDE_CTRL_SRST 0x04 /* soft reset */#define IDE_CTRL_NIEN 0x02 /* disable interrupts *//* 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 0xDEstruct controller controller;struct harddisk_info harddisk_info[2];static int await_ide(int (*done)(struct controller *ctrl), struct controller *ctrl, unsigned long timeout){ int result; for(;;) { result = done(ctrl); if (result) { return 0; } poll_interruptions(); if ((timeout == 0) || (currticks() > timeout)) { 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. */#define IDE_TIMEOUT (32*TICKS_PER_SEC)static int not_bsy(struct controller *ctrl){ return !(inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY);}#if !BSY_SET_DURING_SPINUPstatic int timeout(struct controller *ctrl){ return 0;}#endifstatic int ide_software_reset(struct controller *ctrl){ /* 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. */ if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } /* Disable Interrupts and reset the ide bus */ outb(IDE_CTRL_HD15 | IDE_CTRL_SRST | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl)); udelay(5); outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl)); mdelay(2); if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } return 0;}static void pio_set_registers( struct controller *ctrl, const struct ide_pio_command *cmd){ uint8_t device; /* Disable Interrupts */ outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, IDE_REG_DEVICE_CONTROL(ctrl)); /* Possibly switch selected device */ device = inb(IDE_REG_DEVICE(ctrl)); outb(cmd->device, IDE_REG_DEVICE(ctrl)); if ((device & (1UL << 4)) != (cmd->device & (1UL << 4))) { /* 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); } outb(cmd->feature, IDE_REG_FEATURE(ctrl)); outb(cmd->sector_count2, IDE_REG_SECTOR_COUNT(ctrl)); outb(cmd->sector_count, IDE_REG_SECTOR_COUNT(ctrl)); outb(cmd->lba_low2, IDE_REG_LBA_LOW(ctrl)); outb(cmd->lba_low, IDE_REG_LBA_LOW(ctrl)); outb(cmd->lba_mid2, IDE_REG_LBA_MID(ctrl)); outb(cmd->lba_mid, IDE_REG_LBA_MID(ctrl)); outb(cmd->lba_high2, IDE_REG_LBA_HIGH(ctrl)); outb(cmd->lba_high, IDE_REG_LBA_HIGH(ctrl)); outb(cmd->command, IDE_REG_COMMAND(ctrl));}static int pio_non_data(struct controller *ctrl, const struct ide_pio_command *cmd){ /* Wait until the busy bit is clear */ if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } pio_set_registers(ctrl, cmd); if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } /* FIXME is there more error checking I could do here? */ return 0;}static int pio_data_in(struct controller *ctrl, const struct ide_pio_command *cmd, void *buffer, size_t bytes){ unsigned int status; /* FIXME handle commands with multiple blocks */ /* Wait until the busy bit is clear */ if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } /* How do I tell if INTRQ is asserted? */ pio_set_registers(ctrl, cmd); if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } status = inb(IDE_REG_STATUS(ctrl)); if (!(status & IDE_STATUS_DRQ)) { return -1; } insw(IDE_REG_DATA(ctrl), buffer, bytes/2); status = inb(IDE_REG_STATUS(ctrl)); if (status & IDE_STATUS_DRQ) { return -1; } return 0;}#if 0static int pio_packet(struct controller *ctrl, int in, const void *packet, int packet_len, void *buffer, int buffer_len){ const uint8_t *pbuf; unsigned int status; struct ide_pio_command cmd; memset(&cmd, 0, sizeof(cmd)); /* Wait until the busy bit is clear */ if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } pio_set_registers(ctrl, cmd); ndelay(400); if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) { return -1; } status = inb(IDE_REG_STATUS(ctrl)); if (!(status & IDE_STATUS_DRQ)) { return -1; } while(packet_len > 1) { outb(*pbuf, IDE_REG_DATA(ctrl)); pbuf++; packet_len -= 1; } inb(IDE_REG_ALTSTATUS(ctrl)); if (await_ide){} /*FIXME finish this function */ }#endifstatic inline int ide_read_sector_chs( struct harddisk_info *info, void *buffer, unsigned long sector){ struct ide_pio_command cmd; unsigned int track; unsigned int offset; unsigned int cylinder; memset(&cmd, 0, sizeof(cmd)); cmd.sector_count = 1; track = sector / info->sectors_per_track; /* Sector number */ offset = 1 + (sector % info->sectors_per_track); cylinder = track / info->heads; cmd.lba_low = offset; cmd.lba_mid = cylinder & 0xff; cmd.lba_high = (cylinder >> 8) & 0xff; cmd.device = IDE_DH_DEFAULT | IDE_DH_HEAD(track % info->heads) | info->slave | IDE_DH_CHS; cmd.command = IDE_CMD_READ_SECTORS; return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);}static inline int ide_read_sector_lba( struct harddisk_info *info, void *buffer, unsigned long sector){ struct ide_pio_command cmd; memset(&cmd, 0, sizeof(cmd)); cmd.sector_count = 1; cmd.lba_low = sector & 0xff; cmd.lba_mid = (sector >> 8) & 0xff; cmd.lba_high = (sector >> 16) & 0xff; cmd.device = IDE_DH_DEFAULT | ((sector >> 24) & 0x0f) | info->slave | IDE_DH_LBA; cmd.command = IDE_CMD_READ_SECTORS; return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);}static inline int ide_read_sector_lba48( struct harddisk_info *info, void *buffer, sector_t sector){ struct ide_pio_command cmd; memset(&cmd, 0, sizeof(cmd)); cmd.sector_count = 1; cmd.lba_low = sector & 0xff; cmd.lba_mid = (sector >> 8) & 0xff; cmd.lba_high = (sector >> 16) & 0xff; cmd.lba_low2 = (sector >> 24) & 0xff; cmd.lba_mid2 = (sector >> 32) & 0xff; cmd.lba_high2 = (sector >> 40) & 0xff; cmd.device = info->slave | IDE_DH_LBA; cmd.command = IDE_CMD_READ_SECTORS_EXT; return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);}static int ide_read(struct disk *disk, sector_t sector){ struct harddisk_info *info = disk->priv; int result; /* Report the buffer is empty */ disk->sector = 0; disk->bytes = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -