* 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

View File

@ -6,6 +6,8 @@ if $(TARGET_PLATFORM) != haiku {
UsePublicHeaders [ FDirName drivers ] ;
}
UsePrivateHeaders drivers ;
KernelAddon usb_scsi :
usb_scsi.c
tracing.c

View File

@ -1,19 +1,16 @@
/**
/*
* Copyright 2004-2007, Haiku, Inc. All RightsReserved.
* Distributed under the terms of the MIT 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 <imker@gmx.li>
*
*
* Author:
* Siarzhuk Zharski <imker@gmx.li>
*/
/** definitions for SCSI commands, structures etc. */
#ifndef _SCSI_COMMANDS_H_
#define _SCSI_COMMANDS_H_
#define _SCSI_COMMANDS_H_
/*! Definitions for SCSI commands, structures etc. */
#include <lendian_bitfield.h>
/* References:
* http://www.t10.org/ftp/t10/drafts/rbc/rbc-r10a.pdf
@ -189,18 +186,23 @@ typedef struct{
}scsi_cmd_generic_12;
/* READ_6 / WRITE_6 */
typedef scsi_cmd_generic_6 scsi_cmd_rw_6;
/* READ_10 / WRITE_10 */
typedef struct{
typedef struct {
uint8 opcode;
uint8 byte2;
#define CMD_RW_10_RELADDR 0x01
#define CMD_RW_10_FUA 0x08
#define CMD_RW_10_DPO 0x10
uint8 addr[4];
uint8 reserved;
uint8 len[2];
uint8 ctrl;
}scsi_cmd_rw_10;
LBITFIELD8_5(
relative_address : 1, // relative address
_res1_1 : 2,
force_unit_access : 1, // force unit access (1 = safe, cacheless access)
disable_page_out : 1, // disable page out (1 = not worth caching)
lun : 3
);
uint32 lba; // big endian
uint8 _reserved;
uint16 length; // big endian
uint8 control;
} scsi_cmd_rw_10;
/* MODE_SELECT_6 */
typedef struct{
uint8 opcode;

View File

@ -1,225 +1,241 @@
/**
/*
* Copyright 2004-2007, Haiku, Inc. All RightsReserved.
* Distributed under the terms of the MIT 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 <imker@gmx.li>
*
*
* Author:
* Siarzhuk Zharski <imker@gmx.li>
*/
/** SCSI commands transformations support */
#include "usb_scsi.h"
/*! SCSI commands transformations support */
#include "device_info.h"
#include "transform_procs.h"
#include "tracing.h"
#include "scsi_commands.h"
//#include "proto_common.h"
#include "usb_scsi.h"
#include "device_info.h"
#include "transform_procs.h"
#include "tracing.h"
#include "scsi_commands.h"
#include "settings.h"
#include "strings.h"
#define UFI_COMMAND_LEN 12
#define ATAPI_COMMAND_LEN 12
#define UFI_COMMAND_LEN 12
#define ATAPI_COMMAND_LEN 12
/*! 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 status_t
scsi_transform(usb_device_info *udi, uint8 *cmd,
uint8 len, uint8 **rcmd, uint8 *rlen);
static status_t rbc_transform(usb_device_info *udi, uint8 *cmd,
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 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: 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,
uint8 **rcmd, uint8 *rlen)
static void
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;
memset(*rcmd, 0, *rlen);
switch (from->opcode){
*rlen = 10;
memset(*rcmd, 0, 10);
switch (from->opcode) {
case READ_6:
case WRITE_6:{
scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd);
to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10;
memcpy(to->addr + 1, from->addr, 3);
to->byte2 = from->addr[0];
to->byte2 &= ~CMD_GEN_6_ADDR;
to->addr[1] &= CMD_GEN_6_ADDR;
to->len[1] = from->len;
to->ctrl = from->ctrl;
if(0 == from->len){ /* special case! in 6-byte R/W commands */
to->len[0] = 1; /* the length 0x00 assume transfering 0x100 blocks! */
}
}break;
case WRITE_6:
{
scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd);
to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10;
to->lba = B_HOST_TO_BENDIAN_INT32(((from->addr[0] & 0x1f) << 16)
| (from->addr[1] << 8) | from->addr[0]);
to->lun = (from->addr[0] & CMD_LUN) >> CMD_LUN_SHIFT;
to->control = from->ctrl;
if (from->len == 0) {
/* special case! in 6-byte R/W commands */
/* the length 0x00 assume transfering 0x100 blocks! */
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_SELECT_6:{
scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd);
if(from->opcode == MODE_SENSE_6){
case MODE_SELECT_6:
{
scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd);
if (from->opcode == MODE_SENSE_6) {
to->opcode = MODE_SENSE_10;
((scsi_cmd_mode_sense_10 *)to)->byte3 =
((scsi_cmd_mode_sense_6 *)from)->byte3;
}else
((scsi_cmd_mode_sense_10 *)to)->byte3
= ((scsi_cmd_mode_sense_6 *)from)->byte3;
} else
to->opcode = MODE_SELECT_10;
to->byte2 = from->addr[0];
to->len[1] = from->len + 4; /*TODO: hardcoded length*/
to->ctrl = from->ctrl;
}break;
default:{ /* no transformation needed */
transformed = false;
}break;
to->byte2 = from->addr[0];
to->len[1] = from->len + 4; /*TODO: hardcoded length*/
to->ctrl = from->ctrl;
}
default:
/* 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 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: 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,
uint8 len, uint8 **rcmd, uint8 *rlen)
static bool
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;
switch (from->opcode){
switch (from->opcode) {
case READ_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((transformed = transform_6_to_10(cmd, len, rcmd, rlen)) == true)
*rlen = 10;
}else
transformed = false;
}break;
case WRITE_6:
{
if (!HAS_FIXES(udi->properties, FIX_FORCE_RW_TO_6)) {
transform_6_to_10(cmd, len, rcmd, rlen);
return true;
}
break;
}
case MODE_SENSE_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((transformed = transform_6_to_10(cmd, len, rcmd, rlen)) == true)
*rlen = 10;
}else
transformed = false;
case MODE_SELECT_6:
{
if (HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)) {
transform_6_to_10(cmd, len, rcmd, rlen);
return true;
}
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 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: 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,
uint8 *cmd, uint8 len,
uint8 **rcmd, uint8 *rlen)
static bool
transform_cmd_test_unit_ready(usb_device_info *udi, uint8 *cmd, uint8 len,
uint8 **rcmd, uint8 *rlen)
{
bool transformed = false;
if(HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT)){
scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd);
memset(*rcmd, 0, *rlen);
command->opcode = START_STOP_UNIT;
command->start_loej = CMD_SSU_START;
*rlen = 6;
transformed = true;
}
return transformed;
scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd);
if (!HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT))
return false;
memset(*rcmd, 0, *rlen);
command->opcode = START_STOP_UNIT;
command->start_loej = CMD_SSU_START;
*rlen = 6;
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 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 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
scsi_transform(usb_device_info *udi, uint8 *cmd,
uint8 len, uint8 **rcmd, uint8 *rlen)
static status_t
scsi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 *rlen)
{
status_t status = B_OK;
bool transformed = false;
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
TRACE_SCSI_COMMAND(cmd, len);
switch(command->opcode){
switch (command->opcode) {
case READ_6:
case WRITE_6:
case MODE_SENSE_6:
case MODE_SELECT_6:
transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
break;
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;
default:
break;
}
if(!transformed){ /* transformation was not required */
if (!transformed) {
/* transformation was not required */
*rcmd = cmd;
*rlen = len;
}else
} else
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 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 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,
uint8 len, uint8 **rcmd, uint8 *rlen)
static status_t
rbc_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
uint8 *rlen)
{
status_t status = B_OK;
bool transformed = false;
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
TRACE_SCSI_COMMAND(cmd, len);
switch(command->opcode){
switch (command->opcode) {
case TEST_UNIT_READY:
transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen);
break;
case READ_6:
case WRITE_6: /* there are no such command in list of allowed - transform*/
transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
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 MODE_SELECT_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 VERIFY: /*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 */
*rlen = len; /*TODO: check !!! */
break;
default:
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;
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 !!!*/
if(status == B_OK)
if (status == B_OK)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
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 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 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,
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)
{
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
status_t status = B_OK;
TRACE_SCSI_COMMAND(cmd, 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){
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:
case INQUIRY:
case MODE_SELECT_10:
case MODE_SENSE_10:
case PREVENT_ALLOW_MEDIA_REMOVAL:
case READ_10:
case READ_12: /* mismatch in byte 1 */
case READ_CAPACITY: /* mismatch. no transf len defined... */
case READ_FORMAT_CAPACITY: /* TODO: check!!! */
case REQUEST_SENSE:
case SEEK_10:
case START_STOP_UNIT:
case VERIFY: /* mismatch DPO */
case WRITE_10: /* mismatch in byte 1 */
case WRITE_12: /* mismatch in byte 1 */
case WRITE_AND_VERIFY: /* mismatch byte 1 */
case PAUSE_RESUME:
case PLAY_AUDIO:
case PLAY_AUDIO_MSF:
case REWIND:
case PLAY_AUDIO_TRACK:
/* are in FreeBSD driver but no in 8070/8020 specs ...
//case REZERO_UNIT:
//case SEND_DIAGNOSTIC:
//case POSITION_TO_ELEMENT: */
case GET_CONFIGURATION:
case SYNCHRONIZE_CACHE:
case READ_BUFFER:
case READ_SUBCHANNEL:
case READ_TOC: /* some mismatch */
case READ_HEADER:
case READ_DISK_INFO:
case READ_TRACK_INFO:
case SEND_OPC:
case READ_MASTER_CUE:
case CLOSE_TR_SESSION:
case READ_BUFFER_CAP:
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 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */
memcpy(*rcmd, cmd, len); /* TODO: check!!! */
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;
default:
TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n", command->opcode);
status = B_ERROR;
break;
}
case FORMAT_UNIT:
case INQUIRY:
case MODE_SELECT_10:
case MODE_SENSE_10:
case PREVENT_ALLOW_MEDIA_REMOVAL:
case READ_10:
case READ_12: /* mismatch in byte 1 */
case READ_CAPACITY: /* mismatch. no transf len defined... */
case READ_FORMAT_CAPACITY: /* TODO: check!!! */
case REQUEST_SENSE:
case SEEK_10:
case START_STOP_UNIT:
case VERIFY: /* mismatch DPO */
case WRITE_10: /* mismatch in byte 1 */
case WRITE_12: /* mismatch in byte 1 */
case WRITE_AND_VERIFY: /* mismatch byte 1 */
case PAUSE_RESUME:
case PLAY_AUDIO:
case PLAY_AUDIO_MSF:
case REWIND:
case PLAY_AUDIO_TRACK:
/* are in FreeBSD driver but no in 8070/8020 specs ...
//case REZERO_UNIT:
//case SEND_DIAGNOSTIC:
//case POSITION_TO_ELEMENT: */
case GET_CONFIGURATION:
case SYNCHRONIZE_CACHE:
case READ_BUFFER:
case READ_SUBCHANNEL:
case READ_TOC: /* some mismatch */
case READ_HEADER:
case READ_DISK_INFO:
case READ_TRACK_INFO:
case SEND_OPC:
case READ_MASTER_CUE:
case CLOSE_TR_SESSION:
case READ_BUFFER_CAP:
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 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */
memcpy(*rcmd, cmd, len); /* TODO: check!!! */
break;
default:
TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n",
command->opcode);
status = B_ERROR;
break;
}
*rlen = ATAPI_COMMAND_LEN;
if(status == B_OK)
if (status == B_OK)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
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 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 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,
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)
{
scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
status_t status = B_OK;
TRACE_SCSI_COMMAND(cmd, len);
*rlen = ATAPI_COMMAND_LEN;
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){
case TEST_UNIT_READY:
if(transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen)){
break; // if TEST UNIT READY was transformed
}
case ERASE: /*TODO: check !!! */
case INQUIRY: /*TODO: check !!! */
case LOAD_UNLOAD: /*TODO: check !!! */
case LOCATE: /*TODO: check !!! */
case LOG_SELECT: /*TODO: check !!! */
case LOG_SENSE: /*TODO: check !!! */
case MODE_SELECT_6: /*TODO: check !!! */
case MODE_SENSE_6: /*TODO: check !!! */
case READ_6: /*TODO: check !!! */
case READ_POSITION: /*TODO: check !!! */
case REQUEST_SENSE: /*TODO: check !!! */
case REWIND: /*TODO: check !!! */
case SPACE: /*TODO: check !!! */
case WRITE_6: /*TODO: check !!! */
case WRITE_FILEMARK: /*TODO: check !!! */
*rcmd = cmd; /*TODO: check !!! */
*rlen = len;
break;
default:
TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n", command->opcode);
status = B_ERROR;
break;
}
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 ERASE: /*TODO: check !!! */
case INQUIRY: /*TODO: check !!! */
case LOAD_UNLOAD: /*TODO: check !!! */
case LOCATE: /*TODO: check !!! */
case LOG_SELECT: /*TODO: check !!! */
case LOG_SENSE: /*TODO: check !!! */
case READ_POSITION: /*TODO: check !!! */
case REQUEST_SENSE: /*TODO: check !!! */
case REWIND: /*TODO: check !!! */
case SPACE: /*TODO: check !!! */
case WRITE_FILEMARK: /*TODO: check !!! */
*rcmd = cmd; /*TODO: check !!! */
*rlen = len;
break;
default:
TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n",
command->opcode);
status = B_ERROR;
break;
}
if(status == B_OK)
if (status == B_OK)
TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
return status;
}