OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [usb/] [msd/] [slave/] [current/] [src/] [usbs_msd_scsi.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      usbs_msd_scsi.c
4
//
5
//      Support for slave-side USB mass storage SCSI devices.
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 2008 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later
16
// version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
// for more details.
22
//
23
// You should have received a copy of the GNU General Public License
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26
//
27
// As a special exception, if other files instantiate templates or use
28
// macros or inline functions from this file, or you compile this file
29
// and link it with other works to produce a work based on this file,
30
// this file does not by itself cause the resulting work to be covered by
31
// the GNU General Public License. However the source code for this file
32
// must still be made available in accordance with section (3) of the GNU
33
// General Public License v2.
34
//
35
// This exception does not invalidate any other reasons why a work based
36
// on this file might be covered by the GNU General Public License.
37
// -------------------------------------------
38
// ####ECOSGPLCOPYRIGHTEND####
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    ccoutand <ccoutand@stmi.com>
43
//
44
// Date:         2010-06-02
45
//
46
//####DESCRIPTIONEND####
47
//
48
//==========================================================================
49
 
50
#include <cyg/infra/cyg_type.h>
51
#include <cyg/infra/cyg_ass.h>
52
#include <cyg/infra/cyg_trac.h>
53
#include <cyg/kernel/kapi.h>
54
#include <cyg/infra/diag.h>
55
 
56
#include <pkgconf/io_usb_slave_msd.h>
57
#include <cyg/io/usb/usbs_msd.h>
58
 
59
#include <cyg/io/usb/usbs_msd_opcode.h>
60
#include <cyg/io/usb/usbs_msd_scsi.h>
61
 
62
#include <cyg/io/disk.h>
63
 
64
#include <stdio.h> // for memcpy
65
 
66
#if defined(CYGBLD_IO_USB_SLAVE_MSD_DEBUG)
67
#define DBG diag_printf
68
#else
69
#define DBG (1) ? (void)0 : diag_printf
70
#endif
71
 
72
#if defined(CYGBLD_IO_USB_SLAVE_MSD_TRACE)
73
#define TRACE diag_printf
74
#else
75
#define TRACE (1) ? (void)0 : diag_printf
76
#endif
77
 
78
 
79
const msd_scsi_inq_resp inq_resp = {
80
   USBS_SCSI_DIRECT_ACCESS_BLOCK_DEVICE, // Direct Access Block device
81
   USBS_SCSI_REMOVABLE_DEVICE,           // Device is removable
82
   0x04,                                 // Comply with SPC-2
83
   0x02,                                 // Standard format
84
   0x20,                                 // Response is 0x20 + 4 bytes
85
   0x00,
86
   0x00,
87
   0x00,
88
   {'e','C','o','s',' ',' ',' ',' '},
89
   {'M','a','s','s',' ','S','t','o','r','a','g','e',' ',' ',' ',' '},
90
   {'0','.','0','1'},
91
};
92
 
93
 
94
// Handle Mode Sense Command
95
//
96
static inline void
97
usbs_msd_scsi_update_sense(msd_scsi_req_sense_resp *sense, \
98
                                cyg_uint8 asc, cyg_uint8 ascq, cyg_uint8 key )
99
{
100
   USBS_MSD_SCSI_SET_SENSE_ASC( sense->byte , asc );
101
   USBS_MSD_SCSI_SET_SENSE_ASCQ( sense->byte , ascq );
102
   USBS_MSD_SCSI_SET_SENSE_KEY( sense->byte , key );
103
}
104
 
105
 
106
// Handle Inquiry Request Command
107
//
108
static inline cyg_int32
109
usbs_msd_scsi_handle_inquiry( usbs_msd * msd )
110
{
111
   cyg_int32 tx_bytes = sizeof(msd_scsi_inq_resp);
112
 
113
   TRACE("USB Slave MSD: SCSI inquiry\n\r");
114
 
115
   // Copy over to message buffer
116
   memcpy( msd->buffer, (cyg_uint8 *) &inq_resp, tx_bytes );
117
 
118
   tx_bytes = msd->send( msd, msd->buffer, tx_bytes );
119
 
120
   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
121
 
122
   return tx_bytes;
123
}
124
 
125
 
126
// Handle Read Capacity Command
127
//
128
static inline cyg_int32
129
usbs_msd_scsi_handle_capacity( usbs_msd * msd )
130
{
131
   cyg_disk_info_t disk_info;
132
   cyg_int32 tx_bytes = sizeof(cyg_uint32) << 1;
133
   cyg_uint32 len     = sizeof(cyg_disk_info_t);
134
   cyg_uint32 key     = CYG_IO_GET_CONFIG_DISK_INFO;
135
   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
136
 
137
   TRACE("USB Slave MSD: SCSI capacity\n\r");
138
 
139
   // Get the configuration of a device
140
   cyg_io_get_config( lun, key, &disk_info, &len );
141
 
142
   msd->buffer[0] = BYTE3_32( disk_info.blocks_num );
143
   msd->buffer[1] = BYTE2_32( disk_info.blocks_num );
144
   msd->buffer[2] = BYTE1_32( disk_info.blocks_num );
145
   msd->buffer[3] = BYTE0_32( disk_info.blocks_num );
146
 
147
   msd->buffer[4] = BYTE3_32( disk_info.block_size );
148
   msd->buffer[5] = BYTE2_32( disk_info.block_size );
149
   msd->buffer[6] = BYTE1_32( disk_info.block_size );
150
   msd->buffer[7] = BYTE0_32( disk_info.block_size );
151
 
152
   tx_bytes = msd->send( msd, msd->buffer, tx_bytes );
153
 
154
   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
155
 
156
   return tx_bytes;
157
}
158
 
159
 
160
// Handle Read Command
161
//
162
static inline cyg_int32
163
usbs_msd_scsi_handle_read( usbs_msd * msd, msd_scsi_req_sense_resp *sense )
164
{
165
   Cyg_ErrNo ret;
166
   cyg_uint32 transfert_len = 0, pos = 0, len = 1;
167
   cyg_int32 ret_len = 0;
168
   cyg_int32 tx_byte = 0;
169
   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
170
 
171
   TRACE("USB Slave MSD: SCSI read\n\r");
172
 
173
   pos = ( msd->cbw.cb.data[2] << 24 ) | \
174
         ( msd->cbw.cb.data[3] << 16 ) | \
175
         ( msd->cbw.cb.data[4] <<  8 ) | \
176
           msd->cbw.cb.data[5];
177
 
178
   transfert_len = ( msd->cbw.cb.data[7] << 8 ) | msd->cbw.cb.data[8];
179
 
180
   // Read data from a block device
181
   while ( transfert_len > 0 ) {
182
     if( ( ret = cyg_io_bread( lun, msd->buffer, &len, pos)) != ENOERR )
183
       break;
184
     tx_byte = msd->send( msd, msd->buffer, (USBS_MSD_DISK_SECTOR_SIZE) );
185
     TRACE("USB Slave MSD: Read %d block, %d bytes\n\r", transfert_len, tx_byte);
186
     ret_len += tx_byte;
187
     // Substract 1 sector
188
     transfert_len -= 1;
189
     pos += 1;
190
   }
191
 
192
   if ( ret == ENOERR )
193
   {
194
      msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
195
   }
196
   else
197
   {
198
     msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
199
     usbs_msd_scsi_update_sense( sense, \
200
             USBS_MSD_SCSI_SENSE_ASC_UNRECOVERED_READ_ERROR, \
201
             USBS_MSD_SCSI_SENSE_ASCQ_UNRECOVERED_READ_ERROR, \
202
             USBS_MSD_SCSI_SENSE_MEDIUM_ERROR );
203
   }
204
 
205
   return ret_len;
206
}
207
 
208
 
209
// Handle Write Command
210
//
211
static inline cyg_int32
212
usbs_msd_scsi_handle_write( usbs_msd * msd , msd_scsi_req_sense_resp *sense )
213
{
214
   Cyg_ErrNo ret;
215
   cyg_uint32 transfert_len = 0, pos = 0, len = 1;
216
   cyg_int32 ret_len = 0;
217
   cyg_int32 rx_byte = 0;
218
   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
219
 
220
   DBG("USB Slave MSD: SCSI Write\n\r");
221
 
222
   pos = ( msd->cbw.cb.data[2] << 24 ) | \
223
             ( msd->cbw.cb.data[3] << 16 ) | \
224
             ( msd->cbw.cb.data[4] <<  8 ) | \
225
               msd->cbw.cb.data[5];
226
 
227
   transfert_len = ( msd->cbw.cb.data[7] << 8 ) | msd->cbw.cb.data[8];
228
 
229
   // Read data from a block device
230
   while ( transfert_len > 0 ) {
231
     rx_byte = msd->receive( msd, msd->buffer, (USBS_MSD_DISK_SECTOR_SIZE) );
232
     if( ( ret = cyg_io_bwrite( lun, msd->buffer, &len, pos)) != ENOERR )
233
       break;
234
     TRACE("USB Slave MSD: Write %d block, %d bytes\n\r", transfert_len, rx_byte);
235
     ret_len += ( rx_byte );
236
     // Substract 1 sector
237
     transfert_len -= 1;
238
     pos += 1;
239
   }
240
 
241
   if ( ret == ENOERR )
242
   {
243
     msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
244
   }
245
   else
246
   {
247
     msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
248
     usbs_msd_scsi_update_sense( sense, \
249
             USBS_MSD_SCSI_SENSE_ASC_WRITE_ERROR, \
250
             USBS_MSD_SCSI_SENSE_ASCQ_WRITE_ERROR, \
251
             USBS_MSD_SCSI_SENSE_MEDIUM_ERROR );
252
   }
253
 
254
   return ret_len;
255
}
256
 
257
 
258
// Handle Request Sense Command
259
//
260
static inline cyg_int32
261
usbs_msd_scsi_handle_req_sense( usbs_msd * msd,  \
262
                                      msd_scsi_req_sense_resp *sense )
263
{
264
   cyg_uint8 i = 0;
265
   cyg_int32 tx_bytes = sizeof(msd_scsi_req_sense_resp);
266
 
267
   TRACE("USB Slave MSD: SCSI request sense\n\r");
268
 
269
   // Copy over to message buffer
270
   for(i = 0 ; i < tx_bytes ; i++)
271
       msd->buffer[i] = sense->byte[i];
272
 
273
   tx_bytes = msd->send( msd, msd->buffer, tx_bytes );
274
 
275
   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
276
 
277
   return tx_bytes;
278
}
279
 
280
 
281
// Handle Mode Sense Command
282
//
283
static inline cyg_int32
284
usbs_msd_scsi_handle_sense( usbs_msd * msd,  \
285
                           msd_scsi_req_sense_resp *sense )
286
{
287
   cyg_int32 tx_bytes = 0x0;
288
   DBG("USB Slave MSD: SCSI sense\n\r");
289
 
290
   msd->buffer[0] = 0x03; // Number of byte in the following message
291
   msd->buffer[1] = 0x00; // Media type
292
   msd->buffer[2] = 0x00; // Not Write protected, no cache-control-bit support
293
   msd->buffer[3] = 0x00; // No Mode parameter
294
 
295
   // FIXME : handle different option correctly. For the time being,
296
   // just respond with minimum data
297
   if( ( msd->cbw.cb.data[2] & 0x3F ) == \
298
        USBS_MSD_SCSI_MODE_PAGE_CODE_ALL )
299
   {
300
     DBG("USB Slave MSD: SCSI sense all\n\r");
301
 
302
     tx_bytes = msd->send( msd, msd->buffer, 4 );
303
 
304
     msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
305
   }
306
   else
307
   {
308
     DBG("USB Slave MSD: SCSI sense page: %x\n\r", \
309
             msd->cbw.cb.data[2]);
310
 
311
     tx_bytes = msd->send( msd, msd->buffer, 4 );
312
 
313
     msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
314
   }
315
 
316
   return tx_bytes;
317
}
318
 
319
 
320
// Handle Test Unit Ready Command
321
//
322
static inline cyg_int32
323
usbs_msd_scsi_handle_test_unit_ready( usbs_msd * msd , \
324
                                         msd_scsi_req_sense_resp *sense )
325
{
326
   cyg_disk_info_t disk_info;
327
   Cyg_ErrNo ret;
328
   cyg_uint32 len = sizeof(cyg_disk_info_t);
329
   cyg_uint32 key = CYG_IO_GET_CONFIG_DISK_INFO;
330
   cyg_io_handle_t lun = msd->lun->handle[msd->cbw.lun];
331
 
332
   TRACE("USB Slave MSD: SCSI test unit ready\n\r");
333
 
334
   // Get the configuration of a device
335
   ret = cyg_io_get_config( lun, key, &disk_info, &len);
336
 
337
   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
338
 
339
   USBS_MSD_SCSI_INIT_SENSE_DATA( sense->byte );
340
 
341
   // check if disk is connected / mounted here
342
   if( disk_info.connected == false )
343
   {
344
      DBG("USB Slave MSD: Disk not mounted \n\r");
345
      usbs_msd_scsi_update_sense( sense, \
346
             USBS_MSD_SCSI_SENSE_ASC_MEDIUM_NOT_PRESENT, \
347
             USBS_MSD_SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT, \
348
             USBS_MSD_SCSI_SENSE_UNIT_ATTENTION);
349
 
350
      msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
351
   }
352
 
353
   // No data to transfer
354
   return 0;
355
}
356
 
357
 
358
// Windows host operating system uses this command. Usually if
359
// a command is not supported, the CSW should return failure.
360
// Since no data is sent in the data transfer phase, the TX
361
// endpoint shall be stalled. Since some USB driver in eCos
362
// do not support endpoint stall, is it required to respond
363
// with some data, otherwise the driver would freeze. In the
364
// following case, we fill the data structure but report
365
// failure in the CSW.
366
#if !defined(CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE)
367
// Handle Read Format Capacities
368
//
369
static inline cyg_int32
370
usbs_msd_scsi_read_format_capacities( usbs_msd * msd )
371
{
372
   cyg_int32 i = 0;
373
   DBG("USB Slave MSD: SCSI read format capacities\n\r");
374
 
375
   for(i = 0 ; i < msd->cbw.data_transfert_len; i++)
376
   {
377
     msd->buffer[i] = 0;
378
   }
379
 
380
   i = msd->send( msd, msd->buffer, i );
381
 
382
   msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
383
 
384
   return i;
385
}
386
#endif
387
 
388
 
389
// Handle Verify
390
//
391
static inline cyg_int32
392
usbs_msd_scsi_handle_verify( usbs_msd * msd )
393
{
394
   DBG("USB Slave MSD: SCSI test unit verify\n\r");
395
 
396
   // FIXME: Should do something here?
397
   // Return success, command is optional
398
   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
399
 
400
   // No data to transfer
401
   return 0;
402
}
403
 
404
 
405
// Handle Medium Removal
406
//
407
static inline cyg_int32
408
usbs_msd_scsi_handle_removal( usbs_msd * msd )
409
{
410
   DBG("USB Slave MSD: SCSI Prevent / Allow device removal, LUN %d, flag %d %d\n\r",
411
          ( msd->cbw.cb.data[1] & 0xf0 >> 4 ) , ( msd->cbw.cb.data[4] & 0x01 ),
412
            msd->cbw.data_transfert_len );
413
 
414
   // Support for this command is not mandatory.
415
   // No specific handling of this command is implemented.
416
   // Maybe mount / umount the disc?
417
   msd->csw.status = USBS_MSD_CSW_STATUS_PASSED;
418
 
419
   // No data to transfer
420
   return 0;
421
}
422
 
423
 
424
// Handle SCSI command
425
//
426
cyg_int32
427
usbs_msd_scsi_handle_cmd( usbs_msd * msd )
428
{
429
   bool ret;
430
   cyg_uint8 cmd = msd->cbw.cb.data[0];
431
   msd_scsi_req_sense_resp *sense = (msd_scsi_req_sense_resp *) msd->handler_data;
432
 
433
   switch( cmd )
434
   {
435
     case USBS_SCSI_INQUIRY:
436
        ret = usbs_msd_scsi_handle_inquiry( msd );
437
        break;
438
 
439
     case USBS_SCSI_READ_CAPACITY:
440
        ret = usbs_msd_scsi_handle_capacity( msd );
441
        break;
442
 
443
     case USBS_SCSI_READ_10:
444
        ret = usbs_msd_scsi_handle_read(msd , sense );
445
        break;
446
 
447
     case USBS_SCSI_WRITE_10:
448
        ret = usbs_msd_scsi_handle_write( msd , sense );
449
        break;
450
 
451
     case USBS_SCSI_REQUEST_SENSE:
452
        ret = usbs_msd_scsi_handle_req_sense( msd , sense );
453
        break;
454
 
455
     case USBS_SCSI_SENSE_6:
456
        ret = usbs_msd_scsi_handle_sense( msd , sense);
457
        break;
458
 
459
     case USBS_SCSI_TEST_UNIT_READY:
460
        ret = usbs_msd_scsi_handle_test_unit_ready( msd , sense );
461
        break;
462
 
463
     case USBS_SCSI_VERIFY_10:
464
        ret = usbs_msd_scsi_handle_verify( msd );
465
        break;
466
 
467
#if !defined(CYGSEM_IO_USB_SLAVE_MSD_STALL_ENABLE)
468
     case USBS_SCSI_READ_FORMAT_CAPACITIES:
469
        ret = usbs_msd_scsi_read_format_capacities( msd );
470
        break;
471
#endif
472
 
473
     case USBS_SCSI_PREVENT_ALLOW_REMOVAL:
474
        ret = usbs_msd_scsi_handle_removal( msd );
475
        break;
476
 
477
     default:
478
        // Use for all commands not implemented, not
479
        // supported
480
        DBG("USB Slave MSD: SCSI illegal request %x \n\r", cmd );
481
        USBS_MSD_SCSI_INIT_SENSE_DATA( sense->byte );
482
        usbs_msd_scsi_update_sense( sense, \
483
                USBS_MSD_SCSI_SENSE_ASC_INVALID_OPCODE, \
484
                USBS_MSD_SCSI_SENSE_ASCQ_INVALID_OPCODE, \
485
                USBS_MSD_SCSI_SENSE_ILLEGAL_REQUEST);
486
        msd->csw.status = USBS_MSD_CSW_STATUS_FAILED;
487
        ret = 0;
488
        break;
489
 
490
   }
491
 
492
   return ret;
493
 
494
}
495
 
496
// SCSI initialization
497
//
498
bool
499
usbs_msd_scsi_init( void ** ctxt )
500
{
501
  static msd_scsi_req_sense_resp sense;
502
 
503
  DBG("USB Slave MSD: SCSI init %p\n", &sense);
504
 
505
  USBS_MSD_SCSI_INIT_SENSE_DATA( sense.byte );
506
 
507
  *ctxt = &sense;
508
 
509
  return true;
510
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.