19bb1a5cdSimker/**
29bb1a5cdSimker *
39bb1a5cdSimker * TODO: description
406437987SMatt Madia *
506437987SMatt Madia * This file is a part of USB SCSI CAM for Haiku.
69bb1a5cdSimker * May be used under terms of the MIT License
79bb1a5cdSimker *
89bb1a5cdSimker * Author(s):
99bb1a5cdSimker * 	Siarzhuk Zharski <imker@gmx.li>
1006437987SMatt Madia *
1106437987SMatt Madia *
12b3d94504SStephan Aßmus */
13b3d94504SStephan Aßmus/** Main part of USB SIM implementation */
14b3d94504SStephan Aßmus
1506437987SMatt Madia#include "usb_scsi.h"
16b3d94504SStephan Aßmus
17b3d94504SStephan Aßmus#include <KernelExport.h>
18b3d94504SStephan Aßmus#include <module.h>
19b3d94504SStephan Aßmus#include <malloc.h>
20b3d94504SStephan Aßmus#include <strings.h>
21b3d94504SStephan Aßmus#include <stdio.h>
22f5f8df45Simker#include <device_manager.h>
23f5f8df45Simker#include <bus/SCSI.h>
2406437987SMatt Madia#include "device_info.h"
2506437987SMatt Madia#include "settings.h"
2606437987SMatt Madia#include "transform_procs.h"
2706437987SMatt Madia#include "tracing.h"
2806437987SMatt Madia#include "scsi_commands.h"
29b3d94504SStephan Aßmus#include "proto_common.h"
3006437987SMatt Madia#include "proto_bulk.h"
3106437987SMatt Madia#include "proto_cbi.h"
3206437987SMatt Madia#include "usb_defs.h"
3306437987SMatt Madia#include "fake_device.h"
3406437987SMatt Madia#include "sg_buffer.h"
35b3d94504SStephan Aßmus
36f5f8df45Simker
37f5f8df45Simker#if 0
389bb1a5cdSimkerstatus_t device_added(const usb_device device, void **cookie);
3906437987SMatt Madia
40b3d94504SStephan Aßmusstatus_t device_removed(void *cookie);
41b3d94504SStephan Aßmus
42b3d94504SStephan Aßmusstatic long sim_action(CCB_HEADER *ccbh);
43b3d94504SStephan Aßmusstatic long sim_init();
44b3d94504SStephan Aßmus
45b3d94504SStephan Aßmus#define SIM_VERSION 1
46b3d94504SStephan Aßmus#define HBA_VERSION 1
47b3d94504SStephan Aßmus
48b3d94504SStephan Aßmus//#define ROUNDUP(size, seg) (((size) + (seg) - 1) & ~((seg) - 1))
49b3d94504SStephan Aßmus
509bb1a5cdSimker#define INQ_VENDOR_LEN		0x08
519bb1a5cdSimker#define INQ_PRODUCT_LEN		0x10
529bb1a5cdSimker#define INQ_REVISION_LEN	0x04
53b3d94504SStephan Aßmus
549bb1a5cdSimker#define TRANS_TIMEOUT		7500000
55b3d94504SStephan Aßmus
569bb1a5cdSimkerstatic long path_id		= -1;
579bb1a5cdSimkerstatic int32 load_count	= 0;
5806437987SMatt Madia
59f5f8df45Simkerstatic char sim_vendor_name[]	= "Haiku";		/* who wrote this driver */
609bb1a5cdSimkerstatic char hba_vendor_name[]	= "USB";		/* who made the hardware */
619bb1a5cdSimkerstatic char controller_family[]	= "USB SCSI";	/* what family of products */
6206437987SMatt Madia
63b3d94504SStephan Aßmusstruct usb_support_descriptor supported_devices[] = {
649bb1a5cdSimker	{0, 0, 0, 0, 0}
65b3d94504SStephan Aßmus};
66b3d94504SStephan Aßmus
67b3d94504SStephan Aßmususb_device_info *usb_devices[MAX_DEVICES_COUNT];
68b3d94504SStephan Aßmus/* main devices table locking semaphore */
69b3d94504SStephan Aßmussem_id usb_serial_lock = -1;
7006437987SMatt Madia
71b3d94504SStephan Aßmususb_module_info *usb;
72b3d94504SStephan Aßmusstatic cam_for_sim_module_info *cam;
73b3d94504SStephan Aßmus
74b3d94504SStephan Aßmusstruct usb_notify_hooks notify_hooks = {
759bb1a5cdSimker	device_added,
769bb1a5cdSimker	device_removed
77b3d94504SStephan Aßmus};
789bb1a5cdSimker
799bb1a5cdSimker/* function prototupes */
809bb1a5cdSimkerstatic status_t get_interface_properties(usb_interface_info *uii, uint32 *pproperties);
819bb1a5cdSimkerstatic status_t load_vendor_module(char **path, const char *path_mask, const char *prop, module_info **mi);
829bb1a5cdSimkerstatic status_t setup_transport_modules(usb_device_info *udi, usb_device_settings *uds);
839bb1a5cdSimkerstatic status_t setup_endpoints(usb_interface_info *uii, usb_device_info *udi);
849bb1a5cdSimkerstatic status_t allocate_resources(usb_device_info *udi);
859bb1a5cdSimkerstatic void 	release_resources(usb_device_info *udi);
869bb1a5cdSimkerstatic status_t xpt_scsi_io(CCB_SCSIIO *ccbio);
879bb1a5cdSimkerstatic status_t xpt_path_inquiry(CCB_PATHINQ *ccbp);
889bb1a5cdSimkerstatic status_t xpt_extended_path_inquiry(CCB_EXTENDED_PATHINQ *ccbep);
899bb1a5cdSimker
90b3d94504SStephan Aßmus/**
919bb1a5cdSimker	\fn:match_device
929bb1a5cdSimker	\param device:???
939bb1a5cdSimker	\param uii:???
949bb1a5cdSimker	\param pproperties:???
959bb1a5cdSimker	\return:B_BAD_TYPE , B_ENTRY_NOT_FOUND, B_OK
9606437987SMatt Madia
979bb1a5cdSimker	??
98b3d94504SStephan Aßmus*/
999bb1a5cdSimkerstatus_t get_interface_properties(usb_interface_info *uii, uint32 *pproperties)
100b3d94504SStephan Aßmus{
1019bb1a5cdSimker	status_t status = B_BAD_TYPE;
1029bb1a5cdSimker	if(uii->descr->interface_class == USB_DEV_CLASS_MASS){
1039bb1a5cdSimker		status = B_OK;
1049bb1a5cdSimker		switch(uii->descr->interface_subclass){
1059bb1a5cdSimker		case USB_DEV_SUBCLASS_RBC:		*pproperties |= CMDSET_RBC; break;
10606437987SMatt Madia		case USB_DEV_SUBCLASS_UFI:		*pproperties |= CMDSET_UFI;	break;
10706437987SMatt Madia		case USB_DEV_SUBCLASS_SFF8020I:
1089bb1a5cdSimker		case USB_DEV_SUBCLASS_SFF8070I: *pproperties |= CMDSET_ATAPI;	break;
1099bb1a5cdSimker		case USB_DEV_SUBCLASS_SCSI:		*pproperties |= CMDSET_SCSI;	break;
1109bb1a5cdSimker		case USB_DEV_SUBCLASS_QIC157:	*pproperties |= CMDSET_QIC157;	break;
11106437987SMatt Madia		default:
1129bb1a5cdSimker			TRACE_ALWAYS("get_interface_properties:unknown USB subclass:%02x\n",
1139bb1a5cdSimker									 uii->descr->interface_subclass);
1149bb1a5cdSimker			/*status = B_ENTRY_NOT_FOUND;*/ /*B_BAD_TYPE assumed*/
1159bb1a5cdSimker			break;
1169bb1a5cdSimker		}
1179bb1a5cdSimker		switch(uii->descr->interface_protocol){
1189bb1a5cdSimker		case USB_DEV_PROTOCOL_CBI:	*pproperties |= PROTO_CBI;	break;
1199bb1a5cdSimker		case USB_DEV_PROTOCOL_CB:	*pproperties |= PROTO_CB;	break;
1209bb1a5cdSimker		case USB_DEV_PROTOCOL_BULK:	*pproperties |= PROTO_BULK_ONLY; break;
12106437987SMatt Madia		default:
1229bb1a5cdSimker			TRACE_ALWAYS("get_interface_properties:unknown USB protocol:%02x\n",
1239bb1a5cdSimker									 uii->descr->interface_protocol);
1249bb1a5cdSimker			/*status = B_ENTRY_NOT_FOUND;*/ /*B_BAD_TYPE assumed*/
1259bb1a5cdSimker			break;
1269bb1a5cdSimker		}
1279bb1a5cdSimker		if(status == B_OK){
1289bb1a5cdSimker			TRACE("get_interface_properties: standard properties:%08x\n", *pproperties);
1299bb1a5cdSimker		}
1309bb1a5cdSimker	}
1319bb1a5cdSimker	return status;
132b3d94504SStephan Aßmus}
133b3d94504SStephan Aßmus/**
1349bb1a5cdSimker	\fn:
13506437987SMatt Madia
136b3d94504SStephan Aßmus*/
137b3d94504SStephan Aßmusstatus_t load_vendor_module(char **path, const char *path_mask,
1389bb1a5cdSimker							const char *prop, module_info **mi)
139b3d94504SStephan Aßmus{
1409bb1a5cdSimker	status_t status = B_NO_MEMORY;
1419bb1a5cdSimker	int path_len = strlen(path_mask) + strlen(prop);
1429bb1a5cdSimker	*path = malloc(path_len);
1439bb1a5cdSimker	if(*path){
1449bb1a5cdSimker		sprintf(*path, path_mask, prop);
1459bb1a5cdSimker		status = get_module(*path, mi);
1469bb1a5cdSimker		if(status != B_OK)
1479bb1a5cdSimker			TRACE_ALWAYS("load_vendor_module:get_module(%s) failed:%08x\n", *path, status);
1489bb1a5cdSimker	} else {
1499bb1a5cdSimker		TRACE_ALWAYS("load_vendor_module:couldn't allocate %d bytes\n", path_len);
1509bb1a5cdSimker	}
1519bb1a5cdSimker	return status;
152b3d94504SStephan Aßmus}
153b3d94504SStephan Aßmus/**
1549bb1a5cdSimker	\fn:
15506437987SMatt Madia
156b3d94504SStephan Aßmus*/
157b3d94504SStephan Aßmusstatus_t setup_transport_modules(usb_device_info *udi,
1589bb1a5cdSimker									 usb_device_settings *uds)
159b3d94504SStephan Aßmus{
1609bb1a5cdSimker	status_t status = B_OK;
1619bb1a5cdSimker	switch(PROTO(udi->properties)){
1629bb1a5cdSimker	case PROTO_BULK_ONLY:
1639bb1a5cdSimker		udi->protocol_m = &bulk_only_protocol_m;
1649bb1a5cdSimker		break;
1659bb1a5cdSimker	case PROTO_CB:
1669bb1a5cdSimker	case PROTO_CBI:
1679bb1a5cdSimker		udi->protocol_m = &cbi_protocol_m;
1689bb1a5cdSimker		break;
1699bb1a5cdSimker	case PROTO_VENDOR:{
1709bb1a5cdSimker			status = load_vendor_module(&udi->protocol_m_path,
1719bb1a5cdSimker										PROTOCOL_MODULE_MASK,
1729bb1a5cdSimker										uds->vendor_protocol,
1739bb1a5cdSimker										(module_info**)&udi->protocol_m);
1749bb1a5cdSimker		}break;
1759bb1a5cdSimker	default:
1769bb1a5cdSimker		TRACE_ALWAYS("setup_transport_modules: "
1779bb1a5cdSimker					 "transport %02x is not supported\n", PROTO(udi->properties));
1789bb1a5cdSimker		status = B_ENTRY_NOT_FOUND;
1799bb1a5cdSimker	}
1809bb1a5cdSimker	if(status == B_OK){
1819bb1a5cdSimker		switch(CMDSET(udi->properties)){
1829bb1a5cdSimker		case CMDSET_SCSI:
1839bb1a5cdSimker			udi->transform_m = &scsi_transform_m;
1849bb1a5cdSimker			break;
1859bb1a5cdSimker		case CMDSET_UFI:
1869bb1a5cdSimker			udi->transform_m = &ufi_transform_m;
1879bb1a5cdSimker			udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */
1889bb1a5cdSimker			break;
1899bb1a5cdSimker		case CMDSET_ATAPI:
1909bb1a5cdSimker			udi->transform_m = &atapi_transform_m;
1919bb1a5cdSimker			udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */
1929bb1a5cdSimker			break;
1939bb1a5cdSimker		case CMDSET_RBC:
1949bb1a5cdSimker			udi->transform_m = &rbc_transform_m;
1959bb1a5cdSimker			break;
1969bb1a5cdSimker		case CMDSET_QIC157:
1979bb1a5cdSimker			udi->transform_m = &qic157_transform_m;
1989bb1a5cdSimker			udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */
1999bb1a5cdSimker			break;
2009bb1a5cdSimker		case CMDSET_VENDOR:{
2019bb1a5cdSimker				status = load_vendor_module(&udi->transform_m_path,
2029bb1a5cdSimker										TRANSFORM_MODULE_MASK,
2039bb1a5cdSimker										uds->vendor_commandset,
2049bb1a5cdSimker										(module_info**)&udi->transform_m);
2059bb1a5cdSimker			}break;
2069bb1a5cdSimker		default:
2079bb1a5cdSimker			TRACE_ALWAYS("setup_transport_modules: "
2089bb1a5cdSimker						 "protocol %02x is not supported\n", CMDSET(udi->properties));
2099bb1a5cdSimker			status = B_ENTRY_NOT_FOUND;
2109bb1a5cdSimker		}
2119bb1a5cdSimker	}
2129bb1a5cdSimker	return status;
213b3d94504SStephan Aßmus}
214b3d94504SStephan Aßmus
215b3d94504SStephan Aßmusstatic void
216b3d94504SStephan Aßmusrelease_transport_modules(usb_device_info *udi)
217b3d94504SStephan Aßmus{
2189bb1a5cdSimker	if(PROTO(udi->properties) == PROTO_VENDOR && 0 != udi->protocol_m_path){
2199bb1a5cdSimker		put_module(udi->protocol_m_path);
2209bb1a5cdSimker		udi->protocol_m = 0;
2219bb1a5cdSimker		free(udi->protocol_m_path);
2229bb1a5cdSimker	}
2239bb1a5cdSimker	if(CMDSET(udi->properties) == CMDSET_VENDOR && 0 != udi->transform_m_path){
2249bb1a5cdSimker		put_module(udi->transform_m_path);
2259bb1a5cdSimker		udi->transform_m = 0;
2269bb1a5cdSimker		free(udi->transform_m_path);
2279bb1a5cdSimker	}
228b3d94504SStephan Aßmus}
229b3d94504SStephan Aßmus
230b3d94504SStephan Aßmus/**
2319bb1a5cdSimker	\fn:
232b3d94504SStephan Aßmus*/
2339bb1a5cdSimkerstatus_t setup_endpoints(usb_interface_info *uii, usb_device_info *udi)
234b3d94504SStephan Aßmus{
2359bb1a5cdSimker	status_t status = B_OK;
2369bb1a5cdSimker	int16 idx = 0;
2379bb1a5cdSimker	enum{ epIn = 0, epOut, epIntr, epCount };
2389bb1a5cdSimker	size_t epts[epCount] = { -1, -1, -1 };
2399bb1a5cdSimker	char	*epnames[epCount] = {"input", "output", "interrupt"};
2409bb1a5cdSimker	size_t ep = 0;
2419bb1a5cdSimker	for(; ep < uii->endpoint_count; ep++){
2429bb1a5cdSimker		usb_endpoint_descriptor *ed = uii->endpoint[ep].descr;
2439bb1a5cdSimker		TRACE("try endpoint:%d %x %x %x\n", ep, (int32)ed->attributes, (int32)ed->endpoint_address, uii->endpoint[ep].handle);
2449bb1a5cdSimker		if((ed->attributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK){
2459bb1a5cdSimker			if((ed->endpoint_address & USB_EP_ADDR_DIR_IN) == USB_EP_ADDR_DIR_IN){
2469bb1a5cdSimker				epts[epIn]	= ep;
2479bb1a5cdSimker			}else{
2489bb1a5cdSimker				epts[epOut] = ep;
2499bb1a5cdSimker			}
2509bb1a5cdSimker		}else{
2519bb1a5cdSimker			if((ed->attributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTERRUPT)
2529bb1a5cdSimker				epts[epIntr] = ep;
2539bb1a5cdSimker		}
2549bb1a5cdSimker	}
2559bb1a5cdSimker	switch(PROTO(udi->properties)){
2569bb1a5cdSimker	case PROTO_CB:
2579bb1a5cdSimker	case PROTO_BULK_ONLY:
2589bb1a5cdSimker		if(epts[epIntr] == -1)
2599bb1a5cdSimker			epts[epIntr] = 0; /* not required for this transports - set it to default*/
2609bb1a5cdSimker		break;
2619bb1a5cdSimker	case PROTO_CBI:
2629bb1a5cdSimker	default:
2639bb1a5cdSimker	}
2649bb1a5cdSimker	for(idx = 0; idx < epCount; idx++){
2659bb1a5cdSimker		if(epts[idx] == -1 && PROTO(udi->properties) != PROTO_VENDOR){
2669bb1a5cdSimker			TRACE_ALWAYS("setup_endpoints: required %s endpoint not found. "
2679bb1a5cdSimker						 "ignore this interface\n", epnames[idx]);
2689bb1a5cdSimker			// DEBUG!!!!!!!!!!
2699bb1a5cdSimker			status = B_ERROR;
2709bb1a5cdSimker		}
2719bb1a5cdSimker	}
2729bb1a5cdSimker	if(status == B_OK){
2739bb1a5cdSimker		udi->pipe_in	= uii->endpoint[epts[epIn]].handle;
2749bb1a5cdSimker		udi->pipe_out	= uii->endpoint[epts[epOut]].handle;
2759bb1a5cdSimker		udi->pipe_intr	= uii->endpoint[epts[epIntr]].handle;
2769bb1a5cdSimker		//TRACE("setup_endpoints: input:%d output:%d "
2779bb1a5cdSimker		//		 "interrupt:%d\n", epts[epIn], epts[epOut], epts[epIntr]);
2789bb1a5cdSimker		TRACE("endpoint:%x %x %x\n", udi->pipe_in, udi->pipe_out, udi->pipe_intr);
2799bb1a5cdSimker	}
2809bb1a5cdSimker	return status;
281b3d94504SStephan Aßmus}
282b3d94504SStephan Aßmus/**
2839bb1a5cdSimker	\fn:create_device_info
2849bb1a5cdSimker	\param device:???
2859bb1a5cdSimker	\param ppudi:???
2869bb1a5cdSimker	\return:???
28706437987SMatt Madia
2889bb1a5cdSimker	???
289b3d94504SStephan Aßmus*/
290b3d94504SStephan Aßmusstatus_t allocate_resources(usb_device_info *udi)
291b3d94504SStephan Aßmus{
2929bb1a5cdSimker	char name[32];
2939bb1a5cdSimker	status_t status = B_NO_MEMORY;
2949bb1a5cdSimker	uint16 dev = 0;
2959bb1a5cdSimker	acquire_sem(usb_serial_lock);
2969bb1a5cdSimker	for(; dev < MAX_DEVICES_COUNT; dev++){
2979bb1a5cdSimker		if(!usb_devices[dev])
2989bb1a5cdSimker			break;
2999bb1a5cdSimker	}
3009bb1a5cdSimker	if(dev < MAX_DEVICES_COUNT){
3019bb1a5cdSimker		usb_devices[dev] = udi;
3029bb1a5cdSimker		udi->lock_sem =
3039bb1a5cdSimker		udi->trans_sem = -1;
3049bb1a5cdSimker		sprintf(name, "usb_scsi lock_sem:%d", dev);
3059bb1a5cdSimker		if((udi->lock_sem = create_sem(0, name)) >= 0){
3069bb1a5cdSimker			sprintf(name, "usb_scsi trans_sem:%d", dev);
3079bb1a5cdSimker			if((udi->trans_sem = create_sem(0, name))>=0){
3089bb1a5cdSimker				udi->dev_num = dev;
3099bb1a5cdSimker				release_sem(udi->lock_sem);
3109bb1a5cdSimker				status = B_OK;
31106437987SMatt Madia			}else
3129bb1a5cdSimker				status = udi->trans_sem;
31306437987SMatt Madia		} else
3149bb1a5cdSimker			status = udi->lock_sem;
31506437987SMatt Madia
3169bb1a5cdSimker		if(status != B_OK){
3179bb1a5cdSimker			TRACE_ALWAYS("allocate_resources:error:%s", strerror(status));
3189bb1a5cdSimker			if(udi->lock_sem >= 0)
3199bb1a5cdSimker				delete_sem(udi->lock_sem);
3209bb1a5cdSimker			if(udi->trans_sem >= 0)
3219bb1a5cdSimker				delete_sem(udi->trans_sem);
3229bb1a5cdSimker			usb_devices[dev] = NULL;
3239bb1a5cdSimker			free(udi);
3249bb1a5cdSimker		}
3259bb1a5cdSimker	}else{
3269bb1a5cdSimker		TRACE_ALWAYS("allocate_resources:reserved devices space exhausted."
3279bb1a5cdSimker								 "Unplug unnesesary devices or reconfigure this driver.\n");
3289bb1a5cdSimker	}
3299bb1a5cdSimker	release_sem(usb_serial_lock);
3309bb1a5cdSimker	return status;
331b3d94504SStephan Aßmus}
332b3d94504SStephan Aßmus/**
3339bb1a5cdSimker	\fn:
33406437987SMatt Madia
335b3d94504SStephan Aßmus*/
336b3d94504SStephan Aßmusvoid release_resources(usb_device_info *udi)
337b3d94504SStephan Aßmus{
3389bb1a5cdSimker	release_transport_modules(udi);
3399bb1a5cdSimker	udi->usb_m = 0;
3409bb1a5cdSimker	(*usb->cancel_queued_transfers)(udi->pipe_in);
3419bb1a5cdSimker	(*usb->cancel_queued_transfers)(udi->pipe_out);
3429bb1a5cdSimker	delete_sem(udi->lock_sem);
3439bb1a5cdSimker	delete_sem(udi->trans_sem);
3449bb1a5cdSimker	acquire_sem(usb_serial_lock);
3459bb1a5cdSimker	usb_devices[udi->dev_num] = NULL;
3469bb1a5cdSimker	release_sem(usb_serial_lock);
347b3d94504SStephan Aßmus}
348b3d94504SStephan Aßmus/**
3499bb1a5cdSimker	\fn:device_added
3509bb1a5cdSimker	\param device:??
3519bb1a5cdSimker	\param cookie:??
3529bb1a5cdSimker	\return:??
35306437987SMatt Madia
3549bb1a5cdSimker	??
355b3d94504SStephan Aßmus*/
3569bb1a5cdSimkerstatus_t device_added(const usb_device device, void **cookie){
3579bb1a5cdSimker	status_t status = B_NO_MEMORY;
3589bb1a5cdSimker	const usb_configuration_info *uci = NULL;
3599bb1a5cdSimker	uint16 cfg = 0;
3609bb1a5cdSimker	bool b_found = false;
3619bb1a5cdSimker	bool b_has_extra_settings = false;
3629bb1a5cdSimker	const usb_device_descriptor *udd = (*usb->get_device_descriptor)(device);
3639bb1a5cdSimker	usb_device_info *udi = (usb_device_info *)malloc(sizeof(usb_device_info));
3649bb1a5cdSimker	TRACE("device_added: probing canidate: "
36506437987SMatt Madia		"%04x/%04x %02d/%02d/%02d\n",
3669bb1a5cdSimker			udd->vendor_id, udd->product_id,
36706437987SMatt Madia			udd->device_class,
36806437987SMatt Madia			udd->device_subclass,
3699bb1a5cdSimker			udd->device_protocol);
3709bb1a5cdSimker	if(udi){
3719bb1a5cdSimker		status = B_NO_INIT;
3729bb1a5cdSimker		while(!b_found && (uci = (*usb->get_nth_configuration)(device, cfg++))){
3739bb1a5cdSimker			uint16 itf = 0;
3749bb1a5cdSimker			for(; itf < uci->interface_count && !b_found; itf++){
3759bb1a5cdSimker				usb_interface_list *ifl = &uci->interface[itf];
3769bb1a5cdSimker				uint16 alt = 0;
3779bb1a5cdSimker				for(; alt < ifl->alt_count; alt++){
3789bb1a5cdSimker					usb_interface_info *uii = &ifl->alt[alt];
3799bb1a5cdSimker					usb_device_settings ud_settings;
3809bb1a5cdSimker					memset(udi, 0, sizeof(usb_device_info));
3819bb1a5cdSimker					memset(&ud_settings, 0, sizeof(usb_device_settings));
3829bb1a5cdSimker					udi->device = device;
3839bb1a5cdSimker					udi->interface	= itf;
3849bb1a5cdSimker					b_has_extra_settings = lookup_device_settings(udd, &ud_settings);
3859bb1a5cdSimker					switch(get_interface_properties(uii, &udi->properties)){
3869bb1a5cdSimker					case B_BAD_TYPE: /* non-standard USB class*/
3879bb1a5cdSimker						if(!b_has_extra_settings){
3889bb1a5cdSimker							continue; /* skip to next interface */
3899bb1a5cdSimker						} /* no break - fall through */
3909bb1a5cdSimker					case B_OK:
3919bb1a5cdSimker						if(b_has_extra_settings){
3929bb1a5cdSimker							if(PROTO(ud_settings.properties) != PROTO_NONE){
3939bb1a5cdSimker								udi->properties &= ~PROTO_MASK;
3949bb1a5cdSimker								udi->properties |= PROTO(ud_settings.properties);
3959bb1a5cdSimker							}
3969bb1a5cdSimker							if(CMDSET(ud_settings.properties) != CMDSET_NONE){
3979bb1a5cdSimker								udi->properties &= ~CMDSET_MASK;
3989bb1a5cdSimker								udi->properties |= CMDSET(ud_settings.properties);
3999bb1a5cdSimker							}
4009bb1a5cdSimker							udi->properties |= ud_settings.properties & FIX_MASK;
4019bb1a5cdSimker							TRACE("device_added: properties merged:%08x\n", udi->properties);
4029bb1a5cdSimker						}
4039bb1a5cdSimker						if( B_OK == setup_transport_modules(udi, &ud_settings)){
4049bb1a5cdSimker							break;
4059bb1a5cdSimker						} /* else - no break - fall through */
40606437987SMatt Madia					default:
4079bb1a5cdSimker						continue; /* skip to next interface */
4089bb1a5cdSimker					}
4099bb1a5cdSimker					if(alt != 0){ /*TODO: are we need this ???*/
4109bb1a5cdSimker						if((status = (*usb->set_alt_interface)(device, uii)) != B_OK){
4119bb1a5cdSimker							TRACE_ALWAYS("device_added:setting alt interface failed:%s",
4129bb1a5cdSimker												strerror(status));
4139bb1a5cdSimker							goto Failed;/* Break - is it right?*/
41406437987SMatt Madia						}
4159bb1a5cdSimker					}
4169bb1a5cdSimker					if((*usb->get_configuration)(device) != uci){
4179bb1a5cdSimker						if((status = (*usb->set_configuration)(device, uci)) != B_OK){
4189bb1a5cdSimker								TRACE_ALWAYS("device_added:setting configuration failed:%08x uci: %08x\n",
4199bb1a5cdSimker											 (*usb->get_configuration)(device), uci);
4209bb1a5cdSimker							TRACE_ALWAYS("device_added:setting configuration failed:%s\n",
4219bb1a5cdSimker													strerror(status));
42206437987SMatt Madia
4239bb1a5cdSimker							goto Failed;/* Break - is it right?*/
4249bb1a5cdSimker						}
4259bb1a5cdSimker					}
4269bb1a5cdSimker					if(B_OK != setup_endpoints(uii, udi)){
4279bb1a5cdSimker						continue; /* skip to next interface */
4289bb1a5cdSimker					}
4299bb1a5cdSimker					if((status = allocate_resources(udi)) == B_OK){
4309bb1a5cdSimker						udi->b_trace = b_log_protocol;
4319bb1a5cdSimker						udi->trace = usb_scsi_trace;
4329bb1a5cdSimker						udi->trace_bytes = usb_scsi_trace_bytes;
43306437987SMatt Madia						udi->trans_timeout = TRANS_TIMEOUT;
4349bb1a5cdSimker						udi->usb_m = usb;
4359bb1a5cdSimker						udi->not_ready_luns = 0xff; /*assume all LUNs initially not ready */
4369bb1a5cdSimker						if((status = (*udi->protocol_m->init)(udi)) == B_OK){
4379bb1a5cdSimker							TRACE("device_added[%d]: SUCCESS! Enjoy using!\n", udi->dev_num);
4389bb1a5cdSimker							*cookie = udi;
4399bb1a5cdSimker							b_found = true; /* we have found something useful - time to go out! */
4409bb1a5cdSimker							break;					/* ... now break alternatives iteration.*/
44106437987SMatt Madia						} else {
4429bb1a5cdSimker							release_resources(udi);
4439bb1a5cdSimker						}
4449bb1a5cdSimker					}
4459bb1a5cdSimker					/* go to next iteration - check all configurations for possible devices */
4469bb1a5cdSimker				}/* for(...) iterate interface alternates*/
4479bb1a5cdSimker			}/* for(...) iterate interfaces*/
4489bb1a5cdSimker		}/* while(...) iterate configurations */
4499bb1a5cdSimker		if(status == B_OK){
4509bb1a5cdSimker			(*cam->minfo.rescan)();
4519bb1a5cdSimker		} else {
4529bb1a5cdSimker			free(udi);
4539bb1a5cdSimker		}
4549bb1a5cdSimker	} /* if(udi){ */
4559bb1a5cdSimker	if(status != B_OK){
4569bb1a5cdSimker		TRACE("device_added: probing failed (%s) for: %04x/%04x\n",
4579bb1a5cdSimker				strerror(status), udd->vendor_id, udd->product_id);
45806437987SMatt Madia	}
45906437987SMatt MadiaFailed:
4609bb1a5cdSimker	return status;
461b3d94504SStephan Aßmus}
462b3d94504SStephan Aßmus/**
4639bb1a5cdSimker	\fn:device_removed
4649bb1a5cdSimker	\param cookie:???
4659bb1a5cdSimker	\return:???
46606437987SMatt Madia
4679bb1a5cdSimker	???
468b3d94504SStephan Aßmus*/
469b3d94504SStephan Aßmusstatus_t device_removed(void *cookie)
470b3d94504SStephan Aßmus{
4719bb1a5cdSimker	status_t status = B_OK;
4729bb1a5cdSimker	usb_device_info *udi = (usb_device_info *)cookie;
47306437987SMatt Madia	acquire_sem(udi->lock_sem); /* wait for possible I/O operation complete */
4749bb1a5cdSimker	release_resources(udi);
4759bb1a5cdSimker	/* no corresponding call of release_sem(udi->lock_sem);
4769bb1a5cdSimker		 - semaphore was deleted in release_resources, any waiting thread
47706437987SMatt Madia		   was failed with BAD_SEM_ID.
4789bb1a5cdSimker	*/
4799bb1a5cdSimker	TRACE_ALWAYS("device_removed[%d]:All The Best !!!\n", udi->dev_num);
4809bb1a5cdSimker	free(udi);
4819bb1a5cdSimker	(*cam->minfo.rescan)();
4829bb1a5cdSimker	return status;
483b3d94504SStephan Aßmus}
484b3d94504SStephan Aßmus/**
4859bb1a5cdSimker	\fn:sim_init
4869bb1a5cdSimker	\return: ???
48706437987SMatt Madia
4889bb1a5cdSimker	called on SIM init
489b3d94504SStephan Aßmus*/
490b3d94504SStephan Aßmusstatic long sim_init(void)
491b3d94504SStephan Aßmus{
4929bb1a5cdSimker	status_t status = B_OK;
4939bb1a5cdSimker	TRACE("sim_init\n");
4949bb1a5cdSimker	return status;
495b3d94504SStephan Aßmus}
496b3d94504SStephan Aßmus
497b3d94504SStephan Aßmus/**
498b3d94504SStephan Aßmus*/
499b3d94504SStephan Aßmusstatic bool
5009bb1a5cdSimkerpre_check_scsi_io_request(usb_device_info *udi, CCB_SCSIIO *ccbio,
5019bb1a5cdSimker												status_t *ret_status)
502b3d94504SStephan Aßmus{
5039bb1a5cdSimker	int target_id	 = ccbio->cam_ch.cam_target_id;
5049bb1a5cdSimker	uint8 target_lun = ccbio->cam_ch.cam_target_lun;
5059bb1a5cdSimker	*ret_status 	 = B_OK;
5069bb1a5cdSimker	/* handle reserved device and luns entries */
50706437987SMatt Madia	if(b_reservation_on && udi == NULL &&
5089bb1a5cdSimker		 target_id < reserved_devices &&
5099bb1a5cdSimker		 target_lun < reserved_luns)
5109bb1a5cdSimker	{
5119bb1a5cdSimker		*ret_status = fake_scsi_io(ccbio);
5129bb1a5cdSimker		return false;
5139bb1a5cdSimker	}
5149bb1a5cdSimker	/* no device for this target | LUN */
5159bb1a5cdSimker	if(udi == NULL || target_lun > udi->max_lun){
5169bb1a5cdSimker		ccbio->cam_ch.cam_status = CAM_DEV_NOT_THERE;
5179bb1a5cdSimker		*ret_status = B_DEV_BAD_DRIVE_NUM;
5189bb1a5cdSimker		return false;
5199bb1a5cdSimker	}
5209bb1a5cdSimker	/* check command length */
5219bb1a5cdSimker	if(ccbio->cam_cdb_len != 6	&&
5229bb1a5cdSimker		 ccbio->cam_cdb_len != 10 &&
5239bb1a5cdSimker		 ccbio->cam_cdb_len != 12)
5249bb1a5cdSimker	{
5259bb1a5cdSimker		TRACE("Bad SCSI command length:%d.Ignore\n", ccbio->cam_cdb_len);
5269bb1a5cdSimker		ccbio->cam_ch.cam_status = CAM_REQ_INVALID;
5279bb1a5cdSimker		*ret_status = B_BAD_VALUE;
5289bb1a5cdSimker		return false;
5299bb1a5cdSimker	}
5309bb1a5cdSimker	/* Clean up auto sense buffer.
5319bb1a5cdSimker		 To avoid misunderstanding in not ready luns logic detection.*/
5329bb1a5cdSimker	if(NULL == ccbio->cam_sense_ptr){
5339bb1a5cdSimker		memset(&udi->autosense_data, 0, sizeof(udi->autosense_data));
5349bb1a5cdSimker	} else {
5359bb1a5cdSimker		memset(ccbio->cam_sense_ptr, 0, ccbio->cam_sense_len);
53606437987SMatt Madia	}
5379bb1a5cdSimker	return true;
538b3d94504SStephan Aßmus}
539b3d94504SStephan Aßmus/**
540b3d94504SStephan Aßmus*/
541b3d94504SStephan Aßmusstatic bool
5429bb1a5cdSimkerpre_handle_features(usb_device_info *udi, CCB_SCSIIO *ccbio,
5439bb1a5cdSimker					scsi_cmd_generic *command, sg_buffer *sgb,
5449bb1a5cdSimker											status_t *ret_status)
545b3d94504SStephan Aßmus{
5469bb1a5cdSimker	uint8 target_lun = ccbio->cam_ch.cam_target_lun;
5479bb1a5cdSimker	*ret_status = B_OK;
54806437987SMatt Madia	udi->trans_timeout = TRANS_TIMEOUT;
5499bb1a5cdSimker	switch(command->opcode){
5509bb1a5cdSimker	case MODE_SELECT_6:
5519bb1a5cdSimker	case MODE_SENSE_6:{
5529bb1a5cdSimker		bool b_select = (MODE_SELECT_6 == command->opcode);
5539bb1a5cdSimker		const char*cmd_name = b_select ? "MODE_SELECT" : "MODE_SENSE";
5549bb1a5cdSimker		if(udi->not_ready_luns & (1 << target_lun)){
5559bb1a5cdSimker			TRACE("pre_handle_features:%s_6 bypassed for LUN:%d\n", cmd_name, target_lun);
5569bb1a5cdSimker			goto set_REQ_INVALID_and_return;
5579bb1a5cdSimker		}
5589bb1a5cdSimker		if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){
5599bb1a5cdSimker			if( B_OK != realloc_sg_buffer(sgb, ccbio->cam_dxfer_len + 4)){ /* TODO: 4 - hardcoded? */
5609bb1a5cdSimker				TRACE_ALWAYS("pre_handle_features:error allocating %d bytes for %s_10\n",
5619bb1a5cdSimker								 ccbio->cam_dxfer_len + 4, cmd_name);
5629bb1a5cdSimker				goto set_REQ_INVALID_and_return;
5639bb1a5cdSimker			}
5649bb1a5cdSimker			if(b_select){
5659bb1a5cdSimker				sg_buffer sgb_sense_6;
5669bb1a5cdSimker				/*TODO: implemenet and try refragment_sg_buffer - to check handling of real scatter/gather!!*/
5679bb1a5cdSimker				if(B_OK != init_sg_buffer(&sgb_sense_6, ccbio)){
5689bb1a5cdSimker					/* In case of error TRACE-ing was already performed in sg_ functions */
5699bb1a5cdSimker					goto set_REQ_INVALID_and_return;
5709bb1a5cdSimker				}
5719bb1a5cdSimker				TRACE_MODE_SENSE_SGB("MODE SELECT 6:", &sgb_sense_6);
5729bb1a5cdSimker				if(B_OK != sg_memcpy(sgb, 1, &sgb_sense_6, 0, 3) ||
57306437987SMatt Madia					 B_OK != sg_memcpy(sgb, 7, &sgb_sense_6, 3, 1) ||
5749bb1a5cdSimker					 B_OK != sg_memcpy(sgb, 8, &sgb_sense_6, 4, ccbio->cam_dxfer_len - sizeof(scsi_mode_param_header_6)))
5759bb1a5cdSimker				{
5769bb1a5cdSimker					/* In case of error TRACE-ing was already performed in sg_ functions */
5779bb1a5cdSimker					goto set_REQ_INVALID_and_return;
5789bb1a5cdSimker				}
5799bb1a5cdSimker				TRACE_MODE_SENSE_SGB("MODE SELECT 10:", sgb);
58006437987SMatt Madia			}
5819bb1a5cdSimker		} /*else {
5829bb1a5cdSimker			if(b_select){ / * trace data if configured in settings * /
5839bb1a5cdSimker				TRACE_MODE_SENSE_DATA("MODE_SELECT:", ccbio->cam_data_ptr, ccbio->cam_dxfer_len);
58406437987SMatt Madia			}
5859bb1a5cdSimker		}*/
5869bb1a5cdSimker	}break;
5879bb1a5cdSimker	case INQUIRY: /* fake INQUIRY request */
5889bb1a5cdSimker		if(HAS_FIXES(udi->properties, FIX_NO_INQUIRY)){
5899bb1a5cdSimker			fake_inquiry_request(udi, ccbio);
5909bb1a5cdSimker			goto set_REQ_CMP_and_return;
5919bb1a5cdSimker		} break;
5929bb1a5cdSimker	case TEST_UNIT_READY: /* fake INQUIRY request */
5939bb1a5cdSimker		if(HAS_FIXES(udi->properties, FIX_NO_TEST_UNIT)){
5949bb1a5cdSimker			goto set_REQ_CMP_and_return;
5959bb1a5cdSimker		} break;
5969bb1a5cdSimker	case PREVENT_ALLOW_MEDIA_REMOVAL: /* fake PREVENT_ALLOW_MEDIA_REMOVAL request */
5979bb1a5cdSimker		if(HAS_FIXES(udi->properties, FIX_NO_PREVENT_MEDIA)){
5989bb1a5cdSimker			goto set_REQ_CMP_and_return;
5999bb1a5cdSimker		} break;
6009bb1a5cdSimker	case FORMAT_UNIT:
6019bb1a5cdSimker		udi->trans_timeout = B_INFINITE_TIMEOUT;
6029bb1a5cdSimker		break;
603