1 /*
2 * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include "esp_log.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <assert.h>
14 #include "esp_check.h"
15 #include "esp_log.h"
16 #include "msc_common.h"
17 #include "msc_scsi_bot.h"
18
19 #define TAG "USB_MSC_SCSI"
20
21 /* --------------------------- SCSI Definitions ----------------------------- */
22 #define CMD_SENSE_VALID_BIT (1 << 7)
23 #define SCSI_FLAG_DPO (1<<4)
24 #define SCSI_FLAG_FUA (1<<3)
25
26 #define SCSI_CMD_FORMAT_UNIT 0x04
27 #define SCSI_CMD_INQUIRY 0x12
28 #define SCSI_CMD_MODE_SELECT 0x55
29 #define SCSI_CMD_MODE_SENSE 0x5A
30 #define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
31 #define SCSI_CMD_READ10 0x28
32 #define SCSI_CMD_READ12 0xA8
33 #define SCSI_CMD_READ_CAPACITY 0x25
34 #define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
35 #define SCSI_CMD_REQUEST_SENSE 0x03
36 #define SCSI_CMD_REZERO 0x01
37 #define SCSI_CMD_SEEK10 0x2B
38 #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
39 #define SCSI_CMD_START_STOP Unit 0x1B
40 #define SCSI_CMD_TEST_UNIT_READY 0x00
41 #define SCSI_CMD_VERIFY 0x2F
42 #define SCSI_CMD_WRITE10 0x2A
43 #define SCSI_CMD_WRITE12 0xAA
44 #define SCSI_CMD_WRITE_AND_VERIFY 0x2E
45
46 #define IN_DIR CWB_FLAG_DIRECTION_IN
47 #define OUT_DIR 0
48
49 #define INQUIRY_VID_SIZE 8
50 #define INQUIRY_PID_SIZE 16
51 #define INQUIRY_REV_SIZE 4
52
53 #define CBW_CMD_SIZE(cmd) (sizeof(cmd) - sizeof(msc_cbw_t))
54
55 #define CBW_BASE_INIT(dir, cbw_len, data_len) \
56 .base = { \
57 .signature = 0x43425355, \
58 .tag = ++cbw_tag, \
59 .flags = dir, \
60 .lun = 0, \
61 .data_length = data_len, \
62 .cbw_length = cbw_len, \
63 }
64
65 #define FEATURE_SELECTOR_ENDPOINT 0
66 #define CSW_SIGNATURE 0x53425355
67 #define CBW_SIZE 31
68
69 #define USB_MASS_REQ_INIT_RESET(ctrl_req_ptr, intf_num) ({ \
70 (ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | \
71 USB_BM_REQUEST_TYPE_TYPE_CLASS | \
72 USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
73 (ctrl_req_ptr)->bRequest = 0xFF; \
74 (ctrl_req_ptr)->wValue = 0; \
75 (ctrl_req_ptr)->wIndex = (intf_num); \
76 (ctrl_req_ptr)->wLength = 0; \
77 })
78
79 #define USB_MASS_REQ_INIT_GET_MAX_LUN(ctrl_req_ptr, intf_num) ({ \
80 (ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | \
81 USB_BM_REQUEST_TYPE_TYPE_CLASS | \
82 USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
83 (ctrl_req_ptr)->bRequest = 0xFE; \
84 (ctrl_req_ptr)->wValue = 0; \
85 (ctrl_req_ptr)->wIndex = (intf_num); \
86 (ctrl_req_ptr)->wLength = 1; \
87 })
88
89 #define USB_SETUP_PACKET_INIT_CLEAR_FEATURE_EP(ctrl_req_ptr, ep_num) ({ \
90 (ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | \
91 USB_BM_REQUEST_TYPE_TYPE_STANDARD | \
92 USB_BM_REQUEST_TYPE_RECIP_ENDPOINT; \
93 (ctrl_req_ptr)->bRequest = USB_B_REQUEST_CLEAR_FEATURE; \
94 (ctrl_req_ptr)->wValue = FEATURE_SELECTOR_ENDPOINT; \
95 (ctrl_req_ptr)->wIndex = (ep_num); \
96 (ctrl_req_ptr)->wLength = 0; \
97 })
98
99 #define CWB_FLAG_DIRECTION_IN (1<<7) // device -> host
100
101 /**
102 * @brief Command Block Wrapper structure
103 */
104 typedef struct __attribute__((packed))
105 {
106 uint32_t signature;
107 uint32_t tag;
108 uint32_t data_length;
109 uint8_t flags;
110 uint8_t lun;
111 uint8_t cbw_length;
112 } msc_cbw_t;
113
114 /**
115 * @brief Command Status Wrapper structure
116 */
117 typedef struct __attribute__((packed))
118 {
119 uint32_t signature;
120 uint32_t tag;
121 uint32_t dataResidue;
122 uint8_t status;
123 } msc_csw_t;
124
125 typedef struct __attribute__((packed))
126 {
127 msc_cbw_t base;
128 uint8_t opcode;
129 uint8_t flags;
130 uint32_t address;
131 uint8_t reserved1;
132 uint16_t length;
133 uint8_t reserved2[3];
134 } cbw_read10_t;
135
136 typedef struct __attribute__((packed))
137 {
138 msc_cbw_t base;
139 uint8_t opcode;
140 uint8_t flags;
141 uint32_t address;
142 uint8_t reserved1;
143 uint16_t length;
144 uint8_t reserved2[1];
145 } cbw_write10_t;
146
147 typedef struct __attribute__((packed))
148 {
149 msc_cbw_t base;
150 uint8_t opcode;
151 uint8_t flags;
152 uint32_t address;
153 uint8_t reserved[6];
154 } cbw_read_capacity_t;
155
156 typedef struct __attribute__((packed))
157 {
158 uint32_t block_count;
159 uint32_t block_size;
160 } cbw_read_capacity_response_t;
161
162 typedef struct __attribute__((packed))
163 {
164 msc_cbw_t base;
165 uint8_t opcode;
166 uint8_t flags;
167 uint8_t reserved[10];
168 } cbw_unit_ready_t;
169
170 typedef struct __attribute__((packed))
171 {
172 msc_cbw_t base;
173 uint8_t opcode;
174 uint8_t flags;
175 uint8_t reserved_0[2];
176 uint8_t allocation_length;
177 uint8_t reserved_1[7];
178 } cbw_sense_t;
179
180 typedef struct __attribute__((packed))
181 {
182 uint8_t error_code;
183 uint8_t reserved_0;
184 uint8_t sense_key;
185 uint32_t info;
186 uint8_t sense_len;
187 uint32_t reserved_1;
188 uint8_t sense_code;
189 uint8_t sense_code_qualifier;
190 uint32_t reserved_2;
191 } cbw_sense_response_t;
192
193 typedef struct __attribute__((packed))
194 {
195 msc_cbw_t base;
196 uint8_t opcode;
197 uint8_t flags;
198 uint8_t page_code;
199 uint8_t reserved_0;
200 uint8_t allocation_length;
201 uint8_t reserved_1[7];
202 } cbw_inquiry_t;
203
204 typedef struct __attribute__((packed))
205 {
206 msc_cbw_t base;
207 uint8_t opcode;
208 uint8_t flags;
209 uint8_t pc_page_code;
210 uint8_t reserved_1[4];
211 uint16_t parameter_list_length;
212 uint8_t reserved_2[3];
213 } mode_sense_t;
214
215 typedef struct __attribute__((packed))
216 {
217 uint8_t data[8];
218 } mode_sense_response_t;
219
220 typedef struct __attribute__((packed))
221 {
222 msc_cbw_t base;
223 uint8_t opcode;
224 uint8_t flags;
225 uint8_t reserved_1[2];
226 uint8_t prevent;
227 uint8_t reserved_2[7];
228 } prevent_allow_medium_removal_t;
229
230 typedef struct __attribute__((packed))
231 {
232 uint8_t data[36];
233 } cbw_inquiry_response_t;
234
235 // Unique number based on which MSC protocol pairs request and response
236 static uint32_t cbw_tag;
237
check_csw(msc_csw_t * csw,uint32_t tag)238 static esp_err_t check_csw(msc_csw_t *csw, uint32_t tag)
239 {
240 bool csw_ok = csw->signature == CSW_SIGNATURE && csw->tag == tag &&
241 csw->dataResidue == 0 && csw->status == 0;
242
243 if (!csw_ok) {
244 ESP_LOGD(TAG, "CSW failed: status %d", csw->status);
245 }
246
247 return csw_ok ? ESP_OK : ESP_FAIL;
248 }
249
clear_feature(msc_device_t * device,uint8_t endpoint)250 static esp_err_t clear_feature(msc_device_t *device, uint8_t endpoint)
251 {
252 usb_device_handle_t dev = device->handle;
253 usb_transfer_t *xfer = device->xfer;
254
255 MSC_RETURN_ON_ERROR( usb_host_endpoint_clear(dev, endpoint) );
256 USB_SETUP_PACKET_INIT_CLEAR_FEATURE_EP((usb_setup_packet_t *)xfer->data_buffer, endpoint);
257 MSC_RETURN_ON_ERROR( msc_control_transfer(device, xfer, USB_SETUP_PACKET_SIZE) );
258
259 return ESP_OK;
260 }
261
msc_mass_reset(msc_device_t * device)262 esp_err_t msc_mass_reset(msc_device_t *device)
263 {
264 usb_transfer_t *xfer = device->xfer;
265
266 USB_MASS_REQ_INIT_RESET((usb_setup_packet_t *)xfer->data_buffer, 0);
267 MSC_RETURN_ON_ERROR( msc_control_transfer(device, xfer, USB_SETUP_PACKET_SIZE) );
268
269 return ESP_OK;
270 }
271
msc_get_max_lun(msc_device_t * device,uint8_t * lun)272 esp_err_t msc_get_max_lun(msc_device_t *device, uint8_t *lun)
273 {
274 usb_transfer_t *xfer = device->xfer;
275
276 USB_MASS_REQ_INIT_GET_MAX_LUN((usb_setup_packet_t *)xfer->data_buffer, 0);
277 MSC_RETURN_ON_ERROR( msc_control_transfer(device, xfer, USB_SETUP_PACKET_SIZE + 1) );
278
279 *lun = xfer->data_buffer[USB_SETUP_PACKET_SIZE];
280
281 return ESP_OK;
282 }
283
bot_execute_command(msc_device_t * device,msc_cbw_t * cbw,void * data,size_t size)284 static esp_err_t bot_execute_command(msc_device_t *device, msc_cbw_t *cbw, void *data, size_t size)
285 {
286 msc_csw_t csw;
287 msc_endpoint_t ep = (cbw->flags & CWB_FLAG_DIRECTION_IN) ? MSC_EP_IN : MSC_EP_OUT;
288
289 MSC_RETURN_ON_ERROR( msc_bulk_transfer(device, (uint8_t *)cbw, CBW_SIZE, MSC_EP_OUT) );
290
291 if (data) {
292 MSC_RETURN_ON_ERROR( msc_bulk_transfer(device, (uint8_t *)data, size, ep) );
293 }
294
295 esp_err_t err = msc_bulk_transfer(device, (uint8_t *)&csw, sizeof(msc_csw_t), MSC_EP_IN);
296
297 if (err == ESP_FAIL && device->transfer_status == USB_TRANSFER_STATUS_STALL) {
298 ESP_RETURN_ON_ERROR( clear_feature(device, MSC_EP_IN), TAG, "Clear feature failed" );
299 // Try to read csw again after clearing feature
300 err = msc_bulk_transfer(device, (uint8_t *)&csw, sizeof(msc_csw_t), MSC_EP_IN);
301 if (err) {
302 ESP_RETURN_ON_ERROR( clear_feature(device, MSC_EP_IN), TAG, "Clear feature failed" );
303 ESP_RETURN_ON_ERROR( msc_mass_reset(device), TAG, "Mass reset failed" );
304 return ESP_FAIL;
305 }
306 }
307
308 MSC_RETURN_ON_ERROR(err);
309
310 return check_csw(&csw, cbw->tag);
311 }
312
313
scsi_cmd_read10(msc_device_t * device,uint8_t * data,uint32_t sector_address,uint32_t num_sectors,uint32_t sector_size)314 esp_err_t scsi_cmd_read10(msc_device_t *device,
315 uint8_t *data,
316 uint32_t sector_address,
317 uint32_t num_sectors,
318 uint32_t sector_size)
319 {
320 cbw_read10_t cbw = {
321 CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_read10_t), num_sectors * sector_size),
322 .opcode = SCSI_CMD_READ10,
323 .flags = 0, // lun
324 .address = __builtin_bswap32(sector_address),
325 .length = __builtin_bswap16(num_sectors),
326 };
327
328 return bot_execute_command(device, &cbw.base, data, num_sectors * sector_size);
329 }
330
scsi_cmd_write10(msc_device_t * device,const uint8_t * data,uint32_t sector_address,uint32_t num_sectors,uint32_t sector_size)331 esp_err_t scsi_cmd_write10(msc_device_t *device,
332 const uint8_t *data,
333 uint32_t sector_address,
334 uint32_t num_sectors,
335 uint32_t sector_size)
336 {
337 cbw_write10_t cbw = {
338 CBW_BASE_INIT(OUT_DIR, CBW_CMD_SIZE(cbw_write10_t), num_sectors * sector_size),
339 .opcode = SCSI_CMD_WRITE10,
340 .address = __builtin_bswap32(sector_address),
341 .length = __builtin_bswap16(num_sectors),
342 };
343
344 return bot_execute_command(device, &cbw.base, (void *)data, num_sectors * sector_size);
345 }
346
scsi_cmd_read_capacity(msc_device_t * device,uint32_t * block_size,uint32_t * block_count)347 esp_err_t scsi_cmd_read_capacity(msc_device_t *device, uint32_t *block_size, uint32_t *block_count)
348 {
349 cbw_read_capacity_response_t response;
350
351 cbw_read_capacity_t cbw = {
352 CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_read_capacity_t), sizeof(response)),
353 .opcode = SCSI_CMD_READ_CAPACITY,
354 };
355
356 MSC_RETURN_ON_ERROR( bot_execute_command(device, &cbw.base, &response, sizeof(response)) );
357
358 *block_count = __builtin_bswap32(response.block_count);
359 *block_size = __builtin_bswap32(response.block_size);
360
361 return ESP_OK;
362 }
363
scsi_cmd_unit_ready(msc_device_t * device)364 esp_err_t scsi_cmd_unit_ready(msc_device_t *device)
365 {
366 cbw_unit_ready_t cbw = {
367 CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_unit_ready_t), 0),
368 .opcode = SCSI_CMD_TEST_UNIT_READY,
369 };
370
371 return bot_execute_command(device, &cbw.base, NULL, 0);
372 }
373
scsi_cmd_sense(msc_device_t * device,scsi_sense_data_t * sense)374 esp_err_t scsi_cmd_sense(msc_device_t *device, scsi_sense_data_t *sense)
375 {
376 cbw_sense_response_t response;
377
378 cbw_sense_t cbw = {
379 CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_sense_t), sizeof(response)),
380 .opcode = SCSI_CMD_REQUEST_SENSE,
381 .allocation_length = sizeof(response),
382 };
383
384 MSC_RETURN_ON_ERROR( bot_execute_command(device, &cbw.base, &response, sizeof(response)) );
385
386 if (sense->key) {
387 ESP_LOGD(TAG, "sense_key: 0x%02X, code: 0x%02X, qualifier: 0x%02X",
388 response.sense_key, response.sense_code, response.sense_code_qualifier);
389 }
390
391 sense->key = response.sense_key;
392 sense->code = response.sense_code;
393 sense->code_q = response.sense_code_qualifier;
394
395 return ESP_OK;
396 }
397
scsi_cmd_inquiry(msc_device_t * device)398 esp_err_t scsi_cmd_inquiry(msc_device_t *device)
399 {
400 cbw_inquiry_response_t response = { 0 };
401
402 cbw_inquiry_t cbw = {
403 CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_inquiry_t), sizeof(response)),
404 .opcode = SCSI_CMD_INQUIRY,
405 .allocation_length = sizeof(response),
406 };
407
408 return bot_execute_command(device, &cbw.base, &response, sizeof(response) );
409 }
410
scsi_cmd_mode_sense(msc_device_t * device)411 esp_err_t scsi_cmd_mode_sense(msc_device_t *device)
412 {
413 mode_sense_response_t response = { 0 };
414
415 mode_sense_t cbw = {
416 CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(mode_sense_t), sizeof(response)),
417 .opcode = SCSI_CMD_MODE_SENSE,
418 .pc_page_code = 0x3F,
419 .parameter_list_length = sizeof(response),
420 };
421
422 return bot_execute_command(device, &cbw.base, &response, sizeof(response) );
423 }
424
scsi_cmd_prevent_removal(msc_device_t * device,bool prevent)425 esp_err_t scsi_cmd_prevent_removal(msc_device_t *device, bool prevent)
426 {
427 prevent_allow_medium_removal_t cbw = {
428 CBW_BASE_INIT(OUT_DIR, CBW_CMD_SIZE(prevent_allow_medium_removal_t), 0),
429 .opcode = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
430 .prevent = 1,
431 };
432
433 return bot_execute_command(device, &cbw.base, NULL, 0);
434 }
435