tud_msc_inquiry_cb:
   28|      3|TU_ATTR_WEAK void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
   29|      3|  (void) lun; (void) vendor_id; (void) product_id; (void) product_rev;
   30|      3|}
tud_msc_inquiry2_cb:
   31|      3|TU_ATTR_WEAK uint32_t tud_msc_inquiry2_cb(uint8_t lun, scsi_inquiry_resp_t *inquiry_resp, uint32_t bufsize) {
   32|      3|  (void) lun; (void) inquiry_resp; (void) bufsize;
   33|      3|  return 0;
   34|      3|}
tud_msc_read10_complete_cb:
  214|     66|TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun) {
  215|     66|  (void) lun;
  216|     66|}
tud_msc_write10_complete_cb:
  218|     46|TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun) {
  219|     46|  (void) lun;
  220|     46|}
tud_msc_scsi_complete_cb:
  222|     81|TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]) {
  223|     81|  (void) lun;
  224|     81|  (void) scsi_cmd;
  225|     81|}
tud_msc_start_stop_cb:
  231|      4|TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
  232|      4|  (void) lun;
  233|      4|  (void) power_condition;
  234|      4|  (void) start;
  235|      4|  (void) load_eject;
  236|       |  return true;
  237|      4|}
tud_msc_prevent_allow_medium_removal_cb:
  239|      5|TU_ATTR_WEAK bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control) {
  240|      5|  (void) lun;
  241|      5|  (void) prohibit_removal;
  242|      5|  (void) control;
  243|       |  return true;
  244|      5|}
tud_msc_request_sense_cb:
  246|     25|TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize) {
  247|     25|  (void) lun;
  248|     25|  (void) buffer;
  249|     25|  (void) bufsize;
  250|     25|  return sizeof(scsi_sense_fixed_resp_t);
  251|     25|}
tud_msc_is_writable_cb:
  253|  2.91k|TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun) {
  254|  2.91k|  (void) lun;
  255|       |  return true;
  256|  2.91k|}
tud_msc_set_sense:
  287|    237|bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier) {
  288|    237|  (void) lun;
  289|    237|  _mscd_itf.sense_key           = sense_key;
  290|    237|  _mscd_itf.add_sense_code      = add_sense_code;
  291|    237|  _mscd_itf.add_sense_qualifier = add_sense_qualifier;
  292|       |  return true;
  293|    237|}
mscd_init:
  338|    536|void mscd_init(void) {
  339|    536|  TU_LOG_INT(CFG_TUD_MSC_LOG_LEVEL, sizeof(mscd_interface_t));
  340|    536|  tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
  ------------------
  |  |   95|    536|#define tu_memclr(buffer, size)  (void) memset((buffer), 0, (size))
  ------------------
  341|    536|}
