Skip to content

Commit 9a1537b

Browse files
begin tidying up ahci driver
1 parent d4615bd commit 9a1537b

3 files changed

Lines changed: 75 additions & 114 deletions

File tree

include/ahci.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
#pragma once
77

8-
#include "kernel.h"
8+
#include <kernel.h>
99

1010
typedef enum ahci_fis_type_t {
1111
FIS_TYPE_REG_H2D = 0x27, // Register FIS - host to device
@@ -345,4 +345,14 @@ typedef struct achi_hba_cmd_tbl_t
345345
#define HDD_SECTOR_SIZE 512
346346
#define ATAPI_SECTOR_SIZE 2048
347347

348+
struct storage_device_t;
349+
348350
void init_ahci();
351+
352+
int find_cmdslot(ahci_hba_port_t *port, ahci_hba_mem_t *abar);
353+
bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *buf, ahci_hba_mem_t* abar);
354+
bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf, ahci_hba_mem_t* abar);
355+
bool ahci_atapi_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *buf, ahci_hba_mem_t* abar);
356+
uint64_t ahci_read_size(ahci_hba_port_t *port, ahci_hba_mem_t* abar);
357+
void build_sata_label(struct storage_device_t *sd, const uint8_t *id_page);
358+
void humanise_capacity(char *out, size_t out_len, uint64_t bytes);

src/ahci.c renamed to src/block/ahci/main.c

Lines changed: 63 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
1-
#include <kernel.h>
1+
#include "kernel.h"
22

33
void* aligned_buf = NULL;
44
uint8_t* raw_buf = NULL;
55
uint8_t* buf = NULL;
66
static uint8_t* raw_write_buf = NULL;
77
static uint8_t* aligned_write_buf = NULL;
88

9-
int find_cmdslot(ahci_hba_port_t *port, ahci_hba_mem_t *abar);
10-
bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *buf, ahci_hba_mem_t* abar);
11-
bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf, ahci_hba_mem_t* abar);
12-
bool ahci_atapi_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *buf, ahci_hba_mem_t* abar);
13-
uint64_t ahci_read_size(ahci_hba_port_t *port, ahci_hba_mem_t* abar);
14-
static void build_sata_label(storage_device_t *sd, const uint8_t *id_page);
15-
static void humanise_capacity(char *out, size_t out_len, uint64_t bytes);
16-
179
void ahci_handler([[maybe_unused]] uint8_t isr, [[maybe_unused]] uint64_t error, [[maybe_unused]] uint64_t irq, void* opaque)
1810
{
1911
ahci_hba_mem_t* abar = (ahci_hba_mem_t*)opaque;
@@ -208,9 +200,42 @@ static void build_atapi_label(storage_device_t *sd, const uint8_t *inq) {
208200
sd->ui.is_optical = true;
209201
}
210202

203+
bool wait_for_ready(ahci_hba_port_t* port) {
204+
int spin = 0;
205+
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
206+
spin++;
207+
}
208+
if (spin == 1000000) {
209+
return false;
210+
}
211+
return true;
212+
}
213+
214+
void fill_prdt(achi_hba_cmd_tbl_t* cmdtbl, size_t index, void* address, uint32_t byte_count_minus_one, bool interrupt) {
215+
cmdtbl->prdt_entry[index].dba = (uint32_t)((uint64_t)address & 0xffffffff);
216+
cmdtbl->prdt_entry[index].dbau = (uint32_t)(((uint64_t)(address) >> 32) & 0xffffffff);
217+
cmdtbl->prdt_entry[index].dbc = byte_count_minus_one;
218+
cmdtbl->prdt_entry[index].i = interrupt ? 1 : 0;
219+
}
220+
221+
ahci_hba_cmd_header_t* get_cmdheader_for_slot(ahci_hba_port_t* port, size_t slot, bool write, bool atapi, uint16_t prdtls) {
222+
ahci_hba_cmd_header_t *cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)port->clb;
223+
cmdheader += slot;
224+
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t);
225+
cmdheader->w = write ? 1 : 0;
226+
cmdheader->a = atapi ? 1 : 0;
227+
cmdheader->prdtl = prdtls;
228+
return cmdheader;
229+
}
230+
231+
achi_hba_cmd_tbl_t* get_and_clear_cmdtbl(ahci_hba_cmd_header_t* cmdheader) {
232+
achi_hba_cmd_tbl_t *cmdtbl = (achi_hba_cmd_tbl_t*)((uint64_t)cmdheader->ctba);
233+
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl-1)*sizeof(ahci_hba_prdt_entry_t));
234+
return cmdtbl;
235+
}
236+
211237
/* Fills a 512-byte ATA IDENTIFY buffer into 'out'. Returns true on success. */
212-
bool ahci_identify_page(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *out)
213-
{
238+
bool ahci_identify_page(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *out) {
214239
if (!out) {
215240
return false;
216241
}
@@ -227,31 +252,18 @@ bool ahci_identify_page(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *ou
227252
buf = (uint8_t*)(((uintptr_t)raw_buf + 0xFFF) & ~0xFFF);
228253
}
229254

230-
ahci_hba_cmd_header_t *cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)port->clb;
231-
cmdheader += slot;
232-
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t);
233-
cmdheader->w = 0;
234-
cmdheader->prdtl = 1;
235-
236-
achi_hba_cmd_tbl_t *cmdtbl = (achi_hba_cmd_tbl_t*)((uint64_t)cmdheader->ctba);
237-
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl - 1) * sizeof(ahci_hba_prdt_entry_t));
255+
ahci_hba_cmd_header_t* cmdheader = get_cmdheader_for_slot(port, slot, false, false, 1);
256+
achi_hba_cmd_tbl_t* cmdtbl = get_and_clear_cmdtbl(cmdheader);
238257

