- 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 */ /** 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"
+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: /* 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,
}; };
+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_ #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"
+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 <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_ */