mscd_xfer_cb:
  453|  52.7k|bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
  454|  52.7k|  (void) event;
  455|       |
  456|  52.7k|  mscd_interface_t* p_msc = &_mscd_itf;
  457|  52.7k|  msc_cbw_t * p_cbw = &p_msc->cbw;
  458|  52.7k|  msc_csw_t * p_csw = &p_msc->csw;
  459|       |
  460|  52.7k|  switch (p_msc->stage) {
  461|    536|    case MSC_STAGE_CMD: {
  ------------------
  |  Branch (461:5): [True: 536, False: 52.2k]
  ------------------
  462|       |      //------------- new CBW received -------------//
  463|       |      // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
  464|    536|      if (ep_addr != p_msc->ep_out) {
  ------------------
  |  Branch (464:11): [True: 0, False: 536]
  ------------------
  465|      0|        return true;
  466|      0|      }
  467|       |
  468|    536|      const uint32_t signature = tu_le32toh(tu_unaligned_read32(_mscd_epbuf.buf));
  ------------------
  |  |  294|    536|  #define tu_le32toh(u32) (u32)
  ------------------
  469|       |
  470|    536|      if (!(xferred_bytes == sizeof(msc_cbw_t) && signature == MSC_CBW_SIGNATURE)) {
  ------------------
  |  Branch (470:13): [True: 536, False: 0]
  |  Branch (470:51): [True: 536, False: 0]
  ------------------
  471|       |        // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery
  472|      0|        TU_LOG_DRV("  SCSI CBW is not valid\r\n");
  473|      0|        p_msc->stage = MSC_STAGE_NEED_RESET;
  474|      0|        usbd_edpt_stall(rhport, p_msc->ep_in);
  475|      0|        usbd_edpt_stall(rhport, p_msc->ep_out);
  476|      0|        return false;
  477|      0|      }
  478|       |
  479|    536|      memcpy(p_cbw, _mscd_epbuf.buf, sizeof(msc_cbw_t));
  480|       |
  481|    536|      TU_LOG_DRV("  SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
  482|       |      // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_cbw, xferred_bytes, 2);
  483|       |
  484|    536|      p_csw->signature    = MSC_CSW_SIGNATURE;
  485|    536|      p_csw->tag          = p_cbw->tag;
  486|    536|      p_csw->data_residue = 0;
  487|    536|      p_csw->status       = MSC_CSW_STATUS_PASSED;
  488|       |
  489|       |      /*------------- Parse command and prepare DATA -------------*/
  490|    536|      p_msc->stage = MSC_STAGE_DATA;
  491|    536|      p_msc->total_len = p_cbw->total_bytes;
  492|    536|      p_msc->xferred_len = 0;
  493|       |
  494|       |      // Read10 or Write10
  495|    536|      if ((SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0])) {
  ------------------
  |  Branch (495:11): [True: 123, False: 413]
  |  Branch (495:54): [True: 181, False: 232]
  ------------------
  496|    304|        uint8_t const status = rdwr10_validate_cmd(p_cbw);
  497|       |
  498|    304|        if (status != MSC_CSW_STATUS_PASSED) {
  ------------------
  |  Branch (498:13): [True: 66, False: 238]
  ------------------
  499|     66|          fail_scsi_op(p_msc, status);
  500|    238|        } else if (p_cbw->total_bytes > 0) {
  ------------------
  |  Branch (500:20): [True: 237, False: 1]
  ------------------
  501|    237|          if (SCSI_CMD_READ_10 == p_cbw->command[0]) {
  ------------------
  |  Branch (501:15): [True: 86, False: 151]
  ------------------
  502|     86|            proc_read10_cmd(p_msc);
  503|    151|          } else {
  504|    151|            proc_write10_cmd(p_msc);
  505|    151|          }
  506|    237|        } else {
  507|       |          // no data transfer, only exist in complaint test suite
  508|      1|          p_msc->stage = MSC_STAGE_STATUS;
  509|      1|        }
  510|    304|      } else {
  511|       |        // For other SCSI commands
  512|       |        // 1. OUT : queue transfer (invoke app callback after done)
  513|       |        // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
  514|    232|        if ((p_cbw->total_bytes > 0) && !is_data_in(p_cbw->dir)) {
  ------------------
  |  Branch (514:13): [True: 229, False: 3]
  |  Branch (514:41): [True: 91, False: 138]
  ------------------
  515|     91|          if (p_cbw->total_bytes > CFG_TUD_MSC_EP_BUFSIZE) {
  ------------------
  |  |   10|     91|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  |  Branch (515:15): [True: 62, False: 29]
  ------------------
  516|     62|            TU_LOG_DRV("  SCSI reject non READ10/WRITE10 with large data\r\n");
  517|     62|            fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  518|     62|          } else {
  519|       |            // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
  520|       |            // but it is OK to just receive data then responded with failed status
  521|     29|            TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, (uint16_t) p_msc->total_len, false));
  ------------------
  |  |  112|     29|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|     29|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|     29|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  108|     29|#define TU_ASSERT_1ARGS(_cond)         TU_ASSERT_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|     29|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|     29|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 29]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|     29|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 29]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  522|     29|          }
  523|    141|        } else {
  524|       |          // First process if it is a built-in commands
  525|    141|          int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_epbuf.buf, CFG_TUD_MSC_EP_BUFSIZE);
  ------------------
  |  |   10|    141|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  526|       |
  527|       |          // Invoke user callback if not built-in
  528|    141|          if ((resplen < 0) && (p_msc->sense_key == 0)) {
  ------------------
  |  Branch (528:15): [True: 15, False: 126]
  |  Branch (528:32): [True: 15, False: 0]
  ------------------
  529|     15|            resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_epbuf.buf,
  530|     15|                                      (uint16_t) tu_min32(p_msc->total_len, CFG_TUD_MSC_EP_BUFSIZE));
  ------------------
  |  |   10|     15|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  531|     15|          }
  532|       |
  533|    141|          if (resplen < 0) {
  ------------------
  |  Branch (533:15): [True: 15, False: 126]
  ------------------
  534|       |            // unsupported command
  535|     15|            TU_LOG_DRV("  SCSI unsupported or failed command\r\n");
  536|     15|            fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  537|    126|          } else if (resplen == 0) {
  ------------------
  |  Branch (537:22): [True: 59, False: 67]
  ------------------
  538|     59|            if (p_cbw->total_bytes > 0) {
  ------------------
  |  Branch (538:17): [True: 57, False: 2]
  ------------------
  539|       |              // 6.7 The 13 Cases: case 4 (Hi > Dn)
  540|       |              // TU_LOG_DRV("  SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes);
  541|     57|              fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  542|     57|            } else {
  543|       |              // case 1 Hn = Dn: all good
  544|      2|              p_msc->stage = MSC_STAGE_STATUS;
  545|      2|            }
  546|     67|          } else {
  547|     67|            if (p_cbw->total_bytes == 0) {
  ------------------
  |  Branch (547:17): [True: 1, False: 66]
  ------------------
  548|       |              // 6.7 The 13 Cases: case 2 (Hn < Di)
  549|       |              // TU_LOG_DRV("  SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes);
  550|      1|              fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  551|     66|            } else {
  552|       |              // cannot return more than host expect
  553|     66|              p_msc->total_len = tu_min32((uint32_t)resplen, p_cbw->total_bytes);
  554|     66|              TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) p_msc->total_len, false));
  ------------------
  |  |  112|     66|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|     66|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|     66|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  108|     66|#define TU_ASSERT_1ARGS(_cond)         TU_ASSERT_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|     66|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|     66|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 66]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|     66|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 66]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  555|     66|            }
  556|     67|          }
  557|    141|        }
  558|    232|      }
  559|    536|      break;
  560|    536|    }
  561|       |
  562|  52.0k|    case MSC_STAGE_DATA:
  ------------------
  |  Branch (562:5): [True: 52.0k, False: 729]
  ------------------
  563|  52.0k|      TU_LOG_DRV("  SCSI Data [Lun%u]\r\n", p_cbw->lun);
  564|  52.0k|      TU_ASSERT(xferred_bytes <= CFG_TUD_MSC_EP_BUFSIZE); // sanity check to avoid buffer overflow
  ------------------
  |  |  112|  52.0k|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|  52.0k|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|  52.0k|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  108|  52.0k|#define TU_ASSERT_1ARGS(_cond)         TU_ASSERT_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|  52.0k|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|  52.0k|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 52.0k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|  52.0k|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 52.0k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  565|       |      // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, _mscd_epbuf.buf, xferred_bytes, 2);
  566|       |
  567|  52.0k|      if (SCSI_CMD_READ_10 == p_cbw->command[0]) {
  ------------------
  |  Branch (567:11): [True: 49.1k, False: 2.84k]
  ------------------
  568|  49.1k|        p_msc->xferred_len += xferred_bytes;
  569|       |
  570|  49.1k|        if ( p_msc->xferred_len >= p_msc->total_len ) {
  ------------------
  |  Branch (570:14): [True: 47, False: 49.1k]
  ------------------
  571|       |          // Data Stage is complete
  572|     47|          p_msc->stage = MSC_STAGE_STATUS;
  573|  49.1k|        }else {
  574|  49.1k|          proc_read10_cmd(p_msc);
  575|  49.1k|        }
  576|  49.1k|      } else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) {
  ------------------
  |  Branch (576:18): [True: 2.77k, False: 77]
  ------------------
  577|  2.77k|        proc_write10_host_data(p_msc, xferred_bytes);
  578|  2.77k|      } else {
  579|     77|        p_msc->xferred_len += xferred_bytes;
  580|       |
  581|       |        // OUT transfer, invoke callback if needed
  582|     77|        if ( !is_data_in(p_cbw->dir) ) {
  ------------------
  |  Branch (582:14): [True: 11, False: 66]
  ------------------
  583|     11|          int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_epbuf.buf, (uint16_t) p_msc->total_len);
  584|       |
  585|     11|          if ( cb_result < 0 ) {
  ------------------
  |  Branch (585:16): [True: 11, False: 0]
  ------------------
  586|       |            // unsupported command
  587|     11|            TU_LOG_DRV("  SCSI unsupported command\r\n");
  588|     11|            fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  589|     11|          }else {
  590|       |            // TODO haven't implement this scenario any further yet
  591|      0|          }
  592|     11|        }
  593|       |
  594|     77|        if ( p_msc->xferred_len >= p_msc->total_len ) {
  ------------------
  |  Branch (594:14): [True: 77, False: 0]
  ------------------
  595|       |          // Data Stage is complete
  596|     77|          p_msc->stage = MSC_STAGE_STATUS;
  597|     77|        } else {
  598|       |          // This scenario with command that take more than one transfer is already rejected at Command stage
  599|      0|          TU_BREAKPOINT();
  ------------------
  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  ------------------
  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  ------------------
  ------------------
  600|      0|        }
  601|     77|      }
  602|  52.0k|    break;
  603|       |
  604|      0|    case MSC_STAGE_STATUS:
  ------------------
  |  Branch (604:5): [True: 0, False: 52.7k]
  ------------------
  605|       |      // processed immediately after this switch, supposedly to be empty
  606|      0|    break;
  607|       |
  608|    193|    case MSC_STAGE_STATUS_SENT:
  ------------------
  |  Branch (608:5): [True: 193, False: 52.5k]
  ------------------
  609|       |      // Status phase is complete
  610|    193|      if ((ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t))) {
  ------------------
  |  Branch (610:11): [True: 193, False: 0]
  |  Branch (610:40): [True: 193, False: 0]
  ------------------
  611|    193|        TU_LOG_DRV("  SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
  612|       |        // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_csw, xferred_bytes, 2);
  613|       |
  614|       |        // Invoke complete callback if defined
  615|       |        // Note: There is racing issue with samd51 + qspi flash testing with arduino
  616|       |        // if complete_cb() is invoked after queuing the status.
  617|    193|        switch (p_cbw->command[0]) {
  618|     66|          case SCSI_CMD_READ_10:
  ------------------
  |  Branch (618:11): [True: 66, False: 127]
  ------------------
  619|     66|            tud_msc_read10_complete_cb(p_cbw->lun);
  620|     66|            break;
  621|       |
  622|     46|          case SCSI_CMD_WRITE_10:
  ------------------
  |  Branch (622:11): [True: 46, False: 147]
  ------------------
  623|     46|            tud_msc_write10_complete_cb(p_cbw->lun);
  624|     46|            break;
  625|       |
  626|     81|          default:
  ------------------
  |  Branch (626:11): [True: 81, False: 112]
  ------------------
  627|     81|            tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command);
  628|     81|            break;
  629|    193|        }
  630|       |
  631|    193|        if (!usbd_edpt_stalled(rhport, p_msc->ep_out)) {
  ------------------
  |  Branch (631:13): [True: 108, False: 85]
  ------------------
  632|    108|          TU_ASSERT(prepare_cbw(p_msc));
  ------------------
  |  |  112|    108|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|    108|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|    108|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  108|    108|#define TU_ASSERT_1ARGS(_cond)         TU_ASSERT_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|    108|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|    108|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 108]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|    108|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 108]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  633|    108|        } else {
  634|     85|          p_msc->stage = MSC_STAGE_CMD;
  635|     85|        }
  636|    193|      } else {
  637|       |        // Any xfer ended here is considered unknown error, ignore it
  638|      0|        TU_LOG1("  Warning expect SCSI Status but received unknown data\r\n");
  639|      0|      }
  640|    193|      break;
  641|       |
  642|    193|    default: break; // nothing to do
  ------------------
  |  Branch (642:5): [True: 0, False: 52.7k]
  ------------------
  643|  52.7k|  }
  644|       |
  645|  52.7k|  if (p_msc->stage == MSC_STAGE_STATUS) {
  ------------------
  |  Branch (645:7): [True: 353, False: 52.3k]
  ------------------
  646|    353|    TU_ASSERT(proc_stage_status(p_msc));
  ------------------
  |  |  112|    353|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|    353|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|    353|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  108|    353|#define TU_ASSERT_1ARGS(_cond)         TU_ASSERT_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|    353|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|    353|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 353]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|    353|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 353]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  647|    353|  }
  648|       |
  649|  52.7k|  return true;
  650|  52.7k|}