239-
cmdtbl->prdt_entry[0].dba = (uint32_t)((uint64_t)buf & 0xffffffff);
240-
cmdtbl->prdt_entry[0].dbau = (uint32_t)(((uint64_t)buf) >> 32);
241-
cmdtbl->prdt_entry[0].dbc = 511;
242-
cmdtbl->prdt_entry[0].i = 1;
258+
fill_prdt(cmdtbl, 0, buf, 511, true);
243259

244260
ahci_fis_reg_h2d_t *cmdfis = (ahci_fis_reg_h2d_t*)(&cmdtbl->cfis);
245261
memset(cmdfis, 0, sizeof(ahci_fis_reg_h2d_t));
246262
cmdfis->fis_type = FIS_TYPE_REG_H2D;
247263
cmdfis->c = 1;
248264
cmdfis->command = ATA_CMD_IDENTIFY;
249265

250-
int spin = 0;
251-
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
252-
spin++;
253-
}
254-
if (spin == 1000000) {
266+
if (!wait_for_ready(port)) {
255267
dprintf("Port hung [identify]\n");
256268
return false;
257269
}
@@ -302,20 +314,10 @@ bool atapi_enquiry(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *out, ui
302314
return false;
303315
}
304316

305-
ahci_hba_cmd_header_t *cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)port->clb;
306-
cmdheader += slot;
307-
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t);
308-
cmdheader->w = 0;
309-
cmdheader->a = 1;
310-
cmdheader->prdtl = 1;
311-
312-
achi_hba_cmd_tbl_t *cmdtbl = (achi_hba_cmd_tbl_t*)((uint64_t)cmdheader->ctba);
313-
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl - 1) * sizeof(ahci_hba_prdt_entry_t));
317+
ahci_hba_cmd_header_t* cmdheader = get_cmdheader_for_slot(port, slot, false, true, 1);
318+
achi_hba_cmd_tbl_t* cmdtbl = get_and_clear_cmdtbl(cmdheader);
314319

315-
cmdtbl->prdt_entry[0].dba = (uint32_t)((uint64_t)aligned_buf & 0xffffffff);
316-
cmdtbl->prdt_entry[0].dbau = (uint32_t)(((uint64_t)aligned_buf) >> 32);
317-
cmdtbl->prdt_entry[0].dbc = len - 1;
318-
cmdtbl->prdt_entry[0].i = 1;
320+
fill_prdt(cmdtbl, 0, aligned_buf, len - 1, true);
319321

320322
ahci_fis_reg_h2d_t *cmdfis = (ahci_fis_reg_h2d_t*)(&cmdtbl->cfis);
321323
memset(cmdfis, 0, sizeof(ahci_fis_reg_h2d_t));
@@ -332,11 +334,7 @@ bool atapi_enquiry(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *out, ui
332334
cmdtbl->acmd[4] = (uint8_t)len; /* Allocation length (1 byte for 6-byte CDB) */
333335
cmdtbl->acmd[5] = 0; /* Control */
334336

335-
int spin = 0;
336-
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
337-
spin++;
338-
}
339-
if (spin == 1000000) {
337+
if (!wait_for_ready(port)) {
340338
dprintf("Port hung [inquiry]\n");
341339
return false;
342340
}
@@ -454,20 +452,13 @@ bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *
454452

455453
port->is = (uint32_t)-1;
456454

457-
int spin = 0;
458455
int slot = find_cmdslot(port, abar);
459456
if (slot == -1) {
460457
return false;
461458
}
462459

463-
ahci_hba_cmd_header_t *cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)port->clb;
464-
cmdheader += slot;
465-
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t); // Command FIS size
466-
cmdheader->w = 0; // read
467-
cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count (ceil(count/16))
468-
469-
achi_hba_cmd_tbl_t *cmdtbl = (achi_hba_cmd_tbl_t*)((uint64_t)cmdheader->ctba);
470-
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl - 1) * sizeof(ahci_hba_prdt_entry_t));
460+
ahci_hba_cmd_header_t* cmdheader = get_cmdheader_for_slot(port, slot, false, false, ((count - 1) >> 4) + 1);
461+
achi_hba_cmd_tbl_t* cmdtbl = get_and_clear_cmdtbl(cmdheader);
471462

