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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e5024111 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
RevLine 
[380e0364]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
[89d3f3c7]34 * USB mass storage bulk-only transport.
[380e0364]35 */
36#include <bool.h>
37#include <errno.h>
38#include <str_error.h>
39#include <usb/debug.h>
[7d521e24]40#include <usb/dev/request.h>
[380e0364]41
[89d3f3c7]42#include "bo_trans.h"
43#include "cmdw.h"
[7190bbc]44#include "usbmast.h"
[89d3f3c7]45
[026793d]46bool usb_mast_verbose = false;
[380e0364]47
48#define MASTLOG(format, ...) \
49 do { \
50 if (usb_mast_verbose) { \
[026793d]51 usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
[380e0364]52 } \
53 } while (false)
54
[38c9505]55/** Send command via bulk-only transport.
[380e0364]56 *
[7190bbc]57 * @param mfun Mass storage function
[38c9505]58 * @param tag Command block wrapper tag (automatically compared
59 * with answer)
[de3432b]60 * @param cmd SCSI command
[38c9505]61 *
62 * @return Error code
[380e0364]63 */
[de3432b]64int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
[380e0364]65{
66 int rc;
[45cae6b]67 int retval = EOK;
[380e0364]68 size_t act_size;
[2aceec5]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;
[de3432b]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 }
[380e0364]86
87 /* Prepare CBW - command block wrapper */
88 usb_massstor_cbw_t cbw;
[e6b32a8]89 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
[de3432b]90 cmd->cdb_size, cmd->cdb);
[380e0364]91
[38c9505]92 /* Send the CBW. */
[45cae6b]93 MASTLOG("Sending CBW.\n");
[380e0364]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));
[45cae6b]98 if (rc != EOK)
99 return EIO;
[380e0364]100
[45cae6b]101 MASTLOG("Transferring data.\n");
[38c9505]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
[45cae6b]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;
[380e0364]127 }
128
129 /* Read CSW. */
130 usb_massstor_csw_t csw;
131 size_t csw_size;
[45cae6b]132 MASTLOG("Reading CSW.\n");
[380e0364]133 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
[38c9505]134 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
[380e0364]135 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
136 str_error(rc));
137 if (rc != EOK) {
[f7a55f9]138 MASTLOG("rc != EOK\n");
[45cae6b]139 return EIO;
[380e0364]140 }
[f7a55f9]141
[380e0364]142 if (csw_size != sizeof(csw)) {
[f7a55f9]143 MASTLOG("csw_size != sizeof(csw)\n");
[45cae6b]144 return EIO;
[380e0364]145 }
146
147 if (csw.dCSWTag != tag) {
[f7a55f9]148 MASTLOG("csw.dCSWTag != tag\n");
[45cae6b]149 return EIO;
[380e0364]150 }
151
152 /*
153 * Determine the actual return value from the CSW.
154 */
[45cae6b]155 switch (csw.dCSWStatus) {
156 case cbs_passed:
[de3432b]157 cmd->status = CMDS_GOOD;
[45cae6b]158 break;
159 case cbs_failed:
160 MASTLOG("Command failed\n");
[de3432b]161 cmd->status = CMDS_FAILED;
[45cae6b]162 break;
163 case cbs_phase_error:
164 MASTLOG("Phase error\n");
165 retval = EIO;
166 break;
167 default:
168 retval = EIO;
169 break;
[380e0364]170 }
171
172 size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
[38c9505]173 if (residue > dbuf_size) {
174 MASTLOG("residue > dbuf_size\n");
[45cae6b]175 return EIO;
[380e0364]176 }
[f7a55f9]177
178 /*
[38c9505]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).
[f7a55f9]184 */
185
[de3432b]186 if (ddir == USB_DIRECTION_IN)
187 cmd->rcvd_size = dbuf_size - residue;
[380e0364]188
[45cae6b]189 return retval;
[380e0364]190}
191
[cf002dbf]192/** Perform bulk-only mass storage reset.
193 *
[7190bbc]194 * @param mfun Mass storage function
195 * @return Error code
[cf002dbf]196 */
[2aceec5]197int usb_massstor_reset(usbmast_dev_t *mdev)
[70c12d6]198{
[2aceec5]199 return usb_control_request_set(&mdev->usb_dev->ctrl_pipe,
[70c12d6]200 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
[2aceec5]201 0xFF, 0, mdev->usb_dev->interface_no, NULL, 0);
[70c12d6]202}
203
[cf002dbf]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 *
[7190bbc]209 * @param mfun Mass storage function
[cf002dbf]210 */
[2aceec5]211void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
[70c12d6]212{
213 /* We would ignore errors here because if this fails
214 * we are doomed anyway and any following transaction would fail.
215 */
[2aceec5]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);
[70c12d6]221}
222
[cf002dbf]223/** Get max LUN of a mass storage device.
[5f0fe4e9]224 *
225 * @see usb_masstor_get_lun_count
[cf002dbf]226 *
227 * @warning Error from this command does not necessarily indicate malfunction
228 * of the device. Device does not need to support this request.
[5f0fe4e9]229 * You shall rather use usb_masstor_get_lun_count.
[cf002dbf]230 *
[7190bbc]231 * @param mfun Mass storage function
232 * @return Error code of maximum LUN (index, not count)
[cf002dbf]233 */
[2aceec5]234int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
[70c12d6]235{
236 uint8_t max_lun;
237 size_t data_recv_len;
[2aceec5]238 int rc = usb_control_request_get(&mdev->usb_dev->ctrl_pipe,
[70c12d6]239 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
[2aceec5]240 0xFE, 0, mdev->usb_dev->interface_no, &max_lun, 1, &data_recv_len);
[70c12d6]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
[5f0fe4e9]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 *
[7190bbc]255 * @param mfun Mass storage function
256 * @return Number of LUNs
[5f0fe4e9]257 */
[2aceec5]258size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
[5f0fe4e9]259{
[2aceec5]260 int max_lun = usb_massstor_get_max_lun(mdev);
[5f0fe4e9]261 if (max_lun < 0) {
262 max_lun = 1;
263 } else {
264 max_lun++;
265 }
266
267 return (size_t) max_lun;
268}
269
[380e0364]270/**
271 * @}
272 */
Note: See TracBrowser for help on using the repository browser.