fuzz.c:proc_read_io_data:
  852|  49.2k|static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) {
  853|  49.2k|  const uint8_t rhport = p_msc->rhport;
  854|  49.2k|  if (nbytes > 0) {
  ------------------
  |  Branch (854:7): [True: 49.2k, False: 0]
  ------------------
  855|  49.2k|    TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes, false),);
  ------------------
  |  |  112|  49.2k|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|  49.2k|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|  49.2k|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  109|  49.2k|#define TU_ASSERT_2ARGS(_cond, _ret)   TU_ASSERT_DEFINE(_cond, _ret)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|  49.2k|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|  49.2k|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 49.2k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|  49.2k|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 49.2k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  856|  49.2k|  } else {
  857|       |    // nbytes is status
  858|      0|    switch (nbytes) {
  859|      0|      case TUD_MSC_RET_ERROR:
  ------------------
  |  Branch (859:7): [True: 0, False: 0]
  ------------------
  860|       |        // error -> endpoint is stalled & status in CSW set to failed
  861|      0|        TU_LOG_DRV("  IO read() failed\r\n");
  862|      0|        set_sense_medium_not_present(p_msc->cbw.lun);
  863|      0|        fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  864|      0|        break;
  865|       |
  866|      0|      case TUD_MSC_RET_BUSY:
  ------------------
  |  Branch (866:7): [True: 0, False: 0]
  ------------------
  867|       |        // not ready yet -> fake a transfer complete so that this driver callback will fire again
  868|      0|        dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
  869|      0|        break;
  870|       |
  871|      0|      default: break; // nothing to do
  ------------------
  |  Branch (871:7): [True: 0, False: 0]
  ------------------
  872|      0|    }
  873|      0|  }
  874|  49.2k|}
fuzz.c:proc_write_io_data:
  912|  2.77k|static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) {
  913|  2.77k|  if (nbytes < 0) {
  ------------------
  |  Branch (913:7): [True: 0, False: 2.77k]
  ------------------
  914|       |    // nbytes is status
  915|      0|    switch (nbytes) {
  916|      0|      case TUD_MSC_RET_ERROR:
  ------------------
  |  Branch (916:7): [True: 0, False: 0]
  ------------------
  917|       |        // IO error -> failed this scsi op
  918|      0|        TU_LOG_DRV("  IO write() failed\r\n");
  919|      0|        set_sense_medium_not_present(p_msc->cbw.lun);
  920|      0|        fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  921|      0|        break;
  922|       |
  923|      0|      default: break; // nothing to do
  ------------------
  |  Branch (923:7): [True: 0, False: 0]
  ------------------
  924|      0|    }
  925|  2.77k|  } else {
  926|  2.77k|    if ((uint32_t)nbytes < xferred_bytes) {
  ------------------
  |  Branch (926:9): [True: 0, False: 2.77k]
  ------------------
  927|       |      // Application consume less than what we got including TUD_MSC_RET_BUSY (0)
  928|      0|      const uint32_t left_over = xferred_bytes - (uint32_t)nbytes;
  929|      0|      if (nbytes > 0) {
  ------------------
  |  Branch (929:11): [True: 0, False: 0]
  ------------------
  930|      0|        memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over);
  931|      0|      }
  932|       |
  933|       |      // fake a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameters
  934|      0|      dcd_event_xfer_complete(p_msc->rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
  935|  2.77k|    } else {
  936|       |      // Application consume all bytes in our buffer
  937|  2.77k|      p_msc->xferred_len += xferred_bytes;
  938|       |
  939|  2.77k|      if (p_msc->xferred_len >= p_msc->total_len) {
  ------------------
  |  Branch (939:11): [True: 25, False: 2.74k]
  ------------------
  940|       |        // Data Stage is complete
  941|     25|        p_msc->stage = MSC_STAGE_STATUS;
  942|  2.74k|      } else {
  943|       |        // prepare to receive more data from host
  944|  2.74k|        proc_write10_cmd(p_msc);
  945|  2.74k|      }
  946|  2.77k|    }
  947|  2.77k|  }
  948|  2.77k|}
