예제 #1
0
static bool_t msc_decode(USBDriver *usbp) {
  uint32_t nblocks, secsize;

  switch (CBW.CBWCB[0]) {
  case SCSI_REQUEST_SENSE:
    break;
  case SCSI_INQUIRY:
    msc_transmit(usbp, (uint8_t *)&scsi_inquiry_data,
                 sizeof scsi_inquiry_data);
    CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
    break;
  case SCSI_READ_FORMAT_CAPACITIES:
    buf[8]  = scsi_read_format_capacities(&nblocks, &secsize);
    buf[0]  = buf[1] = buf[2] = 0;
    buf[3]  = 8;
    buf[4]  = (uint8_t)(nblocks >> 24);
    buf[5]  = (uint8_t)(nblocks >> 16);
    buf[6]  = (uint8_t)(nblocks >> 8);
    buf[7]  = (uint8_t)(nblocks >> 0);
    buf[9]  = (uint8_t)(secsize >> 16);
    buf[10] = (uint8_t)(secsize >> 8);
    buf[11] = (uint8_t)(secsize >> 0);
    msc_transmit(usbp, buf, 12);
    CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
    break;
  default:
    return TRUE;
  }
  return FALSE;
}
예제 #2
0
파일: usb-msc.c 프로젝트: ggkitsas/gnuk
void
msc_handle_command (void)
{
  size_t n;
  uint32_t nblocks, secsize;
  uint32_t lba;
  int r;

  chopstx_mutex_lock (msc_mutex);
  msc_state = MSC_IDLE;
  usb_start_receive ((uint8_t *)&CBW, sizeof CBW);
  chopstx_cond_wait (msc_cond, msc_mutex);

  if (msg != RDY_OK)
    {
      /* Error occured, ignore the request and go into error state */
      msc_state = MSC_ERROR;
      usb_lld_stall_rx (ENDP6);
      goto done;
    }

  n = ep6_out.rxcnt;

  if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
    {
      msc_state = MSC_ERROR;
      usb_lld_stall_rx (ENDP6);
      goto done;
    }

  CSW.dCSWTag = CBW.dCBWTag;
  switch (CBW.CBWCB[0]) {
  case SCSI_REPORT_LUN:
    buf[0]  = buf[1] = buf[2] = buf[3] = 0;
    buf[4]  = buf[5] = buf[6] = buf[7] = 0;
    msc_send_result (buf, 8);
    goto done;
  case SCSI_REQUEST_SENSE:
    if (CBW.CBWCB[1] & 0x01) /* DESC */
      msc_send_result ((uint8_t *)&scsi_sense_data_desc,
		       sizeof scsi_sense_data_desc);
    else
      msc_send_result ((uint8_t *)&scsi_sense_data_fixed,
		       sizeof scsi_sense_data_fixed);
    /* After the error is reported, clear it, if it's .  */
    if (!keep_contingent_allegiance)
      {
	contingent_allegiance = 0;
	set_scsi_sense_data (0x00, 0x00);
      }
    goto done;
  case SCSI_INQUIRY:
    if (CBW.CBWCB[1] & 0x01)
      /* EVPD */
      {
	if (CBW.CBWCB[2] == 0x83)
	  /* Handle the case Page Code 0x83 */
	  msc_send_result ((uint8_t *)&scsi_inquiry_data_83,
			   sizeof scsi_inquiry_data_83);
	else
	  /* Otherwise, assume page 00 */
	  msc_send_result ((uint8_t *)&scsi_inquiry_data_00,
			   sizeof scsi_inquiry_data_00);
      }
    else
      msc_send_result ((uint8_t *)&scsi_inquiry_data,
		       sizeof scsi_inquiry_data);
    goto done;
  case SCSI_READ_FORMAT_CAPACITIES:
    buf[8]  = scsi_read_format_capacities (&nblocks, &secsize);
    buf[0]  = buf[1] = buf[2] = 0;
    buf[3]  = 8;
    buf[4]  = (uint8_t)(nblocks >> 24);
    buf[5]  = (uint8_t)(nblocks >> 16);
    buf[6]  = (uint8_t)(nblocks >> 8);
    buf[7]  = (uint8_t)(nblocks >> 0);
    buf[9]  = (uint8_t)(secsize >> 16);
    buf[10] = (uint8_t)(secsize >> 8);
    buf[11] = (uint8_t)(secsize >> 0);
    msc_send_result (buf, 12);
    goto done;
  case SCSI_START_STOP_UNIT:
    if (CBW.CBWCB[4] == 0x00 /* stop */
	|| CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
      {
	msc_scsi_stop (CBW.CBWCB[4]);
	set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */
	contingent_allegiance = 1;
	keep_contingent_allegiance = 1;
      }
    /* CBW.CBWCB[4] == 0x01 *//* start */
    goto success;
  case SCSI_TEST_UNIT_READY:
    if (contingent_allegiance)
      {
	CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
	CSW.dCSWDataResidue = 0;
	msc_send_result (NULL, 0);
	goto done;
      }
    /* fall through */
  success:
  case SCSI_SYNCHRONIZE_CACHE:
  case SCSI_VERIFY10:
  case SCSI_ALLOW_MEDIUM_REMOVAL:
    CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
    CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
    msc_send_result (NULL, 0);
    goto done;
  case SCSI_MODE_SENSE6:
    buf[0] = 0x03;
    buf[1] = buf[2] = buf[3] = 0;
    msc_send_result (buf, 4);
    goto done;
  case SCSI_READ_CAPACITY10:
    scsi_read_format_capacities (&nblocks, &secsize);
    buf[0]  = (uint8_t)((nblocks - 1) >> 24);
    buf[1]  = (uint8_t)((nblocks - 1) >> 16);
    buf[2]  = (uint8_t)((nblocks - 1) >> 8);
    buf[3]  = (uint8_t)((nblocks - 1) >> 0);
    buf[4]  = (uint8_t)(secsize >> 24);
    buf[5]  = (uint8_t)(secsize >> 16);
    buf[6] = (uint8_t)(secsize >> 8);
    buf[7] = (uint8_t)(secsize >> 0);
    msc_send_result (buf, 8);
    goto done;
  case SCSI_READ10:
  case SCSI_WRITE10:
    break;
  default:
    if (CBW.dCBWDataTransferLength == 0)
      {
	CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
	CSW.dCSWDataResidue = 0;
	msc_send_result (NULL, 0);
	goto done;
      }
    else
      {
	msc_state = MSC_ERROR;
	usb_lld_stall_tx (ENDP6);
	usb_lld_stall_rx (ENDP6);
	goto done;
      }
  }

  lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16)
      | (CBW.CBWCB[4] <<  8) | CBW.CBWCB[5];

  /* Transfer direction.*/
  if (CBW.bmCBWFlags & 0x80)
    {
      /* IN, Device to Host.*/
      msc_state = MSC_DATA_IN;
      if (CBW.CBWCB[0] == SCSI_READ10)
	{
	  const uint8_t *p;

	  CSW.dCSWDataResidue = 0;
	  while (1)
	    {
	      if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0)
		{
		  CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
		  break;
		}

	      if ((r = msc_scsi_read (lba, &p)) == 0)
		{
		  msc_send_data (p, 512);
		  if (++CBW.CBWCB[5] == 0)
		    if (++CBW.CBWCB[4] == 0)
		      if (++CBW.CBWCB[3] == 0)
			++CBW.CBWCB[2];
		  if (CBW.CBWCB[8]-- == 0)
		    CBW.CBWCB[7]--;
		  CSW.dCSWDataResidue += 512;
		  lba++;
		}
	      else
		{
		  CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
		  contingent_allegiance = 1;
		  if (r == SCSI_ERROR_NOT_READY)
		    set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
		  else
		    set_scsi_sense_data (r, 0x00);
		  break;
		}
	    }

	  msc_send_result (NULL, 0);
	}
    }
  else
    {
      /* OUT, Host to Device.*/
      if (CBW.CBWCB[0] == SCSI_WRITE10)
	{
	  CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;

	  while (1)
	    {
	      if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0)
		{
		  CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
		  break;
		}

	      msc_recv_data ();
	      if (msg != RDY_OK)
		/* ignore erroneous packet, ang go next.  */
		continue;

	      if ((r = msc_scsi_write (lba, buf, 512)) == 0)
		{
		  if (++CBW.CBWCB[5] == 0)
		    if (++CBW.CBWCB[4] == 0)
		      if (++CBW.CBWCB[3] == 0)
			++CBW.CBWCB[2];
		  if (CBW.CBWCB[8]-- == 0)
		    CBW.CBWCB[7]--;
		  CSW.dCSWDataResidue -= 512;
		  lba++;
		}
	      else
		{
		  CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
		  contingent_allegiance = 1;
		  if (r == SCSI_ERROR_NOT_READY)
		    set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
		  else
		    set_scsi_sense_data (r, 0x00);
		  break;
		}
	    }

	  msc_send_result (NULL, 0);
	}
    }

 done:
  chopstx_mutex_unlock (msc_mutex);
}
예제 #3
0
파일: usb_ms_scsi.c 프로젝트: longsleep/ec
int scsi_parse(uint8_t *block, uint8_t in_len)
{
	/* set new operation */
	if (state == USB_MS_SCSI_STATE_IDLE) {
		state = USB_MS_SCSI_STATE_PARSE;

		op = block[0];
	}

	/* skip operation if sending reply */
	if (state != USB_MS_SCSI_STATE_REPLY) {
		switch (op) {
		case SCSI_INQUIRY:
			scsi_inquiry(block, in_len);
		break;
		case SCSI_MODE_SENSE6:
			scsi_mode_sense6(block, in_len);
		break;
		case SCSI_READ10:
			scsi_read10(block, in_len);
		break;
		case SCSI_READ_CAPACITY10:
			scsi_read_capacity10(block, in_len);
		break;
		case SCSI_READ_FORMAT_CAPACITIES:
			scsi_read_format_capacities(block, in_len);
		break;
		case SCSI_REPORT_LUNS:
			scsi_report_luns(block, in_len);
		break;
		case SCSI_REQUEST_SENSE:
			scsi_request_sense(block, in_len);
		break;
		case SCSI_START_STOP_UNIT:
			scsi_start_stop_unit(block, in_len);
		break;
		case SCSI_SYNCHRONIZE_CACHE10:
			scsi_synchronize_cache10(block, in_len);
		break;
		case SCSI_TEST_UNIT_READY:
			scsi_test_unit_ready(block, in_len);
		break;
		case SCSI_WRITE10:
			scsi_write10(block, in_len);
		break;
		default:
			state = USB_MS_SCSI_STATE_REPLY;
			scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_INVALID_COMMAND_OPERATION_CODE);
		break;
		}
	}

	/* error during data rx/tx */
	if (((state == USB_MS_SCSI_STATE_DATA_OUT) ||
			(state == USB_MS_SCSI_STATE_DATA_IN)) &&
			scsi_sense_data.key) {
		btable_ep[USB_EP_MS_TX].tx_count = 0;
		state = USB_MS_SCSI_STATE_REPLY;
		return SCSI_STATUS_CONTINUE;
	}

	/* done sending data */
	if (state == USB_MS_SCSI_STATE_REPLY) {
		state = USB_MS_SCSI_STATE_IDLE;
		return scsi_sense_data.key;
	}

	/* still sending/receiving data and no error has occurred */
	return SCSI_STATUS_CONTINUE;
}