1618ef149SAxel Dörfler/*
2618ef149SAxel Dörfler * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
3618ef149SAxel Dörfler * Distributed under the terms of the MIT License.
457c4d430Simker *
5618ef149SAxel Dörfler * Author:
6618ef149SAxel Dörfler *		Siarzhuk Zharski <imker@gmx.li>
7b3d94504SStephan Aßmus */
8b3d94504SStephan Aßmus
9618ef149SAxel Dörfler/*! SCSI commands transformations support */
10618ef149SAxel Dörfler
11618ef149SAxel Dörfler#include "usb_scsi.h"
12b3d94504SStephan Aßmus
13618ef149SAxel Dörfler#include "device_info.h"
14618ef149SAxel Dörfler#include "transform_procs.h"
15618ef149SAxel Dörfler#include "tracing.h"
16618ef149SAxel Dörfler#include "scsi_commands.h"
1757c4d430Simker#include "settings.h"
1857c4d430Simker#include "strings.h"
19b3d94504SStephan Aßmus
2042630943SJaroslaw Pelczar#include <string.h>
2142630943SJaroslaw Pelczar
22618ef149SAxel Dörfler#define UFI_COMMAND_LEN		12
23618ef149SAxel Dörfler#define ATAPI_COMMAND_LEN	12
24618ef149SAxel Dörfler
25618ef149SAxel Dörfler
26618ef149SAxel Dörfler/*! Transforms a 6-byte command to 10-byte one if required. Transformed command
27618ef149SAxel Dörfler	is returned in rcmd parameter. In case if no transformation was performed
28618ef149SAxel Dörfler	the return buffer is untouched.
29b3d94504SStephan Aßmus
3057c4d430Simker	\param cmd: SCSI command buffer to be transformed
3157c4d430Simker	\param len: length of buffer, pointed by cmd parameter
3257c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
3357c4d430Simker	\param rlen: a place for length of transformed command
3457c4d430Simker	\return: true if transformation was performed
35b3d94504SStephan Aßmus*/
36618ef149SAxel Dörflerstatic void
37618ef149SAxel Dörflertransform_6_to_10(uint8	*cmd, uint8	len, uint8 **rcmd, uint8 *rlen)
38b3d94504SStephan Aßmus{
3957c4d430Simker	scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd;
40618ef149SAxel Dörfler
41618ef149SAxel Dörfler	*rlen = 10;
42618ef149SAxel Dörfler	memset(*rcmd, 0, 10);
43618ef149SAxel Dörfler
44618ef149SAxel Dörfler	switch (from->opcode) {
4557c4d430Simker		case READ_6:
46618ef149SAxel Dörfler		case WRITE_6:
47618ef149SAxel Dörfler		{
48618ef149SAxel Dörfler			scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd);
49618ef149SAxel Dörfler
50618ef149SAxel Dörfler			to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10;
51618ef149SAxel Dörfler			to->lba = B_HOST_TO_BENDIAN_INT32(((from->addr[0] & 0x1f) << 16)
52618ef149SAxel Dörfler				| (from->addr[1] << 8) | from->addr[0]);
53618ef149SAxel Dörfler			to->lun = (from->addr[0] & CMD_LUN) >> CMD_LUN_SHIFT;
54618ef149SAxel Dörfler			to->control = from->ctrl;
55618ef149SAxel Dörfler			if (from->len == 0) {
56618ef149SAxel Dörfler				/* special case! in 6-byte R/W commands	*/
57618ef149SAxel Dörfler				/* the length 0x00 assume transfering 0x100 blocks! */
58618ef149SAxel Dörfler				to->length = B_HOST_TO_BENDIAN_INT16((uint16)256);
59618ef149SAxel Dörfler			} else
60618ef149SAxel Dörfler				to->length = B_HOST_TO_BENDIAN_INT16((uint16)from->len);
61618ef149SAxel Dörfler		}
62618ef149SAxel Dörfler
6357c4d430Simker		case MODE_SENSE_6:
64618ef149SAxel Dörfler		case MODE_SELECT_6:
65618ef149SAxel Dörfler		{
66618ef149SAxel Dörfler			scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd);
67618ef149SAxel Dörfler
68618ef149SAxel Dörfler			if (from->opcode == MODE_SENSE_6) {
6957c4d430Simker				to->opcode = MODE_SENSE_10;
70618ef149SAxel Dörfler				((scsi_cmd_mode_sense_10 *)to)->byte3
71618ef149SAxel Dörfler					= ((scsi_cmd_mode_sense_6 *)from)->byte3;
72618ef149SAxel Dörfler			} else
7357c4d430Simker				to->opcode = MODE_SELECT_10;
74618ef149SAxel Dörfler			to->byte2 = from->addr[0];
75618ef149SAxel Dörfler			to->len[1] = from->len + 4; /*TODO: hardcoded length*/
76618ef149SAxel Dörfler			to->ctrl = from->ctrl;
77618ef149SAxel Dörfler		}
78618ef149SAxel Dörfler
79618ef149SAxel Dörfler		default:
80618ef149SAxel Dörfler			/* no transformation needed */
81618ef149SAxel Dörfler			break;
8257c4d430Simker	}
83b3d94504SStephan Aßmus}
84618ef149SAxel Dörfler
85618ef149SAxel Dörfler
86618ef149SAxel Dörfler/*!	Transforms a 6-byte command to 10-byte depending on information provided
87618ef149SAxel Dörfler	with udi object.
88618ef149SAxel Dörfler
8957c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
9057c4d430Simker	\param cmd: SCSI command buffer to be transformed
9157c4d430Simker	\param len: length of buffer, pointed by cmd parameter
9257c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
9357c4d430Simker	\param rlen: a place for length of transformed command
9457c4d430Simker	\return: true if transformation was performed
95b3d94504SStephan Aßmus*/
96618ef149SAxel Dörflerstatic bool
97618ef149SAxel Dörflertransform_cmd_6_to_10(usb_device_info *udi, uint8 *cmd, uint8 len,
98618ef149SAxel Dörfler	uint8 **rcmd, uint8 *rlen)
99b3d94504SStephan Aßmus{
10057c4d430Simker	scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd;
101618ef149SAxel Dörfler
102618ef149SAxel Dörfler	switch (from->opcode) {
10357c4d430Simker		case READ_6:
104618ef149SAxel Dörfler		case WRITE_6:
105618ef149SAxel Dörfler		{
106618ef149SAxel Dörfler			if (!HAS_FIXES(udi->properties, FIX_FORCE_RW_TO_6)) {
107618ef149SAxel Dörfler				transform_6_to_10(cmd, len, rcmd, rlen);
108618ef149SAxel Dörfler				return true;
109618ef149SAxel Dörfler			}
110618ef149SAxel Dörfler			break;
111618ef149SAxel Dörfler		}
112618ef149SAxel Dörfler
11357c4d430Simker		case MODE_SENSE_6:
114618ef149SAxel Dörfler		case MODE_SELECT_6:
115618ef149SAxel Dörfler		{
116618ef149SAxel Dörfler			if (HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)) {
117618ef149SAxel Dörfler				transform_6_to_10(cmd, len, rcmd, rlen);
118618ef149SAxel Dörfler				return true;
119618ef149SAxel Dörfler			}
120618ef149SAxel Dörfler			break;
12157c4d430Simker		}
12257c4d430Simker	}
123618ef149SAxel Dörfler
124618ef149SAxel Dörfler	return false;
125b3d94504SStephan Aßmus}
126618ef149SAxel Dörfler
127618ef149SAxel Dörfler
128618ef149SAxel Dörfler/*!	Transforms a TEST_UNIT_COMAND SCSI command to START_STOP_UNIT one depending
129618ef149SAxel Dörfler	on properties provided with udi object.
130618ef149SAxel Dörfler
13157c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
13257c4d430Simker	\param cmd: SCSI command buffer to be transformed
13357c4d430Simker	\param len: length of buffer, pointed by cmd parameter
13457c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
13557c4d430Simker	\param rlen: a place for length of transformed command
13657c4d430Simker	\return: true if transformation was performed
137b3d94504SStephan Aßmus*/
138618ef149SAxel Dörflerstatic bool
139618ef149SAxel Dörflertransform_cmd_test_unit_ready(usb_device_info *udi, uint8 *cmd, uint8 len,
140618ef149SAxel Dörfler	uint8 **rcmd, uint8	*rlen)
141b3d94504SStephan Aßmus{
142618ef149SAxel Dörfler	scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd);
143618ef149SAxel Dörfler
144618ef149SAxel Dörfler	if (!HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT))
145618ef149SAxel Dörfler		return false;
146618ef149SAxel Dörfler
147618ef149SAxel Dörfler	memset(*rcmd, 0, *rlen);
148618ef149SAxel Dörfler	command->opcode = START_STOP_UNIT;
149618ef149SAxel Dörfler	command->start_loej = CMD_SSU_START;
150618ef149SAxel Dörfler	*rlen = 6;
151618ef149SAxel Dörfler
152618ef149SAxel Dörfler	return true;
153b3d94504SStephan Aßmus}
154618ef149SAxel Dörfler
155618ef149SAxel Dörfler
156618ef149SAxel Dörfler//	#pragma mark -
157618ef149SAxel Dörfler
158618ef149SAxel Dörfler
159618ef149SAxel Dörfler/*!	This is the "transformation procedure" for transparent SCSI (0x06) USB
160618ef149SAxel Dörfler	subclass. It performs all SCSI commands transformations required by this
161618ef149SAxel Dörfler	protocol. Additionally it tries to make some workarounds for "broken" USB
162618ef149SAxel Dörfler	devices. If no transformation was performed resulting command buffer
163618ef149SAxel Dörfler	points to original one.
164618ef149SAxel Dörfler
16557c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
16657c4d430Simker	\param cmd: SCSI command buffer to be transformed
16757c4d430Simker	\param len: length of buffer, pointed by cmd parameter
16857c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
16957c4d430Simker	\param rlen: a place for length of transformed command
17057c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
171b3d94504SStephan Aßmus*/
172618ef149SAxel Dörflerstatic status_t
173618ef149SAxel Dörflerscsi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
174618ef149SAxel Dörfler	uint8 *rlen)
175b3d94504SStephan Aßmus{
17657c4d430Simker	bool transformed = false;
17757c4d430Simker	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
17857c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
179618ef149SAxel Dörfler
180618ef149SAxel Dörfler	switch (command->opcode) {
18157c4d430Simker		case READ_6:
18257c4d430Simker		case WRITE_6:
18357c4d430Simker		case MODE_SENSE_6:
18457c4d430Simker		case MODE_SELECT_6:
18557c4d430Simker			transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
18657c4d430Simker			break;
187618ef149SAxel Dörfler
18857c4d430Simker		case TEST_UNIT_READY:
189618ef149SAxel Dörfler			transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd,
190618ef149SAxel Dörfler				rlen);
19157c4d430Simker			break;
192618ef149SAxel Dörfler
193618ef149SAxel Dörfler		default:
194618ef149SAxel Dörfler			break;
19557c4d430Simker	}
196618ef149SAxel Dörfler
197618ef149SAxel Dörfler	if (!transformed) {
198618ef149SAxel Dörfler		/* transformation was not required */
19957c4d430Simker		*rcmd = cmd;
20057c4d430Simker		*rlen = len;
201618ef149SAxel Dörfler	} else
20257c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
203618ef149SAxel Dörfler
204618ef149SAxel Dörfler	return B_OK;
205b3d94504SStephan Aßmus}
206618ef149SAxel Dörfler
207618ef149SAxel Dörfler
208618ef149SAxel Dörfler/*!	This is the "transformation procedure" for RBC USB subclass (0x01). It
209618ef149SAxel Dörfler	performs all SCSI commands transformations required by this protocol.
210618ef149SAxel Dörfler	Additionally it tries to make some workarounds for "broken" USB devices.
211618ef149SAxel Dörfler	If no transformation was performed resulting command buffer points to
212618ef149SAxel Dörfler	original one.
213618ef149SAxel Dörfler
21457c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
21557c4d430Simker	\param cmd: SCSI command buffer to be transformed
21657c4d430Simker	\param len: length of buffer, pointed by cmd parameter
21757c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
21857c4d430Simker	\param rlen: a place for length of transformed command
21957c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
220b3d94504SStephan Aßmus*/
221618ef149SAxel Dörflerstatic status_t
222618ef149SAxel Dörflerrbc_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
223618ef149SAxel Dörfler	uint8 *rlen)
224b3d94504SStephan Aßmus{
22557c4d430Simker	bool transformed = false;
22657c4d430Simker	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
22757c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
228618ef149SAxel Dörfler
229618ef149SAxel Dörfler	switch (command->opcode) {
23057c4d430Simker		case TEST_UNIT_READY:
23157c4d430Simker			transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen);
23257c4d430Simker			break;
233618ef149SAxel Dörfler
23457c4d430Simker		case READ_6:
23557c4d430Simker		case WRITE_6: /* there are no such command in list of allowed - transform*/
23657c4d430Simker			transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
23757c4d430Simker			break;
238618ef149SAxel Dörfler
239618ef149SAxel Dörfler		/* TODO: all following ones are not checked against specs !!!*/
240618ef149SAxel Dörfler		case FORMAT_UNIT:
24157c4d430Simker		case INQUIRY: /*TODO: check !!! */
24257c4d430Simker		case MODE_SELECT_6: /*TODO: check !!! */
24357c4d430Simker		case MODE_SENSE_6: /*TODO: check !!! */
24457c4d430Simker		case PERSISTENT_RESERVE_IN: /*TODO: check !!! */
24557c4d430Simker		case PERSISTENT_RESERVE_OUT: /*TODO: check !!! */
24657c4d430Simker		case PREVENT_ALLOW_MEDIA_REMOVAL: /*TODO: check !!! */
24757c4d430Simker		case READ_10: /*TODO: check !!! */
24857c4d430Simker		case READ_CAPACITY: /*TODO: check !!! */
24957c4d430Simker		case RELEASE_6: /*TODO: check !!! */
25057c4d430Simker		case REQUEST_SENSE: /*TODO: check !!! */
25157c4d430Simker		case RESERVE_6: /*TODO: check !!! */
25257c4d430Simker		case START_STOP_UNIT: /*TODO: check !!! */
25357c4d430Simker		case SYNCHRONIZE_CACHE: /*TODO: check !!! */
25457c4d430Simker		case VERIFY: /*TODO: check !!! */
25557c4d430Simker		case WRITE_10: /*TODO: check !!! */
256618ef149SAxel Dörfler		case WRITE_BUFFER: /*TODO Check correctnes of such translation!*/
25757c4d430Simker			*rcmd = cmd;		/* No need to copy */
25857c4d430Simker			*rlen = len;	/*TODO: check !!! */
259618ef149SAxel Dörfler			break;
260618ef149SAxel Dörfler
26157c4d430Simker		default:
26257c4d430Simker			TRACE_ALWAYS("An unsupported RBC command: %08x\n", command->opcode);
263618ef149SAxel Dörfler			return B_ERROR;
26457c4d430Simker	}
265618ef149SAxel Dörfler
266618ef149SAxel Dörfler	if (transformed)
26757c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
268618ef149SAxel Dörfler
269618ef149SAxel Dörfler	return B_OK;
270b3d94504SStephan Aßmus}
271618ef149SAxel Dörfler
272618ef149SAxel Dörfler
273618ef149SAxel Dörfler/*!	This is the "transformation procedure" for UFI USB subclass (0x04). It
274618ef149SAxel Dörfler	performs all SCSI commands transformations required by this protocol.
275618ef149SAxel Dörfler	Additionally it tries to make some workarounds for "broken" USB devices.
276618ef149SAxel Dörfler	If no transformation was performed resulting command buffer points to
277618ef149SAxel Dörfler	the original one.
278618ef149SAxel Dörfler
27957c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
28057c4d430Simker	\param cmd: SCSI command buffer to be transformed
28157c4d430Simker	\param len: length of buffer, pointed by cmd parameter
28257c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
28357c4d430Simker	\param rlen: a place for length of transformed command
28457c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
285b3d94504SStephan Aßmus*/
286618ef149SAxel Dörflerstatic status_t
287618ef149SAxel Dörflerufi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
288618ef149SAxel Dörfler	uint8 *rlen)
289b3d94504SStephan Aßmus{
290618ef149SAxel Dörfler	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
29157c4d430Simker	status_t status = B_OK;
292618ef149SAxel Dörfler
29357c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
29457c4d430Simker	memset(*rcmd, 0, UFI_COMMAND_LEN);
295618ef149SAxel Dörfler
296618ef149SAxel Dörfler	switch (command->opcode) {
297618ef149SAxel Dörfler		case READ_6:
298618ef149SAxel Dörfler		case WRITE_6:
299618ef149SAxel Dörfler		case MODE_SENSE_6:
300618ef149SAxel Dörfler		case MODE_SELECT_6:
301618ef149SAxel Dörfler			// TODO: not transform_cmd_*()?
302618ef149SAxel Dörfler			transform_6_to_10(cmd, len, rcmd, rlen);
303618ef149SAxel Dörfler			break;
304618ef149SAxel Dörfler		case TEST_UNIT_READY:
305618ef149SAxel Dörfler			if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
306618ef149SAxel Dörfler				break; /* if TEST UNIT READY was transformed*/
307618ef149SAxel Dörfler		case FORMAT_UNIT:	/* TODO: mismatch */
308618ef149SAxel Dörfler		case INQUIRY:
309618ef149SAxel Dörfler		case START_STOP_UNIT:
310618ef149SAxel Dörfler		case MODE_SELECT_10:
311618ef149SAxel Dörfler		case MODE_SENSE_10:
312618ef149SAxel Dörfler		case PREVENT_ALLOW_MEDIA_REMOVAL:
313618ef149SAxel Dörfler		case READ_10:
314618ef149SAxel Dörfler		case READ_12:
315618ef149SAxel Dörfler		case READ_CAPACITY:
316618ef149SAxel Dörfler		case READ_FORMAT_CAPACITY: /* TODO: not in the SCSI-2 specs */
317618ef149SAxel Dörfler		case REQUEST_SENSE:
318618ef149SAxel Dörfler		case REZERO_UNIT:
319618ef149SAxel Dörfler		case SEEK_10:
320618ef149SAxel Dörfler		case SEND_DIAGNOSTICS: /* TODO: parameter list len mismatch */
321618ef149SAxel Dörfler		case VERIFY:
322618ef149SAxel Dörfler		case WRITE_10:
323618ef149SAxel Dörfler		case WRITE_12: /* TODO: EBP. mismatch */
324618ef149SAxel Dörfler		case WRITE_AND_VERIFY:
325618ef149SAxel Dörfler			memcpy(*rcmd, cmd, len);
326618ef149SAxel Dörfler			/*TODO what about control? ignored in UFI?*/
327618ef149SAxel Dörfler			break;
328618ef149SAxel Dörfler		default:
329618ef149SAxel Dörfler			TRACE_ALWAYS("An unsupported UFI command: %08x\n",
330618ef149SAxel Dörfler				command->opcode);
331618ef149SAxel Dörfler			status = B_ERROR;
332618ef149SAxel Dörfler			break;
33357c4d430Simker	}
334618ef149SAxel Dörfler
33557c4d430Simker	*rlen = UFI_COMMAND_LEN; /* override any value set in transform funcs !!!*/
336618ef149SAxel Dörfler
337618ef149SAxel Dörfler	if (status == B_OK)
33857c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
339618ef149SAxel Dörfler
34057c4d430Simker	return status;
341b3d94504SStephan Aßmus}
342618ef149SAxel Dörfler
343618ef149SAxel Dörfler
344618ef149SAxel Dörfler/*!	This is the "transformation procedure" for SFF8020I and SFF8070I
345618ef149SAxel Dörfler	USB subclassses (0x02 and 0x05). It performs all SCSI commands
346618ef149SAxel Dörfler	transformations required by this protocol. Additionally it tries to make
347618ef149SAxel Dörfler	some workarounds for "broken" USB devices. If no transformation was
348618ef149SAxel Dörfler	performed resulting command buffer points to the original one.
349618ef149SAxel Dörfler
35057c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
35157c4d430Simker	\param cmd: SCSI command buffer to be transformed
35257c4d430Simker	\param len: length of buffer, pointed by cmd parameter
35357c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
35457c4d430Simker	\param rlen: a place for length of transformed command
35557c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
356b3d94504SStephan Aßmus*/
357618ef149SAxel Dörflerstatic status_t
358618ef149SAxel Dörfleratapi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
359618ef149SAxel Dörfler	uint8 *rlen)
360b3d94504SStephan Aßmus{
361618ef149SAxel Dörfler	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
36257c4d430Simker	status_t status = B_OK;
363618ef149SAxel Dörfler
36457c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
36557c4d430Simker	memset(*rcmd, 0, ATAPI_COMMAND_LEN);
366618ef149SAxel Dörfler
367618ef149SAxel Dörfler	switch (command->opcode) {
368618ef149SAxel Dörfler		case READ_6:
369618ef149SAxel Dörfler		case WRITE_6:
370618ef149SAxel Dörfler		case MODE_SENSE_6:
371618ef149SAxel Dörfler		case MODE_SELECT_6:
372618ef149SAxel Dörfler			// TODO: not transform_cmd_*()?
3738e185f27SAxel Dörfler			transform_6_to_10(cmd, len, rcmd, rlen);
374618ef149SAxel Dörfler			break;
375618ef149SAxel Dörfler		case TEST_UNIT_READY:
376618ef149SAxel Dörfler			if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
37757c4d430Simker				break;
378618ef149SAxel Dörfler		case FORMAT_UNIT:
379618ef149SAxel Dörfler		case INQUIRY:
380618ef149SAxel Dörfler		case MODE_SELECT_10:
381618ef149SAxel Dörfler		case MODE_SENSE_10:
382618ef149SAxel Dörfler		case PREVENT_ALLOW_MEDIA_REMOVAL:
383618ef149SAxel Dörfler		case READ_10:
384618ef149SAxel Dörfler		case READ_12: /* mismatch in byte 1 */
385618ef149SAxel Dörfler		case READ_CAPACITY: /* mismatch. no transf len defined... */
386618ef149SAxel Dörfler		case READ_FORMAT_CAPACITY: /* TODO: check!!! */
387618ef149SAxel Dörfler		case REQUEST_SENSE:
388618ef149SAxel Dörfler		case SEEK_10:
389618ef149SAxel Dörfler		case START_STOP_UNIT:
390618ef149SAxel Dörfler		case VERIFY: /* mismatch DPO */
391618ef149SAxel Dörfler		case WRITE_10: /* mismatch in byte 1 */
392618ef149SAxel Dörfler		case WRITE_12: /* mismatch in byte 1 */
393618ef149SAxel Dörfler		case WRITE_AND_VERIFY: /* mismatch byte 1 */
394618ef149SAxel Dörfler		case PAUSE_RESUME:
395618ef149SAxel Dörfler		case PLAY_AUDIO:
396618ef149SAxel Dörfler		case PLAY_AUDIO_MSF:
397618ef149SAxel Dörfler		case REWIND:
398618ef149SAxel Dörfler		case PLAY_AUDIO_TRACK:
399618ef149SAxel Dörfler		/* are in FreeBSD driver but no in 8070/8020 specs ...
400618ef149SAxel Dörfler		//case REZERO_UNIT:
401618ef149SAxel Dörfler		//case SEND_DIAGNOSTIC:
402618ef149SAxel Dörfler		//case POSITION_TO_ELEMENT:	*/
403618ef149SAxel Dörfler		case GET_CONFIGURATION:
404618ef149SAxel Dörfler		case SYNCHRONIZE_CACHE:
405618ef149SAxel Dörfler		case READ_BUFFER:
406618ef149SAxel Dörfler	 	case READ_SUBCHANNEL:
407618ef149SAxel Dörfler		case READ_TOC: /* some mismatch */
408618ef149SAxel Dörfler		case READ_HEADER:
409618ef149SAxel Dörfler		case READ_DISK_INFO:
410618ef149SAxel Dörfler		case READ_TRACK_INFO:
411618ef149SAxel Dörfler		case SEND_OPC:
412618ef149SAxel Dörfler		case READ_MASTER_CUE:
413618ef149SAxel Dörfler		case CLOSE_TR_SESSION:
414618ef149SAxel Dörfler		case READ_BUFFER_CAP:
415618ef149SAxel Dörfler		case SEND_CUE_SHEET:
416618ef149SAxel Dörfler		case BLANK:
417618ef149SAxel Dörfler		case EXCHANGE_MEDIUM:
418618ef149SAxel Dörfler		case READ_DVD_STRUCTURE:
419618ef149SAxel Dörfler		case SET_CD_SPEED:
420618ef149SAxel Dörfler		case DVD_REPORT_KEY:
421618ef149SAxel Dörfler		case DVD_SEND_KEY:
422618ef149SAxel Dörfler		//case 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */
423618ef149SAxel Dörfler			memcpy(*rcmd, cmd, len); /* TODO: check!!! */
424618ef149SAxel Dörfler			break;
425618ef149SAxel Dörfler
426618ef149SAxel Dörfler		default:
427618ef149SAxel Dörfler			TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n",
428618ef149SAxel Dörfler				command->opcode);
429618ef149SAxel Dörfler			status = B_ERROR;
430618ef149SAxel Dörfler			break;
43157c4d430Simker	}
432618ef149SAxel Dörfler
43357c4d430Simker	*rlen = ATAPI_COMMAND_LEN;
434618ef149SAxel Dörfler
435618ef149SAxel Dörfler	if (status == B_OK)
43657c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
437618ef149SAxel Dörfler
43857c4d430Simker	return status;
439b3d94504SStephan Aßmus}
440618ef149SAxel Dörfler
441618ef149SAxel Dörfler
442618ef149SAxel Dörfler/*!	This is the "transformation procedure" for QIC157 USB subclass (0x03). It
443618ef149SAxel Dörfler	performs all SCSI commands transformations required by this protocol.
444618ef149SAxel Dörfler	Additionally it tries to make some workarounds for "broken" USB devices.
445618ef149SAxel Dörfler	If no transformation was performed the resulting command buffer points to
446618ef149SAxel Dörfler	the original one.
447618ef149SAxel Dörfler
44857c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
44957c4d430Simker	\param cmd: SCSI command buffer to be transformed
45057c4d430Simker	\param len: length of buffer, pointed by cmd parameter
45157c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
45257c4d430Simker	\param rlen: a place for length of transformed command
45357c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
454b3d94504SStephan Aßmus*/
455618ef149SAxel Dörflerstatic status_t
456618ef149SAxel Dörflerqic157_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
457618ef149SAxel Dörfler	uint8 *rlen)
458b3d94504SStephan Aßmus{
459618ef149SAxel Dörfler	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
46057c4d430Simker	status_t status = B_OK;
461618ef149SAxel Dörfler
46257c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
46357c4d430Simker	*rlen = ATAPI_COMMAND_LEN;
46457c4d430Simker	memset(*rcmd, 0, *rlen);
465618ef149SAxel Dörfler
466618ef149SAxel Dörfler	switch (command->opcode) {
467618ef149SAxel Dörfler		case READ_6:
468618ef149SAxel Dörfler		case WRITE_6:
469618ef149SAxel Dörfler		case MODE_SENSE_6:
470618ef149SAxel Dörfler		case MODE_SELECT_6:
471618ef149SAxel Dörfler			// TODO: not transform_cmd_*()?
472618ef149SAxel Dörfler			transform_6_to_10(cmd, len, rcmd, rlen);
473618ef149SAxel Dörfler			break;
474618ef149SAxel Dörfler		case TEST_UNIT_READY:
475618ef149SAxel Dörfler			if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
476618ef149SAxel Dörfler				break; // if TEST UNIT READY was transformed
477618ef149SAxel Dörfler		case ERASE: /*TODO: check !!! */
478618ef149SAxel Dörfler		case INQUIRY: /*TODO: check !!! */
479618ef149SAxel Dörfler		case LOAD_UNLOAD: /*TODO: check !!! */
480618ef149SAxel Dörfler		case LOCATE: /*TODO: check !!! */
481618ef149SAxel Dörfler		case LOG_SELECT: /*TODO: check !!! */
482618ef149SAxel Dörfler		case LOG_SENSE: /*TODO: check !!! */
483618ef149SAxel Dörfler		case READ_POSITION: /*TODO: check !!! */
484618ef149SAxel Dörfler		case REQUEST_SENSE: /*TODO: check !!! */
485618ef149SAxel Dörfler		case REWIND: /*TODO: check !!! */
486618ef149SAxel Dörfler		case SPACE: /*TODO: check !!! */
487618ef149SAxel Dörfler		case WRITE_FILEMARK: /*TODO: check !!! */
488618ef149SAxel Dörfler			*rcmd = cmd; /*TODO: check !!! */
489618ef149SAxel Dörfler			*rlen = len;
490618ef149SAxel Dörfler			break;
491618ef149SAxel Dörfler		default:
492618ef149SAxel Dörfler			TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n",
493618ef149SAxel Dörfler				command->opcode);
494618ef149SAxel Dörfler			status = B_ERROR;
495618ef149SAxel Dörfler			break;
49657c4d430Simker	}
497618ef149SAxel Dörfler
498618ef149SAxel Dörfler	if (status == B_OK)
49957c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
500618ef149SAxel Dörfler
50157c4d430Simker	return status;
502b3d94504SStephan Aßmus}
503b3d94504SStephan Aßmus
504b3d94504SStephan Aßmus
505b3d94504SStephan Aßmustransform_module_info scsi_transform_m = {
50657c4d430Simker	{0, 0, 0}, /* this is not a real kernel module - just interface */
507