fuzz.c:prepare_cbw:
  102|    644|TU_ATTR_ALWAYS_INLINE static inline bool prepare_cbw(mscd_interface_t* p_msc) {
  103|    644|  uint8_t rhport = p_msc->rhport;
  104|    644|  p_msc->stage = MSC_STAGE_CMD;
  105|       |  return usbd_edpt_xfer(rhport, p_msc->ep_out,  _mscd_epbuf.buf, sizeof(msc_cbw_t), false);
  106|    644|}
fuzz.c:send_csw:
   93|    193|TU_ATTR_ALWAYS_INLINE static inline bool send_csw(mscd_interface_t* p_msc) {
   94|       |  // Data residue is always = host expect - actual transferred
   95|    193|  uint8_t rhport = p_msc->rhport;
   96|    193|  p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
   97|    193|  p_msc->stage = MSC_STAGE_STATUS_SENT;
   98|    193|  memcpy(_mscd_epbuf.buf, &p_msc->csw, sizeof(msc_csw_t)); //-V1086
   99|       |  return usbd_edpt_xfer(rhport, p_msc->ep_in , _mscd_epbuf.buf, sizeof(msc_csw_t), false);
  100|    193|}
fuzz.c:rdwr10_validate_cmd:
  152|    304|static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) {
  153|    304|  uint8_t status = MSC_CSW_STATUS_PASSED;
  154|    304|  uint16_t const block_count = rdwr10_get_blockcount(cbw);
  155|       |
  156|    304|  if (cbw->total_bytes == 0) {
  ------------------
  |  Branch (156:7): [True: 17, False: 287]
  ------------------
  157|     17|    if (block_count > 0) {
  ------------------
  |  Branch (157:9): [True: 16, False: 1]
  ------------------
  158|     16|      TU_LOG_DRV("  SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n");
  159|     16|      status = MSC_CSW_STATUS_PHASE_ERROR;
  160|     16|    } else {
  161|       |      // no data transfer, only exist in complaint test suite
  162|      1|    }
  163|    287|  } else {
  164|    287|    if (SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir)) {
  ------------------
  |  Branch (164:9): [True: 111, False: 176]
  |  Branch (164:48): [True: 7, False: 104]
  ------------------
  165|      7|      TU_LOG_DRV("  SCSI case 10 (Ho <> Di)\r\n");
  166|      7|      status = MSC_CSW_STATUS_PHASE_ERROR;
  167|    280|    } else if (SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir)) {
  ------------------
  |  Branch (167:16): [True: 176, False: 104]
  |  Branch (167:56): [True: 9, False: 167]
  ------------------
  168|      9|      TU_LOG_DRV("  SCSI case 8 (Hi <> Do)\r\n");
  169|      9|      status = MSC_CSW_STATUS_PHASE_ERROR;
  170|    271|    } else if (0 == block_count || (cbw->total_bytes >> 16) >= block_count) { // or block size > 16-bit, without a divide
  ------------------
  |  Branch (170:16): [True: 4, False: 267]
  |  Branch (170:36): [True: 25, False: 242]
  ------------------
  171|     29|      TU_LOG_DRV("  SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n");
  172|     29|      status = MSC_CSW_STATUS_FAILED;
  173|    242|    } else if (cbw->total_bytes / block_count == 0) {
  ------------------
  |  Branch (173:16): [True: 5, False: 237]
  ------------------
  174|      5|      TU_LOG_DRV(" Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n");
  175|      5|      status = MSC_CSW_STATUS_PHASE_ERROR;
  176|    237|    } else {
  177|       |      // nothing to do
  178|    237|    }
  179|    287|  }
  180|       |
  181|    304|  return status;
  182|    304|}
fuzz.c:rdwr10_get_blockcount:
  138|  52.2k|TU_ATTR_ALWAYS_INLINE static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) {
  139|  52.2k|  uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count));
  140|  52.2k|  return tu_ntohs(block_count);
  ------------------
  |  |  285|  52.2k|  #define tu_ntohs(u16)  (TU_BSWAP16(u16))
  |  |  ------------------
  |  |  |  |  206|  52.2k|    #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
  |  |  ------------------
  ------------------
  141|  52.2k|}
fuzz.c:fail_scsi_op:
  108|    212|static void fail_scsi_op(mscd_interface_t* p_msc, uint8_t status) {
  109|    212|  msc_cbw_t const * p_cbw = &p_msc->cbw;
  110|    212|  msc_csw_t       * p_csw = &p_msc->csw;
  111|    212|  uint8_t rhport = p_msc->rhport;
  112|       |
  113|    212|  p_csw->status       = status;
  114|    212|  p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
  115|    212|  p_msc->stage        = MSC_STAGE_STATUS;
  116|       |
  117|       |  // failed but sense key is not set: default to Illegal Request
  118|    212|  if (p_msc->sense_key == 0) {
  ------------------
  |  Branch (118:7): [True: 212, False: 0]
  ------------------
  119|    212|    (void) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
  120|    212|  }
  121|       |
  122|       |  // If there is data stage and not yet complete, stall it
  123|    212|  if (p_cbw->total_bytes && p_csw->data_residue) {
  ------------------
  |  Branch (123:7): [True: 195, False: 17]
  |  Branch (123:29): [True: 184, False: 11]
  ------------------
  124|    184|    if (is_data_in(p_cbw->dir)) {
  ------------------
  |  Branch (124:9): [True: 99, False: 85]
  ------------------
  125|     99|      usbd_edpt_stall(rhport, p_msc->ep_in);
  126|     99|    } else {
  127|     85|      usbd_edpt_stall(rhport, p_msc->ep_out);
  128|     85|    }
  129|    184|  }
  130|    212|}
fuzz.c:is_data_in:
   89|    923|TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) {
   90|    923|  return tu_bit_test(dir, 7);
   91|    923|}
fuzz.c:proc_stage_status:
  184|    353|static bool proc_stage_status(mscd_interface_t *p_msc) {
  185|    353|  uint8_t rhport = p_msc->rhport;
  186|    353|  msc_cbw_t const *p_cbw = &p_msc->cbw;
  187|       |
  188|       |  // skip status if epin is currently stalled, will do it when received Clear Stall request
  189|    353|  if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) {
  ------------------
  |  Branch (189:7): [True: 254, False: 99]
  ------------------
  190|    254|    if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) {
  ------------------
  |  Branch (190:9): [True: 146, False: 108]
  |  Branch (190:54): [True: 61, False: 85]
  ------------------
  191|       |      // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
  192|       |      // TU_LOG_DRV("  SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
  193|     61|      usbd_edpt_stall(rhport, p_msc->ep_in);
  194|    193|    } else {
  195|    193|      TU_ASSERT(send_csw(p_msc));
  ------------------
  |  |  112|    193|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|    193|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|    193|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  108|    193|#define TU_ASSERT_1ARGS(_cond)         TU_ASSERT_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|    193|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|    193|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 193]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|    193|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 193]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  196|    193|    }
  197|    254|  }
  198|       |
  199|       |  #if TU_CHECK_MCU(OPT_MCU_CXD56)
  200|       |  // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD.
  201|       |  // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and
  202|       |  // hope everything will work
  203|       |  if (usbd_edpt_stalled(rhport, p_msc->ep_in)) {
  204|       |    usbd_edpt_clear_stall(rhport, p_msc->ep_in);
  205|       |    send_csw(p_msc);
  206|       |  }
  207|       |  #endif
  208|    353|  return true;
  209|    353|}
