usbd_msc_scsi.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. /*!
  2. \file usbd_msc_scsi.c
  3. \brief USB SCSI layer functions
  4. \version 2020-08-01, V3.0.0, firmware for GD32F4xx
  5. \version 2022-03-09, V3.1.0, firmware for GD32F4xx
  6. \version 2022-06-30, V3.2.0, firmware for GD32F4xx
  7. */
  8. /*
  9. Copyright (c) 2022, GigaDevice Semiconductor Inc.
  10. Redistribution and use in source and binary forms, with or without modification,
  11. are permitted provided that the following conditions are met:
  12. 1. Redistributions of source code must retain the above copyright notice, this
  13. list of conditions and the following disclaimer.
  14. 2. Redistributions in binary form must reproduce the above copyright notice,
  15. this list of conditions and the following disclaimer in the documentation
  16. and/or other materials provided with the distribution.
  17. 3. Neither the name of the copyright holder nor the names of its contributors
  18. may be used to endorse or promote products derived from this software without
  19. specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  22. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  23. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  24. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27. WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  29. OF SUCH DAMAGE.
  30. */
  31. #include "usbd_enum.h"
  32. #include "usbd_msc_bbb.h"
  33. #include "usbd_msc_scsi.h"
  34. /* USB mass storage page 0 inquiry data */
  35. const uint8_t msc_page00_inquiry_data[] =
  36. {
  37. 0x00U,
  38. 0x00U,
  39. 0x00U,
  40. 0x00U,
  41. (INQUIRY_PAGE00_LENGTH - 4U),
  42. 0x80U,
  43. 0x83U,
  44. };
  45. /* USB mass storage sense 6 data */
  46. const uint8_t msc_mode_sense6_data[] =
  47. {
  48. 0x00U,
  49. 0x00U,
  50. 0x00U,
  51. 0x00U,
  52. 0x00U,
  53. 0x00U,
  54. 0x00U,
  55. 0x00U
  56. };
  57. /* USB mass storage sense 10 data */
  58. const uint8_t msc_mode_sense10_data[] =
  59. {
  60. 0x00U,
  61. 0x06U,
  62. 0x00U,
  63. 0x00U,
  64. 0x00U,
  65. 0x00U,
  66. 0x00U,
  67. 0x00U
  68. };
  69. /* local function prototypes ('static') */
  70. static int8_t scsi_test_unit_ready (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  71. static int8_t scsi_mode_select6 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  72. static int8_t scsi_mode_select10 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  73. static int8_t scsi_inquiry (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  74. static int8_t scsi_read_format_capacity (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  75. static int8_t scsi_read_capacity10 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  76. static int8_t scsi_request_sense (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  77. static int8_t scsi_mode_sense6 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  78. static int8_t scsi_toc_cmd_read (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  79. static int8_t scsi_mode_sense10 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  80. static int8_t scsi_write10 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  81. static int8_t scsi_read10 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  82. static int8_t scsi_verify10 (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  83. static int8_t scsi_process_read (usb_core_driver *udev, uint8_t lun);
  84. static int8_t scsi_process_write (usb_core_driver *udev, uint8_t lun);
  85. static inline int8_t scsi_check_address_range (usb_core_driver *udev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr);
  86. static inline int8_t scsi_format_cmd (usb_core_driver *udev, uint8_t lun);
  87. static inline int8_t scsi_start_stop_unit (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  88. static inline int8_t scsi_allow_medium_removal (usb_core_driver *udev, uint8_t lun, uint8_t *params);
  89. /*!
  90. \brief process SCSI commands
  91. \param[in] udev: pointer to USB device instance
  92. \param[in] lun: logical unit number
  93. \param[in] params: command parameters
  94. \param[out] none
  95. \retval status
  96. */
  97. int8_t scsi_process_cmd(usb_core_driver *udev, uint8_t lun, uint8_t *params)
  98. {
  99. switch (params[0]) {
  100. case SCSI_TEST_UNIT_READY:
  101. return scsi_test_unit_ready (udev, lun, params);
  102. case SCSI_REQUEST_SENSE:
  103. return scsi_request_sense (udev, lun, params);
  104. case SCSI_INQUIRY:
  105. return scsi_inquiry (udev, lun, params);
  106. case SCSI_START_STOP_UNIT:
  107. return scsi_start_stop_unit (udev, lun, params);
  108. case SCSI_ALLOW_MEDIUM_REMOVAL:
  109. return scsi_allow_medium_removal (udev, lun, params);
  110. case SCSI_MODE_SENSE6:
  111. return scsi_mode_sense6 (udev, lun, params);
  112. case SCSI_MODE_SENSE10:
  113. return scsi_mode_sense10 (udev, lun, params);
  114. case SCSI_READ_FORMAT_CAPACITIES:
  115. return scsi_read_format_capacity (udev, lun, params);
  116. case SCSI_READ_CAPACITY10:
  117. return scsi_read_capacity10 (udev, lun, params);
  118. case SCSI_READ10:
  119. return scsi_read10 (udev, lun, params);
  120. case SCSI_WRITE10:
  121. return scsi_write10 (udev, lun, params);
  122. case SCSI_VERIFY10:
  123. return scsi_verify10 (udev, lun, params);
  124. case SCSI_FORMAT_UNIT:
  125. return scsi_format_cmd (udev, lun);
  126. case SCSI_READ_TOC_DATA:
  127. return scsi_toc_cmd_read (udev, lun, params);
  128. case SCSI_MODE_SELECT6:
  129. return scsi_mode_select6 (udev, lun, params);
  130. case SCSI_MODE_SELECT10:
  131. return scsi_mode_select10 (udev, lun, params);
  132. default:
  133. scsi_sense_code (udev, lun, ILLEGAL_REQUEST, INVALID_CDB);
  134. return -1;
  135. }
  136. }
  137. /*!
  138. \brief load the last error code in the error list
  139. \param[in] udev: pointer to USB device instance
  140. \param[in] lun: logical unit number
  141. \param[in] skey: sense key
  142. \param[in] asc: additional sense key
  143. \param[out] none
  144. \retval none
  145. */
  146. void scsi_sense_code (usb_core_driver *udev, uint8_t lun, uint8_t skey, uint8_t asc)
  147. {
  148. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  149. msc->scsi_sense[msc->scsi_sense_tail].SenseKey = skey;
  150. msc->scsi_sense[msc->scsi_sense_tail].ASC = asc;
  151. msc->scsi_sense_tail++;
  152. if (SENSE_LIST_DEEPTH == msc->scsi_sense_tail) {
  153. msc->scsi_sense_tail = 0U;
  154. }
  155. }
  156. /*!
  157. \brief process SCSI Test Unit Ready command
  158. \param[in] udev: pointer to USB device instance
  159. \param[in] lun: logical unit number
  160. \param[in] params: command parameters
  161. \param[out] none
  162. \retval status
  163. */
  164. static int8_t scsi_test_unit_ready (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  165. {
  166. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  167. /* case 9 : Hi > D0 */
  168. if (0U != msc->bbb_cbw.dCBWDataTransferLength) {
  169. scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
  170. return -1;
  171. }
  172. if (0 != usbd_mem_fops->mem_ready(lun)) {
  173. scsi_sense_code(udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
  174. return -1;
  175. }
  176. msc->bbb_datalen = 0U;
  177. return 0;
  178. }
  179. /*!
  180. \brief process Inquiry command
  181. \param[in] udev: pointer to USB device instance
  182. \param[in] lun: logical unit number
  183. \param[in] params: command parameters
  184. \param[out] none
  185. \retval status
  186. */
  187. static int8_t scsi_mode_select6 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  188. {
  189. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  190. msc->bbb_datalen = 0U;
  191. return 0;
  192. }
  193. /*!
  194. \brief process Inquiry command
  195. \param[in] udev: pointer to USB device instance
  196. \param[in] lun: logical unit number
  197. \param[in] params: command parameters
  198. \param[out] none
  199. \retval status
  200. */
  201. static int8_t scsi_mode_select10 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  202. {
  203. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  204. msc->bbb_datalen = 0U;
  205. return 0;
  206. }
  207. /*!
  208. \brief process Inquiry command
  209. \param[in] udev: pointer to USB device instance
  210. \param[in] lun: logical unit number
  211. \param[in] params: command parameters
  212. \param[out] none
  213. \retval status
  214. */
  215. static int8_t scsi_inquiry (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  216. {
  217. uint8_t *page = NULL;
  218. uint16_t len = 0U;
  219. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  220. if (params[1] & 0x01U) {
  221. page = (uint8_t *)msc_page00_inquiry_data;
  222. len = INQUIRY_PAGE00_LENGTH;
  223. } else {
  224. page = (uint8_t *)usbd_mem_fops->mem_inquiry_data[lun];
  225. len = (uint16_t)(page[4] + 5U);
  226. if (params[4] <= len) {
  227. len = params[4];
  228. }
  229. }
  230. msc->bbb_datalen = len;
  231. while (len) {
  232. len--;
  233. msc->bbb_data[len] = page[len];
  234. }
  235. return 0;
  236. }
  237. /*!
  238. \brief process Read Capacity 10 command
  239. \param[in] udev: pointer to USB device instance
  240. \param[in] lun: logical unit number
  241. \param[in] params: command parameters
  242. \param[out] none
  243. \retval status
  244. */
  245. static int8_t scsi_read_capacity10 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  246. {
  247. uint32_t blk_num = usbd_mem_fops->mem_block_len[lun] - 1U;
  248. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  249. msc->scsi_blk_nbr[lun] = usbd_mem_fops->mem_block_len[lun];
  250. msc->scsi_blk_size[lun] = usbd_mem_fops->mem_block_size[lun];
  251. msc->bbb_data[0] = (uint8_t)(blk_num >> 24U);
  252. msc->bbb_data[1] = (uint8_t)(blk_num >> 16U);
  253. msc->bbb_data[2] = (uint8_t)(blk_num >> 8U);
  254. msc->bbb_data[3] = (uint8_t)(blk_num);
  255. msc->bbb_data[4] = (uint8_t)(msc->scsi_blk_size[lun] >> 24U);
  256. msc->bbb_data[5] = (uint8_t)(msc->scsi_blk_size[lun] >> 16U);
  257. msc->bbb_data[6] = (uint8_t)(msc->scsi_blk_size[lun] >> 8U);
  258. msc->bbb_data[7] = (uint8_t)(msc->scsi_blk_size[lun]);
  259. msc->bbb_datalen = 8U;
  260. return 0;
  261. }
  262. /*!
  263. \brief process Read Format Capacity command
  264. \param[in] udev: pointer to USB device instance
  265. \param[in] lun: logical unit number
  266. \param[in] params: command parameters
  267. \param[out] none
  268. \retval status
  269. */
  270. static int8_t scsi_read_format_capacity (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  271. {
  272. uint16_t i = 0U;
  273. uint32_t blk_size = usbd_mem_fops->mem_block_size[lun];
  274. uint32_t blk_num = usbd_mem_fops->mem_block_len[lun];
  275. uint32_t blk_nbr = blk_num - 1U;
  276. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  277. for (i = 0U; i < 12U; i++) {
  278. msc->bbb_data[i] = 0U;
  279. }
  280. msc->bbb_data[3] = 0x08U;
  281. msc->bbb_data[4] = (uint8_t)(blk_nbr >> 24U);
  282. msc->bbb_data[5] = (uint8_t)(blk_nbr >> 16U);
  283. msc->bbb_data[6] = (uint8_t)(blk_nbr >> 8U);
  284. msc->bbb_data[7] = (uint8_t)(blk_nbr);
  285. msc->bbb_data[8] = 0x02U;
  286. msc->bbb_data[9] = (uint8_t)(blk_size >> 16U);
  287. msc->bbb_data[10] = (uint8_t)(blk_size >> 8U);
  288. msc->bbb_data[11] = (uint8_t)(blk_size);
  289. msc->bbb_datalen = 12U;
  290. return 0;
  291. }
  292. /*!
  293. \brief process Mode Sense6 command
  294. \param[in] udev: pointer to USB device instance
  295. \param[in] lun: logical unit number
  296. \param[in] params: command parameters
  297. \param[out] none
  298. \retval status
  299. */
  300. static int8_t scsi_mode_sense6 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  301. {
  302. uint16_t len = 8U;
  303. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  304. msc->bbb_datalen = len;
  305. while (len) {
  306. len--;
  307. msc->bbb_data[len] = msc_mode_sense6_data[len];
  308. }
  309. return 0;
  310. }
  311. /*!
  312. \brief process Mode Sense10 command
  313. \param[in] udev: pointer to USB device instance
  314. \param[in] lun: logical unit number
  315. \param[in] params: command parameters
  316. \param[out] none
  317. \retval status
  318. */
  319. static int8_t scsi_mode_sense10 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  320. {
  321. uint16_t len = 8U;
  322. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  323. msc->bbb_datalen = len;
  324. while (len) {
  325. len--;
  326. msc->bbb_data[len] = msc_mode_sense10_data[len];
  327. }
  328. return 0;
  329. }
  330. /*!
  331. \brief process Request Sense command
  332. \param[in] udev: pointer to USB device instance
  333. \param[in] lun: logical unit number
  334. \param[in] params: command parameters
  335. \param[out] none
  336. \retval status
  337. */
  338. static int8_t scsi_request_sense (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  339. {
  340. uint8_t i = 0U;
  341. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  342. for (i = 0U; i < REQUEST_SENSE_DATA_LEN; i++) {
  343. msc->bbb_data[i] = 0U;
  344. }
  345. msc->bbb_data[0] = 0x70U;
  346. msc->bbb_data[7] = REQUEST_SENSE_DATA_LEN - 6U;
  347. if ((msc->scsi_sense_head != msc->scsi_sense_tail)) {
  348. msc->bbb_data[2] = msc->scsi_sense[msc->scsi_sense_head].SenseKey;
  349. msc->bbb_data[12] = msc->scsi_sense[msc->scsi_sense_head].ASC;
  350. msc->bbb_data[13] = msc->scsi_sense[msc->scsi_sense_head].ASCQ;
  351. msc->scsi_sense_head++;
  352. if (msc->scsi_sense_head == SENSE_LIST_DEEPTH) {
  353. msc->scsi_sense_head = 0U;
  354. }
  355. }
  356. msc->bbb_datalen = USB_MIN(REQUEST_SENSE_DATA_LEN, params[4]);
  357. return 0;
  358. }
  359. /*
  360. byte 5 (index 4) of start stop unit
  361. 7 6 5 4 3 2 1 0
  362. [ PWRCON ] R F E S
  363. S = start
  364. E = loadeject
  365. */
  366. #define STARTSTOPUNIT_START (1)
  367. #define STARTSTOPUNIT_LOADEJECT (2)
  368. /*!
  369. \brief process Start Stop Unit command
  370. \param[in] udev: pointer to USB device instance
  371. \param[in] lun: logical unit number
  372. \param[in] params: command parameters
  373. \param[out] none
  374. \retval status
  375. */
  376. static inline int8_t scsi_start_stop_unit (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  377. {
  378. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  379. msc->bbb_datalen = 0U;
  380. /* not part of GDS class! make sure to bring this over if updating USB class */
  381. // if start = 0, load eject = 1, host is advising of media eject (usually a device removal too)
  382. if ((params[4] & STARTSTOPUNIT_LOADEJECT)) {
  383. if (!(params[4] & STARTSTOPUNIT_START))
  384. msc->scsi_disk_pop = 1U;
  385. }
  386. return 0;
  387. }
  388. /*!
  389. \brief process Allow Medium Removal command
  390. \param[in] udev: pointer to USB device instance
  391. \param[in] lun: logical unit number
  392. \param[in] params: command parameters
  393. \param[out] none
  394. \retval status
  395. */
  396. static inline int8_t scsi_allow_medium_removal (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  397. {
  398. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  399. msc->bbb_datalen = 0U;
  400. return 0;
  401. }
  402. /*!
  403. \brief process Read10 command
  404. \param[in] udev: pointer to USB device instance
  405. \param[in] lun: logical unit number
  406. \param[in] params: command parameters
  407. \param[out] none
  408. \retval status
  409. */
  410. static int8_t scsi_read10 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  411. {
  412. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  413. if (msc->bbb_state == BBB_IDLE) {
  414. /* direction is from device to host */
  415. if (0x80U != (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
  416. scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
  417. return -1;
  418. }
  419. if (0 != usbd_mem_fops->mem_ready(lun)) {
  420. scsi_sense_code (udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
  421. return -1;
  422. }
  423. msc->scsi_blk_addr = (params[2] << 24U) | (params[3] << 16U) | \
  424. (params[4] << 8U) | params[5];
  425. msc->scsi_blk_len = (params[7] << 8U) | params[8];
  426. if (scsi_check_address_range (udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
  427. return -1; /* error */
  428. }
  429. msc->bbb_state = BBB_DATA_IN;
  430. msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
  431. msc->scsi_blk_len *= msc->scsi_blk_size[lun];
  432. /* cases 4,5 : Hi <> Dn */
  433. if (msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
  434. scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
  435. return -1;
  436. }
  437. }
  438. msc->bbb_datalen = MSC_MEDIA_PACKET_SIZE;
  439. return scsi_process_read (udev, lun);
  440. }
  441. /*!
  442. \brief process Write10 command
  443. \param[in] udev: pointer to USB device instance
  444. \param[in] lun: logical unit number
  445. \param[in] params: command parameters
  446. \param[out] none
  447. \retval status
  448. */
  449. static int8_t scsi_write10 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  450. {
  451. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  452. if (BBB_IDLE == msc->bbb_state) {
  453. /* case 8 : Hi <> Do */
  454. if (0x80U == (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
  455. scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
  456. return -1;
  457. }
  458. /* check whether media is ready */
  459. if (0 != usbd_mem_fops->mem_ready(lun)) {
  460. scsi_sense_code (udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
  461. return -1;
  462. }
  463. /* check if media is write-protected */
  464. if (0 != usbd_mem_fops->mem_protected(lun)) {
  465. scsi_sense_code (udev, lun, NOT_READY, WRITE_PROTECTED);
  466. return -1;
  467. }
  468. msc->scsi_blk_addr = (params[2] << 24U) | (params[3] << 16U) | \
  469. (params[4] << 8U) | params[5];
  470. msc->scsi_blk_len = (params[7] << 8U) | params[8];
  471. /* check if LBA address is in the right range */
  472. if (scsi_check_address_range (udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
  473. return -1; /* error */
  474. }
  475. msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
  476. msc->scsi_blk_len *= msc->scsi_blk_size[lun];
  477. /* cases 3,11,13 : Hn,Ho <> D0 */
  478. if (msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
  479. scsi_sense_code (udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
  480. return -1;
  481. }
  482. /* prepare endpoint to receive first data packet */
  483. msc->bbb_state = BBB_DATA_OUT;
  484. usbd_ep_recev (udev,
  485. MSC_OUT_EP,
  486. msc->bbb_data,
  487. USB_MIN (msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
  488. } else { /* write process ongoing */
  489. return scsi_process_write (udev, lun);
  490. }
  491. return 0;
  492. }
  493. /*!
  494. \brief process Verify10 command
  495. \param[in] udev: pointer to USB device instance
  496. \param[in] lun: logical unit number
  497. \param[in] params: command parameters
  498. \param[out] none
  499. \retval status
  500. */
  501. static int8_t scsi_verify10 (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  502. {
  503. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  504. if (0x02U == (params[1] & 0x02U)) {
  505. scsi_sense_code (udev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
  506. return -1; /* error, verify mode not supported*/
  507. }
  508. if (scsi_check_address_range (udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
  509. return -1; /* error */
  510. }
  511. msc->bbb_datalen = 0U;
  512. return 0;
  513. }
  514. /*!
  515. \brief check address range
  516. \param[in] udev: pointer to USB device instance
  517. \param[in] lun: logical unit number
  518. \param[in] blk_offset: block offset
  519. \param[in] blk_nbr: number of block to be processed
  520. \param[out] none
  521. \retval status
  522. */
  523. static inline int8_t scsi_check_address_range (usb_core_driver *udev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr)
  524. {
  525. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  526. if ((blk_offset + blk_nbr) > msc->scsi_blk_nbr[lun]) {
  527. scsi_sense_code (udev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
  528. return -1;
  529. }
  530. return 0;
  531. }
  532. /*!
  533. \brief handle read process
  534. \param[in] udev: pointer to USB device instance
  535. \param[in] lun: logical unit number
  536. \param[out] none
  537. \retval status
  538. */
  539. static int8_t scsi_process_read (usb_core_driver *udev, uint8_t lun)
  540. {
  541. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  542. uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
  543. if (usbd_mem_fops->mem_read(lun,
  544. msc->bbb_data,
  545. msc->scsi_blk_addr,
  546. (uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
  547. scsi_sense_code(udev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
  548. return -1;
  549. }
  550. usbd_ep_send (udev, MSC_IN_EP, msc->bbb_data, len);
  551. msc->scsi_blk_addr += len;
  552. msc->scsi_blk_len -= len;
  553. /* case 6 : Hi = Di */
  554. msc->bbb_csw.dCSWDataResidue -= len;
  555. if (0U == msc->scsi_blk_len) {
  556. msc->bbb_state = BBB_LAST_DATA_IN;
  557. }
  558. return 0;
  559. }
  560. /*!
  561. \brief handle write process
  562. \param[in] udev: pointer to USB device instance
  563. \param[in] lun: logical unit number
  564. \param[out] none
  565. \retval status
  566. */
  567. static int8_t scsi_process_write (usb_core_driver *udev, uint8_t lun)
  568. {
  569. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  570. uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
  571. if (usbd_mem_fops->mem_write (lun,
  572. msc->bbb_data,
  573. msc->scsi_blk_addr,
  574. (uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
  575. scsi_sense_code(udev, lun, HARDWARE_ERROR, WRITE_FAULT);
  576. return -1;
  577. }
  578. msc->scsi_blk_addr += len;
  579. msc->scsi_blk_len -= len;
  580. /* case 12 : Ho = Do */
  581. msc->bbb_csw.dCSWDataResidue -= len;
  582. if (0U == msc->scsi_blk_len) {
  583. msc_bbb_csw_send (udev, CSW_CMD_PASSED);
  584. } else {
  585. /* prepare endpoint to receive next packet */
  586. usbd_ep_recev (udev,
  587. MSC_OUT_EP,
  588. msc->bbb_data,
  589. USB_MIN (msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
  590. }
  591. return 0;
  592. }
  593. /*!
  594. \brief process Format Unit command
  595. \param[in] udev: pointer to USB device instance
  596. \param[in] lun: logical unit number
  597. \param[out] none
  598. \retval status
  599. */
  600. static inline int8_t scsi_format_cmd (usb_core_driver *udev, uint8_t lun)
  601. {
  602. return 0;
  603. }
  604. /*!
  605. \brief process Read_Toc command
  606. \param[in] udev: pointer to USB device instance
  607. \param[in] lun: logical unit number
  608. \param[in] params: command parameters
  609. \param[out] none
  610. \retval status
  611. */
  612. static int8_t scsi_toc_cmd_read (usb_core_driver *udev, uint8_t lun, uint8_t *params)
  613. {
  614. uint8_t* pPage;
  615. uint16_t len;
  616. usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
  617. pPage = (uint8_t *)&usbd_mem_fops->mem_toc_data[lun * READ_TOC_CMD_LEN];
  618. len = (uint16_t)pPage[1] + 2U;
  619. msc->bbb_datalen = len;
  620. while (len) {
  621. len--;
  622. msc->bbb_data[len] = pPage[len];
  623. }
  624. return 0;
  625. }