const static int AHCI_FIS_TYPE_REG_H2D = 0x27;
const static int AHCI_FIS_TYPE_REG_D2H = 0x34;
+const static int AHCI_FIS_TYPE_DMA_ACTIVE = 0x39;
+const static int AHCI_FIS_TYPE_DMA_SETUP = 0x41;
+const static int AHCI_FIS_TYPE_DATA = 0x46;
+
+const static uint32_t AHCI_INTERRUPT_STATUS_DHRS = (1U << 0); // device to host fis interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_PSS = (1U << 1); // pio setup fis interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_DSS = (1U << 2); // DMA setup fis interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_SDBS = (1U << 3); // set device bits interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_UFS = (1U << 4); // unknown fis interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_DPS = (1U << 5); // descriptor process error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_PCS = (1U << 6); // port change error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_DMPS = (1U << 7); // device mechanical presence
+const static uint32_t AHCI_INTERRUPT_STATUS_PRCS = (1U << 22); // phyrdy change interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_IPMS = (1U << 23); // incorrect port multiplier interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_OFS = (1U << 24); // overflow status interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_INFS = (1U << 26); // interface non-fatal error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_IFS = (1U << 27); // interface fatal error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_HBDS = (1U << 28); // host bus data error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_HBFS = (1U << 29); // host bus fatal error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_TFES = (1U << 30); // task file error interrupt
+const static uint32_t AHCI_INTERRUPT_STATUS_CPDS = (1U << 31); // cold port detect interrupt
const static uint32_t AHCI_INTERRUPT_ENABLE_DHRS = (1U << 0); // device to host fis interrupt enable
const static uint32_t AHCI_INTERRUPT_ENABLE_PSE = (1U << 1); // pio setup fis interrupt enable
uint8_t _reserved1[4];
} ahci_fis_reg_h2d_t;
+// 双向
+typedef struct {
+ uint8_t fis_type;
+ uint8_t pmport : 4;
+ uint8_t _r : 1;
+ uint8_t direction : 1; // direction: 0: transmitter->receiver; 1: receiver->transmitter
+ uint8_t i : 1; // interrupt
+ uint8_t auto_active : 1; // auto-activate
+
+ uint8_t _reserved0[2];
+
+ uint32_t dma_buffer_identifier;
+ uint32_t _dma_buffer_identifier_upper;
+
+ uint32_t _reserved1;
+
+ uint32_t dma_buffer_offset; // bit[1:0] 应该为0
+ uint32_t dma_transfer_count; // bit[0] 应该为0
+
+ uint32_t _reserved2;
+} ahci_fis_dma_setup_t;
+
+// 双向
+typedef struct {
+ uint8_t fis_type;
+
+ uint8_t pmport : 4;
+ uint8_t _r : 4;
+
+ uint8_t _reserved[2];
+
+ uint8_t data[0];
+} ahci_fis_data_t;
+
typedef struct {
uint32_t data_base; // 第0位必为0
uint32_t cfl : 5; // length of the command fis: 命令FIS大小(双字为单位)
uint32_t a : 1; // 该命令需要发送到ATAPI设备
uint32_t w : 1; // 该命令需要向设备写入数据
- uint32_t p : 1; //
- uint32_t r : 1;
- uint32_t b : 1;
- uint32_t c : 1; // 命令执行完后,需要将 task_file_data的BSY位清零
+ uint32_t p : 1; // Prefetchable
+ uint32_t r : 1; // reset
+ uint32_t b : 1; // BIST FIS
+ uint32_t c : 1; // 命令执行完后,需要将 task_file_data的BSY位清零
uint32_t R : 1;
uint32_t pmp : 4;
uint32_t prdtl : 16; // prdt entry count
int sata_irq_triggered = 0;
-void init_sata_device(ahci_hba_t* hba, ahci_port_t* port, int index) {
+int max_sata_devices = 0;
+sata_device_t sata_devices[MAX_SATA_DEVICES] = {0};
+
+uint8_t sector[512];
+void init_sata_device(ahci_hba_t* hba, ahci_port_t* port, int port_index) {
+ int index = max_sata_devices;
+
assert(hba != NULL);
assert(port != NULL);
+ assert(port_index >= 0 && port_index < MAX_SATA_DEVICES);
assert(index >= 0 && index < MAX_SATA_DEVICES);
sata_device_t* sata = sata_devices + index;
+ memset(sata, 0, sizeof(sata_device_t));
sata->hba = hba;
sata->port = port;
sata->index = index;
+ sata->port_index = port_index;
printk("ahci port clb %08x fb %08x sata_status 0x%08X signature %08X\n", port->cmd_list_base, port->fis_base,
port->sata_status, port->signature);
vaddr_t cmd_list_base = (vaddr_t)ioremap(PAGE_ALIGN(port->cmd_list_base), 0x1000);
- vaddr_t fis_base = cmd_list_base;
+ vaddr_t fis_base = 0;
- if (PAGE_ALIGN(port->cmd_list_base) != PAGE_ALIGN(port->fis_base)) {
+ // fis_base大概率和cmd_list_base在同一个页上
+ // 如果不在同一个页上,那么需要单独分配空间
+ if (PAGE_ALIGN(port->cmd_list_base) == PAGE_ALIGN(port->fis_base)) {
+ fis_base = cmd_list_base;
+ } else {
fis_base = (vaddr_t)ioremap(PAGE_ALIGN(port->fis_base), 0x1000);
}
+ // 算出各自在页内的偏移
cmd_list_base += port->cmd_list_base - PAGE_ALIGN(port->cmd_list_base);
fis_base += port->fis_base - PAGE_ALIGN(port->fis_base);
//
sata_identify(sata);
+
+ if (!sata->lba48) {
+ return;
+ }
+
+ if (!sata->dma) {
+ return;
+ }
+
+ max_sata_devices += 1;
+
+ memset(sector, 0xCC, 512);
+ sata_dma_read(sata, 0, 1, (paddr_t)va2pa(sector));
+ printk("sector %08x\n", (uint32_t*)sector);
+}
+
+void sata_irq_handler(unsigned int irq, pt_regs_t* regs, void* dev_id) {
+ sata_irq_triggered = 1;
+
+ for (int i = 0; i < max_sata_devices; i++) {
+ sata_device_t* sata = sata_devices + i;
+ ahci_port_t* port = sata->port;
+ assert(port != NULL);
+
+ //
+ uint32_t interrupt_status = port->interrupt_status;
+ if (0 == interrupt_status) {
+ continue;
+ }
+
+ printk("SATA[%u] IRQ[%u] is %08x\n", i, irq, interrupt_status);
+ if (interrupt_status & AHCI_INTERRUPT_STATUS_DHRS) {
+ //
+ }
+
+ port->interrupt_status = interrupt_status;
+ }
+
+ ioapic_eoi();
+}
+
+bool sata_ready(sata_device_t* sata) {
+ if (sata->port->task_file_data & 0x80) {
+ return false;
+ }
+ return true;
+}
+int sata_wait_ready(sata_device_t* sata) {
+ assert(sata != NULL);
+ ahci_port_t* port = sata->port;
+ assert(port != NULL);
+
+ // 清除error 和 中断状态
+ port->sata_error = port->sata_error;
+ port->interrupt_status = port->interrupt_status;
+
+ uint32_t timeout = 1000000;
+ while (timeout--) {
+ if (sata_ready(sata)) {
+ return 0;
+ }
+ asm("pause");
+ }
+ return -1;
+}
+
+int sata_dma_read(sata_device_t* sata, uint64_t lba, uint32_t sectors, paddr_t paddr) {
+ assert(sata != NULL);
+ assert(sectors <= 4);
+ assert(lba + sectors <= sata->max_lba);
+
+ ahci_port_t* port = sata->port;
+ assert(port != NULL);
+
+ uint32_t bytes = sectors * 512;
+
+ //
+ if (0 != sata_wait_ready(sata)) {
+ panic("sata wait ready timeout");
+ }
+
+ //
+ sata->prdte0->data_base = paddr;
+ sata->prdte0->data_byte_count = (bytes - 1) | 1;
+ sata->prdte0->ioc = 1;
+
+ //
+ ahci_fis_reg_h2d_t* fis = (ahci_fis_reg_h2d_t*)sata->cmd_table0->cmd_fis;
+ memset(fis, 0, sizeof(ahci_fis_reg_h2d_t));
+ fis->fis_type = AHCI_FIS_TYPE_REG_H2D;
+ fis->c = 1;
+ fis->command = SATA_CMD_READ_DMA_EXT;
+ fis->device = SATA_DEVICE_LBA;
+ fis->lba0 = (lba >> (0 * 8)) & 0xFF;
+ fis->lba1 = (lba >> (1 * 8)) & 0xFF;
+ fis->lba2 = (lba >> (2 * 8)) & 0xFF;
+ fis->lba3 = (lba >> (3 * 8)) & 0xFF;
+ fis->lba4 = (lba >> (4 * 8)) & 0xFF;
+ fis->lba5 = (lba >> (5 * 8)) & 0xFF;
+
+ //
+ fis->count_low = (sectors >> 0) & 0xFF;
+ fis->count_high = (sectors >> 8) & 0xFF;
+
+ //
+ sata->cmd_list0->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t);
+ sata->cmd_list0->prdtl = 1;
+ sata->cmd_list0->w = 0; // read
+ sata->cmd_list0->a = 0; // ata device
+ sata->cmd_list0->c = 1;
+ sata->cmd_list0->prd_byte_count = 0;
+
+ //
+ port->sata_error = port->sata_error;
+ port->interrupt_status = port->interrupt_status;
+
+ //
+ port->interrupt_enable = AHCI_INTERRUPT_ENABLE_DHRS;
+
+ //
+ port->cmd_issue = 1 << 0;
+
+ return 0;
}
void sata_identify(sata_device_t* sata) {
sata->cmd_list0->prdtl = 1;
sata->cmd_list0->w = 0; // read
sata->cmd_list0->a = 0; // ata device
+ sata->cmd_list0->c = 1;
sata->cmd_list0->prd_byte_count = 0;
// 清除中断状态
printk("HD Model: %s\n", s);
}
-sata_device_t sata_devices[MAX_SATA_DEVICES] = {0};
-
void sata_read_identify_string(const uint16_t* identify, int bgn, int end, char* buf) {
const char* p = (const char*)(identify + bgn);
int i = 0;