Contiki-NG
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 
20 static 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 
30 static void
31 scsi_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 
43 static void
44 scsi_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 
52 static 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 
72 static 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 
99 static 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 
115 static 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 
129 static usb_msc_handler_status
130 handle_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 
175 static usb_msc_handler_status
176 handle_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 
184 static usb_msc_handler_status
185 handle_test_unit_ready_cmd(struct usb_msc_command_state *state)
186 {
187  scsi_ok();
188  return USB_MSC_HANDLER_OK;
189 }
190 
191 static 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 
197 static usb_msc_handler_status
198 handle_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 
206 static 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 
228 static usb_msc_handler_status
229 handle_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 
249 static usb_msc_handler_status
250 handle_mode_select(struct usb_msc_command_state *state)
251 {
252  /* Can't change anything */
253  return USB_MSC_HANDLER_OK;
254 }
255 static uint8_t disk_blocks[USB_RBC_NUM_BLOCKS][512];
256 
257 static usb_msc_handler_status
258 handle_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 
275 static void
276 handle_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 
283 static usb_msc_handler_status
284 handle_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 
302 static usb_msc_handler_status
303 handle_start_stop_unit(struct usb_msc_command_state *state)
304 {
305  scsi_ok();
306  return USB_MSC_HANDLER_OK;
307 }
308 
309 static usb_msc_handler_status
310 handle_verify(struct usb_msc_command_state *state)
311 {
312  scsi_ok();
313  return USB_MSC_HANDLER_OK;
314 }
315 
316 usb_msc_handler_status
317 usb_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 
362 void
363 usb_msc_command_handler_init()
364 {
365 }
Header file for the Contiki process interface.