Beispiel #1
0
static status_t
usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount,
	void *buffer, size_t *length)
{
	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_WRITE_12;
	commandBlock[1] = lun->logical_unit_number << 5;
	commandBlock[2] = blockPosition >> 24;
	commandBlock[3] = blockPosition >> 16;
	commandBlock[4] = blockPosition >> 8;
	commandBlock[5] = blockPosition;
	commandBlock[6] = blockCount >> 24;
	commandBlock[7] = blockCount >> 16;
	commandBlock[8] = blockCount >> 8;
	commandBlock[9] = blockCount;

	status_t result;
	result = usb_disk_operation(lun, commandBlock, buffer, length,
		false);

	int retry = 10;
	while (result == B_DEV_NO_MEDIA && retry > 0) {
		snooze(10000);
		result = usb_disk_request_sense(lun);
		retry--;
	}

	if (result == B_OK)
		lun->should_sync = true;
	return result;
}
Beispiel #2
0
status_t
usb_disk_inquiry(device_lun *lun)
{
	uint32 dataLength = sizeof(scsi_inquiry_6_parameter);
	scsi_inquiry_6_parameter parameter;
	status_t result = B_ERROR;
	for (uint32 tries = 0; tries < 3; tries++) {
		result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength,
			&parameter, &dataLength, true);
		if (result == B_OK)
			break;
	}
	if (result != B_OK) {
		TRACE_ALWAYS("getting inquiry data failed\n");
		lun->device_type = B_DISK;
		lun->removable = true;
		return result;
	}

	TRACE("peripherial_device_type  0x%02x\n", parameter.peripherial_device_type);
	TRACE("peripherial_qualifier    0x%02x\n", parameter.peripherial_qualifier);
	TRACE("removable_medium         %s\n", parameter.removable_medium ? "yes" : "no");
	TRACE("version                  0x%02x\n", parameter.version);
	TRACE("response_data_format     0x%02x\n", parameter.response_data_format);	
	TRACE_ALWAYS("vendor_identification    \"%.8s\"\n", parameter.vendor_identification);	
	TRACE_ALWAYS("product_identification   \"%.16s\"\n", parameter.product_identification);	
	TRACE_ALWAYS("product_revision_level   \"%.4s\"\n", parameter.product_revision_level);	
	lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */
	lun->removable = (parameter.removable_medium == 1);
	return B_OK;
}
Beispiel #3
0
status_t
usb_disk_update_capacity(device_lun *lun)
{
	uint32 dataLength = sizeof(scsi_read_capacity_10_parameter);
	scsi_read_capacity_10_parameter parameter;
	status_t result = B_ERROR;

	// Retry reading the capacity up to three times. The first try might only
	// yield a unit attention telling us that the device or media status
	// changed, which is more or less expected if it is the first operation
	// on the device or the device only clears the unit atention for capacity
	// reads.
	for (int32 i = 0; i < 3; i++) {
		result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0,
			&parameter, &dataLength, true);
		if (result == B_OK)
			break;
	}

	if (result != B_OK) {
		TRACE_ALWAYS("failed to update capacity\n");
		lun->media_present = false;
		lun->media_changed = false;
		usb_disk_reset_capacity(lun);
		return result;
	}

	lun->media_present = true;
	lun->media_changed = false;
	lun->block_size = ntohl(parameter.logical_block_length);
	lun->block_count = ntohl(parameter.last_logical_block_address) + 1;
	return B_OK;
}
Beispiel #4
0
status_t
usb_disk_synchronize(device_lun *lun, bool force)
{
	if (lun->device->sync_support == 0) {
		// this device reported an illegal request when syncing or repeatedly
		// returned an other error, it apparently does not support syncing...
		return B_UNSUPPORTED;
	}

	if (!lun->should_sync && !force)
		return B_OK;

	status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10,
		0, 0, NULL, NULL, false);

	if (result == B_OK) {
		lun->device->sync_support = SYNC_SUPPORT_RELOAD;
		lun->should_sync = false;
		return B_OK;
	}

	if (result == B_DEV_INVALID_IOCTL)
		lun->device->sync_support = 0;
	else
		lun->device->sync_support--;

	return result;
}
Beispiel #5
0
status_t
usb_disk_mode_sense(device_lun *lun)
{
	uint32 dataLength = sizeof(scsi_mode_sense_6_parameter);

	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_MODE_SENSE_6;
	commandBlock[1] = lun->logical_unit_number << 5;
	commandBlock[2] = 0; // Current values
	commandBlock[7] = dataLength >> 8;
	commandBlock[8] = dataLength;

	scsi_mode_sense_6_parameter parameter;
	status_t result = usb_disk_operation(lun, commandBlock,
		&parameter, &dataLength, true);
	if (result != B_OK) {
		TRACE_ALWAYS("getting mode sense data failed\n");
		return result;
	}

	lun->write_protected
		= (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) != 0;
	TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no");
	return B_OK;
}
Beispiel #6
0
static status_t
usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount,
	void *buffer, size_t *length)
{
	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_READ_12;
	commandBlock[1] = lun->logical_unit_number << 5;
	commandBlock[2] = blockPosition >> 24;
	commandBlock[3] = blockPosition >> 16;
	commandBlock[4] = blockPosition >> 8;
	commandBlock[5] = blockPosition;
	commandBlock[6] = blockCount >> 24;
	commandBlock[7] = blockCount >> 16;
	commandBlock[8] = blockCount >> 8;
	commandBlock[9] = blockCount;

	status_t result = B_OK;
	for (int tries = 0; tries < 5; tries++) {
		result = usb_disk_operation(lun, commandBlock, buffer, length,
			true);
		if (result == B_OK)
			break;
		else
			snooze(10000);
	}
	return result;
}
Beispiel #7
0
static status_t
usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount,
	void *buffer, size_t *length)
{
	status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition,
		blockCount, buffer, length, true);
	return result;
}
Beispiel #8
0
status_t
usb_disk_inquiry(device_lun *lun)
{
	size_t dataLength = sizeof(scsi_inquiry_6_parameter);

	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_INQUIRY_6;
	commandBlock[1] = lun->logical_unit_number << 5;
	commandBlock[2] = 0; // page code
	commandBlock[4] = dataLength;

	scsi_inquiry_6_parameter parameter;
	status_t result = B_ERROR;
	for (uint32 tries = 0; tries < 3; tries++) {
		result = usb_disk_operation(lun, commandBlock, &parameter, &dataLength,
			true);
		if (result == B_OK)
			break;
	}
	if (result != B_OK) {
		TRACE_ALWAYS("getting inquiry data failed\n");
		lun->device_type = B_DISK;
		lun->removable = true;
		return result;
	}

	TRACE("peripherial_device_type  0x%02x\n",
		parameter.peripherial_device_type);
	TRACE("peripherial_qualifier    0x%02x\n",
		parameter.peripherial_qualifier);
	TRACE("removable_medium         %s\n",
		parameter.removable_medium ? "yes" : "no");
	TRACE("version                  0x%02x\n", parameter.version);
	TRACE("response_data_format     0x%02x\n", parameter.response_data_format);
	TRACE_ALWAYS("vendor_identification    \"%.8s\"\n",
		parameter.vendor_identification);
	TRACE_ALWAYS("product_identification   \"%.16s\"\n",
		parameter.product_identification);
	TRACE_ALWAYS("product_revision_level   \"%.4s\"\n",
		parameter.product_revision_level);

	memcpy(lun->vendor_name, parameter.vendor_identification,
		MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification)));
	memcpy(lun->product_name, parameter.product_identification,
		MIN(sizeof(lun->product_name),
			sizeof(parameter.product_identification)));
	memcpy(lun->product_revision, parameter.product_revision_level,
		MIN(sizeof(lun->product_revision),
			sizeof(parameter.product_revision_level)));

	lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */
	lun->removable = (parameter.removable_medium == 1);
	return B_OK;
}
Beispiel #9
0
static status_t
usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount,
	void *buffer, size_t *length)
{
	status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition,
		blockCount, buffer, length, false);
	if (result == B_OK)
		lun->should_sync = true;
	return result;
}
Beispiel #10
0
status_t
usb_disk_inquiry(device_lun *lun)
{
	size_t dataLength = sizeof(scsi_inquiry_6_parameter);
	scsi_inquiry_6_parameter parameter;
	status_t result = B_ERROR;
	err_act action = err_act_ok;
	for (uint32 tries = 0; tries < 3; tries++) {
		result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength,
			&parameter, &dataLength, true, &action);
		if (result == B_OK || (action != err_act_retry
				&& action != err_act_many_retries)) {
			break;
		}
	}
	if (result != B_OK) {
		TRACE_ALWAYS("getting inquiry data failed: %s\n", strerror(result));
		lun->device_type = B_DISK;
		lun->removable = true;
		return result;
	}

	TRACE("peripherial_device_type  0x%02x\n",
		parameter.peripherial_device_type);
	TRACE("peripherial_qualifier    0x%02x\n",
		parameter.peripherial_qualifier);
	TRACE("removable_medium         %s\n",
		parameter.removable_medium ? "yes" : "no");
	TRACE("version                  0x%02x\n", parameter.version);
	TRACE("response_data_format     0x%02x\n", parameter.response_data_format);
	TRACE_ALWAYS("vendor_identification    \"%.8s\"\n",
		parameter.vendor_identification);
	TRACE_ALWAYS("product_identification   \"%.16s\"\n",
		parameter.product_identification);
	TRACE_ALWAYS("product_revision_level   \"%.4s\"\n",
		parameter.product_revision_level);

	memcpy(lun->vendor_name, parameter.vendor_identification,
		MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification)));
	memcpy(lun->product_name, parameter.product_identification,
		MIN(sizeof(lun->product_name),
			sizeof(parameter.product_identification)));
	memcpy(lun->product_revision, parameter.product_revision_level,
		MIN(sizeof(lun->product_revision),
			sizeof(parameter.product_revision_level)));

	lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */
	lun->removable = (parameter.removable_medium == 1);
	return B_OK;
}
Beispiel #11
0
status_t
usb_disk_test_unit_ready(device_lun *lun)
{
	// if unsupported we assume the unit is fixed and therefore always ok
	if (!lun->device->tur_supported)
		return B_OK;

	status_t result;
	if (lun->device->is_atapi) {
		result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 1,
			NULL, NULL, false);
	} else {
		result = usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0,
			NULL, NULL, true);
	}

	if (result == B_DEV_INVALID_IOCTL) {
		lun->device->tur_supported = false;
		return B_OK;
	}

	return result;
}
Beispiel #12
0
status_t
usb_disk_request_sense(device_lun *lun, err_act *_action)
{
	size_t dataLength = sizeof(scsi_request_sense_6_parameter);
	scsi_request_sense_6_parameter parameter;
	status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0,
		dataLength, &parameter, &dataLength, true);
	if (result != B_OK) {
		TRACE_ALWAYS("getting request sense data failed: %s\n",
			strerror(result));
		return result;
	}

	const char *label = NULL;
	err_act action = err_act_fail;
	status_t status = B_ERROR;
	scsi_get_sense_asc_info((parameter.additional_sense_code << 8)
		| parameter.additional_sense_code_qualifier, &label, &action,
		&status);

	if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY
		&& parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
		TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: "
			"0x%02x; %s\n", parameter.sense_key, parameter.additional_sense_code,
			parameter.additional_sense_code_qualifier,
			label ? label : "(unknown)");
	}

	if ((parameter.additional_sense_code == 0
			&& parameter.additional_sense_code_qualifier == 0)
		|| label == NULL) {
		scsi_get_sense_key_info(parameter.sense_key, &label, &action, &status);
	}

	if (status == B_DEV_MEDIA_CHANGED) {
		lun->media_changed = true;
		lun->media_present = true;
	} else if (parameter.sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION
		&& status != B_DEV_NO_MEDIA) {
		lun->media_present = true;
	} else if (status == B_DEV_NOT_READY) {
		lun->media_present = false;
		usb_disk_reset_capacity(lun);
	}

	if (_action != NULL)
		*_action = action;

	return status;
}
Beispiel #13
0
status_t
usb_disk_test_unit_ready(device_lun *lun)
{
	return B_OK;

	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_TEST_UNIT_READY_6;
	commandBlock[1] = lun->logical_unit_number << 5;

	status_t result = usb_disk_operation(lun, commandBlock, NULL, NULL, false);

	return result;
}
Beispiel #14
0
status_t
usb_disk_mode_sense(device_lun *lun)
{
	uint32 dataLength = sizeof(scsi_mode_sense_6_parameter);
	scsi_mode_sense_6_parameter parameter;
	status_t result = usb_disk_operation(lun, SCSI_MODE_SENSE_6, 6,
		SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, &parameter,
		&dataLength, true);
	if (result != B_OK) {
		TRACE_ALWAYS("getting mode sense data failed\n");
		return result;
	}

	lun->write_protected
		= (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) != 0;
	TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no");	
	return B_OK;
}
Beispiel #15
0
status_t
usb_disk_send_diagnostic(device_lun *lun)
{
	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_SEND_DIAGNOSTIC;
	commandBlock[1] = (lun->logical_unit_number << 5) | 4;

	status_t result = usb_disk_operation(lun, commandBlock, NULL,
		NULL, false);

	int retry = 100;
	while(result == B_DEV_NO_MEDIA && retry > 0) {
		snooze(10000);
		result = usb_disk_request_sense(lun);
		retry--;
	}

	if (result != B_OK)
		TRACE("Send Diagnostic failed: %s\n", strerror(result));
	return result;
}
Beispiel #16
0
status_t
usb_disk_update_capacity(device_lun *lun)
{
	uint32 dataLength = sizeof(scsi_read_capacity_10_parameter);
	scsi_read_capacity_10_parameter parameter;
	status_t result = B_ERROR;

	uint8 commandBlock[12];
	memset(commandBlock, 0, sizeof(commandBlock));

	commandBlock[0] = SCSI_READ_CAPACITY_10;
	commandBlock[1] = lun->logical_unit_number << 5;

	for (int tries = 0; tries < 5; tries++) {
		result = usb_disk_operation(lun, commandBlock, &parameter, &dataLength,
			true);
		if (result == B_DEV_NO_MEDIA || result == B_TIMED_OUT
				|| result == B_DEV_STALLED)
			snooze(10000);
		else
			break;
	}

	if (result != B_OK) {
		TRACE_ALWAYS("failed to update capacity\n");
		lun->media_present = false;
		lun->media_changed = false;
		usb_disk_reset_capacity(lun);
		return result;
	}

	lun->media_present = true;
	lun->media_changed = false;
	lun->block_size = ntohl(parameter.logical_block_length);
	lun->block_count = ntohl(parameter.last_logical_block_address) + 1;
	return B_OK;
}
Beispiel #17
0
static status_t
usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
{
	device_lun *lun = (device_lun *)cookie;
	disk_device *device = lun->device;
	mutex_lock(&device->lock);
	if (device->removed) {
		mutex_unlock(&device->lock);
		return B_DEV_NOT_READY;
	}

	status_t result = B_DEV_INVALID_IOCTL;
	switch (op) {
		case B_GET_DEVICE_SIZE: {
			if (lun->media_changed) {
				result = usb_disk_update_capacity(lun);
				if (result != B_OK)
					break;
			}

			size_t size = lun->block_size * lun->block_count;
			result = user_memcpy(buffer, &size, sizeof(size));

			break;
		}
		
		case B_GET_MEDIA_STATUS: {
			*(status_t *)buffer = usb_disk_test_unit_ready(lun);
			TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer);
			result = B_OK;
			break;
		}

		case B_GET_GEOMETRY: {
			if (lun->media_changed) {
				result = usb_disk_update_capacity(lun);
				if (result != B_OK)
					break;
			}

			device_geometry *geometry = (device_geometry *)buffer;
			geometry->bytes_per_sector = lun->block_size;
			geometry->cylinder_count = lun->block_count;
			geometry->sectors_per_track = geometry->head_count = 1;
			geometry->device_type = lun->device_type;
			geometry->removable = lun->removable;
			geometry->read_only = lun->write_protected;
			geometry->write_once = (lun->device_type == B_WORM);
			TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n",
				geometry->cylinder_count, geometry->bytes_per_sector);
			result = B_OK;
			break;
		}

		case B_FLUSH_DRIVE_CACHE:
			TRACE("B_FLUSH_DRIVE_CACHE\n");
			result = usb_disk_synchronize(lun, true);
			break;

		case B_EJECT_DEVICE:
		{
			uint8 commandBlock[12];
			memset(commandBlock, 0, sizeof(commandBlock));

			commandBlock[0] = SCSI_START_STOP_UNIT_6;
			commandBlock[1] = lun->logical_unit_number << 5;
			commandBlock[4] = 2;

			result = usb_disk_operation(lun, commandBlock, NULL, NULL, false);
			break;
		}

		case B_LOAD_MEDIA:
		{
			uint8 commandBlock[12];
			memset(commandBlock, 0, sizeof(commandBlock));

			commandBlock[0] = SCSI_START_STOP_UNIT_6;
			commandBlock[1] = lun->logical_unit_number << 5;
			commandBlock[4] = 3;

			result = usb_disk_operation(lun, commandBlock, NULL, NULL, false);
			break;
		}