fuzz.c:proc_builtin_scsi:
  658|    141|static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize) {
  659|    141|  (void)bufsize; // TODO refractor later
  660|    141|  int32_t resplen;
  661|       |
  662|    141|  mscd_interface_t* p_msc = &_mscd_itf;
  663|       |
  664|    141|  switch (scsi_cmd[0]) {
  665|     50|    case SCSI_CMD_TEST_UNIT_READY:
  ------------------
  |  Branch (665:5): [True: 50, False: 91]
  ------------------
  666|     50|      resplen = 0;
  667|     50|      if (!tud_msc_test_unit_ready_cb(lun)) {
  ------------------
  |  Branch (667:11): [True: 0, False: 50]
  ------------------
  668|       |        // Failed status response
  669|      0|        resplen = -1;
  670|       |
  671|       |        // set default sense if not set by callback
  672|      0|        if (p_msc->sense_key == 0) {
  ------------------
  |  Branch (672:13): [True: 0, False: 0]
  ------------------
  673|      0|          set_sense_medium_not_present(lun);
  674|      0|        }
  675|      0|      }
  676|     50|      break;
  677|       |
  678|      4|    case SCSI_CMD_START_STOP_UNIT: {
  ------------------
  |  Branch (678:5): [True: 4, False: 137]
  ------------------
  679|      4|      resplen = 0;
  680|      4|      scsi_start_stop_unit_t const* start_stop = (scsi_start_stop_unit_t const*)scsi_cmd;
  681|      4|      if (!tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject)) {
  ------------------
  |  Branch (681:11): [True: 0, False: 4]
  ------------------
  682|       |        // Failed status response
  683|      0|        resplen = -1;
  684|       |
  685|       |        // set default sense if not set by callback
  686|      0|        if (p_msc->sense_key == 0) {
  ------------------
  |  Branch (686:13): [True: 0, False: 0]
  ------------------
  687|      0|          set_sense_medium_not_present(lun);
  688|      0|        }
  689|      0|      }
  690|      4|      break;
  691|      0|    }
  692|       |
  693|      5|    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: {
  ------------------
  |  Branch (693:5): [True: 5, False: 136]
  ------------------
  694|      5|      resplen = 0;
  695|      5|      scsi_prevent_allow_medium_removal_t const* prevent_allow = (scsi_prevent_allow_medium_removal_t const*)scsi_cmd;
  696|      5|      if (!tud_msc_prevent_allow_medium_removal_cb(lun, prevent_allow->prohibit_removal, prevent_allow->control)) {
  ------------------
  |  Branch (696:11): [True: 0, False: 5]
  ------------------
  697|       |        // Failed status response
  698|      0|        resplen = -1;
  699|       |
  700|       |        // set default sense if not set by callback
  701|      0|        if (p_msc->sense_key == 0) {
  ------------------
  |  Branch (701:13): [True: 0, False: 0]
  ------------------
  702|      0|          set_sense_medium_not_present(lun);
  703|      0|        }
  704|      0|      }
  705|      5|      break;
  706|      0|    }
  707|       |
  708|     10|    case SCSI_CMD_READ_CAPACITY_10: {
  ------------------
  |  Branch (708:5): [True: 10, False: 131]
  ------------------
  709|     10|      uint32_t block_count;
  710|     10|      uint32_t block_size;
  711|     10|      uint16_t block_size_u16;
  712|       |
  713|     10|      tud_msc_capacity_cb(lun, &block_count, &block_size_u16);
  714|     10|      block_size = (uint32_t)block_size_u16;
  715|       |
  716|       |      // Invalid block size/count from callback, possibly unit is not ready
  717|       |      // stall this request, set sense key to NOT READY
  718|     10|      if (block_count == 0 || block_size == 0) {
  ------------------
  |  Branch (718:11): [True: 0, False: 10]
  |  Branch (718:31): [True: 0, False: 10]
  ------------------
  719|      0|        resplen = -1;
  720|       |
  721|       |        // set default sense if not set by callback
  722|      0|        if (p_msc->sense_key == 0) {
  ------------------
  |  Branch (722:13): [True: 0, False: 0]
  ------------------
  723|      0|          set_sense_medium_not_present(lun);
  724|      0|        }
  725|     10|      } else {
  726|     10|        scsi_read_capacity10_resp_t read_capa10;
  727|       |
  728|     10|        read_capa10.last_lba = tu_htonl(block_count-1);
  ------------------
  |  |  287|     10|  #define tu_htonl(u32)  (TU_BSWAP32(u32))
  |  |  ------------------
  |  |  |  |  207|     10|    #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
  |  |  ------------------
  ------------------
  729|     10|        read_capa10.block_size = tu_htonl(block_size);
  ------------------
  |  |  287|     10|  #define tu_htonl(u32)  (TU_BSWAP32(u32))
  |  |  ------------------
  |  |  |  |  207|     10|    #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
  |  |  ------------------
  ------------------
  730|       |
  731|     10|        resplen = sizeof(read_capa10);
  732|     10|        TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_capa10, (size_t) resplen));
  ------------------
  |  |   95|     10|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|     10|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |   95|     10|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   92|     10|#define TU_VERIFY_1ARGS(_cond)         TU_VERIFY_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   86|     10|  do {                                \
  |  |  |  |  |  |  |  |  |  |   87|     10|    if (!(_cond)) {                   \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (87:9): [True: 0, False: 10]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   88|      0|      return _ret;                    \
  |  |  |  |  |  |  |  |  |  |   89|      0|    }                                 \
  |  |  |  |  |  |  |  |  |  |   90|     10|  } while (0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (90:12): [Folded, False: 10]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  733|     10|      }
  734|     10|      break;
  735|     10|    }
  736|       |
  737|     13|    case SCSI_CMD_READ_FORMAT_CAPACITY: {
  ------------------
  |  Branch (737:5): [True: 13, False: 128]
  ------------------
  738|     13|      scsi_read_format_capacity_data_t read_fmt_capa = {
  739|     13|        .list_length = 8,
  740|     13|        .block_num = 0,
  741|     13|        .descriptor_type = 2, // formatted media
  742|     13|        .block_size_u16 = 0
  743|     13|      };
  744|       |
  745|     13|      uint32_t block_count;
  746|     13|      uint16_t block_size;
  747|       |
  748|     13|      tud_msc_capacity_cb(lun, &block_count, &block_size);
  749|       |
  750|       |      // Invalid block size/count from callback, possibly unit is not ready
  751|       |      // stall this request, set sense key to NOT READY
  752|     13|      if (block_count == 0 || block_size == 0) {
  ------------------
  |  Branch (752:11): [True: 0, False: 13]
  |  Branch (752:31): [True: 0, False: 13]
  ------------------
  753|      0|        resplen = -1;
  754|       |
  755|       |        // set default sense if not set by callback
  756|      0|        if (p_msc->sense_key == 0) {
  ------------------
  |  Branch (756:13): [True: 0, False: 0]
  ------------------
  757|      0|          set_sense_medium_not_present(lun);
  758|      0|        }
  759|     13|      } else {
  760|     13|        read_fmt_capa.block_num = tu_htonl(block_count);
  ------------------
  |  |  287|     13|  #define tu_htonl(u32)  (TU_BSWAP32(u32))
  |  |  ------------------
  |  |  |  |  207|     13|    #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
  |  |  ------------------
  ------------------
  761|     13|        read_fmt_capa.block_size_u16 = tu_htons(block_size);
  ------------------
  |  |  284|     13|  #define tu_htons(u16)  (TU_BSWAP16(u16))
  |  |  ------------------
  |  |  |  |  206|     13|    #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
  |  |  ------------------
  ------------------
  762|       |
  763|     13|        resplen = sizeof(read_fmt_capa);
  764|     13|        TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &read_fmt_capa, (size_t) resplen));
  ------------------
  |  |   95|     13|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|     13|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |   95|     13|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   92|     13|#define TU_VERIFY_1ARGS(_cond)         TU_VERIFY_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   86|     13|  do {                                \
  |  |  |  |  |  |  |  |  |  |   87|     13|    if (!(_cond)) {                   \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (87:9): [True: 0, False: 13]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   88|      0|      return _ret;                    \
  |  |  |  |  |  |  |  |  |  |   89|      0|    }                                 \
  |  |  |  |  |  |  |  |  |  |   90|     13|  } while (0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (90:12): [Folded, False: 13]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  765|     13|      }
  766|     13|      break;
  767|     13|    }
  768|       |
  769|     13|    case SCSI_CMD_INQUIRY: {
  ------------------
  |  Branch (769:5): [True: 3, False: 138]
  ------------------
  770|      3|      scsi_inquiry_resp_t *inquiry_rsp = (scsi_inquiry_resp_t *) buffer;
  771|      3|      tu_memclr(inquiry_rsp, sizeof(scsi_inquiry_resp_t));
  ------------------
  |  |   95|      3|#define tu_memclr(buffer, size)  (void) memset((buffer), 0, (size))
  ------------------
  772|      3|      inquiry_rsp->is_removable = 1;
  773|      3|      inquiry_rsp->version = 2;
  774|      3|      inquiry_rsp->response_data_format = 2;
  775|      3|      inquiry_rsp->additional_length = sizeof(scsi_inquiry_resp_t) - 5;
  776|       |
  777|      3|      resplen = (int32_t) tud_msc_inquiry2_cb(lun, inquiry_rsp, bufsize);
  778|      3|      if (resplen == 0) {
  ------------------
  |  Branch (778:11): [True: 3, False: 0]
  ------------------
  779|       |        // stub callback with no response, use v1 callback
  780|      3|        tud_msc_inquiry_cb(lun, inquiry_rsp->vendor_id, inquiry_rsp->product_id, inquiry_rsp->product_rev);
  781|      3|        resplen = sizeof(scsi_inquiry_resp_t);
  782|      3|      }
  783|      3|      break;
  784|     13|    }
  785|       |
  786|     16|    case SCSI_CMD_MODE_SENSE_6: {
  ------------------
  |  Branch (786:5): [True: 16, False: 125]
  ------------------
  787|     16|      scsi_mode_sense6_resp_t mode_resp = {
  788|     16|        .data_len = 3,
  789|     16|        .medium_type = 0,
  790|     16|        .write_protected = false,
  791|     16|        .reserved = 0,
  792|     16|        .block_descriptor_len = 0 // no block descriptor are included
  793|     16|      };
  794|       |
  795|     16|      bool writable = tud_msc_is_writable_cb(lun);
  796|       |
  797|     16|      mode_resp.write_protected = !writable;
  798|       |
  799|     16|      resplen = sizeof(mode_resp);
  800|     16|      TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &mode_resp, (size_t) resplen));
  ------------------
  |  |   95|     16|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|     16|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |   95|     16|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   92|     16|#define TU_VERIFY_1ARGS(_cond)         TU_VERIFY_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   86|     16|  do {                                \
  |  |  |  |  |  |  |  |  |  |   87|     16|    if (!(_cond)) {                   \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (87:9): [True: 0, False: 16]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   88|      0|      return _ret;                    \
  |  |  |  |  |  |  |  |  |  |   89|      0|    }                                 \
  |  |  |  |  |  |  |  |  |  |   90|     16|  } while (0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (90:12): [Folded, False: 16]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  801|     16|      break;
  802|     16|    }
  803|       |
  804|     25|    case SCSI_CMD_REQUEST_SENSE: {
  ------------------
  |  Branch (804:5): [True: 25, False: 116]
  ------------------
  805|     25|      scsi_sense_fixed_resp_t sense_rsp = {
  806|     25|        .response_code = 0x70, // current, fixed format
  807|     25|        .valid = 1
  808|     25|      };
  809|       |
  810|     25|      sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8;
  811|     25|      sense_rsp.sense_key = (uint8_t)(p_msc->sense_key & 0x0F);
  812|     25|      sense_rsp.add_sense_code = p_msc->add_sense_code;
  813|     25|      sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier;
  814|       |
  815|     25|      resplen = sizeof(sense_rsp);
  816|     25|      TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen));
  ------------------
  |  |   95|     25|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|     25|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |   95|     25|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   92|     25|#define TU_VERIFY_1ARGS(_cond)         TU_VERIFY_DEFINE(_cond, false)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   86|     25|  do {                                \
  |  |  |  |  |  |  |  |  |  |   87|     25|    if (!(_cond)) {                   \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (87:9): [True: 0, False: 25]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   88|      0|      return _ret;                    \
  |  |  |  |  |  |  |  |  |  |   89|      0|    }                                 \
  |  |  |  |  |  |  |  |  |  |   90|     25|  } while (0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (90:12): [Folded, False: 25]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  817|       |
  818|       |      // request sense callback could overwrite the sense data
  819|     25|      resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t)bufsize);
  820|       |
  821|       |      // Clear sense data after copy
  822|     25|      (void) tud_msc_set_sense(lun, 0, 0, 0);
  823|     25|      break;
  824|     25|    }
  825|       |
  826|     15|    default: resplen = -1;
  ------------------
  |  Branch (826:5): [True: 15, False: 126]
  ------------------
  827|     15|      break;
  828|    141|  }
  829|       |
  830|    141|  return resplen;
  831|    141|}
