kprintf("\t Port %d: %s (%x)\n",
i,
&sata_ifs[device_state],
- port->regs[HBA_RPxSIG]);
+ port->device->flags);
struct hba_device* dev_info = port->device;
if (!device_state || !dev_info) {
// 构建命令头(Command Header)和命令表(Command Table)
struct hba_cmdh* cmd_header = &port->cmdlst[slot];
- struct hba_cmdt* cmd_table = valloc_dma(sizeof(struct hba_cmdt));
+ struct hba_cmdt* cmd_table = vcalloc_dma(sizeof(struct hba_cmdt));
memset(cmd_header, 0, sizeof(*cmd_header));
- memset(cmd_table, 0, sizeof(*cmd_table));
// 将命令表挂到命令头上
cmd_header->cmd_table_base = vmm_v2p(cmd_table);
#include <hal/ahci/sata.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
#include <lunaix/spike.h>
int
int bitmask = 1 << slot;
// 确保端口是空闲的
- wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY)));
+ wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY | HBA_PxTFD_DRQ)));
port->regs[HBA_RPxIS] = 0;
- table->entries[0] =
- (struct hba_prdte){ .byte_count = size - 1, .data_base = buffer };
+ table->entries[0] = (struct hba_prdte){ .byte_count = size - 1,
+ .data_base = vmm_v2p(buffer) };
header->prdt_len = 1;
header->options |= HBA_CMDH_WRITE * (write == 1);
- uint16_t count = size / port->device->block_size;
- if (count == 0 && size < port->device->block_size) {
- // 一个special case: 当count=0的时候,表示的是65536个区块会被传输
- // 如果这个0是因为不够除而导致的,那么说明size太小了
- goto fail;
- }
-
+ uint16_t count = ICEIL(size, port->device->block_size);
struct sata_reg_fis* fis = table->command_fis;
+
if ((port->device->flags & HBA_DEV_FEXTLBA)) {
// 如果该设备支持48位LBA寻址
sata_create_fis(
fis, write ? ATA_WRITE_DMA_EXT : ATA_READ_DMA_EXT, lba, count);
+ fis->dev = (1 << 6) * (!write);
} else {
sata_create_fis(fis, write ? ATA_WRITE_DMA : ATA_READ_DMA, lba, count);
}
- port->regs[HBA_RPxCI] = bitmask;
+ int retries = 0;
- wait_until(!(port->regs[HBA_RPxCI] & bitmask));
+ while (retries < MAX_RETRY) {
+ port->regs[HBA_RPxCI] = bitmask;
- if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) {
- // 有错误
- sata_read_error(port);
- goto fail;
- }
+ wait_until(!(port->regs[HBA_RPxCI] & bitmask));
- vfree_dma(table);
- return 1;
+ if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) {
+ // 有错误
+ sata_read_error(port);
+ retries++;
+ } else {
+ vfree_dma(table);
+ return 1;
+ }
+ }
fail:
vfree_dma(table);
#include <hal/ahci/utils.h>
#include <klibc/string.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
#include <lunaix/spike.h>
+#include <lunaix/syslog.h>
void
scsi_create_packet12(struct scsi_cdb12* cdb,
memset(cdb, 0, sizeof(*cdb));
cdb->opcode = opcode;
cdb->lba_be = SCSI_FLIP(lba);
- cdb->length = alloc_size;
+ cdb->length = SCSI_FLIP(alloc_size);
}
void
{
memset(cdb, 0, sizeof(*cdb));
cdb->opcode = opcode;
- cdb->lba_be_hi = SCSI_FLIP(lba >> 32);
+ cdb->lba_be_hi = SCSI_FLIP((uint32_t)(lba >> 32));
cdb->lba_be_lo = SCSI_FLIP((uint32_t)lba);
- cdb->length = alloc_size;
+ cdb->length = SCSI_FLIP(alloc_size);
}
void
int bitmask = 1 << slot;
// 确保端口是空闲的
- wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY)));
+ wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY | HBA_PxTFD_DRQ)));
port->regs[HBA_RPxIS] = 0;
- table->entries[0] =
- (struct hba_prdte){ .byte_count = size - 1, .data_base = buffer };
+ table->entries[0] = (struct hba_prdte){ .byte_count = size - 1,
+ .data_base = vmm_v2p(buffer) };
header->prdt_len = 1;
header->options |= (HBA_CMDH_WRITE * (write == 1)) | HBA_CMDH_ATAPI;
- uint32_t count = size / port->device->block_size;
- if (count == 0) {
- // 对ATAPI设备来说,READ/WRITE (16/12) 没有这个count=0的 special case
- // 但是对于READ/WRITE (6),就存在这个special case
- goto fail;
- }
+ uint32_t count = ICEIL(size, port->device->block_size);
struct sata_reg_fis* fis = table->command_fis;
void* cdb = table->atapi_cmd;
- sata_create_fis(fis, ATA_PACKET, (size << 8) & 0xffffff, 0);
+ sata_create_fis(fis, ATA_PACKET, (size << 8), 0);
+ fis->feature = 1 | ((!write) << 2);
if (port->device->cbd_size == 16) {
scsi_create_packet16((struct scsi_cdb16*)cdb,
write ? SCSI_WRITE_BLOCKS_16 : SCSI_READ_BLOCKS_16,
lba,
count);
+ ((struct scsi_cdb16*)cdb)->misc1 = 3 << 5; // 禁用保护检查
} else {
scsi_create_packet12((struct scsi_cdb12*)cdb,
write ? SCSI_WRITE_BLOCKS_12 : SCSI_READ_BLOCKS_12,
lba,
count);
+ ((struct scsi_cdb12*)cdb)->misc1 = 3 << 5; // 禁用保护检查
}
- port->regs[HBA_RPxCI] = bitmask;
+ int retries = 0;
- wait_until(!(port->regs[HBA_RPxCI] & bitmask));
+ while (retries < MAX_RETRY) {
+ port->regs[HBA_RPxCI] = bitmask;
- if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) {
- // 有错误
- sata_read_error(port);
- goto fail;
- }
+ wait_until(!(port->regs[HBA_RPxCI] & bitmask));
- vfree_dma(table);
- return 1;
+ if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) {
+ // 有错误
+ sata_read_error(port);
+ retries++;
+ } else {
+ vfree_dma(table);
+ return 1;
+ }
+ }
fail:
vfree_dma(table);
{
dev_info->max_lba = *((uint32_t*)(data + IDDEV_OFFMAXLBA));
dev_info->block_size = *((uint32_t*)(data + IDDEV_OFFLSECSIZE));
- dev_info->cbd_size = (*data & 0x3) ? 12 : 16;
+ dev_info->cbd_size = (*data & 0x3) ? 16 : 12;
dev_info->wwn = *(uint64_t*)(data + IDDEV_OFFWWN);
if (!dev_info->block_size) {
#ifndef __LUNAIX_AHCI_H
#define __LUNAIX_AHCI_H
+#include "hba.h"
+
/*
* Macro naming rule:
* HBA_R[xxx]
#define ATA_IDENTIFY_DEVICE 0xec
#define ATA_IDENTIFY_PAKCET_DEVICE 0xa1
#define ATA_PACKET 0xa0
-#define ATA_READ_DMA_EXT 0xc8
-#define ATA_READ_DMA 0x25
-#define ATA_WRITE_DMA_EXT 0xca
-#define ATA_WRITE_DMA 0x35
+#define ATA_READ_DMA_EXT 0x25
+#define ATA_READ_DMA 0xc8
+#define ATA_WRITE_DMA_EXT 0x35
+#define ATA_WRITE_DMA 0xca
+
+#define MAX_RETRY 2
struct sata_fis_head
{
uint8_t lba0, lba8, lba16;
uint8_t dev;
uint8_t lba24, lba32, lba40;
- uint8_t reserved1;
+ uint8_t feature;
uint16_t count;
// 除法向上取整
#define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k))
+#define ICEIL(x, y) ((x) / (y) + ((x) % (y) != 0))
+
// 除法向下取整
#define FLOOR(v, k) ((v) >> (k))
#include <stdarg.h>
-#define _LEVEL_INFO "0"
-#define _LEVEL_WARN "1"
+#define _LEVEL_INFO "0"
+#define _LEVEL_WARN "1"
#define _LEVEL_ERROR "2"
#define _LEVEL_DEBUG "3"
-#define KINFO "\x1b" _LEVEL_INFO
-#define KWARN "\x1b" _LEVEL_WARN
-#define KERROR "\x1b" _LEVEL_ERROR
-#define KDEBUG "\x1b" _LEVEL_DEBUG
-
-#define LOG_MODULE(module) \
- static void kprintf(const char* fmt, ...) { \
- va_list args; \
- va_start(args, fmt); \
- __kprintf(module, fmt, args); \
- va_end(args); \
+#define KINFO "\x1b" _LEVEL_INFO
+#define KWARN "\x1b" _LEVEL_WARN
+#define KERROR "\x1b" _LEVEL_ERROR
+#define KDEBUG "\x1b" _LEVEL_DEBUG
+
+#define LOG_MODULE(module) \
+ static void kprintf(const char* fmt, ...) \
+ { \
+ va_list args; \
+ va_start(args, fmt); \
+ __kprintf(module, fmt, args); \
+ va_end(args); \
}
void
__kprintf(const char* component, const char* fmt, va_list args);
+void
+kprint_hex(const void* buffer, unsigned int size);
void
kprint_panic(const char* fmt, ...);
tty_put_str_at(buf, 0, 24);
va_end(args);
+}
+
+void
+kprint_hex(const void* buffer, unsigned int size)
+{
+ unsigned char* data = (unsigned char*)buffer;
+ char buf[16];
+ char ch_cache[16];
+ unsigned int ptr = 0;
+ int i;
+
+ ch_cache[0] = '|';
+ ch_cache[1] = ' ';
+ while (size) {
+ snprintf(buf, 64, " %.4p: ", ptr);
+ console_write_str(buf);
+ for (i = 0; i < 8 && size; i++, size--, ptr++) {
+ unsigned char c = *(data + ptr) & 0xff;
+ ch_cache[2 + i] = (32 <= c && c < 127) ? c : '.';
+ snprintf(buf, 64, "%.2x ", c);
+ console_write_str(buf);
+ }
+ ch_cache[2 + i] = '\0';
+ console_write_str(ch_cache);
+ console_write_char('\n');
+ }
}
\ No newline at end of file
};
static char piles_names_dma[MAX_CLASS][PILE_NAME_MAXLEN] = {
- "valloc_dma_128", "valloc_dma_512", "valloc_dma_512",
+ "valloc_dma_128", "valloc_dma_256", "valloc_dma_512",
"valloc_dma_1k", "valloc_dma_2k", "valloc_dma_4k"
};
#include <hal/ioapic.h>
#include <hal/pci.h>
+#include <klibc/string.h>
+
LOG_MODULE("PROC0")
extern void
extern uint8_t __init_hhk_end; /* link/linker.ld */
extern multiboot_info_t* _k_init_mb_info; /* k_init.c */
+char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
+ "There were two regal sisters who ruled together "
+ "and created harmony for all the land.";
+
+void
+__test_disk_io()
+{
+ struct hba_port* port = ahci_get_port(0);
+ char* buffer = valloc_dma(port->device->block_size);
+ strcpy(buffer, test_sequence);
+ kprintf("WRITE: %s\n", buffer);
+ int result;
+
+ // 写入第一扇区
+ result =
+ port->device->ops.write_buffer(port, 1, buffer, port->device->block_size);
+ if (!result) {
+ kprintf(KWARN "fail to write: %x\n", port->device->last_error);
+ }
+
+ memset(buffer, 0, port->device->block_size);
+
+ // 读出我们刚刚写的内容!
+ result =
+ port->device->ops.read_buffer(port, 1, buffer, port->device->block_size);
+ kprintf(KDEBUG "%x, %x\n", port->regs[HBA_RPxIS], port->regs[HBA_RPxTFD]);
+ if (!result) {
+ kprintf(KWARN "fail to read: %x\n", port->device->last_error);
+ } else {
+ kprint_hex(buffer, 256);
+ }
+}
+
void
init_platform()
{
ahci_init();
ahci_list_device();
+ __test_disk_io();
+
cake_stats();
syscall_install();