xref: /minix3/minix/drivers/usb/usb_storage/usb_storage.c (revision 2d64210c1dbcd340904718f2d4e9e81adeab3c7d)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * Minix3 USB mass storage driver implementation
3433d6423SLionel Sambuc  * using DDEkit, and libblockdriver
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6*2d64210cSWojciech Zajac #include <sys/cdefs.h>			/* __CTASSERT() */
7433d6423SLionel Sambuc #include <sys/ioc_disk.h>		/* cases for mass_storage_ioctl */
8433d6423SLionel Sambuc #ifdef USB_STORAGE_SIGNAL
9433d6423SLionel Sambuc #include <sys/signal.h>			/* signal handling */
10433d6423SLionel Sambuc #endif
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include <ddekit/minix/msg_queue.h>
13433d6423SLionel Sambuc #include <ddekit/thread.h>
14433d6423SLionel Sambuc #include <ddekit/usb.h>
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #include <minix/blockdriver.h>
17433d6423SLionel Sambuc #include <minix/com.h>			/* for msg_queue ranges */
18433d6423SLionel Sambuc #include <minix/drvlib.h>		/* DEV_PER_DRIVE, partition */
19433d6423SLionel Sambuc #include <minix/ipc.h>			/* message */
20433d6423SLionel Sambuc #include <minix/safecopies.h>		/* GRANT_VALID */
21433d6423SLionel Sambuc #include <minix/sef.h>
22433d6423SLionel Sambuc #include <minix/sysutil.h>		/* panic */
23433d6423SLionel Sambuc #include <minix/usb.h>			/* structures like usb_ctrlrequest */
24433d6423SLionel Sambuc #include <minix/usb_ch9.h>		/* descriptor structures */
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc #include <assert.h>
27433d6423SLionel Sambuc #include <limits.h>			/* ULONG_MAX */
28*2d64210cSWojciech Zajac #include <time.h>			/* nanosleep */
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc #include "common.h"
31433d6423SLionel Sambuc #include "bulk.h"
32433d6423SLionel Sambuc #include "usb_storage.h"
33433d6423SLionel Sambuc #include "urb_helper.h"
34433d6423SLionel Sambuc #include "scsi.h"
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc /*---------------------------*
38433d6423SLionel Sambuc  *    declared functions     *
39433d6423SLionel Sambuc  *---------------------------*/
40433d6423SLionel Sambuc /* TODO: these are missing from DDE header files */
41433d6423SLionel Sambuc extern void ddekit_minix_wait_exit(void);
42433d6423SLionel Sambuc extern void ddekit_shutdown(void);
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc /* SCSI URB related prototypes */
45433d6423SLionel Sambuc static int mass_storage_send_scsi_cbw_out(int, scsi_transfer *);
46433d6423SLionel Sambuc static int mass_storage_send_scsi_data_in(void *, unsigned int);
47433d6423SLionel Sambuc static int mass_storage_send_scsi_data_out(void *, unsigned int);
48433d6423SLionel Sambuc static int mass_storage_send_scsi_csw_in(void);
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc #ifdef MASS_RESET_RECOVERY
51433d6423SLionel Sambuc /* Bulk only URB related prototypes */
52433d6423SLionel Sambuc static int mass_storage_reset_recovery(void);
53433d6423SLionel Sambuc static int mass_storage_send_bulk_reset(void);
54433d6423SLionel Sambuc static int mass_storage_send_clear_feature(int, int);
55433d6423SLionel Sambuc #endif
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc /* SEF related functions */
58433d6423SLionel Sambuc static int mass_storage_sef_hdlr(int, sef_init_info_t *);
59433d6423SLionel Sambuc static void mass_storage_signal_handler(int);
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc /* DDEKit IPC related */
62433d6423SLionel Sambuc static void ddekit_usb_task(void *);
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc /* Mass storage related prototypes */
65433d6423SLionel Sambuc static void mass_storage_task(void *);
66433d6423SLionel Sambuc static int mass_storage_test(void);
67*2d64210cSWojciech Zajac static int mass_storage_check_error(void);
68433d6423SLionel Sambuc static int mass_storage_try_first_open(void);
69433d6423SLionel Sambuc static int mass_storage_transfer_restrictions(u64_t, unsigned long);
70433d6423SLionel Sambuc static ssize_t mass_storage_write(unsigned long, endpoint_t, iovec_t *,
71433d6423SLionel Sambuc 				unsigned int, unsigned long);
72433d6423SLionel Sambuc static ssize_t mass_storage_read(unsigned long, endpoint_t, iovec_t *,
73433d6423SLionel Sambuc 				unsigned int, unsigned long);
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc /* Minix's libblockdriver callbacks */
76433d6423SLionel Sambuc static int mass_storage_open(devminor_t, int);
77433d6423SLionel Sambuc static int mass_storage_close(devminor_t);
78433d6423SLionel Sambuc static ssize_t mass_storage_transfer(devminor_t, int, u64_t, endpoint_t,
79433d6423SLionel Sambuc 					iovec_t *, unsigned int, int);
80433d6423SLionel Sambuc static int mass_storage_ioctl(devminor_t, unsigned long, endpoint_t,
81433d6423SLionel Sambuc 				cp_grant_id_t, endpoint_t);
82433d6423SLionel Sambuc static void mass_storage_cleanup(void);
83433d6423SLionel Sambuc static struct device * mass_storage_part(devminor_t);
84433d6423SLionel Sambuc static void mass_storage_geometry(devminor_t, struct part_geom *);
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc /* DDEKit's USB driver callbacks */
87433d6423SLionel Sambuc static void usb_driver_completion(void *);
88433d6423SLionel Sambuc static void usb_driver_connect(struct ddekit_usb_dev *, unsigned int);
89433d6423SLionel Sambuc static void usb_driver_disconnect(struct ddekit_usb_dev *);
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc /* Simplified enumeration method for endpoint resolution */
92433d6423SLionel Sambuc static int mass_storage_get_endpoints(urb_ep_config *, urb_ep_config *);
93433d6423SLionel Sambuc static int mass_storage_parse_endpoint(usb_descriptor_t *, urb_ep_config *,
94433d6423SLionel Sambuc 					urb_ep_config *);
95433d6423SLionel Sambuc static int mass_storage_parse_descriptors(char *, unsigned int, urb_ep_config *,
96433d6423SLionel Sambuc 					urb_ep_config *);
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc /*---------------------------*
100433d6423SLionel Sambuc  *    defined variables      *
101433d6423SLionel Sambuc  *---------------------------*/
102*2d64210cSWojciech Zajac #define MASS_PACKED __attribute__((__packed__))
103*2d64210cSWojciech Zajac 
104433d6423SLionel Sambuc /* Mass Storage callback structure */
105433d6423SLionel Sambuc static struct blockdriver mass_storage = {
106433d6423SLionel Sambuc 	.bdr_type	= BLOCKDRIVER_TYPE_DISK,
107433d6423SLionel Sambuc 	.bdr_open	= mass_storage_open,
108433d6423SLionel Sambuc 	.bdr_close	= mass_storage_close,
109433d6423SLionel Sambuc 	.bdr_transfer	= mass_storage_transfer,
110433d6423SLionel Sambuc 	.bdr_ioctl	= mass_storage_ioctl,
111433d6423SLionel Sambuc 	.bdr_cleanup	= mass_storage_cleanup,
112433d6423SLionel Sambuc 	.bdr_part	= mass_storage_part,
113433d6423SLionel Sambuc 	.bdr_geometry	= mass_storage_geometry,
114433d6423SLionel Sambuc 	.bdr_intr	= NULL,
115433d6423SLionel Sambuc 	.bdr_alarm	= NULL,
116433d6423SLionel Sambuc 	.bdr_other	= NULL,
117433d6423SLionel Sambuc 	.bdr_device	= NULL
118433d6423SLionel Sambuc };
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc /* USB callback structure */
121433d6423SLionel Sambuc static struct ddekit_usb_driver mass_storage_driver = {
122433d6423SLionel Sambuc 	.completion	= usb_driver_completion,
123433d6423SLionel Sambuc 	.connect	= usb_driver_connect,
124433d6423SLionel Sambuc 	.disconnect	= usb_driver_disconnect
125433d6423SLionel Sambuc };
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc /* Instance of global driver information */
128433d6423SLionel Sambuc mass_storage_state driver_state;
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc /* Tags used to pair CBW and CSW for bulk communication
131433d6423SLionel Sambuc  * With this we can check if SCSI reply was meant for SCSI request */
132433d6423SLionel Sambuc static unsigned int current_cbw_tag = 0;	/* What shall be send next */
133433d6423SLionel Sambuc static unsigned int last_cbw_tag = 0;		/* What was sent recently */
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc /* Semaphore used to block mass storage thread to
136433d6423SLionel Sambuc  * allow DDE dispatcher operation */
137433d6423SLionel Sambuc static ddekit_sem_t * mass_storage_sem = NULL;
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc /* Mass storage (using libblockdriver) thread */
140433d6423SLionel Sambuc ddekit_thread_t * mass_storage_thread = NULL;
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc /* DDEKit USB message handling thread */
143433d6423SLionel Sambuc ddekit_thread_t * ddekit_usb_thread = NULL;
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc /* Static URB buffer size (must be multiple of SECTOR_SIZE) */
146433d6423SLionel Sambuc #define BUFFER_SIZE (64*SECTOR_SIZE)
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc /* Large buffer for URB read/write operations */
149433d6423SLionel Sambuc static unsigned char buffer[BUFFER_SIZE];
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc /* Length of local buffer where descriptors are temporarily stored */
152433d6423SLionel Sambuc #define MAX_DESCRIPTORS_LEN 128
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc /* Maximum 'Test Unit Ready' command retries */
155433d6423SLionel Sambuc #define MAX_TEST_RETRIES 3
156433d6423SLionel Sambuc 
157*2d64210cSWojciech Zajac /* 'Test Unit Ready' failure delay time (in nanoseconds) */
158*2d64210cSWojciech Zajac #define NEXT_TEST_DELAY 50000000 /* 50ms */
159*2d64210cSWojciech Zajac 
160*2d64210cSWojciech Zajac 
161433d6423SLionel Sambuc /*---------------------------*
162433d6423SLionel Sambuc  *    defined functions      *
163433d6423SLionel Sambuc  *---------------------------*/
164433d6423SLionel Sambuc /*===========================================================================*
165433d6423SLionel Sambuc  *    main                                                                   *
166433d6423SLionel Sambuc  *===========================================================================*/
167433d6423SLionel Sambuc int
main(int argc,char * argv[])168433d6423SLionel Sambuc main(int argc, char * argv[])
169433d6423SLionel Sambuc {
170433d6423SLionel Sambuc 	MASS_DEBUG_MSG("Starting...");
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc 	/* Store arguments for future parsing */
173433d6423SLionel Sambuc 	env_setargs(argc, argv);
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc 	/* Clear current state */
176433d6423SLionel Sambuc 	memset(&driver_state, 0, sizeof(driver_state));
177433d6423SLionel Sambuc 
178433d6423SLionel Sambuc 	/* Initialize SEF related callbacks */
179433d6423SLionel Sambuc 	sef_setcb_init_fresh(mass_storage_sef_hdlr);
180433d6423SLionel Sambuc 	sef_setcb_init_lu(mass_storage_sef_hdlr);
181433d6423SLionel Sambuc 	sef_setcb_init_restart(mass_storage_sef_hdlr);
182433d6423SLionel Sambuc 	sef_setcb_signal_handler(mass_storage_signal_handler);
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc 	/* Initialize DDEkit (involves sef_startup()) */
185433d6423SLionel Sambuc 	ddekit_init();
186433d6423SLionel Sambuc 	MASS_DEBUG_MSG("DDEkit ready...");
187433d6423SLionel Sambuc 
188433d6423SLionel Sambuc 	/* Semaphore initialization */
189433d6423SLionel Sambuc 	mass_storage_sem = ddekit_sem_init(0);
190433d6423SLionel Sambuc 	if (NULL == mass_storage_sem)
191433d6423SLionel Sambuc 		panic("Initializing mass_storage_sem failed!");
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc 	/* Starting mass storage thread */
194433d6423SLionel Sambuc 	mass_storage_thread = ddekit_thread_create(mass_storage_task, NULL,
195433d6423SLionel Sambuc 						"mass_storage_task");
196433d6423SLionel Sambuc 	if (NULL == mass_storage_thread)
197433d6423SLionel Sambuc 		panic("Initializing mass_storage_thread failed!");
198433d6423SLionel Sambuc 
199433d6423SLionel Sambuc 	MASS_DEBUG_MSG("Storage task (libblockdriver) ready...");
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 	/* Run USB IPC task to collect messages */
202433d6423SLionel Sambuc 	ddekit_usb_thread = ddekit_thread_create(ddekit_usb_task, NULL,
203433d6423SLionel Sambuc 						"ddekit_task" );
204433d6423SLionel Sambuc 	if (NULL == ddekit_usb_thread)
205433d6423SLionel Sambuc 		panic("Initializing ddekit_usb_thread failed!");
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc 	MASS_DEBUG_MSG("USB IPC task ready...");
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc 	/* Block and wait until exit signal is received */
210433d6423SLionel Sambuc 	ddekit_minix_wait_exit();
211433d6423SLionel Sambuc 	MASS_DEBUG_MSG("Exiting...");
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc 	/* Release objects that were explicitly allocated above */
214433d6423SLionel Sambuc 	ddekit_thread_terminate(ddekit_usb_thread);
215433d6423SLionel Sambuc 	ddekit_thread_terminate(mass_storage_thread);
216433d6423SLionel Sambuc 	ddekit_sem_deinit(mass_storage_sem);
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 	/* TODO: no ddekit_deinit for proper cleanup? */
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc 	MASS_DEBUG_MSG("Cleanup completed...");
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 	return EXIT_SUCCESS;
223433d6423SLionel Sambuc }
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc /*===========================================================================*
227433d6423SLionel Sambuc  *    mass_storage_send_scsi_cbw_out                                         *
228433d6423SLionel Sambuc  *===========================================================================*/
229433d6423SLionel Sambuc static int
mass_storage_send_scsi_cbw_out(int scsi_cmd,scsi_transfer * info)230433d6423SLionel Sambuc mass_storage_send_scsi_cbw_out(int scsi_cmd, scsi_transfer * info)
231433d6423SLionel Sambuc {
232433d6423SLionel Sambuc 	/* URB to be send */
233433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
234433d6423SLionel Sambuc 
235433d6423SLionel Sambuc 	/* CBW data buffer */
236433d6423SLionel Sambuc 	mass_storage_cbw cbw;
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 	/* Reset URB and assign given values */
241433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev,
242433d6423SLionel Sambuc 		&(driver_state.cur_periph->ep_out));
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc 	/* Reset CBW and assign default values */
245433d6423SLionel Sambuc 	init_cbw(&cbw, last_cbw_tag = current_cbw_tag++);
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 	/* Fill CBW with SCSI command */
248433d6423SLionel Sambuc 	if (create_scsi_cmd(&cbw, scsi_cmd, info))
249433d6423SLionel Sambuc 		return EXIT_FAILURE;
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 	/* Attach CBW to URB */
252433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_DATA, &cbw, sizeof(cbw));
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 	/* Send and wait for response */
255433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem, URB_SUBMIT_CHECK_LEN))
256433d6423SLionel Sambuc 		return EXIT_FAILURE;
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc 	return EXIT_SUCCESS;
259433d6423SLionel Sambuc }
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc 
262433d6423SLionel Sambuc /*===========================================================================*
263433d6423SLionel Sambuc  *    mass_storage_send_scsi_data_in                                         *
264433d6423SLionel Sambuc  *===========================================================================*/
265433d6423SLionel Sambuc static int
mass_storage_send_scsi_data_in(void * buf,unsigned int in_len)266433d6423SLionel Sambuc mass_storage_send_scsi_data_in(void * buf, unsigned int in_len)
267433d6423SLionel Sambuc {
268433d6423SLionel Sambuc 	/* URB to be send */
269433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc 	/* Reset URB and assign given values */
274433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev,
275433d6423SLionel Sambuc 		&(driver_state.cur_periph->ep_in));
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc 	/* Attach buffer to URB */
278433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_DATA, buf, in_len);
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	/* Send and wait for response */
281433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem, URB_SUBMIT_CHECK_LEN))
282433d6423SLionel Sambuc 		return EXIT_FAILURE;
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc 	return EXIT_SUCCESS;
285433d6423SLionel Sambuc }
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc /*===========================================================================*
289433d6423SLionel Sambuc  *    mass_storage_send_scsi_data_out                                        *
290433d6423SLionel Sambuc  *===========================================================================*/
291433d6423SLionel Sambuc static int
mass_storage_send_scsi_data_out(void * buf,unsigned int out_len)292433d6423SLionel Sambuc mass_storage_send_scsi_data_out(void * buf, unsigned int out_len)
293433d6423SLionel Sambuc {
294433d6423SLionel Sambuc 	/* URB to be send */
295433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc 	/* Reset URB and assign given values */
300433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev,
301433d6423SLionel Sambuc 		&(driver_state.cur_periph->ep_out));
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc 	/* Attach buffer to URB */
304433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_DATA, buf, out_len);
305433d6423SLionel Sambuc 
306433d6423SLionel Sambuc 	/* Send and wait for response */
307433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem, URB_SUBMIT_CHECK_LEN))
308433d6423SLionel Sambuc 		return EXIT_FAILURE;
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc 	return EXIT_SUCCESS;
311433d6423SLionel Sambuc }
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc /*===========================================================================*
315433d6423SLionel Sambuc  *    mass_storage_send_scsi_csw_in                                          *
316433d6423SLionel Sambuc  *===========================================================================*/
317433d6423SLionel Sambuc static int
mass_storage_send_scsi_csw_in(void)318433d6423SLionel Sambuc mass_storage_send_scsi_csw_in(void)
319433d6423SLionel Sambuc {
320433d6423SLionel Sambuc 	/* URB to be send */
321433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc 	/* CBW data buffer */
324433d6423SLionel Sambuc 	mass_storage_csw csw;
325433d6423SLionel Sambuc 
326433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc 	/* Reset URB and assign given values */
329433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev,
330433d6423SLionel Sambuc 		&(driver_state.cur_periph->ep_in));
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc 	/* Clear CSW for receiving */
333433d6423SLionel Sambuc 	init_csw(&csw);
334433d6423SLionel Sambuc 
335433d6423SLionel Sambuc 	/* Attach CSW to URB */
336433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_DATA, &csw, sizeof(csw));
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc 	/* Send and wait for response */
339433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem, URB_SUBMIT_CHECK_LEN))
340433d6423SLionel Sambuc 		return EXIT_FAILURE;
341433d6423SLionel Sambuc 
342433d6423SLionel Sambuc 	/* Check for proper reply */
343433d6423SLionel Sambuc 	if (check_csw(&csw, last_cbw_tag))
344433d6423SLionel Sambuc 		return EXIT_FAILURE;
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc 	return EXIT_SUCCESS;
347433d6423SLionel Sambuc }
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc #ifdef MASS_RESET_RECOVERY
351433d6423SLionel Sambuc /*===========================================================================*
352433d6423SLionel Sambuc  *    mass_storage_reset_recovery                                            *
353433d6423SLionel Sambuc  *===========================================================================*/
354433d6423SLionel Sambuc static int
mass_storage_reset_recovery(void)355433d6423SLionel Sambuc mass_storage_reset_recovery(void)
356433d6423SLionel Sambuc {
357433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	/* Bulk-Only Mass Storage Reset */
360433d6423SLionel Sambuc 	if (mass_storage_send_bulk_reset()) {
361433d6423SLionel Sambuc 		MASS_MSG("Bulk-only mass storage reset failed");
362433d6423SLionel Sambuc 		return EIO;
363433d6423SLionel Sambuc 	}
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc 	/* Clear Feature HALT to the Bulk-In endpoint */
366433d6423SLionel Sambuc 	if (URB_INVALID_EP != driver_state.cur_periph->ep_in.ep_num)
367433d6423SLionel Sambuc 		if (mass_storage_send_clear_feature(
368433d6423SLionel Sambuc 					driver_state.cur_periph->ep_in.ep_num,
369433d6423SLionel Sambuc 					DDEKIT_USB_IN)) {
370433d6423SLionel Sambuc 			MASS_MSG("Resetting IN EP failed");
371433d6423SLionel Sambuc 			return EIO;
372433d6423SLionel Sambuc 		}
373433d6423SLionel Sambuc 
374433d6423SLionel Sambuc 	/* Clear Feature HALT to the Bulk-Out endpoint */
375433d6423SLionel Sambuc 	if (URB_INVALID_EP != driver_state.cur_periph->ep_out.ep_num)
376433d6423SLionel Sambuc 		if (mass_storage_send_clear_feature(
377433d6423SLionel Sambuc 					driver_state.cur_periph->ep_out.ep_num,
378433d6423SLionel Sambuc 					DDEKIT_USB_OUT)) {
379433d6423SLionel Sambuc 			MASS_MSG("Resetting OUT EP failed");
380433d6423SLionel Sambuc 			return EIO;
381433d6423SLionel Sambuc 		}
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc 	return EXIT_SUCCESS;
384433d6423SLionel Sambuc }
385433d6423SLionel Sambuc 
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc /*===========================================================================*
388433d6423SLionel Sambuc  *    mass_storage_send_bulk_reset                                           *
389433d6423SLionel Sambuc  *===========================================================================*/
390433d6423SLionel Sambuc static int
mass_storage_send_bulk_reset(void)391433d6423SLionel Sambuc mass_storage_send_bulk_reset(void)
392433d6423SLionel Sambuc {
393433d6423SLionel Sambuc 	/* URB to be send */
394433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc 	/* Setup buffer to be send */
397433d6423SLionel Sambuc 	struct usb_ctrlrequest bulk_setup;
398433d6423SLionel Sambuc 
399433d6423SLionel Sambuc 	/* Control EP configuration */
400433d6423SLionel Sambuc 	urb_ep_config ep_conf;
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc 	/* Initialize EP configuration */
405433d6423SLionel Sambuc 	ep_conf.ep_num = 0;
406433d6423SLionel Sambuc 	ep_conf.direction = DDEKIT_USB_OUT;
407433d6423SLionel Sambuc 	ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
408433d6423SLionel Sambuc 	ep_conf.max_packet_size = 0;
409433d6423SLionel Sambuc 	ep_conf.interval = 0;
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc 	/* Reset URB and assign given values */
412433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev, &ep_conf);
413433d6423SLionel Sambuc 
414433d6423SLionel Sambuc 	/* Clear setup data */
415433d6423SLionel Sambuc 	memset(&bulk_setup, 0, sizeof(bulk_setup));
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc 	/* For explanation of these values see usbmassbulk_10.pdf */
418433d6423SLionel Sambuc 	/* 3.1 Bulk-Only Mass Storage Reset */
419433d6423SLionel Sambuc 	bulk_setup.bRequestType = 0x21; /* Class, Interface, host to device */
420433d6423SLionel Sambuc 	bulk_setup.bRequest = 0xff;
421433d6423SLionel Sambuc 	bulk_setup.wValue = 0x00;
422433d6423SLionel Sambuc 	bulk_setup.wIndex = 0x00; /* TODO: hard-coded interface 0 */
423433d6423SLionel Sambuc 	bulk_setup.wLength = 0x00;
424433d6423SLionel Sambuc 
425433d6423SLionel Sambuc 	/* Attach request to URB */
426433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
427433d6423SLionel Sambuc 			&bulk_setup, sizeof(bulk_setup));
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc 	/* Send and wait for response */
430433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem, URB_SUBMIT_CHECK_LEN))
431433d6423SLionel Sambuc 		return EXIT_FAILURE;
432433d6423SLionel Sambuc 
433433d6423SLionel Sambuc 	return EXIT_SUCCESS;
434433d6423SLionel Sambuc }
435433d6423SLionel Sambuc 
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc /*===========================================================================*
438433d6423SLionel Sambuc  *    mass_storage_send_clear_feature                                        *
439433d6423SLionel Sambuc  *===========================================================================*/
440433d6423SLionel Sambuc static int
mass_storage_send_clear_feature(int ep_num,int direction)441433d6423SLionel Sambuc mass_storage_send_clear_feature(int ep_num, int direction)
442433d6423SLionel Sambuc {
443433d6423SLionel Sambuc 	/* URB to be send */
444433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
445433d6423SLionel Sambuc 
446433d6423SLionel Sambuc 	/* Setup buffer to be send */
447433d6423SLionel Sambuc 	struct usb_ctrlrequest bulk_setup;
448433d6423SLionel Sambuc 
449433d6423SLionel Sambuc 	/* Control EP configuration */
450433d6423SLionel Sambuc 	urb_ep_config ep_conf;
451433d6423SLionel Sambuc 
452433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc 	assert((ep_num >= 0) && (ep_num < 16));
455433d6423SLionel Sambuc 	assert((DDEKIT_USB_OUT == direction) || (DDEKIT_USB_IN == direction));
456433d6423SLionel Sambuc 
457433d6423SLionel Sambuc 	/* Initialize EP configuration */
458433d6423SLionel Sambuc 	ep_conf.ep_num = 0;
459433d6423SLionel Sambuc 	ep_conf.direction = DDEKIT_USB_OUT;
460433d6423SLionel Sambuc 	ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
461433d6423SLionel Sambuc 	ep_conf.max_packet_size = 0;
462433d6423SLionel Sambuc 	ep_conf.interval = 0;
463433d6423SLionel Sambuc 
464433d6423SLionel Sambuc 	/* Reset URB and assign given values */
465433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev, &ep_conf);
466433d6423SLionel Sambuc 
467433d6423SLionel Sambuc 	/* Clear setup data */
468433d6423SLionel Sambuc 	memset(&bulk_setup, 0, sizeof(bulk_setup));
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 	/* For explanation of these values see usbmassbulk_10.pdf */
471433d6423SLionel Sambuc 	/* 3.1 Bulk-Only Mass Storage Reset */
472433d6423SLionel Sambuc 	bulk_setup.bRequestType = 0x02; /* Standard, Endpoint, host to device */
473433d6423SLionel Sambuc 	bulk_setup.bRequest = 0x01; /* CLEAR_FEATURE */
474433d6423SLionel Sambuc 	bulk_setup.wValue = 0x00; /* Endpoint */
475433d6423SLionel Sambuc 	bulk_setup.wIndex = ep_num; /* Endpoint number... */
476433d6423SLionel Sambuc 	if (DDEKIT_USB_IN == direction)
477433d6423SLionel Sambuc 		bulk_setup.wIndex |= UE_DIR_IN; /* ...and direction bit */
478433d6423SLionel Sambuc 	bulk_setup.wLength = 0x00;
479433d6423SLionel Sambuc 
480433d6423SLionel Sambuc 	/* Attach request to URB */
481433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
482433d6423SLionel Sambuc 			&bulk_setup, sizeof(bulk_setup));
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc 	/* Send and wait for response */
485433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem, URB_SUBMIT_CHECK_LEN))
486433d6423SLionel Sambuc 		return EXIT_FAILURE;
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc 	return EXIT_SUCCESS;
489433d6423SLionel Sambuc }
490433d6423SLionel Sambuc #endif
491433d6423SLionel Sambuc 
492433d6423SLionel Sambuc 
493433d6423SLionel Sambuc /*===========================================================================*
494433d6423SLionel Sambuc  *    mass_storage_sef_hdlr                                                  *
495433d6423SLionel Sambuc  *===========================================================================*/
496433d6423SLionel Sambuc static int
mass_storage_sef_hdlr(int type,sef_init_info_t * UNUSED (info))497433d6423SLionel Sambuc mass_storage_sef_hdlr(int type, sef_init_info_t * UNUSED(info))
498433d6423SLionel Sambuc {
499433d6423SLionel Sambuc 	int env_res;
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
502433d6423SLionel Sambuc 
503433d6423SLionel Sambuc 	/* Parse given environment */
504433d6423SLionel Sambuc 	env_res = env_parse("instance", "d", 0,
505433d6423SLionel Sambuc 			&(driver_state.instance),0, 255);
506433d6423SLionel Sambuc 
507433d6423SLionel Sambuc 	/* Get instance number */
508433d6423SLionel Sambuc 	if (EP_UNSET == env_res) {
509433d6423SLionel Sambuc 		MASS_DEBUG_MSG("Instance number was not supplied");
510433d6423SLionel Sambuc 		driver_state.instance = 0;
511433d6423SLionel Sambuc 	} else {
512433d6423SLionel Sambuc 		/* Only SET and UNSET are allowed */
513433d6423SLionel Sambuc 		if (EP_SET != env_res)
514433d6423SLionel Sambuc 			return EXIT_FAILURE;
515433d6423SLionel Sambuc 	}
516433d6423SLionel Sambuc 
517433d6423SLionel Sambuc 	switch (type) {
518433d6423SLionel Sambuc 		case SEF_INIT_FRESH:
519433d6423SLionel Sambuc 			/* Announce we are up! */
520433d6423SLionel Sambuc 			blockdriver_announce(type);
521433d6423SLionel Sambuc 			return EXIT_SUCCESS;
522433d6423SLionel Sambuc 		case SEF_INIT_LU:
523433d6423SLionel Sambuc 		case SEF_INIT_RESTART:
524433d6423SLionel Sambuc 			MASS_MSG("Only 'fresh' SEF initialization supported\n");
525433d6423SLionel Sambuc 			break;
526433d6423SLionel Sambuc 		default:
527433d6423SLionel Sambuc 			MASS_MSG("illegal SEF type\n");
528433d6423SLionel Sambuc 			break;
529433d6423SLionel Sambuc 	}
530433d6423SLionel Sambuc 
531433d6423SLionel Sambuc 	return EXIT_FAILURE;
532433d6423SLionel Sambuc }
533433d6423SLionel Sambuc 
534433d6423SLionel Sambuc 
535433d6423SLionel Sambuc /*===========================================================================*
536433d6423SLionel Sambuc  *    mass_storage_signal_handler                                            *
537433d6423SLionel Sambuc  *===========================================================================*/
538433d6423SLionel Sambuc static void
mass_storage_signal_handler(int this_signal)539433d6423SLionel Sambuc mass_storage_signal_handler(int this_signal)
540433d6423SLionel Sambuc {
541433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
542433d6423SLionel Sambuc 
543433d6423SLionel Sambuc #ifdef USB_STORAGE_SIGNAL
544433d6423SLionel Sambuc 	/* Only check for termination signal, ignore anything else. */
545433d6423SLionel Sambuc 	if (this_signal != SIGTERM)
546433d6423SLionel Sambuc 		return;
547433d6423SLionel Sambuc #else
548433d6423SLionel Sambuc 	MASS_MSG("Handling signal 0x%X", this_signal);
549433d6423SLionel Sambuc #endif
550433d6423SLionel Sambuc 
551433d6423SLionel Sambuc 	/* Try graceful DDEKit exit */
552433d6423SLionel Sambuc 	ddekit_shutdown();
553433d6423SLionel Sambuc 
554433d6423SLionel Sambuc 	/* Unreachable, when ddekit_shutdown works correctly */
555433d6423SLionel Sambuc 	panic("Calling ddekit_shutdown failed!");
556433d6423SLionel Sambuc }
557433d6423SLionel Sambuc 
558433d6423SLionel Sambuc 
559433d6423SLionel Sambuc /*===========================================================================*
560433d6423SLionel Sambuc  *    ddekit_usb_task                                                        *
561433d6423SLionel Sambuc  *===========================================================================*/
562433d6423SLionel Sambuc static void
ddekit_usb_task(void * UNUSED (arg))563433d6423SLionel Sambuc ddekit_usb_task(void * UNUSED(arg))
564433d6423SLionel Sambuc {
565433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
566433d6423SLionel Sambuc 
567433d6423SLionel Sambuc 	/* TODO: This call was meant to return 'int' but loops forever instead,
568433d6423SLionel Sambuc 	 * so no return value is checked */
569433d6423SLionel Sambuc 	ddekit_usb_init(&mass_storage_driver, NULL, NULL);
570433d6423SLionel Sambuc }
571433d6423SLionel Sambuc 
572433d6423SLionel Sambuc 
573433d6423SLionel Sambuc /*===========================================================================*
574433d6423SLionel Sambuc  *    mass_storage_task                                                      *
575433d6423SLionel Sambuc  *===========================================================================*/
576433d6423SLionel Sambuc static void
mass_storage_task(void * UNUSED (unused))577433d6423SLionel Sambuc mass_storage_task(void * UNUSED(unused))
578433d6423SLionel Sambuc {
579433d6423SLionel Sambuc 	message m;
580433d6423SLionel Sambuc 	int ipc_status;
581433d6423SLionel Sambuc 	struct ddekit_minix_msg_q * mq;
582433d6423SLionel Sambuc 
583433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
584433d6423SLionel Sambuc 
585433d6423SLionel Sambuc 	mq = ddekit_minix_create_msg_q(BDEV_RQ_BASE, BDEV_RQ_BASE + 0xff);
586433d6423SLionel Sambuc 
587433d6423SLionel Sambuc 	for (;;) {
588433d6423SLionel Sambuc 		ddekit_minix_rcv(mq, &m, &ipc_status);
589433d6423SLionel Sambuc 		blockdriver_process(&mass_storage, &m, ipc_status);
590433d6423SLionel Sambuc 	}
591433d6423SLionel Sambuc }
592433d6423SLionel Sambuc 
593433d6423SLionel Sambuc 
594433d6423SLionel Sambuc /*===========================================================================*
595433d6423SLionel Sambuc  *    mass_storage_test                                                      *
596433d6423SLionel Sambuc  *===========================================================================*/
597433d6423SLionel Sambuc static int
mass_storage_test(void)598433d6423SLionel Sambuc mass_storage_test(void)
599433d6423SLionel Sambuc {
600433d6423SLionel Sambuc 	int repeat;
601*2d64210cSWojciech Zajac 	int error;
602*2d64210cSWojciech Zajac 
603*2d64210cSWojciech Zajac 	struct timespec test_wait;
604433d6423SLionel Sambuc 
605433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
606433d6423SLionel Sambuc 
607*2d64210cSWojciech Zajac 	/* Delay between consecutive test commands, in case of their failure */
608*2d64210cSWojciech Zajac 	test_wait.tv_nsec = NEXT_TEST_DELAY;
609*2d64210cSWojciech Zajac 	test_wait.tv_sec = 0;
610*2d64210cSWojciech Zajac 
611433d6423SLionel Sambuc 	for (repeat = 0; repeat < MAX_TEST_RETRIES; repeat++) {
612433d6423SLionel Sambuc 
613433d6423SLionel Sambuc 		/* SCSI TEST UNIT READY OUT stage */
614433d6423SLionel Sambuc 		if (mass_storage_send_scsi_cbw_out(SCSI_TEST_UNIT_READY, NULL))
615*2d64210cSWojciech Zajac 			return EIO;
616433d6423SLionel Sambuc 
617433d6423SLionel Sambuc 		/* TODO: Only CSW failure should normally contribute to retry */
618433d6423SLionel Sambuc 
619433d6423SLionel Sambuc 		/* SCSI TEST UNIT READY IN stage */
620433d6423SLionel Sambuc 		if (EXIT_SUCCESS == mass_storage_send_scsi_csw_in())
621433d6423SLionel Sambuc 			return EXIT_SUCCESS;
622*2d64210cSWojciech Zajac 
623*2d64210cSWojciech Zajac 		/* Check for errors */
624*2d64210cSWojciech Zajac 		if (EXIT_SUCCESS != (error = mass_storage_check_error())) {
625*2d64210cSWojciech Zajac 			MASS_MSG("SCSI sense error checking failed");
626*2d64210cSWojciech Zajac 			return error;
627433d6423SLionel Sambuc 		}
628433d6423SLionel Sambuc 
629*2d64210cSWojciech Zajac 		/* Ignore potential signal interruption (no return value check),
630*2d64210cSWojciech Zajac 		 * since it causes driver termination anyway */
631*2d64210cSWojciech Zajac 		if (nanosleep(&test_wait, NULL))
632*2d64210cSWojciech Zajac 			MASS_MSG("Calling nanosleep() failed");
633*2d64210cSWojciech Zajac 	}
634*2d64210cSWojciech Zajac 
635*2d64210cSWojciech Zajac 	return EIO;
636*2d64210cSWojciech Zajac }
637*2d64210cSWojciech Zajac 
638*2d64210cSWojciech Zajac 
639*2d64210cSWojciech Zajac /*===========================================================================*
640*2d64210cSWojciech Zajac  *    mass_storage_check_error                                               *
641*2d64210cSWojciech Zajac  *===========================================================================*/
642*2d64210cSWojciech Zajac static int
mass_storage_check_error(void)643*2d64210cSWojciech Zajac mass_storage_check_error(void)
644*2d64210cSWojciech Zajac {
645*2d64210cSWojciech Zajac 	/* SCSI sense structure for local use */
646*2d64210cSWojciech Zajac 	typedef struct MASS_PACKED scsi_sense {
647*2d64210cSWojciech Zajac 
648*2d64210cSWojciech Zajac 		uint8_t code : 7;
649*2d64210cSWojciech Zajac 		uint8_t valid : 1;
650*2d64210cSWojciech Zajac 		uint8_t obsolete : 8;
651*2d64210cSWojciech Zajac 		uint8_t sense : 4;
652*2d64210cSWojciech Zajac 		uint8_t reserved : 1;
653*2d64210cSWojciech Zajac 		uint8_t ili : 1;
654*2d64210cSWojciech Zajac 		uint8_t eom : 1;
655*2d64210cSWojciech Zajac 		uint8_t filemark : 1;
656*2d64210cSWojciech Zajac 		uint32_t information : 32;
657*2d64210cSWojciech Zajac 		uint8_t additional_len : 8;
658*2d64210cSWojciech Zajac 		uint32_t command_specific : 32;
659*2d64210cSWojciech Zajac 		uint8_t additional_code : 8;
660*2d64210cSWojciech Zajac 		uint8_t additional_qual : 8;
661*2d64210cSWojciech Zajac 		uint8_t unit_code : 8;
662*2d64210cSWojciech Zajac 		uint8_t key_specific1 : 7;
663*2d64210cSWojciech Zajac 		uint8_t sksv : 1;
664*2d64210cSWojciech Zajac 		uint16_t key_specific2 : 16;
665*2d64210cSWojciech Zajac 	}
666*2d64210cSWojciech Zajac 	scsi_sense;
667*2d64210cSWojciech Zajac 
668*2d64210cSWojciech Zajac 	/* Sense variable to hold received data */
669*2d64210cSWojciech Zajac 	scsi_sense sense;
670*2d64210cSWojciech Zajac 
671*2d64210cSWojciech Zajac 	MASS_DEBUG_DUMP;
672*2d64210cSWojciech Zajac 
673*2d64210cSWojciech Zajac 	/* Check if bit-fields are packed correctly */
674*2d64210cSWojciech Zajac 	__CTASSERT(sizeof(sense) == SCSI_REQUEST_SENSE_DATA_LEN);
675*2d64210cSWojciech Zajac 
676*2d64210cSWojciech Zajac 	/* SCSI REQUEST SENSE OUT stage */
677*2d64210cSWojciech Zajac 	if (mass_storage_send_scsi_cbw_out(SCSI_REQUEST_SENSE, NULL))
678*2d64210cSWojciech Zajac 		return EIO;
679*2d64210cSWojciech Zajac 
680*2d64210cSWojciech Zajac 	/* SCSI REQUEST SENSE first IN stage */
681*2d64210cSWojciech Zajac 	if (mass_storage_send_scsi_data_in(&sense, sizeof(sense)))
682*2d64210cSWojciech Zajac 		return EIO;
683*2d64210cSWojciech Zajac 
684*2d64210cSWojciech Zajac 	/* SCSI REQUEST SENSE second IN stage */
685*2d64210cSWojciech Zajac 	if (mass_storage_send_scsi_csw_in())
686*2d64210cSWojciech Zajac 		return EIO;
687*2d64210cSWojciech Zajac 
688*2d64210cSWojciech Zajac 	/* When any sense code is present something may have failed */
689*2d64210cSWojciech Zajac 	if (sense.sense) {
690*2d64210cSWojciech Zajac #ifdef MASS_DEBUG
691*2d64210cSWojciech Zajac 		MASS_MSG("SCSI sense:                ");
692*2d64210cSWojciech Zajac 		MASS_MSG("code             : %8X", sense.code            );
693*2d64210cSWojciech Zajac 		MASS_MSG("valid            : %8X", sense.valid           );
694*2d64210cSWojciech Zajac 		MASS_MSG("obsolete         : %8X", sense.obsolete        );
695*2d64210cSWojciech Zajac 		MASS_MSG("sense            : %8X", sense.sense           );
696*2d64210cSWojciech Zajac 		MASS_MSG("reserved         : %8X", sense.reserved        );
697*2d64210cSWojciech Zajac 		MASS_MSG("ili              : %8X", sense.ili             );
698*2d64210cSWojciech Zajac 		MASS_MSG("eom              : %8X", sense.eom             );
699*2d64210cSWojciech Zajac 		MASS_MSG("filemark         : %8X", sense.filemark        );
700*2d64210cSWojciech Zajac 		MASS_MSG("information      : %8X", sense.information     );
701*2d64210cSWojciech Zajac 		MASS_MSG("additional_len   : %8X", sense.additional_len  );
702*2d64210cSWojciech Zajac 		MASS_MSG("command_specific : %8X", sense.command_specific);
703*2d64210cSWojciech Zajac 		MASS_MSG("additional_code  : %8X", sense.additional_code );
704*2d64210cSWojciech Zajac 		MASS_MSG("additional_qual  : %8X", sense.additional_qual );
705*2d64210cSWojciech Zajac 		MASS_MSG("unit_code        : %8X", sense.unit_code       );
706*2d64210cSWojciech Zajac 		MASS_MSG("key_specific1    : %8X", sense.key_specific1   );
707*2d64210cSWojciech Zajac 		MASS_MSG("sksv             : %8X", sense.sksv            );
708*2d64210cSWojciech Zajac 		MASS_MSG("key_specific2    : %8X", sense.key_specific2   );
709*2d64210cSWojciech Zajac #else
710*2d64210cSWojciech Zajac 		MASS_MSG("SCSI sense: 0x%02X 0x%02X 0x%02X", sense.sense,
711*2d64210cSWojciech Zajac 			sense.additional_code, sense.additional_qual);
712*2d64210cSWojciech Zajac #endif
713*2d64210cSWojciech Zajac 	}
714*2d64210cSWojciech Zajac 
715*2d64210cSWojciech Zajac 	return EXIT_SUCCESS;
716433d6423SLionel Sambuc }
717433d6423SLionel Sambuc 
718433d6423SLionel Sambuc 
719433d6423SLionel Sambuc /*===========================================================================*
720433d6423SLionel Sambuc  *    mass_storage_try_first_open                                            *
721433d6423SLionel Sambuc  *===========================================================================*/
722433d6423SLionel Sambuc static int
mass_storage_try_first_open()723433d6423SLionel Sambuc mass_storage_try_first_open()
724433d6423SLionel Sambuc {
725433d6423SLionel Sambuc 	unsigned int llba;
726433d6423SLionel Sambuc 	unsigned int blen;
727433d6423SLionel Sambuc 	unsigned char inquiry[SCSI_INQUIRY_DATA_LEN];
728433d6423SLionel Sambuc 	unsigned char capacity[SCSI_READ_CAPACITY_DATA_LEN];
729433d6423SLionel Sambuc 
730433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
731433d6423SLionel Sambuc 
732433d6423SLionel Sambuc 	assert(NULL != driver_state.cur_drive);
733433d6423SLionel Sambuc 
734433d6423SLionel Sambuc 	llba = 0; /* Last logical block address */
735433d6423SLionel Sambuc 	blen = 0; /* Block length (usually 512B) */
736433d6423SLionel Sambuc 
737433d6423SLionel Sambuc 	/* Run TEST UNIT READY before other SCSI command
738433d6423SLionel Sambuc 	 * Some devices refuse to work without this */
739433d6423SLionel Sambuc 	if (mass_storage_test())
740433d6423SLionel Sambuc 		return EIO;
741433d6423SLionel Sambuc 
742433d6423SLionel Sambuc 	/* SCSI INQUIRY OUT stage */
743433d6423SLionel Sambuc 	if (mass_storage_send_scsi_cbw_out(SCSI_INQUIRY, NULL))
744433d6423SLionel Sambuc 		return EIO;
745433d6423SLionel Sambuc 
746433d6423SLionel Sambuc 	/* SCSI INQUIRY first IN stage */
747433d6423SLionel Sambuc 	if (mass_storage_send_scsi_data_in(inquiry, sizeof(inquiry)))
748433d6423SLionel Sambuc 		return EIO;
749433d6423SLionel Sambuc 
750433d6423SLionel Sambuc 	/* SCSI INQUIRY second IN stage */
751433d6423SLionel Sambuc 	if (mass_storage_send_scsi_csw_in())
752433d6423SLionel Sambuc 		return EIO;
753433d6423SLionel Sambuc 
754433d6423SLionel Sambuc 	/* Check for proper reply */
755433d6423SLionel Sambuc 	if (check_inquiry_reply(inquiry))
756433d6423SLionel Sambuc 		return EIO;
757433d6423SLionel Sambuc 
758433d6423SLionel Sambuc 	/* Run TEST UNIT READY before other SCSI command
759433d6423SLionel Sambuc 	 * Some devices refuse to work without this */
760433d6423SLionel Sambuc 	if (mass_storage_test())
761433d6423SLionel Sambuc 		return EIO;
762433d6423SLionel Sambuc 
763433d6423SLionel Sambuc 	/* SCSI READ CAPACITY OUT stage */
764433d6423SLionel Sambuc 	if (mass_storage_send_scsi_cbw_out(SCSI_READ_CAPACITY, NULL))
765433d6423SLionel Sambuc 		return EIO;
766433d6423SLionel Sambuc 
767433d6423SLionel Sambuc 	/* SCSI READ CAPACITY first IN stage */
768433d6423SLionel Sambuc 	if (mass_storage_send_scsi_data_in(capacity, sizeof(capacity)))
769433d6423SLionel Sambuc 		return EIO;
770433d6423SLionel Sambuc 
771433d6423SLionel Sambuc 	/* SCSI READ CAPACITY second IN stage */
772433d6423SLionel Sambuc 	if (mass_storage_send_scsi_csw_in())
773433d6423SLionel Sambuc 		return EIO;
774433d6423SLionel Sambuc 
775433d6423SLionel Sambuc 	/* Check for proper reply */
776433d6423SLionel Sambuc 	if (check_read_capacity_reply(capacity, &llba, &blen))
777433d6423SLionel Sambuc 		return EIO;
778433d6423SLionel Sambuc 
779433d6423SLionel Sambuc 	/* For now only Minix's default SECTOR_SIZE is supported */
780433d6423SLionel Sambuc 	if (SECTOR_SIZE != blen)
781433d6423SLionel Sambuc 		panic("Invalid block size used by USB device!");
782433d6423SLionel Sambuc 
783433d6423SLionel Sambuc 	/* Get information about capacity from reply */
784433d6423SLionel Sambuc 	driver_state.cur_drive->disk.dv_base = 0;
785433d6423SLionel Sambuc 	driver_state.cur_drive->disk.dv_size = llba * blen;
786433d6423SLionel Sambuc 
787433d6423SLionel Sambuc 	return EXIT_SUCCESS;
788433d6423SLionel Sambuc }
789433d6423SLionel Sambuc 
790433d6423SLionel Sambuc 
791433d6423SLionel Sambuc /*===========================================================================*
792433d6423SLionel Sambuc  *    mass_storage_transfer_restrictions                                     *
793433d6423SLionel Sambuc  *===========================================================================*/
794433d6423SLionel Sambuc static int
mass_storage_transfer_restrictions(u64_t pos,unsigned long bytes)795433d6423SLionel Sambuc mass_storage_transfer_restrictions(u64_t pos, unsigned long bytes)
796433d6423SLionel Sambuc {
797433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
798433d6423SLionel Sambuc 
799433d6423SLionel Sambuc 	assert(NULL != driver_state.cur_device);
800433d6423SLionel Sambuc 
801433d6423SLionel Sambuc 	/* Zero-length request must not be issued */
802433d6423SLionel Sambuc 	if (0 == bytes) {
803433d6423SLionel Sambuc 		MASS_MSG("Transfer request length equals 0");
804433d6423SLionel Sambuc 		return EINVAL;
805433d6423SLionel Sambuc 	}
806433d6423SLionel Sambuc 
807433d6423SLionel Sambuc 	/* Starting position must be aligned to sector */
808433d6423SLionel Sambuc 	if (0 != (pos % SECTOR_SIZE)) {
809433d6423SLionel Sambuc 		MASS_MSG("Transfer position not divisible by %u", SECTOR_SIZE);
810433d6423SLionel Sambuc 		return EINVAL;
811433d6423SLionel Sambuc 	}
812433d6423SLionel Sambuc 
813433d6423SLionel Sambuc 	/* Length must be integer multiple of sector sizes */
814433d6423SLionel Sambuc 	if (0 != (bytes % SECTOR_SIZE)) {
815433d6423SLionel Sambuc 		MASS_MSG("Data length not divisible by %u", SECTOR_SIZE);
816433d6423SLionel Sambuc 		return EINVAL;
817433d6423SLionel Sambuc 	}
818433d6423SLionel Sambuc 
819433d6423SLionel Sambuc 	/* Guard against ridiculous 64B overflow */
820433d6423SLionel Sambuc 	if ((pos + bytes) <= pos) {
821433d6423SLionel Sambuc 		MASS_MSG("Request outside available address space");
822433d6423SLionel Sambuc 		return EINVAL;
823433d6423SLionel Sambuc 	}
824433d6423SLionel Sambuc 
825433d6423SLionel Sambuc 	return EXIT_SUCCESS;
826433d6423SLionel Sambuc }
827433d6423SLionel Sambuc 
828433d6423SLionel Sambuc 
829433d6423SLionel Sambuc /*===========================================================================*
830433d6423SLionel Sambuc  *    mass_storage_write                                                     *
831433d6423SLionel Sambuc  *===========================================================================*/
832433d6423SLionel Sambuc static ssize_t
mass_storage_write(unsigned long sector_number,endpoint_t endpt,iovec_t * iov,unsigned int iov_count,unsigned long bytes_left)833433d6423SLionel Sambuc mass_storage_write(unsigned long sector_number,
834433d6423SLionel Sambuc 		endpoint_t endpt,
835433d6423SLionel Sambuc 		iovec_t * iov,
836433d6423SLionel Sambuc 		unsigned int iov_count,
837433d6423SLionel Sambuc 		unsigned long bytes_left)
838433d6423SLionel Sambuc {
839433d6423SLionel Sambuc 	/*
840433d6423SLionel Sambuc 	 * This function writes whatever was put in 'iov' array
841433d6423SLionel Sambuc 	 * (iov[0] : iov[iov_count]), into continuous region of mass storage,
842433d6423SLionel Sambuc 	 * starting from sector 'sector_number'. Total amount of 'iov'
843433d6423SLionel Sambuc 	 * data should be greater or equal to initial value of 'bytes_left'.
844433d6423SLionel Sambuc 	 *
845433d6423SLionel Sambuc 	 * Endpoint value 'endpt', determines if vectors 'iov' contain memory
846433d6423SLionel Sambuc 	 * addresses for copying or grant IDs.
847433d6423SLionel Sambuc 	 */
848433d6423SLionel Sambuc 
849433d6423SLionel Sambuc 	iov_state cur_iov;		/* Current state of vector copying */
850433d6423SLionel Sambuc 	unsigned long bytes_to_write;	/* To be written in this iteration */
851433d6423SLionel Sambuc 	ssize_t bytes_already_written;	/* Total amount written (retval) */
852433d6423SLionel Sambuc 
853433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
854433d6423SLionel Sambuc 
855433d6423SLionel Sambuc 	/* Initialize locals */
856433d6423SLionel Sambuc 	cur_iov.remaining_bytes = 0;	/* No IO vector initially */
857433d6423SLionel Sambuc 	cur_iov.iov_idx = 0;		/* Starting from first vector */
858433d6423SLionel Sambuc 	bytes_already_written = 0;	/* Nothing copied yet */
859433d6423SLionel Sambuc 
860433d6423SLionel Sambuc 	/* Mass storage operations are sector based */
861433d6423SLionel Sambuc 	assert(0 == (sizeof(buffer) % SECTOR_SIZE));
862433d6423SLionel Sambuc 	assert(0 == (bytes_left % SECTOR_SIZE));
863433d6423SLionel Sambuc 
864433d6423SLionel Sambuc 	while (bytes_left > 0) {
865433d6423SLionel Sambuc 
866433d6423SLionel Sambuc 		/* Fill write buffer with data from IO Vectors */
867433d6423SLionel Sambuc 		{
868433d6423SLionel Sambuc 			unsigned long buf_offset;
869433d6423SLionel Sambuc 			unsigned long copy_len;
870433d6423SLionel Sambuc 
871433d6423SLionel Sambuc 			/* Start copying to the beginning of the buffer */
872433d6423SLionel Sambuc 			buf_offset = 0;
873433d6423SLionel Sambuc 
874433d6423SLionel Sambuc 			/* Copy as long as not copied vectors exist or
875433d6423SLionel Sambuc 			 * buffer is not fully filled */
876433d6423SLionel Sambuc 			for (;;) {
877433d6423SLionel Sambuc 
878433d6423SLionel Sambuc 				/* If entire previous vector
879433d6423SLionel Sambuc 				 * was used get new one */
880433d6423SLionel Sambuc 				if (0 == cur_iov.remaining_bytes) {
881433d6423SLionel Sambuc 					/* Check if there are
882433d6423SLionel Sambuc 					 * vectors to copied */
883433d6423SLionel Sambuc 					if (cur_iov.iov_idx < iov_count) {
884433d6423SLionel Sambuc 
885433d6423SLionel Sambuc 						cur_iov.base_addr =
886433d6423SLionel Sambuc 						  iov[cur_iov.iov_idx].iov_addr;
887433d6423SLionel Sambuc 						cur_iov.remaining_bytes =
888433d6423SLionel Sambuc 						  iov[cur_iov.iov_idx].iov_size;
889433d6423SLionel Sambuc 						cur_iov.offset = 0;
890433d6423SLionel Sambuc 						cur_iov.iov_idx++;
891433d6423SLionel Sambuc 
892433d6423SLionel Sambuc 					} else {
893433d6423SLionel Sambuc 						/* All vectors copied */
894433d6423SLionel Sambuc 						break;
895433d6423SLionel Sambuc 					}
896433d6423SLionel Sambuc 				}
897433d6423SLionel Sambuc 
898433d6423SLionel Sambuc 				/* Copy as much as it is possible from vector
899433d6423SLionel Sambuc 				 * and at most the amount that can be
900433d6423SLionel Sambuc 				 * put in buffer */
901433d6423SLionel Sambuc 				copy_len = MIN(sizeof(buffer) - buf_offset,
902433d6423SLionel Sambuc 						cur_iov.remaining_bytes);
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc 				/* This distinction is required as transfer can
905433d6423SLionel Sambuc 				 * be used from within this process and meaning
906433d6423SLionel Sambuc 				 * of IO vector'a address is different than
907433d6423SLionel Sambuc 				 * grant ID */
908433d6423SLionel Sambuc 				if (endpt == SELF) {
909433d6423SLionel Sambuc 					memcpy(&buffer[buf_offset],
910433d6423SLionel Sambuc 						(void*)(cur_iov.base_addr +
911433d6423SLionel Sambuc 						cur_iov.offset), copy_len);
912433d6423SLionel Sambuc 				} else {
913433d6423SLionel Sambuc 					ssize_t copy_res;
914433d6423SLionel Sambuc 					if ((copy_res = sys_safecopyfrom(endpt,
915433d6423SLionel Sambuc 						cur_iov.base_addr,
916433d6423SLionel Sambuc 						cur_iov.offset,
917433d6423SLionel Sambuc 						(vir_bytes)
918433d6423SLionel Sambuc 						(&buffer[buf_offset]),
919433d6423SLionel Sambuc 						copy_len))) {
920433d6423SLionel Sambuc 						MASS_MSG("sys_safecopyfrom "
921433d6423SLionel Sambuc 							"failed");
922433d6423SLionel Sambuc 						return copy_res;
923433d6423SLionel Sambuc 					}
924433d6423SLionel Sambuc 				}
925433d6423SLionel Sambuc 
926433d6423SLionel Sambuc 				/* Alter current state of copying */
927433d6423SLionel Sambuc 				buf_offset += copy_len;
928433d6423SLionel Sambuc 				cur_iov.offset += copy_len;
929433d6423SLionel Sambuc 				cur_iov.remaining_bytes -= copy_len;
930433d6423SLionel Sambuc 
931433d6423SLionel Sambuc 				/* Buffer was filled */
932433d6423SLionel Sambuc 				if (sizeof(buffer) == buf_offset)
933433d6423SLionel Sambuc 					break;
934433d6423SLionel Sambuc 			}
935433d6423SLionel Sambuc 
936433d6423SLionel Sambuc 			/* Determine how many bytes from copied buffer we wish
937433d6423SLionel Sambuc 			 * to write, buf_offset represents total amount of
938433d6423SLionel Sambuc 			 * bytes copied above */
939433d6423SLionel Sambuc 			if (bytes_left >= buf_offset) {
940433d6423SLionel Sambuc 				bytes_to_write = buf_offset;
941433d6423SLionel Sambuc 				bytes_left -= buf_offset;
942433d6423SLionel Sambuc 			} else {
943433d6423SLionel Sambuc 				bytes_to_write = bytes_left;
944433d6423SLionel Sambuc 				bytes_left = 0;
945433d6423SLionel Sambuc 			}
946433d6423SLionel Sambuc 		}
947433d6423SLionel Sambuc 
948433d6423SLionel Sambuc 		/* Send URB and alter sector number */
949433d6423SLionel Sambuc 		if (bytes_to_write > 0) {
950433d6423SLionel Sambuc 
951433d6423SLionel Sambuc 			scsi_transfer info;
952433d6423SLionel Sambuc 
953433d6423SLionel Sambuc 			info.length = bytes_to_write;
954433d6423SLionel Sambuc 			info.lba = sector_number;
955433d6423SLionel Sambuc 
956433d6423SLionel Sambuc 			/* SCSI WRITE first OUT stage */
957433d6423SLionel Sambuc 			if (mass_storage_send_scsi_cbw_out(SCSI_WRITE, &info))
958433d6423SLionel Sambuc 				return EIO;
959433d6423SLionel Sambuc 
960433d6423SLionel Sambuc 			/* SCSI WRITE second OUT stage */
961433d6423SLionel Sambuc 			if (mass_storage_send_scsi_data_out(buffer,
962433d6423SLionel Sambuc 							bytes_to_write))
963433d6423SLionel Sambuc 				return EIO;
964433d6423SLionel Sambuc 
965433d6423SLionel Sambuc 			/* SCSI WRITE IN stage */
966433d6423SLionel Sambuc 			if (mass_storage_send_scsi_csw_in())
967433d6423SLionel Sambuc 				return EIO;
968433d6423SLionel Sambuc 
969433d6423SLionel Sambuc 			/* Writing completed so shift starting
970433d6423SLionel Sambuc 			 * sector for next iteration */
971433d6423SLionel Sambuc 			sector_number += bytes_to_write / SECTOR_SIZE;
972433d6423SLionel Sambuc 
973433d6423SLionel Sambuc 			/* Update amount of data already copied */
974433d6423SLionel Sambuc 			bytes_already_written += bytes_to_write;
975433d6423SLionel Sambuc 		}
976433d6423SLionel Sambuc 	}
977433d6423SLionel Sambuc 
978433d6423SLionel Sambuc 	return bytes_already_written;
979433d6423SLionel Sambuc }
980433d6423SLionel Sambuc 
981433d6423SLionel Sambuc 
982433d6423SLionel Sambuc /*===========================================================================*
983433d6423SLionel Sambuc  *    mass_storage_read                                                      *
984433d6423SLionel Sambuc  *===========================================================================*/
985433d6423SLionel Sambuc static ssize_t
mass_storage_read(unsigned long sector_number,endpoint_t endpt,iovec_t * iov,unsigned int iov_count,unsigned long bytes_left)986433d6423SLionel Sambuc mass_storage_read(unsigned long sector_number,
987433d6423SLionel Sambuc 		endpoint_t endpt,
988433d6423SLionel Sambuc 		iovec_t * iov,
989433d6423SLionel Sambuc 		unsigned int iov_count,
990433d6423SLionel Sambuc 		unsigned long bytes_left)
991433d6423SLionel Sambuc {
992433d6423SLionel Sambuc 	/*
993433d6423SLionel Sambuc 	 * This function reads 'bytes_left' bytes of mass storage data into
994433d6423SLionel Sambuc 	 * 'iov' array (iov[0] : iov[iov_count]) starting from sector
995433d6423SLionel Sambuc 	 * 'sector_number'. Total amount of 'iov' data should be greater or
996433d6423SLionel Sambuc 	 * equal to initial value of 'bytes_left'.
997433d6423SLionel Sambuc 	 *
998433d6423SLionel Sambuc 	 * Endpoint value 'endpt', determines if vectors 'iov' contain memory
999433d6423SLionel Sambuc 	 * addresses for copying or grant IDs.
1000433d6423SLionel Sambuc 	 */
1001433d6423SLionel Sambuc 
1002433d6423SLionel Sambuc 	iov_state cur_iov;		/* Current state of vector copying */
1003433d6423SLionel Sambuc 	unsigned long bytes_to_read;	/* To be read in this iteration */
1004433d6423SLionel Sambuc 	ssize_t bytes_already_read;	/* Total amount read (retval) */
1005433d6423SLionel Sambuc 
1006433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1007433d6423SLionel Sambuc 
1008433d6423SLionel Sambuc 	/* Initialize locals */
1009433d6423SLionel Sambuc 	cur_iov.remaining_bytes = 0;	/* No IO vector initially */
1010433d6423SLionel Sambuc 	cur_iov.iov_idx = 0;		/* Starting from first vector */
1011433d6423SLionel Sambuc 	bytes_already_read = 0;		/* Nothing copied yet */
1012433d6423SLionel Sambuc 
1013433d6423SLionel Sambuc 	/* Mass storage operations are sector based */
1014433d6423SLionel Sambuc 	assert(0 == (sizeof(buffer) % SECTOR_SIZE));
1015433d6423SLionel Sambuc 	assert(0 == (bytes_left % SECTOR_SIZE));
1016433d6423SLionel Sambuc 
1017433d6423SLionel Sambuc 	while (bytes_left > 0) {
1018433d6423SLionel Sambuc 
1019433d6423SLionel Sambuc 		/* Decide read length and alter remaining bytes */
1020433d6423SLionel Sambuc 		{
1021433d6423SLionel Sambuc 			/* Number of bytes to be read in next URB */
1022433d6423SLionel Sambuc 			if (bytes_left > sizeof(buffer)) {
1023433d6423SLionel Sambuc 				bytes_to_read = sizeof(buffer);
1024433d6423SLionel Sambuc 			} else {
1025433d6423SLionel Sambuc 				bytes_to_read = bytes_left;
1026433d6423SLionel Sambuc 			}
1027433d6423SLionel Sambuc 
1028433d6423SLionel Sambuc 			bytes_left -= bytes_to_read;
1029433d6423SLionel Sambuc 		}
1030433d6423SLionel Sambuc 
1031433d6423SLionel Sambuc 		/* Send URB and alter sector number */
1032433d6423SLionel Sambuc 		{
1033433d6423SLionel Sambuc 			scsi_transfer info;
1034433d6423SLionel Sambuc 
1035433d6423SLionel Sambuc 			info.length = bytes_to_read;
1036433d6423SLionel Sambuc 			info.lba = sector_number;
1037433d6423SLionel Sambuc 
1038433d6423SLionel Sambuc 			/* SCSI READ OUT stage */
1039433d6423SLionel Sambuc 			if (mass_storage_send_scsi_cbw_out(SCSI_READ, &info))
1040433d6423SLionel Sambuc 				return EIO;
1041433d6423SLionel Sambuc 
1042433d6423SLionel Sambuc 			/* SCSI READ first IN stage */
1043433d6423SLionel Sambuc 			if (mass_storage_send_scsi_data_in(buffer,
1044433d6423SLionel Sambuc 							bytes_to_read))
1045433d6423SLionel Sambuc 				return EIO;
1046433d6423SLionel Sambuc 
1047433d6423SLionel Sambuc 			/* SCSI READ second IN stage */
1048433d6423SLionel Sambuc 			if (mass_storage_send_scsi_csw_in())
1049433d6423SLionel Sambuc 				return EIO;
1050433d6423SLionel Sambuc 
1051433d6423SLionel Sambuc 			/* Reading completed so shift starting
1052433d6423SLionel Sambuc 			 * sector for next iteration */
1053433d6423SLionel Sambuc 			sector_number += bytes_to_read / SECTOR_SIZE;
1054433d6423SLionel Sambuc 		}
1055433d6423SLionel Sambuc 
1056433d6423SLionel Sambuc 		/* Fill IO Vectors with data from buffer */
1057433d6423SLionel Sambuc 		{
1058433d6423SLionel Sambuc 			unsigned long buf_offset;
1059433d6423SLionel Sambuc 			unsigned long copy_len;
1060433d6423SLionel Sambuc 
1061433d6423SLionel Sambuc 			/* Start copying from the beginning of the buffer */
1062433d6423SLionel Sambuc 			buf_offset = 0;
1063433d6423SLionel Sambuc 
1064433d6423SLionel Sambuc 			/* Copy as long as there are unfilled vectors
1065433d6423SLionel Sambuc 			 * or data in buffer remains */
1066433d6423SLionel Sambuc 			for (;;) {
1067433d6423SLionel Sambuc 
1068433d6423SLionel Sambuc 				/* If previous vector was filled get new one */
1069433d6423SLionel Sambuc 				if (0 == cur_iov.remaining_bytes) {
1070433d6423SLionel Sambuc 					/* Check if there are vectors
1071433d6423SLionel Sambuc 					 * to be filled */
1072433d6423SLionel Sambuc 					if (cur_iov.iov_idx < iov_count) {
1073433d6423SLionel Sambuc 
1074433d6423SLionel Sambuc 						cur_iov.base_addr =
1075433d6423SLionel Sambuc 						  iov[cur_iov.iov_idx].iov_addr;
1076433d6423SLionel Sambuc 						cur_iov.remaining_bytes =
1077433d6423SLionel Sambuc 						  iov[cur_iov.iov_idx].iov_size;
1078433d6423SLionel Sambuc 						cur_iov.offset = 0;
1079433d6423SLionel Sambuc 						cur_iov.iov_idx++;
1080433d6423SLionel Sambuc 
1081433d6423SLionel Sambuc 					} else {
1082433d6423SLionel Sambuc 						/* Total length of vectors
1083433d6423SLionel Sambuc 						 * should be greater or equal
1084433d6423SLionel Sambuc 						 * to initial value of
1085433d6423SLionel Sambuc 						 * bytes_left. Being here means
1086433d6423SLionel Sambuc 						 * that everything should
1087433d6423SLionel Sambuc 						 * have been copied already */
1088433d6423SLionel Sambuc 						assert(0 == bytes_left);
1089433d6423SLionel Sambuc 						break;
1090433d6423SLionel Sambuc 					}
1091433d6423SLionel Sambuc 				}
1092433d6423SLionel Sambuc 
1093433d6423SLionel Sambuc 				/* Copy as much as it is possible from buffer
1094433d6423SLionel Sambuc 				 * and at most the amount that can be
1095433d6423SLionel Sambuc 				 * put in vector */
1096433d6423SLionel Sambuc 				copy_len = MIN(bytes_to_read - buf_offset,
1097433d6423SLionel Sambuc 						cur_iov.remaining_bytes);
1098433d6423SLionel Sambuc 
1099433d6423SLionel Sambuc 				/* This distinction is required as transfer can
1100433d6423SLionel Sambuc 				 * be used from within this process and meaning
1101433d6423SLionel Sambuc 				 * of IO vector'a address is different than
1102433d6423SLionel Sambuc 				 * grant ID */
1103433d6423SLionel Sambuc 				if (endpt == SELF) {
1104433d6423SLionel Sambuc 					memcpy((void*)(cur_iov.base_addr +
1105433d6423SLionel Sambuc 							cur_iov.offset),
1106433d6423SLionel Sambuc 							&buffer[buf_offset],
1107433d6423SLionel Sambuc 							copy_len);
1108433d6423SLionel Sambuc 				} else {
1109433d6423SLionel Sambuc 					ssize_t copy_res;
1110433d6423SLionel Sambuc 					if ((copy_res = sys_safecopyto(endpt,
1111433d6423SLionel Sambuc 						cur_iov.base_addr,
1112433d6423SLionel Sambuc 						cur_iov.offset,
1113433d6423SLionel Sambuc 						(vir_bytes)
1114433d6423SLionel Sambuc 						(&buffer[buf_offset]),
1115433d6423SLionel Sambuc 						copy_len))) {
1116433d6423SLionel Sambuc 						MASS_MSG("sys_safecopyto "
1117433d6423SLionel Sambuc 							"failed");
1118433d6423SLionel Sambuc 						return copy_res;
1119433d6423SLionel Sambuc 					}
1120433d6423SLionel Sambuc 				}
1121433d6423SLionel Sambuc 
1122433d6423SLionel Sambuc 				/* Alter current state of copying */
1123433d6423SLionel Sambuc 				buf_offset += copy_len;
1124433d6423SLionel Sambuc 				cur_iov.offset += copy_len;
1125433d6423SLionel Sambuc 				cur_iov.remaining_bytes -= copy_len;
1126433d6423SLionel Sambuc 
1127433d6423SLionel Sambuc 				/* Everything was copied */
1128433d6423SLionel Sambuc 				if (bytes_to_read == buf_offset)
1129433d6423SLionel Sambuc 					break;
1130433d6423SLionel Sambuc 			}
1131433d6423SLionel Sambuc 
1132433d6423SLionel Sambuc 			/* Update amount of data already copied */
1133433d6423SLionel Sambuc 			bytes_already_read += buf_offset;
1134433d6423SLionel Sambuc 		}
1135433d6423SLionel Sambuc 	}
1136433d6423SLionel Sambuc 
1137433d6423SLionel Sambuc 	return bytes_already_read;
1138433d6423SLionel Sambuc }
1139433d6423SLionel Sambuc 
1140433d6423SLionel Sambuc 
1141433d6423SLionel Sambuc /*===========================================================================*
1142433d6423SLionel Sambuc  *    mass_storage_open                                                      *
1143433d6423SLionel Sambuc  *===========================================================================*/
1144433d6423SLionel Sambuc static int
mass_storage_open(devminor_t minor,int UNUSED (access))1145433d6423SLionel Sambuc mass_storage_open(devminor_t minor, int UNUSED(access))
1146433d6423SLionel Sambuc {
1147433d6423SLionel Sambuc 	mass_storage_drive * d;
1148433d6423SLionel Sambuc 	int r;
1149433d6423SLionel Sambuc 
1150433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1151433d6423SLionel Sambuc 
1152433d6423SLionel Sambuc 	/* Decode minor into drive device information */
1153433d6423SLionel Sambuc 	if (NULL == (mass_storage_part(minor)))
1154433d6423SLionel Sambuc 		return ENXIO;
1155433d6423SLionel Sambuc 
1156433d6423SLionel Sambuc 	/* Copy evaluated current drive for simplified dereference */
1157433d6423SLionel Sambuc 	d = driver_state.cur_drive;
1158433d6423SLionel Sambuc 
1159433d6423SLionel Sambuc #ifdef MASS_RESET_RECOVERY
1160433d6423SLionel Sambuc 	/* In case of previous CBW mismatch */
1161433d6423SLionel Sambuc 	if (mass_storage_reset_recovery()) {
1162433d6423SLionel Sambuc 		MASS_MSG("Resetting mass storage device failed");
1163433d6423SLionel Sambuc 		return EIO;
1164433d6423SLionel Sambuc 	}
1165433d6423SLionel Sambuc #endif
1166433d6423SLionel Sambuc 
1167433d6423SLionel Sambuc 	/* In case of missing endpoint information, do simple
1168433d6423SLionel Sambuc 	 * enumeration and hold it for future use */
1169433d6423SLionel Sambuc 	if ((URB_INVALID_EP == driver_state.cur_periph->ep_in.ep_num) ||
1170433d6423SLionel Sambuc 		(URB_INVALID_EP == driver_state.cur_periph->ep_out.ep_num)) {
1171433d6423SLionel Sambuc 
1172433d6423SLionel Sambuc 		if (mass_storage_get_endpoints(&driver_state.cur_periph->ep_in,
1173433d6423SLionel Sambuc 					&driver_state.cur_periph->ep_out))
1174433d6423SLionel Sambuc 			return EIO;
1175433d6423SLionel Sambuc 	}
1176433d6423SLionel Sambuc 
1177433d6423SLionel Sambuc 	/* If drive hasn't been opened yet, try to open it */
1178433d6423SLionel Sambuc 	if (d->open_ct == 0) {
1179433d6423SLionel Sambuc 		if ((r = mass_storage_try_first_open())) {
1180433d6423SLionel Sambuc 			MASS_MSG("Opening mass storage device"
1181433d6423SLionel Sambuc 				" for the first time failed");
1182*2d64210cSWojciech Zajac 
1183*2d64210cSWojciech Zajac 			/* Do one more test before failing, to output
1184*2d64210cSWojciech Zajac 			 * sense errors in case they weren't dumped already */
1185*2d64210cSWojciech Zajac 			if (mass_storage_test())
1186*2d64210cSWojciech Zajac 				MASS_MSG("Final TEST UNIT READY failed");
1187*2d64210cSWojciech Zajac 
1188433d6423SLionel Sambuc 			return r;
1189433d6423SLionel Sambuc 		}
1190433d6423SLionel Sambuc 
1191433d6423SLionel Sambuc 		/* Clear remembered device state for current
1192433d6423SLionel Sambuc 		 * drive before calling partition */
1193433d6423SLionel Sambuc 		memset(&d->part[0],	0, sizeof(d->part));
1194433d6423SLionel Sambuc 		memset(&d->subpart[0],	0, sizeof(d->subpart));
1195433d6423SLionel Sambuc 
1196433d6423SLionel Sambuc 		/* Try parsing partition table (for entire drive) */
1197433d6423SLionel Sambuc 		/* Warning!! This call uses mass_storage_part with own minors
1198433d6423SLionel Sambuc 		 * and alters global driver_state.cur_device! */
1199433d6423SLionel Sambuc 		partition(&mass_storage, (d->drive_idx * DEV_PER_DRIVE),
1200433d6423SLionel Sambuc 			P_PRIMARY, 0);
1201433d6423SLionel Sambuc 
1202433d6423SLionel Sambuc 		/* Decode minor into UPDATED drive device information */
1203433d6423SLionel Sambuc 		if (NULL == (mass_storage_part(minor)))
1204433d6423SLionel Sambuc 			return ENXIO;
1205433d6423SLionel Sambuc 
1206433d6423SLionel Sambuc 		/* Decoded size must be positive or else
1207433d6423SLionel Sambuc 		 * we assume device (partition) is unavailable */
1208433d6423SLionel Sambuc 		if (0 == driver_state.cur_device->dv_size)
1209433d6423SLionel Sambuc 			return ENXIO;
1210433d6423SLionel Sambuc 	}
1211433d6423SLionel Sambuc 
1212433d6423SLionel Sambuc 	/* Run TEST UNIT READY before further commands
1213433d6423SLionel Sambuc 	 * Some devices refuse to work without this */
1214433d6423SLionel Sambuc 	if (mass_storage_test())
1215433d6423SLionel Sambuc 		return EIO;
1216433d6423SLionel Sambuc 
1217433d6423SLionel Sambuc 	/* Opening completed */
1218433d6423SLionel Sambuc 	d->open_ct++;
1219433d6423SLionel Sambuc 
1220433d6423SLionel Sambuc 	return EXIT_SUCCESS;
1221433d6423SLionel Sambuc }
1222433d6423SLionel Sambuc 
1223433d6423SLionel Sambuc 
1224433d6423SLionel Sambuc /*===========================================================================*
1225433d6423SLionel Sambuc  *    mass_storage_close                                                     *
1226433d6423SLionel Sambuc  *===========================================================================*/
mass_storage_close(devminor_t minor)1227433d6423SLionel Sambuc static int mass_storage_close(devminor_t minor)
1228433d6423SLionel Sambuc {
1229433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1230433d6423SLionel Sambuc 
1231433d6423SLionel Sambuc 	/* Decode minor into drive device information */
1232433d6423SLionel Sambuc 	if (NULL == (mass_storage_part(minor)))
1233433d6423SLionel Sambuc 		return ENXIO;
1234433d6423SLionel Sambuc 
1235433d6423SLionel Sambuc 	/* If drive hasn't been opened yet */
1236433d6423SLionel Sambuc 	if (driver_state.cur_drive->open_ct == 0) {
1237433d6423SLionel Sambuc 		MASS_MSG("Device was not opened yet");
1238433d6423SLionel Sambuc 		return ERESTART;
1239433d6423SLionel Sambuc 	}
1240433d6423SLionel Sambuc 
1241433d6423SLionel Sambuc 	/* Act accordingly */
1242433d6423SLionel Sambuc 	driver_state.cur_drive->open_ct--;
1243433d6423SLionel Sambuc 
1244433d6423SLionel Sambuc 	return EXIT_SUCCESS;
1245433d6423SLionel Sambuc }
1246433d6423SLionel Sambuc 
1247433d6423SLionel Sambuc 
1248433d6423SLionel Sambuc /*===========================================================================*
1249433d6423SLionel Sambuc  *    mass_storage_transfer                                                  *
1250433d6423SLionel Sambuc  *===========================================================================*/
1251433d6423SLionel Sambuc static ssize_t
mass_storage_transfer(devminor_t minor,int do_write,u64_t pos,endpoint_t endpt,iovec_t * iov,unsigned int iov_count,int UNUSED (flags))1252433d6423SLionel Sambuc mass_storage_transfer(devminor_t minor,		/* device minor number */
1253433d6423SLionel Sambuc 		int do_write,			/* 1 write, 0 read */
1254433d6423SLionel Sambuc 		u64_t pos,			/* position of starting point */
1255433d6423SLionel Sambuc 		endpoint_t endpt,		/* endpoint */
1256433d6423SLionel Sambuc 		iovec_t * iov,			/* vector */
1257433d6423SLionel Sambuc 		unsigned int iov_count,		/* how many vectors */
1258433d6423SLionel Sambuc 		int UNUSED(flags))		/* transfer flags */
1259433d6423SLionel Sambuc {
1260433d6423SLionel Sambuc 	u64_t temp_sector_number;
1261433d6423SLionel Sambuc 	unsigned long bytes;
1262433d6423SLionel Sambuc 	unsigned long sector_number;
1263433d6423SLionel Sambuc 	unsigned int cur_iov_idx;
1264433d6423SLionel Sambuc 	int r;
1265433d6423SLionel Sambuc 
1266433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1267433d6423SLionel Sambuc 
1268433d6423SLionel Sambuc 	/* Decode minor into drive device information */
1269433d6423SLionel Sambuc 	if (NULL == (mass_storage_part(minor)))
1270433d6423SLionel Sambuc 		return ENXIO;
1271433d6423SLionel Sambuc 
1272433d6423SLionel Sambuc 	bytes = 0;
1273433d6423SLionel Sambuc 
1274433d6423SLionel Sambuc 	/* How much data is going to be transferred? */
1275433d6423SLionel Sambuc 	for (cur_iov_idx = 0; cur_iov_idx < iov_count; ++cur_iov_idx) {
1276433d6423SLionel Sambuc 
1277433d6423SLionel Sambuc 		/* Check if grant ID was supplied
1278433d6423SLionel Sambuc 		 * instead of address and if it is valid */
1279433d6423SLionel Sambuc 		if (endpt != SELF)
1280433d6423SLionel Sambuc 			if (!GRANT_VALID((cp_grant_id_t)
1281433d6423SLionel Sambuc 				(iov[cur_iov_idx].iov_addr)))
1282433d6423SLionel Sambuc 				return EINVAL;
1283433d6423SLionel Sambuc 
1284433d6423SLionel Sambuc 		/* All supplied vectors must have positive length */
1285433d6423SLionel Sambuc 		if ((signed long)(iov[cur_iov_idx].iov_size) <= 0) {
1286433d6423SLionel Sambuc 			MASS_MSG("Transfer request length is not positive");
1287433d6423SLionel Sambuc 			return EINVAL;
1288433d6423SLionel Sambuc 		}
1289433d6423SLionel Sambuc 
1290433d6423SLionel Sambuc 		/* Requirements were met, more bytes can be transferred */
1291433d6423SLionel Sambuc 		bytes += iov[cur_iov_idx].iov_size;
1292433d6423SLionel Sambuc 
1293433d6423SLionel Sambuc 		/* Request size must never overflow */
1294433d6423SLionel Sambuc 		if ((signed long)bytes <= 0) {
1295433d6423SLionel Sambuc 			MASS_MSG("Transfer request length overflowed");
1296433d6423SLionel Sambuc 			return EINVAL;
1297433d6423SLionel Sambuc 		}
1298433d6423SLionel Sambuc 	}
1299433d6423SLionel Sambuc 
1300433d6423SLionel Sambuc 	/* Check if reading beyond device/partition */
1301433d6423SLionel Sambuc 	if (pos >= driver_state.cur_device->dv_size) {
1302433d6423SLionel Sambuc 		MASS_MSG("Request out of bounds for given device");
1303433d6423SLionel Sambuc 		return 0; /* No error and no bytes read */
1304433d6423SLionel Sambuc 	}
1305433d6423SLionel Sambuc 
1306433d6423SLionel Sambuc 	/* Check if arguments agree with accepted restriction
1307433d6423SLionel Sambuc 	 * for parameters of transfer */
1308433d6423SLionel Sambuc 	if ((r = mass_storage_transfer_restrictions(pos, bytes)))
1309433d6423SLionel Sambuc 		return r;
1310433d6423SLionel Sambuc 
1311433d6423SLionel Sambuc 	/* If 'hard' requirements above were met, do additional
1312433d6423SLionel Sambuc 	 * limiting to device/partition boundary */
1313433d6423SLionel Sambuc 	if ((pos + bytes) > driver_state.cur_device->dv_size)
1314433d6423SLionel Sambuc 		bytes = (driver_state.cur_device->dv_size - pos) &
1315433d6423SLionel Sambuc 			~SECTOR_MASK;
1316433d6423SLionel Sambuc 
1317433d6423SLionel Sambuc 	/* We have to obtain sector number of given position
1318433d6423SLionel Sambuc 	 * and limit it to what URB can handle */
1319433d6423SLionel Sambuc 	temp_sector_number = (driver_state.cur_device->dv_base + pos) /
1320433d6423SLionel Sambuc 				SECTOR_SIZE;
1321433d6423SLionel Sambuc 	assert(temp_sector_number < ULONG_MAX); /* LBA is limited to 32B */
1322433d6423SLionel Sambuc 	sector_number = (unsigned long)temp_sector_number;
1323433d6423SLionel Sambuc 
1324433d6423SLionel Sambuc 	if (do_write)
1325433d6423SLionel Sambuc 		return mass_storage_write(sector_number, endpt, iov,
1326433d6423SLionel Sambuc 					iov_count, bytes);
1327433d6423SLionel Sambuc 	else
1328433d6423SLionel Sambuc 		return mass_storage_read(sector_number, endpt, iov,
1329433d6423SLionel Sambuc 					iov_count, bytes);
1330433d6423SLionel Sambuc }
1331433d6423SLionel Sambuc 
1332433d6423SLionel Sambuc 
1333433d6423SLionel Sambuc /*===========================================================================*
1334433d6423SLionel Sambuc  *    mass_storage_ioctl                                                     *
1335433d6423SLionel Sambuc  *===========================================================================*/
1336433d6423SLionel Sambuc static int
mass_storage_ioctl(devminor_t minor,unsigned long request,endpoint_t endpt,cp_grant_id_t grant,endpoint_t UNUSED (user_endpt))1337433d6423SLionel Sambuc mass_storage_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
1338433d6423SLionel Sambuc 			cp_grant_id_t grant, endpoint_t UNUSED(user_endpt))
1339433d6423SLionel Sambuc {
1340433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1341433d6423SLionel Sambuc 
1342433d6423SLionel Sambuc 	/* Decode minor into drive device information */
1343433d6423SLionel Sambuc 	if (NULL == (mass_storage_part(minor)))
1344433d6423SLionel Sambuc 		return ENXIO;
1345433d6423SLionel Sambuc 
1346433d6423SLionel Sambuc 	switch (request) {
1347433d6423SLionel Sambuc 		case DIOCOPENCT:
1348433d6423SLionel Sambuc 			if (sys_safecopyto(endpt, grant, 0,
1349433d6423SLionel Sambuc 				(vir_bytes) &(driver_state.cur_drive->open_ct),
1350433d6423SLionel Sambuc 				sizeof(driver_state.cur_drive->open_ct)))
1351433d6423SLionel Sambuc 				panic("sys_safecopyto failed!");
1352433d6423SLionel Sambuc 
1353433d6423SLionel Sambuc 			return EXIT_SUCCESS;
1354433d6423SLionel Sambuc 
1355433d6423SLionel Sambuc 		default:
1356433d6423SLionel Sambuc 			MASS_MSG("Unimplemented IOCTL request: 0x%X",
1357433d6423SLionel Sambuc 				(int)request);
1358433d6423SLionel Sambuc 			break;
1359433d6423SLionel Sambuc 	}
1360433d6423SLionel Sambuc 
1361433d6423SLionel Sambuc 	return ENOTTY;
1362433d6423SLionel Sambuc }
1363433d6423SLionel Sambuc 
1364433d6423SLionel Sambuc 
1365433d6423SLionel Sambuc /*===========================================================================*
1366433d6423SLionel Sambuc  *    mass_storage_cleanup                                                   *
1367433d6423SLionel Sambuc  *===========================================================================*/
mass_storage_cleanup(void)1368433d6423SLionel Sambuc static void mass_storage_cleanup(void)
1369433d6423SLionel Sambuc {
1370433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1371433d6423SLionel Sambuc 	return;
1372433d6423SLionel Sambuc }
1373433d6423SLionel Sambuc 
1374433d6423SLionel Sambuc 
1375433d6423SLionel Sambuc /*===========================================================================*
1376433d6423SLionel Sambuc  *    mass_storage_part                                                      *
1377433d6423SLionel Sambuc  *===========================================================================*/
1378433d6423SLionel Sambuc static struct device *
mass_storage_part(devminor_t minor)1379433d6423SLionel Sambuc mass_storage_part(devminor_t minor)
1380433d6423SLionel Sambuc {
1381433d6423SLionel Sambuc 	unsigned long sel_drive;
1382433d6423SLionel Sambuc 	unsigned long sel_device;
1383433d6423SLionel Sambuc 
1384433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1385433d6423SLionel Sambuc 
1386433d6423SLionel Sambuc 	/* Override every time before further decision */
1387433d6423SLionel Sambuc 	driver_state.cur_drive = NULL;
1388433d6423SLionel Sambuc 	driver_state.cur_device = NULL;
1389433d6423SLionel Sambuc 	driver_state.cur_periph = NULL;
1390433d6423SLionel Sambuc 
1391433d6423SLionel Sambuc 	/* Decode 'minor' code to find which device file was used */
1392433d6423SLionel Sambuc 	if (minor < MINOR_d0p0s0) {
1393433d6423SLionel Sambuc 
1394433d6423SLionel Sambuc 		/* No sub-partitions used */
1395433d6423SLionel Sambuc 		sel_drive = minor / DEV_PER_DRIVE;
1396433d6423SLionel Sambuc 		sel_device = minor % DEV_PER_DRIVE;
1397433d6423SLionel Sambuc 
1398433d6423SLionel Sambuc 		/* Only valid minors */
1399433d6423SLionel Sambuc 		if (sel_drive < MAX_DRIVES) {
1400433d6423SLionel Sambuc 			/* Associate minor (device/partition)
1401433d6423SLionel Sambuc 			 * with peripheral number */
1402433d6423SLionel Sambuc 			/* TODO:PERIPH
1403433d6423SLionel Sambuc 			 * Proper peripheral selection based
1404433d6423SLionel Sambuc 			 * on minor should be here: */
1405433d6423SLionel Sambuc 			driver_state.cur_periph = &driver_state.periph[0];
1406433d6423SLionel Sambuc 
1407433d6423SLionel Sambuc 			/* Select drive entry for opening count etc. */
1408433d6423SLionel Sambuc 			driver_state.cur_drive =
1409433d6423SLionel Sambuc 				&(driver_state.cur_periph->drives[sel_drive]);
1410433d6423SLionel Sambuc 
1411433d6423SLionel Sambuc 			/* Select device entry for given device file */
1412433d6423SLionel Sambuc 			/* Device 0 means entire drive.
1413433d6423SLionel Sambuc 			 * Devices 1,2,3,4 mean partitions 0,1,2,3 */
1414433d6423SLionel Sambuc 			if (0 == sel_device)
1415433d6423SLionel Sambuc 				driver_state.cur_device =
1416433d6423SLionel Sambuc 					&(driver_state.cur_drive->disk);
1417433d6423SLionel Sambuc 			else
1418433d6423SLionel Sambuc 				driver_state.cur_device =
1419433d6423SLionel Sambuc 					&(driver_state.cur_drive->part
1420433d6423SLionel Sambuc 								[sel_device-1]);
1421433d6423SLionel Sambuc 		}
1422433d6423SLionel Sambuc 
1423433d6423SLionel Sambuc 	} else {
1424433d6423SLionel Sambuc 
1425433d6423SLionel Sambuc 		/* Shift values accordingly */
1426433d6423SLionel Sambuc 		minor -= MINOR_d0p0s0;
1427433d6423SLionel Sambuc 
1428433d6423SLionel Sambuc 		/* Sub-partitions used */
1429433d6423SLionel Sambuc 		sel_drive = minor / SUBPART_PER_DISK;
1430433d6423SLionel Sambuc 		sel_device = minor % SUBPART_PER_DISK;
1431433d6423SLionel Sambuc 
1432433d6423SLionel Sambuc 		/* Only valid minors */
1433433d6423SLionel Sambuc 		if (sel_drive < MAX_DRIVES) {
1434433d6423SLionel Sambuc 			/* Leave in case of ridiculously high number */
1435433d6423SLionel Sambuc 			if (minor < SUBPART_PER_DISK) {
1436433d6423SLionel Sambuc 				/* Associate minor (device/partition)
1437433d6423SLionel Sambuc 				 * with peripheral number */
1438433d6423SLionel Sambuc 				/* TODO:PERIPH
1439433d6423SLionel Sambuc 				 * Proper peripheral selection based
1440433d6423SLionel Sambuc 				 * on minor should be here: */
1441433d6423SLionel Sambuc 				driver_state.cur_periph =
1442433d6423SLionel Sambuc 						&driver_state.periph[0];
1443433d6423SLionel Sambuc 
1444433d6423SLionel Sambuc 				/* Select drive entry for opening count etc. */
1445433d6423SLionel Sambuc 				driver_state.cur_drive =
1446433d6423SLionel Sambuc 					&(driver_state.cur_periph->drives
1447433d6423SLionel Sambuc 								[sel_drive]);
1448433d6423SLionel Sambuc 				/* Select device entry for given
1449433d6423SLionel Sambuc 				 * sub-partition device file */
1450433d6423SLionel Sambuc 				driver_state.cur_device =
1451433d6423SLionel Sambuc 					&(driver_state.cur_drive->subpart
1452433d6423SLionel Sambuc 								[sel_device]);
1453433d6423SLionel Sambuc 			}
1454433d6423SLionel Sambuc 		}
1455433d6423SLionel Sambuc 	}
1456433d6423SLionel Sambuc 
1457433d6423SLionel Sambuc 	/* Check for success */
1458433d6423SLionel Sambuc 	if (NULL == driver_state.cur_device) {
1459433d6423SLionel Sambuc 		MASS_MSG("Device for minor: %u not found", minor);
1460433d6423SLionel Sambuc 	} else {
1461433d6423SLionel Sambuc 		/* Assign index as well */
1462433d6423SLionel Sambuc 		driver_state.cur_drive->drive_idx = sel_drive;
1463433d6423SLionel Sambuc 	}
1464433d6423SLionel Sambuc 
1465433d6423SLionel Sambuc 	return driver_state.cur_device;
1466433d6423SLionel Sambuc }
1467433d6423SLionel Sambuc 
1468433d6423SLionel Sambuc 
1469433d6423SLionel Sambuc /*===========================================================================*
1470433d6423SLionel Sambuc  *    mass_storage_geometry                                                  *
1471433d6423SLionel Sambuc  *===========================================================================*/
1472*2d64210cSWojciech Zajac /* This command is optional for most mass storage devices
1473*2d64210cSWojciech Zajac  * It should rather be used with USB floppy disk reader */
1474433d6423SLionel Sambuc #ifdef MASS_USE_GEOMETRY
1475433d6423SLionel Sambuc static void
mass_storage_geometry(devminor_t minor,struct part_geom * part)1476433d6423SLionel Sambuc mass_storage_geometry(devminor_t minor, struct part_geom * part)
1477433d6423SLionel Sambuc {
1478433d6423SLionel Sambuc 	char flexible_disk_page[SCSI_MODE_SENSE_FLEX_DATA_LEN];
1479433d6423SLionel Sambuc 
1480433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1481433d6423SLionel Sambuc 
1482433d6423SLionel Sambuc 	/* Decode minor into drive device information */
1483433d6423SLionel Sambuc 	if (NULL == (mass_storage_part(minor)))
1484433d6423SLionel Sambuc 		return;
1485433d6423SLionel Sambuc 
1486433d6423SLionel Sambuc 	/* SCSI MODE SENSE OUT stage */
1487433d6423SLionel Sambuc 	if (mass_storage_send_scsi_cbw_out(SCSI_MODE_SENSE, NULL))
1488433d6423SLionel Sambuc 		return;
1489433d6423SLionel Sambuc 
1490433d6423SLionel Sambuc 	/* SCSI MODE SENSE first IN stage */
1491433d6423SLionel Sambuc 	if (mass_storage_send_scsi_data_in(flexible_disk_page,
1492433d6423SLionel Sambuc 					sizeof(flexible_disk_page)))
1493433d6423SLionel Sambuc 		return;
1494433d6423SLionel Sambuc 
1495433d6423SLionel Sambuc 	/* SCSI MODE SENSE second IN stage */
1496433d6423SLionel Sambuc 	if (mass_storage_send_scsi_csw_in())
1497433d6423SLionel Sambuc 		return;
1498433d6423SLionel Sambuc 
1499433d6423SLionel Sambuc 	/* Get geometry from reply */
1500433d6423SLionel Sambuc 	if (check_mode_sense_reply(flexible_disk_page, &(part->cylinders),
1501433d6423SLionel Sambuc 				&(part->heads), &(part->sectors)))
1502433d6423SLionel Sambuc 		return;
1503433d6423SLionel Sambuc #else
1504433d6423SLionel Sambuc static void
1505433d6423SLionel Sambuc mass_storage_geometry(devminor_t UNUSED(minor), struct part_geom * part)
1506433d6423SLionel Sambuc {
1507433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1508433d6423SLionel Sambuc 
1509433d6423SLionel Sambuc 	part->cylinders = part->size / SECTOR_SIZE;
1510433d6423SLionel Sambuc 	part->heads = 64;
1511433d6423SLionel Sambuc 	part->sectors = 32;
1512433d6423SLionel Sambuc #endif
1513433d6423SLionel Sambuc }
1514433d6423SLionel Sambuc 
1515433d6423SLionel Sambuc 
1516433d6423SLionel Sambuc /*===========================================================================*
1517433d6423SLionel Sambuc  *    usb_driver_completion                                                  *
1518433d6423SLionel Sambuc  *===========================================================================*/
1519433d6423SLionel Sambuc static void
1520433d6423SLionel Sambuc usb_driver_completion(void * UNUSED(priv))
1521433d6423SLionel Sambuc {
1522433d6423SLionel Sambuc 	/* Last request was completed so allow continuing
1523433d6423SLionel Sambuc 	 * execution from place where semaphore was downed */
1524433d6423SLionel Sambuc 	ddekit_sem_up(mass_storage_sem);
1525433d6423SLionel Sambuc }
1526433d6423SLionel Sambuc 
1527433d6423SLionel Sambuc 
1528433d6423SLionel Sambuc /*===========================================================================*
1529433d6423SLionel Sambuc  *    usb_driver_connect                                                     *
1530433d6423SLionel Sambuc  *===========================================================================*/
1531433d6423SLionel Sambuc static void
1532433d6423SLionel Sambuc usb_driver_connect(struct ddekit_usb_dev * dev,
1533433d6423SLionel Sambuc 		unsigned int interfaces)
1534433d6423SLionel Sambuc {
1535433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1536433d6423SLionel Sambuc 
1537433d6423SLionel Sambuc 	/* TODO:PERIPH
1538433d6423SLionel Sambuc 	 * Some sort of more complex peripheral assignment should be here */
1539433d6423SLionel Sambuc 	driver_state.cur_periph = &driver_state.periph[0];
1540433d6423SLionel Sambuc 
1541433d6423SLionel Sambuc 	if (NULL != driver_state.cur_periph->dev)
1542433d6423SLionel Sambuc 		panic("Only one peripheral can be connected!");
1543433d6423SLionel Sambuc 
1544433d6423SLionel Sambuc 	/* Hold host information for future use */
1545433d6423SLionel Sambuc 	driver_state.cur_periph->dev = dev;
1546433d6423SLionel Sambuc 	driver_state.cur_periph->interfaces = interfaces;
1547433d6423SLionel Sambuc 	driver_state.cur_periph->ep_in.ep_num = URB_INVALID_EP;
1548433d6423SLionel Sambuc 	driver_state.cur_periph->ep_out.ep_num = URB_INVALID_EP;
1549433d6423SLionel Sambuc }
1550433d6423SLionel Sambuc 
1551433d6423SLionel Sambuc 
1552433d6423SLionel Sambuc /*===========================================================================*
1553433d6423SLionel Sambuc  *    usb_driver_disconnect                                                  *
1554433d6423SLionel Sambuc  *===========================================================================*/
1555433d6423SLionel Sambuc static void
1556433d6423SLionel Sambuc usb_driver_disconnect(struct ddekit_usb_dev * UNUSED(dev))
1557433d6423SLionel Sambuc {
1558433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1559433d6423SLionel Sambuc 
1560433d6423SLionel Sambuc 	/* TODO:PERIPH
1561433d6423SLionel Sambuc 	 * Some sort of peripheral discard should be here */
1562433d6423SLionel Sambuc 	driver_state.cur_periph = &driver_state.periph[0];
1563433d6423SLionel Sambuc 
1564433d6423SLionel Sambuc 	assert(NULL != driver_state.cur_periph->dev);
1565433d6423SLionel Sambuc 
1566433d6423SLionel Sambuc 	/* Clear */
1567433d6423SLionel Sambuc 	driver_state.cur_periph->dev = NULL;
1568433d6423SLionel Sambuc 	driver_state.cur_periph->interfaces = 0;
1569433d6423SLionel Sambuc 	driver_state.cur_periph->ep_in.ep_num = URB_INVALID_EP;
1570433d6423SLionel Sambuc 	driver_state.cur_periph->ep_out.ep_num = URB_INVALID_EP;
1571433d6423SLionel Sambuc }
1572433d6423SLionel Sambuc 
1573433d6423SLionel Sambuc 
1574433d6423SLionel Sambuc /*===========================================================================*
1575433d6423SLionel Sambuc  *    mass_storage_get_endpoints                                             *
1576433d6423SLionel Sambuc  *===========================================================================*/
1577433d6423SLionel Sambuc static int
1578433d6423SLionel Sambuc mass_storage_get_endpoints(urb_ep_config * ep_in, urb_ep_config * ep_out)
1579433d6423SLionel Sambuc {
1580433d6423SLionel Sambuc 	/* URB to be send */
1581433d6423SLionel Sambuc 	struct ddekit_usb_urb urb;
1582433d6423SLionel Sambuc 
1583433d6423SLionel Sambuc 	/* Setup buffer to be attached */
1584433d6423SLionel Sambuc 	struct usb_ctrlrequest setup_buf;
1585433d6423SLionel Sambuc 
1586433d6423SLionel Sambuc 	/* Control EP configuration */
1587433d6423SLionel Sambuc 	urb_ep_config ep_conf;
1588433d6423SLionel Sambuc 
1589433d6423SLionel Sambuc 	/* Descriptors' buffer */
1590433d6423SLionel Sambuc 	unsigned char descriptors[MAX_DESCRIPTORS_LEN];
1591433d6423SLionel Sambuc 
1592433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1593433d6423SLionel Sambuc 
1594433d6423SLionel Sambuc 	/* Initialize EP configuration */
1595433d6423SLionel Sambuc 	ep_conf.ep_num = 0;
1596433d6423SLionel Sambuc 	ep_conf.direction = DDEKIT_USB_IN;
1597433d6423SLionel Sambuc 	ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
1598433d6423SLionel Sambuc 	ep_conf.max_packet_size = 0;
1599433d6423SLionel Sambuc 	ep_conf.interval = 0;
1600433d6423SLionel Sambuc 
1601433d6423SLionel Sambuc 	/* Reset URB and assign given values */
1602433d6423SLionel Sambuc 	init_urb(&urb, driver_state.cur_periph->dev, &ep_conf);
1603433d6423SLionel Sambuc 
1604433d6423SLionel Sambuc 	/* Clear setup data */
1605433d6423SLionel Sambuc 	memset(&setup_buf, 0, sizeof(setup_buf));
1606433d6423SLionel Sambuc 
1607433d6423SLionel Sambuc 	/* Standard get endpoint request */
1608433d6423SLionel Sambuc 	setup_buf.bRequestType = 0x80; /* Device to host */
1609433d6423SLionel Sambuc 	setup_buf.bRequest = UR_GET_DESCRIPTOR;
1610433d6423SLionel Sambuc 	setup_buf.wValue = UDESC_CONFIG << 8; /* TODO: configuration 0 */
1611433d6423SLionel Sambuc 	setup_buf.wIndex = 0x00;
1612433d6423SLionel Sambuc 	setup_buf.wLength = MAX_DESCRIPTORS_LEN;
1613433d6423SLionel Sambuc 
1614433d6423SLionel Sambuc 	/* Attach buffers to URB */
1615433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
1616433d6423SLionel Sambuc 			&setup_buf, sizeof(setup_buf));
1617433d6423SLionel Sambuc 	attach_urb_data(&urb, URB_BUF_TYPE_DATA,
1618433d6423SLionel Sambuc 			descriptors, sizeof(descriptors));
1619433d6423SLionel Sambuc 
1620433d6423SLionel Sambuc 	/* Send and wait for response */
1621433d6423SLionel Sambuc 	if (blocking_urb_submit(&urb, mass_storage_sem,
1622433d6423SLionel Sambuc 				URB_SUBMIT_ALLOW_MISMATCH))
1623433d6423SLionel Sambuc 		return EXIT_FAILURE;
1624433d6423SLionel Sambuc 
1625433d6423SLionel Sambuc 	/* Check if buffer was supposed to hold more data */
1626433d6423SLionel Sambuc 	if (urb.size < urb.actual_length) {
1627433d6423SLionel Sambuc 		MASS_MSG("Too much descriptor data received");
1628433d6423SLionel Sambuc 		return EXIT_FAILURE;
1629433d6423SLionel Sambuc 	}
1630433d6423SLionel Sambuc 
1631433d6423SLionel Sambuc 	return mass_storage_parse_descriptors(urb.data, urb.actual_length,
1632433d6423SLionel Sambuc 						ep_in, ep_out);
1633433d6423SLionel Sambuc }
1634433d6423SLionel Sambuc 
1635433d6423SLionel Sambuc 
1636433d6423SLionel Sambuc /*===========================================================================*
1637433d6423SLionel Sambuc  *    mass_storage_parse_endpoint                                            *
1638433d6423SLionel Sambuc  *===========================================================================*/
1639433d6423SLionel Sambuc static int
1640433d6423SLionel Sambuc mass_storage_parse_endpoint(usb_descriptor_t * cur_desc,
1641433d6423SLionel Sambuc 			urb_ep_config * ep_in, urb_ep_config * ep_out)
1642433d6423SLionel Sambuc {
1643433d6423SLionel Sambuc 	usb_endpoint_descriptor_t * ep_desc;
1644433d6423SLionel Sambuc 
1645433d6423SLionel Sambuc 	urb_ep_config * this_ep;
1646433d6423SLionel Sambuc 
1647433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1648433d6423SLionel Sambuc 
1649433d6423SLionel Sambuc 	ep_desc = (usb_endpoint_descriptor_t *)cur_desc;
1650433d6423SLionel Sambuc 
1651433d6423SLionel Sambuc 	/* Only bulk with no other attributes are important */
1652433d6423SLionel Sambuc 	if (UE_BULK == ep_desc->bmAttributes) {
1653433d6423SLionel Sambuc 
1654433d6423SLionel Sambuc 		/* Check for direction */
1655433d6423SLionel Sambuc 		if (UE_DIR_IN == UE_GET_DIR(ep_desc->bEndpointAddress)) {
1656433d6423SLionel Sambuc 
1657433d6423SLionel Sambuc 			this_ep = ep_in;
1658433d6423SLionel Sambuc 			this_ep->direction = DDEKIT_USB_IN;
1659433d6423SLionel Sambuc 
1660433d6423SLionel Sambuc 		} else {
1661433d6423SLionel Sambuc 
1662433d6423SLionel Sambuc 			this_ep = ep_out;
1663433d6423SLionel Sambuc 			this_ep->direction = DDEKIT_USB_OUT;
1664433d6423SLionel Sambuc 		}
1665433d6423SLionel Sambuc 
1666433d6423SLionel Sambuc 		/* Check if it was set before */
1667433d6423SLionel Sambuc 		if (URB_INVALID_EP != this_ep->ep_num) {
1668433d6423SLionel Sambuc 			MASS_MSG("BULK EP already set");
1669433d6423SLionel Sambuc 			return EXIT_FAILURE;
1670433d6423SLionel Sambuc 		}
1671433d6423SLionel Sambuc 
1672433d6423SLionel Sambuc 		/* Assign rest */
1673433d6423SLionel Sambuc 		this_ep->ep_num = UE_GET_ADDR(ep_desc->bEndpointAddress);
1674433d6423SLionel Sambuc 		this_ep->type = DDEKIT_USB_TRANSFER_BLK;
1675433d6423SLionel Sambuc 		this_ep->max_packet_size = UGETW(ep_desc->wMaxPacketSize);
1676433d6423SLionel Sambuc 		this_ep->interval = ep_desc->bInterval;
1677433d6423SLionel Sambuc 	}
1678433d6423SLionel Sambuc 
1679433d6423SLionel Sambuc 	/* EP type other than bulk, is also correct,
1680433d6423SLionel Sambuc 	 * just no parsing is performed */
1681433d6423SLionel Sambuc 	return EXIT_SUCCESS;
1682433d6423SLionel Sambuc }
1683433d6423SLionel Sambuc 
1684433d6423SLionel Sambuc /*===========================================================================*
1685433d6423SLionel Sambuc  *    mass_storage_parse_descriptors                                         *
1686433d6423SLionel Sambuc  *===========================================================================*/
1687433d6423SLionel Sambuc static int
1688433d6423SLionel Sambuc mass_storage_parse_descriptors(char * desc_buf, unsigned int buf_len,
1689433d6423SLionel Sambuc 				urb_ep_config * ep_in, urb_ep_config * ep_out)
1690433d6423SLionel Sambuc {
1691433d6423SLionel Sambuc 	/* Currently parsed, descriptors */
1692433d6423SLionel Sambuc 	usb_descriptor_t * cur_desc;
1693433d6423SLionel Sambuc 	usb_interface_descriptor_t * ifc_desc;
1694433d6423SLionel Sambuc 
1695433d6423SLionel Sambuc 	/* Byte counter for descriptor parsing */
1696433d6423SLionel Sambuc 	unsigned int cur_byte;
1697433d6423SLionel Sambuc 
1698433d6423SLionel Sambuc 	/* Non zero if recently parsed interface is valid for this device */
1699433d6423SLionel Sambuc 	int valid_interface;
1700433d6423SLionel Sambuc 
1701433d6423SLionel Sambuc 	MASS_DEBUG_DUMP;
1702433d6423SLionel Sambuc 
1703433d6423SLionel Sambuc 	/* Parse descriptors to get endpoints */
1704433d6423SLionel Sambuc 	ep_in->ep_num = URB_INVALID_EP;
1705433d6423SLionel Sambuc 	ep_out->ep_num = URB_INVALID_EP;
1706433d6423SLionel Sambuc 	valid_interface = 0;
1707433d6423SLionel Sambuc 	cur_byte = 0;
1708433d6423SLionel Sambuc 
1709433d6423SLionel Sambuc 	while (cur_byte < buf_len) {
1710433d6423SLionel Sambuc 
1711433d6423SLionel Sambuc 		/* Map descriptor to buffer */
1712433d6423SLionel Sambuc 		/* Structure is packed so alignment should not matter */
1713433d6423SLionel Sambuc 		cur_desc = (usb_descriptor_t *)&(desc_buf[cur_byte]);
1714433d6423SLionel Sambuc 
1715433d6423SLionel Sambuc 		/* Check this so we won't be reading
1716433d6423SLionel Sambuc 		 * memory outside the buffer */
1717433d6423SLionel Sambuc 		if ((cur_desc->bLength > 3) &&
1718433d6423SLionel Sambuc 			(cur_byte + cur_desc->bLength <= buf_len)) {
1719433d6423SLionel Sambuc 
1720433d6423SLionel Sambuc 			/* Parse based on descriptor type */
1721433d6423SLionel Sambuc 			switch (cur_desc->bDescriptorType) {
1722433d6423SLionel Sambuc 
1723433d6423SLionel Sambuc 				case UDESC_CONFIG: {
1724433d6423SLionel Sambuc 					if (USB_CONFIG_DESCRIPTOR_SIZE !=
1725433d6423SLionel Sambuc 						cur_desc->bLength) {
1726433d6423SLionel Sambuc 						MASS_MSG("Wrong configuration"
1727433d6423SLionel Sambuc 							" descriptor length");
1728433d6423SLionel Sambuc 						return EXIT_FAILURE;
1729433d6423SLionel Sambuc 					}
1730433d6423SLionel Sambuc 					break;
1731433d6423SLionel Sambuc 				}
1732433d6423SLionel Sambuc 
1733433d6423SLionel Sambuc 				case UDESC_STRING:
1734433d6423SLionel Sambuc 					break;
1735433d6423SLionel Sambuc 
1736433d6423SLionel Sambuc 				case UDESC_INTERFACE: {
1737433d6423SLionel Sambuc 					ifc_desc =
1738433d6423SLionel Sambuc 					 (usb_interface_descriptor_t *)cur_desc;
1739433d6423SLionel Sambuc 
1740433d6423SLionel Sambuc 					if (USB_INTERFACE_DESCRIPTOR_SIZE !=
1741433d6423SLionel Sambuc 						cur_desc->bLength) {
1742433d6423SLionel Sambuc 						MASS_MSG("Wrong interface"
1743433d6423SLionel Sambuc 							" descriptor length");
1744433d6423SLionel Sambuc 						return EXIT_FAILURE;
1745433d6423SLionel Sambuc 					}
1746433d6423SLionel Sambuc 
1747433d6423SLionel Sambuc 					/* Check if following data is meant
1748433d6423SLionel Sambuc 					 * for our interfaces */
1749433d6423SLionel Sambuc 					if ((1 << ifc_desc->bInterfaceNumber) &
1750433d6423SLionel Sambuc 					    driver_state.cur_periph->interfaces)
1751433d6423SLionel Sambuc 						valid_interface = 1;
1752433d6423SLionel Sambuc 					else
1753433d6423SLionel Sambuc 						valid_interface = 0;
1754433d6423SLionel Sambuc 
1755433d6423SLionel Sambuc 					break;
1756433d6423SLionel Sambuc 				}
1757433d6423SLionel Sambuc 
1758433d6423SLionel Sambuc 				case UDESC_ENDPOINT: {
1759433d6423SLionel Sambuc 					if (USB_ENDPOINT_DESCRIPTOR_SIZE !=
1760433d6423SLionel Sambuc 						cur_desc->bLength) {
1761433d6423SLionel Sambuc 						MASS_MSG("Wrong endpoint"
1762433d6423SLionel Sambuc 							" descriptor length");
1763433d6423SLionel Sambuc 						return EXIT_FAILURE;
1764433d6423SLionel Sambuc 					}
1765433d6423SLionel Sambuc 
1766433d6423SLionel Sambuc 					/* Previous interface was,
1767433d6423SLionel Sambuc 					 * what we were looking for */
1768433d6423SLionel Sambuc 					if (valid_interface) {
1769433d6423SLionel Sambuc 						if (EXIT_SUCCESS !=
1770433d6423SLionel Sambuc 						    mass_storage_parse_endpoint(
1771433d6423SLionel Sambuc 						    cur_desc, ep_in, ep_out))
1772433d6423SLionel Sambuc 							return EXIT_FAILURE;
1773433d6423SLionel Sambuc 
1774433d6423SLionel Sambuc 					}
1775433d6423SLionel Sambuc 
1776433d6423SLionel Sambuc 					break;
1777433d6423SLionel Sambuc 				}
1778433d6423SLionel Sambuc 
1779433d6423SLionel Sambuc 				default: {
1780433d6423SLionel Sambuc 					MASS_MSG("Wrong descriptor type");
1781433d6423SLionel Sambuc 					return EXIT_FAILURE;
1782433d6423SLionel Sambuc 				}
1783433d6423SLionel Sambuc 			}
1784433d6423SLionel Sambuc 
1785433d6423SLionel Sambuc 		} else {
1786433d6423SLionel Sambuc 			MASS_MSG("Invalid descriptor length");
1787433d6423SLionel Sambuc 			return EXIT_FAILURE;
1788433d6423SLionel Sambuc 		}
1789433d6423SLionel Sambuc 
1790433d6423SLionel Sambuc 		/* Get next descriptor */
1791433d6423SLionel Sambuc 		cur_byte += cur_desc->bLength;
1792433d6423SLionel Sambuc 	}
1793433d6423SLionel Sambuc 
1794433d6423SLionel Sambuc 	/* Total length should match sum of all descriptors' lengths... */
1795433d6423SLionel Sambuc 	if (cur_byte > buf_len)
1796433d6423SLionel Sambuc 		return EXIT_FAILURE;
1797433d6423SLionel Sambuc 
1798433d6423SLionel Sambuc 	/* ...and descriptors should be valid */
1799433d6423SLionel Sambuc 	if ((URB_INVALID_EP == ep_in->ep_num) ||
1800433d6423SLionel Sambuc 		(URB_INVALID_EP == ep_out->ep_num)) {
1801433d6423SLionel Sambuc 		MASS_MSG("Valid bulk endpoints not found");
1802433d6423SLionel Sambuc 		return EXIT_FAILURE;
1803433d6423SLionel Sambuc 	}
1804433d6423SLionel Sambuc 
1805433d6423SLionel Sambuc 	return EXIT_SUCCESS;
1806433d6423SLionel Sambuc }
1807