fuzz.c:proc_read10_cmd:
  833|  49.2k|static void proc_read10_cmd(mscd_interface_t* p_msc) {
  834|  49.2k|  msc_cbw_t const* p_cbw = &p_msc->cbw;
  835|  49.2k|  uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero
  836|  49.2k|  TU_VERIFY(block_sz != 0, );
  ------------------
  |  |   95|  49.2k|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|  49.2k|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |   95|  49.2k|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   93|  49.2k|#define TU_VERIFY_2ARGS(_cond, _ret)   TU_VERIFY_DEFINE(_cond, _ret)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   86|  49.2k|  do {                                \
  |  |  |  |  |  |  |  |  |  |   87|  49.2k|    if (!(_cond)) {                   \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (87:9): [True: 0, False: 49.2k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   88|      0|      return _ret;                    \
  |  |  |  |  |  |  |  |  |  |   89|      0|    }                                 \
  |  |  |  |  |  |  |  |  |  |   90|  49.2k|  } while (0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (90:12): [Folded, False: 49.2k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  837|       |  // Adjust lba & offset with transferred bytes
  838|  49.2k|  uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
  839|  49.2k|  uint32_t const offset = p_msc->xferred_len % block_sz;
  840|       |
  841|       |  // remaining bytes capped at class buffer
  842|  49.2k|  int32_t nbytes = (int32_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len);
  ------------------
  |  |   10|  49.2k|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  843|       |
  844|  49.2k|  p_msc->pending_io = true;
  845|  49.2k|  nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes);
  846|  49.2k|  if (nbytes != TUD_MSC_RET_ASYNC) {
  ------------------
  |  Branch (846:7): [True: 49.2k, False: 0]
  ------------------
  847|       |    p_msc->pending_io = false;
  848|  49.2k|    proc_read_io_data(p_msc, nbytes);
  849|  49.2k|  }
  850|  49.2k|}
fuzz.c:rdwr10_get_blocksize:
  143|  51.9k|TU_ATTR_ALWAYS_INLINE static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) {
  144|       |  // first extract block count in the command
  145|  51.9k|  uint16_t const block_count = rdwr10_get_blockcount(cbw);
  146|  51.9k|  if (block_count == 0) {
  ------------------
  |  Branch (146:7): [True: 0, False: 51.9k]
  ------------------
  147|      0|    return 0; // invalid block count
  148|      0|  }
  149|  51.9k|  return (uint16_t) (cbw->total_bytes / block_count);
  150|  51.9k|}