#if HAIKU_TARGET_PLATFORM_HAIKU
		case B_GET_ICON:
			// We don't support this legacy ioctl anymore, but the two other
			// icon ioctls below instead.
			break;

		case B_GET_ICON_NAME:
			result = user_strlcpy((char *)buffer,
				"devices/drive-removable-media-usb", B_FILE_NAME_LENGTH);
			break;

		case B_GET_VECTOR_ICON:
		{
			if (length != sizeof(device_icon)) {
				result = B_BAD_VALUE;
				break;
			}

			device_icon iconData;
			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) {
				result = B_BAD_ADDRESS;
				break;
			}

			if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) {
				if (user_memcpy(iconData.icon_data, kDeviceIcon,
						sizeof(kDeviceIcon)) != B_OK) {
					result = B_BAD_ADDRESS;
					break;
				}
			}

			iconData.icon_size = sizeof(kDeviceIcon);
			result = user_memcpy(buffer, &iconData, sizeof(device_icon));
			break;
		}

		case B_GET_DEVICE_NAME:
		{
			size_t nameLength = sizeof(lun->vendor_name)
				+ sizeof(lun->product_name) + sizeof(lun->product_revision) + 3;

			char name[nameLength];
			snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name,
				lun->product_name, lun->product_revision);

			normalize_name(name, nameLength);

			result = user_strlcpy((char *)buffer, name, length);
			if (result > 0)
				result = B_OK;

			TRACE_ALWAYS("got device name: \"%s\" = %s\n", name, strerror(result));
			break;
		}
