@@ -159,7 +159,7 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
159159 case MSC_REQ_GET_MAX_LUN :
160160 {
161161 uint8_t maxlun = 1 ;
162- if (tud_msc_maxlun_cb ) maxlun = tud_msc_maxlun_cb ();
162+ if (tud_msc_get_maxlun_cb ) maxlun = tud_msc_get_maxlun_cb ();
163163 TU_VERIFY (maxlun );
164164
165165 // MAX LUN is minus 1 by specs
@@ -186,30 +186,64 @@ bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const
186186 return true;
187187}
188188
189- // return length of response (copied to buffer), -1 if it is not an built-in commands
190- int32_t proc_builtin_scsi (msc_cbw_t const * p_cbw , uint8_t * buffer , uint32_t bufsize )
189+ // return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW)
190+ // In case of a failed status, sense key must be set for reason of failure
191+ int32_t proc_builtin_scsi (uint8_t lun , uint8_t const scsi_cmd [16 ], uint8_t * buffer , uint32_t bufsize )
191192{
192193 (void ) bufsize ; // TODO refractor later
193- int32_t ret ;
194+ int32_t resplen ;
194195
195- switch ( p_cbw -> command [0 ] )
196+ switch ( scsi_cmd [0 ] )
196197 {
198+ case SCSI_CMD_TEST_UNIT_READY :
199+ resplen = 0 ;
200+ if ( !tud_msc_test_unit_ready_cb (lun ) )
201+ {
202+ // not ready response with Failed status and sense key = not ready
203+ resplen = - 1 ;
204+
205+ // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
206+ if ( _mscd_itf .sense_key == 0 ) tud_msc_set_sense (lun , SCSI_SENSE_NOT_READY , 0x04 , 0x00 );
207+ }
208+ break ;
209+
210+ case SCSI_CMD_START_STOP_UNIT :
211+ resplen = 0 ;
212+
213+ if (tud_msc_start_stop_cb )
214+ {
215+ scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const * ) scsi_cmd ;
216+ tud_msc_start_stop_cb (lun , start_stop -> power_condition , start_stop -> start , start_stop -> load_eject );
217+ }
218+ break ;
219+
197220 case SCSI_CMD_READ_CAPACITY_10 :
198221 {
199- scsi_read_capacity10_resp_t read_capa10 ;
200-
201222 uint32_t block_count ;
202223 uint32_t block_size ;
203224 uint16_t block_size_u16 ;
204225
205- tud_msc_capacity_cb (p_cbw -> lun , & block_count , & block_size_u16 );
226+ tud_msc_capacity_cb (lun , & block_count , & block_size_u16 );
206227 block_size = (uint32_t ) block_size_u16 ;
207228
208- read_capa10 .last_lba = ENDIAN_BE (block_count - 1 );
209- read_capa10 .block_size = ENDIAN_BE (block_size );
229+ // Invalid block size/count from callback, possibly unit is not ready
230+ // stall this request, set sense key to NOT READY
231+ if (block_count == 0 || block_size == 0 )
232+ {
233+ resplen = -1 ;
234+
235+ // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
236+ if ( _mscd_itf .sense_key == 0 ) tud_msc_set_sense (lun , SCSI_SENSE_NOT_READY , 0x04 , 0x00 );
237+ }else
238+ {
239+ scsi_read_capacity10_resp_t read_capa10 ;
240+
241+ read_capa10 .last_lba = ENDIAN_BE (block_count - 1 );
242+ read_capa10 .block_size = ENDIAN_BE (block_size );
210243
211- ret = sizeof (read_capa10 );
212- memcpy (buffer , & read_capa10 , ret );
244+ resplen = sizeof (read_capa10 );
245+ memcpy (buffer , & read_capa10 , resplen );
246+ }
213247 }
214248 break ;
215249
@@ -226,12 +260,24 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
226260 uint32_t block_count ;
227261 uint16_t block_size ;
228262
229- tud_msc_capacity_cb (p_cbw -> lun , & block_count , & block_size );
230- read_fmt_capa .block_num = ENDIAN_BE (block_count );
231- read_fmt_capa .block_size_u16 = ENDIAN_BE16 (block_size );
263+ tud_msc_capacity_cb (lun , & block_count , & block_size );
264+
265+ // Invalid block size/count from callback, possibly unit is not ready
266+ // stall this request, set sense key to NOT READY
267+ if (block_count == 0 || block_size == 0 )
268+ {
269+ resplen = -1 ;
232270
233- ret = sizeof (read_fmt_capa );
234- memcpy (buffer , & read_fmt_capa , ret );
271+ // If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
272+ if ( _mscd_itf .sense_key == 0 ) tud_msc_set_sense (lun , SCSI_SENSE_NOT_READY , 0x04 , 0x00 );
273+ }else
274+ {
275+ read_fmt_capa .block_num = ENDIAN_BE (block_count );
276+ read_fmt_capa .block_size_u16 = ENDIAN_BE16 (block_size );
277+
278+ resplen = sizeof (read_fmt_capa );
279+ memcpy (buffer , & read_fmt_capa , resplen );
280+ }
235281 }
236282 break ;
237283
@@ -242,23 +288,17 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
242288 .is_removable = 1 ,
243289 .version = 2 ,
244290 .response_data_format = 2 ,
245- // vendor_id, product_id, product_rev is space padded string
246- .vendor_id = "" ,
247- .product_id = "" ,
248- .product_rev = "" ,
249291 };
250292
251- memset (inquiry_rsp .vendor_id , ' ' , sizeof (inquiry_rsp .vendor_id ));
252- memcpy (inquiry_rsp .vendor_id , CFG_TUD_MSC_VENDOR , tu_min32 (strlen (CFG_TUD_MSC_VENDOR ), sizeof (inquiry_rsp .vendor_id )));
253-
254- memset (inquiry_rsp .product_id , ' ' , sizeof (inquiry_rsp .product_id ));
255- memcpy (inquiry_rsp .product_id , CFG_TUD_MSC_PRODUCT , tu_min32 (strlen (CFG_TUD_MSC_PRODUCT ), sizeof (inquiry_rsp .product_id )));
256-
293+ // vendor_id, product_id, product_rev is space padded string
294+ memset (inquiry_rsp .vendor_id , ' ' , sizeof (inquiry_rsp .vendor_id ));
295+ memset (inquiry_rsp .product_id , ' ' , sizeof (inquiry_rsp .product_id ));
257296 memset (inquiry_rsp .product_rev , ' ' , sizeof (inquiry_rsp .product_rev ));
258- memcpy (inquiry_rsp .product_rev , CFG_TUD_MSC_PRODUCT_REV , tu_min32 (strlen (CFG_TUD_MSC_PRODUCT_REV ), sizeof (inquiry_rsp .product_rev )));
259297
260- ret = sizeof (inquiry_rsp );
261- memcpy (buffer , & inquiry_rsp , ret );
298+ tud_msc_inquiry_cb (lun , inquiry_rsp .vendor_id , inquiry_rsp .product_id , inquiry_rsp .product_rev );
299+
300+ resplen = sizeof (inquiry_rsp );
301+ memcpy (buffer , & inquiry_rsp , resplen );
262302 }
263303 break ;
264304
@@ -275,12 +315,12 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
275315
276316 bool writable = true;
277317 if (tud_msc_is_writable_cb ) {
278- writable = tud_msc_is_writable_cb (p_cbw -> lun );
318+ writable = tud_msc_is_writable_cb (lun );
279319 }
280320 mode_resp .write_protected = !writable ;
281321
282- ret = sizeof (mode_resp );
283- memcpy (buffer , & mode_resp , ret );
322+ resplen = sizeof (mode_resp );
323+ memcpy (buffer , & mode_resp , resplen );
284324 }
285325 break ;
286326
@@ -298,18 +338,18 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
298338 sense_rsp .add_sense_code = _mscd_itf .add_sense_code ;
299339 sense_rsp .add_sense_qualifier = _mscd_itf .add_sense_qualifier ;
300340
301- ret = sizeof (sense_rsp );
302- memcpy (buffer , & sense_rsp , ret );
341+ resplen = sizeof (sense_rsp );
342+ memcpy (buffer , & sense_rsp , resplen );
303343
304344 // Clear sense data after copy
305- tud_msc_set_sense (p_cbw -> lun , 0 , 0 , 0 );
345+ tud_msc_set_sense (lun , 0 , 0 , 0 );
306346 }
307347 break ;
308348
309- default : ret = -1 ; break ;
349+ default : resplen = -1 ; break ;
310350 }
311351
312- return ret ;
352+ return resplen ;
313353}
314354
315355bool mscd_xfer_cb (uint8_t rhport , uint8_t ep_addr , xfer_result_t event , uint32_t xferred_bytes )
@@ -348,60 +388,50 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
348388 else
349389 {
350390 // For other SCSI commands
351- // 1. Zero : Invoke app callback, skip DATA and move to STATUS stage
352- // 2. OUT : queue transfer (invoke app callback after done)
353- // 3. IN : invoke app callback to get response
354- if ( p_cbw -> total_bytes == 0 )
391+ // 1. OUT : queue transfer (invoke app callback after done)
392+ // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
393+ if ( (p_cbw -> total_bytes > 0 ) && !TU_BIT_TEST (p_cbw -> dir , 7 ) )
355394 {
356- int32_t const cb_result = tud_msc_scsi_cb (p_cbw -> lun , p_cbw -> command , NULL , 0 );
357-
358- p_msc -> total_len = 0 ;
359- p_msc -> stage = MSC_STAGE_STATUS ;
360-
361- if ( cb_result < 0 )
362- {
363- p_csw -> status = MSC_CSW_STATUS_FAILED ;
364- tud_msc_set_sense (p_cbw -> lun , SCSI_SENSE_ILLEGAL_REQUEST , 0x20 , 0x00 ); // Sense = Invalid Command Operation
365- }
366- else
367- {
368- p_csw -> status = MSC_CSW_STATUS_PASSED ;
369- }
370- }
371- else if ( !TU_BIT_TEST (p_cbw -> dir , 7 ) )
372- {
373- // OUT transfer
395+ // queue transfer
374396 TU_ASSERT ( dcd_edpt_xfer (rhport , p_msc -> ep_out , _mscd_buf , p_msc -> total_len ) );
375- }
376- else
397+ }else
377398 {
378- // IN Transfer
379- int32_t cb_result ;
399+ int32_t resplen ;
380400
381- // first process if it is a built-in commands
382- cb_result = proc_builtin_scsi (p_cbw , _mscd_buf , sizeof (_mscd_buf ));
401+ // First process if it is a built-in commands
402+ resplen = proc_builtin_scsi (p_cbw -> lun , p_cbw -> command , _mscd_buf , sizeof (_mscd_buf ));
383403
384- // Not an built-in command , invoke user callback
385- if ( cb_result < 0 )
404+ // Not built-in, invoke user callback
405+ if ( ( resplen < 0 ) && ( p_msc -> sense_key == 0 ) )
386406 {
387- cb_result = tud_msc_scsi_cb (p_cbw -> lun , p_cbw -> command , _mscd_buf , p_msc -> total_len );
407+ resplen = tud_msc_scsi_cb (p_cbw -> lun , p_cbw -> command , _mscd_buf , p_msc -> total_len );
388408 }
389409
390- if ( cb_result > 0 )
391- {
392- p_msc -> total_len = (uint32_t ) cb_result ;
393- p_csw -> status = MSC_CSW_STATUS_PASSED ;
394-
395- TU_ASSERT ( p_cbw -> total_bytes >= p_msc -> total_len ); // cannot return more than host expect
396- TU_ASSERT ( dcd_edpt_xfer (rhport , p_msc -> ep_in , _mscd_buf , p_msc -> total_len ) );
397- }else
410+ if ( resplen < 0 )
398411 {
399412 p_msc -> total_len = 0 ;
400413 p_csw -> status = MSC_CSW_STATUS_FAILED ;
401414 p_msc -> stage = MSC_STAGE_STATUS ;
402415
403- tud_msc_set_sense (p_cbw -> lun , SCSI_SENSE_ILLEGAL_REQUEST , 0x20 , 0x00 ); // Sense = Invalid Command Operation
404- usbd_edpt_stall (rhport , p_msc -> ep_in );
416+ // failed but senskey is not set: default to Illegal Request
417+ if ( p_msc -> sense_key == 0 ) tud_msc_set_sense (p_cbw -> lun , SCSI_SENSE_ILLEGAL_REQUEST , 0x20 , 0x00 );
418+
419+ /// Stall bulk In if needed
420+ if (p_cbw -> total_bytes ) usbd_edpt_stall (rhport , p_msc -> ep_in );
421+ }
422+ else
423+ {
424+ p_msc -> total_len = (uint32_t ) resplen ;
425+ p_csw -> status = MSC_CSW_STATUS_PASSED ;
426+
427+ if (p_msc -> total_len )
428+ {
429+ TU_ASSERT ( p_cbw -> total_bytes >= p_msc -> total_len ); // cannot return more than host expect
430+ TU_ASSERT ( dcd_edpt_xfer (rhport , p_msc -> ep_in , _mscd_buf , p_msc -> total_len ) );
431+ }else
432+ {
433+ p_msc -> stage = MSC_STAGE_STATUS ;
434+ }
405435 }
406436 }
407437 }
0 commit comments