472463
uint8_t *rd_buf = aligned_read_buf;
473464

@@ -503,10 +494,7 @@ bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *
503494
cmdfis->countl = o_count & 0xFF;
504495
cmdfis->counth = (o_count >> 8) & 0xFF;
505496

506-
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
507-
spin++;
508-
}
509-
if (spin == 1000000) {
497+
if (!wait_for_ready(port)) {
510498
dprintf("Port hung [read] (start %lx count %x)\n", start, o_count);
511499
return false;
512500
}
@@ -539,20 +527,13 @@ bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *
539527
uint64_t ahci_read_size(ahci_hba_port_t *port, ahci_hba_mem_t* abar)
540528
{
541529
port->is = (uint32_t) -1; // Clear pending interrupt bits
542-
int spin = 0; // Spin lock timeout counter
543530
int slot = find_cmdslot(port, abar);
544531
if (slot == -1) {
545532
return 0;
546533
}
547-
548-
ahci_hba_cmd_header_t *cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)port->clb;
549-
cmdheader += slot;
550-
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t)/sizeof(uint32_t); // Command FIS size
551-
cmdheader->w = 0; // Read from device
552-
cmdheader->prdtl = 1; // PRDT entries count
553-
554-
achi_hba_cmd_tbl_t *cmdtbl = (achi_hba_cmd_tbl_t*)((uint64_t)cmdheader->ctba);
555-
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl-1)*sizeof(ahci_hba_prdt_entry_t));
534+
535+
ahci_hba_cmd_header_t* cmdheader = get_cmdheader_for_slot(port, slot, false, false, 1);
536+
achi_hba_cmd_tbl_t* cmdtbl = get_and_clear_cmdtbl(cmdheader);
556537

557538
if (!raw_buf && !buf) {
558539
raw_buf = (uint8_t*)kmalloc_low(HDD_SECTOR_SIZE + 0x1000); // extra for alignment
@@ -561,27 +542,20 @@ uint64_t ahci_read_size(ahci_hba_port_t *port, ahci_hba_mem_t* abar)
561542

562543
// 8K bytes (16 sectors) per PRDT
563544
// Last entry
564-
cmdtbl->prdt_entry[0].dba = (uint32_t)((uint64_t)buf & 0xffffffff);
565-
cmdtbl->prdt_entry[0].dbau = (uint32_t)(((uint64_t)(buf) >> 32) & 0xffffffff);
566-
cmdtbl->prdt_entry[0].dbc = 511;
567-
cmdtbl->prdt_entry[0].i = 1;
545+
fill_prdt(cmdtbl, 0, buf, 511, true);
568546

569547
// Setup command
570548
ahci_fis_reg_h2d_t *cmdfis = (ahci_fis_reg_h2d_t*)(&cmdtbl->cfis);
571549
memset(cmdfis, 0, sizeof(ahci_fis_reg_h2d_t));
572550
cmdfis->fis_type = FIS_TYPE_REG_H2D;
573551
cmdfis->c = 1; // Command
574552
cmdfis->command = ATA_CMD_IDENTIFY; // ATA_CMD_READ_DMA_EX;
575-
576-
// The below loop waits until the port is no longer busy before issuing a new command
577-
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
578-
spin++;
579-
}
580-
if (spin == 1000000) {
553+
554+
if (!wait_for_ready(port)) {
581555
dprintf("Port hung [read size]\n");
582-
return 0;
556+
return false;
583557
}
584-
558+
585559
port->ci = 1<<slot; // Issue command
586560

587561
// Wait for completion
@@ -623,22 +597,11 @@ bool ahci_atapi_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint
623597
return false;
624598
}
625599

626-
ahci_hba_cmd_header_t* cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)(port->clb);
627-
cmdheader += slot;
628-
629-
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t) / sizeof(uint32_t);
630-
cmdheader->w = 0;
631-
cmdheader->a = 1;
632-
cmdheader->prdtl = 1;
633-
634-
struct achi_hba_cmd_tbl_t* cmdtbl = (achi_hba_cmd_tbl_t*)(uint64_t)(cmdheader->ctba);
635-
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl - 1) * sizeof(ahci_hba_prdt_entry_t));
600+
ahci_hba_cmd_header_t* cmdheader = get_cmdheader_for_slot(port, slot, false, true, 1);
601+
achi_hba_cmd_tbl_t* cmdtbl = get_and_clear_cmdtbl(cmdheader);
636602

