| 1 | #include <asm.h> |
| 2 | #include <console/printf.h> |
| 3 | #include <drivers/ahci.h> |
| 4 | #include <drivers/ata.h> |
| 5 | #include <drivers/pci.h> |
| 6 | #include <mem/alloc.h> |
| 7 | #include <registry.h> |
| 8 | #include <stdbool.h> |
| 9 | #include <stdint.h> |
| 10 | #include <time/spin_sleep.h> |
| 11 | |
| 12 | void ata_select_drive(struct ata_drive *ata_drive) { |
| 13 | uint16_t base = ata_drive->io_base; |
| 14 | |
| 15 | outb(REG_DRIVE_HEAD(base), value: 0xA0 | (ata_drive->slave ? 0x10 : 0x00)); |
| 16 | io_wait(); |
| 17 | } |
| 18 | |
| 19 | void ata_soft_reset(struct ata_drive *ata_drive) { |
| 20 | uint16_t ctrl = ata_drive->ctrl_base; |
| 21 | |
| 22 | outb(port: ctrl, value: 0x04); // nIEN=0, SRST=1 |
| 23 | io_wait(); |
| 24 | |
| 25 | outb(port: ctrl, value: 0x00); // nIEN=0, SRST=0 |
| 26 | io_wait(); |
| 27 | |
| 28 | uint16_t base = ata_drive->io_base; |
| 29 | uint64_t timeout = IDE_CMD_TIMEOUT_MS * 1000; |
| 30 | |
| 31 | while (inb(REG_STATUS(base)) & STATUS_BSY) { |
| 32 | sleep_spin_us(us: 10); |
| 33 | timeout--; |
| 34 | if (timeout == 0) |
| 35 | return; |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | bool ata_identify(struct ata_drive *ata_drive) { |
| 40 | ata_select_drive(ata_drive); |
| 41 | io_wait(); |
| 42 | |
| 43 | outb(REG_COMMAND(ata_drive->io_base), AHCI_CMD_IDENTIFY); |
| 44 | uint8_t status = inb(REG_STATUS(ata_drive->io_base)); |
| 45 | |
| 46 | if (status == 0) |
| 47 | return false; |
| 48 | |
| 49 | uint64_t timeout = IDE_IDENT_TIMEOUT_MS * 1000; |
| 50 | while ((status & STATUS_BSY)) { |
| 51 | status = inb(REG_STATUS(ata_drive->io_base)); |
| 52 | sleep_spin_us(us: 1); |
| 53 | timeout--; |
| 54 | if (timeout == 0) |
| 55 | return false; |
| 56 | } |
| 57 | |
| 58 | if (inb(REG_LBA_MID(ata_drive->io_base)) || |
| 59 | inb(REG_LBA_HIGH(ata_drive->io_base))) |
| 60 | return false; |
| 61 | |
| 62 | insw(port: ata_drive->io_base, addr: (uint16_t *) ata_drive->identify_data, count: 256); |
| 63 | return true; |
| 64 | } |
| 65 | |
| 66 | bool ata_setup_drive(struct ata_drive *ide, struct pci_device *devices, |
| 67 | uint64_t count, int channel, bool is_slave) { |
| 68 | |
| 69 | for (uint64_t i = 0; i < count; i++) { |
| 70 | struct pci_device *curr = &devices[i]; |
| 71 | |
| 72 | if (curr->class_code == 1 && curr->subclass == 1) { |
| 73 | uint32_t bar = |
| 74 | pci_read_bar(bus: curr->bus, device: curr->dev, function: curr->function, bar_index: channel * 2); |
| 75 | |
| 76 | uint32_t ctrl_bar = pci_read_bar(bus: curr->bus, device: curr->dev, |
| 77 | function: curr->function, bar_index: channel * 2 + 1); |
| 78 | ide->io_base = (bar & 1) ? (bar & 0xFFFFFFFC) |
| 79 | : ((channel == 0) ? ATA_PRIMARY_IO |
| 80 | : ATA_SECONDARY_IO); |
| 81 | |
| 82 | uint8_t prog_if = pci_read_config8(bus: curr->bus, device: curr->dev, |
| 83 | function: curr->function, PCI_PROG_IF); |
| 84 | bool primary_native = (prog_if & 0x01); |
| 85 | bool secondary_native = (prog_if & 0x04); |
| 86 | |
| 87 | if ((channel == 0 && !primary_native) || |
| 88 | (channel == 1 && !secondary_native)) { |
| 89 | ide->irq = (channel == 0) ? 14 : 15; |
| 90 | } else { |
| 91 | ide->irq = pci_read_config8(bus: curr->bus, device: curr->dev, |
| 92 | function: curr->function, PCI_INTERRUPT_LINE); |
| 93 | } |
| 94 | |
| 95 | ide->ctrl_base = |
| 96 | (ctrl_bar & 1) |
| 97 | ? (ctrl_bar & 0xFFFFFFFC) |
| 98 | : ((channel == 0) ? ATA_PRIMARY_CTRL : ATA_SECONDARY_CTRL); |
| 99 | |
| 100 | ide->slave = is_slave; |
| 101 | ide->identify_data = kmalloc(512); |
| 102 | if (!ide->identify_data) |
| 103 | panic("Could not allocate space for IDE Identify" ); |
| 104 | |
| 105 | ata_select_drive(ata_drive: ide); |
| 106 | ata_soft_reset(ata_drive: ide); |
| 107 | |
| 108 | if (ata_identify(ata_drive: ide)) { |
| 109 | ide->type = IDE_TYPE_ATA; |
| 110 | ide->sector_size = 512; |
| 111 | return true; |
| 112 | } else if (atapi_identify(ide)) { |
| 113 | ide->type = IDE_TYPE_ATAPI; |
| 114 | ide->sector_size = 2048; |
| 115 | return true; |
| 116 | } |
| 117 | |
| 118 | return false; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | ide->io_base = 0; |
| 123 | ide->ctrl_base = 0; |
| 124 | ide->slave = 0; |
| 125 | return false; |
| 126 | } |
| 127 | |
| 128 | static uint64_t ide_cnt = 1, atapi_cnt = 1; |
| 129 | |
| 130 | void ata_init(struct pci_device *devices, uint64_t count) { |
| 131 | struct ata_drive *drives = |
| 132 | kmalloc(sizeof(struct ata_drive) * 4, ALLOC_FLAGS_ZERO); |
| 133 | if (!drives) |
| 134 | panic("Could not allocate space for devices" ); |
| 135 | |
| 136 | for (int i = 0; i < 2; i++) { |
| 137 | for (int j = 0; j < 2; j++) { |
| 138 | int ind = i * 2 + j; |
| 139 | if (ata_setup_drive(ide: &drives[ind], devices, count, channel: i, is_slave: j)) { |
| 140 | struct block_device *d = NULL; |
| 141 | |
| 142 | if (drives[ind].type == IDE_TYPE_ATA) { |
| 143 | d = ide_create_generic(ide: &drives[ind]); |
| 144 | registry_mkname(disk: d, prefix: "ata" , counter: ide_cnt++); |
| 145 | } else if (drives[ind].type == IDE_TYPE_ATAPI) { |
| 146 | d = atapi_create_generic(d: &drives[ind]); |
| 147 | registry_mkname(disk: d, prefix: "cdrom" , counter: atapi_cnt++); |
| 148 | } |
| 149 | |
| 150 | if (!d) |
| 151 | continue; |
| 152 | |
| 153 | k_print_register(d->name); |
| 154 | registry_register(disk: d); |
| 155 | } |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |