- fix warnings, produced by Haiku version of gcc;

- space indentation replaced by tab-based one to conform with Haiku coding guidelines;
 - a bit of cleanup;

 NB: Sorry for big amount of changes. :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18781 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
imker
2006-09-08 19:37:58 +00:00
parent 4d493bb44a
commit d8b1cf0703
7 changed files with 690 additions and 671 deletions
+287 -291
View File
@@ -1,15 +1,21 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
/** bulk-only protocol specific implementation */
/* References:
* USB Mass Storage Class specifications:
* http://www.usb.org/developers/data/devclass/usbmassover_11.pdf [1]
* http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf [2]
* http://www.usb.org/developers/data/devclass/usbmassover_11.pdf [1]
* http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf [2]
*/
#include "usb_scsi.h"
@@ -21,37 +27,37 @@
#include "usb_defs.h"
#include <string.h> /* strncpy */
#include <string.h> /* strncpy */
/*Bulk-Only protocol specifics*/
#define USB_REQ_MS_RESET 0xff /* Bulk-Only reset */
#define USB_REQ_MS_RESET 0xff /* Bulk-Only reset */
#define USB_REQ_MS_GET_MAX_LUN 0xfe /* Get maximum lun */
/* Command Block Wrapper */
typedef struct _usb_mass_CBW{
uint32 signature;
uint32 tag;
uint32 data_transfer_len;
uint8 flags;
uint8 lun;
uint8 cdb_len;
uint32 signature;
uint32 tag;
uint32 data_transfer_len;
uint8 flags;
uint8 lun;
uint8 cdb_len;
#define CBW_CDB_LENGTH 16
uint8 CDB[CBW_CDB_LENGTH];
uint8 CDB[CBW_CDB_LENGTH];
} usb_mass_CBW; /*sizeof(usb_mass_CBW) must be 31*/
#define CBW_LENGTH 0x1f
/* Command Status Wrapper */
typedef struct _usb_mass_CSW{
uint32 signature;
uint32 tag;
uint32 data_residue;
uint8 status;
uint32 signature;
uint32 tag;
uint32 data_residue;
uint8 status;
} usb_mass_CSW; /*sizeof(usb_mass_CSW) must be 13*/
#define CSW_LENGTH 0x0d
#define CSW_STATUS_GOOD 0x0
#define CSW_STATUS_FAILED 0x1
#define CSW_STATUS_PHASE 0x2
#define CSW_STATUS_GOOD 0x0
#define CSW_STATUS_FAILED 0x1
#define CSW_STATUS_PHASE 0x2
#define CBW_SIGNATURE 0x43425355
#define CSW_SIGNATURE 0x53425355
@@ -59,325 +65,315 @@ typedef struct _usb_mass_CSW{
#define CBW_FLAGS_OUT 0x00
#define CBW_FLAGS_IN 0x80
static void trace_CBW(usb_device_info *udi, const usb_mass_CBW *cbw);
static void trace_CSW(usb_device_info *udi, const usb_mass_CSW *csw);
static status_t bulk_only_initialize(usb_device_info *udi);
static status_t bulk_only_reset(usb_device_info *udi);
static void bulk_only_transfer(usb_device_info *udi, uint8 *cmd,
uint8 cmdlen, //sg_buffer *sgb,
iovec *sg_data, int32 sg_count,
int32 transfer_len, EDirection dir,
CCB_SCSIIO *ccbio, ud_transfer_callback cb);
/*=========================== tracing helpers ==================================*/
void trace_CBW(usb_device_info *udi, const usb_mass_CBW *cbw)
{
char buf[sizeof(uint32) + 1] = {0};
strncpy(buf, (char *)&cbw->signature, sizeof(uint32));
PTRACE(udi, "\nCBW:{'%s'; tag:%d; data_len:%d; flags:0x%02x; lun:%d; cdb_len:%d;}\n",
buf,
cbw->tag,
cbw->data_transfer_len,
cbw->flags,
cbw->lun,
cbw->cdb_len);
udi->trace_bytes("CDB:\n", cbw->CDB, CBW_CDB_LENGTH);
char buf[sizeof(uint32) + 1] = {0};
strncpy(buf, (char *)&cbw->signature, sizeof(uint32));
PTRACE(udi, "\nCBW:{'%s'; tag:%d; data_len:%d; flags:0x%02x; lun:%d; cdb_len:%d;}\n",
buf, cbw->tag, cbw->data_transfer_len,
cbw->flags, cbw->lun, cbw->cdb_len);
udi->trace_bytes("CDB:\n", cbw->CDB, CBW_CDB_LENGTH);
}
void trace_CSW(usb_device_info *udi, const usb_mass_CSW *csw)
{
char buf[sizeof(uint32) + 1] = {0};
strncpy(buf, (char *)&csw->signature, sizeof(uint32));
PTRACE(udi, "CSW:{'%s'; tag:%d; residue:%d; status:0x%02x}\n",
buf,
csw->tag,
csw->data_residue,
csw->status);
char buf[sizeof(uint32) + 1] = {0};
strncpy(buf, (char *)&csw->signature, sizeof(uint32));
PTRACE(udi, "CSW:{'%s'; tag:%d; residue:%d; status:0x%02x}\n",
buf, csw->tag, csw->data_residue, csw->status);
}
/**
\fn:get_max_luns
\param udi: device for wich max LUN info is requested
\return:always B_OK - if info was not retrieved max LUN is defaulted to 0
tries to retrieve the maximal Logical Unit Number supported by
this device. If device doesn't support GET_MAX_LUN request - single LUN is
assumed. ([2] 3.2)
\fn:get_max_luns
\param udi: device for wich max LUN info is requested
\return:always B_OK - if info was not retrieved max LUN is defaulted to 0
tries to retrieve the maximal Logical Unit Number supported by
this device. If device doesn't support GET_MAX_LUN request - single LUN is
assumed. ([2] 3.2)
*/
static status_t
get_max_luns(usb_device_info *udi)
{
status_t status = B_OK;
udi->max_lun = 0;
if(!HAS_FIXES(udi->properties, FIX_NO_GETMAXLUN)){
size_t len = 0;
if(B_OK != (status = (*udi->usb_m->send_request)(udi->device,
USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_CLASS,
USB_REQ_MS_GET_MAX_LUN, 0x0, udi->interface,
0x1, &udi->max_lun, &len)))
{
if(status == B_DEV_STALLED){
PTRACE_ALWAYS(udi, "get_max_luns[%d]:not supported. "
"Assuming single LUN available.\n", udi->dev_num);
} else {
PTRACE(udi, "get_max_luns[%d]:failed(%08x)."
"Assuming single LUN available.\n", udi->dev_num, status);
}
udi->max_lun = 0;
status = B_OK;
} /* else - all is OK - max luns info readed */
}
return status;
status_t status = B_OK;
udi->max_lun = 0;
if(!HAS_FIXES(udi->properties, FIX_NO_GETMAXLUN)){
size_t len = 0;
if(B_OK != (status = (*udi->usb_m->send_request)(udi->device,
USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_CLASS,
USB_REQ_MS_GET_MAX_LUN, 0x0, udi->interface,
0x1, &udi->max_lun, &len)))
{
if(status == B_DEV_STALLED){
PTRACE_ALWAYS(udi, "get_max_luns[%d]:not supported. "
"Assuming single LUN available.\n", udi->dev_num);
} else {
PTRACE(udi, "get_max_luns[%d]:failed(%08x)."
"Assuming single LUN available.\n", udi->dev_num, status);
}
udi->max_lun = 0;
status = B_OK;
} /* else - all is OK - max luns info readed */
}
return status;
}
/**
\fn:queue_bulk
\param udi: device for which que_bulk request is performed
\param buffer: data buffer, used in bulk i/o operation
\param len: length of data buffer
\param b_in: is "true" if input (device->host) data transfer, "false" otherwise
\return: status of operation.
performs queue_bulk USB request for corresponding pipe and handle timeout of this
operation.
\fn:queue_bulk
\param udi: device for which que_bulk request is performed
\param buffer: data buffer, used in bulk i/o operation
\param len: length of data buffer
\param b_in: is "true" if input (device->host) data transfer, "false" otherwise
\return: status of operation.
performs queue_bulk USB request for corresponding pipe and handle timeout of this
operation.
*/
static status_t
queue_bulk(usb_device_info *udi,
void *buffer,
size_t len,
bool b_in)
queue_bulk(usb_device_info *udi, void* buffer, size_t len, bool b_in)
{
status_t status = B_OK;
usb_pipe pipe = b_in ? udi->pipe_in : udi->pipe_out;
status = (*udi->usb_m->queue_bulk)(pipe, buffer, len, bulk_callback, udi);
if(status != B_OK){
PTRACE_ALWAYS(udi, "queue_bulk:failed:%08x\n", status);
} else {
status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
if(status != B_OK){
PTRACE_ALWAYS(udi, "queue_bulk:acquire_sem_etc failed:%08x\n", status);
(*udi->usb_m->cancel_queued_transfers)(pipe);
}
}
return status;
status_t status = B_OK;
usb_pipe pipe = b_in ? udi->pipe_in : udi->pipe_out;
status = (*udi->usb_m->queue_bulk)(pipe, buffer, len, bulk_callback, udi);
if(status != B_OK){
PTRACE_ALWAYS(udi, "queue_bulk:failed:%08x\n", status);
} else {
status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
if(status != B_OK){
PTRACE_ALWAYS(udi, "queue_bulk:acquire_sem_etc failed:%08x\n", status);
(*udi->usb_m->cancel_queued_transfers)(pipe);
}
}
return status;
}
/**
\fn:check_CSW
\param udi:corresponding device info
\param csw: CSW to be checked for validity and meaningfullness
\param transfer_len: data transferred during operation, which is checked for status
\return: "true" if CSW valid and meanigfull, "false" otherwise
checks CSW for validity and meaningfullness as required by USB mass strorge
BulkOnly specification ([2] 6.3)
\fn:check_CSW
\param udi:corresponding device info
\param csw: CSW to be checked for validity and meaningfullness
\param transfer_len: data transferred during operation, which is checked for status
\return: "true" if CSW valid and meanigfull, "false" otherwise
checks CSW for validity and meaningfullness as required by USB mass strorge
BulkOnly specification ([2] 6.3)
*/
static bool
check_CSW(usb_device_info *udi,
usb_mass_CSW *csw,
int transfer_len)
check_CSW(usb_device_info *udi, usb_mass_CSW* csw, int transfer_len)
{
bool is_valid = false;
do{
/* check for CSW validity */
if(udi->actual_len != CSW_LENGTH){
PTRACE_ALWAYS(udi, "check_CSW:wrong length %d instead of %d\n",
udi->actual_len, CSW_LENGTH);
break;/* failed */
}
if(csw->signature != CSW_SIGNATURE){
PTRACE_ALWAYS(udi, "check_CSW:wrong signature %08x instead of %08x\n",
csw->signature, CSW_SIGNATURE);
break;/* failed */
}
if(csw->tag != udi->tag - 1){
PTRACE_ALWAYS(udi, "check_CSW:tag mismatch received:%d, awaited:%d\n",
csw->tag, udi->tag-1);
break;/* failed */
}
/* check for CSW meaningfullness */
if(CSW_STATUS_PHASE == csw->status){
PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: phase error\n");
break;/* failed */
}
if(transfer_len < csw->data_residue){
PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: "
"residue:%d is greater than transfer length:%d\n",
csw->data_residue, transfer_len);
break;/* failed */
}
is_valid = true;
}while(false);
return is_valid;
bool is_valid = false;
do{
/* check for CSW validity */
if(udi->actual_len != CSW_LENGTH){
PTRACE_ALWAYS(udi, "check_CSW:wrong length %d instead of %d\n",
udi->actual_len, CSW_LENGTH);
break;/* failed */
}
if(csw->signature != CSW_SIGNATURE){
PTRACE_ALWAYS(udi, "check_CSW:wrong signature %08x instead of %08x\n",
csw->signature, CSW_SIGNATURE);
break;/* failed */
}
if(csw->tag != udi->tag - 1){
PTRACE_ALWAYS(udi, "check_CSW:tag mismatch received:%d, awaited:%d\n",
csw->tag, udi->tag-1);
break;/* failed */
}
/* check for CSW meaningfullness */
if(CSW_STATUS_PHASE == csw->status){
PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: phase error\n");
break;/* failed */
}
if(transfer_len < csw->data_residue){
PTRACE_ALWAYS(udi, "check_CSW:not meaningfull: "
"residue:%d is greater than transfer length:%d\n",
csw->data_residue, transfer_len);
break;/* failed */
}
is_valid = true;
}while(false);
return is_valid;
}
/**
\fn:read_status
\param udi: corresponding device
\param csw: buffer for CSW data
\param transfer_len: data transferred during operation, which is checked for status
\return: success status code
reads CSW from device as proposed in ([2] 5.3.3; Figure 2.).
\fn:read_status
\param udi: corresponding device
\param csw: buffer for CSW data
\param transfer_len: data transferred during operation, which is checked for status
\return: success status code
reads CSW from device as proposed in ([2] 5.3.3; Figure 2.).
*/
static status_t
read_status(usb_device_info *udi,
usb_mass_CSW *csw,
int transfer_len)
read_status(usb_device_info *udi, usb_mass_CSW* csw, int transfer_len)
{
status_t status = B_ERROR;
int try = 0;
do{
status = queue_bulk(udi, csw, CSW_LENGTH, true);
if(0 == try){
if(B_OK != status || B_OK != udi->status){
status = (*udi->usb_m->clear_feature)(udi->pipe_in, USB_FEATURE_ENDPOINT_HALT);
if(status != 0){
PTRACE_ALWAYS(udi, "read_status:failed 1st try, "
"status:%08x; usb_status:%08x\n", status, udi->status);
(*udi->protocol_m->reset)(udi);
break;
}
continue; /* go to second try*/
}
/* CSW was readed without errors */
} else { /* second try */
if(B_OK != status || B_OK != udi->status){
PTRACE_ALWAYS(udi, "read_status:failed 2nd try status:%08x; usb_status:%08x\n",
status, udi->status);
(*udi->protocol_m->reset)(udi);
status = (B_OK == status) ? udi->status : status;
break;
}
}
if(!check_CSW(udi, csw, transfer_len)){
(*udi->protocol_m->reset)(udi);
status = B_ERROR;
break;
}
trace_CSW(udi, csw);
break; /* CSW was read successfully */
}while(try++ < 2);
return status;
status_t status = B_ERROR;
int try = 0;
do{
status = queue_bulk(udi, csw, CSW_LENGTH, true);
if(0 == try){
if(B_OK != status || B_OK != udi->status){
status = (*udi->usb_m->clear_feature)(udi->pipe_in, USB_FEATURE_ENDPOINT_HALT);
if(status != 0){
PTRACE_ALWAYS(udi, "read_status:failed 1st try, "
"status:%08x; usb_status:%08x\n", status, udi->status);
(*udi->protocol_m->reset)(udi);
break;
}
continue; /* go to second try*/
}
/* CSW was readed without errors */
} else { /* second try */
if(B_OK != status || B_OK != udi->status){
PTRACE_ALWAYS(udi, "read_status:failed 2nd try status:%08x; usb_status:%08x\n",
status, udi->status);
(*udi->protocol_m->reset)(udi);
status = (B_OK == status) ? udi->status : status;
break;
}
}
if(!check_CSW(udi, csw, transfer_len)){
(*udi->protocol_m->reset)(udi);
status = B_ERROR;
break;
}
trace_CSW(udi, csw);
break; /* CSW was read successfully */
}while(try++ < 2);
return status;
}
/*================= "standard" protocol procedures ==============================*/
/**
\fn:bulk_only_initialize
\param udi: device on wich we should perform initialization
\return:error code if initialization failed or B_OK if it passed
initialize procedure for bulk only protocol devices.
\fn:bulk_only_initialize
\param udi: device on wich we should perform initialization
\return:error code if initialization failed or B_OK if it passed
initialize procedure for bulk only protocol devices.
*/
status_t
bulk_only_initialize(usb_device_info *udi)
{
status_t status = B_OK;
status = get_max_luns(udi);
return status;
status_t status = B_OK;
status = get_max_luns(udi);
return status;
}
/**
\fn:bulk_only_reset
\param udi: device on wich we should perform reset
\return:error code if reset failed or B_OK if it passed
reset procedure for bulk only protocol devices. Tries to send
BulkOnlyReset USB request and clear USB_FEATURE_ENDPOINT_HALT features on
input and output pipes. ([2] 3.1)
\fn:bulk_only_reset
\param udi: device on wich we should perform reset
\return:error code if reset failed or B_OK if it passed
reset procedure for bulk only protocol devices. Tries to send
BulkOnlyReset USB request and clear USB_FEATURE_ENDPOINT_HALT features on
input and output pipes. ([2] 3.1)
*/
status_t
bulk_only_reset(usb_device_info *udi)
{
status_t status = B_ERROR;
status = (*udi->usb_m->send_request)(udi->device,
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
USB_REQ_MS_RESET, 0,
udi->interface, 0, 0, 0);
if(status != B_OK){
PTRACE_ALWAYS(udi, "bulk_only_reset: reset request failed: %08x\n", status);
}
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in,
USB_FEATURE_ENDPOINT_HALT)))
{
PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_in failed: %08x\n", status);
}
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out,
USB_FEATURE_ENDPOINT_HALT)))
{
PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_out failed: %08x\n", status);
}
PTRACE(udi, "bulk_only_reset:%08x\n", status);
return status;
status_t status = B_ERROR;
status = (*udi->usb_m->send_request)(udi->device,
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
USB_REQ_MS_RESET, 0,
udi->interface, 0, 0, 0);
if(status != B_OK){
PTRACE_ALWAYS(udi, "bulk_only_reset: reset request failed: %08x\n", status);
}
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in,
USB_FEATURE_ENDPOINT_HALT)))
{
PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_in failed: %08x\n", status);
}
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out,
USB_FEATURE_ENDPOINT_HALT)))
{
PTRACE_ALWAYS(udi, "bulk_only_reset: clear_feature on pipe_out failed: %08x\n", status);
}
PTRACE(udi, "bulk_only_reset:%08x\n", status);
return status;
}
/**
\fn:bulk_only_transfer
\param udi: corresponding device
\param cmd: SCSI command to be performed on USB device
\param cmdlen: length of SCSI command
\param data_sg: io vectors array with data to transfer
\param sglist_count: count of entries in io vector array
\param transfer_len: overall length of data to be transferred
\param dir: direction of data transfer
\param ccbio: CCB_SCSIIO struct for original SCSI command
\param cb: callback to handle of final stage of command performing (autosense \
request etc.)
transfer procedure for bulk-only protocol. Performs SCSI command on USB device
[2]
\fn:bulk_only_transfer
\param udi: corresponding device
\param cmd: SCSI command to be performed on USB device
\param cmdlen: length of SCSI command
\param data_sg: io vectors array with data to transfer
\param sglist_count: count of entries in io vector array
\param transfer_len: overall length of data to be transferred
\param dir: direction of data transfer
\param ccbio: CCB_SCSIIO struct for original SCSI command
\param cb: callback to handle of final stage of command performing (autosense \
request etc.)
transfer procedure for bulk-only protocol. Performs SCSI command on USB device
[2]
*/
void
bulk_only_transfer(usb_device_info *udi,
uint8 *cmd,
uint8 cmdlen,
//sg_buffer *sgb,
iovec *sg_data,
int32 sg_count,
int32 transfer_len,
EDirection dir,
CCB_SCSIIO *ccbio,
ud_transfer_callback cb)
bulk_only_transfer(usb_device_info *udi, uint8 *cmd, uint8 cmdlen, //sg_buffer *sgb,
iovec *sg_data,int32 sg_count, int32 transfer_len,
EDirection dir, CCB_SCSIIO *ccbio, ud_transfer_callback cb)
{
status_t status = B_OK;
status_t command_status = B_OK;
int32 residue = transfer_len;
usb_mass_CSW csw = {0};
/* initialize and fill in Command Block Wrapper */
usb_mass_CBW cbw = {
.signature = CBW_SIGNATURE,
.tag = atomic_add(&udi->tag, 1),
.data_transfer_len = transfer_len,
.flags = (dir == eDirIn) ? CBW_FLAGS_IN : CBW_FLAGS_OUT,
.lun = ccbio->cam_ch.cam_target_lun & 0xf,
.cdb_len = cmdlen,
};
memcpy(cbw.CDB, cmd, cbw.cdb_len);
do{
trace_CBW(udi, &cbw);
/* send CBW to device */
status = queue_bulk(udi, &cbw, CBW_LENGTH, false);
if(status != B_OK || udi->status != B_OK){
PTRACE_ALWAYS(udi, "bulk_only_transfer: queue_bulk failed:"
"status:%08x usb status:%08x\n", status, udi->status);
(*udi->protocol_m->reset)(udi);
command_status = B_CMD_WIRE_FAILED;
break;
}
/* perform data transfer if required */
if(transfer_len != 0x0){
status = process_data_io(udi, sg_data, sg_count, dir);
if(status != B_OK && status != B_DEV_STALLED){
command_status = B_CMD_WIRE_FAILED;
break;
}
}
/* get status of command */
status = read_status(udi, &csw, transfer_len);
if(B_OK != status){
command_status = B_CMD_WIRE_FAILED;
break;
}
residue = csw.data_residue;
if(csw.status == CSW_STATUS_FAILED){
command_status = B_CMD_FAILED;
}else{
command_status = B_OK;
}
}while(false);
/* finalize transfer */
cb(udi, ccbio, residue, command_status);
status_t status = B_OK;
status_t command_status = B_OK;
int32 residue = transfer_len;
usb_mass_CSW csw = {0};
/* initialize and fill in Command Block Wrapper */
usb_mass_CBW cbw = {
.signature = CBW_SIGNATURE,
.tag = atomic_add(&udi->tag, 1),
.data_transfer_len = transfer_len,
.flags = (dir == eDirIn) ? CBW_FLAGS_IN : CBW_FLAGS_OUT,
.lun = ccbio->cam_ch.cam_target_lun & 0xf,
.cdb_len = cmdlen,
};
memcpy(cbw.CDB, cmd, cbw.cdb_len);
do{
trace_CBW(udi, &cbw);
/* send CBW to device */
status = queue_bulk(udi, &cbw, CBW_LENGTH, false);
if(status != B_OK || udi->status != B_OK){
PTRACE_ALWAYS(udi, "bulk_only_transfer: queue_bulk failed:"
"status:%08x usb status:%08x\n", status, udi->status);
(*udi->protocol_m->reset)(udi);
command_status = B_CMD_WIRE_FAILED;
break;
}
/* perform data transfer if required */
if(transfer_len != 0x0){
status = process_data_io(udi, sg_data, sg_count, dir);
if(status != B_OK && status != B_DEV_STALLED){
command_status = B_CMD_WIRE_FAILED;
break;
}
}
/* get status of command */
status = read_status(udi, &csw, transfer_len);
if(B_OK != status){
command_status = B_CMD_WIRE_FAILED;
break;
}
residue = csw.data_residue;
if(csw.status == CSW_STATUS_FAILED){
command_status = B_CMD_FAILED;
}else{
command_status = B_OK;
}
}while(false);
/* finalize transfer */
cb(udi, ccbio, residue, command_status);
}
protocol_module_info bulk_only_protocol_m = {
{0, 0, 0}, /* this is not a real kernel module - just interface */
bulk_only_initialize,
bulk_only_reset,
bulk_only_transfer,
{0, 0, 0}, /* this is not a real kernel module - just interface */
bulk_only_initialize,
bulk_only_reset,
bulk_only_transfer,
};
@@ -1,14 +1,20 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
/** bulk-only protocol "standard" procedures */
#ifndef _PROTO_BULK_H_
#define _PROTO_BULK_H_
#define _PROTO_BULK_H_
#ifndef _PROTO_MODULE_H_
#include "proto_module.h"
+175 -171
View File
@@ -1,9 +1,15 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
/* References:
* USB Mass Storage Class specifications:
* http://www.usb.org/developers/data/devclass/usbmassover_11.pdf
@@ -27,9 +33,9 @@
typedef struct _usb_mass_CBI_CB{
uint8 op;
uint8 op2;
uint8 padding[14];
uint8 op;
uint8 op2;
uint8 padding[14];
} usb_mass_CBI_CB;
#define CDB_LEN 16
@@ -38,220 +44,218 @@ typedef struct _usb_mass_CBI_CB{
//typedef uint8 usb_mass_CDB[CDB_LEN];
typedef union _usb_mass_CBI_IDB{
struct {
uint8 type;
uint8 value;
} common;
struct {
uint8 asc;
uint8 ascq;
} ufi;
struct {
uint8 type;
uint8 value;
} common;
struct {
uint8 asc;
uint8 ascq;
} ufi;
} usb_mass_CBI_IDB;
#define CBI_IDB_TYPE_CCI 0x00
#define CBI_IDB_VALUE_PASS 0x00
#define CBI_IDB_VALUE_FAIL 0x01
#define CBI_IDB_VALUE_PHASE 0x02
#define CBI_IDB_VALUE_PERSISTENT 0x03
#define CBI_IDB_VALUE_STATUS_MASK 0x03
#define CBI_IDB_TYPE_CCI 0x00
#define CBI_IDB_VALUE_PASS 0x00
#define CBI_IDB_VALUE_FAIL 0x01
#define CBI_IDB_VALUE_PHASE 0x02
#define CBI_IDB_VALUE_PERSISTENT 0x03
#define CBI_IDB_VALUE_STATUS_MASK 0x03
static void trace_CDB(usb_device_info *udi, const usb_mass_CBI_CB *cb, int len);
static status_t cbi_reset(usb_device_info *udi);
static status_t cbi_initialize(usb_device_info *udi);
static void cbi_transfer(usb_device_info *udi, uint8 *cmd, uint8 cmdlen, //sg_buffer *sgb,
iovec *sg_data, int32 sg_count, int32 transfer_len,
EDirection dir, CCB_SCSIIO *ccbio, ud_transfer_callback cb);
/** returns size of private protocol buffer */
//int cbi_buffer_length(){ return sizeof(usb_mass_CBI_CB) + sizeof(usb_mass_CBI_IDB); }
/** casts private protocol buffer to CBI_IDB */
/*#define IDB_BUFFER(__buff)\
((usb_mass_CBI_IDB*)(((uint8*)__buff) + sizeof(usb_mass_CBI_CB)))
((usb_mass_CBI_IDB*)(((uint8*)__buff) + sizeof(usb_mass_CBI_CB)))
*/
/** casts private protocol buffer to CBI_CB */
/*#define CB_BUFFER(__buff)\
((usb_mass_CBI_CB*)(__buff))
((usb_mass_CBI_CB*)(__buff))
*/
void trace_CDB(usb_device_info *udi, const usb_mass_CBI_CB *cb, int len)
{
PTRACE(udi, "CB:{op:0x%02x; op2:0x%02x;}\n", cb->op, cb->op2);
udi->trace_bytes(" padding:", cb->padding, len - 2);
PTRACE(udi, "CB:{op:0x%02x; op2:0x%02x;}\n", cb->op, cb->op2);
udi->trace_bytes(" padding:", cb->padding, len - 2);
}
static status_t
send_request_adsc(usb_device_info *udi,
void *cb,
int length)
send_request_adsc(usb_device_info *udi, void *cb, int length)
{
status_t status = B_ERROR;
size_t len = 0;
trace_CDB(udi, cb, length);
status = (*udi->usb_m->send_request)(udi->device,
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
USB_REQ_CBI_ADSC, 0,
udi->interface, length,
cb, &len);
return status;
status_t status = B_ERROR;
size_t len = 0;
trace_CDB(udi, cb, length);
status = (*udi->usb_m->send_request)(udi->device,
USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
USB_REQ_CBI_ADSC, 0,
udi->interface, length,
cb, &len);
return status;
}
static status_t
request_interrupt(usb_device_info *udi,
usb_mass_CBI_IDB *idb)
request_interrupt(usb_device_info *udi, usb_mass_CBI_IDB *idb)
{
status_t status = B_ERROR;
status = (*udi->usb_m->queue_interrupt)(udi->pipe_intr, idb,
sizeof(usb_mass_CBI_IDB), bulk_callback, udi);
if(status != B_OK){
PTRACE(udi, "request_interrupt:failed:%08x\n", status);
} else {
status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
if(status != B_OK){
PTRACE(udi, "request_interrupt:acquire_sem_etc failed:%08x\n", status);
(*udi->usb_m->cancel_queued_transfers)(udi->pipe_intr);
}
}
udi->trace_bytes("Intr status:", (uint8*)idb, sizeof(usb_mass_CBI_IDB));
return status;
status_t status = B_ERROR;
status = (*udi->usb_m->queue_interrupt)(udi->pipe_intr, idb,
sizeof(usb_mass_CBI_IDB), bulk_callback, udi);
if(status != B_OK){
PTRACE(udi, "request_interrupt:failed:%08x\n", status);
} else {
status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
if(status != B_OK){
PTRACE(udi, "request_interrupt:acquire_sem_etc failed:%08x\n", status);
(*udi->usb_m->cancel_queued_transfers)(udi->pipe_intr);
}
}
udi->trace_bytes("Intr status:", (uint8*)idb, sizeof(usb_mass_CBI_IDB));
return status;
}
static status_t
parse_status(usb_device_info *udi,
usb_mass_CBI_IDB *idb)
parse_status(usb_device_info *udi, usb_mass_CBI_IDB *idb)
{
status_t command_status = B_OK;
if(CMDSET(udi->properties) == CMDSET_UFI){
if(idb->ufi.asc == 0 && idb->ufi.ascq == 0){
command_status = B_OK;
}else{
command_status = B_CMD_FAILED;
}
} else {
if(idb->common.type == CBI_IDB_TYPE_CCI){
switch(idb->common.value & CBI_IDB_VALUE_STATUS_MASK){
case CBI_IDB_VALUE_PASS:
command_status = B_OK;
break;
case CBI_IDB_VALUE_FAIL:
case CBI_IDB_VALUE_PERSISTENT:
command_status = B_CMD_FAILED;
break;
case CBI_IDB_VALUE_PHASE:
default:
command_status = B_CMD_WIRE_FAILED;
break;
}
} /* else ?? */
}
return command_status;
status_t command_status = B_OK;
if(CMDSET(udi->properties) == CMDSET_UFI){
if(idb->ufi.asc == 0 && idb->ufi.ascq == 0){
command_status = B_OK;
}else{
command_status = B_CMD_FAILED;
}
} else {
if(idb->common.type == CBI_IDB_TYPE_CCI){
switch(idb->common.value & CBI_IDB_VALUE_STATUS_MASK){
case CBI_IDB_VALUE_PASS:
command_status = B_OK;
break;
case CBI_IDB_VALUE_FAIL:
case CBI_IDB_VALUE_PERSISTENT:
command_status = B_CMD_FAILED;
break;
case CBI_IDB_VALUE_PHASE:
default:
command_status = B_CMD_WIRE_FAILED;
break;
}
} /* else ?? */
}
return command_status;
}
/*================= "standard" protocol procedures ==============================*/
/**
\fn:
\param udi: ???
\return:??
??
\fn:
\param udi: ???
\return:??
??
*/
status_t
cbi_reset(usb_device_info *udi)
{
status_t status = B_ERROR;
//usb_mass_CBI_CB *cb = CB_BUFFER(udi->proto_buf);
//usb_mass_CDB cdb = {0x1d, 0x04, 0x00};
//memset(cdb + 2, 0xff, CDB_RESET_LEN - 2);
usb_mass_CBI_CB cb = {
.op = 0x1D,
.op2 = 0x04,
};
memset(cb.padding , 0xff, sizeof(cb.padding));
status = send_request_adsc(udi, &cb, CDB_RESET_LEN);
if(status != B_OK)
PTRACE_ALWAYS(udi, "command_block_reset: reset request failed: %08x\n", status);
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in,
USB_FEATURE_ENDPOINT_HALT)))
PTRACE_ALWAYS(udi, "command_block_reset: clear_feature on pipe_in failed: %08x\n", status);
status_t status = B_ERROR;
//usb_mass_CBI_CB *cb = CB_BUFFER(udi->proto_buf);
//usb_mass_CDB cdb = {0x1d, 0x04, 0x00};
//memset(cdb + 2, 0xff, CDB_RESET_LEN - 2);
usb_mass_CBI_CB cb = {
.op = 0x1D,
.op2 = 0x04,
};
memset(cb.padding , 0xff, sizeof(cb.padding));
status = send_request_adsc(udi, &cb, CDB_RESET_LEN);
if(status != B_OK)
PTRACE_ALWAYS(udi, "command_block_reset: reset request failed: %08x\n", status);
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_in,
USB_FEATURE_ENDPOINT_HALT)))
PTRACE_ALWAYS(udi, "command_block_reset: clear_feature on pipe_in failed: %08x\n", status);
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out,
USB_FEATURE_ENDPOINT_HALT)))
PTRACE_ALWAYS(udi, "command_block_reset: clear_feature on pipe_out failed: %08x\n", status);
PTRACE(udi, "command_block_reset:%08x\n", status);
if(B_OK != (status = (*udi->usb_m->clear_feature)(udi->pipe_out,
USB_FEATURE_ENDPOINT_HALT)))
PTRACE_ALWAYS(udi, "command_block_reset: clear_feature on pipe_out failed: %08x\n", status);
PTRACE(udi, "command_block_reset:%08x\n", status);
return status;
return status;
}
/**
\fn:
\fn:
*/
status_t
cbi_initialize(usb_device_info *udi)
{
status_t status = B_OK;
udi->max_lun = 0;
return status;
status_t status = B_OK;
udi->max_lun = 0;
return status;
}
/**
\fn:bulk_only_transfer
\param udi: ???
\param cmd: ???
\param cmdlen: ???
\return:???
???
\fn:bulk_only_transfer
\param udi: ???
\param cmd: ???
\param cmdlen: ???
\return:???
???
*/
void
cbi_transfer(usb_device_info *udi,
uint8 *cmd,
uint8 cmdlen,
//sg_buffer *sgb,
iovec *sg_data,
int32 sg_count,
int32 transfer_len,
EDirection dir,
CCB_SCSIIO *ccbio,
ud_transfer_callback cb)
cbi_transfer(usb_device_info *udi, uint8 *cmd, uint8 cmdlen,
//sg_buffer *sgb,
iovec *sg_data, int32 sg_count, int32 transfer_len,
EDirection dir,CCB_SCSIIO *ccbio, ud_transfer_callback cb)
{
status_t status = B_OK;
status_t command_status = B_OK;
int32 residue = transfer_len;
usb_mass_CBI_IDB idb = {{0}};
do{
status = send_request_adsc(udi, cmd, cmdlen);
if(status != B_OK){
PTRACE(udi, "cbi_transfer:send command block failed: %08x\n", status);
if(status == B_DEV_STALLED){
command_status = B_CMD_FAILED;
} else {
command_status = B_CMD_WIRE_FAILED;
(*udi->protocol_m->reset)(udi);
}
break;
}
if(transfer_len != 0){
status = process_data_io(udi, sg_data, sg_count, dir);
if(status != B_OK){
command_status = B_CMD_WIRE_FAILED;
break;
}
}
if(PROTO(udi->properties) == PROTO_CBI){
status = request_interrupt(udi, &idb);
PTRACE(udi, "cbi_transfer:request interrupt: %08x(%08x)\n", status, udi->status);
if(status != B_OK){
command_status = B_CMD_WIRE_FAILED;
break;
}
if(udi->status == B_DEV_STALLED){
}
command_status = parse_status(udi, &idb);
} else { /* PROP_CB ???*/
command_status = B_CMD_UNKNOWN;
}
residue = 0; /* DEBUG!!!!!!!!!*/
}while(false);
cb(udi, ccbio, residue, command_status);
status_t status = B_OK;
status_t command_status = B_OK;
int32 residue = transfer_len;
usb_mass_CBI_IDB idb = {{0}};
do{
status = send_request_adsc(udi, cmd, cmdlen);
if(status != B_OK){
PTRACE(udi, "cbi_transfer:send command block failed: %08x\n", status);
if(status == B_DEV_STALLED){
command_status = B_CMD_FAILED;
} else {
command_status = B_CMD_WIRE_FAILED;
(*udi->protocol_m->reset)(udi);
}
break;
}
if(transfer_len != 0){
status = process_data_io(udi, sg_data, sg_count, dir);
if(status != B_OK){
command_status = B_CMD_WIRE_FAILED;
break;
}
}
if(PROTO(udi->properties) == PROTO_CBI){
status = request_interrupt(udi, &idb);
PTRACE(udi, "cbi_transfer:request interrupt: %08x(%08x)\n", status, udi->status);
if(status != B_OK){
command_status = B_CMD_WIRE_FAILED;
break;
}
if(udi->status == B_DEV_STALLED){
}
command_status = parse_status(udi, &idb);
} else { /* PROP_CB ???*/
command_status = B_CMD_UNKNOWN;
}
residue = 0; /* DEBUG!!!!!!!!!*/
}while(false);
cb(udi, ccbio, residue, command_status);
}
protocol_module_info cbi_protocol_m = {
{0, 0, 0}, /* this is not a real kernel module - just interface */
cbi_initialize,
cbi_reset,
cbi_transfer,
{0, 0, 0}, /* this is not a real kernel module - just interface */
cbi_initialize,
cbi_reset,
cbi_transfer,
};
+11 -5
View File
@@ -1,11 +1,17 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
#ifndef _PROTO_CBI_H_
#define _PROTO_CBI_H_
#define _PROTO_CBI_H_
#ifndef _PROTO_MODULE_H_
#include "proto_module.h"
+133 -136
View File
@@ -1,9 +1,15 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
#include <string.h>
#include "usb_scsi.h"
@@ -15,150 +21,141 @@
#include "scsi_commands.h"
/**
\fn:bulk_callback
\param cookie:???
\param status:???
\param data:???
\param actual_len:???
\return:???
???
\fn:bulk_callback
\param cookie:???
\param status:???
\param data:???
\param actual_len:???
\return:???
???
*/
void bulk_callback(void *cookie,
uint32 status,
void *data,
uint32 actual_len)
void bulk_callback(void *cookie, uint32 status, void* data, uint32 actual_len)
{
TRACE_BULK_CALLBACK(status, actual_len);
if(cookie){
usb_device_info *udi = (usb_device_info *)cookie;
udi->status = status;
udi->data = data;
udi->actual_len = actual_len;
if(udi->status != B_CANCELED)
release_sem(udi->trans_sem);
}
TRACE_BULK_CALLBACK(status, actual_len);
if(cookie){
usb_device_info *udi = (usb_device_info *)cookie;
udi->status = status;
udi->data = data;
udi->actual_len = actual_len;
if(udi->status != B_CANCELED)
release_sem(udi->trans_sem);
}
}
/**
\fn:exec_io
\param udi: ???
\return:???
???
\fn:exec_io
\param udi: ???
\return:???
???
*/
status_t process_data_io(usb_device_info *udi,
//sg_buffer *sgb,
iovec *sg_data, int32 sg_count,
EDirection dir)
status_t process_data_io(usb_device_info *udi, //sg_buffer *sgb,
iovec *sg_data, int32 sg_count, EDirection dir)
{
status_t status = B_OK;
usb_pipe pipe = (dir == eDirIn) ? udi->pipe_in : udi->pipe_out;
// TRACE_DATA_IO_SG(data_sg, sglist_count);
status = (*udi->usb_m->queue_bulk_v)(pipe, sg_data, sg_count, bulk_callback, udi);
if(status == B_OK){
status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
if(status == B_OK){
status = udi->status;
if(udi->status == B_DEV_STALLED){
status_t st=(*udi->usb_m->clear_feature)(pipe, USB_FEATURE_ENDPOINT_HALT);
TRACE_ALWAYS("clear_on_STALL:%08x\n",st);
}
}else{
TRACE_ALWAYS("process_data_io:acquire_sem failed:%08x\n", status);
(*udi->usb_m->cancel_queued_transfers)(pipe);
}
} else {
TRACE_ALWAYS("process_data_io:queue_bulk_v failed:%08x\n", status);
}
TRACE_DATA_IO("process_data_io:processed:%d;status:%08x\n", udi->actual_len, status);
return status;
status_t status = B_OK;
usb_pipe pipe = (dir == eDirIn) ? udi->pipe_in : udi->pipe_out;
// TRACE_DATA_IO_SG(data_sg, sglist_count);
status = (*udi->usb_m->queue_bulk_v)(pipe, sg_data, sg_count, bulk_callback, udi);
if(status == B_OK){
status = acquire_sem_etc(udi->trans_sem, 1, B_RELATIVE_TIMEOUT, udi->trans_timeout/*LOCK_TIMEOUT*/);
if(status == B_OK){
status = udi->status;
if(udi->status == B_DEV_STALLED){
status_t st=(*udi->usb_m->clear_feature)(pipe, USB_FEATURE_ENDPOINT_HALT);
TRACE_ALWAYS("clear_on_STALL:%08x\n",st);
}
}else{
TRACE_ALWAYS("process_data_io:acquire_sem failed:%08x\n", status);
(*udi->usb_m->cancel_queued_transfers)(pipe);
}
} else {
TRACE_ALWAYS("process_data_io:queue_bulk_v failed:%08x\n", status);
}
TRACE_DATA_IO("process_data_io:processed:%d;status:%08x\n", udi->actual_len, status);
return status;
}
void transfer_callback(struct _usb_device_info *udi,
CCB_SCSIIO *ccbio,
int32 residue,
status_t status)
void transfer_callback(struct _usb_device_info *udi, CCB_SCSIIO *ccbio,
int32 residue, status_t status)
{
ccbio->cam_resid = residue;
switch(status){
case B_OK:
ccbio->cam_ch.cam_status = CAM_REQ_CMP;
break;
case B_CMD_FAILED:
case B_CMD_UNKNOWN:{
size_t sense_data_len = (0 != ccbio->cam_sense_len) ?
ccbio->cam_sense_len : SSD_MIN_SIZE;
uchar *sense_data_ptr = (NULL != ccbio->cam_sense_ptr) ?
ccbio->cam_sense_ptr : (uchar*)&udi->autosense_data;
uint8 lun = ((ccbio->cam_ch.cam_target_lun) << CMD_LUN_SHIFT) & CMD_LUN;
scsi_cmd_generic_6 cmd = { REQUEST_SENSE, {lun, 0}, sense_data_len, 0};
/* transform command as required by protocol */
uint8 *rcmd = udi->scsi_command_buf;
uint8 rcmdlen = sizeof(udi->scsi_command_buf);
iovec sense_sg = { sense_data_ptr, sense_data_len };
TRACE("transfer_callback:requesting sense information "
"due status:%08x\n", status);
memset(&udi->autosense_data, 0, SSD_FULL_SIZE); /* just to be sure */
if(B_OK != (*udi->transform_m->transform)(udi, (uint8 *)&cmd, sizeof(cmd), &rcmd, &rcmdlen)){
TRACE_ALWAYS("transfer_callback: REQUEST SENSE command transform failed\n");
ccbio->cam_ch.cam_status = CAM_IDE; //?????????
break;
}
/* transfer command to device. SCSI status will be handled in callback */
(*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, &sense_sg, 1, sense_data_len,
eDirIn, ccbio, sense_callback);
}
break;
case B_CMD_WIRE_FAILED:
ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR;
break;
default:
TRACE_ALWAYS("transfer_callback:unknown status:%08x\n", status);
ccbio->cam_ch.cam_status = CAM_IDE;
break;
}
ccbio->cam_resid = residue;
switch(status){
case B_OK:
ccbio->cam_ch.cam_status = CAM_REQ_CMP;
break;
case B_CMD_FAILED:
case B_CMD_UNKNOWN:{
size_t sense_data_len = (0 != ccbio->cam_sense_len) ?
ccbio->cam_sense_len : SSD_MIN_SIZE;
uchar *sense_data_ptr = (NULL != ccbio->cam_sense_ptr) ?
ccbio->cam_sense_ptr : (uchar*)&udi->autosense_data;
uint8 lun = ((ccbio->cam_ch.cam_target_lun) << CMD_LUN_SHIFT) & CMD_LUN;
scsi_cmd_generic_6 cmd = { REQUEST_SENSE, {lun, 0}, sense_data_len, 0};
/* transform command as required by protocol */
uint8 *rcmd = udi->scsi_command_buf;
uint8 rcmdlen = sizeof(udi->scsi_command_buf);
iovec sense_sg = { sense_data_ptr, sense_data_len };
TRACE("transfer_callback:requesting sense information "
"due status:%08x\n", status);
memset(&udi->autosense_data, 0, SSD_FULL_SIZE); /* just to be sure */
if(B_OK != (*udi->transform_m->transform)(udi, (uint8 *)&cmd, sizeof(cmd), &rcmd, &rcmdlen)){
TRACE_ALWAYS("transfer_callback: REQUEST SENSE command transform failed\n");
ccbio->cam_ch.cam_status = CAM_IDE; //?????????
break;
}
/* transfer command to device. SCSI status will be handled in callback */
(*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, &sense_sg, 1, sense_data_len,
eDirIn, ccbio, sense_callback);
}
break;
case B_CMD_WIRE_FAILED:
ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR;
break;
default:
TRACE_ALWAYS("transfer_callback:unknown status:%08x\n", status);
ccbio->cam_ch.cam_status = CAM_IDE;
break;
}
}
void sense_callback(struct _usb_device_info *udi,
CCB_SCSIIO *ccbio,
int32 residue,
status_t status)
void sense_callback(struct _usb_device_info *udi, CCB_SCSIIO *ccbio,
int32 residue, status_t status)
{
ccbio->cam_sense_resid = residue;
switch(status){
case B_CMD_UNKNOWN:
case B_CMD_FAILED:
case B_OK:{
bool b_own_data = (ccbio->cam_sense_ptr == NULL);
scsi_sense_data *sense_data = b_own_data ?
&udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr;
int data_len = (ccbio->cam_sense_len != 0) ? ccbio->cam_sense_len : SSD_MIN_SIZE;
TRACE_SENSE_DATA((uint8*)sense_data, data_len);
if((sense_data->flags & SSD_KEY) == SSD_KEY_NO_SENSE){
/* no problems. normal case for CB handling */
TRACE("sense_callback: key OK\n");
ccbio->cam_ch.cam_status = CAM_REQ_CMP;
} else {
if(!b_own_data){ /* we have used CCBIO provided buffer for sense data */
TRACE("sense_callback:sense info OK????:%08x \n", sense_data);
ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID;
ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION;
} else {
/*TODO: ?????????????????????????????????????? */
ccbio->cam_ch.cam_status = CAM_REQ_CMP;
// ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR /*| CAM_AUTOSNS_VALID*/;
// ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION;
TRACE("sense_callback: sense still not handled...\n");
}
}
}
break;
default:
TRACE_ALWAYS("sense_callback:unknown status:%08x\n", status);
case B_CMD_WIRE_FAILED:
ccbio->cam_ch.cam_status = CAM_AUTOSENSE_FAIL;
break;
}
ccbio->cam_sense_resid = residue;
switch(status){
case B_CMD_UNKNOWN:
case B_CMD_FAILED:
case B_OK:{
bool b_own_data = (ccbio->cam_sense_ptr == NULL);
scsi_sense_data *sense_data = b_own_data ?
&udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr;
int data_len = (ccbio->cam_sense_len != 0) ? ccbio->cam_sense_len : SSD_MIN_SIZE;
TRACE_SENSE_DATA((uint8*)sense_data, data_len);
if((sense_data->flags & SSD_KEY) == SSD_KEY_NO_SENSE){
/* no problems. normal case for CB handling */
TRACE("sense_callback: key OK\n");
ccbio->cam_ch.cam_status = CAM_REQ_CMP;
} else {
if(!b_own_data){ /* we have used CCBIO provided buffer for sense data */
TRACE("sense_callback:sense info OK????:%08x \n", sense_data);
ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID;
ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION;
} else {
/*TODO: ?????????????????????????????????????? */
ccbio->cam_ch.cam_status = CAM_REQ_CMP;
// ccbio->cam_ch.cam_status = CAM_REQ_CMP_ERR /*| CAM_AUTOSNS_VALID*/;
// ccbio->cam_scsi_status = SCSI_STATUS_CHECK_CONDITION;
TRACE("sense_callback: sense still not handled...\n");
}
}
}
break;
default:
TRACE_ALWAYS("sense_callback:unknown status:%08x\n", status);
case B_CMD_WIRE_FAILED:
ccbio->cam_ch.cam_status = CAM_AUTOSENSE_FAIL;
break;
}
}
@@ -1,28 +1,30 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
#ifndef _PROTO_COMMON_H_
#define _PROTO_COMMON_H_
#define _PROTO_COMMON_H_
#ifndef _DEVICE_INFO_H_
#include "device_info.h"
#include "device_info.h"
#endif /* _DEVICE_INFO_H_ */
void bulk_callback(void *cookie,
uint32 status,
void *data,
uint32 actual_len);
void bulk_callback(void *cookie, uint32 status, void* data, uint32 actual_len);
status_t process_data_io(usb_device_info *udi, iovec *sg_data, int32 sg_count/*sg_buffer *sgb*/, EDirection dir);
void transfer_callback(usb_device_info *udi,
CCB_SCSIIO *ccbio,
int32 residue,
status_t status);
void sense_callback(usb_device_info *udi,
CCB_SCSIIO *ccbio,
int32 residue,
status_t status);
#endif /*_PROTO_COMMON_H_*/
void transfer_callback(usb_device_info *udi, CCB_SCSIIO *ccbio,
int32 residue, status_t status);
void sense_callback(usb_device_info *udi, CCB_SCSIIO *ccbio,
int32 residue, status_t status);
#endif /*_PROTO_COMMON_H_*/
@@ -1,81 +1,89 @@
/*
* Copyright (c) 2003-2005 by Siarzhuk Zharski <[email protected]>
* Distributed under the terms of the BSD License.
/**
*
* TODO: description
*
* This file is a part of USB SCSI CAM for Haiku OS.
* May be used under terms of the MIT License
*
* Author(s):
* Siarzhuk Zharski <[email protected]>
*
*
*/
#ifndef _PROTO_MODULE_H_
#define _PROTO_MODULE_H_
#define _PROTO_MODULE_H_
#ifndef _MODULE_H
#include <module.h>
#include <module.h>
#endif /*_MODULE_H*/
/*#ifndef _SG_BUFFER_H_
#include "sg_buffer.h"
#include "sg_buffer.h"
#endif / *_SG_BUFFER_H_*/
enum {
/* B_OK */ /* JFYI:command is OK */
B_CMD_FAILED = B_ERRORS_END + 1, /* command failed */
B_CMD_WIRE_FAILED, /* device problems */
B_CMD_UNKNOWN, /* command state unknown */
/* B_OK */ /* JFYI:command is OK */
B_CMD_FAILED = B_ERRORS_END + 1, /* command failed */
B_CMD_WIRE_FAILED, /* device problems */
B_CMD_UNKNOWN, /* command state unknown */
};
typedef enum{
eDirNone = 0,
eDirIn,
eDirOut,
eDirNone = 0,
eDirIn,
eDirOut,
} EDirection;
struct _usb_device_info; /* forward, we can be included from device_info.h */
typedef void (*ud_transfer_callback)(struct _usb_device_info *udi,
CCB_SCSIIO *ccbio,
int32 residue,
status_t status);
CCB_SCSIIO *ccbio,
int32 residue,
status_t status);
typedef struct {
module_info module;
status_t (*init)(struct _usb_device_info *udi);
status_t (*reset)(struct _usb_device_info *udi);
void (*transfer)(struct _usb_device_info *udi,
uint8 *cmd, uint8 cmdlen,
//sg_buffer *sgb,
iovec *sg_data,
int32 sg_count,
int32 transfer_len,
EDirection dir,
CCB_SCSIIO *ccbio,
ud_transfer_callback cb);
module_info module;
status_t (*init)(struct _usb_device_info *udi);
status_t (*reset)(struct _usb_device_info *udi);
void (*transfer)(struct _usb_device_info *udi,
uint8 *cmd, uint8 cmdlen,
//sg_buffer *sgb,
iovec *sg_data,
int32 sg_count,
int32 transfer_len,
EDirection dir,
CCB_SCSIIO *ccbio,
ud_transfer_callback cb);
} protocol_module_info;
typedef struct {
module_info module;
module_info module;
status_t (*transform)(struct _usb_device_info *udi,
uint8 *cmd, uint8 len,
uint8 **rcmd, uint8 *rlen);
status_t (*transform)(struct _usb_device_info *udi,
uint8 *cmd, uint8 len,
uint8 **rcmd, uint8 *rlen);
} transform_module_info;
#define MODULE_PREFIX "generic/usb_scsi_extensions/"
#define PROTOCOL_SUFFIX "/protocol/v1"
#define TRANSFORM_SUFFIX "/transform/v1"
#define PROTOCOL_MODULE_MASK MODULE_PREFIX"%s"PROTOCOL_SUFFIX
#define TRANSFORM_MODULE_MASK MODULE_PREFIX"%s"TRANSFORM_SUFFIX
#define MODULE_PREFIX "generic/usb_scsi_extensions/"
#define PROTOCOL_SUFFIX "/protocol/v1"
#define TRANSFORM_SUFFIX "/transform/v1"
#define PROTOCOL_MODULE_MASK MODULE_PREFIX"%s"PROTOCOL_SUFFIX
#define TRANSFORM_MODULE_MASK MODULE_PREFIX"%s"TRANSFORM_SUFFIX
/**
\define:_TRACE_ALWAYS
trace always - used mainly for error messages
\define:_TRACE_ALWAYS
trace always - used mainly for error messages
*/
#define PTRACE_ALWAYS(__udi, __x...) \
{ /*if(__udi->b_trace)*/ __udi->trace(true, __x); }
{ /*if(__udi->b_trace)*/ __udi->trace(true, __x); }
/**
\define:TRACE
trace only if logging is activated
\define:TRACE
trace only if logging is activated
*/
#define PTRACE(__udi, __x...) \
{ if(__udi->b_trace) __udi->trace(false, __x); }
{ if(__udi->b_trace) __udi->trace(false, __x); }
#endif /* _PROTO_MODULE_H_ */