#endif

		default:
			TRACE_ALWAYS("unhandled ioctl %" B_PRIu32 "\n", op);
			break;
	}

	mutex_unlock(&device->lock);
	return result;
}
Beispiel #18
0
status_t
usb_disk_request_sense(device_lun *lun)
{
	uint32 dataLength = sizeof(scsi_request_sense_6_parameter);
	scsi_request_sense_6_parameter parameter;
	status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0,
		dataLength, &parameter, &dataLength, true);
	if (result != B_OK) {
		TRACE_ALWAYS("getting request sense data failed\n");
		return result;
	}

	if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY
		&& parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
		TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: 0x%02x;\n",
			parameter.sense_key, parameter.additional_sense_code,
			parameter.additional_sense_code_qualifier);
	}

	switch (parameter.sense_key) {
		case SCSI_SENSE_KEY_NO_SENSE:
		case SCSI_SENSE_KEY_RECOVERED_ERROR:
			return B_OK;

		case SCSI_SENSE_KEY_HARDWARE_ERROR:
		case SCSI_SENSE_KEY_MEDIUM_ERROR:
			TRACE_ALWAYS("request_sense: media or hardware error\n");
			return B_DEV_UNREADABLE;

		case SCSI_SENSE_KEY_ILLEGAL_REQUEST:
			TRACE_ALWAYS("request_sense: illegal request\n");
			return B_DEV_INVALID_IOCTL;

		case SCSI_SENSE_KEY_UNIT_ATTENTION:
			if (parameter.additional_sense_code != SCSI_ASC_MEDIUM_NOT_PRESENT) {
				TRACE_ALWAYS("request_sense: media changed\n");
				lun->media_changed = true;
				lun->media_present = true;
				return B_DEV_MEDIA_CHANGED;
			}
			// fall through

		case SCSI_SENSE_KEY_NOT_READY:
			TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n",
				parameter.additional_sense_code,
				parameter.additional_sense_code_qualifier);
			lun->media_present = false;
			usb_disk_reset_capacity(lun);
			return B_DEV_NO_MEDIA;

		case SCSI_SENSE_KEY_DATA_PROTECT:
			TRACE_ALWAYS("request_sense: write protected\n");
			return B_READ_ONLY_DEVICE;

		case SCSI_SENSE_KEY_ABORTED_COMMAND:
			TRACE_ALWAYS("request_sense: command aborted\n");
			return B_CANCELED;
	}

	return B_ERROR;
}
Beispiel #19
0
static status_t
usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
{
	device_lun *lun = (device_lun *)cookie;
	disk_device *device = lun->device;
	mutex_lock(&device->lock);
	if (device->removed) {
		mutex_unlock(&device->lock);
		return B_DEV_NOT_READY;
	}

	status_t result = B_DEV_INVALID_IOCTL;
	switch (op) {
		case B_GET_MEDIA_STATUS: {
			*(status_t *)buffer = usb_disk_test_unit_ready(lun);
			TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer);
			result = B_OK;
			break;
		}

		case B_GET_GEOMETRY: {
			if (lun->media_changed) {
				result = usb_disk_update_capacity(lun);
				if (result != B_OK)
					break;
			}

			device_geometry *geometry = (device_geometry *)buffer;
			geometry->bytes_per_sector = lun->block_size;
			geometry->cylinder_count = lun->block_count;
			geometry->sectors_per_track = geometry->head_count = 1;
			geometry->device_type = lun->device_type;
			geometry->removable = lun->removable;
			geometry->read_only = lun->write_protected;
			geometry->write_once = (lun->device_type == B_WORM);
			TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n",
				geometry->cylinder_count, geometry->bytes_per_sector);
			result = B_OK;
			break;
		}

		case B_FLUSH_DRIVE_CACHE:
			TRACE("B_FLUSH_DRIVE_CACHE\n");
			result = usb_disk_synchronize(lun, true);
			break;

		case B_EJECT_DEVICE:
			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2,
				NULL, NULL, false);
			break;

		case B_LOAD_MEDIA:
			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3,
				NULL, NULL, false);
			break;

