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