[ahci][disk] start to parse the identify block to find disk size

This commit is contained in:
Travis Geiselbrecht
2022-02-28 23:08:46 -08:00
parent 1341158c5c
commit 4839bb9689
2 changed files with 57 additions and 2 deletions

View File

@@ -6,15 +6,25 @@
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#include "disk.h" #include "disk.h"
#include <lk/bits.h>
#include <lk/debug.h> #include <lk/debug.h>
#include <lk/err.h> #include <lk/err.h>
#include <lk/trace.h> #include <lk/trace.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "ata.h" #include "ata.h"
#define LOCAL_TRACE 1 #define LOCAL_TRACE 1
// offsets in the 256 word (2 byte word) IDENTIFY structure
enum ata_identify_words {
ATA_IDENTIFY_MODEL_NUMBER = 27, // 40 bytes
ATA_IDENTIFY_LOGICAL_SECTOR_COUNT_QWORD = 100, // 4 words of logical sector count
ATA_IDENTIFY_PHYS_TO_LOGICAL_SECTOR = 106, // phys size / logical size
ATA_IDENTIFY_LOGICAL_SECTOR_SIZE_DWORD = 117, // dword of logical sector size
};
ahci_disk::ahci_disk(ahci_port &p) : port_(p) { ahci_disk::ahci_disk(ahci_port &p) : port_(p) {
} }
@@ -23,7 +33,7 @@ ahci_disk::~ahci_disk() = default;
status_t ahci_disk::identify() { status_t ahci_disk::identify() {
LTRACE_ENTRY; LTRACE_ENTRY;
__ALIGNED(512) static uint8_t identify_data[512]; __ALIGNED(512) static uint16_t identify_data[256];
FIS_REG_H2D fis = ata_cmd_identify(); FIS_REG_H2D fis = ata_cmd_identify();
int slot; int slot;
@@ -41,6 +51,49 @@ status_t ahci_disk::identify() {
LTRACEF("identify data:\n"); LTRACEF("identify data:\n");
hexdump8(identify_data, sizeof(identify_data)); hexdump8(identify_data, sizeof(identify_data));
char model[20*2 + 1] = {};
for (auto i = 0; i < 20; i++) {
model[i * 2] = identify_data[ATA_IDENTIFY_MODEL_NUMBER + i] >> 8;
model[i * 2 + 1] = identify_data[ATA_IDENTIFY_MODEL_NUMBER + i] & 0xff;
}
LTRACEF("model '%s'\n", model);
// assumes LBA48
bool lba48 = identify_data[83] & (1 << 10);
if (!lba48) {
printf("AHCI: LBA48 required, aborting\n");
return ERR_NOT_SUPPORTED;
}
// sector count is 4 words at offset 100
uint64_t sector_count = identify_data[ATA_IDENTIFY_LOGICAL_SECTOR_COUNT_QWORD] |
((uint64_t)identify_data[ATA_IDENTIFY_LOGICAL_SECTOR_COUNT_QWORD + 1] << 16) |
((uint64_t)identify_data[ATA_IDENTIFY_LOGICAL_SECTOR_COUNT_QWORD + 2] << 32) |
((uint64_t)identify_data[ATA_IDENTIFY_LOGICAL_SECTOR_COUNT_QWORD + 3] << 48);
LTRACEF("logical sector count %#llx\n", sector_count);
// defaults to 512 bytes
uint32_t logical_sector_size = 512;
uint32_t physical_sector_size = 512;
auto phys_to_logical_sector = identify_data[ATA_IDENTIFY_PHYS_TO_LOGICAL_SECTOR];
//LTRACEF("phys size / logical size %#hx\n", identify_data[ATA_IDENTIFY_PHYS_TO_LOGICAL_SECTOR]);
if (BITS(phys_to_logical_sector, 15, 14) == (1 << 14)) { // word 106 has valid info
if (BIT(phys_to_logical_sector, 12)) {
// logical sector size is specified in word 117..118
logical_sector_size = identify_data[ATA_IDENTIFY_LOGICAL_SECTOR_SIZE_DWORD] |
((uint32_t)identify_data[ATA_IDENTIFY_LOGICAL_SECTOR_SIZE_DWORD + 1] << 16);
}
// bits 3:0 have physical sector size in power of 2 times logical size
physical_sector_size = (1U << BITS(phys_to_logical_sector, 3, 0)) * logical_sector_size;
}
LTRACEF("logical sector size %#x\n", logical_sector_size);
LTRACEF("physical sector size %#x\n", physical_sector_size);
LTRACEF("total size %#llx\n", sector_count * logical_sector_size);
return NO_ERROR; return NO_ERROR;
} }

View File

@@ -7,6 +7,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <assert.h>
// portions from https://wiki.osdev.org/AHCI // portions from https://wiki.osdev.org/AHCI
// //
@@ -25,6 +26,8 @@ typedef enum {
typedef enum { typedef enum {
ATA_CMD_IDENTIFY = 0xec, ATA_CMD_IDENTIFY = 0xec,
ATA_CMD_PACKET = 0xa0,
ATA_CMD_PACKET_IDENTIFY = 0xa1,
} ATA_CMD; } ATA_CMD;
typedef struct tagFIS_REG_H2D typedef struct tagFIS_REG_H2D
@@ -175,4 +178,3 @@ typedef struct tagFIS_DMA_SETUP
// DWORD 6 // DWORD 6
uint32_t resvd; // Reserved uint32_t resvd; // Reserved
} FIS_DMA_SETUP; } FIS_DMA_SETUP;