637603
int i = 0;
638-
cmdtbl->prdt_entry[i].dba = (uint32_t)((uint64_t)aligned_buf & 0xffffffff);
639-
cmdtbl->prdt_entry[i].dbau = (uint32_t)(((uint64_t)(aligned_buf) >> 32) & 0xffffffff);
640-
cmdtbl->prdt_entry[i].dbc = count * ATAPI_SECTOR_SIZE - 1; // 2048 bytes per sector
641-
cmdtbl->prdt_entry[i].i = 1;
604+
fill_prdt(cmdtbl, i, aligned_buf, count * ATAPI_SECTOR_SIZE - 1, true);
642605

643606
ahci_fis_reg_h2d_t* cmdfis = (ahci_fis_reg_h2d_t*)cmdtbl->cfis;
644607
memset(cmdfis, 0, sizeof(ahci_fis_reg_h2d_t));
@@ -704,7 +667,6 @@ bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf
704667
uint32_t starth = ((start & 0xFFFFFFFF00000000) >> 32);
705668
uint32_t o_count = count;
706669
port->is = (uint32_t)-1; // Clear pending interrupt bits
707-
int spin = 0; // Spin lock timeout counter
708670
int slot = find_cmdslot(port, abar);
709671
if (slot == -1) {
710672
return false;
@@ -717,15 +679,8 @@ bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf
717679

718680
memcpy(aligned_write_buf, buf, o_count * HDD_SECTOR_SIZE);
719681

720-
ahci_hba_cmd_header_t* cmdheader = (ahci_hba_cmd_header_t*)(uint64_t)port->clb;
721-
cmdheader += slot;
722-
723-
cmdheader->cfl = sizeof(ahci_fis_reg_h2d_t)/sizeof(uint32_t); // Command FIS size
724-
cmdheader->w = 1; // Write device
725-
cmdheader->prdtl = (uint16_t)((o_count-1)>>4) + 1; // PRDT entries count
726-
727-
achi_hba_cmd_tbl_t *cmdtbl = (achi_hba_cmd_tbl_t*)((uint64_t)cmdheader->ctba);
728-
memset(cmdtbl, 0, sizeof(achi_hba_cmd_tbl_t) + (cmdheader->prdtl-1)*sizeof(ahci_hba_prdt_entry_t));
682+
ahci_hba_cmd_header_t* cmdheader = get_cmdheader_for_slot(port, slot, true, false, ((o_count-1)>>4) + 1);
683+
achi_hba_cmd_tbl_t* cmdtbl = get_and_clear_cmdtbl(cmdheader);
729684

730685
uint8_t* wr_buf = aligned_write_buf;
731686

@@ -765,11 +720,7 @@ bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf
765720
cmdfis->countl = o_count & 0xFF;
766721
cmdfis->counth = (o_count >> 8) & 0xFF;
767722

768-
// The below loop waits until the port is no longer busy before issuing a new command
769-
while ((port->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000) {
770-
spin++;
771-
}
772-
if (spin == 1000000) {
723+
if (!wait_for_ready(port)) {
773724
dprintf("Port hung [write] (start %lx count %x)\n", start, o_count);
774725
return false;
775726
}
@@ -818,7 +769,7 @@ static void ata_copy_str(char *dst, size_t dst_len, const uint8_t *id_page, int
818769
}
819770
}
820771

821-
static void humanise_capacity(char *out, size_t out_len, uint64_t bytes) {
772+
void humanise_capacity(char *out, size_t out_len, uint64_t bytes) {
822773
const char *units[] = { "B", "KB", "MB", "GB", "TB", "PB" };
823774
int u = 0;
824775
uint64_t v = bytes;
@@ -831,7 +782,7 @@ static void humanise_capacity(char *out, size_t out_len, uint64_t bytes) {
831782
snprintf(out, out_len, "%lu %s", v, units[u]);
832783
}
833784

834-
static void build_sata_label(storage_device_t *sd, const uint8_t *id_page) {
785+
void build_sata_label(storage_device_t *sd, const uint8_t *id_page) {
835786
char model[48] = {0};
836787
char size_str[24] = {0};
837788

src/fs/ramdisk.c renamed to src/block/ramdisk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include <kernel.h>
1+
#include "kernel.h"
22

33
typedef struct ramdisk_t {
44
const char* name;

0 commit comments

Comments
 (0)