source: mainline/uspace/drv/bus/usb/usbmast/bo_trans.c@ fa65df1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fa65df1 was c53b58e, checked in by Jan Vesely <jano.vesely@…>, 11 years ago

usbmast: Fix cache sync command

the code was obviously never run, let alone tested
add cleanup

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbmast
30 * @{
31 */
32/**
33 * @file
34 * USB mass storage bulk-only transport.
35 */
36#include <stdbool.h>
37#include <errno.h>
38#include <str_error.h>
39#include <usb/debug.h>
40#include <usb/dev/request.h>
41
42#include "bo_trans.h"
43#include "cmdw.h"
44#include "usbmast.h"
45
46bool usb_mast_verbose = false;
47
48#define MASTLOG(format, ...) \
49 do { \
50 if (usb_mast_verbose) { \
51 usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
52 } \
53 } while (false)
54
55/** Send command via bulk-only transport.
56 *
57 * @param mfun Mass storage function
58 * @param tag Command block wrapper tag (automatically compared
59 * with answer)
60 * @param cmd SCSI command
61 *
62 * @return Error code
63 */
64int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
65{
66 int rc;
67
68 if (cmd->data_in && cmd->data_out)
69 return EINVAL;
70
71 usb_pipe_t *bulk_in_pipe = mfun->mdev->bulk_in_pipe;
72 usb_pipe_t *bulk_out_pipe = mfun->mdev->bulk_out_pipe;
73
74 usb_pipe_t *dpipe = bulk_out_pipe;
75 usb_direction_t ddir = USB_DIRECTION_OUT;
76 size_t dbuf_size = cmd->data_out_size;
77
78 if (cmd->data_in) {
79 ddir = USB_DIRECTION_IN;
80 dbuf_size = cmd->data_in_size;
81 dpipe = bulk_in_pipe;
82 }
83
84 /* Prepare CBW - command block wrapper */
85 usb_massstor_cbw_t cbw;
86 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
87 cmd->cdb_size, cmd->cdb);
88
89 /* Send the CBW. */
90 MASTLOG("Sending CBW.\n");
91 rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
92 MASTLOG("CBW '%s' sent: %s.\n",
93 usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
94 str_error(rc));
95 if (rc != EOK)
96 return EIO;
97
98 MASTLOG("Transferring data.\n");
99 if (cmd->data_in) {
100 size_t act_size;
101 /* Recieve data from the device. */
102 rc = usb_pipe_read(dpipe, cmd->data_in, cmd->data_in_size,
103 &act_size);
104 MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
105 usb_debug_str_buffer(cmd->data_in, act_size, 0),
106 str_error(rc));
107 }
108 if (cmd->data_out) {
109 /* Send data to the device. */
110 rc = usb_pipe_write(dpipe, cmd->data_out, cmd->data_out_size);
111 MASTLOG("Sent %zu bytes (%s): %s.\n", cmd->data_out_size,
112 usb_debug_str_buffer(cmd->data_out, cmd->data_out_size, 0),
113 str_error(rc));
114 }
115
116 if (rc == ESTALL) {
117 /* Clear stall condition and continue below to read CSW. */
118 usb_pipe_clear_halt(
119 usb_device_get_default_pipe(mfun->mdev->usb_dev), dpipe);
120 } else if (rc != EOK) {
121 return EIO;
122 }
123
124 /* Read CSW. */
125 usb_massstor_csw_t csw;
126 size_t csw_size;
127 MASTLOG("Reading CSW.\n");
128 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
129 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
130 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
131 str_error(rc));
132 if (rc != EOK) {
133 MASTLOG("rc != EOK\n");
134 return EIO;
135 }
136
137 if (csw_size != sizeof(csw)) {
138 MASTLOG("csw_size != sizeof(csw)\n");
139 return EIO;
140 }
141
142 if (csw.dCSWTag != tag) {
143 MASTLOG("csw.dCSWTag != tag\n");
144 return EIO;
145 }
146
147 /*
148 * Determine the actual return value from the CSW.
149 */
150 switch (csw.dCSWStatus) {
151 case cbs_passed:
152 cmd->status = CMDS_GOOD;
153 break;
154 case cbs_failed:
155 MASTLOG("Command failed\n");
156 cmd->status = CMDS_FAILED;
157 break;
158 case cbs_phase_error:
159 MASTLOG("Phase error\n");
160 rc = EIO;
161 break;
162 default:
163 rc = EIO;
164 break;
165 }
166
167 const size_t residue = uint32_usb2host(csw.dCSWDataResidue);
168 if (residue > dbuf_size) {
169 MASTLOG("residue > dbuf_size\n");
170 return EIO;
171 }
172
173 /*
174 * When the device has less data to send than requested (or cannot
175 * receive moredata), it can either stall the pipe or send garbage
176 * (ignore data) and indicate that via the residue field in CSW.
177 * That means dbuf_size - residue is the authoritative size of data
178 * received (sent).
179 */
180
181 if (cmd->data_in)
182 cmd->rcvd_size = dbuf_size - residue;
183
184 return rc;
185}
186
187/** Perform bulk-only mass storage reset.
188 *
189 * @param mfun Mass storage function
190 * @return Error code
191 */
192int usb_massstor_reset(usbmast_dev_t *mdev)
193{
194 return usb_control_request_set(
195 usb_device_get_default_pipe(mdev->usb_dev),
196 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
197 0xFF, 0, usb_device_get_iface_number(mdev->usb_dev), NULL, 0);
198}
199
200/** Perform complete reset recovery of bulk-only mass storage.
201 *
202 * Notice that no error is reported because if this fails, the error
203 * would reappear on next transaction somehow.
204 *
205 * @param mfun Mass storage function
206 */
207void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
208{
209 /* We would ignore errors here because if this fails
210 * we are doomed anyway and any following transaction would fail.
211 */
212 usb_massstor_reset(mdev);
213 usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
214 mdev->bulk_in_pipe);
215 usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
216 mdev->bulk_out_pipe);
217}
218
219/** Get max LUN of a mass storage device.
220 *
221 * @see usb_masstor_get_lun_count
222 *
223 * @warning Error from this command does not necessarily indicate malfunction
224 * of the device. Device does not need to support this request.
225 * You shall rather use usb_masstor_get_lun_count.
226 *
227 * @param mfun Mass storage function
228 * @return Error code of maximum LUN (index, not count)
229 */
230int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
231{
232 uint8_t max_lun;
233 size_t data_recv_len;
234 int rc = usb_control_request_get(
235 usb_device_get_default_pipe(mdev->usb_dev),
236 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
237 0xFE, 0, usb_device_get_iface_number(mdev->usb_dev), &max_lun, 1,
238 &data_recv_len);
239 if (rc != EOK) {
240 return rc;
241 }
242 if (data_recv_len != 1) {
243 return EEMPTY;
244 }
245 return (int) max_lun;
246}
247
248/** Get number of LUNs supported by mass storage device.
249 *
250 * @warning This function hides any error during the request
251 * (typically that shall not be a problem).
252 *
253 * @param mfun Mass storage function
254 * @return Number of LUNs
255 */
256size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
257{
258 int max_lun = usb_massstor_get_max_lun(mdev);
259 if (max_lun < 0) {
260 max_lun = 1;
261 } else {
262 max_lun++;
263 }
264
265 return (size_t) max_lun;
266}
267
268/**
269 * @}
270 */
Note: See TracBrowser for help on using the repository browser.