예제 #1
0
파일: usb_ms_scsi.c 프로젝트: longsleep/ec
static void scsi_mode_sense6(uint8_t *block, uint8_t in_len)
{
	uint8_t response[4];

	if (state == USB_MS_SCSI_STATE_PARSE) {
		state = USB_MS_SCSI_STATE_DATA_OUT;

		/* terminate if fail to verify */
		if (scsi_verify_cdb6(block, in_len))
			return;

		/* response exceeds allocation length */
		if (block[4] < sizeof(response))
			return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);

		memset(response, 0, sizeof(response));
		/* set WP bit if necessary */
		response[2] = spi_flash_check_protect(0,
			CONFIG_SPI_FLASH_SIZE) ?
			(1 << 7) : 0;

		memcpy_usbram(ms_ep_tx, (uint8_t *) response,
			sizeof(response));
		btable_ep[USB_EP_MS_TX].tx_count = sizeof(response);
	} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
		state = USB_MS_SCSI_STATE_REPLY;

	return scsi_sense_code(SCSI_SENSE_NO_SENSE,
		SCSI_SENSE_CODE_NONE);
}
예제 #2
0
/**
 * Return flash protect state flags from the physical layer.
 *
 * This should only be called by flash_get_protect().
 *
 * Uses the EC_FLASH_PROTECT_* flags from ec_commands.h
 */
uint32_t flash_physical_get_protect_flags(void)
{
	uint32_t flags = 0;

	if (spi_flash_check_protect(CONFIG_WP_STORAGE_OFF,
				    CONFIG_WP_STORAGE_SIZE)) {
		flags |= EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW;
	}

	if (entire_flash_locked)
		flags |= EC_FLASH_PROTECT_ALL_NOW;

	return flags;
}
예제 #3
0
/**
 * Read physical write protect setting for a flash bank.
 *
 * @param bank    Bank index to check.
 * @return        non-zero if bank is protected until reboot.
 */
int flash_physical_get_protect(int bank)
{
	return spi_flash_check_protect(bank * CONFIG_FLASH_BANK_SIZE,
			CONFIG_FLASH_BANK_SIZE);
}
예제 #4
0
파일: usb_ms_scsi.c 프로젝트: longsleep/ec
/*
 * Required by SPC-4.
 */
static void scsi_write10(uint8_t *block, uint8_t in_len)
{
	int rv;
	int write_len;

	if (state == USB_MS_SCSI_STATE_PARSE) {
		state = USB_MS_SCSI_STATE_DATA_IN;

		/* terminate if fail to verify */
		if (scsi_verify_cdb10(block, in_len))
			return;

		/* RELADR bit not supported */
		if (block[1] & 0x1)
			return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);

		buffer = 0;
		offset = SCSI_BLOCK_SIZE_BYTES *
			(block[2] << 24 | block[3] << 16 |
				block[4] << 8 | block[5]);
		bytes = SCSI_BLOCK_SIZE_BYTES * (block[7] << 8 | block[8]);

		/* Chip has protection */
		if (spi_flash_check_protect(offset, bytes))
			return scsi_sense_code(SCSI_SENSE_DATA_PROTECT,
				SCSI_SENSE_CODE_WRITE_PROTECTED);

		/* Wait for any previous operation to complete */
		rv = spi_flash_wait();
		if (rv == EC_ERROR_TIMEOUT)
			return scsi_sense_code(
				SCSI_SENSE_HARDWARE_ERROR,
				SCSI_SENSE_CODE_TIMEOUT);

		rv = spi_flash_erase(offset, bytes);
		/* invalid address */
		if (rv == EC_ERROR_INVAL)
			return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
		else if (rv != EC_SUCCESS)
			return scsi_sense_code(SCSI_SENSE_HARDWARE_ERROR,
				SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);
	} else if (state == USB_MS_SCSI_STATE_DATA_IN) {
		/* write whatever was received */
		write_len = MIN(bytes,
			btable_ep[USB_EP_MS_RX].rx_count & 0x3ff);
		ASSERT(write_len <= SPI_FLASH_MAX_WRITE_SIZE);

#if CONFIG_USB_MS_BUFFER_SIZE != USB_MS_PACKET_SIZE
		/* perform write only when local buffer is over full */
		if (buffer + write_len > CONFIG_USB_MS_BUFFER_SIZE) {
			/* Wait for previous operation to complete */
			rv = spi_flash_wait();
			if (rv == EC_ERROR_TIMEOUT)
				return scsi_sense_code(
					SCSI_SENSE_HARDWARE_ERROR,
					SCSI_SENSE_CODE_TIMEOUT);

			rv = spi_flash_write(offset,
				CONFIG_USB_MS_BUFFER_SIZE, temp_buf);
			if (rv == EC_ERROR_INVAL)
				return scsi_sense_code(
					SCSI_SENSE_ILLEGAL_REQUEST,
					SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
			else if (rv != EC_SUCCESS)
				return scsi_sense_code(
					SCSI_SENSE_HARDWARE_ERROR,
					SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);

			offset += buffer;
			bytes -= buffer;

			buffer = 0;
		}

		/* copy data to local buffer */
		memcpy(temp_buf + buffer, (uint8_t *) ms_ep_rx, write_len);
		buffer += write_len;

		/* on last write */
		if (bytes == buffer) {
			/* Wait for previous operation to complete */
			rv = spi_flash_wait();
			if (rv == EC_ERROR_TIMEOUT)
				return scsi_sense_code(
					SCSI_SENSE_HARDWARE_ERROR,
					SCSI_SENSE_CODE_TIMEOUT);

			rv = spi_flash_write(offset, buffer, temp_buf);
			if (rv == EC_ERROR_INVAL)
				return scsi_sense_code(
					SCSI_SENSE_ILLEGAL_REQUEST,
					SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
			else if (rv == EC_ERROR_ACCESS_DENIED)
				return scsi_sense_code(SCSI_SENSE_DATA_PROTECT,
					SCSI_SENSE_CODE_WRITE_PROTECTED);
			else if (rv != EC_SUCCESS)
				return scsi_sense_code(
					SCSI_SENSE_HARDWARE_ERROR,
					SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);

			/* Wait for last write to complete */
			rv = spi_flash_wait();
			if (rv == EC_ERROR_TIMEOUT)
				return scsi_sense_code(
					SCSI_SENSE_HARDWARE_ERROR,
					SCSI_SENSE_CODE_TIMEOUT);

			offset += buffer;
			bytes -= buffer;

			buffer = 0;
		/* received too much data */
		} else if (bytes < buffer)
			return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
#else
		memcpy(temp_buf, (uint8_t *) ms_ep_rx, write_len);

		/* Wait for previous operation to complete */
		rv = spi_flash_wait();
		if (rv == EC_ERROR_TIMEOUT)
			return scsi_sense_code(
				SCSI_SENSE_HARDWARE_ERROR,
				SCSI_SENSE_CODE_TIMEOUT);

		rv = spi_flash_write(offset, write_len, temp_buf);
		if (rv == EC_ERROR_INVAL)
			return scsi_sense_code(
				SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
		else if (rv == EC_ERROR_ACCESS_DENIED)
			return scsi_sense_code(SCSI_SENSE_DATA_PROTECT,
				SCSI_SENSE_CODE_WRITE_PROTECTED);
		else if (rv != EC_SUCCESS)
			return scsi_sense_code(
				SCSI_SENSE_HARDWARE_ERROR,
				SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);

		offset += write_len;
		bytes -= write_len;
#endif

		/* nothing left to write */
		if (!bytes)
			state = USB_MS_SCSI_STATE_REPLY;
	}
	return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}