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
20618ef149SAxel Dörfler#define UFI_COMMAND_LEN		12
21618ef149SAxel Dörfler#define ATAPI_COMMAND_LEN	12
22618ef149SAxel Dörfler
23618ef149SAxel Dörfler
24618ef149SAxel Dörfler/*! Transforms a 6-byte command to 10-byte one if required. Transformed command
25618ef149SAxel Dörfler	is returned in rcmd parameter. In case if no transformation was performed
26618ef149SAxel Dörfler	the return buffer is untouched.
27b3d94504SStephan Aßmus
2857c4d430Simker	\param cmd: SCSI command buffer to be transformed
2957c4d430Simker	\param len: length of buffer, pointed by cmd parameter
3057c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
3157c4d430Simker	\param rlen: a place for length of transformed command
3257c4d430Simker	\return: true if transformation was performed
33b3d94504SStephan Aßmus*/
34618ef149SAxel Dörflerstatic void
35618ef149SAxel Dörflertransform_6_to_10(uint8	*cmd, uint8	len, uint8 **rcmd, uint8 *rlen)
36b3d94504SStephan Aßmus{
3757c4d430Simker	scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd;
38618ef149SAxel Dörfler
39618ef149SAxel Dörfler	*rlen = 10;
40618ef149SAxel Dörfler	memset(*rcmd, 0, 10);
41618ef149SAxel Dörfler
42618ef149SAxel Dörfler	switch (from->opcode) {
4357c4d430Simker		case READ_6:
44618ef149SAxel Dörfler		case WRITE_6:
45618ef149SAxel Dörfler		{
46618ef149SAxel Dörfler			scsi_cmd_rw_10 *to = (scsi_cmd_rw_10 *)(*rcmd);
47618ef149SAxel Dörfler
48618ef149SAxel Dörfler			to->opcode = (from->opcode == READ_6) ? READ_10 : WRITE_10;
49618ef149SAxel Dörfler			to->lba = B_HOST_TO_BENDIAN_INT32(((from->addr[0] & 0x1f) << 16)
50618ef149SAxel Dörfler				| (from->addr[1] << 8) | from->addr[0]);
51618ef149SAxel Dörfler			to->lun = (from->addr[0] & CMD_LUN) >> CMD_LUN_SHIFT;
52618ef149SAxel Dörfler			to->control = from->ctrl;
53618ef149SAxel Dörfler			if (from->len == 0) {
54618ef149SAxel Dörfler				/* special case! in 6-byte R/W commands	*/
55618ef149SAxel Dörfler				/* the length 0x00 assume transfering 0x100 blocks! */
56618ef149SAxel Dörfler				to->length = B_HOST_TO_BENDIAN_INT16((uint16)256);
57618ef149SAxel Dörfler			} else
58618ef149SAxel Dörfler				to->length = B_HOST_TO_BENDIAN_INT16((uint16)from->len);
59618ef149SAxel Dörfler		}
60618ef149SAxel Dörfler
6157c4d430Simker		case MODE_SENSE_6:
62618ef149SAxel Dörfler		case MODE_SELECT_6:
63618ef149SAxel Dörfler		{
64618ef149SAxel Dörfler			scsi_cmd_generic_10 *to = (scsi_cmd_generic_10 *)(*rcmd);
65618ef149SAxel Dörfler
66618ef149SAxel Dörfler			if (from->opcode == MODE_SENSE_6) {
6757c4d430Simker				to->opcode = MODE_SENSE_10;
68618ef149SAxel Dörfler				((scsi_cmd_mode_sense_10 *)to)->byte3
69618ef149SAxel Dörfler					= ((scsi_cmd_mode_sense_6 *)from)->byte3;
70618ef149SAxel Dörfler			} else
7157c4d430Simker				to->opcode = MODE_SELECT_10;
72618ef149SAxel Dörfler			to->byte2 = from->addr[0];
73618ef149SAxel Dörfler			to->len[1] = from->len + 4; /*TODO: hardcoded length*/
74618ef149SAxel Dörfler			to->ctrl = from->ctrl;
75618ef149SAxel Dörfler		}
76618ef149SAxel Dörfler
77618ef149SAxel Dörfler		default:
78618ef149SAxel Dörfler			/* no transformation needed */
79618ef149SAxel Dörfler			break;
8057c4d430Simker	}
81b3d94504SStephan Aßmus}
82618ef149SAxel Dörfler
83618ef149SAxel Dörfler
84618ef149SAxel Dörfler/*!	Transforms a 6-byte command to 10-byte depending on information provided
85618ef149SAxel Dörfler	with udi object.
86618ef149SAxel Dörfler
8757c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
8857c4d430Simker	\param cmd: SCSI command buffer to be transformed
8957c4d430Simker	\param len: length of buffer, pointed by cmd parameter
9057c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
9157c4d430Simker	\param rlen: a place for length of transformed command
9257c4d430Simker	\return: true if transformation was performed
93b3d94504SStephan Aßmus*/
94618ef149SAxel Dörflerstatic bool
95618ef149SAxel Dörflertransform_cmd_6_to_10(usb_device_info *udi, uint8 *cmd, uint8 len,
96618ef149SAxel Dörfler	uint8 **rcmd, uint8 *rlen)
97b3d94504SStephan Aßmus{
9857c4d430Simker	scsi_cmd_generic_6 *from = (scsi_cmd_generic_6 *)cmd;
99618ef149SAxel Dörfler
100618ef149SAxel Dörfler	switch (from->opcode) {
10157c4d430Simker		case READ_6:
102618ef149SAxel Dörfler		case WRITE_6:
103618ef149SAxel Dörfler		{
104618ef149SAxel Dörfler			if (!HAS_FIXES(udi->properties, FIX_FORCE_RW_TO_6)) {
105618ef149SAxel Dörfler				transform_6_to_10(cmd, len, rcmd, rlen);
106618ef149SAxel Dörfler				return true;
107618ef149SAxel Dörfler			}
108618ef149SAxel Dörfler			break;
109618ef149SAxel Dörfler		}
110618ef149SAxel Dörfler
11157c4d430Simker		case MODE_SENSE_6:
112618ef149SAxel Dörfler		case MODE_SELECT_6:
113618ef149SAxel Dörfler		{
114618ef149SAxel Dörfler			if (HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)) {
115618ef149SAxel Dörfler				transform_6_to_10(cmd, len, rcmd, rlen);
116618ef149SAxel Dörfler				return true;
117618ef149SAxel Dörfler			}
118618ef149SAxel Dörfler			break;
11957c4d430Simker		}
12057c4d430Simker	}
121618ef149SAxel Dörfler
122618ef149SAxel Dörfler	return false;
123b3d94504SStephan Aßmus}
124618ef149SAxel Dörfler
125618ef149SAxel Dörfler
126618ef149SAxel Dörfler/*!	Transforms a TEST_UNIT_COMAND SCSI command to START_STOP_UNIT one depending
127618ef149SAxel Dörfler	on properties provided with udi object.
128618ef149SAxel Dörfler
12957c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
13057c4d430Simker	\param cmd: SCSI command buffer to be transformed
13157c4d430Simker	\param len: length of buffer, pointed by cmd parameter
13257c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
13357c4d430Simker	\param rlen: a place for length of transformed command
13457c4d430Simker	\return: true if transformation was performed
135b3d94504SStephan Aßmus*/
136618ef149SAxel Dörflerstatic bool
137618ef149SAxel Dörflertransform_cmd_test_unit_ready(usb_device_info *udi, uint8 *cmd, uint8 len,
138618ef149SAxel Dörfler	uint8 **rcmd, uint8	*rlen)
139b3d94504SStephan Aßmus{
140618ef149SAxel Dörfler	scsi_cmd_start_stop_unit *command = (scsi_cmd_start_stop_unit *)(*rcmd);
141618ef149SAxel Dörfler
142618ef149SAxel Dörfler	if (!HAS_FIXES(udi->properties, FIX_TRANS_TEST_UNIT))
143618ef149SAxel Dörfler		return false;
144618ef149SAxel Dörfler
145618ef149SAxel Dörfler	memset(*rcmd, 0, *rlen);
146618ef149SAxel Dörfler	command->opcode = START_STOP_UNIT;
147618ef149SAxel Dörfler	command->start_loej = CMD_SSU_START;
148618ef149SAxel Dörfler	*rlen = 6;
149618ef149SAxel Dörfler
150618ef149SAxel Dörfler	return true;
151b3d94504SStephan Aßmus}
152618ef149SAxel Dörfler
153618ef149SAxel Dörfler
154618ef149SAxel Dörfler//	#pragma mark -
155618ef149SAxel Dörfler
156618ef149SAxel Dörfler
157618ef149SAxel Dörfler/*!	This is the "transformation procedure" for transparent SCSI (0x06) USB
158618ef149SAxel Dörfler	subclass. It performs all SCSI commands transformations required by this
159618ef149SAxel Dörfler	protocol. Additionally it tries to make some workarounds for "broken" USB
160618ef149SAxel Dörfler	devices. If no transformation was performed resulting command buffer
161618ef149SAxel Dörfler	points to original one.
162618ef149SAxel Dörfler
16357c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
16457c4d430Simker	\param cmd: SCSI command buffer to be transformed
16557c4d430Simker	\param len: length of buffer, pointed by cmd parameter
16657c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
16757c4d430Simker	\param rlen: a place for length of transformed command
16857c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
169b3d94504SStephan Aßmus*/
170618ef149SAxel Dörflerstatic status_t
171618ef149SAxel Dörflerscsi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
172618ef149SAxel Dörfler	uint8 *rlen)
173b3d94504SStephan Aßmus{
17457c4d430Simker	bool transformed = false;
17557c4d430Simker	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
17657c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
177618ef149SAxel Dörfler
178618ef149SAxel Dörfler	switch (command->opcode) {
17957c4d430Simker		case READ_6:
18057c4d430Simker		case WRITE_6:
18157c4d430Simker		case MODE_SENSE_6:
18257c4d430Simker		case MODE_SELECT_6:
18357c4d430Simker			transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
18457c4d430Simker			break;
185618ef149SAxel Dörfler
18657c4d430Simker		case TEST_UNIT_READY:
187618ef149SAxel Dörfler			transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd,
188618ef149SAxel Dörfler				rlen);
18957c4d430Simker			break;
190618ef149SAxel Dörfler
191618ef149SAxel Dörfler		default:
192618ef149SAxel Dörfler			break;
19357c4d430Simker	}
194618ef149SAxel Dörfler
195618ef149SAxel Dörfler	if (!transformed) {
196618ef149SAxel Dörfler		/* transformation was not required */
19757c4d430Simker		*rcmd = cmd;
19857c4d430Simker		*rlen = len;
199618ef149SAxel Dörfler	} else
20057c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
201618ef149SAxel Dörfler
202618ef149SAxel Dörfler	return B_OK;
203b3d94504SStephan Aßmus}
204618ef149SAxel Dörfler
205618ef149SAxel Dörfler
206618ef149SAxel Dörfler/*!	This is the "transformation procedure" for RBC USB subclass (0x01). It
207618ef149SAxel Dörfler	performs all SCSI commands transformations required by this protocol.
208618ef149SAxel Dörfler	Additionally it tries to make some workarounds for "broken" USB devices.
209618ef149SAxel Dörfler	If no transformation was performed resulting command buffer points to
210618ef149SAxel Dörfler	original one.
211618ef149SAxel Dörfler
21257c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
21357c4d430Simker	\param cmd: SCSI command buffer to be transformed
21457c4d430Simker	\param len: length of buffer, pointed by cmd parameter
21557c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
21657c4d430Simker	\param rlen: a place for length of transformed command
21757c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
218b3d94504SStephan Aßmus*/
219618ef149SAxel Dörflerstatic status_t
220618ef149SAxel Dörflerrbc_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
221618ef149SAxel Dörfler	uint8 *rlen)
222b3d94504SStephan Aßmus{
22357c4d430Simker	bool transformed = false;
22457c4d430Simker	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
22557c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
226618ef149SAxel Dörfler
227618ef149SAxel Dörfler	switch (command->opcode) {
22857c4d430Simker		case TEST_UNIT_READY:
22957c4d430Simker			transformed = transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen);
23057c4d430Simker			break;
231618ef149SAxel Dörfler
23257c4d430Simker		case READ_6:
23357c4d430Simker		case WRITE_6: /* there are no such command in list of allowed - transform*/
23457c4d430Simker			transformed = transform_cmd_6_to_10(udi, cmd, len, rcmd, rlen);
23557c4d430Simker			break;
236618ef149SAxel Dörfler
237618ef149SAxel Dörfler		/* TODO: all following ones are not checked against specs !!!*/
238618ef149SAxel Dörfler		case FORMAT_UNIT:
23957c4d430Simker		case INQUIRY: /*TODO: check !!! */
24057c4d430Simker		case MODE_SELECT_6: /*TODO: check !!! */
24157c4d430Simker		case MODE_SENSE_6: /*TODO: check !!! */
24257c4d430Simker		case PERSISTENT_RESERVE_IN: /*TODO: check !!! */
24357c4d430Simker		case PERSISTENT_RESERVE_OUT: /*TODO: check !!! */
24457c4d430Simker		case PREVENT_ALLOW_MEDIA_REMOVAL: /*TODO: check !!! */
24557c4d430Simker		case READ_10: /*TODO: check !!! */
24657c4d430Simker		case READ_CAPACITY: /*TODO: check !!! */
24757c4d430Simker		case RELEASE_6: /*TODO: check !!! */
24857c4d430Simker		case REQUEST_SENSE: /*TODO: check !!! */
24957c4d430Simker		case RESERVE_6: /*TODO: check !!! */
25057c4d430Simker		case START_STOP_UNIT: /*TODO: check !!! */
25157c4d430Simker		case SYNCHRONIZE_CACHE: /*TODO: check !!! */
25257c4d430Simker		case VERIFY: /*TODO: check !!! */
25357c4d430Simker		case WRITE_10: /*TODO: check !!! */
254618ef149SAxel Dörfler		case WRITE_BUFFER: /*TODO Check correctnes of such translation!*/
25557c4d430Simker			*rcmd = cmd;		/* No need to copy */
25657c4d430Simker			*rlen = len;	/*TODO: check !!! */
257618ef149SAxel Dörfler			break;
258618ef149SAxel Dörfler
25957c4d430Simker		default:
26057c4d430Simker			TRACE_ALWAYS("An unsupported RBC command: %08x\n", command->opcode);
261618ef149SAxel Dörfler			return B_ERROR;
26257c4d430Simker	}
263618ef149SAxel Dörfler
264618ef149SAxel Dörfler	if (transformed)
26557c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
266618ef149SAxel Dörfler
267618ef149SAxel Dörfler	return B_OK;
268b3d94504SStephan Aßmus}
269618ef149SAxel Dörfler
270618ef149SAxel Dörfler
271618ef149SAxel Dörfler/*!	This is the "transformation procedure" for UFI USB subclass (0x04). It
272618ef149SAxel Dörfler	performs all SCSI commands transformations required by this protocol.
273618ef149SAxel Dörfler	Additionally it tries to make some workarounds for "broken" USB devices.
274618ef149SAxel Dörfler	If no transformation was performed resulting command buffer points to
275618ef149SAxel Dörfler	the original one.
276618ef149SAxel Dörfler
27757c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
27857c4d430Simker	\param cmd: SCSI command buffer to be transformed
27957c4d430Simker	\param len: length of buffer, pointed by cmd parameter
28057c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
28157c4d430Simker	\param rlen: a place for length of transformed command
28257c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
283b3d94504SStephan Aßmus*/
284618ef149SAxel Dörflerstatic status_t
285618ef149SAxel Dörflerufi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
286618ef149SAxel Dörfler	uint8 *rlen)
287b3d94504SStephan Aßmus{
288618ef149SAxel Dörfler	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
28957c4d430Simker	status_t status = B_OK;
290618ef149SAxel Dörfler
29157c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
29257c4d430Simker	memset(*rcmd, 0, UFI_COMMAND_LEN);
293618ef149SAxel Dörfler
294618ef149SAxel Dörfler	switch (command->opcode) {
295618ef149SAxel Dörfler		case READ_6:
296618ef149SAxel Dörfler		case WRITE_6:
297618ef149SAxel Dörfler		case MODE_SENSE_6:
298618ef149SAxel Dörfler		case MODE_SELECT_6:
299618ef149SAxel Dörfler			// TODO: not transform_cmd_*()?
300618ef149SAxel Dörfler			transform_6_to_10(cmd, len, rcmd, rlen);
301618ef149SAxel Dörfler			break;
302618ef149SAxel Dörfler		case TEST_UNIT_READY:
303618ef149SAxel Dörfler			if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
304618ef149SAxel Dörfler				break; /* if TEST UNIT READY was transformed*/
305618ef149SAxel Dörfler		case FORMAT_UNIT:	/* TODO: mismatch */
306618ef149SAxel Dörfler		case INQUIRY:
307618ef149SAxel Dörfler		case START_STOP_UNIT:
308618ef149SAxel Dörfler		case MODE_SELECT_10:
309618ef149SAxel Dörfler		case MODE_SENSE_10:
310618ef149SAxel Dörfler		case PREVENT_ALLOW_MEDIA_REMOVAL:
311618ef149SAxel Dörfler		case READ_10:
312618ef149SAxel Dörfler		case READ_12:
313618ef149SAxel Dörfler		case READ_CAPACITY:
314618ef149SAxel Dörfler		case READ_FORMAT_CAPACITY: /* TODO: not in the SCSI-2 specs */
315618ef149SAxel Dörfler		case REQUEST_SENSE:
316618ef149SAxel Dörfler		case REZERO_UNIT:
317618ef149SAxel Dörfler		case SEEK_10:
318618ef149SAxel Dörfler		case SEND_DIAGNOSTICS: /* TODO: parameter list len mismatch */
319618ef149SAxel Dörfler		case VERIFY:
320618ef149SAxel Dörfler		case WRITE_10:
321618ef149SAxel Dörfler		case WRITE_12: /* TODO: EBP. mismatch */
322618ef149SAxel Dörfler		case WRITE_AND_VERIFY:
323618ef149SAxel Dörfler			memcpy(*rcmd, cmd, len);
324618ef149SAxel Dörfler			/*TODO what about control? ignored in UFI?*/
325618ef149SAxel Dörfler			break;
326618ef149SAxel Dörfler		default:
327618ef149SAxel Dörfler			TRACE_ALWAYS("An unsupported UFI command: %08x\n",
328618ef149SAxel Dörfler				command->opcode);
329618ef149SAxel Dörfler			status = B_ERROR;
330618ef149SAxel Dörfler			break;
33157c4d430Simker	}
332618ef149SAxel Dörfler
33357c4d430Simker	*rlen = UFI_COMMAND_LEN; /* override any value set in transform funcs !!!*/
334618ef149SAxel Dörfler
335618ef149SAxel Dörfler	if (status == B_OK)
33657c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
337618ef149SAxel Dörfler
33857c4d430Simker	return status;
339b3d94504SStephan Aßmus}
340618ef149SAxel Dörfler
341618ef149SAxel Dörfler
342618ef149SAxel Dörfler/*!	This is the "transformation procedure" for SFF8020I and SFF8070I
343618ef149SAxel Dörfler	USB subclassses (0x02 and 0x05). It performs all SCSI commands
344618ef149SAxel Dörfler	transformations required by this protocol. Additionally it tries to make
345618ef149SAxel Dörfler	some workarounds for "broken" USB devices. If no transformation was
346618ef149SAxel Dörfler	performed resulting command buffer points to the original one.
347618ef149SAxel Dörfler
34857c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
34957c4d430Simker	\param cmd: SCSI command buffer to be transformed
35057c4d430Simker	\param len: length of buffer, pointed by cmd parameter
35157c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
35257c4d430Simker	\param rlen: a place for length of transformed command
35357c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
354b3d94504SStephan Aßmus*/
355618ef149SAxel Dörflerstatic status_t
356618ef149SAxel Dörfleratapi_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
357618ef149SAxel Dörfler	uint8 *rlen)
358b3d94504SStephan Aßmus{
359618ef149SAxel Dörfler	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
36057c4d430Simker	status_t status = B_OK;
361618ef149SAxel Dörfler
36257c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
36357c4d430Simker	memset(*rcmd, 0, ATAPI_COMMAND_LEN);
364618ef149SAxel Dörfler
365618ef149SAxel Dörfler	switch (command->opcode) {
366618ef149SAxel Dörfler		case READ_6:
367618ef149SAxel Dörfler		case WRITE_6:
368618ef149SAxel Dörfler		case MODE_SENSE_6:
369618ef149SAxel Dörfler		case MODE_SELECT_6:
370618ef149SAxel Dörfler			// TODO: not transform_cmd_*()?
3718e185f27SAxel Dörfler			transform_6_to_10(cmd, len, rcmd, rlen);
372618ef149SAxel Dörfler			break;
373618ef149SAxel Dörfler		case TEST_UNIT_READY:
374618ef149SAxel Dörfler			if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
37557c4d430Simker				break;
376618ef149SAxel Dörfler		case FORMAT_UNIT:
377618ef149SAxel Dörfler		case INQUIRY:
378618ef149SAxel Dörfler		case MODE_SELECT_10:
379618ef149SAxel Dörfler		case MODE_SENSE_10:
380618ef149SAxel Dörfler		case PREVENT_ALLOW_MEDIA_REMOVAL:
381618ef149SAxel Dörfler		case READ_10:
382618ef149SAxel Dörfler		case READ_12: /* mismatch in byte 1 */
383618ef149SAxel Dörfler		case READ_CAPACITY: /* mismatch. no transf len defined... */
384618ef149SAxel Dörfler		case READ_FORMAT_CAPACITY: /* TODO: check!!! */
385618ef149SAxel Dörfler		case REQUEST_SENSE:
386618ef149SAxel Dörfler		case SEEK_10:
387618ef149SAxel Dörfler		case START_STOP_UNIT:
388618ef149SAxel Dörfler		case VERIFY: /* mismatch DPO */
389618ef149SAxel Dörfler		case WRITE_10: /* mismatch in byte 1 */
390618ef149SAxel Dörfler		case WRITE_12: /* mismatch in byte 1 */
391618ef149SAxel Dörfler		case WRITE_AND_VERIFY: /* mismatch byte 1 */
392618ef149SAxel Dörfler		case PAUSE_RESUME:
393618ef149SAxel Dörfler		case PLAY_AUDIO:
394618ef149SAxel Dörfler		case PLAY_AUDIO_MSF:
395618ef149SAxel Dörfler		case REWIND:
396618ef149SAxel Dörfler		case PLAY_AUDIO_TRACK:
397618ef149SAxel Dörfler		/* are in FreeBSD driver but no in 8070/8020 specs ...
398618ef149SAxel Dörfler		//case REZERO_UNIT:
399618ef149SAxel Dörfler		//case SEND_DIAGNOSTIC:
400618ef149SAxel Dörfler		//case POSITION_TO_ELEMENT:	*/
401618ef149SAxel Dörfler		case GET_CONFIGURATION:
402618ef149SAxel Dörfler		case SYNCHRONIZE_CACHE:
403618ef149SAxel Dörfler		case READ_BUFFER:
404618ef149SAxel Dörfler	 	case READ_SUBCHANNEL:
405618ef149SAxel Dörfler		case READ_TOC: /* some mismatch */
406618ef149SAxel Dörfler		case READ_HEADER:
407618ef149SAxel Dörfler		case READ_DISK_INFO:
408618ef149SAxel Dörfler		case READ_TRACK_INFO:
409618ef149SAxel Dörfler		case SEND_OPC:
410618ef149SAxel Dörfler		case READ_MASTER_CUE:
411618ef149SAxel Dörfler		case CLOSE_TR_SESSION:
412618ef149SAxel Dörfler		case READ_BUFFER_CAP:
413618ef149SAxel Dörfler		case SEND_CUE_SHEET:
414618ef149SAxel Dörfler		case BLANK:
415618ef149SAxel Dörfler		case EXCHANGE_MEDIUM:
416618ef149SAxel Dörfler		case READ_DVD_STRUCTURE:
417618ef149SAxel Dörfler		case SET_CD_SPEED:
418618ef149SAxel Dörfler		case DVD_REPORT_KEY:
419618ef149SAxel Dörfler		case DVD_SEND_KEY:
420618ef149SAxel Dörfler		//case 0xe5: /* READ_TRACK_INFO_PHILIPS *//* TODO: check!!! */
421618ef149SAxel Dörfler			memcpy(*rcmd, cmd, len); /* TODO: check!!! */
422618ef149SAxel Dörfler			break;
423618ef149SAxel Dörfler
424618ef149SAxel Dörfler		default:
425618ef149SAxel Dörfler			TRACE_ALWAYS("An unsupported (?) ATAPI command: %08x\n",
426618ef149SAxel Dörfler				command->opcode);
427618ef149SAxel Dörfler			status = B_ERROR;
428618ef149SAxel Dörfler			break;
42957c4d430Simker	}
430618ef149SAxel Dörfler
43157c4d430Simker	*rlen = ATAPI_COMMAND_LEN;
432618ef149SAxel Dörfler
433618ef149SAxel Dörfler	if (status == B_OK)
43457c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
435618ef149SAxel Dörfler
43657c4d430Simker	return status;
437b3d94504SStephan Aßmus}
438618ef149SAxel Dörfler
439618ef149SAxel Dörfler
440618ef149SAxel Dörfler/*!	This is the "transformation procedure" for QIC157 USB subclass (0x03). It
441618ef149SAxel Dörfler	performs all SCSI commands transformations required by this protocol.
442618ef149SAxel Dörfler	Additionally it tries to make some workarounds for "broken" USB devices.
443618ef149SAxel Dörfler	If no transformation was performed the resulting command buffer points to
444618ef149SAxel Dörfler	the original one.
445618ef149SAxel Dörfler
44657c4d430Simker	\param udi: usb_device_info object for wich transformation is requested
44757c4d430Simker	\param cmd: SCSI command buffer to be transformed
44857c4d430Simker	\param len: length of buffer, pointed by cmd parameter
44957c4d430Simker	\param rcmd: a place for buffer pointer with transformed command
45057c4d430Simker	\param rlen: a place for length of transformed command
45157c4d430Simker	\return: B_OK if transformation was successfull, B_ERROR otherwise
452b3d94504SStephan Aßmus*/
453618ef149SAxel Dörflerstatic status_t
454618ef149SAxel Dörflerqic157_transform(usb_device_info *udi, uint8 *cmd, uint8 len, uint8 **rcmd,
455618ef149SAxel Dörfler	uint8 *rlen)
456b3d94504SStephan Aßmus{
457618ef149SAxel Dörfler	scsi_cmd_generic *command = (scsi_cmd_generic *)cmd;
45857c4d430Simker	status_t status = B_OK;
459618ef149SAxel Dörfler
46057c4d430Simker	TRACE_SCSI_COMMAND(cmd, len);
46157c4d430Simker	*rlen = ATAPI_COMMAND_LEN;
46257c4d430Simker	memset(*rcmd, 0, *rlen);
463618ef149SAxel Dörfler
464618ef149SAxel Dörfler	switch (command->opcode) {
465618ef149SAxel Dörfler		case READ_6:
466618ef149SAxel Dörfler		case WRITE_6:
467618ef149SAxel Dörfler		case MODE_SENSE_6:
468618ef149SAxel Dörfler		case MODE_SELECT_6:
469618ef149SAxel Dörfler			// TODO: not transform_cmd_*()?
470618ef149SAxel Dörfler			transform_6_to_10(cmd, len, rcmd, rlen);
471618ef149SAxel Dörfler			break;
472618ef149SAxel Dörfler		case TEST_UNIT_READY:
473618ef149SAxel Dörfler			if (transform_cmd_test_unit_ready(udi, cmd, len, rcmd, rlen))
474618ef149SAxel Dörfler				break; // if TEST UNIT READY was transformed
475618ef149SAxel Dörfler		case ERASE: /*TODO: check !!! */
476618ef149SAxel Dörfler		case INQUIRY: /*TODO: check !!! */
477618ef149SAxel Dörfler		case LOAD_UNLOAD: /*TODO: check !!! */
478618ef149SAxel Dörfler		case LOCATE: /*TODO: check !!! */
479618ef149SAxel Dörfler		case LOG_SELECT: /*TODO: check !!! */
480618ef149SAxel Dörfler		case LOG_SENSE: /*TODO: check !!! */
481618ef149SAxel Dörfler		case READ_POSITION: /*TODO: check !!! */
482618ef149SAxel Dörfler		case REQUEST_SENSE: /*TODO: check !!! */
483618ef149SAxel Dörfler		case REWIND: /*TODO: check !!! */
484618ef149SAxel Dörfler		case SPACE: /*TODO: check !!! */
485618ef149SAxel Dörfler		case WRITE_FILEMARK: /*TODO: check !!! */
486618ef149SAxel Dörfler			*rcmd = cmd; /*TODO: check !!! */
487618ef149SAxel Dörfler			*rlen = len;
488618ef149SAxel Dörfler			break;
489618ef149SAxel Dörfler		default:
490618ef149SAxel Dörfler			TRACE_ALWAYS("An unsupported QIC-157 command: %08x\n",
491618ef149SAxel Dörfler				command->opcode);
492618ef149SAxel Dörfler			status = B_ERROR;
493618ef149SAxel Dörfler			break;
49457c4d430Simker	}
495618ef149SAxel Dörfler
496618ef149SAxel Dörfler	if (status == B_OK)
49757c4d430Simker		TRACE_SCSI_COMMAND_HLIGHT(*rcmd, *rlen);
498618ef149SAxel Dörfler
49957c4d430Simker	return status;
500b3d94504SStephan Aßmus}
501b3d94504SStephan Aßmus
502b3d94504SStephan Aßmus
503b3d94504SStephan Aßmustransform_module_info scsi_transform_m = {
50457c4d430Simker	{0, 0, 0}, /* this is not a real kernel module - just interface */
50557c4d430Simker	scsi_transform,
506