#if HAIKU_TARGET_PLATFORM_HAIKU
		case B_GET_ICON:
			// We don't support this legacy ioctl anymore, but the two other
			// icon ioctls below instead.
			break;

		case B_GET_ICON_NAME:
			result = user_strlcpy((char *)buffer,
				"devices/drive-removable-media-usb", B_FILE_NAME_LENGTH);
			break;

		case B_GET_VECTOR_ICON:
		{
			if (length != sizeof(device_icon)) {
				result = B_BAD_VALUE;
				break;
			}

			device_icon iconData;
			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) {
				result = B_BAD_ADDRESS;
				break;
			}

			if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) {
				if (user_memcpy(iconData.icon_data, kDeviceIcon,
						sizeof(kDeviceIcon)) != B_OK) {
					result = B_BAD_ADDRESS;
					break;
				}
			}

			iconData.icon_size = sizeof(kDeviceIcon);
			result = user_memcpy(buffer, &iconData, sizeof(device_icon));
			break;
		}
#endif

		default:
			TRACE_ALWAYS("unhandled ioctl %ld\n", op);
			break;
	}

	mutex_unlock(&device->lock);
	return result;
}
Beispiel #20
0
static status_t
usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
{
	device_lun *lun = (device_lun *)cookie;
	disk_device *device = lun->device;
	mutex_lock(&device->lock);
	if (device->removed) {
		mutex_unlock(&device->lock);
		return B_DEV_NOT_READY;
	}

	status_t result = B_DEV_INVALID_IOCTL;
	switch (op) {
		case B_GET_MEDIA_STATUS:
		{
			err_act action = err_act_ok;
			for (uint32 tries = 0; tries < 3; tries++) {
				status_t ready = usb_disk_test_unit_ready(lun, &action);
				if (ready == B_OK || ready == B_DEV_NO_MEDIA
					|| (action != err_act_retry
						&& action != err_act_many_retries)) {
					*(status_t *)buffer = ready;
					break;
				}
				snooze(500000);
			}
			TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n",
				*(status_t *)buffer);
			result = B_OK;
			break;
		}

		case B_GET_GEOMETRY:
		{
			if (lun->media_changed) {
				result = usb_disk_update_capacity(lun);
				if (result != B_OK)
					break;
			}

			device_geometry geometry;
			devfs_compute_geometry_size(&geometry, lun->block_count,
				lun->block_size);

			geometry.device_type = lun->device_type;
			geometry.removable = lun->removable;
			geometry.read_only = lun->write_protected;
			geometry.write_once = lun->device_type == B_WORM;
			TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32
				" bytes per sector\n", geometry.cylinder_count,
				geometry.bytes_per_sector);
			result = user_memcpy(buffer, &geometry, sizeof(device_geometry));
			break;
		}

		case B_FLUSH_DRIVE_CACHE:
			TRACE("B_FLUSH_DRIVE_CACHE\n");
			result = usb_disk_synchronize(lun, true);
			break;

		case B_EJECT_DEVICE:
			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2,
				NULL, NULL, false);
			break;

		case B_LOAD_MEDIA:
			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3,
				NULL, NULL, false);
			break;

#if HAIKU_TARGET_PLATFORM_HAIKU
		case B_GET_ICON:
			// We don't support this legacy ioctl anymore, but the two other
			// icon ioctls below instead.
			break;

		case B_GET_ICON_NAME:
			result = user_strlcpy((char *)buffer,
				"devices/drive-removable-media-usb", B_FILE_NAME_LENGTH);
			break;

		case B_GET_VECTOR_ICON:
		{
			if (length != sizeof(device_icon)) {
				result = B_BAD_VALUE;
				break;
			}

			device_icon iconData;
			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) {
				result = B_BAD_ADDRESS;
				break;
			}

			if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) {
				if (user_memcpy(iconData.icon_data, kDeviceIcon,
						sizeof(kDeviceIcon)) != B_OK) {
					result = B_BAD_ADDRESS;
					break;
				}
			}

			iconData.icon_size = sizeof(kDeviceIcon);
			result = user_memcpy(buffer, &iconData, sizeof(device_icon));
			break;
		}

		case B_GET_DEVICE_NAME:
		{
			size_t nameLength = sizeof(lun->vendor_name)
				+ sizeof(lun->product_name) + sizeof(lun->product_revision) + 3;

			char name[nameLength];
			snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name,
				lun->product_name, lun->product_revision);

			normalize_name(name, nameLength);

			result = user_strlcpy((char *)buffer, name, length);
			if (result > 0)
				result = B_OK;

			TRACE_ALWAYS("got device name \"%s\": %s\n", name,
				strerror(result));
			break;
		}
#endif

		default:
			TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op);
			break;
	}

	mutex_unlock(&device->lock);
	return result;
}