New USB stack
[kugel-rb.git] / firmware / usbstack / usb_storage.c
blob2c02284deac155954a4b028e4d08c24c73a4eef5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
10 * Copyright (C) 2007 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "string.h"
20 #include "system.h"
21 #include "usb_core.h"
22 #include "usb_drv.h"
23 //#define LOGF_ENABLE
24 #include "logf.h"
25 #include "ata.h"
26 #include "hotswap.h"
28 #define SECTOR_SIZE 512
30 /* bulk-only class specific requests */
31 #define USB_BULK_RESET_REQUEST 0xff
32 #define USB_BULK_GET_MAX_LUN 0xfe
34 #define DIRECT_ACCESS_DEVICE 0x00 /* disks */
35 #define DEVICE_REMOVABLE 0x80
37 #define CBW_SIGNATURE 0x43425355
38 #define CSW_SIGNATURE 0x53425355
40 #define SCSI_TEST_UNIT_READY 0x00
41 #define SCSI_INQUIRY 0x12
42 #define SCSI_MODE_SENSE 0x1a
43 #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
44 #define SCSI_READ_CAPACITY 0x25
45 #define SCSI_READ_10 0x28
46 #define SCSI_WRITE_10 0x2a
48 #define SCSI_STATUS_GOOD 0x00
49 #define SCSI_STATUS_CHECK_CONDITION 0x02
52 struct inquiry_data {
53 unsigned char DeviceType;
54 unsigned char DeviceTypeModifier;
55 unsigned char Versions;
56 unsigned char Format;
57 unsigned char AdditionalLength;
58 unsigned char Reserved[2];
59 unsigned char Capability;
60 unsigned char VendorId[8];
61 unsigned char ProductId[16];
62 unsigned char ProductRevisionLevel[4];
63 } __attribute__ ((packed));
65 struct command_block_wrapper {
66 unsigned int signature;
67 unsigned int tag;
68 unsigned int data_transfer_length;
69 unsigned char flags;
70 unsigned char lun;
71 unsigned char command_length;
72 unsigned char command_block[16];
73 } __attribute__ ((packed));
75 struct command_status_wrapper {
76 unsigned int signature;
77 unsigned int tag;
78 unsigned int data_residue;
79 unsigned char status;
80 } __attribute__ ((packed));
82 struct capacity {
83 unsigned int block_count;
84 unsigned int block_size;
85 } __attribute__ ((packed));
87 /* the ARC USB controller can at most buffer 16KB unaligned data */
88 static unsigned char _transfer_buffer[16384];
89 static unsigned char* transfer_buffer;
90 static struct inquiry_data _inquiry;
91 static struct inquiry_data* inquiry;
92 static struct capacity _capacity_data;
93 static struct capacity* capacity_data;
95 //static unsigned char partial_sector[SECTOR_SIZE];
97 static struct {
98 unsigned int sector;
99 unsigned int offset; /* if partial sector */
100 unsigned int count;
101 unsigned int tag;
102 } current_cmd;
104 void handle_scsi(struct command_block_wrapper* cbw);
105 void send_csw(unsigned int tag, int status);
106 static void identify2inquiry(void);
108 static enum {
109 IDLE,
110 SENDING,
111 RECEIVING
112 } state = IDLE;
114 /* called by usb_code_init() */
115 void usb_storage_init(void)
117 inquiry = (void*)UNCACHED_ADDR(&_inquiry);
118 transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer);
119 capacity_data = (void*)UNCACHED_ADDR(&_capacity_data);
120 identify2inquiry();
123 /* called by usb_core_transfer_complete() */
124 void usb_storage_transfer_complete(int endpoint)
126 struct command_block_wrapper* cbw = (void*)transfer_buffer;
128 switch (endpoint) {
129 case EP_RX:
130 //logf("ums: %d bytes in", length);
131 switch (state) {
132 case IDLE:
133 handle_scsi(cbw);
134 break;
136 default:
137 break;
140 /* re-prime endpoint */
141 usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer);
142 break;
144 case EP_TX:
145 //logf("ums: %d bytes out", length);
146 break;
150 /* called by usb_core_control_request() */
151 bool usb_storage_control_request(struct usb_ctrlrequest* req)
153 /* note: interrupt context */
155 bool handled = false;
157 switch (req->bRequest) {
158 case USB_BULK_GET_MAX_LUN: {
159 static char maxlun = 0;
160 logf("ums: getmaxlun");
161 usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1);
162 usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */
163 handled = true;
164 break;
167 case USB_BULK_RESET_REQUEST:
168 logf("ums: bulk reset");
169 usb_drv_reset_endpoint(EP_RX, false);
170 usb_drv_reset_endpoint(EP_TX, true);
171 usb_drv_send(EP_CONTROL, NULL, 0); /* ack */
172 handled = true;
173 break;
175 case USB_REQ_SET_CONFIGURATION:
176 logf("ums: set config");
177 /* prime rx endpoint */
178 usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer);
179 handled = true;
180 break;
183 return handled;
186 /****************************************************************************/
188 void handle_scsi(struct command_block_wrapper* cbw)
190 /* USB Mass Storage assumes LBA capability.
191 TODO: support 48-bit LBA */
193 unsigned int length = cbw->data_transfer_length;
195 switch (cbw->command_block[0]) {
196 case SCSI_TEST_UNIT_READY:
197 logf("scsi test_unit_ready");
198 send_csw(cbw->tag, SCSI_STATUS_GOOD);
199 break;
201 case SCSI_INQUIRY:
202 logf("scsi inquiry");
203 length = MIN(length, cbw->command_block[4]);
204 usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length));
205 send_csw(cbw->tag, SCSI_STATUS_GOOD);
206 break;
208 case SCSI_MODE_SENSE: {
209 static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
210 logf("scsi mode_sense");
211 usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data),
212 MIN(sizeof sense_data, length));
213 send_csw(cbw->tag, SCSI_STATUS_GOOD);
214 break;
217 case SCSI_ALLOW_MEDIUM_REMOVAL:
218 logf("scsi allow_medium_removal");
219 send_csw(cbw->tag, SCSI_STATUS_GOOD);
220 break;
222 case SCSI_READ_CAPACITY: {
223 logf("scsi read_capacity");
224 #ifdef HAVE_FLASH_STORAGE
225 tCardInfo* cinfo = card_get_info(0);
226 capacity_data->block_count = htobe32(cinfo->numblocks);
227 capacity_data->block_size = htobe32(cinfo->blocksize);
228 #else
229 unsigned short* identify = ata_get_identify();
230 capacity_data->block_count = htobe32(identify[60] << 16 | identify[61]);
231 capacity_data->block_size = htobe32(SECTOR_SIZE);
232 #endif
233 usb_drv_send(EP_TX, capacity_data,
234 MIN(sizeof _capacity_data, length));
235 send_csw(cbw->tag, SCSI_STATUS_GOOD);
236 break;
239 case SCSI_READ_10:
240 current_cmd.sector =
241 cbw->command_block[2] << 24 |
242 cbw->command_block[3] << 16 |
243 cbw->command_block[4] << 8 |
244 cbw->command_block[5] ;
245 current_cmd.count =
246 cbw->command_block[7] << 16 |
247 cbw->command_block[8];
248 current_cmd.offset = 0;
249 current_cmd.tag = cbw->tag;
251 logf("scsi read %d %d", current_cmd.sector, current_cmd.count);
253 /* too much? */
254 if (current_cmd.count > (sizeof _transfer_buffer / SECTOR_SIZE)) {
255 send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION);
256 break;
259 ata_read_sectors(IF_MV2(0,) current_cmd.sector, current_cmd.count,
260 &transfer_buffer);
261 state = SENDING;
262 usb_drv_send(EP_TX, transfer_buffer,
263 MIN(current_cmd.count * SECTOR_SIZE, length));
264 break;
266 case SCSI_WRITE_10:
267 logf("scsi write10");
268 break;
270 default:
271 logf("scsi unknown cmd %x", cbw->command_block[0]);
272 break;
276 void send_csw(unsigned int tag, int status)
278 static struct command_status_wrapper _csw;
279 struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw);
280 csw->signature = CSW_SIGNATURE;
281 csw->tag = tag;
282 csw->data_residue = 0;
283 csw->status = status;
285 //logf("csw %x %x", csw->tag, csw->signature);
286 usb_drv_send(EP_TX, csw, sizeof _csw);
289 /* convert ATA IDENTIFY to SCSI INQUIRY */
290 static void identify2inquiry(void)
292 unsigned int i;
293 #ifdef HAVE_FLASH_STORAGE
294 for (i=0; i<8; i++)
295 inquiry->VendorId[i] = i + 'A';
297 for (i=0; i<8; i++)
298 inquiry->ProductId[i] = i + 'm';
299 #else
300 unsigned short* dest;
301 unsigned short* src;
302 unsigned short* identify = ata_get_identify();
303 memset(inquiry, 0, sizeof _inquiry);
305 if (identify[82] & 4)
306 inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
308 /* ATA only has a 'model' field, so we copy the
309 first 8 bytes to 'vendor' and the rest to 'product' */
310 src = (unsigned short*)&identify[27];
311 dest = (unsigned short*)&inquiry->VendorId;
312 for (i=0;i<4;i++)
313 dest[i] = src[i];
315 src = (unsigned short*)&identify[27+8];
316 dest = (unsigned short*)&inquiry->ProductId;
317 for (i=0;i<8;i++)
318 dest[i] = src[i];
320 src = (unsigned short*)&identify[23];
321 dest = (unsigned short*)&inquiry->ProductRevisionLevel;
322 for (i=0;i<2;i++)
323 dest[i] = src[i];
324 #endif
326 inquiry->DeviceType = DIRECT_ACCESS_DEVICE;
327 inquiry->AdditionalLength = 0x1f;
328 inquiry->Versions = 3; /* ANSI SCSI level 2 */
329 inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */