Contiki-NG
Loading...
Searching...
No Matches
usb-rbc.c
1#include <usb-msc-bulk.h>
2#include <usb-api.h>
3#include <usb-core.h>
4#include <sys/process.h>
5#include <stdio.h>
6#include <rbc_const.h>
7#include <rbc_struct.h>
8#include <string.h>
9
10#ifdef DEBUG
11#define PRINTF(...) printf(__VA_ARGS__)
12#else
13#define PRINTF(...)
14#endif
15
16#ifndef USB_RBC_NUM_BLOCKS
17#define USB_RBC_NUM_BLOCKS 32
18#endif
19
20static struct spc2_sense_data sense_data =
21 {
22 SCSI_SENSE_CURRENT_ERROR,
23 0,
24 0,
25 {0},
26 (sizeof(struct spc2_sense_data)
27 - offsetof(struct spc2_sense_data, command_specific))
28 };
29
30static void
31scsi_error(unsigned int sense_key, unsigned int asc, int32_t info)
32{
33 sense_data.response_code = SCSI_SENSE_INFORMATION_VALID | SCSI_SENSE_CURRENT_ERROR;
34 sense_data.information[0] = (info >> 24) & 0xff;
35 sense_data.information[1] = (info >> 16) & 0xff;
36 sense_data.information[2] = (info >> 8) & 0xff;
37 sense_data.information[3] = info & 0xff;
38 sense_data.sense_key = sense_key;
39 sense_data.asc = (asc >> 8) & 0xff;
40 sense_data.ascq = asc & 0xff;
41}
42
43static void
44scsi_ok()
45{
46 sense_data.response_code = SCSI_SENSE_CURRENT_ERROR;
47 sense_data.sense_key = SCSI_SENSE_KEY_NO_SENSE;
48 sense_data.asc = 0x00;
49 sense_data.ascq = 0x00;
50};
51
52static const struct spc2_std_inquiry_data std_inquiry_data =
53 {
54 SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC,
55 0,
56 SCSI_STD_INQUIRY_VERSION_SPC2,
57 0,
58 (sizeof(struct spc2_std_inquiry_data)
59 - offsetof(struct spc2_std_inquiry_data, flags3)),
60 0,
61 0,
62 0,
63 {'F','l','u','f','w','a','r','e'},
64 {'T','e','s','t',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '},
65 {'0','.','1',' '}
66 };
67
68#define UNIT_NAME {'F','l','u','f','f','w','a','r','e',' ', \
69 'P','s','e','u','d','o',' ','D','i','s','k'}
70#define UNIT_NAME_LENGTH 21
71
72static const struct
73{
74 struct spc2_vital_product_data_head head;
75 struct {
76 struct spc2_vital_product_data_head head;
77 char unit_name[UNIT_NAME_LENGTH];
78 } descriptor;
79} CC_BYTE_ALIGNED device_identification_data =
80 {
81 {
82 SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC,
83 SCSI_PAGE_DEVICE_IDENTIFICATION,
84 0,
85 sizeof(device_identification_data.descriptor),
86 },
87 {
88 {
89 SCSI_CODE_SET_ACSII,
90 SCSI_IDENTIFIER_TYPE_NON_UNIQUE,
91 0,
92 sizeof(device_identification_data.descriptor.unit_name)
93 },
94 UNIT_NAME
95 }
96 };
97
98
99static const struct
100{
101 struct spc2_vital_product_data_head head;
102 uint8_t supported[3];
103} CC_BYTE_ALIGNED supported_pages_data =
104 {
105 {
106 SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC,
107 SCSI_PAGE_SUPPORTED_PAGES,
108 0,
109 sizeof(supported_pages_data.supported),
110 },
111 {SCSI_PAGE_SUPPORTED_PAGES, SCSI_PAGE_UNIT_SERIAL_NUMBER,
112 SCSI_PAGE_DEVICE_IDENTIFICATION}
113 };
114
115static const struct
116{
117 struct spc2_vital_product_data_head head;
118 uint8_t serial_number[8];
119} CC_BYTE_ALIGNED unit_serial_number_data = {
120 {
121 SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC,
122 SCSI_PAGE_SUPPORTED_PAGES,
123 0,
124 sizeof(unit_serial_number_data.serial_number)
125 },
126 {'1','2','3','4','5','6','7','8'}
127};
128
129static usb_msc_handler_status
130handle_inquiry_cmd(struct usb_msc_command_state *state)
131{
132 struct spc2_inquiry_cmd *cmd = (struct spc2_inquiry_cmd*)state->command;
133 if (cmd->flags & SCSI_INQUIRY_FLAG_CMDDT) {
134 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB,
135 cmd->allocation_length);
136 return USB_MSC_HANDLER_FAILED;
137 }
138 if (cmd->flags & SCSI_INQUIRY_FLAG_EVPD) {
139 PRINTF("Requested page %02x\n", cmd->page);
140 switch (cmd->page) {
141 case SCSI_PAGE_SUPPORTED_PAGES:
142 usb_msc_send_data((uint8_t *)&supported_pages_data,
143 sizeof(supported_pages_data),
144 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
145 break;
146 case SCSI_PAGE_DEVICE_IDENTIFICATION:
147 usb_msc_send_data((uint8_t *)&device_identification_data,
148 sizeof(device_identification_data),
149 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
150 break;
151 case SCSI_PAGE_UNIT_SERIAL_NUMBER:
152 usb_msc_send_data((uint8_t *)&unit_serial_number_data,
153 sizeof(unit_serial_number_data),
154 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
155 break;
156 default:
157 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB,
158 cmd->allocation_length);
159 return USB_MSC_HANDLER_FAILED;
160 }
161 return USB_MSC_HANDLER_OK;
162 } else {
163 if (cmd->page != 0) {
164 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB,
165 cmd->allocation_length);
166 return USB_MSC_HANDLER_FAILED;
167 }
168 usb_msc_send_data((uint8_t *)&std_inquiry_data,
169 sizeof(std_inquiry_data),
170 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
171 }
172 return USB_MSC_HANDLER_OK;
173}
174
175static usb_msc_handler_status
176handle_request_sense_cmd(struct usb_msc_command_state *state)
177{
178 usb_msc_send_data((uint8_t *)&sense_data,
179 sizeof(sense_data),
180 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
181 return USB_MSC_HANDLER_OK;
182}
183
184static usb_msc_handler_status
185handle_test_unit_ready_cmd(struct usb_msc_command_state *state)
186{
187 scsi_ok();
188 return USB_MSC_HANDLER_OK;
189}
190
191static const struct rbc_read_capacity_data read_capacity_data =
192 {
193 HOST32_TO_BE_BYTES(USB_RBC_NUM_BLOCKS-1),
194 HOST32_TO_BE_BYTES(512)
195 };
196
197static usb_msc_handler_status
198handle_read_capacity(struct usb_msc_command_state *state)
199{
200 usb_msc_send_data((uint8_t *)&read_capacity_data,
201 sizeof(read_capacity_data),
202 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
203 return USB_MSC_HANDLER_OK;
204}
205
206static const struct mode_sense_data {
207 struct spc2_mode_parameter_header_6 header;
208 struct rbc_device_parameters_page page;
209} CC_BYTE_ALIGNED mode_sense_data =
210 {
211 {
212 (sizeof(mode_sense_data)
213 - offsetof(struct mode_sense_data, header.medium_type)),
214 0,0,0
215 },
216 {
217 {SCSI_MODE_RBC_DEVICE_PAGE | SCSI_MODE_PAGE_SP,
218 sizeof(mode_sense_data) - offsetof(struct mode_sense_data, page.flags1)},
219 SCSI_MODE_WCD,
220 HOST16_TO_BE_BYTES(512),
221 HOST40_TO_BE_BYTES((long long)USB_RBC_NUM_BLOCKS),
222 0x80,
223 (SCSI_MODE_FORMATD | SCSI_MODE_LOCKD),
224 0
225 }
226 };
227
228static usb_msc_handler_status
229handle_mode_sense(struct usb_msc_command_state *state)
230{
231 struct spc2_mode_sence_6_cmd *cmd =
232 (struct spc2_mode_sence_6_cmd*)state->command;
233 PRINTF("%ld - %ld - %ld\n", sizeof(struct mode_sense_data), offsetof(struct mode_sense_data, page.flags1),offsetof(struct mode_sense_data, page.reserved));
234 switch(cmd->page_code) {
235 case SCSI_MODE_RBC_DEVICE_PAGE:
236 case SCSI_MODE_SENSE_ALL_PAGES:
237 usb_msc_send_data((uint8_t *)&mode_sense_data,
238 sizeof(mode_sense_data),
239 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
240 break;
241 default:
242 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB,
243 cmd->allocation_length);
244 return USB_MSC_HANDLER_FAILED;
245 }
246 return USB_MSC_HANDLER_OK;
247}
248
249static usb_msc_handler_status
250handle_mode_select(struct usb_msc_command_state *state)
251{
252 /* Can't change anything */
253 return USB_MSC_HANDLER_OK;
254}
255static uint8_t disk_blocks[USB_RBC_NUM_BLOCKS][512];
256
257static usb_msc_handler_status
258handle_read(struct usb_msc_command_state *state)
259{
260 struct rbc_read_cmd *cmd = (struct rbc_read_cmd*)state->command;
261 unsigned long lba = be32_to_host(cmd->logical_block_address);
262 unsigned long blocks = be16_to_host(cmd->transfer_length);
263 PRINTF("Requested %ld blocks at %ld\n", blocks, lba);
264 if (lba >= USB_RBC_NUM_BLOCKS || lba + blocks > USB_RBC_NUM_BLOCKS) {
265 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB,
266 blocks);
267 return USB_MSC_HANDLER_FAILED;
268 }
269 usb_msc_send_data((uint8_t *)&disk_blocks[lba], blocks * 512,
270 USB_MSC_DATA_SEND | USB_MSC_DATA_LAST);
271 scsi_ok();
272 return USB_MSC_HANDLER_OK;
273}
274
275static void
276handle_write_done(struct usb_msc_command_state *state)
277{
278 PRINTF("Wrote data\n");
279 state->status = MASS_BULK_CSW_STATUS_PASSED;
280 scsi_ok();
281}
282
283static usb_msc_handler_status
284handle_write(struct usb_msc_command_state *state)
285{
286 struct rbc_write_cmd *cmd = (struct rbc_write_cmd*)state->command;
287 unsigned long lba = be32_to_host(cmd->logical_block_address);
288 unsigned long blocks = be16_to_host(cmd->transfer_length);
289 if (lba >= USB_RBC_NUM_BLOCKS || lba + blocks > USB_RBC_NUM_BLOCKS) {
290 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB,
291 blocks);
292 return USB_MSC_HANDLER_FAILED;
293 }
294 PRINTF("Writing %ld blocks at %ld\n", blocks, lba);
295 usb_msc_receive_data(disk_blocks[lba], blocks * 512,
296 USB_MSC_DATA_RECEIVE | USB_MSC_DATA_LAST
297 | USB_MSC_DATA_DO_CALLBACK);
298 state->data_cb = handle_write_done;
299 return USB_MSC_HANDLER_DELAYED;
300}
301
302static usb_msc_handler_status
303handle_start_stop_unit(struct usb_msc_command_state *state)
304{
305 scsi_ok();
306 return USB_MSC_HANDLER_OK;
307}
308
309static usb_msc_handler_status
310handle_verify(struct usb_msc_command_state *state)
311{
312 scsi_ok();
313 return USB_MSC_HANDLER_OK;
314}
315
316usb_msc_handler_status
317usb_msc_handle_command(struct usb_msc_command_state *state)
318{
319
320 usb_msc_handler_status ret;
321 PRINTF("Got CBW %02x\n", state->command[0]);
322 switch(state->command[0]) {
323 case SCSI_CMD_INQUIRY:
324 ret = handle_inquiry_cmd(state);
325 break;
326 case SCSI_CMD_REQUEST_SENSE:
327 ret = handle_request_sense_cmd(state);
328 break;
329 case SCSI_CMD_TEST_UNIT_READY:
330 ret = handle_test_unit_ready_cmd(state);
331 break;
332 case SCSI_CMD_READ_CAPACITY:
333 ret = handle_read_capacity(state);
334 break;
335 case SCSI_CMD_MODE_SENSE_6:
336 ret = handle_mode_sense(state);
337 break;
338 case SCSI_CMD_MODE_SELECT_6:
339 ret = handle_mode_select(state);
340 break;
341 case SCSI_CMD_READ_10:
342 ret = handle_read(state);
343 break;
344 case SCSI_CMD_WRITE_10:
345 ret = handle_write(state);
346 break;
347 case SCSI_CMD_VERIFY_10:
348 ret = handle_verify(state);
349 break;
350 case SCSI_CMD_START_STOP_UNIT:
351 ret = handle_start_stop_unit(state);
352 break;
353 default:
354 printf("Unhandled request: %02x\n", state->command[0]);
355 scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
356 SCSI_ASC_INVALID_COMMAND_OPERATION,0);
357 return USB_MSC_HANDLER_FAILED;
358 }
359 return ret;
360}
361
362void
363usb_msc_command_handler_init()
364{
365}
Header file for the Contiki process interface.