Commit 900ce48f authored by Eddie Kohler's avatar Eddie Kohler

Better interface to ahcistate::read/write.

parent 701ab8f9
......@@ -58,8 +58,7 @@ void* bufcache::get_disk_block(chickadeefs::blocknum_t bn,
e_[i].flags_ |= bufentry::f_loading;
e_[i].lock_.unlock(irqs);
sata_disk->read
(bn * (chickadeefs::blocksize / sata_disk->sectorsize),
x, chickadeefs::blocksize / sata_disk->sectorsize);
(x, chickadeefs::blocksize, bn * chickadeefs::blocksize);
irqs = e_[i].lock_.lock();
e_[i].flags_ = (e_[i].flags_ & ~bufentry::f_loading)
| bufentry::f_loaded;
......
......@@ -262,15 +262,20 @@ inline void ahcistate::clear(int slot) {
// ahcistate::push_buffer(slot, buf, sz)
// Append a data buffer to the buffers relevant for the next command.
inline void ahcistate::push_buffer(int slot, void* buf, size_t sz) {
// check requirements on address and size
uint64_t pa = kptr2pa(buf);
assert((pa & 1) == 0 && (sz & 1) == 0); // word-aligned
assert(sz > 0 && sz <= (64U << 10)); // >0, <64KiB
assert(pa <= 0x100000000UL); // low physical memory
assert((pa ^ (pa + sz - 1)) < (64U << 10)); // within aligned 64KiB
// check slot availability
assert(unsigned(slot) < unsigned(nslots_));
assert(dma_.ch[slot].nbuf < arraysize(dma_.ct[slot].buf));
int nbuf = dma_.ch[slot].nbuf;
uint64_t pa = kptr2pa(buf);
assert((pa & 1) == 0 && (sz & 1) == 0 && sz > 0);
int nbuf = dma_.ch[slot].nbuf;
dma_.ct[slot].buf[nbuf].pa = pa;
dma_.ct[slot].buf[nbuf].maxbyte = sz - 1;
dma_.ch[slot].nbuf = nbuf + 1;
dma_.ch[slot].buf_byte_pos += sz;
}
......@@ -329,44 +334,17 @@ inline void ahcistate::acknowledge(int slot, int result) {
// FUNCTIONS FOR READING AND WRITING BLOCKS
int ahcistate::read(size_t sector, void* buf, size_t nsectors) {
uintptr_t pa = kptr2pa(buf);
assert(pa <= 0x100000000UL);
assert(nsectors > 0 && nsectors <= (64U << 10) / sectorsize);
assert(nsectors <= nslots_);
assert((pa ^ (pa + nsectors * sectorsize - 1)) < (64U << 10));
// obtain lock
proc* p = current();
auto irqs = lock_.lock();
// block until ready for command
waiter(p).block_until(wq_, [&] () {
return !slots_outstanding_mask_;
}, lock_, irqs);
// send command, record buffer and status storage
int r = E_AGAIN;
clear(0);
push_buffer(0, buf, nsectors * sectorsize);
issue_ncq(0, cmd_read_fpdma_queued, sector);
slot_status_[0] = &r;
lock_.unlock(irqs);
// wait for response
waiter(p).block_until(wq_, [&] () {
return r != E_AGAIN;
});
return 0;
}
// ahcistate::read_or_write(command, buf, sz, off)
// Issue an NCQ read or write command `command`. Read or write
// `sz` bytes of data to or from `buf`, starting at disk offset
// `off`. `sz` and `off` are measured in bytes, but must be
// sector-aligned (i.e., multiples of `ahcistate::sectorsize`).
// Can block. Returns 0 on success and an error code on failure.
int ahcistate::write(size_t sector, const void* buf, size_t nsectors) {
uintptr_t pa = kptr2pa(buf);
assert(pa <= 0x100000000UL);
assert(nsectors > 0 && nsectors <= (64U << 10) / sectorsize);
assert(nsectors <= nslots_);
assert((pa ^ (pa + nsectors * sectorsize - 1)) < (64U << 10));
int ahcistate::read_or_write(idecommand command, void* buf, size_t sz,
size_t off) {
// `sz` and `off` must be sector-aligned
assert(sz % sectorsize == 0 && off % sectorsize == 0);
// obtain lock
proc* p = current();
......@@ -378,10 +356,10 @@ int ahcistate::write(size_t sector, const void* buf, size_t nsectors) {
}, lock_, irqs);
// send command, record buffer and status storage
int r = E_AGAIN;
volatile int r = E_AGAIN;
clear(0);
push_buffer(0, const_cast<void*>(buf), nsectors * sectorsize);
issue_ncq(0, cmd_write_fpdma_queued, sector);
push_buffer(0, buf, sz);
issue_ncq(0, command, off / sectorsize);
slot_status_[0] = &r;
lock_.unlock(irqs);
......@@ -390,7 +368,7 @@ int ahcistate::write(size_t sector, const void* buf, size_t nsectors) {
waiter(p).block_until(wq_, [&] () {
return r != E_AGAIN;
});
return 0;
return r;
}
......
......@@ -219,7 +219,7 @@ struct ahcistate {
wait_queue wq_;
unsigned nslots_available_; // # slots available for commands
uint32_t slots_outstanding_mask_; // 1 == that slot is used
int* slot_status_[32]; // ptrs to status storage, one per slot
volatile int* slot_status_[32]; // ptrs to status storage, one per slot
ahcistate(int pci_addr, int sata_port, volatile regs* mr);
......@@ -227,8 +227,9 @@ struct ahcistate {
static ahcistate* find(int pci_addr = 0, int sata_port = 0);
// high-level functions (they block)
int read(size_t sector, void* buf, size_t nsectors);
int write(size_t sector, const void* buf, size_t nsectors);
inline int read(void* buf, size_t sz, size_t off);
inline int write(const void* buf, size_t sz, size_t off);
int read_or_write(idecommand cmd, void* buf, size_t sz, size_t off);
// interrupt handlers
void handle_interrupt();
......@@ -272,4 +273,13 @@ inline memfile* memfile::initfs_lookup(const char* name) {
return initfs_lookup(name, strlen(name));
}
inline int ahcistate::read(void* buf, size_t sz, size_t off) {
return read_or_write(cmd_read_fpdma_queued, buf, sz, off);
}
inline int ahcistate::write(const void* buf, size_t sz, size_t off) {
return read_or_write(cmd_write_fpdma_queued, const_cast<void*>(buf),
sz, off);
}
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment