From aecb14b3a75199383c0bbe58bbc098df8d35fe9b Mon Sep 17 00:00:00 2001 From: Suraj Malhotra Date: Wed, 17 Oct 2018 21:51:36 -0700 Subject: [PATCH] [ddk][ddktl] Migrate block protocol to autogenerated version Tested: fvm-test, zxcrypt-test, paved vim2, paved pixelbook Change-Id: I1f719a55e8d82372ce4250acf9acaf6a38bb55b6 --- system/dev/block/ahci/ahci.c | 10 +- system/dev/block/ahci/sata.c | 22 +- system/dev/block/ahci/sata.h | 6 +- system/dev/block/block/block.c | 28 ++- system/dev/block/block/server.cpp | 16 +- system/dev/block/block/server.h | 10 +- system/dev/block/bootpart/bootpart.c | 15 +- system/dev/block/fvm/fvm-private.h | 18 +- system/dev/block/fvm/fvm.cpp | 62 +++--- system/dev/block/gpt/gpt.c | 27 +-- system/dev/block/imx-sdhci/imx-sdhci.c | 1 + system/dev/block/mbr/mbr.c | 26 +-- system/dev/block/nvme/nvme.c | 11 +- system/dev/block/ramdisk/ramdisk.c | 23 +- system/dev/block/sdhci/sdhci.c | 1 + system/dev/block/sdmmc/sdmmc.c | 42 ++-- system/dev/block/usb-mass-storage/block.c | 9 +- .../block/usb-mass-storage/usb-mass-storage.c | 2 +- .../block/usb-mass-storage/usb-mass-storage.h | 2 + system/dev/block/zxcrypt/device.cpp | 22 +- system/dev/block/zxcrypt/device.h | 15 +- system/dev/block/zxcrypt/extra.cpp | 7 +- system/dev/block/zxcrypt/extra.h | 5 +- system/dev/bus/virtio/block.cpp | 7 +- system/dev/bus/virtio/block.h | 7 +- system/fidl/ddk/protocols/block.banjo | 85 +++++++ system/fidl/ddk/protocols/makefile | 3 + system/fidl/ddk/protocols/sdmmc.banjo | 8 - system/ulib/ddk/include/ddk/protocol/block.h | 208 +++++++++--------- system/ulib/ddk/include/ddk/protocol/sdmmc.h | 9 - .../include/ddktl/protocol/block-internal.h | 45 ++-- .../ulib/ddktl/include/ddktl/protocol/block.h | 130 ++++++++--- .../ulib/ddktl/include/ddktl/protocol/sdmmc.h | 2 - system/ulib/zxcrypt/volume.cpp | 13 +- 34 files changed, 538 insertions(+), 359 deletions(-) create mode 100644 system/fidl/ddk/protocols/block.banjo diff --git a/system/dev/block/ahci/ahci.c b/system/dev/block/ahci/ahci.c index d514a1befe..1d20bc82bf 100644 --- a/system/dev/block/ahci/ahci.c +++ b/system/dev/block/ahci/ahci.c @@ -534,7 +534,7 @@ static int ahci_worker_thread(void* arg) { zx_pmt_unpin(txn->pmt); } zxlogf(SPEW, "ahci.%d: complete txn %p\n", port->nr, txn); - block_complete(&txn->bop, ZX_OK); + block_complete(txn, ZX_OK); mtx_lock(&port->lock); } port->completed &= ~(1 << slot); @@ -544,7 +544,7 @@ static int ahci_worker_thread(void* arg) { if ((port->flags & AHCI_PORT_FLAG_SYNC_PAUSED) && !port->running) { port->flags &= ~AHCI_PORT_FLAG_SYNC_PAUSED; if (port->sync) { - block_op_t* sop = &port->sync->bop; + sata_txn_t* sop = port->sync; port->sync = NULL; mtx_unlock(&port->lock); block_complete(sop, ZX_OK); @@ -585,7 +585,7 @@ static int ahci_worker_thread(void* arg) { } else { // complete immediately if nothing in flight mtx_unlock(&port->lock); - block_complete(&txn->bop, ZX_OK); + block_complete(txn, ZX_OK); mtx_lock(&port->lock); } } else { @@ -594,7 +594,7 @@ static int ahci_worker_thread(void* arg) { // complete the transaction with if it failed during processing if (st != ZX_OK) { mtx_unlock(&port->lock); - block_complete(&txn->bop, st); + block_complete(txn, st); mtx_lock(&port->lock); continue; } @@ -636,7 +636,7 @@ static int ahci_watchdog_thread(void* arg) { port->running &= ~(1 << slot); port->commands[slot] = NULL; mtx_unlock(&port->lock); - block_complete(&txn->bop, ZX_ERR_TIMED_OUT); + block_complete(txn, ZX_ERR_TIMED_OUT); mtx_lock(&port->lock); } } diff --git a/system/dev/block/ahci/sata.c b/system/dev/block/ahci/sata.c index 8c8c291e25..ad87058f49 100644 --- a/system/dev/block/ahci/sata.c +++ b/system/dev/block/ahci/sata.c @@ -39,10 +39,10 @@ typedef struct sata_device { int max_cmd; // inclusive } sata_device_t; -static void sata_device_identify_complete(block_op_t* op, zx_status_t status) { +static void sata_device_identify_complete(void* cookie, zx_status_t status, block_op_t* op) { sata_txn_t* txn = containerof(op, sata_txn_t, bop); txn->status = status; - sync_completion_signal((sync_completion_t*)op->cookie); + sync_completion_signal((sync_completion_t*)cookie); } #define QEMU_MODEL_ID "EQUMH RADDSI K" // "QEMU HARDDISK" @@ -76,12 +76,11 @@ static zx_status_t sata_device_identify(sata_device_t* dev, ahci_device_t* contr .rw.length = 1, .rw.offset_dev = 0, .rw.offset_vmo = 0, - .rw.pages = NULL, - .completion_cb = sata_device_identify_complete, - .cookie = &completion, }, .cmd = SATA_CMD_IDENTIFY_DEVICE, .device = 0, + .completion_cb = sata_device_identify_complete, + .cookie = &completion, }; ahci_queue(controller, dev->port, &txn); @@ -232,22 +231,25 @@ static void sata_query(void* ctx, block_info_t* info_out, size_t* block_op_size_ *block_op_size_out = sizeof(sata_txn_t); } -static void sata_queue(void* ctx, block_op_t* bop) { +static void sata_queue(void* ctx, block_op_t* bop, block_impl_queue_callback completion_cb, + void* cookie) { sata_device_t* dev = ctx; sata_txn_t* txn = containerof(bop, sata_txn_t, bop); + txn->completion_cb = completion_cb; + txn->cookie = cookie; switch (BLOCK_OP(bop->command)) { case BLOCK_OP_READ: case BLOCK_OP_WRITE: // complete empty transactions immediately if (bop->rw.length == 0) { - block_complete(bop, ZX_ERR_INVALID_ARGS); + block_complete(txn, ZX_ERR_INVALID_ARGS); return; } // transaction must fit within device if ((bop->rw.offset_dev >= dev->info.block_count) || ((dev->info.block_count - bop->rw.offset_dev) < bop->rw.length)) { - block_complete(bop, ZX_ERR_OUT_OF_RANGE); + block_complete(txn, ZX_ERR_OUT_OF_RANGE); return; } @@ -260,14 +262,14 @@ static void sata_queue(void* ctx, block_op_t* bop) { zxlogf(TRACE, "sata: queue FLUSH txn %p\n", txn); break; default: - block_complete(bop, ZX_ERR_NOT_SUPPORTED); + block_complete(txn, ZX_ERR_NOT_SUPPORTED); return; } ahci_queue(dev->controller, dev->port, txn); } -static block_protocol_ops_t sata_block_proto = { +static block_impl_protocol_ops_t sata_block_proto = { .query = sata_query, .queue = sata_queue, }; diff --git a/system/dev/block/ahci/sata.h b/system/dev/block/ahci/sata.h index 52b8448b0e..51f05f9003 100644 --- a/system/dev/block/ahci/sata.h +++ b/system/dev/block/ahci/sata.h @@ -48,6 +48,8 @@ typedef struct sata_txn { zx_status_t status; zx_handle_t pmt; + block_impl_queue_callback completion_cb; + void* cookie; } sata_txn_t; typedef struct ahci_device ahci_device_t; @@ -65,6 +67,6 @@ void ahci_set_devinfo(ahci_device_t* controller, int portnr, sata_devinfo_t* dev // queue a txn on the controller void ahci_queue(ahci_device_t* controller, int portnr, sata_txn_t* txn); -static inline void block_complete(block_op_t* bop, zx_status_t status) { - bop->completion_cb(bop, status); +static inline void block_complete(sata_txn_t* txn, zx_status_t status) { + txn->completion_cb(txn->cookie, status, &txn->bop); } diff --git a/system/dev/block/block/block.c b/system/dev/block/block/block.c index 7632345193..867cba8c1c 100644 --- a/system/dev/block/block/block.c +++ b/system/dev/block/block/block.c @@ -37,10 +37,10 @@ typedef struct blkdev { uint32_t threadcount; // The block protocol of the device we are binding against. - block_protocol_t parent_protocol; + block_impl_protocol_t parent_protocol; // The block protocol for ourselves, which redirects to the parent protocol, // but may also collect auxiliary information like statistics. - block_protocol_t self_protocol; + block_impl_protocol_t self_protocol; block_info_t info; size_t block_op_size; @@ -229,8 +229,8 @@ static zx_status_t blkdev_ioctl(void* ctx, uint32_t op, const void* cmd, } } -static void block_completion_cb(block_op_t* bop, zx_status_t status) { - blkdev_t* bdev = bop->cookie; +static void block_completion_cb(void* cookie, zx_status_t status, block_op_t* bop) { + blkdev_t* bdev = cookie; bdev->iostatus = status; sync_completion_signal(&bdev->iosignal); } @@ -284,12 +284,9 @@ static zx_status_t blkdev_io(blkdev_t* bdev, void* buf, size_t count, bop->rw.vmo = bdev->iovmo; bop->rw.offset_dev = (off + sub_txn_offset) / bsz; bop->rw.offset_vmo = 0; - bop->rw.pages = NULL; - bop->completion_cb = block_completion_cb; - bop->cookie = bdev; sync_completion_reset(&bdev->iosignal); - bdev->self_protocol.ops->queue(bdev->self_protocol.ctx, bop); + block_impl_queue(&bdev->self_protocol, bop, block_completion_cb, bdev); sync_completion_wait(&bdev->iosignal, ZX_TIME_INFINITE); if (bdev->iostatus != ZX_OK) { @@ -359,13 +356,14 @@ static void blkdev_release(void* ctx) { } } -static void block_query(void* ctx, block_info_t* bi, size_t* bopsz) { +static void blkdev_query(void* ctx, block_info_t* bi, size_t* bopsz) { blkdev_t* bdev = ctx; memcpy(bi, &bdev->info, sizeof(block_info_t)); *bopsz = bdev->block_op_size; } -static void block_queue(void* ctx, block_op_t* bop) { +static void blkdev_queue(void* ctx, block_op_t* bop, block_impl_queue_callback completion_cb, + void* cookie) { blkdev_t* bdev = ctx; uint64_t op = bop->command & BLOCK_OP_MASK; bdev->stats.total_ops++; @@ -378,7 +376,7 @@ static void block_queue(void* ctx, block_op_t* bop) { bdev->stats.total_blocks_written += bop->rw.length; bdev->stats.total_blocks += bop->rw.length; } - bdev->parent_protocol.ops->queue(bdev->parent_protocol.ctx, bop); + block_impl_queue(&bdev->parent_protocol, bop, completion_cb, cookie); } static zx_status_t handle_stats(void* ctx, const void* cmd, @@ -416,9 +414,9 @@ static zx_status_t handle_stats(void* ctx, const void* cmd, } } -static block_protocol_ops_t block_ops = { - .query = block_query, - .queue = block_queue, +static block_impl_protocol_ops_t block_ops = { + .query = blkdev_query, + .queue = blkdev_queue, .get_stats = handle_stats, }; @@ -449,7 +447,7 @@ static zx_status_t block_driver_bind(void* ctx, zx_device_t* dev) { bdev->self_protocol.ctx = bdev; bdev->self_protocol.ops = &block_ops; - bdev->parent_protocol.ops->query(bdev->parent_protocol.ctx, &bdev->info, &bdev->block_op_size); + block_impl_query(&bdev->parent_protocol, &bdev->info, &bdev->block_op_size); // TODO(kmerrick) have this start as false and create IOCTL to toggle it bdev->enable_stats = true; diff --git a/system/dev/block/block/server.cpp b/system/dev/block/block/server.cpp index 38663c7745..dd1ff1bff5 100644 --- a/system/dev/block/block/server.cpp +++ b/system/dev/block/block/server.cpp @@ -63,9 +63,9 @@ void BlockComplete(BlockMsg* msg, zx_status_t status) { extra->server->TxnEnd(); } -void BlockCompleteCb(block_op_t* bop, zx_status_t status) { +void BlockCompleteCb(void* cookie, zx_status_t status, block_op_t* bop) { ZX_DEBUG_ASSERT(bop != nullptr); - BlockMsg msg(static_cast(bop->cookie)); + BlockMsg msg(static_cast(cookie)); BlockComplete(&msg, status); } @@ -88,9 +88,6 @@ void InQueueAdd(zx_handle_t vmo, uint64_t length, uint64_t vmo_offset, bop->rw.vmo = vmo; bop->rw.offset_dev = dev_offset; bop->rw.offset_vmo = vmo_offset; - bop->rw.pages = NULL; - bop->completion_cb = BlockCompleteCb; - bop->cookie = msg; queue->push_back(msg); } @@ -262,11 +259,11 @@ void BlockServer::InQueueDrainer() { // This may be altered in the future if block devices // are capable of implementing hardware barriers. msg->op.command &= ~(BLOCK_FL_BARRIER_BEFORE | BLOCK_FL_BARRIER_AFTER); - bp_->ops->queue(bp_->ctx, &msg->op); + bp_->ops->queue(bp_->ctx, &msg->op, BlockCompleteCb, &*msg); } } -zx_status_t BlockServer::Create(block_protocol_t* bp, fzl::fifo* fifo_out, BlockServer** out) { fbl::AllocChecker ac; BlockServer* bs = new (&ac) BlockServer(bp); @@ -489,7 +486,7 @@ zx_status_t BlockServer::Serve() { } } -BlockServer::BlockServer(block_protocol_t* bp) : +BlockServer::BlockServer(block_impl_protocol_t* bp) : bp_(bp), block_op_size_(0), pending_count_(0), barrier_in_progress_(false), last_id_(VMOID_INVALID + 1) { size_t block_op_size; @@ -511,7 +508,8 @@ void BlockServer::ShutDown() { } // C declarations -zx_status_t blockserver_create(block_protocol_t* bp, zx_handle_t* fifo_out, BlockServer** out) { +zx_status_t blockserver_create(block_impl_protocol_t* bp, zx_handle_t* fifo_out, + BlockServer** out) { fzl::fifo fifo; zx_status_t status = BlockServer::Create(bp, &fifo, out); *fifo_out = fifo.release(); diff --git a/system/dev/block/block/server.h b/system/dev/block/block/server.h index b714e3dd78..ddb63f3a2f 100644 --- a/system/dev/block/block/server.h +++ b/system/dev/block/block/server.h @@ -120,6 +120,7 @@ class BlockMsg { return *this; } + ~BlockMsg() { reset(); } @@ -144,7 +145,8 @@ class BlockMsg { class BlockServer { public: // Creates a new BlockServer. - static zx_status_t Create(block_protocol_t* bp, fzl::fifo* fifo_out, BlockServer** out); // Starts the BlockServer using the current thread @@ -169,7 +171,7 @@ class BlockServer { ~BlockServer(); private: DISALLOW_COPY_ASSIGN_AND_MOVE(BlockServer); - BlockServer(block_protocol_t* bp); + BlockServer(block_impl_protocol_t* bp); // Helper for processing a single message read from the FIFO. void ProcessRequest(block_fifo_request_t* request); @@ -194,7 +196,7 @@ class BlockServer { fzl::fifo fifo_; block_info_t info_; - block_protocol_t* bp_; + block_impl_protocol_t* bp_; size_t block_op_size_; // BARRIER_AFTER is implemented by sticking "BARRIER_BEFORE" on the @@ -220,7 +222,7 @@ typedef struct BlockServer BlockServer; __BEGIN_CDECLS // Allocate a new blockserver + FIFO combo -zx_status_t blockserver_create(block_protocol_t* bp, zx_handle_t* fifo_out, BlockServer** out); +zx_status_t blockserver_create(block_impl_protocol_t* bp, zx_handle_t* fifo_out, BlockServer** out); // Shut down the blockserver. It will stop serving requests. void blockserver_shutdown(BlockServer* bs); diff --git a/system/dev/block/bootpart/bootpart.c b/system/dev/block/bootpart/bootpart.c index 92dc86b9f5..40188f14dc 100644 --- a/system/dev/block/bootpart/bootpart.c +++ b/system/dev/block/bootpart/bootpart.c @@ -26,7 +26,7 @@ typedef struct { zx_device_t* zxdev; zx_device_t* parent; - block_protocol_t bp; + block_impl_protocol_t bp; zbi_partition_t part; block_info_t info; @@ -101,7 +101,8 @@ static void bootpart_query(void* ctx, block_info_t* bi, size_t* bopsz) { *bopsz = bootpart->block_op_size; } -static void bootpart_queue(void* ctx, block_op_t* bop) { +static void bootpart_queue(void* ctx, block_op_t* bop, block_impl_queue_callback completion_cb, + void* cookie) { bootpart_device_t* bootpart = ctx; switch (bop->command & BLOCK_OP_MASK) { @@ -113,7 +114,7 @@ static void bootpart_queue(void* ctx, block_op_t* bop) { // Ensure that the request is in-bounds if ((bop->rw.offset_dev >= max) || ((max - bop->rw.offset_dev) < blocks)) { - bop->completion_cb(bop, ZX_ERR_OUT_OF_RANGE); + completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, bop); return; } @@ -124,11 +125,11 @@ static void bootpart_queue(void* ctx, block_op_t* bop) { case BLOCK_OP_FLUSH: break; default: - bop->completion_cb(bop, ZX_ERR_NOT_SUPPORTED); + completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, bop); return; } - bootpart->bp.ops->queue(bootpart->bp.ctx, bop); + bootpart->bp.ops->queue(bootpart->bp.ctx, bop, completion_cb, cookie); } static void bootpart_unbind(void* ctx) { @@ -156,13 +157,13 @@ static zx_protocol_device_t device_proto = { .release = bootpart_release, }; -static block_protocol_ops_t block_ops = { +static block_impl_protocol_ops_t block_ops = { .query = bootpart_query, .queue = bootpart_queue, }; static zx_status_t bootpart_bind(void* ctx, zx_device_t* parent) { - block_protocol_t bp; + block_impl_protocol_t bp; uint8_t buffer[METADATA_PARTITION_MAP_MAX]; size_t actual; diff --git a/system/dev/block/fvm/fvm-private.h b/system/dev/block/fvm/fvm-private.h index 24523e3826..d45fae2f13 100644 --- a/system/dev/block/fvm/fvm-private.h +++ b/system/dev/block/fvm/fvm-private.h @@ -95,7 +95,9 @@ class VPartitionManager : public ManagerDeviceType { // Block Protocol size_t BlockOpSize() const { return block_op_size_; } - void Queue(block_op_t* txn) const { bp_.ops->queue(bp_.ctx, txn); } + void Queue(block_op_t* txn, block_impl_queue_callback completion_cb, void* cookie) const { + bp_.ops->queue(bp_.ctx, txn, completion_cb, cookie); + } // Acquire access to a VPart Entry which has already been modified (and // will, as a consequence, not be de-allocated underneath us). @@ -127,7 +129,7 @@ class VPartitionManager : public ManagerDeviceType { void DdkRelease(); VPartitionManager(zx_device_t* dev, const block_info_t& info, size_t block_op_size, - const block_protocol_t* bp); + const block_impl_protocol_t* bp); ~VPartitionManager(); private: @@ -207,10 +209,10 @@ class VPartitionManager : public ManagerDeviceType { // Block Protocol const size_t block_op_size_; - block_protocol_t bp_; + block_impl_protocol_t bp_; }; -class VPartition : public PartitionDeviceType, public ddk::BlockProtocol { +class VPartition : public PartitionDeviceType, public ddk::BlockImplProtocol { public: static zx_status_t Create(VPartitionManager* vpm, size_t entry_index, fbl::unique_ptr* out); @@ -222,8 +224,12 @@ class VPartition : public PartitionDeviceType, public ddk::BlockProtocol(op->cookie); +static void IoCallback(void* cookie, zx_status_t status, block_op_t* op) { + VpmIoCookie* c = reinterpret_cast(cookie); if (status != ZX_OK) { c->status.store(status); } @@ -183,15 +183,12 @@ zx_status_t VPartitionManager::DoIoLocked(zx_handle_t vmo, size_t off, bop->rw.length = static_cast(length); bop->rw.offset_dev = dev_offset; bop->rw.offset_vmo = vmo_offset; - bop->rw.pages = NULL; - bop->completion_cb = IoCallback; - bop->cookie = &cookie; memset(buffer.get() + (block_op_size_ * i) + sizeof(block_op_t), 0, block_op_size_ - sizeof(block_op_t)); vmo_offset += length; dev_offset += length; - bp_.ops->queue(bp_.ctx, bop); + Queue(bop, IoCallback, &cookie); } if (flushing) { @@ -199,9 +196,7 @@ zx_status_t VPartitionManager::DoIoLocked(zx_handle_t vmo, size_t off, (block_op_size_ * num_data_txns)); memset(bop, 0, sizeof(*bop)); bop->command = BLOCKIO_FLUSH; - bop->completion_cb = IoCallback; - bop->cookie = &cookie; - bp_.ops->queue(bp_.ctx, bop); + Queue(bop, IoCallback, &cookie); } ZX_DEBUG_ASSERT(len_remaining == 0); @@ -982,18 +977,21 @@ zx_status_t VPartition::DdkIoctl(uint32_t op, const void* cmd, size_t cmdlen, } typedef struct multi_txn_state { - multi_txn_state(size_t total, block_op_t* txn) - : txns_completed(0), txns_total(total), status(ZX_OK), original(txn) {} + multi_txn_state(size_t total, block_op_t* txn, block_impl_queue_callback cb, void* cookie) + : txns_completed(0), txns_total(total), status(ZX_OK), original(txn), completion_cb(cb), + cookie(cookie) {} fbl::Mutex lock; size_t txns_completed TA_GUARDED(lock); size_t txns_total TA_GUARDED(lock); zx_status_t status TA_GUARDED(lock); block_op_t* original TA_GUARDED(lock); + block_impl_queue_callback completion_cb TA_GUARDED(lock); + void* cookie TA_GUARDED(lock); } multi_txn_state_t; -static void multi_txn_completion(block_op_t* txn, zx_status_t status) { - multi_txn_state_t* state = static_cast(txn->cookie); +static void multi_txn_completion(void* cookie, zx_status_t status, block_op_t* txn) { + multi_txn_state_t* state = static_cast(cookie); bool last_txn = false; { fbl::AutoLock lock(&state->lock); @@ -1003,7 +1001,7 @@ static void multi_txn_completion(block_op_t* txn, zx_status_t status) { } if (state->txns_completed == state->txns_total) { last_txn = true; - state->original->completion_cb(state->original, state->status); + state->completion_cb(state->cookie, state->status, state->original); } } @@ -1013,7 +1011,8 @@ static void multi_txn_completion(block_op_t* txn, zx_status_t status) { delete[] txn; } -void VPartition::BlockQueue(block_op_t* txn) { +void VPartition::BlockImplQueue(block_op_t* txn, block_impl_queue_callback completion_cb, + void* cookie) { ZX_DEBUG_ASSERT(mgr_->BlockOpSize() > 0); switch (txn->command & BLOCK_OP_MASK) { case BLOCK_OP_READ: @@ -1021,21 +1020,21 @@ void VPartition::BlockQueue(block_op_t* txn) { break; // Pass-through operations case BLOCK_OP_FLUSH: - mgr_->Queue(txn); + mgr_->Queue(txn, completion_cb, cookie); return; default: fprintf(stderr, "[FVM BlockQueue] Unsupported Command: %x\n", txn->command); - txn->completion_cb(txn, ZX_ERR_NOT_SUPPORTED); + completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, txn); return; } const uint64_t device_capacity = DdkGetSize() / BlockSize(); if (txn->rw.length == 0) { - txn->completion_cb(txn, ZX_ERR_INVALID_ARGS); + completion_cb(cookie, ZX_ERR_INVALID_ARGS, txn); return; } else if ((txn->rw.offset_dev >= device_capacity) || (device_capacity - txn->rw.offset_dev < txn->rw.length)) { - txn->completion_cb(txn, ZX_ERR_OUT_OF_RANGE); + completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, txn); return; } @@ -1051,12 +1050,12 @@ void VPartition::BlockQueue(block_op_t* txn) { // Common case: txn occurs within one slice uint32_t pslice = SliceGetLocked(vslice_start); if (pslice == PSLICE_UNALLOCATED) { - txn->completion_cb(txn, ZX_ERR_OUT_OF_RANGE); + completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, txn); return; } txn->rw.offset_dev = SliceStart(disk_size, slice_size, pslice) / BlockSize() + (txn->rw.offset_dev % blocks_per_slice); - mgr_->Queue(txn); + mgr_->Queue(txn, completion_cb, cookie); return; } @@ -1067,7 +1066,7 @@ void VPartition::BlockQueue(block_op_t* txn) { bool contiguous = true; for (size_t vslice = vslice_start; vslice <= vslice_end; vslice++) { if (SliceGetLocked(vslice) == PSLICE_UNALLOCATED) { - txn->completion_cb(txn, ZX_ERR_OUT_OF_RANGE); + completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, txn); return; } if (vslice != vslice_start && SliceGetLocked(vslice - 1) + 1 != SliceGetLocked(vslice)) { @@ -1080,7 +1079,7 @@ void VPartition::BlockQueue(block_op_t* txn) { uint32_t pslice = SliceGetLocked(vslice_start); txn->rw.offset_dev = SliceStart(disk_size, slice_size, pslice) / BlockSize() + (txn->rw.offset_dev % blocks_per_slice); - mgr_->Queue(txn); + mgr_->Queue(txn, completion_cb, cookie); return; } @@ -1090,9 +1089,10 @@ void VPartition::BlockQueue(block_op_t* txn) { txns.reserve(txn_count); fbl::AllocChecker ac; - fbl::unique_ptr state(new (&ac) multi_txn_state_t(txn_count, txn)); + fbl::unique_ptr state( + new (&ac) multi_txn_state_t(txn_count, txn, completion_cb, cookie)); if (!ac.check()) { - txn->completion_cb(txn, ZX_ERR_NO_MEMORY); + completion_cb(cookie, ZX_ERR_NO_MEMORY, txn); return; } @@ -1120,7 +1120,7 @@ void VPartition::BlockQueue(block_op_t* txn) { while (i-- > 0) { delete[] txns[i]; } - txn->completion_cb(txn, ZX_ERR_NO_MEMORY); + completion_cb(cookie, ZX_ERR_NO_MEMORY, txn); return; } memcpy(txns[i], txn, sizeof(*txn)); @@ -1131,13 +1131,11 @@ void VPartition::BlockQueue(block_op_t* txn) { txns[i]->rw.offset_dev += (txn->rw.offset_dev % blocks_per_slice); } length_remaining -= txns[i]->rw.length; - txns[i]->completion_cb = multi_txn_completion; - txns[i]->cookie = state.get(); } ZX_DEBUG_ASSERT(length_remaining == 0); for (size_t i = 0; i < txn_count; i++) { - mgr_->Queue(txns[i]); + mgr_->Queue(txns[i], multi_txn_completion, state.get()); } // TODO(johngro): ask smklein why it is OK to release this managed pointer. __UNUSED auto ptr = state.release(); @@ -1158,7 +1156,7 @@ void VPartition::DdkRelease() { delete this; } -void VPartition::BlockQuery(block_info_t* info_out, size_t* block_op_size_out) { +void VPartition::BlockImplQuery(block_info_t* info_out, size_t* block_op_size_out) { static_assert(fbl::is_same::value, "Info type mismatch"); memcpy(info_out, &info_, sizeof(info_)); *block_op_size_out = mgr_->BlockOpSize(); diff --git a/system/dev/block/gpt/gpt.c b/system/dev/block/gpt/gpt.c index aeefd42c19..8a95f80e5f 100644 --- a/system/dev/block/gpt/gpt.c +++ b/system/dev/block/gpt/gpt.c @@ -40,7 +40,7 @@ typedef struct gptpart_device { zx_device_t* zxdev; zx_device_t* parent; - block_protocol_t bp; + block_impl_protocol_t bp; gpt_entry_t gpt_entry; @@ -161,7 +161,8 @@ static void gpt_query(void* ctx, block_info_t* bi, size_t* bopsz) { *bopsz = gpt->block_op_size; } -static void gpt_queue(void* ctx, block_op_t* bop) { +static void gpt_queue(void* ctx, block_op_t* bop, block_impl_queue_callback completion_cb, + void* cookie) { gptpart_device_t* gpt = ctx; switch (bop->command & BLOCK_OP_MASK) { @@ -173,7 +174,7 @@ static void gpt_queue(void* ctx, block_op_t* bop) { // Ensure that the request is in-bounds if ((bop->rw.offset_dev >= max) || ((max - bop->rw.offset_dev) < blocks)) { - bop->completion_cb(bop, ZX_ERR_OUT_OF_RANGE); + completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, bop); return; } @@ -184,11 +185,11 @@ static void gpt_queue(void* ctx, block_op_t* bop) { case BLOCK_OP_FLUSH: break; default: - bop->completion_cb(bop, ZX_ERR_NOT_SUPPORTED); + completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, bop); return; } - gpt->bp.ops->queue(gpt->bp.ctx, bop); + block_impl_queue(&gpt->bp, bop, completion_cb, cookie); } static void gpt_unbind(void* ctx) { @@ -216,16 +217,16 @@ static zx_protocol_device_t gpt_proto = { .release = gpt_release, }; -static block_protocol_ops_t block_ops = { +static block_impl_protocol_ops_t block_ops = { .query = gpt_query, .queue = gpt_queue, }; -static void gpt_read_sync_complete(block_op_t* bop, zx_status_t status) { +static void gpt_read_sync_complete(void* cookie, zx_status_t status, block_op_t* bop) { // Pass 32bit status back to caller via 32bit command field // Saves from needing custom structs, etc. bop->command = status; - sync_completion_signal((sync_completion_t*)bop->cookie); + sync_completion_signal((sync_completion_t*)cookie); } static zx_status_t vmo_read(zx_handle_t vmo, void* data, uint64_t off, size_t len) { @@ -242,7 +243,7 @@ static int gpt_bind_thread(void* arg) { // used to keep track of number of partitions found unsigned partitions = 0; - block_protocol_t bp; + block_impl_protocol_t bp; memcpy(&bp, &first_dev->bp, sizeof(bp)); block_info_t block_info; @@ -275,11 +276,8 @@ static int gpt_bind_thread(void* arg) { bop->rw.length = 1; bop->rw.offset_dev = 1; bop->rw.offset_vmo = 0; - bop->rw.pages = NULL; - bop->completion_cb = gpt_read_sync_complete; - bop->cookie = &completion; - bp.ops->queue(bp.ctx, bop); + bp.ops->queue(bp.ctx, bop, gpt_read_sync_complete, &completion); sync_completion_wait(&completion, ZX_TIME_INFINITE); if (bop->command != ZX_OK) { zxlogf(ERROR, "gpt: error %d reading partition header\n", bop->command); @@ -312,10 +310,9 @@ static int gpt_bind_thread(void* arg) { bop->rw.length = (table_sz + (block_info.block_size - 1)) / block_info.block_size; bop->rw.offset_dev = header.entries; bop->rw.offset_vmo = 0; - bop->rw.pages = NULL; sync_completion_reset(&completion); - bp.ops->queue(bp.ctx, bop); + bp.ops->queue(bp.ctx, bop, gpt_read_sync_complete, &completion); sync_completion_wait(&completion, ZX_TIME_INFINITE); if (bop->command != ZX_OK) { zxlogf(ERROR, "gpt: error %d reading partition table\n", bop->command); diff --git a/system/dev/block/imx-sdhci/imx-sdhci.c b/system/dev/block/imx-sdhci/imx-sdhci.c index 38a5250125..a1c5e3dca6 100644 --- a/system/dev/block/imx-sdhci/imx-sdhci.c +++ b/system/dev/block/imx-sdhci/imx-sdhci.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/system/dev/block/mbr/mbr.c b/system/dev/block/mbr/mbr.c index 8546788a50..a1e9be8a9a 100644 --- a/system/dev/block/mbr/mbr.c +++ b/system/dev/block/mbr/mbr.c @@ -58,7 +58,7 @@ typedef struct mbrpart_device { zx_device_t* zxdev; zx_device_t* parent; - block_protocol_t bp; + block_impl_protocol_t bp; mbr_partition_entry_t partition; @@ -128,7 +128,8 @@ static void mbr_query(void* ctx, block_info_t* bi, size_t* bopsz) { *bopsz = mbr->block_op_size; } -static void mbr_queue(void* ctx, block_op_t* bop) { +static void mbr_queue(void* ctx, block_op_t* bop, block_impl_queue_callback completion_cb, + void* cookie) { mbrpart_device_t* mbr = ctx; switch (bop->command & BLOCK_OP_MASK) { @@ -140,7 +141,7 @@ static void mbr_queue(void* ctx, block_op_t* bop) { // Ensure that the request is in-bounds if ((bop->rw.offset_dev >= max) || ((max - bop->rw.offset_dev) < blocks)) { - bop->completion_cb(bop, ZX_ERR_INVALID_ARGS); + completion_cb(cookie, ZX_ERR_INVALID_ARGS, bop); return; } @@ -151,11 +152,11 @@ static void mbr_queue(void* ctx, block_op_t* bop) { case BLOCK_OP_FLUSH: break; default: - bop->completion_cb(bop, ZX_ERR_NOT_SUPPORTED); + completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, bop); return; } - mbr->bp.ops->queue(mbr->bp.ctx, bop); + block_impl_queue(&mbr->bp, bop, completion_cb, cookie); } static void mbr_unbind(void* ctx) { @@ -183,14 +184,14 @@ static zx_protocol_device_t mbr_proto = { .release = mbr_release, }; -static block_protocol_ops_t block_ops = { +static block_impl_protocol_ops_t block_ops = { .query = mbr_query, .queue = mbr_queue, }; -static void mbr_read_sync_complete(block_op_t* bop, zx_status_t status) { +static void mbr_read_sync_complete(void* cookie, zx_status_t status, block_op_t* bop) { bop->command = status; - sync_completion_signal((sync_completion_t*)bop->cookie); + sync_completion_signal((sync_completion_t*)cookie); } static zx_status_t vmo_read(zx_handle_t vmo, void* data, uint64_t off, size_t len) { @@ -204,12 +205,12 @@ static int mbr_bind_thread(void* arg) { // Classic MBR supports 4 partitions. uint8_t partition_count = 0; - block_protocol_t bp; + block_impl_protocol_t bp; memcpy(&bp, &first_dev->bp, sizeof(bp)); block_info_t block_info; size_t block_op_size; - bp.ops->query(bp.ctx, &block_info, &block_op_size); + block_impl_query(&bp, &block_info, &block_op_size); zx_handle_t vmo = ZX_HANDLE_INVALID; block_op_t* bop = calloc(1, block_op_size); @@ -240,11 +241,8 @@ static int mbr_bind_thread(void* arg) { bop->rw.length = iosize / block_info.block_size; bop->rw.offset_dev = 0; bop->rw.offset_vmo = 0; - bop->rw.pages = NULL; - bop->completion_cb = mbr_read_sync_complete; - bop->cookie = &cplt; - bp.ops->queue(bp.ctx, bop); + bp.ops->queue(bp.ctx, bop, mbr_read_sync_complete, &cplt); sync_completion_wait(&cplt, ZX_TIME_INFINITE); if (bop->command != ZX_OK) { diff --git a/system/dev/block/nvme/nvme.c b/system/dev/block/nvme/nvme.c index 7cfcc1cb18..b4f706f74a 100644 --- a/system/dev/block/nvme/nvme.c +++ b/system/dev/block/nvme/nvme.c @@ -36,6 +36,8 @@ typedef struct { block_op_t op; list_node_t node; + block_impl_queue_callback completion_cb; + void* cookie; uint16_t pending_utxns; uint8_t opcode; uint8_t flags; @@ -297,7 +299,7 @@ static zx_status_t nvme_admin_txn(nvme_device_t* nvme, nvme_cmd_t* cmd, nvme_cpl } static inline void txn_complete(nvme_txn_t* txn, zx_status_t status) { - txn->op.completion_cb(&txn->op, status); + txn->completion_cb(txn->cookie, status, &txn->op); } // Attempt to generate utxns and queue nvme commands for a txn @@ -518,9 +520,12 @@ static int io_thread(void* arg) { return 0; } -static void nvme_queue(void* ctx, block_op_t* op) { +static void nvme_queue(void* ctx, block_op_t* op, block_impl_queue_callback completion_cb, + void* cookie) { nvme_device_t* nvme = ctx; nvme_txn_t* txn = containerof(op, nvme_txn_t, op); + txn->completion_cb = completion_cb; + txn->cookie = cookie; switch (txn->op.command & BLOCK_OP_MASK) { case BLOCK_OP_READ: @@ -1005,7 +1010,7 @@ static zx_status_t nvme_init(nvme_device_t* nvme) { return ZX_OK; } -block_protocol_ops_t block_ops = { +block_impl_protocol_ops_t block_ops = { .query = nvme_query, .queue = nvme_queue, }; diff --git a/system/dev/block/ramdisk/ramdisk.c b/system/dev/block/ramdisk/ramdisk.c index 32610a4218..b589787c63 100644 --- a/system/dev/block/ramdisk/ramdisk.c +++ b/system/dev/block/ramdisk/ramdisk.c @@ -58,6 +58,8 @@ typedef struct ramdisk_device { typedef struct { block_op_t op; list_node_t node; + block_impl_queue_callback completion_cb; + void* cookie; } ramdisk_txn_t; // The worker thread processes messages from iotxns in the background @@ -179,12 +181,14 @@ static int worker_thread(void* arg) { } } - txn->op.completion_cb(&txn->op, status); + if (txn->completion_cb) { + txn->completion_cb(txn->cookie, status, &txn->op); + } } goodbye: while (txn != NULL) { - txn->op.completion_cb(&txn->op, ZX_ERR_BAD_STATE); + txn->completion_cb(txn->cookie, ZX_ERR_BAD_STATE, &txn->op); txn = list_remove_head_type(&dev->deferred_list, ramdisk_txn_t, node); if (txn == NULL) { @@ -309,7 +313,8 @@ static zx_status_t ramdisk_ioctl(void* ctx, uint32_t op, const void* cmd, size_t } } -static void ramdisk_queue(void* ctx, block_op_t* bop) { +static void ramdisk_queue(void* ctx, block_op_t* bop, block_impl_queue_callback completion_cb, + void* cookie) { ramdisk_device_t* ramdev = ctx; ramdisk_txn_t* txn = containerof(bop, ramdisk_txn_t, op); bool dead; @@ -322,7 +327,7 @@ static void ramdisk_queue(void* ctx, block_op_t* bop) { case BLOCK_OP_WRITE: if ((txn->op.rw.offset_dev >= ramdev->blk_count) || ((ramdev->blk_count - txn->op.rw.offset_dev) < txn->op.rw.length)) { - bop->completion_cb(bop, ZX_ERR_OUT_OF_RANGE); + completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, bop); return; } @@ -331,20 +336,22 @@ static void ramdisk_queue(void* ctx, block_op_t* bop) { if (!read) { ramdev->blk_counts.received += txn->op.rw.length; } + txn->completion_cb = completion_cb; + txn->cookie = cookie; list_add_tail(&ramdev->txn_list, &txn->node); } mtx_unlock(&ramdev->lock); if (dead) { - bop->completion_cb(bop, ZX_ERR_BAD_STATE); + completion_cb(cookie, ZX_ERR_BAD_STATE, bop); } else { sync_completion_signal(&ramdev->signal); } break; case BLOCK_OP_FLUSH: - bop->completion_cb(bop, ZX_OK); + completion_cb(cookie, ZX_OK, bop); break; default: - bop->completion_cb(bop, ZX_ERR_NOT_SUPPORTED); + completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, bop); break; } } @@ -376,7 +383,7 @@ static void ramdisk_release(void* ctx) { free(ramdev); } -static block_protocol_ops_t block_ops = { +static block_impl_protocol_ops_t block_ops = { .query = ramdisk_query, .queue = ramdisk_queue, }; diff --git a/system/dev/block/sdhci/sdhci.c b/system/dev/block/sdhci/sdhci.c index 96a7436255..df7cea05e1 100644 --- a/system/dev/block/sdhci/sdhci.c +++ b/system/dev/block/sdhci/sdhci.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/system/dev/block/sdmmc/sdmmc.c b/system/dev/block/sdmmc/sdmmc.c index b31f445947..7d6bd81fff 100644 --- a/system/dev/block/sdmmc/sdmmc.c +++ b/system/dev/block/sdmmc/sdmmc.c @@ -40,8 +40,17 @@ #define BLOCK_OP(op) ((op) & BLOCK_OP_MASK) -static void block_complete(block_op_t* bop, zx_status_t status, sdmmc_device_t* dev) { - if (bop->completion_cb) { +// block io transactions. one per client request +typedef struct sdmmc_txn { + block_op_t bop; + list_node_t node; + block_impl_queue_callback completion_cb; + void* cookie; +} sdmmc_txn_t; + +static void block_complete(sdmmc_txn_t* txn, zx_status_t status, sdmmc_device_t* dev) { + const block_op_t* bop = &txn->bop; + if (txn->completion_cb) { // If tracing is not enabled this is a no-op. TRACE_ASYNC_END("sdmmc","sdmmc_do_txn", dev->async_id, "command", TA_INT32(bop->rw.command), @@ -49,9 +58,8 @@ static void block_complete(block_op_t* bop, zx_status_t status, sdmmc_device_t* "length", TA_INT32(bop->rw.length), "offset_vmo", TA_INT64(bop->rw.offset_vmo), "offset_dev", TA_INT64(bop->rw.offset_dev), - "pages", TA_POINTER(bop->rw.pages), "txn_status", TA_INT32(status)); - bop->completion_cb(bop, status); + txn->completion_cb(txn->cookie, status, &txn->bop); } else { zxlogf(TRACE, "sdmmc: block op %p completion_cb unset!\n", bop); } @@ -102,7 +110,7 @@ static void sdmmc_release(void* ctx) { list_for_every_entry(&dev->txn_list, txn, sdmmc_txn_t, node) { SDMMC_UNLOCK(dev); - block_complete(&txn->bop, ZX_ERR_BAD_STATE, dev); + block_complete(txn, ZX_ERR_BAD_STATE, dev); SDMMC_LOCK(dev); } @@ -134,20 +142,23 @@ static void sdmmc_query(void* ctx, block_info_t* info_out, size_t* block_op_size *block_op_size_out = sizeof(sdmmc_txn_t); } -static void sdmmc_queue(void* ctx, block_op_t* btxn) { +static void sdmmc_queue(void* ctx, block_op_t* btxn, block_impl_queue_callback completion_cb, + void* cookie) { sdmmc_device_t* dev = ctx; sdmmc_txn_t* txn = containerof(btxn, sdmmc_txn_t, bop); + txn->completion_cb = completion_cb; + txn->cookie = cookie; switch (BLOCK_OP(btxn->command)) { case BLOCK_OP_READ: case BLOCK_OP_WRITE: { uint64_t max = dev->block_info.block_count; if ((btxn->rw.offset_dev >= max) || ((max - btxn->rw.offset_dev) < btxn->rw.length)) { - block_complete(btxn, ZX_ERR_OUT_OF_RANGE, dev); + block_complete(txn, ZX_ERR_OUT_OF_RANGE, dev); return; } if (btxn->rw.length == 0) { - block_complete(btxn, ZX_OK, dev); + block_complete(txn, ZX_OK, dev); return; } break; @@ -157,7 +168,7 @@ static void sdmmc_queue(void* ctx, block_op_t* btxn) { // driver, when this op gets processed all previous ops are complete. break; default: - block_complete(btxn, ZX_ERR_NOT_SUPPORTED, dev); + block_complete(txn, ZX_ERR_NOT_SUPPORTED, dev); return; } @@ -172,7 +183,7 @@ static void sdmmc_queue(void* ctx, block_op_t* btxn) { } // Block protocol -static block_protocol_ops_t block_proto = { +static block_impl_protocol_ops_t block_proto = { .query = sdmmc_query, .queue = sdmmc_queue, }; @@ -231,8 +242,7 @@ static void sdmmc_do_txn(sdmmc_device_t* dev, sdmmc_txn_t* txn) { "extra", TA_INT32(txn->bop.rw.extra), "length", TA_INT32(txn->bop.rw.length), "offset_vmo", TA_INT64(txn->bop.rw.offset_vmo), - "offset_dev", TA_INT64(txn->bop.rw.offset_dev), - "pages", TA_POINTER(txn->bop.rw.pages)); + "offset_dev", TA_INT64(txn->bop.rw.offset_dev)); } uint32_t cmd_idx = 0; @@ -259,13 +269,13 @@ static void sdmmc_do_txn(sdmmc_device_t* dev, sdmmc_txn_t* txn) { } break; case BLOCK_OP_FLUSH: - block_complete(&txn->bop, ZX_OK, dev); + block_complete(txn, ZX_OK, dev); return; default: // should not get here zxlogf(ERROR, "sdmmc: do_txn invalid block op %d\n", BLOCK_OP(txn->bop.command)); ZX_DEBUG_ASSERT(true); - block_complete(&txn->bop, ZX_ERR_INVALID_ARGS, dev); + block_complete(txn, ZX_ERR_INVALID_ARGS, dev); return; } @@ -300,7 +310,7 @@ static void sdmmc_do_txn(sdmmc_device_t* dev, sdmmc_txn_t* txn) { (uintptr_t*)&req->virt_buffer); if (st != ZX_OK) { zxlogf(TRACE, "sdmmc: do_txn vmo map error %d\n", st); - block_complete(&txn->bop, st, dev); + block_complete(txn, st, dev); return; } req->virt_size = txn->bop.rw.length; @@ -324,7 +334,7 @@ static void sdmmc_do_txn(sdmmc_device_t* dev, sdmmc_txn_t* txn) { if (!req->use_dma) { zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)req->virt_buffer, req->virt_size); } - block_complete(&txn->bop, st, dev); + block_complete(txn, st, dev); zxlogf(TRACE, "sdmmc: do_txn complete\n"); } diff --git a/system/dev/block/usb-mass-storage/block.c b/system/dev/block/usb-mass-storage/block.c index ee1e0895f1..64b68f68c6 100644 --- a/system/dev/block/usb-mass-storage/block.c +++ b/system/dev/block/usb-mass-storage/block.c @@ -9,9 +9,12 @@ #include #include -static void ums_block_queue(void* ctx, block_op_t* op) { +static void ums_block_queue(void* ctx, block_op_t* op, block_impl_queue_callback completion_cb, + void* cookie) { ums_block_t* dev = ctx; ums_txn_t* txn = block_op_to_txn(op); + txn->completion_cb = completion_cb; + txn->cookie = cookie; switch (op->command & BLOCK_OP_MASK) { case BLOCK_OP_READ: @@ -25,7 +28,7 @@ static void ums_block_queue(void* ctx, block_op_t* op) { break; default: zxlogf(ERROR, "ums_block_queue: unsupported command %u\n", op->command); - op->completion_cb(&txn->op, ZX_ERR_NOT_SUPPORTED); + completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, &txn->op); return; } @@ -53,7 +56,7 @@ static void ums_block_query(void* ctx, block_info_t* info_out, size_t* block_op_ *block_op_size_out = sizeof(ums_txn_t); } -static block_protocol_ops_t ums_block_ops = { +static block_impl_protocol_ops_t ums_block_ops = { .query = ums_block_query, .queue = ums_block_queue, }; diff --git a/system/dev/block/usb-mass-storage/usb-mass-storage.c b/system/dev/block/usb-mass-storage/usb-mass-storage.c index 92f3e03f26..cc3c062b45 100644 --- a/system/dev/block/usb-mass-storage/usb-mass-storage.c +++ b/system/dev/block/usb-mass-storage/usb-mass-storage.c @@ -30,7 +30,7 @@ static csw_status_t ums_verify_csw(ums_t* ums, usb_request_t* csw_request, uint3 static inline void txn_complete(ums_txn_t* txn, zx_status_t status) { zxlogf(TRACE, "UMS DONE %d (%p)\n", status, &txn->op); - txn->op.completion_cb(&txn->op, status); + txn->completion_cb(txn->cookie, status, &txn->op); } static zx_status_t ums_reset(ums_t* ums) { diff --git a/system/dev/block/usb-mass-storage/usb-mass-storage.h b/system/dev/block/usb-mass-storage/usb-mass-storage.h index 3c424f4696..3418868850 100644 --- a/system/dev/block/usb-mass-storage/usb-mass-storage.h +++ b/system/dev/block/usb-mass-storage/usb-mass-storage.h @@ -66,6 +66,8 @@ typedef struct { typedef struct ums_txn { block_op_t op; + block_impl_queue_callback completion_cb; + void* cookie; list_node_t node; ums_block_t* dev; } ums_txn_t; diff --git a/system/dev/block/zxcrypt/device.cpp b/system/dev/block/zxcrypt/device.cpp index 22a31f579a..8ddbaa6533 100644 --- a/system/dev/block/zxcrypt/device.cpp +++ b/system/dev/block/zxcrypt/device.cpp @@ -317,7 +317,7 @@ void Device::DdkRelease() { //////////////////////////////////////////////////////////////// // ddk::BlockProtocol methods -void Device::BlockQuery(block_info_t* out_info, size_t* out_op_size) { +void Device::BlockImplQuery(block_info_t* out_info, size_t* out_op_size) { LOG_ENTRY_ARGS("out_info=%p, out_op_size=%p", out_info, out_op_size); ZX_DEBUG_ASSERT(info_); @@ -326,21 +326,22 @@ void Device::BlockQuery(block_info_t* out_info, size_t* out_op_size) { *out_op_size = info_->op_size; } -void Device::BlockQueue(block_op_t* block) { +void Device::BlockImplQueue(block_op_t* block, block_impl_queue_callback completion_cb, + void* cookie) { LOG_ENTRY_ARGS("block=%p", block); ZX_DEBUG_ASSERT(info_); // Check if the device is active. if (!active_.load()) { zxlogf(ERROR, "rejecting I/O request: device is not active\n"); - block->completion_cb(block, ZX_ERR_BAD_STATE); + completion_cb(cookie, ZX_ERR_BAD_STATE, block); return; } num_ops_.fetch_add(1); // Initialize our extra space and save original values extra_op_t* extra = BlockToExtra(block, info_->op_size); - zx_status_t rc = extra->Init(block, info_->reserved_blocks); + zx_status_t rc = extra->Init(block, completion_cb, cookie, info_->reserved_blocks); if (rc != ZX_OK) { zxlogf(ERROR, "failed to initialize extra info: %s\n", zx_status_get_string(rc)); BlockComplete(block, rc); @@ -377,12 +378,9 @@ void Device::BlockForward(block_op_t* block, zx_status_t status) { BlockComplete(block, ZX_ERR_BAD_STATE); return; } - // Register ourselves as the callback - block->completion_cb = BlockCallback; - block->cookie = this; // Send the request to the parent device - info_->proto.ops->queue(info_->proto.ctx, block); + block_impl_queue(&info_->proto, block, BlockCallback, this); } void Device::BlockComplete(block_op_t* block, zx_status_t status) { @@ -404,7 +402,7 @@ void Device::BlockComplete(block_op_t* block, zx_status_t status) { } // Complete the request. - block->completion_cb(block, status); + extra->completion_cb(extra->cookie, status, block); // If we previously stalled, try to re-queue the deferred requests; otherwise, avoid taking the // lock. @@ -493,18 +491,16 @@ void Device::SendToWorker(block_op_t* block) { } } -void Device::BlockCallback(block_op_t* block, zx_status_t status) { +void Device::BlockCallback(void* cookie, zx_status_t status, block_op_t* block) { LOG_ENTRY_ARGS("block=%p, status=%s", block, zx_status_get_string(status)); // Restore data that may have changed - Device* device = static_cast(block->cookie); + Device* device = static_cast(cookie); extra_op_t* extra = BlockToExtra(block, device->op_size()); block->rw.vmo = extra->vmo; block->rw.length = extra->length; block->rw.offset_dev = extra->offset_dev; block->rw.offset_vmo = extra->offset_vmo; - block->completion_cb = extra->completion_cb; - block->cookie = extra->cookie; if (status != ZX_OK) { zxlogf(TRACE, "parent device returned %s\n", zx_status_get_string(status)); diff --git a/system/dev/block/zxcrypt/device.h b/system/dev/block/zxcrypt/device.h index b90650594e..e4d81fe8b4 100644 --- a/system/dev/block/zxcrypt/device.h +++ b/system/dev/block/zxcrypt/device.h @@ -40,7 +40,7 @@ using DeviceType = ddk::Device { +class Device final : public DeviceType, public ddk::BlockImplProtocol { public: explicit Device(zx_device_t* parent); ~Device(); @@ -65,8 +65,13 @@ class Device final : public DeviceType, public ddk::BlockProtocol { void DdkRelease(); // ddk::BlockProtocol methods; see ddktl/protocol/block.h - void BlockQuery(block_info_t* out_info, size_t* out_op_size); - void BlockQueue(block_op_t* block) __TA_EXCLUDES(mtx_); + void BlockImplQuery(block_info_t* out_info, size_t* out_op_size); + void BlockImplQueue(block_op_t* block, block_impl_queue_callback completion_cb, + void* cookie) __TA_EXCLUDES(mtx_); + zx_status_t BlockImplGetStats(const void* cmd_buffer, size_t cmd_size, void* out_reply_buffer, + size_t reply_size, size_t* out_reply_actual) { + return ZX_ERR_NOT_SUPPORTED; + } // If |status| is |ZX_OK|, sends |block| to the parent block device; otherwise calls // |BlockComplete| on the |block|. Uses the extra space following the |block| to save fields @@ -92,7 +97,7 @@ class Device final : public DeviceType, public ddk::BlockProtocol { // Callback used for block ops sent to the parent device. Restores the fields saved by // |BlockForward|. - static void BlockCallback(block_op_t* block, zx_status_t status); + static void BlockCallback(void* cookie, zx_status_t status, block_op_t* block); // Requests that the workers stop if it the device is inactive and no ops are "in-flight". void StopWorkersIfDone(); @@ -119,7 +124,7 @@ class Device final : public DeviceType, public ddk::BlockProtocol { // The parent device's required block_op_t size. size_t op_size; // Callbacks to the parent's block protocol methods. - block_protocol_t proto; + block_impl_protocol_t proto; // The number of blocks reserved for metadata. uint64_t reserved_blocks; // The number of slices reserved for metadata. diff --git a/system/dev/block/zxcrypt/extra.cpp b/system/dev/block/zxcrypt/extra.cpp index cc9a91c989..024c2c21d7 100644 --- a/system/dev/block/zxcrypt/extra.cpp +++ b/system/dev/block/zxcrypt/extra.cpp @@ -18,13 +18,14 @@ namespace zxcrypt { -zx_status_t extra_op_t::Init(block_op_t* block, size_t reserved_blocks) { +zx_status_t extra_op_t::Init(block_op_t* block, block_impl_queue_callback cb, void* _cookie, + size_t reserved_blocks) { LOG_ENTRY_ARGS("block=%p, reserved_blocks=%zu", block, reserved_blocks); list_initialize(&node); data = nullptr; - completion_cb = block->completion_cb; - cookie = block->cookie; + completion_cb = cb; + cookie = _cookie; switch (block->command & BLOCK_OP_MASK) { case BLOCK_OP_READ: diff --git a/system/dev/block/zxcrypt/extra.h b/system/dev/block/zxcrypt/extra.h index 516fe1d606..fc61c4a8b3 100644 --- a/system/dev/block/zxcrypt/extra.h +++ b/system/dev/block/zxcrypt/extra.h @@ -33,11 +33,12 @@ struct extra_op_t { uint32_t length; uint64_t offset_dev; uint64_t offset_vmo; - void (*completion_cb)(block_op_t* block, zx_status_t status); + block_impl_queue_callback completion_cb; void* cookie; // Resets this structure to an initial state. - zx_status_t Init(block_op_t* block, size_t reserved_blocks); + zx_status_t Init(block_op_t* block, block_impl_queue_callback completion_cb, void* cookie, + size_t reserved_blocks); }; // Translates |block_op_t|s to |extra_op_t|s and vice versa. diff --git a/system/dev/bus/virtio/block.cpp b/system/dev/bus/virtio/block.cpp index 73792825e0..cadf0bc7da 100644 --- a/system/dev/bus/virtio/block.cpp +++ b/system/dev/bus/virtio/block.cpp @@ -32,7 +32,7 @@ void BlockDevice::txn_complete(block_txn_t* txn, zx_status_t status) { zx_pmt_unpin(txn->pmt); txn->pmt = ZX_HANDLE_INVALID; } - txn->op.completion_cb(&txn->op, status); + txn->completion_cb(txn->cookie, status, &txn->op); } // DDK level ops @@ -65,10 +65,13 @@ void BlockDevice::virtio_block_query(void* ctx, block_info_t* info, size_t* bops *bopsz = sizeof(block_txn_t); } -void BlockDevice::virtio_block_queue(void* ctx, block_op_t* bop) { +void BlockDevice::virtio_block_queue(void* ctx, block_op_t* bop, + block_impl_queue_callback completion_cb, void* cookie) { BlockDevice* bd = static_cast(ctx); block_txn_t* txn = static_cast((void*) bop); txn->pmt = ZX_HANDLE_INVALID; + txn->completion_cb = completion_cb; + txn->cookie = cookie; switch(txn->op.command & BLOCK_OP_MASK) { case BLOCK_OP_READ: diff --git a/system/dev/bus/virtio/block.h b/system/dev/bus/virtio/block.h index c14f5ebf18..4a34982606 100644 --- a/system/dev/bus/virtio/block.h +++ b/system/dev/bus/virtio/block.h @@ -20,6 +20,8 @@ namespace virtio { struct block_txn_t { block_op_t op; + block_impl_queue_callback completion_cb; + void* cookie; struct vring_desc* desc; size_t index; list_node_t node; @@ -50,7 +52,8 @@ class BlockDevice : public Device { void* out_buf, size_t out_len, size_t* out_actual); static void virtio_block_query(void* ctx, block_info_t* bi, size_t* bopsz); - static void virtio_block_queue(void* ctx, block_op_t* bop); + static void virtio_block_queue(void* ctx, block_op_t* bop, + block_impl_queue_callback completion_cb, void* cookie); void GetInfo(block_info_t* info); @@ -103,7 +106,7 @@ class BlockDevice : public Device { bool txn_wait_ = false; sync_completion_t txn_signal_; - block_protocol_ops_t block_ops_ = {}; + block_impl_protocol_ops_t block_ops_ = {}; }; } // namespace virtio diff --git a/system/fidl/ddk/protocols/block.banjo b/system/fidl/ddk/protocols/block.banjo new file mode 100644 index 0000000000..8870a12d89 --- /dev/null +++ b/system/fidl/ddk/protocols/block.banjo @@ -0,0 +1,85 @@ +// Copyright 2018 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +library ddk.protocol.block; + +using zircon.device.block; +using zx; + +/// `BLOCK_OP_READ`, `BLOCK_OP_WRITE` +struct BlockReadWrite { + /// Command and flags. + uint32 command; + /// Available for temporary use. + uint32 extra; + /// VMO of data to read or write. + handle vmo; + /// Transfer length in blocks (0 is invalid). + uint32 length; + /// Device offset in blocks. + uint64 offset_dev; + /// VMO offset in blocks. + uint64 offset_vmo; +}; + +/// `BLOCK_OP_TRIM` +struct BlockTrim { + /// Command and flags. + uint32 command; + // ??? +}; + +union BlockOp { + /// All Commands + uint32 command; + /// Read and Write ops use rw for parameters. + BlockReadWrite rw; + BlockTrim trim; +}; + +const uint32 BLOCK_OP_READ = 0x00000001; +const uint32 BLOCK_OP_WRITE = 0x00000002; + +/// Write any controller or device cached data to nonvolatile storage. +/// This operation always implies BARRIER_BEFORE and BARRIER_AFTER, +/// meaning that previous operations will complete before it starts +/// and later operations will not start until it is done. +const uint32 BLOCK_OP_FLUSH = 0x00000003; + +// TBD +const uint32 BLOCK_OP_TRIM = 0x00000004; +const uint32 BLOCK_OP_MASK = 0x000000FF; + +/// Mark this operation as "Force Unit Access" (FUA), indicating that +/// it should not complete until the data is written to the non-volatile +/// medium (write), and that reads should bypass any on-device caches. +const uint32 BLOCK_FL_FORCE_ACCESS = 0x00001000; + +/// Require that this operation will not begin until all previous +/// operations have completed. +/// +/// Prevents earlier operations from being reordered after this one. +const uint32 BLOCK_FL_BARRIER_BEFORE = 0x00000100; + +/// Require that this operation complete before any subsequent +/// operations are started. +/// +/// Prevents later operations from being reordered before this one. +const uint32 BLOCK_FL_BARRIER_AFTER = 0x00000200; + +[Layout="ddk-protocol", DefaultProtocol] +interface BlockImpl { + /// Obtain the parameters of the block device (block_info_t) and + /// the required size of block_txn_t. The block_txn_t's submitted + /// via queue() must have block_op_size_out - sizeof(block_op_t) bytes + /// available at the end of the structure for the use of the driver. + 1: Query() -> (zircon.device.block.BlockInfo info, usize block_op_size); + /// Submit an IO request for processing. Ownership of |op| is transferred to + /// callee until |completion_cb| is invoked|. Success or failure will + /// be reported via the |completion_cb|. This / callback may be called + /// before the queue() method returns. + [Async] + 2: Queue(BlockOp? txn) -> (zx.status status, BlockOp? op); + 3: GetStats(vector cmd) -> (zx.status s, vector reply); +}; diff --git a/system/fidl/ddk/protocols/makefile b/system/fidl/ddk/protocols/makefile index 8d4780790f..5e5d78fa4c 100644 --- a/system/fidl/ddk/protocols/makefile +++ b/system/fidl/ddk/protocols/makefile @@ -32,6 +32,9 @@ amlogic-canvas: bad-block: $(run-banjo) +block: $(LOCAL_DIR)/libs/block.banjo + $(run-banjo) + bt-gatt-svc: $(run-banjo) diff --git a/system/fidl/ddk/protocols/sdmmc.banjo b/system/fidl/ddk/protocols/sdmmc.banjo index c10f64a0c9..2771049d94 100644 --- a/system/fidl/ddk/protocols/sdmmc.banjo +++ b/system/fidl/ddk/protocols/sdmmc.banjo @@ -4,8 +4,6 @@ library ddk.protocol.sdmmc; -using ddk.protocol.block; -using zircon.listnode; using zx; enum SdmmcVoltage : uint8 { @@ -35,12 +33,6 @@ enum SdmmcTiming : uint8 { MAX = 10; }; -/// block io transactions. one per client request -struct SdmmcTxn { - ddk.protocol.block.BlockOp bop; - zircon.listnode.ListNode node; -}; - /// number of pages per request - 2M per request /// matches DMA_DESC_COUNT in dev/block/sdhci /// (PAGE_SIZE / sizeof(zx_paddr_t)) diff --git a/system/ulib/ddk/include/ddk/protocol/block.h b/system/ulib/ddk/include/ddk/protocol/block.h index 53a20be5b5..d0d04b1dfa 100644 --- a/system/ulib/ddk/include/ddk/protocol/block.h +++ b/system/ulib/ddk/include/ddk/protocol/block.h @@ -1,123 +1,125 @@ -// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Copyright 2018 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// WARNING: THIS FILE IS MACHINE GENERATED. DO NOT EDIT. +// MODIFY system/fidl/protocols/block.banjo INSTEAD. + #pragma once -#include -#include +#include #include +#include -// block_op_t's are submitted for processing via the queue() method -// of the block_protocol. Once submitted, the contents of the block_op_t -// may be modified while it's being processed and/or as it is passed down -// the stack to lower layered drivers. -// -// The contents may be mutated along the way -- for example, a partition -// driver would, after validation, adjust offset_dev to reflect the position -// of the partition. -// -// The completion_cb() must eventually be called upon success or failure and -// at that point the cookie field must contain whatever value was in it when -// the block_op_t was originally queued. -// -// The rw.pages field may be modified but the *contents* of the array it points -// to may not be modified. - -typedef struct block_op block_op_t; - -struct block_op { - union { - // All Commands - uint32_t command; // command and flags - - // BLOCK_OP_READ, BLOCK_OP_WRITE - struct { - uint32_t command; // command and flags - uint32_t extra; // available for temporary use - zx_handle_t vmo; // vmo of data to read or write - uint32_t length; // transfer length in blocks (0 is invalid) - uint64_t offset_dev; // device offset in blocks - uint64_t offset_vmo; // vmo offset in blocks - uint64_t* pages; // optional physical page list - } rw; - - // BLOCK_OP_TRIM - struct { - uint32_t command; // command and flags - // ??? - } trim; - }; - - // The completion_cb() will be called when the block operation - // succeeds or fails, and cookie will be whatever was set when - // the block_op was initially queue()'d. - void (*completion_cb)(block_op_t* block, zx_status_t status); - void* cookie; -}; +__BEGIN_CDECLS; -static_assert(sizeof(block_op_t) == 56, ""); - -typedef struct block_protocol_ops { - // Obtain the parameters of the block device (block_info_t) and - // the required size of block_txn_t. The block_txn_t's submitted - // via queue() must have block_op_size_out - sizeof(block_op_t) bytes - // available at the end of the structure for the use of the driver. - void (*query)(void* ctx, block_info_t* info_out, size_t* block_op_size_out); - - // Submit an IO request for processing. Success or failure will - // be reported via the completion_cb() in the block_op_t. This - // callback may be called before the queue() method returns. - void (*queue)(void* ctx, block_op_t* txn); - - // Return stats concerning IO operations on the device. Will - // return ZX_ERR_NOT_SUPPORTED if stats are not enabled on this - // device - zx_status_t (*get_stats)(void* ctx, const void* cmd, - size_t cmdlen, void* reply, size_t max, size_t* out_actual); -} block_protocol_ops_t; - -typedef struct block_protocol { - block_protocol_ops_t* ops; - void* ctx; -} block_protocol_t; +// Forward declarations -// Read and Write ops use u.rw for parameters. -// -// If u.rw.pages is not NULL, the VMO is already appropriately pinned -// for IO and pages is an array of the physical addresses covering -// offset_vmo * block_size through (offset_vmo + length + 1U) * block_size. -// -// The number of entries in this array is always -// ((u.rw.length + 1U * block_size + PAGE_SIZE - 1) / PAGE_SIZE) -#define BLOCK_OP_READ 0x00000001 -#define BLOCK_OP_WRITE 0x00000002 +typedef struct block_read_write block_read_write_t; +typedef struct block_trim block_trim_t; +typedef union block_op block_op_t; +typedef struct block_impl_protocol block_impl_protocol_t; +typedef void (*block_impl_queue_callback)(void* ctx, zx_status_t status, block_op_t* op); + +// Declarations + +// Require that this operation will not begin until all previous +// operations have completed. +// Prevents earlier operations from being reordered after this one. +#define BLOCK_FL_BARRIER_BEFORE UINT32_C(0x00000100) + +// Require that this operation complete before any subsequent +// operations are started. +// Prevents later operations from being reordered before this one. +#define BLOCK_FL_BARRIER_AFTER UINT32_C(0x00000200) + +// Mark this operation as "Force Unit Access" (FUA), indicating that +// it should not complete until the data is written to the non-volatile +// medium (write), and that reads should bypass any on-device caches. +#define BLOCK_FL_FORCE_ACCESS UINT32_C(0x00001000) + +struct block_read_write { + // Command and flags. + uint32_t command; + // Available for temporary use. + uint32_t extra; + // VMO of data to read or write. + zx_handle_t vmo; + // Transfer length in blocks (0 is invalid). + uint32_t length; + // Device offset in blocks. + uint64_t offset_dev; + // VMO offset in blocks. + uint64_t offset_vmo; +}; + +#define BLOCK_OP_WRITE UINT32_C(0x00000002) // Write any controller or device cached data to nonvolatile storage. // This operation always implies BARRIER_BEFORE and BARRIER_AFTER, // meaning that previous operations will complete before it starts // and later operations will not start until it is done. -#define BLOCK_OP_FLUSH 0x00000003 +#define BLOCK_OP_FLUSH UINT32_C(0x00000003) -// TBD -#define BLOCK_OP_TRIM 0x00000004 +#define BLOCK_OP_TRIM UINT32_C(0x00000004) -#define BLOCK_OP_MASK 0x000000FF +// Read and Write ops use rw for parameters. +// If rw.pages is not NULL, the VMO is already appropriately pinned +// for IO and pages is an array of the physical addresses covering +// offset_vmo * block_size through (offset_vmo + length + 1U) * block_size. +// The number of entries in this array is always +// ((rw.length + 1U * block_size + PAGE_SIZE - 1) / PAGE_SIZE) +#define BLOCK_OP_READ UINT32_C(0x00000001) +#define BLOCK_OP_MASK UINT32_C(0x000000FF) -// Mark this operation as "Force Unit Access" (FUA), indicating that -// it should not complete until the data is written to the non-volatile -// medium (write), and that reads should bypass any on-device caches. -#define BLOCK_FL_FORCE_ACCESS 0x00001000 +struct block_trim { + // Command and flags. + uint32_t command; +}; -// Require that this operation will not begin until all previous -// operations have completed. -// -// Prevents earlier operations from being reordered after this one. -#define BLOCK_FL_BARRIER_BEFORE 0x00000100 +union block_op { + // All Commands + uint32_t command; + // `BLOCK_OP_READ`, `BLOCK_OP_WRITE` + block_read_write_t rw; + // `BLOCK_OP_TRIM` + block_trim_t trim; +}; -// Require that this operation complete before any subsequent -// operations are started. -// -// Prevents later operations from being reordered before this one. -#define BLOCK_FL_BARRIER_AFTER 0x00000200 +typedef struct block_impl_protocol_ops { + void (*query)(void* ctx, block_info_t* out_info, size_t* out_block_op_size); + void (*queue)(void* ctx, block_op_t* txn, block_impl_queue_callback callback, void* cookie); + zx_status_t (*get_stats)(void* ctx, const void* cmd_buffer, size_t cmd_size, + void* out_reply_buffer, size_t reply_size, size_t* out_reply_actual); +} block_impl_protocol_ops_t; + +struct block_impl_protocol { + block_impl_protocol_ops_t* ops; + void* ctx; +}; + +// Obtain the parameters of the block device (block_info_t) and +// the required size of block_txn_t. The block_txn_t's submitted +// via queue() must have block_op_size_out - sizeof(block_op_t) bytes +// available at the end of the structure for the use of the driver. +static inline void block_impl_query(const block_impl_protocol_t* proto, block_info_t* out_info, + size_t* out_block_op_size) { + proto->ops->query(proto->ctx, out_info, out_block_op_size); +} +// Submit an IO request for processing. Success or failure will +// be reported via the completion_cb() in the block_op_t. This +// callback may be called before the queue() method returns. +static inline void block_impl_queue(const block_impl_protocol_t* proto, block_op_t* txn, + block_impl_queue_callback callback, void* cookie) { + proto->ops->queue(proto->ctx, txn, callback, cookie); +} +static inline zx_status_t block_impl_get_stats(const block_impl_protocol_t* proto, + const void* cmd_buffer, size_t cmd_size, + void* out_reply_buffer, size_t reply_size, + size_t* out_reply_actual) { + return proto->ops->get_stats(proto->ctx, cmd_buffer, cmd_size, out_reply_buffer, reply_size, + out_reply_actual); +} + +__END_CDECLS; diff --git a/system/ulib/ddk/include/ddk/protocol/sdmmc.h b/system/ulib/ddk/include/ddk/protocol/sdmmc.h index 5b972c2c61..4537df7a50 100644 --- a/system/ulib/ddk/include/ddk/protocol/sdmmc.h +++ b/system/ulib/ddk/include/ddk/protocol/sdmmc.h @@ -7,9 +7,7 @@ #pragma once -#include #include -#include #include __BEGIN_CDECLS; @@ -54,7 +52,6 @@ typedef uint8_t sdmmc_timing_t; typedef struct sdmmc_req sdmmc_req_t; typedef struct sdmmc_protocol sdmmc_protocol_t; -typedef struct sdmmc_txn sdmmc_txn_t; // Declarations @@ -148,10 +145,4 @@ static inline zx_status_t sdmmc_request(const sdmmc_protocol_t* proto, sdmmc_req return proto->ops->request(proto->ctx, req); } -// block io transactions. one per client request -struct sdmmc_txn { - block_op_t bop; - list_node_t node; -}; - __END_CDECLS; diff --git a/system/ulib/ddktl/include/ddktl/protocol/block-internal.h b/system/ulib/ddktl/include/ddktl/protocol/block-internal.h index dac50a2259..b11b601bcc 100644 --- a/system/ulib/ddktl/include/ddktl/protocol/block-internal.h +++ b/system/ulib/ddktl/include/ddktl/protocol/block-internal.h @@ -2,31 +2,42 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// WARNING: THIS FILE IS MACHINE GENERATED. DO NOT EDIT. +// MODIFY system/fidl/protocols/block.banjo INSTEAD. + #pragma once -#include -#include +#include #include -#include - -#include namespace ddk { namespace internal { -DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_block_query, BlockQuery, - void (C::*)(block_info_t*, size_t*)); -DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_block_queue, BlockQueue, void (C::*)(block_op_t*)); +DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_block_impl_protocol_query, BlockImplQuery, + void (C::*)(block_info_t* out_info, + size_t* out_block_op_size)); +DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_block_impl_protocol_queue, BlockImplQueue, + void (C::*)(block_op_t* txn, + block_impl_queue_callback callback, void* cookie)); +DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_block_impl_protocol_get_stats, BlockImplGetStats, + zx_status_t (C::*)(const void* cmd_buffer, size_t cmd_size, + void* out_reply_buffer, size_t reply_size, + size_t* out_reply_actual)); template -constexpr void CheckBlockProtocolSubclass() { - static_assert(internal::has_block_query::value, - "BlockProtocol subclasses must implement " - "BlockQuery(block_info_t* info_out, size_t* block_op_size_out)"); - static_assert(internal::has_block_queue::value, - "BlockProtocol subclasses must implement " - "BlockQueue(block_op_t* txn)"); +constexpr void CheckBlockImplProtocolSubclass() { + static_assert(internal::has_block_impl_protocol_query::value, + "BlockImplProtocol subclasses must implement " + "void BlockImplQuery(block_info_t* out_info, size_t* out_block_op_size"); + static_assert( + internal::has_block_impl_protocol_queue::value, + "BlockImplProtocol subclasses must implement " + "void BlockImplQueue(block_op_t* txn, block_impl_queue_callback callback, void* cookie"); + static_assert(internal::has_block_impl_protocol_get_stats::value, + "BlockImplProtocol subclasses must implement " + "zx_status_t BlockImplGetStats(const void* cmd_buffer, size_t cmd_size, void* " + "out_reply_buffer, size_t reply_size, size_t* out_reply_actual"); } -} // namespace internal -} // namespace ddk +} // namespace internal +} // namespace ddk diff --git a/system/ulib/ddktl/include/ddktl/protocol/block.h b/system/ulib/ddktl/include/ddktl/protocol/block.h index 93cd8ee296..c734b81264 100644 --- a/system/ulib/ddktl/include/ddktl/protocol/block.h +++ b/system/ulib/ddktl/include/ddktl/protocol/block.h @@ -1,75 +1,135 @@ -// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Copyright 2018 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// WARNING: THIS FILE IS MACHINE GENERATED. DO NOT EDIT. +// MODIFY system/fidl/protocols/block.banjo INSTEAD. + #pragma once -#include #include -#include -#include -#include +#include #include +#include +#include +#include + +#include "block-internal.h" -// DDK block protocol support +// DDK block-impl-protocol support +// +// :: Proxies :: +// +// ddk::BlockImplProtocolProxy is a simple wrapper around +// block_impl_protocol_t. It does not own the pointers passed to it // // :: Mixins :: // -// ddk::BlockIfc and ddk::BlockProtocol are mixin classes that simplify writing DDK drivers that -// interact with the block protocol. They take care of implementing the function pointer tables -// and calling into the object that wraps them. +// ddk::BlockImplProtocol is a mixin class that simplifies writing DDK drivers +// that implement the block-impl protocol. It doesn't set the base protocol. // // :: Examples :: // -// // A driver that implements a ZX_PROTOCOL_BLOCK_IMPL device -// class BlockDevice; -// using BlockDeviceType = ddk::Device; +// // A driver that implements a ZX_PROTOCOL_BLOCK_IMPL device. +// class BlockImplDevice { +// using BlockImplDeviceType = ddk::Device; // -// class BlockDevice : public BlockDeviceType, -// public ddk::BlockProtocol { +// class BlockImplDevice : public BlockImplDeviceType, +// public ddk::BlockImplProtocol { // public: -// BlockDevice(zx_device_t* parent) -// : BlockDeviceType("my-block-device", parent) {} +// BlockImplDevice(zx_device_t* parent) +// : BlockImplDeviceType("my-block-impl-protocol-device", parent) {} // -// zx_status_t Bind() { -// DdkAdd(); -// } +// void BlockImplQuery(block_info_t* out_info, size_t* out_block_op_size); // -// void DdkRelease() { -// // Clean up -// } +// void BlockImplQueue(block_op_t* txn, block_impl_queue_callback callback, void* cookie); +// +// zx_status_t BlockImplGetStats(const void* cmd_buffer, size_t cmd_size, void* +// out_reply_buffer, size_t reply_size, size_t* out_reply_actual); // -// ... -// private: // ... // }; namespace ddk { template -class BlockProtocol : public internal::base_protocol { +class BlockImplProtocol : public internal::base_protocol { public: - BlockProtocol() { - internal::CheckBlockProtocolSubclass(); - ops_.query = Query; - ops_.queue = Queue; + BlockImplProtocol() { + internal::CheckBlockImplProtocolSubclass(); + ops_.query = BlockImplQuery; + ops_.queue = BlockImplQueue; + ops_.get_stats = BlockImplGetStats; - // Can only inherit from one base_protocol implementation + // Can only inherit from one base_protocol implementation. ZX_ASSERT(ddk_proto_id_ == 0); ddk_proto_id_ = ZX_PROTOCOL_BLOCK_IMPL; ddk_proto_ops_ = &ops_; } +protected: + block_impl_protocol_ops_t ops_ = {}; + private: - static void Query(void* ctx, block_info_t* info_out, size_t* block_op_size_out) { - static_cast(ctx)->BlockQuery(info_out, block_op_size_out); + // Obtain the parameters of the block device (block_info_t) and + // the required size of block_txn_t. The block_txn_t's submitted + // via queue() must have block_op_size_out - sizeof(block_op_t) bytes + // available at the end of the structure for the use of the driver. + static void BlockImplQuery(void* ctx, block_info_t* out_info, size_t* out_block_op_size) { + static_cast(ctx)->BlockImplQuery(out_info, out_block_op_size); + } + // Submit an IO request for processing. Success or failure will + // be reported via the completion_cb() in the block_op_t. This + // callback may be called before the queue() method returns. + static void BlockImplQueue(void* ctx, block_op_t* txn, block_impl_queue_callback callback, + void* cookie) { + static_cast(ctx)->BlockImplQueue(txn, callback, cookie); + } + static zx_status_t BlockImplGetStats(void* ctx, const void* cmd_buffer, size_t cmd_size, + void* out_reply_buffer, size_t reply_size, + size_t* out_reply_actual) { + return static_cast(ctx)->BlockImplGetStats(cmd_buffer, cmd_size, out_reply_buffer, + reply_size, out_reply_actual); } +}; + +class BlockImplProtocolProxy { +public: + BlockImplProtocolProxy() : ops_(nullptr), ctx_(nullptr) {} + BlockImplProtocolProxy(const block_impl_protocol_t* proto) + : ops_(proto->ops), ctx_(proto->ctx) {} - static void Queue(void* ctx, block_op_t* txn) { - static_cast(ctx)->BlockQueue(txn); + void GetProto(block_impl_protocol_t* proto) { + proto->ctx = ctx_; + proto->ops = ops_; + } + bool is_valid() { return ops_ != nullptr; } + void clear() { + ctx_ = nullptr; + ops_ = nullptr; + } + // Obtain the parameters of the block device (block_info_t) and + // the required size of block_txn_t. The block_txn_t's submitted + // via queue() must have block_op_size_out - sizeof(block_op_t) bytes + // available at the end of the structure for the use of the driver. + void Query(block_info_t* out_info, size_t* out_block_op_size) { + ops_->query(ctx_, out_info, out_block_op_size); + } + // Submit an IO request for processing. Success or failure will + // be reported via the completion_cb() in the block_op_t. This + // callback may be called before the queue() method returns. + void Queue(block_op_t* txn, block_impl_queue_callback callback, void* cookie) { + ops_->queue(ctx_, txn, callback, cookie); + } + zx_status_t GetStats(const void* cmd_buffer, size_t cmd_size, void* out_reply_buffer, + size_t reply_size, size_t* out_reply_actual) { + return ops_->get_stats(ctx_, cmd_buffer, cmd_size, out_reply_buffer, reply_size, + out_reply_actual); } - block_protocol_ops_t ops_ = {}; +private: + block_impl_protocol_ops_t* ops_; + void* ctx_; }; } // namespace ddk diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h b/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h index c4aa6c7ae8..b2a73da283 100644 --- a/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h +++ b/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h @@ -7,12 +7,10 @@ #pragma once -#include #include #include #include #include -#include #include #include "sdmmc-internal.h" diff --git a/system/ulib/zxcrypt/volume.cpp b/system/ulib/zxcrypt/volume.cpp index 505f6a9e3e..1ccc7be0cd 100644 --- a/system/ulib/zxcrypt/volume.cpp +++ b/system/ulib/zxcrypt/volume.cpp @@ -76,11 +76,11 @@ const char* kWrapIvLabel = "wrap iv %" PRIu64; // Header is type GUID | instance GUID | version. const size_t kHeaderLen = sizeof(zxcrypt_magic) + GUID_LEN + sizeof(uint32_t); -void SyncComplete(block_op_t* block, zx_status_t status) { +void SyncComplete(void* cookie, zx_status_t status, block_op_t* block) { // Use the 32bit command field to shuttle the response back to the callsite that's waiting on // the completion block->command = status; - sync_completion_signal(static_cast(block->cookie)); + sync_completion_signal(static_cast(cookie)); } // Performs synchronous I/O @@ -92,7 +92,7 @@ zx_status_t SyncIO(zx_device_t* dev, uint32_t cmd, void* buf, size_t off, size_t return ZX_ERR_INVALID_ARGS; } - block_protocol_t proto; + block_impl_protocol_t proto; if ((rc = device_get_protocol(dev, ZX_PROTOCOL_BLOCK, &proto)) != ZX_OK) { xprintf("block protocol not support\n"); return ZX_ERR_NOT_SUPPORTED; @@ -106,7 +106,7 @@ zx_status_t SyncIO(zx_device_t* dev, uint32_t cmd, void* buf, size_t off, size_t block_info_t info; size_t op_size; - proto.ops->query(proto.ctx, &info, &op_size); + block_impl_query(&proto, &info, &op_size); size_t bsz = info.block_size; ZX_DEBUG_ASSERT(off / bsz <= UINT32_MAX); @@ -123,16 +123,13 @@ zx_status_t SyncIO(zx_device_t* dev, uint32_t cmd, void* buf, size_t off, size_t block->rw.length = static_cast(len / bsz); block->rw.offset_dev = static_cast(off / bsz); block->rw.offset_vmo = 0; - block->rw.pages = nullptr; - block->completion_cb = SyncComplete; - block->cookie = &completion; if (cmd == BLOCK_OP_WRITE && (rc = vmo.write(buf, 0, len)) != ZX_OK) { xprintf("zx::vmo::write failed: %s\n", zx_status_get_string(rc)); return rc; } - proto.ops->queue(proto.ctx, block); + block_impl_queue(&proto, block, SyncComplete, &completion); sync_completion_wait(&completion, ZX_TIME_INFINITE); rc = block->command;