1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "usb-mass-storage.h" 6 7#include <ddk/debug.h> 8 9#include <stdio.h> 10#include <string.h> 11 12static void ums_block_queue(void* ctx, block_op_t* op) { 13 ums_block_t* dev = ctx; 14 ums_txn_t* txn = block_op_to_txn(op); 15 16 switch (op->command & BLOCK_OP_MASK) { 17 case BLOCK_OP_READ: 18 case BLOCK_OP_WRITE: 19 zxlogf(TRACE, "UMS QUEUE %s %u @%zu (%p)\n", 20 (op->command & BLOCK_OP_MASK) == BLOCK_OP_READ ? "RD" : "WR", 21 op->rw.length, op->rw.offset_dev, op); 22 break; 23 case BLOCK_OP_FLUSH: 24 zxlogf(TRACE, "UMS QUEUE FLUSH (%p)\n", op); 25 break; 26 default: 27 zxlogf(ERROR, "ums_block_queue: unsupported command %u\n", op->command); 28 op->completion_cb(&txn->op, ZX_ERR_NOT_SUPPORTED); 29 return; 30 } 31 32 ums_t* ums = block_to_ums(dev); 33 txn->dev = dev; 34 35 mtx_lock(&ums->txn_lock); 36 list_add_tail(&ums->queued_txns, &txn->node); 37 mtx_unlock(&ums->txn_lock); 38 sync_completion_signal(&ums->txn_completion); 39} 40 41static void ums_get_info(void* ctx, block_info_t* info) { 42 ums_block_t* dev = ctx; 43 ums_t* ums = block_to_ums(dev); 44 memset(info, 0, sizeof(*info)); 45 info->block_size = dev->block_size; 46 info->block_count = dev->total_blocks; 47 info->max_transfer_size = ums->max_transfer; 48 info->flags = dev->flags; 49} 50 51static void ums_block_query(void* ctx, block_info_t* info_out, size_t* block_op_size_out) { 52 ums_get_info(ctx, info_out); 53 *block_op_size_out = sizeof(ums_txn_t); 54} 55 56static block_protocol_ops_t ums_block_ops = { 57 .query = ums_block_query, 58 .queue = ums_block_queue, 59}; 60 61static zx_status_t ums_block_ioctl(void* ctx, uint32_t op, const void* cmd, size_t cmdlen, 62 void* reply, size_t max, size_t* out_actual) { 63 ums_block_t* dev = ctx; 64 65 // TODO implement other block ioctls 66 switch (op) { 67 case IOCTL_BLOCK_GET_INFO: { 68 block_info_t* info = reply; 69 if (max < sizeof(*info)) 70 return ZX_ERR_BUFFER_TOO_SMALL; 71 ums_get_info(dev, info); 72 *out_actual = sizeof(*info); 73 return ZX_OK; 74 } 75 case IOCTL_DEVICE_SYNC: { 76 return ZX_OK; 77 } 78 default: 79 return ZX_ERR_NOT_SUPPORTED; 80 } 81} 82 83static zx_off_t ums_block_get_size(void* ctx) { 84 ums_block_t* dev = ctx; 85 return dev->block_size * dev->total_blocks; 86} 87 88static zx_protocol_device_t ums_block_proto = { 89 .version = DEVICE_OPS_VERSION, 90 .ioctl = ums_block_ioctl, 91 .get_size = ums_block_get_size, 92}; 93 94zx_status_t ums_block_add_device(ums_t* ums, ums_block_t* dev) { 95 char name[16]; 96 snprintf(name, sizeof(name), "lun-%03d", dev->lun); 97 98 device_add_args_t args = { 99 .version = DEVICE_ADD_ARGS_VERSION, 100 .name = name, 101 .ctx = dev, 102 .ops = &ums_block_proto, 103 .proto_id = ZX_PROTOCOL_BLOCK_IMPL, 104 .proto_ops = &ums_block_ops, 105 }; 106 107 return device_add(ums->zxdev, &args, &dev->zxdev); 108} 109