* Made at least scsi_cmd_rw_10 the same as the one in private/drivers/scsi_cmds.h;

ideally, we would only have one file and no copies - later.
* That also changed how READ/WRITE_6 commands are translated to READ/WRITE_10
  commands, but it was obviously correct before, at least I can still reproduce
  bug #1577 (so it has to be something else).
* Spotted a few suspicious uses of transform_6_10() vs. transform_cmd_6_10();
  at least the FreeBSD driver seem to work differently here, anyway (it always
  uses 12 byte commands for most of these).
* Cleaned up the file.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22838 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-11-05 22:28:03 +00:00
parent 8bef760f81
commit 618ef1498d
3 changed files with 381 additions and 332 deletions
@@ -6,6 +6,8 @@ if $(TARGET_PLATFORM) != haiku {
UsePublicHeaders [ FDirName drivers ] ; UsePublicHeaders [ FDirName drivers ] ;
} }
UsePrivateHeaders drivers ;
KernelAddon usb_scsi : KernelAddon usb_scsi :
usb_scsi.c usb_scsi.c
tracing.c tracing.c
@@ -1,19 +1,16 @@
/** /*
* * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
* TODO: description * Distributed under the terms of the MIT License.
*
* 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]>
*
* *
* Author:
* Siarzhuk Zharski <[email protected]>
*/ */
/** definitions for SCSI commands, structures etc. */
#ifndef _SCSI_COMMANDS_H_ #ifndef _SCSI_COMMANDS_H_
#define _SCSI_COMMANDS_H_ #define _SCSI_COMMANDS_H_
/*! Definitions for SCSI commands, structures etc. */
#include <lendian_bitfield.h>
/* References: /* References:
* http://www.t10.org/ftp/t10/drafts/rbc/rbc-r10a.pdf * http://www.t10.org/ftp/t10/drafts/rbc/rbc-r10a.pdf
@@ -189,18 +186,23 @@ typedef struct{
}scsi_cmd_generic_12; }scsi_cmd_generic_12;
/* READ_6 / WRITE_6 */ /* READ_6 / WRITE_6 */
typedef scsi_cmd_generic_6 scsi_cmd_rw_6; typedef scsi_cmd_generic_6 scsi_cmd_rw_6;
/* READ_10 / WRITE_10 */ /* READ_10 / WRITE_10 */
typedef struct{ typedef struct {
uint8 opcode; uint8 opcode;
uint8 byte2; LBITFIELD8_5(
#define CMD_RW_10_RELADDR 0x01 relative_address : 1, // relative address
#define CMD_RW_10_FUA 0x08 _res1_1 : 2,
#define CMD_RW_10_DPO 0x10 force_unit_access : 1, // force unit access (1 = safe, cacheless access)
uint8 addr[4]; disable_page_out : 1, // disable page out (1 = not worth caching)
uint8 reserved; lun : 3
uint8 len[2]; );
uint8 ctrl; uint32 lba; // big endian
}scsi_cmd_rw_10; uint8 _reserved;
uint16 length; // big endian
uint8 control;
} scsi_cmd_rw_10;
/* MODE_SELECT_6 */ /* MODE_SELECT_6 */
typedef struct{ typedef struct{
uint8 opcode; uint8 opcode;
@@ -1,16 +1,12 @@
/** /*
* * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
* TODO: description * Distributed under the terms of the MIT License.
*
* 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]>
*
* *
* Author:
* Siarzhuk Zharski <[email protected]>
*/ */
/** SCSI commands transformations support */
/*! SCSI commands transformations support */
#include "usb_scsi.h" #include "usb_scsi.h"
@@ -18,208 +14,228 @@
#include "transform_procs.h" #include "transform_procs.h"
#include "tracing.h" #include "tracing.h"
#include "scsi_commands.h" #include "scsi_commands.h"
//#include "proto_common.h"
#include "settings.h" #include "settings.h"
#include "strings.h" #include "strings.h"
#define UFI_COMMAND_LEN 12 #define UFI_COMMAND_LEN 12
#define ATAPI_COMMAND_LEN 12 #define ATAPI_COMMAND_LEN 12
static status_t
scsi_transform(usb_device_info *udi, uint8 *cmd, /*! Transforms a 6-byte command to 10-byte one if required. Transformed command
uint8 len, uint8 **rcmd, uint8 *rlen); is returned in rcmd parameter. In case if no transformation was performed
static status_t rbc_transform(usb_device_info *udi, uint8 *cmd, the return buffer is untouched.
uint8 len, uint8 **rcmd, uint8 *rlen);
static status_t ufi_transform(usb_device_info *udi, uint8 *cmd,
uint8 len, uint8 **rcmd, uint8 *rlen);
static status_t atapi_transform(usb_device_info *udi, uint8 *cmd,
uint8 len, uint8 **rcmd, uint8 *rlen);
static status_t qic157_transform(usb_device_info *udi, uint8 *cmd,
uint8 len, uint8 **rcmd, uint8 *rlen);
/**
\fn:transform_6_to_10
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: true if transformation was performed \return: true if transformation was performed
transforms a 6-byte command to 10-byte one if required.Transformed command is
returned in rcmd parameter. In case if no transformation was performed the return
buffer is untouched.
*/ */
static bool transform_6_to_10(uint8 *cmd, uint8 len, static void
uint8 **rcmd, uint8 *rlen) transform_6_to_10(uint8 *cmd, uint8 len, uint8 **rcmd, uint8 *rlen)
{ {
bool transformed = true;
scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd; scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd;
memset(*rcmd, 0, *rlen);
switch (from->opcode){ *rlen = 10;
memset(*rcmd, 0, 10);
switch (from->opcode) {
case READ_6: case READ_6:
case WRITE_6:{ case WRITE_6:
scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd); {
to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10; scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd);
memcpy(to->addr + 1, from->addr, 3);
to->byte2 = from->addr[0]; to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10;
to->byte2 &= ~CMD_GEN_6_ADDR; to->lba = B_HOST_TO_BENDIAN_INT32(((from->addr[0] & 0x1f) << 16)
to->addr[1] &= CMD_GEN_6_ADDR; | (from->addr[1] << 8) | from->addr[0]);
to->len[1] = from->len; to->lun = (from->addr[0] & CMD_LUN) >> CMD_LUN_SHIFT;
to->ctrl = from->ctrl; to->control = from->ctrl;
if(0 == from->len){ /* special case! in 6-byte R/W commands */ if (from->len == 0) {
to->len[0] = 1; /* the length 0x00 assume transfering 0x100 blocks! */ /* special case! in 6-byte R/W commands */
} /* the length 0x00 assume transfering 0x100 blocks! */
}break; to->length = B_HOST_TO_BENDIAN_INT16((uint16)256);
} else
to->length = B_HOST_TO_BENDIAN_INT16((uint16)from->len);
}
case MODE_SENSE_6: case MODE_SENSE_6:
case MODE_SELECT_6:{ case MODE_SELECT_6:
scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd); {
if(from->opcode == MODE_SENSE_6){ scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd);
if (from->opcode == MODE_SENSE_6) {
to->opcode = MODE_SENSE_10; to->opcode = MODE_SENSE_10;
((scsi_cmd_mode_sense_10 *)to)->byte3 = ((scsi_cmd_mode_sense_10 *)to)->byte3
((scsi_cmd_mode_sense_6 *)from)->byte3; = ((scsi_cmd_mode_sense_6 *)from)->byte3;
}else } else
to->opcode = MODE_SELECT_10; to->opcode = MODE_SELECT_10;
to->byte2 = from->addr[0]; to->byte2 = from->addr[0];
to->len[1] = from->len + 4; /*TODO: hardcoded length*/ to->len[1] = from->len + 4; /*TODO: hardcoded length*/
to->ctrl = from->ctrl; to->ctrl = from->ctrl;
}break; }
default:{ /* no transformation needed */
transformed = false; default:
}break; /* no transformation needed */
break;
} }
return transformed;
} }
/**
\fn:transform_cmd_6_to_10
/*! Transforms a 6-byte command to 10-byte depending on information provided
with udi object.
\param udi: usb_device_info object for wich transformation is requested \param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: true if transformation was performed \return: true if transformation was performed
transforms a 6-byte command to 10-byte depending on information provided with
udi object.
*/ */
static bool transform_cmd_6_to_10(usb_device_info *udi, uint8 *cmd, static bool
uint8 len, uint8 **rcmd, uint8 *rlen) transform_cmd_6_to_10(usb_device_info *udi, uint8 *cmd, uint8 len,
uint8 **rcmd, uint8 *rlen)
{ {
bool transformed = true;
scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd; scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd;
switch (from->opcode){
switch (from->opcode) {
case READ_6: case READ_6:
case WRITE_6:{ case WRITE_6:
// if(!(HAS_FEATURES(udi->descr.properties, PROP_FORCE_TO_6))){ {
if(!HAS_FIXES(udi->properties, FIX_FORCE_RW_TO_6)){ if (!HAS_FIXES(udi->properties, FIX_FORCE_RW_TO_6)) {
if((transformed = transform_6_to_10(cmd, len, rcmd, rlen)) == true) transform_6_to_10(cmd, len, rcmd, rlen);
*rlen = 10; return true;
}else }
transformed = false; break;
}break; }
case MODE_SENSE_6: case MODE_SENSE_6:
case MODE_SELECT_6:{ case MODE_SELECT_6:
// if(HAS_FEATURES(udi->descr.properties, PROP_USE_MODESENSE_10)){ {
if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){ if (HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)) {
if((transformed = transform_6_to_10(cmd, len, rcmd, rlen)) == true) transform_6_to_10(cmd, len, rcmd, rlen);
*rlen = 10; return true;
}else }
transformed = false; break;
} }
} }
return transformed;
return false;
} }
/**
\fn:transform_cmd_test_unit_ready
/*! Transforms a TEST_UNIT_COMAND SCSI command to START_STOP_UNIT one depending
on properties provided with udi object.
\param udi: usb_device_info object for wich transformation is requested \param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: true if transformation was performed \return: true if transformation was performed
transforms a TEST_UNIT_COMAND SCSI command to START_STOP_UNIT one depending
on properties provided with udi object.
*/ */
static bool transform_cmd_test_unit_ready(usb_device_info *udi, static bool
uint8 *cmd, uint8 len, transform_cmd_test_unit_ready(usb_device_info *udi, uint8 *cmd, uint8 len,
uint8 **rcmd, uint8 *rlen) uint8 **rcmd, uint8 *rlen)
{ {
bool transformed = false; scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd);
if(HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT)){
scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd); if (!HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT))
memset(*rcmd, 0, *rlen); return false;
command->opcode = START_STOP_UNIT;
command->start_loej = CMD_SSU_START; memset(*rcmd, 0, *rlen);
*rlen = 6; command->opcode = START_STOP_UNIT;
transformed = true; command->start_loej = CMD_SSU_START;
} *rlen = 6;
return transformed;
return true;
} }
/**
\fn:scsi_transform
// #pragma mark -
/*! This is the "transformation procedure" for transparent SCSI (0x06) USB
subclass. It performs all SCSI commands transformations required by this
protocol. Additionally it tries to make some workarounds for "broken" USB
devices. If no transformation was performed resulting command buffer
points to original one.
\param udi: usb_device_info object for wich transformation is requested \param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: B_OK if transformation was successfull, B_ERROR otherwise \return: B_OK if transformation was successfull, B_ERROR otherwise
this is the "transformation procedure" for transparent SCSI (0x06) USB subclass.It
performs all SCSI commands transformations required by this protocol. Additionally
it tries to make some workarounds for "brocken" USB devices. If no transformation
was performed resulting command buffer points to original one.
*/ */
status_t static status_t
scsi_transform(usb_device_info *udi, uint8 *cmd, scsi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 len, uint8 **rcmd, uint8 *rlen) uint8 *rlen)
{ {
status_t status = B_OK;
bool transformed = false; bool transformed = false;
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
TRACE_SCSI_COMMAND(cmd, len); TRACE_SCSI_COMMAND(cmd, len);
switch(command->opcode){
switch (command->opcode) {
case READ_6: case READ_6:
case WRITE_6: case WRITE_6:
case MODE_SENSE_6: case MODE_SENSE_6:
case MODE_SELECT_6: case MODE_SELECT_6:
transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen); transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
break; break;
case TEST_UNIT_READY: case TEST_UNIT_READY:
transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen); transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd,
rlen);
break;
default:
break; break;
default: break;
} }
if(!transformed){ /* transformation was not required */
if (!transformed) {
/* transformation was not required */
*rcmd = cmd; *rcmd = cmd;
*rlen = len; *rlen = len;
}else } else
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return status;
return B_OK;
} }
/**
\fn:rbc_transform
/*! This is the "transformation procedure" for RBC USB subclass (0x01). It
performs all SCSI commands transformations required by this protocol.
Additionally it tries to make some workarounds for "broken" USB devices.
If no transformation was performed resulting command buffer points to
original one.
\param udi: usb_device_info object for wich transformation is requested \param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: B_OK if transformation was successfull, B_ERROR otherwise \return: B_OK if transformation was successfull, B_ERROR otherwise
this is the "transformation procedure" for RBC USB subclass (0x01).It
performs all SCSI commands transformations required by this protocol. Additionally
it tries to make some workarounds for "brocken" USB devices. If no transformation
was performed resulting command buffer points to original one.
*/ */
status_t rbc_transform(usb_device_info *udi, uint8 *cmd, static status_t
uint8 len, uint8 **rcmd, uint8 *rlen) rbc_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 *rlen)
{ {
status_t status = B_OK;
bool transformed = false; bool transformed = false;
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
TRACE_SCSI_COMMAND(cmd, len); TRACE_SCSI_COMMAND(cmd, len);
switch(command->opcode){
switch (command->opcode) {
case TEST_UNIT_READY: case TEST_UNIT_READY:
transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen); transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen);
break; break;
case READ_6: case READ_6:
case WRITE_6: /* there are no such command in list of allowed - transform*/ case WRITE_6: /* there are no such command in list of allowed - transform*/
transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen); transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
break; break;
case FORMAT_UNIT: /* TODO: all following ones are not checked against specs !!!*/
/* TODO: all following ones are not checked against specs !!!*/
case FORMAT_UNIT:
case INQUIRY: /*TODO: check !!! */ case INQUIRY: /*TODO: check !!! */
case MODE_SELECT_6: /*TODO: check !!! */ case MODE_SELECT_6: /*TODO: check !!! */
case MODE_SENSE_6: /*TODO: check !!! */ case MODE_SENSE_6: /*TODO: check !!! */
@@ -235,222 +251,251 @@ status_t rbc_transform(usb_device_info *udi, uint8 *cmd,
case SYNCHRONIZE_CACHE: /*TODO: check !!! */ case SYNCHRONIZE_CACHE: /*TODO: check !!! */
case VERIFY: /*TODO: check !!! */ case VERIFY: /*TODO: check !!! */
case WRITE_10: /*TODO: check !!! */ case WRITE_10: /*TODO: check !!! */
case WRITE_BUFFER:/*TODO Check correctnes of such translation!*/ case WRITE_BUFFER: /*TODO Check correctnes of such translation!*/
*rcmd = cmd; /* No need to copy */ *rcmd = cmd; /* No need to copy */
*rlen = len; /*TODO: check !!! */ *rlen = len; /*TODO: check !!! */
break;
default: default:
TRACE_ALWAYS("An unsupported RBC command: %08x\n", command->opcode); TRACE_ALWAYS("An unsupported RBC command: %08x\n", command->opcode);
return B_ERROR;
}
if (transformed)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return B_OK;
}
/*! This is the "transformation procedure" for UFI USB subclass (0x04). It
performs all SCSI commands transformations required by this protocol.
Additionally it tries to make some workarounds for "broken" USB devices.
If no transformation was performed resulting command buffer points to
the original one.
\param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command
\return: B_OK if transformation was successfull, B_ERROR otherwise
*/
static status_t
ufi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 *rlen)
{
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
status_t status = B_OK;
TRACE_SCSI_COMMAND(cmd, len);
memset(*rcmd, 0, UFI_COMMAND_LEN);
switch (command->opcode) {
case READ_6:
case WRITE_6:
case MODE_SENSE_6:
case MODE_SELECT_6:
// TODO: not transform_cmd_*()?
transform_6_to_10(cmd, len, rcmd, rlen);
break;
case TEST_UNIT_READY:
if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
break; /* if TEST UNIT READY was transformed*/
case FORMAT_UNIT: /* TODO: mismatch */
case INQUIRY:
case START_STOP_UNIT:
case MODE_SELECT_10:
case MODE_SENSE_10:
case PREVENT_ALLOW_MEDIA_REMOVAL:
case READ_10:
case READ_12:
case READ_CAPACITY:
case READ_FORMAT_CAPACITY: /* TODO: not in the SCSI-2 specs */
case REQUEST_SENSE:
case REZERO_UNIT:
case SEEK_10:
case SEND_DIAGNOSTICS: /* TODO: parameter list len mismatch */
case VERIFY:
case WRITE_10:
case WRITE_12: /* TODO: EBP. mismatch */
case WRITE_AND_VERIFY:
memcpy(*rcmd, cmd, len);
/*TODO what about control? ignored in UFI?*/
break;
default:
TRACE_ALWAYS("An unsupported UFI command: %08x\n",
command->opcode);
status = B_ERROR; status = B_ERROR;
break; break;
} }
if(transformed)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return status;
}
/**
\fn:ufi_transform
\param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command
\return: B_OK if transformation was successfull, B_ERROR otherwise
this is the "transformation procedure" for UFI USB subclass (0x04).It
performs all SCSI commands transformations required by this protocol. Additionally
it tries to make some workarounds for "brocken" USB devices. If no transformation
was performed resulting command buffer points to original one.
*/
status_t ufi_transform(usb_device_info *udi,
uint8 *cmd,
uint8 len,
uint8 **rcmd,
uint8 *rlen)
{
status_t status = B_OK;
TRACE_SCSI_COMMAND(cmd, len);
memset(*rcmd, 0, UFI_COMMAND_LEN);
if(!transform_6_to_10(cmd, len, rcmd, rlen)){ /* was not transformed ?*/
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
switch(command->opcode){
case TEST_UNIT_READY:
if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){
break; /* if TEST UNIT READY was transformed*/
}
case FORMAT_UNIT: /* TODO: mismatch */
case INQUIRY:
case START_STOP_UNIT:
case MODE_SELECT_10:
case MODE_SENSE_10:
case PREVENT_ALLOW_MEDIA_REMOVAL:
case READ_10:
case READ_12:
case READ_CAPACITY:
case READ_FORMAT_CAPACITY: /* TODO: not in the SCSI-2 specs */
case REQUEST_SENSE:
case REZERO_UNIT:
case SEEK_10:
case SEND_DIAGNOSTICS: /* TODO: parameter list len mismatch */
case VERIFY:
case WRITE_10:
case WRITE_12: /* TODO: EBP. mismatch */
case WRITE_AND_VERIFY:
memcpy(*rcmd, cmd, len); /*TODO what about control? ignored in UFI?*/
break;
default:
TRACE_ALWAYS("An unsupported UFI command: %08x\n", command->opcode);
status = B_ERROR;
break;
}
}
*rlen = UFI_COMMAND_LEN; /* override any value set in transform funcs !!!*/ *rlen = UFI_COMMAND_LEN; /* override any value set in transform funcs !!!*/
if(status == B_OK)
if (status == B_OK)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return status; return status;
} }
/**
\fn:atapi_transform
/*! This is the "transformation procedure" for SFF8020I and SFF8070I
USB subclassses (0x02 and 0x05). It performs all SCSI commands
transformations required by this protocol. Additionally it tries to make
some workarounds for "broken" USB devices. If no transformation was
performed resulting command buffer points to the original one.
\param udi: usb_device_info object for wich transformation is requested \param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: B_OK if transformation was successfull, B_ERROR otherwise \return: B_OK if transformation was successfull, B_ERROR otherwise
this is the "transformation procedure" for SFF8020I and SFF8070I
USB subclassses (0x02 and 0x05). It performs all SCSI commands transformations
required by this protocol. Additionally it tries to make some workarounds for
"broken" USB devices. If no transformation was performed resulting command
buffer points to original one.
*/ */
status_t atapi_transform(usb_device_info *udi, static status_t
uint8 *cmd, atapi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 len, uint8 *rlen)
uint8 **rcmd,
uint8 *rlen)
{ {
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
status_t status = B_OK; status_t status = B_OK;
TRACE_SCSI_COMMAND(cmd, len); TRACE_SCSI_COMMAND(cmd, len);
memset(*rcmd, 0, ATAPI_COMMAND_LEN); memset(*rcmd, 0, ATAPI_COMMAND_LEN);
if(!transform_6_to_10(cmd, len, rcmd, rlen)){ /* was not transformed ?*/
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; switch (command->opcode) {
switch(command->opcode){ case READ_6:
case TEST_UNIT_READY: case WRITE_6:
if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){ case MODE_SENSE_6:
break; /* if TEST UNIT READY was transformed*/ case MODE_SELECT_6:
} // TODO: not transform_cmd_*()?
case FORMAT_UNIT: transform_6_to_10(cmd, len, rcmd, rlen))
case INQUIRY: break;
case MODE_SELECT_10: case TEST_UNIT_READY:
case MODE_SENSE_10: if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
case PREVENT_ALLOW_MEDIA_REMOVAL: break;
case READ_10: case FORMAT_UNIT:
case READ_12: /* mismatch in byte 1 */ case INQUIRY:
case READ_CAPACITY: /* mismatch. no transf len defined... */ case MODE_SELECT_10:
case READ_FORMAT_CAPACITY: /* TODO: check!!! */ case MODE_SENSE_10:
case REQUEST_SENSE: case PREVENT_ALLOW_MEDIA_REMOVAL:
case SEEK_10: case READ_10:
case START_STOP_UNIT: case READ_12: /* mismatch in byte 1 */
case VERIFY: /* mismatch DPO */ case READ_CAPACITY: /* mismatch. no transf len defined... */
case WRITE_10: /* mismatch in byte 1 */ case READ_FORMAT_CAPACITY: /* TODO: check!!! */
case WRITE_12: /* mismatch in byte 1 */ case REQUEST_SENSE:
case WRITE_AND_VERIFY: /* mismatch byte 1 */ case SEEK_10:
case PAUSE_RESUME: case START_STOP_UNIT:
case PLAY_AUDIO: case VERIFY: /* mismatch DPO */
case PLAY_AUDIO_MSF: case WRITE_10: /* mismatch in byte 1 */
case REWIND: case WRITE_12: /* mismatch in byte 1 */
case PLAY_AUDIO_TRACK: case WRITE_AND_VERIFY: /* mismatch byte 1 */
/* are in FreeBSD driver but no in 8070/8020 specs ... case PAUSE_RESUME:
//case REZERO_UNIT: case PLAY_AUDIO:
//case SEND_DIAGNOSTIC: case PLAY_AUDIO_MSF:
//case POSITION_TO_ELEMENT: */ case REWIND:
case GET_CONFIGURATION: case PLAY_AUDIO_TRACK:
case SYNCHRONIZE_CACHE: /* are in FreeBSD driver but no in 8070/8020 specs ...
case READ_BUFFER: //case REZERO_UNIT:
case READ_SUBCHANNEL: //case SEND_DIAGNOSTIC:
case READ_TOC: /* some mismatch */ //case POSITION_TO_ELEMENT: */
case READ_HEADER: case GET_CONFIGURATION:
case READ_DISK_INFO: case SYNCHRONIZE_CACHE:
case READ_TRACK_INFO: case READ_BUFFER:
case SEND_OPC: case READ_SUBCHANNEL:
case READ_MASTER_CUE: case READ_TOC: /* some mismatch */
case CLOSE_TR_SESSION: case READ_HEADER:
case READ_BUFFER_CAP: case READ_DISK_INFO:
case SEND_CUE_SHEET: case READ_TRACK_INFO:
case BLANK: case SEND_OPC:
case EXCHANGE_MEDIUM: case READ_MASTER_CUE:
case READ_DVD_STRUCTURE: case CLOSE_TR_SESSION:
case SET_CD_SPEED: case READ_BUFFER_CAP:
case DVD_REPORT_KEY: case SEND_CUE_SHEET:
case BLANK:
case EXCHANGE_MEDIUM:
case READ_DVD_STRUCTURE:
case SET_CD_SPEED:
case DVD_REPORT_KEY:
case DVD_SEND_KEY: case DVD_SEND_KEY:
// case 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */ //case 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */
memcpy(*rcmd, cmd, len); /* TODO: check!!! */ memcpy(*rcmd, cmd, len); /* TODO: check!!! */
break; break;
default:
TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n", command->opcode); default:
status = B_ERROR; TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n",
break; command->opcode);
} status = B_ERROR;
break;
} }
*rlen = ATAPI_COMMAND_LEN; *rlen = ATAPI_COMMAND_LEN;
if(status == B_OK)
if (status == B_OK)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return status; return status;
} }
/**
\fn:qic157_transform
/*! This is the "transformation procedure" for QIC157 USB subclass (0x03). It
performs all SCSI commands transformations required by this protocol.
Additionally it tries to make some workarounds for "broken" USB devices.
If no transformation was performed the resulting command buffer points to
the original one.
\param udi: usb_device_info object for wich transformation is requested \param udi: usb_device_info object for wich transformation is requested
\param cmd: SCSI command buffer to be transformed \param cmd: SCSI command buffer to be transformed
\param len: length of buffer, pointed by cmd parameter \param len: length of buffer, pointed by cmd parameter
\param rcmd: a place for buffer pointer with transformed command \param rcmd: a place for buffer pointer with transformed command
\param rlen: a place for length of transformed command \param rlen: a place for length of transformed command
\return: B_OK if transformation was successfull, B_ERROR otherwise \return: B_OK if transformation was successfull, B_ERROR otherwise
this is the "transformation procedure" for QIC157 USB subclass (0x03).It
performs all SCSI commands transformations required by this protocol. Additionally
it tries to make some workarounds for "brocken" USB devices. If no transformation
was performed resulting command buffer points to original one.
*/ */
status_t qic157_transform(usb_device_info *udi, static status_t
uint8 *cmd, qic157_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 len, uint8 *rlen)
uint8 **rcmd,
uint8 *rlen)
{ {
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
status_t status = B_OK; status_t status = B_OK;
TRACE_SCSI_COMMAND(cmd, len); TRACE_SCSI_COMMAND(cmd, len);
*rlen = ATAPI_COMMAND_LEN; *rlen = ATAPI_COMMAND_LEN;
memset(*rcmd, 0, *rlen); memset(*rcmd, 0, *rlen);
if(!transform_6_to_10(cmd, len, rcmd, rlen)){ // was not transformed ?
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd; switch (command->opcode) {
switch(command->opcode){ case READ_6:
case TEST_UNIT_READY: case WRITE_6:
if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){ case MODE_SENSE_6:
break; // if TEST UNIT READY was transformed case MODE_SELECT_6:
} // TODO: not transform_cmd_*()?
case ERASE: /*TODO: check !!! */ transform_6_to_10(cmd, len, rcmd, rlen);
case INQUIRY: /*TODO: check !!! */ break;
case LOAD_UNLOAD: /*TODO: check !!! */ case TEST_UNIT_READY:
case LOCATE: /*TODO: check !!! */ if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
case LOG_SELECT: /*TODO: check !!! */ break; // if TEST UNIT READY was transformed
case LOG_SENSE: /*TODO: check !!! */ case ERASE: /*TODO: check !!! */
case MODE_SELECT_6: /*TODO: check !!! */ case INQUIRY: /*TODO: check !!! */
case MODE_SENSE_6: /*TODO: check !!! */ case LOAD_UNLOAD: /*TODO: check !!! */
case READ_6: /*TODO: check !!! */ case LOCATE: /*TODO: check !!! */
case READ_POSITION: /*TODO: check !!! */ case LOG_SELECT: /*TODO: check !!! */
case REQUEST_SENSE: /*TODO: check !!! */ case LOG_SENSE: /*TODO: check !!! */
case REWIND: /*TODO: check !!! */ case READ_POSITION: /*TODO: check !!! */
case SPACE: /*TODO: check !!! */ case REQUEST_SENSE: /*TODO: check !!! */
case WRITE_6: /*TODO: check !!! */ case REWIND: /*TODO: check !!! */
case WRITE_FILEMARK: /*TODO: check !!! */ case SPACE: /*TODO: check !!! */
*rcmd = cmd; /*TODO: check !!! */ case WRITE_FILEMARK: /*TODO: check !!! */
*rlen = len; *rcmd = cmd; /*TODO: check !!! */
break; *rlen = len;
default: break;
TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n", command->opcode); default:
status = B_ERROR; TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n",
break; command->opcode);
} status = B_ERROR;
break;
} }
if(status == B_OK)
if (status == B_OK)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen); TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return status; return status;
} }