source: mainline/uspace/drv/block/usbmast/main.c@ 9905da7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9905da7 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * Copyright (c) 2011 Jiri Svoboda
4 * Copyright (c) 2018 Ondrej Hlavaty
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup drvusbmast
32 * @{
33 */
34/**
35 * @file
36 * Main routines of USB mass storage driver.
37 */
38
39#include <as.h>
40#include <async.h>
41#include <bd_srv.h>
42#include <macros.h>
43#include <usb/dev/driver.h>
44#include <usb/debug.h>
45#include <usb/classes/classes.h>
46#include <usb/classes/massstor.h>
47#include <errno.h>
48#include <io/logctl.h>
49#include <str_error.h>
50#include "cmdw.h"
51#include "bo_trans.h"
52#include "scsi_ms.h"
53#include "usbmast.h"
54
55#define NAME "usbmast"
56
57static const usb_endpoint_description_t bulk_in_ep = {
58 .transfer_type = USB_TRANSFER_BULK,
59 .direction = USB_DIRECTION_IN,
60 .interface_class = USB_CLASS_MASS_STORAGE,
61 .interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
62 .interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
63 .flags = 0
64};
65static const usb_endpoint_description_t bulk_out_ep = {
66 .transfer_type = USB_TRANSFER_BULK,
67 .direction = USB_DIRECTION_OUT,
68 .interface_class = USB_CLASS_MASS_STORAGE,
69 .interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
70 .interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
71 .flags = 0
72};
73
74static const usb_endpoint_description_t *mast_endpoints[] = {
75 &bulk_in_ep,
76 &bulk_out_ep,
77 NULL
78};
79
80static errno_t usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun);
81static void usbmast_bd_connection(ipc_call_t *icall, void *arg);
82
83static errno_t usbmast_bd_open(bd_srvs_t *, bd_srv_t *);
84static errno_t usbmast_bd_close(bd_srv_t *);
85static errno_t usbmast_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
86static errno_t usbmast_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
87static errno_t usbmast_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
88static errno_t usbmast_bd_get_block_size(bd_srv_t *, size_t *);
89static errno_t usbmast_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
90
91static bd_ops_t usbmast_bd_ops = {
92 .open = usbmast_bd_open,
93 .close = usbmast_bd_close,
94 .read_blocks = usbmast_bd_read_blocks,
95 .sync_cache = usbmast_bd_sync_cache,
96 .write_blocks = usbmast_bd_write_blocks,
97 .get_block_size = usbmast_bd_get_block_size,
98 .get_num_blocks = usbmast_bd_get_num_blocks
99};
100
101static usbmast_fun_t *bd_srv_usbmast(bd_srv_t *bd)
102{
103 return (usbmast_fun_t *) bd->srvs->sarg;
104}
105
106/** Callback when a device is removed from the system.
107 *
108 * @param dev Representation of USB device.
109 * @return Error code.
110 */
111static errno_t usbmast_device_gone(usb_device_t *dev)
112{
113 usbmast_dev_t *mdev = usb_device_data_get(dev);
114 assert(mdev);
115
116 for (size_t i = 0; i < mdev->lun_count; ++i) {
117 const errno_t rc = ddf_fun_unbind(mdev->luns[i]);
118 if (rc != EOK) {
119 usb_log_error("Failed to unbind LUN function %zu: "
120 "%s\n", i, str_error(rc));
121 return rc;
122 }
123 ddf_fun_destroy(mdev->luns[i]);
124 mdev->luns[i] = NULL;
125 }
126 free(mdev->luns);
127 return EOK;
128}
129
130/** Callback when a device is about to be removed.
131 *
132 * @param dev Representation of USB device.
133 * @return Error code.
134 */
135static errno_t usbmast_device_remove(usb_device_t *dev)
136{
137 //TODO: flush buffers, or whatever.
138 //TODO: remove device
139 return ENOTSUP;
140}
141
142/** Callback when new device is attached and recognized as a mass storage.
143 *
144 * @param dev Representation of USB device.
145 * @return Error code.
146 */
147static errno_t usbmast_device_add(usb_device_t *dev)
148{
149 errno_t rc;
150 usbmast_dev_t *mdev = NULL;
151 unsigned i;
152
153 usb_endpoint_mapping_t *epm_in =
154 usb_device_get_mapped_ep_desc(dev, &bulk_in_ep);
155 usb_endpoint_mapping_t *epm_out =
156 usb_device_get_mapped_ep_desc(dev, &bulk_out_ep);
157 if (!epm_in || !epm_out || !epm_in->present || !epm_out->present) {
158 usb_log_error("Required EPs were not mapped.");
159 return ENOENT;
160 }
161
162 /* Allocate softstate */
163 mdev = usb_device_data_alloc(dev, sizeof(usbmast_dev_t));
164 if (mdev == NULL) {
165 usb_log_error("Failed allocating softstate.");
166 return ENOMEM;
167 }
168
169 mdev->usb_dev = dev;
170
171 usb_log_info("Initializing mass storage `%s'.",
172 usb_device_get_name(dev));
173 usb_log_debug("Bulk in endpoint: %d [%zuB].",
174 epm_in->pipe.desc.endpoint_no, epm_in->pipe.desc.max_transfer_size);
175 usb_log_debug("Bulk out endpoint: %d [%zuB].",
176 epm_out->pipe.desc.endpoint_no, epm_out->pipe.desc.max_transfer_size);
177
178 usb_log_debug("Get LUN count...");
179 mdev->lun_count = usb_masstor_get_lun_count(mdev);
180 mdev->luns = calloc(mdev->lun_count, sizeof(ddf_fun_t *));
181 if (mdev->luns == NULL) {
182 usb_log_error("Failed allocating luns table.");
183 return ENOMEM;
184 }
185
186 mdev->bulk_in_pipe = &epm_in->pipe;
187 mdev->bulk_out_pipe = &epm_out->pipe;
188 for (i = 0; i < mdev->lun_count; i++) {
189 rc = usbmast_fun_create(mdev, i);
190 if (rc != EOK)
191 goto error;
192 }
193
194 return EOK;
195error:
196 /* Destroy functions */
197 for (size_t i = 0; i < mdev->lun_count; ++i) {
198 if (mdev->luns[i] == NULL)
199 continue;
200 const errno_t rc = ddf_fun_unbind(mdev->luns[i]);
201 if (rc != EOK) {
202 usb_log_warning("Failed to unbind LUN function %zu: "
203 "%s.\n", i, str_error(rc));
204 }
205 ddf_fun_destroy(mdev->luns[i]);
206 }
207 free(mdev->luns);
208 return rc;
209}
210
211/** Create mass storage function.
212 *
213 * Called once for each LUN.
214 *
215 * @param mdev Mass storage device
216 * @param lun LUN
217 * @return EOK on success or an error code.
218 */
219static errno_t usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
220{
221 errno_t rc;
222 char *fun_name = NULL;
223 ddf_fun_t *fun = NULL;
224 usbmast_fun_t *mfun = NULL;
225
226 if (asprintf(&fun_name, "l%u", lun) < 0) {
227 usb_log_error("Out of memory.");
228 rc = ENOMEM;
229 goto error;
230 }
231
232 fun = usb_device_ddf_fun_create(mdev->usb_dev, fun_exposed, fun_name);
233 if (fun == NULL) {
234 usb_log_error("Failed to create DDF function %s.", fun_name);
235 rc = ENOMEM;
236 goto error;
237 }
238
239 /* Allocate soft state */
240 mfun = ddf_fun_data_alloc(fun, sizeof(usbmast_fun_t));
241 if (mfun == NULL) {
242 usb_log_error("Failed allocating softstate.");
243 rc = ENOMEM;
244 goto error;
245 }
246
247 mfun->ddf_fun = fun;
248 mfun->mdev = mdev;
249 mfun->lun = lun;
250
251 bd_srvs_init(&mfun->bds);
252 mfun->bds.ops = &usbmast_bd_ops;
253 mfun->bds.sarg = mfun;
254
255 /* Set up a connection handler. */
256 ddf_fun_set_conn_handler(fun, usbmast_bd_connection);
257
258 usb_log_debug("Inquire...");
259 usbmast_inquiry_data_t inquiry;
260 rc = usbmast_inquiry(mfun, &inquiry);
261 if (rc != EOK) {
262 usb_log_warning("Failed to inquire device `%s': %s.",
263 usb_device_get_name(mdev->usb_dev), str_error(rc));
264 rc = EIO;
265 goto error;
266 }
267
268 usb_log_info("Mass storage `%s' LUN %u: "
269 "%s by %s rev. %s is %s (%s).\n",
270 usb_device_get_name(mdev->usb_dev),
271 lun,
272 inquiry.product,
273 inquiry.vendor,
274 inquiry.revision,
275 usbmast_scsi_dev_type_str(inquiry.device_type),
276 inquiry.removable ? "removable" : "non-removable");
277
278 uint32_t nblocks, block_size;
279
280 rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
281 if (rc != EOK) {
282 usb_log_warning("Failed to read capacity, device `%s': %s.",
283 usb_device_get_name(mdev->usb_dev), str_error(rc));
284 rc = EIO;
285 goto error;
286 }
287
288 usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
289 "block_size=%" PRIu32 "\n", nblocks, block_size);
290
291 mfun->nblocks = nblocks;
292 mfun->block_size = block_size;
293
294 rc = ddf_fun_bind(fun);
295 if (rc != EOK) {
296 usb_log_error("Failed to bind DDF function %s: %s.",
297 fun_name, str_error(rc));
298 goto error;
299 }
300
301 ddf_fun_add_to_category(fun, "disk");
302
303 free(fun_name);
304 mdev->luns[lun] = fun;
305
306 return EOK;
307
308 /* Error cleanup */
309error:
310 if (fun != NULL)
311 ddf_fun_destroy(fun);
312 if (fun_name != NULL)
313 free(fun_name);
314 return rc;
315}
316
317/** Blockdev client connection handler. */
318static void usbmast_bd_connection(ipc_call_t *icall, void *arg)
319{
320 usbmast_fun_t *mfun;
321
322 mfun = (usbmast_fun_t *) ddf_fun_data_get((ddf_fun_t *)arg);
323 bd_conn(icall, &mfun->bds);
324}
325
326/** Open device. */
327static errno_t usbmast_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
328{
329 return EOK;
330}
331
332/** Close device. */
333static errno_t usbmast_bd_close(bd_srv_t *bd)
334{
335 return EOK;
336}
337
338/** Read blocks from the device. */
339static errno_t usbmast_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
340 size_t size)
341{
342 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
343
344 if (size < cnt * mfun->block_size)
345 return EINVAL;
346
347 return usbmast_read(mfun, ba, cnt, buf);
348}
349
350/** Synchronize blocks to nonvolatile storage. */
351static errno_t usbmast_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
352{
353 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
354
355 return usbmast_sync_cache(mfun, ba, cnt);
356}
357
358/** Write blocks to the device. */
359static errno_t usbmast_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
360 const void *buf, size_t size)
361{
362 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
363
364 if (size < cnt * mfun->block_size)
365 return EINVAL;
366
367 return usbmast_write(mfun, ba, cnt, buf);
368}
369
370/** Get device block size. */
371static errno_t usbmast_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
372{
373 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
374 *rsize = mfun->block_size;
375 return EOK;
376}
377
378/** Get number of blocks on device. */
379static errno_t usbmast_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
380{
381 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
382 *rnb = mfun->nblocks;
383 return EOK;
384}
385
386
387/** USB mass storage driver ops. */
388static const usb_driver_ops_t usbmast_driver_ops = {
389 .device_add = usbmast_device_add,
390 .device_remove = usbmast_device_remove,
391 .device_gone = usbmast_device_gone,
392};
393
394/** USB mass storage driver. */
395static const usb_driver_t usbmast_driver = {
396 .name = NAME,
397 .ops = &usbmast_driver_ops,
398 .endpoints = mast_endpoints
399};
400
401int main(int argc, char *argv[])
402{
403 log_init(NAME);
404 logctl_set_log_level(NAME, LVL_NOTE);
405 return usb_driver_main(&usbmast_driver);
406}
407
408/**
409 * @}
410 */
Note: See TracBrowser for help on using the repository browser.