assert(value[0] == 'h' && value[1] == 'd');
assert(value[2] >= 'a' && value[2] <= 'd');
- int disk_drv_no = value[2] - 'a';
+ int disk_drvid = value[2] - 'a';
- uint32_t part_no = atoi(value + 3);
- assert(part_no >= 1);
+ uint32_t partid = atoi(value + 3);
+ assert(partid >= 1);
- system.root_dev = MAKE_DISK_DEV(disk_drv_no, part_no);
+ system.root_dev = MAKE_DISK_DEV(disk_drvid, partid);
printk("root device %s [0x%08x]\n", value, system.root_dev);
get_value("delay", value);
void ide_ata_init() {
printk("IDE %04X %04X %04X %04X\n", IDE_CHL0_CMD_BASE, IDE_CHL1_CMD_BASE, IDE_CHL0_CTL_BASE, IDE_CHL1_CTL_BASE);
for (int i = 0; i < MAX_IDE_DRIVE_CNT; i++) {
- int drv_no = i;
- int channel = drv_no >> 1;
+ int drvid = i;
+ int channel = drvid >> 1;
memset(ide_drives + i, 0, sizeof(ide_drive_t));
- ide_drive_t *drv = ide_drives + drv_no;
- drv->drv_no = drv_no;
+ ide_drive_t *drv = ide_drives + drvid;
+ drv->drvid = drvid;
+ drv->channel = channel;
drv->ide_pci_controller = ide_pci_controller + channel;
// https://wiki.osdev.org/ATA_PIO_Mode
// 3. 等到status的DRQ位或ERR位设置
uint8_t status = 0;
const char *ide_drive_type = "NONE";
- if (ata_read_identify(drv_no, 1, &status, identify)) {
+ if (ata_read_identify(drvid, 1, &status, identify)) {
drv->present = 1;
drv->type = IDE_DRIVE_TYPE_ATA;
ide_drive_type = "ATA";
} else {
- if (ata_read_identify_packet(drv_no, 1, &status, identify)) {
+ if (ata_read_identify_packet(drvid, 1, &status, identify)) {
// printk("ATAPI DEVICE\n");
drv->present = 1;
drv->type = IDE_DRIVE_TYPE_ATAPI;
continue;
}
- // insl(REG_DATA(drv_no), identify, SECT_SIZE / sizeof(uint32_t));
+ // insl(REG_DATA(drvid), identify, SECT_SIZE / sizeof(uint32_t));
// Bit 15: 0 表示 ATA 设备,1 表示 ATAPI 设备。
// Bit 14-8: 保留。
}
for (int i = 0; i < MAX_IDE_DRIVE_CNT; i++) {
- int drv_no = i;
- ide_drive_t *drv = ide_drives + drv_no;
+ int drvid = i;
+ ide_drive_t *drv = ide_drives + drvid;
if (drv->present) {
assert(drv->dma == 1);
// assert(drv->lba48 == 1);
}
void tmp_ide_disk_read(dev_t dev, uint32_t sect_nr, uint32_t count, char *buf) {
- disk_request_t r;
- r.dev = dev;
- r.command = DISK_REQ_READ;
- r.pos = sect_nr;
- r.count = count;
- r.buf = buf;
- r.bb = NULL;
- send_disk_request(&r);
+ int ret = 0;
+ int retry = 3;
+ while (retry--) {
+ disk_request_t r;
+ r.dev = dev;
+ r.command = DISK_REQ_READ;
+ r.pos = sect_nr;
+ r.count = count;
+ r.buf = buf;
+ r.bb = NULL;
+ ret = send_disk_request(&r);
+ if (ret == 0) {
+ break;
+ }
+ }
+
+ if (ret != 0) {
+ panic("read disk error");
+ }
}
// mbr_ext_offset: 在MBR中的扩展分区记录里的偏移地址
void read_partition_table(ide_drive_t *drv, uint32_t mbr_ext_offset, uint64_t lba_partition_table, int depth) {
// disk_request_t r;
char *sect = kmalloc(SECT_SIZE, 0);
-
+ memset(sect, 0xAA, SECT_SIZE);
#if 1
- // part_no == 0 代表整块硬盘
- tmp_ide_disk_read(MAKE_DISK_DEV(drv->drv_no, 0), lba_partition_table, 1, sect);
+ // partid == 0 代表整块硬盘
+ tmp_ide_disk_read(MAKE_DISK_DEV(drv->drvid, 0), lba_partition_table, 1, sect);
#else
- // part_no == 0 代表整块硬盘
- r.dev = MAKE_DISK_DEV(drv->drv_no, 0);
+ // partid == 0 代表整块硬盘
+ r.dev = MAKE_DISK_DEV(drv->drvid, 0);
r.command = DISK_REQ_READ;
r.pos = lba_partition_table;
r.count = 1;
continue;
}
- printk("read ide drive %u\n", drv->drv_no);
+ printk("read ide drive %u\n", drv->drvid);
read_partition_table(drv, 0, 0, 0);
printk("--------------\n");
}
assert(((dest_paddr + size - (size == 0 ? 0 : 1)) & _64K) == (dest_paddr & _64K));
#endif
+ uint8_t pci_status = inb(ide_ctrl->bus_status);
+ if (pci_status & PCI_IDE_STATUS_ACT) {
+ panic("Bus master IDE active");
+ }
+
ide_ctrl->prdt[0].phys_addr = dest_paddr;
ide_ctrl->prdt[0].byte_count = size;
ide_ctrl->prdt[0].reserved = 0;
// printk("ide irq %d handler pci status: 0x%02x\n", irq, ata_pci_bus_status());
int channel = irq == ide_pci_controller[0].irq_line ? 0 : 1;
+#if 0
// printk("ide[%d] irq %d handler\n", channel, irq);
ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel;
+
atomic_inc(&ide_ctrl->irq_cnt);
ata_dma_stop(channel);
add_irq_bh_handler(ide_irq_bh_handler, (void *)channel);
+#endif
+
+ const int drvid = (channel << 1); // 虚拟一个
+ ide_pci_controller_t *ide_ctrl = ide_pci_controller + channel;
+ ide_ctrl->status = inb(REG_STATUS(drvid));
+ ide_ctrl->pci_status = inb(ide_ctrl->bus_status);
+
+ // 之前这里是用up()来唤醒磁盘任务
+ // 但在中断的底半处理,不应该切换任务,因为会引起irq里的reenter问题,导致不能再进底半处理,也无法切换任务
+ // 所以就移除了up()里的 schedule()
+ // 后来就改用完成量来通知磁盘任务,就不存在这个问题了
+
+ // complete会唤醒进程,但不会立即重新调度进程
+ complete(&ide_ctrl->intr_complete);
}
unsigned int IDE_CHL0_CMD_BASE = 0x1F0;
ide_pci_controller[i].bus_prdt = iobase + PCI_IDE_PRDT;
ide_pci_controller[i].prdt = (prdte_t *)page2va(alloc_one_page(0));
+ ide_pci_controller[i].status = 0;
+ ide_pci_controller[i].pci_status = 0;
+
ide_pci_controller[i].pci = pci;
unsigned int irq_line = pci_read_config_byte(pci_cmd(pci, PCI_INTRLINE));
int major = DEV_MAJOR(dev);
int minor = DEV_MINOR(dev);
- int drv_no = (minor & 0xFFFF) >> 8;
+ int drvid = (minor & 0xFFFF) >> 8;
assert(major == DEV_MAJOR_DISK);
assert(minor >= 0);
- assert(drv_no < MAX_IDE_DRIVE_CNT);
+ assert(drvid < MAX_IDE_DRIVE_CNT);
- ide_drive_t *drv = ide_drives + drv_no;
+ ide_drive_t *drv = ide_drives + drvid;
return drv;
}
#pragma once
+#include <ata.h>
#include <atomic.h>
#include <disk.h>
+#include <io.h>
#include <pci.h>
#include <semaphore.h>
#include <system.h>
prdte_t *prdt;
+ //
+ uint8_t status;
+ uint8_t pci_status;
+
// 提出请求的任务用这个字段互斥地添加请求到request_queue
// 同时也和disk任务互斥
mutex_t request_mutex;
typedef struct _ide_drive {
int type;
int present;
- int drv_no;
+ int drvid;
+ int channel;
+
int dma; // 是否支持DMA
int lba48; // 是否支持LBA48
uint64_t max_lba;
disk_request_cmd_t command; // 命令
list_head_t list;
semaphore_t sem;
+
+ int ret;
} disk_request_t;
typedef struct {
semaphore_t sem;
} disk_request_queue_t;
-void send_disk_request(disk_request_t *r);
+int send_disk_request(disk_request_t *r);
#define DEV_MINOR_MASK ((1UL << DEV_MAJOR_BITS) - 1)
#define MAKE_DEV(major, minor) ((major) << DEV_MAJOR_BITS | minor)
-#define MAKE_DISK_DEV(drv_no, part_no) MAKE_DEV(DEV_MAJOR_DISK, (((drv_no) & 0x03) << 8) | (((part_no) & 0xFF) << 0))
+#define MAKE_DISK_DEV(drvid, partid) MAKE_DEV(DEV_MAJOR_DISK, (((drvid) & 0x03) << 8) | (((partid) & 0xFF) << 0))
#define DEV_MAJOR(dev) ((unsigned int)((dev) >> DEV_MAJOR_BITS))
#define DEV_MINOR(dev) ((unsigned int)((dev) & DEV_MINOR_MASK))
#include <sched.h>
void ata_read_identify(int drv, int disable_intr);
-void ata_pio_read_data(int drv_no, int sect_cnt, void *dst);
+void ata_pio_read_data(int drvid, int sect_cnt, void *dst);
void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest);
-void send_disk_request(disk_request_t *r) {
+int send_disk_request(disk_request_t *r) {
if (NULL == r) {
panic("null disk request");
}
// 这个用来让task_disk唤醒自己
semaphore_init(&r->sem, 0);
+ r->ret = 0;
+
// 校验pos,和pos+count是否大于硬盘返回的最大LBA48
// ...
// 等待被task_disk唤醒
down(&r->sem);
+
+ return r->ret;
}
void disk_task_entry(void *arg) {
mutex_unlock(&ide_ctrl->request_mutex);
ide_drive_t *drv = ide_get_drive(r->dev);
- int drv_no = drv->drv_no;
+ int drvid = drv->drvid;
if (drv->present == 0) {
panic("disk not present");
}
int part_id = DEV_MINOR((r->dev)) & 0xFF;
assert(part_id < MAX_DISK_PARTIONS);
- assert(MAKE_DISK_DEV(drv_no, part_id) == r->dev);
+ assert(MAKE_DISK_DEV(drvid, part_id) == r->dev);
uint64_t pos = r->pos + drv->partions[part_id].lba_start;
// printk("pos %lu partid %d lba end %lu\n", pos, part_id, drv->partions[part_id].lba_end);
panic("INVARG");
}
- const bool pio_mode = true;
+ const bool pio_mode = false;
init_completion(&ide_ctrl->intr_complete);
switch (r->command) {
case DISK_REQ_IDENTIFY:
- printk("try to read disk drive %u identify\n", drv_no);
+ printk("try to read disk drive %u identify\n", drvid);
assert(r->count == 1);
- ata_read_identify(drv_no, 0);
+ ata_read_identify(drvid, 0);
break;
case DISK_REQ_READ:
assert(r->count > 0);
assert(r->buf != NULL || r->bb->data != NULL);
- // printk("DISK READ drv_no %u pos %u count %u bb %x\n", drv_no, (uint32_t)pos, r->count, r->bb);
+ // printk("DISK READ drvid %u pos %u count %u bb %x\n", drvid, (uint32_t)pos, r->count, r->bb);
if (pio_mode) {
int ata_pio_read_ext(int drvid, uint64_t pos, uint16_t count, int timeout, void *dest);
if (r->bb != 0) {
- ata_pio_read_ext(drv_no, pos, r->count, 100, r->bb->data);
+ ata_pio_read_ext(drvid, pos, r->count, 100, r->bb->data);
} else {
- ata_pio_read_ext(drv_no, pos, r->count, 100, r->buf);
+ ata_pio_read_ext(drvid, pos, r->count, 100, r->buf);
}
} else {
if (r->bb != 0) {
- ata_dma_read_ext(drv_no, pos, r->count, r->bb->data);
+ ata_dma_read_ext(drvid, pos, r->count, r->bb->data);
} else {
- ata_dma_read_ext(drv_no, pos, r->count, r->buf);
+ ata_dma_read_ext(drvid, pos, r->count, r->buf);
}
}
break;
break;
}
+ int ret = 0;
if (!pio_mode) {
// 等待硬盘中断
wait_completion(&ide_ctrl->intr_complete);
+
+ if ((ide_ctrl->status & (ATA_STATUS_BSY | ATA_STATUS_BSY | ATA_STATUS_WF)) != 0) {
+ printk("IDE status %02X error for drv %u pos %lu count %u\n", ide_ctrl->status, drvid, pos, r->count);
+ ret = -1;
+ }
}
// 读数据
if (DISK_REQ_IDENTIFY == r->command) {
- ata_pio_read_data(drv_no, 1, r->buf);
+ ata_pio_read_data(drvid, 1, r->buf);
}
if (r->bb != 0) {
complete(&r->bb->io_done);
}
+ r->ret = ret;
+
// 唤醒等待该请求的进程
up(&(r->sem));
}