fuzz.c:rdwr10_get_lba:
  132|  51.9k|TU_ATTR_ALWAYS_INLINE static inline uint32_t rdwr10_get_lba(uint8_t const command[]) {
  133|       |  // use offsetof to avoid pointer to the odd/unaligned address
  134|  51.9k|  const uint32_t lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba));
  135|  51.9k|  return tu_ntohl(lba); // lba is in Big Endian
  ------------------
  |  |  288|  51.9k|  #define tu_ntohl(u32)  (TU_BSWAP32(u32))
  |  |  ------------------
  |  |  |  |  207|  51.9k|    #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
  |  |  ------------------
  ------------------
  136|  51.9k|}
fuzz.c:proc_write10_cmd:
  876|  2.89k|static void proc_write10_cmd(mscd_interface_t* p_msc) {
  877|  2.89k|  msc_cbw_t const* p_cbw = &p_msc->cbw;
  878|  2.89k|  const bool writable = tud_msc_is_writable_cb(p_cbw->lun);
  879|       |
  880|  2.89k|  if (!writable) {
  ------------------
  |  Branch (880:7): [True: 0, False: 2.89k]
  ------------------
  881|       |    // Not writable, complete this SCSI op with error
  882|       |    // Sense = Write protected
  883|      0|    (void) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00);
  884|      0|    fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
  885|      0|    return;
  886|      0|  }
  887|       |
  888|       |  // remaining bytes capped at class buffer
  889|  2.89k|  uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len);
  ------------------
  |  |   10|  2.89k|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  890|       |  // Write10 callback will be called later when usb transfer complete
  891|  2.89k|  TU_ASSERT(usbd_edpt_xfer(p_msc->rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes, false),);
  ------------------
  |  |  112|  2.89k|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|  2.89k|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |  112|  2.89k|#define TU_ASSERT(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  109|  2.89k|#define TU_ASSERT_2ARGS(_cond, _ret)   TU_ASSERT_DEFINE(_cond, _ret)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  104|  2.89k|  do {                                                                \
  |  |  |  |  |  |  |  |  |  |  105|  2.89k|    if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   54|      0|  #define TU_MESS_FAILED() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (54:41): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |                   if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |   77|      0|  #define TU_BREAKPOINT() do {} while (0)
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  |  |  Branch (77:40): [Folded, False: 0]
  |  |  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (105:10): [True: 0, False: 2.89k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  106|  2.89k|  } while(0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (106:11): [Folded, False: 2.89k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  892|  2.89k|}
fuzz.c:proc_write10_host_data:
  895|  2.77k|static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) {
  896|  2.77k|  msc_cbw_t const* p_cbw = &p_msc->cbw;
  897|  2.77k|  uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero
  898|  2.77k|  TU_VERIFY(block_sz != 0, );
  ------------------
  |  |   95|  2.77k|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  ------------------
  |  |  |  |  131|  2.77k|#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...)        arg3
  |  |  |  |  ------------------
  |  |  |  |  |  |   95|  2.77k|#define TU_VERIFY(...)                 TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   93|  2.77k|#define TU_VERIFY_2ARGS(_cond, _ret)   TU_VERIFY_DEFINE(_cond, _ret)
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   86|  2.77k|  do {                                \
  |  |  |  |  |  |  |  |  |  |   87|  2.77k|    if (!(_cond)) {                   \
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (87:9): [True: 0, False: 2.77k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   88|      0|      return _ret;                    \
  |  |  |  |  |  |  |  |  |  |   89|      0|    }                                 \
  |  |  |  |  |  |  |  |  |  |   90|  2.77k|  } while (0)
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |  |  Branch (90:12): [Folded, False: 2.77k]
  |  |  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  899|       |
  900|       |  // Adjust lba & offset with transferred bytes
  901|  2.77k|  uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
  902|  2.77k|  uint32_t const offset = p_msc->xferred_len % block_sz;
  903|       |
  904|  2.77k|  p_msc->pending_io = true;
  905|  2.77k|  int32_t nbytes =  tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes);
  906|  2.77k|  if (nbytes != TUD_MSC_RET_ASYNC) {
  ------------------
  |  Branch (906:7): [True: 2.77k, False: 0]
  ------------------
  907|       |    p_msc->pending_io = false;
  908|  2.77k|    proc_write_io_data(p_msc, xferred_bytes, nbytes);
  909|  2.77k|  }
  910|  2.77k|}

fuzz.c:tu_unaligned_read32:
  242|  52.5k|TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void *mem) {
  243|  52.5k|  tu_unaligned_uint32_t const *ua32 = (tu_unaligned_uint32_t const *) mem;
  244|  52.5k|  return ua32->val;
  245|  52.5k|}
fuzz.c:tu_unaligned_read16:
  252|  52.2k|TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void *mem) {
  253|  52.2k|  tu_unaligned_uint16_t const *ua16 = (tu_unaligned_uint16_t const *) mem;
  254|  52.2k|  return ua16->val;
  255|  52.2k|}
fuzz.c:tu_bit_test:
  183|    923|TU_ATTR_ALWAYS_INLINE static inline bool     tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; }
  ------------------
  |  |   46|    923|#define TU_BIT(n)                     (1UL << (n))
  ------------------
  |  Branch (183:97): [True: 477, False: 446]
  ------------------
