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
ums_block_queue(void * ctx,block_op_t * op,block_impl_queue_callback completion_cb,void * cookie)12 static void ums_block_queue(void* ctx, block_op_t* op, block_impl_queue_callback completion_cb,
13 void* cookie) {
14 ums_block_t* dev = ctx;
15 ums_txn_t* txn = block_op_to_txn(op);
16 txn->completion_cb = completion_cb;
17 txn->cookie = cookie;
18
19 switch (op->command & BLOCK_OP_MASK) {
20 case BLOCK_OP_READ:
21 case BLOCK_OP_WRITE:
22 zxlogf(TRACE, "UMS QUEUE %s %u @%zu (%p)\n",
23 (op->command & BLOCK_OP_MASK) == BLOCK_OP_READ ? "RD" : "WR",
24 op->rw.length, op->rw.offset_dev, op);
25 break;
26 case BLOCK_OP_FLUSH:
27 zxlogf(TRACE, "UMS QUEUE FLUSH (%p)\n", op);
28 break;
29 default:
30 zxlogf(ERROR, "ums_block_queue: unsupported command %u\n", op->command);
31 completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, &txn->op);
32 return;
33 }
34
35 ums_t* ums = block_to_ums(dev);
36 txn->dev = dev;
37
38 mtx_lock(&ums->txn_lock);
39 list_add_tail(&ums->queued_txns, &txn->node);
40 mtx_unlock(&ums->txn_lock);
41 sync_completion_signal(&ums->txn_completion);
42 }
43
ums_get_info(void * ctx,block_info_t * info)44 static void ums_get_info(void* ctx, block_info_t* info) {
45 ums_block_t* dev = ctx;
46 ums_t* ums = block_to_ums(dev);
47 memset(info, 0, sizeof(*info));
48 info->block_size = dev->block_size;
49 info->block_count = dev->total_blocks;
50 info->max_transfer_size = ums->max_transfer;
51 info->flags = dev->flags;
52 }
53
ums_block_query(void * ctx,block_info_t * info_out,size_t * block_op_size_out)54 static void ums_block_query(void* ctx, block_info_t* info_out, size_t* block_op_size_out) {
55 ums_get_info(ctx, info_out);
56 *block_op_size_out = sizeof(ums_txn_t);
57 }
58
59 static block_impl_protocol_ops_t ums_block_ops = {
60 .query = ums_block_query,
61 .queue = ums_block_queue,
62 };
63
ums_block_ioctl(void * ctx,uint32_t op,const void * cmd,size_t cmdlen,void * reply,size_t max,size_t * out_actual)64 static zx_status_t ums_block_ioctl(void* ctx, uint32_t op, const void* cmd, size_t cmdlen,
65 void* reply, size_t max, size_t* out_actual) {
66 ums_block_t* dev = ctx;
67
68 // TODO implement other block ioctls
69 switch (op) {
70 case IOCTL_BLOCK_GET_INFO: {
71 block_info_t* info = reply;
72 if (max < sizeof(*info))
73 return ZX_ERR_BUFFER_TOO_SMALL;
74 ums_get_info(dev, info);
75 *out_actual = sizeof(*info);
76 return ZX_OK;
77 }
78 default:
79 return ZX_ERR_NOT_SUPPORTED;
80 }
81 }
82
ums_block_get_size(void * ctx)83 static 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
88 static 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
ums_block_add_device(ums_t * ums,ums_block_t * dev)94 zx_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