Add ATAPI support to ata(4).
This commit is contained in:
parent
bce37028f5
commit
80f5ca398a
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2013, 2014, 2015, 2016, 2018 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -92,7 +92,11 @@ static void InitializeDevice(Ref<Descriptor> dev, const char* devpath,
|
||||||
{
|
{
|
||||||
HBA* hba = new HBA(devaddr);
|
HBA* hba = new HBA(devaddr);
|
||||||
if ( !hba )
|
if ( !hba )
|
||||||
PanicF("Failed to allocate ATA driver for AHCI device 0x%X", devaddr);
|
{
|
||||||
|
Log::PrintF("ahci: pci 0x%X: "
|
||||||
|
"failed to allocate driver object", devaddr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( !hba->Initialize(dev, devpath) )
|
if ( !hba->Initialize(dev, devpath) )
|
||||||
return delete hba;
|
return delete hba;
|
||||||
|
|
|
@ -314,8 +314,6 @@ bool Port::FinishInitialize()
|
||||||
(uint64_t) words[118] << 16);
|
(uint64_t) words[118] << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Verify the block size is a power of two.
|
|
||||||
|
|
||||||
cylinder_count = words[1];
|
cylinder_count = words[1];
|
||||||
head_count = words[3];
|
head_count = words[3];
|
||||||
sector_count = words[6];
|
sector_count = words[6];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2018 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -37,7 +37,10 @@ static void InitializeDevice(Ref<Descriptor> dev, const char* devpath,
|
||||||
{
|
{
|
||||||
HBA* hba = new HBA(devaddr);
|
HBA* hba = new HBA(devaddr);
|
||||||
if ( !hba )
|
if ( !hba )
|
||||||
PanicF("Failed to allocate ATA driver for PCI device 0x%X", devaddr);
|
{
|
||||||
|
Log::PrintF("ata: pci 0x%X: failed to allocate driver object", devaddr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( !hba->Initialize(dev, devpath) )
|
if ( !hba->Initialize(dev, devpath) )
|
||||||
return delete hba;
|
return delete hba;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2018, 2021 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -170,7 +170,11 @@ bool Port::FinishInitialize()
|
||||||
|
|
||||||
channel->SelectDrive(port_index);
|
channel->SelectDrive(port_index);
|
||||||
|
|
||||||
outport8(channel->port_base + REG_COMMAND, CMD_IDENTIFY);
|
// ATAPI can be detected by using the LBA registers after IDENTIFY.
|
||||||
|
is_packet_interface = false;
|
||||||
|
retry_identify_packet:
|
||||||
|
outport8(channel->port_base + REG_COMMAND,
|
||||||
|
is_packet_interface ? CMD_IDENTIFY_PACKET : CMD_IDENTIFY);
|
||||||
|
|
||||||
sleep_400_nanoseconds();
|
sleep_400_nanoseconds();
|
||||||
|
|
||||||
|
@ -211,9 +215,13 @@ bool Port::FinishInitialize()
|
||||||
|
|
||||||
if ( (mid == 0x14 && high == 0xEB) || (mid == 0x69 && high == 0x96) )
|
if ( (mid == 0x14 && high == 0xEB) || (mid == 0x69 && high == 0x96) )
|
||||||
{
|
{
|
||||||
// TODO: Add ATAPI support.
|
if ( is_packet_interface )
|
||||||
//LogF("ignoring: found ATAPI device instead");
|
{
|
||||||
return errno = ENODRV, false;
|
LogF("ignoring: IDENTIFY_PACKET returned error status");
|
||||||
|
return errno = EIO, false;
|
||||||
|
}
|
||||||
|
is_packet_interface = true;
|
||||||
|
goto retry_identify_packet;
|
||||||
}
|
}
|
||||||
else if ( mid == 0x3C && high == 0xC3 )
|
else if ( mid == 0x3C && high == 0xC3 )
|
||||||
{
|
{
|
||||||
|
@ -248,46 +256,15 @@ bool Port::FinishInitialize()
|
||||||
|
|
||||||
little_uint16_t* words = (little_uint16_t*) identify_data;
|
little_uint16_t* words = (little_uint16_t*) identify_data;
|
||||||
|
|
||||||
if ( words[0] & (1 << 15) )
|
if ( !is_packet_interface && (words[0] & (1 << 15)) )
|
||||||
return errno = EINVAL, false; // Skipping non-ATA device.
|
return errno = EINVAL, false; // Skipping non-ATA device.
|
||||||
if ( !(words[49] & (1 << 9)) )
|
if ( !is_packet_interface && !(words[49] & (1 << 9)) )
|
||||||
return errno = EINVAL, false; // Skipping non-LBA device.
|
return errno = EINVAL, false; // Skipping non-LBA device.
|
||||||
|
|
||||||
this->is_lba48 = words[83] & (1 << 10);
|
|
||||||
|
|
||||||
copy_ata_string(serial, (const char*) &words[10], sizeof(serial) - 1);
|
copy_ata_string(serial, (const char*) &words[10], sizeof(serial) - 1);
|
||||||
copy_ata_string(revision, (const char*) &words[23], sizeof(revision) - 1);
|
copy_ata_string(revision, (const char*) &words[23], sizeof(revision) - 1);
|
||||||
copy_ata_string(model, (const char*) &words[27], sizeof(model) - 1);
|
copy_ata_string(model, (const char*) &words[27], sizeof(model) - 1);
|
||||||
|
|
||||||
uint64_t block_count;
|
|
||||||
if ( is_lba48 )
|
|
||||||
{
|
|
||||||
block_count = (uint64_t) words[100] << 0 |
|
|
||||||
(uint64_t) words[101] << 16 |
|
|
||||||
(uint64_t) words[102] << 32 |
|
|
||||||
(uint64_t) words[103] << 48;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
block_count = (uint64_t) words[60] << 0 |
|
|
||||||
(uint64_t) words[61] << 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t block_size = 512;
|
|
||||||
if( (words[106] & (1 << 14)) &&
|
|
||||||
!(words[106] & (1 << 15)) &&
|
|
||||||
(words[106] & (1 << 12)) )
|
|
||||||
{
|
|
||||||
block_size = 2 * ((uint64_t) words[117] << 0 |
|
|
||||||
(uint64_t) words[118] << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Verify the block size is a power of two.
|
|
||||||
|
|
||||||
cylinder_count = words[1];
|
|
||||||
head_count = words[3];
|
|
||||||
sector_count = words[6];
|
|
||||||
|
|
||||||
is_using_dma = true;
|
is_using_dma = true;
|
||||||
|
|
||||||
// This is apparently the case on older hardware, there are additional
|
// This is apparently the case on older hardware, there are additional
|
||||||
|
@ -319,7 +296,57 @@ bool Port::FinishInitialize()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( __builtin_mul_overflow(block_count, block_size, &this->device_size) )
|
if ( is_packet_interface )
|
||||||
|
{
|
||||||
|
is_lba48 = true;
|
||||||
|
block_count = 0;
|
||||||
|
block_size = 0;
|
||||||
|
cylinder_count = 0;
|
||||||
|
head_count = 0;
|
||||||
|
sector_count = 0;
|
||||||
|
device_size = 0;
|
||||||
|
if ( !ReadCapacityATAPI(true) )
|
||||||
|
{
|
||||||
|
//LogF("ReadCapacityATAPI failed: %m");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->is_lba48 = words[83] & (1 << 10);
|
||||||
|
|
||||||
|
uint64_t block_count;
|
||||||
|
if ( is_lba48 )
|
||||||
|
{
|
||||||
|
block_count = (uint64_t) words[100] << 0 |
|
||||||
|
(uint64_t) words[101] << 16 |
|
||||||
|
(uint64_t) words[102] << 32 |
|
||||||
|
(uint64_t) words[103] << 48;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block_count = (uint64_t) words[60] << 0 |
|
||||||
|
(uint64_t) words[61] << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t block_size = 512;
|
||||||
|
if( (words[106] & (1 << 14)) &&
|
||||||
|
!(words[106] & (1 << 15)) &&
|
||||||
|
(words[106] & (1 << 12)) )
|
||||||
|
{
|
||||||
|
block_size = 2 * ((uint64_t) words[117] << 0 |
|
||||||
|
(uint64_t) words[118] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
cylinder_count = words[1];
|
||||||
|
head_count = words[3];
|
||||||
|
sector_count = words[6];
|
||||||
|
|
||||||
|
if ( Page::Size() < block_size )
|
||||||
|
{
|
||||||
|
LogF("error: block size is larger than page size: %ji", block_size);
|
||||||
|
return errno = EINVAL, false;
|
||||||
|
}
|
||||||
|
if ( __builtin_mul_overflow(block_count, block_size, &device_size) )
|
||||||
{
|
{
|
||||||
LogF("error: device size overflows off_t");
|
LogF("error: device size overflows off_t");
|
||||||
return errno = EOVERFLOW, false;
|
return errno = EOVERFLOW, false;
|
||||||
|
@ -331,6 +358,67 @@ bool Port::FinishInitialize()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Port::ReadCapacityATAPI(bool no_error)
|
||||||
|
{
|
||||||
|
struct atapi_packet* packet = (struct atapi_packet*) dma_alloc.from;
|
||||||
|
memset(packet, 0, sizeof(*packet));
|
||||||
|
packet->operation = ATAPI_CMD_READ_CAPACITY;
|
||||||
|
struct atapi_capacity* reply = (struct atapi_capacity*) dma_alloc.from;
|
||||||
|
if ( !CommandATAPI(sizeof(*reply), no_error) )
|
||||||
|
return errno = ENOMEDIUM, false;
|
||||||
|
block_count = (blkcnt_t) reply->last_lba + 1;
|
||||||
|
block_size = (blkcnt_t) reply->block_size;
|
||||||
|
if ( Page::Size() < (uintmax_t) block_size )
|
||||||
|
{
|
||||||
|
LogF("error: block size is larger than page size: %ji", block_size);
|
||||||
|
return errno = EINVAL, false;
|
||||||
|
}
|
||||||
|
if ( __builtin_mul_overflow(block_count, block_size, &device_size) )
|
||||||
|
{
|
||||||
|
LogF("error: device size overflows off_t");
|
||||||
|
return errno = EOVERFLOW, false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Port::CommandATAPI(size_t response_size, bool no_error)
|
||||||
|
{
|
||||||
|
outport8(channel->port_base + REG_FEATURE, is_using_dma ? 0x01 : 0x00);
|
||||||
|
outport8(channel->port_base + REG_LBA_LOW, 0x08);
|
||||||
|
outport8(channel->port_base + REG_LBA_MID, 0x08);
|
||||||
|
if ( is_using_dma )
|
||||||
|
CommandDMA(CMD_PACKET, response_size, false);
|
||||||
|
else
|
||||||
|
CommandPIO(CMD_PACKET, response_size, false);
|
||||||
|
if ( !TransferPIO(sizeof(struct atapi_packet), true, no_error) )
|
||||||
|
{
|
||||||
|
if ( !no_error )
|
||||||
|
LogF("EIO: %s:%u", __FILE__, __LINE__);
|
||||||
|
return errno = EIO, false;
|
||||||
|
}
|
||||||
|
if ( is_using_dma )
|
||||||
|
{
|
||||||
|
if ( !FinishTransferDMA() )
|
||||||
|
{
|
||||||
|
if ( !no_error )
|
||||||
|
LogF("EIO: %s:%u", __FILE__, __LINE__);
|
||||||
|
return errno = EIO, false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Read LBA Mid and LBA High to know how many bytes we are
|
||||||
|
// expected to transfer.
|
||||||
|
if ( !TransferPIO(response_size, false, no_error) )
|
||||||
|
{
|
||||||
|
if ( !no_error )
|
||||||
|
LogF("EIO: %s:%u", __FILE__, __LINE__);
|
||||||
|
return errno = EIO, false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Port::Seek(blkcnt_t block_index, size_t count)
|
void Port::Seek(blkcnt_t block_index, size_t count)
|
||||||
{
|
{
|
||||||
uintmax_t lba = (uintmax_t) block_index;
|
uintmax_t lba = (uintmax_t) block_index;
|
||||||
|
@ -449,7 +537,7 @@ void Port::CommandPIO(uint8_t cmd, size_t size, bool write)
|
||||||
outport8(channel->port_base + REG_COMMAND, cmd);
|
outport8(channel->port_base + REG_COMMAND, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Port::TransferPIO(size_t size, bool write)
|
bool Port::TransferPIO(size_t size, bool write, bool no_error)
|
||||||
{
|
{
|
||||||
const char* op = write ? "write" : "read";
|
const char* op = write ? "write" : "read";
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
@ -457,14 +545,16 @@ bool Port::TransferPIO(size_t size, bool write)
|
||||||
{
|
{
|
||||||
if ( !write && i < size && !AwaitInterrupt(10000 /*ms*/) )
|
if ( !write && i < size && !AwaitInterrupt(10000 /*ms*/) )
|
||||||
{
|
{
|
||||||
LogF("error: %s timed out, waiting for transfer start", op);
|
if ( !no_error )
|
||||||
|
LogF("error: %s timed out, waiting for transfer start", op);
|
||||||
return errno = EIO, false;
|
return errno = EIO, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !wait_inport8_clear(channel->port_base + REG_STATUS,
|
if ( !wait_inport8_clear(channel->port_base + REG_STATUS,
|
||||||
STATUS_BUSY, false, 10000 /*ms*/) )
|
STATUS_BUSY, false, 10000 /*ms*/) )
|
||||||
{
|
{
|
||||||
LogF("error: %s timed out waiting for transfer pre idle", op);
|
if ( !no_error )
|
||||||
|
LogF("error: %s timed out waiting for transfer pre idle", op);
|
||||||
return errno = EIO, false;
|
return errno = EIO, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,13 +562,17 @@ bool Port::TransferPIO(size_t size, bool write)
|
||||||
|
|
||||||
if ( status & STATUS_BUSY )
|
if ( status & STATUS_BUSY )
|
||||||
{
|
{
|
||||||
LogF("error: %s unexpectedly still busy", op);
|
if ( !no_error )
|
||||||
|
LogF("error: %s unexpectedly still busy", op);
|
||||||
return errno = EIO, false;
|
return errno = EIO, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status & (STATUS_ERROR | STATUS_DRIVEFAULT) )
|
if ( status & (STATUS_ERROR | STATUS_DRIVEFAULT) )
|
||||||
{
|
{
|
||||||
LogF("error: %s error", op);
|
if ( !no_error )
|
||||||
|
LogF("error: %s error%s%s", op,
|
||||||
|
status & STATUS_ERROR ? " STATUS_ERROR" : "",
|
||||||
|
status & STATUS_DRIVEFAULT ? " STATUS_DRIVEFAULT" : "");
|
||||||
return errno = EIO, false;
|
return errno = EIO, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,13 +581,14 @@ bool Port::TransferPIO(size_t size, bool write)
|
||||||
|
|
||||||
if ( !(status & STATUS_DATAREADY) )
|
if ( !(status & STATUS_DATAREADY) )
|
||||||
{
|
{
|
||||||
LogF("error: %s unexpectedly not ready", op);
|
if ( !no_error )
|
||||||
|
LogF("error: %s unexpectedly not ready", op);
|
||||||
return errno = EIO, false;
|
return errno = EIO, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anticipate another IRQ if we're not at the end.
|
// Anticipate another IRQ if we're not at the end.
|
||||||
size_t i_sector_end = i + block_size;
|
size_t i_sector_end = is_packet_interface ? i + size : i + block_size;
|
||||||
if ( i_sector_end != size )
|
if ( (is_packet_interface && write) || i_sector_end != size )
|
||||||
PrepareAwaitInterrupt();
|
PrepareAwaitInterrupt();
|
||||||
|
|
||||||
uint8_t* dma_data = (uint8_t*) dma_alloc.from;
|
uint8_t* dma_data = (uint8_t*) dma_alloc.from;
|
||||||
|
@ -520,7 +615,8 @@ bool Port::TransferPIO(size_t size, bool write)
|
||||||
|
|
||||||
if ( write && !AwaitInterrupt(10000 /*ms*/) )
|
if ( write && !AwaitInterrupt(10000 /*ms*/) )
|
||||||
{
|
{
|
||||||
LogF("error: %s timed out, waiting for transfer end", op);
|
if ( !no_error )
|
||||||
|
LogF("error: %s timed out, waiting for transfer end", op);
|
||||||
return errno = EIO, false;
|
return errno = EIO, false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,6 +681,11 @@ const unsigned char* Port::GetATAIdentify(size_t* size_ptr)
|
||||||
|
|
||||||
int Port::sync(ioctx_t* ctx)
|
int Port::sync(ioctx_t* ctx)
|
||||||
{
|
{
|
||||||
|
if ( is_packet_interface )
|
||||||
|
{
|
||||||
|
// TODO: SYNCHRONIZE CACHE 0x35
|
||||||
|
return errno = ENOSYS, -1;
|
||||||
|
}
|
||||||
(void) ctx;
|
(void) ctx;
|
||||||
ScopedLock lock(&channel->hw_lock);
|
ScopedLock lock(&channel->hw_lock);
|
||||||
channel->SelectDrive(port_index);
|
channel->SelectDrive(port_index);
|
||||||
|
@ -613,6 +714,8 @@ int Port::sync(ioctx_t* ctx)
|
||||||
|
|
||||||
ssize_t Port::pread(ioctx_t* ctx, unsigned char* buf, size_t count, off_t off)
|
ssize_t Port::pread(ioctx_t* ctx, unsigned char* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
|
if ( !block_size )
|
||||||
|
return errno = ENOMEDIUM, -1;
|
||||||
ssize_t result = 0;
|
ssize_t result = 0;
|
||||||
while ( count )
|
while ( count )
|
||||||
{
|
{
|
||||||
|
@ -635,20 +738,36 @@ ssize_t Port::pread(ioctx_t* ctx, unsigned char* buf, size_t count, off_t off)
|
||||||
unsigned char* dma_data = (unsigned char*) dma_alloc.from;
|
unsigned char* dma_data = (unsigned char*) dma_alloc.from;
|
||||||
unsigned char* data = dma_data + block_offset;
|
unsigned char* data = dma_data + block_offset;
|
||||||
size_t data_size = amount - block_offset;
|
size_t data_size = amount - block_offset;
|
||||||
Seek(block_index, num_blocks);
|
if ( is_packet_interface )
|
||||||
if ( is_using_dma )
|
|
||||||
{
|
{
|
||||||
uint8_t cmd = is_lba48 ? CMD_READ_DMA_EXT : CMD_READ_DMA;
|
struct atapi_packet* packet = (struct atapi_packet*) dma_alloc.from;
|
||||||
CommandDMA(cmd, (size_t) full_amount, false);
|
memset(packet, 0, sizeof(*packet));
|
||||||
if ( !FinishTransferDMA() )
|
packet->operation = ATAPI_CMD_READ;
|
||||||
|
packet->lba[0] = block_index >> 24 & 0xFF;
|
||||||
|
packet->lba[1] = block_index >> 16 & 0xFF;
|
||||||
|
packet->lba[2] = block_index >> 8 & 0xFF;
|
||||||
|
packet->lba[3] = block_index >> 0 & 0xFF;
|
||||||
|
packet->control = num_blocks;
|
||||||
|
if ( !CommandATAPI((size_t) full_amount) )
|
||||||
return result ? result : -1;
|
return result ? result : -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint8_t cmd = is_lba48 ? CMD_READ_EXT : CMD_READ;
|
Seek(block_index, num_blocks);
|
||||||
CommandPIO(cmd, (size_t) full_amount, false);
|
if ( is_using_dma )
|
||||||
if ( !TransferPIO((size_t) full_amount, false) )
|
{
|
||||||
return result ? result : -1;
|
uint8_t cmd = is_lba48 ? CMD_READ_DMA_EXT : CMD_READ_DMA;
|
||||||
|
CommandDMA(cmd, (size_t) full_amount, false);
|
||||||
|
if ( !FinishTransferDMA() )
|
||||||
|
return result ? result : -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t cmd = is_lba48 ? CMD_READ_EXT : CMD_READ;
|
||||||
|
CommandPIO(cmd, (size_t) full_amount, false);
|
||||||
|
if ( !TransferPIO((size_t) full_amount, false) )
|
||||||
|
return result ? result : -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( !ctx->copy_to_dest(buf, data, data_size) )
|
if ( !ctx->copy_to_dest(buf, data, data_size) )
|
||||||
return result ? result : -1;
|
return result ? result : -1;
|
||||||
|
@ -662,6 +781,10 @@ ssize_t Port::pread(ioctx_t* ctx, unsigned char* buf, size_t count, off_t off)
|
||||||
|
|
||||||
ssize_t Port::pwrite(ioctx_t* ctx, const unsigned char* buf, size_t count, off_t off)
|
ssize_t Port::pwrite(ioctx_t* ctx, const unsigned char* buf, size_t count, off_t off)
|
||||||
{
|
{
|
||||||
|
if ( is_packet_interface )
|
||||||
|
return errno = EPERM, -1;
|
||||||
|
if ( !block_size )
|
||||||
|
return errno = ENOMEDIUM, -1;
|
||||||
ssize_t result = 0;
|
ssize_t result = 0;
|
||||||
while ( count )
|
while ( count )
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2018, 2021 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -65,11 +65,13 @@ public:
|
||||||
private:
|
private:
|
||||||
__attribute__((format(printf, 2, 3)))
|
__attribute__((format(printf, 2, 3)))
|
||||||
void LogF(const char* format, ...);
|
void LogF(const char* format, ...);
|
||||||
|
bool ReadCapacityATAPI(bool no_error = false);
|
||||||
void Seek(blkcnt_t block_index, size_t count);
|
void Seek(blkcnt_t block_index, size_t count);
|
||||||
|
bool CommandATAPI(size_t response_size, bool no_error = false);
|
||||||
void CommandDMA(uint8_t cmd, size_t size, bool write);
|
void CommandDMA(uint8_t cmd, size_t size, bool write);
|
||||||
void CommandPIO(uint8_t cmd, size_t size, bool write);
|
void CommandPIO(uint8_t cmd, size_t size, bool write);
|
||||||
bool FinishTransferDMA();
|
bool FinishTransferDMA();
|
||||||
bool TransferPIO(size_t size, bool write);
|
bool TransferPIO(size_t size, bool write, bool no_error = false);
|
||||||
void PrepareAwaitInterrupt();
|
void PrepareAwaitInterrupt();
|
||||||
bool AwaitInterrupt(unsigned int msescs);
|
bool AwaitInterrupt(unsigned int msescs);
|
||||||
void OnInterrupt();
|
void OnInterrupt();
|
||||||
|
@ -90,6 +92,7 @@ private:
|
||||||
bool is_dma_page_mapped;
|
bool is_dma_page_mapped;
|
||||||
bool is_lba48;
|
bool is_lba48;
|
||||||
bool is_using_dma;
|
bool is_using_dma;
|
||||||
|
bool is_packet_interface;
|
||||||
off_t device_size;
|
off_t device_size;
|
||||||
blksize_t block_count;
|
blksize_t block_count;
|
||||||
blkcnt_t block_size;
|
blkcnt_t block_size;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2011-2016, 2018, 2021 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -33,6 +33,25 @@ struct prd
|
||||||
little_uint16_t flags;
|
little_uint16_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct atapi_packet
|
||||||
|
{
|
||||||
|
uint8_t operation;
|
||||||
|
uint8_t reladdr_lun;
|
||||||
|
uint8_t lba[4];
|
||||||
|
uint8_t reserved0;
|
||||||
|
uint8_t reserved1;
|
||||||
|
uint8_t pmi;
|
||||||
|
uint8_t control;
|
||||||
|
uint8_t reserved2;
|
||||||
|
uint8_t reserved3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct atapi_capacity
|
||||||
|
{
|
||||||
|
big_uint32_t last_lba;
|
||||||
|
big_uint32_t block_size;
|
||||||
|
};
|
||||||
|
|
||||||
static const uint16_t PRD_FLAG_EOT = 1 << 15;
|
static const uint16_t PRD_FLAG_EOT = 1 << 15;
|
||||||
|
|
||||||
static const uint16_t REG_DATA = 0x0;
|
static const uint16_t REG_DATA = 0x0;
|
||||||
|
@ -57,6 +76,12 @@ static const uint8_t CMD_WRITE_DMA_EXT = 0x35;
|
||||||
static const uint8_t CMD_FLUSH_CACHE = 0xE7;
|
static const uint8_t CMD_FLUSH_CACHE = 0xE7;
|
||||||
static const uint8_t CMD_FLUSH_CACHE_EXT = 0xEA;
|
static const uint8_t CMD_FLUSH_CACHE_EXT = 0xEA;
|
||||||
static const uint8_t CMD_IDENTIFY = 0xEC;
|
static const uint8_t CMD_IDENTIFY = 0xEC;
|
||||||
|
static const uint8_t CMD_PACKET = 0xA0;
|
||||||
|
static const uint8_t CMD_IDENTIFY_PACKET = 0xA1;
|
||||||
|
|
||||||
|
static const uint8_t ATAPI_CMD_READ_CAPACITY = 0x25;
|
||||||
|
static const uint8_t ATAPI_CMD_WRITE_CAPACITY = 0x28;
|
||||||
|
static const uint8_t ATAPI_CMD_READ = 0xA8;
|
||||||
|
|
||||||
static const uint8_t STATUS_ERROR = 1 << 0;
|
static const uint8_t STATUS_ERROR = 1 << 0;
|
||||||
static const uint8_t STATUS_DATAREADY = 1 << 3;
|
static const uint8_t STATUS_DATAREADY = 1 << 3;
|
||||||
|
|
Loading…
Reference in New Issue