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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 013517b was de3432b, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Allow simpler passing around / processing of SCSI commands by creating
scsi_cmd_t structure which holds input and output arguments of a SCSI
command and is loosely modeled after the SAM-4 Execute Command procedure
call.

  • Property mode set to 100644
File size: 7.5 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 <bool.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 int retval = EOK;
68 size_t act_size;
69 usb_pipe_t *bulk_in_pipe = mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
70 usb_pipe_t *bulk_out_pipe = mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
71 usb_direction_t ddir;
72 void *dbuf;
73 size_t dbuf_size;
74
75 if (cmd->data_out != NULL && cmd->data_in == NULL) {
76 ddir = USB_DIRECTION_OUT;
77 dbuf = (void *)cmd->data_out;
78 dbuf_size = cmd->data_out_size;
79 } else if (cmd->data_out == NULL && cmd->data_in != NULL) {
80 ddir = USB_DIRECTION_IN;
81 dbuf = cmd->data_in;
82 dbuf_size = cmd->data_in_size;
83 } else {
84 assert(false);
85 }
86
87 /* Prepare CBW - command block wrapper */
88 usb_massstor_cbw_t cbw;
89 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
90 cmd->cdb_size, cmd->cdb);
91
92 /* Send the CBW. */
93 MASTLOG("Sending CBW.\n");
94 rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
95 MASTLOG("CBW '%s' sent: %s.\n",
96 usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
97 str_error(rc));
98 if (rc != EOK)
99 return EIO;
100
101 MASTLOG("Transferring data.\n");
102 if (ddir == USB_DIRECTION_IN) {
103 /* Recieve data from the device. */
104 rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
105 MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
106 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
107 str_error(rc));
108 } else {
109 /* Send data to the device. */
110 rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
111 MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
112 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
113 str_error(rc));
114 }
115
116 if (rc == ESTALL) {
117 /* Clear stall condition and continue below to read CSW. */
118 if (ddir == USB_DIRECTION_IN) {
119 usb_pipe_clear_halt(&mfun->mdev->usb_dev->ctrl_pipe,
120 mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe);
121 } else {
122 usb_pipe_clear_halt(&mfun->mdev->usb_dev->ctrl_pipe,
123 mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
124 }
125 } else if (rc != EOK) {
126 return EIO;
127 }
128
129 /* Read CSW. */
130 usb_massstor_csw_t csw;
131 size_t csw_size;
132 MASTLOG("Reading CSW.\n");
133 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
134 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
135 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
136 str_error(rc));
137 if (rc != EOK) {
138 MASTLOG("rc != EOK\n");
139 return EIO;
140 }
141
142 if (csw_size != sizeof(csw)) {
143 MASTLOG("csw_size != sizeof(csw)\n");
144 return EIO;
145 }
146
147 if (csw.dCSWTag != tag) {
148 MASTLOG("csw.dCSWTag != tag\n");
149 return EIO;
150 }
151
152 /*
153 * Determine the actual return value from the CSW.
154 */
155 switch (csw.dCSWStatus) {
156 case cbs_passed:
157 cmd->status = CMDS_GOOD;
158 break;
159 case cbs_failed:
160 MASTLOG("Command failed\n");
161 cmd->status = CMDS_FAILED;
162 break;
163 case cbs_phase_error:
164 MASTLOG("Phase error\n");
165 retval = EIO;
166 break;
167 default:
168 retval = EIO;
169 break;
170 }
171
172 size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
173 if (residue > dbuf_size) {
174 MASTLOG("residue > dbuf_size\n");
175 return EIO;
176 }
177
178 /*
179 * When the device has less data to send than requested (or cannot
180 * receive moredata), it can either stall the pipe or send garbage
181 * (ignore data) and indicate that via the residue field in CSW.
182 * That means dbuf_size - residue is the authoritative size of data
183 * received (sent).
184 */
185
186 if (ddir == USB_DIRECTION_IN)
187 cmd->rcvd_size = dbuf_size - residue;
188
189 return retval;
190}
191
192/** Perform bulk-only mass storage reset.
193 *
194 * @param mfun Mass storage function
195 * @return Error code
196 */
197int usb_massstor_reset(usbmast_dev_t *mdev)
198{
199 return usb_control_request_set(&mdev->usb_dev->ctrl_pipe,
200 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
201 0xFF, 0, mdev->usb_dev->interface_no, NULL, 0);
202}
203
204/** Perform complete reset recovery of bulk-only mass storage.
205 *
206 * Notice that no error is reported because if this fails, the error
207 * would reappear on next transaction somehow.
208 *
209 * @param mfun Mass storage function
210 */
211void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
212{
213 /* We would ignore errors here because if this fails
214 * we are doomed anyway and any following transaction would fail.
215 */
216 usb_massstor_reset(mdev);
217 usb_pipe_clear_halt(&mdev->usb_dev->ctrl_pipe,
218 mdev->usb_dev->pipes[BULK_IN_EP].pipe);
219 usb_pipe_clear_halt(&mdev->usb_dev->ctrl_pipe,
220 mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
221}
222
223/** Get max LUN of a mass storage device.
224 *
225 * @see usb_masstor_get_lun_count
226 *
227 * @warning Error from this command does not necessarily indicate malfunction
228 * of the device. Device does not need to support this request.
229 * You shall rather use usb_masstor_get_lun_count.
230 *
231 * @param mfun Mass storage function
232 * @return Error code of maximum LUN (index, not count)
233 */
234int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
235{
236 uint8_t max_lun;
237 size_t data_recv_len;
238 int rc = usb_control_request_get(&mdev->usb_dev->ctrl_pipe,
239 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
240 0xFE, 0, mdev->usb_dev->interface_no, &max_lun, 1, &data_recv_len);
241 if (rc != EOK) {
242 return rc;
243 }
244 if (data_recv_len != 1) {
245 return EEMPTY;
246 }
247 return (int) max_lun;
248}
249
250/** Get number of LUNs supported by mass storage device.
251 *
252 * @warning This function hides any error during the request
253 * (typically that shall not be a problem).
254 *
255 * @param mfun Mass storage function
256 * @return Number of LUNs
257 */
258size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
259{
260 int max_lun = usb_massstor_get_max_lun(mdev);
261 if (max_lun < 0) {
262 max_lun = 1;
263 } else {
264 max_lun++;
265 }
266
267 return (size_t) max_lun;
268}
269
270/**
271 * @}
272 */
Note: See TracBrowser for help on using the repository browser.