fuzz.c:tu_min32:
  188|  52.1k|TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; }
  ------------------
  |  Branch (188:89): [True: 52.0k, False: 116]
  ------------------
fuzz.c:tu_memcpy_s:
  118|     64|TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count) {
  119|     64|  if (dest == NULL) {
  ------------------
  |  Branch (119:7): [True: 0, False: 64]
  ------------------
  120|      0|    return -1;
  121|      0|  }
  122|       |
  123|     64|  if (count == 0u) {
  ------------------
  |  Branch (123:7): [True: 0, False: 64]
  ------------------
  124|      0|    return 0;
  125|      0|  }
  126|       |
  127|     64|  if (src == NULL) {
  ------------------
  |  Branch (127:7): [True: 0, False: 64]
  ------------------
  128|      0|    return -1;
  129|      0|  }
  130|       |
  131|     64|  if (count > destsz) {
  ------------------
  |  Branch (131:7): [True: 0, False: 64]
  ------------------
  132|      0|    return -1;
  133|      0|  }
  134|       |
  135|     64|  (void) memcpy(dest, src, count);
  136|     64|  return 0;
  137|     64|}

usbd_edpt_xfer:
   16|  53.0k|bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t length, bool is_isr) {
   17|  53.0k|  (void) rhport;
   18|  53.0k|  (void) is_isr;
   19|  53.0k|  queued_ep = ep_addr;
   20|  53.0k|  queued_buffer = buffer;
   21|  53.0k|  queued_length = length;
   22|       |  return true;
   23|  53.0k|}
usbd_edpt_stall:
   36|    245|void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
   37|    245|  (void) rhport;
   38|       |  ep_stalled[ep_addr >> 7] = true;
   39|    245|}
usbd_edpt_stalled:
   41|    546|bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) {
   42|    546|  (void) rhport;
   43|    546|  return ep_stalled[ep_addr >> 7];
   44|    546|}
tud_msc_test_unit_ready_cb:
   82|     50|bool tud_msc_test_unit_ready_cb(uint8_t lun) {
   83|     50|  (void) lun;
   84|       |  return true;
   85|     50|}
tud_msc_capacity_cb:
   87|     23|void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
   88|     23|  (void) lun;
   89|     23|  *block_count = 1024;
   90|     23|  *block_size = 512;
   91|     23|}
tud_msc_read10_cb:
   93|  49.2k|int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
   94|  49.2k|  (void) lun;
   95|  49.2k|  (void) lba;
   96|  49.2k|  (void) offset;
   97|  49.2k|  memset(buffer, 0, bufsize);
   98|  49.2k|  return (int32_t) bufsize;
   99|  49.2k|}
tud_msc_write10_cb:
  102|  2.77k|                            uint8_t *buffer, uint32_t bufsize) {
  103|  2.77k|  (void) lun;
  104|  2.77k|  (void) lba;
  105|  2.77k|  (void) offset;
  106|  2.77k|  (void) buffer;
  107|  2.77k|  return (int32_t) bufsize;
  108|  2.77k|}
tud_msc_scsi_cb:
  110|     26|int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const command[16], void *buffer, uint16_t bufsize) {
  111|     26|  (void) lun;
  112|     26|  (void) command;
  113|     26|  (void) buffer;
  114|     26|  (void) bufsize;
  115|     26|  return -1;
  116|     26|}
LLVMFuzzerTestOneInput:
  118|    544|int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) {
  119|    544|  if (size < sizeof(msc_cbw_t)) return 0;
  ------------------
  |  Branch (119:7): [True: 8, False: 536]
  ------------------
  120|       |
  121|    536|  ep_stalled[0] = ep_stalled[1] = false;
  122|       |
  123|    536|  mscd_init();
  124|    536|  _mscd_itf.rhport = 0;
  125|    536|  _mscd_itf.ep_out = 0x01;
  126|    536|  _mscd_itf.ep_in = 0x81;
  127|    536|  prepare_cbw(&_mscd_itf);
  128|       |
  129|    536|  msc_cbw_t cbw;
  130|    536|  memcpy(&cbw, data, sizeof(cbw));
  131|    536|  cbw.signature = MSC_CBW_SIGNATURE;
  132|    536|  memcpy(queued_buffer, &cbw, sizeof(cbw));
  133|    536|  queued_length = 0;  // don't re-complete the CBW if nothing new was queued
  134|    536|  mscd_xfer_cb(0, 0x01, XFER_RESULT_SUCCESS, sizeof(cbw));
  135|       |
  136|    536|  size_t offset = sizeof(cbw);
  137|       |
  138|       |  // Allow enough steps for multi-block READ10/WRITE10 commands to reach their
  139|       |  // CSW (one CFG_TUD_MSC_EP_BUFSIZE chunk per step), with a hard cap to bound
  140|       |  // run time for fuzz-controlled total_bytes. The driver ends the loop by
  141|       |  // itself once the stage is back to MSC_STAGE_CMD or MSC_STAGE_NEED_RESET.
  142|    536|  unsigned max_steps = cbw.total_bytes / CFG_TUD_MSC_EP_BUFSIZE + 4;
  ------------------
  |  |   10|    536|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  143|    536|  if (max_steps > 1024) max_steps = 1024;
  ------------------
  |  Branch (143:7): [True: 325, False: 211]
  ------------------
  144|       |
  145|  52.7k|  for (unsigned step = 0; step < max_steps && _mscd_itf.stage != MSC_STAGE_CMD &&
  ------------------
  |  Branch (145:27): [True: 52.7k, False: 39]
  |  Branch (145:47): [True: 52.5k, False: 193]
  ------------------
  146|  52.5k|                          _mscd_itf.stage != MSC_STAGE_NEED_RESET; ++step) {
  ------------------
  |  Branch (146:27): [True: 52.5k, False: 0]
  ------------------
  147|  52.5k|    uint8_t ep = queued_ep;
  148|  52.5k|    uint16_t length = queued_length;
  149|  52.5k|    if (length == 0 || length > CFG_TUD_MSC_EP_BUFSIZE) break;
  ------------------
  |  |   10|  52.3k|#define CFG_TUD_MSC_EP_BUFSIZE 512
  ------------------
  |  Branch (149:9): [True: 160, False: 52.3k]
  |  Branch (149:24): [True: 0, False: 52.3k]
  ------------------
  150|  52.3k|    if (_mscd_itf.stage == MSC_STAGE_DATA && ep == 0x01) {
  ------------------
  |  Branch (150:9): [True: 52.1k, False: 193]
  |  Branch (150:46): [True: 2.92k, False: 49.2k]
  ------------------
  151|  2.92k|      if (offset + length > size) break;
  ------------------
  |  Branch (151:11): [True: 144, False: 2.78k]
  ------------------
  152|  2.78k|      memcpy(queued_buffer, data + offset, length);
  153|  2.78k|      offset += length;
  154|  2.78k|    }
  155|  52.2k|    queued_length = 0;
  156|  52.2k|    mscd_xfer_cb(0, ep, XFER_RESULT_SUCCESS, length);
  157|  52.2k|  }
  158|    536|  return 0;
  159|    544|}

