--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: ahci.c
+ * Author: Zhao Yanbai
+ * 2026-01-16 21:32:08 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#include <pci.h>
+#include <system.h>
+#include <ioremap.h>
+#include <string.h>
+
+#include <sata.h>
+
+#include <pci.h>
+#include <list.h>
+
+void init_ahci_device(pci_device_t* pci, int index) {
+ assert(pci != NULL);
+ assert(index >= 0);
+
+ printk("found ahci[%d] sata pci %03d:%02d.%d #%02d %04X:%04X\n", index, pci->bus, pci->dev, pci->devfn,
+ pci->intr_line, pci->vendor, pci->device);
+
+ uint32_t bar5 = pci->bars[5];
+ printk("ahci pci BAR5 value 0x%08X\n", bar5);
+ for (int i = 0; i < 6; i++) {
+ printk(" ahci pci BAR%u value 0x%08X\n", i, pci->bars[i]);
+ }
+
+ pci_write_config_word(0xFFFFFFFF, PCI_BAR5);
+ uint32_t size = pci_read_config_word(PCI_BAR5);
+ assert(size > 0);
+#if 1
+ size += 1;
+#else
+ size &= 0xFFFFFFF0;
+ size = (~size) + 1;
+#endif
+ printk("ahci pci BAR5 size 0x%08X\n", size);
+
+ uint32_t* mapped = ioremap(bar5, size);
+ if (mapped == NULL) {
+ panic("failed to map sata bar5\n");
+ return;
+ }
+ printk("ahci pci BAR5 mapped to 0x%08X\n", mapped);
+
+ struct {
+ uint32_t offset;
+ const char* name;
+ } regs[] = {
+ {0x00, "CAP"}, //
+ {0x04, "GHC"}, //
+ {0x08, "IS"}, //
+ {0x0C, "PI"}, //
+ {0x10, "VS"}, //
+ {0x14, "CCC_CTL"}, //
+ {0x18, "CCC_PORTS"}, //
+ {0x1C, "EM_LOC"}, //
+ {0x20, "EM_CTL"}, //
+ {0x24, "CAP2"}, //
+ {0x28, "BOHC"}, //
+ };
+
+ for (int i = 0; i < sizeof(regs) / sizeof(regs[0]); i++) {
+ uint32_t value = mapped[regs[i].offset / 4];
+ printk(" ahci registers 0x%08X[%s]\n", value, regs[i].name);
+ }
+
+ ahci_hba_t* hba = (ahci_hba_t*)mapped;
+
+ hba->global_hba_control |= AHCI_ENABLE;
+
+ uint32_t cap = hba->capability;
+
+ int num_ports = (cap & 0x1F) + 1;
+ int num_cs = ((cap >> 8) & 0x1F) + 1; // command slots
+ int iss = (cap >> 20) & 0x0F; // interface speed support
+ int s64a = (cap >> 31) & 0x01; // supports 64bit addressing
+ printk("ahci ports %d cmd slots %d\n", num_ports, num_cs);
+ printk("support 64bit addressing %s\n", s64a ? "Y" : "N");
+
+ switch (iss) {
+ case 0b0001:
+ printk(" Gen1 (1.5 Gbps)\n");
+ break;
+ case 0b0010:
+ printk(" Gen2 (3.0 Gbps)\n");
+ break;
+ case 0b0100:
+ printk(" Gen3 (6.0 Gbps)\n");
+ break;
+ default:
+ printk(" unknown interface speed support %02X\n", iss);
+ break;
+ }
+
+ uint32_t ahci_pi = hba->ports_implemented;
+ printk("ahci port implemented %08X\n", ahci_pi);
+
+ uint32_t ahci_version = hba->version;
+ char version[16];
+ switch (ahci_version) {
+ case 0x00000905:
+ strcpy(version, "0.95");
+ break;
+ case 0x00010000:
+ strcpy(version, "1.0");
+ break;
+ case 0x00010100:
+ strcpy(version, "1.1");
+ break;
+ case 0x00010200:
+ strcpy(version, "1.2");
+ break;
+ case 0x00010300:
+ strcpy(version, "1.3");
+ break;
+ case 0x00010301:
+ strcpy(version, "1.3.1");
+ break;
+ default:
+ strcpy(version, "unknown");
+ break;
+ }
+ printk("ahci version %s[%08x]\n", version, ahci_version);
+
+ assert(sizeof(ahci_port_t) == 0x80);
+ int sata_index = 0;
+ for (int i = 0; i < num_ports; i++) {
+ if (ahci_pi & (1 << i)) {
+ ahci_port_t* port = hba->ports + i;
+ uint32_t sata_status = port->sata_status;
+ uint32_t sata_det = (sata_status >> 0) & 0x0F; // device detection
+ uint32_t sata_spd = (sata_status >> 4) & 0x0F; // current interface speed
+ uint32_t sata_ipm = (sata_status >> 8) & 0x0F; // interface power management
+
+ if (sata_det != 3) {
+ continue;
+ }
+
+ if (sata_ipm != 0x01) {
+ continue;
+ }
+
+ switch (port->signature) {
+ case SATA_SIGNATURE_ATA:
+ printk("SATA device detected\n");
+ extern void init_sata_device(ahci_hba_t * hba, ahci_port_t * port, int index);
+ init_sata_device(hba, port, sata_index);
+ sata_index++;
+ break;
+ case SATA_SIGNATURE_ATAPI:
+ printk("SATAPI device detected\n");
+ break;
+ case SATA_SIGNATURE_SEMB:
+ printk("SEMB device detected\n");
+ break;
+ case SATA_SIGNATURE_PM:
+ printk("PM device detected\n");
+ break;
+ default:
+ printk("unknown ahci device detected\n");
+ break;
+ }
+ }
+ }
+
+ // TODO
+ // 开启ahci的global_hba_control的interrupt enable位
+ hba->global_hba_control |= AHCI_INTERRUPT_ENABLE;
+}
+
+void init_ahci() {
+ // progif
+ // 0x01 AHCI
+ pci_init_device(0x0106, 0x01, init_ahci_device);
+}
--- /dev/null
+/*
+ * ------------------------------------------------------------------------
+ * File Name: ahci.h
+ * Author: Zhao Yanbai
+ * 2026-01-16 21:32:06 Friday CST
+ * Description: none
+ * ------------------------------------------------------------------------
+ */
+
+#pragma once
+
+#include <types.h>
+
+const static int AHCI_PORT_COUNT = 32;
+const static int AHCI_CMD_SLOT_COUNT = 32;
+
+const static int AHCI_DEVICE_NULL = 0;
+const static int AHCI_DEVICE_SATA = 1;
+const static int AHCI_DEVICE_SEMB = 2;
+const static int AHCI_DEVICE_PM = 3;
+const static int AHCI_DEVICE_SATAPI = 4;
+
+const static int AHCI_FIS_TYPE_REG_H2D = 0x27;
+const static int AHCI_FIS_TYPE_REG_D2H = 0x34;
+
+typedef struct {
+ uint8_t fis_type;
+ uint8_t pmport : 4; // port multiplier
+ uint8_t _reserved0 : 3;
+ uint8_t c : 1; // 0: control; 1: command
+
+ uint8_t command;
+ uint8_t feature;
+
+ uint8_t lba0;
+ uint8_t lba1;
+ uint8_t lba2;
+ uint8_t device;
+
+ uint8_t lba3;
+ uint8_t lba4;
+ uint8_t lba5;
+ uint8_t feature_high;
+
+ uint8_t count_low;
+ uint8_t count_high;
+ uint8_t icc;
+ uint8_t control;
+
+ uint8_t _reserved1[4];
+} ahci_fis_reg_h2d_t;
+
+typedef struct {
+ uint32_t data_base; // 第0位必为0
+
+ uint32_t _data_base_upper;
+
+ uint32_t _reserved;
+
+ uint32_t data_byte_count : 22; // 第0位必为1。另外该值表示实际为data_byte_count+1字节
+ uint32_t _reserved1 : 9;
+ uint32_t ioc : 1; // interrupt on completion
+
+} ahci_prdt_entry_t;
+
+typedef struct {
+ // 0x00 - 0x40
+ uint8_t cmd_fis[64];
+
+ // 0x40 - 0x50
+ uint8_t _atapi_cmd[16]; // 12 or 16 bytes
+
+ // 0x50 - 0x80
+ uint8_t _reserved[48];
+
+ // 0x80
+ ahci_prdt_entry_t prdt[0]; // update to 65536 entries
+} ahci_cmd_table_t;
+
+// prd: physical region descriptor
+typedef struct {
+ 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 R : 1;
+ uint32_t pmp : 4;
+ uint32_t prdtl : 16; // prdt entry count
+
+ uint32_t prd_byte_count; // prd byte count
+
+ uint32_t cmd_table_base; // 指向ahci_cmd_table_t
+ uint32_t _cmd_table_base_upper;
+
+ uint32_t reserved[4];
+} ahci_cmd_header_t;
+
+typedef struct {
+ uint32_t cmd_list_base;
+ uint32_t _cmd_list_base_upper;
+ uint32_t fis_base;
+ uint32_t _fis_base_upper;
+ uint32_t interrupt_status;
+ uint32_t interrupt_enable;
+ uint32_t command_and_status;
+ uint32_t reserved;
+ uint32_t task_file_data;
+ uint32_t signature;
+ // DET[03:00]: Device Detection
+ // SPD[07:04]: Current Interface Speed
+ // IPM[11:08]: Interface Power Management
+ uint32_t sata_status;
+ uint32_t sata_control;
+ uint32_t sata_error;
+ uint32_t sata_active;
+ uint32_t cmd_issue;
+ uint32_t sata_notification;
+ uint32_t fis_base_switch_control;
+ uint32_t device_sleep;
+ uint32_t reserved2[10];
+ uint32_t vendor_specific[4];
+} ahci_port_t;
+
+typedef struct {
+ // 0x00 - 0x2C
+ uint32_t capability;
+#define AHCI_ENABLE 0x80000000
+#define AHCI_INTERRUPT_ENABLE 0x00000002
+#define AHCI_RESET 0x00000001
+ uint32_t global_hba_control;
+ uint32_t interrupt_status;
+ uint32_t ports_implemented;
+ uint32_t version;
+ uint32_t ccc_ctrl; // command completion coalescing control
+ uint32_t ccc_ports; // command completion coalescing ports
+ uint32_t em_loc; // enclosure management location
+ uint32_t em_ctl; // enclosure management control
+ uint32_t capability_extended; // capability extended
+ uint32_t bios_handoff_control_status;
+
+ // 0x2C - 0xA0
+ uint8_t reserved[0xA0 - 0x2C];
+
+ // 0xA0 - 0x100
+ uint8_t vendor_specific[0x100 - 0xA0];
+
+ // 0x100
+ ahci_port_t ports[32];
+} ahci_hba_t;
* ------------------------------------------------------------------------
*/
-#include <pci.h>
-#include <system.h>
+#include <sata.h>
+#include <printk.h>
#include <ioremap.h>
+#include <page.h>
+#include <assert.h>
#include <string.h>
+#include <system.h>
-void init_sata() {
- pci_device_t* pci = pci_find_device_by_classcode(0x0106);
- if (pci == NULL) {
- printk("can not find pci classcode: %08x", 0x0106);
- printk("can not find sata controller");
- return;
+void init_sata_device(ahci_hba_t* hba, ahci_port_t* port, int index) {
+ assert(hba != NULL);
+ assert(port != NULL);
+ assert(index >= 0 && index < MAX_SATA_DEVICES);
+
+ sata_device_t* sata = sata_devices + index;
+ sata->hba = hba;
+ sata->port = port;
+ sata->index = 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;
+
+ if (PAGE_ALIGN(port->cmd_list_base) != PAGE_ALIGN(port->fis_base)) {
+ fis_base = (vaddr_t)ioremap(PAGE_ALIGN(port->fis_base), 0x1000);
}
- // progif
- // 0x01 AHCI
+ cmd_list_base += port->cmd_list_base - PAGE_ALIGN(port->cmd_list_base);
+ fis_base += port->fis_base - PAGE_ALIGN(port->fis_base);
+
+ printk(" cmd_list_base %08x->%08x\n", port->cmd_list_base, cmd_list_base);
+ printk(" fis_base %08x->%08x\n", port->fis_base, fis_base);
+
+ sata->cmd_list_base_vaddr = (ahci_cmd_header_t*)cmd_list_base;
+ sata->fis_base_vaddr = fis_base;
+
//
- // 另外读取 BAR5 的 CAP 寄存器,如果 CAP 寄存器的 31 位为 1,则表示支持 AHCI 模式。
+ // 1. 端口重置
+ // 2. 分配空间,设置cmd_list_base, fis_base
+ // 3. 将sata_error清空
+ // 4. 将需要使用的中断通过interrupt_enable开启
- if (pci->progif == 0x01) {
- printk("AHCI mode supported\n");
- } else {
- printk("AHCI mode not supported\n");
+ //
+ assert(sizeof(ahci_cmd_header_t) == 32);
+ ahci_cmd_header_t* cmd_list = (ahci_cmd_header_t*)sata->cmd_list_base_vaddr;
+#if 1
+ for (int i = 0; i < 32; i++) {
+ ahci_cmd_header_t* hdr = &cmd_list[i];
+ printk(" cmd_list[%02d] base %08x prdt %04x:%d\n", i, hdr->cmd_table_base, hdr->prdtl, hdr->prdtl);
+ hdr->cmd_table_base = 0;
+ hdr->prdtl = 0;
}
+#endif
+
+ sata->cmd_table_paddr = (paddr_t)page2pa(alloc_one_page(0));
+ sata->cmd_table_vaddr = (ahci_cmd_table_t*)ioremap(sata->cmd_table_paddr, PAGE_SIZE);
+ memset((void*)sata->cmd_table_vaddr, 0, PAGE_SIZE);
+
+ sata->data_paddr = (paddr_t)page2pa(alloc_one_page(0));
+ sata->data_vaddr = (vaddr_t)ioremap(sata->data_paddr, PAGE_SIZE);
+ memset((void*)sata->data_vaddr, 0, PAGE_SIZE);
+
+ memset((void*)cmd_list, 0, sizeof(ahci_cmd_header_t));
+ cmd_list[0].cfl = 0;
+ cmd_list[0].a = 0;
+ cmd_list[0].w = 0;
+ cmd_list[0].pmp = 0;
+ cmd_list[0].prdtl = 1;
+ cmd_list[0].prd_byte_count = 0;
+ cmd_list[0].cmd_table_base = sata->cmd_table_paddr;
+ sata->cmd_list0 = cmd_list;
+
+ ahci_cmd_table_t* cmd_table = (ahci_cmd_table_t*)sata->cmd_table_vaddr;
+ memset(cmd_table, 0, sizeof(ahci_cmd_table_t));
+ sata->cmd_table0 = cmd_table + 0;
+ sata->prdte0 = cmd_table[0].prdt + 0;
+
+ sata->prdte0->data_base = sata->data_paddr;
+ sata->prdte0->data_byte_count = (512 - 1) | 1;
+ sata->prdte0->ioc = 1;
- printk("found ahci sata pci progif %02x %03d:%02d.%d #%02d %04X:%04X\n", pci->progif, pci->bus, pci->dev,
- pci->devfn, pci->intr_line, pci->vendor, pci->device);
+ //
+ 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_IDENTIFY;
+ fis->device = SATA_DEVICE_LBA;
+
+ 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->prd_byte_count = 0;
+
+ // 清除中断状态
+ // 写1清0
+ port->interrupt_status = port->interrupt_status;
- uint32_t bar5 = pci->bars[5];
- printk("ahci pci BAR5 value 0x%08X\n", bar5);
- for (int i = 0; i < 6; i++) {
- printk(" ahci pci BAR%u value 0x%08X\n", i, pci->bars[i]);
- // if (pci->bars[i] != 0) {
- // assert((pci->bars[i] & 0x1) == 0x1);
- // }
- }
+ //
+ port->cmd_issue = 1 << 0;
- pci_write_config_word(0xFFFFFFFF, PCI_BAR5);
- uint32_t size = pci_read_config_word(PCI_BAR5);
- printk("ahci pci BAR5 size 0x%08X\n", size);
+ uint32_t timeout = 1000000;
+ while (timeout--) {
+ if (port->interrupt_status & 1) {
+ break;
+ }
+ if (port->sata_error) {
+ printk("SATA ERROR: %08x\n", port->sata_error);
+ return;
+ }
+ asm("pause");
+ }
- assert(size > 0);
- size += 1;
+ if (timeout == 0) {
+ printk("SATA TIMEOUT\n");
+ return;
+ }
- uint32_t* mapped = ioremap(bar5, size);
- if (mapped == NULL) {
- panic("failed to map sata bar5\n");
+ if (sata->cmd_list0->prd_byte_count != 512) {
+ printk("SATA PRD BYTE COUNT: %08x\n", sata->cmd_list0->prd_byte_count);
return;
}
- printk("ahci pci BAR5 mapped to 0x%08X\n", mapped);
-
- struct {
- uint32_t offset;
- const char* name;
- uint32_t value;
- } regs[] = {
- {0x00, "CAP"}, //
- {0x04, "GHC"}, //
- {0x08, "IS"}, //
- {0x0C, "PI"}, //
- {0x10, "VS"}, //
- {0x14, "CCC_CTL"}, //
- {0x18, "CCC_PORTS"}, //
- {0x1C, "EM_LOC"}, //
- {0x20, "EM_CTL"}, //
- {0x24, "CAP2"}, //
- {0x28, "BOHC"}, //
- };
-
- for (int i = 0; i < sizeof(regs) / sizeof(regs[0]); i++) {
- regs[i].value = mapped[regs[i].offset / 4];
- printk("ahci registers 0x%08X[%s]\n", regs[i].value, regs[i].name);
+
+ printk("identify data %08x\n", sata->data_vaddr);
+ uint16_t* identify = (uint16_t*)sata->data_vaddr;
+
+ // 第49个word的第8个bit位表示是否支持DMA
+ // 第83个word的第10个bit位表示是否支持LBA48,为1表示支持。
+ // 第100~103个word的八个字节表示user的LBA最大值
+ if ((identify[49] & (1 << 8)) != 0) {
+ sata->dma = 1;
+ } else {
+ panic("your sata disk drive do not support DMA");
}
- uint32_t cap = mapped[0x00 / 4];
- int num_ports = (cap & 0x1F) + 1;
- int num_cs = (cap >> 8) & 0x1F; // command slots
- int iss = (cap >> 20) & 0x0F; // interface speed support
- int s64a = (cap >> 31) & 0x01;
- printk("ahci num_ports %d num_cs %d\n", num_ports, num_cs);
-
- switch (iss) {
- case 0b0001:
- printk(" Gen1 (1.5 Gbps)\n");
- break;
- case 0b0010:
- printk(" Gen2 (3.0 Gbps)\n");
- break;
- case 0b0100:
- printk(" Gen3 (6.0 Gbps)\n");
- break;
- default:
- printk(" unknown iss %02X\n", iss);
- break;
+ uint64_t max_lba = 0;
+
+ if ((identify[83] & (1 << 10)) != 0) {
+ sata->lba48 = 1;
+ max_lba = *(uint64_t*)(identify + 100);
+ } else {
+ panic("your sata disk drive do not support LBA48");
+ // max_lba = (identify[61] << 16) | identify[60];
}
- printk("support 64bit addressing %s\n", s64a ? "Y" : "N");
-
- uint32_t ahci_pi = mapped[0x0C / 4];
- printk("ahci port implemented %08X\n", ahci_pi);
-
- uint32_t ahci_version = mapped[0x10 / 4];
- printk("ahci version 0x%08X\n", ahci_version);
-
- char version[16];
- switch (ahci_version) {
- case 0x00000905:
- strcpy(version, "0.95");
- break;
- case 0x00010000:
- strcpy(version, "1.0");
- break;
- case 0x00010100:
- strcpy(version, "1.1");
- break;
- case 0x00010200:
- strcpy(version, "1.2");
- break;
- case 0x00010300:
- strcpy(version, "1.3");
- break;
- case 0x00010301:
- strcpy(version, "1.3.1");
- break;
- default:
- strcpy(version, "unknown");
- break;
+
+ sata->max_lba = max_lba;
+
+ printk("%s %s size: %u MB ", sata->dma == 1 ? "DMA" : "", sata->lba48 == 1 ? "LBA48" : "LBA28",
+ (max_lba * 512) >> 20);
+
+ uint16_t sata_major = identify[80];
+ uint16_t sata_minor = identify[81];
+ if (sata_major & (1 << 8)) {
+ printk("ATA8-ACS ");
}
- printk("ahci version %s\n", version);
-
- typedef struct {
- uint32_t cmd_list_base;
- uint32_t cmd_list_base_upper;
- uint32_t fis_base;
- uint32_t fis_base_upper;
- uint32_t interrupt_status;
- uint32_t interrupt_enable;
- uint32_t command_and_status;
- uint32_t reserved;
- uint32_t task_file_data;
- uint32_t signature;
- uint32_t sata_status;
- uint32_t sata_control;
- uint32_t sata_error;
- uint32_t sata_active;
- uint32_t cmd_issue;
- uint32_t sata_notification;
- uint32_t fis_base_switch_control;
- uint32_t device_sleep;
- uint32_t reserved2[10];
- uint32_t vendor_specific[4];
- } ahci_port_t;
-
- assert(sizeof(ahci_port_t) == 0x80);
- for (int i = 0; i < 32; i++) {
- if (ahci_pi & (1 << i)) {
- // printk("ahci port %d implemented\n", i);
- ahci_port_t* port = (ahci_port_t*)(mapped + (0x100 + i * 0x80) / 4);
- // printk("ahci port %d dt 0x%08X\n", i, port->command_and_status);
- uint32_t sata_status = port->sata_status;
- uint32_t sata_det = (sata_status >> 0) & 0x0F;
- uint32_t sata_ipm = (sata_status >> 8) & 0x0F;
-
- if (sata_det != 3) {
- continue;
- }
-
- if (sata_ipm != 0x01) {
- continue;
- }
-
- printk("ahci port %d clb %08x fb %08x sata_status 0x%08X signature %08X\n", i, port->cmd_list_base,
- port->fis_base, sata_status, port->signature);
-
-#define SATA_SIGNATURE_ATA 0x00000101
-#define SATA_SIGNATURE_ATAPI 0xEB140101
-#define SATA_SIGNATURE_SEMB 0xC33C0101
-#define SATA_SIGNATURE_PM 0x96690101
-
- switch (port->signature) {
- case SATA_SIGNATURE_ATA:
- printk("SATA device detected\n");
- break;
- case SATA_SIGNATURE_ATAPI:
- printk("SATAPI device detected\n");
- break;
- case SATA_SIGNATURE_SEMB:
- printk("SEMB device detected\n");
- break;
- case SATA_SIGNATURE_PM:
- printk("PM device detected\n");
- break;
- default:
- printk("unknown device detected\n");
- break;
- }
- }
+ if (sata_major & (1 << 7)) {
+ printk("ATA/ATAPI-7 ");
+ }
+ if (sata_major & (1 << 6)) {
+ printk("ATA/ATAPI-6 ");
+ }
+ if (sata_major & (1 << 5)) {
+ printk("ATA/ATAPI-5 ");
+ }
+ if (sata_major & (1 << 4)) {
+ printk("ATA/ATAPI-4 ");
+ }
+
+ printk("[Major %04X Minor %02X]\n", sata_major, sata_minor);
+
+ char s[64];
+ sata_read_identify_string(identify, 10, 19, s);
+ printk("SN: %s\n", s);
+
+ sata_read_identify_string(identify, 23, 26, s);
+ printk("Firmware Revision: %s\n", s);
+
+ sata_read_identify_string(identify, 27, 46, s);
+ 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;
+ for (; i <= (end - bgn); i++) {
+ buf[2 * i + 1] = p[0];
+ buf[2 * i + 0] = p[1];
+ p += 2;
}
+ buf[i] = 0;
}