HelenOS sources
This source file includes following definitions.
- usb_massstor_cmd
- usb_massstor_reset
- usb_massstor_reset_recovery
- usb_massstor_get_max_lun
- usb_masstor_get_lun_count
#include <stdbool.h>
#include <errno.h>
#include <str_error.h>
#include <usb/debug.h>
#include <usb/dev/request.h>
#include "bo_trans.h"
#include "cmdw.h"
#include "usbmast.h"
#define MASTLOG(format, ...) \
usb_log_debug2("USB cl08: " format, ##__VA_ARGS__)
errno_t usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
{
errno_t rc;
if (cmd->data_in && cmd->data_out)
return EINVAL;
usb_pipe_t *bulk_in_pipe = mfun->mdev->bulk_in_pipe;
usb_pipe_t *bulk_out_pipe = mfun->mdev->bulk_out_pipe;
usb_pipe_t *dpipe = bulk_out_pipe;
usb_direction_t ddir = USB_DIRECTION_OUT;
size_t dbuf_size = cmd->data_out_size;
if (cmd->data_in) {
ddir = USB_DIRECTION_IN;
dbuf_size = cmd->data_in_size;
dpipe = bulk_in_pipe;
}
usb_massstor_cbw_t cbw;
usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
cmd->cdb_size, cmd->cdb);
MASTLOG("Sending CBW.\n");
rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
MASTLOG("CBW '%s' sent: %s.\n",
usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
str_error(rc));
if (rc != EOK) {
usb_log_error("Bulk out write failed: %s", str_error(rc));
return EIO;
}
MASTLOG("Transferring data.\n");
if (cmd->data_in) {
size_t act_size;
rc = usb_pipe_read(dpipe, cmd->data_in, cmd->data_in_size,
&act_size);
MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
usb_debug_str_buffer(cmd->data_in, act_size, 0),
str_error(rc));
}
if (cmd->data_out) {
rc = usb_pipe_write(dpipe, cmd->data_out, cmd->data_out_size);
MASTLOG("Sent %zu bytes (%s): %s.\n", cmd->data_out_size,
usb_debug_str_buffer(cmd->data_out, cmd->data_out_size, 0),
str_error(rc));
}
if (rc == ESTALL) {
usb_pipe_clear_halt(
usb_device_get_default_pipe(mfun->mdev->usb_dev), dpipe);
} else if (rc != EOK) {
usb_log_error("Failed to transfer data: %s", str_error(rc));
return EIO;
}
usb_massstor_csw_t csw;
size_t csw_size;
MASTLOG("Reading CSW.\n");
rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
str_error(rc));
if (rc != EOK) {
usb_log_error("Failed to read CSW: %s", str_error(rc));
return EIO;
}
if (csw_size != sizeof(csw)) {
usb_log_error("Received CSW of incorrect size.");
return EIO;
}
if (csw.dCSWTag != tag) {
usb_log_error("Received CSW with incorrect tag. (expected: %"
PRIX32 " received: %" PRIx32, tag, csw.dCSWTag);
return EIO;
}
switch (csw.dCSWStatus) {
case cbs_passed:
cmd->status = CMDS_GOOD;
break;
case cbs_failed:
cmd->status = CMDS_FAILED;
usb_log_error("CBS Failed.");
break;
case cbs_phase_error:
usb_log_error("CBS phase error.");
rc = EIO;
break;
default:
usb_log_error("CBS other error.");
rc = EIO;
break;
}
const size_t residue = uint32_usb2host(csw.dCSWDataResidue);
if (residue > dbuf_size) {
usb_log_error("Residue > buffer size (%zu > %zu).",
residue, dbuf_size);
return EIO;
}
if (cmd->data_in)
cmd->rcvd_size = dbuf_size - residue;
return rc;
}
errno_t usb_massstor_reset(usbmast_dev_t *mdev)
{
return usb_control_request_set(
usb_device_get_default_pipe(mdev->usb_dev),
USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
0xFF, 0, usb_device_get_iface_number(mdev->usb_dev), NULL, 0);
}
void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
{
usb_massstor_reset(mdev);
usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
mdev->bulk_in_pipe);
usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
mdev->bulk_out_pipe);
}
int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
{
uint8_t max_lun;
size_t data_recv_len;
errno_t rc = usb_control_request_get(
usb_device_get_default_pipe(mdev->usb_dev),
USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
0xFE, 0, usb_device_get_iface_number(mdev->usb_dev), &max_lun, 1,
&data_recv_len);
if (rc != EOK) {
return -1;
}
if (data_recv_len != 1) {
return -1;
}
return max_lun;
}
size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
{
int max_lun = usb_massstor_get_max_lun(mdev);
if (max_lun < 0) {
max_lun = 1;
} else {
max_lun++;
}
return (size_t) max_lun;
}
HelenOS homepage, sources at GitHub